@strapi/review-workflows 0.0.0-experimental.74c69aeafc770d59d5b3d5d37cd249934ef395ba → 0.0.0-experimental.779667bd163026468f566293decf331a0246fff9

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