@strapi/admin 4.12.0-beta.1 → 4.12.0-beta.4
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/CollectionTypeFormWrapper/index.js +14 -38
- package/admin/src/content-manager/components/RelationInput/components/Option.js +6 -5
- package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +7 -7
- package/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js +23 -21
- package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +21 -23
- package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +24 -22
- package/admin/src/content-manager/pages/ListView/components/Body/index.js +191 -0
- package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/ConfirmBulkActionDialog/index.js +164 -0
- package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +468 -0
- package/admin/src/content-manager/{components/DynamicTable/BulkActionsBar → pages/ListView/components/BulkActionButtons}/index.js +56 -132
- package/admin/src/content-manager/pages/ListView/components/CellContent/RelationMultiple/index.js +63 -69
- package/admin/src/content-manager/pages/ListView/components/CellContent/RepeatableComponent/index.js +28 -21
- package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +7 -3
- package/admin/src/content-manager/pages/ListView/index.js +191 -132
- package/admin/src/layouts/UnauthenticatedLayout/LocaleToggle/index.js +7 -7
- package/admin/src/pages/AuthPage/components/Register/index.js +4 -0
- package/admin/src/translations/ca.json +4 -4
- package/admin/src/translations/de.json +4 -4
- package/admin/src/translations/dk.json +2 -2
- package/admin/src/translations/en.json +23 -4
- package/admin/src/translations/es.json +4 -4
- package/admin/src/translations/eu.json +4 -4
- package/admin/src/translations/fr.json +2 -2
- package/admin/src/translations/gu.json +4 -4
- package/admin/src/translations/hi.json +4 -4
- package/admin/src/translations/hu.json +4 -4
- package/admin/src/translations/ja.json +2 -2
- package/admin/src/translations/ko.json +2 -2
- package/admin/src/translations/ml.json +4 -4
- package/admin/src/translations/nl.json +4 -4
- package/admin/src/translations/pl.json +4 -4
- package/admin/src/translations/pt-BR.json +4 -4
- package/admin/src/translations/ru.json +4 -4
- package/admin/src/translations/sa.json +4 -4
- package/admin/src/translations/sk.json +4 -4
- package/admin/src/translations/sv.json +4 -4
- package/admin/src/translations/tr.json +4 -4
- package/admin/src/translations/zh-Hans.json +4 -4
- package/admin/src/translations/zh.json +4 -4
- package/build/2379.0ca87a89.chunk.js +1 -0
- package/build/2395.df7a044a.chunk.js +26 -0
- package/build/2801.b1140c9b.chunk.js +1 -0
- package/build/{3100.21c343fa.chunk.js → 3100.2ba4df95.chunk.js} +1 -1
- package/build/{3483.e182b190.chunk.js → 3483.e2ee2547.chunk.js} +1 -1
- package/build/{970.89601f27.chunk.js → 3739.63e352f1.chunk.js} +52 -20
- package/build/3984.dda474f7.chunk.js +1 -0
- package/build/502.8ae8ef60.chunk.js +1 -0
- package/build/5483.6dd2e776.chunk.js +6 -0
- package/build/6158.c974fd83.chunk.js +1 -0
- package/build/6691.f880a0b6.chunk.js +105 -0
- package/build/7065.99ca8ab1.chunk.js +112 -0
- package/build/7464.8a6c1e6c.chunk.js +1 -0
- package/build/8276.6c7b8e6e.chunk.js +26 -0
- package/build/{9932.b5a3bb3a.chunk.js → 9806.91360bb6.chunk.js} +47 -47
- package/build/{Admin-authenticatedApp.2ffa318a.chunk.js → Admin-authenticatedApp.24998de8.chunk.js} +2 -2
- package/build/Admin_settingsPage.8c600d1a.chunk.js +111 -0
- package/build/{admin-app.088bcd33.chunk.js → admin-app.c2e4e128.chunk.js} +9 -9
- package/build/{ca-json.1fed5d8b.chunk.js → ca-json.a53c10b6.chunk.js} +1 -1
- package/build/content-manager.8772445b.chunk.js +1103 -0
- package/build/{content-type-builder-translation-ar-json.56d8fcf4.chunk.js → content-type-builder-translation-ar-json.3e808e2f.chunk.js} +1 -1
- package/build/{content-type-builder-translation-cs-json.a5b299ca.chunk.js → content-type-builder-translation-cs-json.1ef9e106.chunk.js} +1 -1
- package/build/{content-type-builder-translation-de-json.393a76c0.chunk.js → content-type-builder-translation-de-json.63fcff7b.chunk.js} +1 -1
- package/build/{content-type-builder-translation-dk-json.fbd39bb7.chunk.js → content-type-builder-translation-dk-json.fd626b67.chunk.js} +1 -1
- package/build/{content-type-builder-translation-en-json.38e20391.chunk.js → content-type-builder-translation-en-json.ed29ff4d.chunk.js} +1 -1
- package/build/{content-type-builder-translation-es-json.9288474b.chunk.js → content-type-builder-translation-es-json.a4a361a9.chunk.js} +1 -1
- package/build/{content-type-builder-translation-fr-json.d35e269c.chunk.js → content-type-builder-translation-fr-json.499c3a46.chunk.js} +1 -1
- package/build/{content-type-builder-translation-id-json.f0513929.chunk.js → content-type-builder-translation-id-json.65255f93.chunk.js} +1 -1
- package/build/{content-type-builder-translation-it-json.aaf16753.chunk.js → content-type-builder-translation-it-json.e268ab74.chunk.js} +1 -1
- package/build/{content-type-builder-translation-ko-json.8fe21a7f.chunk.js → content-type-builder-translation-ko-json.04cb309d.chunk.js} +1 -1
- package/build/{content-type-builder-translation-ms-json.3b5d2d3e.chunk.js → content-type-builder-translation-ms-json.f6b743b9.chunk.js} +1 -1
- package/build/{content-type-builder-translation-nl-json.225ef5d3.chunk.js → content-type-builder-translation-nl-json.997fe8cc.chunk.js} +1 -1
- package/build/{content-type-builder-translation-pl-json.92f36be2.chunk.js → content-type-builder-translation-pl-json.634f638b.chunk.js} +1 -1
- package/build/{content-type-builder-translation-pt-BR-json.3bd10f89.chunk.js → content-type-builder-translation-pt-BR-json.6a95dc71.chunk.js} +1 -1
- package/build/{content-type-builder-translation-ru-json.9bfe47ce.chunk.js → content-type-builder-translation-ru-json.3af65503.chunk.js} +1 -1
- package/build/{content-type-builder-translation-sk-json.d03cc18a.chunk.js → content-type-builder-translation-sk-json.c6078082.chunk.js} +1 -1
- package/build/{content-type-builder-translation-sv-json.d23dcd32.chunk.js → content-type-builder-translation-sv-json.a6df2462.chunk.js} +1 -1
- package/build/{content-type-builder-translation-th-json.7ad256e2.chunk.js → content-type-builder-translation-th-json.122277cc.chunk.js} +1 -1
- package/build/{content-type-builder-translation-tr-json.926f6191.chunk.js → content-type-builder-translation-tr-json.41f44f77.chunk.js} +1 -1
- package/build/{content-type-builder-translation-uk-json.7bf19546.chunk.js → content-type-builder-translation-uk-json.e1315acd.chunk.js} +1 -1
- package/build/{content-type-builder-translation-zh-Hans-json.415577fb.chunk.js → content-type-builder-translation-zh-Hans-json.6ff57db6.chunk.js} +1 -1
- package/build/{content-type-builder-translation-zh-json.958d90e1.chunk.js → content-type-builder-translation-zh-json.3532b962.chunk.js} +1 -1
- package/build/{content-type-builder.3963fb2d.chunk.js → content-type-builder.40534de5.chunk.js} +21 -17
- package/build/{de-json.fcac7381.chunk.js → de-json.b3be02c7.chunk.js} +1 -1
- package/build/{dk-json.e34cad0d.chunk.js → dk-json.842aa391.chunk.js} +1 -1
- package/build/{en-json.fb9f6ddd.chunk.js → en-json.4c733bd1.chunk.js} +1 -1
- package/build/{es-json.42096084.chunk.js → es-json.f57b5335.chunk.js} +1 -1
- package/build/{eu-json.fb17c8f9.chunk.js → eu-json.633025f0.chunk.js} +1 -1
- package/build/{fr-json.69789980.chunk.js → fr-json.aa8839d2.chunk.js} +1 -1
- package/build/{gu-json.4d667d0c.chunk.js → gu-json.5bd62812.chunk.js} +1 -1
- package/build/{hi-json.323be97d.chunk.js → hi-json.9104eb78.chunk.js} +1 -1
- package/build/{hu-json.fe71e6c8.chunk.js → hu-json.9f4aae42.chunk.js} +1 -1
- package/build/index.html +1 -1
- package/build/{ja-json.81b6d1e3.chunk.js → ja-json.91286391.chunk.js} +1 -1
- package/build/{ko-json.4539f4ba.chunk.js → ko-json.fcf3ec4b.chunk.js} +1 -1
- package/build/main.ef5fb1a8.js +2856 -0
- package/build/{ml-json.8988e374.chunk.js → ml-json.557aa14c.chunk.js} +1 -1
- package/build/{nl-json.98345913.chunk.js → nl-json.b2b16eea.chunk.js} +1 -1
- package/build/{pl-json.59a5dab3.chunk.js → pl-json.f094a417.chunk.js} +1 -1
- package/build/{pt-BR-json.9410688b.chunk.js → pt-BR-json.dec7fb01.chunk.js} +1 -1
- package/build/review-workflows-settings-create-view.d4b5dbb8.chunk.js +1 -0
- package/build/review-workflows-settings-edit-view.77299c63.chunk.js +1 -0
- package/build/review-workflows-settings-list-view.3ee9190d.chunk.js +56 -0
- package/build/{ru-json.678cd48b.chunk.js → ru-json.8193d8c4.chunk.js} +1 -1
- package/build/{runtime~main.44bf2a37.js → runtime~main.c99f4c36.js} +2 -2
- package/build/{sa-json.6359a11c.chunk.js → sa-json.a56836f1.chunk.js} +1 -1
- package/build/{sk-json.2374f129.chunk.js → sk-json.bf2f057a.chunk.js} +1 -1
- package/build/sso-settings-page.3a1ed8c9.chunk.js +1 -0
- package/build/{sv-json.ae6e71ea.chunk.js → sv-json.fd0e86c6.chunk.js} +1 -1
- package/build/{tr-json.bac5dbd3.chunk.js → tr-json.56c32cf6.chunk.js} +1 -1
- package/build/upload.cbfeefa5.chunk.js +58 -0
- package/build/{zh-Hans-json.fada6f40.chunk.js → zh-Hans-json.36d81cdc.chunk.js} +1 -1
- package/build/{zh-json.3529f1e5.chunk.js → zh-json.1cc86ff0.chunk.js} +1 -1
- package/ee/admin/constants.js +3 -0
- package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +12 -4
- package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +2 -2
- package/ee/admin/hooks/index.js +1 -1
- package/ee/admin/hooks/useLicenseLimitNotification/index.js +1 -1
- package/ee/admin/hooks/useLicenseLimits/__mocks__/index.js +8 -0
- package/ee/admin/hooks/useLicenseLimits/index.js +1 -3
- package/ee/admin/hooks/useLicenseLimits/useLicenseLimits.js +3 -13
- package/ee/admin/pages/SettingsPage/pages/ApplicationInfosPage/components/AdminSeatInfo/index.js +19 -4
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +7 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stages.js +20 -16
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/WorkflowAttributes.js +38 -23
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/constants.js +3 -0
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +62 -14
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/index.js +8 -3
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +91 -33
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/index.js +8 -3
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +72 -55
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/index.js +8 -3
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +1 -7
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/{getWorkflowValidationSchema.js → validateWorkflow.js} +33 -2
- package/ee/admin/pages/SettingsPage/pages/SingleSignOn/utils/schema.js +8 -5
- package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
- package/ee/server/constants/workflows.js +1 -0
- package/ee/server/services/review-workflows/review-workflows.js +1 -1
- package/ee/server/services/review-workflows/validation.js +12 -4
- package/ee/server/services/review-workflows/workflows/content-types.js +28 -19
- package/ee/server/services/review-workflows/workflows/index.js +14 -2
- package/ee/server/validation/authentication.js +14 -8
- package/ee/server/validation/review-workflows.js +6 -2
- package/package.json +9 -9
- package/build/190.66d89241.chunk.js +0 -117
- package/build/2379.d33a2e16.chunk.js +0 -1
- package/build/2395.b0419a54.chunk.js +0 -26
- package/build/2801.18ac397d.chunk.js +0 -1
- package/build/3984.ea7b8036.chunk.js +0 -1
- package/build/502.ccb38223.chunk.js +0 -1
- package/build/5483.ed2c7efa.chunk.js +0 -6
- package/build/6158.f9d82db9.chunk.js +0 -1
- package/build/6691.e6d5ac38.chunk.js +0 -105
- package/build/7464.c6d0565c.chunk.js +0 -1
- package/build/8276.23e0763b.chunk.js +0 -26
- package/build/Admin_settingsPage.3ad19487.chunk.js +0 -79
- package/build/content-manager.9b569036.chunk.js +0 -1094
- package/build/main.98c989b0.js +0 -2908
- package/build/review-workflows-settings-create-view.60bc516c.chunk.js +0 -1
- package/build/review-workflows-settings-edit-view.898ea409.chunk.js +0 -1
- package/build/review-workflows-settings-list-view.240cacdf.chunk.js +0 -56
- package/build/sso-settings-page.ed6f3f15.chunk.js +0 -1
- package/build/upload.8d01c525.chunk.js +0 -26
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/ProtectedPage.js +0 -21
- package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/index.js +0 -1
- /package/admin/src/content-manager/components/{DynamicTable → ListViewTable}/CellContent/PublicationState/PublicationState.js +0 -0
- /package/admin/src/content-manager/components/{DynamicTable → ListViewTable}/CellContent/PublicationState/index.js +0 -0
|
@@ -23,18 +23,22 @@ import {
|
|
|
23
23
|
useAPIErrorHandler,
|
|
24
24
|
useFetchClient,
|
|
25
25
|
useNotification,
|
|
26
|
+
useRBAC,
|
|
26
27
|
useTracking,
|
|
27
28
|
} from '@strapi/helper-plugin';
|
|
28
29
|
import { Pencil, Plus, Trash } from '@strapi/icons';
|
|
29
30
|
import { useIntl } from 'react-intl';
|
|
30
31
|
import { useMutation } from 'react-query';
|
|
32
|
+
import { useSelector } from 'react-redux';
|
|
31
33
|
import { useHistory } from 'react-router-dom';
|
|
32
34
|
import styled from 'styled-components';
|
|
33
35
|
|
|
34
36
|
import { useContentTypes } from '../../../../../../../../admin/src/hooks/useContentTypes';
|
|
37
|
+
import { selectAdminPermissions } from '../../../../../../../../admin/src/pages/App/selectors';
|
|
35
38
|
import { useLicenseLimits } from '../../../../../../hooks';
|
|
36
39
|
import * as Layout from '../../components/Layout';
|
|
37
40
|
import * as LimitsModal from '../../components/LimitsModal';
|
|
41
|
+
import { CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME } from '../../constants';
|
|
38
42
|
import { useReviewWorkflows } from '../../hooks/useReviewWorkflows';
|
|
39
43
|
|
|
40
44
|
const ActionLink = styled(Link)`
|
|
@@ -76,6 +80,10 @@ export function ReviewWorkflowsListView() {
|
|
|
76
80
|
const toggleNotification = useNotification();
|
|
77
81
|
const { getFeature, isLoading: isLicenseLoading } = useLicenseLimits();
|
|
78
82
|
const { trackUsage } = useTracking();
|
|
83
|
+
const permissions = useSelector(selectAdminPermissions);
|
|
84
|
+
const {
|
|
85
|
+
allowedActions: { canCreate, canDelete },
|
|
86
|
+
} = useRBAC(permissions.settings['review-workflows']);
|
|
79
87
|
|
|
80
88
|
const limits = getFeature('review-workflows');
|
|
81
89
|
|
|
@@ -148,24 +156,21 @@ export function ReviewWorkflowsListView() {
|
|
|
148
156
|
|
|
149
157
|
React.useEffect(() => {
|
|
150
158
|
if (!isLoading && !isLicenseLoading) {
|
|
151
|
-
if (
|
|
159
|
+
if (
|
|
160
|
+
limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
|
|
161
|
+
meta?.workflowCount > parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
|
|
162
|
+
) {
|
|
152
163
|
setShowLimitModal(true);
|
|
153
164
|
}
|
|
154
165
|
}
|
|
155
|
-
}, [
|
|
156
|
-
isLicenseLoading,
|
|
157
|
-
isLoading,
|
|
158
|
-
limits.stagesPerWorkflow,
|
|
159
|
-
limits.workflows,
|
|
160
|
-
meta?.workflowCount,
|
|
161
|
-
meta.workflowsTotal,
|
|
162
|
-
]);
|
|
166
|
+
}, [isLicenseLoading, isLoading, limits, meta?.workflowCount, meta.workflowsTotal]);
|
|
163
167
|
|
|
164
168
|
return (
|
|
165
169
|
<>
|
|
166
170
|
<Layout.Header
|
|
167
171
|
primaryAction={
|
|
168
172
|
<LinkButton
|
|
173
|
+
disabled={!canCreate}
|
|
169
174
|
startIcon={<Plus />}
|
|
170
175
|
size="S"
|
|
171
176
|
to="/settings/review-workflows/create"
|
|
@@ -180,7 +185,10 @@ export function ReviewWorkflowsListView() {
|
|
|
180
185
|
* current hard-limit of 200 they will see an error thrown by the API.
|
|
181
186
|
*/
|
|
182
187
|
|
|
183
|
-
if (
|
|
188
|
+
if (
|
|
189
|
+
limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
|
|
190
|
+
meta?.workflowCount >= parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
|
|
191
|
+
) {
|
|
184
192
|
event.preventDefault();
|
|
185
193
|
setShowLimitModal(true);
|
|
186
194
|
} else {
|
|
@@ -207,42 +215,50 @@ export function ReviewWorkflowsListView() {
|
|
|
207
215
|
|
|
208
216
|
<Layout.Root>
|
|
209
217
|
{isLoading || isLoadingModels ? (
|
|
210
|
-
<
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
218
|
+
<Flex justifyContent="center">
|
|
219
|
+
<Loader>
|
|
220
|
+
{formatMessage({
|
|
221
|
+
id: 'Settings.review-workflows.page.list.isLoading',
|
|
222
|
+
defaultMessage: 'Workflows are loading',
|
|
223
|
+
})}
|
|
224
|
+
</Loader>
|
|
225
|
+
</Flex>
|
|
216
226
|
) : (
|
|
217
227
|
<Table
|
|
218
228
|
colCount={3}
|
|
219
229
|
footer={
|
|
220
230
|
// TODO: we should be able to use a link here instead of an (inaccessible onClick) handler
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
231
|
+
canCreate && (
|
|
232
|
+
<TFooter
|
|
233
|
+
icon={<Plus />}
|
|
234
|
+
onClick={() => {
|
|
235
|
+
/**
|
|
236
|
+
* If the current license has a workflow limit:
|
|
237
|
+
* check if the total count of workflows exceeds that limit
|
|
238
|
+
*
|
|
239
|
+
* If the current license does not have a limit (e.g. offline license):
|
|
240
|
+
* allow the user to navigate to the create-view. In case they exceed the
|
|
241
|
+
* current hard-limit of 200 they will see an error thrown by the API.
|
|
242
|
+
*/
|
|
232
243
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
244
|
+
if (
|
|
245
|
+
limits?.[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME] &&
|
|
246
|
+
meta?.workflowCount >=
|
|
247
|
+
parseInt(limits[CHARGEBEE_WORKFLOW_ENTITLEMENT_NAME], 10)
|
|
248
|
+
) {
|
|
249
|
+
setShowLimitModal(true);
|
|
250
|
+
} else {
|
|
251
|
+
push('/settings/review-workflows/create');
|
|
252
|
+
trackUsage('willCreateWorkflow');
|
|
253
|
+
}
|
|
254
|
+
}}
|
|
255
|
+
>
|
|
256
|
+
{formatMessage({
|
|
257
|
+
id: 'Settings.review-workflows.list.page.create',
|
|
258
|
+
defaultMessage: 'Create new workflow',
|
|
259
|
+
})}
|
|
260
|
+
</TFooter>
|
|
261
|
+
)
|
|
246
262
|
}
|
|
247
263
|
rowCount={1}
|
|
248
264
|
>
|
|
@@ -326,21 +342,22 @@ export function ReviewWorkflowsListView() {
|
|
|
326
342
|
<Pencil />
|
|
327
343
|
</ActionLink>
|
|
328
344
|
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
{
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
345
|
+
{workflows.length > 1 && canDelete && (
|
|
346
|
+
<IconButton
|
|
347
|
+
aria-label={formatMessage(
|
|
348
|
+
{
|
|
349
|
+
id: 'Settings.review-workflows.list.page.list.column.actions.delete.label',
|
|
350
|
+
defaultMessage: 'Delete {name}',
|
|
351
|
+
},
|
|
352
|
+
{ name: 'Default workflow' }
|
|
353
|
+
)}
|
|
354
|
+
icon={<Trash />}
|
|
355
|
+
noBorder
|
|
356
|
+
onClick={() => {
|
|
357
|
+
handleDeleteWorkflow(workflow.id);
|
|
358
|
+
}}
|
|
359
|
+
/>
|
|
360
|
+
)}
|
|
344
361
|
</Flex>
|
|
345
362
|
</Td>
|
|
346
363
|
</Tr>
|
|
@@ -1,13 +1,18 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import { CheckPagePermissions } from '@strapi/helper-plugin';
|
|
4
|
+
import { useSelector } from 'react-redux';
|
|
5
|
+
|
|
6
|
+
import { selectAdminPermissions } from '../../../../../../../../admin/src/pages/App/selectors';
|
|
4
7
|
|
|
5
8
|
import { ReviewWorkflowsListView } from './ListView';
|
|
6
9
|
|
|
7
10
|
export default function () {
|
|
11
|
+
const permissions = useSelector(selectAdminPermissions);
|
|
12
|
+
|
|
8
13
|
return (
|
|
9
|
-
<
|
|
14
|
+
<CheckPagePermissions permissions={permissions.settings['review-workflows'].main}>
|
|
10
15
|
<ReviewWorkflowsListView />
|
|
11
|
-
</
|
|
16
|
+
</CheckPagePermissions>
|
|
12
17
|
);
|
|
13
18
|
}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
import set from 'lodash/set';
|
|
1
2
|
import * as yup from 'yup';
|
|
2
3
|
|
|
3
|
-
export function
|
|
4
|
-
|
|
4
|
+
export async function validateWorkflow({ values, formatMessage }) {
|
|
5
|
+
const schema = yup.object({
|
|
5
6
|
contentTypes: yup.array().of(yup.string()),
|
|
6
7
|
name: yup
|
|
7
8
|
.string()
|
|
@@ -32,6 +33,20 @@ export function getWorkflowValidationSchema({ formatMessage }) {
|
|
|
32
33
|
id: 'Settings.review-workflows.validation.stage.max-length',
|
|
33
34
|
defaultMessage: 'Name can not be longer than 255 characters',
|
|
34
35
|
})
|
|
36
|
+
)
|
|
37
|
+
.test(
|
|
38
|
+
'unique-name',
|
|
39
|
+
formatMessage({
|
|
40
|
+
id: 'Settings.review-workflows.validation.stage.duplicate',
|
|
41
|
+
defaultMessage: 'Stage name must be unique',
|
|
42
|
+
}),
|
|
43
|
+
function (stageName) {
|
|
44
|
+
const {
|
|
45
|
+
options: { context },
|
|
46
|
+
} = this;
|
|
47
|
+
|
|
48
|
+
return context.stages.filter((stage) => stage.name === stageName).length === 1;
|
|
49
|
+
}
|
|
35
50
|
),
|
|
36
51
|
color: yup
|
|
37
52
|
.string()
|
|
@@ -46,4 +61,20 @@ export function getWorkflowValidationSchema({ formatMessage }) {
|
|
|
46
61
|
)
|
|
47
62
|
.min(1),
|
|
48
63
|
});
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
await schema.validate(values, { abortEarly: false, context: values });
|
|
67
|
+
|
|
68
|
+
return true;
|
|
69
|
+
} catch (error) {
|
|
70
|
+
let errors = {};
|
|
71
|
+
|
|
72
|
+
if (error instanceof yup.ValidationError) {
|
|
73
|
+
error.inner.forEach((error) => {
|
|
74
|
+
set(errors, error.path, error.message);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
return errors;
|
|
79
|
+
}
|
|
49
80
|
}
|
|
@@ -6,11 +6,14 @@ const schema = yup.object().shape({
|
|
|
6
6
|
defaultRole: yup.mixed().when('autoRegister', (value, initSchema) => {
|
|
7
7
|
return value ? initSchema.required(translatedErrors.required) : initSchema.nullable();
|
|
8
8
|
}),
|
|
9
|
-
ssoLockedRoles: yup
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
ssoLockedRoles: yup
|
|
10
|
+
.array()
|
|
11
|
+
.nullable()
|
|
12
|
+
.of(
|
|
13
|
+
yup.mixed().when('ssoLockedRoles', (value, initSchema) => {
|
|
14
|
+
return value ? initSchema.required(translatedErrors.required) : initSchema.nullable();
|
|
15
|
+
})
|
|
16
|
+
),
|
|
14
17
|
});
|
|
15
18
|
|
|
16
19
|
export default schema;
|
|
@@ -14,5 +14,6 @@ module.exports = {
|
|
|
14
14
|
'You’ve reached the limit of workflows in your plan. Delete a workflow or contact Sales to enable more workflows.',
|
|
15
15
|
STAGES_LIMIT:
|
|
16
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
|
+
DUPLICATED_STAGE_NAME: 'Stage names must be unique.',
|
|
17
18
|
},
|
|
18
19
|
};
|
|
@@ -22,7 +22,7 @@ const MAX_JOIN_TABLE_NAME_SUFFIX =
|
|
|
22
22
|
const MAX_CONTENT_TYPE_NAME_LEN = MAX_DB_TABLE_NAME_LEN - MAX_JOIN_TABLE_NAME_SUFFIX;
|
|
23
23
|
|
|
24
24
|
const DEFAULT_OPTIONS = {
|
|
25
|
-
|
|
25
|
+
numberOfWorkflows: MAX_WORKFLOWS,
|
|
26
26
|
stagesPerWorkflow: MAX_STAGES_PER_WORKFLOW,
|
|
27
27
|
};
|
|
28
28
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
const { uniq } = require('lodash/fp');
|
|
3
4
|
const { ValidationError } = require('@strapi/utils').errors;
|
|
4
5
|
const { getService } = require('../../utils');
|
|
5
6
|
const { ERRORS, MAX_WORKFLOWS, MAX_STAGES_PER_WORKFLOW } = require('../../constants/workflows');
|
|
@@ -8,12 +9,14 @@ const { clampMaxWorkflows, clampMaxStagesPerWorkflow } = require('../../utils/re
|
|
|
8
9
|
module.exports = ({ strapi }) => {
|
|
9
10
|
return {
|
|
10
11
|
limits: {
|
|
11
|
-
|
|
12
|
+
numberOfWorkflows: MAX_WORKFLOWS,
|
|
12
13
|
stagesPerWorkflow: MAX_STAGES_PER_WORKFLOW,
|
|
13
14
|
},
|
|
14
|
-
register({
|
|
15
|
+
register({ numberOfWorkflows, stagesPerWorkflow }) {
|
|
15
16
|
if (!Object.isFrozen(this.limits)) {
|
|
16
|
-
this.limits.
|
|
17
|
+
this.limits.numberOfWorkflows = clampMaxWorkflows(
|
|
18
|
+
numberOfWorkflows || this.limits.numberOfWorkflows
|
|
19
|
+
);
|
|
17
20
|
this.limits.stagesPerWorkflow = clampMaxStagesPerWorkflow(
|
|
18
21
|
stagesPerWorkflow || this.limits.stagesPerWorkflow
|
|
19
22
|
);
|
|
@@ -32,6 +35,11 @@ module.exports = ({ strapi }) => {
|
|
|
32
35
|
if (stages.length > this.limits.stagesPerWorkflow) {
|
|
33
36
|
throw new ValidationError(ERRORS.STAGES_LIMIT);
|
|
34
37
|
}
|
|
38
|
+
// Validate stage names are not duplicated
|
|
39
|
+
const stageNames = stages.map((stage) => stage.name);
|
|
40
|
+
if (uniq(stageNames).length !== stageNames.length) {
|
|
41
|
+
throw new ValidationError(ERRORS.DUPLICATED_STAGE_NAME);
|
|
42
|
+
}
|
|
35
43
|
},
|
|
36
44
|
|
|
37
45
|
async validateWorkflowCountStages(workflowId, countAddedStages = 0) {
|
|
@@ -52,7 +60,7 @@ module.exports = ({ strapi }) => {
|
|
|
52
60
|
async validateWorkflowCount(countAddedWorkflows = 0) {
|
|
53
61
|
const workflowsService = getService('workflows', { strapi });
|
|
54
62
|
const countWorkflows = await workflowsService.count();
|
|
55
|
-
if (countWorkflows + countAddedWorkflows > this.limits.
|
|
63
|
+
if (countWorkflows + countAddedWorkflows > this.limits.numberOfWorkflows) {
|
|
56
64
|
throw new ValidationError(ERRORS.WORKFLOWS_LIMIT);
|
|
57
65
|
}
|
|
58
66
|
},
|
|
@@ -30,26 +30,35 @@ module.exports = ({ strapi }) => {
|
|
|
30
30
|
* @param {Workflow.Stage} options.stageId - The new stage to assign the entities to
|
|
31
31
|
*/
|
|
32
32
|
async migrate({ srcContentTypes = [], destContentTypes, stageId }) {
|
|
33
|
-
// Workflows service is using this content-types service, to avoid an infinite loop, we need to get the service in the method
|
|
34
33
|
const workflowsService = getService('workflows', { strapi });
|
|
35
34
|
const { created, deleted } = diffContentTypes(srcContentTypes, destContentTypes);
|
|
36
35
|
|
|
37
|
-
await mapAsync(
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
//
|
|
42
|
-
await
|
|
43
|
-
return this.transferContentType(srcWorkflow, uid);
|
|
44
|
-
}
|
|
45
|
-
await updateContentTypeConfig(uid, true);
|
|
36
|
+
await mapAsync(
|
|
37
|
+
created,
|
|
38
|
+
async (uid) => {
|
|
39
|
+
// Content Types should only be assigned to one workflow
|
|
40
|
+
// However, edge cases can happen, and this handles them
|
|
41
|
+
const srcWorkflows = await workflowsService._getAssignedWorkflows(uid, {});
|
|
46
42
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
43
|
+
if (srcWorkflows.length) {
|
|
44
|
+
// Updates all existing entities stages links to the new stage
|
|
45
|
+
await stagesService.updateEntitiesStage(uid, { toStageId: stageId });
|
|
46
|
+
// Transfer content types from the previous workflow(s)
|
|
47
|
+
await mapAsync(srcWorkflows, (srcWorkflow) =>
|
|
48
|
+
this.transferContentTypes(srcWorkflow, uid)
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
await updateContentTypeConfig(uid, true);
|
|
52
|
+
|
|
53
|
+
// Create new stages links to the new stage
|
|
54
|
+
return stagesService.updateEntitiesStage(uid, {
|
|
55
|
+
fromStageId: null,
|
|
56
|
+
toStageId: stageId,
|
|
57
|
+
});
|
|
58
|
+
},
|
|
59
|
+
// transferContentTypes can cause race conditions if called in parallel when updating the same workflow
|
|
60
|
+
{ concurrency: 1 }
|
|
61
|
+
);
|
|
53
62
|
|
|
54
63
|
await mapAsync(deleted, async (uid) => {
|
|
55
64
|
await updateContentTypeConfig(uid, false);
|
|
@@ -58,15 +67,15 @@ module.exports = ({ strapi }) => {
|
|
|
58
67
|
},
|
|
59
68
|
|
|
60
69
|
/**
|
|
61
|
-
* Filters the content types assigned to
|
|
70
|
+
* Filters the content types assigned to a workflow
|
|
62
71
|
* @param {Workflow} srcWorkflow - The workflow to transfer from
|
|
63
72
|
* @param {string} uid - The content type uid
|
|
64
73
|
*/
|
|
65
|
-
async
|
|
74
|
+
async transferContentTypes(srcWorkflow, uid) {
|
|
66
75
|
// Update assignedContentTypes of the previous workflow
|
|
67
76
|
await strapi.entityService.update(WORKFLOW_MODEL_UID, srcWorkflow.id, {
|
|
68
77
|
data: {
|
|
69
|
-
contentTypes: srcWorkflow.contentTypes.filter((
|
|
78
|
+
contentTypes: srcWorkflow.contentTypes.filter((contentType) => contentType !== uid),
|
|
70
79
|
},
|
|
71
80
|
});
|
|
72
81
|
},
|
|
@@ -163,11 +163,23 @@ module.exports = ({ strapi }) => {
|
|
|
163
163
|
* @returns {Promise<object|null>} - Assigned workflow object if found, or null.
|
|
164
164
|
*/
|
|
165
165
|
async getAssignedWorkflow(uid, opts = {}) {
|
|
166
|
-
const workflows = await this.
|
|
166
|
+
const workflows = await this._getAssignedWorkflows(uid, opts);
|
|
167
|
+
return workflows.length > 0 ? workflows[0] : null;
|
|
168
|
+
},
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Finds all the assigned workflows for a given content type ID.
|
|
172
|
+
* Normally, there should only be one workflow assigned to a content type.
|
|
173
|
+
* However, edge cases can occur where a content type is assigned to multiple workflows.
|
|
174
|
+
* @param {string} uid - Content type ID to find the assigned workflows for.
|
|
175
|
+
* @param {object} opts - Options for the query.
|
|
176
|
+
* @returns {Promise<object[]>} - List of assigned workflow objects.
|
|
177
|
+
*/
|
|
178
|
+
async _getAssignedWorkflows(uid, opts = {}) {
|
|
179
|
+
return this.find({
|
|
167
180
|
...opts,
|
|
168
181
|
filters: { contentTypes: getWorkflowContentTypeFilter({ strapi }, uid) },
|
|
169
182
|
});
|
|
170
|
-
return workflows.length > 0 ? workflows[0] : null;
|
|
171
183
|
},
|
|
172
184
|
|
|
173
185
|
/**
|
|
@@ -10,14 +10,20 @@ const providerOptionsUpdateSchema = yup.object().shape({
|
|
|
10
10
|
.test('is-valid-role', 'You must submit a valid default role', (roleId) => {
|
|
11
11
|
return strapi.admin.services.role.exists({ id: roleId });
|
|
12
12
|
}),
|
|
13
|
-
ssoLockedRoles: yup
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
13
|
+
ssoLockedRoles: yup
|
|
14
|
+
.array()
|
|
15
|
+
.nullable()
|
|
16
|
+
.of(
|
|
17
|
+
yup
|
|
18
|
+
.strapiID()
|
|
19
|
+
.test(
|
|
20
|
+
'is-valid-role',
|
|
21
|
+
'You must submit a valid role for the SSO Locked roles',
|
|
22
|
+
(roleId) => {
|
|
23
|
+
return strapi.admin.services.role.exists({ id: roleId });
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
),
|
|
21
27
|
});
|
|
22
28
|
|
|
23
29
|
module.exports = {
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
+
/* eslint-disable func-names */
|
|
4
|
+
|
|
3
5
|
const { yup, validateYupSchema } = require('@strapi/utils');
|
|
4
6
|
const { hasStageAttribute } = require('../utils/review-workflows');
|
|
5
7
|
|
|
@@ -42,10 +44,11 @@ const validateContentTypes = yup.array().of(
|
|
|
42
44
|
);
|
|
43
45
|
|
|
44
46
|
const validateWorkflowCreateSchema = yup.object().shape({
|
|
45
|
-
name: yup.string().max(255).required(),
|
|
47
|
+
name: yup.string().max(255).min(1, 'Workflow name can not be empty').required(),
|
|
46
48
|
stages: yup
|
|
47
49
|
.array()
|
|
48
50
|
.of(stageObject)
|
|
51
|
+
.uniqueProperty('name', 'Stage name must be unique')
|
|
49
52
|
.min(1, 'Can not create a workflow without stages')
|
|
50
53
|
.max(200, 'Can not have more than 200 stages')
|
|
51
54
|
.required('Can not create a workflow without stages'),
|
|
@@ -53,10 +56,11 @@ const validateWorkflowCreateSchema = yup.object().shape({
|
|
|
53
56
|
});
|
|
54
57
|
|
|
55
58
|
const validateWorkflowUpdateSchema = yup.object().shape({
|
|
56
|
-
name: yup.string().max(255),
|
|
59
|
+
name: yup.string().max(255).min(1, 'Workflow name can not be empty'),
|
|
57
60
|
stages: yup
|
|
58
61
|
.array()
|
|
59
62
|
.of(stageObject)
|
|
63
|
+
.uniqueProperty('name', 'Stage name must be unique')
|
|
60
64
|
.min(1, 'Can not update a workflow without stages')
|
|
61
65
|
.max(200, 'Can not have more than 200 stages'),
|
|
62
66
|
contentTypes: validateContentTypes,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@strapi/admin",
|
|
3
|
-
"version": "4.12.0-beta.
|
|
3
|
+
"version": "4.12.0-beta.4",
|
|
4
4
|
"description": "Strapi Admin",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -42,14 +42,14 @@
|
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@casl/ability": "^5.4.3",
|
|
44
44
|
"@pmmmwh/react-refresh-webpack-plugin": "0.5.10",
|
|
45
|
-
"@strapi/data-transfer": "4.12.0-beta.
|
|
45
|
+
"@strapi/data-transfer": "4.12.0-beta.4",
|
|
46
46
|
"@strapi/design-system": "1.8.2",
|
|
47
|
-
"@strapi/helper-plugin": "4.12.0-beta.
|
|
47
|
+
"@strapi/helper-plugin": "4.12.0-beta.4",
|
|
48
48
|
"@strapi/icons": "1.8.2",
|
|
49
|
-
"@strapi/permissions": "4.12.0-beta.
|
|
50
|
-
"@strapi/provider-audit-logs-local": "4.12.0-beta.
|
|
51
|
-
"@strapi/typescript-utils": "4.12.0-beta.
|
|
52
|
-
"@strapi/utils": "4.12.0-beta.
|
|
49
|
+
"@strapi/permissions": "4.12.0-beta.4",
|
|
50
|
+
"@strapi/provider-audit-logs-local": "4.12.0-beta.4",
|
|
51
|
+
"@strapi/typescript-utils": "4.12.0-beta.4",
|
|
52
|
+
"@strapi/utils": "4.12.0-beta.4",
|
|
53
53
|
"axios": "1.4.0",
|
|
54
54
|
"bcryptjs": "2.4.3",
|
|
55
55
|
"browserslist": "^4.17.3",
|
|
@@ -117,7 +117,7 @@
|
|
|
117
117
|
"reselect": "^4.1.7",
|
|
118
118
|
"rimraf": "3.0.2",
|
|
119
119
|
"sanitize-html": "2.10.0",
|
|
120
|
-
"semver": "7.5.
|
|
120
|
+
"semver": "7.5.2",
|
|
121
121
|
"sift": "16.0.1",
|
|
122
122
|
"style-loader": "3.3.1",
|
|
123
123
|
"styled-components": "5.3.3",
|
|
@@ -154,5 +154,5 @@
|
|
|
154
154
|
}
|
|
155
155
|
}
|
|
156
156
|
},
|
|
157
|
-
"gitHead": "
|
|
157
|
+
"gitHead": "edcf86b496a7bee5189cdbfeb16f5a5c0abccc81"
|
|
158
158
|
}
|