@strapi/admin 4.10.0-beta.0 → 4.10.0-beta.1

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 (193) hide show
  1. package/.eslintignore +4 -0
  2. package/.eslintrc.js +14 -0
  3. package/admin/src/components/LanguageProvider/index.js +1 -1
  4. package/admin/src/components/LocalesProvider/__mocks__/useLocalesProvider.js +7 -0
  5. package/admin/src/components/LocalesProvider/index.js +2 -3
  6. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +3 -6
  7. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +2 -0
  8. package/admin/src/content-manager/components/DynamicTable/index.js +11 -29
  9. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +12 -6
  10. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/findAllAndReplace.js +10 -3
  11. package/admin/src/content-manager/components/InputUID/endActionStyle.js +4 -13
  12. package/admin/src/content-manager/components/InputUID/index.js +95 -72
  13. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +4 -8
  14. package/admin/src/content-manager/pages/App/LeftMenu/index.js +56 -35
  15. package/admin/src/content-manager/pages/App/actions.js +19 -7
  16. package/admin/src/content-manager/pages/App/constants.js +3 -3
  17. package/admin/src/content-manager/pages/App/index.js +5 -4
  18. package/admin/src/content-manager/pages/App/reducer.js +7 -6
  19. package/admin/src/content-manager/pages/App/selectors.js +3 -0
  20. package/admin/src/content-manager/pages/App/{useModels.js → useContentManagerInitData.js} +29 -28
  21. package/admin/src/content-manager/pages/App/utils/generateModelsLinks.js +2 -2
  22. package/admin/src/content-manager/pages/App/utils/getContentTypeLinks.js +17 -15
  23. package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +4 -5
  24. package/admin/src/content-manager/pages/EditSettingsView/index.js +4 -0
  25. package/admin/src/content-manager/pages/EditSettingsView/reducer.js +6 -7
  26. package/admin/src/content-manager/pages/EditSettingsView/utils/layout.js +1 -30
  27. package/admin/src/content-manager/pages/EditView/DeleteLink/index.js +5 -11
  28. package/admin/src/content-manager/pages/EditView/index.js +2 -7
  29. package/admin/src/content-manager/pages/ListSettingsView/index.js +1 -0
  30. package/admin/src/content-manager/sharedReducers/crudReducer/actions.js +6 -0
  31. package/admin/src/content-manager/sharedReducers/crudReducer/constants.js +1 -0
  32. package/admin/src/content-manager/sharedReducers/crudReducer/reducer.js +5 -0
  33. package/admin/src/hooks/useConfigurations/__mocks__/index.js +7 -0
  34. package/admin/src/hooks/useFetchMarketplacePlugins/utils/api.js +7 -8
  35. package/admin/src/hooks/useFetchMarketplaceProviders/utils/api.js +5 -0
  36. package/admin/src/hooks/useRegenerate/index.js +12 -7
  37. package/admin/src/pages/AuthPage/components/Register/index.js +46 -38
  38. package/admin/src/pages/HomePage/SocialLinks.js +1 -1
  39. package/admin/src/pages/MarketplacePage/components/EmptyNpmPackageSearch/index.js +3 -3
  40. package/admin/src/pages/MarketplacePage/components/NpmPackagesGrid/index.js +42 -9
  41. package/admin/src/pages/MarketplacePage/components/NpmPackagesPagination/index.js +26 -0
  42. package/admin/src/pages/MarketplacePage/components/OfflineLayout/index.js +45 -0
  43. package/admin/src/pages/MarketplacePage/index.js +80 -175
  44. package/admin/src/pages/MarketplacePage/utils/useMarketplaceData.js +85 -0
  45. package/admin/src/pages/SettingsPage/components/Tokens/FormHead/index.js +4 -0
  46. package/admin/src/pages/SettingsPage/components/Tokens/Regenerate/index.js +5 -3
  47. package/admin/src/pages/SettingsPage/components/Tokens/TokenTypeSelect/index.js +7 -5
  48. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/components/RoleRow/index.js +12 -4
  49. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +21 -2
  50. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/components/FormTransferTokenContainer/index.js +41 -0
  51. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +53 -9
  52. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/utils/schema.js +1 -0
  53. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +27 -5
  54. package/admin/src/translations/en.json +51 -49
  55. package/admin/src/translations/ru.json +51 -19
  56. package/build/1387.84b454d3.chunk.js +1 -0
  57. package/build/1657.45231968.chunk.js +168 -0
  58. package/build/3081.bcf9a12f.chunk.js +108 -0
  59. package/build/462.8fff7f3b.chunk.js +71 -0
  60. package/build/4628.20631dd1.chunk.js +1 -0
  61. package/build/5542.b8240e3f.chunk.js +70 -0
  62. package/build/5563.905daa13.chunk.js +79 -0
  63. package/build/6404.68405699.chunk.js +100 -0
  64. package/build/7259.b7d00cea.chunk.js +1 -0
  65. package/build/8694.6522968d.chunk.js +247 -0
  66. package/build/Admin-authenticatedApp.52c88751.chunk.js +79 -0
  67. package/build/Admin_InternalErrorPage.15c6bf07.chunk.js +1 -0
  68. package/build/Admin_homePage.f9309c6d.chunk.js +73 -0
  69. package/build/Admin_marketplace.56bc1008.chunk.js +31 -0
  70. package/build/Admin_pluginsPage.f6b52ee9.chunk.js +6 -0
  71. package/build/Admin_profilePage.9112cffc.chunk.js +15 -0
  72. package/build/Admin_settingsPage.257b3477.chunk.js +79 -0
  73. package/build/Upload_ConfigureTheView.eaaec495.chunk.js +1 -0
  74. package/build/admin-app.dfaeea5d.chunk.js +110 -0
  75. package/build/admin-edit-roles-page.4f1858e9.chunk.js +280 -0
  76. package/build/admin-edit-users.7e14d85f.chunk.js +10 -0
  77. package/build/admin-roles-list.329c1f63.chunk.js +31 -0
  78. package/build/admin-users.d02de059.chunk.js +34 -0
  79. package/build/api-tokens-create-page.97595e12.chunk.js +1 -0
  80. package/build/api-tokens-edit-page.cd36e30e.chunk.js +1 -0
  81. package/build/api-tokens-list-page.6757c7b9.chunk.js +16 -0
  82. package/build/audit-logs-settings-page.19d90bda.chunk.js +76 -0
  83. package/build/content-manager.def692c2.chunk.js +1130 -0
  84. package/build/content-type-builder-list-view.9c2c020c.chunk.js +214 -0
  85. package/build/content-type-builder-translation-en-json.510e88ca.chunk.js +1 -0
  86. package/build/content-type-builder.5e1f4afc.chunk.js +126 -0
  87. package/build/email-settings-page.1095e1ab.chunk.js +10 -0
  88. package/build/en-json.08303b37.chunk.js +1 -0
  89. package/build/{highlight.js.26ef649f.chunk.js → highlight.js.28a1547e.chunk.js} +2 -2
  90. package/build/i18n-settings-page.7d80aae0.chunk.js +60 -0
  91. package/build/index.html +1 -1
  92. package/build/main.120be100.js +2280 -0
  93. package/build/review-workflows-settings.9092ed72.chunk.js +106 -0
  94. package/build/ru-json.e0662702.chunk.js +1 -0
  95. package/build/{runtime~main.5a95bee6.js → runtime~main.112b3101.js} +2 -2
  96. package/build/sso-settings-page.1dd4886e.chunk.js +1 -0
  97. package/build/transfer-tokens-create-page.ec2ca215.chunk.js +1 -0
  98. package/build/transfer-tokens-edit-page.22bf28e5.chunk.js +1 -0
  99. package/build/transfer-tokens-list-page.cf8c77f2.chunk.js +16 -0
  100. package/build/upload-settings.945fdcfa.chunk.js +13 -0
  101. package/build/{upload-translation-th-json.3847dae0.chunk.js → upload-translation-th-json.98d35574.chunk.js} +1 -1
  102. package/build/upload.a86b1054.chunk.js +33 -0
  103. package/build/users-advanced-settings-page.5b5a9baa.chunk.js +8 -0
  104. package/build/users-email-settings-page.e5506eb4.chunk.js +23 -0
  105. package/build/users-providers-settings-page.e32089c2.chunk.js +28 -0
  106. package/build/users-roles-settings-page.2f85dcec.chunk.js +30 -0
  107. package/build/webhook-edit-page.213f0075.chunk.js +75 -0
  108. package/build/webhook-list-page.5beb2a5c.chunk.js +71 -0
  109. package/{admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStage.js → ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/ReviewWorkflowsStageEE.js} +2 -2
  110. package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn.js +45 -0
  111. package/ee/admin/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +3 -0
  112. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +61 -18
  113. package/ee/admin/hooks/useLicenseLimitNotification/index.js +1 -1
  114. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/hooks/useAuditLogsData.js +6 -3
  115. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +15 -5
  116. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/utils/getDisplayedFilters.js +52 -45
  117. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +8 -4
  118. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +2 -2
  119. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/hooks/useReviewWorkflows.js +2 -2
  120. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/reducer/index.js +2 -1
  121. package/ee/server/content-types/workflow/index.js +0 -3
  122. package/ee/server/content-types/workflow-stage/index.js +0 -5
  123. package/ee/server/controllers/workflows/stages/index.js +8 -1
  124. package/ee/server/register.js +3 -1
  125. package/ee/server/services/audit-logs.js +75 -16
  126. package/ee/server/services/review-workflows/entity-service-decorator.js +17 -5
  127. package/ee/server/services/review-workflows/review-workflows.js +27 -91
  128. package/ee/server/services/review-workflows/stages.js +108 -7
  129. package/ee/server/utils/persisted-tables.js +114 -22
  130. package/ee/server/utils/review-workflows.js +9 -0
  131. package/jest.config.front.js +1 -6
  132. package/package.json +24 -22
  133. package/server/controllers/transfer/runner.js +4 -2
  134. package/server/middlewares/data-transfer.js +4 -1
  135. package/server/routes/transfer.js +13 -4
  136. package/server/services/constants.js +4 -0
  137. package/server/services/transfer/permission.js +1 -1
  138. package/server/services/transfer/token.js +33 -31
  139. package/server/validation/transfer/token.js +10 -2
  140. package/webpack.config.js +6 -2
  141. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/index.js +0 -1
  142. package/admin/src/content-manager/pages/App/LeftMenu/utils/index.js +0 -1
  143. package/admin/src/content-manager/pages/App/LeftMenu/utils/matchByTitle.js +0 -24
  144. package/build/2263.4c5916f9.chunk.js +0 -98
  145. package/build/4049.64715f20.chunk.js +0 -1
  146. package/build/4649.213b8a3b.chunk.js +0 -30
  147. package/build/6985.66cca29c.chunk.js +0 -1
  148. package/build/7259.aefb51e8.chunk.js +0 -1
  149. package/build/8469.853c822b.chunk.js +0 -1
  150. package/build/9505.dbe702ab.chunk.js +0 -14
  151. package/build/9816.01ee964f.chunk.js +0 -2
  152. package/build/Admin-authenticatedApp.f50ad423.chunk.js +0 -79
  153. package/build/Admin_InternalErrorPage.4ad8b0df.chunk.js +0 -1
  154. package/build/Admin_homePage.1411fb7c.chunk.js +0 -68
  155. package/build/Admin_marketplace.02608d56.chunk.js +0 -22
  156. package/build/Admin_pluginsPage.15e3b0fd.chunk.js +0 -1
  157. package/build/Admin_profilePage.76afeca0.chunk.js +0 -15
  158. package/build/Admin_settingsPage.147755cd.chunk.js +0 -9
  159. package/build/Upload_ConfigureTheView.34dde278.chunk.js +0 -1
  160. package/build/admin-app.55dd7921.chunk.js +0 -112
  161. package/build/admin-edit-roles-page.cf543488.chunk.js +0 -216
  162. package/build/admin-edit-users.31c20712.chunk.js +0 -10
  163. package/build/admin-roles-list.489c501f.chunk.js +0 -2
  164. package/build/admin-users.3e111a7d.chunk.js +0 -11
  165. package/build/api-tokens-create-page.4328b852.chunk.js +0 -1
  166. package/build/api-tokens-edit-page.bce5050f.chunk.js +0 -1
  167. package/build/api-tokens-list-page.93f24348.chunk.js +0 -16
  168. package/build/audit-logs-settings-page.7be97e82.chunk.js +0 -1
  169. package/build/content-manager.4480ae88.chunk.js +0 -1137
  170. package/build/content-type-builder-list-view.cf38fe2f.chunk.js +0 -191
  171. package/build/content-type-builder-translation-en-json.7961593e.chunk.js +0 -1
  172. package/build/content-type-builder.af9abf1e.chunk.js +0 -126
  173. package/build/email-settings-page.4bdbef9a.chunk.js +0 -3
  174. package/build/en-json.697b4bcf.chunk.js +0 -1
  175. package/build/i18n-settings-page.2bb5be96.chunk.js +0 -1
  176. package/build/main.af8c0f31.js +0 -3790
  177. package/build/review-workflows-settings.7a7dc773.chunk.js +0 -57
  178. package/build/ru-json.6a01cea6.chunk.js +0 -1
  179. package/build/sso-settings-page.272b87c8.chunk.js +0 -1
  180. package/build/transfer-tokens-create-page.a1f14bb1.chunk.js +0 -1
  181. package/build/transfer-tokens-edit-page.00ee1c74.chunk.js +0 -1
  182. package/build/transfer-tokens-list-page.ce37354b.chunk.js +0 -16
  183. package/build/upload-settings.0875e973.chunk.js +0 -1
  184. package/build/upload.c7da1611.chunk.js +0 -13
  185. package/build/users-advanced-settings-page.1d3c14c7.chunk.js +0 -1
  186. package/build/users-email-settings-page.e8db68c4.chunk.js +0 -1
  187. package/build/users-providers-settings-page.14cac425.chunk.js +0 -1
  188. package/build/users-roles-settings-page.2ea4de84.chunk.js +0 -30
  189. package/build/webhook-edit-page.329141a5.chunk.js +0 -23
  190. package/build/webhook-list-page.029957a4.chunk.js +0 -1
  191. package/ee/server/migrations/review-workflows.js +0 -39
  192. package/ee/server/utils/test.js +0 -11
  193. /package/admin/src/{content-manager/components/InputUID/useDebounce.js → hooks/useDebounce/index.js} +0 -0
package/.eslintignore ADDED
@@ -0,0 +1,4 @@
1
+ node_modules/
2
+ .eslintrc.js
3
+ build/
4
+ admin/src/plugins.js
package/.eslintrc.js ADDED
@@ -0,0 +1,14 @@
1
+ module.exports = {
2
+ root: true,
3
+ overrides: [
4
+ {
5
+ files: ['admin/**/*', 'ee/admin/**/*'],
6
+ extends: ['custom/front'],
7
+ },
8
+ {
9
+ files: ['**/*'],
10
+ excludedFiles: ['admin/**/*', 'ee/admin/**/*'],
11
+ extends: ['custom/back'],
12
+ },
13
+ ],
14
+ };
@@ -35,7 +35,7 @@ const LanguageProvider = ({ children, localeNames, messages }) => {
35
35
 
36
36
  return (
37
37
  <IntlProvider locale={locale} defaultLocale="en" messages={appMessages} textComponent="span">
38
- <LocalesProvider changeLocale={changeLocale} localeNames={localeNames} messages={appMessages}>
38
+ <LocalesProvider changeLocale={changeLocale} localeNames={localeNames}>
39
39
  {children}
40
40
  </LocalesProvider>
41
41
  </IntlProvider>
@@ -0,0 +1,7 @@
1
+ export default function useLocalesProvider() {
2
+ return {
3
+ changeLocale() {},
4
+ localeNames: { en: 'English' },
5
+ messages: ['test'],
6
+ };
7
+ }
@@ -2,9 +2,9 @@ import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import LocalesProviderContext from './context';
4
4
 
5
- const LocalesProvider = ({ changeLocale, children, localeNames, messages }) => {
5
+ const LocalesProvider = ({ changeLocale, children, localeNames }) => {
6
6
  return (
7
- <LocalesProviderContext.Provider value={{ changeLocale, localeNames, messages }}>
7
+ <LocalesProviderContext.Provider value={{ changeLocale, localeNames }}>
8
8
  {children}
9
9
  </LocalesProviderContext.Provider>
10
10
  );
@@ -14,7 +14,6 @@ LocalesProvider.propTypes = {
14
14
  changeLocale: PropTypes.func.isRequired,
15
15
  children: PropTypes.element.isRequired,
16
16
  localeNames: PropTypes.object.isRequired,
17
- messages: PropTypes.object.isRequired,
18
17
  };
19
18
 
20
19
  export default LocalesProvider;
@@ -222,6 +222,8 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
222
222
 
223
223
  trackUsageRef.current('didDeleteEntry', trackerProperty);
224
224
 
225
+ replace(redirectionLink);
226
+
225
227
  return Promise.resolve(data);
226
228
  } catch (err) {
227
229
  trackUsageRef.current('didNotDeleteEntry', { error: err, ...trackerProperty });
@@ -229,13 +231,9 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
229
231
  return Promise.reject(err);
230
232
  }
231
233
  },
232
- [id, slug, toggleNotification, del]
234
+ [id, slug, toggleNotification, del, redirectionLink, replace]
233
235
  );
234
236
 
235
- const onDeleteSucceeded = useCallback(() => {
236
- replace(redirectionLink);
237
- }, [redirectionLink, replace]);
238
-
239
237
  const onPost = useCallback(
240
238
  async (body, trackerProperty) => {
241
239
  const endPoint = `${getRequestUrl(`collection-types/${slug}`)}${rawQuery}`;
@@ -409,7 +407,6 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
409
407
  isCreatingEntry,
410
408
  isLoadingForData: isLoading,
411
409
  onDelete,
412
- onDeleteSucceeded,
413
410
  onPost,
414
411
  onPublish,
415
412
  onDraftRelationCheck,
@@ -0,0 +1,2 @@
1
+ // Overwritten in EE
2
+ export default () => null;
@@ -4,6 +4,7 @@ import { useIntl } from 'react-intl';
4
4
  import { DynamicTable as Table, useStrapiApp } from '@strapi/helper-plugin';
5
5
  import { useSelector } from 'react-redux';
6
6
 
7
+ import getReviewWorkflowsColumn from 'ee_else_ce/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn';
7
8
  import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
8
9
  import { selectDisplayedHeaders } from '../../pages/ListView/selectors';
9
10
  import { getTrad } from '../../utils';
@@ -11,7 +12,6 @@ import TableRows from './TableRows';
11
12
  import ConfirmDialogDeleteAll from './ConfirmDialogDeleteAll';
12
13
  import ConfirmDialogDelete from './ConfirmDialogDelete';
13
14
  import { PublicationState } from './CellContent/PublicationState/PublicationState';
14
- import { ReviewWorkflowsStage } from './CellContent/ReviewWorkflowsStage';
15
15
 
16
16
  const DynamicTable = ({
17
17
  canCreate,
@@ -27,7 +27,6 @@ const DynamicTable = ({
27
27
  }) => {
28
28
  const { runHookWaterfall } = useStrapiApp();
29
29
  const hasDraftAndPublish = layout.contentType.options?.draftAndPublish ?? false;
30
- const hasReviewWorkflows = layout.contentType.options?.reviewWorkflows ?? false;
31
30
  const { formatMessage } = useIntl();
32
31
  const displayedHeaders = useSelector(selectDisplayedHeaders);
33
32
 
@@ -74,36 +73,19 @@ const DynamicTable = ({
74
73
  });
75
74
  }
76
75
 
77
- if (hasReviewWorkflows) {
78
- formattedHeaders.push({
79
- key: '__strapi_reviewWorkflows_stage_temp_key__',
80
- name: 'strapi_reviewWorkflows_stage',
81
- fieldSchema: {
82
- type: 'custom',
83
- },
84
- metadatas: {
85
- label: formatMessage({
86
- id: getTrad(`containers.ListPage.table-headers.reviewWorkflows.stage`),
87
- defaultMessage: 'Review stage',
88
- }),
89
- searchable: false,
90
- sortable: false,
91
- },
92
- cellFormatter({ strapi_reviewWorkflows_stage }) {
93
- return <ReviewWorkflowsStage name={strapi_reviewWorkflows_stage.name} />;
94
- },
95
- });
76
+ // this should not exist. Ideally we would use registerHook() similar to what has been done
77
+ // in the i18n plugin. In order to do that review-workflows should have been a plugin. In
78
+ // a future iteration we need to find a better pattern.
79
+
80
+ // In CE this will return null - in EE a column definition including the custom formatting component.
81
+ const reviewWorkflowColumn = getReviewWorkflowsColumn(layout);
82
+
83
+ if (reviewWorkflowColumn) {
84
+ formattedHeaders.push(reviewWorkflowColumn);
96
85
  }
97
86
 
98
87
  return formattedHeaders;
99
- }, [
100
- runHookWaterfall,
101
- displayedHeaders,
102
- layout,
103
- hasDraftAndPublish,
104
- hasReviewWorkflows,
105
- formatMessage,
106
- ]);
88
+ }, [runHookWaterfall, displayedHeaders, layout, hasDraftAndPublish, formatMessage]);
107
89
 
108
90
  return (
109
91
  <Table
@@ -186,11 +186,15 @@ const reducer = (state, action) =>
186
186
  const newRelations = [...modifiedDataRelations];
187
187
 
188
188
  if (action.type === 'REORDER_RELATION') {
189
- const [newKey] = generateNKeysBetween(
190
- modifiedDataRelations[newIndex - 1]?.__temp_key__,
191
- modifiedDataRelations[newIndex]?.__temp_key__,
192
- 1
193
- );
189
+ const startKey =
190
+ oldIndex > newIndex
191
+ ? modifiedDataRelations[newIndex - 1]?.__temp_key__
192
+ : modifiedDataRelations[newIndex]?.__temp_key__;
193
+ const endKey =
194
+ oldIndex > newIndex
195
+ ? modifiedDataRelations[newIndex]?.__temp_key__
196
+ : modifiedDataRelations[newIndex + 1]?.__temp_key__;
197
+ const [newKey] = generateNKeysBetween(startKey, endKey, 1);
194
198
 
195
199
  newRelations.splice(oldIndex, 1);
196
200
  newRelations.splice(newIndex, 0, { ...currentItem, __temp_key__: newKey });
@@ -220,7 +224,9 @@ const reducer = (state, action) =>
220
224
 
221
225
  const findAllRelationsAndReplaceWithEmptyArray = findAllAndReplace(
222
226
  components,
223
- (value) => value.type === 'relation',
227
+ (value) => {
228
+ return value.type === 'relation';
229
+ },
224
230
  (_, { path }) => {
225
231
  if (state.modifiedData?.id === data.id && get(state.modifiedData, path)) {
226
232
  return get(state.modifiedData, path);
@@ -26,7 +26,11 @@ const findAllAndReplaceSetup = (components, predicate = () => false, replacement
26
26
  /**
27
27
  * @type {<TData extends object = object>(data: TData, attributes: Attributes, options?: { ignoreFalseyValues?: boolean}) => TData}
28
28
  */
29
- const findAllAndReplace = (data, attributes, { ignoreFalseyValues = false, path = [] } = {}) => {
29
+ const findAllAndReplace = (
30
+ data,
31
+ attributes,
32
+ { ignoreFalseyValues = false, path = [], parent = attributes } = {}
33
+ ) => {
30
34
  return Object.entries(attributes).reduce(
31
35
  (acc, [key, value]) => {
32
36
  if (
@@ -36,7 +40,7 @@ const findAllAndReplaceSetup = (components, predicate = () => false, replacement
36
40
  return acc;
37
41
  }
38
42
 
39
- if (predicate(value, { path: [...path, key], parent: acc })) {
43
+ if (predicate(value, { path: [...path, key], parent })) {
40
44
  acc[key] =
41
45
  typeof replacement === 'function'
42
46
  ? replacement(acc[key], { path: [...path, key], parent: acc })
@@ -46,16 +50,18 @@ const findAllAndReplaceSetup = (components, predicate = () => false, replacement
46
50
  if (value.type === 'component') {
47
51
  const componentAttributes = components[value.component].attributes;
48
52
 
49
- if (!value.repeatable) {
53
+ if (!value.repeatable && acc[key] && typeof acc[key] === 'object') {
50
54
  acc[key] = findAllAndReplace(acc[key], componentAttributes, {
51
55
  ignoreFalseyValues,
52
56
  path: [...path, key],
57
+ parent: attributes[key],
53
58
  });
54
59
  } else if (value.repeatable && Array.isArray(acc[key])) {
55
60
  acc[key] = acc[key].map((datum, index) => {
56
61
  const data = findAllAndReplace(datum, componentAttributes, {
57
62
  ignoreFalseyValues,
58
63
  path: [...path, key, index],
64
+ parent: attributes[key],
59
65
  });
60
66
 
61
67
  return data;
@@ -67,6 +73,7 @@ const findAllAndReplaceSetup = (components, predicate = () => false, replacement
67
73
  const data = findAllAndReplace(datum, componentAttributes, {
68
74
  ignoreFalseyValues,
69
75
  path: [...path, key, index],
76
+ parent: attributes[key],
70
77
  });
71
78
 
72
79
  return data;
@@ -1,9 +1,5 @@
1
1
  import styled, { keyframes } from 'styled-components';
2
- import { Box, Flex, FieldAction } from '@strapi/design-system';
3
-
4
- export const EndActionWrapper = styled(Box)`
5
- position: relative;
6
- `;
2
+ import { Flex, FieldAction } from '@strapi/design-system';
7
3
 
8
4
  export const FieldActionWrapper = styled(FieldAction)`
9
5
  svg {
@@ -22,18 +18,13 @@ export const FieldActionWrapper = styled(FieldAction)`
22
18
  `;
23
19
 
24
20
  export const TextValidation = styled(Flex)`
25
- position: absolute;
26
- right: ${({ theme }) => theme.spaces[6]};
27
- width: 100px;
28
- pointer-events: none;
29
-
30
21
  svg {
31
- margin-right: ${({ theme }) => theme.spaces[1]};
32
22
  height: ${12 / 16}rem;
33
23
  width: ${12 / 16}rem;
24
+
34
25
  path {
35
- fill: ${({ theme, notAvailable }) =>
36
- !notAvailable ? theme.colors.success600 : theme.colors.danger600};
26
+ fill: ${({ theme, available }) =>
27
+ available ? theme.colors.success600 : theme.colors.danger600};
37
28
  }
38
29
  }
39
30
  `;
@@ -1,19 +1,19 @@
1
1
  import React, { useEffect, useState, useRef } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { useCMEditViewDataManager, useFetchClient } from '@strapi/helper-plugin';
3
+ import {
4
+ useCMEditViewDataManager,
5
+ useFetchClient,
6
+ useNotification,
7
+ useAPIErrorHandler,
8
+ } from '@strapi/helper-plugin';
4
9
  import { useIntl } from 'react-intl';
5
- import get from 'lodash/get';
6
- import { TextInput, Typography } from '@strapi/design-system';
10
+ import { Flex, TextInput, Typography } from '@strapi/design-system';
7
11
  import { Refresh, CheckCircle, ExclamationMarkCircle, Loader } from '@strapi/icons';
12
+
8
13
  import { getRequestUrl } from '../../utils';
9
- import useDebounce from './useDebounce';
14
+ import useDebounce from '../../../hooks/useDebounce';
10
15
  import UID_REGEX from './regex';
11
- import {
12
- EndActionWrapper,
13
- FieldActionWrapper,
14
- TextValidation,
15
- LoadingWrapper,
16
- } from './endActionStyle';
16
+ import { FieldActionWrapper, TextValidation, LoadingWrapper } from './endActionStyle';
17
17
 
18
18
  const InputUID = ({
19
19
  attribute,
@@ -34,9 +34,11 @@ const InputUID = ({
34
34
  const [availability, setAvailability] = useState(null);
35
35
  const debouncedValue = useDebounce(value, 300);
36
36
  const generateUid = useRef();
37
+ const toggleNotification = useNotification();
38
+ const { formatAPIError } = useAPIErrorHandler();
37
39
  const initialValue = initialData[name];
38
40
  const { formatMessage } = useIntl();
39
- const createdAtName = get(layout, ['options', 'timestamps', 0]);
41
+ const createdAtName = layout?.options?.timestamps ?? 0;
40
42
  const isCreation = !initialData[createdAtName];
41
43
  const debouncedTargetFieldValue = useDebounce(modifiedData[attribute.targetField], 300);
42
44
  const [isCustomized, setIsCustomized] = useState(false);
@@ -59,72 +61,74 @@ const InputUID = ({
59
61
 
60
62
  generateUid.current = async (shouldSetInitialValue = false) => {
61
63
  setIsLoading(true);
62
- const requestURL = getRequestUrl('uid/generate');
64
+
63
65
  try {
64
66
  const {
65
67
  data: { data },
66
- } = await post(requestURL, {
68
+ } = await post(getRequestUrl('uid/generate'), {
67
69
  contentTypeUID,
68
70
  field: name,
69
71
  data: modifiedData,
70
72
  });
73
+
71
74
  onChange({ target: { name, value: data, type: 'text' } }, shouldSetInitialValue);
72
75
  setIsLoading(false);
73
- } catch (err) {
76
+ } catch (error) {
74
77
  setIsLoading(false);
78
+ toggleNotification({
79
+ type: 'warning',
80
+ message: formatAPIError(error),
81
+ });
75
82
  }
76
83
  };
77
84
 
78
85
  const checkAvailability = async () => {
79
- setIsLoading(true);
80
-
81
- const requestURL = getRequestUrl('uid/check-availability');
82
-
83
86
  if (!value) {
84
87
  return;
85
88
  }
86
89
 
90
+ setIsLoading(true);
91
+
87
92
  try {
88
- const { data } = await post(requestURL, {
93
+ const { data } = await post(getRequestUrl('uid/check-availability'), {
89
94
  contentTypeUID,
90
95
  field: name,
91
96
  value: value ? value.trim() : '',
92
97
  });
93
98
 
94
- setAvailability(data);
95
-
96
99
  setIsLoading(false);
97
- } catch (err) {
100
+ setAvailability(data);
101
+ } catch (error) {
98
102
  setIsLoading(false);
103
+ toggleNotification({
104
+ type: 'warning',
105
+ message: formatAPIError(error),
106
+ });
99
107
  }
100
108
  };
101
109
 
102
- // // FIXME: we need to find a better way to autofill the input when it is required.
110
+ // FIXME: we need to find a better way to autofill the input when it is required.
103
111
  useEffect(() => {
104
112
  if (!value && attribute.required) {
105
113
  generateUid.current(true);
106
114
  }
107
- // eslint-disable-next-line react-hooks/exhaustive-deps
108
- }, []);
115
+ }, [attribute.required, generateUid, value]);
109
116
 
110
117
  useEffect(() => {
111
- if (
112
- debouncedValue &&
113
- debouncedValue.trim().match(UID_REGEX) &&
114
- debouncedValue !== initialValue
115
- ) {
118
+ if (debouncedValue?.trim().match(UID_REGEX) && debouncedValue !== initialValue) {
116
119
  checkAvailability();
117
120
  }
121
+
118
122
  if (!debouncedValue) {
119
123
  setAvailability(null);
120
124
  }
121
125
  // eslint-disable-next-line react-hooks/exhaustive-deps
122
- }, [debouncedValue, initialValue]);
126
+ }, [initialValue, debouncedValue]);
123
127
 
124
128
  useEffect(() => {
125
129
  let timer;
126
130
 
127
- if (availability && availability.isAvailable) {
131
+ if (availability?.isAvailable) {
128
132
  timer = setTimeout(() => {
129
133
  setAvailability(null);
130
134
  }, 4000);
@@ -176,51 +180,70 @@ const InputUID = ({
176
180
  disabled={disabled}
177
181
  error={error}
178
182
  endAction={
179
- <EndActionWrapper>
180
- {availability && availability.isAvailable && !regenerateLabel && (
181
- <TextValidation alignItems="center" justifyContent="flex-end">
182
- <CheckCircle />
183
- <Typography textColor="success600" variant="pi">
184
- {formatMessage({
185
- id: 'content-manager.components.uid.available',
186
- defaultMessage: 'Available',
187
- })}
183
+ <Flex position="relative" gap={1}>
184
+ {availability && !regenerateLabel && (
185
+ <TextValidation
186
+ alignItems="center"
187
+ gap={1}
188
+ justifyContent="flex-end"
189
+ available={!!availability?.isAvailable}
190
+ data-not-here-outer
191
+ position="absolute"
192
+ pointerEvents="none"
193
+ right={6}
194
+ width="100px"
195
+ >
196
+ {availability?.isAvailable ? <CheckCircle /> : <ExclamationMarkCircle />}
197
+
198
+ <Typography
199
+ textColor={availability.isAvailable ? 'success600' : 'danger600'}
200
+ variant="pi"
201
+ >
202
+ {formatMessage(
203
+ availability.isAvailable
204
+ ? {
205
+ id: 'content-manager.components.uid.available',
206
+ defaultMessage: 'Available',
207
+ }
208
+ : {
209
+ id: 'content-manager.components.uid.unavailable',
210
+ defaultMessage: 'Unavailable',
211
+ }
212
+ )}
188
213
  </Typography>
189
214
  </TextValidation>
190
215
  )}
191
- {availability && !availability.isAvailable && !regenerateLabel && (
192
- <TextValidation notAvailable alignItems="center" justifyContent="flex-end">
193
- <ExclamationMarkCircle />
194
- <Typography textColor="danger600" variant="pi">
195
- {formatMessage({
196
- id: 'content-manager.components.uid.unavailable',
197
- defaultMessage: 'Unavailable',
216
+
217
+ {!disabled && (
218
+ <>
219
+ {regenerateLabel && (
220
+ <TextValidation alignItems="center" justifyContent="flex-end" gap={1}>
221
+ <Typography textColor="primary600" variant="pi">
222
+ {regenerateLabel}
223
+ </Typography>
224
+ </TextValidation>
225
+ )}
226
+
227
+ <FieldActionWrapper
228
+ onClick={() => generateUid.current()}
229
+ label={formatMessage({
230
+ id: 'content-manager.components.uid.regenerate',
231
+ defaultMessage: 'Regenerate',
198
232
  })}
199
- </Typography>
200
- </TextValidation>
201
- )}
202
- {regenerateLabel && (
203
- <TextValidation alignItems="center" justifyContent="flex-end">
204
- <Typography textColor="primary600" variant="pi">
205
- {regenerateLabel}
206
- </Typography>
207
- </TextValidation>
233
+ onMouseEnter={handleGenerateMouseEnter}
234
+ onMouseLeave={handleGenerateMouseLeave}
235
+ >
236
+ {isLoading ? (
237
+ <LoadingWrapper data-testid="loading-wrapper">
238
+ <Loader />
239
+ </LoadingWrapper>
240
+ ) : (
241
+ <Refresh />
242
+ )}
243
+ </FieldActionWrapper>
244
+ </>
208
245
  )}
209
- <FieldActionWrapper
210
- onClick={() => generateUid.current()}
211
- label="regenerate"
212
- onMouseEnter={handleGenerateMouseEnter}
213
- onMouseLeave={handleGenerateMouseLeave}
214
- >
215
- {isLoading ? (
216
- <LoadingWrapper>
217
- <Loader />
218
- </LoadingWrapper>
219
- ) : (
220
- <Refresh />
221
- )}
222
- </FieldActionWrapper>
223
- </EndActionWrapper>
246
+ </Flex>
224
247
  }
225
248
  hint={hint}
226
249
  label={label}
@@ -172,6 +172,9 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
172
172
 
173
173
  trackUsageRef.current('didDeleteEntry', trackerProperty);
174
174
 
175
+ setIsCreatingEntry(true);
176
+ dispatch(initForm(rawQuery, true));
177
+
175
178
  return Promise.resolve(data);
176
179
  } catch (err) {
177
180
  trackUsageRef.current('didNotDeleteEntry', { error: err, ...trackerProperty });
@@ -181,15 +184,9 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
181
184
  return Promise.reject(err);
182
185
  }
183
186
  },
184
- [del, slug, displayErrors, toggleNotification, searchToSend]
187
+ [del, slug, displayErrors, toggleNotification, searchToSend, dispatch, rawQuery]
185
188
  );
186
189
 
187
- const onDeleteSucceeded = useCallback(() => {
188
- setIsCreatingEntry(true);
189
-
190
- dispatch(initForm(rawQuery, true));
191
- }, [dispatch, rawQuery]);
192
-
193
190
  const onPost = useCallback(
194
191
  async (body, trackerProperty) => {
195
192
  const endPoint = getRequestUrl(`${slug}${rawQuery}`);
@@ -370,7 +367,6 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
370
367
  isCreatingEntry,
371
368
  isLoadingForData: isLoading,
372
369
  onDelete,
373
- onDeleteSucceeded,
374
370
  onPost,
375
371
  onDraftRelationCheck,
376
372
  onPublish,