@strapi/review-workflows 0.0.0-next.39c0188c3aa01bec7b64b948211571d5159e811d → 0.0.0-next.3a1d87a9c3b1d4d89f741c6ecd7f501230fd8d76

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