@strapi/content-manager 0.0.0-experimental.7afdc9b682bc83a53ce599c4fb7c9e4506b31fff → 0.0.0-experimental.7b750d18de359d0a42233cb8707e3c31c5983345

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 (134) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js → ComponentConfigurationPage-DnnZJc1F.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js.map → ComponentConfigurationPage-DnnZJc1F.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs → ComponentConfigurationPage-hLMNf7KI.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs.map → ComponentConfigurationPage-hLMNf7KI.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js → EditConfigurationPage-CpLj5gYZ.js} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js.map → EditConfigurationPage-CpLj5gYZ.js.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs → EditConfigurationPage-Dh6sq-G4.mjs} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs.map → EditConfigurationPage-Dh6sq-G4.mjs.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-DvaV7U9b.mjs → EditViewPage-BU1ugeVi.mjs} +58 -47
  11. package/dist/_chunks/EditViewPage-BU1ugeVi.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CoQEnFlC.js → EditViewPage-D2QVRr_2.js} +57 -46
  13. package/dist/_chunks/EditViewPage-D2QVRr_2.js.map +1 -0
  14. package/dist/_chunks/{Field-ZdrmmQ4Y.js → Field-BEDX9i_V.js} +528 -220
  15. package/dist/_chunks/Field-BEDX9i_V.js.map +1 -0
  16. package/dist/_chunks/{Field-Cz_J9551.mjs → Field-VSPY6uzs.mjs} +526 -218
  17. package/dist/_chunks/Field-VSPY6uzs.mjs.map +1 -0
  18. package/dist/_chunks/{Form-Dxmihyw8.mjs → Form-05Oaes1N.mjs} +53 -35
  19. package/dist/_chunks/Form-05Oaes1N.mjs.map +1 -0
  20. package/dist/_chunks/{Form-Bpig5rch.js → Form-DCaY8xBX.js} +51 -33
  21. package/dist/_chunks/Form-DCaY8xBX.js.map +1 -0
  22. package/dist/_chunks/{History-BZP8n7KT.mjs → History-BqO2G3MV.mjs} +141 -37
  23. package/dist/_chunks/History-BqO2G3MV.mjs.map +1 -0
  24. package/dist/_chunks/{History-BfX6XmZK.js → History-BrJ1tUvt.js} +140 -36
  25. package/dist/_chunks/History-BrJ1tUvt.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DxKuVkKz.mjs → ListConfigurationPage-C6rsFlme.mjs} +58 -48
  27. package/dist/_chunks/ListConfigurationPage-C6rsFlme.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-B3CXj8PY.js → ListConfigurationPage-Eane5LKE.js} +57 -46
  29. package/dist/_chunks/ListConfigurationPage-Eane5LKE.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-Bk9VO__I.js → ListViewPage-Coj-RPsx.js} +105 -104
  31. package/dist/_chunks/ListViewPage-Coj-RPsx.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-D5D3tVPq.mjs → ListViewPage-yE_zYhcI.mjs} +103 -102
  33. package/dist/_chunks/ListViewPage-yE_zYhcI.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js → NoContentTypePage-BDJ0dshy.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js.map → NoContentTypePage-BDJ0dshy.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs → NoContentTypePage-NW_FSVdY.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs.map → NoContentTypePage-NW_FSVdY.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js → NoPermissionsPage-BOtb5FTM.js} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js.map → NoPermissionsPage-BOtb5FTM.js.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs → NoPermissionsPage-h0I3ImsX.mjs} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs.map → NoPermissionsPage-h0I3ImsX.mjs.map} +1 -1
  42. package/dist/_chunks/{Relations-B6B3A3mb.js → Relations-CVh0DOKv.js} +4 -4
  43. package/dist/_chunks/Relations-CVh0DOKv.js.map +1 -0
  44. package/dist/_chunks/{Relations-BOYZmuWy.mjs → Relations-FP0uWpBz.mjs} +4 -4
  45. package/dist/_chunks/Relations-FP0uWpBz.mjs.map +1 -0
  46. package/dist/_chunks/{en-BN1bvFK7.js → en-BlhnxQfj.js} +14 -9
  47. package/dist/_chunks/{en-BN1bvFK7.js.map → en-BlhnxQfj.js.map} +1 -1
  48. package/dist/_chunks/{en-Dzv55oQw.mjs → en-C8YBvRrK.mjs} +14 -9
  49. package/dist/_chunks/{en-Dzv55oQw.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  50. package/dist/_chunks/{index-VHviNMeW.mjs → index-CPCHQ3X_.mjs} +1031 -874
  51. package/dist/_chunks/index-CPCHQ3X_.mjs.map +1 -0
  52. package/dist/_chunks/{index-DzN3kBgx.js → index-DTKVhcla.js} +1008 -851
  53. package/dist/_chunks/index-DTKVhcla.js.map +1 -0
  54. package/dist/_chunks/{layout-CPn1PM6x.mjs → layout-B4UhJ8MJ.mjs} +41 -23
  55. package/dist/_chunks/layout-B4UhJ8MJ.mjs.map +1 -0
  56. package/dist/_chunks/{layout-b91XRlD2.js → layout-CWgZzMYf.js} +39 -21
  57. package/dist/_chunks/layout-CWgZzMYf.js.map +1 -0
  58. package/dist/_chunks/{relations-BsqxS6tR.mjs → relations-B83Ge9a7.mjs} +2 -2
  59. package/dist/_chunks/{relations-BsqxS6tR.mjs.map → relations-B83Ge9a7.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CA7IYmcP.js → relations-D81a_2zw.js} +2 -2
  61. package/dist/_chunks/{relations-CA7IYmcP.js.map → relations-D81a_2zw.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 +7 -6
  69. package/dist/admin/src/exports.d.ts +1 -1
  70. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  71. package/dist/admin/src/history/index.d.ts +3 -0
  72. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  73. package/dist/admin/src/hooks/useDocument.d.ts +30 -1
  74. package/dist/admin/src/index.d.ts +1 -0
  75. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  76. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  78. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  79. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  80. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  81. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  82. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  83. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  84. package/dist/admin/src/services/api.d.ts +1 -1
  85. package/dist/admin/src/services/components.d.ts +2 -2
  86. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  87. package/dist/admin/src/services/documents.d.ts +19 -17
  88. package/dist/admin/src/services/init.d.ts +1 -1
  89. package/dist/admin/src/services/relations.d.ts +2 -2
  90. package/dist/admin/src/services/uid.d.ts +3 -3
  91. package/dist/admin/src/utils/validation.d.ts +4 -1
  92. package/dist/server/index.js +183 -108
  93. package/dist/server/index.js.map +1 -1
  94. package/dist/server/index.mjs +184 -109
  95. package/dist/server/index.mjs.map +1 -1
  96. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  97. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  98. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  99. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  100. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  101. package/dist/server/src/history/services/history.d.ts.map +1 -1
  102. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  103. package/dist/server/src/history/services/utils.d.ts +2 -1
  104. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  105. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  106. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  107. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  108. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  109. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  110. package/dist/shared/contracts/collection-types.d.ts +3 -1
  111. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  112. package/package.json +11 -11
  113. package/dist/_chunks/EditViewPage-CoQEnFlC.js.map +0 -1
  114. package/dist/_chunks/EditViewPage-DvaV7U9b.mjs.map +0 -1
  115. package/dist/_chunks/Field-Cz_J9551.mjs.map +0 -1
  116. package/dist/_chunks/Field-ZdrmmQ4Y.js.map +0 -1
  117. package/dist/_chunks/Form-Bpig5rch.js.map +0 -1
  118. package/dist/_chunks/Form-Dxmihyw8.mjs.map +0 -1
  119. package/dist/_chunks/History-BZP8n7KT.mjs.map +0 -1
  120. package/dist/_chunks/History-BfX6XmZK.js.map +0 -1
  121. package/dist/_chunks/ListConfigurationPage-B3CXj8PY.js.map +0 -1
  122. package/dist/_chunks/ListConfigurationPage-DxKuVkKz.mjs.map +0 -1
  123. package/dist/_chunks/ListViewPage-Bk9VO__I.js.map +0 -1
  124. package/dist/_chunks/ListViewPage-D5D3tVPq.mjs.map +0 -1
  125. package/dist/_chunks/Relations-B6B3A3mb.js.map +0 -1
  126. package/dist/_chunks/Relations-BOYZmuWy.mjs.map +0 -1
  127. package/dist/_chunks/index-DzN3kBgx.js.map +0 -1
  128. package/dist/_chunks/index-VHviNMeW.mjs.map +0 -1
  129. package/dist/_chunks/layout-CPn1PM6x.mjs.map +0 -1
  130. package/dist/_chunks/layout-b91XRlD2.js.map +0 -1
  131. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  132. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  133. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  134. 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": {
@@ -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,267 @@ 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
+ return {
1169
+ components,
1170
+ document: data?.data,
1171
+ meta: data?.meta,
1172
+ isLoading,
1173
+ schema,
1174
+ schemas,
1175
+ validate
1176
+ };
1177
+ };
1178
+ const useDoc = () => {
1179
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1180
+ const [{ query }] = strapiAdmin.useQueryParams();
1181
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1182
+ if (!collectionType) {
1183
+ throw new Error("Could not find collectionType in url params");
1184
+ }
1185
+ if (!slug) {
1186
+ throw new Error("Could not find model in url params");
1187
+ }
1188
+ return {
1189
+ collectionType,
844
1190
  model: slug,
845
1191
  id: origin || id === "create" ? void 0 : id,
846
1192
  ...useDocument(
@@ -851,6 +1197,45 @@ const useDoc = () => {
851
1197
  )
852
1198
  };
853
1199
  };
1200
+ const useContentManagerContext = () => {
1201
+ const {
1202
+ collectionType,
1203
+ model,
1204
+ id,
1205
+ components,
1206
+ isLoading: isLoadingDoc,
1207
+ schema,
1208
+ schemas
1209
+ } = useDoc();
1210
+ const layout = useDocumentLayout(model);
1211
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1212
+ const isSingleType = collectionType === SINGLE_TYPES;
1213
+ const slug = model;
1214
+ const isCreatingEntry = id === "create";
1215
+ useContentTypeSchema();
1216
+ const isLoading = isLoadingDoc || layout.isLoading;
1217
+ const error = layout.error;
1218
+ return {
1219
+ error,
1220
+ isLoading,
1221
+ // Base metadata
1222
+ model,
1223
+ collectionType,
1224
+ id,
1225
+ slug,
1226
+ isCreatingEntry,
1227
+ isSingleType,
1228
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1229
+ // All schema infos
1230
+ components,
1231
+ contentType: schema,
1232
+ contentTypes: schemas,
1233
+ // Form state
1234
+ form,
1235
+ // layout infos
1236
+ layout
1237
+ };
1238
+ };
854
1239
  const prefixPluginTranslations = (trad, pluginId) => {
855
1240
  if (!pluginId) {
856
1241
  throw new TypeError("pluginId can't be empty");
@@ -870,6 +1255,8 @@ const useDocumentActions = () => {
870
1255
  const { formatMessage } = reactIntl.useIntl();
871
1256
  const { trackUsage } = strapiAdmin.useTracking();
872
1257
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1258
+ const navigate = reactRouterDom.useNavigate();
1259
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
873
1260
  const [deleteDocument] = useDeleteDocumentMutation();
874
1261
  const _delete = React__namespace.useCallback(
875
1262
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -948,12 +1335,13 @@ const useDocumentActions = () => {
948
1335
  );
949
1336
  const [discardDocument] = useDiscardDocumentMutation();
950
1337
  const discard = React__namespace.useCallback(
951
- async ({ collectionType, model, documentId }) => {
1338
+ async ({ collectionType, model, documentId, params }) => {
952
1339
  try {
953
1340
  const res = await discardDocument({
954
1341
  collectionType,
955
1342
  model,
956
- documentId
1343
+ documentId,
1344
+ params
957
1345
  });
958
1346
  if ("error" in res) {
959
1347
  toggleNotification({
@@ -1183,6 +1571,7 @@ const useDocumentActions = () => {
1183
1571
  defaultMessage: "Saved document"
1184
1572
  })
1185
1573
  });
1574
+ setCurrentStep("contentManager.success");
1186
1575
  return res.data;
1187
1576
  } catch (err) {
1188
1577
  toggleNotification({
@@ -1204,7 +1593,6 @@ const useDocumentActions = () => {
1204
1593
  sourceId
1205
1594
  });
1206
1595
  if ("error" in res) {
1207
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1208
1596
  return { error: res.error };
1209
1597
  }
1210
1598
  toggleNotification({
@@ -1223,7 +1611,7 @@ const useDocumentActions = () => {
1223
1611
  throw err;
1224
1612
  }
1225
1613
  },
1226
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1614
+ [autoCloneDocument, formatMessage, toggleNotification]
1227
1615
  );
1228
1616
  const [cloneDocument] = useCloneDocumentMutation();
1229
1617
  const clone = React__namespace.useCallback(
@@ -1249,6 +1637,7 @@ const useDocumentActions = () => {
1249
1637
  defaultMessage: "Cloned document"
1250
1638
  })
1251
1639
  });
1640
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1252
1641
  return res.data;
1253
1642
  } catch (err) {
1254
1643
  toggleNotification({
@@ -1259,7 +1648,7 @@ const useDocumentActions = () => {
1259
1648
  throw err;
1260
1649
  }
1261
1650
  },
1262
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1651
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1263
1652
  );
1264
1653
  const [getDoc] = useLazyGetDocumentQuery();
1265
1654
  const getDocument = React__namespace.useCallback(
@@ -1285,7 +1674,7 @@ const useDocumentActions = () => {
1285
1674
  };
1286
1675
  };
1287
1676
  const ProtectedHistoryPage = React.lazy(
1288
- () => Promise.resolve().then(() => require("./History-BfX6XmZK.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1677
+ () => Promise.resolve().then(() => require("./History-BrJ1tUvt.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1289
1678
  );
1290
1679
  const routes$1 = [
1291
1680
  {
@@ -1298,31 +1687,31 @@ const routes$1 = [
1298
1687
  }
1299
1688
  ];
1300
1689
  const ProtectedEditViewPage = React.lazy(
1301
- () => Promise.resolve().then(() => require("./EditViewPage-CoQEnFlC.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1690
+ () => Promise.resolve().then(() => require("./EditViewPage-D2QVRr_2.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1302
1691
  );
1303
1692
  const ProtectedListViewPage = React.lazy(
1304
- () => Promise.resolve().then(() => require("./ListViewPage-Bk9VO__I.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1693
+ () => Promise.resolve().then(() => require("./ListViewPage-Coj-RPsx.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1305
1694
  );
1306
1695
  const ProtectedListConfiguration = React.lazy(
1307
- () => Promise.resolve().then(() => require("./ListConfigurationPage-B3CXj8PY.js")).then((mod) => ({
1696
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-Eane5LKE.js")).then((mod) => ({
1308
1697
  default: mod.ProtectedListConfiguration
1309
1698
  }))
1310
1699
  );
1311
1700
  const ProtectedEditConfigurationPage = React.lazy(
1312
- () => Promise.resolve().then(() => require("./EditConfigurationPage-tDtWj7R2.js")).then((mod) => ({
1701
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-CpLj5gYZ.js")).then((mod) => ({
1313
1702
  default: mod.ProtectedEditConfigurationPage
1314
1703
  }))
1315
1704
  );
1316
1705
  const ProtectedComponentConfigurationPage = React.lazy(
1317
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DJcn1DrO.js")).then((mod) => ({
1706
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DnnZJc1F.js")).then((mod) => ({
1318
1707
  default: mod.ProtectedComponentConfigurationPage
1319
1708
  }))
1320
1709
  );
1321
1710
  const NoPermissions = React.lazy(
1322
- () => Promise.resolve().then(() => require("./NoPermissionsPage-BQDM64_b.js")).then((mod) => ({ default: mod.NoPermissions }))
1711
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-BOtb5FTM.js")).then((mod) => ({ default: mod.NoPermissions }))
1323
1712
  );
1324
1713
  const NoContentType = React.lazy(
1325
- () => Promise.resolve().then(() => require("./NoContentTypePage-DsB2F7Z1.js")).then((mod) => ({ default: mod.NoContentType }))
1714
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BDJ0dshy.js")).then((mod) => ({ default: mod.NoContentType }))
1326
1715
  );
1327
1716
  const CollectionTypePages = () => {
1328
1717
  const { collectionType } = reactRouterDom.useParams();
@@ -1436,12 +1825,14 @@ const DocumentActionButton = (action) => {
1436
1825
  /* @__PURE__ */ jsxRuntime.jsx(
1437
1826
  designSystem.Button,
1438
1827
  {
1439
- flex: 1,
1828
+ flex: "auto",
1440
1829
  startIcon: action.icon,
1441
1830
  disabled: action.disabled,
1442
1831
  onClick: handleClick(action),
1443
1832
  justifyContent: "center",
1444
1833
  variant: action.variant || "default",
1834
+ paddingTop: "7px",
1835
+ paddingBottom: "7px",
1445
1836
  children: action.label
1446
1837
  }
1447
1838
  ),
@@ -1449,7 +1840,7 @@ const DocumentActionButton = (action) => {
1449
1840
  DocumentActionConfirmDialog,
1450
1841
  {
1451
1842
  ...action.dialog,
1452
- variant: action.variant,
1843
+ variant: action.dialog?.variant ?? action.variant,
1453
1844
  isOpen: dialogId === action.id,
1454
1845
  onClose: handleClose
1455
1846
  }
@@ -1506,9 +1897,9 @@ const DocumentActionsMenu = ({
1506
1897
  disabled: isDisabled,
1507
1898
  size: "S",
1508
1899
  endIcon: null,
1509
- paddingTop: "7px",
1510
- paddingLeft: "9px",
1511
- paddingRight: "9px",
1900
+ paddingTop: "4px",
1901
+ paddingLeft: "7px",
1902
+ paddingRight: "7px",
1512
1903
  variant,
1513
1904
  children: [
1514
1905
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1519,7 +1910,7 @@ const DocumentActionsMenu = ({
1519
1910
  ]
1520
1911
  }
1521
1912
  ),
1522
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1913
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1523
1914
  actions2.map((action) => {
1524
1915
  return /* @__PURE__ */ jsxRuntime.jsx(
1525
1916
  designSystem.Menu.Item,
@@ -1528,10 +1919,25 @@ const DocumentActionsMenu = ({
1528
1919
  onSelect: handleClick(action),
1529
1920
  display: "block",
1530
1921
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1531
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1532
- action.icon,
1533
- action.label
1534
- ] }),
1922
+ /* @__PURE__ */ jsxRuntime.jsxs(
1923
+ designSystem.Flex,
1924
+ {
1925
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1926
+ gap: 2,
1927
+ tag: "span",
1928
+ children: [
1929
+ /* @__PURE__ */ jsxRuntime.jsx(
1930
+ designSystem.Flex,
1931
+ {
1932
+ tag: "span",
1933
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1934
+ children: action.icon
1935
+ }
1936
+ ),
1937
+ action.label
1938
+ ]
1939
+ }
1940
+ ),
1535
1941
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1536
1942
  designSystem.Flex,
1537
1943
  {
@@ -1590,6 +1996,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1590
1996
  return "primary600";
1591
1997
  }
1592
1998
  };
1999
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2000
+ switch (variant) {
2001
+ case "danger":
2002
+ return "danger600";
2003
+ case "secondary":
2004
+ return "neutral500";
2005
+ case "success":
2006
+ return "success600";
2007
+ default:
2008
+ return "primary600";
2009
+ }
2010
+ };
1593
2011
  const DocumentActionConfirmDialog = ({
1594
2012
  onClose,
1595
2013
  onCancel,
@@ -1612,22 +2030,20 @@ const DocumentActionConfirmDialog = ({
1612
2030
  }
1613
2031
  onClose();
1614
2032
  };
1615
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1616
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1617
- /* @__PURE__ */ jsxRuntime.jsx(
1618
- designSystem.DialogFooter,
1619
- {
1620
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1621
- id: "app.components.Button.cancel",
1622
- defaultMessage: "Cancel"
1623
- }) }),
1624
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1625
- id: "app.components.Button.confirm",
1626
- defaultMessage: "Confirm"
1627
- }) })
1628
- }
1629
- )
1630
- ] });
2033
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2034
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2035
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2036
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2038
+ id: "app.components.Button.cancel",
2039
+ defaultMessage: "Cancel"
2040
+ }) }) }),
2041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2042
+ id: "app.components.Button.confirm",
2043
+ defaultMessage: "Confirm"
2044
+ }) })
2045
+ ] })
2046
+ ] }) });
1631
2047
  };
1632
2048
  const DocumentActionModal = ({
1633
2049
  isOpen,
@@ -1637,34 +2053,17 @@ const DocumentActionModal = ({
1637
2053
  content: Content,
1638
2054
  onModalClose
1639
2055
  }) => {
1640
- const id = React__namespace.useId();
1641
- if (!isOpen) {
1642
- return null;
1643
- }
1644
2056
  const handleClose = () => {
1645
2057
  if (onClose) {
1646
2058
  onClose();
1647
2059
  }
1648
2060
  onModalClose();
1649
2061
  };
1650
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1651
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(
1654
- designSystem.Box,
1655
- {
1656
- paddingTop: 4,
1657
- paddingBottom: 4,
1658
- paddingLeft: 5,
1659
- paddingRight: 5,
1660
- borderWidth: "1px 0 0 0",
1661
- borderStyle: "solid",
1662
- borderColor: "neutral150",
1663
- background: "neutral100",
1664
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1665
- }
1666
- )
1667
- ] });
2062
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2064
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2065
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2066
+ ] }) });
1668
2067
  };
1669
2068
  const PublishAction$1 = ({
1670
2069
  activeTab,
@@ -1678,13 +2077,17 @@ const PublishAction$1 = ({
1678
2077
  const navigate = reactRouterDom.useNavigate();
1679
2078
  const { toggleNotification } = strapiAdmin.useNotification();
1680
2079
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2080
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1681
2081
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1682
2082
  const { formatMessage } = reactIntl.useIntl();
1683
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1684
- "PublishAction",
1685
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1686
- );
2083
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1687
2084
  const { publish } = useDocumentActions();
2085
+ const [
2086
+ countDraftRelations,
2087
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2088
+ ] = useLazyGetDraftRelationCountQuery();
2089
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2090
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1688
2091
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1689
2092
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1690
2093
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1693,10 +2096,103 @@ const PublishAction$1 = ({
1693
2096
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1694
2097
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1695
2098
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2099
+ React__namespace.useEffect(() => {
2100
+ if (isErrorDraftRelations) {
2101
+ toggleNotification({
2102
+ type: "danger",
2103
+ message: formatMessage({
2104
+ id: getTranslation("error.records.fetch-draft-relatons"),
2105
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2106
+ })
2107
+ });
2108
+ }
2109
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2110
+ React__namespace.useEffect(() => {
2111
+ const localDraftRelations = /* @__PURE__ */ new Set();
2112
+ const extractDraftRelations = (data) => {
2113
+ const relations = data.connect || [];
2114
+ relations.forEach((relation) => {
2115
+ if (relation.status === "draft") {
2116
+ localDraftRelations.add(relation.id);
2117
+ }
2118
+ });
2119
+ };
2120
+ const traverseAndExtract = (data) => {
2121
+ Object.entries(data).forEach(([key, value]) => {
2122
+ if (key === "connect" && Array.isArray(value)) {
2123
+ extractDraftRelations({ connect: value });
2124
+ } else if (typeof value === "object" && value !== null) {
2125
+ traverseAndExtract(value);
2126
+ }
2127
+ });
2128
+ };
2129
+ if (!documentId || modified) {
2130
+ traverseAndExtract(formValues);
2131
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2132
+ }
2133
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2134
+ React__namespace.useEffect(() => {
2135
+ if (!document || !document.documentId || isListView) {
2136
+ return;
2137
+ }
2138
+ const fetchDraftRelationsCount = async () => {
2139
+ const { data, error } = await countDraftRelations({
2140
+ collectionType,
2141
+ model,
2142
+ documentId,
2143
+ params
2144
+ });
2145
+ if (error) {
2146
+ throw error;
2147
+ }
2148
+ if (data) {
2149
+ setServerCountOfDraftRelations(data.data);
2150
+ }
2151
+ };
2152
+ fetchDraftRelationsCount();
2153
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1696
2154
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1697
2155
  if (!schema?.options?.draftAndPublish) {
1698
2156
  return null;
1699
2157
  }
2158
+ const performPublish = async () => {
2159
+ setSubmitting(true);
2160
+ try {
2161
+ const { errors } = await validate();
2162
+ if (errors) {
2163
+ toggleNotification({
2164
+ type: "danger",
2165
+ message: formatMessage({
2166
+ id: "content-manager.validation.error",
2167
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2168
+ })
2169
+ });
2170
+ return;
2171
+ }
2172
+ const res = await publish(
2173
+ {
2174
+ collectionType,
2175
+ model,
2176
+ documentId,
2177
+ params
2178
+ },
2179
+ formValues
2180
+ );
2181
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2182
+ navigate({
2183
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2184
+ search: rawQuery
2185
+ });
2186
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2187
+ setErrors(formatValidationErrors(res.error));
2188
+ }
2189
+ } finally {
2190
+ setSubmitting(false);
2191
+ }
2192
+ };
2193
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2194
+ const enableDraftRelationsCount = false;
2195
+ const hasDraftRelations = enableDraftRelationsCount;
1700
2196
  return {
1701
2197
  /**
1702
2198
  * Disabled when:
@@ -1706,49 +2202,36 @@ const PublishAction$1 = ({
1706
2202
  * - the document is already published & not modified
1707
2203
  * - the document is being created & not modified
1708
2204
  * - the user doesn't have the permission to publish
1709
- * - the user doesn't have the permission to create a new document
1710
- * - the user doesn't have the permission to update the document
1711
2205
  */
1712
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2206
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1713
2207
  label: formatMessage({
1714
2208
  id: "app.utils.publish",
1715
2209
  defaultMessage: "Publish"
1716
2210
  }),
1717
2211
  onClick: async () => {
1718
- setSubmitting(true);
1719
- try {
1720
- const { errors } = await validate();
1721
- if (errors) {
1722
- toggleNotification({
1723
- type: "danger",
1724
- message: formatMessage({
1725
- id: "content-manager.validation.error",
1726
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1727
- })
1728
- });
1729
- return;
1730
- }
1731
- const res = await publish(
1732
- {
1733
- collectionType,
1734
- model,
1735
- documentId,
1736
- params
1737
- },
1738
- formValues
1739
- );
1740
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1741
- navigate({
1742
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1743
- search: rawQuery
1744
- });
1745
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1746
- setErrors(formatValidationErrors(res.error));
2212
+ await performPublish();
2213
+ },
2214
+ dialog: hasDraftRelations ? {
2215
+ type: "dialog",
2216
+ variant: "danger",
2217
+ footer: null,
2218
+ title: formatMessage({
2219
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2220
+ defaultMessage: "Confirmation"
2221
+ }),
2222
+ content: formatMessage(
2223
+ {
2224
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2225
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2226
+ },
2227
+ {
2228
+ count: totalDraftRelations
1747
2229
  }
1748
- } finally {
1749
- setSubmitting(false);
2230
+ ),
2231
+ onConfirm: async () => {
2232
+ await performPublish();
1750
2233
  }
1751
- }
2234
+ } : void 0
1752
2235
  };
1753
2236
  };
1754
2237
  PublishAction$1.type = "publish";
@@ -1764,10 +2247,6 @@ const UpdateAction = ({
1764
2247
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1765
2248
  const isCloning = cloneMatch !== null;
1766
2249
  const { formatMessage } = reactIntl.useIntl();
1767
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1768
- canCreate: canCreate2,
1769
- canUpdate: canUpdate2
1770
- }));
1771
2250
  const { create, update, clone } = useDocumentActions();
1772
2251
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1773
2252
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1784,10 +2263,8 @@ const UpdateAction = ({
1784
2263
  * - the form is submitting
1785
2264
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1786
2265
  * - the active tab is the published tab
1787
- * - the user doesn't have the permission to create a new document
1788
- * - the user doesn't have the permission to update the document
1789
2266
  */
1790
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2267
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1791
2268
  label: formatMessage({
1792
2269
  id: "content-manager.containers.Edit.save",
1793
2270
  defaultMessage: "Save"
@@ -1795,16 +2272,18 @@ const UpdateAction = ({
1795
2272
  onClick: async () => {
1796
2273
  setSubmitting(true);
1797
2274
  try {
1798
- const { errors } = await validate();
1799
- if (errors) {
1800
- toggleNotification({
1801
- type: "danger",
1802
- message: formatMessage({
1803
- id: "content-manager.validation.error",
1804
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1805
- })
1806
- });
1807
- return;
2275
+ if (activeTab !== "draft") {
2276
+ const { errors } = await validate();
2277
+ if (errors) {
2278
+ toggleNotification({
2279
+ type: "danger",
2280
+ message: formatMessage({
2281
+ id: "content-manager.validation.error",
2282
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2283
+ })
2284
+ });
2285
+ return;
2286
+ }
1808
2287
  }
1809
2288
  if (isCloning) {
1810
2289
  const res = await clone(
@@ -1816,10 +2295,13 @@ const UpdateAction = ({
1816
2295
  document
1817
2296
  );
1818
2297
  if ("data" in res) {
1819
- navigate({
1820
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1821
- search: rawQuery
1822
- });
2298
+ navigate(
2299
+ {
2300
+ pathname: `../${res.data.documentId}`,
2301
+ search: rawQuery
2302
+ },
2303
+ { relative: "path" }
2304
+ );
1823
2305
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1824
2306
  setErrors(formatValidationErrors(res.error));
1825
2307
  }
@@ -1847,10 +2329,13 @@ const UpdateAction = ({
1847
2329
  document
1848
2330
  );
1849
2331
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1850
- navigate({
1851
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1852
- search: rawQuery
1853
- });
2332
+ navigate(
2333
+ {
2334
+ pathname: `../${res.data.documentId}`,
2335
+ search: rawQuery
2336
+ },
2337
+ { replace: true, relative: "path" }
2338
+ );
1854
2339
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1855
2340
  setErrors(formatValidationErrors(res.error));
1856
2341
  }
@@ -1882,10 +2367,8 @@ const UnpublishAction$1 = ({
1882
2367
  const { toggleNotification } = strapiAdmin.useNotification();
1883
2368
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1884
2369
  const isDocumentModified = document?.status === "modified";
1885
- const handleChange = (e) => {
1886
- if ("value" in e.target) {
1887
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1888
- }
2370
+ const handleChange = (value) => {
2371
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
2372
  };
1890
2373
  if (!schema?.options?.draftAndPublish) {
1891
2374
  return null;
@@ -1896,7 +2379,7 @@ const UnpublishAction$1 = ({
1896
2379
  id: "app.utils.unpublish",
1897
2380
  defaultMessage: "Unpublish"
1898
2381
  }),
1899
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2382
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1900
2383
  onClick: async () => {
1901
2384
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1902
2385
  if (!documentId) {
@@ -1935,40 +2418,24 @@ const UnpublishAction$1 = ({
1935
2418
  }) })
1936
2419
  ] }),
1937
2420
  /* @__PURE__ */ jsxRuntime.jsxs(
1938
- designSystem.Flex,
2421
+ designSystem.Radio.Group,
1939
2422
  {
1940
- onChange: handleChange,
1941
- direction: "column",
1942
- alignItems: "flex-start",
1943
- tag: "fieldset",
1944
- borderWidth: 0,
1945
- gap: 3,
2423
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2424
+ name: "discard-options",
2425
+ "aria-label": formatMessage({
2426
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2427
+ defaultMessage: "Choose an option to unpublish the document."
2428
+ }),
2429
+ onValueChange: handleChange,
1946
2430
  children: [
1947
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1948
- /* @__PURE__ */ jsxRuntime.jsx(
1949
- designSystem.Radio,
1950
- {
1951
- checked: shouldKeepDraft,
1952
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1953
- name: "discard-options",
1954
- children: formatMessage({
1955
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1956
- defaultMessage: "Keep draft"
1957
- })
1958
- }
1959
- ),
1960
- /* @__PURE__ */ jsxRuntime.jsx(
1961
- designSystem.Radio,
1962
- {
1963
- checked: !shouldKeepDraft,
1964
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1965
- name: "discard-options",
1966
- children: formatMessage({
1967
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1968
- defaultMessage: "Replace draft"
1969
- })
1970
- }
1971
- )
2431
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2432
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2433
+ defaultMessage: "Keep draft"
2434
+ }) }),
2435
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2436
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2437
+ defaultMessage: "Replace draft"
2438
+ }) })
1972
2439
  ]
1973
2440
  }
1974
2441
  )
@@ -2024,7 +2491,7 @@ const DiscardAction = ({
2024
2491
  id: "content-manager.actions.discard.label",
2025
2492
  defaultMessage: "Discard changes"
2026
2493
  }),
2027
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2494
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2028
2495
  position: ["panel", "table-row"],
2029
2496
  variant: "danger",
2030
2497
  dialog: {
@@ -2052,11 +2519,6 @@ const DiscardAction = ({
2052
2519
  };
2053
2520
  };
2054
2521
  DiscardAction.type = "discard";
2055
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2056
- path {
2057
- fill: currentColor;
2058
- }
2059
- `;
2060
2522
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2061
2523
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2062
2524
  const RelativeTime = React__namespace.forwardRef(
@@ -2104,7 +2566,7 @@ const getDisplayName = ({
2104
2566
  };
2105
2567
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2106
2568
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2107
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2569
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2108
2570
  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) }) });
2109
2571
  };
2110
2572
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2114,23 +2576,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2114
2576
  id: "content-manager.containers.edit.title.new",
2115
2577
  defaultMessage: "Create an entry"
2116
2578
  }) : documentTitle;
2117
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2579
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2118
2580
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2119
- /* @__PURE__ */ jsxRuntime.jsxs(
2120
- designSystem.Flex,
2121
- {
2122
- width: "100%",
2123
- justifyContent: "space-between",
2124
- paddingTop: 1,
2125
- gap: "80px",
2126
- alignItems: "flex-start",
2127
- children: [
2128
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2129
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2130
- ]
2131
- }
2132
- ),
2133
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2581
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2582
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2583
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2584
+ ] }),
2585
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2134
2586
  ] });
2135
2587
  };
2136
2588
  const HeaderToolbar = () => {
@@ -2297,8 +2749,22 @@ const Information = ({ activeTab }) => {
2297
2749
  );
2298
2750
  };
2299
2751
  const HeaderActions = ({ actions: actions2 }) => {
2300
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2301
- if ("options" in action) {
2752
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2753
+ const handleClick = (action) => async (e) => {
2754
+ if (!("options" in action)) {
2755
+ const { onClick = () => false, dialog, id } = action;
2756
+ const muteDialog = await onClick(e);
2757
+ if (dialog && !muteDialog) {
2758
+ e.preventDefault();
2759
+ setDialogId(id);
2760
+ }
2761
+ }
2762
+ };
2763
+ const handleClose = () => {
2764
+ setDialogId(null);
2765
+ };
2766
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2767
+ if (action.options) {
2302
2768
  return /* @__PURE__ */ jsxRuntime.jsx(
2303
2769
  designSystem.SingleSelect,
2304
2770
  {
@@ -2312,10 +2778,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2312
2778
  action.id
2313
2779
  );
2314
2780
  } else {
2315
- return null;
2781
+ if (action.type === "icon") {
2782
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2783
+ /* @__PURE__ */ jsxRuntime.jsx(
2784
+ designSystem.IconButton,
2785
+ {
2786
+ disabled: action.disabled,
2787
+ label: action.label,
2788
+ size: "S",
2789
+ onClick: handleClick(action),
2790
+ children: action.icon
2791
+ }
2792
+ ),
2793
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2794
+ HeaderActionDialog,
2795
+ {
2796
+ ...action.dialog,
2797
+ isOpen: dialogId === action.id,
2798
+ onClose: handleClose
2799
+ }
2800
+ ) : null
2801
+ ] }, action.id);
2802
+ }
2316
2803
  }
2317
2804
  }) });
2318
2805
  };
2806
+ const HeaderActionDialog = ({
2807
+ onClose,
2808
+ onCancel,
2809
+ title,
2810
+ content: Content,
2811
+ isOpen
2812
+ }) => {
2813
+ const handleClose = async () => {
2814
+ if (onCancel) {
2815
+ await onCancel();
2816
+ }
2817
+ onClose();
2818
+ };
2819
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2820
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2821
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2822
+ ] }) });
2823
+ };
2319
2824
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2320
2825
  const navigate = reactRouterDom.useNavigate();
2321
2826
  const { formatMessage } = reactIntl.useIntl();
@@ -2356,12 +2861,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2356
2861
  const { delete: deleteAction } = useDocumentActions();
2357
2862
  const { toggleNotification } = strapiAdmin.useNotification();
2358
2863
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2864
+ const isLocalized = document?.locale != null;
2359
2865
  return {
2360
2866
  disabled: !canDelete || !document,
2361
- label: formatMessage({
2362
- id: "content-manager.actions.delete.label",
2363
- defaultMessage: "Delete document"
2364
- }),
2867
+ label: formatMessage(
2868
+ {
2869
+ id: "content-manager.actions.delete.label",
2870
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2871
+ },
2872
+ { isLocalized }
2873
+ ),
2365
2874
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2366
2875
  dialog: {
2367
2876
  type: "dialog",
@@ -2451,7 +2960,7 @@ const ActionsPanel = () => {
2451
2960
  return {
2452
2961
  title: formatMessage({
2453
2962
  id: "content-manager.containers.edit.panels.default.title",
2454
- defaultMessage: "Document"
2963
+ defaultMessage: "Entry"
2455
2964
  }),
2456
2965
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2457
2966
  };
@@ -2459,361 +2968,59 @@ const ActionsPanel = () => {
2459
2968
  ActionsPanel.type = "actions";
2460
2969
  const ActionsPanelContent = () => {
2461
2970
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2462
- const [
2463
- {
2464
- query: { status = "draft" }
2465
- }
2466
- ] = strapiAdmin.useQueryParams();
2467
- const { model, id, document, meta, collectionType } = useDoc();
2468
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2469
- const props = {
2470
- activeTab: status,
2471
- model,
2472
- documentId: id,
2473
- document: isCloning ? void 0 : document,
2474
- meta: isCloning ? void 0 : meta,
2475
- collectionType
2476
- };
2477
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2478
- /* @__PURE__ */ jsxRuntime.jsx(
2479
- strapiAdmin.DescriptionComponentRenderer,
2480
- {
2481
- props,
2482
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2483
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2484
- }
2485
- ),
2486
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2487
- ] });
2488
- };
2489
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2490
- return /* @__PURE__ */ jsxRuntime.jsxs(
2491
- designSystem.Flex,
2492
- {
2493
- ref,
2494
- tag: "aside",
2495
- "aria-labelledby": "additional-information",
2496
- background: "neutral0",
2497
- borderColor: "neutral150",
2498
- hasRadius: true,
2499
- paddingBottom: 4,
2500
- paddingLeft: 4,
2501
- paddingRight: 4,
2502
- paddingTop: 4,
2503
- shadow: "tableShadow",
2504
- gap: 3,
2505
- direction: "column",
2506
- justifyContent: "stretch",
2507
- alignItems: "flex-start",
2508
- children: [
2509
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2510
- children
2511
- ]
2512
- }
2513
- );
2514
- });
2515
- const HOOKS = {
2516
- /**
2517
- * Hook that allows to mutate the displayed headers of the list view table
2518
- * @constant
2519
- * @type {string}
2520
- */
2521
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2522
- /**
2523
- * Hook that allows to mutate the CM's collection types links pre-set filters
2524
- * @constant
2525
- * @type {string}
2526
- */
2527
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2528
- /**
2529
- * Hook that allows to mutate the CM's edit view layout
2530
- * @constant
2531
- * @type {string}
2532
- */
2533
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2534
- /**
2535
- * Hook that allows to mutate the CM's single types links pre-set filters
2536
- * @constant
2537
- * @type {string}
2538
- */
2539
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2540
- };
2541
- const contentTypesApi = contentManagerApi.injectEndpoints({
2542
- endpoints: (builder) => ({
2543
- getContentTypeConfiguration: builder.query({
2544
- query: (uid) => ({
2545
- url: `/content-manager/content-types/${uid}/configuration`,
2546
- method: "GET"
2547
- }),
2548
- transformResponse: (response) => response.data,
2549
- providesTags: (_result, _error, uid) => [
2550
- { type: "ContentTypesConfiguration", id: uid },
2551
- { type: "ContentTypeSettings", id: "LIST" }
2552
- ]
2553
- }),
2554
- getAllContentTypeSettings: builder.query({
2555
- query: () => "/content-manager/content-types-settings",
2556
- transformResponse: (response) => response.data,
2557
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2558
- }),
2559
- updateContentTypeConfiguration: builder.mutation({
2560
- query: ({ uid, ...body }) => ({
2561
- url: `/content-manager/content-types/${uid}/configuration`,
2562
- method: "PUT",
2563
- data: body
2564
- }),
2565
- transformResponse: (response) => response.data,
2566
- invalidatesTags: (_result, _error, { uid }) => [
2567
- { type: "ContentTypesConfiguration", id: uid },
2568
- { type: "ContentTypeSettings", id: "LIST" },
2569
- // Is this necessary?
2570
- { type: "InitialData" }
2571
- ]
2572
- })
2573
- })
2574
- });
2575
- const {
2576
- useGetContentTypeConfigurationQuery,
2577
- useGetAllContentTypeSettingsQuery,
2578
- useUpdateContentTypeConfigurationMutation
2579
- } = contentTypesApi;
2580
- const checkIfAttributeIsDisplayable = (attribute) => {
2581
- const { type } = attribute;
2582
- if (type === "relation") {
2583
- return !attribute.relation.toLowerCase().includes("morph");
2584
- }
2585
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2586
- };
2587
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2588
- if (!mainFieldName) {
2589
- return void 0;
2590
- }
2591
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2592
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2593
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2594
- );
2595
- return {
2596
- name: mainFieldName,
2597
- type: mainFieldType ?? "string"
2598
- };
2599
- };
2600
- const DEFAULT_SETTINGS = {
2601
- bulkable: false,
2602
- filterable: false,
2603
- searchable: false,
2604
- pagination: false,
2605
- defaultSortBy: "",
2606
- defaultSortOrder: "asc",
2607
- mainField: "id",
2608
- pageSize: 10
2609
- };
2610
- const useDocumentLayout = (model) => {
2611
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2612
- const [{ query }] = strapiAdmin.useQueryParams();
2613
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2614
- const { toggleNotification } = strapiAdmin.useNotification();
2615
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2616
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2617
- const {
2618
- data,
2619
- isLoading: isLoadingConfigs,
2620
- error,
2621
- isFetching: isFetchingConfigs
2622
- } = useGetContentTypeConfigurationQuery(model);
2623
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2624
- React__namespace.useEffect(() => {
2625
- if (error) {
2626
- toggleNotification({
2627
- type: "danger",
2628
- message: formatAPIError(error)
2629
- });
2630
- }
2631
- }, [error, formatAPIError, toggleNotification]);
2632
- const editLayout = React__namespace.useMemo(
2633
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2634
- layout: [],
2635
- components: {},
2636
- metadatas: {},
2637
- options: {},
2638
- settings: DEFAULT_SETTINGS
2639
- },
2640
- [data, isLoading, schemas, schema, components]
2641
- );
2642
- const listLayout = React__namespace.useMemo(() => {
2643
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2644
- layout: [],
2645
- metadatas: {},
2646
- options: {},
2647
- settings: DEFAULT_SETTINGS
2648
- };
2649
- }, [data, isLoading, schemas, schema, components]);
2650
- const { layout: edit } = React__namespace.useMemo(
2651
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2652
- layout: editLayout,
2653
- query
2654
- }),
2655
- [editLayout, query, runHookWaterfall]
2656
- );
2657
- return {
2658
- error,
2659
- isLoading,
2660
- edit,
2661
- list: listLayout
2662
- };
2663
- };
2664
- const useDocLayout = () => {
2665
- const { model } = useDoc();
2666
- return useDocumentLayout(model);
2667
- };
2668
- const formatEditLayout = (data, {
2669
- schemas,
2670
- schema,
2671
- components
2672
- }) => {
2673
- let currentPanelIndex = 0;
2674
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2675
- data.contentType.layouts.edit,
2676
- schema?.attributes,
2677
- data.contentType.metadatas,
2678
- { configurations: data.components, schemas: components },
2679
- schemas
2680
- ).reduce((panels, row) => {
2681
- if (row.some((field) => field.type === "dynamiczone")) {
2682
- panels.push([row]);
2683
- currentPanelIndex += 2;
2684
- } else {
2685
- if (!panels[currentPanelIndex]) {
2686
- panels.push([]);
2687
- }
2688
- panels[currentPanelIndex].push(row);
2689
- }
2690
- return panels;
2691
- }, []);
2692
- const componentEditAttributes = Object.entries(data.components).reduce(
2693
- (acc, [uid, configuration]) => {
2694
- acc[uid] = {
2695
- layout: convertEditLayoutToFieldLayouts(
2696
- configuration.layouts.edit,
2697
- components[uid].attributes,
2698
- configuration.metadatas
2699
- ),
2700
- settings: {
2701
- ...configuration.settings,
2702
- icon: components[uid].info.icon,
2703
- displayName: components[uid].info.displayName
2704
- }
2705
- };
2706
- return acc;
2707
- },
2708
- {}
2709
- );
2710
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2711
- (acc, [attribute, metadata]) => {
2712
- return {
2713
- ...acc,
2714
- [attribute]: metadata.edit
2715
- };
2716
- },
2717
- {}
2718
- );
2719
- return {
2720
- layout: panelledEditAttributes,
2721
- components: componentEditAttributes,
2722
- metadatas: editMetadatas,
2723
- settings: {
2724
- ...data.contentType.settings,
2725
- displayName: schema?.info.displayName
2726
- },
2727
- options: {
2728
- ...schema?.options,
2729
- ...schema?.pluginOptions,
2730
- ...data.contentType.options
2731
- }
2732
- };
2733
- };
2734
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2735
- return rows.map(
2736
- (row) => row.map((field) => {
2737
- const attribute = attributes[field.name];
2738
- if (!attribute) {
2739
- return null;
2740
- }
2741
- const { edit: metadata } = metadatas[field.name];
2742
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2743
- return {
2744
- attribute,
2745
- disabled: !metadata.editable,
2746
- hint: metadata.description,
2747
- label: metadata.label ?? "",
2748
- name: field.name,
2749
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2750
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2751
- schemas,
2752
- components: components?.schemas ?? {}
2753
- }),
2754
- placeholder: metadata.placeholder ?? "",
2755
- required: attribute.required ?? false,
2756
- size: field.size,
2757
- unique: "unique" in attribute ? attribute.unique : false,
2758
- visible: metadata.visible ?? true,
2759
- type: attribute.type
2760
- };
2761
- }).filter((field) => field !== null)
2762
- );
2763
- };
2764
- const formatListLayout = (data, {
2765
- schemas,
2766
- schema,
2767
- components
2768
- }) => {
2769
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2770
- (acc, [attribute, metadata]) => {
2771
- return {
2772
- ...acc,
2773
- [attribute]: metadata.list
2774
- };
2775
- },
2776
- {}
2777
- );
2778
- const listAttributes = convertListLayoutToFieldLayouts(
2779
- data.contentType.layouts.list,
2780
- schema?.attributes,
2781
- listMetadatas,
2782
- { configurations: data.components, schemas: components },
2783
- schemas
2784
- );
2785
- return {
2786
- layout: listAttributes,
2787
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2788
- metadatas: listMetadatas,
2789
- options: {
2790
- ...schema?.options,
2791
- ...schema?.pluginOptions,
2792
- ...data.contentType.options
2971
+ const [
2972
+ {
2973
+ query: { status = "draft" }
2793
2974
  }
2975
+ ] = strapiAdmin.useQueryParams();
2976
+ const { model, id, document, meta, collectionType } = useDoc();
2977
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2978
+ const props = {
2979
+ activeTab: status,
2980
+ model,
2981
+ documentId: id,
2982
+ document: isCloning ? void 0 : document,
2983
+ meta: isCloning ? void 0 : meta,
2984
+ collectionType
2794
2985
  };
2986
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2987
+ /* @__PURE__ */ jsxRuntime.jsx(
2988
+ strapiAdmin.DescriptionComponentRenderer,
2989
+ {
2990
+ props,
2991
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
2992
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2993
+ }
2994
+ ),
2995
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2996
+ ] });
2795
2997
  };
2796
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2797
- return columns.map((name) => {
2798
- const attribute = attributes[name];
2799
- if (!attribute) {
2800
- return null;
2998
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2999
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3000
+ designSystem.Flex,
3001
+ {
3002
+ ref,
3003
+ tag: "aside",
3004
+ "aria-labelledby": "additional-information",
3005
+ background: "neutral0",
3006
+ borderColor: "neutral150",
3007
+ hasRadius: true,
3008
+ paddingBottom: 4,
3009
+ paddingLeft: 4,
3010
+ paddingRight: 4,
3011
+ paddingTop: 4,
3012
+ shadow: "tableShadow",
3013
+ gap: 3,
3014
+ direction: "column",
3015
+ justifyContent: "stretch",
3016
+ alignItems: "flex-start",
3017
+ children: [
3018
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
3019
+ children
3020
+ ]
2801
3021
  }
2802
- const metadata = metadatas[name];
2803
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2804
- return {
2805
- attribute,
2806
- label: metadata.label ?? "",
2807
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2808
- schemas,
2809
- components: components?.schemas ?? {}
2810
- }),
2811
- name,
2812
- searchable: metadata.searchable ?? true,
2813
- sortable: metadata.sortable ?? true
2814
- };
2815
- }).filter((field) => field !== null);
2816
- };
3022
+ );
3023
+ });
2817
3024
  const ConfirmBulkActionDialog = ({
2818
3025
  onToggleDialog,
2819
3026
  isOpen = false,
@@ -2821,30 +3028,23 @@ const ConfirmBulkActionDialog = ({
2821
3028
  endAction
2822
3029
  }) => {
2823
3030
  const { formatMessage } = reactIntl.useIntl();
2824
- return /* @__PURE__ */ jsxRuntime.jsxs(
2825
- designSystem.Dialog,
2826
- {
2827
- onClose: onToggleDialog,
2828
- title: formatMessage({
2829
- id: "app.components.ConfirmDialog.title",
2830
- defaultMessage: "Confirmation"
2831
- }),
2832
- isOpen,
2833
- children: [
2834
- /* @__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 }) }),
2835
- /* @__PURE__ */ jsxRuntime.jsx(
2836
- designSystem.DialogFooter,
2837
- {
2838
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2839
- id: "app.components.Button.cancel",
2840
- defaultMessage: "Cancel"
2841
- }) }),
2842
- endAction
2843
- }
2844
- )
2845
- ]
2846
- }
2847
- );
3031
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3032
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
3033
+ id: "app.components.ConfirmDialog.title",
3034
+ defaultMessage: "Confirmation"
3035
+ }) }),
3036
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3038
+ dialogBody
3039
+ ] }) }),
3040
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
3041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
3042
+ id: "app.components.Button.cancel",
3043
+ defaultMessage: "Cancel"
3044
+ }) }) }),
3045
+ endAction
3046
+ ] })
3047
+ ] }) });
2848
3048
  };
2849
3049
  const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2850
3050
  const ConfirmDialogPublishAll = ({
@@ -2859,6 +3059,7 @@ const ConfirmDialogPublishAll = ({
2859
3059
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2860
3060
  const { model, schema } = useDoc();
2861
3061
  const [{ query }] = strapiAdmin.useQueryParams();
3062
+ const enableDraftRelationsCount = false;
2862
3063
  const {
2863
3064
  data: countDraftRelations = 0,
2864
3065
  isLoading,
@@ -2870,7 +3071,7 @@ const ConfirmDialogPublishAll = ({
2870
3071
  locale: query?.plugins?.i18n?.locale
2871
3072
  },
2872
3073
  {
2873
- skip: selectedEntries.length === 0
3074
+ skip: !enableDraftRelationsCount
2874
3075
  }
2875
3076
  );
2876
3077
  React__namespace.useEffect(() => {
@@ -2949,16 +3150,30 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2949
3150
  )
2950
3151
  );
2951
3152
  } else {
2952
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3153
+ messages.push(
3154
+ ...formatErrorMessages(
3155
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3156
+ value,
3157
+ currentKey,
3158
+ formatMessage
3159
+ )
3160
+ );
2953
3161
  }
3162
+ } else {
3163
+ messages.push(
3164
+ formatMessage(
3165
+ {
3166
+ id: `${value}.withField`,
3167
+ defaultMessage: value
3168
+ },
3169
+ { field: currentKey }
3170
+ )
3171
+ );
2954
3172
  }
2955
3173
  });
2956
3174
  return messages;
2957
3175
  };
2958
- const EntryValidationText = ({
2959
- validationErrors,
2960
- isPublished = false
2961
- }) => {
3176
+ const EntryValidationText = ({ validationErrors, status }) => {
2962
3177
  const { formatMessage } = reactIntl.useIntl();
2963
3178
  if (validationErrors) {
2964
3179
  const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
@@ -2969,7 +3184,7 @@ const EntryValidationText = ({
2969
3184
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
2970
3185
  ] });
2971
3186
  }
2972
- if (isPublished) {
3187
+ if (status === "published") {
2973
3188
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2974
3189
  /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
2975
3190
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
@@ -2978,6 +3193,15 @@ const EntryValidationText = ({
2978
3193
  }) })
2979
3194
  ] });
2980
3195
  }
3196
+ if (status === "modified") {
3197
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3198
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3199
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3200
+ id: "content-manager.bulk-publish.modified",
3201
+ defaultMessage: "Ready to publish changes"
3202
+ }) })
3203
+ ] });
3204
+ }
2981
3205
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2982
3206
  /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
2983
3207
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -3029,10 +3253,10 @@ const SelectedEntriesTableContent = ({
3029
3253
  EntryValidationText,
3030
3254
  {
3031
3255
  validationErrors: validationErrors[row.documentId],
3032
- isPublished: row.status === "published"
3256
+ status: row.status
3033
3257
  }
3034
3258
  ) }),
3035
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3259
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3036
3260
  designSystem.IconButton,
3037
3261
  {
3038
3262
  tag: reactRouterDom.Link,
@@ -3055,9 +3279,10 @@ const SelectedEntriesTableContent = ({
3055
3279
  ),
3056
3280
  target: "_blank",
3057
3281
  marginLeft: "auto",
3058
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3282
+ variant: "ghost",
3283
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3059
3284
  }
3060
- ) })
3285
+ ) }) })
3061
3286
  ] }, row.id)) })
3062
3287
  ] });
3063
3288
  };
@@ -3094,7 +3319,13 @@ const SelectedEntriesModalContent = ({
3094
3319
  );
3095
3320
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3096
3321
  if (data.length > 0 && schema) {
3097
- const validate = createYupSchema(schema.attributes, components);
3322
+ const validate = createYupSchema(
3323
+ schema.attributes,
3324
+ components,
3325
+ // Since this is the "Publish" action, the validation
3326
+ // schema must enforce the rules for published entities
3327
+ { status: "published" }
3328
+ );
3098
3329
  const validationErrors2 = {};
3099
3330
  const rows2 = data.map((entry) => {
3100
3331
  try {
@@ -3170,7 +3401,7 @@ const SelectedEntriesModalContent = ({
3170
3401
  );
3171
3402
  };
3172
3403
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3173
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalBody, { children: [
3404
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3174
3405
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3175
3406
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3176
3407
  SelectedEntriesTableContent,
@@ -3182,27 +3413,24 @@ const SelectedEntriesModalContent = ({
3182
3413
  }
3183
3414
  ) })
3184
3415
  ] }),
3185
- /* @__PURE__ */ jsxRuntime.jsx(
3186
- designSystem.ModalFooter,
3187
- {
3188
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3189
- id: "app.components.Button.cancel",
3190
- defaultMessage: "Cancel"
3191
- }) }),
3192
- endActions: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3193
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3194
- /* @__PURE__ */ jsxRuntime.jsx(
3195
- designSystem.Button,
3196
- {
3197
- onClick: toggleDialog,
3198
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3199
- loading: isSubmittingForm,
3200
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3201
- }
3202
- )
3203
- ] })
3204
- }
3205
- ),
3416
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3417
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3418
+ id: "app.components.Button.cancel",
3419
+ defaultMessage: "Cancel"
3420
+ }) }),
3421
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3422
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3423
+ /* @__PURE__ */ jsxRuntime.jsx(
3424
+ designSystem.Button,
3425
+ {
3426
+ onClick: toggleDialog,
3427
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3428
+ loading: isSubmittingForm,
3429
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3430
+ }
3431
+ )
3432
+ ] })
3433
+ ] }),
3206
3434
  /* @__PURE__ */ jsxRuntime.jsx(
3207
3435
  ConfirmDialogPublishAll,
3208
3436
  {
@@ -3267,143 +3495,10 @@ const BulkActionsRenderer = () => {
3267
3495
  documents: selectedRows
3268
3496
  },
3269
3497
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3270
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
3498
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3271
3499
  }
3272
3500
  ) });
3273
3501
  };
3274
- const BulkActionAction = (action) => {
3275
- const [dialogId, setDialogId] = React__namespace.useState(null);
3276
- const { toggleNotification } = strapiAdmin.useNotification();
3277
- const handleClick = (action2) => (e) => {
3278
- const { onClick, dialog, id } = action2;
3279
- if (onClick) {
3280
- onClick(e);
3281
- }
3282
- if (dialog) {
3283
- switch (dialog.type) {
3284
- case "notification":
3285
- toggleNotification({
3286
- title: dialog.title,
3287
- message: dialog.content,
3288
- type: dialog.status,
3289
- timeout: dialog.timeout,
3290
- onClose: dialog.onClose
3291
- });
3292
- break;
3293
- case "dialog":
3294
- case "modal": {
3295
- e.preventDefault();
3296
- setDialogId(id);
3297
- }
3298
- }
3299
- }
3300
- };
3301
- const handleClose = () => {
3302
- setDialogId(null);
3303
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3304
- action.dialog.onClose();
3305
- }
3306
- };
3307
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3308
- /* @__PURE__ */ jsxRuntime.jsx(
3309
- designSystem.Button,
3310
- {
3311
- disabled: action.disabled,
3312
- startIcon: action.icon,
3313
- variant: action.variant,
3314
- onClick: handleClick(action),
3315
- children: action.label
3316
- }
3317
- ),
3318
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
3319
- BulkActionConfirmDialog,
3320
- {
3321
- ...action.dialog,
3322
- variant: action.variant,
3323
- isOpen: dialogId === action.id,
3324
- onClose: handleClose
3325
- }
3326
- ) : null,
3327
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
3328
- BulkActionModal,
3329
- {
3330
- ...action.dialog,
3331
- onModalClose: handleClose,
3332
- isOpen: dialogId === action.id
3333
- }
3334
- ) : null
3335
- ] });
3336
- };
3337
- const BulkActionConfirmDialog = ({
3338
- onClose,
3339
- onCancel,
3340
- onConfirm,
3341
- title,
3342
- content,
3343
- confirmButton,
3344
- isOpen,
3345
- variant = "secondary"
3346
- }) => {
3347
- const { formatMessage } = reactIntl.useIntl();
3348
- const handleClose = async () => {
3349
- if (onCancel) {
3350
- await onCancel();
3351
- }
3352
- onClose();
3353
- };
3354
- const handleConfirm = async () => {
3355
- if (onConfirm) {
3356
- await onConfirm();
3357
- }
3358
- onClose();
3359
- };
3360
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
3361
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
3362
- /* @__PURE__ */ jsxRuntime.jsx(
3363
- designSystem.DialogFooter,
3364
- {
3365
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3366
- id: "app.components.Button.cancel",
3367
- defaultMessage: "Cancel"
3368
- }) }),
3369
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
3370
- designSystem.Button,
3371
- {
3372
- onClick: handleConfirm,
3373
- variant: variant === "danger-light" ? variant : "secondary",
3374
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3375
- children: confirmButton ? confirmButton : formatMessage({
3376
- id: "app.components.Button.confirm",
3377
- defaultMessage: "Confirm"
3378
- })
3379
- }
3380
- )
3381
- }
3382
- )
3383
- ] });
3384
- };
3385
- const BulkActionModal = ({
3386
- isOpen,
3387
- title,
3388
- onClose,
3389
- content: Content,
3390
- onModalClose
3391
- }) => {
3392
- const id = React__namespace.useId();
3393
- if (!isOpen) {
3394
- return null;
3395
- }
3396
- const handleClose = () => {
3397
- if (onClose) {
3398
- onClose();
3399
- }
3400
- onModalClose();
3401
- };
3402
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3403
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3404
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
3405
- ] });
3406
- };
3407
3502
  const DeleteAction = ({ documents, model }) => {
3408
3503
  const { formatMessage } = reactIntl.useIntl();
3409
3504
  const { schema: contentType } = useDoc();
@@ -3436,6 +3531,7 @@ const DeleteAction = ({ documents, model }) => {
3436
3531
  defaultMessage: "Confirmation"
3437
3532
  }),
3438
3533
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3534
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3439
3535
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3440
3536
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3441
3537
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3472,7 +3568,7 @@ const UnpublishAction = ({ documents, model }) => {
3472
3568
  selectRow([]);
3473
3569
  }
3474
3570
  };
3475
- const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
3571
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3476
3572
  if (!showUnpublishButton)
3477
3573
  return null;
3478
3574
  return {
@@ -3485,6 +3581,7 @@ const UnpublishAction = ({ documents, model }) => {
3485
3581
  defaultMessage: "Confirmation"
3486
3582
  }),
3487
3583
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3584
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3488
3585
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3489
3586
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3490
3587
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3578,7 +3675,7 @@ const TableActions = ({ document }) => {
3578
3675
  strapiAdmin.DescriptionComponentRenderer,
3579
3676
  {
3580
3677
  props,
3581
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3678
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3582
3679
  children: (actions2) => {
3583
3680
  const tableRowActions = actions2.filter((action) => {
3584
3681
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3689,7 +3786,7 @@ const CloneAction = ({ model, documentId }) => {
3689
3786
  }),
3690
3787
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3691
3788
  footer: ({ onClose }) => {
3692
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3789
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3693
3790
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3694
3791
  id: "cancel",
3695
3792
  defaultMessage: "Cancel"
@@ -3730,8 +3827,7 @@ class ContentManagerPlugin {
3730
3827
  documentActions = [
3731
3828
  ...DEFAULT_ACTIONS,
3732
3829
  ...DEFAULT_TABLE_ROW_ACTIONS,
3733
- ...DEFAULT_HEADER_ACTIONS,
3734
- HistoryAction
3830
+ ...DEFAULT_HEADER_ACTIONS
3735
3831
  ];
3736
3832
  editViewSidePanels = [ActionsPanel];
3737
3833
  headerActions = [];
@@ -3820,6 +3916,52 @@ const getPrintableType = (value) => {
3820
3916
  }
3821
3917
  return nativeType;
3822
3918
  };
3919
+ const HistoryAction = ({ model, document }) => {
3920
+ const { formatMessage } = reactIntl.useIntl();
3921
+ const [{ query }] = strapiAdmin.useQueryParams();
3922
+ const navigate = reactRouterDom.useNavigate();
3923
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3924
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3925
+ return null;
3926
+ }
3927
+ return {
3928
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3929
+ label: formatMessage({
3930
+ id: "content-manager.history.document-action",
3931
+ defaultMessage: "Content History"
3932
+ }),
3933
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3934
+ disabled: (
3935
+ /**
3936
+ * The user is creating a new document.
3937
+ * It hasn't been saved yet, so there's no history to go to
3938
+ */
3939
+ !document || /**
3940
+ * The document has been created but the current dimension has never been saved.
3941
+ * For example, the user is creating a new locale in an existing document,
3942
+ * so there's no history for the document in that locale
3943
+ */
3944
+ !document.id || /**
3945
+ * History is only available for content types created by the user.
3946
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3947
+ * which start with `admin::` or `plugin::`
3948
+ */
3949
+ !model.startsWith("api::")
3950
+ ),
3951
+ position: "header"
3952
+ };
3953
+ };
3954
+ HistoryAction.type = "history";
3955
+ const historyAdmin = {
3956
+ bootstrap(app) {
3957
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3958
+ addDocumentAction((actions2) => {
3959
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3960
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3961
+ return actions2;
3962
+ });
3963
+ }
3964
+ };
3823
3965
  const initialState = {
3824
3966
  collectionTypeLinks: [],
3825
3967
  components: [],
@@ -3870,15 +4012,29 @@ const index = {
3870
4012
  defaultMessage: "Content Manager"
3871
4013
  },
3872
4014
  permissions: [],
3873
- Component: () => Promise.resolve().then(() => require("./layout-b91XRlD2.js")).then((mod) => ({ default: mod.Layout })),
3874
4015
  position: 1
3875
4016
  });
4017
+ app.router.addRoute({
4018
+ path: "content-manager/*",
4019
+ lazy: async () => {
4020
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CWgZzMYf.js"));
4021
+ return {
4022
+ Component: Layout
4023
+ };
4024
+ },
4025
+ children: routes
4026
+ });
3876
4027
  app.registerPlugin(cm.config);
3877
4028
  },
4029
+ bootstrap(app) {
4030
+ if (typeof historyAdmin.bootstrap === "function") {
4031
+ historyAdmin.bootstrap(app);
4032
+ }
4033
+ },
3878
4034
  async registerTrads({ locales }) {
3879
4035
  const importedTrads = await Promise.all(
3880
4036
  locales.map((locale) => {
3881
- 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-BN1bvFK7.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 }) => {
4037
+ 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 }) => {
3882
4038
  return {
3883
4039
  data: prefixPluginTranslations(data, PLUGIN_ID),
3884
4040
  locale
@@ -3896,6 +4052,7 @@ const index = {
3896
4052
  };
3897
4053
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3898
4054
  exports.BulkActionsRenderer = BulkActionsRenderer;
4055
+ exports.CLONE_PATH = CLONE_PATH;
3899
4056
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3900
4057
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3901
4058
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3922,8 +4079,8 @@ exports.getDisplayName = getDisplayName;
3922
4079
  exports.getMainField = getMainField;
3923
4080
  exports.getTranslation = getTranslation;
3924
4081
  exports.index = index;
3925
- exports.routes = routes;
3926
4082
  exports.setInitialData = setInitialData;
4083
+ exports.useContentManagerContext = useContentManagerContext;
3927
4084
  exports.useContentTypeSchema = useContentTypeSchema;
3928
4085
  exports.useDoc = useDoc;
3929
4086
  exports.useDocLayout = useDocLayout;
@@ -3936,4 +4093,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3936
4093
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3937
4094
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3938
4095
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3939
- //# sourceMappingURL=index-DzN3kBgx.js.map
4096
+ //# sourceMappingURL=index-DTKVhcla.js.map