@strapi/admin 4.11.2 → 4.11.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (205) hide show
  1. package/admin/src/components/AuthenticatedApp/index.js +2 -2
  2. package/admin/src/constants.js +90 -0
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +10 -1
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/index.js +12 -8
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +5 -6
  6. package/admin/src/content-manager/components/RelationInput/RelationInput.js +99 -178
  7. package/admin/src/content-manager/components/RelationInput/components/Option.js +17 -15
  8. package/admin/src/content-manager/components/RelationInput/components/RelationList.js +2 -2
  9. package/admin/src/content-manager/components/RelationInputDataManager/RelationInputDataManager.js +12 -6
  10. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +18 -3
  11. package/admin/src/content-manager/pages/App/index.js +4 -4
  12. package/admin/src/content-manager/pages/CollectionTypeRecursivePath/index.js +9 -5
  13. package/admin/src/content-manager/pages/ComponentSetttingsView/index.js +3 -4
  14. package/admin/src/content-manager/pages/EditView/hooks/useOnce.js +14 -0
  15. package/admin/src/content-manager/pages/EditView/index.js +31 -10
  16. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RelationMultiple/index.js +1 -1
  17. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/utils/hasContent.js +1 -1
  18. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/ConfirmDialogDelete/index.js +7 -4
  19. package/admin/src/content-manager/pages/ListView/components/ConfirmDialogDeleteAll/index.js +78 -0
  20. package/admin/src/content-manager/pages/ListView/{FieldPicker → components/FieldPicker}/index.js +20 -9
  21. package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/TableRows/index.js +90 -61
  22. package/admin/src/content-manager/pages/ListView/index.js +173 -34
  23. package/admin/src/content-manager/pages/ListView/utils/index.js +0 -2
  24. package/admin/src/content-manager/pages/ListViewLayoutManager/Permissions.js +1 -1
  25. package/admin/src/content-manager/pages/SingleTypeRecursivePath/index.js +4 -4
  26. package/admin/src/hooks/useMenu/index.js +70 -37
  27. package/admin/src/hooks/useMenu/utils/getGeneralLinks.js +5 -2
  28. package/admin/src/hooks/useSettingsMenu/constants.js +0 -7
  29. package/admin/src/hooks/useSettingsMenu/index.js +19 -5
  30. package/admin/src/pages/App/constants.js +1 -0
  31. package/admin/src/pages/App/index.js +23 -2
  32. package/admin/src/pages/App/reducer.js +8 -1
  33. package/admin/src/pages/App/selectors.js +12 -0
  34. package/admin/src/pages/AuthPage/{utils/forms.js → constants.js} +6 -8
  35. package/admin/src/pages/AuthPage/index.js +17 -5
  36. package/admin/src/pages/InstalledPluginsPage/index.js +10 -7
  37. package/admin/src/pages/MarketplacePage/index.js +11 -6
  38. package/admin/src/pages/ProfilePage/index.js +2 -2
  39. package/admin/src/pages/SettingsPage/components/Tokens/Table/index.js +15 -1
  40. package/admin/src/pages/SettingsPage/pages/ApiTokens/EditView/index.js +4 -2
  41. package/admin/src/pages/SettingsPage/pages/ApiTokens/ListView/index.js +4 -2
  42. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedCreateView/index.js +5 -2
  43. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedEditView/index.js +5 -2
  44. package/admin/src/pages/SettingsPage/pages/ApiTokens/ProtectedListView/index.js +11 -6
  45. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +130 -107
  46. package/admin/src/pages/SettingsPage/pages/Roles/CreatePage/index.js +5 -3
  47. package/admin/src/pages/SettingsPage/pages/Roles/ListPage/index.js +4 -2
  48. package/admin/src/pages/SettingsPage/pages/Roles/ProtectedEditPage/index.js +8 -9
  49. package/admin/src/pages/SettingsPage/pages/Roles/ProtectedListPage/index.js +11 -6
  50. package/admin/src/pages/SettingsPage/pages/TransferTokens/EditView/index.js +4 -2
  51. package/admin/src/pages/SettingsPage/pages/TransferTokens/ListView/index.js +4 -2
  52. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedCreateView/index.js +5 -2
  53. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedEditView/index.js +5 -2
  54. package/admin/src/pages/SettingsPage/pages/TransferTokens/ProtectedListView/index.js +11 -6
  55. package/admin/src/pages/SettingsPage/pages/Users/EditPage/index.js +2 -2
  56. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/{utils/layout.js → constants.js} +35 -2
  57. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/index.js +43 -10
  58. package/admin/src/pages/SettingsPage/pages/Users/ListPage/index.js +4 -2
  59. package/admin/src/pages/SettingsPage/pages/Users/ProtectedEditPage/index.js +13 -9
  60. package/admin/src/pages/SettingsPage/pages/Users/ProtectedListPage/index.js +11 -6
  61. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +4 -2
  62. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/WebhookForm/utils/makeWebhookValidationSchema.js +11 -5
  63. package/admin/src/pages/SettingsPage/pages/Webhooks/ListView/index.js +4 -3
  64. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedCreateView/index.js +11 -6
  65. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedEditView/index.js +11 -6
  66. package/admin/src/pages/SettingsPage/pages/Webhooks/ProtectedListView/index.js +11 -6
  67. package/admin/src/translations/ca.json +1 -0
  68. package/admin/src/translations/en.json +4 -1
  69. package/admin/src/translations/es.json +5 -0
  70. package/admin/src/translations/fr.json +1 -0
  71. package/build/1386.3b2aa6a7.chunk.js +3 -0
  72. package/build/1799.44d2e264.chunk.js +33 -0
  73. package/build/1970.39a2d75e.chunk.js +1 -0
  74. package/build/3269.1ea0f5a6.chunk.js +1 -0
  75. package/build/{3528.969338e2.chunk.js → 3528.4845cf92.chunk.js} +1 -1
  76. package/build/448.829e1344.chunk.js +1 -0
  77. package/build/{5542.64b623c9.chunk.js → 5542.c62d0daf.chunk.js} +1 -1
  78. package/build/5563.86f9aa9c.chunk.js +79 -0
  79. package/build/{5932.9e1f8f92.chunk.js → 5932.6a23b88c.chunk.js} +1 -1
  80. package/build/{7018.0e8a6297.chunk.js → 7018.98feed67.chunk.js} +1 -1
  81. package/build/7259.fb69d4bf.chunk.js +1 -0
  82. package/build/7394.423886bd.chunk.js +1 -0
  83. package/build/{371.6e4e2c1f.chunk.js → 970.89601f27.chunk.js} +24 -24
  84. package/build/Admin-authenticatedApp.cb649fc1.chunk.js +79 -0
  85. package/build/{Admin_InternalErrorPage.4a6f7b20.chunk.js → Admin_InternalErrorPage.8911cb49.chunk.js} +1 -1
  86. package/build/{Admin_homePage.6cd6c25c.chunk.js → Admin_homePage.be30ef4e.chunk.js} +1 -1
  87. package/build/{Admin_marketplace.c82c1d3c.chunk.js → Admin_marketplace.74a58e20.chunk.js} +8 -8
  88. package/build/Admin_pluginsPage.ce464189.chunk.js +6 -0
  89. package/build/{Admin_profilePage.9d70d609.chunk.js → Admin_profilePage.2131eb68.chunk.js} +2 -2
  90. package/build/Admin_settingsPage.4069bb8a.chunk.js +79 -0
  91. package/build/{Upload_ConfigureTheView.34f449d7.chunk.js → Upload_ConfigureTheView.7a1cb9c9.chunk.js} +1 -1
  92. package/build/admin-app.fea867af.chunk.js +61 -0
  93. package/build/admin-edit-roles-page.3fdd6b9d.chunk.js +267 -0
  94. package/build/admin-edit-users.200551e3.chunk.js +10 -0
  95. package/build/admin-roles-list.e17b00d7.chunk.js +23 -0
  96. package/build/admin-users.3b12dca2.chunk.js +11 -0
  97. package/build/api-tokens-create-page.3dd4e921.chunk.js +1 -0
  98. package/build/api-tokens-edit-page.9a1dd2fa.chunk.js +1 -0
  99. package/build/api-tokens-list-page.a103f526.chunk.js +16 -0
  100. package/build/audit-logs-settings-page.f538490f.chunk.js +1 -0
  101. package/build/ca-json.1fed5d8b.chunk.js +1 -0
  102. package/build/content-manager.c40f5ff9.chunk.js +1088 -0
  103. package/build/{content-type-builder-list-view.c28d33a6.chunk.js → content-type-builder-list-view.a200a358.chunk.js} +3 -3
  104. package/build/content-type-builder.bd1bbff1.chunk.js +166 -0
  105. package/build/{email-settings-page.aee46eaa.chunk.js → email-settings-page.45695daa.chunk.js} +2 -2
  106. package/build/en-json.fb9f6ddd.chunk.js +1 -0
  107. package/build/es-json.42096084.chunk.js +1 -0
  108. package/build/fr-json.69789980.chunk.js +1 -0
  109. package/build/{i18n-settings-page.4bc37a3f.chunk.js → i18n-settings-page.29308d0b.chunk.js} +1 -1
  110. package/build/index.html +1 -1
  111. package/build/main.ee36abd9.js +2927 -0
  112. package/build/review-workflows-settings.93808ae0.chunk.js +110 -0
  113. package/build/{runtime~main.2d0ed226.js → runtime~main.efd966f6.js} +2 -2
  114. package/build/sso-settings-page.0cdb96a6.chunk.js +1 -0
  115. package/build/transfer-tokens-create-page.de14cad4.chunk.js +1 -0
  116. package/build/transfer-tokens-edit-page.4f5e39af.chunk.js +1 -0
  117. package/build/transfer-tokens-list-page.7237443d.chunk.js +16 -0
  118. package/build/{upload-settings.a05aa26c.chunk.js → upload-settings.cb6c14c3.chunk.js} +2 -2
  119. package/build/upload.7e629643.chunk.js +26 -0
  120. package/build/users-advanced-settings-page.750b1f76.chunk.js +9 -0
  121. package/build/{users-email-settings-page.0bc87315.chunk.js → users-email-settings-page.e9bcd865.chunk.js} +1 -1
  122. package/build/{users-providers-settings-page.e88f1ac5.chunk.js → users-providers-settings-page.a94253e9.chunk.js} +1 -1
  123. package/build/{users-roles-settings-page.573a5c3e.chunk.js → users-roles-settings-page.1f505119.chunk.js} +5 -5
  124. package/build/webhook-edit-page.77ef4f1a.chunk.js +33 -0
  125. package/build/webhook-list-page.940a40f1.chunk.js +63 -0
  126. package/ee/admin/constants.js +16 -0
  127. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +1 -1
  128. package/ee/admin/hooks/useLicenseLimits/index.js +4 -2
  129. package/ee/admin/hooks/useSettingsMenu/constants.js +0 -5
  130. package/ee/admin/pages/AuthPage/constants.js +12 -0
  131. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ListView/index.js +7 -7
  132. package/ee/admin/pages/SettingsPage/pages/AuditLogs/ProtectedListPage/index.js +11 -6
  133. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ProtectedPage.js +20 -0
  134. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/ReviewWorkflows.js +68 -73
  135. package/ee/admin/pages/SettingsPage/pages/SingleSignOn/index.js +16 -12
  136. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/ModalForm/{utils/roleSettingsForm.js → constants.js} +14 -8
  137. package/ee/admin/pages/SettingsPage/pages/Webhooks/EditView/components/EventTable/EventTableEE.js +8 -9
  138. package/ee/server/constants/webhookEvents.js +5 -0
  139. package/ee/server/controllers/workflows/stages/index.js +1 -1
  140. package/ee/server/services/passport.js +1 -1
  141. package/ee/server/services/review-workflows/entity-service-decorator.js +52 -1
  142. package/ee/server/services/review-workflows/review-workflows.js +4 -1
  143. package/package.json +12 -12
  144. package/server/content-types/User.js +10 -0
  145. package/server/services/permission/permissions-manager/sanitize.js +1 -1
  146. package/server/strategies/api-token.js +9 -5
  147. package/server/strategies/data-transfer.js +9 -5
  148. package/admin/src/content-manager/components/DynamicTable/index.js +0 -163
  149. package/admin/src/content-manager/components/RelationInput/components/Relation.js +0 -53
  150. package/admin/src/content-manager/pages/ListView/FieldPicker/utils/getAllAllowedHeader.js +0 -17
  151. package/admin/src/content-manager/pages/ListView/PaginationFooter/index.js +0 -35
  152. package/admin/src/hooks/useMenu/reducer.js +0 -63
  153. package/admin/src/pages/AuthPage/utils/index.js +0 -2
  154. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel.js +0 -8
  155. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/roleSettingsForm.js +0 -3
  156. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/schema.js +0 -11
  157. package/admin/src/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/stepper.js +0 -17
  158. package/admin/src/permissions/customPermissions.js +0 -1
  159. package/admin/src/permissions/defaultPermissions.js +0 -92
  160. package/admin/src/permissions/index.js +0 -8
  161. package/build/1970.d246745e.chunk.js +0 -1
  162. package/build/3562.e0b1a0b3.chunk.js +0 -50
  163. package/build/5563.8a76bb1d.chunk.js +0 -79
  164. package/build/7259.eac09d4b.chunk.js +0 -1
  165. package/build/7447.3dabc92f.chunk.js +0 -35
  166. package/build/9363.6a7a78fc.chunk.js +0 -33
  167. package/build/Admin-authenticatedApp.4e158a8c.chunk.js +0 -79
  168. package/build/Admin_pluginsPage.5d9d4060.chunk.js +0 -6
  169. package/build/Admin_settingsPage.fefeafa0.chunk.js +0 -79
  170. package/build/admin-app.42c7a752.chunk.js +0 -63
  171. package/build/admin-edit-roles-page.6d62ca0b.chunk.js +0 -267
  172. package/build/admin-edit-users.bce64103.chunk.js +0 -10
  173. package/build/admin-roles-list.81ae57e3.chunk.js +0 -23
  174. package/build/admin-users.1ec50325.chunk.js +0 -11
  175. package/build/api-tokens-create-page.65411a36.chunk.js +0 -1
  176. package/build/api-tokens-edit-page.60312cb6.chunk.js +0 -1
  177. package/build/api-tokens-list-page.36a241c1.chunk.js +0 -16
  178. package/build/audit-logs-settings-page.fca8e2a0.chunk.js +0 -1
  179. package/build/ca-json.43e14418.chunk.js +0 -1
  180. package/build/content-manager.d6e60c78.chunk.js +0 -1094
  181. package/build/content-type-builder.dc0c8745.chunk.js +0 -132
  182. package/build/en-json.f5fa476a.chunk.js +0 -1
  183. package/build/es-json.715b6fd8.chunk.js +0 -1
  184. package/build/fr-json.73494bf5.chunk.js +0 -1
  185. package/build/main.9b423e8b.js +0 -2926
  186. package/build/review-workflows-settings.fc0b59ca.chunk.js +0 -61
  187. package/build/sso-settings-page.52f8d7de.chunk.js +0 -1
  188. package/build/transfer-tokens-create-page.9ec277d7.chunk.js +0 -1
  189. package/build/transfer-tokens-edit-page.fa5ade14.chunk.js +0 -1
  190. package/build/transfer-tokens-list-page.ae9900e4.chunk.js +0 -16
  191. package/build/upload.b0efd607.chunk.js +0 -26
  192. package/build/users-advanced-settings-page.d9e11bab.chunk.js +0 -9
  193. package/build/webhook-edit-page.1e8c9382.chunk.js +0 -31
  194. package/build/webhook-list-page.b2bcb3b6.chunk.js +0 -63
  195. package/ee/admin/pages/AuthPage/utils/forms.js +0 -16
  196. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/ModalForm/utils/formDataModel.js +0 -14
  197. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/CellValue.js +0 -0
  198. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/Media/FileWrapper.js +0 -0
  199. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/Media/index.js +0 -0
  200. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/MultipleMedias.js +0 -0
  201. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RelationSingle/index.js +0 -0
  202. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/RepeatableComponent/index.js +0 -0
  203. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/SingleComponent/index.js +0 -0
  204. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/index.js +0 -0
  205. /package/admin/src/content-manager/{components/DynamicTable → pages/ListView/components}/CellContent/utils/isSingleRelation.js +0 -0
@@ -2,6 +2,7 @@ import { useMemo } from 'react';
2
2
 
3
3
  import { useCMEditViewDataManager } from '@strapi/helper-plugin';
4
4
  import get from 'lodash/get';
5
+ import { useRouteMatch } from 'react-router-dom';
5
6
 
6
7
  import { getRequestUrl } from '../../../utils';
7
8
 
@@ -21,6 +22,16 @@ function useSelect({
21
22
  modifiedData,
22
23
  } = useCMEditViewDataManager();
23
24
 
25
+ /**
26
+ * This is our cloning route because the EditView & CloneView share the same UI component
27
+ * We need the origin ID to pre-load the relations into the modifiedData of the new
28
+ * to-be-cloned entity.
29
+ */
30
+ const { params } =
31
+ useRouteMatch('/content-manager/collectionType/:collectionType/create/clone/:origin') ?? {};
32
+
33
+ const { origin } = params ?? {};
34
+
24
35
  const isFieldAllowed = useMemo(() => {
25
36
  if (isUserAllowedToEditField === true) {
26
37
  return true;
@@ -54,9 +65,11 @@ function useSelect({
54
65
  componentId = get(modifiedData, fieldNameKeys.slice(0, -1))?.id;
55
66
  }
56
67
 
68
+ const entityId = origin || modifiedData.id;
69
+
57
70
  // /content-manager/relations/[model]/[id]/[field-name]
58
71
  const relationFetchEndpoint = useMemo(() => {
59
- if (isCreatingEntry) {
72
+ if (isCreatingEntry && !origin) {
60
73
  return null;
61
74
  }
62
75
 
@@ -69,8 +82,8 @@ function useSelect({
69
82
  : null;
70
83
  }
71
84
 
72
- return getRequestUrl(`relations/${slug}/${modifiedData.id}/${name.split('.').at(-1)}`);
73
- }, [isCreatingEntry, componentUid, slug, modifiedData.id, name, componentId, fieldNameKeys]);
85
+ return getRequestUrl(`relations/${slug}/${entityId}/${name.split('.').at(-1)}`);
86
+ }, [isCreatingEntry, origin, componentUid, slug, entityId, name, componentId, fieldNameKeys]);
74
87
 
75
88
  // /content-manager/relations/[model]/[field-name]
76
89
  const relationSearchEndpoint = useMemo(() => {
@@ -82,6 +95,7 @@ function useSelect({
82
95
  }, [componentUid, slug, name]);
83
96
 
84
97
  return {
98
+ entityId,
85
99
  componentId,
86
100
  isComponentRelation: Boolean(componentUid),
87
101
  queryInfos: {
@@ -91,6 +105,7 @@ function useSelect({
91
105
  relation: relationFetchEndpoint,
92
106
  },
93
107
  },
108
+ isCloningEntry: Boolean(origin),
94
109
  isCreatingEntry,
95
110
  isFieldAllowed,
96
111
  isFieldReadable,
@@ -10,10 +10,11 @@ import {
10
10
  import sortBy from 'lodash/sortBy';
11
11
  import { Helmet } from 'react-helmet';
12
12
  import { useIntl } from 'react-intl';
13
+ import { useSelector } from 'react-redux';
13
14
  import { Redirect, Route, Switch, useLocation, useRouteMatch } from 'react-router-dom';
14
15
 
15
16
  import { DragLayer } from '../../../components/DragLayer';
16
- import permissions from '../../../permissions';
17
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
17
18
  import ModelsContext from '../../contexts/ModelsContext';
18
19
  import getTrad from '../../utils/getTrad';
19
20
  import ItemTypes from '../../utils/ItemTypes';
@@ -29,8 +30,6 @@ import { RelationDragPreview } from './components/RelationDragPreview';
29
30
  import LeftMenu from './LeftMenu';
30
31
  import useContentManagerInitData from './useContentManagerInitData';
31
32
 
32
- const cmPermissions = permissions.contentManager;
33
-
34
33
  function renderDraglayerItem({ type, item }) {
35
34
  if ([ItemTypes.EDIT_FIELD, ItemTypes.FIELD].includes(type)) {
36
35
  return <CardDragPreview labelField={item.labelField} />;
@@ -73,6 +72,7 @@ const App = () => {
73
72
  const { formatMessage } = useIntl();
74
73
  const { startSection } = useGuidedTour();
75
74
  const startSectionRef = useRef(startSection);
75
+ const permissions = useSelector(selectAdminPermissions);
76
76
 
77
77
  useEffect(() => {
78
78
  if (startSectionRef.current) {
@@ -127,7 +127,7 @@ const App = () => {
127
127
  <ModelsContext.Provider value={{ refetchData }}>
128
128
  <Switch>
129
129
  <Route path="/content-manager/components/:uid/configurations/edit">
130
- <CheckPagePermissions permissions={cmPermissions.componentsConfigurations}>
130
+ <CheckPagePermissions permissions={permissions.contentManager.componentsConfigurations}>
131
131
  <ComponentSettingsView />
132
132
  </CheckPagePermissions>
133
133
  </Route>
@@ -3,9 +3,10 @@ import React, { memo, useMemo } from 'react';
3
3
  import { CheckPagePermissions, LoadingIndicatorPage } from '@strapi/helper-plugin';
4
4
  import PropTypes from 'prop-types';
5
5
  import { ErrorBoundary } from 'react-error-boundary';
6
+ import { useSelector } from 'react-redux';
6
7
  import { Route, Switch } from 'react-router-dom';
7
8
 
8
- import permissions from '../../../permissions';
9
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
9
10
  import { ContentTypeLayoutContext } from '../../contexts';
10
11
  import { useFetchContentTypeLayout } from '../../hooks';
11
12
  import { formatLayoutToApi } from '../../utils';
@@ -16,14 +17,13 @@ import ListViewLayout from '../ListViewLayoutManager';
16
17
 
17
18
  import ErrorFallback from './components/ErrorFallback';
18
19
 
19
- const cmPermissions = permissions.contentManager;
20
-
21
20
  const CollectionTypeRecursivePath = ({
22
21
  match: {
23
22
  params: { slug },
24
23
  url,
25
24
  },
26
25
  }) => {
26
+ const permissions = useSelector(selectAdminPermissions);
27
27
  const { isLoading, layout, updateLayout } = useFetchContentTypeLayout(slug);
28
28
 
29
29
  const { rawContentTypeLayout, rawComponentsLayouts } = useMemo(() => {
@@ -92,7 +92,9 @@ const CollectionTypeRecursivePath = ({
92
92
  <ContentTypeLayoutContext.Provider value={layout}>
93
93
  <Switch>
94
94
  <Route path={`${url}/configurations/list`}>
95
- <CheckPagePermissions permissions={cmPermissions.collectionTypesConfigurations}>
95
+ <CheckPagePermissions
96
+ permissions={permissions.contentManager.collectionTypesConfigurations}
97
+ >
96
98
  <ListSettingsView
97
99
  layout={rawContentTypeLayout}
98
100
  slug={slug}
@@ -101,7 +103,9 @@ const CollectionTypeRecursivePath = ({
101
103
  </CheckPagePermissions>
102
104
  </Route>
103
105
  <Route path={`${url}/configurations/edit`}>
104
- <CheckPagePermissions permissions={cmPermissions.collectionTypesConfigurations}>
106
+ <CheckPagePermissions
107
+ permissions={permissions.contentManager.collectionTypesConfigurations}
108
+ >
105
109
  <EditSettingsView
106
110
  components={rawComponentsLayouts}
107
111
  isContentTypeView
@@ -5,19 +5,18 @@ import axios from 'axios';
5
5
  import { shallowEqual, useSelector } from 'react-redux';
6
6
  import { useParams } from 'react-router-dom';
7
7
 
8
- import permissions from '../../../permissions';
8
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
9
9
  import { getData, getDataSucceeded } from '../../sharedReducers/crudReducer/actions';
10
10
  import crudReducer, { crudInitialState } from '../../sharedReducers/crudReducer/reducer';
11
11
  import { mergeMetasWithSchema } from '../../utils';
12
12
  import { makeSelectModelAndComponentSchemas } from '../App/selectors';
13
13
  import EditSettingsView from '../EditSettingsView';
14
14
 
15
- const cmPermissions = permissions.contentManager;
16
-
17
15
  const ComponentSettingsView = () => {
18
16
  const [{ isLoading, data: layout }, dispatch] = useReducer(crudReducer, crudInitialState);
19
17
  const schemasSelector = useMemo(makeSelectModelAndComponentSchemas, []);
20
18
  const { schemas } = useSelector((state) => schemasSelector(state), shallowEqual);
19
+ const permissions = useSelector(selectAdminPermissions);
21
20
  const { uid } = useParams();
22
21
  const { get } = useFetchClient();
23
22
 
@@ -54,7 +53,7 @@ const ComponentSettingsView = () => {
54
53
  }
55
54
 
56
55
  return (
57
- <CheckPagePermissions permissions={cmPermissions.componentsConfigurations}>
56
+ <CheckPagePermissions permissions={permissions.contentManager.componentsConfigurations}>
58
57
  <EditSettingsView components={layout.components} mainLayout={layout.component} slug={uid} />
59
58
  </CheckPagePermissions>
60
59
  );
@@ -0,0 +1,14 @@
1
+ /* eslint-disable react-hooks/exhaustive-deps */
2
+ import { useEffect } from 'react';
3
+
4
+ /**
5
+ *
6
+ * @param {import('react').EffectCallback} effect
7
+ * @returns void
8
+ */
9
+ export const useOnce = (effect) => useEffect(effect, emptyDeps);
10
+
11
+ /**
12
+ * @type {import('react').DependencyList}
13
+ */
14
+ const emptyDeps = [];
@@ -1,10 +1,11 @@
1
- import React, { memo } from 'react';
1
+ import * as React from 'react';
2
2
 
3
- import { Box, ContentLayout, Flex, Grid, GridItem, Main } from '@strapi/design-system';
3
+ import { Main, ContentLayout, Grid, GridItem, Flex, Box } from '@strapi/design-system';
4
4
  import {
5
5
  CheckPermissions,
6
6
  LinkButton,
7
7
  LoadingIndicatorPage,
8
+ useNotification,
8
9
  useTracking,
9
10
  } from '@strapi/helper-plugin';
10
11
  import { Layer, Pencil } from '@strapi/icons';
@@ -12,8 +13,9 @@ import InformationBox from 'ee_else_ce/content-manager/pages/EditView/Informatio
12
13
  import PropTypes from 'prop-types';
13
14
  import { useIntl } from 'react-intl';
14
15
  import { useSelector } from 'react-redux';
16
+ import { useLocation } from 'react-router-dom';
15
17
 
16
- import permissions from '../../../permissions';
18
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
17
19
  import { InjectionZone } from '../../../shared/components';
18
20
  import CollectionTypeFormWrapper from '../../components/CollectionTypeFormWrapper';
19
21
  import { DynamicZone } from '../../components/DynamicZone';
@@ -26,16 +28,35 @@ import DeleteLink from './DeleteLink';
26
28
  import DraftAndPublishBadge from './DraftAndPublishBadge';
27
29
  import GridRow from './GridRow';
28
30
  import Header from './Header';
29
- import { selectAttributesLayout, selectCurrentLayout, selectCustomFieldUids } from './selectors';
31
+ import { useOnce } from './hooks/useOnce';
32
+ import { selectCurrentLayout, selectAttributesLayout, selectCustomFieldUids } from './selectors';
30
33
  import { getFieldsActionMatchingPermissions } from './utils';
31
34
 
32
- const cmPermissions = permissions.contentManager;
33
- const ctbPermissions = [{ action: 'plugin::content-type-builder.read', subject: null }];
35
+ // TODO: this seems suspicious
36
+ const CTB_PERMISSIONS = [{ action: 'plugin::content-type-builder.read', subject: null }];
34
37
 
35
38
  /* eslint-disable react/no-array-index-key */
36
39
  const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, userPermissions }) => {
37
40
  const { trackUsage } = useTracking();
38
41
  const { formatMessage } = useIntl();
42
+ const permissions = useSelector(selectAdminPermissions);
43
+ const location = useLocation();
44
+ const toggleNotification = useNotification();
45
+
46
+ useOnce(() => {
47
+ /**
48
+ * We only ever want to fire the notification once otherwise
49
+ * whenever the app re-renders it'll pop up regardless of
50
+ * what we do because the state comes from react-router-dom
51
+ */
52
+ if (location?.state && 'error' in location.state) {
53
+ toggleNotification({
54
+ type: 'warning',
55
+ message: location.state.error,
56
+ timeout: 5000,
57
+ });
58
+ }
59
+ });
39
60
 
40
61
  const { layout, formattedContentTypeLayout, customFieldUids } = useSelector((state) => ({
41
62
  layout: selectCurrentLayout(state),
@@ -49,8 +70,8 @@ const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, user
49
70
  getFieldsActionMatchingPermissions(userPermissions, slug);
50
71
 
51
72
  const configurationPermissions = isSingleType
52
- ? cmPermissions.singleTypesConfigurations
53
- : cmPermissions.collectionTypesConfigurations;
73
+ ? permissions.contentManager.singleTypesConfigurations
74
+ : permissions.contentManager.collectionTypesConfigurations;
54
75
 
55
76
  // // FIXME when changing the routing
56
77
  const configurationsURL = `/content-manager/${
@@ -188,7 +209,7 @@ const EditView = ({ allowedActions, isSingleType, goBack, slug, id, origin, user
188
209
  <Flex direction="column" alignItems="stretch" gap={2}>
189
210
  <InjectionZone area="contentManager.editView.right-links" slug={slug} />
190
211
  {slug !== 'strapi::administrator' && (
191
- <CheckPermissions permissions={ctbPermissions}>
212
+ <CheckPermissions permissions={CTB_PERMISSIONS}>
192
213
  <LinkButton
193
214
  onClick={() => {
194
215
  trackUsage('willEditEditLayout');
@@ -261,4 +282,4 @@ EditView.propTypes = {
261
282
  userPermissions: PropTypes.array,
262
283
  };
263
284
 
264
- export default memo(EditView);
285
+ export default EditView;
@@ -16,7 +16,7 @@ import { useIntl } from 'react-intl';
16
16
  import { useQuery } from 'react-query';
17
17
  import styled from 'styled-components';
18
18
 
19
- import { getRequestUrl, getTrad } from '../../../../utils';
19
+ import { getRequestUrl, getTrad } from '../../../../../utils';
20
20
  import CellValue from '../CellValue';
21
21
 
22
22
  const TypographyMaxWidth = styled(Typography)`
@@ -1,7 +1,7 @@
1
1
  import isEmpty from 'lodash/isEmpty';
2
2
  import isNumber from 'lodash/isNumber';
3
3
 
4
- import isFieldTypeNumber from '../../../../utils/isFieldTypeNumber';
4
+ import isFieldTypeNumber from '../../../../../utils/isFieldTypeNumber';
5
5
 
6
6
  import isSingleRelation from './isSingleRelation';
7
7
 
@@ -5,9 +5,14 @@ import { ExclamationMarkCircle, Trash } from '@strapi/icons';
5
5
  import PropTypes from 'prop-types';
6
6
  import { useIntl } from 'react-intl';
7
7
 
8
- import InjectionZoneList from '../../InjectionZoneList';
8
+ import InjectionZoneList from '../../../../components/InjectionZoneList';
9
9
 
10
- const ConfirmDialogDelete = ({ isConfirmButtonLoading, isOpen, onToggleDialog, onConfirm }) => {
10
+ export const ConfirmDialogDelete = ({
11
+ isConfirmButtonLoading,
12
+ isOpen,
13
+ onToggleDialog,
14
+ onConfirm,
15
+ }) => {
11
16
  const { formatMessage } = useIntl();
12
17
 
13
18
  return (
@@ -70,5 +75,3 @@ ConfirmDialogDelete.propTypes = {
70
75
  onConfirm: PropTypes.func.isRequired,
71
76
  onToggleDialog: PropTypes.func.isRequired,
72
77
  };
73
-
74
- export default ConfirmDialogDelete;
@@ -0,0 +1,78 @@
1
+ import React from 'react';
2
+
3
+ import { Dialog, DialogBody, DialogFooter, Flex, Typography, Button } from '@strapi/design-system';
4
+ import { ExclamationMarkCircle, Trash } from '@strapi/icons';
5
+ import PropTypes from 'prop-types';
6
+ import { useIntl } from 'react-intl';
7
+
8
+ import InjectionZoneList from '../../../../components/InjectionZoneList';
9
+ import { getTrad } from '../../../../utils';
10
+
11
+ export const ConfirmDialogDeleteAll = ({
12
+ isConfirmButtonLoading,
13
+ isOpen,
14
+ onToggleDialog,
15
+ onConfirm,
16
+ }) => {
17
+ const { formatMessage } = useIntl();
18
+
19
+ return (
20
+ <Dialog
21
+ onClose={onToggleDialog}
22
+ title={formatMessage({
23
+ id: 'app.components.ConfirmDialog.title',
24
+ defaultMessage: 'Confirmation',
25
+ })}
26
+ labelledBy="confirmation"
27
+ describedBy="confirm-description"
28
+ isOpen={isOpen}
29
+ >
30
+ <DialogBody icon={<ExclamationMarkCircle />}>
31
+ <Flex direction="column" alignItems="stretch" gap={2}>
32
+ <Flex justifyContent="center">
33
+ <Typography id="confirm-description">
34
+ {formatMessage({
35
+ id: getTrad('popUpWarning.bodyMessage.contentType.delete.all'),
36
+ defaultMessage: 'Are you sure you want to delete these entries?',
37
+ })}
38
+ </Typography>
39
+ </Flex>
40
+ <Flex>
41
+ <InjectionZoneList area="contentManager.listView.deleteModalAdditionalInfos" />
42
+ </Flex>
43
+ </Flex>
44
+ </DialogBody>
45
+ <DialogFooter
46
+ startAction={
47
+ <Button onClick={onToggleDialog} variant="tertiary">
48
+ {formatMessage({
49
+ id: 'app.components.Button.cancel',
50
+ defaultMessage: 'Cancel',
51
+ })}
52
+ </Button>
53
+ }
54
+ endAction={
55
+ <Button
56
+ onClick={onConfirm}
57
+ variant="danger-light"
58
+ startIcon={<Trash />}
59
+ id="confirm-delete"
60
+ loading={isConfirmButtonLoading}
61
+ >
62
+ {formatMessage({
63
+ id: 'app.components.Button.confirm',
64
+ defaultMessage: 'Confirm',
65
+ })}
66
+ </Button>
67
+ }
68
+ />
69
+ </Dialog>
70
+ );
71
+ };
72
+
73
+ ConfirmDialogDeleteAll.propTypes = {
74
+ isConfirmButtonLoading: PropTypes.bool.isRequired,
75
+ isOpen: PropTypes.bool.isRequired,
76
+ onConfirm: PropTypes.func.isRequired,
77
+ onToggleDialog: PropTypes.func.isRequired,
78
+ };
@@ -1,18 +1,16 @@
1
- import React, { memo } from 'react';
1
+ import React from 'react';
2
2
 
3
- import { Box, Option, Select } from '@strapi/design-system';
3
+ import { Select, Option, Box } from '@strapi/design-system';
4
4
  import { useTracking } from '@strapi/helper-plugin';
5
5
  import PropTypes from 'prop-types';
6
6
  import { useIntl } from 'react-intl';
7
7
  import { useDispatch, useSelector } from 'react-redux';
8
8
 
9
- import getTrad from '../../../utils/getTrad';
10
- import { onChangeListHeaders } from '../actions';
11
- import { selectDisplayedHeaders } from '../selectors';
9
+ import { getTrad, checkIfAttributeIsDisplayable } from '../../../../utils';
10
+ import { onChangeListHeaders } from '../../actions';
11
+ import { selectDisplayedHeaders } from '../../selectors';
12
12
 
13
- import getAllAllowedHeaders from './utils/getAllAllowedHeader';
14
-
15
- const FieldPicker = ({ layout }) => {
13
+ export const FieldPicker = ({ layout }) => {
16
14
  const dispatch = useDispatch();
17
15
  const displayedHeaders = useSelector(selectDisplayedHeaders);
18
16
  const { trackUsage } = useTracking();
@@ -26,6 +24,7 @@ const FieldPicker = ({ layout }) => {
26
24
  intlLabel: { id: metadatas.label, defaultMessage: metadatas.label },
27
25
  };
28
26
  });
27
+
29
28
  const values = displayedHeaders.map(({ name }) => name);
30
29
 
31
30
  const handleChange = (updatedValues) => {
@@ -94,4 +93,16 @@ FieldPicker.propTypes = {
94
93
  }).isRequired,
95
94
  };
96
95
 
97
- export default memo(FieldPicker);
96
+ const getAllAllowedHeaders = (attributes) => {
97
+ const allowedAttributes = Object.keys(attributes).reduce((acc, current) => {
98
+ const attribute = attributes[current];
99
+
100
+ if (checkIfAttributeIsDisplayable(attribute)) {
101
+ acc.push(current);
102
+ }
103
+
104
+ return acc;
105
+ }, []);
106
+
107
+ return allowedAttributes.sort();
108
+ };
@@ -1,17 +1,19 @@
1
1
  import React from 'react';
2
2
 
3
- import { BaseCheckbox, Box, Flex, IconButton, Tbody, Td, Tr } from '@strapi/design-system';
4
- import { onRowClick, stopPropagation, useTracking } from '@strapi/helper-plugin';
5
- import { Duplicate, Pencil, Trash } from '@strapi/icons';
3
+ import { BaseCheckbox, IconButton, Tbody, Td, Tr, Flex } from '@strapi/design-system';
4
+ import { useTracking, useFetchClient, useAPIErrorHandler } from '@strapi/helper-plugin';
5
+ import { Trash, Duplicate, Pencil } from '@strapi/icons';
6
+ import { AxiosError } from 'axios';
6
7
  import PropTypes from 'prop-types';
7
8
  import { useIntl } from 'react-intl';
8
9
  import { Link, useHistory } from 'react-router-dom';
9
10
 
10
- import { getFullName } from '../../../../utils';
11
- import { usePluginsQueryParams } from '../../../hooks';
11
+ import { getFullName } from '../../../../../utils';
12
+ import { usePluginsQueryParams } from '../../../../hooks';
13
+ import { getTrad } from '../../../../utils';
12
14
  import CellContent from '../CellContent';
13
15
 
14
- const TableRows = ({
16
+ export const TableRows = ({
15
17
  canCreate,
16
18
  canDelete,
17
19
  contentType,
@@ -23,19 +25,63 @@ const TableRows = ({
23
25
  withBulkActions,
24
26
  rows,
25
27
  }) => {
26
- const {
27
- push,
28
- location: { pathname },
29
- } = useHistory();
28
+ const { push, location } = useHistory();
29
+ const { pathname } = location;
30
30
  const { formatMessage } = useIntl();
31
+ const { post } = useFetchClient();
31
32
 
32
33
  const { trackUsage } = useTracking();
33
34
  const pluginsQueryParams = usePluginsQueryParams();
35
+ const { formatAPIError } = useAPIErrorHandler(getTrad);
34
36
 
37
+ /**
38
+ *
39
+ * @param {string} id
40
+ * @returns void
41
+ */
42
+ const handleRowClick = (id) => () => {
43
+ if (!withBulkActions) return;
44
+
45
+ trackUsage('willEditEntryFromList');
46
+ push({
47
+ pathname: `${pathname}/${id}`,
48
+ state: { from: pathname },
49
+ search: pluginsQueryParams,
50
+ });
51
+ };
52
+
53
+ const handleCloneClick = (id) => async () => {
54
+ try {
55
+ const { data } = await post(
56
+ `/content-manager/collection-types/${contentType.uid}/auto-clone/${id}?${pluginsQueryParams}`
57
+ );
58
+
59
+ if ('id' in data) {
60
+ push({
61
+ pathname: `${pathname}/${data.id}`,
62
+ state: { from: pathname },
63
+ search: pluginsQueryParams,
64
+ });
65
+ }
66
+ } catch (err) {
67
+ if (err instanceof AxiosError) {
68
+ push({
69
+ pathname: `${pathname}/create/clone/${id}`,
70
+ state: { from: pathname, error: formatAPIError(err) },
71
+ search: pluginsQueryParams,
72
+ });
73
+ }
74
+ }
75
+ };
76
+
77
+ /**
78
+ * Table Cells with actions e.g edit, delete, duplicate have `stopPropagation`
79
+ * to prevent the row from being selected.
80
+ */
35
81
  return (
36
82
  <Tbody>
37
83
  {rows.map((data, index) => {
38
- const isChecked = entriesToDelete.findIndex((id) => id === data.id) !== -1;
84
+ const isChecked = entriesToDelete.includes(data.id);
39
85
  const itemLineText = formatMessage(
40
86
  {
41
87
  id: 'content-manager.components.DynamicTable.row-line',
@@ -46,21 +92,12 @@ const TableRows = ({
46
92
 
47
93
  return (
48
94
  <Tr
95
+ cursor={withBulkActions ? 'pointer' : 'default'}
49
96
  key={data.id}
50
- {...onRowClick({
51
- fn() {
52
- trackUsage('willEditEntryFromList');
53
- push({
54
- pathname: `${pathname}/${data.id}`,
55
- state: { from: pathname },
56
- search: pluginsQueryParams,
57
- });
58
- },
59
- condition: withBulkActions,
60
- })}
97
+ onClick={handleRowClick(data.id)}
61
98
  >
62
99
  {withMainAction && (
63
- <Td {...stopPropagation}>
100
+ <Td onClick={(e) => e.stopPropagation()}>
64
101
  <BaseCheckbox
65
102
  aria-label={formatMessage(
66
103
  {
@@ -96,7 +133,7 @@ const TableRows = ({
96
133
 
97
134
  {withBulkActions && (
98
135
  <Td>
99
- <Flex justifyContent="end" {...stopPropagation}>
136
+ <Flex as="span" justifyContent="end" gap={1} onClick={(e) => e.stopPropagation()}>
100
137
  <IconButton
101
138
  forwardedAs={Link}
102
139
  onClick={() => {
@@ -112,46 +149,40 @@ const TableRows = ({
112
149
  { target: itemLineText }
113
150
  )}
114
151
  noBorder
115
- icon={<Pencil />}
116
- />
152
+ >
153
+ <Pencil />
154
+ </IconButton>
117
155
 
118
156
  {canCreate && (
119
- <Box paddingLeft={1}>
120
- <IconButton
121
- forwardedAs={Link}
122
- to={{
123
- pathname: `${pathname}/create/clone/${data.id}`,
124
- state: { from: pathname },
125
- search: pluginsQueryParams,
126
- }}
127
- label={formatMessage(
128
- {
129
- id: 'app.component.table.duplicate',
130
- defaultMessage: 'Duplicate {target}',
131
- },
132
- { target: itemLineText }
133
- )}
134
- noBorder
135
- icon={<Duplicate />}
136
- />
137
- </Box>
157
+ <IconButton
158
+ onClick={handleCloneClick(data.id)}
159
+ label={formatMessage(
160
+ {
161
+ id: 'app.component.table.duplicate',
162
+ defaultMessage: 'Duplicate {target}',
163
+ },
164
+ { target: itemLineText }
165
+ )}
166
+ noBorder
167
+ >
168
+ <Duplicate />
169
+ </IconButton>
138
170
  )}
139
171
 
140
172
  {canDelete && (
141
- <Box paddingLeft={1}>
142
- <IconButton
143
- onClick={() => {
144
- trackUsage('willDeleteEntryFromList');
145
- onClickDelete(data.id);
146
- }}
147
- label={formatMessage(
148
- { id: 'global.delete-target', defaultMessage: 'Delete {target}' },
149
- { target: itemLineText }
150
- )}
151
- noBorder
152
- icon={<Trash />}
153
- />
154
- </Box>
173
+ <IconButton
174
+ onClick={() => {
175
+ trackUsage('willDeleteEntryFromList');
176
+ onClickDelete(data.id);
177
+ }}
178
+ label={formatMessage(
179
+ { id: 'global.delete-target', defaultMessage: 'Delete {target}' },
180
+ { target: itemLineText }
181
+ )}
182
+ noBorder
183
+ >
184
+ <Trash />
185
+ </IconButton>
155
186
  )}
156
187
  </Flex>
157
188
  </Td>
@@ -188,5 +219,3 @@ TableRows.propTypes = {
188
219
  withBulkActions: PropTypes.bool,
189
220
  withMainAction: PropTypes.bool,
190
221
  };
191
-
192
- export default TableRows;