@strapi/review-workflows 0.0.0-experimental.d23c1d5b0e45dd06ef09977f526c85468be05403 → 0.0.0-experimental.d2a56e52af31fcf0f0c582a5a2e58e310966e96b

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 (128) hide show
  1. package/LICENSE +12 -17
  2. package/dist/admin/chunks/Layout-C4ri_ldC.js +290 -0
  3. package/dist/admin/chunks/Layout-C4ri_ldC.js.map +1 -0
  4. package/dist/admin/chunks/Layout-CF497D6H.mjs +265 -0
  5. package/dist/admin/chunks/Layout-CF497D6H.mjs.map +1 -0
  6. package/dist/admin/chunks/en-BNGiWajd.js +20 -0
  7. package/dist/admin/chunks/en-BNGiWajd.js.map +1 -0
  8. package/dist/admin/chunks/en-BrZXFtVv.mjs +18 -0
  9. package/dist/admin/chunks/en-BrZXFtVv.mjs.map +1 -0
  10. package/dist/admin/chunks/id-DVOtqJqn.js +1442 -0
  11. package/dist/admin/chunks/id-DVOtqJqn.js.map +1 -0
  12. package/dist/admin/chunks/id-QD0V9dME.mjs +1420 -0
  13. package/dist/admin/chunks/id-QD0V9dME.mjs.map +1 -0
  14. package/dist/admin/chunks/index-CCx4kT-t.js +293 -0
  15. package/dist/admin/chunks/index-CCx4kT-t.js.map +1 -0
  16. package/dist/admin/chunks/index-CzdEqFOm.js +1115 -0
  17. package/dist/admin/chunks/index-CzdEqFOm.js.map +1 -0
  18. package/dist/admin/chunks/index-DcEF47R4.mjs +1081 -0
  19. package/dist/admin/chunks/index-DcEF47R4.mjs.map +1 -0
  20. package/dist/admin/chunks/index-iChY7MsG.mjs +271 -0
  21. package/dist/admin/chunks/index-iChY7MsG.mjs.map +1 -0
  22. package/dist/admin/chunks/purchase-review-workflows-4n0KXAeo.mjs +200 -0
  23. package/dist/admin/chunks/purchase-review-workflows-4n0KXAeo.mjs.map +1 -0
  24. package/dist/admin/chunks/purchase-review-workflows-BDLncDcz.js +202 -0
  25. package/dist/admin/chunks/purchase-review-workflows-BDLncDcz.js.map +1 -0
  26. package/dist/admin/chunks/router-ChVwf8TN.js +30 -0
  27. package/dist/admin/chunks/router-ChVwf8TN.js.map +1 -0
  28. package/dist/admin/chunks/router-D-YCUzYy.mjs +28 -0
  29. package/dist/admin/chunks/router-D-YCUzYy.mjs.map +1 -0
  30. package/dist/admin/chunks/uk-CbRUr1I7.js +16 -0
  31. package/dist/admin/chunks/uk-CbRUr1I7.js.map +1 -0
  32. package/dist/admin/chunks/uk-DLlzEBUF.mjs +14 -0
  33. package/dist/admin/chunks/uk-DLlzEBUF.mjs.map +1 -0
  34. package/dist/admin/index.js +17 -2
  35. package/dist/admin/index.js.map +1 -1
  36. package/dist/admin/index.mjs +12 -4
  37. package/dist/admin/index.mjs.map +1 -1
  38. package/dist/admin/src/components/LimitsModal.d.ts +2 -4
  39. package/dist/admin/src/routes/content-manager/model/id/components/AssigneeSelect.d.ts +4 -0
  40. package/dist/admin/src/routes/content-manager/model/id/components/Header.d.ts +5 -0
  41. package/dist/admin/src/routes/content-manager/model/id/components/Panel.d.ts +3 -0
  42. package/dist/admin/src/routes/content-manager/model/id/components/StageSelect.d.ts +3 -0
  43. package/dist/admin/src/routes/settings/hooks/useDragAndDrop.d.ts +4 -4
  44. package/dist/admin/src/routes/settings/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  45. package/dist/admin/src/routes/settings/hooks/useReviewWorkflows.d.ts +3 -3
  46. package/dist/admin/src/services/admin.d.ts +2 -2
  47. package/dist/admin/src/services/api.d.ts +2 -3
  48. package/dist/admin/src/services/content-manager.d.ts +7 -7
  49. package/dist/admin/src/services/settings.d.ts +1740 -10
  50. package/dist/admin/src/utils/api.d.ts +4 -19
  51. package/dist/admin/src/utils/cm-hooks.d.ts +1 -1
  52. package/dist/server/index.js +2110 -8013
  53. package/dist/server/index.js.map +1 -1
  54. package/dist/server/index.mjs +2116 -8022
  55. package/dist/server/index.mjs.map +1 -1
  56. package/dist/server/src/bootstrap.d.ts.map +1 -1
  57. package/dist/server/src/constants/workflows.d.ts +1 -0
  58. package/dist/server/src/constants/workflows.d.ts.map +1 -1
  59. package/dist/server/src/content-types/index.d.ts +6 -0
  60. package/dist/server/src/content-types/index.d.ts.map +1 -1
  61. package/dist/server/src/content-types/workflow/index.d.ts +6 -0
  62. package/dist/server/src/content-types/workflow/index.d.ts.map +1 -1
  63. package/dist/server/src/controllers/assignees.d.ts.map +1 -1
  64. package/dist/server/src/controllers/index.d.ts +0 -1
  65. package/dist/server/src/controllers/index.d.ts.map +1 -1
  66. package/dist/server/src/controllers/stages.d.ts.map +1 -1
  67. package/dist/server/src/controllers/workflows.d.ts +0 -7
  68. package/dist/server/src/controllers/workflows.d.ts.map +1 -1
  69. package/dist/server/src/index.d.ts +28 -7
  70. package/dist/server/src/index.d.ts.map +1 -1
  71. package/dist/server/src/register.d.ts.map +1 -1
  72. package/dist/server/src/routes/review-workflows.d.ts.map +1 -1
  73. package/dist/server/src/services/assignees.d.ts +8 -4
  74. package/dist/server/src/services/assignees.d.ts.map +1 -1
  75. package/dist/server/src/services/document-service-middleware.d.ts +2 -1
  76. package/dist/server/src/services/document-service-middleware.d.ts.map +1 -1
  77. package/dist/server/src/services/index.d.ts +16 -6
  78. package/dist/server/src/services/index.d.ts.map +1 -1
  79. package/dist/server/src/services/metrics/index.d.ts +4 -4
  80. package/dist/server/src/services/metrics/index.d.ts.map +1 -1
  81. package/dist/server/src/services/metrics/weekly-metrics.d.ts.map +1 -1
  82. package/dist/server/src/services/stages.d.ts +7 -7
  83. package/dist/server/src/services/stages.d.ts.map +1 -1
  84. package/dist/server/src/services/workflows.d.ts.map +1 -1
  85. package/dist/server/src/validation/review-workflows.d.ts +4 -0
  86. package/dist/server/src/validation/review-workflows.d.ts.map +1 -1
  87. package/dist/shared/contracts/review-workflows.d.ts +9 -18
  88. package/dist/shared/contracts/review-workflows.d.ts.map +1 -1
  89. package/package.json +22 -22
  90. package/dist/_chunks/Layout-dGg4FA1R.js +0 -260
  91. package/dist/_chunks/Layout-dGg4FA1R.js.map +0 -1
  92. package/dist/_chunks/Layout-facLKucY.mjs +0 -240
  93. package/dist/_chunks/Layout-facLKucY.mjs.map +0 -1
  94. package/dist/_chunks/_id-B6DgrtpA.js +0 -1333
  95. package/dist/_chunks/_id-B6DgrtpA.js.map +0 -1
  96. package/dist/_chunks/_id-D4CXKOqG.mjs +0 -1311
  97. package/dist/_chunks/_id-D4CXKOqG.mjs.map +0 -1
  98. package/dist/_chunks/en-D9ZrQAV6.mjs +0 -12
  99. package/dist/_chunks/en-D9ZrQAV6.mjs.map +0 -1
  100. package/dist/_chunks/en-xcewH2pC.js +0 -12
  101. package/dist/_chunks/en-xcewH2pC.js.map +0 -1
  102. package/dist/_chunks/index-BuKZWpJw.js +0 -268
  103. package/dist/_chunks/index-BuKZWpJw.js.map +0 -1
  104. package/dist/_chunks/index-D7Y0ofdg.mjs +0 -851
  105. package/dist/_chunks/index-D7Y0ofdg.mjs.map +0 -1
  106. package/dist/_chunks/index-DX8AGcIP.js +0 -871
  107. package/dist/_chunks/index-DX8AGcIP.js.map +0 -1
  108. package/dist/_chunks/index-QbWLXdZR.mjs +0 -247
  109. package/dist/_chunks/index-QbWLXdZR.mjs.map +0 -1
  110. package/dist/_chunks/purchase-review-workflows-B-V0sA2I.mjs +0 -51
  111. package/dist/_chunks/purchase-review-workflows-B-V0sA2I.mjs.map +0 -1
  112. package/dist/_chunks/purchase-review-workflows-Ds61D_tk.js +0 -51
  113. package/dist/_chunks/purchase-review-workflows-Ds61D_tk.js.map +0 -1
  114. package/dist/_chunks/router-CL62NScV.js +0 -24
  115. package/dist/_chunks/router-CL62NScV.js.map +0 -1
  116. package/dist/_chunks/router-ylD0eA48.mjs +0 -24
  117. package/dist/_chunks/router-ylD0eA48.mjs.map +0 -1
  118. package/dist/admin/src/routes/content-manager/[model]/[id]/components/AssigneeSelect.d.ts +0 -2
  119. package/dist/admin/src/routes/content-manager/[model]/[id]/components/Panel.d.ts +0 -3
  120. package/dist/admin/src/routes/content-manager/[model]/[id]/components/StageSelect.d.ts +0 -1
  121. package/strapi-server.js +0 -3
  122. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/AssigneeFilter.d.ts +0 -0
  123. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/StageFilter.d.ts +0 -0
  124. /package/dist/admin/src/routes/content-manager/{[model] → model}/components/TableColumns.d.ts +0 -0
  125. /package/dist/admin/src/routes/content-manager/{[model] → model}/configure/constants.d.ts +0 -0
  126. /package/dist/admin/src/routes/content-manager/{[model] → model}/constants.d.ts +0 -0
  127. /package/dist/admin/src/routes/content-manager/{[model]/[id] → model/id}/components/constants.d.ts +0 -0
  128. /package/dist/admin/src/routes/settings/{:id.d.ts → id.d.ts} +0 -0
@@ -1,1333 +0,0 @@
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