@strapi/content-manager 0.0.0-experimental.a53a4b1c8f7981a689823cdd719105671e1c6392 → 0.0.0-experimental.a6728ad43ac70ae19dabb624dbfca1f2d9610a86

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 (130) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-DJ5voqEK.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-DJ5voqEK.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-_6osrv39.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-_6osrv39.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-CZofxSLy.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-CZofxSLy.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-ZN3s568V.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-ZN3s568V.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-Co2IKQZH.js} +19 -8
  11. package/dist/_chunks/EditViewPage-Co2IKQZH.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-HYljoEY7.mjs} +19 -8
  13. package/dist/_chunks/EditViewPage-HYljoEY7.mjs.map +1 -0
  14. package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-BOPUMZ1u.mjs} +194 -141
  15. package/dist/_chunks/Field-BOPUMZ1u.mjs.map +1 -0
  16. package/dist/_chunks/{Field-Boxf9Ajp.js → Field-G9CkFUtP.js} +196 -143
  17. package/dist/_chunks/Field-G9CkFUtP.js.map +1 -0
  18. package/dist/_chunks/{Form-DHrru2AV.mjs → Form-CDwNp7pU.mjs} +35 -16
  19. package/dist/_chunks/Form-CDwNp7pU.mjs.map +1 -0
  20. package/dist/_chunks/{Form-y5g1SRsh.js → Form-crsbkGxI.js} +35 -16
  21. package/dist/_chunks/Form-crsbkGxI.js.map +1 -0
  22. package/dist/_chunks/{History-Bru_KoeP.mjs → History-BDZrgfZ3.mjs} +44 -19
  23. package/dist/_chunks/History-BDZrgfZ3.mjs.map +1 -0
  24. package/dist/_chunks/{History-CqN6K7SX.js → History-CWcM9HnW.js} +44 -19
  25. package/dist/_chunks/History-CWcM9HnW.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BZ3ScUna.mjs} +20 -8
  27. package/dist/_chunks/ListConfigurationPage-BZ3ScUna.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-DGzoQD_I.js} +20 -8
  29. package/dist/_chunks/ListConfigurationPage-DGzoQD_I.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-BBAC9aPu.js} +60 -42
  31. package/dist/_chunks/ListViewPage-BBAC9aPu.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-CsX7tWx-.mjs} +58 -40
  33. package/dist/_chunks/ListViewPage-CsX7tWx-.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-CwVDx_YC.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-CwVDx_YC.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-LClTUPWs.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-LClTUPWs.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-D2iWw-sn.js} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-D2iWw-sn.js.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-S4Re3FwO.mjs} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-S4Re3FwO.mjs.map} +1 -1
  42. package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-Dmv0Tpe5.mjs} +4 -4
  43. package/dist/_chunks/Relations-Dmv0Tpe5.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-jwuTFGOV.js} +4 -4
  45. package/dist/_chunks/Relations-jwuTFGOV.js.map +1 -0
  46. package/dist/_chunks/{en-fbKQxLGn.js → en-BlhnxQfj.js} +11 -9
  47. package/dist/_chunks/{en-fbKQxLGn.js.map → en-BlhnxQfj.js.map} +1 -1
  48. package/dist/_chunks/{en-Ux26r5pl.mjs → en-C8YBvRrK.mjs} +11 -9
  49. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  50. package/dist/_chunks/{index-DJXJw9V5.mjs → index-BmUAydCA.mjs} +977 -680
  51. package/dist/_chunks/index-BmUAydCA.mjs.map +1 -0
  52. package/dist/_chunks/{index-DVPWZkbS.js → index-CBX6KyXv.js} +958 -661
  53. package/dist/_chunks/index-CBX6KyXv.js.map +1 -0
  54. package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-ClP-DC72.mjs} +25 -12
  55. package/dist/_chunks/layout-ClP-DC72.mjs.map +1 -0
  56. package/dist/_chunks/{layout-Dm6fbiQj.js → layout-CxxkX9jY.js} +24 -11
  57. package/dist/_chunks/layout-CxxkX9jY.js.map +1 -0
  58. package/dist/_chunks/{relations-CKnpRgrN.js → relations-DIjTADIu.js} +2 -2
  59. package/dist/_chunks/{relations-CKnpRgrN.js.map → relations-DIjTADIu.js.map} +1 -1
  60. package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-op89RClB.mjs} +2 -2
  61. package/dist/_chunks/{relations-BH_kBSJ0.mjs.map → relations-op89RClB.mjs.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 +5 -4
  69. package/dist/admin/src/exports.d.ts +1 -1
  70. package/dist/admin/src/history/index.d.ts +3 -0
  71. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  72. package/dist/admin/src/hooks/useDocument.d.ts +30 -1
  73. package/dist/admin/src/index.d.ts +1 -0
  74. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  75. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  76. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  78. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  79. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  80. package/dist/admin/src/services/api.d.ts +1 -1
  81. package/dist/admin/src/services/components.d.ts +2 -2
  82. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  83. package/dist/admin/src/services/documents.d.ts +19 -17
  84. package/dist/admin/src/services/init.d.ts +1 -1
  85. package/dist/admin/src/services/relations.d.ts +2 -2
  86. package/dist/admin/src/services/uid.d.ts +3 -3
  87. package/dist/admin/src/utils/validation.d.ts +4 -1
  88. package/dist/server/index.js +181 -107
  89. package/dist/server/index.js.map +1 -1
  90. package/dist/server/index.mjs +182 -108
  91. package/dist/server/index.mjs.map +1 -1
  92. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  93. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  94. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  95. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  96. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  97. package/dist/server/src/history/services/history.d.ts.map +1 -1
  98. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  99. package/dist/server/src/history/services/utils.d.ts +2 -1
  100. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  101. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  102. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  103. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  104. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  105. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  106. package/dist/shared/contracts/collection-types.d.ts +3 -1
  107. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  108. package/package.json +11 -11
  109. package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
  110. package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
  111. package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
  112. package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
  113. package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
  114. package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
  115. package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
  116. package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
  117. package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
  118. package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
  119. package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
  120. package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
  121. package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
  122. package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
  123. package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
  124. package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
  125. package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
  126. package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
  127. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  128. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  129. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  130. 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,7 +179,8 @@ 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({
@@ -229,7 +194,12 @@ const documentApi = contentManagerApi.injectEndpoints({
229
194
  params: query
230
195
  }
231
196
  }),
232
- 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
+ }
233
203
  }),
234
204
  cloneDocument: builder.mutation({
235
205
  query: ({ model, sourceId, data, params }) => ({
@@ -240,7 +210,10 @@ const documentApi = contentManagerApi.injectEndpoints({
240
210
  params
241
211
  }
242
212
  }),
243
- 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
+ ]
244
217
  }),
245
218
  /**
246
219
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -257,7 +230,8 @@ const documentApi = contentManagerApi.injectEndpoints({
257
230
  }),
258
231
  invalidatesTags: (result, _error, { model }) => [
259
232
  { type: "Document", id: `${model}_LIST` },
260
- "Relations"
233
+ "Relations",
234
+ { type: "UidAvailability", id: model }
261
235
  ]
262
236
  }),
263
237
  deleteDocument: builder.mutation({
@@ -298,7 +272,8 @@ const documentApi = contentManagerApi.injectEndpoints({
298
272
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
299
273
  },
300
274
  { type: "Document", id: `${model}_LIST` },
301
- "Relations"
275
+ "Relations",
276
+ { type: "UidAvailability", id: model }
302
277
  ];
303
278
  }
304
279
  }),
@@ -316,6 +291,7 @@ const documentApi = contentManagerApi.injectEndpoints({
316
291
  }),
317
292
  providesTags: (result, _error, arg) => {
318
293
  return [
294
+ { type: "Document", id: `ALL_LIST` },
319
295
  { type: "Document", id: `${arg.model}_LIST` },
320
296
  ...result?.results.map(({ documentId }) => ({
321
297
  type: "Document",
@@ -354,6 +330,11 @@ const documentApi = contentManagerApi.injectEndpoints({
354
330
  {
355
331
  type: "Document",
356
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`
357
338
  }
358
339
  ];
359
340
  }
@@ -417,8 +398,21 @@ const documentApi = contentManagerApi.injectEndpoints({
417
398
  type: "Document",
418
399
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
419
400
  },
420
- "Relations"
401
+ "Relations",
402
+ { type: "UidAvailability", id: model }
421
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
+ }
422
416
  }
423
417
  }),
424
418
  unpublishDocument: builder.mutation({
@@ -488,7 +482,7 @@ const buildValidParams = (query) => {
488
482
  const isBaseQueryError = (error) => {
489
483
  return error.name !== void 0;
490
484
  };
491
- const createYupSchema = (attributes = {}, components = {}) => {
485
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
492
486
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
493
487
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
494
488
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -501,7 +495,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
501
495
  addMinValidation,
502
496
  addMaxValidation,
503
497
  addRegexValidation
504
- ].map((fn) => fn(attribute));
498
+ ].map((fn) => fn(attribute, options));
505
499
  const transformSchema = pipe__default.default(...validations);
506
500
  switch (attribute.type) {
507
501
  case "component": {
@@ -602,6 +596,14 @@ const createAttributeSchema = (attribute) => {
602
596
  if (!value || typeof value === "string" && value.length === 0) {
603
597
  return true;
604
598
  }
599
+ if (typeof value === "object") {
600
+ try {
601
+ JSON.stringify(value);
602
+ return true;
603
+ } catch (err) {
604
+ return false;
605
+ }
606
+ }
605
607
  try {
606
608
  JSON.parse(value);
607
609
  return true;
@@ -620,13 +622,7 @@ const createAttributeSchema = (attribute) => {
620
622
  return yup__namespace.mixed();
621
623
  }
622
624
  };
623
- const addRequiredValidation = (attribute) => (schema) => {
624
- if (attribute.required) {
625
- return schema.required({
626
- id: strapiAdmin.translatedErrors.required.id,
627
- defaultMessage: "This field is required."
628
- });
629
- }
625
+ const nullableSchema = (schema) => {
630
626
  return schema?.nullable ? schema.nullable() : (
631
627
  // In some cases '.nullable' will not be available on the schema.
632
628
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -634,7 +630,22 @@ const addRequiredValidation = (attribute) => (schema) => {
634
630
  schema
635
631
  );
636
632
  };
637
- 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
+ }
638
649
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
639
650
  return schema.min(attribute.minLength, {
640
651
  ...strapiAdmin.translatedErrors.minLength,
@@ -656,9 +667,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
656
667
  }
657
668
  return schema;
658
669
  };
659
- const addMinValidation = (attribute) => (schema) => {
670
+ const addMinValidation = (attribute, options) => (schema) => {
660
671
  if ("min" in attribute) {
661
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
+ }
662
695
  if ("min" in schema && min) {
663
696
  return schema.min(min, {
664
697
  ...strapiAdmin.translatedErrors.min,
@@ -777,16 +810,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
777
810
  }, {});
778
811
  return componentsByKey;
779
812
  };
780
- 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);
781
912
  const { toggleNotification } = strapiAdmin.useNotification();
782
913
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
914
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
783
915
  const {
784
- currentData: data,
785
- isLoading: isLoadingDocument,
786
- isFetching: isFetchingDocument,
787
- error
788
- } = useGetDocumentQuery(args, opts);
789
- 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;
790
922
  React__namespace.useEffect(() => {
791
923
  if (error) {
792
924
  toggleNotification({
@@ -794,54 +926,267 @@ const useDocument = (args, opts) => {
794
926
  message: formatAPIError(error)
795
927
  });
796
928
  }
797
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
798
- const validationSchema = React__namespace.useMemo(() => {
799
- if (!schema) {
800
- return null;
801
- }
802
- return createYupSchema(schema.attributes, components);
803
- }, [schema, components]);
804
- const validate = React__namespace.useCallback(
805
- (document) => {
806
- if (!validationSchema) {
807
- throw new Error(
808
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
809
- );
810
- }
811
- try {
812
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
813
- return null;
814
- } catch (error2) {
815
- if (error2 instanceof yup.ValidationError) {
816
- return strapiAdmin.getYupValidationErrors(error2);
817
- }
818
- throw error2;
819
- }
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
820
937
  },
821
- [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]
822
954
  );
823
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
824
955
  return {
825
- components,
826
- document: data?.data,
827
- meta: data?.meta,
956
+ error,
828
957
  isLoading,
829
- schema,
830
- validate
958
+ edit,
959
+ list: listLayout
831
960
  };
832
961
  };
833
- const useDoc = () => {
834
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
835
- const [{ query }] = strapiAdmin.useQueryParams();
836
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
837
- if (!collectionType) {
838
- throw new Error("Could not find collectionType in url params");
839
- }
840
- if (!slug) {
841
- throw new Error("Could not find model in url params");
842
- }
843
- return {
844
- 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,
845
1190
  model: slug,
846
1191
  id: origin || id === "create" ? void 0 : id,
847
1192
  ...useDocument(
@@ -852,6 +1197,45 @@ const useDoc = () => {
852
1197
  )
853
1198
  };
854
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
+ };
855
1239
  const prefixPluginTranslations = (trad, pluginId) => {
856
1240
  if (!pluginId) {
857
1241
  throw new TypeError("pluginId can't be empty");
@@ -871,6 +1255,8 @@ const useDocumentActions = () => {
871
1255
  const { formatMessage } = reactIntl.useIntl();
872
1256
  const { trackUsage } = strapiAdmin.useTracking();
873
1257
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1258
+ const navigate = reactRouterDom.useNavigate();
1259
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
874
1260
  const [deleteDocument] = useDeleteDocumentMutation();
875
1261
  const _delete = React__namespace.useCallback(
876
1262
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1185,6 +1571,7 @@ const useDocumentActions = () => {
1185
1571
  defaultMessage: "Saved document"
1186
1572
  })
1187
1573
  });
1574
+ setCurrentStep("contentManager.success");
1188
1575
  return res.data;
1189
1576
  } catch (err) {
1190
1577
  toggleNotification({
@@ -1206,7 +1593,6 @@ const useDocumentActions = () => {
1206
1593
  sourceId
1207
1594
  });
1208
1595
  if ("error" in res) {
1209
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1210
1596
  return { error: res.error };
1211
1597
  }
1212
1598
  toggleNotification({
@@ -1225,7 +1611,7 @@ const useDocumentActions = () => {
1225
1611
  throw err;
1226
1612
  }
1227
1613
  },
1228
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1614
+ [autoCloneDocument, formatMessage, toggleNotification]
1229
1615
  );
1230
1616
  const [cloneDocument] = useCloneDocumentMutation();
1231
1617
  const clone = React__namespace.useCallback(
@@ -1251,6 +1637,7 @@ const useDocumentActions = () => {
1251
1637
  defaultMessage: "Cloned document"
1252
1638
  })
1253
1639
  });
1640
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1254
1641
  return res.data;
1255
1642
  } catch (err) {
1256
1643
  toggleNotification({
@@ -1261,7 +1648,7 @@ const useDocumentActions = () => {
1261
1648
  throw err;
1262
1649
  }
1263
1650
  },
1264
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1651
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1265
1652
  );
1266
1653
  const [getDoc] = useLazyGetDocumentQuery();
1267
1654
  const getDocument = React__namespace.useCallback(
@@ -1287,7 +1674,7 @@ const useDocumentActions = () => {
1287
1674
  };
1288
1675
  };
1289
1676
  const ProtectedHistoryPage = React.lazy(
1290
- () => Promise.resolve().then(() => require("./History-CqN6K7SX.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1677
+ () => Promise.resolve().then(() => require("./History-CWcM9HnW.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1291
1678
  );
1292
1679
  const routes$1 = [
1293
1680
  {
@@ -1300,31 +1687,31 @@ const routes$1 = [
1300
1687
  }
1301
1688
  ];
1302
1689
  const ProtectedEditViewPage = React.lazy(
1303
- () => Promise.resolve().then(() => require("./EditViewPage-zT3fBr4Y.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1690
+ () => Promise.resolve().then(() => require("./EditViewPage-Co2IKQZH.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1304
1691
  );
1305
1692
  const ProtectedListViewPage = React.lazy(
1306
- () => Promise.resolve().then(() => require("./ListViewPage-pEw_zug9.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1693
+ () => Promise.resolve().then(() => require("./ListViewPage-BBAC9aPu.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1307
1694
  );
1308
1695
  const ProtectedListConfiguration = React.lazy(
1309
- () => Promise.resolve().then(() => require("./ListConfigurationPage-R_p-SbHZ.js")).then((mod) => ({
1696
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-DGzoQD_I.js")).then((mod) => ({
1310
1697
  default: mod.ProtectedListConfiguration
1311
1698
  }))
1312
1699
  );
1313
1700
  const ProtectedEditConfigurationPage = React.lazy(
1314
- () => Promise.resolve().then(() => require("./EditConfigurationPage-DjFJw56M.js")).then((mod) => ({
1701
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-ZN3s568V.js")).then((mod) => ({
1315
1702
  default: mod.ProtectedEditConfigurationPage
1316
1703
  }))
1317
1704
  );
1318
1705
  const ProtectedComponentConfigurationPage = React.lazy(
1319
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-C-49MccQ.js")).then((mod) => ({
1706
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-_6osrv39.js")).then((mod) => ({
1320
1707
  default: mod.ProtectedComponentConfigurationPage
1321
1708
  }))
1322
1709
  );
1323
1710
  const NoPermissions = React.lazy(
1324
- () => Promise.resolve().then(() => require("./NoPermissionsPage-BtPrImPP.js")).then((mod) => ({ default: mod.NoPermissions }))
1711
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-D2iWw-sn.js")).then((mod) => ({ default: mod.NoPermissions }))
1325
1712
  );
1326
1713
  const NoContentType = React.lazy(
1327
- () => Promise.resolve().then(() => require("./NoContentTypePage-C5dcQojD.js")).then((mod) => ({ default: mod.NoContentType }))
1714
+ () => Promise.resolve().then(() => require("./NoContentTypePage-CwVDx_YC.js")).then((mod) => ({ default: mod.NoContentType }))
1328
1715
  );
1329
1716
  const CollectionTypePages = () => {
1330
1717
  const { collectionType } = reactRouterDom.useParams();
@@ -1438,12 +1825,14 @@ const DocumentActionButton = (action) => {
1438
1825
  /* @__PURE__ */ jsxRuntime.jsx(
1439
1826
  designSystem.Button,
1440
1827
  {
1441
- flex: 1,
1828
+ flex: "auto",
1442
1829
  startIcon: action.icon,
1443
1830
  disabled: action.disabled,
1444
1831
  onClick: handleClick(action),
1445
1832
  justifyContent: "center",
1446
1833
  variant: action.variant || "default",
1834
+ paddingTop: "7px",
1835
+ paddingBottom: "7px",
1447
1836
  children: action.label
1448
1837
  }
1449
1838
  ),
@@ -1451,7 +1840,7 @@ const DocumentActionButton = (action) => {
1451
1840
  DocumentActionConfirmDialog,
1452
1841
  {
1453
1842
  ...action.dialog,
1454
- variant: action.variant,
1843
+ variant: action.dialog?.variant ?? action.variant,
1455
1844
  isOpen: dialogId === action.id,
1456
1845
  onClose: handleClose
1457
1846
  }
@@ -1508,9 +1897,9 @@ const DocumentActionsMenu = ({
1508
1897
  disabled: isDisabled,
1509
1898
  size: "S",
1510
1899
  endIcon: null,
1511
- paddingTop: "7px",
1512
- paddingLeft: "9px",
1513
- paddingRight: "9px",
1900
+ paddingTop: "4px",
1901
+ paddingLeft: "7px",
1902
+ paddingRight: "7px",
1514
1903
  variant,
1515
1904
  children: [
1516
1905
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1521,7 +1910,7 @@ const DocumentActionsMenu = ({
1521
1910
  ]
1522
1911
  }
1523
1912
  ),
1524
- /* @__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: [
1525
1914
  actions2.map((action) => {
1526
1915
  return /* @__PURE__ */ jsxRuntime.jsx(
1527
1916
  designSystem.Menu.Item,
@@ -1530,10 +1919,25 @@ const DocumentActionsMenu = ({
1530
1919
  onSelect: handleClick(action),
1531
1920
  display: "block",
1532
1921
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1533
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1534
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1535
- action.label
1536
- ] }),
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
+ ),
1537
1941
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1538
1942
  designSystem.Flex,
1539
1943
  {
@@ -1630,11 +2034,11 @@ const DocumentActionConfirmDialog = ({
1630
2034
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1631
2035
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1632
2036
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1633
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
2037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1634
2038
  id: "app.components.Button.cancel",
1635
2039
  defaultMessage: "Cancel"
1636
2040
  }) }) }),
1637
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
2041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1638
2042
  id: "app.components.Button.confirm",
1639
2043
  defaultMessage: "Confirm"
1640
2044
  }) })
@@ -1673,13 +2077,17 @@ const PublishAction$1 = ({
1673
2077
  const navigate = reactRouterDom.useNavigate();
1674
2078
  const { toggleNotification } = strapiAdmin.useNotification();
1675
2079
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2080
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1676
2081
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1677
2082
  const { formatMessage } = reactIntl.useIntl();
1678
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1679
- "PublishAction",
1680
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1681
- );
2083
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1682
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);
1683
2091
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1684
2092
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1685
2093
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1688,62 +2096,142 @@ const PublishAction$1 = ({
1688
2096
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1689
2097
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1690
2098
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1691
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1692
- if (!schema?.options?.draftAndPublish) {
1693
- return null;
1694
- }
1695
- return {
1696
- /**
1697
- * Disabled when:
1698
- * - currently if you're cloning a document we don't support publish & clone at the same time.
1699
- * - the form is submitting
1700
- * - the active tab is the published tab
1701
- * - the document is already published & not modified
1702
- * - the document is being created & not modified
1703
- * - the user doesn't have the permission to publish
1704
- * - the user doesn't have the permission to create a new document
1705
- * - the user doesn't have the permission to update the document
1706
- */
1707
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
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]);
2154
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
2155
+ if (!schema?.options?.draftAndPublish) {
2156
+ return null;
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;
2196
+ return {
2197
+ /**
2198
+ * Disabled when:
2199
+ * - currently if you're cloning a document we don't support publish & clone at the same time.
2200
+ * - the form is submitting
2201
+ * - the active tab is the published tab
2202
+ * - the document is already published & not modified
2203
+ * - the document is being created & not modified
2204
+ * - the user doesn't have the permission to publish
2205
+ */
2206
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1708
2207
  label: formatMessage({
1709
2208
  id: "app.utils.publish",
1710
2209
  defaultMessage: "Publish"
1711
2210
  }),
1712
2211
  onClick: async () => {
1713
- setSubmitting(true);
1714
- try {
1715
- const { errors } = await validate();
1716
- if (errors) {
1717
- toggleNotification({
1718
- type: "danger",
1719
- message: formatMessage({
1720
- id: "content-manager.validation.error",
1721
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1722
- })
1723
- });
1724
- return;
1725
- }
1726
- const res = await publish(
1727
- {
1728
- collectionType,
1729
- model,
1730
- documentId,
1731
- params
1732
- },
1733
- formValues
1734
- );
1735
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1736
- navigate({
1737
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1738
- search: rawQuery
1739
- });
1740
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1741
- 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
1742
2229
  }
1743
- } finally {
1744
- setSubmitting(false);
2230
+ ),
2231
+ onConfirm: async () => {
2232
+ await performPublish();
1745
2233
  }
1746
- }
2234
+ } : void 0
1747
2235
  };
1748
2236
  };
1749
2237
  PublishAction$1.type = "publish";
@@ -1759,10 +2247,6 @@ const UpdateAction = ({
1759
2247
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1760
2248
  const isCloning = cloneMatch !== null;
1761
2249
  const { formatMessage } = reactIntl.useIntl();
1762
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1763
- canCreate: canCreate2,
1764
- canUpdate: canUpdate2
1765
- }));
1766
2250
  const { create, update, clone } = useDocumentActions();
1767
2251
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1768
2252
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1779,10 +2263,8 @@ const UpdateAction = ({
1779
2263
  * - the form is submitting
1780
2264
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1781
2265
  * - the active tab is the published tab
1782
- * - the user doesn't have the permission to create a new document
1783
- * - the user doesn't have the permission to update the document
1784
2266
  */
1785
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2267
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1786
2268
  label: formatMessage({
1787
2269
  id: "content-manager.containers.Edit.save",
1788
2270
  defaultMessage: "Save"
@@ -1790,16 +2272,18 @@ const UpdateAction = ({
1790
2272
  onClick: async () => {
1791
2273
  setSubmitting(true);
1792
2274
  try {
1793
- const { errors } = await validate();
1794
- if (errors) {
1795
- toggleNotification({
1796
- type: "danger",
1797
- message: formatMessage({
1798
- id: "content-manager.validation.error",
1799
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1800
- })
1801
- });
1802
- 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
+ }
1803
2287
  }
1804
2288
  if (isCloning) {
1805
2289
  const res = await clone(
@@ -1811,10 +2295,13 @@ const UpdateAction = ({
1811
2295
  document
1812
2296
  );
1813
2297
  if ("data" in res) {
1814
- navigate({
1815
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1816
- search: rawQuery
1817
- });
2298
+ navigate(
2299
+ {
2300
+ pathname: `../${res.data.documentId}`,
2301
+ search: rawQuery
2302
+ },
2303
+ { relative: "path" }
2304
+ );
1818
2305
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1819
2306
  setErrors(formatValidationErrors(res.error));
1820
2307
  }
@@ -1842,10 +2329,13 @@ const UpdateAction = ({
1842
2329
  document
1843
2330
  );
1844
2331
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1845
- navigate({
1846
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1847
- search: rawQuery
1848
- });
2332
+ navigate(
2333
+ {
2334
+ pathname: `../${res.data.documentId}`,
2335
+ search: rawQuery
2336
+ },
2337
+ { replace: true, relative: "path" }
2338
+ );
1849
2339
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1850
2340
  setErrors(formatValidationErrors(res.error));
1851
2341
  }
@@ -1889,7 +2379,7 @@ const UnpublishAction$1 = ({
1889
2379
  id: "app.utils.unpublish",
1890
2380
  defaultMessage: "Unpublish"
1891
2381
  }),
1892
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2382
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1893
2383
  onClick: async () => {
1894
2384
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1895
2385
  if (!documentId) {
@@ -2001,7 +2491,7 @@ const DiscardAction = ({
2001
2491
  id: "content-manager.actions.discard.label",
2002
2492
  defaultMessage: "Discard changes"
2003
2493
  }),
2004
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2494
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2005
2495
  position: ["panel", "table-row"],
2006
2496
  variant: "danger",
2007
2497
  dialog: {
@@ -2029,11 +2519,6 @@ const DiscardAction = ({
2029
2519
  };
2030
2520
  };
2031
2521
  DiscardAction.type = "discard";
2032
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2033
- path {
2034
- fill: currentColor;
2035
- }
2036
- `;
2037
2522
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2038
2523
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2039
2524
  const RelativeTime = React__namespace.forwardRef(
@@ -2081,7 +2566,7 @@ const getDisplayName = ({
2081
2566
  };
2082
2567
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2083
2568
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2084
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2569
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2085
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) }) });
2086
2571
  };
2087
2572
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2091,23 +2576,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2091
2576
  id: "content-manager.containers.edit.title.new",
2092
2577
  defaultMessage: "Create an entry"
2093
2578
  }) : documentTitle;
2094
- 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: [
2095
2580
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2096
- /* @__PURE__ */ jsxRuntime.jsxs(
2097
- designSystem.Flex,
2098
- {
2099
- width: "100%",
2100
- justifyContent: "space-between",
2101
- paddingTop: 1,
2102
- gap: "80px",
2103
- alignItems: "flex-start",
2104
- children: [
2105
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2106
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2107
- ]
2108
- }
2109
- ),
2110
- 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
2111
2586
  ] });
2112
2587
  };
2113
2588
  const HeaderToolbar = () => {
@@ -2274,8 +2749,22 @@ const Information = ({ activeTab }) => {
2274
2749
  );
2275
2750
  };
2276
2751
  const HeaderActions = ({ actions: actions2 }) => {
2277
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2278
- 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) {
2279
2768
  return /* @__PURE__ */ jsxRuntime.jsx(
2280
2769
  designSystem.SingleSelect,
2281
2770
  {
@@ -2289,10 +2778,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2289
2778
  action.id
2290
2779
  );
2291
2780
  } else {
2292
- 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
+ }
2293
2803
  }
2294
2804
  }) });
2295
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
+ };
2296
2824
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2297
2825
  const navigate = reactRouterDom.useNavigate();
2298
2826
  const { formatMessage } = reactIntl.useIntl();
@@ -2333,12 +2861,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2333
2861
  const { delete: deleteAction } = useDocumentActions();
2334
2862
  const { toggleNotification } = strapiAdmin.useNotification();
2335
2863
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2864
+ const isLocalized = document?.locale != null;
2336
2865
  return {
2337
2866
  disabled: !canDelete || !document,
2338
- label: formatMessage({
2339
- id: "content-manager.actions.delete.label",
2340
- defaultMessage: "Delete document"
2341
- }),
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
+ ),
2342
2874
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2343
2875
  dialog: {
2344
2876
  type: "dialog",
@@ -2372,425 +2904,123 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2372
2904
  return;
2373
2905
  }
2374
2906
  const res = await deleteAction({
2375
- documentId,
2376
- model,
2377
- collectionType,
2378
- params: {
2379
- locale: "*"
2380
- }
2381
- });
2382
- if (!("error" in res)) {
2383
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2384
- }
2385
- } finally {
2386
- if (!listViewPathMatch) {
2387
- setSubmitting(false);
2388
- }
2389
- }
2390
- }
2391
- },
2392
- variant: "danger",
2393
- position: ["header", "table-row"]
2394
- };
2395
- };
2396
- DeleteAction$1.type = "delete";
2397
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2398
- const Panels = () => {
2399
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2400
- const [
2401
- {
2402
- query: { status }
2403
- }
2404
- ] = strapiAdmin.useQueryParams({
2405
- status: "draft"
2406
- });
2407
- const { model, id, document, meta, collectionType } = useDoc();
2408
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2409
- const props = {
2410
- activeTab: status,
2411
- model,
2412
- documentId: id,
2413
- document: isCloning ? void 0 : document,
2414
- meta: isCloning ? void 0 : meta,
2415
- collectionType
2416
- };
2417
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2418
- strapiAdmin.DescriptionComponentRenderer,
2419
- {
2420
- props,
2421
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2422
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2423
- }
2424
- ) });
2425
- };
2426
- const ActionsPanel = () => {
2427
- const { formatMessage } = reactIntl.useIntl();
2428
- return {
2429
- title: formatMessage({
2430
- id: "content-manager.containers.edit.panels.default.title",
2431
- defaultMessage: "Document"
2432
- }),
2433
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2434
- };
2435
- };
2436
- ActionsPanel.type = "actions";
2437
- const ActionsPanelContent = () => {
2438
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2439
- const [
2440
- {
2441
- query: { status = "draft" }
2442
- }
2443
- ] = strapiAdmin.useQueryParams();
2444
- const { model, id, document, meta, collectionType } = useDoc();
2445
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2446
- const props = {
2447
- activeTab: status,
2448
- model,
2449
- documentId: id,
2450
- document: isCloning ? void 0 : document,
2451
- meta: isCloning ? void 0 : meta,
2452
- collectionType
2453
- };
2454
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2455
- /* @__PURE__ */ jsxRuntime.jsx(
2456
- strapiAdmin.DescriptionComponentRenderer,
2457
- {
2458
- props,
2459
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2460
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2461
- }
2462
- ),
2463
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2464
- ] });
2465
- };
2466
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2467
- return /* @__PURE__ */ jsxRuntime.jsxs(
2468
- designSystem.Flex,
2469
- {
2470
- ref,
2471
- tag: "aside",
2472
- "aria-labelledby": "additional-information",
2473
- background: "neutral0",
2474
- borderColor: "neutral150",
2475
- hasRadius: true,
2476
- paddingBottom: 4,
2477
- paddingLeft: 4,
2478
- paddingRight: 4,
2479
- paddingTop: 4,
2480
- shadow: "tableShadow",
2481
- gap: 3,
2482
- direction: "column",
2483
- justifyContent: "stretch",
2484
- alignItems: "flex-start",
2485
- children: [
2486
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2487
- children
2488
- ]
2489
- }
2490
- );
2491
- });
2492
- const HOOKS = {
2493
- /**
2494
- * Hook that allows to mutate the displayed headers of the list view table
2495
- * @constant
2496
- * @type {string}
2497
- */
2498
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2499
- /**
2500
- * Hook that allows to mutate the CM's collection types links pre-set filters
2501
- * @constant
2502
- * @type {string}
2503
- */
2504
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2505
- /**
2506
- * Hook that allows to mutate the CM's edit view layout
2507
- * @constant
2508
- * @type {string}
2509
- */
2510
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2511
- /**
2512
- * Hook that allows to mutate the CM's single types links pre-set filters
2513
- * @constant
2514
- * @type {string}
2515
- */
2516
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2517
- };
2518
- const contentTypesApi = contentManagerApi.injectEndpoints({
2519
- endpoints: (builder) => ({
2520
- getContentTypeConfiguration: builder.query({
2521
- query: (uid) => ({
2522
- url: `/content-manager/content-types/${uid}/configuration`,
2523
- method: "GET"
2524
- }),
2525
- transformResponse: (response) => response.data,
2526
- providesTags: (_result, _error, uid) => [
2527
- { type: "ContentTypesConfiguration", id: uid },
2528
- { type: "ContentTypeSettings", id: "LIST" }
2529
- ]
2530
- }),
2531
- getAllContentTypeSettings: builder.query({
2532
- query: () => "/content-manager/content-types-settings",
2533
- transformResponse: (response) => response.data,
2534
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2535
- }),
2536
- updateContentTypeConfiguration: builder.mutation({
2537
- query: ({ uid, ...body }) => ({
2538
- url: `/content-manager/content-types/${uid}/configuration`,
2539
- method: "PUT",
2540
- data: body
2541
- }),
2542
- transformResponse: (response) => response.data,
2543
- invalidatesTags: (_result, _error, { uid }) => [
2544
- { type: "ContentTypesConfiguration", id: uid },
2545
- { type: "ContentTypeSettings", id: "LIST" },
2546
- // Is this necessary?
2547
- { type: "InitialData" }
2548
- ]
2549
- })
2550
- })
2551
- });
2552
- const {
2553
- useGetContentTypeConfigurationQuery,
2554
- useGetAllContentTypeSettingsQuery,
2555
- useUpdateContentTypeConfigurationMutation
2556
- } = contentTypesApi;
2557
- const checkIfAttributeIsDisplayable = (attribute) => {
2558
- const { type } = attribute;
2559
- if (type === "relation") {
2560
- return !attribute.relation.toLowerCase().includes("morph");
2561
- }
2562
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2563
- };
2564
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2565
- if (!mainFieldName) {
2566
- return void 0;
2567
- }
2568
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2569
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2570
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2571
- );
2572
- return {
2573
- name: mainFieldName,
2574
- type: mainFieldType ?? "string"
2575
- };
2576
- };
2577
- const DEFAULT_SETTINGS = {
2578
- bulkable: false,
2579
- filterable: false,
2580
- searchable: false,
2581
- pagination: false,
2582
- defaultSortBy: "",
2583
- defaultSortOrder: "asc",
2584
- mainField: "id",
2585
- pageSize: 10
2586
- };
2587
- const useDocumentLayout = (model) => {
2588
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2589
- const [{ query }] = strapiAdmin.useQueryParams();
2590
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2591
- const { toggleNotification } = strapiAdmin.useNotification();
2592
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2593
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2594
- const {
2595
- data,
2596
- isLoading: isLoadingConfigs,
2597
- error,
2598
- isFetching: isFetchingConfigs
2599
- } = useGetContentTypeConfigurationQuery(model);
2600
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2601
- React__namespace.useEffect(() => {
2602
- if (error) {
2603
- toggleNotification({
2604
- type: "danger",
2605
- message: formatAPIError(error)
2606
- });
2607
- }
2608
- }, [error, formatAPIError, toggleNotification]);
2609
- const editLayout = React__namespace.useMemo(
2610
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2611
- layout: [],
2612
- components: {},
2613
- metadatas: {},
2614
- options: {},
2615
- settings: DEFAULT_SETTINGS
2616
- },
2617
- [data, isLoading, schemas, schema, components]
2618
- );
2619
- const listLayout = React__namespace.useMemo(() => {
2620
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2621
- layout: [],
2622
- metadatas: {},
2623
- options: {},
2624
- settings: DEFAULT_SETTINGS
2625
- };
2626
- }, [data, isLoading, schemas, schema, components]);
2627
- const { layout: edit } = React__namespace.useMemo(
2628
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2629
- layout: editLayout,
2630
- query
2631
- }),
2632
- [editLayout, query, runHookWaterfall]
2633
- );
2634
- return {
2635
- error,
2636
- isLoading,
2637
- edit,
2638
- list: listLayout
2639
- };
2640
- };
2641
- const useDocLayout = () => {
2642
- const { model } = useDoc();
2643
- return useDocumentLayout(model);
2644
- };
2645
- const formatEditLayout = (data, {
2646
- schemas,
2647
- schema,
2648
- components
2649
- }) => {
2650
- let currentPanelIndex = 0;
2651
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2652
- data.contentType.layouts.edit,
2653
- schema?.attributes,
2654
- data.contentType.metadatas,
2655
- { configurations: data.components, schemas: components },
2656
- schemas
2657
- ).reduce((panels, row) => {
2658
- if (row.some((field) => field.type === "dynamiczone")) {
2659
- panels.push([row]);
2660
- currentPanelIndex += 2;
2661
- } else {
2662
- if (!panels[currentPanelIndex]) {
2663
- panels.push([]);
2664
- }
2665
- panels[currentPanelIndex].push(row);
2666
- }
2667
- return panels;
2668
- }, []);
2669
- const componentEditAttributes = Object.entries(data.components).reduce(
2670
- (acc, [uid, configuration]) => {
2671
- acc[uid] = {
2672
- layout: convertEditLayoutToFieldLayouts(
2673
- configuration.layouts.edit,
2674
- components[uid].attributes,
2675
- configuration.metadatas
2676
- ),
2677
- settings: {
2678
- ...configuration.settings,
2679
- icon: components[uid].info.icon,
2680
- displayName: components[uid].info.displayName
2907
+ documentId,
2908
+ model,
2909
+ collectionType,
2910
+ params: {
2911
+ locale: "*"
2912
+ }
2913
+ });
2914
+ if (!("error" in res)) {
2915
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2916
+ }
2917
+ } finally {
2918
+ if (!listViewPathMatch) {
2919
+ setSubmitting(false);
2920
+ }
2681
2921
  }
2682
- };
2683
- return acc;
2684
- },
2685
- {}
2686
- );
2687
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2688
- (acc, [attribute, metadata]) => {
2689
- return {
2690
- ...acc,
2691
- [attribute]: metadata.edit
2692
- };
2693
- },
2694
- {}
2695
- );
2696
- return {
2697
- layout: panelledEditAttributes,
2698
- components: componentEditAttributes,
2699
- metadatas: editMetadatas,
2700
- settings: {
2701
- ...data.contentType.settings,
2702
- displayName: schema?.info.displayName
2922
+ }
2703
2923
  },
2704
- options: {
2705
- ...schema?.options,
2706
- ...schema?.pluginOptions,
2707
- ...data.contentType.options
2708
- }
2924
+ variant: "danger",
2925
+ position: ["header", "table-row"]
2709
2926
  };
2710
2927
  };
2711
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2712
- return rows.map(
2713
- (row) => row.map((field) => {
2714
- const attribute = attributes[field.name];
2715
- if (!attribute) {
2716
- return null;
2717
- }
2718
- const { edit: metadata } = metadatas[field.name];
2719
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2720
- return {
2721
- attribute,
2722
- disabled: !metadata.editable,
2723
- hint: metadata.description,
2724
- label: metadata.label ?? "",
2725
- name: field.name,
2726
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2727
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2728
- schemas,
2729
- components: components?.schemas ?? {}
2730
- }),
2731
- placeholder: metadata.placeholder ?? "",
2732
- required: attribute.required ?? false,
2733
- size: field.size,
2734
- unique: "unique" in attribute ? attribute.unique : false,
2735
- visible: metadata.visible ?? true,
2736
- type: attribute.type
2737
- };
2738
- }).filter((field) => field !== null)
2739
- );
2928
+ DeleteAction$1.type = "delete";
2929
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2930
+ const Panels = () => {
2931
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2932
+ const [
2933
+ {
2934
+ query: { status }
2935
+ }
2936
+ ] = strapiAdmin.useQueryParams({
2937
+ status: "draft"
2938
+ });
2939
+ const { model, id, document, meta, collectionType } = useDoc();
2940
+ const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2941
+ const props = {
2942
+ activeTab: status,
2943
+ model,
2944
+ documentId: id,
2945
+ document: isCloning ? void 0 : document,
2946
+ meta: isCloning ? void 0 : meta,
2947
+ collectionType
2948
+ };
2949
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2950
+ strapiAdmin.DescriptionComponentRenderer,
2951
+ {
2952
+ props,
2953
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2954
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2955
+ }
2956
+ ) });
2740
2957
  };
2741
- const formatListLayout = (data, {
2742
- schemas,
2743
- schema,
2744
- components
2745
- }) => {
2746
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2747
- (acc, [attribute, metadata]) => {
2748
- return {
2749
- ...acc,
2750
- [attribute]: metadata.list
2751
- };
2752
- },
2753
- {}
2754
- );
2755
- const listAttributes = convertListLayoutToFieldLayouts(
2756
- data.contentType.layouts.list,
2757
- schema?.attributes,
2758
- listMetadatas,
2759
- { configurations: data.components, schemas: components },
2760
- schemas
2761
- );
2958
+ const ActionsPanel = () => {
2959
+ const { formatMessage } = reactIntl.useIntl();
2762
2960
  return {
2763
- layout: listAttributes,
2764
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2765
- metadatas: listMetadatas,
2766
- options: {
2767
- ...schema?.options,
2768
- ...schema?.pluginOptions,
2769
- ...data.contentType.options
2770
- }
2961
+ title: formatMessage({
2962
+ id: "content-manager.containers.edit.panels.default.title",
2963
+ defaultMessage: "Entry"
2964
+ }),
2965
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2771
2966
  };
2772
2967
  };
2773
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2774
- return columns.map((name) => {
2775
- const attribute = attributes[name];
2776
- if (!attribute) {
2777
- return null;
2968
+ ActionsPanel.type = "actions";
2969
+ const ActionsPanelContent = () => {
2970
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2971
+ const [
2972
+ {
2973
+ query: { status = "draft" }
2778
2974
  }
2779
- const metadata = metadatas[name];
2780
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2781
- return {
2782
- attribute,
2783
- label: metadata.label ?? "",
2784
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2785
- schemas,
2786
- components: components?.schemas ?? {}
2787
- }),
2788
- name,
2789
- searchable: metadata.searchable ?? true,
2790
- sortable: metadata.sortable ?? true
2791
- };
2792
- }).filter((field) => field !== null);
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
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
+ ] });
2793
2997
  };
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
+ ]
3021
+ }
3022
+ );
3023
+ });
2794
3024
  const ConfirmBulkActionDialog = ({
2795
3025
  onToggleDialog,
2796
3026
  isOpen = false,
@@ -2798,7 +3028,7 @@ const ConfirmBulkActionDialog = ({
2798
3028
  endAction
2799
3029
  }) => {
2800
3030
  const { formatMessage } = reactIntl.useIntl();
2801
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3031
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2802
3032
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2803
3033
  id: "app.components.ConfirmDialog.title",
2804
3034
  defaultMessage: "Confirmation"
@@ -2829,6 +3059,7 @@ const ConfirmDialogPublishAll = ({
2829
3059
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2830
3060
  const { model, schema } = useDoc();
2831
3061
  const [{ query }] = strapiAdmin.useQueryParams();
3062
+ const enableDraftRelationsCount = false;
2832
3063
  const {
2833
3064
  data: countDraftRelations = 0,
2834
3065
  isLoading,
@@ -2840,7 +3071,7 @@ const ConfirmDialogPublishAll = ({
2840
3071
  locale: query?.plugins?.i18n?.locale
2841
3072
  },
2842
3073
  {
2843
- skip: selectedEntries.length === 0
3074
+ skip: !enableDraftRelationsCount
2844
3075
  }
2845
3076
  );
2846
3077
  React__namespace.useEffect(() => {
@@ -2919,7 +3150,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2919
3150
  )
2920
3151
  );
2921
3152
  } else {
2922
- 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
+ );
2923
3161
  }
2924
3162
  } else {
2925
3163
  messages.push(
@@ -3018,7 +3256,7 @@ const SelectedEntriesTableContent = ({
3018
3256
  status: row.status
3019
3257
  }
3020
3258
  ) }),
3021
- /* @__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(
3022
3260
  designSystem.IconButton,
3023
3261
  {
3024
3262
  tag: reactRouterDom.Link,
@@ -3041,9 +3279,10 @@ const SelectedEntriesTableContent = ({
3041
3279
  ),
3042
3280
  target: "_blank",
3043
3281
  marginLeft: "auto",
3044
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3282
+ variant: "ghost",
3283
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3045
3284
  }
3046
- ) })
3285
+ ) }) })
3047
3286
  ] }, row.id)) })
3048
3287
  ] });
3049
3288
  };
@@ -3080,7 +3319,13 @@ const SelectedEntriesModalContent = ({
3080
3319
  );
3081
3320
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3082
3321
  if (data.length > 0 && schema) {
3083
- 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
+ );
3084
3329
  const validationErrors2 = {};
3085
3330
  const rows2 = data.map((entry) => {
3086
3331
  try {
@@ -3430,7 +3675,7 @@ const TableActions = ({ document }) => {
3430
3675
  strapiAdmin.DescriptionComponentRenderer,
3431
3676
  {
3432
3677
  props,
3433
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3678
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3434
3679
  children: (actions2) => {
3435
3680
  const tableRowActions = actions2.filter((action) => {
3436
3681
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3541,7 +3786,7 @@ const CloneAction = ({ model, documentId }) => {
3541
3786
  }),
3542
3787
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3543
3788
  footer: ({ onClose }) => {
3544
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3789
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3545
3790
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3546
3791
  id: "cancel",
3547
3792
  defaultMessage: "Cancel"
@@ -3582,8 +3827,7 @@ class ContentManagerPlugin {
3582
3827
  documentActions = [
3583
3828
  ...DEFAULT_ACTIONS,
3584
3829
  ...DEFAULT_TABLE_ROW_ACTIONS,
3585
- ...DEFAULT_HEADER_ACTIONS,
3586
- HistoryAction
3830
+ ...DEFAULT_HEADER_ACTIONS
3587
3831
  ];
3588
3832
  editViewSidePanels = [ActionsPanel];
3589
3833
  headerActions = [];
@@ -3672,6 +3916,52 @@ const getPrintableType = (value) => {
3672
3916
  }
3673
3917
  return nativeType;
3674
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
+ };
3675
3965
  const initialState = {
3676
3966
  collectionTypeLinks: [],
3677
3967
  components: [],
@@ -3727,7 +4017,7 @@ const index = {
3727
4017
  app.router.addRoute({
3728
4018
  path: "content-manager/*",
3729
4019
  lazy: async () => {
3730
- const { Layout } = await Promise.resolve().then(() => require("./layout-Dm6fbiQj.js"));
4020
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CxxkX9jY.js"));
3731
4021
  return {
3732
4022
  Component: Layout
3733
4023
  };
@@ -3736,10 +4026,15 @@ const index = {
3736
4026
  });
3737
4027
  app.registerPlugin(cm.config);
3738
4028
  },
4029
+ bootstrap(app) {
4030
+ if (typeof historyAdmin.bootstrap === "function") {
4031
+ historyAdmin.bootstrap(app);
4032
+ }
4033
+ },
3739
4034
  async registerTrads({ locales }) {
3740
4035
  const importedTrads = await Promise.all(
3741
4036
  locales.map((locale) => {
3742
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-fbKQxLGn.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
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 }) => {
3743
4038
  return {
3744
4039
  data: prefixPluginTranslations(data, PLUGIN_ID),
3745
4040
  locale
@@ -3757,6 +4052,7 @@ const index = {
3757
4052
  };
3758
4053
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3759
4054
  exports.BulkActionsRenderer = BulkActionsRenderer;
4055
+ exports.CLONE_PATH = CLONE_PATH;
3760
4056
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3761
4057
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3762
4058
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3784,6 +4080,7 @@ exports.getMainField = getMainField;
3784
4080
  exports.getTranslation = getTranslation;
3785
4081
  exports.index = index;
3786
4082
  exports.setInitialData = setInitialData;
4083
+ exports.useContentManagerContext = useContentManagerContext;
3787
4084
  exports.useContentTypeSchema = useContentTypeSchema;
3788
4085
  exports.useDoc = useDoc;
3789
4086
  exports.useDocLayout = useDocLayout;
@@ -3796,4 +4093,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3796
4093
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3797
4094
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3798
4095
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3799
- //# sourceMappingURL=index-DVPWZkbS.js.map
4096
+ //# sourceMappingURL=index-CBX6KyXv.js.map