@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
@@ -1,55 +1,64 @@
1
- import React, { memo, useCallback, useEffect, useRef } from 'react';
1
+ import * as React from 'react';
2
2
 
3
3
  import {
4
- ActionLayout,
4
+ IconButton,
5
+ Main,
5
6
  Box,
7
+ ActionLayout,
6
8
  Button,
7
9
  ContentLayout,
8
10
  HeaderLayout,
9
- IconButton,
10
- Main,
11
11
  useNotifyAT,
12
+ Flex,
13
+ Typography,
14
+ Status,
12
15
  } from '@strapi/design-system';
13
16
  import {
14
- CheckPermissions,
15
- getYupInnerErrors,
16
- Link,
17
17
  NoPermissions,
18
+ CheckPermissions,
18
19
  SearchURLQuery,
19
- useAPIErrorHandler,
20
20
  useFetchClient,
21
21
  useFocusWhenNavigate,
22
- useNotification,
23
22
  useQueryParams,
23
+ useNotification,
24
24
  useRBACProvider,
25
25
  useTracking,
26
+ Link,
27
+ useAPIErrorHandler,
28
+ getYupInnerErrors,
29
+ useStrapiApp,
30
+ DynamicTable,
31
+ PaginationURLQuery,
32
+ PageSizeURLQuery,
26
33
  } from '@strapi/helper-plugin';
27
34
  import { ArrowLeft, Cog, Plus } from '@strapi/icons';
28
35
  import axios from 'axios';
36
+ import getReviewWorkflowsColumn from 'ee_else_ce/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumn';
29
37
  import isEqual from 'lodash/isEqual';
30
38
  import PropTypes from 'prop-types';
31
39
  import { stringify } from 'qs';
32
40
  import { useIntl } from 'react-intl';
33
41
  import { useMutation } from 'react-query';
34
- import { connect } from 'react-redux';
35
- import { Link as ReactRouterLink, useHistory, useLocation } from 'react-router-dom';
42
+ import { connect, useSelector } from 'react-redux';
43
+ import { useHistory, useLocation, Link as ReactRouterLink } from 'react-router-dom';
36
44
  import { bindActionCreators, compose } from 'redux';
37
45
  import styled from 'styled-components';
38
46
 
39
- import permissions from '../../../permissions';
47
+ import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
48
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
40
49
  import { InjectionZone } from '../../../shared/components';
41
50
  import AttributeFilter from '../../components/AttributeFilter';
42
- import DynamicTable from '../../components/DynamicTable';
51
+ import BulkActionsBar from '../../components/DynamicTable/BulkActionsBar';
43
52
  import { createYupSchema, getRequestUrl, getTrad } from '../../utils';
44
53
 
45
54
  import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } from './actions';
46
- import FieldPicker from './FieldPicker';
47
- import PaginationFooter from './PaginationFooter';
48
- import makeSelectListView from './selectors';
55
+ import { ConfirmDialogDelete } from './components/ConfirmDialogDelete';
56
+ import { ConfirmDialogDeleteAll } from './components/ConfirmDialogDeleteAll';
57
+ import { FieldPicker } from './components/FieldPicker';
58
+ import { TableRows } from './components/TableRows';
59
+ import makeSelectListView, { selectDisplayedHeaders } from './selectors';
49
60
  import { buildQueryString } from './utils';
50
61
 
51
- const cmPermissions = permissions.contentManager;
52
-
53
62
  const ConfigureLayoutBox = styled(Box)`
54
63
  svg {
55
64
  path {
@@ -74,6 +83,8 @@ function ListView({
74
83
  const { total } = pagination;
75
84
  const { contentType } = layout;
76
85
  const {
86
+ info,
87
+ options,
77
88
  metadatas,
78
89
  settings: { bulkable: isBulkable, filterable: isFilterable, searchable: isSearchable },
79
90
  } = contentType;
@@ -81,10 +92,11 @@ function ListView({
81
92
  const toggleNotification = useNotification();
82
93
  const { trackUsage } = useTracking();
83
94
  const { refetchPermissions } = useRBACProvider();
84
- const trackUsageRef = useRef(trackUsage);
85
- const fetchPermissionsRef = useRef(refetchPermissions);
95
+ const trackUsageRef = React.useRef(trackUsage);
96
+ const fetchPermissionsRef = React.useRef(refetchPermissions);
86
97
  const { notifyStatus } = useNotifyAT();
87
98
  const { formatAPIError } = useAPIErrorHandler(getTrad);
99
+ const permissions = useSelector(selectAdminPermissions);
88
100
 
89
101
  useFocusWhenNavigate();
90
102
 
@@ -95,7 +107,7 @@ function ListView({
95
107
  const { pathname } = useLocation();
96
108
  const { push } = useHistory();
97
109
  const { formatMessage } = useIntl();
98
- const hasDraftAndPublish = contentType.options?.draftAndPublish ?? false;
110
+ const hasDraftAndPublish = options?.draftAndPublish || false;
99
111
  const fetchClient = useFetchClient();
100
112
  const { post, del } = fetchClient;
101
113
 
@@ -146,9 +158,12 @@ function ListView({
146
158
  // FIXME
147
159
  // Using a ref to avoid requests being fired multiple times on slug on change
148
160
  // We need it because the hook as mulitple dependencies so it may run before the permissions have checked
149
- const requestUrlRef = useRef('');
161
+ const requestUrlRef = React.useRef('');
150
162
 
151
- const fetchData = useCallback(
163
+ /**
164
+ * TODO: re-write all of this, it's a mess.
165
+ */
166
+ const fetchData = React.useCallback(
152
167
  async (endPoint, source) => {
153
168
  getData();
154
169
 
@@ -200,7 +215,7 @@ function ListView({
200
215
  [formatMessage, getData, getDataSucceeded, notifyStatus, push, toggleNotification, fetchClient]
201
216
  );
202
217
 
203
- const handleConfirmDeleteAllData = useCallback(
218
+ const handleConfirmDeleteAllData = React.useCallback(
204
219
  async (ids) => {
205
220
  try {
206
221
  await post(getRequestUrl(`collection-types/${slug}/actions/bulkDelete`), {
@@ -220,7 +235,7 @@ function ListView({
220
235
  [fetchData, params, slug, toggleNotification, formatAPIError, post]
221
236
  );
222
237
 
223
- const handleConfirmDeleteData = useCallback(
238
+ const handleConfirmDeleteData = React.useCallback(
224
239
  async (idToDelete) => {
225
240
  try {
226
241
  await del(getRequestUrl(`collection-types/${slug}/${idToDelete}`));
@@ -306,7 +321,7 @@ function ListView({
306
321
  return bulkUnpublishMutation.mutateAsync({ ids: selectedEntries });
307
322
  };
308
323
 
309
- useEffect(() => {
324
+ React.useEffect(() => {
310
325
  const CancelToken = axios.CancelToken;
311
326
  const source = CancelToken.source();
312
327
 
@@ -329,10 +344,101 @@ function ListView({
329
344
  defaultMessage: 'Content',
330
345
  });
331
346
  const headerLayoutTitle = formatMessage({
332
- id: contentType.info.displayName,
333
- defaultMessage: contentType.info.displayName || defaultHeaderLayoutTitle,
347
+ id: info.displayName,
348
+ defaultMessage: info.displayName || defaultHeaderLayoutTitle,
334
349
  });
335
350
 
351
+ const { runHookWaterfall } = useStrapiApp();
352
+ const displayedHeaders = useSelector(selectDisplayedHeaders);
353
+
354
+ const tableHeaders = React.useMemo(() => {
355
+ const headers = runHookWaterfall(INJECT_COLUMN_IN_TABLE, {
356
+ displayedHeaders,
357
+ layout,
358
+ });
359
+
360
+ const formattedHeaders = headers.displayedHeaders.map((header) => {
361
+ const { metadatas } = header;
362
+
363
+ if (header.fieldSchema.type === 'relation') {
364
+ const sortFieldValue = `${header.name}.${header.metadatas.mainField.name}`;
365
+
366
+ return {
367
+ ...header,
368
+ metadatas: {
369
+ ...metadatas,
370
+ label: formatMessage({
371
+ id: getTrad(`containers.ListPage.table-headers.${header.name}`),
372
+ defaultMessage: metadatas.label,
373
+ }),
374
+ },
375
+ name: sortFieldValue,
376
+ };
377
+ }
378
+
379
+ return {
380
+ ...header,
381
+ metadatas: {
382
+ ...metadatas,
383
+ label: formatMessage({
384
+ id: getTrad(`containers.ListPage.table-headers.${header.name}`),
385
+ defaultMessage: metadatas.label,
386
+ }),
387
+ },
388
+ };
389
+ });
390
+
391
+ if (!hasDraftAndPublish) {
392
+ return formattedHeaders;
393
+ }
394
+
395
+ // this should not exist. Ideally we would use registerHook() similar to what has been done
396
+ // in the i18n plugin. In order to do that review-workflows should have been a plugin. In
397
+ // a future iteration we need to find a better pattern.
398
+
399
+ // In CE this will return null - in EE a column definition including the custom formatting component.
400
+ const reviewWorkflowColumn = getReviewWorkflowsColumn(layout);
401
+
402
+ if (reviewWorkflowColumn) {
403
+ formattedHeaders.push(reviewWorkflowColumn);
404
+ }
405
+
406
+ return [
407
+ ...formattedHeaders,
408
+ {
409
+ key: '__published_at_temp_key__',
410
+ name: 'publishedAt',
411
+ fieldSchema: {
412
+ type: 'custom',
413
+ },
414
+ metadatas: {
415
+ label: formatMessage({
416
+ id: getTrad(`containers.ListPage.table-headers.publishedAt`),
417
+ defaultMessage: 'publishedAt',
418
+ }),
419
+ searchable: false,
420
+ sortable: true,
421
+ },
422
+ // eslint-disable-next-line react/no-unstable-nested-components
423
+ cellFormatter(cellData) {
424
+ const isPublished = cellData.publishedAt;
425
+ const variant = isPublished ? 'success' : 'secondary';
426
+
427
+ return (
428
+ <Status width="min-content" showBullet={false} variant={variant} size="S">
429
+ <Typography fontWeight="bold" textColor={`${variant}700`}>
430
+ {formatMessage({
431
+ id: getTrad(`containers.List.${isPublished ? 'published' : 'draft'}`),
432
+ defaultMessage: isPublished ? 'Published' : 'Draft',
433
+ })}
434
+ </Typography>
435
+ </Status>
436
+ );
437
+ },
438
+ },
439
+ ];
440
+ }, [runHookWaterfall, displayedHeaders, layout, hasDraftAndPublish, formatMessage]);
441
+
336
442
  const subtitle = canRead
337
443
  ? formatMessage(
338
444
  {
@@ -391,7 +497,9 @@ function ListView({
391
497
  <>
392
498
  <InjectionZone area="contentManager.listView.actions" />
393
499
  <FieldPicker layout={layout} />
394
- <CheckPermissions permissions={cmPermissions.collectionTypesConfigurations}>
500
+ <CheckPermissions
501
+ permissions={permissions.contentManager.collectionTypesConfigurations}
502
+ >
395
503
  <ConfigureLayoutBox paddingTop={1} paddingBottom={1}>
396
504
  <IconButton
397
505
  onClick={() => {
@@ -433,7 +541,7 @@ function ListView({
433
541
  )}
434
542
  <ContentLayout>
435
543
  {canRead ? (
436
- <>
544
+ <Flex gap={4} direction="column" alignItems="stretch">
437
545
  <DynamicTable
438
546
  canCreate={canCreate}
439
547
  canDelete={canDelete}
@@ -448,10 +556,41 @@ function ListView({
448
556
  // FIXME: remove the layout props drilling
449
557
  layout={layout}
450
558
  rows={data}
559
+ components={{ ConfirmDialogDelete, ConfirmDialogDeleteAll }}
560
+ contentType={headerLayoutTitle}
451
561
  action={getCreateAction({ variant: 'secondary' })}
452
- />
453
- <PaginationFooter pagination={{ pageCount: pagination?.pageCount || 1 }} />
454
- </>
562
+ headers={tableHeaders}
563
+ onOpenDeleteAllModalTrackedEvent="willBulkDeleteEntries"
564
+ withBulkActions
565
+ withMainAction={canDelete && isBulkable}
566
+ renderBulkActionsBar={({ selectedEntries, clearSelectedEntries }) => (
567
+ <BulkActionsBar
568
+ showPublish={canPublish && hasDraftAndPublish}
569
+ showDelete={canDelete}
570
+ onConfirmDeleteAll={handleConfirmDeleteAllData}
571
+ onConfirmPublishAll={handleConfirmPublishAllData}
572
+ onConfirmUnpublishAll={handleConfirmUnpublishAllData}
573
+ selectedEntries={selectedEntries}
574
+ clearSelectedEntries={clearSelectedEntries}
575
+ />
576
+ )}
577
+ bulkAction
578
+ >
579
+ <TableRows
580
+ canCreate={canCreate}
581
+ canDelete={canDelete}
582
+ contentType={contentType}
583
+ headers={tableHeaders}
584
+ rows={data}
585
+ withBulkActions
586
+ withMainAction={canDelete && isBulkable}
587
+ />
588
+ </DynamicTable>
589
+ <Flex alignItems="flex-end" justifyContent="space-between">
590
+ <PageSizeURLQuery trackedEvent="willChangeNumberOfEntriesPerPage" />
591
+ <PaginationURLQuery pagination={{ pageCount: pagination?.pageCount || 1 }} />
592
+ </Flex>
593
+ </Flex>
455
594
  ) : (
456
595
  <NoPermissions />
457
596
  )}
@@ -503,4 +642,4 @@ export function mapDispatchToProps(dispatch) {
503
642
  }
504
643
  const withConnect = connect(mapStateToProps, mapDispatchToProps);
505
644
 
506
- export default compose(withConnect)(memo(ListView, isEqual));
645
+ export default compose(withConnect)(React.memo(ListView, isEqual));
@@ -1,3 +1 @@
1
- // export { default as getAllAllowedHeaders } from './getAllAllowedHeaders';
2
- // export { default as getFirstSortableHeader } from './getFirstSortableHeader';
3
1
  export { default as buildQueryString } from './buildQueryString';
@@ -34,7 +34,7 @@ export default memo(Permissions, (prev, next) => {
34
34
  // When we navigate from the EV to the LV using the menu the state is lost at some point
35
35
  // and this causes the component to rerender twice and firing requests twice
36
36
  // this hack prevents this
37
- // TODO at some point we will need to refacto the LV and migrate to react-query
37
+ // TODO: at some point we will need to refactor the LV and migrate to react-query
38
38
  const propNamesThatHaveChanged = Object.keys(differenceBetweenRerenders).filter(
39
39
  (propName) => propName !== 'state'
40
40
  );
@@ -2,23 +2,23 @@ import React, { memo, useMemo } from 'react';
2
2
 
3
3
  import { CheckPagePermissions, LoadingIndicatorPage } from '@strapi/helper-plugin';
4
4
  import PropTypes from 'prop-types';
5
+ import { useSelector } from 'react-redux';
5
6
  import { Route, Switch } from 'react-router-dom';
6
7
 
7
- import permissions from '../../../permissions';
8
+ import { selectAdminPermissions } from '../../../pages/App/selectors';
8
9
  import { ContentTypeLayoutContext } from '../../contexts';
9
10
  import { useFetchContentTypeLayout } from '../../hooks';
10
11
  import { formatLayoutToApi } from '../../utils';
11
12
  import EditSettingsView from '../EditSettingsView';
12
13
  import EditViewLayoutManager from '../EditViewLayoutManager';
13
14
 
14
- const cmPermissions = permissions.contentManager;
15
-
16
15
  const SingleTypeRecursivePath = ({
17
16
  match: {
18
17
  params: { slug },
19
18
  url,
20
19
  },
21
20
  }) => {
21
+ const permissions = useSelector(selectAdminPermissions);
22
22
  const { isLoading, layout, updateLayout } = useFetchContentTypeLayout(slug);
23
23
 
24
24
  const { rawContentTypeLayout, rawComponentsLayouts } = useMemo(() => {
@@ -48,7 +48,7 @@ const SingleTypeRecursivePath = ({
48
48
  <ContentTypeLayoutContext.Provider value={layout}>
49
49
  <Switch>
50
50
  <Route path={`${url}/configurations/edit`}>
51
- <CheckPagePermissions permissions={cmPermissions.singleTypesConfigurations}>
51
+ <CheckPagePermissions permissions={permissions.contentManager.singleTypesConfigurations}>
52
52
  <EditSettingsView
53
53
  components={rawComponentsLayouts}
54
54
  isContentTypeView
@@ -1,53 +1,86 @@
1
- import { useEffect, useReducer, useRef } from 'react';
1
+ import * as React from 'react';
2
2
 
3
3
  import { useAppInfo, useRBACProvider, useStrapiApp } from '@strapi/helper-plugin';
4
+ import { Cog, Puzzle, ShoppingCart } from '@strapi/icons';
5
+ import { useSelector } from 'react-redux';
6
+
7
+ import { selectAdminPermissions } from '../../pages/App/selectors';
4
8
 
5
- import reducer, { initialState } from './reducer';
6
9
  import getGeneralLinks from './utils/getGeneralLinks';
7
10
  import getPluginSectionLinks from './utils/getPluginSectionLinks';
8
11
 
9
12
  const useMenu = () => {
10
- const [state, dispatch] = useReducer(reducer, initialState);
11
- const { allPermissions } = useRBACProvider();
13
+ const { allPermissions: userPermissions } = useRBACProvider();
12
14
  const { shouldUpdateStrapi } = useAppInfo();
13
15
  const { menu } = useStrapiApp();
14
-
15
- // We are using a ref because we don't want our effect to have this in its dependencies array
16
- const generalSectionLinksRef = useRef(state.generalSectionLinks);
17
- const shouldUpdateStrapiRef = useRef(shouldUpdateStrapi);
18
- // Once in the app lifecycle the menu should not be added into any dependencies array
19
-
20
- const resolvePermissions = async (permissions = allPermissions) => {
21
- const pluginsSectionLinks = menu;
22
-
23
- const authorizedPluginSectionLinks = await getPluginSectionLinks(
24
- permissions,
25
- pluginsSectionLinks
26
- );
27
-
28
- const authorizedGeneralSectionLinks = await getGeneralLinks(
29
- permissions,
30
- generalSectionLinksRef.current,
31
- shouldUpdateStrapiRef.current
32
- );
33
-
34
- dispatch({
35
- type: 'SET_SECTION_LINKS',
36
- data: {
37
- authorizedGeneralSectionLinks,
38
- authorizedPluginSectionLinks,
16
+ const permissions = useSelector(selectAdminPermissions);
17
+ const [menuWithUserPermissions, setMenuWithUserPermissions] = React.useState({
18
+ generalSectionLinks: [
19
+ {
20
+ icon: Puzzle,
21
+ intlLabel: {
22
+ id: 'global.plugins',
23
+ defaultMessage: 'Plugins',
24
+ },
25
+ to: '/list-plugins',
26
+ permissions: permissions.marketplace.main,
27
+ },
28
+ {
29
+ icon: ShoppingCart,
30
+ intlLabel: {
31
+ id: 'global.marketplace',
32
+ defaultMessage: 'Marketplace',
33
+ },
34
+ to: '/marketplace',
35
+ permissions: permissions.marketplace.main,
39
36
  },
40
- });
41
- dispatch({ type: 'UNSET_IS_LOADING' });
42
- };
37
+ {
38
+ icon: Cog,
39
+ intlLabel: {
40
+ id: 'global.settings',
41
+ defaultMessage: 'Settings',
42
+ },
43
+ to: '/settings',
44
+ // Permissions of this link are retrieved in the init phase
45
+ // using the settings menu
46
+ permissions: [],
47
+ notificationsCount: 0,
48
+ },
49
+ ],
50
+ pluginsSectionLinks: [],
51
+ isLoading: true,
52
+ });
53
+ const generalSectionLinksRef = React.useRef(menuWithUserPermissions.generalSectionLinks);
54
+
55
+ React.useEffect(() => {
56
+ async function applyMenuPermissions() {
57
+ const authorizedPluginSectionLinks = await getPluginSectionLinks(userPermissions, menu);
58
+
59
+ const authorizedGeneralSectionLinks = await getGeneralLinks(
60
+ userPermissions,
61
+ generalSectionLinksRef.current,
62
+ shouldUpdateStrapi
63
+ );
43
64
 
44
- const resolvePermissionsRef = useRef(resolvePermissions);
65
+ setMenuWithUserPermissions((state) => ({
66
+ ...state,
67
+ generalSectionLinks: authorizedGeneralSectionLinks,
68
+ pluginsSectionLinks: authorizedPluginSectionLinks,
69
+ isLoading: false,
70
+ }));
71
+ }
45
72
 
46
- useEffect(() => {
47
- resolvePermissionsRef.current(allPermissions);
48
- }, [allPermissions, dispatch]);
73
+ applyMenuPermissions();
74
+ }, [
75
+ setMenuWithUserPermissions,
76
+ generalSectionLinksRef,
77
+ userPermissions,
78
+ menu,
79
+ permissions,
80
+ shouldUpdateStrapi,
81
+ ]);
49
82
 
50
- return state;
83
+ return menuWithUserPermissions;
51
84
  };
52
85
 
53
86
  export default useMenu;
@@ -2,8 +2,11 @@ import cloneDeep from 'lodash/cloneDeep';
2
2
 
3
3
  import checkPermissions from './checkPermissions';
4
4
 
5
- const getGeneralLinks = async (permissions, generalSectionRawLinks, shouldUpdateStrapi) => {
6
- const generalSectionPermissionsPromises = checkPermissions(permissions, generalSectionRawLinks);
5
+ const getGeneralLinks = async (userPermissions, generalSectionRawLinks, shouldUpdateStrapi) => {
6
+ const generalSectionPermissionsPromises = checkPermissions(
7
+ userPermissions,
8
+ generalSectionRawLinks
9
+ );
7
10
  const generalSectionLinksPermissions = await Promise.all(generalSectionPermissionsPromises);
8
11
 
9
12
  const authorizedGeneralSectionLinks = generalSectionRawLinks.filter(
@@ -1,5 +1,3 @@
1
- import adminPermissions from '../../permissions';
2
-
3
1
  export const LINKS_CE = {
4
2
  global: [
5
3
  {
@@ -12,19 +10,16 @@ export const LINKS_CE = {
12
10
  intlLabel: { id: 'Settings.webhooks.title', defaultMessage: 'Webhooks' },
13
11
  to: '/settings/webhooks',
14
12
  id: 'webhooks',
15
- permissions: adminPermissions.settings.webhooks.main,
16
13
  },
17
14
  {
18
15
  intlLabel: { id: 'Settings.apiTokens.title', defaultMessage: 'API Tokens' },
19
16
  to: '/settings/api-tokens?sort=name:ASC',
20
17
  id: 'api-tokens',
21
- permissions: adminPermissions.settings['api-tokens'].main,
22
18
  },
23
19
  {
24
20
  intlLabel: { id: 'Settings.transferTokens.title', defaultMessage: 'Transfer Tokens' },
25
21
  to: '/settings/transfer-tokens?sort=name:ASC',
26
22
  id: 'transfer-tokens',
27
- permissions: adminPermissions.settings['transfer-tokens'].main,
28
23
  },
29
24
  ],
30
25
 
@@ -33,14 +28,12 @@ export const LINKS_CE = {
33
28
  intlLabel: { id: 'global.roles', defaultMessage: 'Roles' },
34
29
  to: '/settings/roles',
35
30
  id: 'roles',
36
- permissions: adminPermissions.settings.roles.main,
37
31
  },
38
32
  {
39
33
  intlLabel: { id: 'global.users' },
40
34
  // Init the search params directly
41
35
  to: '/settings/users?pageSize=10&page=1&sort=firstname',
42
36
  id: 'users',
43
- permissions: adminPermissions.settings.users.main,
44
37
  },
45
38
  ],
46
39
  };
@@ -1,7 +1,9 @@
1
1
  import { useState, useEffect } from 'react';
2
2
 
3
3
  import { hasPermissions, useRBACProvider, useStrapiApp, useAppInfo } from '@strapi/helper-plugin';
4
+ import { useSelector } from 'react-redux';
4
5
 
6
+ import { selectAdminPermissions } from '../../pages/App/selectors';
5
7
  import { useEnterprise } from '../useEnterprise';
6
8
 
7
9
  import { LINKS_CE } from './constants';
@@ -13,17 +15,29 @@ const useSettingsMenu = () => {
13
15
  isLoading: true,
14
16
  menu: [],
15
17
  });
16
- const { allPermissions: permissions } = useRBACProvider();
18
+ const { allPermissions: userPermissions } = useRBACProvider();
17
19
  const { shouldUpdateStrapi } = useAppInfo();
18
20
  const { settings } = useStrapiApp();
21
+ const permissions = useSelector(selectAdminPermissions);
19
22
  const { global: globalLinks, admin: adminLinks } = useEnterprise(
20
23
  LINKS_CE,
21
24
  async () => (await import('../../../../ee/admin/hooks/useSettingsMenu/constants')).LINKS_EE,
22
25
  {
23
26
  combine(ceLinks, eeLinks) {
27
+ function addPermissions(link) {
28
+ if (!link.id) {
29
+ throw new Error('The settings menu item must have an id attribute.');
30
+ }
31
+
32
+ return {
33
+ ...link,
34
+ permissions: permissions.settings?.[link.id]?.main,
35
+ };
36
+ }
37
+
24
38
  return {
25
- admin: [...eeLinks.admin, ...ceLinks.admin],
26
- global: [...ceLinks.global, ...eeLinks.global],
39
+ admin: [...eeLinks.admin, ...ceLinks.admin].map(addPermissions),
40
+ global: [...ceLinks.global, ...eeLinks.global].map(addPermissions),
27
41
  };
28
42
  },
29
43
  defaultValue: {
@@ -40,7 +54,7 @@ const useSettingsMenu = () => {
40
54
  sections.reduce((acc, section, sectionIndex) => {
41
55
  const buildMenuPermissions = (links) =>
42
56
  links.map(async (link, linkIndex) => ({
43
- hasPermission: await hasPermissions(permissions, link.permissions),
57
+ hasPermission: await hasPermissions(userPermissions, link.permissions),
44
58
  sectionIndex,
45
59
  linkIndex,
46
60
  }));
@@ -89,7 +103,7 @@ const useSettingsMenu = () => {
89
103
  ]);
90
104
 
91
105
  getData();
92
- }, [adminLinks, globalLinks, permissions, settings, shouldUpdateStrapi]);
106
+ }, [adminLinks, globalLinks, userPermissions, settings, shouldUpdateStrapi]);
93
107
 
94
108
  return { isLoading, menu };
95
109
  };
@@ -1,3 +1,4 @@
1
1
  export const SET_APP_RUNTIME_STATUS = 'StrapiAdmin/APP/SET_APP_RUNTIME_STATUS';
2
+ export const SET_ADMIN_PERMISSIONS = 'StrapiAdmin/App/SET_ADMIN_PERMISSIONS';
2
3
 
3
4
  export const ROUTES_CE = [];