@strapi/admin 4.12.0-beta.1 → 4.12.0-beta.3

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 (123) hide show
  1. package/admin/src/content-manager/components/CollectionTypeFormWrapper/index.js +1 -3
  2. package/admin/src/content-manager/components/RelationInput/components/Option.js +6 -5
  3. package/admin/src/content-manager/components/SingleTypeFormWrapper/index.js +7 -7
  4. package/admin/src/content-manager/pages/EditSettingsView/components/DisplayedFields.js +23 -21
  5. package/admin/src/content-manager/pages/EditSettingsView/components/ModalForm.js +21 -23
  6. package/admin/src/content-manager/pages/ListSettingsView/components/SortDisplayedFields.js +24 -22
  7. package/admin/src/content-manager/pages/ListView/components/Body/index.js +191 -0
  8. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/ConfirmBulkActionDialog/index.js +164 -0
  9. package/admin/src/content-manager/pages/ListView/components/BulkActionButtons/SelectedEntriesModal/index.js +468 -0
  10. package/admin/src/content-manager/{components/DynamicTable/BulkActionsBar → pages/ListView/components/BulkActionButtons}/index.js +56 -132
  11. package/admin/src/content-manager/pages/ListView/components/CellContent/RelationMultiple/index.js +63 -69
  12. package/admin/src/content-manager/pages/ListView/components/CellContent/RepeatableComponent/index.js +28 -21
  13. package/admin/src/content-manager/pages/ListView/index.js +191 -132
  14. package/admin/src/layouts/UnauthenticatedLayout/LocaleToggle/index.js +7 -7
  15. package/admin/src/translations/ca.json +4 -4
  16. package/admin/src/translations/de.json +4 -4
  17. package/admin/src/translations/dk.json +2 -2
  18. package/admin/src/translations/en.json +23 -4
  19. package/admin/src/translations/es.json +4 -4
  20. package/admin/src/translations/eu.json +4 -4
  21. package/admin/src/translations/fr.json +2 -2
  22. package/admin/src/translations/gu.json +4 -4
  23. package/admin/src/translations/hi.json +4 -4
  24. package/admin/src/translations/hu.json +4 -4
  25. package/admin/src/translations/ja.json +2 -2
  26. package/admin/src/translations/ko.json +2 -2
  27. package/admin/src/translations/ml.json +4 -4
  28. package/admin/src/translations/nl.json +4 -4
  29. package/admin/src/translations/pl.json +4 -4
  30. package/admin/src/translations/pt-BR.json +4 -4
  31. package/admin/src/translations/ru.json +4 -4
  32. package/admin/src/translations/sa.json +4 -4
  33. package/admin/src/translations/sk.json +4 -4
  34. package/admin/src/translations/sv.json +4 -4
  35. package/admin/src/translations/tr.json +4 -4
  36. package/admin/src/translations/zh-Hans.json +4 -4
  37. package/admin/src/translations/zh.json +4 -4
  38. package/build/{2801.18ac397d.chunk.js → 2801.18f38baf.chunk.js} +1 -1
  39. package/build/{3483.e182b190.chunk.js → 3483.ddd2d6df.chunk.js} +1 -1
  40. package/build/{970.89601f27.chunk.js → 3739.63e352f1.chunk.js} +52 -20
  41. package/build/6158.c974fd83.chunk.js +1 -0
  42. package/build/6691.f880a0b6.chunk.js +105 -0
  43. package/build/8298.fd253c9f.chunk.js +117 -0
  44. package/build/{9932.b5a3bb3a.chunk.js → 9806.91360bb6.chunk.js} +47 -47
  45. package/build/{Admin-authenticatedApp.2ffa318a.chunk.js → Admin-authenticatedApp.36b3826c.chunk.js} +2 -2
  46. package/build/Admin_settingsPage.8c600d1a.chunk.js +111 -0
  47. package/build/{admin-app.088bcd33.chunk.js → admin-app.1c3f7fd6.chunk.js} +9 -9
  48. package/build/{ca-json.1fed5d8b.chunk.js → ca-json.a53c10b6.chunk.js} +1 -1
  49. package/build/content-manager.b8d593d4.chunk.js +1103 -0
  50. package/build/{content-type-builder-translation-ar-json.56d8fcf4.chunk.js → content-type-builder-translation-ar-json.3e808e2f.chunk.js} +1 -1
  51. package/build/{content-type-builder-translation-cs-json.a5b299ca.chunk.js → content-type-builder-translation-cs-json.1ef9e106.chunk.js} +1 -1
  52. package/build/{content-type-builder-translation-de-json.393a76c0.chunk.js → content-type-builder-translation-de-json.63fcff7b.chunk.js} +1 -1
  53. package/build/{content-type-builder-translation-dk-json.fbd39bb7.chunk.js → content-type-builder-translation-dk-json.fd626b67.chunk.js} +1 -1
  54. package/build/{content-type-builder-translation-en-json.38e20391.chunk.js → content-type-builder-translation-en-json.ed29ff4d.chunk.js} +1 -1
  55. package/build/{content-type-builder-translation-es-json.9288474b.chunk.js → content-type-builder-translation-es-json.a4a361a9.chunk.js} +1 -1
  56. package/build/{content-type-builder-translation-fr-json.d35e269c.chunk.js → content-type-builder-translation-fr-json.499c3a46.chunk.js} +1 -1
  57. package/build/{content-type-builder-translation-id-json.f0513929.chunk.js → content-type-builder-translation-id-json.65255f93.chunk.js} +1 -1
  58. package/build/{content-type-builder-translation-it-json.aaf16753.chunk.js → content-type-builder-translation-it-json.e268ab74.chunk.js} +1 -1
  59. package/build/{content-type-builder-translation-ko-json.8fe21a7f.chunk.js → content-type-builder-translation-ko-json.04cb309d.chunk.js} +1 -1
  60. package/build/{content-type-builder-translation-ms-json.3b5d2d3e.chunk.js → content-type-builder-translation-ms-json.f6b743b9.chunk.js} +1 -1
  61. package/build/{content-type-builder-translation-nl-json.225ef5d3.chunk.js → content-type-builder-translation-nl-json.997fe8cc.chunk.js} +1 -1
  62. package/build/{content-type-builder-translation-pl-json.92f36be2.chunk.js → content-type-builder-translation-pl-json.634f638b.chunk.js} +1 -1
  63. package/build/{content-type-builder-translation-pt-BR-json.3bd10f89.chunk.js → content-type-builder-translation-pt-BR-json.6a95dc71.chunk.js} +1 -1
  64. package/build/{content-type-builder-translation-ru-json.9bfe47ce.chunk.js → content-type-builder-translation-ru-json.3af65503.chunk.js} +1 -1
  65. package/build/{content-type-builder-translation-sk-json.d03cc18a.chunk.js → content-type-builder-translation-sk-json.c6078082.chunk.js} +1 -1
  66. package/build/{content-type-builder-translation-sv-json.d23dcd32.chunk.js → content-type-builder-translation-sv-json.a6df2462.chunk.js} +1 -1
  67. package/build/{content-type-builder-translation-th-json.7ad256e2.chunk.js → content-type-builder-translation-th-json.122277cc.chunk.js} +1 -1
  68. package/build/{content-type-builder-translation-tr-json.926f6191.chunk.js → content-type-builder-translation-tr-json.41f44f77.chunk.js} +1 -1
  69. package/build/{content-type-builder-translation-uk-json.7bf19546.chunk.js → content-type-builder-translation-uk-json.e1315acd.chunk.js} +1 -1
  70. package/build/{content-type-builder-translation-zh-Hans-json.415577fb.chunk.js → content-type-builder-translation-zh-Hans-json.6ff57db6.chunk.js} +1 -1
  71. package/build/{content-type-builder-translation-zh-json.958d90e1.chunk.js → content-type-builder-translation-zh-json.3532b962.chunk.js} +1 -1
  72. package/build/{content-type-builder.3963fb2d.chunk.js → content-type-builder.40534de5.chunk.js} +21 -17
  73. package/build/{de-json.fcac7381.chunk.js → de-json.b3be02c7.chunk.js} +1 -1
  74. package/build/{dk-json.e34cad0d.chunk.js → dk-json.842aa391.chunk.js} +1 -1
  75. package/build/{en-json.fb9f6ddd.chunk.js → en-json.4c733bd1.chunk.js} +1 -1
  76. package/build/{es-json.42096084.chunk.js → es-json.f57b5335.chunk.js} +1 -1
  77. package/build/{eu-json.fb17c8f9.chunk.js → eu-json.633025f0.chunk.js} +1 -1
  78. package/build/{fr-json.69789980.chunk.js → fr-json.aa8839d2.chunk.js} +1 -1
  79. package/build/{gu-json.4d667d0c.chunk.js → gu-json.5bd62812.chunk.js} +1 -1
  80. package/build/{hi-json.323be97d.chunk.js → hi-json.9104eb78.chunk.js} +1 -1
  81. package/build/{hu-json.fe71e6c8.chunk.js → hu-json.9f4aae42.chunk.js} +1 -1
  82. package/build/index.html +1 -1
  83. package/build/{ja-json.81b6d1e3.chunk.js → ja-json.91286391.chunk.js} +1 -1
  84. package/build/{ko-json.4539f4ba.chunk.js → ko-json.fcf3ec4b.chunk.js} +1 -1
  85. package/build/main.a12c4c0f.js +2856 -0
  86. package/build/{ml-json.8988e374.chunk.js → ml-json.557aa14c.chunk.js} +1 -1
  87. package/build/{nl-json.98345913.chunk.js → nl-json.b2b16eea.chunk.js} +1 -1
  88. package/build/{pl-json.59a5dab3.chunk.js → pl-json.f094a417.chunk.js} +1 -1
  89. package/build/{pt-BR-json.9410688b.chunk.js → pt-BR-json.dec7fb01.chunk.js} +1 -1
  90. package/build/review-workflows-settings-create-view.dfd87e1f.chunk.js +1 -0
  91. package/build/review-workflows-settings-edit-view.53c00afe.chunk.js +1 -0
  92. package/build/{review-workflows-settings-list-view.240cacdf.chunk.js → review-workflows-settings-list-view.a34be805.chunk.js} +5 -5
  93. package/build/{ru-json.678cd48b.chunk.js → ru-json.8193d8c4.chunk.js} +1 -1
  94. package/build/{runtime~main.44bf2a37.js → runtime~main.d197f488.js} +2 -2
  95. package/build/{sa-json.6359a11c.chunk.js → sa-json.a56836f1.chunk.js} +1 -1
  96. package/build/{sk-json.2374f129.chunk.js → sk-json.bf2f057a.chunk.js} +1 -1
  97. package/build/{sv-json.ae6e71ea.chunk.js → sv-json.fd0e86c6.chunk.js} +1 -1
  98. package/build/{tr-json.bac5dbd3.chunk.js → tr-json.56c32cf6.chunk.js} +1 -1
  99. package/build/upload.cbfeefa5.chunk.js +58 -0
  100. package/build/{zh-Hans-json.fada6f40.chunk.js → zh-Hans-json.36d81cdc.chunk.js} +1 -1
  101. package/build/{zh-json.3529f1e5.chunk.js → zh-json.1cc86ff0.chunk.js} +1 -1
  102. package/ee/admin/content-manager/pages/ListView/ReviewWorkflowsColumn/constants.js +2 -2
  103. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/components/ProtectedPage/ProtectedPage.js +1 -1
  104. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/CreateView/CreateView.js +34 -6
  105. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/pages/EditView/EditView.js +42 -11
  106. package/ee/admin/pages/SettingsPage/pages/ReviewWorkflows/utils/{getWorkflowValidationSchema.js → validateWorkflow.js} +33 -2
  107. package/ee/admin/pages/SettingsPage/pages/Users/ListPage/index.js +1 -1
  108. package/ee/server/constants/workflows.js +1 -0
  109. package/ee/server/services/review-workflows/validation.js +6 -0
  110. package/ee/server/validation/review-workflows.js +6 -2
  111. package/package.json +9 -9
  112. package/admin/src/content-manager/pages/ListView/components/TableRows/index.js +0 -300
  113. package/build/190.66d89241.chunk.js +0 -117
  114. package/build/6158.f9d82db9.chunk.js +0 -1
  115. package/build/6691.e6d5ac38.chunk.js +0 -105
  116. package/build/Admin_settingsPage.3ad19487.chunk.js +0 -79
  117. package/build/content-manager.9b569036.chunk.js +0 -1094
  118. package/build/main.98c989b0.js +0 -2908
  119. package/build/review-workflows-settings-create-view.60bc516c.chunk.js +0 -1
  120. package/build/review-workflows-settings-edit-view.898ea409.chunk.js +0 -1
  121. package/build/upload.8d01c525.chunk.js +0 -26
  122. /package/admin/src/content-manager/components/{DynamicTable → ListViewTable}/CellContent/PublicationState/PublicationState.js +0 -0
  123. /package/admin/src/content-manager/components/{DynamicTable → ListViewTable}/CellContent/PublicationState/index.js +0 -0
@@ -0,0 +1,468 @@
1
+ import React from 'react';
2
+
3
+ import {
4
+ Box,
5
+ Button,
6
+ Typography,
7
+ ModalLayout,
8
+ ModalHeader,
9
+ ModalBody,
10
+ ModalFooter,
11
+ Tr,
12
+ Td,
13
+ IconButton,
14
+ Flex,
15
+ Icon,
16
+ Tooltip,
17
+ Loader,
18
+ } from '@strapi/design-system';
19
+ import {
20
+ useTableContext,
21
+ Table,
22
+ getYupInnerErrors,
23
+ useFetchClient,
24
+ useQueryParams,
25
+ useNotification,
26
+ } from '@strapi/helper-plugin';
27
+ import { Pencil, CrossCircle, CheckCircle } from '@strapi/icons';
28
+ import PropTypes from 'prop-types';
29
+ import { useIntl } from 'react-intl';
30
+ import { useMutation, useQuery } from 'react-query';
31
+ import { useSelector } from 'react-redux';
32
+ import { Link, useHistory } from 'react-router-dom';
33
+ import styled from 'styled-components';
34
+
35
+ import formatAPIError from '../../../../../../utils/formatAPIErrors';
36
+ import { getTrad, createYupSchema } from '../../../../../utils';
37
+ import { listViewDomain } from '../../../selectors';
38
+ import { Body } from '../../Body';
39
+ import { ConfirmDialogPublishAll } from '../ConfirmBulkActionDialog';
40
+
41
+ const TypographyMaxWidth = styled(Typography)`
42
+ max-width: 300px;
43
+ `;
44
+
45
+ /* -------------------------------------------------------------------------------------------------
46
+ * EntryValidationText
47
+ * -----------------------------------------------------------------------------------------------*/
48
+
49
+ const EntryValidationText = ({ errors, isPublished }) => {
50
+ const { formatMessage } = useIntl();
51
+
52
+ if (errors) {
53
+ const errorMessages = Object.entries(errors)
54
+ .map(([key, value]) =>
55
+ formatMessage(
56
+ { id: `${value.id}.withField`, defaultMessage: value.defaultMessage },
57
+ { field: key }
58
+ )
59
+ )
60
+ .join(' ');
61
+
62
+ return (
63
+ <Flex gap={2}>
64
+ <Icon color="danger600" as={CrossCircle} />
65
+ <Tooltip description={errorMessages}>
66
+ <TypographyMaxWidth textColor="danger600" variant="omega" fontWeight="semiBold" ellipsis>
67
+ {errorMessages}
68
+ </TypographyMaxWidth>
69
+ </Tooltip>
70
+ </Flex>
71
+ );
72
+ }
73
+
74
+ if (isPublished) {
75
+ return (
76
+ <Flex gap={2}>
77
+ <Icon color="success600" as={CheckCircle} />
78
+ <Typography textColor="success600" fontWeight="bold">
79
+ {formatMessage({
80
+ id: 'app.utils.published',
81
+ defaultMessage: 'Published',
82
+ })}
83
+ </Typography>
84
+ </Flex>
85
+ );
86
+ }
87
+
88
+ return (
89
+ <Flex gap={2}>
90
+ <Icon color="success600" as={CheckCircle} />
91
+ <Typography>
92
+ {formatMessage({
93
+ id: 'app.utils.ready-to-publish',
94
+ defaultMessage: 'Ready to publish',
95
+ })}
96
+ </Typography>
97
+ </Flex>
98
+ );
99
+ };
100
+
101
+ EntryValidationText.defaultProps = {
102
+ errors: null,
103
+ isPublished: false,
104
+ };
105
+
106
+ EntryValidationText.propTypes = {
107
+ errors: PropTypes.shape({
108
+ [PropTypes.string]: PropTypes.shape({
109
+ id: PropTypes.string,
110
+ defaultMessage: PropTypes.string,
111
+ }),
112
+ }),
113
+ isPublished: PropTypes.bool,
114
+ };
115
+
116
+ /* -------------------------------------------------------------------------------------------------
117
+ * SelectedEntriesTableContent
118
+ * -----------------------------------------------------------------------------------------------*/
119
+
120
+ const SelectedEntriesTableContent = ({ isPublishing, rowsToDisplay, entriesToPublish }) => {
121
+ const {
122
+ location: { pathname },
123
+ } = useHistory();
124
+ const { formatMessage } = useIntl();
125
+
126
+ // Get main field from list view layout
127
+ const listViewStore = useSelector(listViewDomain());
128
+ const { mainField } = listViewStore.contentType.settings;
129
+ const shouldDisplayMainField = mainField != null && mainField !== 'id';
130
+
131
+ const getItemLineText = (count) =>
132
+ formatMessage(
133
+ {
134
+ id: 'content-manager.components.ListViewTable.row-line',
135
+ defaultMessage: 'item line {number}',
136
+ },
137
+ { number: count + 1 }
138
+ );
139
+
140
+ return (
141
+ <Table.Content>
142
+ <Table.Head>
143
+ <Table.HeaderCheckboxCell />
144
+ <Table.HeaderCell fieldSchemaType="number" label="id" name="id" />
145
+ {shouldDisplayMainField && (
146
+ <Table.HeaderCell fieldSchemaType="string" label="name" name="name" />
147
+ )}
148
+ <Table.HeaderCell fieldSchemaType="string" label="status" name="status" />
149
+ </Table.Head>
150
+ <Table.LoadingBody />
151
+ <Table.Body>
152
+ {rowsToDisplay.map(({ entity, errors }, index) => (
153
+ <Tr key={entity.id}>
154
+ <Body.CheckboxDataCell rowId={entity.id} index={index} />
155
+ <Td>
156
+ <Typography>{entity.id}</Typography>
157
+ </Td>
158
+ {shouldDisplayMainField && (
159
+ <Td>
160
+ <Typography>{entity[mainField]}</Typography>
161
+ </Td>
162
+ )}
163
+ <Td>
164
+ {isPublishing && entriesToPublish.includes(entity.id) ? (
165
+ <Flex gap={2}>
166
+ <Typography>
167
+ {formatMessage({
168
+ id: 'content-manager.success.record.publishing',
169
+ defaultMessage: 'Publishing...',
170
+ })}
171
+ </Typography>
172
+ <Loader small />
173
+ </Flex>
174
+ ) : (
175
+ <EntryValidationText errors={errors} isPublished={entity.publishedAt !== null} />
176
+ )}
177
+ </Td>
178
+ <Td>
179
+ <IconButton
180
+ forwardedAs={Link}
181
+ to={{
182
+ pathname: `${pathname}/${entity.id}`,
183
+ state: { from: pathname },
184
+ }}
185
+ label={formatMessage(
186
+ { id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
187
+ { target: getItemLineText(index) }
188
+ )}
189
+ noBorder
190
+ target="_blank"
191
+ >
192
+ <Pencil />
193
+ </IconButton>
194
+ </Td>
195
+ </Tr>
196
+ ))}
197
+ </Table.Body>
198
+ </Table.Content>
199
+ );
200
+ };
201
+
202
+ SelectedEntriesTableContent.defaultProps = {
203
+ isPublishing: false,
204
+ rowsToDisplay: [],
205
+ entriesToPublish: [],
206
+ };
207
+
208
+ SelectedEntriesTableContent.propTypes = {
209
+ isPublishing: PropTypes.bool,
210
+ rowsToDisplay: PropTypes.arrayOf(PropTypes.object),
211
+ entriesToPublish: PropTypes.arrayOf(PropTypes.number),
212
+ };
213
+
214
+ /* -------------------------------------------------------------------------------------------------
215
+ * BoldChunk
216
+ * -----------------------------------------------------------------------------------------------*/
217
+
218
+ const BoldChunk = (chunks) => <Typography fontWeight="bold">{chunks}</Typography>;
219
+
220
+ /* -------------------------------------------------------------------------------------------------
221
+ * SelectedEntriesModalContent
222
+ * -----------------------------------------------------------------------------------------------*/
223
+
224
+ const SelectedEntriesModalContent = ({ toggleModal, refetchModalData, setEntriesToFetch }) => {
225
+ const { formatMessage } = useIntl();
226
+ const { selectedEntries, rows, onSelectRow, isLoading, isFetching } = useTableContext();
227
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
228
+ const [rowsToDisplay, setRowsToDisplay] = React.useState([]);
229
+ const [publishedCount, setPublishedCount] = React.useState(0);
230
+
231
+ const entriesToPublish = rows
232
+ .filter(({ entity, errors }) => selectedEntries.includes(entity.id) && !errors)
233
+ .map(({ entity }) => entity.id);
234
+
235
+ const { post } = useFetchClient();
236
+ const toggleNotification = useNotification();
237
+ const { contentType } = useSelector(listViewDomain());
238
+
239
+ const selectedEntriesWithErrorsCount = rowsToDisplay.filter(
240
+ ({ entity, errors }) => selectedEntries.includes(entity.id) && errors
241
+ ).length;
242
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount;
243
+
244
+ const bulkPublishMutation = useMutation(
245
+ (data) =>
246
+ post(`/content-manager/collection-types/${contentType.uid}/actions/bulkPublish`, data),
247
+ {
248
+ onSuccess() {
249
+ const update = rowsToDisplay.filter((row) => {
250
+ if (entriesToPublish.includes(row.entity.id)) {
251
+ // Deselect the entries that have been published from the modal table
252
+ onSelectRow({ name: row.entity.id, value: false });
253
+ }
254
+
255
+ // Remove the entries that have been published from the table
256
+ return !entriesToPublish.includes(row.entity.id);
257
+ });
258
+
259
+ setRowsToDisplay(update);
260
+ // Set the parent's entries to fetch when clicking refresh
261
+ setEntriesToFetch(update.map(({ entity }) => entity.id));
262
+
263
+ if (update.length === 0) {
264
+ toggleModal();
265
+ }
266
+
267
+ toggleNotification({
268
+ type: 'success',
269
+ message: { id: 'content-manager.success.record.publish', defaultMessage: 'Published' },
270
+ });
271
+ },
272
+ onError(error) {
273
+ toggleNotification({
274
+ type: 'warning',
275
+ message: formatAPIError(error),
276
+ });
277
+ },
278
+ }
279
+ );
280
+
281
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
282
+
283
+ const handleConfirmBulkPublish = async () => {
284
+ toggleDialog();
285
+ const { data } = await bulkPublishMutation.mutateAsync({ ids: entriesToPublish });
286
+ setPublishedCount(data.count);
287
+ };
288
+
289
+ const getFormattedCountMessage = () => {
290
+ if (publishedCount) {
291
+ return formatMessage(
292
+ {
293
+ id: getTrad('containers.ListPage.selectedEntriesModal.publishedCount'),
294
+ defaultMessage:
295
+ '<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action.',
296
+ },
297
+ {
298
+ publishedCount,
299
+ withErrorsCount: selectedEntriesWithErrorsCount,
300
+ b: BoldChunk,
301
+ }
302
+ );
303
+ }
304
+
305
+ return formatMessage(
306
+ {
307
+ id: getTrad('containers.ListPage.selectedEntriesModal.selectedCount'),
308
+ defaultMessage:
309
+ '<b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action.',
310
+ },
311
+ {
312
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
313
+ withErrorsCount: selectedEntriesWithErrorsCount,
314
+ b: BoldChunk,
315
+ }
316
+ );
317
+ };
318
+
319
+ React.useEffect(() => {
320
+ // When the api responds with data
321
+ if (rows.length > 0) {
322
+ // Update the rows to display
323
+ setRowsToDisplay(rows);
324
+ }
325
+ }, [rows]);
326
+
327
+ return (
328
+ <ModalLayout onClose={toggleModal} labelledBy="title">
329
+ <ModalHeader>
330
+ <Typography fontWeight="bold" textColor="neutral800" as="h2" id="title">
331
+ {formatMessage({
332
+ id: getTrad('containers.ListPage.selectedEntriesModal.title'),
333
+ defaultMessage: 'Publish entries',
334
+ })}
335
+ </Typography>
336
+ </ModalHeader>
337
+ <ModalBody>
338
+ <Typography>{getFormattedCountMessage()}</Typography>
339
+ <Box marginTop={5}>
340
+ <SelectedEntriesTableContent
341
+ isPublishing={bulkPublishMutation.isLoading}
342
+ rowsToDisplay={rowsToDisplay}
343
+ entriesToPublish={entriesToPublish}
344
+ />
345
+ </Box>
346
+ </ModalBody>
347
+ <ModalFooter
348
+ startActions={
349
+ <Button onClick={toggleModal} variant="tertiary">
350
+ {formatMessage({
351
+ id: 'app.components.Button.cancel',
352
+ defaultMessage: 'Cancel',
353
+ })}
354
+ </Button>
355
+ }
356
+ endActions={
357
+ <Flex gap={2}>
358
+ <Button onClick={refetchModalData} variant="tertiary" loading={isFetching}>
359
+ {formatMessage({ id: 'app.utils.refresh', defaultMessage: 'Refresh' })}
360
+ </Button>
361
+ <Button
362
+ onClick={toggleDialog}
363
+ disabled={
364
+ selectedEntries.length === 0 ||
365
+ selectedEntries.length === selectedEntriesWithErrorsCount ||
366
+ isLoading
367
+ }
368
+ loading={bulkPublishMutation.isLoading}
369
+ >
370
+ {formatMessage({ id: 'app.utils.publish', defaultMessage: 'Publish' })}
371
+ </Button>
372
+ </Flex>
373
+ }
374
+ />
375
+ <ConfirmDialogPublishAll
376
+ isOpen={isDialogOpen}
377
+ onToggleDialog={toggleDialog}
378
+ isConfirmButtonLoading={bulkPublishMutation.isLoading}
379
+ onConfirm={handleConfirmBulkPublish}
380
+ />
381
+ </ModalLayout>
382
+ );
383
+ };
384
+
385
+ SelectedEntriesModalContent.propTypes = {
386
+ toggleModal: PropTypes.func.isRequired,
387
+ refetchModalData: PropTypes.func.isRequired,
388
+ setEntriesToFetch: PropTypes.func.isRequired,
389
+ };
390
+
391
+ /* -------------------------------------------------------------------------------------------------
392
+ * SelectedEntriesModal
393
+ * -----------------------------------------------------------------------------------------------*/
394
+
395
+ const SelectedEntriesModal = ({ onToggle }) => {
396
+ const { selectedEntries: selectedListViewEntries } = useTableContext();
397
+ const { contentType, components } = useSelector(listViewDomain());
398
+ // The child table will update this value based on the entries that were published
399
+ const [entriesToFetch, setEntriesToFetch] = React.useState(selectedListViewEntries);
400
+
401
+ // We want to keep the selected entries order same as the list view
402
+ const [
403
+ {
404
+ query: { sort },
405
+ },
406
+ ] = useQueryParams();
407
+ const queryParams = {
408
+ sort,
409
+ filters: {
410
+ id: {
411
+ $in: entriesToFetch,
412
+ },
413
+ },
414
+ };
415
+
416
+ const { get } = useFetchClient();
417
+
418
+ const { data, isLoading, isFetching, refetch } = useQuery(
419
+ ['entries', contentType.uid, queryParams],
420
+ async () => {
421
+ const { data } = await get(`content-manager/collection-types/${contentType.uid}`, {
422
+ params: queryParams,
423
+ });
424
+
425
+ if (data.results) {
426
+ const schema = createYupSchema(contentType, { components }, { isDraft: false });
427
+ const rows = data.results.map((entry) => {
428
+ try {
429
+ schema.validateSync(entry, { abortEarly: false });
430
+
431
+ return { entity: entry };
432
+ } catch (e) {
433
+ return {
434
+ entity: entry,
435
+ errors: getYupInnerErrors(e),
436
+ };
437
+ }
438
+ });
439
+
440
+ return rows;
441
+ }
442
+
443
+ return [];
444
+ }
445
+ );
446
+
447
+ return (
448
+ <Table.Root
449
+ rows={data}
450
+ defaultSelectedEntries={selectedListViewEntries}
451
+ colCount={4}
452
+ isLoading={isLoading}
453
+ isFetching={isFetching}
454
+ >
455
+ <SelectedEntriesModalContent
456
+ setEntriesToFetch={setEntriesToFetch}
457
+ toggleModal={onToggle}
458
+ refetchModalData={refetch}
459
+ />
460
+ </Table.Root>
461
+ );
462
+ };
463
+
464
+ SelectedEntriesModal.propTypes = {
465
+ onToggle: PropTypes.func.isRequired,
466
+ };
467
+
468
+ export default SelectedEntriesModal;