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