@strapi/admin 4.12.0-beta.5 → 4.12.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 (23) hide show
  1. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/ConfirmBulkActionDialog/index.js +2 -0
  2. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +83 -36
  3. package/admin/src/pages/AuthPage/components/Register/index.js +0 -4
  4. package/admin/src/pages/SettingsPage/pages/Webhooks/EditView/components/Events/index.js +1 -1
  5. package/admin/src/translations/en.json +1 -0
  6. package/build/{Admin-authenticatedApp.6b8dfa45.chunk.js → Admin-authenticatedApp.376233ff.chunk.js} +1 -1
  7. package/build/{admin-app.c2e4e128.chunk.js → admin-app.1c3f7fd6.chunk.js} +8 -8
  8. package/build/{content-manager.8772445b.chunk.js → content-manager.e9205db1.chunk.js} +95 -95
  9. package/build/{en-json.4c733bd1.chunk.js → en-json.e34140fc.chunk.js} +1 -1
  10. package/build/index.html +1 -1
  11. package/build/{main.af84ad9c.js → main.1e3b0985.js} +1 -1
  12. package/build/{review-workflows-settings-list-view.3ee9190d.chunk.js → review-workflows-settings-list-view.f055e1be.chunk.js} +8 -8
  13. package/build/{runtime~main.a65ca6fb.js → runtime~main.58ec8df6.js} +1 -1
  14. package/build/{webhook-edit-page.a91f27a1.chunk.js → webhook-edit-page.6cb479ff.chunk.js} +2 -2
  15. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/ListView/ListView.js +1 -2
  16. package/ee/server/bootstrap.js +2 -0
  17. package/ee/server/services/auth.js +1 -1
  18. package/ee/server/services/index.js +1 -0
  19. package/ee/server/services/review-workflows/metrics/index.js +51 -0
  20. package/ee/server/services/review-workflows/metrics/weekly-metrics.js +76 -0
  21. package/ee/server/services/review-workflows/workflows/index.js +5 -0
  22. package/package.json +8 -8
  23. package/ee/server/services/review-workflows/metrics.js +0 -24
@@ -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
  );
@@ -98,10 +98,6 @@ const Register = ({ authType, fieldsToDisable, noSignin, onSubmit, schema }) =>
98
98
 
99
99
  if (!['password', 'confirmPassword'].includes(key) && typeof value === 'string') {
100
100
  normalizedvalue = normalizedvalue.trim();
101
-
102
- if (key === 'lastname') {
103
- normalizedvalue = normalizedvalue || null;
104
- }
105
101
  }
106
102
 
107
103
  acc[key] = normalizedvalue;
@@ -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
  };
@@ -678,6 +678,7 @@
678
678
  "content-manager.components.SettingsViewWrapper.pluginHeader.description.edit-settings": "Customize how the edit view will look like.",
679
679
  "content-manager.components.SettingsViewWrapper.pluginHeader.description.list-settings": "Define the settings of the list view.",
680
680
  "content-manager.components.SettingsViewWrapper.pluginHeader.title": "Configure the view — {name}",
681
+ "content-manager.bulk-publish.already-published": "Already Published",
681
682
  "content-manager.components.TableDelete.delete": "Delete all",
682
683
  "content-manager.components.TableDelete.deleteSelected": "Delete selected",
683
684
  "content-manager.components.TableDelete.label": "{number, plural, one {# entry} other {# entries}} selected",
@@ -1,4 +1,4 @@
1
- "use strict";(self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[801],{63546:function(K,T,n){n.r(T),n.d(T,{default:function(){return jt}});var e=n(32735),s=n(19565),b=n(33795),Z=n.n(b),y=n(20108),M=JSON.parse('{"i8":"4.12.0-beta.5"}'),S=n(2160),L=n(86209),P=n(74506),F=n(51968),D=n(15062),f=n(53038),Re=n(88311),ee=n.n(Re),Ae=n(75974),m=n(87933),te=n(71933),ne=n(67563),Le=n(50563),v=n(72850),V=n(41415),ae=n(35331),Oe=n(60216),r=n.n(Oe),B=n(67879),C=n(8471);const xe=(0,C.ZP)(m.k)`
1
+ "use strict";(self.webpackChunk_strapi_admin=self.webpackChunk_strapi_admin||[]).push([[801],{63546:function(K,T,n){n.r(T),n.d(T,{default:function(){return jt}});var e=n(32735),s=n(19565),b=n(33795),Z=n.n(b),y=n(20108),M={i8:"4.12.0"},S=n(2160),L=n(86209),P=n(74506),F=n(51968),D=n(15062),f=n(53038),Re=n(88311),ee=n.n(Re),Ae=n(75974),m=n(87933),te=n(71933),ne=n(67563),Le=n(50563),v=n(72850),V=n(41415),ae=n(35331),Oe=n(60216),r=n.n(Oe),B=n(67879),C=n(8471);const xe=(0,C.ZP)(m.k)`
2
2
  position: fixed;
3
3
  z-index: 4;
4
4
  inset: 0;