@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
@@ -301,9 +301,7 @@ const CollectionTypeFormWrapper = ({ allLayoutData, children, slug, id, origin }
301
301
  try {
302
302
  trackUsageRef.current('willCheckDraftRelations');
303
303
 
304
- const endPoint = getRequestUrl(
305
- `collection-types/${slug}/${id}/actions/numberOfDraftRelations`
306
- );
304
+ const endPoint = getRequestUrl(`collection-types/${slug}/${id}/actions/countDraftRelations`);
307
305
  dispatch(setStatus('draft-relation-check-pending'));
308
306
 
309
307
  const numberOfDraftRelations = await fetchClient.get(endPoint);
@@ -20,6 +20,7 @@ const StyledBullet = styled.div`
20
20
 
21
21
  export const Option = ({ publicationState, mainField, id }) => {
22
22
  const { formatMessage } = useIntl();
23
+ const stringifiedDisplayValue = (mainField ?? id).toString();
23
24
 
24
25
  if (publicationState) {
25
26
  const isDraft = publicationState === 'draft';
@@ -34,18 +35,18 @@ export const Option = ({ publicationState, mainField, id }) => {
34
35
  const title = isDraft ? formatMessage(draftMessage) : formatMessage(publishedMessage);
35
36
 
36
37
  return (
37
- <ComboboxOption value={id} textValue={mainField ?? id}>
38
+ <ComboboxOption value={id} textValue={stringifiedDisplayValue}>
38
39
  <Flex>
39
40
  <StyledBullet title={title} isDraft={isDraft} />
40
- <Typography ellipsis>{mainField ?? id}</Typography>
41
+ <Typography ellipsis>{stringifiedDisplayValue}</Typography>
41
42
  </Flex>
42
43
  </ComboboxOption>
43
44
  );
44
45
  }
45
46
 
46
47
  return (
47
- <ComboboxOption value={id} textValue={mainField ?? id}>
48
- {mainField ?? id}
48
+ <ComboboxOption value={id} textValue={stringifiedDisplayValue}>
49
+ {stringifiedDisplayValue}
49
50
  </ComboboxOption>
50
51
  );
51
52
  };
@@ -57,6 +58,6 @@ Option.defaultProps = {
57
58
 
58
59
  Option.propTypes = {
59
60
  id: PropTypes.number.isRequired,
60
- mainField: PropTypes.string,
61
+ mainField: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
61
62
  publicationState: PropTypes.oneOfType([PropTypes.string, PropTypes.bool]),
62
63
  };
@@ -159,7 +159,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
159
159
  trackUsageRef.current('willDeleteEntry', trackerProperty);
160
160
 
161
161
  const { data } = await del(getRequestUrl(slug), {
162
- params: query,
162
+ params,
163
163
  });
164
164
 
165
165
  toggleNotification({
@@ -181,7 +181,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
181
181
  return Promise.reject(err);
182
182
  }
183
183
  },
184
- [del, slug, displayErrors, toggleNotification, query, dispatch, rawQuery]
184
+ [del, slug, params, toggleNotification, dispatch, rawQuery, displayErrors]
185
185
  );
186
186
 
187
187
  const onPost = useCallback(
@@ -237,7 +237,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
237
237
  try {
238
238
  trackUsageRef.current('willCheckDraftRelations');
239
239
 
240
- const endPoint = getRequestUrl(`${slug}/actions/numberOfDraftRelations`);
240
+ const endPoint = getRequestUrl(`${slug}/actions/countDraftRelations`);
241
241
  dispatch(setStatus('draft-relation-check-pending'));
242
242
 
243
243
  const numberOfDraftRelations = await fetchClient.get(endPoint);
@@ -265,7 +265,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
265
265
  endPoint,
266
266
  {},
267
267
  {
268
- params: query,
268
+ params,
269
269
  }
270
270
  );
271
271
 
@@ -287,7 +287,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
287
287
 
288
288
  return Promise.reject(err);
289
289
  }
290
- }, [post, cleanReceivedData, displayErrors, slug, query, dispatch, toggleNotification]);
290
+ }, [slug, dispatch, post, params, toggleNotification, cleanReceivedData, displayErrors]);
291
291
 
292
292
  const onPut = useCallback(
293
293
  async (body, trackerProperty) => {
@@ -341,7 +341,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
341
341
  endPoint,
342
342
  {},
343
343
  {
344
- params: query,
344
+ params,
345
345
  }
346
346
  );
347
347
 
@@ -358,7 +358,7 @@ const SingleTypeFormWrapper = ({ allLayoutData, children, slug }) => {
358
358
  dispatch(setStatus('resolved'));
359
359
  displayErrors(err);
360
360
  }
361
- }, [post, cleanReceivedData, toggleNotification, displayErrors, slug, dispatch, query]);
361
+ }, [slug, dispatch, post, params, toggleNotification, cleanReceivedData, displayErrors]);
362
362
 
363
363
  return children({
364
364
  componentsDataStructure,
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
 
3
- import { Box, Button, Flex, MenuItem, SimpleMenu, Typography } from '@strapi/design-system';
3
+ import { Box, Flex, Typography } from '@strapi/design-system';
4
+ import { Menu } from '@strapi/design-system/v2';
4
5
  import { Plus } from '@strapi/icons';
5
6
  import PropTypes from 'prop-types';
6
7
  import { useIntl } from 'react-intl';
@@ -41,26 +42,27 @@ const DisplayedFields = ({ editLayout, fields, onRemoveField, onAddField }) => {
41
42
  {editLayout.map((row, index) => (
42
43
  <RowsLayout key={row.rowId} row={row} rowIndex={index} onRemoveField={onRemoveField} />
43
44
  ))}
44
- <SimpleMenu
45
- id="label"
46
- label={formatMessage({
47
- id: getTrad('containers.SettingPage.add.field'),
48
- defaultMessage: 'Insert another field',
49
- })}
50
- as={Button}
51
- data-testid="add-field"
52
- fullWidth
53
- startIcon={<Plus />}
54
- endIcon={null}
55
- variant="secondary"
56
- disabled={fields.length === 0}
57
- >
58
- {fields.map((field) => (
59
- <MenuItem key={field} onClick={() => onAddField(field)}>
60
- {field}
61
- </MenuItem>
62
- ))}
63
- </SimpleMenu>
45
+ <Menu.Root>
46
+ <Menu.Trigger
47
+ startIcon={<Plus />}
48
+ endIcon={null}
49
+ disabled={fields.length === 0}
50
+ fullWidth
51
+ variant="secondary"
52
+ >
53
+ {formatMessage({
54
+ id: getTrad('containers.SettingPage.add.field'),
55
+ defaultMessage: 'Insert another field',
56
+ })}
57
+ </Menu.Trigger>
58
+ <Menu.Content>
59
+ {fields.map((field) => (
60
+ <Menu.Item key={field} onSelect={() => onAddField(field)}>
61
+ {field}
62
+ </Menu.Item>
63
+ ))}
64
+ </Menu.Content>
65
+ </Menu.Root>
64
66
  </Flex>
65
67
  </Box>
66
68
  </Flex>
@@ -105,32 +105,30 @@ const ModalForm = ({ onMetaChange, onSizeChange }) => {
105
105
  const { type, customField } = attributes[selectedField];
106
106
  const { isResizable } = fieldSizes[customField] ?? fieldSizes[type];
107
107
 
108
- const sizeField = (
109
- <GridItem col={6} key="size">
110
- <Select
111
- value={fieldForm?.size}
112
- name="size"
113
- onChange={(value) => {
114
- onSizeChange({ name: selectedField, value });
115
- }}
116
- label={formatMessage({
117
- id: getTrad('containers.SettingPage.editSettings.size.label'),
118
- defaultMessage: 'Size',
119
- })}
120
- >
121
- {FIELD_SIZES.map(([value, label]) => (
122
- <Option key={value} value={value}>
123
- {label}
124
- </Option>
125
- ))}
126
- </Select>
127
- </GridItem>
128
- );
129
-
130
108
  return (
131
109
  <>
132
110
  {metaFields}
133
- {isResizable && sizeField}
111
+ {isResizable && (
112
+ <GridItem col={6} key="size">
113
+ <Select
114
+ value={fieldForm?.size}
115
+ name="size"
116
+ onChange={(value) => {
117
+ onSizeChange({ name: selectedField, value });
118
+ }}
119
+ label={formatMessage({
120
+ id: getTrad('containers.SettingPage.editSettings.size.label'),
121
+ defaultMessage: 'Size',
122
+ })}
123
+ >
124
+ {FIELD_SIZES.map(([value, label]) => (
125
+ <Option key={value} value={value}>
126
+ {label}
127
+ </Option>
128
+ ))}
129
+ </Select>
130
+ </GridItem>
131
+ )}
134
132
  </>
135
133
  );
136
134
  };
@@ -1,6 +1,7 @@
1
1
  import React, { useEffect, useRef, useState } from 'react';
2
2
 
3
- import { Box, Flex, IconButton, MenuItem, SimpleMenu, Typography } from '@strapi/design-system';
3
+ import { Box, Flex, VisuallyHidden, Typography } from '@strapi/design-system';
4
+ import { Menu } from '@strapi/design-system/v2';
4
5
  import { Plus } from '@strapi/icons';
5
6
  import { PropTypes } from 'prop-types';
6
7
  import { useIntl } from 'react-intl';
@@ -10,19 +11,12 @@ import { getTrad } from '../../../utils';
10
11
 
11
12
  import DraggableCard from './DraggableCard';
12
13
 
13
- const FlexWrapper = styled(Box)`
14
+ const ScrollableContainer = styled(Box)`
14
15
  flex: ${({ size }) => size};
15
- `;
16
-
17
- const ScrollableContainer = styled(FlexWrapper)`
18
16
  overflow-x: scroll;
19
17
  overflow-y: hidden;
20
18
  `;
21
19
 
22
- const SelectContainer = styled(FlexWrapper)`
23
- max-width: ${32 / 16}rem;
24
- `;
25
-
26
20
  const SortDisplayedFields = ({
27
21
  displayedFields,
28
22
  listRemainingFields,
@@ -89,24 +83,32 @@ const SortDisplayedFields = ({
89
83
  ))}
90
84
  </Flex>
91
85
  </ScrollableContainer>
92
- <SelectContainer size="auto" paddingBottom={4}>
93
- <SimpleMenu
94
- label={formatMessage({
95
- id: getTrad('components.FieldSelect.label'),
96
- defaultMessage: 'Add a field',
97
- })}
98
- as={IconButton}
99
- icon={<Plus />}
86
+ <Menu.Root>
87
+ <Menu.Trigger
88
+ paddingLeft={2}
89
+ paddingRight={2}
90
+ justifyContent="center"
91
+ endIcon={null}
100
92
  disabled={listRemainingFields.length <= 0}
101
- data-testid="add-field"
93
+ marginBottom={4}
94
+ variant="tertiary"
102
95
  >
96
+ <VisuallyHidden as="span">
97
+ {formatMessage({
98
+ id: getTrad('components.FieldSelect.label'),
99
+ defaultMessage: 'Add a field',
100
+ })}
101
+ </VisuallyHidden>
102
+ <Plus aria-hidden focusable={false} style={{ position: 'relative', top: 2 }} />
103
+ </Menu.Trigger>
104
+ <Menu.Content>
103
105
  {listRemainingFields.map((field) => (
104
- <MenuItem key={field} onClick={() => handleAddField(field)}>
106
+ <Menu.Item key={field} onSelect={() => handleAddField(field)}>
105
107
  {metadatas[field].list.label || field}
106
- </MenuItem>
108
+ </Menu.Item>
107
109
  ))}
108
- </SimpleMenu>
109
- </SelectContainer>
110
+ </Menu.Content>
111
+ </Menu.Root>
110
112
  </Flex>
111
113
  </>
112
114
  );
@@ -0,0 +1,191 @@
1
+ import React from 'react';
2
+
3
+ import { BaseCheckbox, IconButton, Td, Flex } from '@strapi/design-system';
4
+ import { useTracking, useTableContext, Table } from '@strapi/helper-plugin';
5
+ import { Trash, Duplicate, Pencil } from '@strapi/icons';
6
+ import PropTypes from 'prop-types';
7
+ import { useIntl } from 'react-intl';
8
+ import { Link, useHistory } from 'react-router-dom';
9
+
10
+ import { usePluginsQueryParams } from '../../../../hooks';
11
+ import { ConfirmDialogDelete } from '../ConfirmDialogDelete';
12
+
13
+ const stopPropagation = (e) => e.stopPropagation();
14
+
15
+ /* -------------------------------------------------------------------------------------------------
16
+ * CheckboxDataCell
17
+ * -----------------------------------------------------------------------------------------------*/
18
+
19
+ const CheckboxDataCell = ({ rowId, index }) => {
20
+ const { selectedEntries, onSelectRow } = useTableContext();
21
+ const { formatMessage } = useIntl();
22
+ const isChecked = selectedEntries.findIndex((id) => id === rowId) !== -1;
23
+ const ariaLabel = formatMessage(
24
+ {
25
+ id: 'app.component.table.select.one-entry',
26
+ defaultMessage: `Select {target}`,
27
+ },
28
+ { target: index + 1 }
29
+ );
30
+
31
+ return (
32
+ <Td onClick={stopPropagation}>
33
+ <BaseCheckbox
34
+ aria-label={ariaLabel}
35
+ checked={isChecked}
36
+ onChange={() => {
37
+ onSelectRow({ name: rowId, value: !isChecked });
38
+ }}
39
+ />
40
+ </Td>
41
+ );
42
+ };
43
+
44
+ CheckboxDataCell.propTypes = {
45
+ rowId: PropTypes.number.isRequired,
46
+ index: PropTypes.number.isRequired,
47
+ };
48
+
49
+ /* -------------------------------------------------------------------------------------------------
50
+ * EntityActionsDataCell
51
+ * -----------------------------------------------------------------------------------------------*/
52
+
53
+ const EntityActionsDataCell = ({
54
+ rowId,
55
+ index,
56
+ canCreate,
57
+ canDelete,
58
+ setIsConfirmDeleteRowOpen,
59
+ handleCloneClick,
60
+ }) => {
61
+ const { formatMessage } = useIntl();
62
+ const { trackUsage } = useTracking();
63
+ const { setSelectedEntries } = useTableContext();
64
+ const pluginsQueryParams = usePluginsQueryParams();
65
+ const {
66
+ location: { pathname },
67
+ } = useHistory();
68
+
69
+ const itemLineText = formatMessage(
70
+ {
71
+ id: 'content-manager.components.ListViewTable.row-line',
72
+ defaultMessage: 'item line {number}',
73
+ },
74
+ { number: index + 1 }
75
+ );
76
+
77
+ return (
78
+ <Td>
79
+ <Flex gap={1} justifyContent="end" onClick={stopPropagation}>
80
+ <IconButton
81
+ forwardedAs={Link}
82
+ onClick={() => {
83
+ trackUsage('willEditEntryFromButton');
84
+ }}
85
+ to={{
86
+ pathname: `${pathname}/${rowId}`,
87
+ state: { from: pathname },
88
+ search: pluginsQueryParams,
89
+ }}
90
+ label={formatMessage(
91
+ { id: 'app.component.table.edit', defaultMessage: 'Edit {target}' },
92
+ { target: itemLineText }
93
+ )}
94
+ noBorder
95
+ >
96
+ <Pencil />
97
+ </IconButton>
98
+
99
+ {canCreate && (
100
+ <IconButton
101
+ onClick={handleCloneClick(rowId)}
102
+ label={formatMessage(
103
+ {
104
+ id: 'app.component.table.duplicate',
105
+ defaultMessage: 'Duplicate {target}',
106
+ },
107
+ { target: itemLineText }
108
+ )}
109
+ noBorder
110
+ >
111
+ <Duplicate />
112
+ </IconButton>
113
+ )}
114
+
115
+ {canDelete && (
116
+ <IconButton
117
+ onClick={() => {
118
+ trackUsage('willDeleteEntryFromList');
119
+ setSelectedEntries([rowId]);
120
+ setIsConfirmDeleteRowOpen(true);
121
+ }}
122
+ label={formatMessage(
123
+ { id: 'global.delete-target', defaultMessage: 'Delete {target}' },
124
+ { target: itemLineText }
125
+ )}
126
+ noBorder
127
+ >
128
+ <Trash />
129
+ </IconButton>
130
+ )}
131
+ </Flex>
132
+ </Td>
133
+ );
134
+ };
135
+
136
+ EntityActionsDataCell.defaultProps = {
137
+ canCreate: false,
138
+ canDelete: false,
139
+ };
140
+
141
+ EntityActionsDataCell.propTypes = {
142
+ rowId: PropTypes.number.isRequired,
143
+ index: PropTypes.number.isRequired,
144
+ setIsConfirmDeleteRowOpen: PropTypes.func.isRequired,
145
+ handleCloneClick: PropTypes.func.isRequired,
146
+ canCreate: PropTypes.bool,
147
+ canDelete: PropTypes.bool,
148
+ };
149
+
150
+ /* -------------------------------------------------------------------------------------------------
151
+ * Root
152
+ * -----------------------------------------------------------------------------------------------*/
153
+
154
+ const Root = ({ children, onConfirmDelete, isConfirmDeleteRowOpen, setIsConfirmDeleteRowOpen }) => {
155
+ const [isLoading, setIsLoading] = React.useState(false);
156
+ const { selectedEntries, setSelectedEntries } = useTableContext();
157
+
158
+ const handleConfirmDelete = async () => {
159
+ try {
160
+ setIsLoading(true);
161
+ await onConfirmDelete(selectedEntries[0]);
162
+ setIsConfirmDeleteRowOpen(false);
163
+ setIsLoading(false);
164
+ setSelectedEntries([]);
165
+ } catch (error) {
166
+ setIsLoading(false);
167
+ setIsConfirmDeleteRowOpen(false);
168
+ }
169
+ };
170
+
171
+ return (
172
+ <Table.Body>
173
+ {children}
174
+ <ConfirmDialogDelete
175
+ isConfirmButtonLoading={isLoading}
176
+ onConfirm={handleConfirmDelete}
177
+ onToggleDialog={() => setIsConfirmDeleteRowOpen(!isConfirmDeleteRowOpen)}
178
+ isOpen={isConfirmDeleteRowOpen}
179
+ />
180
+ </Table.Body>
181
+ );
182
+ };
183
+
184
+ Root.propTypes = {
185
+ children: PropTypes.node.isRequired,
186
+ onConfirmDelete: PropTypes.func.isRequired,
187
+ isConfirmDeleteRowOpen: PropTypes.bool.isRequired,
188
+ setIsConfirmDeleteRowOpen: PropTypes.func.isRequired,
189
+ };
190
+
191
+ export const Body = { CheckboxDataCell, EntityActionsDataCell, Root };
@@ -0,0 +1,164 @@
1
+ import * as React from 'react';
2
+
3
+ import { Button, Flex, Dialog, DialogBody, DialogFooter, Typography } from '@strapi/design-system';
4
+ import {
5
+ useTableContext,
6
+ useFetchClient,
7
+ useNotification,
8
+ useAPIErrorHandler,
9
+ } from '@strapi/helper-plugin';
10
+ import { Check, ExclamationMarkCircle } from '@strapi/icons';
11
+ import PropTypes from 'prop-types';
12
+ import { useIntl } from 'react-intl';
13
+ import { useQuery } from 'react-query';
14
+ import { useSelector } from 'react-redux';
15
+
16
+ import InjectionZoneList from '../../../../../components/InjectionZoneList';
17
+ import { getTrad } from '../../../../../utils';
18
+ import { listViewDomain } from '../../../selectors';
19
+
20
+ const ConfirmBulkActionDialog = ({ onToggleDialog, isOpen, dialogBody, endAction }) => {
21
+ const { formatMessage } = useIntl();
22
+
23
+ return (
24
+ <Dialog
25
+ onClose={onToggleDialog}
26
+ title={formatMessage({
27
+ id: 'app.components.ConfirmDialog.title',
28
+ defaultMessage: 'Confirmation',
29
+ })}
30
+ isOpen={isOpen}
31
+ >
32
+ <DialogBody icon={<ExclamationMarkCircle />}>
33
+ <Flex direction="column" alignItems="stretch" gap={2}>
34
+ {dialogBody}
35
+ </Flex>
36
+ </DialogBody>
37
+ <DialogFooter
38
+ startAction={
39
+ <Button onClick={onToggleDialog} variant="tertiary">
40
+ {formatMessage({
41
+ id: 'app.components.Button.cancel',
42
+ defaultMessage: 'Cancel',
43
+ })}
44
+ </Button>
45
+ }
46
+ endAction={endAction}
47
+ />
48
+ </Dialog>
49
+ );
50
+ };
51
+
52
+ ConfirmBulkActionDialog.propTypes = {
53
+ isOpen: PropTypes.bool.isRequired,
54
+ onToggleDialog: PropTypes.func.isRequired,
55
+ dialogBody: PropTypes.node.isRequired,
56
+ endAction: PropTypes.node.isRequired,
57
+ };
58
+
59
+ export const confirmDialogsPropTypes = {
60
+ isConfirmButtonLoading: PropTypes.bool.isRequired,
61
+ isOpen: PropTypes.bool.isRequired,
62
+ onConfirm: PropTypes.func.isRequired,
63
+ onToggleDialog: PropTypes.func.isRequired,
64
+ };
65
+
66
+ /* -------------------------------------------------------------------------------------------------
67
+ * BoldChunk
68
+ * -----------------------------------------------------------------------------------------------*/
69
+
70
+ const BoldChunk = (chunks) => <Typography fontWeight="bold">{chunks}</Typography>;
71
+
72
+ /* -------------------------------------------------------------------------------------------------
73
+ * ConfirmDialogPublishAll
74
+ * -----------------------------------------------------------------------------------------------*/
75
+
76
+ const ConfirmDialogPublishAll = ({ isOpen, onToggleDialog, isConfirmButtonLoading, onConfirm }) => {
77
+ const { formatMessage } = useIntl();
78
+ const { get } = useFetchClient();
79
+ const { selectedEntries } = useTableContext();
80
+ const toggleNotification = useNotification();
81
+ const { formatAPIError } = useAPIErrorHandler(getTrad);
82
+ const {
83
+ contentType: { uid: slug },
84
+ } = useSelector(listViewDomain());
85
+
86
+ const {
87
+ data: countDraftRelations,
88
+ isLoading,
89
+ isError,
90
+ } = useQuery(
91
+ ['content-manager', 'draft-relations', slug, selectedEntries],
92
+ async () => {
93
+ const {
94
+ data: { data },
95
+ } = await get(
96
+ `/content-manager/collection-types/${slug}/actions/countManyEntriesDraftRelations`,
97
+ {
98
+ params: {
99
+ ids: selectedEntries,
100
+ },
101
+ }
102
+ );
103
+
104
+ return data;
105
+ },
106
+ {
107
+ onError(error) {
108
+ toggleNotification({ type: 'warning', message: formatAPIError(error) });
109
+ },
110
+ }
111
+ );
112
+
113
+ if (isError) {
114
+ return null;
115
+ }
116
+
117
+ return (
118
+ <ConfirmBulkActionDialog
119
+ isOpen={isOpen && !isLoading}
120
+ onToggleDialog={onToggleDialog}
121
+ dialogBody={
122
+ <>
123
+ <Typography id="confirm-description" textAlign="center">
124
+ {countDraftRelations > 0 &&
125
+ formatMessage(
126
+ {
127
+ id: getTrad(`popUpwarning.warning.bulk-has-draft-relations.message`),
128
+ defaultMessage:
129
+ '<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. ',
130
+ },
131
+ {
132
+ b: BoldChunk,
133
+ count: countDraftRelations,
134
+ entities: selectedEntries.length,
135
+ }
136
+ )}
137
+ {formatMessage({
138
+ id: getTrad('popUpWarning.bodyMessage.contentType.publish.all'),
139
+ defaultMessage: 'Are you sure you want to publish these entries?',
140
+ })}
141
+ </Typography>
142
+ <InjectionZoneList area="contentManager.listView.publishModalAdditionalInfos" />
143
+ </>
144
+ }
145
+ endAction={
146
+ <Button
147
+ onClick={onConfirm}
148
+ variant="secondary"
149
+ startIcon={<Check />}
150
+ loading={isConfirmButtonLoading}
151
+ >
152
+ {formatMessage({
153
+ id: 'app.utils.publish',
154
+ defaultMessage: 'Publish',
155
+ })}
156
+ </Button>
157
+ }
158
+ />
159
+ );
160
+ };
161
+
162
+ ConfirmDialogPublishAll.propTypes = confirmDialogsPropTypes;
163
+
164
+ export { ConfirmDialogPublishAll, ConfirmBulkActionDialog };