@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.
Files changed (176) hide show
  1. package/admin/src/components/AuthenticatedApp/index.js +2 -2
  2. package/admin/src/constants.js +83 -83
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +8 -5
  4. package/admin/src/content-manager/components/Inputs/index.js +3 -47
  5. package/admin/src/content-manager/components/RelationInput/RelationInput.js +99 -178
  6. package/admin/src/content-manager/components/RelationInput/components/Option.js +17 -15
  7. package/admin/src/content-manager/components/RelationInput/components/RelationList.js +2 -2
  8. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +34 -37
  9. package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +0 -27
  10. package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +93 -14
  11. package/admin/src/content-manager/pages/ListView/index.js +65 -47
  12. package/admin/src/content-manager/pages/ListView/utils/buildValidGetParams.js +30 -0
  13. package/admin/src/content-manager/pages/ListView/utils/index.js +1 -1
  14. package/admin/src/content-manager/utils/mergeMetasWithSchema.js +5 -1
  15. package/admin/src/hooks/index.js +0 -1
  16. package/admin/src/hooks/useAdminUsers/useAdminUsers.js +3 -3
  17. package/admin/src/hooks/useEnterprise/useEnterprise.js +4 -4
  18. package/admin/src/pages/App/index.js +28 -23
  19. package/admin/src/pages/AuthPage/components/Register/index.js +5 -1
  20. package/admin/src/pages/ProfilePage/index.js +6 -1
  21. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +15 -1
  22. package/admin/src/pages/SettingsPage/components/Tokens/TokenBox/index.js +1 -1
  23. package/admin/src/pages/SettingsPage/pages/Roles/ProtectedEditPage/index.js +4 -10
  24. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -2
  25. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +11 -5
  26. package/admin/src/translations/ca.json +1 -0
  27. package/admin/src/translations/en.json +4 -1
  28. package/admin/src/translations/es.json +5 -0
  29. package/admin/src/translations/fr.json +1 -0
  30. package/admin/src/translations/zh-Hans.json +1 -1
  31. package/build/0cd5f8915b265d5b1856.png +0 -0
  32. package/build/2799.cf9b491f.chunk.js +1 -0
  33. package/build/4485.d3c6dd1d.chunk.js +6 -0
  34. package/build/539.865446c0.chunk.js +1 -0
  35. package/build/{5542.64b623c9.chunk.js → 5542.c62d0daf.chunk.js} +1 -1
  36. package/build/{5563.86f9aa9c.chunk.js → 5563.a146acac.chunk.js} +2 -2
  37. package/build/7018.f3dad3c1.chunk.js +1 -0
  38. package/build/7259.0e25ab5d.chunk.js +1 -0
  39. package/build/9465.d8fc1377.chunk.js +112 -0
  40. package/build/{6405.27e1bee5.chunk.js → 970.89601f27.chunk.js} +2 -2
  41. package/build/9944.29289a16.chunk.js +26 -0
  42. package/build/Admin-authenticatedApp.9d3afb79.chunk.js +79 -0
  43. package/build/{Admin_settingsPage.4069bb8a.chunk.js → Admin_settingsPage.074655f6.chunk.js} +13 -13
  44. package/build/admin-app.3ede71ad.chunk.js +61 -0
  45. package/build/{admin-edit-roles-page.2040034a.chunk.js → admin-edit-roles-page.3fdd6b9d.chunk.js} +11 -11
  46. package/build/admin-edit-users.78552758.chunk.js +10 -0
  47. package/build/admin-users.c23322fc.chunk.js +11 -0
  48. package/build/api-tokens-list-page.a103f526.chunk.js +16 -0
  49. package/build/audit-logs-settings-page.37fe915c.chunk.js +1 -0
  50. package/build/ca-json.1fed5d8b.chunk.js +1 -0
  51. package/build/content-manager.08541eeb.chunk.js +1094 -0
  52. package/build/{content-type-builder-list-view.0c3ceb4e.chunk.js → content-type-builder-list-view.a200a358.chunk.js} +1 -1
  53. package/build/content-type-builder-translation-en-json.38e20391.chunk.js +1 -0
  54. package/build/content-type-builder.de22f7c9.chunk.js +166 -0
  55. package/build/{email-settings-page.6b38222d.chunk.js → email-settings-page.45695daa.chunk.js} +1 -1
  56. package/build/en-json.fb9f6ddd.chunk.js +1 -0
  57. package/build/es-json.42096084.chunk.js +1 -0
  58. package/build/fr-json.69789980.chunk.js +1 -0
  59. package/build/{i18n-settings-page.ff863f20.chunk.js → i18n-settings-page.29308d0b.chunk.js} +1 -1
  60. package/build/index.html +1 -1
  61. package/build/main.a8ede50d.js +2927 -0
  62. package/build/review-workflows-settings-create-view.56f61e18.chunk.js +1 -0
  63. package/build/review-workflows-settings-edit-view.912bc9c0.chunk.js +1 -0
  64. package/build/review-workflows-settings-list-view.cf6a08d3.chunk.js +56 -0
  65. package/build/runtime~main.5e9bf4b3.js +2 -0
  66. package/build/sso-settings-page.0cdb96a6.chunk.js +1 -0
  67. package/build/transfer-tokens-list-page.7237443d.chunk.js +16 -0
  68. package/build/{upload-settings.43cf16cd.chunk.js → upload-settings.cb6c14c3.chunk.js} +1 -1
  69. package/build/{upload.72f8f8fc.chunk.js → upload.7e629643.chunk.js} +2 -2
  70. package/build/users-advanced-settings-page.750b1f76.chunk.js +9 -0
  71. package/build/{users-email-settings-page.33359797.chunk.js → users-email-settings-page.e9bcd865.chunk.js} +1 -1
  72. package/build/{users-providers-settings-page.1e7a4a71.chunk.js → users-providers-settings-page.a94253e9.chunk.js} +1 -1
  73. package/build/{users-roles-settings-page.235378b6.chunk.js → users-roles-settings-page.d286426a.chunk.js} +5 -5
  74. package/build/webhook-edit-page.77ef4f1a.chunk.js +33 -0
  75. package/build/{zh-Hans-json.4cfef87d.chunk.js → zh-Hans-json.fada6f40.chunk.js} +1 -1
  76. package/ee/admin/constants.js +14 -14
  77. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +84 -30
  78. package/ee/admin/content-manager/{components/DynamicTable/CellContent/ReviewWorkflowsStage → pages/ListView/ReviewWorkflowsColumn}/ReviewWorkflowsStageEE.js +7 -2
  79. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +24 -0
  80. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/index.js +1 -0
  81. package/ee/admin/hooks/useLicenseLimitNotification/index.js +17 -6
  82. package/ee/admin/hooks/useLicenseLimits/index.js +1 -32
  83. package/ee/admin/hooks/useLicenseLimits/useLicenseLimits.js +44 -0
  84. package/ee/admin/pages/SettingsPage/constants.js +25 -1
  85. package/ee/admin/pages/SettingsPage/pages/ApplicationInfosPage/components/AdminSeatInfo/index.js +6 -4
  86. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +6 -4
  87. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +4 -9
  88. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/actions/index.js +19 -4
  89. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Layout/Layout.js +65 -0
  90. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Layout/index.js +1 -0
  91. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/LimitsModal.js +111 -0
  92. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/assets/balloon.png +0 -0
  93. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/LimitsModal/index.js +3 -0
  94. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/ProtectedPage.js +21 -0
  95. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/index.js +1 -0
  96. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +4 -4
  97. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/WorkflowAttributes.js +110 -0
  98. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/WorkflowAttributes/index.js +1 -0
  99. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/constants.js +3 -1
  100. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +13 -19
  101. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +246 -0
  102. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/index.js +13 -0
  103. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +269 -0
  104. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/index.js +13 -0
  105. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +382 -0
  106. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/index.js +13 -0
  107. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +53 -23
  108. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/getWorkflowValidationSchema.js +43 -28
  109. package/ee/admin/pages/SettingsPage/pages/SingleSignOn/index.js +4 -9
  110. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +9 -2
  111. package/ee/server/config/admin-actions.js +24 -0
  112. package/ee/server/constants/default-stages.json +8 -4
  113. package/ee/server/constants/default-workflow.json +3 -1
  114. package/ee/server/constants/workflows.js +10 -1
  115. package/ee/server/content-types/workflow/index.js +10 -0
  116. package/ee/server/content-types/workflow-stage/index.js +3 -1
  117. package/ee/server/controllers/admin.js +1 -0
  118. package/ee/server/controllers/workflows/index.js +135 -8
  119. package/ee/server/controllers/workflows/stages/index.js +38 -38
  120. package/ee/server/migrations/review-workflows-content-types.js +29 -0
  121. package/ee/server/migrations/review-workflows-deleted-ct-in-workflows.js +39 -0
  122. package/ee/server/migrations/review-workflows-stage-attribute.js +49 -0
  123. package/ee/server/migrations/review-workflows-stages-color.js +2 -2
  124. package/ee/server/migrations/review-workflows-workflow-name.js +21 -0
  125. package/ee/server/register.js +12 -2
  126. package/ee/server/routes/review-workflows.js +44 -10
  127. package/ee/server/services/index.js +1 -0
  128. package/ee/server/services/review-workflows/entity-service-decorator.js +28 -24
  129. package/ee/server/services/review-workflows/review-workflows.js +45 -53
  130. package/ee/server/services/review-workflows/stages.js +84 -46
  131. package/ee/server/services/review-workflows/validation.js +60 -0
  132. package/ee/server/services/review-workflows/workflows/content-types.js +80 -0
  133. package/ee/server/services/review-workflows/workflows/index.js +207 -0
  134. package/ee/server/utils/review-workflows.js +30 -25
  135. package/ee/server/validation/review-workflows.js +49 -10
  136. package/package.json +13 -14
  137. package/server/content-types/User.js +10 -0
  138. package/server/strategies/api-token.js +9 -5
  139. package/server/strategies/data-transfer.js +9 -5
  140. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +0 -2
  141. package/admin/src/content-manager/components/RelationInput/components/Relation.js +0 -53
  142. package/admin/src/content-manager/pages/ListView/utils/buildQueryString.js +0 -36
  143. package/admin/src/content-manager/pages/ListView/utils/createPluginsFilter.js +0 -4
  144. package/admin/src/hooks/useLicenseLimits/index.js +0 -3
  145. package/admin/src/pages/App/utils/index.js +0 -3
  146. package/admin/src/pages/App/utils/unique-identifier.js +0 -12
  147. package/build/1799.84268ad3.chunk.js +0 -33
  148. package/build/5932.6a23b88c.chunk.js +0 -1
  149. package/build/7018.98feed67.chunk.js +0 -1
  150. package/build/7259.fb69d4bf.chunk.js +0 -1
  151. package/build/Admin-authenticatedApp.69855f1b.chunk.js +0 -79
  152. package/build/admin-app.fea867af.chunk.js +0 -61
  153. package/build/admin-edit-users.53e4290a.chunk.js +0 -10
  154. package/build/admin-users.3b12dca2.chunk.js +0 -11
  155. package/build/api-tokens-list-page.201fb67a.chunk.js +0 -16
  156. package/build/audit-logs-settings-page.b07ad202.chunk.js +0 -1
  157. package/build/ca-json.43e14418.chunk.js +0 -1
  158. package/build/content-manager.66cec770.chunk.js +0 -1094
  159. package/build/content-type-builder-translation-en-json.f592325b.chunk.js +0 -1
  160. package/build/content-type-builder.e1b6d13b.chunk.js +0 -166
  161. package/build/en-json.f5fa476a.chunk.js +0 -1
  162. package/build/es-json.715b6fd8.chunk.js +0 -1
  163. package/build/fr-json.73494bf5.chunk.js +0 -1
  164. package/build/main.83edb3fc.js +0 -2926
  165. package/build/review-workflows-settings.93808ae0.chunk.js +0 -110
  166. package/build/runtime~main.20c3cac6.js +0 -2
  167. package/build/sso-settings-page.35b67909.chunk.js +0 -1
  168. package/build/transfer-tokens-list-page.217573c3.chunk.js +0 -16
  169. package/build/users-advanced-settings-page.1911adf5.chunk.js +0 -9
  170. package/build/webhook-edit-page.1ee02c4b.chunk.js +0 -33
  171. package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +0 -58
  172. package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +0 -3
  173. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ProtectedPage.js +0 -20
  174. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +0 -204
  175. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/index.js +0 -3
  176. package/ee/server/services/review-workflows/workflows.js +0 -25
@@ -10,8 +10,6 @@ import {
10
10
  HeaderLayout,
11
11
  useNotifyAT,
12
12
  Flex,
13
- Typography,
14
- Status,
15
13
  } from '@strapi/design-system';
16
14
  import {
17
15
  NoPermissions,
@@ -44,6 +42,7 @@ import { bindActionCreators, compose } from 'redux';
44
42
  import styled from 'styled-components';
45
43
 
46
44
  import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
45
+ import { useEnterprise } from '../../../hooks/useEnterprise';
47
46
  import { selectAdminPermissions } from '../../../pages/App/selectors';
48
47
  import { InjectionZone } from '../../../shared/components';
49
48
  import AttributeFilter from '../../components/AttributeFilter';
@@ -56,7 +55,7 @@ import { ConfirmDialogDeleteAll } from './components/ConfirmDialogDeleteAll';
56
55
  import { FieldPicker } from './components/FieldPicker';
57
56
  import { TableRows } from './components/TableRows';
58
57
  import makeSelectListView, { selectDisplayedHeaders } from './selectors';
59
- import { buildQueryString } from './utils';
58
+ import { buildValidGetParams } from './utils';
60
59
 
61
60
  const ConfigureLayoutBox = styled(Box)`
62
61
  svg {
@@ -66,6 +65,8 @@ const ConfigureLayoutBox = styled(Box)`
66
65
  }
67
66
  `;
68
67
 
68
+ const REVIEW_WORKFLOW_COLUMNS_CE = null;
69
+
69
70
  function ListView({
70
71
  canCreate,
71
72
  canDelete,
@@ -100,14 +101,30 @@ function ListView({
100
101
  useFocusWhenNavigate();
101
102
 
102
103
  const [{ query }] = useQueryParams();
103
- const params = buildQueryString(query);
104
+ const params = React.useMemo(() => buildValidGetParams(query), [query]);
104
105
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
105
106
 
106
107
  const { pathname } = useLocation();
107
108
  const { push } = useHistory();
108
109
  const { formatMessage } = useIntl();
109
- const hasDraftAndPublish = options?.draftAndPublish || false;
110
110
  const fetchClient = useFetchClient();
111
+
112
+ const hasDraftAndPublish = options?.draftAndPublish ?? false;
113
+ const hasReviewWorkflows = options?.reviewWorkflows ?? false;
114
+
115
+ const reviewWorkflowColumns = useEnterprise(
116
+ REVIEW_WORKFLOW_COLUMNS_CE,
117
+ async () =>
118
+ (
119
+ await import(
120
+ '../../../../../ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants'
121
+ )
122
+ ).REVIEW_WORKFLOW_COLUMNS_EE,
123
+ {
124
+ enabled: !!options?.reviewWorkflows,
125
+ }
126
+ );
127
+
111
128
  const { post, del } = fetchClient;
112
129
 
113
130
  const bulkPublishMutation = useMutation(
@@ -120,7 +137,7 @@ function ListView({
120
137
  message: { id: 'content-manager.success.record.publish', defaultMessage: 'Published' },
121
138
  });
122
139
 
123
- fetchData(`/content-manager/collection-types/${slug}${params}`);
140
+ fetchData(`/content-manager/collection-types/${slug}`, { params });
124
141
  },
125
142
  onError(error) {
126
143
  toggleNotification({
@@ -143,7 +160,7 @@ function ListView({
143
160
  },
144
161
  });
145
162
 
146
- fetchData(`/content-manager/collection-types/${slug}${params}`);
163
+ fetchData(`/content-manager/collection-types/${slug}`, { params });
147
164
  },
148
165
  onError(error) {
149
166
  toggleNotification({
@@ -158,19 +175,17 @@ function ListView({
158
175
  // Using a ref to avoid requests being fired multiple times on slug on change
159
176
  // We need it because the hook as mulitple dependencies so it may run before the permissions have checked
160
177
  const requestUrlRef = React.useRef('');
161
-
162
178
  /**
163
179
  * TODO: re-write all of this, it's a mess.
164
180
  */
165
181
  const fetchData = React.useCallback(
166
- async (endPoint, source) => {
182
+ async (endPoint, options) => {
167
183
  getData();
168
184
 
169
185
  try {
170
- const opts = source ? { cancelToken: source.token } : null;
171
186
  const {
172
187
  data: { results, pagination: paginationResult },
173
- } = await fetchClient.get(endPoint, opts);
188
+ } = await fetchClient.get(endPoint, options);
174
189
 
175
190
  notifyStatus(
176
191
  formatMessage(
@@ -217,12 +232,12 @@ function ListView({
217
232
  const handleConfirmDeleteAllData = React.useCallback(
218
233
  async (ids) => {
219
234
  try {
220
- await post(getRequestUrl(`collection-types/${slug}/actions/bulkDelete`), {
235
+ await post(`/content-manager/collection-types/${slug}/actions/bulkDelete`, {
221
236
  ids,
222
237
  });
223
238
 
224
- const requestUrl = getRequestUrl(`collection-types/${slug}${params}`);
225
- fetchData(requestUrl);
239
+ fetchData(`/content-manager/collection-types/${slug}`, { params });
240
+
226
241
  trackUsageRef.current('didBulkDeleteEntries');
227
242
  } catch (err) {
228
243
  toggleNotification({
@@ -231,16 +246,16 @@ function ListView({
231
246
  });
232
247
  }
233
248
  },
234
- [fetchData, params, slug, toggleNotification, formatAPIError, post]
249
+ [slug, toggleNotification, formatAPIError, post, fetchData, params]
235
250
  );
236
251
 
237
252
  const handleConfirmDeleteData = React.useCallback(
238
253
  async (idToDelete) => {
239
254
  try {
240
- await del(getRequestUrl(`collection-types/${slug}/${idToDelete}`));
255
+ await del(`/content-manager/collection-types/${slug}/${idToDelete}`);
241
256
 
242
- const requestUrl = getRequestUrl(`collection-types/${slug}${params}`);
243
- fetchData(requestUrl);
257
+ const requestUrl = getRequestUrl(`collection-types/${slug}`);
258
+ fetchData(requestUrl, { params });
244
259
 
245
260
  toggleNotification({
246
261
  type: 'success',
@@ -253,7 +268,7 @@ function ListView({
253
268
  });
254
269
  }
255
270
  },
256
- [slug, params, fetchData, toggleNotification, formatAPIError, del]
271
+ [slug, toggleNotification, formatAPIError, del, fetchData, params]
257
272
  );
258
273
 
259
274
  /**
@@ -325,10 +340,10 @@ function ListView({
325
340
  const source = CancelToken.source();
326
341
 
327
342
  const shouldSendRequest = canRead;
328
- const requestUrl = getRequestUrl(`collection-types/${slug}${params}`);
343
+ const requestUrl = getRequestUrl(`collection-types/${slug}`);
329
344
 
330
345
  if (shouldSendRequest && requestUrl.includes(requestUrlRef.current)) {
331
- fetchData(requestUrl, source);
346
+ fetchData(requestUrl, { cancelToken: source.token, params });
332
347
  }
333
348
 
334
349
  return () => {
@@ -387,13 +402,8 @@ function ListView({
387
402
  };
388
403
  });
389
404
 
390
- if (!hasDraftAndPublish) {
391
- return formattedHeaders;
392
- }
393
-
394
- return [
395
- ...formattedHeaders,
396
- {
405
+ if (hasDraftAndPublish) {
406
+ formattedHeaders.push({
397
407
  key: '__published_at_temp_key__',
398
408
  name: 'publishedAt',
399
409
  fieldSchema: {
@@ -407,25 +417,29 @@ function ListView({
407
417
  searchable: false,
408
418
  sortable: true,
409
419
  },
410
- // eslint-disable-next-line react/no-unstable-nested-components
411
- cellFormatter(cellData) {
412
- const isPublished = cellData.publishedAt;
413
- const variant = isPublished ? 'success' : 'secondary';
414
-
415
- return (
416
- <Status width="min-content" showBullet={false} variant={variant} size="S">
417
- <Typography fontWeight="bold" textColor={`${variant}700`}>
418
- {formatMessage({
419
- id: getTrad(`containers.List.${isPublished ? 'published' : 'draft'}`),
420
- defaultMessage: isPublished ? 'Published' : 'Draft',
421
- })}
422
- </Typography>
423
- </Status>
424
- );
425
- },
426
- },
427
- ];
428
- }, [runHookWaterfall, displayedHeaders, layout, hasDraftAndPublish, formatMessage]);
420
+ });
421
+ }
422
+
423
+ if (reviewWorkflowColumns) {
424
+ // Make sure the column header label is translated
425
+ if (typeof reviewWorkflowColumns.metadatas.label !== 'string') {
426
+ reviewWorkflowColumns.metadatas.label = formatMessage(
427
+ reviewWorkflowColumns.metadatas.label
428
+ );
429
+ }
430
+
431
+ formattedHeaders.push(reviewWorkflowColumns);
432
+ }
433
+
434
+ return formattedHeaders;
435
+ }, [
436
+ runHookWaterfall,
437
+ displayedHeaders,
438
+ layout,
439
+ reviewWorkflowColumns,
440
+ hasDraftAndPublish,
441
+ formatMessage,
442
+ ]);
429
443
 
430
444
  const subtitle = canRead
431
445
  ? formatMessage(
@@ -568,6 +582,10 @@ function ListView({
568
582
  canCreate={canCreate}
569
583
  canDelete={canDelete}
570
584
  contentType={contentType}
585
+ features={{
586
+ hasDraftAndPublish,
587
+ hasReviewWorkflows,
588
+ }}
571
589
  headers={tableHeaders}
572
590
  rows={data}
573
591
  withBulkActions
@@ -0,0 +1,30 @@
1
+ const createPluginsFilter = (obj = {}) =>
2
+ Object.values(obj).reduce((acc, current) => Object.assign(acc, current), {});
3
+
4
+ /**
5
+ * @description
6
+ * Creates a valid query params object for get requests
7
+ * ie. plugins[18n][locale]=en becomes locale=en
8
+ * @param {object} [query={}] - The query params
9
+ * @returns {object} - The modified query params
10
+ */
11
+ const buildValidGetParams = (query = {}) => {
12
+ // Extract pluginOptions from the query, they shouldn't be part of the URL
13
+ const {
14
+ plugins: _,
15
+ _q: searchQuery,
16
+ ...validQueryParams
17
+ } = {
18
+ ...query,
19
+ ...createPluginsFilter(query.plugins),
20
+ };
21
+
22
+ if (searchQuery) {
23
+ // Encode the search query here since the paramsSerializer will not
24
+ validQueryParams._q = encodeURIComponent(searchQuery);
25
+ }
26
+
27
+ return validQueryParams;
28
+ };
29
+
30
+ export default buildValidGetParams;
@@ -1 +1 @@
1
- export { default as buildQueryString } from './buildQueryString';
1
+ export { default as buildValidGetParams } from './buildValidGetParams';
@@ -1,3 +1,4 @@
1
+ import merge from 'lodash/merge';
1
2
  import set from 'lodash/set';
2
3
 
3
4
  const mergeMetasWithSchema = (data, schemas, mainSchemaKey) => {
@@ -6,7 +7,10 @@ const mergeMetasWithSchema = (data, schemas, mainSchemaKey) => {
6
7
  const mainUID = data[mainSchemaKey].uid;
7
8
  const mainSchema = findSchema(mainUID);
8
9
 
9
- set(merged, [mainSchemaKey], { ...data[mainSchemaKey], ...mainSchema });
10
+ // TODO
11
+ // In order to merge all the layers of the schema objects, we used the Lodash function "merge".
12
+ // If the destructuration is used, it will only merge the first layer of properties and overwrite the nested objects.
13
+ set(merged, [mainSchemaKey], merge({}, mainSchema, data[mainSchemaKey]));
10
14
 
11
15
  Object.keys(data.components).forEach((compoUID) => {
12
16
  const compoSchema = findSchema(compoUID);
@@ -3,7 +3,6 @@ export { useContentTypes } from './useContentTypes';
3
3
  export { default as useFetchPermissionsLayout } from './useFetchPermissionsLayout';
4
4
  export { default as useFetchRole } from './useFetchRole';
5
5
  export { default as useLicenseLimitNotification } from './useLicenseLimitNotification';
6
- export { default as useLicenseLimit } from './useLicenseLimits';
7
6
  export { default as useMenu } from './useMenu';
8
7
  export { default as usePermissionsDataManager } from './usePermissionsDataManager';
9
8
  export { default as useRegenerate } from './useRegenerate';
@@ -1,10 +1,8 @@
1
1
  import { useFetchClient } from '@strapi/helper-plugin';
2
- import { stringify } from 'qs';
3
2
  import { useQuery } from 'react-query';
4
3
 
5
4
  export function useAdminUsers(params = {}, queryOptions = {}) {
6
5
  const { id = '', ...queryParams } = params;
7
- const queryString = stringify(queryParams, { encode: false });
8
6
 
9
7
  const { get } = useFetchClient();
10
8
 
@@ -13,7 +11,9 @@ export function useAdminUsers(params = {}, queryOptions = {}) {
13
11
  async () => {
14
12
  const {
15
13
  data: { data },
16
- } = await get(`/admin/users/${id}${queryString ? `?${queryString}` : ''}`);
14
+ } = await get(`/admin/users/${id}`, {
15
+ params: queryParams,
16
+ });
17
17
 
18
18
  return data;
19
19
  },
@@ -9,7 +9,7 @@ function isEnterprise() {
9
9
  export function useEnterprise(
10
10
  ceData,
11
11
  eeCallback,
12
- { defaultValue = null, combine = (ceData, eeData) => eeData } = {}
12
+ { defaultValue = null, combine = (ceData, eeData) => eeData, enabled = true } = {}
13
13
  ) {
14
14
  const eeCallbackRef = useCallbackRef(eeCallback);
15
15
  const combineCallbackRef = useCallbackRef(combine);
@@ -17,7 +17,7 @@ export function useEnterprise(
17
17
  // We have to use a nested object here, because functions (e.g. Components)
18
18
  // can not be stored as value directly
19
19
  const [{ data }, setData] = React.useState({
20
- data: isEnterprise() ? defaultValue : ceData,
20
+ data: isEnterprise() && enabled ? defaultValue : ceData,
21
21
  });
22
22
 
23
23
  React.useEffect(() => {
@@ -27,10 +27,10 @@ export function useEnterprise(
27
27
  setData({ data: combineCallbackRef(ceData, eeData) });
28
28
  }
29
29
 
30
- if (isEnterprise()) {
30
+ if (isEnterprise() && enabled) {
31
31
  importEE();
32
32
  }
33
- }, [ceData, eeCallbackRef, combineCallbackRef]);
33
+ }, [ceData, eeCallbackRef, combineCallbackRef, enabled]);
34
34
 
35
35
  return data;
36
36
  }
@@ -31,21 +31,24 @@ import NotFoundPage from '../NotFoundPage';
31
31
  import UseCasePage from '../UseCasePage';
32
32
 
33
33
  import { ROUTES_CE, SET_ADMIN_PERMISSIONS } from './constants';
34
- import { getUID } from './utils';
35
34
 
36
35
  const AuthenticatedApp = lazy(() =>
37
36
  import(/* webpackChunkName: "Admin-authenticatedApp" */ '../../components/AuthenticatedApp')
38
37
  );
39
38
 
40
39
  function App() {
41
- const adminPermissions = useEnterprise(ADMIN_PERMISSIONS_CE, async () => (await import('../../../../ee/admin/constants')).ADMIN_PERMISSIONS_EE, {
42
- combine(cePermissions, eePermissions) {
43
- // the `settings` NS e.g. are deep nested objects, that need a deep merge
44
- return merge({}, cePermissions, eePermissions);
45
- },
46
-
47
- defaultValue: ADMIN_PERMISSIONS_CE,
48
- })
40
+ const adminPermissions = useEnterprise(
41
+ ADMIN_PERMISSIONS_CE,
42
+ async () => (await import('../../../../ee/admin/constants')).ADMIN_PERMISSIONS_EE,
43
+ {
44
+ combine(cePermissions, eePermissions) {
45
+ // the `settings` NS e.g. are deep nested objects, that need a deep merge
46
+ return merge({}, cePermissions, eePermissions);
47
+ },
48
+
49
+ defaultValue: ADMIN_PERMISSIONS_CE,
50
+ }
51
+ );
49
52
  const routes = useEnterprise(
50
53
  ROUTES_CE,
51
54
  async () => (await import('../../../../ee/admin/pages/App/constants')).ROUTES_EE,
@@ -113,8 +116,6 @@ function App() {
113
116
  authLogo: prefixFileUrlWithBackendUrl(authLogo),
114
117
  });
115
118
 
116
- const deviceId = await getUID();
117
-
118
119
  if (uuid) {
119
120
  const {
120
121
  data: { data: properties },
@@ -127,19 +128,23 @@ function App() {
127
128
 
128
129
  try {
129
130
  const event = 'didInitializeAdministration';
130
- await post('https://analytics.strapi.io/api/v2/track', {
131
- // This event is anonymous
132
- event,
133
- userId: '',
134
- deviceId,
135
- eventPropeties: {},
136
- userProperties: { environment: appInfo.currentEnvironment },
137
- groupProperties: { ...properties, projectId: uuid },
138
- }, {
139
- headers: {
140
- 'X-Strapi-Event': event,
131
+ await post(
132
+ 'https://analytics.strapi.io/api/v2/track',
133
+ {
134
+ // This event is anonymous
135
+ event,
136
+ userId: '',
137
+ deviceId,
138
+ eventPropeties: {},
139
+ userProperties: { environment: appInfo.currentEnvironment },
140
+ groupProperties: { ...properties, projectId: uuid },
141
+ },
142
+ {
143
+ headers: {
144
+ 'X-Strapi-Event': event,
145
+ },
141
146
  }
142
- });
147
+ );
143
148
  } catch (e) {
144
149
  // Silent.
145
150
  }
@@ -64,7 +64,11 @@ const Register = ({ authType, fieldsToDisable, noSignin, onSubmit, schema }) =>
64
64
  try {
65
65
  const {
66
66
  data: { data },
67
- } = await get(`/admin/registration-info?registrationToken=${registrationToken}`);
67
+ } = await get(`/admin/registration-info`, {
68
+ params: {
69
+ registrationToken,
70
+ },
71
+ });
68
72
 
69
73
  if (data) {
70
74
  setUserInfo(data);
@@ -203,7 +203,12 @@ const ProfilePage = () => {
203
203
  <HeaderLayout
204
204
  title={data.username || getFullName(data.firstname, data.lastname)}
205
205
  primaryAction={
206
- <Button startIcon={<Check />} loading={isSubmitting} type="submit" disabled={!dirty}>
206
+ <Button
207
+ startIcon={<Check />}
208
+ loading={isSubmitting}
209
+ type="submit"
210
+ disabled={!dirty}
211
+ >
207
212
  {formatMessage({ id: 'global.save', defaultMessage: 'Save' })}
208
213
  </Button>
209
214
  }
@@ -10,6 +10,7 @@ import {
10
10
  useTracking,
11
11
  } from '@strapi/helper-plugin';
12
12
  import PropTypes from 'prop-types';
13
+ import { useIntl } from 'react-intl';
13
14
  import { useHistory } from 'react-router-dom';
14
15
 
15
16
  import DeleteButton from './DeleteButton';
@@ -28,6 +29,7 @@ const Table = ({
28
29
  const { canDelete, canUpdate, canRead } = permissions;
29
30
  const withBulkActions = canDelete || canUpdate || canRead;
30
31
  const [{ query }] = useQueryParams();
32
+ const { formatMessage } = useIntl();
31
33
  const [, sortOrder] = query ? query.sort.split(':') : 'ASC';
32
34
  const {
33
35
  push,
@@ -83,7 +85,19 @@ const Table = ({
83
85
  <Td>
84
86
  {token.lastUsedAt && (
85
87
  <Typography textColor="neutral800">
86
- <RelativeTime timestamp={new Date(token.lastUsedAt)} />
88
+ <RelativeTime
89
+ timestamp={new Date(token.lastUsedAt)}
90
+ customIntervals={[
91
+ {
92
+ unit: 'hours',
93
+ threshold: 1,
94
+ text: formatMessage({
95
+ id: 'Settings.apiTokens.lastHour',
96
+ defaultMessage: 'last hour',
97
+ }),
98
+ },
99
+ ]}
100
+ />
87
101
  </Typography>
88
102
  )}
89
103
  </Td>
@@ -17,7 +17,7 @@ const TokenBox = ({ token, tokenType }) => {
17
17
  const didCopy = await copy(token);
18
18
 
19
19
  if (didCopy) {
20
- trackUsage.current('didCopyTokenKey', {
20
+ trackUsage('didCopyTokenKey', {
21
21
  tokenType,
22
22
  });
23
23
  toggleNotification({
@@ -10,19 +10,13 @@ import EditPage from '../EditPage';
10
10
  const ProtectedEditPage = () => {
11
11
  const permissions = useSelector(selectAdminPermissions);
12
12
 
13
- // TODO: this is necessary because otherwise we run into an
14
- // infinite rendering loop
15
- const permissionsMemoized = React.useMemo(() => {
16
- return {
17
- read: permissions.settings.roles.read,
18
- update: permissions.settings.roles.update,
19
- };
20
- }, [permissions.settings.roles.read, permissions.settings.roles.update]);
21
-
22
13
  const {
23
14
  isLoading,
24
15
  allowedActions: { canRead, canUpdate },
25
- } = useRBAC(permissionsMemoized);
16
+ } = useRBAC({
17
+ read: permissions.settings.roles.read,
18
+ update: permissions.settings.roles.update,
19
+ });
26
20
 
27
21
  if (isLoading) {
28
22
  return <LoadingIndicatorPage />;
@@ -183,13 +183,13 @@ const EditPage = ({ canUpdate }) => {
183
183
  validateOnChange={false}
184
184
  validationSchema={editValidation}
185
185
  >
186
- {({ errors, values, handleChange, isSubmitting }) => {
186
+ {({ errors, values, handleChange, isSubmitting, dirty }) => {
187
187
  return (
188
188
  <Form>
189
189
  <HeaderLayout
190
190
  primaryAction={
191
191
  <Button
192
- disabled={isSubmitting || !canUpdate}
192
+ disabled={isSubmitting || !canUpdate ? true : !dirty}
193
193
  startIcon={<Check />}
194
194
  loading={isSubmitting}
195
195
  type="submit"
@@ -1,4 +1,3 @@
1
- import { translatedErrors } from '@strapi/helper-plugin';
2
1
  import * as yup from 'yup';
3
2
 
4
3
  const NAME_REGEX = /(^$)|(^[A-Za-z][_0-9A-Za-z ]*$)/;
@@ -10,11 +9,18 @@ export const makeWebhookValidationSchema = ({ formatMessage }) =>
10
9
  .string()
11
10
  .required(
12
11
  formatMessage({
13
- id: 'Settings.webhooks.validation.name',
12
+ id: 'Settings.webhooks.validation.name.required',
14
13
  defaultMessage: 'Name is required',
15
14
  })
16
15
  )
17
- .matches(NAME_REGEX, translatedErrors.regex),
16
+ .matches(
17
+ NAME_REGEX,
18
+ formatMessage({
19
+ id: 'Settings.webhooks.validation.name.regex',
20
+ defaultMessage:
21
+ 'The name must start with a letter and only contain letters, numbers, spaces and underscores',
22
+ })
23
+ ),
18
24
  url: yup
19
25
  .string()
20
26
  .required(
@@ -26,8 +32,8 @@ export const makeWebhookValidationSchema = ({ formatMessage }) =>
26
32
  .matches(
27
33
  URL_REGEX,
28
34
  formatMessage({
29
- id: translatedErrors.regex,
30
- defaultMessage: 'The value does not match the regex',
35
+ id: 'Settings.webhooks.validation.url.regex',
36
+ defaultMessage: 'The value must be a valid Url',
31
37
  })
32
38
  ),
33
39
  headers: yup.lazy((array) => {
@@ -88,6 +88,7 @@
88
88
  "Settings.apiTokens.emptyStateLayout": "Encara no tens cap contingut...",
89
89
  "Settings.tokens.notification.copied": "Token copiat al porta-retalls.",
90
90
  "Settings.apiTokens.title": "Tokens d'API",
91
+ "Settings.apiTokens.lastHour": "darrera hora",
91
92
  "Settings.tokens.types.full-access": "Accés complet",
92
93
  "Settings.tokens.types.read-only": "Només lectura",
93
94
  "Settings.application.Strapi-version": "versió de Strapi",
@@ -97,6 +97,7 @@
97
97
  "Settings.apiTokens.emptyStateLayout": "You don’t have any content yet...",
98
98
  "Settings.apiTokens.regenerate": "Regenerate",
99
99
  "Settings.apiTokens.title": "API Tokens",
100
+ "Settings.apiTokens.lastHour": "last hour",
100
101
  "Settings.application.customization": "Customization",
101
102
  "Settings.application.customization.auth-logo.carousel-hint": "Replace the logo in the authentication pages",
102
103
  "Settings.application.customization.carousel-hint": "Change the admin panel logo (Max dimension: {dimension}x{dimension}, Max file size: {size}KB)",
@@ -318,8 +319,10 @@
318
319
  "Settings.webhooks.trigger.test": "Test-trigger",
319
320
  "Settings.webhooks.trigger.title": "Save before Trigger",
320
321
  "Settings.webhooks.value": "Value",
321
- "Settings.webhooks.validation.name": "Name is required",
322
+ "Settings.webhooks.validation.name.required": "Name is required",
323
+ "Settings.webhooks.validation.name.regex": "The name must start with a letter and only contain letters, numbers, spaces and underscores",
322
324
  "Settings.webhooks.validation.url.required": "Url is required",
325
+ "Settings.webhooks.validation.url.regex": "The value must be a valid Url",
323
326
  "Settings.webhooks.validation.key": "Key is required",
324
327
  "Settings.webhooks.validation.value": "Value is required",
325
328
  "Usecase.back-end": "Back-end developer",
@@ -86,6 +86,11 @@
86
86
  "Settings.apiTokens.emptyStateLayout": "Aún no tienes ningún contenido ...",
87
87
  "Settings.tokens.notification.copied": "Token copiado al portapapeles.",
88
88
  "Settings.apiTokens.title": "Tokens de API",
89
+ "Settings.apiTokens.lastHour": "última hora",
90
+ "Settings.tokens.ListView.headers.createdAt": "Creado en",
91
+ "Settings.tokens.ListView.headers.description": "Descripción",
92
+ "Settings.tokens.ListView.headers.lastUsedAt": "Último uso",
93
+ "Settings.tokens.ListView.headers.name": "Nombre",
89
94
  "Settings.tokens.types.full-access": "Acceso completo",
90
95
  "Settings.tokens.types.read-only": "Solo lectura",
91
96
  "Settings.application.description": "Información global del panel de administración",
@@ -100,6 +100,7 @@
100
100
  "Settings.apiTokens.createPage.BoundRoute.title": "Route rattachée à",
101
101
  "Settings.apiTokens.createPage.permissions.header.title": "Paramètres avancés",
102
102
  "Settings.apiTokens.createPage.permissions.header.hint": "Sélectionner les actions de l'application ou du plugin et sur l'icône de la roue crantée pour afficher la route rattachée",
103
+ "Settings.apiTokens.lastHour": "dernière heure",
103
104
  "Settings.tokens.duration.30-days": "30 jours",
104
105
  "Settings.tokens.duration.7-days": "7 jours",
105
106
  "Settings.tokens.duration.90-days": "90 jours",
@@ -799,7 +799,7 @@
799
799
  "content-manager.popUpWarning.warning.unpublish-question": "您确定不要发布它吗?",
800
800
  "content-manager.popUpWarning.warning.updateAllSettings": "这将修改所有设置",
801
801
  "content-manager.popUpwarning.warning.has-draft-relations.button-confirm": "是, 发布",
802
- "content-manager.popUpwarning.warning.has-draft-relations.message": "<b>{count, plural, =0 { 个关联的内容} one { 个关联的内容} other { 个关联的内容}}</b> 尚未发布。<br></br>它可能会在你的项目上产生关联失效和错误。",
802
+ "content-manager.popUpwarning.warning.has-draft-relations.message": "<b>{count, plural, one { 个关联的内容} other { 个关联的内容}}</b> 尚未发布,这可能会导致不可预期的行为。",
803
803
  "content-manager.popover.display-relations.label": "显示关联",
804
804
  "content-manager.relation.add": "添加关联",
805
805
  "content-manager.relation.disconnect": "删除",
Binary file
@@ -0,0 +1 @@
1
+ "use strict";(self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[2799],{42799:function(n,a,e){e.r(a),e.d(a,{REVIEW_WORKFLOW_COLUMNS_EE:function(){return t}});var s=e(47510);const t={key:"__strapi_reviewWorkflows_stage_temp_key__",name:"strapi_reviewWorkflows_stage",fieldSchema:{type:"relation"},metadatas:{label:{id:(0,s.Z)("containers.ListPage.table-headers.reviewWorkflows.stage"),defaultMessage:"Review stage"},searchable:!1,sortable:!0,mainField:{name:"name",schema:{type:"string"}}}}}}]);