@strapi/review-workflows 0.0.0-experimental.9612538209f3c68285c5dea8fe26f96e7e470afd → 0.0.0-experimental.9678892591ed5d28450369e1511b3d21cb7db4f9

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