import { DRAG_DROP_TYPES, DragLayerRendered, Header, Root, useReviewWorkflows } from "./chunk-HDN4UDJS.js"; import { AVAILABLE_COLORS, getStageColorByHex, isBaseQueryError } from "./chunk-KGPWUC7Q.js"; import { CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME, CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME, LimitsModal, reviewWorkflowsApi, useGetContentTypesQuery } from "./chunk-E3IW2VDN.js"; import { useTypedSelector } from "./chunk-MN3D3XJI.js"; import "./chunk-C7H2BX76.js"; import "./chunk-QF6GPHA4.js"; import { getEmptyImage } from "./chunk-SYWYLB7I.js"; import { useDrag, useDrop } from "./chunk-S3HPKOXW.js"; import "./chunk-JRLAXHTE.js"; import "./chunk-E4IFZ6ZT.js"; import "./chunk-QLEKUQKW.js"; import "./chunk-4J3VOWQV.js"; import "./chunk-PFI4R5WA.js"; import { useLicenseLimits } from "./chunk-G2UWKDMB.js"; import "./chunk-B3BGMYGX.js"; import "./chunk-W6ICJ5TB.js"; import "./chunk-IHYIPMY2.js"; import "./chunk-UWHSN2C7.js"; import "./chunk-ERK7O2GM.js"; import "./chunk-FCIM6RNO.js"; import "./chunk-J33IXKN4.js"; import { ConfirmDialog } from "./chunk-NP53ZCXD.js"; import "./chunk-MBK4V2X7.js"; import "./chunk-5ESYXDTN.js"; import "./chunk-K65KIEAL.js"; import "./chunk-B7ZLODDO.js"; import "./chunk-PW7XKCYO.js"; import "./chunk-RMBEU7DO.js"; import "./chunk-RI2W2UZ6.js"; import { BackButton } from "./chunk-IY256CNP.js"; import "./chunk-IFOFBKTA.js"; import { create4 as create, create5 as create2, create6 as create3, create7 as create4 } from "./chunk-XLSIZGJF.js"; import "./chunk-EGNP2T5O.js"; import { useTracking } from "./chunk-GSN7U3BK.js"; import "./chunk-T3B5F2LV.js"; import "./chunk-YXDCVYVT.js"; import "./chunk-QIJGNK42.js"; import "./chunk-7PUJSL55.js"; import "./chunk-C2ZJTFO7.js"; import "./chunk-C75BZXCZ.js"; import "./chunk-APGTER6B.js"; import "./chunk-ZM6TT53G.js"; import { MemoizedInputRenderer } from "./chunk-6AXVGFVQ.js"; import { Form, generateNKeysBetween, useField, useForm } from "./chunk-BFLP6DBI.js"; import { useRBAC } from "./chunk-CMLQV3Z2.js"; import "./chunk-IGCTEXRF.js"; import "./chunk-TIVRAWTC.js"; import "./chunk-PQINNV4N.js"; import "./chunk-VYSYYPOB.js"; import { Page, useAPIErrorHandler } from "./chunk-5CAWUBTQ.js"; import "./chunk-W2TBR6J3.js"; import "./chunk-QEGMJR7H.js"; import "./chunk-LCL5TIBZ.js"; import "./chunk-WOQNBAGN.js"; import "./chunk-BHLYCXQ7.js"; import "./chunk-76QM3EFM.js"; import "./chunk-CE4VABH2.js"; import "./chunk-5VODLFKF.js"; import { useNotification } from "./chunk-N55RVBRV.js"; import { Accordion, Box, Button, Dialog, Field, Flex, Grid, IconButton, Menu, MenuItem, MultiSelect, MultiSelectGroup, MultiSelectOption, SingleSelect, SingleSelectOption, TextInput, Typography, VisuallyHidden, useCollator, useComposedRefs, useIntl } from "./chunk-7XB6XSWQ.js"; import "./chunk-5ZC4PE57.js"; import { useNavigate, useParams } from "./chunk-TUXTO2Z5.js"; import "./chunk-FOD4ENRR.js"; import { ForwardRef$1V, ForwardRef$1f, ForwardRef$3B, ForwardRef$3R, ForwardRef$3T, ForwardRef$4F } from "./chunk-WRD5KPDH.js"; import { require_jsx_runtime } from "./chunk-NIAJZ5MX.js"; import { dt } from "./chunk-ACIMPXWY.js"; import { require_react } from "./chunk-MADUDGYZ.js"; import { __toESM } from "./chunk-PLDDJCW6.js"; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/id.mjs var import_jsx_runtime4 = __toESM(require_jsx_runtime(), 1); var React4 = __toESM(require_react(), 1); // node_modules/@strapi/review-workflows/dist/admin/routes/settings/components/Stages.mjs var import_jsx_runtime2 = __toESM(require_jsx_runtime(), 1); var React3 = __toESM(require_react(), 1); // node_modules/@strapi/review-workflows/dist/admin/services/admin.mjs var adminApi = reviewWorkflowsApi.injectEndpoints({ endpoints(builder) { return { getAdminRoles: builder.query({ query: () => ({ url: `/admin/roles`, method: "GET" }), transformResponse: (res) => { return res.data; } }) }; } }); var { useGetAdminRolesQuery } = adminApi; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/hooks/useDragAndDrop.mjs var React2 = __toESM(require_react(), 1); // node_modules/@strapi/review-workflows/dist/admin/routes/settings/hooks/useKeyboardDragAndDrop.mjs var React = __toESM(require_react(), 1); var useKeyboardDragAndDrop = (active, index, { onCancel, onDropItem, onGrabItem, onMoveItem }) => { const [isSelected, setIsSelected] = React.useState(false); const handleMove = (movement) => { if (!isSelected) { return; } if (typeof index === "number" && onMoveItem) { if (movement === "UP") { onMoveItem(index - 1, index); } else if (movement === "DOWN") { onMoveItem(index + 1, index); } } }; const handleDragClick = () => { if (isSelected) { if (onDropItem) { onDropItem(index); } setIsSelected(false); } else { if (onGrabItem) { onGrabItem(index); } setIsSelected(true); } }; const handleCancel = () => { if (isSelected) { setIsSelected(false); if (onCancel) { onCancel(index); } } }; const handleKeyDown = (e) => { if (!active) { return; } if (e.key === "Tab" && !isSelected) { return; } e.preventDefault(); switch (e.key) { case " ": case "Enter": handleDragClick(); break; case "Escape": handleCancel(); break; case "ArrowDown": case "ArrowRight": handleMove("DOWN"); break; case "ArrowUp": case "ArrowLeft": handleMove("UP"); break; } }; return handleKeyDown; }; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/hooks/useDragAndDrop.mjs var DIRECTIONS = { UPWARD: "upward", DOWNWARD: "downward" }; var DROP_SENSITIVITY = { REGULAR: "regular", IMMEDIATE: "immediate" }; var useDragAndDrop = (active, { type = "STRAPI_DND", index, item, onStart, onEnd, onGrabItem, onDropItem, onCancel, onMoveItem, dropSensitivity = DROP_SENSITIVITY.REGULAR }) => { const objectRef = React2.useRef(null); const [{ handlerId, isOver }, dropRef] = useDrop({ accept: type, collect(monitor) { return { handlerId: monitor.getHandlerId(), isOver: monitor.isOver({ shallow: true }) }; }, drop(item2) { const draggedIndex = item2.index; const newIndex = index; if (isOver && onDropItem) { onDropItem(draggedIndex, newIndex); } }, hover(item2, monitor) { var _a; if (!objectRef.current || !onMoveItem) { return; } const dragIndex = item2.index; const newIndex = index; const hoverBoundingRect = (_a = objectRef.current) == null ? void 0 : _a.getBoundingClientRect(); const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2; const clientOffset = monitor.getClientOffset(); if (!clientOffset) return; const hoverClientY = clientOffset && clientOffset.y - hoverBoundingRect.top; if (typeof dragIndex === "number" && typeof newIndex === "number") { if (dragIndex === newIndex) { return; } if (dropSensitivity === DROP_SENSITIVITY.REGULAR) { if (dragIndex < newIndex && hoverClientY < hoverMiddleY) { return; } if (dragIndex > newIndex && hoverClientY > hoverMiddleY) { return; } } onMoveItem(newIndex, dragIndex); item2.index = newIndex; } else { if (Array.isArray(dragIndex) && Array.isArray(newIndex)) { const minLength = Math.min(dragIndex.length, newIndex.length); let areEqual = true; let isLessThan = false; let isGreaterThan = false; for (let i = 0; i < minLength; i++) { if (dragIndex[i] < newIndex[i]) { isLessThan = true; areEqual = false; break; } else if (dragIndex[i] > newIndex[i]) { isGreaterThan = true; areEqual = false; break; } } if (areEqual && dragIndex.length === newIndex.length) { return; } if (dropSensitivity === DROP_SENSITIVITY.REGULAR) { if (isLessThan && !isGreaterThan && hoverClientY < hoverMiddleY) { return; } if (isGreaterThan && !isLessThan && hoverClientY > hoverMiddleY) { return; } } } onMoveItem(newIndex, dragIndex); item2.index = newIndex; } } }); const getDragDirection = (monitor) => { if (monitor && monitor.isDragging() && !monitor.didDrop() && monitor.getInitialClientOffset() && monitor.getClientOffset()) { const deltaY = monitor.getInitialClientOffset().y - monitor.getClientOffset().y; if (deltaY > 0) return DIRECTIONS.UPWARD; if (deltaY < 0) return DIRECTIONS.DOWNWARD; return null; } return null; }; const [{ isDragging, direction }, dragRef, dragPreviewRef] = useDrag({ type, item() { var _a; if (onStart) { onStart(); } const { width } = ((_a = objectRef.current) == null ? void 0 : _a.getBoundingClientRect()) ?? {}; return { index, width, ...item }; }, end() { if (onEnd) { onEnd(); } }, canDrag: active, /** * This is useful when the item is in a virtualized list. * However, if we don't have an ID then we want the libraries * defaults to take care of this. */ isDragging: (item == null ? void 0 : item.id) ? (monitor) => { return item.id === monitor.getItem().id; } : void 0, collect: (monitor) => ({ isDragging: monitor.isDragging(), initialOffset: monitor.getInitialClientOffset(), currentOffset: monitor.getClientOffset(), direction: getDragDirection(monitor) }) }); const handleKeyDown = useKeyboardDragAndDrop(active, index, { onGrabItem, onDropItem, onCancel, onMoveItem }); return [ { handlerId, isDragging, handleKeyDown, isOverDropTarget: isOver, direction }, objectRef, dropRef, dragRef, dragPreviewRef ]; }; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/components/AddStage.mjs var import_jsx_runtime = __toESM(require_jsx_runtime(), 1); var AddStage = ({ children, ...props }) => { return (0, import_jsx_runtime.jsx)(StyledButton, { tag: "button", background: "neutral0", borderColor: "neutral150", paddingBottom: 3, paddingLeft: 4, paddingRight: 4, paddingTop: 3, shadow: "filterShadow", ...props, children: (0, import_jsx_runtime.jsx)(Typography, { variant: "pi", fontWeight: "bold", children: (0, import_jsx_runtime.jsxs)(Flex, { tag: "span", gap: 2, children: [ (0, import_jsx_runtime.jsx)(ForwardRef$1f, { width: "2.4rem", height: "2.4rem", "aria-hidden": true }), children ] }) }) }); }; var StyledButton = dt(Box)` border-radius: 26px; color: ${({ theme }) => theme.colors.neutral500}; &:hover { color: ${({ theme }) => theme.colors.primary600}; } &:active { color: ${({ theme }) => theme.colors.primary600}; } `; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/components/Stages.mjs var Stages = ({ canDelete = true, canUpdate = true, isCreating }) => { const { formatMessage } = useIntl(); const { trackUsage } = useTracking(); const addFieldRow = useForm("Stages", (state) => state.addFieldRow); const { value: stages = [] } = useField("stages"); return (0, import_jsx_runtime2.jsxs)(Flex, { direction: "column", gap: 6, width: "100%", children: [ (0, import_jsx_runtime2.jsxs)(Box, { position: "relative", width: "100%", children: [ (0, import_jsx_runtime2.jsx)(Background, { background: "neutral200", height: "100%", left: "50%", position: "absolute", top: "0", width: 2 }), (0, import_jsx_runtime2.jsx)(Flex, { direction: "column", alignItems: "stretch", gap: 6, position: "relative", tag: "ol", children: stages.map((stage, index) => { return (0, import_jsx_runtime2.jsx)(Box, { tag: "li", children: (0, import_jsx_runtime2.jsx)(Stage, { index, canDelete: stages.length > 1 && canDelete, canReorder: stages.length > 1, canUpdate, stagesCount: stages.length, defaultOpen: !stage.id, ...stage }) }, stage.__temp_key__); }) }) ] }), canUpdate && (0, import_jsx_runtime2.jsx)(AddStage, { type: "button", onClick: () => { addFieldRow("stages", { name: "" }); trackUsage("willCreateStage"); }, children: formatMessage({ id: "Settings.review-workflows.stage.add", defaultMessage: "Add new stage" }) }) ] }); }; var Background = dt(Box)` transform: translateX(-50%); `; var Stage = ({ index, canDelete = false, canReorder = false, canUpdate = false, stagesCount, name, permissions, color, defaultOpen }) => { const [liveText, setLiveText] = React3.useState(); const { formatMessage } = useIntl(); const { trackUsage } = useTracking(); const stageErrors = useForm("Stages", (state) => state.errors.stages); const error = stageErrors == null ? void 0 : stageErrors[index]; const addFieldRow = useForm("Stage", (state) => state.addFieldRow); const moveFieldRow = useForm("Stage", (state) => state.moveFieldRow); const removeFieldRow = useForm("Stage", (state) => state.removeFieldRow); const getItemPos = (index2) => `${index2 + 1} of ${stagesCount}`; const handleGrabStage = (index2) => { setLiveText(formatMessage({ id: "dnd.grab-item", defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.` }, { item: name, position: getItemPos(index2) })); }; const handleDropStage = (index2) => { setLiveText(formatMessage({ id: "dnd.drop-item", defaultMessage: `{item}, dropped. Final position in list: {position}.` }, { item: name, position: getItemPos(index2) })); }; const handleCancelDragStage = () => { setLiveText(formatMessage({ id: "dnd.cancel-item", defaultMessage: "{item}, dropped. Re-order cancelled." }, { item: name })); }; const handleMoveStage = (newIndex, oldIndex) => { setLiveText(formatMessage({ id: "dnd.reorder", defaultMessage: "{item}, moved. New position in list: {position}." }, { item: name, position: getItemPos(newIndex) })); moveFieldRow("stages", oldIndex, newIndex); }; const [{ handlerId, isDragging, handleKeyDown }, stageRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canReorder, { index, item: { index, name }, onGrabItem: handleGrabStage, onDropItem: handleDropStage, onMoveItem: handleMoveStage, onCancel: handleCancelDragStage, type: DRAG_DROP_TYPES.STAGE }); const composedRef = useComposedRefs(stageRef, dropRef); React3.useEffect(() => { dragPreviewRef(getEmptyImage(), { captureDraggingState: false }); }, [ dragPreviewRef, index ]); const handleCloneClick = () => { addFieldRow("stages", { name, color, permissions }); }; const id = React3.useId(); return (0, import_jsx_runtime2.jsxs)(Box, { ref: composedRef, shadow: "tableShadow", children: [ liveText && (0, import_jsx_runtime2.jsx)(VisuallyHidden, { "aria-live": "assertive", children: liveText }), isDragging ? (0, import_jsx_runtime2.jsx)(Box, { background: "primary100", borderStyle: "dashed", borderColor: "primary600", borderWidth: "1px", display: "block", hasRadius: true, padding: 6 }) : (0, import_jsx_runtime2.jsx)(AccordionRoot, { onValueChange: (value) => { if (value) { trackUsage("willEditStage"); } }, defaultValue: defaultOpen ? id : void 0, $error: Object.values(error ?? {}).length > 0, children: (0, import_jsx_runtime2.jsxs)(Accordion.Item, { value: id, children: [ (0, import_jsx_runtime2.jsxs)(Accordion.Header, { children: [ (0, import_jsx_runtime2.jsx)(Accordion.Trigger, { children: name }), (0, import_jsx_runtime2.jsx)(Accordion.Actions, { children: canDelete || canUpdate ? (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [ (0, import_jsx_runtime2.jsxs)(Menu.Root, { children: [ (0, import_jsx_runtime2.jsxs)(ContextMenuTrigger, { size: "S", endIcon: null, paddingLeft: 2, paddingRight: 2, children: [ (0, import_jsx_runtime2.jsx)(ForwardRef$1V, { "aria-hidden": true, focusable: false }), (0, import_jsx_runtime2.jsx)(VisuallyHidden, { tag: "span", children: formatMessage({ id: "[tbdb].components.DynamicZone.more-actions", defaultMessage: "More actions" }) }) ] }), (0, import_jsx_runtime2.jsx)(Menu.Content, { popoverPlacement: "bottom-end", zIndex: 2, children: (0, import_jsx_runtime2.jsxs)(Menu.SubRoot, { children: [ canUpdate && (0, import_jsx_runtime2.jsx)(MenuItem, { onClick: handleCloneClick, children: formatMessage({ id: "Settings.review-workflows.stage.delete", defaultMessage: "Duplicate stage" }) }), canDelete && (0, import_jsx_runtime2.jsx)(DeleteMenuItem, { onClick: () => removeFieldRow("stages", index), children: formatMessage({ id: "Settings.review-workflows.stage.delete", defaultMessage: "Delete" }) }) ] }) }) ] }), canUpdate && (0, import_jsx_runtime2.jsx)(IconButton, { background: "transparent", hasRadius: true, variant: "ghost", "data-handler-id": handlerId, ref: dragRef, label: formatMessage({ id: "Settings.review-workflows.stage.drag", defaultMessage: "Drag" }), onClick: (e) => e.stopPropagation(), onKeyDown: handleKeyDown, children: (0, import_jsx_runtime2.jsx)(ForwardRef$3T, {}) }) ] }) : null }) ] }), (0, import_jsx_runtime2.jsx)(Accordion.Content, { children: (0, import_jsx_runtime2.jsx)(Grid.Root, { gap: 4, padding: 6, children: [ { disabled: !canUpdate, label: formatMessage({ id: "Settings.review-workflows.stage.name.label", defaultMessage: "Stage name" }), name: `stages.${index}.name`, required: true, size: 6, type: "string" }, { disabled: !canUpdate, label: formatMessage({ id: "content-manager.reviewWorkflows.stage.color", defaultMessage: "Color" }), name: `stages.${index}.color`, required: true, size: 6, type: "color" }, { disabled: !canUpdate, label: formatMessage({ id: "Settings.review-workflows.stage.permissions.label", defaultMessage: "Roles that can change this stage" }), name: `stages.${index}.permissions`, placeholder: formatMessage({ id: "Settings.review-workflows.stage.permissions.placeholder", defaultMessage: "Select a role" }), required: true, size: 6, type: "permissions" } ].map(({ size, ...field }) => (0, import_jsx_runtime2.jsx)(Grid.Item, { col: size, direction: "column", alignItems: "stretch", children: (0, import_jsx_runtime2.jsx)(InputRenderer, { ...field }) }, field.name)) }) }) ] }) }) ] }); }; var AccordionRoot = dt(Accordion.Root)` border: 1px solid ${({ theme, $error }) => $error ? theme.colors.danger600 : theme.colors.neutral200}; `; var DeleteMenuItem = dt(MenuItem)` color: ${({ theme }) => theme.colors.danger600}; `; var ContextMenuTrigger = dt(Menu.Trigger)` :hover, :focus { background-color: ${({ theme }) => theme.colors.neutral100}; } > span { font-size: 0; } `; var InputRenderer = (props) => { switch (props.type) { case "color": return (0, import_jsx_runtime2.jsx)(ColorSelector, { ...props }); case "permissions": return (0, import_jsx_runtime2.jsx)(PermissionsField, { ...props }); default: return (0, import_jsx_runtime2.jsx)(MemoizedInputRenderer, { ...props }); } }; var ColorSelector = ({ disabled, label, name, required }) => { const { formatMessage } = useIntl(); const { value, error, onChange } = useField(name); const colorOptions = AVAILABLE_COLORS.map(({ hex, name: name2 }) => ({ value: hex, label: formatMessage({ id: "Settings.review-workflows.stage.color.name", defaultMessage: "{name}" }, { name: name2 }), color: hex })); const { themeColorName } = getStageColorByHex(value) ?? {}; return (0, import_jsx_runtime2.jsxs)(Field.Root, { error, name, required, children: [ (0, import_jsx_runtime2.jsx)(Field.Label, { children: label }), (0, import_jsx_runtime2.jsx)(SingleSelect, { disabled, onChange: (v) => { onChange(name, v.toString()); }, value: value == null ? void 0 : value.toUpperCase(), startIcon: (0, import_jsx_runtime2.jsx)(Flex, { tag: "span", height: 2, background: value, borderColor: themeColorName === "neutral0" ? "neutral150" : "transparent", hasRadius: true, shrink: 0, width: 2 }), children: colorOptions.map(({ value: value2, label: label2, color }) => { const { themeColorName: themeColorName2 } = getStageColorByHex(color) || {}; return (0, import_jsx_runtime2.jsx)(SingleSelectOption, { value: value2, startIcon: (0, import_jsx_runtime2.jsx)(Flex, { tag: "span", height: 2, background: color, borderColor: themeColorName2 === "neutral0" ? "neutral150" : "transparent", hasRadius: true, shrink: 0, width: 2 }), children: label2 }, value2); }) }), (0, import_jsx_runtime2.jsx)(Field.Error, {}) ] }); }; var PermissionsField = ({ disabled, name, placeholder, required }) => { const { formatMessage } = useIntl(); const { toggleNotification } = useNotification(); const [isApplyAllConfirmationOpen, setIsApplyAllConfirmationOpen] = React3.useState(false); const { value = [], error, onChange } = useField(name); const allStages = useForm("PermissionsField", (state) => state.values.stages); const onFormValueChange = useForm("PermissionsField", (state) => state.onChange); const rolesErrorCount = React3.useRef(0); const { data: roles = [], isLoading, error: getRolesError } = useGetAdminRolesQuery(); const filteredRoles = (roles == null ? void 0 : roles.filter((role) => role.code !== "strapi-super-admin")) ?? []; React3.useEffect(() => { if (!isLoading && getRolesError && "status" in getRolesError && getRolesError.status == 403 && rolesErrorCount.current === 0) { rolesErrorCount.current = 1; toggleNotification({ blockTransition: true, type: "danger", message: formatMessage({ id: "review-workflows.stage.permissions.noPermissions.description", defaultMessage: "You don’t have the permission to see roles. Contact your administrator." }) }); } }, [ formatMessage, isLoading, roles, toggleNotification, getRolesError ]); if (!isLoading && filteredRoles.length === 0) { return (0, import_jsx_runtime2.jsxs)(Field.Root, { name, hint: formatMessage({ id: "Settings.review-workflows.stage.permissions.noPermissions.description", defaultMessage: "You don’t have the permission to see roles" }), required, children: [ (0, import_jsx_runtime2.jsx)(Field.Label, { children: formatMessage({ id: "Settings.review-workflows.stage.permissions.label", defaultMessage: "Roles that can change this stage" }) }), (0, import_jsx_runtime2.jsx)(TextInput, { disabled: true, placeholder: formatMessage({ id: "components.NotAllowedInput.text", defaultMessage: "No permissions to see this field" }), startAction: (0, import_jsx_runtime2.jsx)(ForwardRef$3B, { fill: "neutral600" }), type: "text", value: "" }), (0, import_jsx_runtime2.jsx)(Field.Hint, {}) ] }); } return (0, import_jsx_runtime2.jsx)(import_jsx_runtime2.Fragment, { children: (0, import_jsx_runtime2.jsxs)(Flex, { alignItems: "flex-end", gap: 3, children: [ (0, import_jsx_runtime2.jsx)(PermissionWrapper, { grow: 1, children: (0, import_jsx_runtime2.jsxs)(Field.Root, { error, name, required: true, children: [ (0, import_jsx_runtime2.jsx)(Field.Label, { children: formatMessage({ id: "Settings.review-workflows.stage.permissions.label", defaultMessage: "Roles that can change this stage" }) }), (0, import_jsx_runtime2.jsx)(MultiSelect, { disabled, onChange: (values) => { const permissions = values.map((value2) => ({ role: parseInt(value2, 10), action: "admin::review-workflows.stage.transition" })); onChange(name, permissions); }, placeholder, // The Select component expects strings for values value: value.map((permission) => `${permission.role}`), withTags: true, children: (0, import_jsx_runtime2.jsx)(MultiSelectGroup, { label: formatMessage({ id: "Settings.review-workflows.stage.permissions.allRoles.label", defaultMessage: "All roles" }), values: filteredRoles.map((r) => `${r.id}`), children: filteredRoles.map((role) => { return (0, import_jsx_runtime2.jsx)(NestedOption, { value: `${role.id}`, children: role.name }, role.id); }) }) }), (0, import_jsx_runtime2.jsx)(Field.Error, {}) ] }) }), (0, import_jsx_runtime2.jsxs)(Dialog.Root, { open: isApplyAllConfirmationOpen, onOpenChange: setIsApplyAllConfirmationOpen, children: [ (0, import_jsx_runtime2.jsx)(Dialog.Trigger, { children: (0, import_jsx_runtime2.jsx)(IconButton, { disabled, label: formatMessage({ id: "Settings.review-workflows.stage.permissions.apply.label", defaultMessage: "Apply to all stages" }), size: "L", children: (0, import_jsx_runtime2.jsx)(ForwardRef$3R, {}) }) }), (0, import_jsx_runtime2.jsx)(ConfirmDialog, { onConfirm: () => { onFormValueChange("stages", allStages.map((stage) => ({ ...stage, permissions: value }))); setIsApplyAllConfirmationOpen(false); toggleNotification({ type: "success", message: formatMessage({ id: "Settings.review-workflows.page.edit.confirm.stages.permissions.copy.success", defaultMessage: "Applied roles to all other stages of the workflow" }) }); }, variant: "default", children: formatMessage({ id: "Settings.review-workflows.page.edit.confirm.stages.permissions.copy", defaultMessage: "Roles that can change that stage will be applied to all the other stages." }) }) ] }) ] }) }); }; var NestedOption = dt(MultiSelectOption)` padding-left: ${({ theme }) => theme.spaces[7]}; `; var PermissionWrapper = dt(Flex)` > * { flex-grow: 1; } `; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/components/WorkflowAttributes.mjs var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1); var WorkflowAttributes = ({ canUpdate = true }) => { const { formatMessage } = useIntl(); return (0, import_jsx_runtime3.jsxs)(Grid.Root, { background: "neutral0", hasRadius: true, gap: 4, padding: 6, shadow: "tableShadow", children: [ (0, import_jsx_runtime3.jsx)(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: (0, import_jsx_runtime3.jsx)(MemoizedInputRenderer, { disabled: !canUpdate, label: formatMessage({ id: "Settings.review-workflows.workflow.name.label", defaultMessage: "Workflow Name" }), name: "name", required: true, type: "string" }) }), (0, import_jsx_runtime3.jsx)(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: (0, import_jsx_runtime3.jsx)(ContentTypesSelector, { disabled: !canUpdate }) }), (0, import_jsx_runtime3.jsx)(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: (0, import_jsx_runtime3.jsx)(StageSelector, { disabled: !canUpdate }) }) ] }); }; var ContentTypesSelector = ({ disabled }) => { const { formatMessage, locale } = useIntl(); const { data: contentTypes, isLoading } = useGetContentTypesQuery(); const { workflows } = useReviewWorkflows(); const currentWorkflow = useForm("ContentTypesSelector", (state) => state.values); const { error, value, onChange } = useField("contentTypes"); const formatter = useCollator(locale, { sensitivity: "base" }); const isDisabled = disabled || isLoading || !contentTypes || contentTypes.collectionType.length === 0 && contentTypes.singleType.length === 0; const collectionTypes = ((contentTypes == null ? void 0 : contentTypes.collectionType) ?? []).toSorted((a, b) => formatter.compare(a.info.displayName, b.info.displayName)).map((contentType) => ({ label: contentType.info.displayName, value: contentType.uid })); const singleTypes = ((contentTypes == null ? void 0 : contentTypes.singleType) ?? []).map((contentType) => ({ label: contentType.info.displayName, value: contentType.uid })); return (0, import_jsx_runtime3.jsxs)(Field.Root, { error, name: "contentTypes", children: [ (0, import_jsx_runtime3.jsx)(Field.Label, { children: formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.label", defaultMessage: "Associated to" }) }), (0, import_jsx_runtime3.jsx)(MultiSelect, { customizeContent: (value2) => formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.displayValue", defaultMessage: "{count} {count, plural, one {content type} other {content types}} selected" }, { count: value2 == null ? void 0 : value2.length }), disabled: isDisabled, onChange: (values) => { onChange("contentTypes", values); }, value, placeholder: formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.placeholder", defaultMessage: "Select" }), children: [ ...collectionTypes.length > 0 ? [ { label: formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.collectionTypes.label", defaultMessage: "Collection Types" }), children: collectionTypes } ] : [], ...singleTypes.length > 0 ? [ { label: formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.singleTypes.label", defaultMessage: "Single Types" }), children: singleTypes } ] : [] ].map((opt) => { return (0, import_jsx_runtime3.jsx)(MultiSelectGroup, { label: opt.label, values: opt.children.map((child) => child.value.toString()), children: opt.children.map((child) => { const { name: assignedWorkflowName } = (workflows == null ? void 0 : workflows.find((workflow) => (currentWorkflow && workflow.id !== currentWorkflow.id || !currentWorkflow) && workflow.contentTypes.includes(child.value))) ?? {}; return (0, import_jsx_runtime3.jsx)(NestedOption2, { value: child.value, children: (0, import_jsx_runtime3.jsx)(Typography, { children: ( // @ts-expect-error - formatMessage options doesn't expect to be a React component but that's what we need actually for the and components formatMessage({ id: "Settings.review-workflows.workflow.contentTypes.assigned.notice", defaultMessage: "{label} {name, select, undefined {} other {(assigned to {name} workflow)}}" }, { label: child.label, name: assignedWorkflowName, em: (...children) => (0, import_jsx_runtime3.jsx)(Typography, { tag: "em", fontWeight: "bold", children }), i: (...children) => (0, import_jsx_runtime3.jsx)(ContentTypeTakeNotice, { children }) }) ) }) }, child.value); }) }, opt.label); }) }) ] }); }; var NestedOption2 = dt(MultiSelectOption)` padding-left: ${({ theme }) => theme.spaces[7]}; `; var ContentTypeTakeNotice = dt(Typography)` font-style: italic; `; var StageSelector = ({ disabled }) => { const { value: stages = [] } = useField("stages"); const { formatMessage } = useIntl(); const { error, value, onChange } = useField("stageRequiredToPublish"); const validStages = stages.filter((stage) => stage.name); return (0, import_jsx_runtime3.jsxs)(Field.Root, { error, name: "stageRequiredToPublish", hint: formatMessage({ id: "settings.review-workflows.workflow.stageRequiredToPublish.hint", defaultMessage: "Prevents entries from being published if they are not at the required stage." }), children: [ (0, import_jsx_runtime3.jsx)(Field.Label, { children: formatMessage({ id: "settings.review-workflows.workflow.stageRequiredToPublish.label", defaultMessage: "Required stage for publishing" }) }), (0, import_jsx_runtime3.jsxs)(SingleSelect, { disabled, onChange: (value2) => { onChange("stageRequiredToPublish", value2); }, value, children: [ (0, import_jsx_runtime3.jsx)(SingleSelectOption, { value: "", children: formatMessage({ id: "settings.review-workflows.workflow.stageRequiredToPublish.any", defaultMessage: "Any stage" }) }), validStages.map((stage, i) => { var _a; return (0, import_jsx_runtime3.jsx)(SingleSelectOption, { value: ((_a = stage.id) == null ? void 0 : _a.toString()) || stage.__temp_key__, children: stage.name }, `requiredToPublishStage-${stage.id || stage.__temp_key__}`); }) ] }), (0, import_jsx_runtime3.jsx)(Field.Hint, {}) ] }); }; // node_modules/@strapi/review-workflows/dist/admin/routes/settings/id.mjs var WORKFLOW_SCHEMA = create3({ contentTypes: create4().of(create()), name: create().max(255, { id: "review-workflows.validation.name.max-length", defaultMessage: "Name can not be longer than 255 characters" }).required().nullable(), stages: create4().of(create3().shape({ name: create().nullable().required({ id: "review-workflows.validation.stage.name", defaultMessage: "Name is required" }).max(255, { id: "review-workflows.validation.stage.max-length", defaultMessage: "Name can not be longer than 255 characters" }).test("unique-name", { id: "review-workflows.validation.stage.duplicate", defaultMessage: "Stage name must be unique" }, (stageName, context) => { const { stages } = context.from[1].value; return stages.filter((stage) => stage.name === stageName).length === 1; }), color: create().nullable().required({ id: "review-workflows.validation.stage.color", defaultMessage: "Color is required" }).matches(/^#(?:[0-9a-fA-F]{3}){1,2}$/i), permissions: create4(create3({ role: create2().strict().typeError({ id: "review-workflows.validation.stage.permissions.role.number", defaultMessage: "Role must be of type number" }).required(), action: create().required({ id: "review-workflows.validation.stage.permissions.action.required", defaultMessage: "Action is a required argument" }) })).strict() })).min(1), stageRequiredToPublish: create().nullable() }); var EditPage = () => { const { id = "" } = useParams(); const isCreatingWorkflow = id === "create"; const { formatMessage } = useIntl(); const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler(); const navigate = useNavigate(); const { toggleNotification } = useNotification(); const { isLoading: isLoadingWorkflow, meta, workflows, error, update, create: create5 } = useReviewWorkflows(); const permissions = useTypedSelector((state) => { var _a; return (_a = state.admin_app.permissions["settings"]) == null ? void 0 : _a["review-workflows"]; }); const { allowedActions: { canDelete, canUpdate, canCreate } } = useRBAC(permissions); const [savePrompts, setSavePrompts] = React4.useState({}); const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits(); const [showLimitModal, setShowLimitModal] = React4.useState(null); const currentWorkflow = workflows == null ? void 0 : workflows.find((workflow) => workflow.id === parseInt(id, 10)); const contentTypesFromOtherWorkflows = workflows == null ? void 0 : workflows.filter((workflow) => workflow.id !== parseInt(id, 10)).flatMap((workflow) => workflow.contentTypes); const limits = getFeature("review-workflows"); const numberOfWorkflows = limits == null ? void 0 : limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME]; const stagesPerWorkflow = limits == null ? void 0 : limits[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME]; const submitForm = async (data, helpers) => { var _a; try { const { stageRequiredToPublish, ...rest } = data; const stageRequiredToPublishName = stageRequiredToPublish === "" ? null : (_a = rest.stages.find((stage) => stage.id === Number(stageRequiredToPublish) || stage.__temp_key__ === stageRequiredToPublish)) == null ? void 0 : _a.name; if (!isCreatingWorkflow) { const res = await update(id, { ...rest, // compare permissions of stages and only submit them if at least one has // changed; this enables partial updates e.g. for users who don't have // permissions to see roles stages: rest.stages.map((stage) => { var _a2, _b, _c, _d; let hasUpdatedPermissions = true; const serverStage = (_a2 = currentWorkflow == null ? void 0 : currentWorkflow.stages) == null ? void 0 : _a2.find((serverStage2) => serverStage2.id === (stage == null ? void 0 : stage.id)); if (serverStage) { hasUpdatedPermissions = ((_b = serverStage.permissions) == null ? void 0 : _b.length) !== ((_c = stage.permissions) == null ? void 0 : _c.length) || !((_d = serverStage.permissions) == null ? void 0 : _d.every((serverPermission) => { var _a3; return !!((_a3 = stage.permissions) == null ? void 0 : _a3.find((permission) => permission.role === serverPermission.role)); })); } return { ...stage, permissions: hasUpdatedPermissions ? stage.permissions : void 0 }; }), stageRequiredToPublishName }); if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") { helpers.setErrors(formatValidationErrors(res.error)); } } else { const res = await create5({ ...rest, stageRequiredToPublishName }); if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") { helpers.setErrors(formatValidationErrors(res.error)); } else if ("data" in res) { navigate(`../${res.data.id}`, { replace: true }); } } } catch (error2) { toggleNotification({ type: "danger", message: formatMessage({ id: "notification.error", defaultMessage: "An error occurred" }) }); } setSavePrompts({}); }; const handleConfirmDeleteDialog = (data, helpers) => async () => { await submitForm(data, helpers); }; const handleConfirmClose = () => { setSavePrompts({}); }; const handleSubmit = async (data, helpers) => { const isContentTypeReassignment = data.contentTypes.some((contentType) => contentTypesFromOtherWorkflows == null ? void 0 : contentTypesFromOtherWorkflows.includes(contentType)); const hasDeletedServerStages = !isCreatingWorkflow && !(currentWorkflow == null ? void 0 : currentWorkflow.stages.every((stage) => data.stages.some((newStage) => newStage.id === stage.id))); if (meta && numberOfWorkflows && (meta == null ? void 0 : meta.workflowCount) > parseInt(numberOfWorkflows, 10)) { setShowLimitModal("workflow"); } else if (data.stages && stagesPerWorkflow && data.stages.length > parseInt(stagesPerWorkflow, 10)) { setShowLimitModal("stage"); } else if (hasDeletedServerStages || isContentTypeReassignment) { if (hasDeletedServerStages) { setSavePrompts((prev) => ({ ...prev, hasDeletedServerStages: true })); } if (isContentTypeReassignment) { setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true })); } } else { await submitForm(data, helpers); } }; React4.useEffect(() => { if (!isLoadingWorkflow && !isLicenseLoading) { if (meta && numberOfWorkflows && (meta == null ? void 0 : meta.workflowCount) > parseInt(numberOfWorkflows, 10)) { setShowLimitModal("workflow"); } else if (currentWorkflow && currentWorkflow.stages && stagesPerWorkflow && currentWorkflow.stages.length > parseInt(stagesPerWorkflow, 10)) { setShowLimitModal("stage"); } } }, [ currentWorkflow, isLicenseLoading, isLoadingWorkflow, limits, meta, numberOfWorkflows, stagesPerWorkflow ]); const initialValues = React4.useMemo(() => { var _a; if (isCreatingWorkflow || !currentWorkflow) { return { name: "", stages: [], contentTypes: [], stageRequiredToPublish: "" }; } else { return { name: currentWorkflow.name, stages: addTmpKeysToStages(currentWorkflow.stages), contentTypes: currentWorkflow.contentTypes, stageRequiredToPublish: ((_a = currentWorkflow.stageRequiredToPublish) == null ? void 0 : _a.id.toString()) ?? "" }; } }, [ currentWorkflow, isCreatingWorkflow ]); if (isLoadingWorkflow) { return (0, import_jsx_runtime4.jsx)(Page.Loading, {}); } if (error) { return (0, import_jsx_runtime4.jsx)(Page.Error, {}); } return (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [ (0, import_jsx_runtime4.jsx)(DragLayerRendered, {}), (0, import_jsx_runtime4.jsx)(Form, { method: isCreatingWorkflow ? "POST" : "PUT", initialValues, validationSchema: WORKFLOW_SCHEMA, onSubmit: handleSubmit, children: ({ modified, isSubmitting, values, setErrors }) => { var _a; return (0, import_jsx_runtime4.jsxs)(import_jsx_runtime4.Fragment, { children: [ (0, import_jsx_runtime4.jsx)(Header, { navigationAction: (0, import_jsx_runtime4.jsx)(BackButton, { fallback: ".." }), primaryAction: canUpdate || canCreate ? (0, import_jsx_runtime4.jsx)(Button, { startIcon: (0, import_jsx_runtime4.jsx)(ForwardRef$4F, {}), type: "submit", disabled: !modified || isSubmitting || values.stages.length === 0, // if the confirm dialog is open the loading state is on // the confirm button already loading: !Boolean(Object.keys(savePrompts).length > 0) && isSubmitting, children: formatMessage({ id: "global.save", defaultMessage: "Save" }) }) : null, subtitle: formatMessage({ id: "review-workflows.page.subtitle", defaultMessage: "{count, plural, one {# stage} other {# stages}}" }, { count: ((_a = currentWorkflow == null ? void 0 : currentWorkflow.stages) == null ? void 0 : _a.length) ?? 0 }), title: (currentWorkflow == null ? void 0 : currentWorkflow.name) || formatMessage({ id: "Settings.review-workflows.create.page.title", defaultMessage: "Create Review Workflow" }) }), (0, import_jsx_runtime4.jsx)(Root, { children: (0, import_jsx_runtime4.jsxs)(Flex, { alignItems: "stretch", direction: "column", gap: 7, children: [ (0, import_jsx_runtime4.jsx)(WorkflowAttributes, { canUpdate: canUpdate || canCreate }), (0, import_jsx_runtime4.jsx)(Stages, { canDelete, canUpdate: canUpdate || canCreate, isCreating: isCreatingWorkflow }) ] }) }), (0, import_jsx_runtime4.jsx)(Dialog.Root, { open: Object.keys(savePrompts).length > 0, onOpenChange: handleConfirmClose, children: (0, import_jsx_runtime4.jsx)(ConfirmDialog, { onConfirm: handleConfirmDeleteDialog(values, { setErrors }), children: (0, import_jsx_runtime4.jsxs)(Flex, { direction: "column", gap: 5, children: [ savePrompts.hasDeletedServerStages && (0, import_jsx_runtime4.jsx)(Typography, { textAlign: "center", variant: "omega", children: formatMessage({ id: "review-workflows.page.delete.confirm.stages.body", defaultMessage: "All entries assigned to deleted stages will be moved to the previous stage." }) }), savePrompts.hasReassignedContentTypes && (0, import_jsx_runtime4.jsx)(Typography, { textAlign: "center", variant: "omega", children: formatMessage({ id: "review-workflows.page.delete.confirm.contentType.body", defaultMessage: "{count} {count, plural, one {content-type} other {content-types}} {count, plural, one {is} other {are}} already mapped to {count, plural, one {another workflow} other {other workflows}}. If you save changes, {count, plural, one {this} other {these}} {count, plural, one {content-type} other {{count} content-types}} will no more be mapped to the {count, plural, one {another workflow} other {other workflows}} and all corresponding information will be removed." }, { count: (contentTypesFromOtherWorkflows == null ? void 0 : contentTypesFromOtherWorkflows.filter((contentType) => values.contentTypes.includes(contentType)).length) ?? 0 }) }), (0, import_jsx_runtime4.jsx)(Typography, { textAlign: "center", variant: "omega", children: formatMessage({ id: "review-workflows.page.delete.confirm.confirm", defaultMessage: "Are you sure you want to save?" }) }) ] }) }) }) ] }); } }), (0, import_jsx_runtime4.jsxs)(LimitsModal.Root, { open: showLimitModal === "workflow", onOpenChange: () => setShowLimitModal(null), children: [ (0, import_jsx_runtime4.jsx)(LimitsModal.Title, { children: formatMessage({ id: "review-workflows.edit.page.workflows.limit.title", defaultMessage: "You’ve reached the limit of workflows in your plan" }) }), (0, import_jsx_runtime4.jsx)(LimitsModal.Body, { children: formatMessage({ id: "review-workflows.edit.page.workflows.limit.body", defaultMessage: "Delete a workflow or contact Sales to enable more workflows." }) }) ] }), (0, import_jsx_runtime4.jsxs)(LimitsModal.Root, { open: showLimitModal === "stage", onOpenChange: () => setShowLimitModal(null), children: [ (0, import_jsx_runtime4.jsx)(LimitsModal.Title, { children: formatMessage({ id: "review-workflows.edit.page.stages.limit.title", defaultMessage: "You have reached the limit of stages for this workflow in your plan" }) }), (0, import_jsx_runtime4.jsx)(LimitsModal.Body, { children: formatMessage({ id: "review-workflows.edit.page.stages.limit.body", defaultMessage: "Try deleting some stages or contact Sales to enable more stages." }) }) ] }) ] }); }; var addTmpKeysToStages = (data) => { const keys = generateNKeysBetween(void 0, void 0, data.length); return data.map((datum, index) => ({ ...datum, __temp_key__: keys[index] })); }; var ProtectedEditPage = () => { const permissions = useTypedSelector((state) => { var _a; const { create: create5 = [], update = [], read = [] } = ((_a = state.admin_app.permissions.settings) == null ? void 0 : _a["review-workflows"]) ?? {}; return [ ...create5, ...update, ...read ]; }); return (0, import_jsx_runtime4.jsx)(Page.Protect, { permissions, children: (0, import_jsx_runtime4.jsx)(EditPage, {}) }); }; export { ProtectedEditPage }; //# sourceMappingURL=id-JP5DTOKM.js.map