@strapi/admin 4.9.0 → 4.10.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/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/ReviewWorkflowsStage.js +15 -0
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +1 -0
- package/admin/src/content-manager/components/DynamicTable/index.js +43 -49
- package/admin/src/content-manager/components/DynamicZone/components/DynamicComponent.js +2 -0
- package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +1 -3
- package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js +3 -10
- package/admin/src/content-manager/components/InputUID/endActionStyle.js +13 -4
- package/admin/src/content-manager/components/InputUID/index.js +71 -94
- 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/hooks/useRegenerate/index.js +7 -12
- package/admin/src/index.js +1 -0
- package/admin/src/pages/AuthPage/components/Register/index.js +38 -46
- package/admin/src/pages/SettingsPage/components/Tokens/FormHead/index.js +0 -4
- package/admin/src/pages/SettingsPage/components/Tokens/Regenerate/index.js +3 -5
- package/admin/src/pages/SettingsPage/components/Tokens/TokenTypeSelect/index.js +5 -7
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/FormTransferTokenContainer/index.js +0 -41
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +9 -53
- package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +0 -1
- package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +5 -27
- package/admin/src/translations/en.json +6 -1
- package/build/2263.4c5916f9.chunk.js +98 -0
- package/build/4049.64715f20.chunk.js +1 -0
- package/build/4649.213b8a3b.chunk.js +30 -0
- package/build/6985.66cca29c.chunk.js +1 -0
- package/build/7259.aefb51e8.chunk.js +1 -0
- package/build/8469.853c822b.chunk.js +1 -0
- package/build/9505.dbe702ab.chunk.js +14 -0
- package/build/9816.01ee964f.chunk.js +2 -0
- package/build/Admin-authenticatedApp.f50ad423.chunk.js +79 -0
- package/build/Admin_InternalErrorPage.4ad8b0df.chunk.js +1 -0
- package/build/Admin_homePage.1411fb7c.chunk.js +68 -0
- package/build/Admin_marketplace.02608d56.chunk.js +22 -0
- package/build/Admin_pluginsPage.15e3b0fd.chunk.js +1 -0
- package/build/Admin_profilePage.76afeca0.chunk.js +15 -0
- package/build/Admin_settingsPage.147755cd.chunk.js +9 -0
- package/build/Upload_ConfigureTheView.34dde278.chunk.js +1 -0
- package/build/admin-app.55dd7921.chunk.js +112 -0
- package/build/admin-edit-roles-page.cf543488.chunk.js +216 -0
- package/build/admin-edit-users.31c20712.chunk.js +10 -0
- package/build/admin-roles-list.489c501f.chunk.js +2 -0
- package/build/admin-users.3e111a7d.chunk.js +11 -0
- package/build/api-tokens-create-page.4328b852.chunk.js +1 -0
- package/build/api-tokens-edit-page.bce5050f.chunk.js +1 -0
- package/build/api-tokens-list-page.93f24348.chunk.js +16 -0
- package/build/audit-logs-settings-page.7be97e82.chunk.js +1 -0
- package/build/content-manager.4480ae88.chunk.js +1137 -0
- package/build/content-type-builder-list-view.cf38fe2f.chunk.js +191 -0
- package/build/content-type-builder-translation-en-json.7961593e.chunk.js +1 -0
- package/build/content-type-builder.af9abf1e.chunk.js +126 -0
- package/build/email-settings-page.4bdbef9a.chunk.js +3 -0
- package/build/en-json.697b4bcf.chunk.js +1 -0
- package/build/{highlight.js.28a1547e.chunk.js → highlight.js.26ef649f.chunk.js} +2 -2
- package/build/i18n-settings-page.2bb5be96.chunk.js +1 -0
- package/build/index.html +1 -1
- package/build/main.af8c0f31.js +3790 -0
- package/build/review-workflows-settings.7a7dc773.chunk.js +57 -0
- package/build/runtime~main.5a95bee6.js +2 -0
- package/build/sso-settings-page.272b87c8.chunk.js +1 -0
- package/build/transfer-tokens-create-page.a1f14bb1.chunk.js +1 -0
- package/build/transfer-tokens-edit-page.00ee1c74.chunk.js +1 -0
- package/build/transfer-tokens-list-page.ce37354b.chunk.js +16 -0
- package/build/upload-settings.0875e973.chunk.js +1 -0
- package/build/{upload-translation-th-json.98d35574.chunk.js → upload-translation-th-json.3847dae0.chunk.js} +1 -1
- package/build/upload.c7da1611.chunk.js +13 -0
- package/build/users-advanced-settings-page.1d3c14c7.chunk.js +1 -0
- package/build/users-email-settings-page.e8db68c4.chunk.js +1 -0
- package/build/users-providers-settings-page.14cac425.chunk.js +1 -0
- package/build/users-roles-settings-page.2ea4de84.chunk.js +30 -0
- package/build/webhook-edit-page.329141a5.chunk.js +23 -0
- package/build/webhook-list-page.029957a4.chunk.js +1 -0
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +92 -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 +195 -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 +121 -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 +34 -0
- package/ee/server/content-types/workflow-stage/index.js +41 -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 +95 -0
- package/ee/server/index.js +1 -0
- package/ee/server/middlewares/review-workflows.js +40 -0
- package/ee/server/migrations/review-workflows.js +39 -0
- package/ee/server/register.js +9 -3
- package/ee/server/routes/index.js +104 -0
- package/ee/server/services/audit-logs.js +16 -75
- package/ee/server/services/index.js +4 -0
- package/ee/server/services/review-workflows/entity-service-decorator.js +42 -0
- package/ee/server/services/review-workflows/review-workflows.js +175 -0
- package/ee/server/services/review-workflows/stages.js +148 -0
- package/ee/server/services/review-workflows/workflows.js +25 -0
- package/ee/server/utils/index.js +8 -0
- package/ee/server/utils/review-workflows.js +25 -0
- package/ee/server/utils/test.js +11 -0
- package/ee/server/validation/review-workflows.js +24 -0
- package/jest.config.front.js +6 -1
- package/package.json +15 -17
- package/server/controllers/transfer/runner.js +2 -4
- package/server/middlewares/data-transfer.js +1 -4
- package/server/routes/transfer.js +4 -13
- package/server/services/constants.js +0 -4
- package/server/services/transfer/permission.js +1 -1
- package/server/services/transfer/token.js +31 -33
- package/server/validation/transfer/token.js +2 -10
- package/webpack.config.js +1 -1
- package/.eslintignore +0 -4
- package/.eslintrc.js +0 -14
- package/admin/src/components/LocalesProvider/__mocks__/useLocalesProvider.js +0 -7
- package/admin/src/hooks/useConfigurations/__mocks__/index.js +0 -7
- package/build/1387.84b454d3.chunk.js +0 -1
- package/build/1657.45231968.chunk.js +0 -168
- package/build/3081.bcf9a12f.chunk.js +0 -108
- package/build/462.8fff7f3b.chunk.js +0 -71
- package/build/4628.20631dd1.chunk.js +0 -1
- package/build/5542.b8240e3f.chunk.js +0 -70
- package/build/5563.905daa13.chunk.js +0 -79
- package/build/6404.68405699.chunk.js +0 -100
- package/build/7259.b7d00cea.chunk.js +0 -1
- package/build/8694.6522968d.chunk.js +0 -247
- package/build/9347.058ddb22.chunk.js +0 -1
- package/build/Admin-authenticatedApp.31bf88ef.chunk.js +0 -79
- package/build/Admin_InternalErrorPage.15c6bf07.chunk.js +0 -1
- package/build/Admin_homePage.da2181fe.chunk.js +0 -73
- package/build/Admin_marketplace.d99044eb.chunk.js +0 -31
- package/build/Admin_pluginsPage.f6b52ee9.chunk.js +0 -6
- package/build/Admin_profilePage.9112cffc.chunk.js +0 -15
- package/build/Admin_settingsPage.cb63220f.chunk.js +0 -79
- package/build/Upload_ConfigureTheView.eaaec495.chunk.js +0 -1
- package/build/admin-app.8cde5b22.chunk.js +0 -110
- package/build/admin-edit-roles-page.4f1858e9.chunk.js +0 -280
- package/build/admin-edit-users.7e14d85f.chunk.js +0 -10
- package/build/admin-roles-list.97e198f9.chunk.js +0 -31
- package/build/admin-users.d02de059.chunk.js +0 -34
- package/build/api-tokens-create-page.97595e12.chunk.js +0 -1
- package/build/api-tokens-edit-page.cd36e30e.chunk.js +0 -1
- package/build/api-tokens-list-page.6757c7b9.chunk.js +0 -16
- package/build/audit-logs-settings-page.ca9a3c46.chunk.js +0 -76
- package/build/content-manager.de0ee3e5.chunk.js +0 -1132
- package/build/content-type-builder-list-view.9c2c020c.chunk.js +0 -214
- package/build/content-type-builder-translation-en-json.e577d595.chunk.js +0 -1
- package/build/content-type-builder.ec5ac7ab.chunk.js +0 -126
- package/build/email-settings-page.1095e1ab.chunk.js +0 -10
- package/build/en-json.b052667a.chunk.js +0 -1
- package/build/i18n-settings-page.7d80aae0.chunk.js +0 -60
- package/build/main.d40f9ca1.js +0 -2280
- package/build/runtime~main.7cdc9956.js +0 -2
- package/build/sso-settings-page.1dd4886e.chunk.js +0 -1
- package/build/transfer-tokens-create-page.ec2ca215.chunk.js +0 -1
- package/build/transfer-tokens-edit-page.22bf28e5.chunk.js +0 -1
- package/build/transfer-tokens-list-page.cf8c77f2.chunk.js +0 -16
- package/build/upload-settings.945fdcfa.chunk.js +0 -13
- package/build/upload.a86b1054.chunk.js +0 -33
- package/build/users-advanced-settings-page.5b5a9baa.chunk.js +0 -8
- package/build/users-email-settings-page.e5506eb4.chunk.js +0 -23
- package/build/users-providers-settings-page.e32089c2.chunk.js +0 -28
- package/build/users-roles-settings-page.a5c5b0df.chunk.js +0 -30
- package/build/webhook-edit-page.213f0075.chunk.js +0 -75
- package/build/webhook-list-page.5beb2a5c.chunk.js +0 -71
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import {
|
|
3
|
+
ReactSelect,
|
|
4
|
+
useCMEditViewDataManager,
|
|
5
|
+
useAPIErrorHandler,
|
|
6
|
+
useFetchClient,
|
|
7
|
+
} from '@strapi/helper-plugin';
|
|
8
|
+
import { Field, FieldLabel, FieldError, Flex } from '@strapi/design-system';
|
|
9
|
+
import { useIntl } from 'react-intl';
|
|
10
|
+
import { useMutation } from 'react-query';
|
|
11
|
+
|
|
12
|
+
import { useReviewWorkflows } from '../../../../pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows';
|
|
13
|
+
import Information from '../../../../../../admin/src/content-manager/pages/EditView/Information';
|
|
14
|
+
|
|
15
|
+
const ATTRIBUTE_NAME = 'strapi_reviewWorkflows_stage';
|
|
16
|
+
|
|
17
|
+
export function InformationBoxEE() {
|
|
18
|
+
const {
|
|
19
|
+
initialData,
|
|
20
|
+
isCreatingEntry,
|
|
21
|
+
layout: { uid },
|
|
22
|
+
} = useCMEditViewDataManager();
|
|
23
|
+
const { put } = useFetchClient();
|
|
24
|
+
const activeWorkflowStage = initialData?.[ATTRIBUTE_NAME] ?? null;
|
|
25
|
+
const { formatMessage } = useIntl();
|
|
26
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
27
|
+
|
|
28
|
+
const { workflows: { data: [workflow] = [] } = {} } = useReviewWorkflows();
|
|
29
|
+
|
|
30
|
+
const { error, isLoading, mutateAsync } = useMutation(async ({ entityId, stageId, uid }) => {
|
|
31
|
+
const {
|
|
32
|
+
data: { data },
|
|
33
|
+
} = await put(`/admin/content-manager/collection-types/${uid}/${entityId}/stage`, {
|
|
34
|
+
data: { id: stageId },
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
return data;
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// stages are empty while the workflow is loading
|
|
41
|
+
const options = (workflow?.stages ?? []).map(({ id, name }) => ({ value: id, label: name }));
|
|
42
|
+
const formattedError = error ? formatAPIError(error) : null;
|
|
43
|
+
|
|
44
|
+
const handleStageChange = async ({ value: stageId }) => {
|
|
45
|
+
try {
|
|
46
|
+
await mutateAsync({
|
|
47
|
+
entityId: initialData.id,
|
|
48
|
+
stageId,
|
|
49
|
+
uid,
|
|
50
|
+
});
|
|
51
|
+
} catch (error) {
|
|
52
|
+
// react-query@v3: the error doesn't have to be handled here
|
|
53
|
+
// see: https://github.com/TanStack/query/issues/121
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
return (
|
|
58
|
+
<Information.Root>
|
|
59
|
+
<Information.Title />
|
|
60
|
+
|
|
61
|
+
{activeWorkflowStage && (
|
|
62
|
+
<Field error={formattedError} name={ATTRIBUTE_NAME} id={ATTRIBUTE_NAME}>
|
|
63
|
+
<Flex direction="column" gap={2} alignItems="stretch">
|
|
64
|
+
<FieldLabel>
|
|
65
|
+
{formatMessage({
|
|
66
|
+
id: 'content-manager.reviewWorkflows.stage.label',
|
|
67
|
+
defaultMessage: 'Review stage',
|
|
68
|
+
})}
|
|
69
|
+
</FieldLabel>
|
|
70
|
+
|
|
71
|
+
<ReactSelect
|
|
72
|
+
error={formattedError}
|
|
73
|
+
inputId={ATTRIBUTE_NAME}
|
|
74
|
+
isDisabled={isCreatingEntry}
|
|
75
|
+
options={options}
|
|
76
|
+
name={ATTRIBUTE_NAME}
|
|
77
|
+
defaultValue={{ value: activeWorkflowStage?.id, label: activeWorkflowStage?.name }}
|
|
78
|
+
isLoading={isLoading}
|
|
79
|
+
isSearchable={false}
|
|
80
|
+
isClearable={false}
|
|
81
|
+
onChange={handleStageChange}
|
|
82
|
+
/>
|
|
83
|
+
|
|
84
|
+
<FieldError />
|
|
85
|
+
</Flex>
|
|
86
|
+
</Field>
|
|
87
|
+
)}
|
|
88
|
+
|
|
89
|
+
<Information.Body />
|
|
90
|
+
</Information.Root>
|
|
91
|
+
);
|
|
92
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
import adminPermissions from '../../../../../admin/src/permissions';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
? [
|
|
5
|
-
{
|
|
6
|
-
intlLabel: { id: 'global.auditLogs', defaultMessage: 'Audit Logs' },
|
|
7
|
-
to: '/settings/audit-logs?pageSize=50&page=1&sort=date:DESC',
|
|
8
|
-
id: 'auditLogs',
|
|
9
|
-
isDisplayed: false,
|
|
10
|
-
permissions: adminPermissions.settings.auditLogs.main,
|
|
11
|
-
},
|
|
12
|
-
]
|
|
13
|
-
: [];
|
|
3
|
+
const items = [];
|
|
14
4
|
|
|
15
|
-
|
|
5
|
+
if (window.strapi.features.isEnabled(window.strapi.features.AUDIT_LOGS)) {
|
|
6
|
+
items.push({
|
|
7
|
+
intlLabel: { id: 'global.auditLogs', defaultMessage: 'Audit Logs' },
|
|
8
|
+
to: '/settings/audit-logs?pageSize=50&page=1&sort=date:DESC',
|
|
9
|
+
id: 'auditLogs',
|
|
10
|
+
isDisplayed: false,
|
|
11
|
+
permissions: adminPermissions.settings.auditLogs.main,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const customAdminLinks = items;
|
|
16
16
|
|
|
17
17
|
export default customAdminLinks;
|
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
import adminPermissions from '../../../../../admin/src/permissions';
|
|
2
2
|
|
|
3
|
-
const
|
|
4
|
-
? [
|
|
5
|
-
{
|
|
6
|
-
intlLabel: { id: 'Settings.sso.title', defaultMessage: 'Single Sign-On' },
|
|
7
|
-
to: '/settings/single-sign-on',
|
|
8
|
-
id: 'sso',
|
|
9
|
-
isDisplayed: false,
|
|
10
|
-
permissions: adminPermissions.settings.sso.main,
|
|
11
|
-
},
|
|
12
|
-
]
|
|
13
|
-
: [];
|
|
3
|
+
const items = [];
|
|
14
4
|
|
|
15
|
-
|
|
5
|
+
if (window.strapi.features.isEnabled(window.strapi.features.SSO)) {
|
|
6
|
+
items.push({
|
|
7
|
+
intlLabel: { id: 'Settings.sso.title', defaultMessage: 'Single Sign-On' },
|
|
8
|
+
to: '/settings/single-sign-on',
|
|
9
|
+
id: 'sso',
|
|
10
|
+
isDisplayed: false,
|
|
11
|
+
permissions: adminPermissions.settings.sso.main,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
16
14
|
|
|
17
|
-
|
|
15
|
+
if (window.strapi.features.isEnabled(window.strapi.features.REVIEW_WORKFLOWS)) {
|
|
16
|
+
items.push({
|
|
17
|
+
intlLabel: { id: 'Settings.review-workflows.page.title', defaultMessage: 'Review Workflows' },
|
|
18
|
+
to: '/settings/review-workflows',
|
|
19
|
+
id: 'review-workflows',
|
|
20
|
+
isDisplayed: false,
|
|
21
|
+
permissions: adminPermissions.settings['review-workflows'].main,
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default items;
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
import React, { useEffect, useState } from 'react';
|
|
2
|
+
import { FormikProvider, useFormik, Form } from 'formik';
|
|
3
|
+
import { useIntl } from 'react-intl';
|
|
4
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
5
|
+
import { useMutation } from 'react-query';
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
CheckPagePermissions,
|
|
9
|
+
ConfirmDialog,
|
|
10
|
+
SettingsPageTitle,
|
|
11
|
+
useAPIErrorHandler,
|
|
12
|
+
useFetchClient,
|
|
13
|
+
useNotification,
|
|
14
|
+
useTracking,
|
|
15
|
+
} from '@strapi/helper-plugin';
|
|
16
|
+
import { Button, ContentLayout, HeaderLayout, Layout, Loader, Main } from '@strapi/design-system';
|
|
17
|
+
import { Check } from '@strapi/icons';
|
|
18
|
+
|
|
19
|
+
import { Stages } from './components/Stages';
|
|
20
|
+
import { reducer, initialState } from './reducer';
|
|
21
|
+
import { REDUX_NAMESPACE } from './constants';
|
|
22
|
+
import { useInjectReducer } from '../../../../../../admin/src/hooks/useInjectReducer';
|
|
23
|
+
import { useReviewWorkflows } from './hooks/useReviewWorkflows';
|
|
24
|
+
import { setWorkflows } from './actions';
|
|
25
|
+
import { getWorkflowValidationSchema } from './utils/getWorkflowValidationSchema';
|
|
26
|
+
import adminPermissions from '../../../../../../admin/src/permissions';
|
|
27
|
+
|
|
28
|
+
export function ReviewWorkflowsPage() {
|
|
29
|
+
const { trackUsage } = useTracking();
|
|
30
|
+
const { formatMessage } = useIntl();
|
|
31
|
+
const dispatch = useDispatch();
|
|
32
|
+
const { put } = useFetchClient();
|
|
33
|
+
const { formatAPIError } = useAPIErrorHandler();
|
|
34
|
+
const toggleNotification = useNotification();
|
|
35
|
+
const { workflows: workflowsData, refetchWorkflow } = useReviewWorkflows();
|
|
36
|
+
const {
|
|
37
|
+
status,
|
|
38
|
+
clientState: {
|
|
39
|
+
currentWorkflow: {
|
|
40
|
+
data: currentWorkflow,
|
|
41
|
+
isDirty: currentWorkflowIsDirty,
|
|
42
|
+
hasDeletedServerStages: currentWorkflowHasDeletedServerStages,
|
|
43
|
+
},
|
|
44
|
+
},
|
|
45
|
+
} = useSelector((state) => state?.[REDUX_NAMESPACE] ?? initialState);
|
|
46
|
+
const [isConfirmDeleteDialogOpen, setIsConfirmDeleteDialogOpen] = useState(false);
|
|
47
|
+
|
|
48
|
+
const { mutateAsync, isLoading } = useMutation(
|
|
49
|
+
async ({ workflowId, stages }) => {
|
|
50
|
+
try {
|
|
51
|
+
const {
|
|
52
|
+
data: { data },
|
|
53
|
+
} = await put(`/admin/review-workflows/workflows/${workflowId}/stages`, {
|
|
54
|
+
data: stages,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
return data;
|
|
58
|
+
} catch (error) {
|
|
59
|
+
toggleNotification({
|
|
60
|
+
type: 'warning',
|
|
61
|
+
message: formatAPIError(error),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
onError(error) {
|
|
69
|
+
toggleNotification({
|
|
70
|
+
type: 'warning',
|
|
71
|
+
message: formatAPIError(error),
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
|
|
75
|
+
onSuccess() {
|
|
76
|
+
toggleNotification({
|
|
77
|
+
type: 'success',
|
|
78
|
+
message: { id: 'notification.success.saved', defaultMessage: 'Saved' },
|
|
79
|
+
});
|
|
80
|
+
},
|
|
81
|
+
}
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
const updateWorkflowStages = (workflowId, stages) => {
|
|
85
|
+
return mutateAsync({ workflowId, stages });
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const submitForm = async () => {
|
|
89
|
+
setIsConfirmDeleteDialogOpen(false);
|
|
90
|
+
|
|
91
|
+
await updateWorkflowStages(currentWorkflow.id, currentWorkflow.stages);
|
|
92
|
+
refetchWorkflow();
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const handleConfirmDeleteDialog = async () => {
|
|
96
|
+
await submitForm();
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const toggleConfirmDeleteDialog = () => {
|
|
100
|
+
setIsConfirmDeleteDialogOpen((prev) => !prev);
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
const formik = useFormik({
|
|
104
|
+
enableReinitialize: true,
|
|
105
|
+
initialValues: currentWorkflow,
|
|
106
|
+
async onSubmit() {
|
|
107
|
+
if (currentWorkflowHasDeletedServerStages) {
|
|
108
|
+
setIsConfirmDeleteDialogOpen(true);
|
|
109
|
+
} else {
|
|
110
|
+
submitForm();
|
|
111
|
+
}
|
|
112
|
+
},
|
|
113
|
+
validationSchema: getWorkflowValidationSchema({ formatMessage }),
|
|
114
|
+
validateOnChange: false,
|
|
115
|
+
});
|
|
116
|
+
|
|
117
|
+
useInjectReducer(REDUX_NAMESPACE, reducer);
|
|
118
|
+
|
|
119
|
+
useEffect(() => {
|
|
120
|
+
dispatch(setWorkflows({ status: workflowsData.status, data: workflowsData.data }));
|
|
121
|
+
}, [workflowsData.status, workflowsData.data, dispatch]);
|
|
122
|
+
|
|
123
|
+
useEffect(() => {
|
|
124
|
+
trackUsage('didViewWorkflow');
|
|
125
|
+
}, [trackUsage]);
|
|
126
|
+
|
|
127
|
+
return (
|
|
128
|
+
<CheckPagePermissions permissions={adminPermissions.settings['review-workflows'].main}>
|
|
129
|
+
<Layout>
|
|
130
|
+
<SettingsPageTitle
|
|
131
|
+
name={formatMessage({
|
|
132
|
+
id: 'Settings.review-workflows.page.title',
|
|
133
|
+
defaultMessage: 'Review Workflows',
|
|
134
|
+
})}
|
|
135
|
+
/>
|
|
136
|
+
<Main tabIndex={-1}>
|
|
137
|
+
<FormikProvider value={formik}>
|
|
138
|
+
<Form onSubmit={formik.handleSubmit}>
|
|
139
|
+
<HeaderLayout
|
|
140
|
+
primaryAction={
|
|
141
|
+
<Button
|
|
142
|
+
startIcon={<Check />}
|
|
143
|
+
type="submit"
|
|
144
|
+
size="M"
|
|
145
|
+
disabled={!currentWorkflowIsDirty}
|
|
146
|
+
>
|
|
147
|
+
{formatMessage({
|
|
148
|
+
id: 'global.save',
|
|
149
|
+
defaultMessage: 'Save',
|
|
150
|
+
})}
|
|
151
|
+
</Button>
|
|
152
|
+
}
|
|
153
|
+
title={formatMessage({
|
|
154
|
+
id: 'Settings.review-workflows.page.title',
|
|
155
|
+
defaultMessage: 'Review Workflows',
|
|
156
|
+
})}
|
|
157
|
+
subtitle={formatMessage(
|
|
158
|
+
{
|
|
159
|
+
id: 'Settings.review-workflows.page.subtitle',
|
|
160
|
+
defaultMessage: '{count, plural, one {# stage} other {# stages}}',
|
|
161
|
+
},
|
|
162
|
+
{ count: currentWorkflow?.stages?.length ?? 0 }
|
|
163
|
+
)}
|
|
164
|
+
/>
|
|
165
|
+
<ContentLayout>
|
|
166
|
+
{status === 'loading' && (
|
|
167
|
+
<Loader>
|
|
168
|
+
{formatMessage({
|
|
169
|
+
id: 'Settings.review-workflows.page.isLoading',
|
|
170
|
+
defaultMessage: 'Workflow is loading',
|
|
171
|
+
})}
|
|
172
|
+
</Loader>
|
|
173
|
+
)}
|
|
174
|
+
|
|
175
|
+
<Stages stages={formik.values?.stages} />
|
|
176
|
+
</ContentLayout>
|
|
177
|
+
</Form>
|
|
178
|
+
</FormikProvider>
|
|
179
|
+
|
|
180
|
+
<ConfirmDialog
|
|
181
|
+
bodyText={{
|
|
182
|
+
id: 'Settings.review-workflows.page.delete.confirm.body',
|
|
183
|
+
defaultMessage:
|
|
184
|
+
'All entries assigned to deleted stages will be moved to the first stage. Are you sure you want to save this?',
|
|
185
|
+
}}
|
|
186
|
+
isConfirmButtonLoading={isLoading}
|
|
187
|
+
isOpen={isConfirmDeleteDialogOpen}
|
|
188
|
+
onToggleDialog={toggleConfirmDeleteDialog}
|
|
189
|
+
onConfirm={handleConfirmDeleteDialog}
|
|
190
|
+
/>
|
|
191
|
+
</Main>
|
|
192
|
+
</Layout>
|
|
193
|
+
</CheckPagePermissions>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import {
|
|
2
|
+
ACTION_SET_WORKFLOWS,
|
|
3
|
+
ACTION_DELETE_STAGE,
|
|
4
|
+
ACTION_ADD_STAGE,
|
|
5
|
+
ACTION_UPDATE_STAGE,
|
|
6
|
+
} from '../constants';
|
|
7
|
+
|
|
8
|
+
export function setWorkflows({ status, data }) {
|
|
9
|
+
return {
|
|
10
|
+
type: ACTION_SET_WORKFLOWS,
|
|
11
|
+
payload: {
|
|
12
|
+
status,
|
|
13
|
+
workflows: data,
|
|
14
|
+
},
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function deleteStage(stageId) {
|
|
19
|
+
return {
|
|
20
|
+
type: ACTION_DELETE_STAGE,
|
|
21
|
+
payload: {
|
|
22
|
+
stageId,
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function addStage(stage = {}) {
|
|
28
|
+
return {
|
|
29
|
+
type: ACTION_ADD_STAGE,
|
|
30
|
+
payload: stage,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export function updateStage(stageId, payload) {
|
|
35
|
+
return {
|
|
36
|
+
type: ACTION_UPDATE_STAGE,
|
|
37
|
+
payload: {
|
|
38
|
+
stageId,
|
|
39
|
+
...payload,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
|
|
5
|
+
import { Box, Flex, Typography } from '@strapi/design-system';
|
|
6
|
+
import { PlusCircle } from '@strapi/icons';
|
|
7
|
+
|
|
8
|
+
const StyledAddIcon = styled(PlusCircle)`
|
|
9
|
+
> circle {
|
|
10
|
+
fill: ${({ theme }) => theme.colors.neutral150};
|
|
11
|
+
}
|
|
12
|
+
> path {
|
|
13
|
+
fill: ${({ theme }) => theme.colors.neutral600};
|
|
14
|
+
}
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const StyledButton = styled(Box)`
|
|
18
|
+
border-radius: 26px;
|
|
19
|
+
|
|
20
|
+
svg {
|
|
21
|
+
height: ${({ theme }) => theme.spaces[6]};
|
|
22
|
+
width: ${({ theme }) => theme.spaces[6]};
|
|
23
|
+
|
|
24
|
+
> path {
|
|
25
|
+
fill: ${({ theme }) => theme.colors.neutral600};
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
&:hover {
|
|
30
|
+
color: ${({ theme }) => theme.colors.primary600} !important;
|
|
31
|
+
${Typography} {
|
|
32
|
+
color: ${({ theme }) => theme.colors.primary600} !important;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
${StyledAddIcon} {
|
|
36
|
+
> circle {
|
|
37
|
+
fill: ${({ theme }) => theme.colors.primary600};
|
|
38
|
+
}
|
|
39
|
+
> path {
|
|
40
|
+
fill: ${({ theme }) => theme.colors.neutral100};
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
&:active {
|
|
46
|
+
${Typography} {
|
|
47
|
+
color: ${({ theme }) => theme.colors.primary600};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
${StyledAddIcon} {
|
|
51
|
+
> circle {
|
|
52
|
+
fill: ${({ theme }) => theme.colors.primary600};
|
|
53
|
+
}
|
|
54
|
+
> path {
|
|
55
|
+
fill: ${({ theme }) => theme.colors.neutral100};
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
`;
|
|
60
|
+
|
|
61
|
+
export function AddStage({ children, ...props }) {
|
|
62
|
+
return (
|
|
63
|
+
<StyledButton
|
|
64
|
+
as="button"
|
|
65
|
+
background="neutral0"
|
|
66
|
+
border="neutral150"
|
|
67
|
+
paddingBottom={3}
|
|
68
|
+
paddingLeft={4}
|
|
69
|
+
paddingRight={4}
|
|
70
|
+
paddingTop={3}
|
|
71
|
+
shadow="filterShadow"
|
|
72
|
+
{...props}
|
|
73
|
+
>
|
|
74
|
+
<Flex gap={2}>
|
|
75
|
+
<StyledAddIcon aria-hidden />
|
|
76
|
+
|
|
77
|
+
<Typography variant="pi" fontWeight="bold" textColor="neutral500">
|
|
78
|
+
{children}
|
|
79
|
+
</Typography>
|
|
80
|
+
</Flex>
|
|
81
|
+
</StyledButton>
|
|
82
|
+
);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
AddStage.propTypes = {
|
|
86
|
+
children: PropTypes.node.isRequired,
|
|
87
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './AddStage';
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import React, { useState } from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import { useField } from 'formik';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import { useDispatch } from 'react-redux';
|
|
6
|
+
import {
|
|
7
|
+
Accordion,
|
|
8
|
+
AccordionToggle,
|
|
9
|
+
AccordionContent,
|
|
10
|
+
Grid,
|
|
11
|
+
GridItem,
|
|
12
|
+
IconButton,
|
|
13
|
+
TextInput,
|
|
14
|
+
} from '@strapi/design-system';
|
|
15
|
+
import { useTracking } from '@strapi/helper-plugin';
|
|
16
|
+
import { Trash } from '@strapi/icons';
|
|
17
|
+
|
|
18
|
+
import { deleteStage, updateStage } from '../../../actions';
|
|
19
|
+
|
|
20
|
+
function Stage({ id, name, index, canDelete, isOpen: isOpenDefault = false }) {
|
|
21
|
+
const { formatMessage } = useIntl();
|
|
22
|
+
const { trackUsage } = useTracking();
|
|
23
|
+
const [isOpen, setIsOpen] = useState(isOpenDefault);
|
|
24
|
+
const fieldIdentifier = `stages.${index}.name`;
|
|
25
|
+
const [field, meta] = useField(fieldIdentifier);
|
|
26
|
+
const dispatch = useDispatch();
|
|
27
|
+
|
|
28
|
+
return (
|
|
29
|
+
<Accordion
|
|
30
|
+
size="S"
|
|
31
|
+
variant="primary"
|
|
32
|
+
onToggle={() => {
|
|
33
|
+
setIsOpen(!isOpen);
|
|
34
|
+
|
|
35
|
+
if (!isOpen) {
|
|
36
|
+
trackUsage('willEditStage');
|
|
37
|
+
}
|
|
38
|
+
}}
|
|
39
|
+
expanded={isOpen}
|
|
40
|
+
shadow="tableShadow"
|
|
41
|
+
>
|
|
42
|
+
<AccordionToggle
|
|
43
|
+
title={name}
|
|
44
|
+
togglePosition="left"
|
|
45
|
+
action={
|
|
46
|
+
canDelete ? (
|
|
47
|
+
<IconButton
|
|
48
|
+
backgroundColor="transparent"
|
|
49
|
+
noBorder
|
|
50
|
+
onClick={() => dispatch(deleteStage(id))}
|
|
51
|
+
label={formatMessage({
|
|
52
|
+
id: 'Settings.review-workflows.stage.delete',
|
|
53
|
+
defaultMessage: 'Delete stage',
|
|
54
|
+
})}
|
|
55
|
+
icon={<Trash />}
|
|
56
|
+
/>
|
|
57
|
+
) : null
|
|
58
|
+
}
|
|
59
|
+
/>
|
|
60
|
+
<AccordionContent padding={6} background="neutral0">
|
|
61
|
+
<Grid gap={4}>
|
|
62
|
+
<GridItem col={6}>
|
|
63
|
+
<TextInput
|
|
64
|
+
{...field}
|
|
65
|
+
id={fieldIdentifier}
|
|
66
|
+
value={name}
|
|
67
|
+
label={formatMessage({
|
|
68
|
+
id: 'Settings.review-workflows.stage.name.label',
|
|
69
|
+
defaultMessage: 'Stage name',
|
|
70
|
+
})}
|
|
71
|
+
error={meta.error ?? false}
|
|
72
|
+
onChange={(event) => {
|
|
73
|
+
field.onChange(event);
|
|
74
|
+
dispatch(updateStage(id, { name: event.target.value }));
|
|
75
|
+
}}
|
|
76
|
+
/>
|
|
77
|
+
</GridItem>
|
|
78
|
+
</Grid>
|
|
79
|
+
</AccordionContent>
|
|
80
|
+
</Accordion>
|
|
81
|
+
);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export { Stage };
|
|
85
|
+
|
|
86
|
+
Stage.propTypes = PropTypes.shape({
|
|
87
|
+
id: PropTypes.number.isRequired,
|
|
88
|
+
name: PropTypes.string.isRequired,
|
|
89
|
+
canDelete: PropTypes.bool.isRequired,
|
|
90
|
+
}).isRequired;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Stage';
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import PropTypes from 'prop-types';
|
|
3
|
+
import styled from 'styled-components';
|
|
4
|
+
import { useIntl } from 'react-intl';
|
|
5
|
+
import { useDispatch } from 'react-redux';
|
|
6
|
+
import { Box, Flex } from '@strapi/design-system';
|
|
7
|
+
import { useTracking } from '@strapi/helper-plugin';
|
|
8
|
+
|
|
9
|
+
import { addStage } from '../../actions';
|
|
10
|
+
import { AddStage } from '../AddStage';
|
|
11
|
+
import { Stage } from './Stage';
|
|
12
|
+
|
|
13
|
+
const StagesContainer = styled(Box)`
|
|
14
|
+
position: relative;
|
|
15
|
+
`;
|
|
16
|
+
|
|
17
|
+
const Background = styled(Box)`
|
|
18
|
+
left: 50%;
|
|
19
|
+
position: absolute;
|
|
20
|
+
top: 0;
|
|
21
|
+
transform: translateX(-50%);
|
|
22
|
+
`;
|
|
23
|
+
|
|
24
|
+
function Stages({ stages }) {
|
|
25
|
+
const { formatMessage } = useIntl();
|
|
26
|
+
const dispatch = useDispatch();
|
|
27
|
+
const { trackUsage } = useTracking();
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<Flex direction="column" gap={6} width="100%">
|
|
31
|
+
<StagesContainer spacing={4} width="100%">
|
|
32
|
+
<Background background="neutral200" height="100%" width={2} zIndex={1} />
|
|
33
|
+
|
|
34
|
+
<Flex
|
|
35
|
+
direction="column"
|
|
36
|
+
alignItems="stretch"
|
|
37
|
+
gap={6}
|
|
38
|
+
zIndex={2}
|
|
39
|
+
position="relative"
|
|
40
|
+
as="ol"
|
|
41
|
+
>
|
|
42
|
+
{stages.map((stage, index) => {
|
|
43
|
+
const id = stage?.id ?? stage.__temp_key__;
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<Box key={`stage-${id}`} as="li">
|
|
47
|
+
<Stage
|
|
48
|
+
{...stage}
|
|
49
|
+
id={id}
|
|
50
|
+
index={index}
|
|
51
|
+
canDelete={stages.length > 1}
|
|
52
|
+
isOpen={!stage.id}
|
|
53
|
+
/>
|
|
54
|
+
</Box>
|
|
55
|
+
);
|
|
56
|
+
})}
|
|
57
|
+
</Flex>
|
|
58
|
+
</StagesContainer>
|
|
59
|
+
|
|
60
|
+
<Flex direction="column" gap={6}>
|
|
61
|
+
<AddStage
|
|
62
|
+
type="button"
|
|
63
|
+
onClick={() => {
|
|
64
|
+
dispatch(addStage({ name: '' }));
|
|
65
|
+
trackUsage('willCreateStage');
|
|
66
|
+
}}
|
|
67
|
+
>
|
|
68
|
+
{formatMessage({
|
|
69
|
+
id: 'Settings.review-workflows.stage.add',
|
|
70
|
+
defaultMessage: 'Add new stage',
|
|
71
|
+
})}
|
|
72
|
+
</AddStage>
|
|
73
|
+
</Flex>
|
|
74
|
+
</Flex>
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export { Stages };
|
|
79
|
+
|
|
80
|
+
Stages.defaultProps = {
|
|
81
|
+
stages: [],
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
Stages.propTypes = {
|
|
85
|
+
stages: PropTypes.arrayOf(
|
|
86
|
+
PropTypes.shape({
|
|
87
|
+
id: PropTypes.number,
|
|
88
|
+
__temp_key__: PropTypes.number,
|
|
89
|
+
name: PropTypes.string.isRequired,
|
|
90
|
+
})
|
|
91
|
+
),
|
|
92
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Stages';
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export const REDUX_NAMESPACE = 'settings_review-workflows';
|
|
2
|
+
|
|
3
|
+
export const ACTION_SET_WORKFLOWS = `Settings/Review_Workflows/SET_WORKFLOWS`;
|
|
4
|
+
export const ACTION_DELETE_STAGE = `Settings/Review_Workflows/WORKFLOW_DELETE_STAGE`;
|
|
5
|
+
export const ACTION_ADD_STAGE = `Settings/Review_Workflows/WORKFLOW_ADD_STAGE`;
|
|
6
|
+
export const ACTION_UPDATE_STAGE = `Settings/Review_Workflows/WORKFLOW_UPDATE_STAGE`;
|