@strapi/review-workflows 5.0.0-beta.3 → 5.0.0-beta.5

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