@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
|
@@ -141,8 +141,8 @@ export function Stage({
|
|
|
141
141
|
const { trackUsage } = useTracking();
|
|
142
142
|
const dispatch = useDispatch();
|
|
143
143
|
const [isOpen, setIsOpen] = React.useState(isOpenDefault);
|
|
144
|
-
const [nameField, nameMeta] = useField(`stages.${index}.name`);
|
|
145
|
-
const [colorField, colorMeta] = useField(`stages.${index}.color`);
|
|
144
|
+
const [nameField, nameMeta, nameHelper] = useField(`stages.${index}.name`);
|
|
145
|
+
const [colorField, colorMeta, colorHelper] = useField(`stages.${index}.color`);
|
|
146
146
|
const [{ handlerId, isDragging, handleKeyDown }, stageRef, dropRef, dragRef, dragPreviewRef] =
|
|
147
147
|
useDragAndDrop(canReorder, {
|
|
148
148
|
index,
|
|
@@ -246,7 +246,7 @@ export function Stage({
|
|
|
246
246
|
})}
|
|
247
247
|
error={nameMeta.error ?? false}
|
|
248
248
|
onChange={(event) => {
|
|
249
|
-
|
|
249
|
+
nameHelper.setValue(event.target.value);
|
|
250
250
|
dispatch(updateStage(id, { name: event.target.value }));
|
|
251
251
|
}}
|
|
252
252
|
required
|
|
@@ -263,7 +263,7 @@ export function Stage({
|
|
|
263
263
|
defaultMessage: 'Color',
|
|
264
264
|
})}
|
|
265
265
|
onChange={(value) => {
|
|
266
|
-
|
|
266
|
+
colorHelper.setValue(value);
|
|
267
267
|
dispatch(updateStage(id, { color: value }));
|
|
268
268
|
}}
|
|
269
269
|
value={colorField.value.toUpperCase()}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Grid, GridItem, MultiSelectNested, TextInput } from '@strapi/design-system';
|
|
4
|
+
import { useCollator } from '@strapi/helper-plugin';
|
|
5
|
+
import { useField } from 'formik';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
import { useIntl } from 'react-intl';
|
|
8
|
+
import { useDispatch } from 'react-redux';
|
|
9
|
+
|
|
10
|
+
import { updateWorkflow } from '../../actions';
|
|
11
|
+
|
|
12
|
+
export function WorkflowAttributes({ contentTypes: { collectionTypes, singleTypes } }) {
|
|
13
|
+
const { formatMessage, locale } = useIntl();
|
|
14
|
+
const dispatch = useDispatch();
|
|
15
|
+
const [nameField, nameMeta, nameHelper] = useField('name');
|
|
16
|
+
const [contentTypesField, contentTypesMeta, contentTypesHelper] = useField('contentTypes');
|
|
17
|
+
const formatter = useCollator(locale, {
|
|
18
|
+
sensitivity: 'base',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
return (
|
|
22
|
+
<Grid background="neutral0" hasRadius gap={4} padding={6} shadow="tableShadow">
|
|
23
|
+
<GridItem col={6}>
|
|
24
|
+
<TextInput
|
|
25
|
+
{...nameField}
|
|
26
|
+
id={nameField.name}
|
|
27
|
+
label={formatMessage({
|
|
28
|
+
id: 'Settings.review-workflows.workflow.name.label',
|
|
29
|
+
defaultMessage: 'Workflow Name',
|
|
30
|
+
})}
|
|
31
|
+
error={nameMeta.error ?? false}
|
|
32
|
+
onChange={(event) => {
|
|
33
|
+
dispatch(updateWorkflow({ name: event.target.value }));
|
|
34
|
+
nameHelper.setValue(event.target.value);
|
|
35
|
+
}}
|
|
36
|
+
required
|
|
37
|
+
/>
|
|
38
|
+
</GridItem>
|
|
39
|
+
|
|
40
|
+
<GridItem col={6}>
|
|
41
|
+
<MultiSelectNested
|
|
42
|
+
{...contentTypesField}
|
|
43
|
+
customizeContent={(value) =>
|
|
44
|
+
formatMessage(
|
|
45
|
+
{
|
|
46
|
+
id: 'Settings.review-workflows.workflow.contentTypes.displayValue',
|
|
47
|
+
defaultMessage:
|
|
48
|
+
'{count} {count, plural, one {content type} other {content types}} selected',
|
|
49
|
+
},
|
|
50
|
+
{ count: value.length }
|
|
51
|
+
)
|
|
52
|
+
}
|
|
53
|
+
error={contentTypesMeta.error ?? false}
|
|
54
|
+
id={contentTypesField.name}
|
|
55
|
+
label={formatMessage({
|
|
56
|
+
id: 'Settings.review-workflows.workflow.contentTypes.label',
|
|
57
|
+
defaultMessage: 'Associated to',
|
|
58
|
+
})}
|
|
59
|
+
onChange={(values) => {
|
|
60
|
+
dispatch(updateWorkflow({ contentTypes: values }));
|
|
61
|
+
contentTypesHelper.setValue(values);
|
|
62
|
+
}}
|
|
63
|
+
options={[
|
|
64
|
+
{
|
|
65
|
+
label: formatMessage({
|
|
66
|
+
id: 'Settings.review-workflows.workflow.contentTypes.collectionTypes.label',
|
|
67
|
+
defaultMessage: 'Collection Types',
|
|
68
|
+
}),
|
|
69
|
+
children: collectionTypes
|
|
70
|
+
.sort((a, b) => formatter.compare(a.info.displayName, b.info.displayName))
|
|
71
|
+
.map((contentType) => ({
|
|
72
|
+
label: contentType.info.displayName,
|
|
73
|
+
value: contentType.uid,
|
|
74
|
+
})),
|
|
75
|
+
},
|
|
76
|
+
|
|
77
|
+
{
|
|
78
|
+
label: formatMessage({
|
|
79
|
+
id: 'Settings.review-workflows.workflow.contentTypes.singleTypes.label',
|
|
80
|
+
defaultMessage: 'Single Types',
|
|
81
|
+
}),
|
|
82
|
+
children: singleTypes.map((contentType) => ({
|
|
83
|
+
label: contentType.info.displayName,
|
|
84
|
+
value: contentType.uid,
|
|
85
|
+
})),
|
|
86
|
+
},
|
|
87
|
+
]}
|
|
88
|
+
placeholder={formatMessage({
|
|
89
|
+
id: 'Settings.review-workflows.workflow.contentTypes.placeholder',
|
|
90
|
+
defaultMessage: 'Select',
|
|
91
|
+
})}
|
|
92
|
+
/>
|
|
93
|
+
</GridItem>
|
|
94
|
+
</Grid>
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const ContentTypeType = PropTypes.shape({
|
|
99
|
+
uid: PropTypes.string.isRequired,
|
|
100
|
+
info: PropTypes.shape({
|
|
101
|
+
displayName: PropTypes.string.isRequired,
|
|
102
|
+
}).isRequired,
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
WorkflowAttributes.propTypes = {
|
|
106
|
+
contentTypes: PropTypes.shape({
|
|
107
|
+
collectionTypes: PropTypes.arrayOf(ContentTypeType).isRequired,
|
|
108
|
+
singleTypes: PropTypes.arrayOf(ContentTypeType).isRequired,
|
|
109
|
+
}).isRequired,
|
|
110
|
+
};
|
package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './WorkflowAttributes';
|
|
@@ -2,11 +2,13 @@ import { lightTheme } from '@strapi/design-system';
|
|
|
2
2
|
|
|
3
3
|
export const REDUX_NAMESPACE = 'settings_review-workflows';
|
|
4
4
|
|
|
5
|
-
export const
|
|
5
|
+
export const ACTION_RESET_WORKFLOW = `Settings/Review_Workflows/RESET_WORKFLOW`;
|
|
6
|
+
export const ACTION_SET_WORKFLOW = `Settings/Review_Workflows/SET_WORKFLOW`;
|
|
6
7
|
export const ACTION_DELETE_STAGE = `Settings/Review_Workflows/WORKFLOW_DELETE_STAGE`;
|
|
7
8
|
export const ACTION_ADD_STAGE = `Settings/Review_Workflows/WORKFLOW_ADD_STAGE`;
|
|
8
9
|
export const ACTION_UPDATE_STAGE = `Settings/Review_Workflows/WORKFLOW_UPDATE_STAGE`;
|
|
9
10
|
export const ACTION_UPDATE_STAGE_POSITION = `Settings/Review_Workflows/WORKFLOW_UPDATE_STAGE_POSITION`;
|
|
11
|
+
export const ACTION_UPDATE_WORKFLOW = `Settings/Review_Workflows/WORKFLOW_UPDATE`;
|
|
10
12
|
|
|
11
13
|
export const STAGE_COLORS = {
|
|
12
14
|
primary600: 'Blue',
|
|
@@ -1,43 +1,37 @@
|
|
|
1
1
|
import { useFetchClient } from '@strapi/helper-plugin';
|
|
2
|
-
import { stringify } from 'qs';
|
|
3
2
|
import { useQuery } from 'react-query';
|
|
4
3
|
|
|
5
4
|
export function useReviewWorkflows(params = {}) {
|
|
5
|
+
const { get } = useFetchClient();
|
|
6
|
+
|
|
6
7
|
const { id = '', ...queryParams } = params;
|
|
7
8
|
const defaultQueryParams = {
|
|
8
9
|
populate: 'stages',
|
|
9
10
|
};
|
|
10
11
|
|
|
11
|
-
const { get } = useFetchClient();
|
|
12
|
-
const queryString = stringify({ ...defaultQueryParams, ...queryParams }, { encode: false });
|
|
13
|
-
|
|
14
12
|
const { data, isLoading, status, refetch } = useQuery(
|
|
15
13
|
['review-workflows', 'workflows', id],
|
|
16
14
|
async () => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
} = await get(
|
|
21
|
-
`/admin/review-workflows/workflows/${id}${queryString ? `?${queryString}` : ''}`
|
|
22
|
-
);
|
|
15
|
+
const res = await get(`/admin/review-workflows/workflows/${id}`, {
|
|
16
|
+
params: { ...defaultQueryParams, ...queryParams },
|
|
17
|
+
});
|
|
23
18
|
|
|
24
|
-
|
|
25
|
-
} catch (err) {
|
|
26
|
-
// silence
|
|
27
|
-
return null;
|
|
28
|
-
}
|
|
19
|
+
return res.data;
|
|
29
20
|
}
|
|
30
21
|
);
|
|
31
22
|
|
|
32
23
|
let workflows = [];
|
|
33
24
|
|
|
34
|
-
if (id && data) {
|
|
35
|
-
workflows = [data];
|
|
36
|
-
} else if (Array.isArray(data)) {
|
|
37
|
-
workflows = data;
|
|
25
|
+
if (id && data?.data) {
|
|
26
|
+
workflows = [data.data];
|
|
27
|
+
} else if (Array.isArray(data?.data)) {
|
|
28
|
+
workflows = data.data;
|
|
38
29
|
}
|
|
39
30
|
|
|
40
31
|
return {
|
|
32
|
+
// meta contains e.g. the total of all workflows. we can not use
|
|
33
|
+
// the pagination object here, because the list is not paginated.
|
|
34
|
+
meta: data?.meta ?? {},
|
|
41
35
|
workflows,
|
|
42
36
|
isLoading,
|
|
43
37
|
status,
|
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Button, Flex, Loader } from '@strapi/design-system';
|
|
4
|
+
import { useAPIErrorHandler, useFetchClient, useNotification } from '@strapi/helper-plugin';
|
|
5
|
+
import { Check } from '@strapi/icons';
|
|
6
|
+
import { useFormik, Form, FormikProvider } from 'formik';
|
|
7
|
+
import { useIntl } from 'react-intl';
|
|
8
|
+
import { useMutation } from 'react-query';
|
|
9
|
+
import { useDispatch, useSelector } from 'react-redux';
|
|
10
|
+
import { useHistory } from 'react-router-dom';
|
|
11
|
+
|
|
12
|
+
import { useContentTypes } from '../../../../../../../../admin/src/hooks/useContentTypes';
|
|
13
|
+
import { useInjectReducer } from '../../../../../../../../admin/src/hooks/useInjectReducer';
|
|
14
|
+
import { useLicenseLimits } from '../../../../../../hooks';
|
|
15
|
+
import { resetWorkflow } from '../../actions';
|
|
16
|
+
import * as Layout from '../../components/Layout';
|
|
17
|
+
import * as LimitsModal from '../../components/LimitsModal';
|
|
18
|
+
import { Stages } from '../../components/Stages';
|
|
19
|
+
import { WorkflowAttributes } from '../../components/WorkflowAttributes';
|
|
20
|
+
import { REDUX_NAMESPACE } from '../../constants';
|
|
21
|
+
import { useReviewWorkflows } from '../../hooks/useReviewWorkflows';
|
|
22
|
+
import { reducer, initialState } from '../../reducer';
|
|
23
|
+
import { getWorkflowValidationSchema } from '../../utils/getWorkflowValidationSchema';
|
|
24
|
+
|
|
25
|
+
export function ReviewWorkflowsCreateView() {
|
|
26
|
+
const { formatMessage } = useIntl();
|
|
27
|
+
const { post } = useFetchClient();
|
|
28
|
+
const { push } = useHistory();
|
|
29
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
30
|
+
const dispatch = useDispatch();
|
|
31
|
+
const toggleNotification = useNotification();
|
|
32
|
+
const { collectionTypes, singleTypes, isLoading: isLoadingModels } = useContentTypes();
|
|
33
|
+
const {
|
|
34
|
+
clientState: {
|
|
35
|
+
currentWorkflow: { data: currentWorkflow, isDirty: currentWorkflowIsDirty },
|
|
36
|
+
},
|
|
37
|
+
} = useSelector((state) => state?.[REDUX_NAMESPACE] ?? initialState);
|
|
38
|
+
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
|
39
|
+
const { isLoading: isLicenseLoading, getFeature } = useLicenseLimits();
|
|
40
|
+
const { meta, isLoading: isWorkflowLoading } = useReviewWorkflows();
|
|
41
|
+
|
|
42
|
+
const { mutateAsync, isLoading } = useMutation(
|
|
43
|
+
async ({ workflow }) => {
|
|
44
|
+
const {
|
|
45
|
+
data: { data },
|
|
46
|
+
} = await post(`/admin/review-workflows/workflows`, {
|
|
47
|
+
data: workflow,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
return data;
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
onSuccess() {
|
|
54
|
+
toggleNotification({
|
|
55
|
+
type: 'success',
|
|
56
|
+
message: {
|
|
57
|
+
id: 'Settings.review-workflows.create.page.notification.success',
|
|
58
|
+
defaultMessage: 'Workflow successfully created',
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
|
|
65
|
+
const submitForm = async () => {
|
|
66
|
+
try {
|
|
67
|
+
const workflow = await mutateAsync({ workflow: currentWorkflow });
|
|
68
|
+
|
|
69
|
+
push(`/settings/review-workflows/${workflow.id}`);
|
|
70
|
+
|
|
71
|
+
return workflow;
|
|
72
|
+
} catch (error) {
|
|
73
|
+
toggleNotification({
|
|
74
|
+
type: 'warning',
|
|
75
|
+
message: formatAPIError(error),
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
|
|
82
|
+
const limits = getFeature('review-workflows');
|
|
83
|
+
|
|
84
|
+
const formik = useFormik({
|
|
85
|
+
enableReinitialize: true,
|
|
86
|
+
initialValues: currentWorkflow,
|
|
87
|
+
async onSubmit() {
|
|
88
|
+
/**
|
|
89
|
+
* If the current license has a limit, check if the total count of workflows
|
|
90
|
+
* exceeds that limit and display the limits modal instead of sending the
|
|
91
|
+
* update, because it would throw an API error.
|
|
92
|
+
*/
|
|
93
|
+
|
|
94
|
+
if (limits?.workflows && meta?.workflowCount >= limits.workflows) {
|
|
95
|
+
setShowLimitModal('workflow');
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* If the current license has a limit, check if the total count of stages
|
|
99
|
+
* exceeds that limit and display the limits modal instead of sending the
|
|
100
|
+
* update, because it would throw an API error.
|
|
101
|
+
*/
|
|
102
|
+
} else if (
|
|
103
|
+
limits?.stagesPerWorkflow &&
|
|
104
|
+
currentWorkflow.stages.length >= limits.stagesPerWorkflow
|
|
105
|
+
) {
|
|
106
|
+
setShowLimitModal('stage');
|
|
107
|
+
} else {
|
|
108
|
+
submitForm();
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
validationSchema: getWorkflowValidationSchema({ formatMessage }),
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
useInjectReducer(REDUX_NAMESPACE, reducer);
|
|
115
|
+
|
|
116
|
+
React.useEffect(() => {
|
|
117
|
+
dispatch(resetWorkflow());
|
|
118
|
+
}, [dispatch]);
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* If the current license has a limit:
|
|
122
|
+
* check if the total count of workflows or stages exceeds that limit and display
|
|
123
|
+
* the limits modal on page load. It can be closed by the user, but the
|
|
124
|
+
* API will throw an error in case they try to create a new workflow or update the
|
|
125
|
+
* stages.
|
|
126
|
+
*
|
|
127
|
+
* If the current license does not have a limit (e.g. offline license):
|
|
128
|
+
* do nothing (for now). In case they are trying to create the 201st workflow/ stage
|
|
129
|
+
* the API will throw an error.
|
|
130
|
+
*
|
|
131
|
+
*/
|
|
132
|
+
|
|
133
|
+
React.useEffect(() => {
|
|
134
|
+
if (!isWorkflowLoading && !isLicenseLoading) {
|
|
135
|
+
if (limits.workflows && meta?.workflowsTotal >= limits.workflows) {
|
|
136
|
+
setShowLimitModal('workflow');
|
|
137
|
+
} else if (
|
|
138
|
+
limits.stagesPerWorkflow &&
|
|
139
|
+
currentWorkflow.stages.length >= limits.stagesPerWorkflow
|
|
140
|
+
) {
|
|
141
|
+
setShowLimitModal('stage');
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}, [
|
|
145
|
+
isLicenseLoading,
|
|
146
|
+
isWorkflowLoading,
|
|
147
|
+
limits.stagesPerWorkflow,
|
|
148
|
+
limits?.workflows,
|
|
149
|
+
meta?.workflowsTotal,
|
|
150
|
+
currentWorkflow.stages.length,
|
|
151
|
+
]);
|
|
152
|
+
|
|
153
|
+
return (
|
|
154
|
+
<>
|
|
155
|
+
<Layout.DragLayerRendered />
|
|
156
|
+
|
|
157
|
+
<FormikProvider value={formik}>
|
|
158
|
+
<Form onSubmit={formik.handleSubmit}>
|
|
159
|
+
<Layout.Header
|
|
160
|
+
navigationAction={<Layout.Back href="/settings/review-workflows" />}
|
|
161
|
+
primaryAction={
|
|
162
|
+
<Button
|
|
163
|
+
startIcon={<Check />}
|
|
164
|
+
type="submit"
|
|
165
|
+
size="M"
|
|
166
|
+
disabled={!currentWorkflowIsDirty}
|
|
167
|
+
isLoading={isLoading}
|
|
168
|
+
>
|
|
169
|
+
{formatMessage({
|
|
170
|
+
id: 'global.save',
|
|
171
|
+
defaultMessage: 'Save',
|
|
172
|
+
})}
|
|
173
|
+
</Button>
|
|
174
|
+
}
|
|
175
|
+
title={formatMessage({
|
|
176
|
+
id: 'Settings.review-workflows.create.page.title',
|
|
177
|
+
defaultMessage: 'Create Review Workflow',
|
|
178
|
+
})}
|
|
179
|
+
subtitle={formatMessage(
|
|
180
|
+
{
|
|
181
|
+
id: 'Settings.review-workflows.page.subtitle',
|
|
182
|
+
defaultMessage: '{count, plural, one {# stage} other {# stages}}',
|
|
183
|
+
},
|
|
184
|
+
{ count: currentWorkflow?.stages?.length ?? 0 }
|
|
185
|
+
)}
|
|
186
|
+
/>
|
|
187
|
+
<Layout.Root>
|
|
188
|
+
<Flex alignItems="stretch" direction="column" gap={7}>
|
|
189
|
+
{isLoadingModels ? (
|
|
190
|
+
<Loader>
|
|
191
|
+
{formatMessage({
|
|
192
|
+
id: 'Settings.review-workflows.page.isLoading',
|
|
193
|
+
defaultMessage: 'Workflow is loading',
|
|
194
|
+
})}
|
|
195
|
+
</Loader>
|
|
196
|
+
) : (
|
|
197
|
+
<Flex alignItems="stretch" direction="column" gap={7}>
|
|
198
|
+
<WorkflowAttributes contentTypes={{ collectionTypes, singleTypes }} />
|
|
199
|
+
<Stages stages={formik.values?.stages} />
|
|
200
|
+
</Flex>
|
|
201
|
+
)}
|
|
202
|
+
</Flex>
|
|
203
|
+
</Layout.Root>
|
|
204
|
+
</Form>
|
|
205
|
+
</FormikProvider>
|
|
206
|
+
|
|
207
|
+
<LimitsModal.Root
|
|
208
|
+
isOpen={showLimitModal === 'workflow'}
|
|
209
|
+
onClose={() => setShowLimitModal(false)}
|
|
210
|
+
>
|
|
211
|
+
<LimitsModal.Title>
|
|
212
|
+
{formatMessage({
|
|
213
|
+
id: 'Settings.review-workflows.create.page.workflows.limit.title',
|
|
214
|
+
defaultMessage: 'You’ve reached the limit of workflows in your plan',
|
|
215
|
+
})}
|
|
216
|
+
</LimitsModal.Title>
|
|
217
|
+
|
|
218
|
+
<LimitsModal.Body>
|
|
219
|
+
{formatMessage({
|
|
220
|
+
id: 'Settings.review-workflows.create.page.workflows.limit.body',
|
|
221
|
+
defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.',
|
|
222
|
+
})}
|
|
223
|
+
</LimitsModal.Body>
|
|
224
|
+
</LimitsModal.Root>
|
|
225
|
+
|
|
226
|
+
<LimitsModal.Root
|
|
227
|
+
isOpen={showLimitModal === 'stage'}
|
|
228
|
+
onClose={() => setShowLimitModal(false)}
|
|
229
|
+
>
|
|
230
|
+
<LimitsModal.Title>
|
|
231
|
+
{formatMessage({
|
|
232
|
+
id: 'Settings.review-workflows.create.page.stages.limit.title',
|
|
233
|
+
defaultMessage: 'You have reached the limit of stages for this workflow in your plan',
|
|
234
|
+
})}
|
|
235
|
+
</LimitsModal.Title>
|
|
236
|
+
|
|
237
|
+
<LimitsModal.Body>
|
|
238
|
+
{formatMessage({
|
|
239
|
+
id: 'Settings.review-workflows.create.page.stages.limit.body',
|
|
240
|
+
defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.',
|
|
241
|
+
})}
|
|
242
|
+
</LimitsModal.Body>
|
|
243
|
+
</LimitsModal.Root>
|
|
244
|
+
</>
|
|
245
|
+
);
|
|
246
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
|
|
3
|
+
import { ProtectedPage } from '../../components/ProtectedPage';
|
|
4
|
+
|
|
5
|
+
import { ReviewWorkflowsCreateView } from './CreateView';
|
|
6
|
+
|
|
7
|
+
export default function () {
|
|
8
|
+
return (
|
|
9
|
+
<ProtectedPage>
|
|
10
|
+
<ReviewWorkflowsCreateView />
|
|
11
|
+
</ProtectedPage>
|
|
12
|
+
);
|
|
13
|
+
}
|