@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
@@ -1,4 +1,4 @@
1
- import React, { useRef, useState } from 'react';
1
+ import React, { forwardRef, useRef, useState } from 'react';
2
2
 
3
3
  import { Box, Flex, Typography } from '@strapi/design-system';
4
4
  import { prefixFileUrlWithBackendUrl, useLibrary } from '@strapi/helper-plugin';
@@ -30,160 +30,155 @@ const TypographyAsterisk = styled(Typography)`
30
30
  line-height: 0;
31
31
  `;
32
32
 
33
- const Wysiwyg = ({
34
- hint,
35
- disabled,
36
- error,
37
- intlLabel,
38
- labelAction,
39
- name,
40
- onChange,
41
- placeholder,
42
- value,
43
- required,
44
- }) => {
45
- const { formatMessage } = useIntl();
46
- const textareaRef = useRef(null);
47
- const editorRef = useRef(null);
48
- const [isPreviewMode, setIsPreviewMode] = useState(false);
49
- const [mediaLibVisible, setMediaLibVisible] = useState(false);
50
- const [isExpandMode, setIsExpandMode] = useState(false);
51
- const { components } = useLibrary();
52
-
53
- const MediaLibraryDialog = components['media-library'];
54
-
55
- const handleToggleMediaLib = () => setMediaLibVisible((prev) => !prev);
56
- const handleTogglePreviewMode = () => setIsPreviewMode((prev) => !prev);
57
- const handleToggleExpand = () => {
58
- setIsPreviewMode(false);
59
- setIsExpandMode((prev) => !prev);
60
- };
61
-
62
- const handleActionClick = (value, currentEditorRef, togglePopover) => {
63
- switch (value) {
64
- case 'Link':
65
- case 'Strikethrough': {
66
- markdownHandler(currentEditorRef, value);
67
- togglePopover();
68
- break;
33
+ const Wysiwyg = forwardRef(
34
+ (
35
+ { hint, disabled, error, intlLabel, labelAction, name, onChange, placeholder, value, required },
36
+ forwardedRef
37
+ ) => {
38
+ const { formatMessage } = useIntl();
39
+ const textareaRef = useRef(null);
40
+ const editorRef = useRef(null);
41
+ const [isPreviewMode, setIsPreviewMode] = useState(false);
42
+ const [mediaLibVisible, setMediaLibVisible] = useState(false);
43
+ const [isExpandMode, setIsExpandMode] = useState(false);
44
+ const { components } = useLibrary();
45
+
46
+ const MediaLibraryDialog = components['media-library'];
47
+
48
+ const handleToggleMediaLib = () => setMediaLibVisible((prev) => !prev);
49
+ const handleTogglePreviewMode = () => setIsPreviewMode((prev) => !prev);
50
+ const handleToggleExpand = () => {
51
+ setIsPreviewMode(false);
52
+ setIsExpandMode((prev) => !prev);
53
+ };
54
+
55
+ const handleActionClick = (value, currentEditorRef, togglePopover) => {
56
+ switch (value) {
57
+ case 'Link':
58
+ case 'Strikethrough': {
59
+ markdownHandler(currentEditorRef, value);
60
+ togglePopover();
61
+ break;
62
+ }
63
+ case 'Code':
64
+ case 'Quote': {
65
+ quoteAndCodeHandler(currentEditorRef, value);
66
+ togglePopover();
67
+ break;
68
+ }
69
+ case 'Bold':
70
+ case 'Italic':
71
+ case 'Underline': {
72
+ markdownHandler(currentEditorRef, value);
73
+ break;
74
+ }
75
+ case 'BulletList':
76
+ case 'NumberList': {
77
+ listHandler(currentEditorRef, value);
78
+ togglePopover();
79
+ break;
80
+ }
81
+ case 'h1':
82
+ case 'h2':
83
+ case 'h3':
84
+ case 'h4':
85
+ case 'h5':
86
+ case 'h6': {
87
+ titleHandler(currentEditorRef, value);
88
+ break;
89
+ }
90
+ default: {
91
+ // Nothing
92
+ }
69
93
  }
70
- case 'Code':
71
- case 'Quote': {
72
- quoteAndCodeHandler(currentEditorRef, value);
73
- togglePopover();
74
- break;
75
- }
76
- case 'Bold':
77
- case 'Italic':
78
- case 'Underline': {
79
- markdownHandler(currentEditorRef, value);
80
- break;
81
- }
82
- case 'BulletList':
83
- case 'NumberList': {
84
- listHandler(currentEditorRef, value);
85
- togglePopover();
86
- break;
87
- }
88
- case 'h1':
89
- case 'h2':
90
- case 'h3':
91
- case 'h4':
92
- case 'h5':
93
- case 'h6': {
94
- titleHandler(currentEditorRef, value);
95
- break;
96
- }
97
- default: {
98
- // Nothing
99
- }
100
- }
101
- };
102
-
103
- const handleSelectAssets = (files) => {
104
- const formattedFiles = files.map((f) => ({
105
- alt: f.alternativeText || f.name,
106
- url: prefixFileUrlWithBackendUrl(f.url),
107
- mime: f.mime,
108
- }));
109
-
110
- insertFile(editorRef, formattedFiles);
111
- setMediaLibVisible(false);
112
- };
113
-
114
- const formattedPlaceholder = placeholder
115
- ? formatMessage(
116
- { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
117
- { ...placeholder.values }
118
- )
119
- : '';
120
-
121
- const label = intlLabel.id
122
- ? formatMessage(
123
- { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
124
- { ...intlLabel.values }
125
- )
126
- : name;
127
-
128
- return (
129
- <>
130
- <Flex direction="column" alignItems="stretch" gap={1}>
131
- <Flex gap={1}>
132
- <Typography variant="pi" fontWeight="bold" textColor="neutral800">
133
- {label}
134
- {required && <TypographyAsterisk textColor="danger600">*</TypographyAsterisk>}
135
- </Typography>
136
- {labelAction && <LabelAction paddingLeft={1}>{labelAction}</LabelAction>}
137
- </Flex>
138
-
139
- <EditorLayout
140
- isExpandMode={isExpandMode}
141
- error={error}
142
- previewContent={value}
143
- onCollapse={handleToggleExpand}
144
- >
145
- <WysiwygNav
146
- isExpandMode={isExpandMode}
147
- editorRef={editorRef}
148
- isPreviewMode={isPreviewMode}
149
- onActionClick={handleActionClick}
150
- onToggleMediaLib={handleToggleMediaLib}
151
- onTogglePreviewMode={isExpandMode ? undefined : handleTogglePreviewMode}
152
- disabled={disabled}
153
- />
154
-
155
- <Editor
156
- disabled={disabled}
94
+ };
95
+
96
+ const handleSelectAssets = (files) => {
97
+ const formattedFiles = files.map((f) => ({
98
+ alt: f.alternativeText || f.name,
99
+ url: prefixFileUrlWithBackendUrl(f.url),
100
+ mime: f.mime,
101
+ }));
102
+
103
+ insertFile(editorRef, formattedFiles);
104
+ setMediaLibVisible(false);
105
+ };
106
+
107
+ const formattedPlaceholder = placeholder
108
+ ? formatMessage(
109
+ { id: placeholder.id, defaultMessage: placeholder.defaultMessage },
110
+ { ...placeholder.values }
111
+ )
112
+ : '';
113
+
114
+ const label = intlLabel.id
115
+ ? formatMessage(
116
+ { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
117
+ { ...intlLabel.values }
118
+ )
119
+ : name;
120
+
121
+ return (
122
+ <>
123
+ <Flex direction="column" alignItems="stretch" gap={1}>
124
+ <Flex gap={1}>
125
+ <Typography variant="pi" fontWeight="bold" textColor="neutral800">
126
+ {label}
127
+ {required && <TypographyAsterisk textColor="danger600">*</TypographyAsterisk>}
128
+ </Typography>
129
+ {labelAction && <LabelAction paddingLeft={1}>{labelAction}</LabelAction>}
130
+ </Flex>
131
+
132
+ <EditorLayout
157
133
  isExpandMode={isExpandMode}
158
- editorRef={editorRef}
159
134
  error={error}
160
- isPreviewMode={isPreviewMode}
161
- name={name}
162
- onChange={onChange}
163
- placeholder={formattedPlaceholder}
164
- textareaRef={textareaRef}
165
- value={value}
166
- />
167
-
168
- {!isExpandMode && <WysiwygFooter onToggleExpand={handleToggleExpand} />}
169
- </EditorLayout>
170
- <Hint hint={hint} name={name} error={error} />
171
- </Flex>
172
-
173
- {error && (
174
- <Box paddingTop={1}>
175
- <Typography variant="pi" textColor="danger600" data-strapi-field-error>
176
- {error}
177
- </Typography>
178
- </Box>
179
- )}
180
-
181
- {mediaLibVisible && (
182
- <MediaLibraryDialog onClose={handleToggleMediaLib} onSelectAssets={handleSelectAssets} />
183
- )}
184
- </>
185
- );
186
- };
135
+ previewContent={value}
136
+ onCollapse={handleToggleExpand}
137
+ >
138
+ <WysiwygNav
139
+ isExpandMode={isExpandMode}
140
+ editorRef={editorRef}
141
+ isPreviewMode={isPreviewMode}
142
+ onActionClick={handleActionClick}
143
+ onToggleMediaLib={handleToggleMediaLib}
144
+ onTogglePreviewMode={isExpandMode ? undefined : handleTogglePreviewMode}
145
+ disabled={disabled}
146
+ />
147
+
148
+ <Editor
149
+ disabled={disabled}
150
+ isExpandMode={isExpandMode}
151
+ editorRef={editorRef}
152
+ error={error}
153
+ isPreviewMode={isPreviewMode}
154
+ name={name}
155
+ onChange={onChange}
156
+ placeholder={formattedPlaceholder}
157
+ textareaRef={textareaRef}
158
+ value={value}
159
+ ref={forwardedRef}
160
+ />
161
+
162
+ {!isExpandMode && <WysiwygFooter onToggleExpand={handleToggleExpand} />}
163
+ </EditorLayout>
164
+ <Hint hint={hint} name={name} error={error} />
165
+ </Flex>
166
+
167
+ {error && (
168
+ <Box paddingTop={1}>
169
+ <Typography variant="pi" textColor="danger600" data-strapi-field-error>
170
+ {error}
171
+ </Typography>
172
+ </Box>
173
+ )}
174
+
175
+ {mediaLibVisible && (
176
+ <MediaLibraryDialog onClose={handleToggleMediaLib} onSelectAssets={handleSelectAssets} />
177
+ )}
178
+ </>
179
+ );
180
+ }
181
+ );
187
182
 
188
183
  Wysiwyg.defaultProps = {
189
184
  disabled: false,
@@ -0,0 +1,47 @@
1
+ import { useRBACProvider, findMatchingPermissions } from '@strapi/helper-plugin';
2
+
3
+ const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamiczone', 'password'];
4
+ const TIMESTAMPS = ['createdAt', 'updatedAt'];
5
+ const CREATOR_ATTRIBUTES = ['createdBy', 'updatedBy'];
6
+
7
+ export const useAllowedAttributes = (contentType, slug) => {
8
+ const { allPermissions } = useRBACProvider();
9
+
10
+ const readPermissionsForSlug = findMatchingPermissions(allPermissions, [
11
+ {
12
+ action: 'plugin::content-manager.explorer.read',
13
+ subject: slug,
14
+ },
15
+ ]);
16
+
17
+ const canReadAdminUsers =
18
+ findMatchingPermissions(allPermissions, [
19
+ {
20
+ action: 'admin::users.read',
21
+ subject: null,
22
+ },
23
+ ]).length > 0;
24
+
25
+ const attributesWithReadPermissions = readPermissionsForSlug?.[0]?.properties?.fields ?? [];
26
+
27
+ const allowedAttributes = attributesWithReadPermissions.filter((attr) => {
28
+ const current = contentType?.attributes?.[attr] ?? {};
29
+
30
+ if (!current.type) {
31
+ return false;
32
+ }
33
+
34
+ if (NOT_ALLOWED_FILTERS.includes(current.type)) {
35
+ return false;
36
+ }
37
+
38
+ return true;
39
+ });
40
+
41
+ return [
42
+ 'id',
43
+ ...allowedAttributes,
44
+ ...TIMESTAMPS,
45
+ ...(canReadAdminUsers ? CREATOR_ATTRIBUTES : []),
46
+ ];
47
+ };
@@ -5,8 +5,7 @@ import { useCMEditViewDataManager } from '@strapi/helper-plugin';
5
5
  import PropTypes from 'prop-types';
6
6
  import { useIntl } from 'react-intl';
7
7
 
8
- import { getFullName } from '../../../../utils';
9
- import { getTrad } from '../../../utils';
8
+ import { getTrad, getDisplayName } from '../../../utils';
10
9
 
11
10
  import getUnits from './utils/getUnits';
12
11
 
@@ -42,9 +41,13 @@ const KeyValuePair = ({ label, value }) => {
42
41
  );
43
42
  };
44
43
 
44
+ KeyValuePair.defaultProps = {
45
+ value: '-',
46
+ };
47
+
45
48
  KeyValuePair.propTypes = {
46
49
  label: PropTypes.string.isRequired,
47
- value: PropTypes.string.isRequired,
50
+ value: PropTypes.string,
48
51
  };
49
52
 
50
53
  const Body = () => {
@@ -53,18 +56,16 @@ const Body = () => {
53
56
  const currentTime = useRef(Date.now());
54
57
 
55
58
  const getFieldInfo = (atField, byField) => {
56
- const { firstname, lastname, username } = initialData[byField] ?? {};
59
+ const user = initialData[byField] ?? {};
57
60
 
58
- const userFirstname = firstname ?? '';
59
- const userLastname = lastname ?? '';
60
- const user = username ?? getFullName(userFirstname, userLastname);
61
+ const displayName = getDisplayName(user, formatMessage);
61
62
  const timestamp = initialData[atField] ? new Date(initialData[atField]).getTime() : Date.now();
62
63
  const elapsed = timestamp - currentTime.current;
63
64
  const { unit, value } = getUnits(-elapsed);
64
65
 
65
66
  return {
66
67
  at: formatRelativeTime(value, unit, { numeric: 'auto' }),
67
- by: isCreatingEntry ? '-' : user,
68
+ by: isCreatingEntry ? '-' : displayName,
68
69
  };
69
70
  };
70
71
 
@@ -10,14 +10,41 @@ import {
10
10
  ToggleInput,
11
11
  Typography,
12
12
  } from '@strapi/design-system';
13
+ import { useCollator } from '@strapi/helper-plugin';
13
14
  import PropTypes from 'prop-types';
14
15
  import { useIntl } from 'react-intl';
15
16
 
17
+ import { useEnterprise } from '../../../../hooks/useEnterprise';
16
18
  import { getTrad } from '../../../utils';
17
19
 
18
- export const Settings = ({ modifiedData, onChange, sortOptions }) => {
19
- const { formatMessage } = useIntl();
20
- const { settings, metadatas } = modifiedData;
20
+ export const Settings = ({
21
+ contentTypeOptions,
22
+ modifiedData,
23
+ onChange,
24
+ sortOptions: sortOptionsCE,
25
+ }) => {
26
+ const { formatMessage, locale } = useIntl();
27
+ const formatter = useCollator(locale, {
28
+ sensitivity: 'base',
29
+ });
30
+ const sortOptions = useEnterprise(
31
+ sortOptionsCE,
32
+ async () =>
33
+ (await import('../../../../../../ee/admin/content-manager/pages/ListSettingsView/constants'))
34
+ .REVIEW_WORKFLOW_STAGE_SORT_OPTION_NAME,
35
+ {
36
+ combine(ceOptions, eeOption) {
37
+ return [...ceOptions, { ...eeOption, label: formatMessage(eeOption.label) }];
38
+ },
39
+
40
+ defaultValue: sortOptionsCE,
41
+
42
+ enabled: !!contentTypeOptions?.reviewWorkflows,
43
+ }
44
+ );
45
+
46
+ const sortOptionsSorted = sortOptions.sort((a, b) => formatter.compare(a.label, b.label));
47
+ const { settings } = modifiedData;
21
48
 
22
49
  return (
23
50
  <Flex direction="column" alignItems="stretch" gap={4}>
@@ -129,9 +156,9 @@ export const Settings = ({ modifiedData, onChange, sortOptions }) => {
129
156
  name="settings.defaultSortBy"
130
157
  value={modifiedData.settings.defaultSortBy || ''}
131
158
  >
132
- {sortOptions.map((sortBy) => (
133
- <Option key={sortBy} value={sortBy}>
134
- {metadatas[sortBy].list.label || sortBy}
159
+ {sortOptionsSorted.map(({ value, label }) => (
160
+ <Option key={value} value={value}>
161
+ {label}
135
162
  </Option>
136
163
  ))}
137
164
  </Select>
@@ -164,7 +191,13 @@ Settings.defaultProps = {
164
191
  };
165
192
 
166
193
  Settings.propTypes = {
194
+ contentTypeOptions: PropTypes.object.isRequired,
167
195
  modifiedData: PropTypes.object,
168
196
  onChange: PropTypes.func.isRequired,
169
- sortOptions: PropTypes.array,
197
+ sortOptions: PropTypes.arrayOf(
198
+ PropTypes.shape({
199
+ value: PropTypes.string,
200
+ label: PropTypes.string,
201
+ }).isRequired
202
+ ),
170
203
  };
@@ -47,7 +47,7 @@ export const ListSettingsView = ({ layout, slug }) => {
47
47
 
48
48
  const isModalFormOpen = Object.keys(fieldForm).length !== 0;
49
49
 
50
- const { attributes } = layout;
50
+ const { attributes, options } = layout;
51
51
  const displayedFields = modifiedData.layouts.list;
52
52
 
53
53
  const goBackUrl = () => {
@@ -169,7 +169,10 @@ export const ListSettingsView = ({ layout, slug }) => {
169
169
 
170
170
  const sortOptions = Object.entries(attributes)
171
171
  .filter(([, attribute]) => !EXCLUDED_SORT_ATTRIBUTE_TYPES.includes(attribute.type))
172
- .map(([name]) => name);
172
+ .map(([name]) => ({
173
+ value: name,
174
+ label: layout.metadatas[name].list.label,
175
+ }));
173
176
 
174
177
  const move = (originalIndex, atIndex) => {
175
178
  dispatch({
@@ -225,6 +228,7 @@ export const ListSettingsView = ({ layout, slug }) => {
225
228
  paddingRight={7}
226
229
  >
227
230
  <Settings
231
+ contentTypeOptions={options}
228
232
  modifiedData={modifiedData}
229
233
  onChange={handleChange}
230
234
  sortOptions={sortOptions}
@@ -1,81 +1,93 @@
1
1
  import React from 'react';
2
2
 
3
- import { Select, Option, Box } from '@strapi/design-system';
4
- import { useTracking } from '@strapi/helper-plugin';
3
+ import { Flex, BaseCheckbox, TextButton, Typography } from '@strapi/design-system';
4
+ import { useCollator, 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
+ import styled from 'styled-components';
8
9
 
9
- import { getTrad, checkIfAttributeIsDisplayable } from '../../../../utils';
10
- import { onChangeListHeaders } from '../../actions';
10
+ import { checkIfAttributeIsDisplayable } from '../../../../utils';
11
+ import { onChangeListHeaders, onResetListHeaders } from '../../actions';
11
12
  import { selectDisplayedHeaders } from '../../selectors';
12
13
 
14
+ const ChackboxWrapper = styled(Flex)`
15
+ :hover {
16
+ background-color: ${(props) => props.theme.colors.primary100};
17
+ }
18
+ `;
19
+
13
20
  export const FieldPicker = ({ layout }) => {
14
21
  const dispatch = useDispatch();
15
22
  const displayedHeaders = useSelector(selectDisplayedHeaders);
16
23
  const { trackUsage } = useTracking();
17
- const { formatMessage } = useIntl();
18
-
19
- const allAllowedHeaders = getAllAllowedHeaders(layout.contentType.attributes).map((attrName) => {
20
- const metadatas = layout.contentType.metadatas[attrName].list;
21
-
22
- return {
23
- name: attrName,
24
- intlLabel: { id: metadatas.label, defaultMessage: metadatas.label },
25
- };
24
+ const { formatMessage, locale } = useIntl();
25
+ const formatter = useCollator(locale, {
26
+ sensitivity: 'base',
26
27
  });
27
28
 
28
- const values = displayedHeaders.map(({ name }) => name);
29
+ const columns = Object.keys(layout.contentType.attributes)
30
+ .filter((name) => checkIfAttributeIsDisplayable(layout.contentType.attributes[name]))
31
+ .map((name) => ({
32
+ name,
33
+ label: layout.contentType.metadatas[name].list.label,
34
+ }))
35
+ .sort((a, b) => formatter.compare(a.label, b.label));
29
36
 
30
- const handleChange = (updatedValues) => {
31
- trackUsage('didChangeDisplayedFields');
37
+ const displayedHeaderKeys = displayedHeaders.map(({ name }) => name);
32
38
 
33
- // removing a header
34
- if (updatedValues.length < values.length) {
35
- const removedHeader = values.filter((value) => {
36
- return updatedValues.indexOf(value) === -1;
37
- });
38
-
39
- dispatch(onChangeListHeaders({ name: removedHeader[0], value: true }));
40
- } else {
41
- const addedHeader = updatedValues.filter((value) => {
42
- return values.indexOf(value) === -1;
43
- });
39
+ const handleChange = (name) => {
40
+ trackUsage('didChangeDisplayedFields');
41
+ dispatch(onChangeListHeaders({ name, value: displayedHeaderKeys.includes(name) }));
42
+ };
44
43
 
45
- dispatch(onChangeListHeaders({ name: addedHeader[0], value: false }));
46
- }
44
+ const handleReset = () => {
45
+ dispatch(onResetListHeaders());
47
46
  };
48
47
 
49
48
  return (
50
- <Box paddingTop={1} paddingBottom={1}>
51
- <Select
52
- aria-label="change displayed fields"
53
- value={values}
54
- onChange={handleChange}
55
- customizeContent={(values) =>
56
- formatMessage(
57
- {
58
- id: getTrad('select.currently.selected'),
59
- defaultMessage: '{count} currently selected',
60
- },
61
- { count: values.length }
62
- )
63
- }
64
- multi
65
- size="S"
66
- >
67
- {allAllowedHeaders.map((header) => {
49
+ <Flex as="fieldset" direction="column" alignItems="stretch" gap={3}>
50
+ <Flex justifyContent="space-between">
51
+ <Typography as="legend" variant="pi" fontWeight="bold">
52
+ {formatMessage({
53
+ id: 'containers.ListPage.displayedFields',
54
+ defaultMessage: 'Displayed fields',
55
+ })}
56
+ </Typography>
57
+
58
+ <TextButton onClick={handleReset}>
59
+ {formatMessage({
60
+ id: 'app.components.Button.reset',
61
+ defaultMessage: 'Reset',
62
+ })}
63
+ </TextButton>
64
+ </Flex>
65
+
66
+ <Flex direction="column" alignItems="stretch">
67
+ {columns.map((header) => {
68
+ const isActive = displayedHeaderKeys.includes(header.name);
69
+
68
70
  return (
69
- <Option key={header.name} value={header.name}>
70
- {formatMessage({
71
- id: header.intlLabel.id || header.name,
72
- defaultMessage: header.intlLabel.defaultMessage || header.name,
73
- })}
74
- </Option>
71
+ <ChackboxWrapper
72
+ wrap="wrap"
73
+ gap={2}
74
+ as="label"
75
+ background={isActive ? 'primary100' : 'transparent'}
76
+ hasRadius
77
+ padding={2}
78
+ key={header.name}
79
+ >
80
+ <BaseCheckbox
81
+ onChange={() => handleChange(header.name)}
82
+ value={isActive}
83
+ name={header.name}
84
+ />
85
+ <Typography fontSize={1}>{header.label}</Typography>
86
+ </ChackboxWrapper>
75
87
  );
76
88
  })}
77
- </Select>
78
- </Box>
89
+ </Flex>
90
+ </Flex>
79
91
  );
80
92
  };
81
93
 
@@ -92,17 +104,3 @@ FieldPicker.propTypes = {
92
104
  }).isRequired,
93
105
  }).isRequired,
94
106
  };
95
-
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
- };