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