@strapi/admin 4.11.4 → 4.12.0-beta.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/admin/src/constants.js +83 -83
- package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +8 -5
- package/admin/src/content-manager/components/Inputs/index.js +3 -47
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +34 -37
- package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +0 -27
- package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +93 -14
- package/admin/src/content-manager/pages/ListView/index.js +65 -59
- package/admin/src/content-manager/pages/ListView/utils/buildValidGetParams.js +30 -0
- package/admin/src/content-manager/pages/ListView/utils/index.js +1 -1
- package/admin/src/content-manager/utils/mergeMetasWithSchema.js +5 -1
- package/admin/src/hooks/index.js +0 -1
- package/admin/src/hooks/useAdminUsers/useAdminUsers.js +3 -3
- package/admin/src/hooks/useEnterprise/useEnterprise.js +4 -4
- package/admin/src/pages/App/index.js +28 -23
- package/admin/src/pages/AuthPage/components/Register/index.js +5 -1
- package/admin/src/pages/ProfilePage/index.js +6 -1
- package/admin/src/pages/SettingsPage/components/Tokens/TokenBox/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +1 -1
- package/admin/src/translations/zh-Hans.json +1 -1
- package/build/0cd5f8915b265d5b1856.png +0 -0
- package/build/2799.cf9b491f.chunk.js +1 -0
- package/build/4485.d3c6dd1d.chunk.js +6 -0
- package/build/539.865446c0.chunk.js +1 -0
- package/build/{5563.86f9aa9c.chunk.js → 5563.a146acac.chunk.js} +2 -2
- package/build/7018.f3dad3c1.chunk.js +1 -0
- package/build/7259.0e25ab5d.chunk.js +1 -0
- package/build/9465.d8fc1377.chunk.js +112 -0
- package/build/9944.29289a16.chunk.js +26 -0
- package/build/{Admin-authenticatedApp.cb649fc1.chunk.js → Admin-authenticatedApp.9d3afb79.chunk.js} +2 -2
- package/build/{Admin_settingsPage.4069bb8a.chunk.js → Admin_settingsPage.074655f6.chunk.js} +13 -13
- package/build/admin-app.3ede71ad.chunk.js +61 -0
- package/build/admin-edit-users.78552758.chunk.js +10 -0
- package/build/admin-users.c23322fc.chunk.js +11 -0
- package/build/audit-logs-settings-page.37fe915c.chunk.js +1 -0
- package/build/content-manager.08541eeb.chunk.js +1094 -0
- package/build/content-type-builder-translation-en-json.38e20391.chunk.js +1 -0
- package/build/content-type-builder.de22f7c9.chunk.js +166 -0
- package/build/index.html +1 -1
- package/build/main.a8ede50d.js +2927 -0
- package/build/review-workflows-settings-create-view.56f61e18.chunk.js +1 -0
- package/build/review-workflows-settings-edit-view.912bc9c0.chunk.js +1 -0
- package/build/review-workflows-settings-list-view.cf6a08d3.chunk.js +56 -0
- package/build/runtime~main.5e9bf4b3.js +2 -0
- package/build/{users-roles-settings-page.1f505119.chunk.js → users-roles-settings-page.d286426a.chunk.js} +1 -1
- package/build/{zh-Hans-json.4cfef87d.chunk.js → zh-Hans-json.fada6f40.chunk.js} +1 -1
- package/ee/admin/constants.js +14 -14
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +84 -30
- package/ee/admin/content-manager/{components/DynamicTable/CellContent/ReviewWorkflowsStage → pages/ListView/ReviewWorkflowsColumn}/ReviewWorkflowsStageEE.js +7 -2
- package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +24 -0
- package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/index.js +1 -0
- package/ee/admin/hooks/useLicenseLimitNotification/index.js +17 -6
- package/ee/admin/hooks/useLicenseLimits/index.js +1 -32
- package/ee/admin/hooks/useLicenseLimits/useLicenseLimits.js +44 -0
- package/ee/admin/pages/SettingsPage/constants.js +25 -1
- package/ee/admin/pages/SettingsPage/pages/ApplicationInfosPage/components/AdminSeatInfo/index.js +6 -4
- package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +6 -4
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/actions/index.js +19 -4
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Layout/Layout.js +65 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Layout/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/LimitsModal.js +111 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/assets/balloon.png +0 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/index.js +3 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/ProtectedPage.js +21 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +4 -4
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/WorkflowAttributes.js +110 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/constants.js +3 -1
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +13 -19
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +246 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/index.js +13 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +269 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/index.js +13 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +382 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/index.js +13 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +53 -23
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js +43 -28
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +9 -2
- package/ee/server/config/admin-actions.js +24 -0
- package/ee/server/constants/default-stages.json +8 -4
- package/ee/server/constants/default-workflow.json +3 -1
- package/ee/server/constants/workflows.js +10 -1
- package/ee/server/content-types/workflow/index.js +10 -0
- package/ee/server/content-types/workflow-stage/index.js +3 -1
- package/ee/server/controllers/admin.js +1 -0
- package/ee/server/controllers/workflows/index.js +135 -8
- package/ee/server/controllers/workflows/stages/index.js +38 -38
- package/ee/server/migrations/review-workflows-content-types.js +29 -0
- package/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js +39 -0
- package/ee/server/migrations/review-workflows-stage-attribute.js +49 -0
- package/ee/server/migrations/review-workflows-stages-color.js +2 -2
- package/ee/server/migrations/review-workflows-workflow-name.js +21 -0
- package/ee/server/register.js +12 -2
- package/ee/server/routes/review-workflows.js +44 -10
- package/ee/server/services/index.js +1 -0
- package/ee/server/services/review-workflows/entity-service-decorator.js +8 -13
- package/ee/server/services/review-workflows/review-workflows.js +45 -53
- package/ee/server/services/review-workflows/stages.js +84 -46
- package/ee/server/services/review-workflows/validation.js +60 -0
- package/ee/server/services/review-workflows/workflows/content-types.js +80 -0
- package/ee/server/services/review-workflows/workflows/index.js +207 -0
- package/ee/server/utils/review-workflows.js +30 -25
- package/ee/server/validation/review-workflows.js +49 -10
- package/package.json +10 -11
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +0 -2
- package/admin/src/content-manager/pages/ListView/utils/buildQueryString.js +0 -36
- package/admin/src/content-manager/pages/ListView/utils/createPluginsFilter.js +0 -4
- package/admin/src/hooks/useLicenseLimits/index.js +0 -3
- package/admin/src/pages/App/utils/index.js +0 -3
- package/admin/src/pages/App/utils/unique-identifier.js +0 -12
- package/build/1799.44d2e264.chunk.js +0 -33
- package/build/5932.6a23b88c.chunk.js +0 -1
- package/build/7018.98feed67.chunk.js +0 -1
- package/build/7259.fb69d4bf.chunk.js +0 -1
- package/build/admin-app.fea867af.chunk.js +0 -61
- package/build/admin-edit-users.200551e3.chunk.js +0 -10
- package/build/admin-users.3b12dca2.chunk.js +0 -11
- package/build/audit-logs-settings-page.f538490f.chunk.js +0 -1
- package/build/content-manager.c40f5ff9.chunk.js +0 -1088
- package/build/content-type-builder-translation-en-json.f592325b.chunk.js +0 -1
- package/build/content-type-builder.bd1bbff1.chunk.js +0 -166
- package/build/main.ee36abd9.js +0 -2927
- package/build/review-workflows-settings.93808ae0.chunk.js +0 -110
- package/build/runtime~main.efd966f6.js +0 -2
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +0 -58
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +0 -3
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ProtectedPage.js +0 -20
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +0 -204
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/index.js +0 -3
- package/ee/server/services/review-workflows/workflows.js +0 -25
|
@@ -4,20 +4,35 @@ import isEqual from 'lodash/isEqual';
|
|
|
4
4
|
import {
|
|
5
5
|
ACTION_ADD_STAGE,
|
|
6
6
|
ACTION_DELETE_STAGE,
|
|
7
|
-
|
|
7
|
+
ACTION_RESET_WORKFLOW,
|
|
8
|
+
ACTION_SET_WORKFLOW,
|
|
8
9
|
ACTION_UPDATE_STAGE,
|
|
9
10
|
ACTION_UPDATE_STAGE_POSITION,
|
|
11
|
+
ACTION_UPDATE_WORKFLOW,
|
|
10
12
|
STAGE_COLOR_DEFAULT,
|
|
11
13
|
} from '../constants';
|
|
12
14
|
|
|
13
15
|
export const initialState = {
|
|
14
16
|
status: 'loading',
|
|
15
17
|
serverState: {
|
|
16
|
-
|
|
17
|
-
workflows: [],
|
|
18
|
+
workflow: null,
|
|
18
19
|
},
|
|
19
20
|
clientState: {
|
|
20
|
-
currentWorkflow: {
|
|
21
|
+
currentWorkflow: {
|
|
22
|
+
data: {
|
|
23
|
+
name: '',
|
|
24
|
+
contentTypes: [],
|
|
25
|
+
stages: [
|
|
26
|
+
{
|
|
27
|
+
color: STAGE_COLOR_DEFAULT,
|
|
28
|
+
name: '',
|
|
29
|
+
__temp_key__: 1,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
},
|
|
33
|
+
isDirty: false,
|
|
34
|
+
hasDeletedServerStages: false,
|
|
35
|
+
},
|
|
21
36
|
},
|
|
22
37
|
};
|
|
23
38
|
|
|
@@ -26,29 +41,31 @@ export function reducer(state = initialState, action) {
|
|
|
26
41
|
const { payload } = action;
|
|
27
42
|
|
|
28
43
|
switch (action.type) {
|
|
29
|
-
case
|
|
30
|
-
const { status,
|
|
44
|
+
case ACTION_SET_WORKFLOW: {
|
|
45
|
+
const { status, workflow } = payload;
|
|
31
46
|
|
|
32
47
|
draft.status = status;
|
|
33
48
|
|
|
34
|
-
if (
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
defaultWorkflow = {
|
|
40
|
-
...defaultWorkflow,
|
|
41
|
-
stages: defaultWorkflow.stages.map((stage) => ({
|
|
49
|
+
if (workflow) {
|
|
50
|
+
draft.serverState.workflow = workflow;
|
|
51
|
+
draft.clientState.currentWorkflow.data = {
|
|
52
|
+
...workflow,
|
|
53
|
+
stages: workflow.stages.map((stage) => ({
|
|
42
54
|
...stage,
|
|
55
|
+
// A safety net in case a stage does not have a color assigned;
|
|
56
|
+
// this normallly should not happen
|
|
43
57
|
color: stage?.color ?? STAGE_COLOR_DEFAULT,
|
|
44
58
|
})),
|
|
45
59
|
};
|
|
46
|
-
|
|
47
|
-
draft.serverState.workflows = workflows;
|
|
48
|
-
draft.serverState.currentWorkflow = defaultWorkflow;
|
|
49
|
-
draft.clientState.currentWorkflow.data = defaultWorkflow;
|
|
50
|
-
draft.clientState.currentWorkflow.hasDeletedServerStages = false;
|
|
51
60
|
}
|
|
61
|
+
|
|
62
|
+
draft.clientState.currentWorkflow.hasDeletedServerStages = false;
|
|
63
|
+
break;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
case ACTION_RESET_WORKFLOW: {
|
|
67
|
+
draft.clientState.currentWorkflow.data = initialState.clientState.currentWorkflow.data;
|
|
68
|
+
draft.serverState = initialState.serverState;
|
|
52
69
|
break;
|
|
53
70
|
}
|
|
54
71
|
|
|
@@ -61,8 +78,9 @@ export function reducer(state = initialState, action) {
|
|
|
61
78
|
);
|
|
62
79
|
|
|
63
80
|
if (!currentWorkflow.hasDeletedServerStages) {
|
|
64
|
-
draft.clientState.currentWorkflow.hasDeletedServerStages =
|
|
65
|
-
|
|
81
|
+
draft.clientState.currentWorkflow.hasDeletedServerStages = !!(
|
|
82
|
+
state.serverState.currentWorkflow?.stages ?? []
|
|
83
|
+
).find((stage) => stage.id === stageId);
|
|
66
84
|
}
|
|
67
85
|
|
|
68
86
|
break;
|
|
@@ -125,15 +143,27 @@ export function reducer(state = initialState, action) {
|
|
|
125
143
|
break;
|
|
126
144
|
}
|
|
127
145
|
|
|
146
|
+
case ACTION_UPDATE_WORKFLOW: {
|
|
147
|
+
draft.clientState.currentWorkflow.data = {
|
|
148
|
+
...draft.clientState.currentWorkflow.data,
|
|
149
|
+
...payload,
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
break;
|
|
153
|
+
}
|
|
154
|
+
|
|
128
155
|
default:
|
|
129
156
|
break;
|
|
130
157
|
}
|
|
131
158
|
|
|
132
|
-
if (state.clientState.currentWorkflow.data) {
|
|
159
|
+
if (state.clientState.currentWorkflow.data && draft.serverState.workflow) {
|
|
133
160
|
draft.clientState.currentWorkflow.isDirty = !isEqual(
|
|
134
161
|
current(draft.clientState.currentWorkflow).data,
|
|
135
|
-
draft.serverState.
|
|
162
|
+
draft.serverState.workflow
|
|
136
163
|
);
|
|
164
|
+
} else {
|
|
165
|
+
// if there is no workflow on the server, the workflow is awalys considered dirty
|
|
166
|
+
draft.clientState.currentWorkflow.isDirty = true;
|
|
137
167
|
}
|
|
138
168
|
});
|
|
139
169
|
}
|
package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js
CHANGED
|
@@ -2,33 +2,48 @@ import * as yup from 'yup';
|
|
|
2
2
|
|
|
3
3
|
export function getWorkflowValidationSchema({ formatMessage }) {
|
|
4
4
|
return yup.object({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
5
|
+
contentTypes: yup.array().of(yup.string()),
|
|
6
|
+
name: yup
|
|
7
|
+
.string()
|
|
8
|
+
.max(
|
|
9
|
+
255,
|
|
10
|
+
formatMessage({
|
|
11
|
+
id: 'Settings.review-workflows.validation.name.max-length',
|
|
12
|
+
defaultMessage: 'Name can not be longer than 255 characters',
|
|
13
|
+
})
|
|
14
|
+
)
|
|
15
|
+
.required(),
|
|
16
|
+
|
|
17
|
+
stages: yup
|
|
18
|
+
.array()
|
|
19
|
+
.of(
|
|
20
|
+
yup.object().shape({
|
|
21
|
+
name: yup
|
|
22
|
+
.string()
|
|
23
|
+
.required(
|
|
24
|
+
formatMessage({
|
|
25
|
+
id: 'Settings.review-workflows.validation.stage.name',
|
|
26
|
+
defaultMessage: 'Name is required',
|
|
27
|
+
})
|
|
28
|
+
)
|
|
29
|
+
.max(
|
|
30
|
+
255,
|
|
31
|
+
formatMessage({
|
|
32
|
+
id: 'Settings.review-workflows.validation.stage.max-length',
|
|
33
|
+
defaultMessage: 'Name can not be longer than 255 characters',
|
|
34
|
+
})
|
|
35
|
+
),
|
|
36
|
+
color: yup
|
|
37
|
+
.string()
|
|
38
|
+
.required(
|
|
39
|
+
formatMessage({
|
|
40
|
+
id: 'Settings.review-workflows.validation.stage.color',
|
|
41
|
+
defaultMessage: 'Color is required',
|
|
42
|
+
})
|
|
43
|
+
)
|
|
44
|
+
.matches(/^#(?:[0-9a-fA-F]{3}){1,2}$/i),
|
|
45
|
+
})
|
|
46
|
+
)
|
|
47
|
+
.min(1),
|
|
33
48
|
});
|
|
34
49
|
}
|
|
@@ -10,8 +10,15 @@ import { useLicenseLimits } from '../../../../../../hooks';
|
|
|
10
10
|
|
|
11
11
|
const CreateAction = ({ onClick }) => {
|
|
12
12
|
const { formatMessage } = useIntl();
|
|
13
|
-
const {
|
|
14
|
-
|
|
13
|
+
const {
|
|
14
|
+
license: { permittedSeats, shouldStopCreate },
|
|
15
|
+
isError,
|
|
16
|
+
isLoading,
|
|
17
|
+
} = useLicenseLimits();
|
|
18
|
+
|
|
19
|
+
if (isError || isLoading) {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
15
22
|
|
|
16
23
|
return (
|
|
17
24
|
<Flex gap={2}>
|
|
@@ -30,6 +30,30 @@ module.exports = {
|
|
|
30
30
|
},
|
|
31
31
|
],
|
|
32
32
|
reviewWorkflows: [
|
|
33
|
+
{
|
|
34
|
+
uid: 'review-workflows.create',
|
|
35
|
+
displayName: 'Create',
|
|
36
|
+
pluginName: 'admin',
|
|
37
|
+
section: 'settings',
|
|
38
|
+
category: 'review workflows',
|
|
39
|
+
subCategory: 'options',
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
uid: 'review-workflows.update',
|
|
43
|
+
displayName: 'Update',
|
|
44
|
+
pluginName: 'admin',
|
|
45
|
+
section: 'settings',
|
|
46
|
+
category: 'review workflows',
|
|
47
|
+
subCategory: 'options',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
uid: 'review-workflows.delete',
|
|
51
|
+
displayName: 'Delete',
|
|
52
|
+
pluginName: 'admin',
|
|
53
|
+
section: 'settings',
|
|
54
|
+
category: 'review workflows',
|
|
55
|
+
subCategory: 'options',
|
|
56
|
+
},
|
|
33
57
|
{
|
|
34
58
|
uid: 'review-workflows.read',
|
|
35
59
|
displayName: 'Read',
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
[
|
|
2
2
|
{
|
|
3
|
-
"name": "To do"
|
|
3
|
+
"name": "To do",
|
|
4
|
+
"color": "#4945FF"
|
|
4
5
|
},
|
|
5
6
|
{
|
|
6
|
-
"name": "Ready to review"
|
|
7
|
+
"name": "Ready to review",
|
|
8
|
+
"color": "#9736E8"
|
|
7
9
|
},
|
|
8
10
|
{
|
|
9
|
-
"name": "In progress"
|
|
11
|
+
"name": "In progress",
|
|
12
|
+
"color": "#FF4945"
|
|
10
13
|
},
|
|
11
14
|
{
|
|
12
|
-
"name": "Reviewed"
|
|
15
|
+
"name": "Reviewed",
|
|
16
|
+
"color": "#328048"
|
|
13
17
|
}
|
|
14
18
|
]
|
|
@@ -5,5 +5,14 @@ module.exports = {
|
|
|
5
5
|
WORKFLOW_MODEL_UID: 'admin::workflow',
|
|
6
6
|
STAGE_MODEL_UID: 'admin::workflow-stage',
|
|
7
7
|
STAGE_DEFAULT_COLOR: '#4945FF',
|
|
8
|
-
ENTITY_STAGE_ATTRIBUTE: '
|
|
8
|
+
ENTITY_STAGE_ATTRIBUTE: 'strapi_stage',
|
|
9
|
+
MAX_WORKFLOWS: 200,
|
|
10
|
+
MAX_STAGES_PER_WORKFLOW: 200,
|
|
11
|
+
ERRORS: {
|
|
12
|
+
WORKFLOW_WITHOUT_STAGES: 'A workflow must have at least one stage.',
|
|
13
|
+
WORKFLOWS_LIMIT:
|
|
14
|
+
'You’ve reached the limit of workflows in your plan. Delete a workflow or contact Sales to enable more workflows.',
|
|
15
|
+
STAGES_LIMIT:
|
|
16
|
+
'You’ve reached the limit of stages for this workflow in your plan. Try deleting some stages or contact Sales to enable more stages.',
|
|
17
|
+
},
|
|
9
18
|
};
|
|
@@ -20,12 +20,22 @@ module.exports = {
|
|
|
20
20
|
},
|
|
21
21
|
},
|
|
22
22
|
attributes: {
|
|
23
|
+
name: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
required: true,
|
|
26
|
+
unique: true,
|
|
27
|
+
},
|
|
23
28
|
stages: {
|
|
24
29
|
type: 'relation',
|
|
25
30
|
target: 'admin::workflow-stage',
|
|
26
31
|
relation: 'oneToMany',
|
|
27
32
|
mappedBy: 'workflow',
|
|
28
33
|
},
|
|
34
|
+
contentTypes: {
|
|
35
|
+
type: 'json',
|
|
36
|
+
required: true,
|
|
37
|
+
default: [],
|
|
38
|
+
},
|
|
29
39
|
},
|
|
30
40
|
},
|
|
31
41
|
};
|
|
@@ -42,6 +42,7 @@ module.exports = {
|
|
|
42
42
|
shouldStopCreate: isNil(permittedSeats) ? false : currentActiveUserCount >= permittedSeats,
|
|
43
43
|
licenseLimitStatus,
|
|
44
44
|
isHostedOnStrapiCloud: env('STRAPI_HOSTING', null) === 'strapi.cloud',
|
|
45
|
+
features: ee.features.list() ?? [],
|
|
45
46
|
};
|
|
46
47
|
|
|
47
48
|
return { data };
|
|
@@ -1,36 +1,163 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { mapAsync } = require('@strapi/utils');
|
|
3
4
|
const { getService } = require('../../utils');
|
|
4
5
|
|
|
6
|
+
const {
|
|
7
|
+
validateWorkflowCreate,
|
|
8
|
+
validateWorkflowUpdate,
|
|
9
|
+
} = require('../../validation/review-workflows');
|
|
10
|
+
const { WORKFLOW_MODEL_UID } = require('../../constants/workflows');
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
*
|
|
14
|
+
* @param { Strapi } strapi - Strapi instance
|
|
15
|
+
* @param userAbility
|
|
16
|
+
* @return { PermissionChecker }
|
|
17
|
+
*/
|
|
18
|
+
function getWorkflowsPermissionChecker({ strapi }, userAbility) {
|
|
19
|
+
return strapi
|
|
20
|
+
.plugin('content-manager')
|
|
21
|
+
.service('permission-checker')
|
|
22
|
+
.create({ userAbility, model: WORKFLOW_MODEL_UID });
|
|
23
|
+
}
|
|
24
|
+
|
|
5
25
|
module.exports = {
|
|
6
26
|
/**
|
|
7
|
-
*
|
|
27
|
+
* Create a new workflow
|
|
8
28
|
* @param {import('koa').BaseContext} ctx - koa context
|
|
9
29
|
*/
|
|
10
|
-
async
|
|
11
|
-
const {
|
|
30
|
+
async create(ctx) {
|
|
31
|
+
const { body, query } = ctx.request;
|
|
32
|
+
const { sanitizeCreateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(
|
|
33
|
+
{ strapi },
|
|
34
|
+
ctx.state.userAbility
|
|
35
|
+
);
|
|
36
|
+
const { populate } = await sanitizedQuery.create(query);
|
|
37
|
+
|
|
38
|
+
const workflowBody = await validateWorkflowCreate(body.data);
|
|
39
|
+
|
|
40
|
+
const workflowService = getService('workflows');
|
|
41
|
+
const createdWorkflow = await workflowService.create({
|
|
42
|
+
data: await sanitizeCreateInput(workflowBody),
|
|
43
|
+
populate,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
ctx.body = {
|
|
47
|
+
data: await sanitizeOutput(createdWorkflow),
|
|
48
|
+
};
|
|
49
|
+
},
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* Update a workflow
|
|
53
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
54
|
+
*/
|
|
55
|
+
async update(ctx) {
|
|
56
|
+
const { id } = ctx.params;
|
|
57
|
+
const { body, query } = ctx.request;
|
|
12
58
|
const workflowService = getService('workflows');
|
|
13
|
-
const
|
|
59
|
+
const { sanitizeUpdateInput, sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(
|
|
60
|
+
{ strapi },
|
|
61
|
+
ctx.state.userAbility
|
|
62
|
+
);
|
|
63
|
+
const { populate } = await sanitizedQuery.update(query);
|
|
64
|
+
|
|
65
|
+
const workflowBody = await validateWorkflowUpdate(body.data);
|
|
66
|
+
|
|
67
|
+
const workflow = await workflowService.findById(id, { populate: ['stages'] });
|
|
68
|
+
if (!workflow) {
|
|
69
|
+
return ctx.notFound();
|
|
70
|
+
}
|
|
71
|
+
const getPermittedFieldToUpdate = sanitizeUpdateInput(workflow);
|
|
72
|
+
|
|
73
|
+
const dataToUpdate = await getPermittedFieldToUpdate(workflowBody);
|
|
74
|
+
|
|
75
|
+
const updatedWorkflow = await workflowService.update(workflow, {
|
|
76
|
+
data: dataToUpdate,
|
|
14
77
|
populate,
|
|
15
78
|
});
|
|
16
79
|
|
|
17
80
|
ctx.body = {
|
|
18
|
-
data,
|
|
81
|
+
data: await sanitizeOutput(updatedWorkflow),
|
|
82
|
+
};
|
|
83
|
+
},
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* Delete a workflow
|
|
87
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
88
|
+
*/
|
|
89
|
+
async delete(ctx) {
|
|
90
|
+
const { id } = ctx.params;
|
|
91
|
+
const { query } = ctx.request;
|
|
92
|
+
const workflowService = getService('workflows');
|
|
93
|
+
const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(
|
|
94
|
+
{ strapi },
|
|
95
|
+
ctx.state.userAbility
|
|
96
|
+
);
|
|
97
|
+
const { populate } = await sanitizedQuery.delete(query);
|
|
98
|
+
|
|
99
|
+
const workflow = await workflowService.findById(id, { populate: ['stages'] });
|
|
100
|
+
if (!workflow) {
|
|
101
|
+
return ctx.notFound("Workflow doesn't exist");
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
const deletedWorkflow = await workflowService.delete(workflow, { populate });
|
|
105
|
+
|
|
106
|
+
ctx.body = {
|
|
107
|
+
data: await sanitizeOutput(deletedWorkflow),
|
|
108
|
+
};
|
|
109
|
+
},
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* List all workflows
|
|
113
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
114
|
+
*/
|
|
115
|
+
async find(ctx) {
|
|
116
|
+
const { query } = ctx.request;
|
|
117
|
+
const workflowService = getService('workflows');
|
|
118
|
+
const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(
|
|
119
|
+
{ strapi },
|
|
120
|
+
ctx.state.userAbility
|
|
121
|
+
);
|
|
122
|
+
const { populate, filters, sort } = await sanitizedQuery.read(query);
|
|
123
|
+
|
|
124
|
+
const [workflows, workflowCount] = await Promise.all([
|
|
125
|
+
workflowService.find({ populate, filters, sort }),
|
|
126
|
+
workflowService.count(),
|
|
127
|
+
]);
|
|
128
|
+
|
|
129
|
+
ctx.body = {
|
|
130
|
+
data: await mapAsync(workflows, sanitizeOutput),
|
|
131
|
+
meta: {
|
|
132
|
+
workflowCount,
|
|
133
|
+
},
|
|
19
134
|
};
|
|
20
135
|
},
|
|
21
136
|
/**
|
|
22
137
|
* Get one workflow based on its id contained in request parameters
|
|
138
|
+
* Returns count of workflows in meta, used to prevent workflow edition when
|
|
139
|
+
* max workflow count is reached for the current plan
|
|
23
140
|
* @param {import('koa').BaseContext} ctx - koa context
|
|
24
141
|
*/
|
|
25
142
|
async findById(ctx) {
|
|
26
143
|
const { id } = ctx.params;
|
|
27
|
-
const {
|
|
144
|
+
const { query } = ctx.request;
|
|
145
|
+
const { sanitizeOutput, sanitizedQuery } = getWorkflowsPermissionChecker(
|
|
146
|
+
{ strapi },
|
|
147
|
+
ctx.state.userAbility
|
|
148
|
+
);
|
|
149
|
+
const { populate } = await sanitizedQuery.read(query);
|
|
28
150
|
|
|
29
151
|
const workflowService = getService('workflows');
|
|
30
|
-
|
|
152
|
+
|
|
153
|
+
const [workflow, workflowCount] = await Promise.all([
|
|
154
|
+
workflowService.findById(id, { populate }),
|
|
155
|
+
workflowService.count(),
|
|
156
|
+
]);
|
|
31
157
|
|
|
32
158
|
ctx.body = {
|
|
33
|
-
data,
|
|
159
|
+
data: await sanitizeOutput(workflow),
|
|
160
|
+
meta: { workflowCount },
|
|
34
161
|
};
|
|
35
162
|
},
|
|
36
163
|
};
|
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const { mapAsync } = require('@strapi/utils');
|
|
4
4
|
const { getService } = require('../../../utils');
|
|
5
|
-
const {
|
|
6
|
-
const {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
5
|
+
const { validateUpdateStageOnEntity } = require('../../../validation/review-workflows');
|
|
6
|
+
const { STAGE_MODEL_UID } = require('../../../constants/workflows');
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
* @param { Strapi } strapi - Strapi instance
|
|
11
|
+
* @param userAbility
|
|
12
|
+
* @return { (Stage) => SanitizedStage }
|
|
13
|
+
*/
|
|
14
|
+
function sanitizeStage({ strapi }, userAbility) {
|
|
15
|
+
const permissionChecker = strapi
|
|
16
|
+
.plugin('content-manager')
|
|
17
|
+
.service('permission-checker')
|
|
18
|
+
.create({ userAbility, model: STAGE_MODEL_UID });
|
|
19
|
+
|
|
20
|
+
return (entity) => permissionChecker.sanitizeOutput(entity);
|
|
21
|
+
}
|
|
10
22
|
|
|
11
23
|
module.exports = {
|
|
12
24
|
/**
|
|
@@ -17,14 +29,15 @@ module.exports = {
|
|
|
17
29
|
const { workflow_id: workflowId } = ctx.params;
|
|
18
30
|
const { populate } = ctx.query;
|
|
19
31
|
const stagesService = getService('stages');
|
|
32
|
+
const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);
|
|
20
33
|
|
|
21
|
-
const
|
|
34
|
+
const stages = await stagesService.find({
|
|
22
35
|
workflowId,
|
|
23
36
|
populate,
|
|
24
37
|
});
|
|
25
38
|
|
|
26
39
|
ctx.body = {
|
|
27
|
-
data,
|
|
40
|
+
data: await mapAsync(stages, sanitizer),
|
|
28
41
|
};
|
|
29
42
|
},
|
|
30
43
|
/**
|
|
@@ -35,36 +48,18 @@ module.exports = {
|
|
|
35
48
|
const { id, workflow_id: workflowId } = ctx.params;
|
|
36
49
|
const { populate } = ctx.query;
|
|
37
50
|
const stagesService = getService('stages');
|
|
51
|
+
const sanitizer = sanitizeStage({ strapi }, ctx.state.userAbility);
|
|
38
52
|
|
|
39
|
-
const
|
|
53
|
+
const stage = await stagesService.findById(id, {
|
|
40
54
|
workflowId,
|
|
41
55
|
populate,
|
|
42
56
|
});
|
|
43
57
|
|
|
44
58
|
ctx.body = {
|
|
45
|
-
data,
|
|
59
|
+
data: await sanitizer(stage),
|
|
46
60
|
};
|
|
47
61
|
},
|
|
48
62
|
|
|
49
|
-
/**
|
|
50
|
-
* Replace all stages in a workflow
|
|
51
|
-
* @param {import('koa').BaseContext} ctx - koa context
|
|
52
|
-
*
|
|
53
|
-
*/
|
|
54
|
-
async replace(ctx) {
|
|
55
|
-
const { workflow_id: workflowId } = ctx.params;
|
|
56
|
-
const stagesService = getService('stages');
|
|
57
|
-
const {
|
|
58
|
-
body: { data: stages },
|
|
59
|
-
} = ctx.request;
|
|
60
|
-
|
|
61
|
-
const stagesValidated = await validateUpdateStages(stages);
|
|
62
|
-
|
|
63
|
-
const data = await stagesService.replaceWorkflowStages(workflowId, stagesValidated);
|
|
64
|
-
|
|
65
|
-
ctx.body = { data };
|
|
66
|
-
},
|
|
67
|
-
|
|
68
63
|
/**
|
|
69
64
|
* Updates an entity's stage.
|
|
70
65
|
* @async
|
|
@@ -80,23 +75,28 @@ module.exports = {
|
|
|
80
75
|
*/
|
|
81
76
|
async updateEntity(ctx) {
|
|
82
77
|
const stagesService = getService('stages');
|
|
78
|
+
const workflowService = getService('workflows');
|
|
79
|
+
|
|
83
80
|
const { model_uid: modelUID, id: entityIdString } = ctx.params;
|
|
81
|
+
const { body } = ctx.request;
|
|
82
|
+
|
|
84
83
|
const entityId = Number(entityIdString);
|
|
85
84
|
|
|
85
|
+
const { sanitizeOutput } = strapi
|
|
86
|
+
.plugin('content-manager')
|
|
87
|
+
.service('permission-checker')
|
|
88
|
+
.create({ userAbility: ctx.state.userAbility, model: modelUID });
|
|
89
|
+
|
|
86
90
|
const { id: stageId } = await validateUpdateStageOnEntity(
|
|
87
|
-
|
|
91
|
+
{ id: Number(body?.data?.id) },
|
|
88
92
|
'You should pass an id to the body of the put request.'
|
|
89
93
|
);
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// TODO When multiple workflows are possible, check if the stage is part of the right one
|
|
96
|
-
// Didn't need this today as their can only be one workflow
|
|
95
|
+
const workflow = await workflowService.assertContentTypeBelongsToWorkflow(modelUID);
|
|
96
|
+
workflowService.assertStageBelongsToWorkflow(stageId, workflow);
|
|
97
97
|
|
|
98
|
-
const
|
|
98
|
+
const entity = await stagesService.updateEntity({ id: entityId, modelUID }, stageId);
|
|
99
99
|
|
|
100
|
-
ctx.body = { data };
|
|
100
|
+
ctx.body = { data: await sanitizeOutput(entity) };
|
|
101
101
|
},
|
|
102
102
|
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { get, keys, pickBy, pipe } = require('lodash/fp');
|
|
4
|
+
const { WORKFLOW_MODEL_UID } = require('../constants/workflows');
|
|
5
|
+
|
|
6
|
+
async function migrateWorkflowsContentTypes({ oldContentTypes, contentTypes }) {
|
|
7
|
+
// Look for RW contentTypes attribute
|
|
8
|
+
const hadContentTypes = !!oldContentTypes?.[WORKFLOW_MODEL_UID]?.attributes?.contentTypes;
|
|
9
|
+
const hasContentTypes = !!contentTypes?.[WORKFLOW_MODEL_UID]?.attributes?.contentTypes;
|
|
10
|
+
|
|
11
|
+
if (!hadContentTypes && hasContentTypes) {
|
|
12
|
+
// Initialize contentTypes with an empty array and assign only to one
|
|
13
|
+
// workflow the Content Types which were using Review Workflow before.
|
|
14
|
+
await strapi.query(WORKFLOW_MODEL_UID).updateMany({ data: { contentTypes: [] } });
|
|
15
|
+
|
|
16
|
+
// Find Content Types which were using Review Workflow before
|
|
17
|
+
const contentTypes = pipe([pickBy(get('options.reviewWorkflows')), keys])(oldContentTypes);
|
|
18
|
+
|
|
19
|
+
if (contentTypes.length) {
|
|
20
|
+
// Update only one workflow with the contentTypes
|
|
21
|
+
// Before this release there was only one workflow, so this operation is safe.
|
|
22
|
+
await strapi
|
|
23
|
+
.query(WORKFLOW_MODEL_UID)
|
|
24
|
+
.update({ where: { id: { $notNull: true } }, data: { contentTypes } });
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
module.exports = migrateWorkflowsContentTypes;
|