@strapi/admin 4.12.0-beta.5 → 4.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (162) hide show
  1. package/admin/src/components/LeftMenu/index.js +1 -1
  2. package/admin/src/components/PluginsInitializer/index.js +23 -0
  3. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +9 -14
  4. package/admin/src/content-manager/components/EditViewDataManagerProvider/utils/cleanData.js +1 -1
  5. package/admin/src/content-manager/components/InputUID/index.js +2 -3
  6. package/admin/src/content-manager/components/RelationInput/RelationInput.js +1 -1
  7. package/admin/src/content-manager/components/RelationInputDataManager/utils/getRelationLink.js +1 -3
  8. package/admin/src/content-manager/components/RelationInputDataManager/utils/select.js +4 -6
  9. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +7 -9
  10. package/admin/src/content-manager/pages/App/utils/getContentTypeLinks.js +1 -3
  11. package/admin/src/content-manager/pages/EditSettingsView/index.js +31 -18
  12. package/admin/src/content-manager/pages/ListSettingsView/components/EditFieldForm.js +1 -3
  13. package/admin/src/content-manager/pages/ListSettingsView/components/Settings.js +1 -3
  14. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +14 -32
  15. package/admin/src/content-manager/pages/ListSettingsView/index.js +50 -40
  16. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/ConfirmBulkActionDialog/index.js +2 -0
  17. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +83 -36
  18. package/admin/src/content-manager/pages/ListView/components/CellContent/RelationMultiple/index.js +2 -2
  19. package/admin/src/content-manager/pages/ListView/index.js +3 -3
  20. package/admin/src/content-manager/sharedReducers/crudReducer/reducer.js +1 -1
  21. package/admin/src/content-manager/utils/checkIfAttributeIsDisplayable.js +2 -4
  22. package/admin/src/content-manager/utils/index.js +0 -1
  23. package/admin/src/pages/AuthPage/constants.js +2 -2
  24. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +1 -1
  25. package/admin/src/translations/ar.json +9 -3
  26. package/admin/src/translations/ca.json +8 -2
  27. package/admin/src/translations/de.json +8 -2
  28. package/admin/src/translations/dk.json +8 -2
  29. package/admin/src/translations/en.json +9 -2
  30. package/admin/src/translations/es.json +9 -3
  31. package/admin/src/translations/eu.json +8 -2
  32. package/admin/src/translations/fr.json +9 -2
  33. package/admin/src/translations/gu.json +8 -2
  34. package/admin/src/translations/hi.json +9 -3
  35. package/admin/src/translations/hu.json +9 -3
  36. package/admin/src/translations/ja.json +12 -6
  37. package/admin/src/translations/ko.json +12 -6
  38. package/admin/src/translations/ml.json +8 -2
  39. package/admin/src/translations/nl.json +8 -2
  40. package/admin/src/translations/pl.json +8 -2
  41. package/admin/src/translations/pt-BR.json +8 -2
  42. package/admin/src/translations/ru.json +8 -2
  43. package/admin/src/translations/sa.json +9 -3
  44. package/admin/src/translations/sk.json +8 -2
  45. package/admin/src/translations/sv.json +7 -2
  46. package/admin/src/translations/tr.json +8 -2
  47. package/admin/src/translations/zh-Hans.json +8 -2
  48. package/admin/src/translations/zh.json +8 -2
  49. package/admin/src/utils/index.js +0 -1
  50. package/build/{1049.758a01f5.chunk.js → 1049.c3d082e9.chunk.js} +1 -1
  51. package/build/1386.879bcd90.chunk.js +7 -0
  52. package/build/{2225.15d1df72.chunk.js → 2225.0e4f8c77.chunk.js} +1 -1
  53. package/build/2379.f1641312.chunk.js +1 -0
  54. package/build/2395.46f8d0c1.chunk.js +26 -0
  55. package/build/2801.5cef5ec8.chunk.js +1 -0
  56. package/build/{3483.e2ee2547.chunk.js → 3483.03c24f96.chunk.js} +1 -1
  57. package/build/3929.5632f24d.chunk.js +114 -0
  58. package/build/4546.cfafae68.chunk.js +1 -0
  59. package/build/6691.4985ef22.chunk.js +105 -0
  60. package/build/7464.3e64a1d5.chunk.js +1 -0
  61. package/build/8276.10a3f883.chunk.js +26 -0
  62. package/build/{9806.aa25371d.chunk.js → 9806.3392505e.chunk.js} +2 -2
  63. package/build/{Admin-authenticatedApp.6b8dfa45.chunk.js → Admin-authenticatedApp.8dfbc48d.chunk.js} +3 -3
  64. package/build/{Admin_profilePage.a968035f.chunk.js → Admin_profilePage.ca82c67b.chunk.js} +1 -1
  65. package/build/{Admin_settingsPage.8c600d1a.chunk.js → Admin_settingsPage.50c867bf.chunk.js} +1 -1
  66. package/build/admin-app.041dcd81.chunk.js +36 -0
  67. package/build/{admin-edit-users.67704088.chunk.js → admin-edit-users.79eeb125.chunk.js} +1 -1
  68. package/build/{admin-users.3279ffb0.chunk.js → admin-users.123aa08e.chunk.js} +1 -1
  69. package/build/ar-json.74e40bc7.chunk.js +1 -0
  70. package/build/{ca-json.a53c10b6.chunk.js → ca-json.fc6001d3.chunk.js} +1 -1
  71. package/build/content-manager.098eb004.chunk.js +1099 -0
  72. package/build/content-type-builder.64f4d6ac.chunk.js +170 -0
  73. package/build/{de-json.b3be02c7.chunk.js → de-json.e72545cf.chunk.js} +1 -1
  74. package/build/dk-json.e77140ef.chunk.js +1 -0
  75. package/build/{en-json.4c733bd1.chunk.js → en-json.01456e61.chunk.js} +1 -1
  76. package/build/es-json.b1f2284b.chunk.js +1 -0
  77. package/build/{eu-json.633025f0.chunk.js → eu-json.63d0a898.chunk.js} +1 -1
  78. package/build/{fr-json.aa8839d2.chunk.js → fr-json.33c6428b.chunk.js} +1 -1
  79. package/build/{gu-json.5bd62812.chunk.js → gu-json.7efe8cc2.chunk.js} +1 -1
  80. package/build/{hi-json.9104eb78.chunk.js → hi-json.0d633692.chunk.js} +1 -1
  81. package/build/{hu-json.9f4aae42.chunk.js → hu-json.c74b6a1e.chunk.js} +1 -1
  82. package/build/index.html +1 -1
  83. package/build/{ja-json.91286391.chunk.js → ja-json.e1959a1c.chunk.js} +1 -1
  84. package/build/{ko-json.fcf3ec4b.chunk.js → ko-json.ce5d6d94.chunk.js} +1 -1
  85. package/build/{main.af84ad9c.js → main.1f8cc299.js} +429 -429
  86. package/build/{ml-json.557aa14c.chunk.js → ml-json.940d7ace.chunk.js} +1 -1
  87. package/build/{nl-json.b2b16eea.chunk.js → nl-json.fe38f0fb.chunk.js} +1 -1
  88. package/build/{pl-json.f094a417.chunk.js → pl-json.d55e8e78.chunk.js} +1 -1
  89. package/build/{pt-BR-json.dec7fb01.chunk.js → pt-BR-json.ae0a0d2e.chunk.js} +1 -1
  90. package/build/review-workflows-settings-create-view.cb08cfa2.chunk.js +1 -0
  91. package/build/review-workflows-settings-edit-view.3c7cbe63.chunk.js +1 -0
  92. package/build/review-workflows-settings-list-view.1611dc1f.chunk.js +56 -0
  93. package/build/{ru-json.8193d8c4.chunk.js → ru-json.1c976644.chunk.js} +1 -1
  94. package/build/{runtime~main.a65ca6fb.js → runtime~main.80a43c16.js} +2 -2
  95. package/build/{sa-json.a56836f1.chunk.js → sa-json.2c03ef4e.chunk.js} +1 -1
  96. package/build/sk-json.b41847e8.chunk.js +1 -0
  97. package/build/sso-settings-page.81152e62.chunk.js +1 -0
  98. package/build/{sv-json.fd0e86c6.chunk.js → sv-json.568cb7ae.chunk.js} +1 -1
  99. package/build/{tr-json.56c32cf6.chunk.js → tr-json.c9f22432.chunk.js} +1 -1
  100. package/build/transfer-tokens-list-page.692eee77.chunk.js +16 -0
  101. package/build/upload-settings.7f93d4c0.chunk.js +14 -0
  102. package/build/upload.77d8a64c.chunk.js +58 -0
  103. package/build/users-advanced-settings-page.f0760eb8.chunk.js +9 -0
  104. package/build/users-email-settings-page.ff4b32f3.chunk.js +9 -0
  105. package/build/users-providers-settings-page.48de0306.chunk.js +14 -0
  106. package/build/users-roles-settings-page.3f9f063e.chunk.js +30 -0
  107. package/build/{webhook-edit-page.a91f27a1.chunk.js → webhook-edit-page.6cb479ff.chunk.js} +2 -2
  108. package/build/{zh-Hans-json.36d81cdc.chunk.js → zh-Hans-json.937b395b.chunk.js} +1 -1
  109. package/build/{zh-json.1cc86ff0.chunk.js → zh-json.bfc2e036.chunk.js} +1 -1
  110. package/ee/admin/hooks/useAuthProviders/index.js +1 -3
  111. package/ee/admin/pages/AuthResponse/index.js +1 -3
  112. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/Stages/Stage/Stage.js +35 -32
  113. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +1 -7
  114. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +16 -14
  115. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +33 -33
  116. package/ee/admin/pages/SettingsPage/pages/SingleSignOn/index.js +1 -2
  117. package/ee/server/bootstrap.js +2 -0
  118. package/ee/server/config/admin-actions.js +6 -6
  119. package/ee/server/services/auth.js +1 -1
  120. package/ee/server/services/index.js +1 -0
  121. package/ee/server/services/review-workflows/entity-service-decorator.js +4 -3
  122. package/ee/server/services/review-workflows/metrics/index.js +51 -0
  123. package/ee/server/services/review-workflows/metrics/weekly-metrics.js +76 -0
  124. package/ee/server/services/review-workflows/workflows/index.js +5 -0
  125. package/package.json +16 -16
  126. package/server/middlewares/rateLimit.js +6 -2
  127. package/server/services/transfer/token.js +27 -4
  128. package/server/validation/authentication/register.js +2 -2
  129. package/admin/src/content-manager/components/SingleTypeFormWrapper/utils/getRequestUrl.js +0 -5
  130. package/admin/src/content-manager/components/SingleTypeFormWrapper/utils/index.js +0 -2
  131. package/admin/src/content-manager/pages/EditSettingsView/utils/api.js +0 -16
  132. package/admin/src/content-manager/pages/ListSettingsView/init.js +0 -9
  133. package/admin/src/content-manager/utils/getRequestUrl.js +0 -4
  134. package/admin/src/utils/getRequestUrl.js +0 -3
  135. package/build/1386.762d6eb8.chunk.js +0 -7
  136. package/build/2379.0ca87a89.chunk.js +0 -1
  137. package/build/2395.df7a044a.chunk.js +0 -26
  138. package/build/2801.b1140c9b.chunk.js +0 -1
  139. package/build/4546.ff9fdf30.chunk.js +0 -1
  140. package/build/6691.f880a0b6.chunk.js +0 -105
  141. package/build/7065.ec811562.chunk.js +0 -114
  142. package/build/7464.8a6c1e6c.chunk.js +0 -1
  143. package/build/8276.6c7b8e6e.chunk.js +0 -26
  144. package/build/admin-app.c2e4e128.chunk.js +0 -36
  145. package/build/ar-json.f530bc3f.chunk.js +0 -1
  146. package/build/content-manager.8772445b.chunk.js +0 -1103
  147. package/build/content-type-builder.40534de5.chunk.js +0 -170
  148. package/build/dk-json.842aa391.chunk.js +0 -1
  149. package/build/es-json.f57b5335.chunk.js +0 -1
  150. package/build/review-workflows-settings-create-view.05758184.chunk.js +0 -1
  151. package/build/review-workflows-settings-edit-view.c33f7c58.chunk.js +0 -1
  152. package/build/review-workflows-settings-list-view.3ee9190d.chunk.js +0 -56
  153. package/build/sk-json.bf2f057a.chunk.js +0 -1
  154. package/build/sso-settings-page.7c9b2fd9.chunk.js +0 -1
  155. package/build/transfer-tokens-list-page.22147d2c.chunk.js +0 -16
  156. package/build/upload-settings.cac210a0.chunk.js +0 -14
  157. package/build/upload.cbfeefa5.chunk.js +0 -58
  158. package/build/users-advanced-settings-page.18379a56.chunk.js +0 -9
  159. package/build/users-email-settings-page.a87978e5.chunk.js +0 -9
  160. package/build/users-providers-settings-page.8876c1ee.chunk.js +0 -14
  161. package/build/users-roles-settings-page.0431f48c.chunk.js +0 -30
  162. package/ee/server/services/review-workflows/metrics.js +0 -24
@@ -1,10 +1,10 @@
1
- import React, { memo, useContext, useReducer, useState } from 'react';
1
+ import React, { useContext, useReducer, useState } from 'react';
2
2
 
3
3
  import {
4
- Box,
5
4
  Button,
6
5
  ContentLayout,
7
6
  Divider,
7
+ Flex,
8
8
  HeaderLayout,
9
9
  Layout,
10
10
  Main,
@@ -17,10 +17,7 @@ import {
17
17
  useTracking,
18
18
  } from '@strapi/helper-plugin';
19
19
  import { ArrowLeft, Check } from '@strapi/icons';
20
- import get from 'lodash/get';
21
- import isEmpty from 'lodash/isEmpty';
22
20
  import isEqual from 'lodash/isEqual';
23
- import pick from 'lodash/pick';
24
21
  import upperFirst from 'lodash/upperFirst';
25
22
  import PropTypes from 'prop-types';
26
23
  import { stringify } from 'qs';
@@ -31,11 +28,10 @@ import ModelsContext from '../../contexts/ModelsContext';
31
28
  import { usePluginsQueryParams } from '../../hooks';
32
29
  import { checkIfAttributeIsDisplayable, getTrad } from '../../utils';
33
30
 
34
- import EditFieldForm from './components/EditFieldForm';
35
- import Settings from './components/Settings';
36
- import SortDisplayedFields from './components/SortDisplayedFields';
31
+ import { EditFieldForm } from './components/EditFieldForm';
32
+ import { Settings } from './components/Settings';
33
+ import { SortDisplayedFields } from './components/SortDisplayedFields';
37
34
  import { EXCLUDED_SORT_ATTRIBUTE_TYPES } from './constants';
38
- import init from './init';
39
35
  import reducer, { initialState } from './reducer';
40
36
 
41
37
  const ListSettingsView = ({ layout, slug }) => {
@@ -45,14 +41,19 @@ const ListSettingsView = ({ layout, slug }) => {
45
41
  const pluginsQueryParams = usePluginsQueryParams();
46
42
  const toggleNotification = useNotification();
47
43
  const { refetchData } = useContext(ModelsContext);
48
-
49
44
  const [showWarningSubmit, setWarningSubmit] = useState(false);
50
45
  const toggleWarningSubmit = () => setWarningSubmit((prevState) => !prevState);
51
- const [reducerState, dispatch] = useReducer(reducer, initialState, () =>
52
- init(initialState, layout)
46
+ const [{ fieldToEdit, fieldForm, initialData, modifiedData }, dispatch] = useReducer(
47
+ reducer,
48
+ initialState,
49
+ () => ({
50
+ ...initialState,
51
+ initialData: layout,
52
+ modifiedData: layout,
53
+ })
53
54
  );
54
- const { fieldToEdit, fieldForm, initialData, modifiedData } = reducerState;
55
- const isModalFormOpen = !isEmpty(fieldForm);
55
+
56
+ const isModalFormOpen = Object.keys(fieldForm).length !== 0;
56
57
 
57
58
  const { attributes } = layout;
58
59
  const displayedFields = modifiedData.layouts.list;
@@ -84,9 +85,30 @@ const ListSettingsView = ({ layout, slug }) => {
84
85
  });
85
86
  };
86
87
 
88
+ const { isLoading: isSubmittingForm, mutate } = useMutation(
89
+ (body) => put(`/content-manager/content-types/${slug}/configuration`, body),
90
+ {
91
+ onSuccess() {
92
+ trackUsage('didEditListSettings');
93
+ refetchData();
94
+ },
95
+ onError() {
96
+ toggleNotification({
97
+ type: 'warning',
98
+ message: { id: 'notification.error' },
99
+ });
100
+ },
101
+ }
102
+ );
103
+
87
104
  const handleConfirm = async () => {
88
- const body = pick(modifiedData, ['layouts', 'settings', 'metadatas']);
89
- submitMutation.mutate(body);
105
+ const { layouts, settings, metadatas } = modifiedData;
106
+
107
+ mutate({
108
+ layouts,
109
+ settings,
110
+ metadatas,
111
+ });
90
112
  };
91
113
 
92
114
  const handleAddField = (item) => {
@@ -139,23 +161,6 @@ const ListSettingsView = ({ layout, slug }) => {
139
161
  handleCloseModal();
140
162
  };
141
163
 
142
- const submitMutation = useMutation(
143
- (body) => put(`/content-manager/content-types/${slug}/configuration`, body),
144
- {
145
- onSuccess() {
146
- trackUsage('didEditListSettings');
147
- refetchData();
148
- },
149
- onError() {
150
- toggleNotification({
151
- type: 'warning',
152
- message: { id: 'notification.error' },
153
- });
154
- },
155
- }
156
- );
157
- const { isLoading: isSubmittingForm } = submitMutation;
158
-
159
164
  const handleChangeEditLabel = ({ target: { name, value } }) => {
160
165
  dispatch({
161
166
  type: 'ON_CHANGE_FIELD_METAS',
@@ -217,8 +222,11 @@ const ListSettingsView = ({ layout, slug }) => {
217
222
  )}
218
223
  />
219
224
  <ContentLayout>
220
- <Box
225
+ <Flex
226
+ alignItems="stretch"
221
227
  background="neutral0"
228
+ direction="column"
229
+ gap={6}
222
230
  hasRadius
223
231
  shadow="tableShadow"
224
232
  paddingTop={6}
@@ -231,9 +239,9 @@ const ListSettingsView = ({ layout, slug }) => {
231
239
  onChange={handleChange}
232
240
  sortOptions={sortOptions}
233
241
  />
234
- <Box paddingTop={6} paddingBottom={6}>
235
- <Divider />
236
- </Box>
242
+
243
+ <Divider />
244
+
237
245
  <SortDisplayedFields
238
246
  listRemainingFields={listRemainingFields}
239
247
  displayedFields={displayedFields}
@@ -243,8 +251,9 @@ const ListSettingsView = ({ layout, slug }) => {
243
251
  onRemoveField={handleRemoveField}
244
252
  metadatas={modifiedData.metadatas}
245
253
  />
246
- </Box>
254
+ </Flex>
247
255
  </ContentLayout>
256
+
248
257
  <ConfirmDialog
249
258
  bodyText={{
250
259
  id: getTrad('popUpWarning.warning.updateAllSettings'),
@@ -258,6 +267,7 @@ const ListSettingsView = ({ layout, slug }) => {
258
267
  variantRightButton="success-light"
259
268
  />
260
269
  </form>
270
+
261
271
  {isModalFormOpen && (
262
272
  <EditFieldForm
263
273
  attributes={attributes}
@@ -266,7 +276,7 @@ const ListSettingsView = ({ layout, slug }) => {
266
276
  onChangeEditLabel={handleChangeEditLabel}
267
277
  onCloseModal={handleCloseModal}
268
278
  onSubmit={handleSubmitFieldEdit}
269
- type={get(attributes, [fieldToEdit, 'type'], 'text')}
279
+ type={attributes?.[fieldToEdit]?.type ?? 'text'}
270
280
  />
271
281
  )}
272
282
  </Main>
@@ -296,4 +306,4 @@ ListSettingsView.propTypes = {
296
306
  slug: PropTypes.string.isRequired,
297
307
  };
298
308
 
299
- export default memo(ListSettingsView);
309
+ export default ListSettingsView;
@@ -104,6 +104,8 @@ const ConfirmDialogPublishAll = ({ isOpen, onToggleDialog, isConfirmButtonLoadin
104
104
  return data;
105
105
  },
106
106
  {
107
+ // The API is called everytime you select/deselect an entry, this check avoids us sending a query with bad data
108
+ enabled: selectedEntries.length > 0,
107
109
  onError(error) {
108
110
  toggleNotification({ type: 'warning', message: formatAPIError(error) });
109
111
  },
@@ -46,11 +46,11 @@ const TypographyMaxWidth = styled(Typography)`
46
46
  * EntryValidationText
47
47
  * -----------------------------------------------------------------------------------------------*/
48
48
 
49
- const EntryValidationText = ({ errors, isPublished }) => {
49
+ const EntryValidationText = ({ validationErrors, isPublished }) => {
50
50
  const { formatMessage } = useIntl();
51
51
 
52
- if (errors) {
53
- const errorMessages = Object.entries(errors)
52
+ if (validationErrors) {
53
+ const validationErrorsMessages = Object.entries(validationErrors)
54
54
  .map(([key, value]) =>
55
55
  formatMessage(
56
56
  { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
@@ -62,9 +62,9 @@ const EntryValidationText = ({ errors, isPublished }) => {
62
62
  return (
63
63
  <Flex gap={2}>
64
64
  <Icon color="danger600" as={CrossCircle} />
65
- <Tooltip description={errorMessages}>
65
+ <Tooltip description={validationErrorsMessages}>
66
66
  <TypographyMaxWidth textColor="danger600" variant="omega" fontWeight="semiBold" ellipsis>
67
- {errorMessages}
67
+ {validationErrorsMessages}
68
68
  </TypographyMaxWidth>
69
69
  </Tooltip>
70
70
  </Flex>
@@ -77,8 +77,8 @@ const EntryValidationText = ({ errors, isPublished }) => {
77
77
  <Icon color="success600" as={CheckCircle} />
78
78
  <Typography textColor="success600" fontWeight="bold">
79
79
  {formatMessage({
80
- id: 'app.utils.published',
81
- defaultMessage: 'Published',
80
+ id: 'content-manager.bulk-publish.already-published',
81
+ defaultMessage: 'Already Published',
82
82
  })}
83
83
  </Typography>
84
84
  </Flex>
@@ -99,12 +99,12 @@ const EntryValidationText = ({ errors, isPublished }) => {
99
99
  };
100
100
 
101
101
  EntryValidationText.defaultProps = {
102
- errors: null,
102
+ validationErrors: undefined,
103
103
  isPublished: false,
104
104
  };
105
105
 
106
106
  EntryValidationText.propTypes = {
107
- errors: PropTypes.shape({
107
+ validationErrors: PropTypes.shape({
108
108
  [PropTypes.string]: PropTypes.shape({
109
109
  id: PropTypes.string,
110
110
  defaultMessage: PropTypes.string,
@@ -117,7 +117,12 @@ EntryValidationText.propTypes = {
117
117
  * SelectedEntriesTableContent
118
118
  * -----------------------------------------------------------------------------------------------*/
119
119
 
120
- const SelectedEntriesTableContent = ({ isPublishing, rowsToDisplay, entriesToPublish }) => {
120
+ const SelectedEntriesTableContent = ({
121
+ isPublishing,
122
+ rowsToDisplay,
123
+ entriesToPublish,
124
+ validationErrors,
125
+ }) => {
121
126
  const {
122
127
  location: { pathname },
123
128
  } = useHistory();
@@ -149,19 +154,19 @@ const SelectedEntriesTableContent = ({ isPublishing, rowsToDisplay, entriesToPub
149
154
  </Table.Head>
150
155
  <Table.LoadingBody />
151
156
  <Table.Body>
152
- {rowsToDisplay.map(({ entity, errors }, index) => (
153
- <Tr key={entity.id}>
154
- <Body.CheckboxDataCell rowId={entity.id} index={index} />
157
+ {rowsToDisplay.map((row, index) => (
158
+ <Tr key={row.id}>
159
+ <Body.CheckboxDataCell rowId={row.id} index={index} />
155
160
  <Td>
156
- <Typography>{entity.id}</Typography>
161
+ <Typography>{row.id}</Typography>
157
162
  </Td>
158
163
  {shouldDisplayMainField && (
159
164
  <Td>
160
- <Typography>{entity[mainField]}</Typography>
165
+ <Typography>{row[mainField]}</Typography>
161
166
  </Td>
162
167
  )}
163
168
  <Td>
164
- {isPublishing && entriesToPublish.includes(entity.id) ? (
169
+ {isPublishing && entriesToPublish.includes(row.id) ? (
165
170
  <Flex gap={2}>
166
171
  <Typography>
167
172
  {formatMessage({
@@ -172,14 +177,17 @@ const SelectedEntriesTableContent = ({ isPublishing, rowsToDisplay, entriesToPub
172
177
  <Loader small />
173
178
  </Flex>
174
179
  ) : (
175
- <EntryValidationText errors={errors} isPublished={entity.publishedAt !== null} />
180
+ <EntryValidationText
181
+ validationErrors={validationErrors[row.id]}
182
+ isPublished={row.publishedAt !== null}
183
+ />
176
184
  )}
177
185
  </Td>
178
186
  <Td>
179
187
  <IconButton
180
188
  forwardedAs={Link}
181
189
  to={{
182
- pathname: `${pathname}/${entity.id}`,
190
+ pathname: `${pathname}/${row.id}`,
183
191
  state: { from: pathname },
184
192
  }}
185
193
  label={formatMessage(
@@ -188,6 +196,7 @@ const SelectedEntriesTableContent = ({ isPublishing, rowsToDisplay, entriesToPub
188
196
  )}
189
197
  noBorder
190
198
  target="_blank"
199
+ marginLeft="auto"
191
200
  >
192
201
  <Pencil />
193
202
  </IconButton>
@@ -203,12 +212,19 @@ SelectedEntriesTableContent.defaultProps = {
203
212
  isPublishing: false,
204
213
  rowsToDisplay: [],
205
214
  entriesToPublish: [],
215
+ validationErrors: {},
206
216
  };
207
217
 
208
218
  SelectedEntriesTableContent.propTypes = {
209
219
  isPublishing: PropTypes.bool,
210
220
  rowsToDisplay: PropTypes.arrayOf(PropTypes.object),
211
221
  entriesToPublish: PropTypes.arrayOf(PropTypes.number),
222
+ validationErrors: PropTypes.shape({
223
+ [PropTypes.string]: PropTypes.shape({
224
+ id: PropTypes.string,
225
+ defaultMessage: PropTypes.string,
226
+ }),
227
+ }),
212
228
  };
213
229
 
214
230
  /* -------------------------------------------------------------------------------------------------
@@ -221,7 +237,13 @@ const BoldChunk = (chunks) => <Typography fontWeight="bold">{chunks}</Typography
221
237
  * SelectedEntriesModalContent
222
238
  * -----------------------------------------------------------------------------------------------*/
223
239
 
224
- const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntriesToFetch }) => {
240
+ const SelectedEntriesModalContent = ({
241
+ toggleModal,
242
+ refetchModalData,
243
+ setEntriesToFetch,
244
+ setSelectedListViewEntries,
245
+ validationErrors,
246
+ }) => {
225
247
  const { formatMessage } = useIntl();
226
248
  const { selectedEntries, rows, onSelectRow, isLoading, isFetching } = useTableContext();
227
249
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);
@@ -229,15 +251,15 @@ const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntries
229
251
  const [publishedCount, setPublishedCount] = React.useState(0);
230
252
 
231
253
  const entriesToPublish = rows
232
- .filter(({ entity, errors }) => selectedEntries.includes(entity.id) && !errors)
233
- .map(({ entity }) => entity.id);
254
+ .filter(({ id }) => selectedEntries.includes(id) && !validationErrors[id])
255
+ .map(({ id }) => id);
234
256
 
235
257
  const { post } = useFetchClient();
236
258
  const toggleNotification = useNotification();
237
259
  const { contentType } = useSelector(listViewDomain());
238
260
 
239
261
  const selectedEntriesWithErrorsCount = rowsToDisplay.filter(
240
- ({ entity, errors }) => selectedEntries.includes(entity.id) && errors
262
+ ({ id }) => selectedEntries.includes(id) && validationErrors[id]
241
263
  ).length;
242
264
  const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount;
243
265
 
@@ -247,18 +269,21 @@ const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntries
247
269
  {
248
270
  onSuccess() {
249
271
  const update = rowsToDisplay.filter((row) => {
250
- if (entriesToPublish.includes(row.entity.id)) {
272
+ if (entriesToPublish.includes(row.id)) {
251
273
  // Deselect the entries that have been published from the modal table
252
- onSelectRow({ name: row.entity.id, value: false });
274
+ onSelectRow({ name: row.id, value: false });
253
275
  }
254
276
 
255
277
  // Remove the entries that have been published from the table
256
- return !entriesToPublish.includes(row.entity.id);
278
+ return !entriesToPublish.includes(row.id);
257
279
  });
258
280
 
259
281
  setRowsToDisplay(update);
282
+ const publishedIds = update.map(({ id }) => id);
260
283
  // Set the parent's entries to fetch when clicking refresh
261
- setEntriesToFetch(update.map(({ entity }) => entity.id));
284
+ setEntriesToFetch(publishedIds);
285
+ // Deselect the entries that were published in the list view
286
+ setSelectedListViewEntries(publishedIds);
262
287
 
263
288
  if (update.length === 0) {
264
289
  toggleModal();
@@ -341,6 +366,7 @@ const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntries
341
366
  isPublishing={bulkPublishMutation.isLoading}
342
367
  rowsToDisplay={rowsToDisplay}
343
368
  entriesToPublish={entriesToPublish}
369
+ validationErrors={validationErrors}
344
370
  />
345
371
  </Box>
346
372
  </ModalBody>
@@ -382,10 +408,21 @@ const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntries
382
408
  );
383
409
  };
384
410
 
411
+ SelectedEntriesModalContent.defaultProps = {
412
+ validationErrors: {},
413
+ };
414
+
385
415
  SelectedEntriesModalContent.propTypes = {
386
416
  toggleModal: PropTypes.func.isRequired,
387
417
  refetchModalData: PropTypes.func.isRequired,
388
418
  setEntriesToFetch: PropTypes.func.isRequired,
419
+ setSelectedListViewEntries: PropTypes.func.isRequired,
420
+ validationErrors: PropTypes.shape({
421
+ [PropTypes.string]: PropTypes.shape({
422
+ id: PropTypes.string,
423
+ defaultMessage: PropTypes.string,
424
+ }),
425
+ }),
389
426
  };
390
427
 
391
428
  /* -------------------------------------------------------------------------------------------------
@@ -393,18 +430,23 @@ SelectedEntriesModalContent.propTypes = {
393
430
  * -----------------------------------------------------------------------------------------------*/
394
431
 
395
432
  const SelectedEntriesModal = ({ onToggle }) => {
396
- const { selectedEntries: selectedListViewEntries } = useTableContext();
433
+ const {
434
+ selectedEntries: selectedListViewEntries,
435
+ setSelectedEntries: setSelectedListViewEntries,
436
+ } = useTableContext();
397
437
  const { contentType, components } = useSelector(listViewDomain());
398
438
  // The child table will update this value based on the entries that were published
399
439
  const [entriesToFetch, setEntriesToFetch] = React.useState(selectedListViewEntries);
400
-
401
440
  // We want to keep the selected entries order same as the list view
402
441
  const [
403
442
  {
404
443
  query: { sort },
405
444
  },
406
445
  ] = useQueryParams();
446
+
407
447
  const queryParams = {
448
+ page: 1,
449
+ pageSize: entriesToFetch.length,
408
450
  sort,
409
451
  filters: {
410
452
  id: {
@@ -424,38 +466,43 @@ const SelectedEntriesModal = ({ onToggle }) => {
424
466
 
425
467
  if (data.results) {
426
468
  const schema = createYupSchema(contentType, { components }, { isDraft: false });
469
+ const validationErrors = {};
427
470
  const rows = data.results.map((entry) => {
428
471
  try {
429
472
  schema.validateSync(entry, { abortEarly: false });
430
473
 
431
- return { entity: entry };
474
+ return entry;
432
475
  } catch (e) {
433
- return {
434
- entity: entry,
435
- errors: getYupInnerErrors(e),
436
- };
476
+ validationErrors[entry.id] = getYupInnerErrors(e);
477
+
478
+ return entry;
437
479
  }
438
480
  });
439
481
 
440
- return rows;
482
+ return { rows, validationErrors };
441
483
  }
442
484
 
443
- return [];
485
+ return {
486
+ rows: [],
487
+ validationErrors: {},
488
+ };
444
489
  }
445
490
  );
446
491
 
447
492
  return (
448
493
  <Table.Root
449
- rows={data}
494
+ rows={data?.rows}
450
495
  defaultSelectedEntries={selectedListViewEntries}
451
496
  colCount={4}
452
497
  isLoading={isLoading}
453
498
  isFetching={isFetching}
454
499
  >
455
500
  <SelectedEntriesModalContent
501
+ setSelectedListViewEntries={setSelectedListViewEntries}
456
502
  setEntriesToFetch={setEntriesToFetch}
457
503
  toggleModal={onToggle}
458
504
  refetchModalData={refetch}
505
+ validationErrors={data?.validationErrors}
459
506
  />
460
507
  </Table.Root>
461
508
  );
@@ -8,7 +8,7 @@ import { useIntl } from 'react-intl';
8
8
  import { useQuery } from 'react-query';
9
9
  import styled from 'styled-components';
10
10
 
11
- import { getRequestUrl, getTrad } from '../../../../../utils';
11
+ import { getTrad } from '../../../../../utils';
12
12
  import CellValue from '../CellValue';
13
13
 
14
14
  const RelationMultiple = ({ fieldSchema, metadatas, name, entityId, value, contentType }) => {
@@ -24,7 +24,7 @@ const RelationMultiple = ({ fieldSchema, metadatas, name, entityId, value, conte
24
24
  const {
25
25
  data: { results, pagination },
26
26
  } = await get(
27
- getRequestUrl(`relations/${contentType.uid}/${entityId}/${name.split('.')[0]}`)
27
+ `/content-manager/relations/${contentType.uid}/${entityId}/${name.split('.')[0]}`
28
28
  );
29
29
 
30
30
  return { results, pagination };
@@ -50,7 +50,7 @@ import { useEnterprise } from '../../../hooks/useEnterprise';
50
50
  import { selectAdminPermissions } from '../../../pages/App/selectors';
51
51
  import { InjectionZone } from '../../../shared/components';
52
52
  import AttributeFilter from '../../components/AttributeFilter';
53
- import { getRequestUrl, getTrad } from '../../utils';
53
+ import { getTrad } from '../../utils';
54
54
 
55
55
  import { getData, getDataSucceeded, onChangeListHeaders, onResetListHeaders } from './actions';
56
56
  import { Body } from './components/Body';
@@ -247,7 +247,7 @@ function ListView({
247
247
  try {
248
248
  await del(`/content-manager/collection-types/${slug}/${idToDelete}`);
249
249
 
250
- const requestUrl = getRequestUrl(`collection-types/${slug}`);
250
+ const requestUrl = `/content-manager/collection-types/${slug}`;
251
251
  fetchData(requestUrl, { params });
252
252
 
253
253
  toggleNotification({
@@ -273,7 +273,7 @@ function ListView({
273
273
  const source = CancelToken.source();
274
274
 
275
275
  const shouldSendRequest = canRead;
276
- const requestUrl = getRequestUrl(`collection-types/${slug}`);
276
+ const requestUrl = `/content-manager/collection-types/${slug}`;
277
277
 
278
278
  if (shouldSendRequest && requestUrl.includes(requestUrlRef.current)) {
279
279
  fetchData(requestUrl, { cancelToken: source.token, params });
@@ -4,7 +4,7 @@ import produce from 'immer';
4
4
  // NOTE: instead of creating a shared reducer here, we could also create a hook
5
5
  // that returns the dispatch and the state, however it will mess with the linter
6
6
  // and force us to either disable the linter for the hooks dependencies array rule or
7
- // require us to add the dispatch to the array wich is not wanted. This refacto does not require us to
7
+ // require us to add the dispatch to the array which is not wanted. This refacto does not require us to
8
8
  // to do any of this.
9
9
  import {
10
10
  CLEAR_SET_MODIFIED_DATA_ONLY,
@@ -1,10 +1,8 @@
1
- import toLower from 'lodash/toLower';
2
-
3
1
  const checkIfAttributeIsDisplayable = (attribute) => {
4
- const type = attribute.type;
2
+ const { type } = attribute;
5
3
 
6
4
  if (type === 'relation') {
7
- return !toLower(attribute.relationType).includes('morph');
5
+ return !(attribute?.relationType ?? '').toLowerCase().includes('morph');
8
6
  }
9
7
 
10
8
  return !['json', 'dynamiczone', 'richtext', 'password'].includes(type) && !!type;
@@ -6,7 +6,6 @@ export { default as formatLayoutToApi } from './formatLayoutToApi';
6
6
  export { default as generatePermissionsObject } from './generatePermissionsObject';
7
7
  export { default as getFieldName } from './getFieldName';
8
8
  export { default as getMaxTempKey } from './getMaxTempKey';
9
- export { default as getRequestUrl } from './getRequestUrl';
10
9
  export { default as getTrad } from './getTrad';
11
10
  export { default as ItemTypes } from './ItemTypes';
12
11
  export { default as mergeMetasWithSchema } from './mergeMetasWithSchema';
@@ -55,7 +55,7 @@ export const FORMS = {
55
55
  fieldsToOmit: ['userInfo.confirmPassword', 'userInfo.news', 'userInfo.email'],
56
56
  schema: yup.object().shape({
57
57
  firstname: yup.string().trim().required(translatedErrors.required),
58
- lastname: yup.string(),
58
+ lastname: yup.string().nullable(),
59
59
  password: yup
60
60
  .string()
61
61
  .min(8, translatedErrors.minLength)
@@ -79,7 +79,7 @@ export const FORMS = {
79
79
  fieldsToOmit: ['confirmPassword', 'news'],
80
80
  schema: yup.object().shape({
81
81
  firstname: yup.string().trim().required(translatedErrors.required),
82
- lastname: yup.string(),
82
+ lastname: yup.string().nullable(),
83
83
  password: yup
84
84
  .string()
85
85
  .min(8, translatedErrors.minLength)
@@ -308,7 +308,7 @@ const EventRow = ({ disabledEvents, name, events, inputValue, handleSelect, hand
308
308
  </Td>
309
309
  );
310
310
  })}
311
- {events.length < targetColumns && <Td colSpan={`${targetColumns - events.length}`} />}
311
+ {events.length < targetColumns && <Td colSpan={targetColumns - events.length} />}
312
312
  </Tr>
313
313
  );
314
314
  };
@@ -398,18 +398,24 @@
398
398
  "coming.soon": "هذا المحتوى قيد الإنشاء حاليًا وسيعود في غضون أسابيع قليلة!",
399
399
  "component.Input.error.validation.integer": "يجب أن تكون القيمة عددًا صحيحًا",
400
400
  "components.AutoReloadBlocker.description": "Strapi قم بتشغيل باستخدام أحد الأوامر التالية:",
401
- "components.FilterOptions.FILTER_TYPES.$contains": "يحتوي على (حساس لحالة الأحرف)",
401
+ "components.FilterOptions.FILTER_TYPES.$contains": "يحتوي على",
402
+ "components.FilterOptions.FILTER_TYPES.$containsi": "يحتوي على (case insensitive)",
402
403
  "components.FilterOptions.FILTER_TYPES.$endsWith": "ينتهي بـ",
404
+ "components.FilterOptions.FILTER_TYPES.$endsWithi": "ينتهي بـ (case insensitive)",
403
405
  "components.FilterOptions.FILTER_TYPES.$eq": "هو",
406
+ "components.FilterOptions.FILTER_TYPES.$eqi": "هو (case insensitive)",
404
407
  "components.FilterOptions.FILTER_TYPES.$gt": "أكبر من",
405
408
  "components.FilterOptions.FILTER_TYPES.$gte": "أكبر من أو يساوي",
406
409
  "components.FilterOptions.FILTER_TYPES.$lt": "أقل من",
407
410
  "components.FilterOptions.FILTER_TYPES.$lte": "أقل من أو يساوي",
408
411
  "components.FilterOptions.FILTER_TYPES.$ne": "ليس",
409
- "components.FilterOptions.FILTER_TYPES.$notContains": "لا يحتوي على (حساس لحالة الأحرف)",
412
+ "components.FilterOptions.FILTER_TYPES.$nei": "ليس (case insensitive)",
413
+ "components.FilterOptions.FILTER_TYPES.$notContains": "لا يحتوي على",
414
+ "components.FilterOptions.FILTER_TYPES.$notContainsi": "لا يحتوي على (case insensitive)",
410
415
  "components.FilterOptions.FILTER_TYPES.$notNull": "هو ليس لاشيء",
411
416
  "components.FilterOptions.FILTER_TYPES.$null": "هو لاشيء",
412
417
  "components.FilterOptions.FILTER_TYPES.$startsWith": "يبدا ب",
418
+ "components.FilterOptions.FILTER_TYPES.$startsWithi": "يبدا ب (case insensitive)",
413
419
  "components.Input.error.contain.lowercase": "يجب أن تحتوي كلمة المرور على حرف صغير واحد على الأقل",
414
420
  "components.Input.error.contain.number": "يجب ان تحتوي كلمة المرور على الاقل رقما واحدا",
415
421
  "components.Input.error.contain.uppercase": "يجب أن تحتوي كلمة المرور على حرف كبير واحد على الأقل",
@@ -559,7 +565,7 @@
559
565
  "content-manager.success.record.unpublish": "غير منشورة",
560
566
  "content-manager.utils.data-loaded": "The {number, plural, =1 {entry has} other {entries have}} successfully been loaded",
561
567
  "dark": "داكن",
562
- "Documentation": "توثيق",
568
+ "Documentation": "توثيق",
563
569
  "form.button.continue": "واصل",
564
570
  "form.button.done": "منتهي",
565
571
  "global.actions": "أجراءات",
@@ -380,18 +380,24 @@
380
380
  "components.AutoReloadBlocker.description": "Inicia Strapi amb una de les ordres següents:",
381
381
  "components.AutoReloadBlocker.header": "Cal recarregar aquesta extensió.",
382
382
  "components.ErrorBoundary.title": "Alguna cosa ha sortit malament...",
383
- "components.FilterOptions.FILTER_TYPES.$contains": "conté (sensible a majúscules i minúscules)",
383
+ "components.FilterOptions.FILTER_TYPES.$contains": "conté",
384
+ "components.FilterOptions.FILTER_TYPES.$containsi": "conté (no distingeix entre majúscules i minúscules)",
384
385
  "components.FilterOptions.FILTER_TYPES.$endsWith": "acaba amb",
386
+ "components.FilterOptions.FILTER_TYPES.$endsWithi": "acaba amb (no distingeix entre majúscules i minúscules)",
385
387
  "components.FilterOptions.FILTER_TYPES.$eq": "és",
388
+ "components.FilterOptions.FILTER_TYPES.$eqi": "és (no distingeix entre majúscules i minúscules)",
386
389
  "components.FilterOptions.FILTER_TYPES.$gt": "és més gran que",
387
390
  "components.FilterOptions.FILTER_TYPES.$gte": "és més gran o igual a",
388
391
  "components.FilterOptions.FILTER_TYPES.$lt": "és menor que",
389
392
  "components.FilterOptions.FILTER_TYPES.$lte": "és menor o igual a",
390
393
  "components.FilterOptions.FILTER_TYPES.$ne": "no és",
391
- "components.FilterOptions.FILTER_TYPES.$notContains": "no conté (sensible a majúscules i minúscules)",
394
+ "components.FilterOptions.FILTER_TYPES.$nei": "no és (no distingeix entre majúscules i minúscules)",
395
+ "components.FilterOptions.FILTER_TYPES.$notContains": "no conté",
396
+ "components.FilterOptions.FILTER_TYPES.$notContainsi": "no conté (no distingeix entre majúscules i minúscules)",
392
397
  "components.FilterOptions.FILTER_TYPES.$notNull": "no és nul",
393
398
  "components.FilterOptions.FILTER_TYPES.$null": "és nul",
394
399
  "components.FilterOptions.FILTER_TYPES.$startsWith": "comença amb",
400
+ "components.FilterOptions.FILTER_TYPES.$startsWithi": "comença amb (no distingeix entre majúscules i minúscules)",
395
401
  "components.Input.error.attribute.key.taken": "Aquest valor ja existeix",
396
402
  "components.Input.error.attribute.sameKeyAndName": "No pot ser igual",
397
403
  "components.Input.error.attribute.taken": "Aquest nom de camp ja existeix",