@strapi/admin 4.11.3 → 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/components/AuthenticatedApp/index.js +2 -2
- 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/RelationInput/RelationInput.js +99 -178
- package/admin/src/content-manager/components/RelationInput/components/Option.js +17 -15
- package/admin/src/content-manager/components/RelationInput/components/RelationList.js +2 -2
- 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 -47
- 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/Table/index.js +15 -1
- package/admin/src/pages/SettingsPage/components/Tokens/TokenBox/index.js +1 -1
- package/admin/src/pages/SettingsPage/pages/Roles/ProtectedEditPage/index.js +4 -10
- package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -2
- package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +11 -5
- package/admin/src/translations/ca.json +1 -0
- package/admin/src/translations/en.json +4 -1
- package/admin/src/translations/es.json +5 -0
- package/admin/src/translations/fr.json +1 -0
- 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/{5542.64b623c9.chunk.js → 5542.c62d0daf.chunk.js} +1 -1
- 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/{6405.27e1bee5.chunk.js → 970.89601f27.chunk.js} +2 -2
- package/build/9944.29289a16.chunk.js +26 -0
- package/build/Admin-authenticatedApp.9d3afb79.chunk.js +79 -0
- 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-roles-page.2040034a.chunk.js → admin-edit-roles-page.3fdd6b9d.chunk.js} +11 -11
- package/build/admin-edit-users.78552758.chunk.js +10 -0
- package/build/admin-users.c23322fc.chunk.js +11 -0
- package/build/api-tokens-list-page.a103f526.chunk.js +16 -0
- package/build/audit-logs-settings-page.37fe915c.chunk.js +1 -0
- package/build/ca-json.1fed5d8b.chunk.js +1 -0
- package/build/content-manager.08541eeb.chunk.js +1094 -0
- package/build/{content-type-builder-list-view.0c3ceb4e.chunk.js → content-type-builder-list-view.a200a358.chunk.js} +1 -1
- 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/{email-settings-page.6b38222d.chunk.js → email-settings-page.45695daa.chunk.js} +1 -1
- package/build/en-json.fb9f6ddd.chunk.js +1 -0
- package/build/es-json.42096084.chunk.js +1 -0
- package/build/fr-json.69789980.chunk.js +1 -0
- package/build/{i18n-settings-page.ff863f20.chunk.js → i18n-settings-page.29308d0b.chunk.js} +1 -1
- 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/sso-settings-page.0cdb96a6.chunk.js +1 -0
- package/build/transfer-tokens-list-page.7237443d.chunk.js +16 -0
- package/build/{upload-settings.43cf16cd.chunk.js → upload-settings.cb6c14c3.chunk.js} +1 -1
- package/build/{upload.72f8f8fc.chunk.js → upload.7e629643.chunk.js} +2 -2
- package/build/users-advanced-settings-page.750b1f76.chunk.js +9 -0
- package/build/{users-email-settings-page.33359797.chunk.js → users-email-settings-page.e9bcd865.chunk.js} +1 -1
- package/build/{users-providers-settings-page.1e7a4a71.chunk.js → users-providers-settings-page.a94253e9.chunk.js} +1 -1
- package/build/{users-roles-settings-page.235378b6.chunk.js → users-roles-settings-page.d286426a.chunk.js} +5 -5
- package/build/webhook-edit-page.77ef4f1a.chunk.js +33 -0
- 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/AuditLogs/ListView/index.js +4 -9
- 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/SingleSignOn/index.js +4 -9
- 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 +28 -24
- 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 +13 -14
- package/server/content-types/User.js +10 -0
- package/server/strategies/api-token.js +9 -5
- package/server/strategies/data-transfer.js +9 -5
- package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +0 -2
- package/admin/src/content-manager/components/RelationInput/components/Relation.js +0 -53
- 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.84268ad3.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-authenticatedApp.69855f1b.chunk.js +0 -79
- package/build/admin-app.fea867af.chunk.js +0 -61
- package/build/admin-edit-users.53e4290a.chunk.js +0 -10
- package/build/admin-users.3b12dca2.chunk.js +0 -11
- package/build/api-tokens-list-page.201fb67a.chunk.js +0 -16
- package/build/audit-logs-settings-page.b07ad202.chunk.js +0 -1
- package/build/ca-json.43e14418.chunk.js +0 -1
- package/build/content-manager.66cec770.chunk.js +0 -1094
- package/build/content-type-builder-translation-en-json.f592325b.chunk.js +0 -1
- package/build/content-type-builder.e1b6d13b.chunk.js +0 -166
- package/build/en-json.f5fa476a.chunk.js +0 -1
- package/build/es-json.715b6fd8.chunk.js +0 -1
- package/build/fr-json.73494bf5.chunk.js +0 -1
- package/build/main.83edb3fc.js +0 -2926
- package/build/review-workflows-settings.93808ae0.chunk.js +0 -110
- package/build/runtime~main.20c3cac6.js +0 -2
- package/build/sso-settings-page.35b67909.chunk.js +0 -1
- package/build/transfer-tokens-list-page.217573c3.chunk.js +0 -16
- package/build/users-advanced-settings-page.1911adf5.chunk.js +0 -9
- package/build/webhook-edit-page.1ee02c4b.chunk.js +0 -33
- 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
|
@@ -11,16 +11,18 @@ import { useIntl } from 'react-intl';
|
|
|
11
11
|
import { useMutation } from 'react-query';
|
|
12
12
|
|
|
13
13
|
import Information from '../../../../../../admin/src/content-manager/pages/EditView/Information';
|
|
14
|
+
import useLicenseLimits from '../../../../hooks/useLicenseLimits';
|
|
15
|
+
import * as LimitsModal from '../../../../pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal';
|
|
14
16
|
import { useReviewWorkflows } from '../../../../pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows';
|
|
15
17
|
import { getStageColorByHex } from '../../../../pages/SettingsPage/pages/ReviewWorkflows/utils/colors';
|
|
16
18
|
|
|
17
|
-
const ATTRIBUTE_NAME = '
|
|
19
|
+
const ATTRIBUTE_NAME = 'strapi_stage';
|
|
18
20
|
|
|
19
21
|
export function InformationBoxEE() {
|
|
20
22
|
const {
|
|
21
23
|
initialData,
|
|
22
24
|
isCreatingEntry,
|
|
23
|
-
layout: { uid },
|
|
25
|
+
layout: { uid, options },
|
|
24
26
|
isSingleType,
|
|
25
27
|
onChange,
|
|
26
28
|
} = useCMEditViewDataManager();
|
|
@@ -29,17 +31,18 @@ export function InformationBoxEE() {
|
|
|
29
31
|
// be updated at the same time when modifiedData is updated, otherwise
|
|
30
32
|
// the entity is flagged as modified
|
|
31
33
|
const activeWorkflowStage = initialData?.[ATTRIBUTE_NAME] ?? null;
|
|
32
|
-
const hasReviewWorkflowsEnabled =
|
|
33
|
-
initialData,
|
|
34
|
-
ATTRIBUTE_NAME
|
|
35
|
-
);
|
|
34
|
+
const hasReviewWorkflowsEnabled = options?.reviewWorkflows ?? false;
|
|
36
35
|
const { formatMessage } = useIntl();
|
|
37
36
|
const { formatAPIError } = useAPIErrorHandler();
|
|
38
37
|
const toggleNotification = useNotification();
|
|
38
|
+
const { getFeature } = useLicenseLimits();
|
|
39
|
+
const [showLimitModal, setShowLimitModal] = React.useState(false);
|
|
39
40
|
|
|
40
|
-
const {
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
const {
|
|
42
|
+
meta,
|
|
43
|
+
workflows: [workflow],
|
|
44
|
+
isLoading: isWorkflowLoading,
|
|
45
|
+
} = useReviewWorkflows({ filters: { contentTypes: uid } });
|
|
43
46
|
|
|
44
47
|
const { error, isLoading, mutateAsync } = useMutation(
|
|
45
48
|
async ({ entityId, stageId, uid }) => {
|
|
@@ -70,29 +73,42 @@ export function InformationBoxEE() {
|
|
|
70
73
|
}
|
|
71
74
|
);
|
|
72
75
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// set the default stage either which may lead to entities that
|
|
76
|
-
// do not have a stage assigned for a while. By displaying an
|
|
77
|
-
// error by default we are trying to nudge users into assigning a stage.
|
|
78
|
-
const initialStageNullError =
|
|
79
|
-
activeWorkflowStage === null &&
|
|
80
|
-
!workflowIsLoading &&
|
|
81
|
-
!isCreatingEntry &&
|
|
82
|
-
formatMessage({
|
|
83
|
-
id: 'content-manager.reviewWorkflows.stage.select.placeholder',
|
|
84
|
-
defaultMessage: 'Select a stage',
|
|
85
|
-
});
|
|
86
|
-
const formattedMutationError = error && formatAPIError(error);
|
|
87
|
-
const formattedError = formattedMutationError || initialStageNullError || null;
|
|
76
|
+
const limits = getFeature('review-workflows');
|
|
77
|
+
const formattedError = (error && formatAPIError(error)) || null;
|
|
88
78
|
|
|
89
79
|
const handleStageChange = async ({ value: stageId }) => {
|
|
90
80
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
81
|
+
/**
|
|
82
|
+
* If the current license has a limit:
|
|
83
|
+
* check if the total count of workflows exceeds that limit and display
|
|
84
|
+
* the limits modal.
|
|
85
|
+
*
|
|
86
|
+
* If the current license does not have a limit (e.g. offline license):
|
|
87
|
+
* do nothing (for now).
|
|
88
|
+
*
|
|
89
|
+
*/
|
|
90
|
+
|
|
91
|
+
if (limits?.workflows && limits.workflows > meta.workflowCount) {
|
|
92
|
+
setShowLimitModal('workflow');
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* If the current license has a limit:
|
|
96
|
+
* check if the total count of stages exceeds that limit and display
|
|
97
|
+
* the limits modal.
|
|
98
|
+
*
|
|
99
|
+
* If the current license does not have a limit (e.g. offline license):
|
|
100
|
+
* do nothing (for now).
|
|
101
|
+
*
|
|
102
|
+
*/
|
|
103
|
+
} else if (limits?.stagesPerWorkflow && limits.stagesPerWorkflow > workflow.stages.length) {
|
|
104
|
+
setShowLimitModal('stage');
|
|
105
|
+
} else {
|
|
106
|
+
await mutateAsync({
|
|
107
|
+
entityId: initialData.id,
|
|
108
|
+
stageId,
|
|
109
|
+
uid,
|
|
110
|
+
});
|
|
111
|
+
}
|
|
96
112
|
} catch (error) {
|
|
97
113
|
// react-query@v3: the error doesn't have to be handled here
|
|
98
114
|
// see: https://github.com/TanStack/query/issues/121
|
|
@@ -136,7 +152,7 @@ export function InformationBoxEE() {
|
|
|
136
152
|
<Typography textColor="neutral800" ellipsis>
|
|
137
153
|
{activeWorkflowStage?.name}
|
|
138
154
|
</Typography>
|
|
139
|
-
{isLoading ? <Loader small style={{ display: 'flex' }} /> : null}
|
|
155
|
+
{isWorkflowLoading || isLoading ? <Loader small style={{ display: 'flex' }} /> : null}
|
|
140
156
|
</Flex>
|
|
141
157
|
)}
|
|
142
158
|
>
|
|
@@ -168,6 +184,44 @@ export function InformationBoxEE() {
|
|
|
168
184
|
)}
|
|
169
185
|
|
|
170
186
|
<Information.Body />
|
|
187
|
+
|
|
188
|
+
<LimitsModal.Root
|
|
189
|
+
isOpen={showLimitModal === 'workflow'}
|
|
190
|
+
onClose={() => setShowLimitModal(false)}
|
|
191
|
+
>
|
|
192
|
+
<LimitsModal.Title>
|
|
193
|
+
{formatMessage({
|
|
194
|
+
id: 'content-manager.reviewWorkflows.workflows.limit.title',
|
|
195
|
+
defaultMessage: 'You’ve reached the limit of workflows in your plan',
|
|
196
|
+
})}
|
|
197
|
+
</LimitsModal.Title>
|
|
198
|
+
|
|
199
|
+
<LimitsModal.Body>
|
|
200
|
+
{formatMessage({
|
|
201
|
+
id: 'content-manager.reviewWorkflows.workflows.limit.body',
|
|
202
|
+
defaultMessage: 'Delete a workflow or contact Sales to enable more workflows.',
|
|
203
|
+
})}
|
|
204
|
+
</LimitsModal.Body>
|
|
205
|
+
</LimitsModal.Root>
|
|
206
|
+
|
|
207
|
+
<LimitsModal.Root
|
|
208
|
+
isOpen={showLimitModal === 'stage'}
|
|
209
|
+
onClose={() => setShowLimitModal(false)}
|
|
210
|
+
>
|
|
211
|
+
<LimitsModal.Title>
|
|
212
|
+
{formatMessage({
|
|
213
|
+
id: 'content-manager.reviewWorkflows.stages.limit.title',
|
|
214
|
+
defaultMessage: 'You have reached the limit of stages for this workflow in your plan',
|
|
215
|
+
})}
|
|
216
|
+
</LimitsModal.Title>
|
|
217
|
+
|
|
218
|
+
<LimitsModal.Body>
|
|
219
|
+
{formatMessage({
|
|
220
|
+
id: 'content-manager.reviewWorkflows.stages.limit.body',
|
|
221
|
+
defaultMessage: 'Try deleting some stages or contact Sales to enable more stages.',
|
|
222
|
+
})}
|
|
223
|
+
</LimitsModal.Body>
|
|
224
|
+
</LimitsModal.Root>
|
|
171
225
|
</Information.Root>
|
|
172
226
|
);
|
|
173
227
|
}
|
|
@@ -4,7 +4,8 @@ import { Box, Flex, Typography } from '@strapi/design-system';
|
|
|
4
4
|
import { pxToRem } from '@strapi/helper-plugin';
|
|
5
5
|
import PropTypes from 'prop-types';
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { STAGE_COLOR_DEFAULT } from '../../../../pages/SettingsPage/pages/ReviewWorkflows/constants';
|
|
8
|
+
import { getStageColorByHex } from '../../../../pages/SettingsPage/pages/ReviewWorkflows/utils/colors';
|
|
8
9
|
|
|
9
10
|
export function ReviewWorkflowsStageEE({ color, name }) {
|
|
10
11
|
const { themeColorName } = getStageColorByHex(color);
|
|
@@ -27,7 +28,11 @@ export function ReviewWorkflowsStageEE({ color, name }) {
|
|
|
27
28
|
);
|
|
28
29
|
}
|
|
29
30
|
|
|
31
|
+
ReviewWorkflowsStageEE.defaultProps = {
|
|
32
|
+
color: STAGE_COLOR_DEFAULT,
|
|
33
|
+
};
|
|
34
|
+
|
|
30
35
|
ReviewWorkflowsStageEE.propTypes = {
|
|
31
|
-
color: PropTypes.string
|
|
36
|
+
color: PropTypes.string,
|
|
32
37
|
name: PropTypes.string.isRequired,
|
|
33
38
|
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import getTrad from '../../../../../../admin/src/content-manager/utils/getTrad';
|
|
2
|
+
|
|
3
|
+
export const REVIEW_WORKFLOW_COLUMNS_EE = {
|
|
4
|
+
key: '__strapi_reviewWorkflows_stage_temp_key__',
|
|
5
|
+
name: 'strapi_reviewWorkflows_stage',
|
|
6
|
+
fieldSchema: {
|
|
7
|
+
type: 'relation',
|
|
8
|
+
},
|
|
9
|
+
metadatas: {
|
|
10
|
+
// formatMessage() will be applied when the column is rendered
|
|
11
|
+
label: {
|
|
12
|
+
id: getTrad(`containers.ListPage.table-headers.reviewWorkflows.stage`),
|
|
13
|
+
defaultMessage: 'Review stage',
|
|
14
|
+
},
|
|
15
|
+
searchable: false,
|
|
16
|
+
sortable: true,
|
|
17
|
+
mainField: {
|
|
18
|
+
name: 'name',
|
|
19
|
+
schema: {
|
|
20
|
+
type: 'string',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ReviewWorkflowsStageEE';
|
|
@@ -19,18 +19,18 @@ const BILLING_SELF_HOSTED_URL = 'https://strapi.io/billing/request-seats';
|
|
|
19
19
|
|
|
20
20
|
const useLicenseLimitNotification = () => {
|
|
21
21
|
const { formatMessage } = useIntl();
|
|
22
|
-
let { license } = useLicenseLimits();
|
|
22
|
+
let { license, isError, isLoading } = useLicenseLimits();
|
|
23
23
|
const toggleNotification = useNotification();
|
|
24
24
|
const { pathname } = useLocation();
|
|
25
25
|
|
|
26
|
+
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
|
27
|
+
license;
|
|
28
|
+
|
|
26
29
|
useEffect(() => {
|
|
27
|
-
if (
|
|
30
|
+
if (isError || isLoading) {
|
|
28
31
|
return;
|
|
29
32
|
}
|
|
30
33
|
|
|
31
|
-
const { enforcementUserCount, permittedSeats, licenseLimitStatus, isHostedOnStrapiCloud } =
|
|
32
|
-
license?.data ?? {};
|
|
33
|
-
|
|
34
34
|
const shouldDisplayNotification =
|
|
35
35
|
!isNil(permittedSeats) &&
|
|
36
36
|
!window.sessionStorage.getItem(`${STORAGE_KEY_PREFIX}-${pathname}`) &&
|
|
@@ -84,7 +84,18 @@ const useLicenseLimitNotification = () => {
|
|
|
84
84
|
},
|
|
85
85
|
});
|
|
86
86
|
}
|
|
87
|
-
}, [
|
|
87
|
+
}, [
|
|
88
|
+
toggleNotification,
|
|
89
|
+
license,
|
|
90
|
+
pathname,
|
|
91
|
+
formatMessage,
|
|
92
|
+
isLoading,
|
|
93
|
+
permittedSeats,
|
|
94
|
+
licenseLimitStatus,
|
|
95
|
+
enforcementUserCount,
|
|
96
|
+
isHostedOnStrapiCloud,
|
|
97
|
+
isError,
|
|
98
|
+
]);
|
|
88
99
|
};
|
|
89
100
|
|
|
90
101
|
export default useLicenseLimitNotification;
|
|
@@ -1,34 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useQuery } from 'react-query';
|
|
3
|
-
import { useSelector } from 'react-redux';
|
|
4
|
-
|
|
5
|
-
import { selectAdminPermissions } from '../../../../admin/src/pages/App/selectors';
|
|
6
|
-
|
|
7
|
-
const useLicenseLimits = () => {
|
|
8
|
-
const permissions = useSelector(selectAdminPermissions);
|
|
9
|
-
const rbac = useRBAC(permissions.settings.users);
|
|
10
|
-
|
|
11
|
-
const {
|
|
12
|
-
isLoading: isRBACLoading,
|
|
13
|
-
allowedActions: { canRead, canCreate, canUpdate, canDelete },
|
|
14
|
-
} = rbac;
|
|
15
|
-
|
|
16
|
-
const isRBACAllowed = canRead && canCreate && canUpdate && canDelete;
|
|
17
|
-
|
|
18
|
-
const { get } = useFetchClient();
|
|
19
|
-
const fetchLicenseLimitInfo = async () => {
|
|
20
|
-
const {
|
|
21
|
-
data: { data },
|
|
22
|
-
} = await get('/admin/license-limit-information');
|
|
23
|
-
|
|
24
|
-
return data;
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
const license = useQuery(['ee', 'license-limit-info'], fetchLicenseLimitInfo, {
|
|
28
|
-
enabled: !isRBACLoading && isRBACAllowed,
|
|
29
|
-
});
|
|
30
|
-
|
|
31
|
-
return { license };
|
|
32
|
-
};
|
|
1
|
+
import { useLicenseLimits } from './useLicenseLimits';
|
|
33
2
|
|
|
34
3
|
export default useLicenseLimits;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { useFetchClient, useRBAC } from '@strapi/helper-plugin';
|
|
4
|
+
import { useQuery } from 'react-query';
|
|
5
|
+
import { useSelector } from 'react-redux';
|
|
6
|
+
|
|
7
|
+
import { selectAdminPermissions } from '../../../../admin/src/pages/App/selectors';
|
|
8
|
+
|
|
9
|
+
export function useLicenseLimits() {
|
|
10
|
+
const permissions = useSelector(selectAdminPermissions);
|
|
11
|
+
const { get } = useFetchClient();
|
|
12
|
+
const {
|
|
13
|
+
isLoading: isRBACLoading,
|
|
14
|
+
allowedActions: { canRead, canCreate, canUpdate, canDelete },
|
|
15
|
+
} = useRBAC(permissions.settings.users);
|
|
16
|
+
const hasPermissions = canRead && canCreate && canUpdate && canDelete;
|
|
17
|
+
|
|
18
|
+
const { data, isError, isLoading } = useQuery(
|
|
19
|
+
['ee', 'license-limit-info'],
|
|
20
|
+
async () => {
|
|
21
|
+
const {
|
|
22
|
+
data: { data },
|
|
23
|
+
} = await get('/admin/license-limit-information');
|
|
24
|
+
|
|
25
|
+
return data;
|
|
26
|
+
},
|
|
27
|
+
{
|
|
28
|
+
enabled: !isRBACLoading && hasPermissions,
|
|
29
|
+
}
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
const license = data ?? {};
|
|
33
|
+
|
|
34
|
+
const getFeature = React.useCallback(
|
|
35
|
+
(name) => {
|
|
36
|
+
const feature = (license?.features ?? []).find((feature) => feature.name === name);
|
|
37
|
+
|
|
38
|
+
return feature?.options ?? {};
|
|
39
|
+
},
|
|
40
|
+
[license?.features]
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
return { license, getFeature, isError, isLoading };
|
|
44
|
+
}
|
|
@@ -20,7 +20,7 @@ export const ROUTES_EE = [
|
|
|
20
20
|
{
|
|
21
21
|
async Component() {
|
|
22
22
|
const component = await import(
|
|
23
|
-
/* webpackChunkName: "review-workflows-settings" */ './pages/ReviewWorkflows'
|
|
23
|
+
/* webpackChunkName: "review-workflows-settings-list-view" */ './pages/ReviewWorkflows/pages/ListView'
|
|
24
24
|
);
|
|
25
25
|
|
|
26
26
|
return component;
|
|
@@ -28,6 +28,30 @@ export const ROUTES_EE = [
|
|
|
28
28
|
to: '/settings/review-workflows',
|
|
29
29
|
exact: true,
|
|
30
30
|
},
|
|
31
|
+
|
|
32
|
+
{
|
|
33
|
+
async Component() {
|
|
34
|
+
const component = await import(
|
|
35
|
+
/* webpackChunkName: "review-workflows-settings-create-view" */ './pages/ReviewWorkflows/pages/CreateView'
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
return component;
|
|
39
|
+
},
|
|
40
|
+
to: '/settings/review-workflows/create',
|
|
41
|
+
exact: true,
|
|
42
|
+
},
|
|
43
|
+
|
|
44
|
+
{
|
|
45
|
+
async Component() {
|
|
46
|
+
const component = await import(
|
|
47
|
+
/* webpackChunkName: "review-workflows-settings-edit-view" */ './pages/ReviewWorkflows/pages/EditView'
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
return component;
|
|
51
|
+
},
|
|
52
|
+
to: '/settings/review-workflows/:workflowId',
|
|
53
|
+
exact: true,
|
|
54
|
+
},
|
|
31
55
|
]
|
|
32
56
|
: []),
|
|
33
57
|
|
package/ee/admin/pages/SettingsPage/pages/ApplicationInfosPage/components/AdminSeatInfo/index.js
CHANGED
|
@@ -13,11 +13,13 @@ const BILLING_SELF_HOSTED_URL = 'https://strapi.io/billing/request-seats';
|
|
|
13
13
|
|
|
14
14
|
const AdminSeatInfo = () => {
|
|
15
15
|
const { formatMessage } = useIntl();
|
|
16
|
-
const {
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
const {
|
|
17
|
+
license: { licenseLimitStatus, enforcementUserCount, permittedSeats, isHostedOnStrapiCloud },
|
|
18
|
+
isError,
|
|
19
|
+
isLoading,
|
|
20
|
+
} = useLicenseLimits();
|
|
19
21
|
|
|
20
|
-
if (!permittedSeats) {
|
|
22
|
+
if (isError || isLoading || !permittedSeats) {
|
|
21
23
|
return null;
|
|
22
24
|
}
|
|
23
25
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useFetchClient, useNotification } from '@strapi/helper-plugin';
|
|
1
|
+
import { useFetchClient, useNotification, useQueryParams } from '@strapi/helper-plugin';
|
|
2
2
|
import { useQuery } from 'react-query';
|
|
3
3
|
import { useLocation } from 'react-router-dom';
|
|
4
4
|
|
|
@@ -8,6 +8,7 @@ const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
|
|
|
8
8
|
const { get } = useFetchClient();
|
|
9
9
|
const { search } = useLocation();
|
|
10
10
|
const toggleNotification = useNotification();
|
|
11
|
+
const [{ query }] = useQueryParams();
|
|
11
12
|
|
|
12
13
|
const queryOptions = {
|
|
13
14
|
keepPreviousData: true,
|
|
@@ -35,9 +36,10 @@ const useAuditLogsData = ({ canReadAuditLogs, canReadUsers }) => {
|
|
|
35
36
|
isError: isAuditLogsError,
|
|
36
37
|
} = useQuery(
|
|
37
38
|
['auditLogs', search],
|
|
38
|
-
async (
|
|
39
|
-
const
|
|
40
|
-
|
|
39
|
+
async () => {
|
|
40
|
+
const { data } = await get(`/admin/audit-logs`, {
|
|
41
|
+
params: query,
|
|
42
|
+
});
|
|
41
43
|
|
|
42
44
|
return data;
|
|
43
45
|
},
|
|
@@ -33,17 +33,12 @@ const ListView = () => {
|
|
|
33
33
|
const { formatMessage } = useIntl();
|
|
34
34
|
const permissions = useSelector(selectAdminPermissions);
|
|
35
35
|
|
|
36
|
-
// TODO: this is necessary because otherwise we run into an
|
|
37
|
-
// infinite rendering loop
|
|
38
|
-
const permissionsMemoized = React.useMemo(() => {
|
|
39
|
-
return {
|
|
40
|
-
...permissions.settings.auditLogs,
|
|
41
|
-
readUsers: permissions.settings.users.read,
|
|
42
|
-
};
|
|
43
|
-
}, [permissions.settings.auditLogs, permissions.settings.users.read]);
|
|
44
36
|
const {
|
|
45
37
|
allowedActions: { canRead: canReadAuditLogs, canReadUsers },
|
|
46
|
-
} = useRBAC(
|
|
38
|
+
} = useRBAC({
|
|
39
|
+
...permissions.settings.auditLogs,
|
|
40
|
+
readUsers: permissions.settings.users.read,
|
|
41
|
+
});
|
|
47
42
|
|
|
48
43
|
const [{ query }, setQuery] = useQueryParams();
|
|
49
44
|
const { auditLogs, users, isLoading, hasError } = useAuditLogsData({
|
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ACTION_ADD_STAGE,
|
|
3
3
|
ACTION_DELETE_STAGE,
|
|
4
|
-
|
|
4
|
+
ACTION_RESET_WORKFLOW,
|
|
5
|
+
ACTION_SET_WORKFLOW,
|
|
5
6
|
ACTION_UPDATE_STAGE,
|
|
6
7
|
ACTION_UPDATE_STAGE_POSITION,
|
|
8
|
+
ACTION_UPDATE_WORKFLOW,
|
|
7
9
|
} from '../constants';
|
|
8
10
|
|
|
9
|
-
export function
|
|
11
|
+
export function setWorkflow({ status, data }) {
|
|
10
12
|
return {
|
|
11
|
-
type:
|
|
13
|
+
type: ACTION_SET_WORKFLOW,
|
|
12
14
|
payload: {
|
|
13
15
|
status,
|
|
14
|
-
|
|
16
|
+
workflow: data,
|
|
15
17
|
},
|
|
16
18
|
};
|
|
17
19
|
}
|
|
@@ -51,3 +53,16 @@ export function updateStagePosition(oldIndex, newIndex) {
|
|
|
51
53
|
},
|
|
52
54
|
};
|
|
53
55
|
}
|
|
56
|
+
|
|
57
|
+
export function updateWorkflow(payload) {
|
|
58
|
+
return {
|
|
59
|
+
type: ACTION_UPDATE_WORKFLOW,
|
|
60
|
+
payload,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export function resetWorkflow() {
|
|
65
|
+
return {
|
|
66
|
+
type: ACTION_RESET_WORKFLOW,
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/* eslint-disable react/prop-types */
|
|
2
|
+
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
|
|
5
|
+
import { ContentLayout, HeaderLayout, Layout, Main } from '@strapi/design-system';
|
|
6
|
+
import { Link, SettingsPageTitle } from '@strapi/helper-plugin';
|
|
7
|
+
import { ArrowLeft } from '@strapi/icons';
|
|
8
|
+
import { useIntl } from 'react-intl';
|
|
9
|
+
|
|
10
|
+
import { DragLayer } from '../../../../../../../../admin/src/components/DragLayer';
|
|
11
|
+
import { DRAG_DROP_TYPES } from '../../constants';
|
|
12
|
+
import { StageDragPreview } from '../StageDragPreview';
|
|
13
|
+
|
|
14
|
+
function renderDragLayerItem({ type, item }) {
|
|
15
|
+
switch (type) {
|
|
16
|
+
case DRAG_DROP_TYPES.STAGE:
|
|
17
|
+
return <StageDragPreview {...item} />;
|
|
18
|
+
|
|
19
|
+
default:
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function DragLayerRendered() {
|
|
25
|
+
return <DragLayer renderItem={renderDragLayerItem} />;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function Root({ children }) {
|
|
29
|
+
return (
|
|
30
|
+
<Layout>
|
|
31
|
+
<Main tabIndex={-1}>
|
|
32
|
+
<ContentLayout>{children}</ContentLayout>
|
|
33
|
+
</Main>
|
|
34
|
+
</Layout>
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function Back({ href }) {
|
|
39
|
+
const { formatMessage } = useIntl();
|
|
40
|
+
|
|
41
|
+
return (
|
|
42
|
+
<Link startIcon={<ArrowLeft />} to={href}>
|
|
43
|
+
{formatMessage({
|
|
44
|
+
id: 'global.back',
|
|
45
|
+
defaultMessage: 'Back',
|
|
46
|
+
})}
|
|
47
|
+
</Link>
|
|
48
|
+
);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function Header({ title, subtitle, navigationAction, primaryAction }) {
|
|
52
|
+
return (
|
|
53
|
+
<>
|
|
54
|
+
<SettingsPageTitle name={title} />
|
|
55
|
+
<HeaderLayout
|
|
56
|
+
navigationAction={navigationAction}
|
|
57
|
+
primaryAction={primaryAction}
|
|
58
|
+
title={title}
|
|
59
|
+
subtitle={subtitle}
|
|
60
|
+
/>
|
|
61
|
+
</>
|
|
62
|
+
);
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export { Back, DragLayerRendered, Header, Root };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './Layout';
|
package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/LimitsModal.js
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
|
|
3
|
+
import { Box, Flex, IconButton, ModalLayout, ModalBody, Typography } from '@strapi/design-system';
|
|
4
|
+
import { LinkButton } from '@strapi/design-system/v2';
|
|
5
|
+
import { Cross } from '@strapi/icons';
|
|
6
|
+
import PropTypes from 'prop-types';
|
|
7
|
+
import { useIntl } from 'react-intl';
|
|
8
|
+
import styled from 'styled-components';
|
|
9
|
+
|
|
10
|
+
import balloonImageSrc from './assets/balloon.png';
|
|
11
|
+
|
|
12
|
+
const TITLE_ID = 'limits-title';
|
|
13
|
+
|
|
14
|
+
const CTA_LEARN_MORE_HREF = 'https://strapi.io/pricing-cloud';
|
|
15
|
+
const CTA_SALES_HREF = 'https://strapi.io/contact-sales';
|
|
16
|
+
|
|
17
|
+
export function Title({ children }) {
|
|
18
|
+
return (
|
|
19
|
+
<Typography variant="alpha" id={TITLE_ID}>
|
|
20
|
+
{children}
|
|
21
|
+
</Typography>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
Title.propTypes = {
|
|
26
|
+
children: PropTypes.node.isRequired,
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
export function Body({ children }) {
|
|
30
|
+
return <Typography variant="omega">{children}</Typography>;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
Body.propTypes = {
|
|
34
|
+
children: PropTypes.node.isRequired,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function CallToActions() {
|
|
38
|
+
const { formatMessage } = useIntl();
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<Flex gap={2} paddingTop={4}>
|
|
42
|
+
<LinkButton variant="default" isExternal href={CTA_LEARN_MORE_HREF}>
|
|
43
|
+
{formatMessage({
|
|
44
|
+
id: 'Settings.review-workflows.limit.cta.learn',
|
|
45
|
+
defaultMessage: 'Learn more',
|
|
46
|
+
})}
|
|
47
|
+
</LinkButton>
|
|
48
|
+
|
|
49
|
+
<LinkButton variant="tertiary" isExternal href={CTA_SALES_HREF}>
|
|
50
|
+
{formatMessage({
|
|
51
|
+
id: 'Settings.review-workflows.limit.cta.sales',
|
|
52
|
+
defaultMessage: 'Contact Sales',
|
|
53
|
+
})}
|
|
54
|
+
</LinkButton>
|
|
55
|
+
</Flex>
|
|
56
|
+
);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const BalloonImage = styled.img`
|
|
60
|
+
// Margin top|right reverse the padding of ModalBody
|
|
61
|
+
margin-right: ${({ theme }) => `-${theme.spaces[7]}`};
|
|
62
|
+
margin-top: ${({ theme }) => `-${theme.spaces[7]}`};
|
|
63
|
+
width: 360px;
|
|
64
|
+
`;
|
|
65
|
+
|
|
66
|
+
export function LimitsModal({ children, isOpen, onClose }) {
|
|
67
|
+
const { formatMessage } = useIntl();
|
|
68
|
+
|
|
69
|
+
if (!isOpen) {
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<ModalLayout labelledBy={TITLE_ID}>
|
|
75
|
+
<ModalBody>
|
|
76
|
+
<Flex gap={2} paddingLeft={7} position="relative">
|
|
77
|
+
<Flex alignItems="start" direction="column" gap={2} width="60%">
|
|
78
|
+
{children}
|
|
79
|
+
|
|
80
|
+
<CallToActions />
|
|
81
|
+
</Flex>
|
|
82
|
+
|
|
83
|
+
<Flex justifyContent="end" height="100%" width="40%">
|
|
84
|
+
<BalloonImage src={balloonImageSrc} aria-hidden alt="" loading="lazy" />
|
|
85
|
+
|
|
86
|
+
<Box display="flex" position="absolute" right={0} top={0}>
|
|
87
|
+
<IconButton
|
|
88
|
+
icon={<Cross />}
|
|
89
|
+
aria-label={formatMessage({
|
|
90
|
+
id: 'global.close',
|
|
91
|
+
defaultMessage: 'Close',
|
|
92
|
+
})}
|
|
93
|
+
onClick={onClose}
|
|
94
|
+
/>
|
|
95
|
+
</Box>
|
|
96
|
+
</Flex>
|
|
97
|
+
</Flex>
|
|
98
|
+
</ModalBody>
|
|
99
|
+
</ModalLayout>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
LimitsModal.defaultProps = {
|
|
104
|
+
isOpen: false,
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
LimitsModal.propTypes = {
|
|
108
|
+
children: PropTypes.node.isRequired,
|
|
109
|
+
isOpen: PropTypes.bool,
|
|
110
|
+
onClose: PropTypes.func.isRequired,
|
|
111
|
+
};
|
package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/assets/balloon.png
ADDED
|
Binary file
|