@strapi/review-workflows 0.0.0-experimental.74c69aeafc770d59d5b3d5d37cd249934ef395ba → 0.0.0-experimental.76999222c105ee5da1bc2540e3b5e5f57747300c

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