@strapi/review-workflows 5.9.0 → 5.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/admin/chunks/Layout-27uslS7w.mjs +265 -0
  2. package/dist/admin/chunks/Layout-27uslS7w.mjs.map +1 -0
  3. package/dist/admin/chunks/Layout-B4l91S3p.js +290 -0
  4. package/dist/admin/chunks/Layout-B4l91S3p.js.map +1 -0
  5. package/dist/admin/chunks/en-BixG7IBu.mjs +14 -0
  6. package/dist/admin/chunks/en-BixG7IBu.mjs.map +1 -0
  7. package/dist/admin/chunks/en-C6SESe-Y.js +16 -0
  8. package/dist/admin/chunks/en-C6SESe-Y.js.map +1 -0
  9. package/dist/admin/chunks/id-DnRGfGvc.js +1442 -0
  10. package/dist/admin/chunks/id-DnRGfGvc.js.map +1 -0
  11. package/dist/admin/chunks/id-LAMc9ydb.mjs +1420 -0
  12. package/dist/admin/chunks/id-LAMc9ydb.mjs.map +1 -0
  13. package/dist/admin/chunks/index-BiGArvbK.mjs +271 -0
  14. package/dist/admin/chunks/index-BiGArvbK.mjs.map +1 -0
  15. package/dist/admin/chunks/index-C5IeISWp.js +960 -0
  16. package/dist/admin/chunks/index-C5IeISWp.js.map +1 -0
  17. package/dist/admin/chunks/index-CSYOmjZt.mjs +926 -0
  18. package/dist/admin/chunks/index-CSYOmjZt.mjs.map +1 -0
  19. package/dist/admin/chunks/index-DZpcSUvc.js +293 -0
  20. package/dist/admin/chunks/index-DZpcSUvc.js.map +1 -0
  21. package/dist/admin/chunks/purchase-review-workflows-CEP8kvxZ.mjs +53 -0
  22. package/dist/admin/chunks/purchase-review-workflows-CEP8kvxZ.mjs.map +1 -0
  23. package/dist/admin/chunks/purchase-review-workflows-Drlxm8yP.js +55 -0
  24. package/dist/admin/chunks/purchase-review-workflows-Drlxm8yP.js.map +1 -0
  25. package/dist/admin/chunks/router-CrN8UbpP.js +30 -0
  26. package/dist/admin/chunks/router-CrN8UbpP.js.map +1 -0
  27. package/dist/admin/chunks/router-Z3AR7XZ7.mjs +28 -0
  28. package/dist/admin/chunks/router-Z3AR7XZ7.mjs.map +1 -0
  29. package/dist/admin/index.js +17 -2
  30. package/dist/admin/index.js.map +1 -1
  31. package/dist/admin/index.mjs +12 -4
  32. package/dist/admin/index.mjs.map +1 -1
  33. package/dist/server/index.js +2109 -7839
  34. package/dist/server/index.js.map +1 -1
  35. package/dist/server/index.mjs +2114 -7847
  36. package/dist/server/index.mjs.map +1 -1
  37. package/dist/server/src/services/document-service-middleware.d.ts +1 -1
  38. package/dist/server/src/services/document-service-middleware.d.ts.map +1 -1
  39. package/dist/shared/contracts/review-workflows.d.ts +0 -1
  40. package/package.json +14 -10
  41. package/dist/_chunks/Layout-C3IORH2n.js +0 -250
  42. package/dist/_chunks/Layout-C3IORH2n.js.map +0 -1
  43. package/dist/_chunks/Layout-DNKR5bym.mjs +0 -233
  44. package/dist/_chunks/Layout-DNKR5bym.mjs.map +0 -1
  45. package/dist/_chunks/en-CYgjfSep.js +0 -15
  46. package/dist/_chunks/en-CYgjfSep.js.map +0 -1
  47. package/dist/_chunks/en-D9dxziEb.mjs +0 -15
  48. package/dist/_chunks/en-D9dxziEb.mjs.map +0 -1
  49. package/dist/_chunks/id-C9Ku9Br9.mjs +0 -1274
  50. package/dist/_chunks/id-C9Ku9Br9.mjs.map +0 -1
  51. package/dist/_chunks/id-oOE1bYls.js +0 -1293
  52. package/dist/_chunks/id-oOE1bYls.js.map +0 -1
  53. package/dist/_chunks/index-ByXbOW-R.mjs +0 -815
  54. package/dist/_chunks/index-ByXbOW-R.mjs.map +0 -1
  55. package/dist/_chunks/index-CmHHjN95.js +0 -231
  56. package/dist/_chunks/index-CmHHjN95.js.map +0 -1
  57. package/dist/_chunks/index-CyhaJuJG.mjs +0 -213
  58. package/dist/_chunks/index-CyhaJuJG.mjs.map +0 -1
  59. package/dist/_chunks/index-DMT27jNE.js +0 -832
  60. package/dist/_chunks/index-DMT27jNE.js.map +0 -1
  61. package/dist/_chunks/purchase-review-workflows-BxoDFxQ5.js +0 -52
  62. package/dist/_chunks/purchase-review-workflows-BxoDFxQ5.js.map +0 -1
  63. package/dist/_chunks/purchase-review-workflows-DyFV_H0I.mjs +0 -52
  64. package/dist/_chunks/purchase-review-workflows-DyFV_H0I.mjs.map +0 -1
  65. package/dist/_chunks/router-BPl2HZMq.mjs +0 -24
  66. package/dist/_chunks/router-BPl2HZMq.mjs.map +0 -1
  67. package/dist/_chunks/router-vDfGt9bq.js +0 -24
  68. package/dist/_chunks/router-vDfGt9bq.js.map +0 -1
  69. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/AssigneeFilter.d.ts +0 -0
  70. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/StageFilter.d.ts +0 -0
  71. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/TableColumns.d.ts +0 -0
  72. /package/dist/admin/src/routes/content-manager/{[model] → model}/configure/constants.d.ts +0 -0
  73. /package/dist/admin/src/routes/content-manager/{[model] → model}/constants.d.ts +0 -0
  74. /package/dist/admin/src/routes/content-manager/{[model]/[id] → model/id}/components/AssigneeSelect.d.ts +0 -0
  75. /package/dist/admin/src/routes/content-manager/{[model]/[id] → model/id}/components/Panel.d.ts +0 -0
  76. /package/dist/admin/src/routes/content-manager/{[model]/[id] → model/id}/components/StageSelect.d.ts +0 -0
  77. /package/dist/admin/src/routes/content-manager/{[model]/[id] → model/id}/components/constants.d.ts +0 -0
@@ -1,1274 +0,0 @@
1
- import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import * as React from "react";
3
- import { useTracking, useForm, useField, InputRenderer as InputRenderer$1, useNotification, ConfirmDialog, Page, useAPIErrorHandler, useRBAC, Form, BackButton } from "@strapi/admin/strapi-admin";
4
- import { useLicenseLimits } from "@strapi/admin/strapi-admin/ee";
5
- import { Box, Typography, Flex, Accordion, MenuItem, Menu, MultiSelectOption, useComposedRefs, VisuallyHidden, IconButton, Grid, Field, SingleSelect, SingleSelectOption, TextInput, MultiSelect, MultiSelectGroup, Dialog, useCollator, Button } from "@strapi/design-system";
6
- import { PlusCircle, More, Drag, EyeStriked, Duplicate, Check } from "@strapi/icons";
7
- import { generateNKeysBetween } from "fractional-indexing";
8
- import { useIntl } from "react-intl";
9
- import { useParams, useNavigate } from "react-router-dom";
10
- import * as yup from "yup";
11
- import { r as reviewWorkflowsApi, A as AVAILABLE_COLORS, g as getStageColorByHex, u as useGetContentTypesQuery, a as useTypedSelector, C as CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME, b as CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME, L as LimitsModal, i as isBaseQueryError } from "./index-ByXbOW-R.mjs";
12
- import { D as DRAG_DROP_TYPES, u as useReviewWorkflows, a as DragLayerRendered, H as Header, R as Root } from "./Layout-DNKR5bym.mjs";
13
- import { getEmptyImage } from "react-dnd-html5-backend";
14
- import { styled } from "styled-components";
15
- import { useDrop, useDrag } from "react-dnd";
16
- const adminApi = reviewWorkflowsApi.injectEndpoints({
17
- endpoints(builder) {
18
- return {
19
- getAdminRoles: builder.query({
20
- query: () => ({
21
- url: `/admin/roles`,
22
- method: "GET"
23
- }),
24
- transformResponse: (res) => {
25
- return res.data;
26
- }
27
- })
28
- };
29
- }
30
- });
31
- const { useGetAdminRolesQuery } = adminApi;
32
- const useKeyboardDragAndDrop = (active, index, { onCancel, onDropItem, onGrabItem, onMoveItem }) => {
33
- const [isSelected, setIsSelected] = React.useState(false);
34
- const handleMove = (movement) => {
35
- if (!isSelected) {
36
- return;
37
- }
38
- if (typeof index === "number" && onMoveItem) {
39
- if (movement === "UP") {
40
- onMoveItem(index - 1, index);
41
- } else if (movement === "DOWN") {
42
- onMoveItem(index + 1, index);
43
- }
44
- }
45
- };
46
- const handleDragClick = () => {
47
- if (isSelected) {
48
- if (onDropItem) {
49
- onDropItem(index);
50
- }
51
- setIsSelected(false);
52
- } else {
53
- if (onGrabItem) {
54
- onGrabItem(index);
55
- }
56
- setIsSelected(true);
57
- }
58
- };
59
- const handleCancel = () => {
60
- if (isSelected) {
61
- setIsSelected(false);
62
- if (onCancel) {
63
- onCancel(index);
64
- }
65
- }
66
- };
67
- const handleKeyDown = (e) => {
68
- if (!active) {
69
- return;
70
- }
71
- if (e.key === "Tab" && !isSelected) {
72
- return;
73
- }
74
- e.preventDefault();
75
- switch (e.key) {
76
- case " ":
77
- case "Enter":
78
- handleDragClick();
79
- break;
80
- case "Escape":
81
- handleCancel();
82
- break;
83
- case "ArrowDown":
84
- case "ArrowRight":
85
- handleMove("DOWN");
86
- break;
87
- case "ArrowUp":
88
- case "ArrowLeft":
89
- handleMove("UP");
90
- break;
91
- }
92
- };
93
- return handleKeyDown;
94
- };
95
- const DIRECTIONS = {
96
- UPWARD: "upward",
97
- DOWNWARD: "downward"
98
- };
99
- const DROP_SENSITIVITY = {
100
- REGULAR: "regular",
101
- IMMEDIATE: "immediate"
102
- };
103
- const useDragAndDrop = (active, {
104
- type = "STRAPI_DND",
105
- index,
106
- item,
107
- onStart,
108
- onEnd,
109
- onGrabItem,
110
- onDropItem,
111
- onCancel,
112
- onMoveItem,
113
- dropSensitivity = DROP_SENSITIVITY.REGULAR
114
- }) => {
115
- const objectRef = React.useRef(null);
116
- const [{ handlerId, isOver }, dropRef] = useDrop({
117
- accept: type,
118
- collect(monitor) {
119
- return {
120
- handlerId: monitor.getHandlerId(),
121
- isOver: monitor.isOver({ shallow: true })
122
- };
123
- },
124
- drop(item2) {
125
- const draggedIndex = item2.index;
126
- const newIndex = index;
127
- if (isOver && onDropItem) {
128
- onDropItem(draggedIndex, newIndex);
129
- }
130
- },
131
- hover(item2, monitor) {
132
- if (!objectRef.current || !onMoveItem) {
133
- return;
134
- }
135
- const dragIndex = item2.index;
136
- const newIndex = index;
137
- const hoverBoundingRect = objectRef.current?.getBoundingClientRect();
138
- const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
139
- const clientOffset = monitor.getClientOffset();
140
- if (!clientOffset) return;
141
- const hoverClientY = clientOffset && clientOffset.y - hoverBoundingRect.top;
142
- if (typeof dragIndex === "number" && typeof newIndex === "number") {
143
- if (dragIndex === newIndex) {
144
- return;
145
- }
146
- if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
147
- if (dragIndex < newIndex && hoverClientY < hoverMiddleY) {
148
- return;
149
- }
150
- if (dragIndex > newIndex && hoverClientY > hoverMiddleY) {
151
- return;
152
- }
153
- }
154
- onMoveItem(newIndex, dragIndex);
155
- item2.index = newIndex;
156
- } else {
157
- if (Array.isArray(dragIndex) && Array.isArray(newIndex)) {
158
- const minLength = Math.min(dragIndex.length, newIndex.length);
159
- let areEqual = true;
160
- let isLessThan = false;
161
- let isGreaterThan = false;
162
- for (let i = 0; i < minLength; i++) {
163
- if (dragIndex[i] < newIndex[i]) {
164
- isLessThan = true;
165
- areEqual = false;
166
- break;
167
- } else if (dragIndex[i] > newIndex[i]) {
168
- isGreaterThan = true;
169
- areEqual = false;
170
- break;
171
- }
172
- }
173
- if (areEqual && dragIndex.length === newIndex.length) {
174
- return;
175
- }
176
- if (dropSensitivity === DROP_SENSITIVITY.REGULAR) {
177
- if (isLessThan && !isGreaterThan && hoverClientY < hoverMiddleY) {
178
- return;
179
- }
180
- if (isGreaterThan && !isLessThan && hoverClientY > hoverMiddleY) {
181
- return;
182
- }
183
- }
184
- }
185
- onMoveItem(newIndex, dragIndex);
186
- item2.index = newIndex;
187
- }
188
- }
189
- });
190
- const getDragDirection = (monitor) => {
191
- if (monitor && monitor.isDragging() && !monitor.didDrop() && monitor.getInitialClientOffset() && monitor.getClientOffset()) {
192
- const deltaY = monitor.getInitialClientOffset().y - monitor.getClientOffset().y;
193
- if (deltaY > 0) return DIRECTIONS.UPWARD;
194
- if (deltaY < 0) return DIRECTIONS.DOWNWARD;
195
- return null;
196
- }
197
- return null;
198
- };
199
- const [{ isDragging, direction }, dragRef, dragPreviewRef] = useDrag({
200
- type,
201
- item() {
202
- if (onStart) {
203
- onStart();
204
- }
205
- const { width } = objectRef.current?.getBoundingClientRect() ?? {};
206
- return { index, width, ...item };
207
- },
208
- end() {
209
- if (onEnd) {
210
- onEnd();
211
- }
212
- },
213
- canDrag: active,
214
- /**
215
- * This is useful when the item is in a virtualized list.
216
- * However, if we don't have an ID then we want the libraries
217
- * defaults to take care of this.
218
- */
219
- isDragging: item?.id ? (monitor) => {
220
- return item.id === monitor.getItem().id;
221
- } : void 0,
222
- collect: (monitor) => ({
223
- isDragging: monitor.isDragging(),
224
- initialOffset: monitor.getInitialClientOffset(),
225
- currentOffset: monitor.getClientOffset(),
226
- direction: getDragDirection(monitor)
227
- })
228
- });
229
- const handleKeyDown = useKeyboardDragAndDrop(active, index, {
230
- onGrabItem,
231
- onDropItem,
232
- onCancel,
233
- onMoveItem
234
- });
235
- return [
236
- { handlerId, isDragging, handleKeyDown, isOverDropTarget: isOver, direction },
237
- objectRef,
238
- dropRef,
239
- dragRef,
240
- dragPreviewRef
241
- ];
242
- };
243
- const AddStage = ({ children, ...props }) => {
244
- return /* @__PURE__ */ jsx(
245
- StyledButton,
246
- {
247
- tag: "button",
248
- background: "neutral0",
249
- borderColor: "neutral150",
250
- paddingBottom: 3,
251
- paddingLeft: 4,
252
- paddingRight: 4,
253
- paddingTop: 3,
254
- shadow: "filterShadow",
255
- ...props,
256
- children: /* @__PURE__ */ jsx(Typography, { variant: "pi", fontWeight: "bold", children: /* @__PURE__ */ jsxs(Flex, { tag: "span", gap: 2, children: [
257
- /* @__PURE__ */ jsx(PlusCircle, { width: "2.4rem", height: "2.4rem", "aria-hidden": true }),
258
- children
259
- ] }) })
260
- }
261
- );
262
- };
263
- const StyledButton = styled(Box)`
264
- border-radius: 26px;
265
- color: ${({ theme }) => theme.colors.neutral500};
266
-
267
- &:hover {
268
- color: ${({ theme }) => theme.colors.primary600};
269
- }
270
-
271
- &:active {
272
- color: ${({ theme }) => theme.colors.primary600};
273
- }
274
- `;
275
- const Stages = ({ canDelete = true, canUpdate = true, isCreating }) => {
276
- const { formatMessage } = useIntl();
277
- const { trackUsage } = useTracking();
278
- const addFieldRow = useForm("Stages", (state) => state.addFieldRow);
279
- const { value: stages = [] } = useField("stages");
280
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 6, width: "100%", children: [
281
- /* @__PURE__ */ jsxs(Box, { position: "relative", width: "100%", children: [
282
- /* @__PURE__ */ jsx(
283
- Background,
284
- {
285
- background: "neutral200",
286
- height: "100%",
287
- left: "50%",
288
- position: "absolute",
289
- top: "0",
290
- width: 2
291
- }
292
- ),
293
- /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 6, position: "relative", tag: "ol", children: stages.map((stage, index) => {
294
- return /* @__PURE__ */ jsx(Box, { tag: "li", children: /* @__PURE__ */ jsx(
295
- Stage,
296
- {
297
- index,
298
- canDelete: stages.length > 1 && canDelete,
299
- canReorder: stages.length > 1,
300
- canUpdate,
301
- stagesCount: stages.length,
302
- defaultOpen: !stage.id,
303
- ...stage
304
- }
305
- ) }, stage.__temp_key__);
306
- }) })
307
- ] }),
308
- canUpdate && /* @__PURE__ */ jsx(
309
- AddStage,
310
- {
311
- type: "button",
312
- onClick: () => {
313
- addFieldRow("stages", { name: "" });
314
- trackUsage("willCreateStage");
315
- },
316
- children: formatMessage({
317
- id: "Settings.review-workflows.stage.add",
318
- defaultMessage: "Add new stage"
319
- })
320
- }
321
- )
322
- ] });
323
- };
324
- const Background = styled(Box)`
325
- transform: translateX(-50%);
326
- `;
327
- const Stage = ({
328
- index,
329
- canDelete = false,
330
- canReorder = false,
331
- canUpdate = false,
332
- stagesCount,
333
- name,
334
- permissions,
335
- color,
336
- defaultOpen
337
- }) => {
338
- const [liveText, setLiveText] = React.useState();
339
- const { formatMessage } = useIntl();
340
- const { trackUsage } = useTracking();
341
- const stageErrors = useForm("Stages", (state) => state.errors.stages);
342
- const error = stageErrors?.[index];
343
- const addFieldRow = useForm("Stage", (state) => state.addFieldRow);
344
- const moveFieldRow = useForm("Stage", (state) => state.moveFieldRow);
345
- const removeFieldRow = useForm("Stage", (state) => state.removeFieldRow);
346
- const getItemPos = (index2) => `${index2 + 1} of ${stagesCount}`;
347
- const handleGrabStage = (index2) => {
348
- setLiveText(
349
- formatMessage(
350
- {
351
- id: "dnd.grab-item",
352
- defaultMessage: `{item}, grabbed. Current position in list: {position}. Press up and down arrow to change position, Spacebar to drop, Escape to cancel.`
353
- },
354
- {
355
- item: name,
356
- position: getItemPos(index2)
357
- }
358
- )
359
- );
360
- };
361
- const handleDropStage = (index2) => {
362
- setLiveText(
363
- formatMessage(
364
- {
365
- id: "dnd.drop-item",
366
- defaultMessage: `{item}, dropped. Final position in list: {position}.`
367
- },
368
- {
369
- item: name,
370
- position: getItemPos(index2)
371
- }
372
- )
373
- );
374
- };
375
- const handleCancelDragStage = () => {
376
- setLiveText(
377
- formatMessage(
378
- {
379
- id: "dnd.cancel-item",
380
- defaultMessage: "{item}, dropped. Re-order cancelled."
381
- },
382
- {
383
- item: name
384
- }
385
- )
386
- );
387
- };
388
- const handleMoveStage = (newIndex, oldIndex) => {
389
- setLiveText(
390
- formatMessage(
391
- {
392
- id: "dnd.reorder",
393
- defaultMessage: "{item}, moved. New position in list: {position}."
394
- },
395
- {
396
- item: name,
397
- position: getItemPos(newIndex)
398
- }
399
- )
400
- );
401
- moveFieldRow("stages", oldIndex, newIndex);
402
- };
403
- const [{ handlerId, isDragging, handleKeyDown }, stageRef, dropRef, dragRef, dragPreviewRef] = useDragAndDrop(canReorder, {
404
- index,
405
- item: {
406
- index,
407
- name
408
- },
409
- onGrabItem: handleGrabStage,
410
- onDropItem: handleDropStage,
411
- onMoveItem: handleMoveStage,
412
- onCancel: handleCancelDragStage,
413
- type: DRAG_DROP_TYPES.STAGE
414
- });
415
- const composedRef = useComposedRefs(stageRef, dropRef);
416
- React.useEffect(() => {
417
- dragPreviewRef(getEmptyImage(), { captureDraggingState: false });
418
- }, [dragPreviewRef, index]);
419
- const handleCloneClick = () => {
420
- addFieldRow("stages", { name, color, permissions });
421
- };
422
- const id = React.useId();
423
- return /* @__PURE__ */ jsxs(Box, { ref: composedRef, shadow: "tableShadow", children: [
424
- liveText && /* @__PURE__ */ jsx(VisuallyHidden, { "aria-live": "assertive", children: liveText }),
425
- isDragging ? /* @__PURE__ */ jsx(
426
- Box,
427
- {
428
- background: "primary100",
429
- borderStyle: "dashed",
430
- borderColor: "primary600",
431
- borderWidth: "1px",
432
- display: "block",
433
- hasRadius: true,
434
- padding: 6
435
- }
436
- ) : /* @__PURE__ */ jsx(
437
- AccordionRoot,
438
- {
439
- onValueChange: (value) => {
440
- if (value) {
441
- trackUsage("willEditStage");
442
- }
443
- },
444
- defaultValue: defaultOpen ? id : void 0,
445
- $error: Object.values(error ?? {}).length > 0,
446
- children: /* @__PURE__ */ jsxs(Accordion.Item, { value: id, children: [
447
- /* @__PURE__ */ jsxs(Accordion.Header, { children: [
448
- /* @__PURE__ */ jsx(Accordion.Trigger, { children: name }),
449
- /* @__PURE__ */ jsx(Accordion.Actions, { children: canDelete || canUpdate ? /* @__PURE__ */ jsxs(Fragment, { children: [
450
- /* @__PURE__ */ jsxs(Menu.Root, { children: [
451
- /* @__PURE__ */ jsxs(ContextMenuTrigger, { size: "S", endIcon: null, paddingLeft: 2, paddingRight: 2, children: [
452
- /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
453
- /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: formatMessage({
454
- id: "[tbdb].components.DynamicZone.more-actions",
455
- defaultMessage: "More actions"
456
- }) })
457
- ] }),
458
- /* @__PURE__ */ jsx(Menu.Content, { popoverPlacement: "bottom-end", zIndex: 2, children: /* @__PURE__ */ jsxs(Menu.SubRoot, { children: [
459
- canUpdate && /* @__PURE__ */ jsx(MenuItem, { onClick: handleCloneClick, children: formatMessage({
460
- id: "Settings.review-workflows.stage.delete",
461
- defaultMessage: "Duplicate stage"
462
- }) }),
463
- canDelete && /* @__PURE__ */ jsx(DeleteMenuItem, { onClick: () => removeFieldRow("stages", index), children: formatMessage({
464
- id: "Settings.review-workflows.stage.delete",
465
- defaultMessage: "Delete"
466
- }) })
467
- ] }) })
468
- ] }),
469
- canUpdate && /* @__PURE__ */ jsx(
470
- IconButton,
471
- {
472
- background: "transparent",
473
- hasRadius: true,
474
- variant: "ghost",
475
- "data-handler-id": handlerId,
476
- ref: dragRef,
477
- label: formatMessage({
478
- id: "Settings.review-workflows.stage.drag",
479
- defaultMessage: "Drag"
480
- }),
481
- onClick: (e) => e.stopPropagation(),
482
- onKeyDown: handleKeyDown,
483
- children: /* @__PURE__ */ jsx(Drag, {})
484
- }
485
- )
486
- ] }) : null })
487
- ] }),
488
- /* @__PURE__ */ jsx(Accordion.Content, { children: /* @__PURE__ */ jsx(Grid.Root, { gap: 4, padding: 6, children: [
489
- {
490
- disabled: !canUpdate,
491
- label: formatMessage({
492
- id: "Settings.review-workflows.stage.name.label",
493
- defaultMessage: "Stage name"
494
- }),
495
- name: `stages.${index}.name`,
496
- required: true,
497
- size: 6,
498
- type: "string"
499
- },
500
- {
501
- disabled: !canUpdate,
502
- label: formatMessage({
503
- id: "content-manager.reviewWorkflows.stage.color",
504
- defaultMessage: "Color"
505
- }),
506
- name: `stages.${index}.color`,
507
- required: true,
508
- size: 6,
509
- type: "color"
510
- },
511
- {
512
- disabled: !canUpdate,
513
- label: formatMessage({
514
- id: "Settings.review-workflows.stage.permissions.label",
515
- defaultMessage: "Roles that can change this stage"
516
- }),
517
- name: `stages.${index}.permissions`,
518
- placeholder: formatMessage({
519
- id: "Settings.review-workflows.stage.permissions.placeholder",
520
- defaultMessage: "Select a role"
521
- }),
522
- required: true,
523
- size: 6,
524
- type: "permissions"
525
- }
526
- ].map(({ size, ...field }) => /* @__PURE__ */ jsx(Grid.Item, { col: size, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(InputRenderer, { ...field }) }, field.name)) }) })
527
- ] })
528
- }
529
- )
530
- ] });
531
- };
532
- const AccordionRoot = styled(Accordion.Root)`
533
- border: 1px solid
534
- ${({ theme, $error }) => $error ? theme.colors.danger600 : theme.colors.neutral200};
535
- `;
536
- const DeleteMenuItem = styled(MenuItem)`
537
- color: ${({ theme }) => theme.colors.danger600};
538
- `;
539
- const ContextMenuTrigger = styled(Menu.Trigger)`
540
- :hover,
541
- :focus {
542
- background-color: ${({ theme }) => theme.colors.neutral100};
543
- }
544
-
545
- > span {
546
- font-size: 0;
547
- }
548
- `;
549
- const InputRenderer = (props) => {
550
- switch (props.type) {
551
- case "color":
552
- return /* @__PURE__ */ jsx(ColorSelector, { ...props });
553
- case "permissions":
554
- return /* @__PURE__ */ jsx(PermissionsField, { ...props });
555
- default:
556
- return /* @__PURE__ */ jsx(InputRenderer$1, { ...props });
557
- }
558
- };
559
- const ColorSelector = ({ disabled, label, name, required }) => {
560
- const { formatMessage } = useIntl();
561
- const { value, error, onChange } = useField(name);
562
- const colorOptions = AVAILABLE_COLORS.map(({ hex, name: name2 }) => ({
563
- value: hex,
564
- label: formatMessage(
565
- {
566
- id: "Settings.review-workflows.stage.color.name",
567
- defaultMessage: "{name}"
568
- },
569
- { name: name2 }
570
- ),
571
- color: hex
572
- }));
573
- const { themeColorName } = getStageColorByHex(value) ?? {};
574
- return /* @__PURE__ */ jsxs(Field.Root, { error, name, required, children: [
575
- /* @__PURE__ */ jsx(Field.Label, { children: label }),
576
- /* @__PURE__ */ jsx(
577
- SingleSelect,
578
- {
579
- disabled,
580
- onChange: (v) => {
581
- onChange(name, v.toString());
582
- },
583
- value: value?.toUpperCase(),
584
- startIcon: /* @__PURE__ */ jsx(
585
- Flex,
586
- {
587
- tag: "span",
588
- height: 2,
589
- background: value,
590
- borderColor: themeColorName === "neutral0" ? "neutral150" : "transparent",
591
- hasRadius: true,
592
- shrink: 0,
593
- width: 2
594
- }
595
- ),
596
- children: colorOptions.map(({ value: value2, label: label2, color }) => {
597
- const { themeColorName: themeColorName2 } = getStageColorByHex(color) || {};
598
- return /* @__PURE__ */ jsx(
599
- SingleSelectOption,
600
- {
601
- value: value2,
602
- startIcon: /* @__PURE__ */ jsx(
603
- Flex,
604
- {
605
- tag: "span",
606
- height: 2,
607
- background: color,
608
- borderColor: themeColorName2 === "neutral0" ? "neutral150" : "transparent",
609
- hasRadius: true,
610
- shrink: 0,
611
- width: 2
612
- }
613
- ),
614
- children: label2
615
- },
616
- value2
617
- );
618
- })
619
- }
620
- ),
621
- /* @__PURE__ */ jsx(Field.Error, {})
622
- ] });
623
- };
624
- const PermissionsField = ({ disabled, name, placeholder, required }) => {
625
- const { formatMessage } = useIntl();
626
- const { toggleNotification } = useNotification();
627
- const [isApplyAllConfirmationOpen, setIsApplyAllConfirmationOpen] = React.useState(false);
628
- const { value = [], error, onChange } = useField(name);
629
- const allStages = useForm("PermissionsField", (state) => state.values.stages);
630
- const onFormValueChange = useForm("PermissionsField", (state) => state.onChange);
631
- const rolesErrorCount = React.useRef(0);
632
- const { data: roles = [], isLoading, error: getRolesError } = useGetAdminRolesQuery();
633
- const filteredRoles = roles?.filter((role) => role.code !== "strapi-super-admin") ?? [];
634
- React.useEffect(() => {
635
- if (!isLoading && getRolesError && "status" in getRolesError && getRolesError.status == 403 && rolesErrorCount.current === 0) {
636
- rolesErrorCount.current = 1;
637
- toggleNotification({
638
- blockTransition: true,
639
- type: "danger",
640
- message: formatMessage({
641
- id: "review-workflows.stage.permissions.noPermissions.description",
642
- defaultMessage: "You don’t have the permission to see roles. Contact your administrator."
643
- })
644
- });
645
- }
646
- }, [formatMessage, isLoading, roles, toggleNotification, getRolesError]);
647
- if (!isLoading && filteredRoles.length === 0) {
648
- return /* @__PURE__ */ jsxs(
649
- Field.Root,
650
- {
651
- name,
652
- hint: formatMessage({
653
- id: "Settings.review-workflows.stage.permissions.noPermissions.description",
654
- defaultMessage: "You don’t have the permission to see roles"
655
- }),
656
- required,
657
- children: [
658
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
659
- id: "Settings.review-workflows.stage.permissions.label",
660
- defaultMessage: "Roles that can change this stage"
661
- }) }),
662
- /* @__PURE__ */ jsx(
663
- TextInput,
664
- {
665
- disabled: true,
666
- placeholder: formatMessage({
667
- id: "components.NotAllowedInput.text",
668
- defaultMessage: "No permissions to see this field"
669
- }),
670
- startAction: /* @__PURE__ */ jsx(EyeStriked, { fill: "neutral600" }),
671
- type: "text",
672
- value: ""
673
- }
674
- ),
675
- /* @__PURE__ */ jsx(Field.Hint, {})
676
- ]
677
- }
678
- );
679
- }
680
- return /* @__PURE__ */ jsx(Fragment, { children: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-end", gap: 3, children: [
681
- /* @__PURE__ */ jsx(PermissionWrapper, { grow: 1, children: /* @__PURE__ */ jsxs(Field.Root, { error, name, required: true, children: [
682
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
683
- id: "Settings.review-workflows.stage.permissions.label",
684
- defaultMessage: "Roles that can change this stage"
685
- }) }),
686
- /* @__PURE__ */ jsx(
687
- MultiSelect,
688
- {
689
- disabled,
690
- onChange: (values) => {
691
- const permissions = values.map((value2) => ({
692
- role: parseInt(value2, 10),
693
- action: "admin::review-workflows.stage.transition"
694
- }));
695
- onChange(name, permissions);
696
- },
697
- placeholder,
698
- value: value.map((permission) => `${permission.role}`),
699
- withTags: true,
700
- children: /* @__PURE__ */ jsx(
701
- MultiSelectGroup,
702
- {
703
- label: formatMessage({
704
- id: "Settings.review-workflows.stage.permissions.allRoles.label",
705
- defaultMessage: "All roles"
706
- }),
707
- values: filteredRoles.map((r) => `${r.id}`),
708
- children: filteredRoles.map((role) => {
709
- return /* @__PURE__ */ jsx(NestedOption$1, { value: `${role.id}`, children: role.name }, role.id);
710
- })
711
- }
712
- )
713
- }
714
- ),
715
- /* @__PURE__ */ jsx(Field.Error, {})
716
- ] }) }),
717
- /* @__PURE__ */ jsxs(Dialog.Root, { open: isApplyAllConfirmationOpen, onOpenChange: setIsApplyAllConfirmationOpen, children: [
718
- /* @__PURE__ */ jsx(Dialog.Trigger, { children: /* @__PURE__ */ jsx(
719
- IconButton,
720
- {
721
- disabled,
722
- label: formatMessage({
723
- id: "Settings.review-workflows.stage.permissions.apply.label",
724
- defaultMessage: "Apply to all stages"
725
- }),
726
- size: "L",
727
- children: /* @__PURE__ */ jsx(Duplicate, {})
728
- }
729
- ) }),
730
- /* @__PURE__ */ jsx(
731
- ConfirmDialog,
732
- {
733
- onConfirm: () => {
734
- onFormValueChange(
735
- "stages",
736
- allStages.map((stage) => ({
737
- ...stage,
738
- permissions: value
739
- }))
740
- );
741
- setIsApplyAllConfirmationOpen(false);
742
- toggleNotification({
743
- type: "success",
744
- message: formatMessage({
745
- id: "Settings.review-workflows.page.edit.confirm.stages.permissions.copy.success",
746
- defaultMessage: "Applied roles to all other stages of the workflow"
747
- })
748
- });
749
- },
750
- variant: "default",
751
- children: formatMessage({
752
- id: "Settings.review-workflows.page.edit.confirm.stages.permissions.copy",
753
- defaultMessage: "Roles that can change that stage will be applied to all the other stages."
754
- })
755
- }
756
- )
757
- ] })
758
- ] }) });
759
- };
760
- const NestedOption$1 = styled(MultiSelectOption)`
761
- padding-left: ${({ theme }) => theme.spaces[7]};
762
- `;
763
- const PermissionWrapper = styled(Flex)`
764
- > * {
765
- flex-grow: 1;
766
- }
767
- `;
768
- const WorkflowAttributes = ({ canUpdate = true }) => {
769
- const { formatMessage } = useIntl();
770
- return /* @__PURE__ */ jsxs(Grid.Root, { background: "neutral0", hasRadius: true, gap: 4, padding: 6, shadow: "tableShadow", children: [
771
- /* @__PURE__ */ jsx(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(
772
- InputRenderer$1,
773
- {
774
- disabled: !canUpdate,
775
- label: formatMessage({
776
- id: "Settings.review-workflows.workflow.name.label",
777
- defaultMessage: "Workflow Name"
778
- }),
779
- name: "name",
780
- required: true,
781
- type: "string"
782
- }
783
- ) }),
784
- /* @__PURE__ */ jsx(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(ContentTypesSelector, { disabled: !canUpdate }) }),
785
- /* @__PURE__ */ jsx(Grid.Item, { col: 6, direction: "column", alignItems: "stretch", children: /* @__PURE__ */ jsx(StageSelector, { disabled: !canUpdate }) })
786
- ] });
787
- };
788
- const ContentTypesSelector = ({ disabled }) => {
789
- const { formatMessage, locale } = useIntl();
790
- const { data: contentTypes, isLoading } = useGetContentTypesQuery();
791
- const { workflows } = useReviewWorkflows();
792
- const currentWorkflow = useForm("ContentTypesSelector", (state) => state.values);
793
- const { error, value, onChange } = useField("contentTypes");
794
- const formatter = useCollator(locale, {
795
- sensitivity: "base"
796
- });
797
- const isDisabled = disabled || isLoading || !contentTypes || contentTypes.collectionType.length === 0 && contentTypes.singleType.length === 0;
798
- const collectionTypes = (contentTypes?.collectionType ?? []).toSorted((a, b) => formatter.compare(a.info.displayName, b.info.displayName)).map((contentType) => ({
799
- label: contentType.info.displayName,
800
- value: contentType.uid
801
- }));
802
- const singleTypes = (contentTypes?.singleType ?? []).map((contentType) => ({
803
- label: contentType.info.displayName,
804
- value: contentType.uid
805
- }));
806
- return /* @__PURE__ */ jsxs(Field.Root, { error, name: "contentTypes", children: [
807
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
808
- id: "Settings.review-workflows.workflow.contentTypes.label",
809
- defaultMessage: "Associated to"
810
- }) }),
811
- /* @__PURE__ */ jsx(
812
- MultiSelect,
813
- {
814
- customizeContent: (value2) => formatMessage(
815
- {
816
- id: "Settings.review-workflows.workflow.contentTypes.displayValue",
817
- defaultMessage: "{count} {count, plural, one {content type} other {content types}} selected"
818
- },
819
- { count: value2?.length }
820
- ),
821
- disabled: isDisabled,
822
- onChange: (values) => {
823
- onChange("contentTypes", values);
824
- },
825
- value,
826
- placeholder: formatMessage({
827
- id: "Settings.review-workflows.workflow.contentTypes.placeholder",
828
- defaultMessage: "Select"
829
- }),
830
- children: [
831
- ...collectionTypes.length > 0 ? [
832
- {
833
- label: formatMessage({
834
- id: "Settings.review-workflows.workflow.contentTypes.collectionTypes.label",
835
- defaultMessage: "Collection Types"
836
- }),
837
- children: collectionTypes
838
- }
839
- ] : [],
840
- ...singleTypes.length > 0 ? [
841
- {
842
- label: formatMessage({
843
- id: "Settings.review-workflows.workflow.contentTypes.singleTypes.label",
844
- defaultMessage: "Single Types"
845
- }),
846
- children: singleTypes
847
- }
848
- ] : []
849
- ].map((opt) => {
850
- return /* @__PURE__ */ jsx(
851
- MultiSelectGroup,
852
- {
853
- label: opt.label,
854
- values: opt.children.map((child) => child.value.toString()),
855
- children: opt.children.map((child) => {
856
- const { name: assignedWorkflowName } = workflows?.find(
857
- (workflow) => (currentWorkflow && workflow.id !== currentWorkflow.id || !currentWorkflow) && workflow.contentTypes.includes(child.value)
858
- ) ?? {};
859
- return /* @__PURE__ */ jsx(NestedOption, { value: child.value, children: /* @__PURE__ */ jsx(Typography, {
860
- // @ts-expect-error - formatMessage options doesn't expect to be a React component but that's what we need actually for the <i> and <em> components
861
- children: formatMessage(
862
- {
863
- id: "Settings.review-workflows.workflow.contentTypes.assigned.notice",
864
- defaultMessage: "{label} {name, select, undefined {} other {<i>(assigned to <em>{name}</em> workflow)</i>}}"
865
- },
866
- {
867
- label: child.label,
868
- name: assignedWorkflowName,
869
- em: (...children) => /* @__PURE__ */ jsx(Typography, { tag: "em", fontWeight: "bold", children }),
870
- i: (...children) => /* @__PURE__ */ jsx(ContentTypeTakeNotice, { children })
871
- }
872
- )
873
- }) }, child.value);
874
- })
875
- },
876
- opt.label
877
- );
878
- })
879
- }
880
- )
881
- ] });
882
- };
883
- const NestedOption = styled(MultiSelectOption)`
884
- padding-left: ${({ theme }) => theme.spaces[7]};
885
- `;
886
- const ContentTypeTakeNotice = styled(Typography)`
887
- font-style: italic;
888
- `;
889
- const StageSelector = ({ disabled }) => {
890
- const { value: stages = [] } = useField("stages");
891
- const { formatMessage } = useIntl();
892
- const { error, value, onChange } = useField("stageRequiredToPublish");
893
- const validStages = stages.filter((stage) => stage.name);
894
- return /* @__PURE__ */ jsxs(
895
- Field.Root,
896
- {
897
- error,
898
- name: "stageRequiredToPublish",
899
- hint: formatMessage({
900
- id: "settings.review-workflows.workflow.stageRequiredToPublish.hint",
901
- defaultMessage: "Prevents entries from being published if they are not at the required stage."
902
- }),
903
- children: [
904
- /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
905
- id: "settings.review-workflows.workflow.stageRequiredToPublish.label",
906
- defaultMessage: "Required stage for publishing"
907
- }) }),
908
- /* @__PURE__ */ jsxs(
909
- SingleSelect,
910
- {
911
- disabled,
912
- onChange: (value2) => {
913
- onChange("stageRequiredToPublish", value2);
914
- },
915
- value,
916
- children: [
917
- /* @__PURE__ */ jsx(SingleSelectOption, { value: "", children: formatMessage({
918
- id: "settings.review-workflows.workflow.stageRequiredToPublish.any",
919
- defaultMessage: "Any stage"
920
- }) }),
921
- validStages.map((stage, i) => /* @__PURE__ */ jsx(
922
- SingleSelectOption,
923
- {
924
- value: stage.id?.toString() || stage.__temp_key__,
925
- children: stage.name
926
- },
927
- `requiredToPublishStage-${stage.id || stage.__temp_key__}`
928
- ))
929
- ]
930
- }
931
- ),
932
- /* @__PURE__ */ jsx(Field.Hint, {})
933
- ]
934
- }
935
- );
936
- };
937
- const WORKFLOW_SCHEMA = yup.object({
938
- contentTypes: yup.array().of(yup.string()),
939
- name: yup.string().max(255, {
940
- id: "review-workflows.validation.name.max-length",
941
- defaultMessage: "Name can not be longer than 255 characters"
942
- }).required().nullable(),
943
- stages: yup.array().of(
944
- yup.object().shape({
945
- name: yup.string().nullable().required({
946
- id: "review-workflows.validation.stage.name",
947
- defaultMessage: "Name is required"
948
- }).max(255, {
949
- id: "review-workflows.validation.stage.max-length",
950
- defaultMessage: "Name can not be longer than 255 characters"
951
- }).test(
952
- "unique-name",
953
- {
954
- id: "review-workflows.validation.stage.duplicate",
955
- defaultMessage: "Stage name must be unique"
956
- },
957
- (stageName, context) => {
958
- const { stages } = context.from[1].value;
959
- return stages.filter((stage) => stage.name === stageName).length === 1;
960
- }
961
- ),
962
- color: yup.string().nullable().required({
963
- id: "review-workflows.validation.stage.color",
964
- defaultMessage: "Color is required"
965
- }).matches(/^#(?:[0-9a-fA-F]{3}){1,2}$/i),
966
- permissions: yup.array(
967
- yup.object({
968
- role: yup.number().strict().typeError({
969
- id: "review-workflows.validation.stage.permissions.role.number",
970
- defaultMessage: "Role must be of type number"
971
- }).required(),
972
- action: yup.string().required({
973
- id: "review-workflows.validation.stage.permissions.action.required",
974
- defaultMessage: "Action is a required argument"
975
- })
976
- })
977
- ).strict()
978
- })
979
- ).min(1),
980
- stageRequiredToPublish: yup.string().nullable()
981
- });
982
- const EditPage = () => {
983
- const { id = "" } = useParams();
984
- const isCreatingWorkflow = id === "create";
985
- const { formatMessage } = useIntl();
986
- const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
987
- const navigate = useNavigate();
988
- const { toggleNotification } = useNotification();
989
- const {
990
- isLoading: isLoadingWorkflow,
991
- meta,
992
- workflows,
993
- error,
994
- update,
995
- create
996
- } = useReviewWorkflows();
997
- const permissions = useTypedSelector(
998
- (state) => state.admin_app.permissions["settings"]?.["review-workflows"]
999
- );
1000
- const {
1001
- allowedActions: { canDelete, canUpdate, canCreate }
1002
- } = useRBAC(permissions);
1003
- const [savePrompts, setSavePrompts] = React.useState({});
1004
- const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();
1005
- const [showLimitModal, setShowLimitModal] = React.useState(null);
1006
- const currentWorkflow = workflows?.find((workflow) => workflow.id === parseInt(id, 10));
1007
- const contentTypesFromOtherWorkflows = workflows?.filter((workflow) => workflow.id !== parseInt(id, 10)).flatMap((workflow) => workflow.contentTypes);
1008
- const limits = getFeature("review-workflows");
1009
- const numberOfWorkflows = limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME];
1010
- const stagesPerWorkflow = limits?.[CHARGEBEE_STAGES_PER_WORKFLOW_ENTITLEMENT_NAME];
1011
- const submitForm = async (data, helpers) => {
1012
- try {
1013
- const { stageRequiredToPublish, ...rest } = data;
1014
- const stageRequiredToPublishName = stageRequiredToPublish === "" ? null : rest.stages.find(
1015
- (stage) => stage.id === Number(stageRequiredToPublish) || stage.__temp_key__ === stageRequiredToPublish
1016
- )?.name;
1017
- if (!isCreatingWorkflow) {
1018
- const res = await update(id, {
1019
- ...rest,
1020
- // compare permissions of stages and only submit them if at least one has
1021
- // changed; this enables partial updates e.g. for users who don't have
1022
- // permissions to see roles
1023
- stages: rest.stages.map((stage) => {
1024
- let hasUpdatedPermissions = true;
1025
- const serverStage = currentWorkflow?.stages?.find(
1026
- (serverStage2) => serverStage2.id === stage?.id
1027
- );
1028
- if (serverStage) {
1029
- hasUpdatedPermissions = serverStage.permissions?.length !== stage.permissions?.length || !serverStage.permissions?.every(
1030
- (serverPermission) => !!stage.permissions?.find(
1031
- (permission) => permission.role === serverPermission.role
1032
- )
1033
- );
1034
- }
1035
- return {
1036
- ...stage,
1037
- permissions: hasUpdatedPermissions ? stage.permissions : void 0
1038
- };
1039
- }),
1040
- stageRequiredToPublishName
1041
- });
1042
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1043
- helpers.setErrors(formatValidationErrors(res.error));
1044
- }
1045
- } else {
1046
- const res = await create({
1047
- ...rest,
1048
- stageRequiredToPublishName
1049
- });
1050
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1051
- helpers.setErrors(formatValidationErrors(res.error));
1052
- } else if ("data" in res) {
1053
- navigate(`../${res.data.id}`, { replace: true });
1054
- }
1055
- }
1056
- } catch (error2) {
1057
- toggleNotification({
1058
- type: "danger",
1059
- message: formatMessage({
1060
- id: "notification.error",
1061
- defaultMessage: "An error occurred"
1062
- })
1063
- });
1064
- }
1065
- setSavePrompts({});
1066
- };
1067
- const handleConfirmDeleteDialog = (data, helpers) => async () => {
1068
- await submitForm(data, helpers);
1069
- };
1070
- const handleConfirmClose = () => {
1071
- setSavePrompts({});
1072
- };
1073
- const handleSubmit = async (data, helpers) => {
1074
- const isContentTypeReassignment = data.contentTypes.some(
1075
- (contentType) => contentTypesFromOtherWorkflows?.includes(contentType)
1076
- );
1077
- const hasDeletedServerStages = !isCreatingWorkflow && !currentWorkflow?.stages.every(
1078
- (stage) => data.stages.some((newStage) => newStage.id === stage.id)
1079
- );
1080
- if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {
1081
- setShowLimitModal("workflow");
1082
- } else if (data.stages && stagesPerWorkflow && data.stages.length > parseInt(stagesPerWorkflow, 10)) {
1083
- setShowLimitModal("stage");
1084
- } else if (hasDeletedServerStages || isContentTypeReassignment) {
1085
- if (hasDeletedServerStages) {
1086
- setSavePrompts((prev) => ({ ...prev, hasDeletedServerStages: true }));
1087
- }
1088
- if (isContentTypeReassignment) {
1089
- setSavePrompts((prev) => ({ ...prev, hasReassignedContentTypes: true }));
1090
- }
1091
- } else {
1092
- await submitForm(data, helpers);
1093
- }
1094
- };
1095
- React.useEffect(() => {
1096
- if (!isLoadingWorkflow && !isLicenseLoading) {
1097
- if (meta && numberOfWorkflows && meta?.workflowCount > parseInt(numberOfWorkflows, 10)) {
1098
- setShowLimitModal("workflow");
1099
- } else if (currentWorkflow && currentWorkflow.stages && stagesPerWorkflow && currentWorkflow.stages.length > parseInt(stagesPerWorkflow, 10)) {
1100
- setShowLimitModal("stage");
1101
- }
1102
- }
1103
- }, [
1104
- currentWorkflow,
1105
- isLicenseLoading,
1106
- isLoadingWorkflow,
1107
- limits,
1108
- meta,
1109
- numberOfWorkflows,
1110
- stagesPerWorkflow
1111
- ]);
1112
- const initialValues = React.useMemo(() => {
1113
- if (isCreatingWorkflow || !currentWorkflow) {
1114
- return {
1115
- name: "",
1116
- stages: [],
1117
- contentTypes: [],
1118
- stageRequiredToPublish: ""
1119
- };
1120
- } else {
1121
- return {
1122
- name: currentWorkflow.name,
1123
- stages: addTmpKeysToStages(currentWorkflow.stages),
1124
- contentTypes: currentWorkflow.contentTypes,
1125
- stageRequiredToPublish: currentWorkflow.stageRequiredToPublish?.id.toString() ?? ""
1126
- };
1127
- }
1128
- }, [currentWorkflow, isCreatingWorkflow]);
1129
- if (isLoadingWorkflow) {
1130
- return /* @__PURE__ */ jsx(Page.Loading, {});
1131
- }
1132
- if (error) {
1133
- return /* @__PURE__ */ jsx(Page.Error, {});
1134
- }
1135
- return /* @__PURE__ */ jsxs(Fragment, { children: [
1136
- /* @__PURE__ */ jsx(DragLayerRendered, {}),
1137
- /* @__PURE__ */ jsx(
1138
- Form,
1139
- {
1140
- method: isCreatingWorkflow ? "POST" : "PUT",
1141
- initialValues,
1142
- validationSchema: WORKFLOW_SCHEMA,
1143
- onSubmit: handleSubmit,
1144
- children: ({ modified, isSubmitting, values, setErrors }) => /* @__PURE__ */ jsxs(Fragment, { children: [
1145
- /* @__PURE__ */ jsx(
1146
- Header,
1147
- {
1148
- navigationAction: /* @__PURE__ */ jsx(BackButton, { fallback: ".." }),
1149
- primaryAction: canUpdate || canCreate ? /* @__PURE__ */ jsx(
1150
- Button,
1151
- {
1152
- startIcon: /* @__PURE__ */ jsx(Check, {}),
1153
- type: "submit",
1154
- disabled: !modified || isSubmitting || values.stages.length === 0,
1155
- loading: !Boolean(Object.keys(savePrompts).length > 0) && isSubmitting,
1156
- children: formatMessage({
1157
- id: "global.save",
1158
- defaultMessage: "Save"
1159
- })
1160
- }
1161
- ) : null,
1162
- subtitle: formatMessage(
1163
- {
1164
- id: "review-workflows.page.subtitle",
1165
- defaultMessage: "{count, plural, one {# stage} other {# stages}}"
1166
- },
1167
- { count: currentWorkflow?.stages?.length ?? 0 }
1168
- ),
1169
- title: currentWorkflow?.name || formatMessage({
1170
- id: "Settings.review-workflows.create.page.title",
1171
- defaultMessage: "Create Review Workflow"
1172
- })
1173
- }
1174
- ),
1175
- /* @__PURE__ */ jsx(Root, { children: /* @__PURE__ */ jsxs(Flex, { alignItems: "stretch", direction: "column", gap: 7, children: [
1176
- /* @__PURE__ */ jsx(WorkflowAttributes, { canUpdate: canUpdate || canCreate }),
1177
- /* @__PURE__ */ jsx(
1178
- Stages,
1179
- {
1180
- canDelete,
1181
- canUpdate: canUpdate || canCreate,
1182
- isCreating: isCreatingWorkflow
1183
- }
1184
- )
1185
- ] }) }),
1186
- /* @__PURE__ */ jsx(
1187
- Dialog.Root,
1188
- {
1189
- open: Object.keys(savePrompts).length > 0,
1190
- onOpenChange: handleConfirmClose,
1191
- children: /* @__PURE__ */ jsx(ConfirmDialog, { onConfirm: handleConfirmDeleteDialog(values, { setErrors }), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 5, children: [
1192
- savePrompts.hasDeletedServerStages && /* @__PURE__ */ jsx(Typography, { textAlign: "center", variant: "omega", children: formatMessage({
1193
- id: "review-workflows.page.delete.confirm.stages.body",
1194
- defaultMessage: "All entries assigned to deleted stages will be moved to the previous stage."
1195
- }) }),
1196
- savePrompts.hasReassignedContentTypes && /* @__PURE__ */ jsx(Typography, { textAlign: "center", variant: "omega", children: formatMessage(
1197
- {
1198
- id: "review-workflows.page.delete.confirm.contentType.body",
1199
- 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."
1200
- },
1201
- {
1202
- count: contentTypesFromOtherWorkflows?.filter(
1203
- (contentType) => values.contentTypes.includes(contentType)
1204
- ).length ?? 0
1205
- }
1206
- ) }),
1207
- /* @__PURE__ */ jsx(Typography, { textAlign: "center", variant: "omega", children: formatMessage({
1208
- id: "review-workflows.page.delete.confirm.confirm",
1209
- defaultMessage: "Are you sure you want to save?"
1210
- }) })
1211
- ] }) })
1212
- }
1213
- )
1214
- ] })
1215
- }
1216
- ),
1217
- /* @__PURE__ */ jsxs(
1218
- LimitsModal.Root,
1219
- {
1220
- open: showLimitModal === "workflow",
1221
- onOpenChange: () => setShowLimitModal(null),
1222
- children: [
1223
- /* @__PURE__ */ jsx(LimitsModal.Title, { children: formatMessage({
1224
- id: "review-workflows.edit.page.workflows.limit.title",
1225
- defaultMessage: "You’ve reached the limit of workflows in your plan"
1226
- }) }),
1227
- /* @__PURE__ */ jsx(LimitsModal.Body, { children: formatMessage({
1228
- id: "review-workflows.edit.page.workflows.limit.body",
1229
- defaultMessage: "Delete a workflow or contact Sales to enable more workflows."
1230
- }) })
1231
- ]
1232
- }
1233
- ),
1234
- /* @__PURE__ */ jsxs(
1235
- LimitsModal.Root,
1236
- {
1237
- open: showLimitModal === "stage",
1238
- onOpenChange: () => setShowLimitModal(null),
1239
- children: [
1240
- /* @__PURE__ */ jsx(LimitsModal.Title, { children: formatMessage({
1241
- id: "review-workflows.edit.page.stages.limit.title",
1242
- defaultMessage: "You have reached the limit of stages for this workflow in your plan"
1243
- }) }),
1244
- /* @__PURE__ */ jsx(LimitsModal.Body, { children: formatMessage({
1245
- id: "review-workflows.edit.page.stages.limit.body",
1246
- defaultMessage: "Try deleting some stages or contact Sales to enable more stages."
1247
- }) })
1248
- ]
1249
- }
1250
- )
1251
- ] });
1252
- };
1253
- const addTmpKeysToStages = (data) => {
1254
- const keys = generateNKeysBetween(void 0, void 0, data.length);
1255
- return data.map((datum, index) => ({
1256
- ...datum,
1257
- __temp_key__: keys[index]
1258
- }));
1259
- };
1260
- const ProtectedEditPage = () => {
1261
- const permissions = useTypedSelector((state) => {
1262
- const {
1263
- create = [],
1264
- update = [],
1265
- read = []
1266
- } = state.admin_app.permissions.settings?.["review-workflows"] ?? {};
1267
- return [...create, ...update, ...read];
1268
- });
1269
- return /* @__PURE__ */ jsx(Page.Protect, { permissions, children: /* @__PURE__ */ jsx(EditPage, {}) });
1270
- };
1271
- export {
1272
- ProtectedEditPage
1273
- };
1274
- //# sourceMappingURL=id-C9Ku9Br9.mjs.map