@strapi/admin 4.9.2 → 4.10.0-beta.1
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/content-manager/components/DynamicTable/CellContent/PublicationState/PublicationState.js +26 -0
- package/admin/src/content-manager/components/DynamicTable/CellContent/PublicationState/index.js +1 -0
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +2 -0
- package/admin/src/content-manager/components/DynamicTable/index.js +25 -49
- package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +2 -0
- package/admin/src/content-manager/pages/EditView/Information/index.js +77 -53
- package/admin/src/content-manager/pages/EditView/InformationBox/InformationBoxCE.js +13 -0
- package/admin/src/content-manager/pages/EditView/InformationBox/index.js +3 -0
- package/admin/src/content-manager/pages/EditView/index.js +3 -4
- package/admin/src/content-manager/pages/ListView/index.js +6 -9
- package/admin/src/content-manager/sharedReducers/crudReducer/actions.js +6 -0
- package/admin/src/content-manager/sharedReducers/crudReducer/constants.js +1 -0
- package/admin/src/content-manager/sharedReducers/crudReducer/reducer.js +5 -0
- package/admin/src/index.js +1 -0
- package/admin/src/translations/en.json +6 -0
- package/build/{Admin-authenticatedApp.217db666.chunk.js → Admin-authenticatedApp.52c88751.chunk.js} +2 -2
- package/build/{Admin_settingsPage.1dbfc9ce.chunk.js → Admin_settingsPage.257b3477.chunk.js} +7 -7
- package/build/{admin-app.558af642.chunk.js → admin-app.dfaeea5d.chunk.js} +18 -18
- package/build/content-manager.def692c2.chunk.js +1130 -0
- package/build/content-type-builder-translation-en-json.510e88ca.chunk.js +1 -0
- package/build/content-type-builder.5e1f4afc.chunk.js +126 -0
- package/build/en-json.08303b37.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/{main.ef8db4a2.js → main.120be100.js} +145 -145
- package/build/review-workflows-settings.9092ed72.chunk.js +106 -0
- package/build/{runtime~main.3a92d953.js → runtime~main.112b3101.js} +1 -1
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStageEE.js +15 -0
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +45 -0
- package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +3 -0
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +135 -0
- package/ee/admin/content-manager/pages/EditView/InformationBox/index.js +3 -0
- package/ee/admin/hooks/useSettingsMenu/utils/customAdminLinks.js +12 -12
- package/ee/admin/hooks/useSettingsMenu/utils/customGlobalLinks.js +21 -13
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +199 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/actions/index.js +42 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/AddStage/AddStage.js +87 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/AddStage/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +90 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stages.js +92 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/index.js +1 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/constants.js +6 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +35 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/index.js +3 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +122 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js +25 -0
- package/ee/admin/pages/SettingsPage/utils/customRoutes.js +16 -2
- package/ee/admin/permissions/customPermissions.js +3 -0
- package/ee/server/bootstrap.js +13 -0
- package/ee/server/config/admin-actions.js +10 -0
- package/ee/server/constants/default-stages.json +14 -0
- package/ee/server/constants/default-workflow.json +1 -0
- package/ee/server/constants/workflows.js +8 -0
- package/ee/server/content-types/index.js +9 -0
- package/ee/server/content-types/workflow/index.js +31 -0
- package/ee/server/content-types/workflow-stage/index.js +36 -0
- package/ee/server/controllers/index.js +2 -0
- package/ee/server/controllers/workflows/index.js +36 -0
- package/ee/server/controllers/workflows/stages/index.js +102 -0
- package/ee/server/index.js +1 -0
- package/ee/server/middlewares/review-workflows.js +40 -0
- package/ee/server/register.js +8 -0
- package/ee/server/routes/index.js +104 -0
- package/ee/server/services/index.js +4 -0
- package/ee/server/services/review-workflows/entity-service-decorator.js +54 -0
- package/ee/server/services/review-workflows/review-workflows.js +111 -0
- package/ee/server/services/review-workflows/stages.js +249 -0
- package/ee/server/services/review-workflows/workflows.js +25 -0
- package/ee/server/utils/index.js +8 -0
- package/ee/server/utils/persisted-tables.js +114 -22
- package/ee/server/utils/review-workflows.js +34 -0
- package/ee/server/validation/review-workflows.js +24 -0
- package/package.json +9 -9
- package/build/content-manager.d1565bfc.chunk.js +0 -1132
- package/build/content-type-builder-translation-en-json.6c8e69ab.chunk.js +0 -1
- package/build/content-type-builder.9d780e7f.chunk.js +0 -126
- package/build/en-json.cf600231.chunk.js +0 -1
package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as yup from 'yup';
|
|
2
|
+
|
|
3
|
+
export function getWorkflowValidationSchema({ formatMessage }) {
|
|
4
|
+
return yup.object({
|
|
5
|
+
stages: yup.array().of(
|
|
6
|
+
yup.object().shape({
|
|
7
|
+
name: yup
|
|
8
|
+
.string()
|
|
9
|
+
.required(
|
|
10
|
+
formatMessage({
|
|
11
|
+
id: 'Settings.review-workflows.validation.stage.name',
|
|
12
|
+
defaultMessage: 'Name is required',
|
|
13
|
+
})
|
|
14
|
+
)
|
|
15
|
+
.max(
|
|
16
|
+
255,
|
|
17
|
+
formatMessage({
|
|
18
|
+
id: 'Settings.review-workflows.validation.stage.max-length',
|
|
19
|
+
defaultMessage: 'Name can not be longer than 255 characters',
|
|
20
|
+
})
|
|
21
|
+
),
|
|
22
|
+
})
|
|
23
|
+
),
|
|
24
|
+
});
|
|
25
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const routes = [];
|
|
2
2
|
|
|
3
|
-
if (strapi.features.isEnabled(strapi.features.SSO)) {
|
|
3
|
+
if (window.strapi.features.isEnabled(window.strapi.features.SSO)) {
|
|
4
4
|
routes.push({
|
|
5
5
|
async Component() {
|
|
6
6
|
const component = await import(
|
|
@@ -14,7 +14,21 @@ if (strapi.features.isEnabled(strapi.features.SSO)) {
|
|
|
14
14
|
});
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
-
if (strapi.features.isEnabled(strapi.features.
|
|
17
|
+
if (window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)) {
|
|
18
|
+
routes.push({
|
|
19
|
+
async Component() {
|
|
20
|
+
const component = await import(
|
|
21
|
+
/* webpackChunkName: "review-workflows-settings" */ '../pages/ReviewWorkflows'
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
return component;
|
|
25
|
+
},
|
|
26
|
+
to: '/settings/review-workflows',
|
|
27
|
+
exact: true,
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)) {
|
|
18
32
|
routes.push({
|
|
19
33
|
async Component() {
|
|
20
34
|
const component = await import(
|
|
@@ -4,6 +4,9 @@ const customPermissions = {
|
|
|
4
4
|
main: [{ action: 'admin::audit-logs.read', subject: null }],
|
|
5
5
|
read: [{ action: 'admin::audit-logs.read', subject: null }],
|
|
6
6
|
},
|
|
7
|
+
'review-workflows': {
|
|
8
|
+
main: [{ action: 'admin::review-workflows.read', subject: null }],
|
|
9
|
+
},
|
|
7
10
|
sso: {
|
|
8
11
|
main: [{ action: 'admin::provider-login.read', subject: null }],
|
|
9
12
|
read: [{ action: 'admin::provider-login.read', subject: null }],
|
package/ee/server/bootstrap.js
CHANGED
|
@@ -20,6 +20,19 @@ module.exports = async () => {
|
|
|
20
20
|
await actionProvider.registerMany(actions.auditLogs);
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
+
if (features.isEnabled('review-workflows')) {
|
|
24
|
+
await persistTablesWithPrefix('strapi_workflows');
|
|
25
|
+
|
|
26
|
+
const { bootstrap: rwBootstrap } = getService('review-workflows');
|
|
27
|
+
|
|
28
|
+
await rwBootstrap();
|
|
29
|
+
await actionProvider.registerMany(actions.reviewWorkflows);
|
|
30
|
+
|
|
31
|
+
// Decorate the entity service with review workflow logic
|
|
32
|
+
const { decorator } = getService('review-workflows-decorator');
|
|
33
|
+
strapi.entityService.decorate(decorator);
|
|
34
|
+
}
|
|
35
|
+
|
|
23
36
|
await getService('seat-enforcement').seatEnforcementWorkflow();
|
|
24
37
|
|
|
25
38
|
await executeCEBootstrap();
|
|
@@ -29,4 +29,14 @@ module.exports = {
|
|
|
29
29
|
subCategory: 'options',
|
|
30
30
|
},
|
|
31
31
|
],
|
|
32
|
+
reviewWorkflows: [
|
|
33
|
+
{
|
|
34
|
+
uid: 'review-workflows.read',
|
|
35
|
+
displayName: 'Read',
|
|
36
|
+
pluginName: 'admin',
|
|
37
|
+
section: 'settings',
|
|
38
|
+
category: 'review workflows',
|
|
39
|
+
subCategory: 'options',
|
|
40
|
+
},
|
|
41
|
+
],
|
|
32
42
|
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
schema: {
|
|
5
|
+
collectionName: 'strapi_workflows',
|
|
6
|
+
info: {
|
|
7
|
+
name: 'Workflow',
|
|
8
|
+
description: '',
|
|
9
|
+
singularName: 'workflow',
|
|
10
|
+
pluralName: 'workflows',
|
|
11
|
+
displayName: 'Workflow',
|
|
12
|
+
},
|
|
13
|
+
options: {},
|
|
14
|
+
pluginOptions: {
|
|
15
|
+
'content-manager': {
|
|
16
|
+
visible: false,
|
|
17
|
+
},
|
|
18
|
+
'content-type-builder': {
|
|
19
|
+
visible: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
attributes: {
|
|
23
|
+
stages: {
|
|
24
|
+
type: 'relation',
|
|
25
|
+
target: 'admin::workflow-stage',
|
|
26
|
+
relation: 'oneToMany',
|
|
27
|
+
mappedBy: 'workflow',
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
schema: {
|
|
5
|
+
collectionName: 'strapi_workflows_stages',
|
|
6
|
+
info: {
|
|
7
|
+
name: 'Workflow Stage',
|
|
8
|
+
description: '',
|
|
9
|
+
singularName: 'workflow-stage',
|
|
10
|
+
pluralName: 'workflow-stages',
|
|
11
|
+
displayName: 'Stages',
|
|
12
|
+
},
|
|
13
|
+
options: {},
|
|
14
|
+
pluginOptions: {
|
|
15
|
+
'content-manager': {
|
|
16
|
+
visible: false,
|
|
17
|
+
},
|
|
18
|
+
'content-type-builder': {
|
|
19
|
+
visible: false,
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
attributes: {
|
|
23
|
+
name: {
|
|
24
|
+
type: 'string',
|
|
25
|
+
configurable: false,
|
|
26
|
+
},
|
|
27
|
+
workflow: {
|
|
28
|
+
type: 'relation',
|
|
29
|
+
target: 'admin::workflow',
|
|
30
|
+
relation: 'manyToOne',
|
|
31
|
+
inversedBy: 'stages',
|
|
32
|
+
configurable: false,
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { getService } = require('../../utils');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
/**
|
|
7
|
+
* List all workflows
|
|
8
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
9
|
+
*/
|
|
10
|
+
async find(ctx) {
|
|
11
|
+
const { populate } = ctx.query;
|
|
12
|
+
const workflowService = getService('workflows');
|
|
13
|
+
const data = await workflowService.find({
|
|
14
|
+
populate,
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
ctx.body = {
|
|
18
|
+
data,
|
|
19
|
+
};
|
|
20
|
+
},
|
|
21
|
+
/**
|
|
22
|
+
* Get one workflow based on its id contained in request parameters
|
|
23
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
24
|
+
*/
|
|
25
|
+
async findById(ctx) {
|
|
26
|
+
const { id } = ctx.params;
|
|
27
|
+
const { populate } = ctx.query;
|
|
28
|
+
|
|
29
|
+
const workflowService = getService('workflows');
|
|
30
|
+
const data = await workflowService.findById(id, { populate });
|
|
31
|
+
|
|
32
|
+
ctx.body = {
|
|
33
|
+
data,
|
|
34
|
+
};
|
|
35
|
+
},
|
|
36
|
+
};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { ApplicationError } = require('@strapi/utils/lib/errors');
|
|
4
|
+
const { getService } = require('../../../utils');
|
|
5
|
+
const { hasReviewWorkflow } = require('../../../utils/review-workflows');
|
|
6
|
+
const {
|
|
7
|
+
validateUpdateStages,
|
|
8
|
+
validateUpdateStageOnEntity,
|
|
9
|
+
} = require('../../../validation/review-workflows');
|
|
10
|
+
|
|
11
|
+
module.exports = {
|
|
12
|
+
/**
|
|
13
|
+
* List all stages
|
|
14
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
15
|
+
*/
|
|
16
|
+
async find(ctx) {
|
|
17
|
+
const { workflow_id: workflowId } = ctx.params;
|
|
18
|
+
const { populate } = ctx.query;
|
|
19
|
+
const stagesService = getService('stages');
|
|
20
|
+
|
|
21
|
+
const data = await stagesService.find({
|
|
22
|
+
workflowId,
|
|
23
|
+
populate,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
ctx.body = {
|
|
27
|
+
data,
|
|
28
|
+
};
|
|
29
|
+
},
|
|
30
|
+
/**
|
|
31
|
+
* Get one stage
|
|
32
|
+
* @param {import('koa').BaseContext} ctx - koa context
|
|
33
|
+
*/
|
|
34
|
+
async findById(ctx) {
|
|
35
|
+
const { id, workflow_id: workflowId } = ctx.params;
|
|
36
|
+
const { populate } = ctx.query;
|
|
37
|
+
const stagesService = getService('stages');
|
|
38
|
+
|
|
39
|
+
const data = await stagesService.findById(id, {
|
|
40
|
+
workflowId,
|
|
41
|
+
populate,
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
ctx.body = {
|
|
45
|
+
data,
|
|
46
|
+
};
|
|
47
|
+
},
|
|
48
|
+
|
|
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
|
+
/**
|
|
69
|
+
* Updates an entity's stage.
|
|
70
|
+
* @async
|
|
71
|
+
* @param {Object} ctx - The Koa context object.
|
|
72
|
+
* @param {Object} ctx.params - An object containing the parameters from the request URL.
|
|
73
|
+
* @param {string} ctx.params.model_uid - The model UID of the entity.
|
|
74
|
+
* @param {string} ctx.params.id - The ID of the entity to update.
|
|
75
|
+
* @param {Object} ctx.request.body.data - Optional data object containing the new stage ID for the entity.
|
|
76
|
+
* @param {string} ctx.request.body.data.id - The ID of the new stage for the entity.
|
|
77
|
+
* @throws {ApplicationError} If review workflows is not activated on the specified model UID.
|
|
78
|
+
* @throws {ValidationError} If the `data` object in the request body fails to pass validation.
|
|
79
|
+
* @returns {Promise<void>} A promise that resolves when the entity's stage has been updated.
|
|
80
|
+
*/
|
|
81
|
+
async updateEntity(ctx) {
|
|
82
|
+
const stagesService = getService('stages');
|
|
83
|
+
const { model_uid: modelUID, id: entityIdString } = ctx.params;
|
|
84
|
+
const entityId = Number(entityIdString);
|
|
85
|
+
|
|
86
|
+
const { id: stageId } = await validateUpdateStageOnEntity(
|
|
87
|
+
ctx.request?.body?.data,
|
|
88
|
+
'You should pass an id to the body of the put request.'
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
if (!hasReviewWorkflow({ strapi }, modelUID)) {
|
|
92
|
+
throw new ApplicationError(`Review workflows is not activated on ${modelUID}.`);
|
|
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
|
|
97
|
+
|
|
98
|
+
const data = await stagesService.updateEntity({ id: entityId, modelUID }, stageId);
|
|
99
|
+
|
|
100
|
+
ctx.body = { data };
|
|
101
|
+
},
|
|
102
|
+
};
|
package/ee/server/index.js
CHANGED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { set } = require('lodash/fp');
|
|
4
|
+
|
|
5
|
+
module.exports = {
|
|
6
|
+
contentTypeMiddleware,
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* A Strapi middleware function that adds support for review workflows.
|
|
11
|
+
*
|
|
12
|
+
* Why is it needed ?
|
|
13
|
+
* For now, the admin panel cannot have anything but top-level attributes in the content-type for options.
|
|
14
|
+
* But we need the CE part to be agnostics from Review Workflow (which is an EE feature).
|
|
15
|
+
* CE handle the `options` object, that's why we move the reviewWorkflows boolean to the options object.
|
|
16
|
+
*
|
|
17
|
+
* @param {object} strapi - The Strapi instance.
|
|
18
|
+
*/
|
|
19
|
+
function contentTypeMiddleware(strapi) {
|
|
20
|
+
/**
|
|
21
|
+
* A middleware function that moves the `reviewWorkflows` attribute from the top level of
|
|
22
|
+
* the request body to the `options` object within the request body.
|
|
23
|
+
*
|
|
24
|
+
* @param {object} ctx - The Koa context object.
|
|
25
|
+
*/
|
|
26
|
+
const moveReviewWorkflowOption = (ctx) => {
|
|
27
|
+
// Move reviewWorkflows to options.reviewWorkflows
|
|
28
|
+
const { reviewWorkflows, ...contentType } = ctx.request.body.contentType;
|
|
29
|
+
|
|
30
|
+
if (typeof reviewWorkflows === 'boolean') {
|
|
31
|
+
ctx.request.body.contentType = set('options.reviewWorkflows', reviewWorkflows, contentType);
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
strapi.server.router.use('/content-type-builder/content-types/:uid?', (ctx, next) => {
|
|
35
|
+
if (ctx.method === 'PUT' || ctx.method === 'POST') {
|
|
36
|
+
moveReviewWorkflowOption(ctx);
|
|
37
|
+
}
|
|
38
|
+
return next();
|
|
39
|
+
});
|
|
40
|
+
}
|
package/ee/server/register.js
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { features } = require('@strapi/strapi/lib/utils/ee');
|
|
3
4
|
const executeCERegister = require('../../server/register');
|
|
4
5
|
const migrateAuditLogsTable = require('./migrations/audit-logs-table');
|
|
5
6
|
const createAuditLogsService = require('./services/audit-logs');
|
|
7
|
+
const reviewWorkflowsMiddlewares = require('./middlewares/review-workflows');
|
|
8
|
+
const { getService } = require('./utils');
|
|
6
9
|
|
|
7
10
|
module.exports = async ({ strapi }) => {
|
|
8
11
|
const auditLogsIsEnabled = strapi.config.get('admin.auditLogs.enabled', true);
|
|
@@ -13,6 +16,11 @@ module.exports = async ({ strapi }) => {
|
|
|
13
16
|
strapi.container.register('audit-logs', auditLogsService);
|
|
14
17
|
await auditLogsService.register();
|
|
15
18
|
}
|
|
19
|
+
if (features.isEnabled('review-workflows')) {
|
|
20
|
+
const reviewWorkflowService = getService('review-workflows');
|
|
16
21
|
|
|
22
|
+
reviewWorkflowsMiddlewares.contentTypeMiddleware(strapi);
|
|
23
|
+
await reviewWorkflowService.register();
|
|
24
|
+
}
|
|
17
25
|
await executeCERegister({ strapi });
|
|
18
26
|
};
|
|
@@ -122,4 +122,108 @@ module.exports = [
|
|
|
122
122
|
],
|
|
123
123
|
},
|
|
124
124
|
},
|
|
125
|
+
|
|
126
|
+
// Review workflow
|
|
127
|
+
{
|
|
128
|
+
method: 'GET',
|
|
129
|
+
path: '/review-workflows/workflows',
|
|
130
|
+
handler: 'workflows.find',
|
|
131
|
+
config: {
|
|
132
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
133
|
+
policies: [
|
|
134
|
+
'admin::isAuthenticatedAdmin',
|
|
135
|
+
{
|
|
136
|
+
name: 'admin::hasPermissions',
|
|
137
|
+
config: {
|
|
138
|
+
actions: ['admin::review-workflows.read'],
|
|
139
|
+
},
|
|
140
|
+
},
|
|
141
|
+
],
|
|
142
|
+
},
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
method: 'GET',
|
|
146
|
+
path: '/review-workflows/workflows/:id',
|
|
147
|
+
handler: 'workflows.findById',
|
|
148
|
+
config: {
|
|
149
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
150
|
+
policies: [
|
|
151
|
+
'admin::isAuthenticatedAdmin',
|
|
152
|
+
{
|
|
153
|
+
name: 'admin::hasPermissions',
|
|
154
|
+
config: {
|
|
155
|
+
actions: ['admin::review-workflows.read'],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
},
|
|
161
|
+
{
|
|
162
|
+
method: 'GET',
|
|
163
|
+
path: '/review-workflows/workflows/:workflow_id/stages',
|
|
164
|
+
handler: 'stages.find',
|
|
165
|
+
config: {
|
|
166
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
167
|
+
policies: [
|
|
168
|
+
'admin::isAuthenticatedAdmin',
|
|
169
|
+
{
|
|
170
|
+
name: 'admin::hasPermissions',
|
|
171
|
+
config: {
|
|
172
|
+
actions: ['admin::review-workflows.read'],
|
|
173
|
+
},
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
{
|
|
179
|
+
method: 'PUT',
|
|
180
|
+
path: '/review-workflows/workflows/:workflow_id/stages',
|
|
181
|
+
handler: 'stages.replace',
|
|
182
|
+
config: {
|
|
183
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
184
|
+
policies: [
|
|
185
|
+
'admin::isAuthenticatedAdmin',
|
|
186
|
+
{
|
|
187
|
+
name: 'admin::hasPermissions',
|
|
188
|
+
config: {
|
|
189
|
+
actions: ['admin::review-workflows.read'],
|
|
190
|
+
},
|
|
191
|
+
},
|
|
192
|
+
],
|
|
193
|
+
},
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
method: 'GET',
|
|
197
|
+
path: '/review-workflows/workflows/:workflow_id/stages/:id',
|
|
198
|
+
handler: 'stages.findById',
|
|
199
|
+
config: {
|
|
200
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
201
|
+
policies: [
|
|
202
|
+
'admin::isAuthenticatedAdmin',
|
|
203
|
+
{
|
|
204
|
+
name: 'admin::hasPermissions',
|
|
205
|
+
config: {
|
|
206
|
+
actions: ['admin::review-workflows.read'],
|
|
207
|
+
},
|
|
208
|
+
},
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
method: 'PUT',
|
|
214
|
+
path: '/content-manager/(collection|single)-types/:model_uid/:id/stage',
|
|
215
|
+
handler: 'stages.updateEntity',
|
|
216
|
+
config: {
|
|
217
|
+
middlewares: [enableFeatureMiddleware('review-workflows')],
|
|
218
|
+
policies: [
|
|
219
|
+
'admin::isAuthenticatedAdmin',
|
|
220
|
+
{
|
|
221
|
+
name: 'admin::hasPermissions',
|
|
222
|
+
config: {
|
|
223
|
+
actions: ['admin::review-workflows.read'],
|
|
224
|
+
},
|
|
225
|
+
},
|
|
226
|
+
],
|
|
227
|
+
},
|
|
228
|
+
},
|
|
125
229
|
];
|
|
@@ -5,4 +5,8 @@ module.exports = {
|
|
|
5
5
|
role: require('./role'),
|
|
6
6
|
user: require('./user'),
|
|
7
7
|
'seat-enforcement': require('./seat-enforcement'),
|
|
8
|
+
workflows: require('./review-workflows/workflows'),
|
|
9
|
+
stages: require('./review-workflows/stages'),
|
|
10
|
+
'review-workflows': require('./review-workflows/review-workflows'),
|
|
11
|
+
'review-workflows-decorator': require('./review-workflows/entity-service-decorator'),
|
|
8
12
|
};
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { isNil, isNull } = require('lodash/fp');
|
|
4
|
+
const { ENTITY_STAGE_ATTRIBUTE } = require('../../constants/workflows');
|
|
5
|
+
const { hasReviewWorkflow, getDefaultWorkflow } = require('../../utils/review-workflows');
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Assigns the entity data to the default workflow stage if no stage is present in the data
|
|
9
|
+
* @param {Object} data
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
const getDataWithStage = async (data) => {
|
|
13
|
+
if (!isNil(ENTITY_STAGE_ATTRIBUTE, data)) {
|
|
14
|
+
const defaultWorkflow = await getDefaultWorkflow({ strapi });
|
|
15
|
+
return { ...data, [ENTITY_STAGE_ATTRIBUTE]: defaultWorkflow.stages[0].id };
|
|
16
|
+
}
|
|
17
|
+
return data;
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Decorates the entity service with RW business logic
|
|
22
|
+
* @param {object} service - entity service
|
|
23
|
+
*/
|
|
24
|
+
const decorator = (service) => ({
|
|
25
|
+
async create(uid, opts = {}) {
|
|
26
|
+
const hasRW = hasReviewWorkflow({ strapi }, uid);
|
|
27
|
+
|
|
28
|
+
if (!hasRW) {
|
|
29
|
+
return service.create.call(this, uid, opts);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const data = await getDataWithStage(opts.data);
|
|
33
|
+
return service.create.call(this, uid, { ...opts, data });
|
|
34
|
+
},
|
|
35
|
+
async update(uid, entityId, opts = {}) {
|
|
36
|
+
const hasRW = hasReviewWorkflow({ strapi }, uid);
|
|
37
|
+
|
|
38
|
+
if (!hasRW) {
|
|
39
|
+
return service.update.call(this, uid, entityId, opts);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Prevents the stage from being set to null
|
|
43
|
+
const data = { ...opts.data };
|
|
44
|
+
if (isNull(data[ENTITY_STAGE_ATTRIBUTE])) {
|
|
45
|
+
delete data[ENTITY_STAGE_ATTRIBUTE];
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
return service.update.call(this, uid, entityId, { ...opts, data });
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
module.exports = () => ({
|
|
53
|
+
decorator,
|
|
54
|
+
});
|