@strapi/admin 4.12.7 → 4.13.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (178) hide show
  1. package/admin/src/components/NpsSurvey/hooks/useNpsSurveySettings.js +17 -0
  2. package/admin/src/components/NpsSurvey/index.js +365 -0
  3. package/admin/src/content-manager/components/DynamicTable/CellContent/ReviewWorkflowsStage/getTableColumns.js +2 -0
  4. package/admin/src/content-manager/components/DynamicZone/components/DynamicZoneLabel.js +1 -1
  5. package/admin/src/content-manager/components/EditViewDataManagerProvider/reducer.js +8 -1
  6. package/admin/src/content-manager/components/Filter/CustomInputs/AdminUsersFilter.js +42 -0
  7. package/admin/src/content-manager/components/Filter/Filter.js +54 -0
  8. package/admin/src/content-manager/components/Filter/index.js +1 -0
  9. package/admin/src/content-manager/components/InputUID/index.js +222 -216
  10. package/admin/src/content-manager/components/RelationInput/RelationInput.js +4 -0
  11. package/admin/src/content-manager/components/RepeatableComponent/index.js +32 -2
  12. package/admin/src/content-manager/components/Wysiwyg/Editor.js +432 -68
  13. package/admin/src/content-manager/components/Wysiwyg/WysiwygStyles.js +0 -7
  14. package/admin/src/content-manager/components/Wysiwyg/index.js +147 -152
  15. package/admin/src/content-manager/hooks/useAllowedAttributes.js +47 -0
  16. package/admin/src/content-manager/pages/EditView/Information/index.js +9 -8
  17. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +40 -7
  18. package/admin/src/content-manager/pages/ListSettingsView/index.js +6 -2
  19. package/admin/src/content-manager/pages/ListView/components/FieldPicker/index.js +67 -69
  20. package/admin/src/content-manager/pages/ListView/components/ViewSettingsMenu/index.js +80 -0
  21. package/admin/src/content-manager/pages/ListView/index.js +236 -67
  22. package/admin/src/content-manager/utils/getDisplayName.js +33 -0
  23. package/admin/src/content-manager/utils/index.js +1 -0
  24. package/admin/src/pages/Admin/index.js +3 -1
  25. package/admin/src/pages/AuthPage/components/Register/index.js +5 -0
  26. package/admin/src/pages/SettingsPage/components/SettingsNav/index.js +3 -3
  27. package/admin/src/pages/SettingsPage/index.js +16 -26
  28. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/index.js +69 -35
  29. package/admin/src/plugins.js +7 -8
  30. package/admin/src/translations/en.json +10 -1
  31. package/build/{1049.f76cb14b.chunk.js → 1049.ec69f5e0.chunk.js} +1 -1
  32. package/build/1227.9f37e1dc.chunk.js +1 -0
  33. package/build/{1386.879bcd90.chunk.js → 1386.ea73b677.chunk.js} +1 -1
  34. package/build/1504.eff012f7.chunk.js +95 -0
  35. package/build/{2225.c6244756.chunk.js → 2225.649fb7bc.chunk.js} +11 -11
  36. package/build/2237.b832ae6e.chunk.js +114 -0
  37. package/build/2379.1f98a31a.chunk.js +1 -0
  38. package/build/2395.0e5e8ded.chunk.js +26 -0
  39. package/build/2801.8e1aa82a.chunk.js +1 -0
  40. package/build/{3483.03c24f96.chunk.js → 3483.19381b40.chunk.js} +1 -1
  41. package/build/4174.f1f39e40.chunk.js +1 -0
  42. package/build/4546.a5946d22.chunk.js +1 -0
  43. package/build/4724.aea5c8c1.chunk.js +6 -0
  44. package/build/502.7bba43b1.chunk.js +1 -0
  45. package/build/6158.c3c13c20.chunk.js +1 -0
  46. package/build/7464.eb057bec.chunk.js +1 -0
  47. package/build/78.dcc6df5c.chunk.js +1 -0
  48. package/build/8276.be3ed581.chunk.js +26 -0
  49. package/build/{Admin-authenticatedApp.31497f74.chunk.js → Admin-authenticatedApp.43b6ec9a.chunk.js} +2 -2
  50. package/build/{Admin_InternalErrorPage.f45f2462.chunk.js → Admin_InternalErrorPage.38155af3.chunk.js} +1 -1
  51. package/build/{Admin_homePage.ac9dfb86.chunk.js → Admin_homePage.6f128523.chunk.js} +1 -1
  52. package/build/{Admin_marketplace.c94239f6.chunk.js → Admin_marketplace.061a6e5a.chunk.js} +1 -1
  53. package/build/{Admin_pluginsPage.bbe79434.chunk.js → Admin_pluginsPage.16f837b8.chunk.js} +1 -1
  54. package/build/{Admin_profilePage.192edc52.chunk.js → Admin_profilePage.678bce24.chunk.js} +2 -2
  55. package/build/Admin_settingsPage.af7309e4.chunk.js +111 -0
  56. package/build/{Upload_ConfigureTheView.345ac1e0.chunk.js → Upload_ConfigureTheView.3fc1c100.chunk.js} +1 -1
  57. package/build/admin-app.d63bd229.chunk.js +36 -0
  58. package/build/{admin-edit-roles-page.6d567273.chunk.js → admin-edit-roles-page.38a6c863.chunk.js} +3 -3
  59. package/build/{admin-edit-users.acfd4128.chunk.js → admin-edit-users.545fc882.chunk.js} +2 -2
  60. package/build/{admin-roles-list.23ddff26.chunk.js → admin-roles-list.1e2e814d.chunk.js} +1 -1
  61. package/build/{admin-users.00e20017.chunk.js → admin-users.b8ea5677.chunk.js} +2 -2
  62. package/build/{api-tokens-create-page.46c2ea84.chunk.js → api-tokens-create-page.e0c15627.chunk.js} +1 -1
  63. package/build/{api-tokens-edit-page.58139df9.chunk.js → api-tokens-edit-page.9f2dce47.chunk.js} +1 -1
  64. package/build/{api-tokens-list-page.0af7d431.chunk.js → api-tokens-list-page.d747051c.chunk.js} +2 -2
  65. package/build/{audit-logs-settings-page.0f73ccf8.chunk.js → audit-logs-settings-page.96f9d608.chunk.js} +1 -1
  66. package/build/content-manager.ccff1078.chunk.js +1097 -0
  67. package/build/{content-type-builder-list-view.bf9be456.chunk.js → content-type-builder-list-view.b71cf240.chunk.js} +1 -1
  68. package/build/{content-type-builder.cd999f6e.chunk.js → content-type-builder.e5669749.chunk.js} +2 -2
  69. package/build/email-settings-page.2809f0bf.chunk.js +11 -0
  70. package/build/en-json.e12fd5fc.chunk.js +1 -0
  71. package/build/{i18n-settings-page.47f78016.chunk.js → i18n-settings-page.5f716172.chunk.js} +1 -1
  72. package/build/index.html +1 -1
  73. package/build/main.c6c9e04c.js +2859 -0
  74. package/build/review-workflows-settings-create-view.4a156a19.chunk.js +1 -0
  75. package/build/review-workflows-settings-edit-view.ce984d1f.chunk.js +1 -0
  76. package/build/review-workflows-settings-list-view.419b8deb.chunk.js +56 -0
  77. package/build/{runtime~main.d515c521.js → runtime~main.dcf1cb45.js} +2 -2
  78. package/build/{sso-settings-page.12b6d8ae.chunk.js → sso-settings-page.45153df5.chunk.js} +1 -1
  79. package/build/{transfer-tokens-create-page.1597e6ab.chunk.js → transfer-tokens-create-page.ebba16d8.chunk.js} +1 -1
  80. package/build/{transfer-tokens-edit-page.8741529f.chunk.js → transfer-tokens-edit-page.d7bb2b3e.chunk.js} +1 -1
  81. package/build/{transfer-tokens-list-page.d6986b03.chunk.js → transfer-tokens-list-page.cfe1736c.chunk.js} +2 -2
  82. package/build/{upload-settings.7f93d4c0.chunk.js → upload-settings.cc5ad813.chunk.js} +1 -1
  83. package/build/{upload.37488080.chunk.js → upload.756efc28.chunk.js} +1 -1
  84. package/build/users-advanced-settings-page.818d84eb.chunk.js +9 -0
  85. package/build/users-email-settings-page.c1967c09.chunk.js +9 -0
  86. package/build/users-providers-settings-page.11893e08.chunk.js +14 -0
  87. package/build/users-roles-settings-page.2b051e6a.chunk.js +55 -0
  88. package/build/{webhook-edit-page.6cb479ff.chunk.js → webhook-edit-page.de45c635.chunk.js} +2 -2
  89. package/build/{webhook-list-page.65e1b5bb.chunk.js → webhook-list-page.ca91df8b.chunk.js} +1 -1
  90. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/AssigneeFilter.js +42 -0
  91. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/StageFilter.js +70 -0
  92. package/ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/constants.js +71 -0
  93. package/ee/admin/content-manager/pages/EditView/InformationBox/InformationBoxEE.js +9 -217
  94. package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/AssigneeSelect.js +147 -0
  95. package/ee/admin/content-manager/pages/EditView/InformationBox/components/AssigneeSelect/index.js +1 -0
  96. package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/StageSelect.js +243 -0
  97. package/ee/admin/content-manager/pages/EditView/InformationBox/components/StageSelect/index.js +1 -0
  98. package/ee/admin/content-manager/pages/EditView/InformationBox/constants.js +2 -0
  99. package/ee/admin/content-manager/pages/ListSettingsView/constants.js +7 -0
  100. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/ReviewWorkflowsAssigneeEE.js +21 -0
  101. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +44 -17
  102. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/index.js +1 -0
  103. package/ee/admin/hooks/useAuthProviders.js +25 -0
  104. package/ee/admin/hooks/{useLicenseLimitNotification/index.js → useLicenseLimitNotification.js} +2 -4
  105. package/ee/admin/hooks/{useLicenseLimits/useLicenseLimits.js → useLicenseLimits.js} +4 -1
  106. package/ee/admin/pages/AuthPage/components/Login/index.js +8 -4
  107. package/ee/admin/pages/AuthPage/components/Providers/index.js +8 -5
  108. package/ee/admin/pages/HomePage/index.js +1 -1
  109. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -1
  110. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +1 -1
  111. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -1
  112. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/CreateAction/index.js +1 -1
  113. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  114. package/ee/server/constants/workflows.js +1 -0
  115. package/ee/server/controllers/index.js +1 -0
  116. package/ee/server/controllers/workflows/assignees/index.js +44 -0
  117. package/ee/server/routes/review-workflows.js +17 -0
  118. package/ee/server/services/index.js +1 -0
  119. package/ee/server/services/review-workflows/assignees.js +54 -0
  120. package/ee/server/services/review-workflows/metrics/index.js +5 -0
  121. package/ee/server/services/review-workflows/review-workflows.js +20 -11
  122. package/ee/server/validation/review-workflows.js +8 -0
  123. package/index.js +2 -6
  124. package/package.json +9 -9
  125. package/scripts/build.js +15 -15
  126. package/scripts/create-dev-plugins-file.js +5 -38
  127. package/server/controllers/role.js +2 -0
  128. package/server/controllers/user.js +2 -0
  129. package/server/services/permission/permissions-manager/index.js +3 -1
  130. package/server/services/permission/permissions-manager/sanitize.js +19 -7
  131. package/server/services/permission/permissions-manager/validate.js +218 -0
  132. package/utils/create-cache-dir.js +62 -16
  133. package/utils/create-plugins-exclude-path.js +3 -23
  134. package/utils/get-plugins.js +110 -0
  135. package/utils/index.js +1 -1
  136. package/webpack.config.js +10 -13
  137. package/admin/src/content-manager/components/AttributeFilter/Filters.js +0 -58
  138. package/admin/src/content-manager/components/AttributeFilter/hooks/useAllowedAttributes.js +0 -42
  139. package/admin/src/content-manager/components/AttributeFilter/index.js +0 -40
  140. package/admin/src/content-manager/components/Wysiwyg/EditorStylesContainer.js +0 -344
  141. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/api.js +0 -23
  142. package/admin/src/pages/SettingsPage/pages/ApplicationInfosPage/utils/prefixAllUrls.js +0 -17
  143. package/admin/src/pages/SettingsPage/utils/createSectionsRoutes.js +0 -11
  144. package/admin/src/pages/SettingsPage/utils/getSectionsToDisplay.js +0 -5
  145. package/admin/src/pages/SettingsPage/utils/index.js +0 -2
  146. package/build/2379.f1641312.chunk.js +0 -1
  147. package/build/2395.46f8d0c1.chunk.js +0 -26
  148. package/build/2801.5cef5ec8.chunk.js +0 -1
  149. package/build/3929.5632f24d.chunk.js +0 -114
  150. package/build/3984.dda474f7.chunk.js +0 -1
  151. package/build/4546.7a3c0d03.chunk.js +0 -1
  152. package/build/502.8ae8ef60.chunk.js +0 -1
  153. package/build/5483.6dd2e776.chunk.js +0 -6
  154. package/build/5542.2415a393.chunk.js +0 -63
  155. package/build/6158.c974fd83.chunk.js +0 -1
  156. package/build/7464.3e64a1d5.chunk.js +0 -1
  157. package/build/8276.10a3f883.chunk.js +0 -26
  158. package/build/Admin_settingsPage.97cb9d41.chunk.js +0 -111
  159. package/build/admin-app.91898385.chunk.js +0 -36
  160. package/build/content-manager.b40f79c0.chunk.js +0 -1099
  161. package/build/email-settings-page.d494d1eb.chunk.js +0 -11
  162. package/build/en-json.08c05fcf.chunk.js +0 -1
  163. package/build/main.9dbe4579.js +0 -2859
  164. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +0 -1
  165. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +0 -1
  166. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +0 -56
  167. package/build/users-advanced-settings-page.f0760eb8.chunk.js +0 -9
  168. package/build/users-email-settings-page.ff4b32f3.chunk.js +0 -9
  169. package/build/users-providers-settings-page.48de0306.chunk.js +0 -14
  170. package/build/users-roles-settings-page.9d9a1eff.chunk.js +0 -30
  171. package/ee/admin/hooks/index.js +0 -4
  172. package/ee/admin/hooks/useAuthProviders/index.js +0 -50
  173. package/ee/admin/hooks/useAuthProviders/reducer.js +0 -26
  174. package/ee/admin/hooks/useLicenseLimits/index.js +0 -1
  175. package/scripts/create-plugins-file.js +0 -92
  176. package/utils/get-plugins-path.js +0 -41
  177. /package/ee/admin/hooks/{useLicenseLimits/__mocks__/index.js → __mocks__/useLicenseLimits.js} +0 -0
  178. /package/server/services/permission/permissions-manager/{query-builers.js → query-builders.js} +0 -0
@@ -0,0 +1,80 @@
1
+ import React from 'react';
2
+
3
+ import { Flex, IconButton, Popover } from '@strapi/design-system';
4
+ import { CheckPermissions, LinkButton } from '@strapi/helper-plugin';
5
+ import { Cog, Layer } from '@strapi/icons';
6
+ import PropTypes from 'prop-types';
7
+ import { useIntl } from 'react-intl';
8
+ import { useSelector } from 'react-redux';
9
+
10
+ import { selectAdminPermissions } from '../../../../../pages/App/selectors';
11
+ import { FieldPicker } from '../FieldPicker';
12
+
13
+ export const ViewSettingsMenu = ({ slug, layout }) => {
14
+ const [isVisible, setIsVisible] = React.useState(false);
15
+ const cogButtonRef = React.useRef();
16
+ const permissions = useSelector(selectAdminPermissions);
17
+ const { formatMessage } = useIntl();
18
+
19
+ const handleToggle = () => {
20
+ setIsVisible((prev) => !prev);
21
+ };
22
+
23
+ return (
24
+ <>
25
+ <IconButton
26
+ icon={<Cog />}
27
+ label={formatMessage({
28
+ id: 'components.ViewSettings.tooltip',
29
+ defaultMessage: 'View Settings',
30
+ })}
31
+ ref={cogButtonRef}
32
+ onClick={handleToggle}
33
+ />
34
+ {isVisible && (
35
+ <Popover
36
+ placement="bottom-end"
37
+ source={cogButtonRef}
38
+ onDismiss={handleToggle}
39
+ spacing={4}
40
+ padding={3}
41
+ >
42
+ <Flex alignItems="stretch" direction="column" gap={3}>
43
+ <CheckPermissions
44
+ permissions={permissions.contentManager.collectionTypesConfigurations}
45
+ >
46
+ <LinkButton
47
+ size="S"
48
+ startIcon={<Layer />}
49
+ to={`${slug}/configurations/list`}
50
+ variant="secondary"
51
+ >
52
+ {formatMessage({
53
+ id: 'app.links.configure-view',
54
+ defaultMessage: 'Configure the view',
55
+ })}
56
+ </LinkButton>
57
+ </CheckPermissions>
58
+
59
+ <FieldPicker layout={layout} />
60
+ </Flex>
61
+ </Popover>
62
+ )}
63
+ </>
64
+ );
65
+ };
66
+
67
+ ViewSettingsMenu.propTypes = {
68
+ slug: PropTypes.string.isRequired,
69
+ layout: PropTypes.shape({
70
+ contentType: PropTypes.shape({
71
+ attributes: PropTypes.object.isRequired,
72
+ metadatas: PropTypes.object.isRequired,
73
+ layouts: PropTypes.shape({
74
+ list: PropTypes.array.isRequired,
75
+ }).isRequired,
76
+ options: PropTypes.object.isRequired,
77
+ settings: PropTypes.object.isRequired,
78
+ }).isRequired,
79
+ }).isRequired,
80
+ };
@@ -1,9 +1,7 @@
1
1
  import * as React from 'react';
2
2
 
3
3
  import {
4
- IconButton,
5
4
  Main,
6
- Box,
7
5
  ActionLayout,
8
6
  Button,
9
7
  ContentLayout,
@@ -17,8 +15,8 @@ import {
17
15
  lightTheme,
18
16
  } from '@strapi/design-system';
19
17
  import {
18
+ findMatchingPermissions,
20
19
  NoPermissions,
21
- CheckPermissions,
22
20
  SearchURLQuery,
23
21
  useFetchClient,
24
22
  useFocusWhenNavigate,
@@ -28,12 +26,13 @@ import {
28
26
  useTracking,
29
27
  Link,
30
28
  useAPIErrorHandler,
29
+ useCollator,
31
30
  useStrapiApp,
32
31
  Table,
33
32
  PaginationURLQuery,
34
33
  PageSizeURLQuery,
35
34
  } from '@strapi/helper-plugin';
36
- import { ArrowLeft, Cog, Plus } from '@strapi/icons';
35
+ import { ArrowLeft, Plus } from '@strapi/icons';
37
36
  import axios, { AxiosError } from 'axios';
38
37
  import isEqual from 'lodash/isEqual';
39
38
  import PropTypes from 'prop-types';
@@ -43,33 +42,29 @@ import { useMutation } from 'react-query';
43
42
  import { connect, useSelector } from 'react-redux';
44
43
  import { useHistory, useLocation, Link as ReactRouterLink } from 'react-router-dom';
45
44
  import { bindActionCreators, compose } from 'redux';
46
- import styled from 'styled-components';
47
45
 
48
46
  import { INJECT_COLUMN_IN_TABLE } from '../../../exposedHooks';
47
+ import { useAdminUsers } from '../../../hooks/useAdminUsers';
49
48
  import { useEnterprise } from '../../../hooks/useEnterprise';
50
- import { selectAdminPermissions } from '../../../pages/App/selectors';
51
49
  import { InjectionZone } from '../../../shared/components';
52
- import AttributeFilter from '../../components/AttributeFilter';
53
- import { getTrad } from '../../utils';
50
+ import { Filter } from '../../components/Filter';
51
+ import { AdminUsersFilter } from '../../components/Filter/CustomInputs/AdminUsersFilter';
52
+ import { useAllowedAttributes } from '../../hooks/useAllowedAttributes';
53
+ import { getTrad, getDisplayName } from '../../utils';
54
54
 
55
55
  import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } from './actions';
56
56
  import { Body } from './components/Body';
57
57
  import BulkActionButtons from './components/BulkActionButtons';
58
58
  import CellContent from './components/CellContent';
59
- import { FieldPicker } from './components/FieldPicker';
59
+ import { ViewSettingsMenu } from './components/ViewSettingsMenu';
60
60
  import makeSelectListView, { selectDisplayedHeaders } from './selectors';
61
61
  import { buildValidGetParams } from './utils';
62
62
 
63
- const ConfigureLayoutBox = styled(Box)`
64
- svg {
65
- path {
66
- fill: ${({ theme }) => theme.colors.neutral900};
67
- }
68
- }
69
- `;
70
-
71
63
  const REVIEW_WORKFLOW_COLUMNS_CE = null;
72
64
  const REVIEW_WORKFLOW_COLUMNS_CELL_CE = () => null;
65
+ const REVIEW_WORKFLOW_FILTER_CE = [];
66
+ const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
67
+ const USER_FILTER_ATTRIBUTES = [...CREATOR_ATTRIBUTES, 'strapi_assignee'];
73
68
 
74
69
  function ListView({
75
70
  canCreate,
@@ -95,23 +90,106 @@ function ListView({
95
90
  const [isConfirmDeleteRowOpen, setIsConfirmDeleteRowOpen] = React.useState(false);
96
91
  const toggleNotification = useNotification();
97
92
  const { trackUsage } = useTracking();
98
- const { refetchPermissions } = useRBACProvider();
93
+ const { allPermissions, refetchPermissions } = useRBACProvider();
99
94
  const trackUsageRef = React.useRef(trackUsage);
100
95
  const fetchPermissionsRef = React.useRef(refetchPermissions);
101
96
  const { notifyStatus } = useNotifyAT();
102
97
  const { formatAPIError } = useAPIErrorHandler(getTrad);
103
- const permissions = useSelector(selectAdminPermissions);
98
+ const allowedAttributes = useAllowedAttributes(contentType, slug);
99
+ const [{ query }] = useQueryParams();
100
+ const { pathname } = useLocation();
101
+ const { push } = useHistory();
102
+ const { formatMessage, locale } = useIntl();
103
+ const fetchClient = useFetchClient();
104
+ const formatter = useCollator(locale, {
105
+ sensitivity: 'base',
106
+ });
107
+
108
+ const selectedUserIds =
109
+ query?.filters?.$and?.reduce((acc, filter) => {
110
+ const [key, value] = Object.entries(filter)[0];
111
+ const id = value.id?.$eq || value.id?.$ne;
112
+
113
+ // TODO: strapi_assignee should not be in here and rather defined
114
+ // in the ee directory.
115
+ if (USER_FILTER_ATTRIBUTES.includes(key) && !acc.includes(id)) {
116
+ acc.push(id);
117
+ }
118
+
119
+ return acc;
120
+ }, []) ?? [];
121
+
122
+ const { users, isLoading: isLoadingAdminUsers } = useAdminUsers(
123
+ { filter: { id: { in: selectedUserIds } } },
124
+ {
125
+ // fetch the list of admin users only if the filter contains users and the
126
+ // current user has permissions to display users
127
+ enabled:
128
+ selectedUserIds.length > 0 &&
129
+ findMatchingPermissions(allPermissions, [
130
+ {
131
+ action: 'admin::users.read',
132
+ subject: null,
133
+ },
134
+ ]).length > 0,
135
+ }
136
+ );
104
137
 
105
138
  useFocusWhenNavigate();
106
139
 
107
- const [{ query }] = useQueryParams();
108
140
  const params = React.useMemo(() => buildValidGetParams(query), [query]);
109
141
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
110
142
 
111
- const { pathname } = useLocation();
112
- const { push } = useHistory();
113
- const { formatMessage } = useIntl();
114
- const fetchClient = useFetchClient();
143
+ const displayedAttributeFilters = allowedAttributes.map((name) => {
144
+ const attribute = contentType.attributes[name];
145
+ const { type, enum: options } = attribute;
146
+
147
+ const trackedEvent = {
148
+ name: 'didFilterEntries',
149
+ properties: { useRelation: type === 'relation' },
150
+ };
151
+
152
+ const { mainField, label } = metadatas[name].list;
153
+
154
+ const filter = {
155
+ name,
156
+ metadatas: { label: formatMessage({ id: label, defaultMessage: label }) },
157
+ fieldSchema: { type, options, mainField },
158
+ trackedEvent,
159
+ };
160
+
161
+ if (attribute.type === 'relation' && attribute.target === 'admin::user') {
162
+ filter.metadatas = {
163
+ ...filter.metadatas,
164
+ customOperators: [
165
+ {
166
+ intlLabel: {
167
+ id: 'components.FilterOptions.FILTER_TYPES.$eq',
168
+ defaultMessage: 'is',
169
+ },
170
+ value: '$eq',
171
+ },
172
+ {
173
+ intlLabel: {
174
+ id: 'components.FilterOptions.FILTER_TYPES.$ne',
175
+ defaultMessage: 'is not',
176
+ },
177
+ value: '$ne',
178
+ },
179
+ ],
180
+ customInput: AdminUsersFilter,
181
+ options: users.map((user) => ({
182
+ label: getDisplayName(user, formatMessage),
183
+ customValue: user.id.toString(),
184
+ })),
185
+ };
186
+ filter.fieldSchema.mainField = {
187
+ name: 'id',
188
+ };
189
+ }
190
+
191
+ return filter;
192
+ });
115
193
 
116
194
  const hasDraftAndPublish = options?.draftAndPublish ?? false;
117
195
  const hasReviewWorkflows = options?.reviewWorkflows ?? false;
@@ -128,16 +206,82 @@ function ListView({
128
206
  enabled: !!options?.reviewWorkflows,
129
207
  }
130
208
  );
131
- const ReviewWorkflowsStage = useEnterprise(
209
+ const ReviewWorkflowsColumns = useEnterprise(
132
210
  REVIEW_WORKFLOW_COLUMNS_CELL_CE,
133
- async () =>
134
- (await import('../../../../../ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn'))
135
- .ReviewWorkflowsStageEE,
211
+ async () => {
212
+ const { ReviewWorkflowsStageEE, ReviewWorkflowsAssigneeEE } = await import(
213
+ '../../../../../ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn'
214
+ );
215
+
216
+ return { ReviewWorkflowsStageEE, ReviewWorkflowsAssigneeEE };
217
+ },
136
218
  {
137
219
  enabled: hasReviewWorkflows,
138
220
  }
139
221
  );
140
222
 
223
+ const reviewWorkflowFilter = useEnterprise(
224
+ REVIEW_WORKFLOW_FILTER_CE,
225
+ async () =>
226
+ (
227
+ await import(
228
+ '../../../../../ee/admin/content-manager/components/Filter/CustomInputs/ReviewWorkflows/constants'
229
+ )
230
+ ).REVIEW_WORKFLOW_FILTERS,
231
+ {
232
+ combine(ceFilters, eeFilters) {
233
+ return [
234
+ ...ceFilters,
235
+ ...eeFilters
236
+ .filter((eeFilter) => {
237
+ // do not display the filter at all, if the current user does
238
+ // not have permissions to read admin users
239
+ if (eeFilter.name === 'strapi_assignee') {
240
+ return (
241
+ findMatchingPermissions(allPermissions, [
242
+ {
243
+ action: 'admin::users.read',
244
+ subject: null,
245
+ },
246
+ ]).length > 0
247
+ );
248
+ }
249
+
250
+ return true;
251
+ })
252
+ .map((eeFilter) => ({
253
+ ...eeFilter,
254
+ metadatas: {
255
+ ...eeFilter.metadatas,
256
+ // the stage filter needs the current content-type uid to fetch
257
+ // the list of stages that can be assigned to this content-type
258
+ ...(eeFilter.name === 'strapi_stage' ? { uid: contentType.uid } : {}),
259
+
260
+ // translate the filter label
261
+ label: formatMessage(eeFilter.metadatas.label),
262
+
263
+ // `options` allows the filter-tag to render the displayname
264
+ // of a user over a plain id
265
+ options:
266
+ eeFilter.name === 'strapi_assignee' &&
267
+ users.map((user) => ({
268
+ label: getDisplayName(user, formatMessage),
269
+ customValue: user.id.toString(),
270
+ })),
271
+ },
272
+ })),
273
+ ];
274
+ },
275
+
276
+ defaultValue: [],
277
+
278
+ // we have to wait for admin users to be fully loaded, because otherwise
279
+ // combine is called to early and does not contain the latest state of
280
+ // the users array
281
+ enabled: hasReviewWorkflows && !isLoadingAdminUsers,
282
+ }
283
+ );
284
+
141
285
  const { post, del } = fetchClient;
142
286
 
143
287
  const bulkUnpublishMutation = useMutation(
@@ -381,13 +525,15 @@ function ListView({
381
525
 
382
526
  if (reviewWorkflowColumns) {
383
527
  // Make sure the column header label is translated
384
- if (typeof reviewWorkflowColumns.metadatas.label !== 'string') {
385
- reviewWorkflowColumns.metadatas.label = formatMessage(
386
- reviewWorkflowColumns.metadatas.label
387
- );
388
- }
528
+ reviewWorkflowColumns.map((column) => {
529
+ if (typeof column.metadatas.label !== 'string') {
530
+ column.metadatas.label = formatMessage(column.metadatas.label);
531
+ }
389
532
 
390
- formattedHeaders.push(reviewWorkflowColumns);
533
+ return column;
534
+ });
535
+
536
+ formattedHeaders.push(...reviewWorkflowColumns);
391
537
  }
392
538
 
393
539
  return formattedHeaders;
@@ -481,7 +627,7 @@ function ListView({
481
627
  };
482
628
 
483
629
  // Block rendering until the review stage component is fully loaded in EE
484
- if (!ReviewWorkflowsStage) {
630
+ if (!ReviewWorkflowsColumns) {
485
631
  return null;
486
632
  }
487
633
 
@@ -508,25 +654,7 @@ function ListView({
508
654
  endActions={
509
655
  <>
510
656
  <InjectionZone area="contentManager.listView.actions" />
511
- <FieldPicker layout={layout} />
512
- <CheckPermissions
513
- permissions={permissions.contentManager.collectionTypesConfigurations}
514
- >
515
- <ConfigureLayoutBox paddingTop={1} paddingBottom={1}>
516
- <IconButton
517
- onClick={() => {
518
- trackUsage('willEditListLayout');
519
- }}
520
- forwardedAs={ReactRouterLink}
521
- to={{ pathname: `${slug}/configurations/list`, search: pluginsQueryParams }}
522
- icon={<Cog />}
523
- label={formatMessage({
524
- id: 'app.links.configure-view',
525
- defaultMessage: 'Configure the view',
526
- })}
527
- />
528
- </ConfigureLayoutBox>
529
- </CheckPermissions>
657
+ <ViewSettingsMenu slug={slug} layout={layout} />
530
658
  </>
531
659
  }
532
660
  startActions={
@@ -544,8 +672,12 @@ function ListView({
544
672
  trackedEvent="didSearch"
545
673
  />
546
674
  )}
547
- {isFilterable && (
548
- <AttributeFilter contentType={contentType} slug={slug} metadatas={metadatas} />
675
+ {isFilterable && !isLoadingAdminUsers && (
676
+ <Filter
677
+ displayedFilters={[...displayedAttributeFilters, ...reviewWorkflowFilter].sort(
678
+ (a, b) => formatter.compare(a.metadatas.label, b.metadatas.label)
679
+ )}
680
+ />
549
681
  )}
550
682
  </>
551
683
  }
@@ -631,19 +763,56 @@ function ListView({
631
763
  );
632
764
  }
633
765
 
634
- if (hasReviewWorkflows && name === 'strapi_stage') {
766
+ if (hasReviewWorkflows) {
767
+ if (name === 'strapi_stage') {
768
+ return (
769
+ <Td key={key}>
770
+ {rowData.strapi_stage ? (
771
+ <ReviewWorkflowsColumns.ReviewWorkflowsStageEE
772
+ color={
773
+ rowData.strapi_stage.color ?? lightTheme.colors.primary600
774
+ }
775
+ name={rowData.strapi_stage.name}
776
+ />
777
+ ) : (
778
+ <Typography textColor="neutral800">-</Typography>
779
+ )}
780
+ </Td>
781
+ );
782
+ }
783
+ if (name === 'strapi_assignee') {
784
+ return (
785
+ <Td key={key}>
786
+ {rowData.strapi_assignee ? (
787
+ <ReviewWorkflowsColumns.ReviewWorkflowsAssigneeEE
788
+ user={rowData.strapi_assignee}
789
+ />
790
+ ) : (
791
+ <Typography textColor="neutral800">-</Typography>
792
+ )}
793
+ </Td>
794
+ );
795
+ }
796
+ }
797
+
798
+ if (['createdBy', 'updatedBy'].includes(name.split('.')[0])) {
799
+ // Display the users full name
800
+ return (
801
+ <Td key={key}>
802
+ <Typography textColor="neutral800">
803
+ {getDisplayName(rowData[name.split('.')[0]], formatMessage)}
804
+ </Typography>
805
+ </Td>
806
+ );
807
+ }
808
+
809
+ if (['createdBy', 'updatedBy'].includes(name.split('.')[0])) {
810
+ // Display the users full name
635
811
  return (
636
812
  <Td key={key}>
637
- {rowData.strapi_stage ? (
638
- <ReviewWorkflowsStage
639
- color={
640
- rowData.strapi_stage.color ?? lightTheme.colors.primary600
641
- }
642
- name={rowData.strapi_stage.name}
643
- />
644
- ) : (
645
- <Typography textColor="neutral800">-</Typography>
646
- )}
813
+ <Typography textColor="neutral800">
814
+ {getDisplayName(rowData[name.split('.')[0]], formatMessage)}
815
+ </Typography>
647
816
  </Td>
648
817
  );
649
818
  }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Retrieves the display name of an admin panel user
3
+ * @typedef AdminUserNamesAttributes
4
+ * @property {string} firstname
5
+ * @property {string} lastname
6
+ * @property {string} username
7
+ * @property {string} email
8
+ *
9
+ * @type {(user: AdminUserNamesAttributes, formatMessage: import('react-intl').formatMessage) => string}
10
+ */
11
+ const getDisplayName = ({ firstname, lastname, username, email }, formatMessage) => {
12
+ if (username) {
13
+ return username;
14
+ }
15
+
16
+ // firstname is not required if the user is created with a username
17
+ if (firstname) {
18
+ return formatMessage(
19
+ {
20
+ id: 'global.fullname',
21
+ defaultMessage: '{firstname} {lastname}',
22
+ },
23
+ {
24
+ firstname,
25
+ lastname,
26
+ }
27
+ ).trim();
28
+ }
29
+
30
+ return email;
31
+ };
32
+
33
+ export { getDisplayName };
@@ -12,3 +12,4 @@ export { default as mergeMetasWithSchema } from './mergeMetasWithSchema';
12
12
  export { default as removeKeyInObject } from './removeKeyInObject';
13
13
  export { default as removePasswordFieldsFromData } from './removePasswordFieldsFromData';
14
14
  export { default as createYupSchema } from './schema';
15
+ export { getDisplayName } from './getDisplayName';
@@ -42,7 +42,9 @@ const ProfilePage = lazy(() =>
42
42
  import(/* webpackChunkName: "Admin_profilePage" */ '../ProfilePage')
43
43
  );
44
44
  const SettingsPage = lazy(() =>
45
- import(/* webpackChunkName: "Admin_settingsPage" */ '../SettingsPage')
45
+ import(/* webpackChunkName: "Admin_settingsPage" */ '../SettingsPage').then((module) => ({
46
+ default: module.SettingsPage,
47
+ }))
46
48
  );
47
49
 
48
50
  // Simple hook easier for testing
@@ -29,6 +29,7 @@ import { useIntl } from 'react-intl';
29
29
  import { useHistory } from 'react-router-dom';
30
30
  import styled from 'styled-components';
31
31
 
32
+ import { useNpsSurveySettings } from '../../../../components/NpsSurvey/hooks/useNpsSurveySettings';
32
33
  import Logo from '../../../../components/UnauthenticatedLogo';
33
34
  import UnauthenticatedLayout, { LayoutContent } from '../../../../layouts/UnauthenticatedLayout';
34
35
  import FieldActionWrapper from '../FieldActionWrapper';
@@ -55,6 +56,7 @@ const Register = ({ authType, fieldsToDisable, noSignin, onSubmit, schema }) =>
55
56
  const query = useQuery();
56
57
  const { formatAPIError } = useAPIErrorHandler();
57
58
  const { get } = useFetchClient();
59
+ const { setNpsSurveySettings } = useNpsSurveySettings();
58
60
 
59
61
  const registrationToken = query.get('registrationToken');
60
62
 
@@ -143,6 +145,9 @@ const Register = ({ authType, fieldsToDisable, noSignin, onSubmit, schema }) =>
143
145
  } else {
144
146
  onSubmit(normalizedData, formik);
145
147
  }
148
+
149
+ // Only enable EE survey if user accepted the newsletter
150
+ setNpsSurveySettings({ enabled: data.news });
146
151
  } catch (err) {
147
152
  const errors = getYupInnerErrors(err);
148
153
  setSubmitCount(submitCount + 1);
@@ -12,14 +12,14 @@ import PropTypes from 'prop-types';
12
12
  import { useIntl } from 'react-intl';
13
13
  import { NavLink, useLocation } from 'react-router-dom';
14
14
 
15
- import { getSectionsToDisplay } from '../../utils';
16
-
17
15
  const SettingsNav = ({ menu }) => {
18
16
  const { formatMessage } = useIntl();
19
17
  const { trackUsage } = useTracking();
20
18
  const { pathname } = useLocation();
21
19
 
22
- const filteredMenu = getSectionsToDisplay(menu);
20
+ const filteredMenu = menu.filter(
21
+ (section) => !section.links.every((link) => link.isDisplayed === false)
22
+ );
23
23
 
24
24
  const sections = filteredMenu.map((section) => {
25
25
  return {
@@ -1,15 +1,4 @@
1
- /**
2
- *
3
- * SettingsPage
4
- *
5
- */
6
-
7
- // NOTE TO PLUGINS DEVELOPERS:
8
- // If you modify this file you also need to update the documentation accordingly
9
- // Here's the file: strapi/docs/3.0.0-beta.x/plugin-development/frontend-settings-api.md
10
- // IF THE DOC IS NOT UPDATED THE PULL REQUEST WILL NOT BE MERGED
11
-
12
- import React, { memo, useMemo } from 'react';
1
+ import * as React from 'react';
13
2
 
14
3
  import { Layout } from '@strapi/design-system';
15
4
  import { LoadingIndicatorPage, useStrapiApp } from '@strapi/helper-plugin';
@@ -19,14 +8,14 @@ import { Redirect, Route, Switch, useParams } from 'react-router-dom';
19
8
 
20
9
  import { useSettingsMenu } from '../../hooks';
21
10
  import { useEnterprise } from '../../hooks/useEnterprise';
22
- import { createRoute, makeUniqueRoutes } from '../../utils';
11
+ import createRoute from '../../utils/createRoute';
12
+ import makeUniqueRoutes from '../../utils/makeUniqueRoutes';
23
13
 
24
14
  import SettingsNav from './components/SettingsNav';
25
15
  import { ROUTES_CE } from './constants';
26
16
  import ApplicationInfosPage from './pages/ApplicationInfosPage';
27
- import { createSectionsRoutes } from './utils';
28
17
 
29
- function SettingsPage() {
18
+ export function SettingsPage() {
30
19
  const { settingId } = useParams();
31
20
  const { settings } = useStrapiApp();
32
21
  const { formatMessage } = useIntl();
@@ -43,13 +32,17 @@ function SettingsPage() {
43
32
  );
44
33
 
45
34
  // Creates the admin routes
46
- const adminRoutes = useMemo(() => {
35
+ const adminRoutes = React.useMemo(() => {
47
36
  return makeUniqueRoutes(
48
37
  routes.map(({ to, Component, exact }) => createRoute(Component, to, exact))
49
38
  );
50
39
  }, [routes]);
51
40
 
52
- const pluginsRoutes = createSectionsRoutes(settings);
41
+ const pluginsRoutes = Object.values(settings).flatMap((section) => {
42
+ const { links } = section;
43
+
44
+ return links.map((link) => createRoute(link.Component, link.to, link.exact || false));
45
+ });
53
46
 
54
47
  // Since the useSettingsMenu hook can make API calls in order to check the links permissions
55
48
  // We need to add a loading state to prevent redirecting the user while permissions are being checked
@@ -61,14 +54,14 @@ function SettingsPage() {
61
54
  return <Redirect to="/settings/application-infos" />;
62
55
  }
63
56
 
64
- const settingTitle = formatMessage({
65
- id: 'global.settings',
66
- defaultMessage: 'Settings',
67
- });
68
-
69
57
  return (
70
58
  <Layout sideNav={<SettingsNav menu={menu} />}>
71
- <Helmet title={settingTitle} />
59
+ <Helmet
60
+ title={formatMessage({
61
+ id: 'global.settings',
62
+ defaultMessage: 'Settings',
63
+ })}
64
+ />
72
65
 
73
66
  <Switch>
74
67
  <Route path="/settings/application-infos" component={ApplicationInfosPage} exact />
@@ -78,6 +71,3 @@ function SettingsPage() {
78
71
  </Layout>
79
72
  );
80
73
  }
81
-
82
- export default memo(SettingsPage);
83
- export { SettingsPage };