@strapi/content-manager 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78 → 0.0.0-experimental.fb442e5e12dd3f611303691bf85a249520ba348b

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 (110) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs → ComponentConfigurationPage-B3yDbeU1.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs.map → ComponentConfigurationPage-B3yDbeU1.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js → ComponentConfigurationPage-KXSuLnQD.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js.map → ComponentConfigurationPage-KXSuLnQD.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js → EditConfigurationPage-BQ17--5R.js} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js.map → EditConfigurationPage-BQ17--5R.js.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs → EditConfigurationPage-D7PrLO8j.mjs} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs.map → EditConfigurationPage-D7PrLO8j.mjs.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-dFPBya9U.mjs → EditViewPage-B7VgwJaG.mjs} +57 -46
  11. package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-ChgloMyO.js → EditViewPage-BgjdnGz2.js} +56 -45
  13. package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +1 -0
  14. package/dist/_chunks/{Field-dLk-vgLL.js → Field-CdK7ZLmv.js} +504 -165
  15. package/dist/_chunks/Field-CdK7ZLmv.js.map +1 -0
  16. package/dist/_chunks/{Field-C1nUKcdS.mjs → Field-tHCw4lGA.mjs} +505 -166
  17. package/dist/_chunks/Field-tHCw4lGA.mjs.map +1 -0
  18. package/dist/_chunks/{Form-DOlpi7Js.mjs → Form-BJxdTv3Q.mjs} +40 -30
  19. package/dist/_chunks/Form-BJxdTv3Q.mjs.map +1 -0
  20. package/dist/_chunks/{Form-CbXtmHC_.js → Form-C_0KTVvV.js} +38 -28
  21. package/dist/_chunks/Form-C_0KTVvV.js.map +1 -0
  22. package/dist/_chunks/{History-BFNUAiGc.mjs → History-DR2txJLE.mjs} +142 -37
  23. package/dist/_chunks/History-DR2txJLE.mjs.map +1 -0
  24. package/dist/_chunks/{History-BjDfohBr.js → History-nuEzM5qm.js} +141 -36
  25. package/dist/_chunks/History-nuEzM5qm.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-IQBgWTaa.js → ListConfigurationPage-CnB86Psm.js} +57 -46
  27. package/dist/_chunks/ListConfigurationPage-CnB86Psm.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-DDi0KqFm.mjs → ListConfigurationPage-voFVtXu6.mjs} +58 -48
  29. package/dist/_chunks/ListConfigurationPage-voFVtXu6.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-BPjljUsH.mjs → ListViewPage-B_GaWgRH.mjs} +80 -71
  31. package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +1 -0
  32. package/dist/_chunks/{ListViewPage-CZYGqlvF.js → ListViewPage-SXIXm-RM.js} +78 -69
  33. package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js → NoContentTypePage-BzsQ3hLZ.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js.map → NoContentTypePage-BzsQ3hLZ.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs → NoContentTypePage-CYiGpsbj.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs.map → NoContentTypePage-CYiGpsbj.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs → NoPermissionsPage-B5baIHal.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs.map → NoPermissionsPage-B5baIHal.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js → NoPermissionsPage-IGkId4C5.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js.map → NoPermissionsPage-IGkId4C5.js.map} +1 -1
  42. package/dist/_chunks/{Relations-DTowyge2.mjs → Relations-CIYDdKU-.mjs} +5 -5
  43. package/dist/_chunks/Relations-CIYDdKU-.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DU6B7irU.js → Relations-Dhuurpx2.js} +5 -5
  45. package/dist/_chunks/Relations-Dhuurpx2.js.map +1 -0
  46. package/dist/_chunks/{en-GCOTL6jR.mjs → en-BrCTWlZv.mjs} +9 -4
  47. package/dist/_chunks/{en-GCOTL6jR.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  48. package/dist/_chunks/{en-DTULi5-d.js → en-uOUIxfcQ.js} +9 -4
  49. package/dist/_chunks/{en-DTULi5-d.js.map → en-uOUIxfcQ.js.map} +1 -1
  50. package/dist/_chunks/{index-BaGHmIir.mjs → index-C9TJPyni.mjs} +1542 -1063
  51. package/dist/_chunks/index-C9TJPyni.mjs.map +1 -0
  52. package/dist/_chunks/{index-CCJeB7Rw.js → index-CdT0kHZ8.js} +1510 -1031
  53. package/dist/_chunks/index-CdT0kHZ8.js.map +1 -0
  54. package/dist/_chunks/{layout-BinjszSQ.mjs → layout-BNqvLR_b.mjs} +39 -22
  55. package/dist/_chunks/layout-BNqvLR_b.mjs.map +1 -0
  56. package/dist/_chunks/{layout-ni_L9kT1.js → layout-C6dxWYT7.js} +37 -20
  57. package/dist/_chunks/layout-C6dxWYT7.js.map +1 -0
  58. package/dist/_chunks/{relations-c91ji5eR.mjs → relations-CkKqKw65.mjs} +2 -2
  59. package/dist/_chunks/{relations-c91ji5eR.mjs.map → relations-CkKqKw65.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CeJAJc5I.js → relations-DtFaDnP1.js} +2 -2
  61. package/dist/_chunks/{relations-CeJAJc5I.js.map → relations-DtFaDnP1.js.map} +1 -1
  62. package/dist/admin/index.js +1 -1
  63. package/dist/admin/index.mjs +8 -8
  64. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  65. package/dist/admin/src/history/index.d.ts +3 -0
  66. package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -1
  67. package/dist/admin/src/index.d.ts +1 -0
  68. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  69. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  70. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  73. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +12 -32
  74. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  75. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  76. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +14 -0
  77. package/dist/server/index.js +147 -93
  78. package/dist/server/index.js.map +1 -1
  79. package/dist/server/index.mjs +148 -94
  80. package/dist/server/index.mjs.map +1 -1
  81. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  82. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  83. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  84. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  85. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  86. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  87. package/dist/server/src/history/services/utils.d.ts +1 -1
  88. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  89. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  90. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  91. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  92. package/package.json +8 -8
  93. package/dist/_chunks/EditViewPage-ChgloMyO.js.map +0 -1
  94. package/dist/_chunks/EditViewPage-dFPBya9U.mjs.map +0 -1
  95. package/dist/_chunks/Field-C1nUKcdS.mjs.map +0 -1
  96. package/dist/_chunks/Field-dLk-vgLL.js.map +0 -1
  97. package/dist/_chunks/Form-CbXtmHC_.js.map +0 -1
  98. package/dist/_chunks/Form-DOlpi7Js.mjs.map +0 -1
  99. package/dist/_chunks/History-BFNUAiGc.mjs.map +0 -1
  100. package/dist/_chunks/History-BjDfohBr.js.map +0 -1
  101. package/dist/_chunks/ListConfigurationPage-DDi0KqFm.mjs.map +0 -1
  102. package/dist/_chunks/ListConfigurationPage-IQBgWTaa.js.map +0 -1
  103. package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +0 -1
  104. package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +0 -1
  105. package/dist/_chunks/Relations-DTowyge2.mjs.map +0 -1
  106. package/dist/_chunks/Relations-DU6B7irU.js.map +0 -1
  107. package/dist/_chunks/index-BaGHmIir.mjs.map +0 -1
  108. package/dist/_chunks/index-CCJeB7Rw.js.map +0 -1
  109. package/dist/_chunks/layout-BinjszSQ.mjs.map +0 -1
  110. package/dist/_chunks/layout-ni_L9kT1.js.map +0 -1
@@ -2,15 +2,15 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
10
9
  const styledComponents = require("styled-components");
11
10
  const yup = require("yup");
12
11
  const pipe = require("lodash/fp/pipe");
13
12
  const dateFns = require("date-fns");
13
+ const qs = require("qs");
14
14
  const toolkit = require("@reduxjs/toolkit");
15
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
16
  function _interopNamespace(e) {
@@ -70,42 +70,6 @@ const useInjectionZone = (area) => {
70
70
  const [page, position] = area.split(".");
71
71
  return contentManagerPlugin.getInjectedComponents(page, position);
72
72
  };
73
- const HistoryAction = ({ model, document }) => {
74
- const { formatMessage } = reactIntl.useIntl();
75
- const [{ query }] = strapiAdmin.useQueryParams();
76
- const navigate = reactRouterDom.useNavigate();
77
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
78
- if (!window.strapi.features.isEnabled("cms-content-history")) {
79
- return null;
80
- }
81
- return {
82
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
83
- label: formatMessage({
84
- id: "content-manager.history.document-action",
85
- defaultMessage: "Content History"
86
- }),
87
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
88
- disabled: (
89
- /**
90
- * The user is creating a new document.
91
- * It hasn't been saved yet, so there's no history to go to
92
- */
93
- !document || /**
94
- * The document has been created but the current dimension has never been saved.
95
- * For example, the user is creating a new locale in an existing document,
96
- * so there's no history for the document in that locale
97
- */
98
- !document.id || /**
99
- * History is only available for content types created by the user.
100
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
101
- * which start with `admin::` or `plugin::`
102
- */
103
- !model.startsWith("api::")
104
- ),
105
- position: "header"
106
- };
107
- };
108
- HistoryAction.type = "history";
109
73
  const ID = "id";
110
74
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
111
75
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -219,6 +183,7 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
219
183
  ]
220
184
  });
221
185
  const documentApi = contentManagerApi.injectEndpoints({
186
+ overrideExisting: true,
222
187
  endpoints: (builder) => ({
223
188
  autoCloneDocument: builder.mutation({
224
189
  query: ({ model, sourceId, query }) => ({
@@ -228,7 +193,12 @@ const documentApi = contentManagerApi.injectEndpoints({
228
193
  params: query
229
194
  }
230
195
  }),
231
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
196
+ invalidatesTags: (_result, error, { model }) => {
197
+ if (error) {
198
+ return [];
199
+ }
200
+ return [{ type: "Document", id: `${model}_LIST` }];
201
+ }
232
202
  }),
233
203
  cloneDocument: builder.mutation({
234
204
  query: ({ model, sourceId, data, params }) => ({
@@ -315,6 +285,7 @@ const documentApi = contentManagerApi.injectEndpoints({
315
285
  }),
316
286
  providesTags: (result, _error, arg) => {
317
287
  return [
288
+ { type: "Document", id: `ALL_LIST` },
318
289
  { type: "Document", id: `${arg.model}_LIST` },
319
290
  ...result?.results.map(({ documentId }) => ({
320
291
  type: "Document",
@@ -353,6 +324,11 @@ const documentApi = contentManagerApi.injectEndpoints({
353
324
  {
354
325
  type: "Document",
355
326
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
327
+ },
328
+ // Make it easy to invalidate all individual documents queries for a model
329
+ {
330
+ type: "Document",
331
+ id: `${model}_ALL_ITEMS`
356
332
  }
357
333
  ];
358
334
  }
@@ -418,6 +394,18 @@ const documentApi = contentManagerApi.injectEndpoints({
418
394
  },
419
395
  "Relations"
420
396
  ];
397
+ },
398
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
399
+ const patchResult = dispatch(
400
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
401
+ Object.assign(draft.data, data);
402
+ })
403
+ );
404
+ try {
405
+ await queryFulfilled;
406
+ } catch {
407
+ patchResult.undo();
408
+ }
421
409
  }
422
410
  }),
423
411
  unpublishDocument: builder.mutation({
@@ -601,6 +589,14 @@ const createAttributeSchema = (attribute) => {
601
589
  if (!value || typeof value === "string" && value.length === 0) {
602
590
  return true;
603
591
  }
592
+ if (typeof value === "object") {
593
+ try {
594
+ JSON.stringify(value);
595
+ return true;
596
+ } catch (err) {
597
+ return false;
598
+ }
599
+ }
604
600
  try {
605
601
  JSON.parse(value);
606
602
  return true;
@@ -620,11 +616,11 @@ const createAttributeSchema = (attribute) => {
620
616
  }
621
617
  };
622
618
  const addRequiredValidation = (attribute) => (schema) => {
623
- if (attribute.required) {
624
- return schema.required({
625
- id: strapiAdmin.translatedErrors.required.id,
626
- defaultMessage: "This field is required."
627
- });
619
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
620
+ return schema.min(1, strapiAdmin.translatedErrors.required);
621
+ }
622
+ if (attribute.required && attribute.type !== "relation") {
623
+ return schema.required(strapiAdmin.translatedErrors.required);
628
624
  }
629
625
  return schema?.nullable ? schema.nullable() : (
630
626
  // In some cases '.nullable' will not be available on the schema.
@@ -658,6 +654,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
658
654
  const addMinValidation = (attribute) => (schema) => {
659
655
  if ("min" in attribute) {
660
656
  const min = toInteger(attribute.min);
657
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
658
+ if (!attribute.required && "test" in schema && min) {
659
+ return schema.test(
660
+ "custom-min",
661
+ {
662
+ ...strapiAdmin.translatedErrors.min,
663
+ values: {
664
+ min: attribute.min
665
+ }
666
+ },
667
+ (value) => {
668
+ if (!value) {
669
+ return true;
670
+ }
671
+ if (Array.isArray(value) && value.length === 0) {
672
+ return true;
673
+ }
674
+ return value.length >= min;
675
+ }
676
+ );
677
+ }
678
+ }
661
679
  if ("min" in schema && min) {
662
680
  return schema.min(min, {
663
681
  ...strapiAdmin.translatedErrors.min,
@@ -784,7 +802,10 @@ const useDocument = (args, opts) => {
784
802
  isLoading: isLoadingDocument,
785
803
  isFetching: isFetchingDocument,
786
804
  error
787
- } = useGetDocumentQuery(args, opts);
805
+ } = useGetDocumentQuery(args, {
806
+ ...opts,
807
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
808
+ });
788
809
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
789
810
  React__namespace.useEffect(() => {
790
811
  if (error) {
@@ -948,12 +969,13 @@ const useDocumentActions = () => {
948
969
  );
949
970
  const [discardDocument] = useDiscardDocumentMutation();
950
971
  const discard = React__namespace.useCallback(
951
- async ({ collectionType, model, documentId }) => {
972
+ async ({ collectionType, model, documentId, params }) => {
952
973
  try {
953
974
  const res = await discardDocument({
954
975
  collectionType,
955
976
  model,
956
- documentId
977
+ documentId,
978
+ params
957
979
  });
958
980
  if ("error" in res) {
959
981
  toggleNotification({
@@ -1204,7 +1226,6 @@ const useDocumentActions = () => {
1204
1226
  sourceId
1205
1227
  });
1206
1228
  if ("error" in res) {
1207
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1208
1229
  return { error: res.error };
1209
1230
  }
1210
1231
  toggleNotification({
@@ -1285,7 +1306,7 @@ const useDocumentActions = () => {
1285
1306
  };
1286
1307
  };
1287
1308
  const ProtectedHistoryPage = React.lazy(
1288
- () => Promise.resolve().then(() => require("./History-BjDfohBr.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1309
+ () => Promise.resolve().then(() => require("./History-nuEzM5qm.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1289
1310
  );
1290
1311
  const routes$1 = [
1291
1312
  {
@@ -1298,31 +1319,31 @@ const routes$1 = [
1298
1319
  }
1299
1320
  ];
1300
1321
  const ProtectedEditViewPage = React.lazy(
1301
- () => Promise.resolve().then(() => require("./EditViewPage-ChgloMyO.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1322
+ () => Promise.resolve().then(() => require("./EditViewPage-BgjdnGz2.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1302
1323
  );
1303
1324
  const ProtectedListViewPage = React.lazy(
1304
- () => Promise.resolve().then(() => require("./ListViewPage-CZYGqlvF.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1325
+ () => Promise.resolve().then(() => require("./ListViewPage-SXIXm-RM.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1305
1326
  );
1306
1327
  const ProtectedListConfiguration = React.lazy(
1307
- () => Promise.resolve().then(() => require("./ListConfigurationPage-IQBgWTaa.js")).then((mod) => ({
1328
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-CnB86Psm.js")).then((mod) => ({
1308
1329
  default: mod.ProtectedListConfiguration
1309
1330
  }))
1310
1331
  );
1311
1332
  const ProtectedEditConfigurationPage = React.lazy(
1312
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CqBeCPGH.js")).then((mod) => ({
1333
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-BQ17--5R.js")).then((mod) => ({
1313
1334
  default: mod.ProtectedEditConfigurationPage
1314
1335
  }))
1315
1336
  );
1316
1337
  const ProtectedComponentConfigurationPage = React.lazy(
1317
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-by0e_kNd.js")).then((mod) => ({
1338
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-KXSuLnQD.js")).then((mod) => ({
1318
1339
  default: mod.ProtectedComponentConfigurationPage
1319
1340
  }))
1320
1341
  );
1321
1342
  const NoPermissions = React.lazy(
1322
- () => Promise.resolve().then(() => require("./NoPermissionsPage-cYEtLc_e.js")).then((mod) => ({ default: mod.NoPermissions }))
1343
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-IGkId4C5.js")).then((mod) => ({ default: mod.NoPermissions }))
1323
1344
  );
1324
1345
  const NoContentType = React.lazy(
1325
- () => Promise.resolve().then(() => require("./NoContentTypePage-BOAI6VZ1.js")).then((mod) => ({ default: mod.NoContentType }))
1346
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BzsQ3hLZ.js")).then((mod) => ({ default: mod.NoContentType }))
1326
1347
  );
1327
1348
  const CollectionTypePages = () => {
1328
1349
  const { collectionType } = reactRouterDom.useParams();
@@ -1436,12 +1457,14 @@ const DocumentActionButton = (action) => {
1436
1457
  /* @__PURE__ */ jsxRuntime.jsx(
1437
1458
  designSystem.Button,
1438
1459
  {
1439
- flex: 1,
1460
+ flex: "auto",
1440
1461
  startIcon: action.icon,
1441
1462
  disabled: action.disabled,
1442
1463
  onClick: handleClick(action),
1443
1464
  justifyContent: "center",
1444
1465
  variant: action.variant || "default",
1466
+ paddingTop: "7px",
1467
+ paddingBottom: "7px",
1445
1468
  children: action.label
1446
1469
  }
1447
1470
  ),
@@ -1449,7 +1472,7 @@ const DocumentActionButton = (action) => {
1449
1472
  DocumentActionConfirmDialog,
1450
1473
  {
1451
1474
  ...action.dialog,
1452
- variant: action.variant,
1475
+ variant: action.dialog?.variant ?? action.variant,
1453
1476
  isOpen: dialogId === action.id,
1454
1477
  onClose: handleClose
1455
1478
  }
@@ -1501,14 +1524,14 @@ const DocumentActionsMenu = ({
1501
1524
  };
1502
1525
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1503
1526
  /* @__PURE__ */ jsxRuntime.jsxs(
1504
- designSystem.Menu.Trigger,
1527
+ StyledMoreButton,
1505
1528
  {
1506
1529
  disabled: isDisabled,
1507
1530
  size: "S",
1508
1531
  endIcon: null,
1509
- paddingTop: "7px",
1510
- paddingLeft: "9px",
1511
- paddingRight: "9px",
1532
+ paddingTop: "4px",
1533
+ paddingLeft: "7px",
1534
+ paddingRight: "7px",
1512
1535
  variant,
1513
1536
  children: [
1514
1537
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1528,10 +1551,25 @@ const DocumentActionsMenu = ({
1528
1551
  onSelect: handleClick(action),
1529
1552
  display: "block",
1530
1553
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1531
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1532
- action.icon,
1533
- action.label
1534
- ] }),
1554
+ /* @__PURE__ */ jsxRuntime.jsxs(
1555
+ designSystem.Flex,
1556
+ {
1557
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1558
+ gap: 2,
1559
+ tag: "span",
1560
+ children: [
1561
+ /* @__PURE__ */ jsxRuntime.jsx(
1562
+ designSystem.Flex,
1563
+ {
1564
+ tag: "span",
1565
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1566
+ children: action.icon
1567
+ }
1568
+ ),
1569
+ action.label
1570
+ ]
1571
+ }
1572
+ ),
1535
1573
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1536
1574
  designSystem.Flex,
1537
1575
  {
@@ -1590,6 +1628,23 @@ const convertActionVariantToColor = (variant = "secondary") => {
1590
1628
  return "primary600";
1591
1629
  }
1592
1630
  };
1631
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1632
+ switch (variant) {
1633
+ case "danger":
1634
+ return "danger600";
1635
+ case "secondary":
1636
+ return "neutral500";
1637
+ case "success":
1638
+ return "success600";
1639
+ default:
1640
+ return "primary600";
1641
+ }
1642
+ };
1643
+ const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1644
+ & > span {
1645
+ display: flex;
1646
+ }
1647
+ `;
1593
1648
  const DocumentActionConfirmDialog = ({
1594
1649
  onClose,
1595
1650
  onCancel,
@@ -1612,22 +1667,20 @@ const DocumentActionConfirmDialog = ({
1612
1667
  }
1613
1668
  onClose();
1614
1669
  };
1615
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1616
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1617
- /* @__PURE__ */ jsxRuntime.jsx(
1618
- designSystem.DialogFooter,
1619
- {
1620
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1621
- id: "app.components.Button.cancel",
1622
- defaultMessage: "Cancel"
1623
- }) }),
1624
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1625
- id: "app.components.Button.confirm",
1626
- defaultMessage: "Confirm"
1627
- }) })
1628
- }
1629
- )
1630
- ] });
1670
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1671
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1672
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1673
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1674
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
1675
+ id: "app.components.Button.cancel",
1676
+ defaultMessage: "Cancel"
1677
+ }) }) }),
1678
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1679
+ id: "app.components.Button.confirm",
1680
+ defaultMessage: "Confirm"
1681
+ }) })
1682
+ ] })
1683
+ ] }) });
1631
1684
  };
1632
1685
  const DocumentActionModal = ({
1633
1686
  isOpen,
@@ -1637,36 +1690,19 @@ const DocumentActionModal = ({
1637
1690
  content: Content,
1638
1691
  onModalClose
1639
1692
  }) => {
1640
- const id = React__namespace.useId();
1641
- if (!isOpen) {
1642
- return null;
1643
- }
1644
1693
  const handleClose = () => {
1645
1694
  if (onClose) {
1646
1695
  onClose();
1647
1696
  }
1648
1697
  onModalClose();
1649
1698
  };
1650
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1651
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(
1654
- designSystem.Box,
1655
- {
1656
- paddingTop: 4,
1657
- paddingBottom: 4,
1658
- paddingLeft: 5,
1659
- paddingRight: 5,
1660
- borderWidth: "1px 0 0 0",
1661
- borderStyle: "solid",
1662
- borderColor: "neutral150",
1663
- background: "neutral100",
1664
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1665
- }
1666
- )
1667
- ] });
1699
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1700
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1701
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1702
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1703
+ ] }) });
1668
1704
  };
1669
- const PublishAction = ({
1705
+ const PublishAction$1 = ({
1670
1706
  activeTab,
1671
1707
  documentId,
1672
1708
  model,
@@ -1685,6 +1721,12 @@ const PublishAction = ({
1685
1721
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1686
1722
  );
1687
1723
  const { publish } = useDocumentActions();
1724
+ const [
1725
+ countDraftRelations,
1726
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1727
+ ] = useLazyGetDraftRelationCountQuery();
1728
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1729
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1688
1730
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1689
1731
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1690
1732
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1693,10 +1735,101 @@ const PublishAction = ({
1693
1735
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1694
1736
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1695
1737
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1738
+ React__namespace.useEffect(() => {
1739
+ if (isErrorDraftRelations) {
1740
+ toggleNotification({
1741
+ type: "danger",
1742
+ message: formatMessage({
1743
+ id: getTranslation("error.records.fetch-draft-relatons"),
1744
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1745
+ })
1746
+ });
1747
+ }
1748
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1749
+ React__namespace.useEffect(() => {
1750
+ const localDraftRelations = /* @__PURE__ */ new Set();
1751
+ const extractDraftRelations = (data) => {
1752
+ const relations = data.connect || [];
1753
+ relations.forEach((relation) => {
1754
+ if (relation.status === "draft") {
1755
+ localDraftRelations.add(relation.id);
1756
+ }
1757
+ });
1758
+ };
1759
+ const traverseAndExtract = (data) => {
1760
+ Object.entries(data).forEach(([key, value]) => {
1761
+ if (key === "connect" && Array.isArray(value)) {
1762
+ extractDraftRelations({ connect: value });
1763
+ } else if (typeof value === "object" && value !== null) {
1764
+ traverseAndExtract(value);
1765
+ }
1766
+ });
1767
+ };
1768
+ if (!documentId || modified) {
1769
+ traverseAndExtract(formValues);
1770
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1771
+ }
1772
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1773
+ React__namespace.useEffect(() => {
1774
+ if (documentId) {
1775
+ const fetchDraftRelationsCount = async () => {
1776
+ const { data, error } = await countDraftRelations({
1777
+ collectionType,
1778
+ model,
1779
+ documentId,
1780
+ params
1781
+ });
1782
+ if (error) {
1783
+ throw error;
1784
+ }
1785
+ if (data) {
1786
+ setServerCountOfDraftRelations(data.data);
1787
+ }
1788
+ };
1789
+ fetchDraftRelationsCount();
1790
+ }
1791
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1696
1792
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1697
1793
  if (!schema?.options?.draftAndPublish) {
1698
1794
  return null;
1699
1795
  }
1796
+ const performPublish = async () => {
1797
+ setSubmitting(true);
1798
+ try {
1799
+ const { errors } = await validate();
1800
+ if (errors) {
1801
+ toggleNotification({
1802
+ type: "danger",
1803
+ message: formatMessage({
1804
+ id: "content-manager.validation.error",
1805
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1806
+ })
1807
+ });
1808
+ return;
1809
+ }
1810
+ const res = await publish(
1811
+ {
1812
+ collectionType,
1813
+ model,
1814
+ documentId,
1815
+ params
1816
+ },
1817
+ formValues
1818
+ );
1819
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1820
+ navigate({
1821
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1822
+ search: rawQuery
1823
+ });
1824
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1825
+ setErrors(formatValidationErrors(res.error));
1826
+ }
1827
+ } finally {
1828
+ setSubmitting(false);
1829
+ }
1830
+ };
1831
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1832
+ const hasDraftRelations = totalDraftRelations > 0;
1700
1833
  return {
1701
1834
  /**
1702
1835
  * Disabled when:
@@ -1706,52 +1839,42 @@ const PublishAction = ({
1706
1839
  * - the document is already published & not modified
1707
1840
  * - the document is being created & not modified
1708
1841
  * - the user doesn't have the permission to publish
1709
- * - the user doesn't have the permission to create a new document
1710
- * - the user doesn't have the permission to update the document
1711
1842
  */
1712
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1843
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1713
1844
  label: formatMessage({
1714
1845
  id: "app.utils.publish",
1715
1846
  defaultMessage: "Publish"
1716
1847
  }),
1717
1848
  onClick: async () => {
1718
- setSubmitting(true);
1719
- try {
1720
- const { errors } = await validate();
1721
- if (errors) {
1722
- toggleNotification({
1723
- type: "danger",
1724
- message: formatMessage({
1725
- id: "content-manager.validation.error",
1726
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1727
- })
1728
- });
1729
- return;
1730
- }
1731
- const res = await publish(
1732
- {
1733
- collectionType,
1734
- model,
1735
- documentId,
1736
- params
1737
- },
1738
- formValues
1739
- );
1740
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1741
- navigate({
1742
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1743
- search: rawQuery
1744
- });
1745
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1746
- setErrors(formatValidationErrors(res.error));
1849
+ if (hasDraftRelations) {
1850
+ return;
1851
+ }
1852
+ await performPublish();
1853
+ },
1854
+ dialog: hasDraftRelations ? {
1855
+ type: "dialog",
1856
+ variant: "danger",
1857
+ footer: null,
1858
+ title: formatMessage({
1859
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1860
+ defaultMessage: "Confirmation"
1861
+ }),
1862
+ content: formatMessage(
1863
+ {
1864
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1865
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1866
+ },
1867
+ {
1868
+ count: totalDraftRelations
1747
1869
  }
1748
- } finally {
1749
- setSubmitting(false);
1870
+ ),
1871
+ onConfirm: async () => {
1872
+ await performPublish();
1750
1873
  }
1751
- }
1874
+ } : void 0
1752
1875
  };
1753
1876
  };
1754
- PublishAction.type = "publish";
1877
+ PublishAction$1.type = "publish";
1755
1878
  const UpdateAction = ({
1756
1879
  activeTab,
1757
1880
  documentId,
@@ -1764,7 +1887,7 @@ const UpdateAction = ({
1764
1887
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1765
1888
  const isCloning = cloneMatch !== null;
1766
1889
  const { formatMessage } = reactIntl.useIntl();
1767
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1890
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1768
1891
  canCreate: canCreate2,
1769
1892
  canUpdate: canUpdate2
1770
1893
  }));
@@ -1784,10 +1907,8 @@ const UpdateAction = ({
1784
1907
  * - the form is submitting
1785
1908
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1786
1909
  * - the active tab is the published tab
1787
- * - the user doesn't have the permission to create a new document
1788
- * - the user doesn't have the permission to update the document
1789
1910
  */
1790
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1911
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1791
1912
  label: formatMessage({
1792
1913
  id: "content-manager.containers.Edit.save",
1793
1914
  defaultMessage: "Save"
@@ -1816,10 +1937,13 @@ const UpdateAction = ({
1816
1937
  document
1817
1938
  );
1818
1939
  if ("data" in res) {
1819
- navigate({
1820
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1821
- search: rawQuery
1822
- });
1940
+ navigate(
1941
+ {
1942
+ pathname: `../${res.data.documentId}`,
1943
+ search: rawQuery
1944
+ },
1945
+ { relative: "path" }
1946
+ );
1823
1947
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1824
1948
  setErrors(formatValidationErrors(res.error));
1825
1949
  }
@@ -1847,10 +1971,13 @@ const UpdateAction = ({
1847
1971
  document
1848
1972
  );
1849
1973
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1850
- navigate({
1851
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1852
- search: rawQuery
1853
- });
1974
+ navigate(
1975
+ {
1976
+ pathname: `../${res.data.documentId}`,
1977
+ search: rawQuery
1978
+ },
1979
+ { replace: true, relative: "path" }
1980
+ );
1854
1981
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1855
1982
  setErrors(formatValidationErrors(res.error));
1856
1983
  }
@@ -1882,10 +2009,8 @@ const UnpublishAction$1 = ({
1882
2009
  const { toggleNotification } = strapiAdmin.useNotification();
1883
2010
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1884
2011
  const isDocumentModified = document?.status === "modified";
1885
- const handleChange = (e) => {
1886
- if ("value" in e.target) {
1887
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1888
- }
2012
+ const handleChange = (value) => {
2013
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
2014
  };
1890
2015
  if (!schema?.options?.draftAndPublish) {
1891
2016
  return null;
@@ -1935,40 +2060,24 @@ const UnpublishAction$1 = ({
1935
2060
  }) })
1936
2061
  ] }),
1937
2062
  /* @__PURE__ */ jsxRuntime.jsxs(
1938
- designSystem.Flex,
2063
+ designSystem.Radio.Group,
1939
2064
  {
1940
- onChange: handleChange,
1941
- direction: "column",
1942
- alignItems: "flex-start",
1943
- tag: "fieldset",
1944
- borderWidth: 0,
1945
- gap: 3,
2065
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2066
+ name: "discard-options",
2067
+ "aria-label": formatMessage({
2068
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2069
+ defaultMessage: "Choose an option to unpublish the document."
2070
+ }),
2071
+ onValueChange: handleChange,
1946
2072
  children: [
1947
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1948
- /* @__PURE__ */ jsxRuntime.jsx(
1949
- designSystem.Radio,
1950
- {
1951
- checked: shouldKeepDraft,
1952
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1953
- name: "discard-options",
1954
- children: formatMessage({
1955
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1956
- defaultMessage: "Keep draft"
1957
- })
1958
- }
1959
- ),
1960
- /* @__PURE__ */ jsxRuntime.jsx(
1961
- designSystem.Radio,
1962
- {
1963
- checked: !shouldKeepDraft,
1964
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1965
- name: "discard-options",
1966
- children: formatMessage({
1967
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1968
- defaultMessage: "Replace draft"
1969
- })
1970
- }
1971
- )
2073
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2074
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2075
+ defaultMessage: "Keep draft"
2076
+ }) }),
2077
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2078
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2079
+ defaultMessage: "Replace draft"
2080
+ }) })
1972
2081
  ]
1973
2082
  }
1974
2083
  )
@@ -2057,7 +2166,7 @@ const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2057
2166
  fill: currentColor;
2058
2167
  }
2059
2168
  `;
2060
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction$1, DiscardAction];
2169
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2061
2170
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2062
2171
  const RelativeTime = React__namespace.forwardRef(
2063
2172
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2114,23 +2223,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2114
2223
  id: "content-manager.containers.edit.title.new",
2115
2224
  defaultMessage: "Create an entry"
2116
2225
  }) : documentTitle;
2117
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2226
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2118
2227
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2119
- /* @__PURE__ */ jsxRuntime.jsxs(
2120
- designSystem.Flex,
2121
- {
2122
- width: "100%",
2123
- justifyContent: "space-between",
2124
- paddingTop: 1,
2125
- gap: "80px",
2126
- alignItems: "flex-start",
2127
- children: [
2128
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2129
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2130
- ]
2131
- }
2132
- ),
2133
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2228
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2229
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2230
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2231
+ ] }),
2232
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2134
2233
  ] });
2135
2234
  };
2136
2235
  const HeaderToolbar = () => {
@@ -2512,278 +2611,902 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2512
2611
  }
2513
2612
  );
2514
2613
  });
2515
- const BulkActionsRenderer = () => {
2516
- const plugins = strapiAdmin.useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
2517
- const { model, collectionType } = useDoc();
2518
- const { selectedRows } = strapiAdmin.useTable("BulkActionsRenderer", (state) => state);
2519
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2520
- strapiAdmin.DescriptionComponentRenderer,
2521
- {
2522
- props: {
2523
- model,
2524
- collectionType,
2525
- documents: selectedRows
2526
- },
2527
- descriptions: plugins["content-manager"].apis.getBulkActions(),
2528
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
2529
- }
2530
- ) });
2614
+ const HOOKS = {
2615
+ /**
2616
+ * Hook that allows to mutate the displayed headers of the list view table
2617
+ * @constant
2618
+ * @type {string}
2619
+ */
2620
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2621
+ /**
2622
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2623
+ * @constant
2624
+ * @type {string}
2625
+ */
2626
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2627
+ /**
2628
+ * Hook that allows to mutate the CM's edit view layout
2629
+ * @constant
2630
+ * @type {string}
2631
+ */
2632
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2633
+ /**
2634
+ * Hook that allows to mutate the CM's single types links pre-set filters
2635
+ * @constant
2636
+ * @type {string}
2637
+ */
2638
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2531
2639
  };
2532
- const BulkActionAction = (action) => {
2533
- const [dialogId, setDialogId] = React__namespace.useState(null);
2534
- const { toggleNotification } = strapiAdmin.useNotification();
2535
- const handleClick = (action2) => (e) => {
2536
- const { onClick, dialog, id } = action2;
2537
- if (onClick) {
2538
- onClick(e);
2539
- }
2540
- if (dialog) {
2541
- switch (dialog.type) {
2542
- case "notification":
2543
- toggleNotification({
2544
- title: dialog.title,
2545
- message: dialog.content,
2546
- type: dialog.status,
2547
- timeout: dialog.timeout,
2548
- onClose: dialog.onClose
2549
- });
2550
- break;
2551
- case "dialog":
2552
- case "modal": {
2553
- e.preventDefault();
2554
- setDialogId(id);
2555
- }
2556
- }
2557
- }
2558
- };
2559
- const handleClose = () => {
2560
- setDialogId(null);
2561
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
2562
- action.dialog.onClose();
2563
- }
2564
- };
2565
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2566
- /* @__PURE__ */ jsxRuntime.jsx(
2567
- designSystem.Button,
2568
- {
2569
- disabled: action.disabled,
2570
- startIcon: action.icon,
2571
- variant: action.variant,
2572
- onClick: handleClick(action),
2573
- children: action.label
2574
- }
2575
- ),
2576
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
2577
- BulkActionConfirmDialog,
2578
- {
2579
- ...action.dialog,
2580
- variant: action.variant,
2581
- isOpen: dialogId === action.id,
2582
- onClose: handleClose
2583
- }
2584
- ) : null,
2585
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
2586
- BulkActionModal,
2587
- {
2588
- ...action.dialog,
2589
- onModalClose: handleClose,
2590
- isOpen: dialogId === action.id
2591
- }
2592
- ) : null
2593
- ] });
2594
- };
2595
- const BulkActionConfirmDialog = ({
2596
- onClose,
2597
- onCancel,
2598
- onConfirm,
2599
- title,
2600
- content,
2601
- confirmButton,
2602
- isOpen,
2603
- variant = "secondary"
2604
- }) => {
2605
- const { formatMessage } = reactIntl.useIntl();
2606
- const handleClose = async () => {
2607
- if (onCancel) {
2608
- await onCancel();
2609
- }
2610
- onClose();
2611
- };
2612
- const handleConfirm = async () => {
2613
- if (onConfirm) {
2614
- await onConfirm();
2615
- }
2616
- onClose();
2617
- };
2618
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
2619
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
2620
- /* @__PURE__ */ jsxRuntime.jsx(
2621
- designSystem.DialogFooter,
2622
- {
2623
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
2624
- id: "app.components.Button.cancel",
2625
- defaultMessage: "Cancel"
2626
- }) }),
2627
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
2628
- designSystem.Button,
2629
- {
2630
- onClick: handleConfirm,
2631
- variant: variant === "danger-light" ? variant : "secondary",
2632
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
2633
- children: confirmButton ? confirmButton : formatMessage({
2634
- id: "app.components.Button.confirm",
2635
- defaultMessage: "Confirm"
2636
- })
2637
- }
2638
- )
2639
- }
2640
- )
2641
- ] });
2640
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2641
+ endpoints: (builder) => ({
2642
+ getContentTypeConfiguration: builder.query({
2643
+ query: (uid) => ({
2644
+ url: `/content-manager/content-types/${uid}/configuration`,
2645
+ method: "GET"
2646
+ }),
2647
+ transformResponse: (response) => response.data,
2648
+ providesTags: (_result, _error, uid) => [
2649
+ { type: "ContentTypesConfiguration", id: uid },
2650
+ { type: "ContentTypeSettings", id: "LIST" }
2651
+ ]
2652
+ }),
2653
+ getAllContentTypeSettings: builder.query({
2654
+ query: () => "/content-manager/content-types-settings",
2655
+ transformResponse: (response) => response.data,
2656
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2657
+ }),
2658
+ updateContentTypeConfiguration: builder.mutation({
2659
+ query: ({ uid, ...body }) => ({
2660
+ url: `/content-manager/content-types/${uid}/configuration`,
2661
+ method: "PUT",
2662
+ data: body
2663
+ }),
2664
+ transformResponse: (response) => response.data,
2665
+ invalidatesTags: (_result, _error, { uid }) => [
2666
+ { type: "ContentTypesConfiguration", id: uid },
2667
+ { type: "ContentTypeSettings", id: "LIST" },
2668
+ // Is this necessary?
2669
+ { type: "InitialData" }
2670
+ ]
2671
+ })
2672
+ })
2673
+ });
2674
+ const {
2675
+ useGetContentTypeConfigurationQuery,
2676
+ useGetAllContentTypeSettingsQuery,
2677
+ useUpdateContentTypeConfigurationMutation
2678
+ } = contentTypesApi;
2679
+ const checkIfAttributeIsDisplayable = (attribute) => {
2680
+ const { type } = attribute;
2681
+ if (type === "relation") {
2682
+ return !attribute.relation.toLowerCase().includes("morph");
2683
+ }
2684
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2642
2685
  };
2643
- const BulkActionModal = ({
2644
- isOpen,
2645
- title,
2646
- onClose,
2647
- content: Content,
2648
- onModalClose
2649
- }) => {
2650
- const id = React__namespace.useId();
2651
- if (!isOpen) {
2652
- return null;
2686
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2687
+ if (!mainFieldName) {
2688
+ return void 0;
2653
2689
  }
2654
- const handleClose = () => {
2655
- if (onClose) {
2656
- onClose();
2657
- }
2658
- onModalClose();
2690
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2691
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2692
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2693
+ );
2694
+ return {
2695
+ name: mainFieldName,
2696
+ type: mainFieldType ?? "string"
2659
2697
  };
2660
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
2661
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
2662
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
2663
- ] });
2664
2698
  };
2665
- const DeleteAction = ({ documents, model }) => {
2666
- const { formatMessage } = reactIntl.useIntl();
2667
- const { schema: contentType } = useDoc();
2668
- const selectRow = strapiAdmin.useTable("DeleteAction", (state) => state.selectRow);
2669
- const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
2699
+ const DEFAULT_SETTINGS = {
2700
+ bulkable: false,
2701
+ filterable: false,
2702
+ searchable: false,
2703
+ pagination: false,
2704
+ defaultSortBy: "",
2705
+ defaultSortOrder: "asc",
2706
+ mainField: "id",
2707
+ pageSize: 10
2708
+ };
2709
+ const useDocumentLayout = (model) => {
2710
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2670
2711
  const [{ query }] = strapiAdmin.useQueryParams();
2671
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2672
- const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
2673
- const { deleteMany: bulkDeleteAction } = useDocumentActions();
2674
- const documentIds = documents.map(({ documentId }) => documentId);
2675
- const handleConfirmBulkDelete = async () => {
2676
- const res = await bulkDeleteAction({
2677
- documentIds,
2678
- model,
2679
- params
2680
- });
2681
- if (!("error" in res)) {
2682
- selectRow([]);
2712
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2713
+ const { toggleNotification } = strapiAdmin.useNotification();
2714
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2715
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2716
+ const {
2717
+ data,
2718
+ isLoading: isLoadingConfigs,
2719
+ error,
2720
+ isFetching: isFetchingConfigs
2721
+ } = useGetContentTypeConfigurationQuery(model);
2722
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2723
+ React__namespace.useEffect(() => {
2724
+ if (error) {
2725
+ toggleNotification({
2726
+ type: "danger",
2727
+ message: formatAPIError(error)
2728
+ });
2683
2729
  }
2684
- };
2685
- if (!hasDeletePermission)
2686
- return null;
2730
+ }, [error, formatAPIError, toggleNotification]);
2731
+ const editLayout = React__namespace.useMemo(
2732
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2733
+ layout: [],
2734
+ components: {},
2735
+ metadatas: {},
2736
+ options: {},
2737
+ settings: DEFAULT_SETTINGS
2738
+ },
2739
+ [data, isLoading, schemas, schema, components]
2740
+ );
2741
+ const listLayout = React__namespace.useMemo(() => {
2742
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2743
+ layout: [],
2744
+ metadatas: {},
2745
+ options: {},
2746
+ settings: DEFAULT_SETTINGS
2747
+ };
2748
+ }, [data, isLoading, schemas, schema, components]);
2749
+ const { layout: edit } = React__namespace.useMemo(
2750
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2751
+ layout: editLayout,
2752
+ query
2753
+ }),
2754
+ [editLayout, query, runHookWaterfall]
2755
+ );
2687
2756
  return {
2688
- variant: "danger-light",
2689
- label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
2690
- dialog: {
2691
- type: "dialog",
2692
- title: formatMessage({
2693
- id: "app.components.ConfirmDialog.title",
2694
- defaultMessage: "Confirmation"
2695
- }),
2696
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2697
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
2698
- id: "popUpWarning.bodyMessage.contentType.delete.all",
2699
- defaultMessage: "Are you sure you want to delete these entries?"
2700
- }) }),
2701
- hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
2702
- {
2703
- id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
2704
- defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
2705
- },
2706
- {
2707
- em: Emphasis
2708
- }
2709
- ) }) })
2710
- ] }),
2711
- onConfirm: handleConfirmBulkDelete
2712
- }
2757
+ error,
2758
+ isLoading,
2759
+ edit,
2760
+ list: listLayout
2713
2761
  };
2714
2762
  };
2715
- DeleteAction.type = "delete";
2716
- const UnpublishAction = ({ documents, model }) => {
2717
- const { formatMessage } = reactIntl.useIntl();
2718
- const { schema } = useDoc();
2719
- const selectRow = strapiAdmin.useTable("UnpublishAction", (state) => state.selectRow);
2720
- const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
2721
- const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
2722
- const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
2723
- const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
2724
- const documentIds = documents.map(({ documentId }) => documentId);
2725
- const [{ query }] = strapiAdmin.useQueryParams();
2726
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2727
- const handleConfirmBulkUnpublish = async () => {
2728
- const data = await bulkUnpublishAction({ documentIds, model, params });
2729
- if (!("error" in data)) {
2730
- selectRow([]);
2763
+ const useDocLayout = () => {
2764
+ const { model } = useDoc();
2765
+ return useDocumentLayout(model);
2766
+ };
2767
+ const formatEditLayout = (data, {
2768
+ schemas,
2769
+ schema,
2770
+ components
2771
+ }) => {
2772
+ let currentPanelIndex = 0;
2773
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2774
+ data.contentType.layouts.edit,
2775
+ schema?.attributes,
2776
+ data.contentType.metadatas,
2777
+ { configurations: data.components, schemas: components },
2778
+ schemas
2779
+ ).reduce((panels, row) => {
2780
+ if (row.some((field) => field.type === "dynamiczone")) {
2781
+ panels.push([row]);
2782
+ currentPanelIndex += 2;
2783
+ } else {
2784
+ if (!panels[currentPanelIndex]) {
2785
+ panels.push([]);
2786
+ }
2787
+ panels[currentPanelIndex].push(row);
2788
+ }
2789
+ return panels;
2790
+ }, []);
2791
+ const componentEditAttributes = Object.entries(data.components).reduce(
2792
+ (acc, [uid, configuration]) => {
2793
+ acc[uid] = {
2794
+ layout: convertEditLayoutToFieldLayouts(
2795
+ configuration.layouts.edit,
2796
+ components[uid].attributes,
2797
+ configuration.metadatas
2798
+ ),
2799
+ settings: {
2800
+ ...configuration.settings,
2801
+ icon: components[uid].info.icon,
2802
+ displayName: components[uid].info.displayName
2803
+ }
2804
+ };
2805
+ return acc;
2806
+ },
2807
+ {}
2808
+ );
2809
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2810
+ (acc, [attribute, metadata]) => {
2811
+ return {
2812
+ ...acc,
2813
+ [attribute]: metadata.edit
2814
+ };
2815
+ },
2816
+ {}
2817
+ );
2818
+ return {
2819
+ layout: panelledEditAttributes,
2820
+ components: componentEditAttributes,
2821
+ metadatas: editMetadatas,
2822
+ settings: {
2823
+ ...data.contentType.settings,
2824
+ displayName: schema?.info.displayName
2825
+ },
2826
+ options: {
2827
+ ...schema?.options,
2828
+ ...schema?.pluginOptions,
2829
+ ...data.contentType.options
2731
2830
  }
2732
2831
  };
2733
- const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
2734
- if (!showUnpublishButton)
2735
- return null;
2832
+ };
2833
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2834
+ return rows.map(
2835
+ (row) => row.map((field) => {
2836
+ const attribute = attributes[field.name];
2837
+ if (!attribute) {
2838
+ return null;
2839
+ }
2840
+ const { edit: metadata } = metadatas[field.name];
2841
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2842
+ return {
2843
+ attribute,
2844
+ disabled: !metadata.editable,
2845
+ hint: metadata.description,
2846
+ label: metadata.label ?? "",
2847
+ name: field.name,
2848
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2849
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2850
+ schemas,
2851
+ components: components?.schemas ?? {}
2852
+ }),
2853
+ placeholder: metadata.placeholder ?? "",
2854
+ required: attribute.required ?? false,
2855
+ size: field.size,
2856
+ unique: "unique" in attribute ? attribute.unique : false,
2857
+ visible: metadata.visible ?? true,
2858
+ type: attribute.type
2859
+ };
2860
+ }).filter((field) => field !== null)
2861
+ );
2862
+ };
2863
+ const formatListLayout = (data, {
2864
+ schemas,
2865
+ schema,
2866
+ components
2867
+ }) => {
2868
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2869
+ (acc, [attribute, metadata]) => {
2870
+ return {
2871
+ ...acc,
2872
+ [attribute]: metadata.list
2873
+ };
2874
+ },
2875
+ {}
2876
+ );
2877
+ const listAttributes = convertListLayoutToFieldLayouts(
2878
+ data.contentType.layouts.list,
2879
+ schema?.attributes,
2880
+ listMetadatas,
2881
+ { configurations: data.components, schemas: components },
2882
+ schemas
2883
+ );
2736
2884
  return {
2737
- variant: "tertiary",
2738
- label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
2739
- dialog: {
2740
- type: "dialog",
2741
- title: formatMessage({
2742
- id: "app.components.ConfirmDialog.title",
2743
- defaultMessage: "Confirmation"
2885
+ layout: listAttributes,
2886
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2887
+ metadatas: listMetadatas,
2888
+ options: {
2889
+ ...schema?.options,
2890
+ ...schema?.pluginOptions,
2891
+ ...data.contentType.options
2892
+ }
2893
+ };
2894
+ };
2895
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2896
+ return columns.map((name) => {
2897
+ const attribute = attributes[name];
2898
+ if (!attribute) {
2899
+ return null;
2900
+ }
2901
+ const metadata = metadatas[name];
2902
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2903
+ return {
2904
+ attribute,
2905
+ label: metadata.label ?? "",
2906
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2907
+ schemas,
2908
+ components: components?.schemas ?? {}
2744
2909
  }),
2745
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2746
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
2747
- id: "popUpWarning.bodyMessage.contentType.unpublish.all",
2748
- defaultMessage: "Are you sure you want to unpublish these entries?"
2749
- }) }),
2750
- hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
2910
+ name,
2911
+ searchable: metadata.searchable ?? true,
2912
+ sortable: metadata.sortable ?? true
2913
+ };
2914
+ }).filter((field) => field !== null);
2915
+ };
2916
+ const ConfirmBulkActionDialog = ({
2917
+ onToggleDialog,
2918
+ isOpen = false,
2919
+ dialogBody,
2920
+ endAction
2921
+ }) => {
2922
+ const { formatMessage } = reactIntl.useIntl();
2923
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2924
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2925
+ id: "app.components.ConfirmDialog.title",
2926
+ defaultMessage: "Confirmation"
2927
+ }) }),
2928
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2929
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2930
+ dialogBody
2931
+ ] }) }),
2932
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2933
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2934
+ id: "app.components.Button.cancel",
2935
+ defaultMessage: "Cancel"
2936
+ }) }) }),
2937
+ endAction
2938
+ ] })
2939
+ ] }) });
2940
+ };
2941
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2942
+ const ConfirmDialogPublishAll = ({
2943
+ isOpen,
2944
+ onToggleDialog,
2945
+ isConfirmButtonLoading = false,
2946
+ onConfirm
2947
+ }) => {
2948
+ const { formatMessage } = reactIntl.useIntl();
2949
+ const selectedEntries = strapiAdmin.useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2950
+ const { toggleNotification } = strapiAdmin.useNotification();
2951
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2952
+ const { model, schema } = useDoc();
2953
+ const [{ query }] = strapiAdmin.useQueryParams();
2954
+ const {
2955
+ data: countDraftRelations = 0,
2956
+ isLoading,
2957
+ error
2958
+ } = useGetManyDraftRelationCountQuery(
2959
+ {
2960
+ model,
2961
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2962
+ locale: query?.plugins?.i18n?.locale
2963
+ },
2964
+ {
2965
+ skip: selectedEntries.length === 0
2966
+ }
2967
+ );
2968
+ React__namespace.useEffect(() => {
2969
+ if (error) {
2970
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2971
+ }
2972
+ }, [error, formatAPIError, toggleNotification]);
2973
+ if (error) {
2974
+ return null;
2975
+ }
2976
+ return /* @__PURE__ */ jsxRuntime.jsx(
2977
+ ConfirmBulkActionDialog,
2978
+ {
2979
+ isOpen: isOpen && !isLoading,
2980
+ onToggleDialog,
2981
+ dialogBody: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2982
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: [
2983
+ countDraftRelations > 0 && formatMessage(
2984
+ {
2985
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2986
+ defaultMessage: "<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. "
2987
+ },
2988
+ {
2989
+ b: BoldChunk$1,
2990
+ count: countDraftRelations,
2991
+ entities: selectedEntries.length
2992
+ }
2993
+ ),
2994
+ formatMessage({
2995
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2996
+ defaultMessage: "Are you sure you want to publish these entries?"
2997
+ })
2998
+ ] }),
2999
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2751
3000
  {
2752
- id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
2753
- defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3001
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
3002
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2754
3003
  },
2755
3004
  {
2756
3005
  em: Emphasis
2757
3006
  }
2758
- ) }) })
3007
+ ) })
2759
3008
  ] }),
2760
- confirmButton: formatMessage({
2761
- id: "app.utils.unpublish",
2762
- defaultMessage: "Unpublish"
2763
- }),
2764
- onConfirm: handleConfirmBulkUnpublish
3009
+ endAction: /* @__PURE__ */ jsxRuntime.jsx(
3010
+ designSystem.Button,
3011
+ {
3012
+ onClick: onConfirm,
3013
+ variant: "secondary",
3014
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3015
+ loading: isConfirmButtonLoading,
3016
+ children: formatMessage({
3017
+ id: "app.utils.publish",
3018
+ defaultMessage: "Publish"
3019
+ })
3020
+ }
3021
+ )
2765
3022
  }
2766
- };
3023
+ );
2767
3024
  };
2768
- UnpublishAction.type = "unpublish";
2769
- const Emphasis = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
2770
- const DEFAULT_BULK_ACTIONS = [UnpublishAction, DeleteAction];
2771
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3025
+ const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
3026
+ max-width: 300px;
3027
+ `;
3028
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3029
+ const messages = [];
3030
+ Object.entries(errors).forEach(([key, value]) => {
3031
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3032
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3033
+ if ("id" in value && "defaultMessage" in value) {
3034
+ messages.push(
3035
+ formatMessage(
3036
+ {
3037
+ id: `${value.id}.withField`,
3038
+ defaultMessage: value.defaultMessage
3039
+ },
3040
+ { field: currentKey }
3041
+ )
3042
+ );
3043
+ } else {
3044
+ messages.push(
3045
+ ...formatErrorMessages(
3046
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3047
+ value,
3048
+ currentKey,
3049
+ formatMessage
3050
+ )
3051
+ );
3052
+ }
3053
+ } else {
3054
+ messages.push(
3055
+ formatMessage(
3056
+ {
3057
+ id: `${value}.withField`,
3058
+ defaultMessage: value
3059
+ },
3060
+ { field: currentKey }
3061
+ )
3062
+ );
3063
+ }
3064
+ });
3065
+ return messages;
3066
+ };
3067
+ const EntryValidationText = ({ validationErrors, status }) => {
2772
3068
  const { formatMessage } = reactIntl.useIntl();
2773
- const getDefaultErrorMessage = (reason) => {
2774
- switch (reason) {
2775
- case "relation":
2776
- return "Duplicating the relation could remove it from the original entry.";
2777
- case "unique":
2778
- return "Identical values in a unique field are not allowed";
2779
- default:
2780
- return reason;
3069
+ if (validationErrors) {
3070
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3071
+ " "
3072
+ );
3073
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3074
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
3075
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3076
+ ] });
3077
+ }
3078
+ if (status === "published") {
3079
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3080
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3081
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3082
+ id: "content-manager.bulk-publish.already-published",
3083
+ defaultMessage: "Already Published"
3084
+ }) })
3085
+ ] });
3086
+ }
3087
+ if (status === "modified") {
3088
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3089
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3090
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3091
+ id: "content-manager.bulk-publish.modified",
3092
+ defaultMessage: "Ready to publish changes"
3093
+ }) })
3094
+ ] });
3095
+ }
3096
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3097
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3098
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3099
+ id: "app.utils.ready-to-publish",
3100
+ defaultMessage: "Ready to publish"
3101
+ }) })
3102
+ ] });
3103
+ };
3104
+ const TABLE_HEADERS = [
3105
+ { name: "id", label: "id" },
3106
+ { name: "name", label: "name" },
3107
+ { name: "status", label: "status" },
3108
+ { name: "publicationStatus", label: "Publication status" }
3109
+ ];
3110
+ const SelectedEntriesTableContent = ({
3111
+ isPublishing,
3112
+ rowsToDisplay = [],
3113
+ entriesToPublish = [],
3114
+ validationErrors = {}
3115
+ }) => {
3116
+ const { pathname } = reactRouterDom.useLocation();
3117
+ const { formatMessage } = reactIntl.useIntl();
3118
+ const {
3119
+ list: {
3120
+ settings: { mainField }
2781
3121
  }
2782
- };
2783
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2784
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
2785
- id: getTranslation("containers.list.autoCloneModal.title"),
2786
- defaultMessage: "This entry can't be duplicated directly."
3122
+ } = useDocLayout();
3123
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3124
+ return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
3125
+ /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
3126
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCheckboxCell, {}),
3127
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3128
+ (head) => /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCell, { ...head }, head.name)
3129
+ )
3130
+ ] }),
3131
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3132
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3133
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3134
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3135
+ shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
3136
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3137
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3138
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3139
+ id: "content-manager.success.record.publishing",
3140
+ defaultMessage: "Publishing..."
3141
+ }) }),
3142
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
3143
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
3144
+ EntryValidationText,
3145
+ {
3146
+ validationErrors: validationErrors[row.documentId],
3147
+ status: row.status
3148
+ }
3149
+ ) }),
3150
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3151
+ designSystem.IconButton,
3152
+ {
3153
+ tag: reactRouterDom.Link,
3154
+ to: {
3155
+ pathname: `${pathname}/${row.documentId}`,
3156
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3157
+ },
3158
+ state: { from: pathname },
3159
+ label: formatMessage(
3160
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3161
+ {
3162
+ target: formatMessage(
3163
+ {
3164
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3165
+ defaultMessage: "item line {number}"
3166
+ },
3167
+ { number: index2 + 1 }
3168
+ )
3169
+ }
3170
+ ),
3171
+ target: "_blank",
3172
+ marginLeft: "auto",
3173
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3174
+ }
3175
+ ) })
3176
+ ] }, row.id)) })
3177
+ ] });
3178
+ };
3179
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3180
+ const SelectedEntriesModalContent = ({
3181
+ listViewSelectedEntries,
3182
+ toggleModal,
3183
+ setListViewSelectedDocuments,
3184
+ model
3185
+ }) => {
3186
+ const { formatMessage } = reactIntl.useIntl();
3187
+ const { schema, components } = useContentTypeSchema(model);
3188
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3189
+ const [{ query }] = strapiAdmin.useQueryParams();
3190
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3191
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3192
+ {
3193
+ model,
3194
+ params: {
3195
+ page: "1",
3196
+ pageSize: documentIds.length.toString(),
3197
+ sort: query.sort,
3198
+ filters: {
3199
+ documentId: {
3200
+ $in: documentIds
3201
+ }
3202
+ },
3203
+ locale: query.plugins?.i18n?.locale
3204
+ }
3205
+ },
3206
+ {
3207
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3208
+ }
3209
+ );
3210
+ const { rows, validationErrors } = React__namespace.useMemo(() => {
3211
+ if (data.length > 0 && schema) {
3212
+ const validate = createYupSchema(schema.attributes, components);
3213
+ const validationErrors2 = {};
3214
+ const rows2 = data.map((entry) => {
3215
+ try {
3216
+ validate.validateSync(entry, { abortEarly: false });
3217
+ return entry;
3218
+ } catch (e) {
3219
+ if (e instanceof yup.ValidationError) {
3220
+ validationErrors2[entry.documentId] = strapiAdmin.getYupValidationErrors(e);
3221
+ }
3222
+ return entry;
3223
+ }
3224
+ });
3225
+ return { rows: rows2, validationErrors: validationErrors2 };
3226
+ }
3227
+ return {
3228
+ rows: [],
3229
+ validationErrors: {}
3230
+ };
3231
+ }, [components, data, schema]);
3232
+ const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3233
+ const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3234
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3235
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3236
+ const selectedRows = strapiAdmin.useTable("publishAction", (state) => state.selectedRows);
3237
+ const selectedEntries = rows.filter(
3238
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3239
+ );
3240
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3241
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3242
+ ({ documentId }) => validationErrors[documentId]
3243
+ ).length;
3244
+ const selectedEntriesPublished = selectedEntries.filter(
3245
+ ({ status }) => status === "published"
3246
+ ).length;
3247
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3248
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3249
+ const handleConfirmBulkPublish = async () => {
3250
+ toggleDialog();
3251
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3252
+ if (!("error" in res)) {
3253
+ setPublishedCount(res.count);
3254
+ const unpublishedEntries = rows.filter((row) => {
3255
+ return !entriesToPublish.includes(row.documentId);
3256
+ });
3257
+ setListViewSelectedDocuments(unpublishedEntries);
3258
+ }
3259
+ };
3260
+ const getFormattedCountMessage = () => {
3261
+ if (publishedCount) {
3262
+ return formatMessage(
3263
+ {
3264
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3265
+ defaultMessage: "<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."
3266
+ },
3267
+ {
3268
+ publishedCount,
3269
+ withErrorsCount: selectedEntriesWithErrorsCount,
3270
+ b: BoldChunk
3271
+ }
3272
+ );
3273
+ }
3274
+ return formatMessage(
3275
+ {
3276
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3277
+ defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <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."
3278
+ },
3279
+ {
3280
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3281
+ withErrorsCount: selectedEntriesWithErrorsCount,
3282
+ alreadyPublishedCount: selectedEntriesPublished,
3283
+ b: BoldChunk
3284
+ }
3285
+ );
3286
+ };
3287
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3288
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3289
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3290
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3291
+ SelectedEntriesTableContent,
3292
+ {
3293
+ isPublishing: isSubmittingForm,
3294
+ rowsToDisplay: rows,
3295
+ entriesToPublish,
3296
+ validationErrors
3297
+ }
3298
+ ) })
3299
+ ] }),
3300
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3301
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3302
+ id: "app.components.Button.cancel",
3303
+ defaultMessage: "Cancel"
3304
+ }) }),
3305
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3306
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3307
+ /* @__PURE__ */ jsxRuntime.jsx(
3308
+ designSystem.Button,
3309
+ {
3310
+ onClick: toggleDialog,
3311
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3312
+ loading: isSubmittingForm,
3313
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3314
+ }
3315
+ )
3316
+ ] })
3317
+ ] }),
3318
+ /* @__PURE__ */ jsxRuntime.jsx(
3319
+ ConfirmDialogPublishAll,
3320
+ {
3321
+ isOpen: isDialogOpen,
3322
+ onToggleDialog: toggleDialog,
3323
+ isConfirmButtonLoading: isSubmittingForm,
3324
+ onConfirm: handleConfirmBulkPublish
3325
+ }
3326
+ )
3327
+ ] });
3328
+ };
3329
+ const PublishAction = ({ documents, model }) => {
3330
+ const { formatMessage } = reactIntl.useIntl();
3331
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3332
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3333
+ const setListViewSelectedDocuments = strapiAdmin.useTable("publishAction", (state) => state.selectRow);
3334
+ const refetchList = () => {
3335
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3336
+ };
3337
+ if (!showPublishButton)
3338
+ return null;
3339
+ return {
3340
+ actionType: "publish",
3341
+ variant: "tertiary",
3342
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3343
+ dialog: {
3344
+ type: "modal",
3345
+ title: formatMessage({
3346
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3347
+ defaultMessage: "Publish entries"
3348
+ }),
3349
+ content: ({ onClose }) => {
3350
+ return /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsxRuntime.jsx(
3351
+ SelectedEntriesModalContent,
3352
+ {
3353
+ listViewSelectedEntries: documents,
3354
+ toggleModal: () => {
3355
+ onClose();
3356
+ refetchList();
3357
+ },
3358
+ setListViewSelectedDocuments,
3359
+ model
3360
+ }
3361
+ ) });
3362
+ },
3363
+ onClose: () => {
3364
+ refetchList();
3365
+ }
3366
+ }
3367
+ };
3368
+ };
3369
+ const BulkActionsRenderer = () => {
3370
+ const plugins = strapiAdmin.useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3371
+ const { model, collectionType } = useDoc();
3372
+ const { selectedRows } = strapiAdmin.useTable("BulkActionsRenderer", (state) => state);
3373
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3374
+ strapiAdmin.DescriptionComponentRenderer,
3375
+ {
3376
+ props: {
3377
+ model,
3378
+ collectionType,
3379
+ documents: selectedRows
3380
+ },
3381
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3382
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3383
+ }
3384
+ ) });
3385
+ };
3386
+ const DeleteAction = ({ documents, model }) => {
3387
+ const { formatMessage } = reactIntl.useIntl();
3388
+ const { schema: contentType } = useDoc();
3389
+ const selectRow = strapiAdmin.useTable("DeleteAction", (state) => state.selectRow);
3390
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3391
+ const [{ query }] = strapiAdmin.useQueryParams();
3392
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3393
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3394
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3395
+ const documentIds = documents.map(({ documentId }) => documentId);
3396
+ const handleConfirmBulkDelete = async () => {
3397
+ const res = await bulkDeleteAction({
3398
+ documentIds,
3399
+ model,
3400
+ params
3401
+ });
3402
+ if (!("error" in res)) {
3403
+ selectRow([]);
3404
+ }
3405
+ };
3406
+ if (!hasDeletePermission)
3407
+ return null;
3408
+ return {
3409
+ variant: "danger-light",
3410
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3411
+ dialog: {
3412
+ type: "dialog",
3413
+ title: formatMessage({
3414
+ id: "app.components.ConfirmDialog.title",
3415
+ defaultMessage: "Confirmation"
3416
+ }),
3417
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3418
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3419
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3420
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3421
+ defaultMessage: "Are you sure you want to delete these entries?"
3422
+ }) }),
3423
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3424
+ {
3425
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3426
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3427
+ },
3428
+ {
3429
+ em: Emphasis
3430
+ }
3431
+ ) }) })
3432
+ ] }),
3433
+ onConfirm: handleConfirmBulkDelete
3434
+ }
3435
+ };
3436
+ };
3437
+ DeleteAction.type = "delete";
3438
+ const UnpublishAction = ({ documents, model }) => {
3439
+ const { formatMessage } = reactIntl.useIntl();
3440
+ const { schema } = useDoc();
3441
+ const selectRow = strapiAdmin.useTable("UnpublishAction", (state) => state.selectRow);
3442
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3443
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3444
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3445
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3446
+ const documentIds = documents.map(({ documentId }) => documentId);
3447
+ const [{ query }] = strapiAdmin.useQueryParams();
3448
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3449
+ const handleConfirmBulkUnpublish = async () => {
3450
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3451
+ if (!("error" in data)) {
3452
+ selectRow([]);
3453
+ }
3454
+ };
3455
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3456
+ if (!showUnpublishButton)
3457
+ return null;
3458
+ return {
3459
+ variant: "tertiary",
3460
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3461
+ dialog: {
3462
+ type: "dialog",
3463
+ title: formatMessage({
3464
+ id: "app.components.ConfirmDialog.title",
3465
+ defaultMessage: "Confirmation"
3466
+ }),
3467
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3468
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3469
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3470
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3471
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3472
+ }) }),
3473
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3474
+ {
3475
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3476
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3477
+ },
3478
+ {
3479
+ em: Emphasis
3480
+ }
3481
+ ) }) })
3482
+ ] }),
3483
+ confirmButton: formatMessage({
3484
+ id: "app.utils.unpublish",
3485
+ defaultMessage: "Unpublish"
3486
+ }),
3487
+ onConfirm: handleConfirmBulkUnpublish
3488
+ }
3489
+ };
3490
+ };
3491
+ UnpublishAction.type = "unpublish";
3492
+ const Emphasis = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3493
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3494
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3495
+ const { formatMessage } = reactIntl.useIntl();
3496
+ const getDefaultErrorMessage = (reason) => {
3497
+ switch (reason) {
3498
+ case "relation":
3499
+ return "Duplicating the relation could remove it from the original entry.";
3500
+ case "unique":
3501
+ return "Identical values in a unique field are not allowed";
3502
+ default:
3503
+ return reason;
3504
+ }
3505
+ };
3506
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3507
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
3508
+ id: getTranslation("containers.list.autoCloneModal.title"),
3509
+ defaultMessage: "This entry can't be duplicated directly."
2787
3510
  }) }),
2788
3511
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
2789
3512
  id: getTranslation("containers.list.autoCloneModal.description"),
@@ -2826,596 +3549,339 @@ const TableActions = ({ document }) => {
2826
3549
  const { model, collectionType } = useDoc();
2827
3550
  const plugins = strapiAdmin.useStrapiApp("TableActions", (state) => state.plugins);
2828
3551
  const props = {
2829
- activeTab: null,
2830
- model,
2831
- documentId: document.documentId,
2832
- collectionType,
2833
- document
2834
- };
2835
- return /* @__PURE__ */ jsxRuntime.jsx(
2836
- strapiAdmin.DescriptionComponentRenderer,
2837
- {
2838
- props,
2839
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2840
- children: (actions2) => {
2841
- const tableRowActions = actions2.filter((action) => {
2842
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2843
- return positions.includes("table-row");
2844
- });
2845
- return /* @__PURE__ */ jsxRuntime.jsx(
2846
- DocumentActionsMenu,
2847
- {
2848
- actions: tableRowActions,
2849
- label: formatMessage({
2850
- id: "content-manager.containers.list.table.row-actions",
2851
- defaultMessage: "Row action"
2852
- }),
2853
- variant: "ghost"
2854
- }
2855
- );
2856
- }
2857
- }
2858
- );
2859
- };
2860
- const EditAction = ({ documentId }) => {
2861
- const navigate = reactRouterDom.useNavigate();
2862
- const { formatMessage } = reactIntl.useIntl();
2863
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2864
- const { toggleNotification } = strapiAdmin.useNotification();
2865
- const [{ query }] = strapiAdmin.useQueryParams();
2866
- return {
2867
- disabled: !canRead,
2868
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledPencil, {}),
2869
- label: formatMessage({
2870
- id: "content-manager.actions.edit.label",
2871
- defaultMessage: "Edit"
2872
- }),
2873
- position: "table-row",
2874
- onClick: async () => {
2875
- if (!documentId) {
2876
- console.error(
2877
- "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
2878
- );
2879
- toggleNotification({
2880
- message: formatMessage({
2881
- id: "content-manager.actions.edit.error",
2882
- defaultMessage: "An error occurred while trying to edit the document."
2883
- }),
2884
- type: "danger"
2885
- });
2886
- return;
2887
- }
2888
- navigate({
2889
- pathname: documentId,
2890
- search: qs.stringify({
2891
- plugins: query.plugins
2892
- })
2893
- });
2894
- }
2895
- };
2896
- };
2897
- EditAction.type = "edit";
2898
- const StyledPencil = styledComponents.styled(Icons.Pencil)`
2899
- path {
2900
- fill: currentColor;
2901
- }
2902
- `;
2903
- const CloneAction = ({ model, documentId }) => {
2904
- const navigate = reactRouterDom.useNavigate();
2905
- const { formatMessage } = reactIntl.useIntl();
2906
- const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
2907
- const { toggleNotification } = strapiAdmin.useNotification();
2908
- const { autoClone } = useDocumentActions();
2909
- const [prohibitedFields, setProhibitedFields] = React__namespace.useState([]);
2910
- return {
2911
- disabled: !canCreate,
2912
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledDuplicate, {}),
2913
- label: formatMessage({
2914
- id: "content-manager.actions.clone.label",
2915
- defaultMessage: "Duplicate"
2916
- }),
2917
- position: "table-row",
2918
- onClick: async () => {
2919
- if (!documentId) {
2920
- console.error(
2921
- "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
2922
- );
2923
- toggleNotification({
2924
- message: formatMessage({
2925
- id: "content-manager.actions.clone.error",
2926
- defaultMessage: "An error occurred while trying to clone the document."
2927
- }),
2928
- type: "danger"
2929
- });
2930
- return;
2931
- }
2932
- const res = await autoClone({ model, sourceId: documentId });
2933
- if ("data" in res) {
2934
- navigate(res.data.documentId);
2935
- return true;
2936
- }
2937
- if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
2938
- const prohibitedFields2 = res.error.details.prohibitedFields;
2939
- setProhibitedFields(prohibitedFields2);
2940
- }
2941
- },
2942
- dialog: {
2943
- type: "modal",
2944
- title: formatMessage({
2945
- id: "content-manager.containers.list.autoCloneModal.header",
2946
- defaultMessage: "Duplicate"
2947
- }),
2948
- content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2949
- footer: ({ onClose }) => {
2950
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
2951
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2952
- id: "cancel",
2953
- defaultMessage: "Cancel"
2954
- }) }),
2955
- /* @__PURE__ */ jsxRuntime.jsx(
2956
- designSystem.LinkButton,
2957
- {
2958
- tag: reactRouterDom.NavLink,
2959
- to: {
2960
- pathname: `clone/${documentId}`
2961
- },
2962
- children: formatMessage({
2963
- id: "content-manager.containers.list.autoCloneModal.create",
2964
- defaultMessage: "Create"
2965
- })
2966
- }
2967
- )
2968
- ] });
2969
- }
2970
- }
2971
- };
2972
- };
2973
- CloneAction.type = "clone";
2974
- const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
2975
- path {
2976
- fill: currentColor;
2977
- }
2978
- `;
2979
- const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
2980
- class ContentManagerPlugin {
2981
- /**
2982
- * The following properties are the stored ones provided by any plugins registering with
2983
- * the content-manager. The function calls however, need to be called at runtime in the
2984
- * application, so instead we collate them and run them later with the complete list incl.
2985
- * ones already registered & the context of the view.
2986
- */
2987
- bulkActions = [...DEFAULT_BULK_ACTIONS];
2988
- documentActions = [
2989
- ...DEFAULT_ACTIONS,
2990
- ...DEFAULT_TABLE_ROW_ACTIONS,
2991
- ...DEFAULT_HEADER_ACTIONS,
2992
- HistoryAction
2993
- ];
2994
- editViewSidePanels = [ActionsPanel];
2995
- headerActions = [];
2996
- constructor() {
2997
- }
2998
- addEditViewSidePanel(panels) {
2999
- if (Array.isArray(panels)) {
3000
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3001
- } else if (typeof panels === "function") {
3002
- this.editViewSidePanels = panels(this.editViewSidePanels);
3003
- } else {
3004
- throw new Error(
3005
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3006
- panels
3007
- )}`
3008
- );
3009
- }
3010
- }
3011
- addDocumentAction(actions2) {
3012
- if (Array.isArray(actions2)) {
3013
- this.documentActions = [...this.documentActions, ...actions2];
3014
- } else if (typeof actions2 === "function") {
3015
- this.documentActions = actions2(this.documentActions);
3016
- } else {
3017
- throw new Error(
3018
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
3019
- actions2
3020
- )}`
3021
- );
3022
- }
3023
- }
3024
- addDocumentHeaderAction(actions2) {
3025
- if (Array.isArray(actions2)) {
3026
- this.headerActions = [...this.headerActions, ...actions2];
3027
- } else if (typeof actions2 === "function") {
3028
- this.headerActions = actions2(this.headerActions);
3029
- } else {
3030
- throw new Error(
3031
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3032
- actions2
3033
- )}`
3034
- );
3035
- }
3036
- }
3037
- addBulkAction(actions2) {
3038
- if (Array.isArray(actions2)) {
3039
- this.bulkActions = [...this.bulkActions, ...actions2];
3040
- } else if (typeof actions2 === "function") {
3041
- this.bulkActions = actions2(this.bulkActions);
3042
- } else {
3043
- throw new Error(
3044
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3045
- actions2
3046
- )}`
3047
- );
3048
- }
3049
- }
3050
- get config() {
3051
- return {
3052
- id: PLUGIN_ID,
3053
- name: "Content Manager",
3054
- injectionZones: INJECTION_ZONES,
3055
- apis: {
3056
- addBulkAction: this.addBulkAction.bind(this),
3057
- addDocumentAction: this.addDocumentAction.bind(this),
3058
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3059
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3060
- getBulkActions: () => this.bulkActions,
3061
- getDocumentActions: () => this.documentActions,
3062
- getEditViewSidePanels: () => this.editViewSidePanels,
3063
- getHeaderActions: () => this.headerActions
3064
- }
3065
- };
3066
- }
3067
- }
3068
- const getPrintableType = (value) => {
3069
- const nativeType = typeof value;
3070
- if (nativeType === "object") {
3071
- if (value === null)
3072
- return "null";
3073
- if (Array.isArray(value))
3074
- return "array";
3075
- if (value instanceof Object && value.constructor.name !== "Object") {
3076
- return value.constructor.name;
3077
- }
3078
- }
3079
- return nativeType;
3080
- };
3081
- const initialState = {
3082
- collectionTypeLinks: [],
3083
- components: [],
3084
- fieldSizes: {},
3085
- models: [],
3086
- singleTypeLinks: [],
3087
- isLoading: true
3088
- };
3089
- const appSlice = toolkit.createSlice({
3090
- name: "app",
3091
- initialState,
3092
- reducers: {
3093
- setInitialData(state, action) {
3094
- const {
3095
- authorizedCollectionTypeLinks,
3096
- authorizedSingleTypeLinks,
3097
- components,
3098
- contentTypeSchemas,
3099
- fieldSizes
3100
- } = action.payload;
3101
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3102
- ({ isDisplayed }) => isDisplayed
3103
- );
3104
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3105
- state.components = components;
3106
- state.models = contentTypeSchemas;
3107
- state.fieldSizes = fieldSizes;
3108
- state.isLoading = false;
3109
- }
3110
- }
3111
- });
3112
- const { actions, reducer: reducer$1 } = appSlice;
3113
- const { setInitialData } = actions;
3114
- const reducer = toolkit.combineReducers({
3115
- app: reducer$1
3116
- });
3117
- const HOOKS = {
3118
- /**
3119
- * Hook that allows to mutate the displayed headers of the list view table
3120
- * @constant
3121
- * @type {string}
3122
- */
3123
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
3124
- /**
3125
- * Hook that allows to mutate the CM's collection types links pre-set filters
3126
- * @constant
3127
- * @type {string}
3128
- */
3129
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
3130
- /**
3131
- * Hook that allows to mutate the CM's edit view layout
3132
- * @constant
3133
- * @type {string}
3134
- */
3135
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
3136
- /**
3137
- * Hook that allows to mutate the CM's single types links pre-set filters
3138
- * @constant
3139
- * @type {string}
3140
- */
3141
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
3142
- };
3143
- const contentTypesApi = contentManagerApi.injectEndpoints({
3144
- endpoints: (builder) => ({
3145
- getContentTypeConfiguration: builder.query({
3146
- query: (uid) => ({
3147
- url: `/content-manager/content-types/${uid}/configuration`,
3148
- method: "GET"
3149
- }),
3150
- transformResponse: (response) => response.data,
3151
- providesTags: (_result, _error, uid) => [
3152
- { type: "ContentTypesConfiguration", id: uid },
3153
- { type: "ContentTypeSettings", id: "LIST" }
3154
- ]
3155
- }),
3156
- getAllContentTypeSettings: builder.query({
3157
- query: () => "/content-manager/content-types-settings",
3158
- transformResponse: (response) => response.data,
3159
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
3160
- }),
3161
- updateContentTypeConfiguration: builder.mutation({
3162
- query: ({ uid, ...body }) => ({
3163
- url: `/content-manager/content-types/${uid}/configuration`,
3164
- method: "PUT",
3165
- data: body
3166
- }),
3167
- transformResponse: (response) => response.data,
3168
- invalidatesTags: (_result, _error, { uid }) => [
3169
- { type: "ContentTypesConfiguration", id: uid },
3170
- { type: "ContentTypeSettings", id: "LIST" },
3171
- // Is this necessary?
3172
- { type: "InitialData" }
3173
- ]
3174
- })
3175
- })
3176
- });
3177
- const {
3178
- useGetContentTypeConfigurationQuery,
3179
- useGetAllContentTypeSettingsQuery,
3180
- useUpdateContentTypeConfigurationMutation
3181
- } = contentTypesApi;
3182
- const checkIfAttributeIsDisplayable = (attribute) => {
3183
- const { type } = attribute;
3184
- if (type === "relation") {
3185
- return !attribute.relation.toLowerCase().includes("morph");
3186
- }
3187
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
3188
- };
3189
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
3190
- if (!mainFieldName) {
3191
- return void 0;
3192
- }
3193
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
3194
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
3195
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
3196
- );
3197
- return {
3198
- name: mainFieldName,
3199
- type: mainFieldType ?? "string"
3552
+ activeTab: null,
3553
+ model,
3554
+ documentId: document.documentId,
3555
+ collectionType,
3556
+ document
3200
3557
  };
3558
+ return /* @__PURE__ */ jsxRuntime.jsx(
3559
+ strapiAdmin.DescriptionComponentRenderer,
3560
+ {
3561
+ props,
3562
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3563
+ children: (actions2) => {
3564
+ const tableRowActions = actions2.filter((action) => {
3565
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3566
+ return positions.includes("table-row");
3567
+ });
3568
+ return /* @__PURE__ */ jsxRuntime.jsx(
3569
+ DocumentActionsMenu,
3570
+ {
3571
+ actions: tableRowActions,
3572
+ label: formatMessage({
3573
+ id: "content-manager.containers.list.table.row-actions",
3574
+ defaultMessage: "Row action"
3575
+ }),
3576
+ variant: "ghost"
3577
+ }
3578
+ );
3579
+ }
3580
+ }
3581
+ );
3201
3582
  };
3202
- const DEFAULT_SETTINGS = {
3203
- bulkable: false,
3204
- filterable: false,
3205
- searchable: false,
3206
- pagination: false,
3207
- defaultSortBy: "",
3208
- defaultSortOrder: "asc",
3209
- mainField: "id",
3210
- pageSize: 10
3211
- };
3212
- const useDocumentLayout = (model) => {
3213
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
3214
- const [{ query }] = strapiAdmin.useQueryParams();
3215
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
3583
+ const EditAction = ({ documentId }) => {
3584
+ const navigate = reactRouterDom.useNavigate();
3585
+ const { formatMessage } = reactIntl.useIntl();
3586
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3216
3587
  const { toggleNotification } = strapiAdmin.useNotification();
3217
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
3218
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
3219
- const {
3220
- data,
3221
- isLoading: isLoadingConfigs,
3222
- error,
3223
- isFetching: isFetchingConfigs
3224
- } = useGetContentTypeConfigurationQuery(model);
3225
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
3226
- React__namespace.useEffect(() => {
3227
- if (error) {
3228
- toggleNotification({
3229
- type: "danger",
3230
- message: formatAPIError(error)
3588
+ const [{ query }] = strapiAdmin.useQueryParams();
3589
+ return {
3590
+ disabled: !canRead,
3591
+ icon: /* @__PURE__ */ jsxRuntime.jsx(StyledPencil, {}),
3592
+ label: formatMessage({
3593
+ id: "content-manager.actions.edit.label",
3594
+ defaultMessage: "Edit"
3595
+ }),
3596
+ position: "table-row",
3597
+ onClick: async () => {
3598
+ if (!documentId) {
3599
+ console.error(
3600
+ "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
3601
+ );
3602
+ toggleNotification({
3603
+ message: formatMessage({
3604
+ id: "content-manager.actions.edit.error",
3605
+ defaultMessage: "An error occurred while trying to edit the document."
3606
+ }),
3607
+ type: "danger"
3608
+ });
3609
+ return;
3610
+ }
3611
+ navigate({
3612
+ pathname: documentId,
3613
+ search: qs.stringify({
3614
+ plugins: query.plugins
3615
+ })
3231
3616
  });
3232
3617
  }
3233
- }, [error, formatAPIError, toggleNotification]);
3234
- const editLayout = React__namespace.useMemo(
3235
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
3236
- layout: [],
3237
- components: {},
3238
- metadatas: {},
3239
- options: {},
3240
- settings: DEFAULT_SETTINGS
3241
- },
3242
- [data, isLoading, schemas, schema, components]
3243
- );
3244
- const listLayout = React__namespace.useMemo(() => {
3245
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
3246
- layout: [],
3247
- metadatas: {},
3248
- options: {},
3249
- settings: DEFAULT_SETTINGS
3250
- };
3251
- }, [data, isLoading, schemas, schema, components]);
3252
- const { layout: edit } = React__namespace.useMemo(
3253
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
3254
- layout: editLayout,
3255
- query
3256
- }),
3257
- [editLayout, query, runHookWaterfall]
3258
- );
3259
- return {
3260
- error,
3261
- isLoading,
3262
- edit,
3263
- list: listLayout
3264
3618
  };
3265
3619
  };
3266
- const useDocLayout = () => {
3267
- const { model } = useDoc();
3268
- return useDocumentLayout(model);
3269
- };
3270
- const formatEditLayout = (data, {
3271
- schemas,
3272
- schema,
3273
- components
3274
- }) => {
3275
- let currentPanelIndex = 0;
3276
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
3277
- data.contentType.layouts.edit,
3278
- schema?.attributes,
3279
- data.contentType.metadatas,
3280
- { configurations: data.components, schemas: components },
3281
- schemas
3282
- ).reduce((panels, row) => {
3283
- if (row.some((field) => field.type === "dynamiczone")) {
3284
- panels.push([row]);
3285
- currentPanelIndex += 2;
3286
- } else {
3287
- if (!panels[currentPanelIndex]) {
3288
- panels.push([]);
3289
- }
3290
- panels[currentPanelIndex].push(row);
3291
- }
3292
- return panels;
3293
- }, []);
3294
- const componentEditAttributes = Object.entries(data.components).reduce(
3295
- (acc, [uid, configuration]) => {
3296
- acc[uid] = {
3297
- layout: convertEditLayoutToFieldLayouts(
3298
- configuration.layouts.edit,
3299
- components[uid].attributes,
3300
- configuration.metadatas
3301
- ),
3302
- settings: {
3303
- ...configuration.settings,
3304
- icon: components[uid].info.icon,
3305
- displayName: components[uid].info.displayName
3306
- }
3307
- };
3308
- return acc;
3309
- },
3310
- {}
3311
- );
3312
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
3313
- (acc, [attribute, metadata]) => {
3314
- return {
3315
- ...acc,
3316
- [attribute]: metadata.edit
3317
- };
3318
- },
3319
- {}
3320
- );
3620
+ EditAction.type = "edit";
3621
+ const StyledPencil = styledComponents.styled(Icons.Pencil)`
3622
+ path {
3623
+ fill: currentColor;
3624
+ }
3625
+ `;
3626
+ const CloneAction = ({ model, documentId }) => {
3627
+ const navigate = reactRouterDom.useNavigate();
3628
+ const { formatMessage } = reactIntl.useIntl();
3629
+ const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
3630
+ const { toggleNotification } = strapiAdmin.useNotification();
3631
+ const { autoClone } = useDocumentActions();
3632
+ const [prohibitedFields, setProhibitedFields] = React__namespace.useState([]);
3321
3633
  return {
3322
- layout: panelledEditAttributes,
3323
- components: componentEditAttributes,
3324
- metadatas: editMetadatas,
3325
- settings: {
3326
- ...data.contentType.settings,
3327
- displayName: schema?.info.displayName
3634
+ disabled: !canCreate,
3635
+ icon: /* @__PURE__ */ jsxRuntime.jsx(StyledDuplicate, {}),
3636
+ label: formatMessage({
3637
+ id: "content-manager.actions.clone.label",
3638
+ defaultMessage: "Duplicate"
3639
+ }),
3640
+ position: "table-row",
3641
+ onClick: async () => {
3642
+ if (!documentId) {
3643
+ console.error(
3644
+ "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
3645
+ );
3646
+ toggleNotification({
3647
+ message: formatMessage({
3648
+ id: "content-manager.actions.clone.error",
3649
+ defaultMessage: "An error occurred while trying to clone the document."
3650
+ }),
3651
+ type: "danger"
3652
+ });
3653
+ return;
3654
+ }
3655
+ const res = await autoClone({ model, sourceId: documentId });
3656
+ if ("data" in res) {
3657
+ navigate(res.data.documentId);
3658
+ return true;
3659
+ }
3660
+ if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
3661
+ const prohibitedFields2 = res.error.details.prohibitedFields;
3662
+ setProhibitedFields(prohibitedFields2);
3663
+ }
3328
3664
  },
3329
- options: {
3330
- ...schema?.options,
3331
- ...schema?.pluginOptions,
3332
- ...data.contentType.options
3665
+ dialog: {
3666
+ type: "modal",
3667
+ title: formatMessage({
3668
+ id: "content-manager.containers.list.autoCloneModal.header",
3669
+ defaultMessage: "Duplicate"
3670
+ }),
3671
+ content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3672
+ footer: ({ onClose }) => {
3673
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3674
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3675
+ id: "cancel",
3676
+ defaultMessage: "Cancel"
3677
+ }) }),
3678
+ /* @__PURE__ */ jsxRuntime.jsx(
3679
+ designSystem.LinkButton,
3680
+ {
3681
+ tag: reactRouterDom.NavLink,
3682
+ to: {
3683
+ pathname: `clone/${documentId}`
3684
+ },
3685
+ children: formatMessage({
3686
+ id: "content-manager.containers.list.autoCloneModal.create",
3687
+ defaultMessage: "Create"
3688
+ })
3689
+ }
3690
+ )
3691
+ ] });
3692
+ }
3333
3693
  }
3334
3694
  };
3335
3695
  };
3336
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3337
- return rows.map(
3338
- (row) => row.map((field) => {
3339
- const attribute = attributes[field.name];
3340
- if (!attribute) {
3341
- return null;
3696
+ CloneAction.type = "clone";
3697
+ const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
3698
+ path {
3699
+ fill: currentColor;
3700
+ }
3701
+ `;
3702
+ const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
3703
+ class ContentManagerPlugin {
3704
+ /**
3705
+ * The following properties are the stored ones provided by any plugins registering with
3706
+ * the content-manager. The function calls however, need to be called at runtime in the
3707
+ * application, so instead we collate them and run them later with the complete list incl.
3708
+ * ones already registered & the context of the view.
3709
+ */
3710
+ bulkActions = [...DEFAULT_BULK_ACTIONS];
3711
+ documentActions = [
3712
+ ...DEFAULT_ACTIONS,
3713
+ ...DEFAULT_TABLE_ROW_ACTIONS,
3714
+ ...DEFAULT_HEADER_ACTIONS
3715
+ ];
3716
+ editViewSidePanels = [ActionsPanel];
3717
+ headerActions = [];
3718
+ constructor() {
3719
+ }
3720
+ addEditViewSidePanel(panels) {
3721
+ if (Array.isArray(panels)) {
3722
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3723
+ } else if (typeof panels === "function") {
3724
+ this.editViewSidePanels = panels(this.editViewSidePanels);
3725
+ } else {
3726
+ throw new Error(
3727
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3728
+ panels
3729
+ )}`
3730
+ );
3731
+ }
3732
+ }
3733
+ addDocumentAction(actions2) {
3734
+ if (Array.isArray(actions2)) {
3735
+ this.documentActions = [...this.documentActions, ...actions2];
3736
+ } else if (typeof actions2 === "function") {
3737
+ this.documentActions = actions2(this.documentActions);
3738
+ } else {
3739
+ throw new Error(
3740
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
3741
+ actions2
3742
+ )}`
3743
+ );
3744
+ }
3745
+ }
3746
+ addDocumentHeaderAction(actions2) {
3747
+ if (Array.isArray(actions2)) {
3748
+ this.headerActions = [...this.headerActions, ...actions2];
3749
+ } else if (typeof actions2 === "function") {
3750
+ this.headerActions = actions2(this.headerActions);
3751
+ } else {
3752
+ throw new Error(
3753
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3754
+ actions2
3755
+ )}`
3756
+ );
3757
+ }
3758
+ }
3759
+ addBulkAction(actions2) {
3760
+ if (Array.isArray(actions2)) {
3761
+ this.bulkActions = [...this.bulkActions, ...actions2];
3762
+ } else if (typeof actions2 === "function") {
3763
+ this.bulkActions = actions2(this.bulkActions);
3764
+ } else {
3765
+ throw new Error(
3766
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3767
+ actions2
3768
+ )}`
3769
+ );
3770
+ }
3771
+ }
3772
+ get config() {
3773
+ return {
3774
+ id: PLUGIN_ID,
3775
+ name: "Content Manager",
3776
+ injectionZones: INJECTION_ZONES,
3777
+ apis: {
3778
+ addBulkAction: this.addBulkAction.bind(this),
3779
+ addDocumentAction: this.addDocumentAction.bind(this),
3780
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3781
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3782
+ getBulkActions: () => this.bulkActions,
3783
+ getDocumentActions: () => this.documentActions,
3784
+ getEditViewSidePanels: () => this.editViewSidePanels,
3785
+ getHeaderActions: () => this.headerActions
3342
3786
  }
3343
- const { edit: metadata } = metadatas[field.name];
3344
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3345
- return {
3346
- attribute,
3347
- disabled: !metadata.editable,
3348
- hint: metadata.description,
3349
- label: metadata.label ?? "",
3350
- name: field.name,
3351
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3352
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3353
- schemas,
3354
- components: components?.schemas ?? {}
3355
- }),
3356
- placeholder: metadata.placeholder ?? "",
3357
- required: attribute.required ?? false,
3358
- size: field.size,
3359
- unique: "unique" in attribute ? attribute.unique : false,
3360
- visible: metadata.visible ?? true,
3361
- type: attribute.type
3362
- };
3363
- }).filter((field) => field !== null)
3364
- );
3787
+ };
3788
+ }
3789
+ }
3790
+ const getPrintableType = (value) => {
3791
+ const nativeType = typeof value;
3792
+ if (nativeType === "object") {
3793
+ if (value === null)
3794
+ return "null";
3795
+ if (Array.isArray(value))
3796
+ return "array";
3797
+ if (value instanceof Object && value.constructor.name !== "Object") {
3798
+ return value.constructor.name;
3799
+ }
3800
+ }
3801
+ return nativeType;
3365
3802
  };
3366
- const formatListLayout = (data, {
3367
- schemas,
3368
- schema,
3369
- components
3370
- }) => {
3371
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3372
- (acc, [attribute, metadata]) => {
3373
- return {
3374
- ...acc,
3375
- [attribute]: metadata.list
3376
- };
3377
- },
3378
- {}
3379
- );
3380
- const listAttributes = convertListLayoutToFieldLayouts(
3381
- data.contentType.layouts.list,
3382
- schema?.attributes,
3383
- listMetadatas,
3384
- { configurations: data.components, schemas: components },
3385
- schemas
3386
- );
3803
+ const HistoryAction = ({ model, document }) => {
3804
+ const { formatMessage } = reactIntl.useIntl();
3805
+ const [{ query }] = strapiAdmin.useQueryParams();
3806
+ const navigate = reactRouterDom.useNavigate();
3807
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3808
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3809
+ return null;
3810
+ }
3387
3811
  return {
3388
- layout: listAttributes,
3389
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3390
- metadatas: listMetadatas,
3391
- options: {
3392
- ...schema?.options,
3393
- ...schema?.pluginOptions,
3394
- ...data.contentType.options
3395
- }
3812
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3813
+ label: formatMessage({
3814
+ id: "content-manager.history.document-action",
3815
+ defaultMessage: "Content History"
3816
+ }),
3817
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3818
+ disabled: (
3819
+ /**
3820
+ * The user is creating a new document.
3821
+ * It hasn't been saved yet, so there's no history to go to
3822
+ */
3823
+ !document || /**
3824
+ * The document has been created but the current dimension has never been saved.
3825
+ * For example, the user is creating a new locale in an existing document,
3826
+ * so there's no history for the document in that locale
3827
+ */
3828
+ !document.id || /**
3829
+ * History is only available for content types created by the user.
3830
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3831
+ * which start with `admin::` or `plugin::`
3832
+ */
3833
+ !model.startsWith("api::")
3834
+ ),
3835
+ position: "header"
3396
3836
  };
3397
3837
  };
3398
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3399
- return columns.map((name) => {
3400
- const attribute = attributes[name];
3401
- if (!attribute) {
3402
- return null;
3403
- }
3404
- const metadata = metadatas[name];
3405
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3406
- return {
3407
- attribute,
3408
- label: metadata.label ?? "",
3409
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3410
- schemas,
3411
- components: components?.schemas ?? {}
3412
- }),
3413
- name,
3414
- searchable: metadata.searchable ?? true,
3415
- sortable: metadata.sortable ?? true
3416
- };
3417
- }).filter((field) => field !== null);
3838
+ HistoryAction.type = "history";
3839
+ const historyAdmin = {
3840
+ bootstrap(app) {
3841
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3842
+ addDocumentAction((actions2) => {
3843
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3844
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3845
+ return actions2;
3846
+ });
3847
+ }
3848
+ };
3849
+ const initialState = {
3850
+ collectionTypeLinks: [],
3851
+ components: [],
3852
+ fieldSizes: {},
3853
+ models: [],
3854
+ singleTypeLinks: [],
3855
+ isLoading: true
3418
3856
  };
3857
+ const appSlice = toolkit.createSlice({
3858
+ name: "app",
3859
+ initialState,
3860
+ reducers: {
3861
+ setInitialData(state, action) {
3862
+ const {
3863
+ authorizedCollectionTypeLinks,
3864
+ authorizedSingleTypeLinks,
3865
+ components,
3866
+ contentTypeSchemas,
3867
+ fieldSizes
3868
+ } = action.payload;
3869
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3870
+ ({ isDisplayed }) => isDisplayed
3871
+ );
3872
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3873
+ state.components = components;
3874
+ state.models = contentTypeSchemas;
3875
+ state.fieldSizes = fieldSizes;
3876
+ state.isLoading = false;
3877
+ }
3878
+ }
3879
+ });
3880
+ const { actions, reducer: reducer$1 } = appSlice;
3881
+ const { setInitialData } = actions;
3882
+ const reducer = toolkit.combineReducers({
3883
+ app: reducer$1
3884
+ });
3419
3885
  const index = {
3420
3886
  register(app) {
3421
3887
  const cm = new ContentManagerPlugin();
@@ -3430,15 +3896,29 @@ const index = {
3430
3896
  defaultMessage: "Content Manager"
3431
3897
  },
3432
3898
  permissions: [],
3433
- Component: () => Promise.resolve().then(() => require("./layout-ni_L9kT1.js")).then((mod) => ({ default: mod.Layout })),
3434
3899
  position: 1
3435
3900
  });
3901
+ app.router.addRoute({
3902
+ path: "content-manager/*",
3903
+ lazy: async () => {
3904
+ const { Layout } = await Promise.resolve().then(() => require("./layout-C6dxWYT7.js"));
3905
+ return {
3906
+ Component: Layout
3907
+ };
3908
+ },
3909
+ children: routes
3910
+ });
3436
3911
  app.registerPlugin(cm.config);
3437
3912
  },
3913
+ bootstrap(app) {
3914
+ if (typeof historyAdmin.bootstrap === "function") {
3915
+ historyAdmin.bootstrap(app);
3916
+ }
3917
+ },
3438
3918
  async registerTrads({ locales }) {
3439
3919
  const importedTrads = await Promise.all(
3440
3920
  locales.map((locale) => {
3441
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-DTULi5-d.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3921
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-uOUIxfcQ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3442
3922
  return {
3443
3923
  data: prefixPluginTranslations(data, PLUGIN_ID),
3444
3924
  locale
@@ -3482,7 +3962,6 @@ exports.getDisplayName = getDisplayName;
3482
3962
  exports.getMainField = getMainField;
3483
3963
  exports.getTranslation = getTranslation;
3484
3964
  exports.index = index;
3485
- exports.routes = routes;
3486
3965
  exports.setInitialData = setInitialData;
3487
3966
  exports.useContentTypeSchema = useContentTypeSchema;
3488
3967
  exports.useDoc = useDoc;
@@ -3496,4 +3975,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3496
3975
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3497
3976
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3498
3977
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3499
- //# sourceMappingURL=index-CCJeB7Rw.js.map
3978
+ //# sourceMappingURL=index-CdT0kHZ8.js.map