@strapi/content-manager 0.0.0-experimental.c3e9d4b26f9fd3d9eb530b5c11f9baa1d09b13ad → 0.0.0-experimental.c592deb623aed3f74ef7fdacfad9757ed59d34f7

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 (133) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs → ComponentConfigurationPage-7-qB29e7.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs.map → ComponentConfigurationPage-7-qB29e7.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js → ComponentConfigurationPage-DP7AC0UU.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js.map → ComponentConfigurationPage-DP7AC0UU.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs → EditConfigurationPage-CI4XoymK.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs.map → EditConfigurationPage-CI4XoymK.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js → EditConfigurationPage-DITVliEI.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js.map → EditConfigurationPage-DITVliEI.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-CTTDHKkQ.js → EditViewPage-CUS2EAhB.js} +62 -47
  11. package/dist/_chunks/EditViewPage-CUS2EAhB.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-DWb0DE7R.mjs → EditViewPage-Dzpno8xI.mjs} +63 -48
  13. package/dist/_chunks/EditViewPage-Dzpno8xI.mjs.map +1 -0
  14. package/dist/_chunks/{Field-DnStdvQw.mjs → Field-B_jG_EV9.mjs} +541 -221
  15. package/dist/_chunks/Field-B_jG_EV9.mjs.map +1 -0
  16. package/dist/_chunks/{Field-C5Z1Ivdv.js → Field-CtUU1Fg8.js} +543 -223
  17. package/dist/_chunks/Field-CtUU1Fg8.js.map +1 -0
  18. package/dist/_chunks/{Form-DqGgE55Q.mjs → Form-BXHao2mZ.mjs} +53 -35
  19. package/dist/_chunks/Form-BXHao2mZ.mjs.map +1 -0
  20. package/dist/_chunks/{Form-B81OtW-k.js → Form-DTqO0ymI.js} +51 -33
  21. package/dist/_chunks/Form-DTqO0ymI.js.map +1 -0
  22. package/dist/_chunks/{History-DS6-HCYX.mjs → History-2Ah2CQ4T.mjs} +52 -29
  23. package/dist/_chunks/History-2Ah2CQ4T.mjs.map +1 -0
  24. package/dist/_chunks/{History-4NbOq2dX.js → History-C_uSGzO5.js} +51 -28
  25. package/dist/_chunks/History-C_uSGzO5.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DQJJltko.mjs → ListConfigurationPage-BjSJlaoC.mjs} +58 -48
  27. package/dist/_chunks/ListConfigurationPage-BjSJlaoC.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-CpfstlYY.js → ListConfigurationPage-nyuP7OSy.js} +57 -46
  29. package/dist/_chunks/ListConfigurationPage-nyuP7OSy.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-nQrOQuVo.mjs → ListViewPage-B75x3nz2.mjs} +103 -102
  31. package/dist/_chunks/ListViewPage-B75x3nz2.mjs.map +1 -0
  32. package/dist/_chunks/{ListViewPage-CA3I75m5.js → ListViewPage-DHgHD8Xg.js} +105 -104
  33. package/dist/_chunks/ListViewPage-DHgHD8Xg.js.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js → NoContentTypePage-CDUKdZ7d.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js.map → NoContentTypePage-CDUKdZ7d.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs → NoContentTypePage-DUacQSyF.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs.map → NoContentTypePage-DUacQSyF.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs → NoPermissionsPage-SFllMekk.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs.map → NoPermissionsPage-SFllMekk.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-CO2MK200.js → NoPermissionsPage-zwIZydDI.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-CO2MK200.js.map → NoPermissionsPage-zwIZydDI.js.map} +1 -1
  42. package/dist/_chunks/{Relations-BDRl99Ux.mjs → Relations-D2NRW8fC.mjs} +14 -10
  43. package/dist/_chunks/Relations-D2NRW8fC.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DG2jnOcr.js → Relations-NFLaRNPr.js} +14 -10
  45. package/dist/_chunks/Relations-NFLaRNPr.js.map +1 -0
  46. package/dist/_chunks/{en-fbKQxLGn.js → en-BlhnxQfj.js} +11 -9
  47. package/dist/_chunks/{en-fbKQxLGn.js.map → en-BlhnxQfj.js.map} +1 -1
  48. package/dist/_chunks/{en-Ux26r5pl.mjs → en-C8YBvRrK.mjs} +11 -9
  49. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  50. package/dist/_chunks/{index-Drt2DN7v.mjs → index-C9HxCo5R.mjs} +1008 -867
  51. package/dist/_chunks/index-C9HxCo5R.mjs.map +1 -0
  52. package/dist/_chunks/{index-BZoNZMXL.js → index-ovJRE1FM.js} +998 -857
  53. package/dist/_chunks/index-ovJRE1FM.js.map +1 -0
  54. package/dist/_chunks/{layout-BzAbmoO6.mjs → layout-DaUjDiWQ.mjs} +27 -14
  55. package/dist/_chunks/layout-DaUjDiWQ.mjs.map +1 -0
  56. package/dist/_chunks/{layout-DEYBqgF1.js → layout-UNWstw_s.js} +25 -12
  57. package/dist/_chunks/layout-UNWstw_s.js.map +1 -0
  58. package/dist/_chunks/{relations-D26zVRdi.mjs → relations-D8iFAeRu.mjs} +2 -2
  59. package/dist/_chunks/{relations-D26zVRdi.mjs.map → relations-D8iFAeRu.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-D0eZ4VWw.js → relations-NN3coOG5.js} +2 -2
  61. package/dist/_chunks/{relations-D0eZ4VWw.js.map → relations-NN3coOG5.js.map} +1 -1
  62. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  63. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  64. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  65. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  66. package/dist/admin/index.js +2 -1
  67. package/dist/admin/index.js.map +1 -1
  68. package/dist/admin/index.mjs +3 -2
  69. package/dist/admin/src/exports.d.ts +1 -1
  70. package/dist/admin/src/history/index.d.ts +3 -0
  71. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  72. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  73. package/dist/admin/src/index.d.ts +1 -0
  74. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  75. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  76. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  78. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  79. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  80. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  81. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  82. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  83. package/dist/admin/src/services/api.d.ts +1 -1
  84. package/dist/admin/src/services/components.d.ts +2 -2
  85. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  86. package/dist/admin/src/services/documents.d.ts +19 -17
  87. package/dist/admin/src/services/init.d.ts +1 -1
  88. package/dist/admin/src/services/relations.d.ts +2 -2
  89. package/dist/admin/src/services/uid.d.ts +3 -3
  90. package/dist/admin/src/utils/validation.d.ts +4 -1
  91. package/dist/server/index.js +191 -110
  92. package/dist/server/index.js.map +1 -1
  93. package/dist/server/index.mjs +192 -111
  94. package/dist/server/index.mjs.map +1 -1
  95. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  96. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  97. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  98. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  99. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  100. package/dist/server/src/history/services/history.d.ts.map +1 -1
  101. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  102. package/dist/server/src/history/services/utils.d.ts +2 -1
  103. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  104. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  105. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  106. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  107. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  108. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  109. package/dist/shared/contracts/collection-types.d.ts +3 -1
  110. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  111. package/package.json +11 -11
  112. package/dist/_chunks/EditViewPage-CTTDHKkQ.js.map +0 -1
  113. package/dist/_chunks/EditViewPage-DWb0DE7R.mjs.map +0 -1
  114. package/dist/_chunks/Field-C5Z1Ivdv.js.map +0 -1
  115. package/dist/_chunks/Field-DnStdvQw.mjs.map +0 -1
  116. package/dist/_chunks/Form-B81OtW-k.js.map +0 -1
  117. package/dist/_chunks/Form-DqGgE55Q.mjs.map +0 -1
  118. package/dist/_chunks/History-4NbOq2dX.js.map +0 -1
  119. package/dist/_chunks/History-DS6-HCYX.mjs.map +0 -1
  120. package/dist/_chunks/ListConfigurationPage-CpfstlYY.js.map +0 -1
  121. package/dist/_chunks/ListConfigurationPage-DQJJltko.mjs.map +0 -1
  122. package/dist/_chunks/ListViewPage-CA3I75m5.js.map +0 -1
  123. package/dist/_chunks/ListViewPage-nQrOQuVo.mjs.map +0 -1
  124. package/dist/_chunks/Relations-BDRl99Ux.mjs.map +0 -1
  125. package/dist/_chunks/Relations-DG2jnOcr.js.map +0 -1
  126. package/dist/_chunks/index-BZoNZMXL.js.map +0 -1
  127. package/dist/_chunks/index-Drt2DN7v.mjs.map +0 -1
  128. package/dist/_chunks/layout-BzAbmoO6.mjs.map +0 -1
  129. package/dist/_chunks/layout-DEYBqgF1.js.map +0 -1
  130. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  131. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  132. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  133. package/strapi-server.js +0 -3
@@ -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");
10
- const styledComponents = require("styled-components");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
11
9
  const yup = require("yup");
12
10
  const pipe = require("lodash/fp/pipe");
13
11
  const dateFns = require("date-fns");
12
+ const styledComponents = require("styled-components");
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";
@@ -215,10 +179,12 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
215
179
  "Document",
216
180
  "InitialData",
217
181
  "HistoryVersion",
218
- "Relations"
182
+ "Relations",
183
+ "UidAvailability"
219
184
  ]
220
185
  });
221
186
  const documentApi = contentManagerApi.injectEndpoints({
187
+ overrideExisting: true,
222
188
  endpoints: (builder) => ({
223
189
  autoCloneDocument: builder.mutation({
224
190
  query: ({ model, sourceId, query }) => ({
@@ -228,7 +194,12 @@ const documentApi = contentManagerApi.injectEndpoints({
228
194
  params: query
229
195
  }
230
196
  }),
231
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
197
+ invalidatesTags: (_result, error, { model }) => {
198
+ if (error) {
199
+ return [];
200
+ }
201
+ return [{ type: "Document", id: `${model}_LIST` }];
202
+ }
232
203
  }),
233
204
  cloneDocument: builder.mutation({
234
205
  query: ({ model, sourceId, data, params }) => ({
@@ -239,7 +210,10 @@ const documentApi = contentManagerApi.injectEndpoints({
239
210
  params
240
211
  }
241
212
  }),
242
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
213
+ invalidatesTags: (_result, _error, { model }) => [
214
+ { type: "Document", id: `${model}_LIST` },
215
+ { type: "UidAvailability", id: model }
216
+ ]
243
217
  }),
244
218
  /**
245
219
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -256,7 +230,8 @@ const documentApi = contentManagerApi.injectEndpoints({
256
230
  }),
257
231
  invalidatesTags: (result, _error, { model }) => [
258
232
  { type: "Document", id: `${model}_LIST` },
259
- "Relations"
233
+ "Relations",
234
+ { type: "UidAvailability", id: model }
260
235
  ]
261
236
  }),
262
237
  deleteDocument: builder.mutation({
@@ -297,7 +272,8 @@ const documentApi = contentManagerApi.injectEndpoints({
297
272
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
298
273
  },
299
274
  { type: "Document", id: `${model}_LIST` },
300
- "Relations"
275
+ "Relations",
276
+ { type: "UidAvailability", id: model }
301
277
  ];
302
278
  }
303
279
  }),
@@ -315,6 +291,7 @@ const documentApi = contentManagerApi.injectEndpoints({
315
291
  }),
316
292
  providesTags: (result, _error, arg) => {
317
293
  return [
294
+ { type: "Document", id: `ALL_LIST` },
318
295
  { type: "Document", id: `${arg.model}_LIST` },
319
296
  ...result?.results.map(({ documentId }) => ({
320
297
  type: "Document",
@@ -353,6 +330,11 @@ const documentApi = contentManagerApi.injectEndpoints({
353
330
  {
354
331
  type: "Document",
355
332
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
333
+ },
334
+ // Make it easy to invalidate all individual documents queries for a model
335
+ {
336
+ type: "Document",
337
+ id: `${model}_ALL_ITEMS`
356
338
  }
357
339
  ];
358
340
  }
@@ -416,8 +398,21 @@ const documentApi = contentManagerApi.injectEndpoints({
416
398
  type: "Document",
417
399
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
418
400
  },
419
- "Relations"
401
+ "Relations",
402
+ { type: "UidAvailability", id: model }
420
403
  ];
404
+ },
405
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
406
+ const patchResult = dispatch(
407
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
408
+ Object.assign(draft.data, data);
409
+ })
410
+ );
411
+ try {
412
+ await queryFulfilled;
413
+ } catch {
414
+ patchResult.undo();
415
+ }
421
416
  }
422
417
  }),
423
418
  unpublishDocument: builder.mutation({
@@ -487,7 +482,7 @@ const buildValidParams = (query) => {
487
482
  const isBaseQueryError = (error) => {
488
483
  return error.name !== void 0;
489
484
  };
490
- const createYupSchema = (attributes = {}, components = {}) => {
485
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
491
486
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
492
487
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
493
488
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -500,7 +495,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
500
495
  addMinValidation,
501
496
  addMaxValidation,
502
497
  addRegexValidation
503
- ].map((fn) => fn(attribute));
498
+ ].map((fn) => fn(attribute, options));
504
499
  const transformSchema = pipe__default.default(...validations);
505
500
  switch (attribute.type) {
506
501
  case "component": {
@@ -549,7 +544,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
549
544
  } else if (Array.isArray(value)) {
550
545
  return yup__namespace.array().of(
551
546
  yup__namespace.object().shape({
552
- id: yup__namespace.string().required()
547
+ id: yup__namespace.number().required()
553
548
  })
554
549
  );
555
550
  } else if (typeof value === "object") {
@@ -601,6 +596,14 @@ const createAttributeSchema = (attribute) => {
601
596
  if (!value || typeof value === "string" && value.length === 0) {
602
597
  return true;
603
598
  }
599
+ if (typeof value === "object") {
600
+ try {
601
+ JSON.stringify(value);
602
+ return true;
603
+ } catch (err) {
604
+ return false;
605
+ }
606
+ }
604
607
  try {
605
608
  JSON.parse(value);
606
609
  return true;
@@ -619,13 +622,7 @@ const createAttributeSchema = (attribute) => {
619
622
  return yup__namespace.mixed();
620
623
  }
621
624
  };
622
- 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
- });
628
- }
625
+ const nullableSchema = (schema) => {
629
626
  return schema?.nullable ? schema.nullable() : (
630
627
  // In some cases '.nullable' will not be available on the schema.
631
628
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -633,7 +630,22 @@ const addRequiredValidation = (attribute) => (schema) => {
633
630
  schema
634
631
  );
635
632
  };
636
- const addMinLengthValidation = (attribute) => (schema) => {
633
+ const addRequiredValidation = (attribute, options) => (schema) => {
634
+ if (options.status === "draft") {
635
+ return nullableSchema(schema);
636
+ }
637
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
638
+ return schema.min(1, strapiAdmin.translatedErrors.required);
639
+ }
640
+ if (attribute.required && attribute.type !== "relation") {
641
+ return schema.required(strapiAdmin.translatedErrors.required);
642
+ }
643
+ return nullableSchema(schema);
644
+ };
645
+ const addMinLengthValidation = (attribute, options) => (schema) => {
646
+ if (options.status === "draft") {
647
+ return schema;
648
+ }
637
649
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
638
650
  return schema.min(attribute.minLength, {
639
651
  ...strapiAdmin.translatedErrors.minLength,
@@ -655,9 +667,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
655
667
  }
656
668
  return schema;
657
669
  };
658
- const addMinValidation = (attribute) => (schema) => {
670
+ const addMinValidation = (attribute, options) => (schema) => {
659
671
  if ("min" in attribute) {
660
672
  const min = toInteger(attribute.min);
673
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
+ return schema.test(
676
+ "custom-min",
677
+ {
678
+ ...strapiAdmin.translatedErrors.min,
679
+ values: {
680
+ min: attribute.min
681
+ }
682
+ },
683
+ (value) => {
684
+ if (!value) {
685
+ return true;
686
+ }
687
+ if (Array.isArray(value) && value.length === 0) {
688
+ return true;
689
+ }
690
+ return value.length >= min;
691
+ }
692
+ );
693
+ }
694
+ }
661
695
  if ("min" in schema && min) {
662
696
  return schema.min(min, {
663
697
  ...strapiAdmin.translatedErrors.min,
@@ -776,16 +810,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
776
810
  }, {});
777
811
  return componentsByKey;
778
812
  };
779
- const useDocument = (args, opts) => {
813
+ const HOOKS = {
814
+ /**
815
+ * Hook that allows to mutate the displayed headers of the list view table
816
+ * @constant
817
+ * @type {string}
818
+ */
819
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
820
+ /**
821
+ * Hook that allows to mutate the CM's collection types links pre-set filters
822
+ * @constant
823
+ * @type {string}
824
+ */
825
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
826
+ /**
827
+ * Hook that allows to mutate the CM's edit view layout
828
+ * @constant
829
+ * @type {string}
830
+ */
831
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
832
+ /**
833
+ * Hook that allows to mutate the CM's single types links pre-set filters
834
+ * @constant
835
+ * @type {string}
836
+ */
837
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
838
+ };
839
+ const contentTypesApi = contentManagerApi.injectEndpoints({
840
+ endpoints: (builder) => ({
841
+ getContentTypeConfiguration: builder.query({
842
+ query: (uid) => ({
843
+ url: `/content-manager/content-types/${uid}/configuration`,
844
+ method: "GET"
845
+ }),
846
+ transformResponse: (response) => response.data,
847
+ providesTags: (_result, _error, uid) => [
848
+ { type: "ContentTypesConfiguration", id: uid },
849
+ { type: "ContentTypeSettings", id: "LIST" }
850
+ ]
851
+ }),
852
+ getAllContentTypeSettings: builder.query({
853
+ query: () => "/content-manager/content-types-settings",
854
+ transformResponse: (response) => response.data,
855
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
856
+ }),
857
+ updateContentTypeConfiguration: builder.mutation({
858
+ query: ({ uid, ...body }) => ({
859
+ url: `/content-manager/content-types/${uid}/configuration`,
860
+ method: "PUT",
861
+ data: body
862
+ }),
863
+ transformResponse: (response) => response.data,
864
+ invalidatesTags: (_result, _error, { uid }) => [
865
+ { type: "ContentTypesConfiguration", id: uid },
866
+ { type: "ContentTypeSettings", id: "LIST" },
867
+ // Is this necessary?
868
+ { type: "InitialData" }
869
+ ]
870
+ })
871
+ })
872
+ });
873
+ const {
874
+ useGetContentTypeConfigurationQuery,
875
+ useGetAllContentTypeSettingsQuery,
876
+ useUpdateContentTypeConfigurationMutation
877
+ } = contentTypesApi;
878
+ const checkIfAttributeIsDisplayable = (attribute) => {
879
+ const { type } = attribute;
880
+ if (type === "relation") {
881
+ return !attribute.relation.toLowerCase().includes("morph");
882
+ }
883
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
884
+ };
885
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
886
+ if (!mainFieldName) {
887
+ return void 0;
888
+ }
889
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
890
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
891
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
892
+ );
893
+ return {
894
+ name: mainFieldName,
895
+ type: mainFieldType ?? "string"
896
+ };
897
+ };
898
+ const DEFAULT_SETTINGS = {
899
+ bulkable: false,
900
+ filterable: false,
901
+ searchable: false,
902
+ pagination: false,
903
+ defaultSortBy: "",
904
+ defaultSortOrder: "asc",
905
+ mainField: "id",
906
+ pageSize: 10
907
+ };
908
+ const useDocumentLayout = (model) => {
909
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
910
+ const [{ query }] = strapiAdmin.useQueryParams();
911
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
780
912
  const { toggleNotification } = strapiAdmin.useNotification();
781
913
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
914
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
782
915
  const {
783
- currentData: data,
784
- isLoading: isLoadingDocument,
785
- isFetching: isFetchingDocument,
786
- error
787
- } = useGetDocumentQuery(args, opts);
788
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
916
+ data,
917
+ isLoading: isLoadingConfigs,
918
+ error,
919
+ isFetching: isFetchingConfigs
920
+ } = useGetContentTypeConfigurationQuery(model);
921
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
789
922
  React__namespace.useEffect(() => {
790
923
  if (error) {
791
924
  toggleNotification({
@@ -793,54 +926,269 @@ const useDocument = (args, opts) => {
793
926
  message: formatAPIError(error)
794
927
  });
795
928
  }
796
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
797
- const validationSchema = React__namespace.useMemo(() => {
798
- if (!schema) {
799
- return null;
800
- }
801
- return createYupSchema(schema.attributes, components);
802
- }, [schema, components]);
803
- const validate = React__namespace.useCallback(
804
- (document) => {
805
- if (!validationSchema) {
806
- throw new Error(
807
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
808
- );
809
- }
810
- try {
811
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
812
- return null;
813
- } catch (error2) {
814
- if (error2 instanceof yup.ValidationError) {
815
- return strapiAdmin.getYupValidationErrors(error2);
816
- }
817
- throw error2;
818
- }
929
+ }, [error, formatAPIError, toggleNotification]);
930
+ const editLayout = React__namespace.useMemo(
931
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
932
+ layout: [],
933
+ components: {},
934
+ metadatas: {},
935
+ options: {},
936
+ settings: DEFAULT_SETTINGS
819
937
  },
820
- [validationSchema]
938
+ [data, isLoading, schemas, schema, components]
939
+ );
940
+ const listLayout = React__namespace.useMemo(() => {
941
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
942
+ layout: [],
943
+ metadatas: {},
944
+ options: {},
945
+ settings: DEFAULT_SETTINGS
946
+ };
947
+ }, [data, isLoading, schemas, schema, components]);
948
+ const { layout: edit } = React__namespace.useMemo(
949
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
950
+ layout: editLayout,
951
+ query
952
+ }),
953
+ [editLayout, query, runHookWaterfall]
821
954
  );
822
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
823
955
  return {
824
- components,
825
- document: data?.data,
826
- meta: data?.meta,
956
+ error,
827
957
  isLoading,
828
- schema,
829
- validate
958
+ edit,
959
+ list: listLayout
830
960
  };
831
961
  };
832
- const useDoc = () => {
833
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
834
- const [{ query }] = strapiAdmin.useQueryParams();
835
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
836
- if (!collectionType) {
837
- throw new Error("Could not find collectionType in url params");
838
- }
839
- if (!slug) {
840
- throw new Error("Could not find model in url params");
841
- }
842
- return {
843
- collectionType,
962
+ const useDocLayout = () => {
963
+ const { model } = useDoc();
964
+ return useDocumentLayout(model);
965
+ };
966
+ const formatEditLayout = (data, {
967
+ schemas,
968
+ schema,
969
+ components
970
+ }) => {
971
+ let currentPanelIndex = 0;
972
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
973
+ data.contentType.layouts.edit,
974
+ schema?.attributes,
975
+ data.contentType.metadatas,
976
+ { configurations: data.components, schemas: components },
977
+ schemas
978
+ ).reduce((panels, row) => {
979
+ if (row.some((field) => field.type === "dynamiczone")) {
980
+ panels.push([row]);
981
+ currentPanelIndex += 2;
982
+ } else {
983
+ if (!panels[currentPanelIndex]) {
984
+ panels.push([]);
985
+ }
986
+ panels[currentPanelIndex].push(row);
987
+ }
988
+ return panels;
989
+ }, []);
990
+ const componentEditAttributes = Object.entries(data.components).reduce(
991
+ (acc, [uid, configuration]) => {
992
+ acc[uid] = {
993
+ layout: convertEditLayoutToFieldLayouts(
994
+ configuration.layouts.edit,
995
+ components[uid].attributes,
996
+ configuration.metadatas,
997
+ { configurations: data.components, schemas: components }
998
+ ),
999
+ settings: {
1000
+ ...configuration.settings,
1001
+ icon: components[uid].info.icon,
1002
+ displayName: components[uid].info.displayName
1003
+ }
1004
+ };
1005
+ return acc;
1006
+ },
1007
+ {}
1008
+ );
1009
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1010
+ (acc, [attribute, metadata]) => {
1011
+ return {
1012
+ ...acc,
1013
+ [attribute]: metadata.edit
1014
+ };
1015
+ },
1016
+ {}
1017
+ );
1018
+ return {
1019
+ layout: panelledEditAttributes,
1020
+ components: componentEditAttributes,
1021
+ metadatas: editMetadatas,
1022
+ settings: {
1023
+ ...data.contentType.settings,
1024
+ displayName: schema?.info.displayName
1025
+ },
1026
+ options: {
1027
+ ...schema?.options,
1028
+ ...schema?.pluginOptions,
1029
+ ...data.contentType.options
1030
+ }
1031
+ };
1032
+ };
1033
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1034
+ return rows.map(
1035
+ (row) => row.map((field) => {
1036
+ const attribute = attributes[field.name];
1037
+ if (!attribute) {
1038
+ return null;
1039
+ }
1040
+ const { edit: metadata } = metadatas[field.name];
1041
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1042
+ return {
1043
+ attribute,
1044
+ disabled: !metadata.editable,
1045
+ hint: metadata.description,
1046
+ label: metadata.label ?? "",
1047
+ name: field.name,
1048
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1049
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1050
+ schemas,
1051
+ components: components?.schemas ?? {}
1052
+ }),
1053
+ placeholder: metadata.placeholder ?? "",
1054
+ required: attribute.required ?? false,
1055
+ size: field.size,
1056
+ unique: "unique" in attribute ? attribute.unique : false,
1057
+ visible: metadata.visible ?? true,
1058
+ type: attribute.type
1059
+ };
1060
+ }).filter((field) => field !== null)
1061
+ );
1062
+ };
1063
+ const formatListLayout = (data, {
1064
+ schemas,
1065
+ schema,
1066
+ components
1067
+ }) => {
1068
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1069
+ (acc, [attribute, metadata]) => {
1070
+ return {
1071
+ ...acc,
1072
+ [attribute]: metadata.list
1073
+ };
1074
+ },
1075
+ {}
1076
+ );
1077
+ const listAttributes = convertListLayoutToFieldLayouts(
1078
+ data.contentType.layouts.list,
1079
+ schema?.attributes,
1080
+ listMetadatas,
1081
+ { configurations: data.components, schemas: components },
1082
+ schemas
1083
+ );
1084
+ return {
1085
+ layout: listAttributes,
1086
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1087
+ metadatas: listMetadatas,
1088
+ options: {
1089
+ ...schema?.options,
1090
+ ...schema?.pluginOptions,
1091
+ ...data.contentType.options
1092
+ }
1093
+ };
1094
+ };
1095
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1096
+ return columns.map((name) => {
1097
+ const attribute = attributes[name];
1098
+ if (!attribute) {
1099
+ return null;
1100
+ }
1101
+ const metadata = metadatas[name];
1102
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1103
+ return {
1104
+ attribute,
1105
+ label: metadata.label ?? "",
1106
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1107
+ schemas,
1108
+ components: components?.schemas ?? {}
1109
+ }),
1110
+ name,
1111
+ searchable: metadata.searchable ?? true,
1112
+ sortable: metadata.sortable ?? true
1113
+ };
1114
+ }).filter((field) => field !== null);
1115
+ };
1116
+ const useDocument = (args, opts) => {
1117
+ const { toggleNotification } = strapiAdmin.useNotification();
1118
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1119
+ const {
1120
+ currentData: data,
1121
+ isLoading: isLoadingDocument,
1122
+ isFetching: isFetchingDocument,
1123
+ error
1124
+ } = useGetDocumentQuery(args, {
1125
+ ...opts,
1126
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1127
+ });
1128
+ const {
1129
+ components,
1130
+ schema,
1131
+ schemas,
1132
+ isLoading: isLoadingSchema
1133
+ } = useContentTypeSchema(args.model);
1134
+ React__namespace.useEffect(() => {
1135
+ if (error) {
1136
+ toggleNotification({
1137
+ type: "danger",
1138
+ message: formatAPIError(error)
1139
+ });
1140
+ }
1141
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1142
+ const validationSchema = React__namespace.useMemo(() => {
1143
+ if (!schema) {
1144
+ return null;
1145
+ }
1146
+ return createYupSchema(schema.attributes, components);
1147
+ }, [schema, components]);
1148
+ const validate = React__namespace.useCallback(
1149
+ (document) => {
1150
+ if (!validationSchema) {
1151
+ throw new Error(
1152
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1153
+ );
1154
+ }
1155
+ try {
1156
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1157
+ return null;
1158
+ } catch (error2) {
1159
+ if (error2 instanceof yup.ValidationError) {
1160
+ return strapiAdmin.getYupValidationErrors(error2);
1161
+ }
1162
+ throw error2;
1163
+ }
1164
+ },
1165
+ [validationSchema]
1166
+ );
1167
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1168
+ const hasError = !!error;
1169
+ return {
1170
+ components,
1171
+ document: data?.data,
1172
+ meta: data?.meta,
1173
+ isLoading,
1174
+ hasError,
1175
+ schema,
1176
+ schemas,
1177
+ validate
1178
+ };
1179
+ };
1180
+ const useDoc = () => {
1181
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1182
+ const [{ query }] = strapiAdmin.useQueryParams();
1183
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1184
+ if (!collectionType) {
1185
+ throw new Error("Could not find collectionType in url params");
1186
+ }
1187
+ if (!slug) {
1188
+ throw new Error("Could not find model in url params");
1189
+ }
1190
+ return {
1191
+ collectionType,
844
1192
  model: slug,
845
1193
  id: origin || id === "create" ? void 0 : id,
846
1194
  ...useDocument(
@@ -851,6 +1199,45 @@ const useDoc = () => {
851
1199
  )
852
1200
  };
853
1201
  };
1202
+ const useContentManagerContext = () => {
1203
+ const {
1204
+ collectionType,
1205
+ model,
1206
+ id,
1207
+ components,
1208
+ isLoading: isLoadingDoc,
1209
+ schema,
1210
+ schemas
1211
+ } = useDoc();
1212
+ const layout = useDocumentLayout(model);
1213
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1214
+ const isSingleType = collectionType === SINGLE_TYPES;
1215
+ const slug = model;
1216
+ const isCreatingEntry = id === "create";
1217
+ useContentTypeSchema();
1218
+ const isLoading = isLoadingDoc || layout.isLoading;
1219
+ const error = layout.error;
1220
+ return {
1221
+ error,
1222
+ isLoading,
1223
+ // Base metadata
1224
+ model,
1225
+ collectionType,
1226
+ id,
1227
+ slug,
1228
+ isCreatingEntry,
1229
+ isSingleType,
1230
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1231
+ // All schema infos
1232
+ components,
1233
+ contentType: schema,
1234
+ contentTypes: schemas,
1235
+ // Form state
1236
+ form,
1237
+ // layout infos
1238
+ layout
1239
+ };
1240
+ };
854
1241
  const prefixPluginTranslations = (trad, pluginId) => {
855
1242
  if (!pluginId) {
856
1243
  throw new TypeError("pluginId can't be empty");
@@ -870,6 +1257,8 @@ const useDocumentActions = () => {
870
1257
  const { formatMessage } = reactIntl.useIntl();
871
1258
  const { trackUsage } = strapiAdmin.useTracking();
872
1259
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1260
+ const navigate = reactRouterDom.useNavigate();
1261
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
873
1262
  const [deleteDocument] = useDeleteDocumentMutation();
874
1263
  const _delete = React__namespace.useCallback(
875
1264
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1184,6 +1573,7 @@ const useDocumentActions = () => {
1184
1573
  defaultMessage: "Saved document"
1185
1574
  })
1186
1575
  });
1576
+ setCurrentStep("contentManager.success");
1187
1577
  return res.data;
1188
1578
  } catch (err) {
1189
1579
  toggleNotification({
@@ -1205,7 +1595,6 @@ const useDocumentActions = () => {
1205
1595
  sourceId
1206
1596
  });
1207
1597
  if ("error" in res) {
1208
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1209
1598
  return { error: res.error };
1210
1599
  }
1211
1600
  toggleNotification({
@@ -1224,7 +1613,7 @@ const useDocumentActions = () => {
1224
1613
  throw err;
1225
1614
  }
1226
1615
  },
1227
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1616
+ [autoCloneDocument, formatMessage, toggleNotification]
1228
1617
  );
1229
1618
  const [cloneDocument] = useCloneDocumentMutation();
1230
1619
  const clone = React__namespace.useCallback(
@@ -1250,6 +1639,7 @@ const useDocumentActions = () => {
1250
1639
  defaultMessage: "Cloned document"
1251
1640
  })
1252
1641
  });
1642
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1253
1643
  return res.data;
1254
1644
  } catch (err) {
1255
1645
  toggleNotification({
@@ -1260,7 +1650,7 @@ const useDocumentActions = () => {
1260
1650
  throw err;
1261
1651
  }
1262
1652
  },
1263
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1653
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1264
1654
  );
1265
1655
  const [getDoc] = useLazyGetDocumentQuery();
1266
1656
  const getDocument = React__namespace.useCallback(
@@ -1286,7 +1676,7 @@ const useDocumentActions = () => {
1286
1676
  };
1287
1677
  };
1288
1678
  const ProtectedHistoryPage = React.lazy(
1289
- () => Promise.resolve().then(() => require("./History-4NbOq2dX.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1679
+ () => Promise.resolve().then(() => require("./History-C_uSGzO5.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1290
1680
  );
1291
1681
  const routes$1 = [
1292
1682
  {
@@ -1299,31 +1689,31 @@ const routes$1 = [
1299
1689
  }
1300
1690
  ];
1301
1691
  const ProtectedEditViewPage = React.lazy(
1302
- () => Promise.resolve().then(() => require("./EditViewPage-CTTDHKkQ.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1692
+ () => Promise.resolve().then(() => require("./EditViewPage-CUS2EAhB.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1303
1693
  );
1304
1694
  const ProtectedListViewPage = React.lazy(
1305
- () => Promise.resolve().then(() => require("./ListViewPage-CA3I75m5.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1695
+ () => Promise.resolve().then(() => require("./ListViewPage-DHgHD8Xg.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1306
1696
  );
1307
1697
  const ProtectedListConfiguration = React.lazy(
1308
- () => Promise.resolve().then(() => require("./ListConfigurationPage-CpfstlYY.js")).then((mod) => ({
1698
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-nyuP7OSy.js")).then((mod) => ({
1309
1699
  default: mod.ProtectedListConfiguration
1310
1700
  }))
1311
1701
  );
1312
1702
  const ProtectedEditConfigurationPage = React.lazy(
1313
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CPVB8Uqc.js")).then((mod) => ({
1703
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-DITVliEI.js")).then((mod) => ({
1314
1704
  default: mod.ProtectedEditConfigurationPage
1315
1705
  }))
1316
1706
  );
1317
1707
  const ProtectedComponentConfigurationPage = React.lazy(
1318
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-y_7iLdmB.js")).then((mod) => ({
1708
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DP7AC0UU.js")).then((mod) => ({
1319
1709
  default: mod.ProtectedComponentConfigurationPage
1320
1710
  }))
1321
1711
  );
1322
1712
  const NoPermissions = React.lazy(
1323
- () => Promise.resolve().then(() => require("./NoPermissionsPage-CO2MK200.js")).then((mod) => ({ default: mod.NoPermissions }))
1713
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-zwIZydDI.js")).then((mod) => ({ default: mod.NoPermissions }))
1324
1714
  );
1325
1715
  const NoContentType = React.lazy(
1326
- () => Promise.resolve().then(() => require("./NoContentTypePage-Dldu-_Mx.js")).then((mod) => ({ default: mod.NoContentType }))
1716
+ () => Promise.resolve().then(() => require("./NoContentTypePage-CDUKdZ7d.js")).then((mod) => ({ default: mod.NoContentType }))
1327
1717
  );
1328
1718
  const CollectionTypePages = () => {
1329
1719
  const { collectionType } = reactRouterDom.useParams();
@@ -1437,12 +1827,14 @@ const DocumentActionButton = (action) => {
1437
1827
  /* @__PURE__ */ jsxRuntime.jsx(
1438
1828
  designSystem.Button,
1439
1829
  {
1440
- flex: 1,
1830
+ flex: "auto",
1441
1831
  startIcon: action.icon,
1442
1832
  disabled: action.disabled,
1443
1833
  onClick: handleClick(action),
1444
1834
  justifyContent: "center",
1445
1835
  variant: action.variant || "default",
1836
+ paddingTop: "7px",
1837
+ paddingBottom: "7px",
1446
1838
  children: action.label
1447
1839
  }
1448
1840
  ),
@@ -1450,7 +1842,7 @@ const DocumentActionButton = (action) => {
1450
1842
  DocumentActionConfirmDialog,
1451
1843
  {
1452
1844
  ...action.dialog,
1453
- variant: action.variant,
1845
+ variant: action.dialog?.variant ?? action.variant,
1454
1846
  isOpen: dialogId === action.id,
1455
1847
  onClose: handleClose
1456
1848
  }
@@ -1507,9 +1899,9 @@ const DocumentActionsMenu = ({
1507
1899
  disabled: isDisabled,
1508
1900
  size: "S",
1509
1901
  endIcon: null,
1510
- paddingTop: "7px",
1511
- paddingLeft: "9px",
1512
- paddingRight: "9px",
1902
+ paddingTop: "4px",
1903
+ paddingLeft: "7px",
1904
+ paddingRight: "7px",
1513
1905
  variant,
1514
1906
  children: [
1515
1907
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1520,7 +1912,7 @@ const DocumentActionsMenu = ({
1520
1912
  ]
1521
1913
  }
1522
1914
  ),
1523
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1915
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1524
1916
  actions2.map((action) => {
1525
1917
  return /* @__PURE__ */ jsxRuntime.jsx(
1526
1918
  designSystem.Menu.Item,
@@ -1529,10 +1921,25 @@ const DocumentActionsMenu = ({
1529
1921
  onSelect: handleClick(action),
1530
1922
  display: "block",
1531
1923
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1532
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1533
- action.icon,
1534
- action.label
1535
- ] }),
1924
+ /* @__PURE__ */ jsxRuntime.jsxs(
1925
+ designSystem.Flex,
1926
+ {
1927
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1928
+ gap: 2,
1929
+ tag: "span",
1930
+ children: [
1931
+ /* @__PURE__ */ jsxRuntime.jsx(
1932
+ designSystem.Flex,
1933
+ {
1934
+ tag: "span",
1935
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1936
+ children: action.icon
1937
+ }
1938
+ ),
1939
+ action.label
1940
+ ]
1941
+ }
1942
+ ),
1536
1943
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1537
1944
  designSystem.Flex,
1538
1945
  {
@@ -1591,6 +1998,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1591
1998
  return "primary600";
1592
1999
  }
1593
2000
  };
2001
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2002
+ switch (variant) {
2003
+ case "danger":
2004
+ return "danger600";
2005
+ case "secondary":
2006
+ return "neutral500";
2007
+ case "success":
2008
+ return "success600";
2009
+ default:
2010
+ return "primary600";
2011
+ }
2012
+ };
1594
2013
  const DocumentActionConfirmDialog = ({
1595
2014
  onClose,
1596
2015
  onCancel,
@@ -1613,22 +2032,20 @@ const DocumentActionConfirmDialog = ({
1613
2032
  }
1614
2033
  onClose();
1615
2034
  };
1616
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1617
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1618
- /* @__PURE__ */ jsxRuntime.jsx(
1619
- designSystem.DialogFooter,
1620
- {
1621
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1622
- id: "app.components.Button.cancel",
1623
- defaultMessage: "Cancel"
1624
- }) }),
1625
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1626
- id: "app.components.Button.confirm",
1627
- defaultMessage: "Confirm"
1628
- }) })
1629
- }
1630
- )
1631
- ] });
2035
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2036
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2038
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2039
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2040
+ id: "app.components.Button.cancel",
2041
+ defaultMessage: "Cancel"
2042
+ }) }) }),
2043
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2044
+ id: "app.components.Button.confirm",
2045
+ defaultMessage: "Confirm"
2046
+ }) })
2047
+ ] })
2048
+ ] }) });
1632
2049
  };
1633
2050
  const DocumentActionModal = ({
1634
2051
  isOpen,
@@ -1638,34 +2055,17 @@ const DocumentActionModal = ({
1638
2055
  content: Content,
1639
2056
  onModalClose
1640
2057
  }) => {
1641
- const id = React__namespace.useId();
1642
- if (!isOpen) {
1643
- return null;
1644
- }
1645
2058
  const handleClose = () => {
1646
2059
  if (onClose) {
1647
2060
  onClose();
1648
2061
  }
1649
2062
  onModalClose();
1650
2063
  };
1651
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1654
- /* @__PURE__ */ jsxRuntime.jsx(
1655
- designSystem.Box,
1656
- {
1657
- paddingTop: 4,
1658
- paddingBottom: 4,
1659
- paddingLeft: 5,
1660
- paddingRight: 5,
1661
- borderWidth: "1px 0 0 0",
1662
- borderStyle: "solid",
1663
- borderColor: "neutral150",
1664
- background: "neutral100",
1665
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1666
- }
1667
- )
1668
- ] });
2064
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2065
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2066
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2067
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2068
+ ] }) });
1669
2069
  };
1670
2070
  const PublishAction$1 = ({
1671
2071
  activeTab,
@@ -1679,13 +2079,17 @@ const PublishAction$1 = ({
1679
2079
  const navigate = reactRouterDom.useNavigate();
1680
2080
  const { toggleNotification } = strapiAdmin.useNotification();
1681
2081
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2082
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1682
2083
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1683
2084
  const { formatMessage } = reactIntl.useIntl();
1684
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1685
- "PublishAction",
1686
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1687
- );
2085
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1688
2086
  const { publish } = useDocumentActions();
2087
+ const [
2088
+ countDraftRelations,
2089
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2090
+ ] = useLazyGetDraftRelationCountQuery();
2091
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2092
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1689
2093
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1690
2094
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1691
2095
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1694,10 +2098,103 @@ const PublishAction$1 = ({
1694
2098
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1695
2099
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1696
2100
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2101
+ React__namespace.useEffect(() => {
2102
+ if (isErrorDraftRelations) {
2103
+ toggleNotification({
2104
+ type: "danger",
2105
+ message: formatMessage({
2106
+ id: getTranslation("error.records.fetch-draft-relatons"),
2107
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2108
+ })
2109
+ });
2110
+ }
2111
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2112
+ React__namespace.useEffect(() => {
2113
+ const localDraftRelations = /* @__PURE__ */ new Set();
2114
+ const extractDraftRelations = (data) => {
2115
+ const relations = data.connect || [];
2116
+ relations.forEach((relation) => {
2117
+ if (relation.status === "draft") {
2118
+ localDraftRelations.add(relation.id);
2119
+ }
2120
+ });
2121
+ };
2122
+ const traverseAndExtract = (data) => {
2123
+ Object.entries(data).forEach(([key, value]) => {
2124
+ if (key === "connect" && Array.isArray(value)) {
2125
+ extractDraftRelations({ connect: value });
2126
+ } else if (typeof value === "object" && value !== null) {
2127
+ traverseAndExtract(value);
2128
+ }
2129
+ });
2130
+ };
2131
+ if (!documentId || modified) {
2132
+ traverseAndExtract(formValues);
2133
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2134
+ }
2135
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2136
+ React__namespace.useEffect(() => {
2137
+ if (!document || !document.documentId || isListView) {
2138
+ return;
2139
+ }
2140
+ const fetchDraftRelationsCount = async () => {
2141
+ const { data, error } = await countDraftRelations({
2142
+ collectionType,
2143
+ model,
2144
+ documentId,
2145
+ params
2146
+ });
2147
+ if (error) {
2148
+ throw error;
2149
+ }
2150
+ if (data) {
2151
+ setServerCountOfDraftRelations(data.data);
2152
+ }
2153
+ };
2154
+ fetchDraftRelationsCount();
2155
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1697
2156
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1698
2157
  if (!schema?.options?.draftAndPublish) {
1699
2158
  return null;
1700
2159
  }
2160
+ const performPublish = async () => {
2161
+ setSubmitting(true);
2162
+ try {
2163
+ const { errors } = await validate();
2164
+ if (errors) {
2165
+ toggleNotification({
2166
+ type: "danger",
2167
+ message: formatMessage({
2168
+ id: "content-manager.validation.error",
2169
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2170
+ })
2171
+ });
2172
+ return;
2173
+ }
2174
+ const res = await publish(
2175
+ {
2176
+ collectionType,
2177
+ model,
2178
+ documentId,
2179
+ params
2180
+ },
2181
+ formValues
2182
+ );
2183
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2184
+ navigate({
2185
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2186
+ search: rawQuery
2187
+ });
2188
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2189
+ setErrors(formatValidationErrors(res.error));
2190
+ }
2191
+ } finally {
2192
+ setSubmitting(false);
2193
+ }
2194
+ };
2195
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2196
+ const enableDraftRelationsCount = false;
2197
+ const hasDraftRelations = enableDraftRelationsCount;
1701
2198
  return {
1702
2199
  /**
1703
2200
  * Disabled when:
@@ -1707,49 +2204,36 @@ const PublishAction$1 = ({
1707
2204
  * - the document is already published & not modified
1708
2205
  * - the document is being created & not modified
1709
2206
  * - the user doesn't have the permission to publish
1710
- * - the user doesn't have the permission to create a new document
1711
- * - the user doesn't have the permission to update the document
1712
2207
  */
1713
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2208
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1714
2209
  label: formatMessage({
1715
2210
  id: "app.utils.publish",
1716
2211
  defaultMessage: "Publish"
1717
2212
  }),
1718
2213
  onClick: async () => {
1719
- setSubmitting(true);
1720
- try {
1721
- const { errors } = await validate();
1722
- if (errors) {
1723
- toggleNotification({
1724
- type: "danger",
1725
- message: formatMessage({
1726
- id: "content-manager.validation.error",
1727
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1728
- })
1729
- });
1730
- return;
1731
- }
1732
- const res = await publish(
1733
- {
1734
- collectionType,
1735
- model,
1736
- documentId,
1737
- params
1738
- },
1739
- formValues
1740
- );
1741
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1742
- navigate({
1743
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1744
- search: rawQuery
1745
- });
1746
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1747
- setErrors(formatValidationErrors(res.error));
2214
+ await performPublish();
2215
+ },
2216
+ dialog: hasDraftRelations ? {
2217
+ type: "dialog",
2218
+ variant: "danger",
2219
+ footer: null,
2220
+ title: formatMessage({
2221
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2222
+ defaultMessage: "Confirmation"
2223
+ }),
2224
+ content: formatMessage(
2225
+ {
2226
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2227
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2228
+ },
2229
+ {
2230
+ count: totalDraftRelations
1748
2231
  }
1749
- } finally {
1750
- setSubmitting(false);
2232
+ ),
2233
+ onConfirm: async () => {
2234
+ await performPublish();
1751
2235
  }
1752
- }
2236
+ } : void 0
1753
2237
  };
1754
2238
  };
1755
2239
  PublishAction$1.type = "publish";
@@ -1765,10 +2249,6 @@ const UpdateAction = ({
1765
2249
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1766
2250
  const isCloning = cloneMatch !== null;
1767
2251
  const { formatMessage } = reactIntl.useIntl();
1768
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1769
- canCreate: canCreate2,
1770
- canUpdate: canUpdate2
1771
- }));
1772
2252
  const { create, update, clone } = useDocumentActions();
1773
2253
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1774
2254
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1785,10 +2265,8 @@ const UpdateAction = ({
1785
2265
  * - the form is submitting
1786
2266
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1787
2267
  * - the active tab is the published tab
1788
- * - the user doesn't have the permission to create a new document
1789
- * - the user doesn't have the permission to update the document
1790
2268
  */
1791
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2269
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1792
2270
  label: formatMessage({
1793
2271
  id: "content-manager.containers.Edit.save",
1794
2272
  defaultMessage: "Save"
@@ -1796,16 +2274,18 @@ const UpdateAction = ({
1796
2274
  onClick: async () => {
1797
2275
  setSubmitting(true);
1798
2276
  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;
2277
+ if (activeTab !== "draft") {
2278
+ const { errors } = await validate();
2279
+ if (errors) {
2280
+ toggleNotification({
2281
+ type: "danger",
2282
+ message: formatMessage({
2283
+ id: "content-manager.validation.error",
2284
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2285
+ })
2286
+ });
2287
+ return;
2288
+ }
1809
2289
  }
1810
2290
  if (isCloning) {
1811
2291
  const res = await clone(
@@ -1817,10 +2297,13 @@ const UpdateAction = ({
1817
2297
  document
1818
2298
  );
1819
2299
  if ("data" in res) {
1820
- navigate({
1821
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1822
- search: rawQuery
1823
- });
2300
+ navigate(
2301
+ {
2302
+ pathname: `../${res.data.documentId}`,
2303
+ search: rawQuery
2304
+ },
2305
+ { relative: "path" }
2306
+ );
1824
2307
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1825
2308
  setErrors(formatValidationErrors(res.error));
1826
2309
  }
@@ -1848,10 +2331,13 @@ const UpdateAction = ({
1848
2331
  document
1849
2332
  );
1850
2333
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1851
- navigate({
1852
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1853
- search: rawQuery
1854
- });
2334
+ navigate(
2335
+ {
2336
+ pathname: `../${res.data.documentId}`,
2337
+ search: rawQuery
2338
+ },
2339
+ { replace: true, relative: "path" }
2340
+ );
1855
2341
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1856
2342
  setErrors(formatValidationErrors(res.error));
1857
2343
  }
@@ -1883,10 +2369,8 @@ const UnpublishAction$1 = ({
1883
2369
  const { toggleNotification } = strapiAdmin.useNotification();
1884
2370
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1885
2371
  const isDocumentModified = document?.status === "modified";
1886
- const handleChange = (e) => {
1887
- if ("value" in e.target) {
1888
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
- }
2372
+ const handleChange = (value) => {
2373
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1890
2374
  };
1891
2375
  if (!schema?.options?.draftAndPublish) {
1892
2376
  return null;
@@ -1897,7 +2381,7 @@ const UnpublishAction$1 = ({
1897
2381
  id: "app.utils.unpublish",
1898
2382
  defaultMessage: "Unpublish"
1899
2383
  }),
1900
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2384
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1901
2385
  onClick: async () => {
1902
2386
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1903
2387
  if (!documentId) {
@@ -1936,40 +2420,24 @@ const UnpublishAction$1 = ({
1936
2420
  }) })
1937
2421
  ] }),
1938
2422
  /* @__PURE__ */ jsxRuntime.jsxs(
1939
- designSystem.Flex,
2423
+ designSystem.Radio.Group,
1940
2424
  {
1941
- onChange: handleChange,
1942
- direction: "column",
1943
- alignItems: "flex-start",
1944
- tag: "fieldset",
1945
- borderWidth: 0,
1946
- gap: 3,
2425
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2426
+ name: "discard-options",
2427
+ "aria-label": formatMessage({
2428
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2429
+ defaultMessage: "Choose an option to unpublish the document."
2430
+ }),
2431
+ onValueChange: handleChange,
1947
2432
  children: [
1948
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1949
- /* @__PURE__ */ jsxRuntime.jsx(
1950
- designSystem.Radio,
1951
- {
1952
- checked: shouldKeepDraft,
1953
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1954
- name: "discard-options",
1955
- children: formatMessage({
1956
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1957
- defaultMessage: "Keep draft"
1958
- })
1959
- }
1960
- ),
1961
- /* @__PURE__ */ jsxRuntime.jsx(
1962
- designSystem.Radio,
1963
- {
1964
- checked: !shouldKeepDraft,
1965
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1966
- name: "discard-options",
1967
- children: formatMessage({
1968
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1969
- defaultMessage: "Replace draft"
1970
- })
1971
- }
1972
- )
2433
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2434
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2435
+ defaultMessage: "Keep draft"
2436
+ }) }),
2437
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2438
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2439
+ defaultMessage: "Replace draft"
2440
+ }) })
1973
2441
  ]
1974
2442
  }
1975
2443
  )
@@ -2025,7 +2493,7 @@ const DiscardAction = ({
2025
2493
  id: "content-manager.actions.discard.label",
2026
2494
  defaultMessage: "Discard changes"
2027
2495
  }),
2028
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2496
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2029
2497
  position: ["panel", "table-row"],
2030
2498
  variant: "danger",
2031
2499
  dialog: {
@@ -2053,11 +2521,6 @@ const DiscardAction = ({
2053
2521
  };
2054
2522
  };
2055
2523
  DiscardAction.type = "discard";
2056
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2057
- path {
2058
- fill: currentColor;
2059
- }
2060
- `;
2061
2524
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2062
2525
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2063
2526
  const RelativeTime = React__namespace.forwardRef(
@@ -2105,7 +2568,7 @@ const getDisplayName = ({
2105
2568
  };
2106
2569
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2107
2570
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2108
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2571
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2109
2572
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2110
2573
  };
2111
2574
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2115,23 +2578,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2115
2578
  id: "content-manager.containers.edit.title.new",
2116
2579
  defaultMessage: "Create an entry"
2117
2580
  }) : documentTitle;
2118
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2581
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2119
2582
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2120
- /* @__PURE__ */ jsxRuntime.jsxs(
2121
- designSystem.Flex,
2122
- {
2123
- width: "100%",
2124
- justifyContent: "space-between",
2125
- paddingTop: 1,
2126
- gap: "80px",
2127
- alignItems: "flex-start",
2128
- children: [
2129
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2130
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2131
- ]
2132
- }
2133
- ),
2134
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2583
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2584
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2585
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2586
+ ] }),
2587
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2135
2588
  ] });
2136
2589
  };
2137
2590
  const HeaderToolbar = () => {
@@ -2298,25 +2751,77 @@ const Information = ({ activeTab }) => {
2298
2751
  );
2299
2752
  };
2300
2753
  const HeaderActions = ({ actions: actions2 }) => {
2301
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2302
- if ("options" in action) {
2754
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2755
+ const handleClick = (action) => async (e) => {
2756
+ if (!("options" in action)) {
2757
+ const { onClick = () => false, dialog, id } = action;
2758
+ const muteDialog = await onClick(e);
2759
+ if (dialog && !muteDialog) {
2760
+ e.preventDefault();
2761
+ setDialogId(id);
2762
+ }
2763
+ }
2764
+ };
2765
+ const handleClose = () => {
2766
+ setDialogId(null);
2767
+ };
2768
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2769
+ if (action.options) {
2303
2770
  return /* @__PURE__ */ jsxRuntime.jsx(
2304
2771
  designSystem.SingleSelect,
2305
2772
  {
2306
2773
  size: "S",
2307
- disabled: action.disabled,
2308
- "aria-label": action.label,
2309
2774
  onChange: action.onSelect,
2310
- value: action.value,
2775
+ "aria-label": action.label,
2776
+ ...action,
2311
2777
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2312
2778
  },
2313
2779
  action.id
2314
2780
  );
2315
2781
  } else {
2316
- return null;
2782
+ if (action.type === "icon") {
2783
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2784
+ /* @__PURE__ */ jsxRuntime.jsx(
2785
+ designSystem.IconButton,
2786
+ {
2787
+ disabled: action.disabled,
2788
+ label: action.label,
2789
+ size: "S",
2790
+ onClick: handleClick(action),
2791
+ children: action.icon
2792
+ }
2793
+ ),
2794
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2795
+ HeaderActionDialog,
2796
+ {
2797
+ ...action.dialog,
2798
+ isOpen: dialogId === action.id,
2799
+ onClose: handleClose
2800
+ }
2801
+ ) : null
2802
+ ] }, action.id);
2803
+ }
2317
2804
  }
2318
2805
  }) });
2319
2806
  };
2807
+ const HeaderActionDialog = ({
2808
+ onClose,
2809
+ onCancel,
2810
+ title,
2811
+ content: Content,
2812
+ isOpen
2813
+ }) => {
2814
+ const handleClose = async () => {
2815
+ if (onCancel) {
2816
+ await onCancel();
2817
+ }
2818
+ onClose();
2819
+ };
2820
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2821
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2822
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2823
+ ] }) });
2824
+ };
2320
2825
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2321
2826
  const navigate = reactRouterDom.useNavigate();
2322
2827
  const { formatMessage } = reactIntl.useIntl();
@@ -2357,12 +2862,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2357
2862
  const { delete: deleteAction } = useDocumentActions();
2358
2863
  const { toggleNotification } = strapiAdmin.useNotification();
2359
2864
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2865
+ const isLocalized = document?.locale != null;
2360
2866
  return {
2361
2867
  disabled: !canDelete || !document,
2362
- label: formatMessage({
2363
- id: "content-manager.actions.delete.label",
2364
- defaultMessage: "Delete document"
2365
- }),
2868
+ label: formatMessage(
2869
+ {
2870
+ id: "content-manager.actions.delete.label",
2871
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2872
+ },
2873
+ { isLocalized }
2874
+ ),
2366
2875
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2367
2876
  dialog: {
2368
2877
  type: "dialog",
@@ -2448,373 +2957,71 @@ const Panels = () => {
2448
2957
  ) });
2449
2958
  };
2450
2959
  const ActionsPanel = () => {
2451
- const { formatMessage } = reactIntl.useIntl();
2452
- return {
2453
- title: formatMessage({
2454
- id: "content-manager.containers.edit.panels.default.title",
2455
- defaultMessage: "Document"
2456
- }),
2457
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2458
- };
2459
- };
2460
- ActionsPanel.type = "actions";
2461
- const ActionsPanelContent = () => {
2462
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2463
- const [
2464
- {
2465
- query: { status = "draft" }
2466
- }
2467
- ] = strapiAdmin.useQueryParams();
2468
- const { model, id, document, meta, collectionType } = useDoc();
2469
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2470
- const props = {
2471
- activeTab: status,
2472
- model,
2473
- documentId: id,
2474
- document: isCloning ? void 0 : document,
2475
- meta: isCloning ? void 0 : meta,
2476
- collectionType
2477
- };
2478
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2479
- /* @__PURE__ */ jsxRuntime.jsx(
2480
- strapiAdmin.DescriptionComponentRenderer,
2481
- {
2482
- props,
2483
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2484
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2485
- }
2486
- ),
2487
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2488
- ] });
2489
- };
2490
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2491
- return /* @__PURE__ */ jsxRuntime.jsxs(
2492
- designSystem.Flex,
2493
- {
2494
- ref,
2495
- tag: "aside",
2496
- "aria-labelledby": "additional-information",
2497
- background: "neutral0",
2498
- borderColor: "neutral150",
2499
- hasRadius: true,
2500
- paddingBottom: 4,
2501
- paddingLeft: 4,
2502
- paddingRight: 4,
2503
- paddingTop: 4,
2504
- shadow: "tableShadow",
2505
- gap: 3,
2506
- direction: "column",
2507
- justifyContent: "stretch",
2508
- alignItems: "flex-start",
2509
- children: [
2510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2511
- children
2512
- ]
2513
- }
2514
- );
2515
- });
2516
- const HOOKS = {
2517
- /**
2518
- * Hook that allows to mutate the displayed headers of the list view table
2519
- * @constant
2520
- * @type {string}
2521
- */
2522
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2523
- /**
2524
- * Hook that allows to mutate the CM's collection types links pre-set filters
2525
- * @constant
2526
- * @type {string}
2527
- */
2528
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2529
- /**
2530
- * Hook that allows to mutate the CM's edit view layout
2531
- * @constant
2532
- * @type {string}
2533
- */
2534
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2535
- /**
2536
- * Hook that allows to mutate the CM's single types links pre-set filters
2537
- * @constant
2538
- * @type {string}
2539
- */
2540
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2541
- };
2542
- const contentTypesApi = contentManagerApi.injectEndpoints({
2543
- endpoints: (builder) => ({
2544
- getContentTypeConfiguration: builder.query({
2545
- query: (uid) => ({
2546
- url: `/content-manager/content-types/${uid}/configuration`,
2547
- method: "GET"
2548
- }),
2549
- transformResponse: (response) => response.data,
2550
- providesTags: (_result, _error, uid) => [
2551
- { type: "ContentTypesConfiguration", id: uid },
2552
- { type: "ContentTypeSettings", id: "LIST" }
2553
- ]
2554
- }),
2555
- getAllContentTypeSettings: builder.query({
2556
- query: () => "/content-manager/content-types-settings",
2557
- transformResponse: (response) => response.data,
2558
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2559
- }),
2560
- updateContentTypeConfiguration: builder.mutation({
2561
- query: ({ uid, ...body }) => ({
2562
- url: `/content-manager/content-types/${uid}/configuration`,
2563
- method: "PUT",
2564
- data: body
2565
- }),
2566
- transformResponse: (response) => response.data,
2567
- invalidatesTags: (_result, _error, { uid }) => [
2568
- { type: "ContentTypesConfiguration", id: uid },
2569
- { type: "ContentTypeSettings", id: "LIST" },
2570
- // Is this necessary?
2571
- { type: "InitialData" }
2572
- ]
2573
- })
2574
- })
2575
- });
2576
- const {
2577
- useGetContentTypeConfigurationQuery,
2578
- useGetAllContentTypeSettingsQuery,
2579
- useUpdateContentTypeConfigurationMutation
2580
- } = contentTypesApi;
2581
- const checkIfAttributeIsDisplayable = (attribute) => {
2582
- const { type } = attribute;
2583
- if (type === "relation") {
2584
- return !attribute.relation.toLowerCase().includes("morph");
2585
- }
2586
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2587
- };
2588
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2589
- if (!mainFieldName) {
2590
- return void 0;
2591
- }
2592
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2593
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2594
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2595
- );
2596
- return {
2597
- name: mainFieldName,
2598
- type: mainFieldType ?? "string"
2599
- };
2600
- };
2601
- const DEFAULT_SETTINGS = {
2602
- bulkable: false,
2603
- filterable: false,
2604
- searchable: false,
2605
- pagination: false,
2606
- defaultSortBy: "",
2607
- defaultSortOrder: "asc",
2608
- mainField: "id",
2609
- pageSize: 10
2610
- };
2611
- const useDocumentLayout = (model) => {
2612
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2613
- const [{ query }] = strapiAdmin.useQueryParams();
2614
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2615
- const { toggleNotification } = strapiAdmin.useNotification();
2616
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2617
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2618
- const {
2619
- data,
2620
- isLoading: isLoadingConfigs,
2621
- error,
2622
- isFetching: isFetchingConfigs
2623
- } = useGetContentTypeConfigurationQuery(model);
2624
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2625
- React__namespace.useEffect(() => {
2626
- if (error) {
2627
- toggleNotification({
2628
- type: "danger",
2629
- message: formatAPIError(error)
2630
- });
2631
- }
2632
- }, [error, formatAPIError, toggleNotification]);
2633
- const editLayout = React__namespace.useMemo(
2634
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2635
- layout: [],
2636
- components: {},
2637
- metadatas: {},
2638
- options: {},
2639
- settings: DEFAULT_SETTINGS
2640
- },
2641
- [data, isLoading, schemas, schema, components]
2642
- );
2643
- const listLayout = React__namespace.useMemo(() => {
2644
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2645
- layout: [],
2646
- metadatas: {},
2647
- options: {},
2648
- settings: DEFAULT_SETTINGS
2649
- };
2650
- }, [data, isLoading, schemas, schema, components]);
2651
- const { layout: edit } = React__namespace.useMemo(
2652
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2653
- layout: editLayout,
2654
- query
2655
- }),
2656
- [editLayout, query, runHookWaterfall]
2657
- );
2658
- return {
2659
- error,
2660
- isLoading,
2661
- edit,
2662
- list: listLayout
2663
- };
2664
- };
2665
- const useDocLayout = () => {
2666
- const { model } = useDoc();
2667
- return useDocumentLayout(model);
2668
- };
2669
- const formatEditLayout = (data, {
2670
- schemas,
2671
- schema,
2672
- components
2673
- }) => {
2674
- let currentPanelIndex = 0;
2675
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2676
- data.contentType.layouts.edit,
2677
- schema?.attributes,
2678
- data.contentType.metadatas,
2679
- { configurations: data.components, schemas: components },
2680
- schemas
2681
- ).reduce((panels, row) => {
2682
- if (row.some((field) => field.type === "dynamiczone")) {
2683
- panels.push([row]);
2684
- currentPanelIndex += 2;
2685
- } else {
2686
- if (!panels[currentPanelIndex]) {
2687
- panels.push([]);
2688
- }
2689
- panels[currentPanelIndex].push(row);
2690
- }
2691
- return panels;
2692
- }, []);
2693
- const componentEditAttributes = Object.entries(data.components).reduce(
2694
- (acc, [uid, configuration]) => {
2695
- acc[uid] = {
2696
- layout: convertEditLayoutToFieldLayouts(
2697
- configuration.layouts.edit,
2698
- components[uid].attributes,
2699
- configuration.metadatas
2700
- ),
2701
- settings: {
2702
- ...configuration.settings,
2703
- icon: components[uid].info.icon,
2704
- displayName: components[uid].info.displayName
2705
- }
2706
- };
2707
- return acc;
2708
- },
2709
- {}
2710
- );
2711
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2712
- (acc, [attribute, metadata]) => {
2713
- return {
2714
- ...acc,
2715
- [attribute]: metadata.edit
2716
- };
2717
- },
2718
- {}
2719
- );
2720
- return {
2721
- layout: panelledEditAttributes,
2722
- components: componentEditAttributes,
2723
- metadatas: editMetadatas,
2724
- settings: {
2725
- ...data.contentType.settings,
2726
- displayName: schema?.info.displayName
2727
- },
2728
- options: {
2729
- ...schema?.options,
2730
- ...schema?.pluginOptions,
2731
- ...data.contentType.options
2732
- }
2733
- };
2734
- };
2735
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2736
- return rows.map(
2737
- (row) => row.map((field) => {
2738
- const attribute = attributes[field.name];
2739
- if (!attribute) {
2740
- return null;
2741
- }
2742
- const { edit: metadata } = metadatas[field.name];
2743
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2744
- return {
2745
- attribute,
2746
- disabled: !metadata.editable,
2747
- hint: metadata.description,
2748
- label: metadata.label ?? "",
2749
- name: field.name,
2750
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2751
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2752
- schemas,
2753
- components: components?.schemas ?? {}
2754
- }),
2755
- placeholder: metadata.placeholder ?? "",
2756
- required: attribute.required ?? false,
2757
- size: field.size,
2758
- unique: "unique" in attribute ? attribute.unique : false,
2759
- visible: metadata.visible ?? true,
2760
- type: attribute.type
2761
- };
2762
- }).filter((field) => field !== null)
2763
- );
2764
- };
2765
- const formatListLayout = (data, {
2766
- schemas,
2767
- schema,
2768
- components
2769
- }) => {
2770
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2771
- (acc, [attribute, metadata]) => {
2772
- return {
2773
- ...acc,
2774
- [attribute]: metadata.list
2775
- };
2776
- },
2777
- {}
2778
- );
2779
- const listAttributes = convertListLayoutToFieldLayouts(
2780
- data.contentType.layouts.list,
2781
- schema?.attributes,
2782
- listMetadatas,
2783
- { configurations: data.components, schemas: components },
2784
- schemas
2785
- );
2786
- return {
2787
- layout: listAttributes,
2788
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2789
- metadatas: listMetadatas,
2790
- options: {
2791
- ...schema?.options,
2792
- ...schema?.pluginOptions,
2793
- ...data.contentType.options
2794
- }
2960
+ const { formatMessage } = reactIntl.useIntl();
2961
+ return {
2962
+ title: formatMessage({
2963
+ id: "content-manager.containers.edit.panels.default.title",
2964
+ defaultMessage: "Entry"
2965
+ }),
2966
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2795
2967
  };
2796
2968
  };
2797
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2798
- return columns.map((name) => {
2799
- const attribute = attributes[name];
2800
- if (!attribute) {
2801
- return null;
2969
+ ActionsPanel.type = "actions";
2970
+ const ActionsPanelContent = () => {
2971
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2972
+ const [
2973
+ {
2974
+ query: { status = "draft" }
2802
2975
  }
2803
- const metadata = metadatas[name];
2804
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2805
- return {
2806
- attribute,
2807
- label: metadata.label ?? "",
2808
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2809
- schemas,
2810
- components: components?.schemas ?? {}
2811
- }),
2812
- name,
2813
- searchable: metadata.searchable ?? true,
2814
- sortable: metadata.sortable ?? true
2815
- };
2816
- }).filter((field) => field !== null);
2976
+ ] = strapiAdmin.useQueryParams();
2977
+ const { model, id, document, meta, collectionType } = useDoc();
2978
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2979
+ const props = {
2980
+ activeTab: status,
2981
+ model,
2982
+ documentId: id,
2983
+ document: isCloning ? void 0 : document,
2984
+ meta: isCloning ? void 0 : meta,
2985
+ collectionType
2986
+ };
2987
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2988
+ /* @__PURE__ */ jsxRuntime.jsx(
2989
+ strapiAdmin.DescriptionComponentRenderer,
2990
+ {
2991
+ props,
2992
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
2993
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2994
+ }
2995
+ ),
2996
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2997
+ ] });
2817
2998
  };
2999
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3000
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3001
+ designSystem.Flex,
3002
+ {
3003
+ ref,
3004
+ tag: "aside",
3005
+ "aria-labelledby": "additional-information",
3006
+ background: "neutral0",
3007
+ borderColor: "neutral150",
3008
+ hasRadius: true,
3009
+ paddingBottom: 4,
3010
+ paddingLeft: 4,
3011
+ paddingRight: 4,
3012
+ paddingTop: 4,
3013
+ shadow: "tableShadow",
3014
+ gap: 3,
3015
+ direction: "column",
3016
+ justifyContent: "stretch",
3017
+ alignItems: "flex-start",
3018
+ children: [
3019
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
3020
+ children
3021
+ ]
3022
+ }
3023
+ );
3024
+ });
2818
3025
  const ConfirmBulkActionDialog = ({
2819
3026
  onToggleDialog,
2820
3027
  isOpen = false,
@@ -2822,30 +3029,23 @@ const ConfirmBulkActionDialog = ({
2822
3029
  endAction
2823
3030
  }) => {
2824
3031
  const { formatMessage } = reactIntl.useIntl();
2825
- return /* @__PURE__ */ jsxRuntime.jsxs(
2826
- designSystem.Dialog,
2827
- {
2828
- onClose: onToggleDialog,
2829
- title: formatMessage({
2830
- id: "app.components.ConfirmDialog.title",
2831
- defaultMessage: "Confirmation"
2832
- }),
2833
- isOpen,
2834
- children: [
2835
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2836
- /* @__PURE__ */ jsxRuntime.jsx(
2837
- designSystem.DialogFooter,
2838
- {
2839
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2840
- id: "app.components.Button.cancel",
2841
- defaultMessage: "Cancel"
2842
- }) }),
2843
- endAction
2844
- }
2845
- )
2846
- ]
2847
- }
2848
- );
3032
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3033
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
3034
+ id: "app.components.ConfirmDialog.title",
3035
+ defaultMessage: "Confirmation"
3036
+ }) }),
3037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3038
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3039
+ dialogBody
3040
+ ] }) }),
3041
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
3042
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
3043
+ id: "app.components.Button.cancel",
3044
+ defaultMessage: "Cancel"
3045
+ }) }) }),
3046
+ endAction
3047
+ ] })
3048
+ ] }) });
2849
3049
  };
2850
3050
  const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2851
3051
  const ConfirmDialogPublishAll = ({
@@ -2860,6 +3060,7 @@ const ConfirmDialogPublishAll = ({
2860
3060
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2861
3061
  const { model, schema } = useDoc();
2862
3062
  const [{ query }] = strapiAdmin.useQueryParams();
3063
+ const enableDraftRelationsCount = false;
2863
3064
  const {
2864
3065
  data: countDraftRelations = 0,
2865
3066
  isLoading,
@@ -2871,7 +3072,7 @@ const ConfirmDialogPublishAll = ({
2871
3072
  locale: query?.plugins?.i18n?.locale
2872
3073
  },
2873
3074
  {
2874
- skip: selectedEntries.length === 0
3075
+ skip: !enableDraftRelationsCount
2875
3076
  }
2876
3077
  );
2877
3078
  React__namespace.useEffect(() => {
@@ -2950,7 +3151,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2950
3151
  )
2951
3152
  );
2952
3153
  } else {
2953
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3154
+ messages.push(
3155
+ ...formatErrorMessages(
3156
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3157
+ value,
3158
+ currentKey,
3159
+ formatMessage
3160
+ )
3161
+ );
2954
3162
  }
2955
3163
  } else {
2956
3164
  messages.push(
@@ -3049,7 +3257,7 @@ const SelectedEntriesTableContent = ({
3049
3257
  status: row.status
3050
3258
  }
3051
3259
  ) }),
3052
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3260
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3053
3261
  designSystem.IconButton,
3054
3262
  {
3055
3263
  tag: reactRouterDom.Link,
@@ -3072,9 +3280,10 @@ const SelectedEntriesTableContent = ({
3072
3280
  ),
3073
3281
  target: "_blank",
3074
3282
  marginLeft: "auto",
3075
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3283
+ variant: "ghost",
3284
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3076
3285
  }
3077
- ) })
3286
+ ) }) })
3078
3287
  ] }, row.id)) })
3079
3288
  ] });
3080
3289
  };
@@ -3111,7 +3320,13 @@ const SelectedEntriesModalContent = ({
3111
3320
  );
3112
3321
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3113
3322
  if (data.length > 0 && schema) {
3114
- const validate = createYupSchema(schema.attributes, components);
3323
+ const validate = createYupSchema(
3324
+ schema.attributes,
3325
+ components,
3326
+ // Since this is the "Publish" action, the validation
3327
+ // schema must enforce the rules for published entities
3328
+ { status: "published" }
3329
+ );
3115
3330
  const validationErrors2 = {};
3116
3331
  const rows2 = data.map((entry) => {
3117
3332
  try {
@@ -3187,7 +3402,7 @@ const SelectedEntriesModalContent = ({
3187
3402
  );
3188
3403
  };
3189
3404
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3190
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalBody, { children: [
3405
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3191
3406
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3192
3407
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3193
3408
  SelectedEntriesTableContent,
@@ -3199,27 +3414,24 @@ const SelectedEntriesModalContent = ({
3199
3414
  }
3200
3415
  ) })
3201
3416
  ] }),
3202
- /* @__PURE__ */ jsxRuntime.jsx(
3203
- designSystem.ModalFooter,
3204
- {
3205
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3206
- id: "app.components.Button.cancel",
3207
- defaultMessage: "Cancel"
3208
- }) }),
3209
- endActions: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3210
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3211
- /* @__PURE__ */ jsxRuntime.jsx(
3212
- designSystem.Button,
3213
- {
3214
- onClick: toggleDialog,
3215
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3216
- loading: isSubmittingForm,
3217
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3218
- }
3219
- )
3220
- ] })
3221
- }
3222
- ),
3417
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3418
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3419
+ id: "app.components.Button.cancel",
3420
+ defaultMessage: "Cancel"
3421
+ }) }),
3422
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3423
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3424
+ /* @__PURE__ */ jsxRuntime.jsx(
3425
+ designSystem.Button,
3426
+ {
3427
+ onClick: toggleDialog,
3428
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3429
+ loading: isSubmittingForm,
3430
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3431
+ }
3432
+ )
3433
+ ] })
3434
+ ] }),
3223
3435
  /* @__PURE__ */ jsxRuntime.jsx(
3224
3436
  ConfirmDialogPublishAll,
3225
3437
  {
@@ -3284,143 +3496,10 @@ const BulkActionsRenderer = () => {
3284
3496
  documents: selectedRows
3285
3497
  },
3286
3498
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3287
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
3499
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3288
3500
  }
3289
3501
  ) });
3290
3502
  };
3291
- const BulkActionAction = (action) => {
3292
- const [dialogId, setDialogId] = React__namespace.useState(null);
3293
- const { toggleNotification } = strapiAdmin.useNotification();
3294
- const handleClick = (action2) => (e) => {
3295
- const { onClick, dialog, id } = action2;
3296
- if (onClick) {
3297
- onClick(e);
3298
- }
3299
- if (dialog) {
3300
- switch (dialog.type) {
3301
- case "notification":
3302
- toggleNotification({
3303
- title: dialog.title,
3304
- message: dialog.content,
3305
- type: dialog.status,
3306
- timeout: dialog.timeout,
3307
- onClose: dialog.onClose
3308
- });
3309
- break;
3310
- case "dialog":
3311
- case "modal": {
3312
- e.preventDefault();
3313
- setDialogId(id);
3314
- }
3315
- }
3316
- }
3317
- };
3318
- const handleClose = () => {
3319
- setDialogId(null);
3320
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3321
- action.dialog.onClose();
3322
- }
3323
- };
3324
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3325
- /* @__PURE__ */ jsxRuntime.jsx(
3326
- designSystem.Button,
3327
- {
3328
- disabled: action.disabled,
3329
- startIcon: action.icon,
3330
- variant: action.variant,
3331
- onClick: handleClick(action),
3332
- children: action.label
3333
- }
3334
- ),
3335
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
3336
- BulkActionConfirmDialog,
3337
- {
3338
- ...action.dialog,
3339
- variant: action.variant,
3340
- isOpen: dialogId === action.id,
3341
- onClose: handleClose
3342
- }
3343
- ) : null,
3344
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
3345
- BulkActionModal,
3346
- {
3347
- ...action.dialog,
3348
- onModalClose: handleClose,
3349
- isOpen: dialogId === action.id
3350
- }
3351
- ) : null
3352
- ] });
3353
- };
3354
- const BulkActionConfirmDialog = ({
3355
- onClose,
3356
- onCancel,
3357
- onConfirm,
3358
- title,
3359
- content,
3360
- confirmButton,
3361
- isOpen,
3362
- variant = "secondary"
3363
- }) => {
3364
- const { formatMessage } = reactIntl.useIntl();
3365
- const handleClose = async () => {
3366
- if (onCancel) {
3367
- await onCancel();
3368
- }
3369
- onClose();
3370
- };
3371
- const handleConfirm = async () => {
3372
- if (onConfirm) {
3373
- await onConfirm();
3374
- }
3375
- onClose();
3376
- };
3377
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
3378
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
3379
- /* @__PURE__ */ jsxRuntime.jsx(
3380
- designSystem.DialogFooter,
3381
- {
3382
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3383
- id: "app.components.Button.cancel",
3384
- defaultMessage: "Cancel"
3385
- }) }),
3386
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
3387
- designSystem.Button,
3388
- {
3389
- onClick: handleConfirm,
3390
- variant: variant === "danger-light" ? variant : "secondary",
3391
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3392
- children: confirmButton ? confirmButton : formatMessage({
3393
- id: "app.components.Button.confirm",
3394
- defaultMessage: "Confirm"
3395
- })
3396
- }
3397
- )
3398
- }
3399
- )
3400
- ] });
3401
- };
3402
- const BulkActionModal = ({
3403
- isOpen,
3404
- title,
3405
- onClose,
3406
- content: Content,
3407
- onModalClose
3408
- }) => {
3409
- const id = React__namespace.useId();
3410
- if (!isOpen) {
3411
- return null;
3412
- }
3413
- const handleClose = () => {
3414
- if (onClose) {
3415
- onClose();
3416
- }
3417
- onModalClose();
3418
- };
3419
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3420
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3421
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
3422
- ] });
3423
- };
3424
3503
  const DeleteAction = ({ documents, model }) => {
3425
3504
  const { formatMessage } = reactIntl.useIntl();
3426
3505
  const { schema: contentType } = useDoc();
@@ -3453,6 +3532,7 @@ const DeleteAction = ({ documents, model }) => {
3453
3532
  defaultMessage: "Confirmation"
3454
3533
  }),
3455
3534
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3535
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3456
3536
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3457
3537
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3458
3538
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3502,6 +3582,7 @@ const UnpublishAction = ({ documents, model }) => {
3502
3582
  defaultMessage: "Confirmation"
3503
3583
  }),
3504
3584
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3585
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3505
3586
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3506
3587
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3507
3588
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3595,7 +3676,7 @@ const TableActions = ({ document }) => {
3595
3676
  strapiAdmin.DescriptionComponentRenderer,
3596
3677
  {
3597
3678
  props,
3598
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3679
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3599
3680
  children: (actions2) => {
3600
3681
  const tableRowActions = actions2.filter((action) => {
3601
3682
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3706,7 +3787,7 @@ const CloneAction = ({ model, documentId }) => {
3706
3787
  }),
3707
3788
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3708
3789
  footer: ({ onClose }) => {
3709
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3790
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3710
3791
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3711
3792
  id: "cancel",
3712
3793
  defaultMessage: "Cancel"
@@ -3747,8 +3828,7 @@ class ContentManagerPlugin {
3747
3828
  documentActions = [
3748
3829
  ...DEFAULT_ACTIONS,
3749
3830
  ...DEFAULT_TABLE_ROW_ACTIONS,
3750
- ...DEFAULT_HEADER_ACTIONS,
3751
- HistoryAction
3831
+ ...DEFAULT_HEADER_ACTIONS
3752
3832
  ];
3753
3833
  editViewSidePanels = [ActionsPanel];
3754
3834
  headerActions = [];
@@ -3837,6 +3917,52 @@ const getPrintableType = (value) => {
3837
3917
  }
3838
3918
  return nativeType;
3839
3919
  };
3920
+ const HistoryAction = ({ model, document }) => {
3921
+ const { formatMessage } = reactIntl.useIntl();
3922
+ const [{ query }] = strapiAdmin.useQueryParams();
3923
+ const navigate = reactRouterDom.useNavigate();
3924
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3925
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3926
+ return null;
3927
+ }
3928
+ return {
3929
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3930
+ label: formatMessage({
3931
+ id: "content-manager.history.document-action",
3932
+ defaultMessage: "Content History"
3933
+ }),
3934
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3935
+ disabled: (
3936
+ /**
3937
+ * The user is creating a new document.
3938
+ * It hasn't been saved yet, so there's no history to go to
3939
+ */
3940
+ !document || /**
3941
+ * The document has been created but the current dimension has never been saved.
3942
+ * For example, the user is creating a new locale in an existing document,
3943
+ * so there's no history for the document in that locale
3944
+ */
3945
+ !document.id || /**
3946
+ * History is only available for content types created by the user.
3947
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3948
+ * which start with `admin::` or `plugin::`
3949
+ */
3950
+ !model.startsWith("api::")
3951
+ ),
3952
+ position: "header"
3953
+ };
3954
+ };
3955
+ HistoryAction.type = "history";
3956
+ const historyAdmin = {
3957
+ bootstrap(app) {
3958
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3959
+ addDocumentAction((actions2) => {
3960
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3961
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3962
+ return actions2;
3963
+ });
3964
+ }
3965
+ };
3840
3966
  const initialState = {
3841
3967
  collectionTypeLinks: [],
3842
3968
  components: [],
@@ -3887,15 +4013,29 @@ const index = {
3887
4013
  defaultMessage: "Content Manager"
3888
4014
  },
3889
4015
  permissions: [],
3890
- Component: () => Promise.resolve().then(() => require("./layout-DEYBqgF1.js")).then((mod) => ({ default: mod.Layout })),
3891
4016
  position: 1
3892
4017
  });
4018
+ app.router.addRoute({
4019
+ path: "content-manager/*",
4020
+ lazy: async () => {
4021
+ const { Layout } = await Promise.resolve().then(() => require("./layout-UNWstw_s.js"));
4022
+ return {
4023
+ Component: Layout
4024
+ };
4025
+ },
4026
+ children: routes
4027
+ });
3893
4028
  app.registerPlugin(cm.config);
3894
4029
  },
4030
+ bootstrap(app) {
4031
+ if (typeof historyAdmin.bootstrap === "function") {
4032
+ historyAdmin.bootstrap(app);
4033
+ }
4034
+ },
3895
4035
  async registerTrads({ locales }) {
3896
4036
  const importedTrads = await Promise.all(
3897
4037
  locales.map((locale) => {
3898
- 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-fbKQxLGn.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 }) => {
4038
+ 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-BlhnxQfj.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 }) => {
3899
4039
  return {
3900
4040
  data: prefixPluginTranslations(data, PLUGIN_ID),
3901
4041
  locale
@@ -3913,6 +4053,7 @@ const index = {
3913
4053
  };
3914
4054
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3915
4055
  exports.BulkActionsRenderer = BulkActionsRenderer;
4056
+ exports.CLONE_PATH = CLONE_PATH;
3916
4057
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3917
4058
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3918
4059
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3939,8 +4080,8 @@ exports.getDisplayName = getDisplayName;
3939
4080
  exports.getMainField = getMainField;
3940
4081
  exports.getTranslation = getTranslation;
3941
4082
  exports.index = index;
3942
- exports.routes = routes;
3943
4083
  exports.setInitialData = setInitialData;
4084
+ exports.useContentManagerContext = useContentManagerContext;
3944
4085
  exports.useContentTypeSchema = useContentTypeSchema;
3945
4086
  exports.useDoc = useDoc;
3946
4087
  exports.useDocLayout = useDocLayout;
@@ -3953,4 +4094,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3953
4094
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3954
4095
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3955
4096
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3956
- //# sourceMappingURL=index-BZoNZMXL.js.map
4097
+ //# sourceMappingURL=index-ovJRE1FM.js.map