@strapi/content-manager 5.0.0-rc.2 → 5.0.0-rc.20

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 (116) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-Bv-IXOYu.js → ComponentConfigurationPage-DnnZJc1F.js} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-Bv-IXOYu.js.map → ComponentConfigurationPage-DnnZJc1F.js.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BxJCkKZV.mjs → ComponentConfigurationPage-hLMNf7KI.mjs} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-BxJCkKZV.mjs.map → ComponentConfigurationPage-hLMNf7KI.mjs.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-QZl5zOz-.js → EditConfigurationPage-CpLj5gYZ.js} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-QZl5zOz-.js.map → EditConfigurationPage-CpLj5gYZ.js.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-BGwHNypQ.mjs → EditConfigurationPage-Dh6sq-G4.mjs} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-BGwHNypQ.mjs.map → EditConfigurationPage-Dh6sq-G4.mjs.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-CtdtssrH.mjs → EditViewPage-BU1ugeVi.mjs} +19 -8
  10. package/dist/_chunks/EditViewPage-BU1ugeVi.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-DxKueadW.js → EditViewPage-D2QVRr_2.js} +19 -8
  12. package/dist/_chunks/EditViewPage-D2QVRr_2.js.map +1 -0
  13. package/dist/_chunks/{Field-BPw8fE3W.js → Field-BEDX9i_V.js} +120 -92
  14. package/dist/_chunks/Field-BEDX9i_V.js.map +1 -0
  15. package/dist/_chunks/{Field-BU7_nR4F.mjs → Field-VSPY6uzs.mjs} +118 -90
  16. package/dist/_chunks/Field-VSPY6uzs.mjs.map +1 -0
  17. package/dist/_chunks/{Form-ffghBTPI.mjs → Form-05Oaes1N.mjs} +35 -16
  18. package/dist/_chunks/Form-05Oaes1N.mjs.map +1 -0
  19. package/dist/_chunks/{Form-DtvmbGdZ.js → Form-DCaY8xBX.js} +35 -16
  20. package/dist/_chunks/Form-DCaY8xBX.js.map +1 -0
  21. package/dist/_chunks/{History-D6PRyNcx.mjs → History-BqO2G3MV.mjs} +4 -4
  22. package/dist/_chunks/{History-D6PRyNcx.mjs.map → History-BqO2G3MV.mjs.map} +1 -1
  23. package/dist/_chunks/{History-CSr8y9KM.js → History-BrJ1tUvt.js} +4 -4
  24. package/dist/_chunks/{History-CSr8y9KM.js.map → History-BrJ1tUvt.js.map} +1 -1
  25. package/dist/_chunks/{ListConfigurationPage-BC9bCi9k.mjs → ListConfigurationPage-C6rsFlme.mjs} +14 -4
  26. package/dist/_chunks/ListConfigurationPage-C6rsFlme.mjs.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-DsmAQ3YM.js → ListConfigurationPage-Eane5LKE.js} +14 -4
  28. package/dist/_chunks/ListConfigurationPage-Eane5LKE.js.map +1 -0
  29. package/dist/_chunks/{ListViewPage-DqAIb_ie.js → ListViewPage-Coj-RPsx.js} +49 -40
  30. package/dist/_chunks/ListViewPage-Coj-RPsx.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-B1GyNqfn.mjs → ListViewPage-yE_zYhcI.mjs} +47 -38
  32. package/dist/_chunks/ListViewPage-yE_zYhcI.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-xjvn5XwY.js → NoContentTypePage-BDJ0dshy.js} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-xjvn5XwY.js.map → NoContentTypePage-BDJ0dshy.js.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-CJ-HJriz.mjs → NoContentTypePage-NW_FSVdY.mjs} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-CJ-HJriz.mjs.map → NoContentTypePage-NW_FSVdY.mjs.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DObTkKmZ.js → NoPermissionsPage-BOtb5FTM.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DObTkKmZ.js.map → NoPermissionsPage-BOtb5FTM.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage--afHbbbD.mjs → NoPermissionsPage-h0I3ImsX.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage--afHbbbD.mjs.map → NoPermissionsPage-h0I3ImsX.mjs.map} +1 -1
  41. package/dist/_chunks/{Relations-t4Q0DpqW.js → Relations-CVh0DOKv.js} +4 -4
  42. package/dist/_chunks/{Relations-t4Q0DpqW.js.map → Relations-CVh0DOKv.js.map} +1 -1
  43. package/dist/_chunks/{Relations-heq-nLGU.mjs → Relations-FP0uWpBz.mjs} +4 -4
  44. package/dist/_chunks/{Relations-heq-nLGU.mjs.map → Relations-FP0uWpBz.mjs.map} +1 -1
  45. package/dist/_chunks/{en-uOUIxfcQ.js → en-BlhnxQfj.js} +7 -6
  46. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BlhnxQfj.js.map} +1 -1
  47. package/dist/_chunks/{en-BrCTWlZv.mjs → en-C8YBvRrK.mjs} +7 -6
  48. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
  49. package/dist/_chunks/{index-BcQ8cRyl.mjs → index-CPCHQ3X_.mjs} +1927 -1765
  50. package/dist/_chunks/index-CPCHQ3X_.mjs.map +1 -0
  51. package/dist/_chunks/{index-1zxclxo_.js → index-DTKVhcla.js} +1907 -1745
  52. package/dist/_chunks/index-DTKVhcla.js.map +1 -0
  53. package/dist/_chunks/{layout-Jl9mJFJZ.mjs → layout-B4UhJ8MJ.mjs} +22 -9
  54. package/dist/_chunks/layout-B4UhJ8MJ.mjs.map +1 -0
  55. package/dist/_chunks/{layout-tVvbqota.js → layout-CWgZzMYf.js} +21 -8
  56. package/dist/_chunks/layout-CWgZzMYf.js.map +1 -0
  57. package/dist/_chunks/{relations-f4Pv7Kgo.mjs → relations-B83Ge9a7.mjs} +2 -2
  58. package/dist/_chunks/{relations-f4Pv7Kgo.mjs.map → relations-B83Ge9a7.mjs.map} +1 -1
  59. package/dist/_chunks/{relations-CK2Jd0HM.js → relations-D81a_2zw.js} +2 -2
  60. package/dist/_chunks/{relations-CK2Jd0HM.js.map → relations-D81a_2zw.js.map} +1 -1
  61. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  62. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  63. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  64. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  65. package/dist/admin/index.js +2 -1
  66. package/dist/admin/index.js.map +1 -1
  67. package/dist/admin/index.mjs +5 -4
  68. package/dist/admin/src/exports.d.ts +1 -1
  69. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  70. package/dist/admin/src/hooks/useDocument.d.ts +30 -1
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  73. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  74. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  75. package/dist/admin/src/services/api.d.ts +1 -1
  76. package/dist/admin/src/services/components.d.ts +2 -2
  77. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  78. package/dist/admin/src/services/documents.d.ts +19 -17
  79. package/dist/admin/src/services/init.d.ts +1 -1
  80. package/dist/admin/src/services/relations.d.ts +2 -2
  81. package/dist/admin/src/services/uid.d.ts +3 -3
  82. package/dist/admin/src/utils/validation.d.ts +4 -1
  83. package/dist/server/index.js +147 -82
  84. package/dist/server/index.js.map +1 -1
  85. package/dist/server/index.mjs +148 -83
  86. package/dist/server/index.mjs.map +1 -1
  87. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  88. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  89. package/dist/server/src/history/services/history.d.ts.map +1 -1
  90. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  91. package/dist/server/src/history/services/utils.d.ts +2 -1
  92. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  93. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  94. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  95. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  96. package/dist/shared/contracts/collection-types.d.ts +3 -1
  97. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  98. package/package.json +11 -11
  99. package/dist/_chunks/EditViewPage-CtdtssrH.mjs.map +0 -1
  100. package/dist/_chunks/EditViewPage-DxKueadW.js.map +0 -1
  101. package/dist/_chunks/Field-BPw8fE3W.js.map +0 -1
  102. package/dist/_chunks/Field-BU7_nR4F.mjs.map +0 -1
  103. package/dist/_chunks/Form-DtvmbGdZ.js.map +0 -1
  104. package/dist/_chunks/Form-ffghBTPI.mjs.map +0 -1
  105. package/dist/_chunks/ListConfigurationPage-BC9bCi9k.mjs.map +0 -1
  106. package/dist/_chunks/ListConfigurationPage-DsmAQ3YM.js.map +0 -1
  107. package/dist/_chunks/ListViewPage-B1GyNqfn.mjs.map +0 -1
  108. package/dist/_chunks/ListViewPage-DqAIb_ie.js.map +0 -1
  109. package/dist/_chunks/index-1zxclxo_.js.map +0 -1
  110. package/dist/_chunks/index-BcQ8cRyl.mjs.map +0 -1
  111. package/dist/_chunks/layout-Jl9mJFJZ.mjs.map +0 -1
  112. package/dist/_chunks/layout-tVvbqota.js.map +0 -1
  113. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  114. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  115. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  116. package/strapi-server.js +0 -3
@@ -6,10 +6,10 @@ const React = require("react");
6
6
  const designSystem = require("@strapi/design-system");
7
7
  const reactIntl = require("react-intl");
8
8
  const reactRouterDom = require("react-router-dom");
9
- const styledComponents = require("styled-components");
10
9
  const yup = require("yup");
11
10
  const pipe = require("lodash/fp/pipe");
12
11
  const dateFns = require("date-fns");
12
+ const styledComponents = require("styled-components");
13
13
  const qs = require("qs");
14
14
  const toolkit = require("@reduxjs/toolkit");
15
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
@@ -179,7 +179,8 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
179
179
  "Document",
180
180
  "InitialData",
181
181
  "HistoryVersion",
182
- "Relations"
182
+ "Relations",
183
+ "UidAvailability"
183
184
  ]
184
185
  });
185
186
  const documentApi = contentManagerApi.injectEndpoints({
@@ -209,7 +210,10 @@ const documentApi = contentManagerApi.injectEndpoints({
209
210
  params
210
211
  }
211
212
  }),
212
- 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
+ ]
213
217
  }),
214
218
  /**
215
219
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -226,7 +230,8 @@ const documentApi = contentManagerApi.injectEndpoints({
226
230
  }),
227
231
  invalidatesTags: (result, _error, { model }) => [
228
232
  { type: "Document", id: `${model}_LIST` },
229
- "Relations"
233
+ "Relations",
234
+ { type: "UidAvailability", id: model }
230
235
  ]
231
236
  }),
232
237
  deleteDocument: builder.mutation({
@@ -267,7 +272,8 @@ const documentApi = contentManagerApi.injectEndpoints({
267
272
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
268
273
  },
269
274
  { type: "Document", id: `${model}_LIST` },
270
- "Relations"
275
+ "Relations",
276
+ { type: "UidAvailability", id: model }
271
277
  ];
272
278
  }
273
279
  }),
@@ -285,6 +291,7 @@ const documentApi = contentManagerApi.injectEndpoints({
285
291
  }),
286
292
  providesTags: (result, _error, arg) => {
287
293
  return [
294
+ { type: "Document", id: `ALL_LIST` },
288
295
  { type: "Document", id: `${arg.model}_LIST` },
289
296
  ...result?.results.map(({ documentId }) => ({
290
297
  type: "Document",
@@ -323,6 +330,11 @@ const documentApi = contentManagerApi.injectEndpoints({
323
330
  {
324
331
  type: "Document",
325
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`
326
338
  }
327
339
  ];
328
340
  }
@@ -386,8 +398,21 @@ const documentApi = contentManagerApi.injectEndpoints({
386
398
  type: "Document",
387
399
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
388
400
  },
389
- "Relations"
401
+ "Relations",
402
+ { type: "UidAvailability", id: model }
390
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
+ }
391
416
  }
392
417
  }),
393
418
  unpublishDocument: builder.mutation({
@@ -457,7 +482,7 @@ const buildValidParams = (query) => {
457
482
  const isBaseQueryError = (error) => {
458
483
  return error.name !== void 0;
459
484
  };
460
- const createYupSchema = (attributes = {}, components = {}) => {
485
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
461
486
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
462
487
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
463
488
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -470,7 +495,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
470
495
  addMinValidation,
471
496
  addMaxValidation,
472
497
  addRegexValidation
473
- ].map((fn) => fn(attribute));
498
+ ].map((fn) => fn(attribute, options));
474
499
  const transformSchema = pipe__default.default(...validations);
475
500
  switch (attribute.type) {
476
501
  case "component": {
@@ -571,6 +596,14 @@ const createAttributeSchema = (attribute) => {
571
596
  if (!value || typeof value === "string" && value.length === 0) {
572
597
  return true;
573
598
  }
599
+ if (typeof value === "object") {
600
+ try {
601
+ JSON.stringify(value);
602
+ return true;
603
+ } catch (err) {
604
+ return false;
605
+ }
606
+ }
574
607
  try {
575
608
  JSON.parse(value);
576
609
  return true;
@@ -589,13 +622,7 @@ const createAttributeSchema = (attribute) => {
589
622
  return yup__namespace.mixed();
590
623
  }
591
624
  };
592
- const addRequiredValidation = (attribute) => (schema) => {
593
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
594
- return schema.min(1, strapiAdmin.translatedErrors.required);
595
- }
596
- if (attribute.required && attribute.type !== "relation") {
597
- return schema.required(strapiAdmin.translatedErrors.required);
598
- }
625
+ const nullableSchema = (schema) => {
599
626
  return schema?.nullable ? schema.nullable() : (
600
627
  // In some cases '.nullable' will not be available on the schema.
601
628
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -603,7 +630,22 @@ const addRequiredValidation = (attribute) => (schema) => {
603
630
  schema
604
631
  );
605
632
  };
606
- 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
+ }
607
649
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
608
650
  return schema.min(attribute.minLength, {
609
651
  ...strapiAdmin.translatedErrors.minLength,
@@ -625,11 +667,11 @@ const addMaxLengthValidation = (attribute) => (schema) => {
625
667
  }
626
668
  return schema;
627
669
  };
628
- const addMinValidation = (attribute) => (schema) => {
670
+ const addMinValidation = (attribute, options) => (schema) => {
629
671
  if ("min" in attribute) {
630
672
  const min = toInteger(attribute.min);
631
673
  if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
632
- if (!attribute.required && "test" in schema && min) {
674
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
633
675
  return schema.test(
634
676
  "custom-min",
635
677
  {
@@ -768,19 +810,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
768
810
  }, {});
769
811
  return componentsByKey;
770
812
  };
771
- 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);
772
912
  const { toggleNotification } = strapiAdmin.useNotification();
773
913
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
914
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
774
915
  const {
775
- currentData: data,
776
- isLoading: isLoadingDocument,
777
- isFetching: isFetchingDocument,
778
- error
779
- } = useGetDocumentQuery(args, {
780
- ...opts,
781
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
782
- });
783
- 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;
784
922
  React__namespace.useEffect(() => {
785
923
  if (error) {
786
924
  toggleNotification({
@@ -788,388 +926,642 @@ const useDocument = (args, opts) => {
788
926
  message: formatAPIError(error)
789
927
  });
790
928
  }
791
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
792
- const validationSchema = React__namespace.useMemo(() => {
793
- if (!schema) {
794
- return null;
795
- }
796
- return createYupSchema(schema.attributes, components);
797
- }, [schema, components]);
798
- const validate = React__namespace.useCallback(
799
- (document) => {
800
- if (!validationSchema) {
801
- throw new Error(
802
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
803
- );
804
- }
805
- try {
806
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
807
- return null;
808
- } catch (error2) {
809
- if (error2 instanceof yup.ValidationError) {
810
- return strapiAdmin.getYupValidationErrors(error2);
811
- }
812
- throw error2;
813
- }
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
814
937
  },
815
- [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]
816
954
  );
817
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
818
955
  return {
819
- components,
820
- document: data?.data,
821
- meta: data?.meta,
956
+ error,
822
957
  isLoading,
823
- schema,
824
- validate
825
- };
826
- };
827
- const useDoc = () => {
828
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
829
- const [{ query }] = strapiAdmin.useQueryParams();
830
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
831
- if (!collectionType) {
832
- throw new Error("Could not find collectionType in url params");
833
- }
834
- if (!slug) {
835
- throw new Error("Could not find model in url params");
836
- }
837
- return {
838
- collectionType,
839
- model: slug,
840
- id: origin || id === "create" ? void 0 : id,
841
- ...useDocument(
842
- { documentId: origin || id, model: slug, collectionType, params },
843
- {
844
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
845
- }
846
- )
958
+ edit,
959
+ list: listLayout
847
960
  };
848
961
  };
849
- const prefixPluginTranslations = (trad, pluginId) => {
850
- if (!pluginId) {
851
- throw new TypeError("pluginId can't be empty");
852
- }
853
- return Object.keys(trad).reduce((acc, current) => {
854
- acc[`${pluginId}.${current}`] = trad[current];
855
- return acc;
856
- }, {});
857
- };
858
- const getTranslation = (id) => `content-manager.${id}`;
859
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
860
- id: "notification.error",
861
- defaultMessage: "An error occurred, please try again"
962
+ const useDocLayout = () => {
963
+ const { model } = useDoc();
964
+ return useDocumentLayout(model);
862
965
  };
863
- const useDocumentActions = () => {
864
- const { toggleNotification } = strapiAdmin.useNotification();
865
- const { formatMessage } = reactIntl.useIntl();
866
- const { trackUsage } = strapiAdmin.useTracking();
867
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
868
- const [deleteDocument] = useDeleteDocumentMutation();
869
- const _delete = React__namespace.useCallback(
870
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
871
- try {
872
- trackUsage("willDeleteEntry", trackerProperty);
873
- const res = await deleteDocument({
874
- collectionType,
875
- model,
876
- documentId,
877
- params
878
- });
879
- if ("error" in res) {
880
- toggleNotification({
881
- type: "danger",
882
- message: formatAPIError(res.error)
883
- });
884
- return { error: res.error };
885
- }
886
- toggleNotification({
887
- type: "success",
888
- message: formatMessage({
889
- id: getTranslation("success.record.delete"),
890
- defaultMessage: "Deleted document"
891
- })
892
- });
893
- trackUsage("didDeleteEntry", trackerProperty);
894
- return res.data;
895
- } catch (err) {
896
- toggleNotification({
897
- type: "danger",
898
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
899
- });
900
- trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
901
- throw err;
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([]);
902
985
  }
903
- },
904
- [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
905
- );
906
- const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
907
- const deleteMany = React__namespace.useCallback(
908
- async ({ model, documentIds, params }) => {
909
- try {
910
- trackUsage("willBulkDeleteEntries");
911
- const res = await deleteManyDocuments({
912
- model,
913
- documentIds,
914
- params
915
- });
916
- if ("error" in res) {
917
- toggleNotification({
918
- type: "danger",
919
- message: formatAPIError(res.error)
920
- });
921
- return { error: res.error };
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
922
1003
  }
923
- toggleNotification({
924
- type: "success",
925
- title: formatMessage({
926
- id: getTranslation("success.records.delete"),
927
- defaultMessage: "Successfully deleted."
928
- }),
929
- message: ""
930
- });
931
- trackUsage("didBulkDeleteEntries");
932
- return res.data;
933
- } catch (err) {
934
- toggleNotification({
935
- type: "danger",
936
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
937
- });
938
- trackUsage("didNotBulkDeleteEntries");
939
- throw err;
940
- }
1004
+ };
1005
+ return acc;
941
1006
  },
942
- [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1007
+ {}
943
1008
  );
944
- const [discardDocument] = useDiscardDocumentMutation();
945
- const discard = React__namespace.useCallback(
946
- async ({ collectionType, model, documentId, params }) => {
947
- try {
948
- const res = await discardDocument({
949
- collectionType,
950
- model,
951
- documentId,
952
- params
953
- });
954
- if ("error" in res) {
955
- toggleNotification({
956
- type: "danger",
957
- message: formatAPIError(res.error)
958
- });
959
- return { error: res.error };
960
- }
961
- toggleNotification({
962
- type: "success",
963
- message: formatMessage({
964
- id: "content-manager.success.record.discard",
965
- defaultMessage: "Changes discarded"
966
- })
967
- });
968
- return res.data;
969
- } catch (err) {
970
- toggleNotification({
971
- type: "danger",
972
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
973
- });
974
- throw err;
975
- }
1009
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1010
+ (acc, [attribute, metadata]) => {
1011
+ return {
1012
+ ...acc,
1013
+ [attribute]: metadata.edit
1014
+ };
976
1015
  },
977
- [discardDocument, formatAPIError, formatMessage, toggleNotification]
1016
+ {}
978
1017
  );
979
- const [publishDocument] = usePublishDocumentMutation();
980
- const publish = React__namespace.useCallback(
981
- async ({ collectionType, model, documentId, params }, data) => {
982
- try {
983
- trackUsage("willPublishEntry");
984
- const res = await publishDocument({
985
- collectionType,
986
- model,
987
- documentId,
988
- data,
989
- params
990
- });
991
- if ("error" in res) {
992
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
993
- return { error: res.error };
994
- }
995
- trackUsage("didPublishEntry");
996
- toggleNotification({
997
- type: "success",
998
- message: formatMessage({
999
- id: getTranslation("success.record.publish"),
1000
- defaultMessage: "Published document"
1001
- })
1002
- });
1003
- return res.data;
1004
- } catch (err) {
1005
- toggleNotification({
1006
- type: "danger",
1007
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1008
- });
1009
- throw err;
1010
- }
1018
+ return {
1019
+ layout: panelledEditAttributes,
1020
+ components: componentEditAttributes,
1021
+ metadatas: editMetadatas,
1022
+ settings: {
1023
+ ...data.contentType.settings,
1024
+ displayName: schema?.info.displayName
1011
1025
  },
1012
- [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1013
- );
1014
- const [publishManyDocuments] = usePublishManyDocumentsMutation();
1015
- const publishMany = React__namespace.useCallback(
1016
- async ({ model, documentIds, params }) => {
1017
- try {
1018
- const res = await publishManyDocuments({
1019
- model,
1020
- documentIds,
1021
- params
1022
- });
1023
- if ("error" in res) {
1024
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1025
- return { error: res.error };
1026
- }
1027
- toggleNotification({
1028
- type: "success",
1029
- message: formatMessage({
1030
- id: getTranslation("success.record.publish"),
1031
- defaultMessage: "Published document"
1032
- })
1033
- });
1034
- return res.data;
1035
- } catch (err) {
1036
- toggleNotification({
1037
- type: "danger",
1038
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1039
- });
1040
- throw err;
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;
1041
1039
  }
1042
- },
1043
- [
1044
- // trackUsage,
1045
- publishManyDocuments,
1046
- toggleNotification,
1047
- formatMessage,
1048
- formatAPIError
1049
- ]
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)
1050
1061
  );
1051
- const [updateDocument] = useUpdateDocumentMutation();
1052
- const update = React__namespace.useCallback(
1053
- async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1054
- try {
1055
- trackUsage("willEditEntry", trackerProperty);
1056
- const res = await updateDocument({
1057
- collectionType,
1058
- model,
1059
- documentId,
1060
- data,
1061
- params
1062
- });
1063
- if ("error" in res) {
1064
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1065
- trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1066
- return { error: res.error };
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);
1067
1161
  }
1068
- trackUsage("didEditEntry", trackerProperty);
1069
- toggleNotification({
1070
- type: "success",
1071
- message: formatMessage({
1072
- id: getTranslation("success.record.save"),
1073
- defaultMessage: "Saved document"
1074
- })
1075
- });
1076
- return res.data;
1077
- } catch (err) {
1078
- trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1079
- toggleNotification({
1080
- type: "danger",
1081
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1082
- });
1083
- throw err;
1162
+ throw error2;
1084
1163
  }
1085
1164
  },
1086
- [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1165
+ [validationSchema]
1087
1166
  );
1088
- const [unpublishDocument] = useUnpublishDocumentMutation();
1089
- const unpublish = React__namespace.useCallback(
1090
- async ({ collectionType, model, documentId, params }, discardDraft = false) => {
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,
1190
+ model: slug,
1191
+ id: origin || id === "create" ? void 0 : id,
1192
+ ...useDocument(
1193
+ { documentId: origin || id, model: slug, collectionType, params },
1194
+ {
1195
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1196
+ }
1197
+ )
1198
+ };
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
+ };
1239
+ const prefixPluginTranslations = (trad, pluginId) => {
1240
+ if (!pluginId) {
1241
+ throw new TypeError("pluginId can't be empty");
1242
+ }
1243
+ return Object.keys(trad).reduce((acc, current) => {
1244
+ acc[`${pluginId}.${current}`] = trad[current];
1245
+ return acc;
1246
+ }, {});
1247
+ };
1248
+ const getTranslation = (id) => `content-manager.${id}`;
1249
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1250
+ id: "notification.error",
1251
+ defaultMessage: "An error occurred, please try again"
1252
+ };
1253
+ const useDocumentActions = () => {
1254
+ const { toggleNotification } = strapiAdmin.useNotification();
1255
+ const { formatMessage } = reactIntl.useIntl();
1256
+ const { trackUsage } = strapiAdmin.useTracking();
1257
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1258
+ const navigate = reactRouterDom.useNavigate();
1259
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1260
+ const [deleteDocument] = useDeleteDocumentMutation();
1261
+ const _delete = React__namespace.useCallback(
1262
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1091
1263
  try {
1092
- trackUsage("willUnpublishEntry");
1093
- const res = await unpublishDocument({
1264
+ trackUsage("willDeleteEntry", trackerProperty);
1265
+ const res = await deleteDocument({
1094
1266
  collectionType,
1095
1267
  model,
1096
1268
  documentId,
1097
- params,
1098
- data: {
1099
- discardDraft
1100
- }
1269
+ params
1101
1270
  });
1102
1271
  if ("error" in res) {
1103
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1272
+ toggleNotification({
1273
+ type: "danger",
1274
+ message: formatAPIError(res.error)
1275
+ });
1104
1276
  return { error: res.error };
1105
1277
  }
1106
- trackUsage("didUnpublishEntry");
1107
1278
  toggleNotification({
1108
1279
  type: "success",
1109
1280
  message: formatMessage({
1110
- id: getTranslation("success.record.unpublish"),
1111
- defaultMessage: "Unpublished document"
1281
+ id: getTranslation("success.record.delete"),
1282
+ defaultMessage: "Deleted document"
1112
1283
  })
1113
1284
  });
1285
+ trackUsage("didDeleteEntry", trackerProperty);
1114
1286
  return res.data;
1115
1287
  } catch (err) {
1116
1288
  toggleNotification({
1117
1289
  type: "danger",
1118
1290
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1119
1291
  });
1292
+ trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
1120
1293
  throw err;
1121
1294
  }
1122
1295
  },
1123
- [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1296
+ [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
1124
1297
  );
1125
- const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1126
- const unpublishMany = React__namespace.useCallback(
1298
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1299
+ const deleteMany = React__namespace.useCallback(
1127
1300
  async ({ model, documentIds, params }) => {
1128
1301
  try {
1129
- trackUsage("willBulkUnpublishEntries");
1130
- const res = await unpublishManyDocuments({
1302
+ trackUsage("willBulkDeleteEntries");
1303
+ const res = await deleteManyDocuments({
1131
1304
  model,
1132
1305
  documentIds,
1133
1306
  params
1134
1307
  });
1135
1308
  if ("error" in res) {
1136
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1309
+ toggleNotification({
1310
+ type: "danger",
1311
+ message: formatAPIError(res.error)
1312
+ });
1137
1313
  return { error: res.error };
1138
1314
  }
1139
- trackUsage("didBulkUnpublishEntries");
1140
1315
  toggleNotification({
1141
1316
  type: "success",
1142
1317
  title: formatMessage({
1143
- id: getTranslation("success.records.unpublish"),
1144
- defaultMessage: "Successfully unpublished."
1318
+ id: getTranslation("success.records.delete"),
1319
+ defaultMessage: "Successfully deleted."
1145
1320
  }),
1146
1321
  message: ""
1147
1322
  });
1323
+ trackUsage("didBulkDeleteEntries");
1148
1324
  return res.data;
1149
1325
  } catch (err) {
1150
1326
  toggleNotification({
1151
1327
  type: "danger",
1152
1328
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1153
1329
  });
1154
- trackUsage("didNotBulkUnpublishEntries");
1330
+ trackUsage("didNotBulkDeleteEntries");
1155
1331
  throw err;
1156
1332
  }
1157
1333
  },
1158
- [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1334
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1159
1335
  );
1160
- const [createDocument] = useCreateDocumentMutation();
1161
- const create = React__namespace.useCallback(
1162
- async ({ model, params }, data, trackerProperty) => {
1336
+ const [discardDocument] = useDiscardDocumentMutation();
1337
+ const discard = React__namespace.useCallback(
1338
+ async ({ collectionType, model, documentId, params }) => {
1163
1339
  try {
1164
- const res = await createDocument({
1340
+ const res = await discardDocument({
1341
+ collectionType,
1165
1342
  model,
1166
- data,
1343
+ documentId,
1167
1344
  params
1168
1345
  });
1169
1346
  if ("error" in res) {
1170
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1171
- trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1172
- return { error: res.error };
1347
+ toggleNotification({
1348
+ type: "danger",
1349
+ message: formatAPIError(res.error)
1350
+ });
1351
+ return { error: res.error };
1352
+ }
1353
+ toggleNotification({
1354
+ type: "success",
1355
+ message: formatMessage({
1356
+ id: "content-manager.success.record.discard",
1357
+ defaultMessage: "Changes discarded"
1358
+ })
1359
+ });
1360
+ return res.data;
1361
+ } catch (err) {
1362
+ toggleNotification({
1363
+ type: "danger",
1364
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1365
+ });
1366
+ throw err;
1367
+ }
1368
+ },
1369
+ [discardDocument, formatAPIError, formatMessage, toggleNotification]
1370
+ );
1371
+ const [publishDocument] = usePublishDocumentMutation();
1372
+ const publish = React__namespace.useCallback(
1373
+ async ({ collectionType, model, documentId, params }, data) => {
1374
+ try {
1375
+ trackUsage("willPublishEntry");
1376
+ const res = await publishDocument({
1377
+ collectionType,
1378
+ model,
1379
+ documentId,
1380
+ data,
1381
+ params
1382
+ });
1383
+ if ("error" in res) {
1384
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1385
+ return { error: res.error };
1386
+ }
1387
+ trackUsage("didPublishEntry");
1388
+ toggleNotification({
1389
+ type: "success",
1390
+ message: formatMessage({
1391
+ id: getTranslation("success.record.publish"),
1392
+ defaultMessage: "Published document"
1393
+ })
1394
+ });
1395
+ return res.data;
1396
+ } catch (err) {
1397
+ toggleNotification({
1398
+ type: "danger",
1399
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1400
+ });
1401
+ throw err;
1402
+ }
1403
+ },
1404
+ [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1405
+ );
1406
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1407
+ const publishMany = React__namespace.useCallback(
1408
+ async ({ model, documentIds, params }) => {
1409
+ try {
1410
+ const res = await publishManyDocuments({
1411
+ model,
1412
+ documentIds,
1413
+ params
1414
+ });
1415
+ if ("error" in res) {
1416
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1417
+ return { error: res.error };
1418
+ }
1419
+ toggleNotification({
1420
+ type: "success",
1421
+ message: formatMessage({
1422
+ id: getTranslation("success.record.publish"),
1423
+ defaultMessage: "Published document"
1424
+ })
1425
+ });
1426
+ return res.data;
1427
+ } catch (err) {
1428
+ toggleNotification({
1429
+ type: "danger",
1430
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1431
+ });
1432
+ throw err;
1433
+ }
1434
+ },
1435
+ [
1436
+ // trackUsage,
1437
+ publishManyDocuments,
1438
+ toggleNotification,
1439
+ formatMessage,
1440
+ formatAPIError
1441
+ ]
1442
+ );
1443
+ const [updateDocument] = useUpdateDocumentMutation();
1444
+ const update = React__namespace.useCallback(
1445
+ async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1446
+ try {
1447
+ trackUsage("willEditEntry", trackerProperty);
1448
+ const res = await updateDocument({
1449
+ collectionType,
1450
+ model,
1451
+ documentId,
1452
+ data,
1453
+ params
1454
+ });
1455
+ if ("error" in res) {
1456
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1457
+ trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1458
+ return { error: res.error };
1459
+ }
1460
+ trackUsage("didEditEntry", trackerProperty);
1461
+ toggleNotification({
1462
+ type: "success",
1463
+ message: formatMessage({
1464
+ id: getTranslation("success.record.save"),
1465
+ defaultMessage: "Saved document"
1466
+ })
1467
+ });
1468
+ return res.data;
1469
+ } catch (err) {
1470
+ trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1471
+ toggleNotification({
1472
+ type: "danger",
1473
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1474
+ });
1475
+ throw err;
1476
+ }
1477
+ },
1478
+ [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1479
+ );
1480
+ const [unpublishDocument] = useUnpublishDocumentMutation();
1481
+ const unpublish = React__namespace.useCallback(
1482
+ async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1483
+ try {
1484
+ trackUsage("willUnpublishEntry");
1485
+ const res = await unpublishDocument({
1486
+ collectionType,
1487
+ model,
1488
+ documentId,
1489
+ params,
1490
+ data: {
1491
+ discardDraft
1492
+ }
1493
+ });
1494
+ if ("error" in res) {
1495
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1496
+ return { error: res.error };
1497
+ }
1498
+ trackUsage("didUnpublishEntry");
1499
+ toggleNotification({
1500
+ type: "success",
1501
+ message: formatMessage({
1502
+ id: getTranslation("success.record.unpublish"),
1503
+ defaultMessage: "Unpublished document"
1504
+ })
1505
+ });
1506
+ return res.data;
1507
+ } catch (err) {
1508
+ toggleNotification({
1509
+ type: "danger",
1510
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1511
+ });
1512
+ throw err;
1513
+ }
1514
+ },
1515
+ [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1516
+ );
1517
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1518
+ const unpublishMany = React__namespace.useCallback(
1519
+ async ({ model, documentIds, params }) => {
1520
+ try {
1521
+ trackUsage("willBulkUnpublishEntries");
1522
+ const res = await unpublishManyDocuments({
1523
+ model,
1524
+ documentIds,
1525
+ params
1526
+ });
1527
+ if ("error" in res) {
1528
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1529
+ return { error: res.error };
1530
+ }
1531
+ trackUsage("didBulkUnpublishEntries");
1532
+ toggleNotification({
1533
+ type: "success",
1534
+ title: formatMessage({
1535
+ id: getTranslation("success.records.unpublish"),
1536
+ defaultMessage: "Successfully unpublished."
1537
+ }),
1538
+ message: ""
1539
+ });
1540
+ return res.data;
1541
+ } catch (err) {
1542
+ toggleNotification({
1543
+ type: "danger",
1544
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1545
+ });
1546
+ trackUsage("didNotBulkUnpublishEntries");
1547
+ throw err;
1548
+ }
1549
+ },
1550
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1551
+ );
1552
+ const [createDocument] = useCreateDocumentMutation();
1553
+ const create = React__namespace.useCallback(
1554
+ async ({ model, params }, data, trackerProperty) => {
1555
+ try {
1556
+ const res = await createDocument({
1557
+ model,
1558
+ data,
1559
+ params
1560
+ });
1561
+ if ("error" in res) {
1562
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1563
+ trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1564
+ return { error: res.error };
1173
1565
  }
1174
1566
  trackUsage("didCreateEntry", trackerProperty);
1175
1567
  toggleNotification({
@@ -1179,6 +1571,7 @@ const useDocumentActions = () => {
1179
1571
  defaultMessage: "Saved document"
1180
1572
  })
1181
1573
  });
1574
+ setCurrentStep("contentManager.success");
1182
1575
  return res.data;
1183
1576
  } catch (err) {
1184
1577
  toggleNotification({
@@ -1218,7 +1611,7 @@ const useDocumentActions = () => {
1218
1611
  throw err;
1219
1612
  }
1220
1613
  },
1221
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1614
+ [autoCloneDocument, formatMessage, toggleNotification]
1222
1615
  );
1223
1616
  const [cloneDocument] = useCloneDocumentMutation();
1224
1617
  const clone = React__namespace.useCallback(
@@ -1244,6 +1637,7 @@ const useDocumentActions = () => {
1244
1637
  defaultMessage: "Cloned document"
1245
1638
  })
1246
1639
  });
1640
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1247
1641
  return res.data;
1248
1642
  } catch (err) {
1249
1643
  toggleNotification({
@@ -1254,7 +1648,7 @@ const useDocumentActions = () => {
1254
1648
  throw err;
1255
1649
  }
1256
1650
  },
1257
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1651
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1258
1652
  );
1259
1653
  const [getDoc] = useLazyGetDocumentQuery();
1260
1654
  const getDocument = React__namespace.useCallback(
@@ -1280,7 +1674,7 @@ const useDocumentActions = () => {
1280
1674
  };
1281
1675
  };
1282
1676
  const ProtectedHistoryPage = React.lazy(
1283
- () => Promise.resolve().then(() => require("./History-CSr8y9KM.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1677
+ () => Promise.resolve().then(() => require("./History-BrJ1tUvt.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1284
1678
  );
1285
1679
  const routes$1 = [
1286
1680
  {
@@ -1293,31 +1687,31 @@ const routes$1 = [
1293
1687
  }
1294
1688
  ];
1295
1689
  const ProtectedEditViewPage = React.lazy(
1296
- () => Promise.resolve().then(() => require("./EditViewPage-DxKueadW.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1690
+ () => Promise.resolve().then(() => require("./EditViewPage-D2QVRr_2.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1297
1691
  );
1298
1692
  const ProtectedListViewPage = React.lazy(
1299
- () => Promise.resolve().then(() => require("./ListViewPage-DqAIb_ie.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1693
+ () => Promise.resolve().then(() => require("./ListViewPage-Coj-RPsx.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1300
1694
  );
1301
1695
  const ProtectedListConfiguration = React.lazy(
1302
- () => Promise.resolve().then(() => require("./ListConfigurationPage-DsmAQ3YM.js")).then((mod) => ({
1696
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-Eane5LKE.js")).then((mod) => ({
1303
1697
  default: mod.ProtectedListConfiguration
1304
1698
  }))
1305
1699
  );
1306
1700
  const ProtectedEditConfigurationPage = React.lazy(
1307
- () => Promise.resolve().then(() => require("./EditConfigurationPage-QZl5zOz-.js")).then((mod) => ({
1701
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-CpLj5gYZ.js")).then((mod) => ({
1308
1702
  default: mod.ProtectedEditConfigurationPage
1309
1703
  }))
1310
1704
  );
1311
1705
  const ProtectedComponentConfigurationPage = React.lazy(
1312
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-Bv-IXOYu.js")).then((mod) => ({
1706
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DnnZJc1F.js")).then((mod) => ({
1313
1707
  default: mod.ProtectedComponentConfigurationPage
1314
1708
  }))
1315
1709
  );
1316
1710
  const NoPermissions = React.lazy(
1317
- () => Promise.resolve().then(() => require("./NoPermissionsPage-DObTkKmZ.js")).then((mod) => ({ default: mod.NoPermissions }))
1711
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-BOtb5FTM.js")).then((mod) => ({ default: mod.NoPermissions }))
1318
1712
  );
1319
1713
  const NoContentType = React.lazy(
1320
- () => Promise.resolve().then(() => require("./NoContentTypePage-xjvn5XwY.js")).then((mod) => ({ default: mod.NoContentType }))
1714
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BDJ0dshy.js")).then((mod) => ({ default: mod.NoContentType }))
1321
1715
  );
1322
1716
  const CollectionTypePages = () => {
1323
1717
  const { collectionType } = reactRouterDom.useParams();
@@ -1360,1064 +1754,746 @@ const routes = [
1360
1754
  Component: NoPermissions
1361
1755
  },
1362
1756
  {
1363
- path: "no-content-types",
1364
- Component: NoContentType
1365
- },
1366
- ...routes$1
1367
- ];
1368
- const DocumentActions = ({ actions: actions2 }) => {
1369
- const { formatMessage } = reactIntl.useIntl();
1370
- const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
1371
- if (action.position === void 0) {
1372
- return true;
1373
- }
1374
- const positions = Array.isArray(action.position) ? action.position : [action.position];
1375
- return positions.includes("panel");
1376
- });
1377
- if (!primaryAction) {
1378
- return null;
1379
- }
1380
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
1381
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1382
- /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
1383
- restActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1384
- DocumentActionsMenu,
1385
- {
1386
- actions: restActions,
1387
- label: formatMessage({
1388
- id: "content-manager.containers.edit.panels.default.more-actions",
1389
- defaultMessage: "More document actions"
1390
- })
1391
- }
1392
- ) : null
1393
- ] }),
1394
- secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
1395
- DocumentActionButton,
1396
- {
1397
- ...secondaryAction,
1398
- variant: secondaryAction.variant || "secondary"
1399
- }
1400
- ) : null
1401
- ] });
1402
- };
1403
- const DocumentActionButton = (action) => {
1404
- const [dialogId, setDialogId] = React__namespace.useState(null);
1405
- const { toggleNotification } = strapiAdmin.useNotification();
1406
- const handleClick = (action2) => async (e) => {
1407
- const { onClick = () => false, dialog, id } = action2;
1408
- const muteDialog = await onClick(e);
1409
- if (dialog && !muteDialog) {
1410
- switch (dialog.type) {
1411
- case "notification":
1412
- toggleNotification({
1413
- title: dialog.title,
1414
- message: dialog.content,
1415
- type: dialog.status,
1416
- timeout: dialog.timeout,
1417
- onClose: dialog.onClose
1418
- });
1419
- break;
1420
- case "dialog":
1421
- case "modal":
1422
- e.preventDefault();
1423
- setDialogId(id);
1424
- }
1425
- }
1426
- };
1427
- const handleClose = () => {
1428
- setDialogId(null);
1429
- };
1430
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1431
- /* @__PURE__ */ jsxRuntime.jsx(
1432
- designSystem.Button,
1433
- {
1434
- flex: 1,
1435
- startIcon: action.icon,
1436
- disabled: action.disabled,
1437
- onClick: handleClick(action),
1438
- justifyContent: "center",
1439
- variant: action.variant || "default",
1440
- children: action.label
1441
- }
1442
- ),
1443
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1444
- DocumentActionConfirmDialog,
1445
- {
1446
- ...action.dialog,
1447
- variant: action.dialog?.variant ?? action.variant,
1448
- isOpen: dialogId === action.id,
1449
- onClose: handleClose
1450
- }
1451
- ) : null,
1452
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1453
- DocumentActionModal,
1454
- {
1455
- ...action.dialog,
1456
- onModalClose: handleClose,
1457
- isOpen: dialogId === action.id
1458
- }
1459
- ) : null
1460
- ] });
1461
- };
1462
- const DocumentActionsMenu = ({
1463
- actions: actions2,
1464
- children,
1465
- label,
1466
- variant = "tertiary"
1467
- }) => {
1468
- const [isOpen, setIsOpen] = React__namespace.useState(false);
1469
- const [dialogId, setDialogId] = React__namespace.useState(null);
1470
- const { formatMessage } = reactIntl.useIntl();
1471
- const { toggleNotification } = strapiAdmin.useNotification();
1472
- const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
1473
- const handleClick = (action) => async (e) => {
1474
- const { onClick = () => false, dialog, id } = action;
1475
- const muteDialog = await onClick(e);
1476
- if (dialog && !muteDialog) {
1477
- switch (dialog.type) {
1478
- case "notification":
1479
- toggleNotification({
1480
- title: dialog.title,
1481
- message: dialog.content,
1482
- type: dialog.status,
1483
- timeout: dialog.timeout,
1484
- onClose: dialog.onClose
1485
- });
1486
- break;
1487
- case "dialog":
1488
- case "modal":
1489
- setDialogId(id);
1490
- }
1491
- }
1492
- };
1493
- const handleClose = () => {
1494
- setDialogId(null);
1495
- setIsOpen(false);
1496
- };
1497
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1498
- /* @__PURE__ */ jsxRuntime.jsxs(
1499
- designSystem.Menu.Trigger,
1500
- {
1501
- disabled: isDisabled,
1502
- size: "S",
1503
- endIcon: null,
1504
- paddingTop: "7px",
1505
- paddingLeft: "9px",
1506
- paddingRight: "9px",
1507
- variant,
1508
- children: [
1509
- /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1511
- id: "content-manager.containers.edit.panels.default.more-actions",
1512
- defaultMessage: "More document actions"
1513
- }) })
1514
- ]
1515
- }
1516
- ),
1517
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1518
- actions2.map((action) => {
1519
- return /* @__PURE__ */ jsxRuntime.jsx(
1520
- designSystem.Menu.Item,
1521
- {
1522
- disabled: action.disabled,
1523
- onSelect: handleClick(action),
1524
- display: "block",
1525
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1526
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1527
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1528
- action.label
1529
- ] }),
1530
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1531
- designSystem.Flex,
1532
- {
1533
- alignItems: "center",
1534
- background: "alternative100",
1535
- borderStyle: "solid",
1536
- borderColor: "alternative200",
1537
- borderWidth: "1px",
1538
- height: 5,
1539
- paddingLeft: 2,
1540
- paddingRight: 2,
1541
- hasRadius: true,
1542
- color: "alternative600",
1543
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1544
- }
1545
- )
1546
- ] })
1547
- },
1548
- action.id
1549
- );
1550
- }),
1551
- children
1552
- ] }),
1553
- actions2.map((action) => {
1554
- return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
1555
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1556
- DocumentActionConfirmDialog,
1557
- {
1558
- ...action.dialog,
1559
- variant: action.variant,
1560
- isOpen: dialogId === action.id,
1561
- onClose: handleClose
1562
- }
1563
- ) : null,
1564
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1565
- DocumentActionModal,
1566
- {
1567
- ...action.dialog,
1568
- onModalClose: handleClose,
1569
- isOpen: dialogId === action.id
1570
- }
1571
- ) : null
1572
- ] }, action.id);
1573
- })
1574
- ] });
1575
- };
1576
- const convertActionVariantToColor = (variant = "secondary") => {
1577
- switch (variant) {
1578
- case "danger":
1579
- return "danger600";
1580
- case "secondary":
1581
- return void 0;
1582
- case "success":
1583
- return "success600";
1584
- default:
1585
- return "primary600";
1586
- }
1587
- };
1588
- const convertActionVariantToIconColor = (variant = "secondary") => {
1589
- switch (variant) {
1590
- case "danger":
1591
- return "danger600";
1592
- case "secondary":
1593
- return "neutral500";
1594
- case "success":
1595
- return "success600";
1596
- default:
1597
- return "primary600";
1598
- }
1599
- };
1600
- const DocumentActionConfirmDialog = ({
1601
- onClose,
1602
- onCancel,
1603
- onConfirm,
1604
- title,
1605
- content,
1606
- isOpen,
1607
- variant = "secondary"
1608
- }) => {
1609
- const { formatMessage } = reactIntl.useIntl();
1610
- const handleClose = async () => {
1611
- if (onCancel) {
1612
- await onCancel();
1613
- }
1614
- onClose();
1615
- };
1616
- const handleConfirm = async () => {
1617
- if (onConfirm) {
1618
- await onConfirm();
1619
- }
1620
- onClose();
1621
- };
1622
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1623
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1624
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1625
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1626
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
1627
- id: "app.components.Button.cancel",
1628
- defaultMessage: "Cancel"
1629
- }) }) }),
1630
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1631
- id: "app.components.Button.confirm",
1632
- defaultMessage: "Confirm"
1633
- }) })
1634
- ] })
1635
- ] }) });
1636
- };
1637
- const DocumentActionModal = ({
1638
- isOpen,
1639
- title,
1640
- onClose,
1641
- footer: Footer,
1642
- content: Content,
1643
- onModalClose
1644
- }) => {
1645
- const handleClose = () => {
1646
- if (onClose) {
1647
- onClose();
1648
- }
1649
- onModalClose();
1650
- };
1651
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1653
- typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1654
- typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1655
- ] }) });
1656
- };
1657
- const PublishAction$1 = ({
1658
- activeTab,
1659
- documentId,
1660
- model,
1661
- collectionType,
1662
- meta,
1663
- document
1664
- }) => {
1665
- const { schema } = useDoc();
1666
- const navigate = reactRouterDom.useNavigate();
1667
- const { toggleNotification } = strapiAdmin.useNotification();
1668
- const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1669
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1670
- const { formatMessage } = reactIntl.useIntl();
1671
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1672
- "PublishAction",
1673
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1674
- );
1675
- const { publish } = useDocumentActions();
1676
- const [
1677
- countDraftRelations,
1678
- { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1679
- ] = useLazyGetDraftRelationCountQuery();
1680
- const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1681
- const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1682
- const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1683
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1684
- const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
1685
- const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
1686
- const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
1687
- const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1688
- const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1689
- const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1690
- React__namespace.useEffect(() => {
1691
- if (isErrorDraftRelations) {
1692
- toggleNotification({
1693
- type: "danger",
1694
- message: formatMessage({
1695
- id: getTranslation("error.records.fetch-draft-relatons"),
1696
- defaultMessage: "An error occurred while fetching draft relations on this document."
1697
- })
1698
- });
1699
- }
1700
- }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1701
- React__namespace.useEffect(() => {
1702
- const localDraftRelations = /* @__PURE__ */ new Set();
1703
- const extractDraftRelations = (data) => {
1704
- const relations = data.connect || [];
1705
- relations.forEach((relation) => {
1706
- if (relation.status === "draft") {
1707
- localDraftRelations.add(relation.id);
1708
- }
1709
- });
1710
- };
1711
- const traverseAndExtract = (data) => {
1712
- Object.entries(data).forEach(([key, value]) => {
1713
- if (key === "connect" && Array.isArray(value)) {
1714
- extractDraftRelations({ connect: value });
1715
- } else if (typeof value === "object" && value !== null) {
1716
- traverseAndExtract(value);
1717
- }
1718
- });
1719
- };
1720
- if (!documentId || modified) {
1721
- traverseAndExtract(formValues);
1722
- setLocalCountOfDraftRelations(localDraftRelations.size);
1723
- }
1724
- }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1725
- React__namespace.useEffect(() => {
1726
- if (documentId) {
1727
- const fetchDraftRelationsCount = async () => {
1728
- const { data, error } = await countDraftRelations({
1729
- collectionType,
1730
- model,
1731
- documentId,
1732
- params
1733
- });
1734
- if (error) {
1735
- throw error;
1736
- }
1737
- if (data) {
1738
- setServerCountOfDraftRelations(data.data);
1739
- }
1740
- };
1741
- fetchDraftRelationsCount();
1757
+ path: "no-content-types",
1758
+ Component: NoContentType
1759
+ },
1760
+ ...routes$1
1761
+ ];
1762
+ const DocumentActions = ({ actions: actions2 }) => {
1763
+ const { formatMessage } = reactIntl.useIntl();
1764
+ const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
1765
+ if (action.position === void 0) {
1766
+ return true;
1742
1767
  }
1743
- }, [documentId, countDraftRelations, collectionType, model, params]);
1744
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1745
- if (!schema?.options?.draftAndPublish) {
1768
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
1769
+ return positions.includes("panel");
1770
+ });
1771
+ if (!primaryAction) {
1746
1772
  return null;
1747
1773
  }
1748
- const performPublish = async () => {
1749
- setSubmitting(true);
1750
- try {
1751
- const { errors } = await validate();
1752
- if (errors) {
1753
- toggleNotification({
1754
- type: "danger",
1755
- message: formatMessage({
1756
- id: "content-manager.validation.error",
1757
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1758
- })
1759
- });
1760
- return;
1761
- }
1762
- const res = await publish(
1763
- {
1764
- collectionType,
1765
- model,
1766
- documentId,
1767
- params
1768
- },
1769
- formValues
1770
- );
1771
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1772
- navigate({
1773
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1774
- search: rawQuery
1775
- });
1776
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1777
- setErrors(formatValidationErrors(res.error));
1778
- }
1779
- } finally {
1780
- setSubmitting(false);
1781
- }
1782
- };
1783
- const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1784
- const hasDraftRelations = totalDraftRelations > 0;
1785
- return {
1786
- /**
1787
- * Disabled when:
1788
- * - currently if you're cloning a document we don't support publish & clone at the same time.
1789
- * - the form is submitting
1790
- * - the active tab is the published tab
1791
- * - the document is already published & not modified
1792
- * - the document is being created & not modified
1793
- * - the user doesn't have the permission to publish
1794
- * - the user doesn't have the permission to create a new document
1795
- * - the user doesn't have the permission to update the document
1796
- */
1797
- disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1798
- label: formatMessage({
1799
- id: "app.utils.publish",
1800
- defaultMessage: "Publish"
1801
- }),
1802
- onClick: async () => {
1803
- if (hasDraftRelations) {
1804
- return;
1805
- }
1806
- await performPublish();
1807
- },
1808
- dialog: hasDraftRelations ? {
1809
- type: "dialog",
1810
- variant: "danger",
1811
- footer: null,
1812
- title: formatMessage({
1813
- id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1814
- defaultMessage: "Confirmation"
1815
- }),
1816
- content: formatMessage(
1817
- {
1818
- id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1819
- defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1820
- },
1774
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
1775
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
1776
+ /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
1777
+ restActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1778
+ DocumentActionsMenu,
1821
1779
  {
1822
- count: totalDraftRelations
1780
+ actions: restActions,
1781
+ label: formatMessage({
1782
+ id: "content-manager.containers.edit.panels.default.more-actions",
1783
+ defaultMessage: "More document actions"
1784
+ })
1823
1785
  }
1824
- ),
1825
- onConfirm: async () => {
1826
- await performPublish();
1786
+ ) : null
1787
+ ] }),
1788
+ secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
1789
+ DocumentActionButton,
1790
+ {
1791
+ ...secondaryAction,
1792
+ variant: secondaryAction.variant || "secondary"
1827
1793
  }
1828
- } : void 0
1829
- };
1794
+ ) : null
1795
+ ] });
1830
1796
  };
1831
- PublishAction$1.type = "publish";
1832
- const UpdateAction = ({
1833
- activeTab,
1834
- documentId,
1835
- model,
1836
- collectionType
1837
- }) => {
1838
- const navigate = reactRouterDom.useNavigate();
1797
+ const DocumentActionButton = (action) => {
1798
+ const [dialogId, setDialogId] = React__namespace.useState(null);
1839
1799
  const { toggleNotification } = strapiAdmin.useNotification();
1840
- const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1841
- const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1842
- const isCloning = cloneMatch !== null;
1843
- const { formatMessage } = reactIntl.useIntl();
1844
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1845
- canCreate: canCreate2,
1846
- canUpdate: canUpdate2
1847
- }));
1848
- const { create, update, clone } = useDocumentActions();
1849
- const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1850
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1851
- const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
1852
- const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
1853
- const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
1854
- const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
1855
- const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1856
- const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1857
- const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1858
- return {
1859
- /**
1860
- * Disabled when:
1861
- * - the form is submitting
1862
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1863
- * - the active tab is the published tab
1864
- * - the user doesn't have the permission to create a new document
1865
- * - the user doesn't have the permission to update the document
1866
- */
1867
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1868
- label: formatMessage({
1869
- id: "content-manager.containers.Edit.save",
1870
- defaultMessage: "Save"
1871
- }),
1872
- onClick: async () => {
1873
- setSubmitting(true);
1874
- try {
1875
- const { errors } = await validate();
1876
- if (errors) {
1800
+ const handleClick = (action2) => async (e) => {
1801
+ const { onClick = () => false, dialog, id } = action2;
1802
+ const muteDialog = await onClick(e);
1803
+ if (dialog && !muteDialog) {
1804
+ switch (dialog.type) {
1805
+ case "notification":
1877
1806
  toggleNotification({
1878
- type: "danger",
1879
- message: formatMessage({
1880
- id: "content-manager.validation.error",
1881
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1882
- })
1807
+ title: dialog.title,
1808
+ message: dialog.content,
1809
+ type: dialog.status,
1810
+ timeout: dialog.timeout,
1811
+ onClose: dialog.onClose
1883
1812
  });
1884
- return;
1885
- }
1886
- if (isCloning) {
1887
- const res = await clone(
1888
- {
1889
- model,
1890
- documentId: cloneMatch.params.origin,
1891
- params
1892
- },
1893
- document
1894
- );
1895
- if ("data" in res) {
1896
- navigate(
1897
- {
1898
- pathname: `../${res.data.documentId}`,
1899
- search: rawQuery
1900
- },
1901
- { relative: "path" }
1902
- );
1903
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1904
- setErrors(formatValidationErrors(res.error));
1905
- }
1906
- } else if (documentId || collectionType === SINGLE_TYPES) {
1907
- const res = await update(
1908
- {
1909
- collectionType,
1910
- model,
1911
- documentId,
1912
- params
1913
- },
1914
- document
1915
- );
1916
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1917
- setErrors(formatValidationErrors(res.error));
1918
- } else {
1919
- resetForm();
1920
- }
1921
- } else {
1922
- const res = await create(
1923
- {
1924
- model,
1925
- params
1926
- },
1927
- document
1928
- );
1929
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1930
- navigate(
1931
- {
1932
- pathname: `../${res.data.documentId}`,
1933
- search: rawQuery
1934
- },
1935
- { replace: true, relative: "path" }
1936
- );
1937
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1938
- setErrors(formatValidationErrors(res.error));
1939
- }
1940
- }
1941
- } finally {
1942
- setSubmitting(false);
1813
+ break;
1814
+ case "dialog":
1815
+ case "modal":
1816
+ e.preventDefault();
1817
+ setDialogId(id);
1943
1818
  }
1944
1819
  }
1945
1820
  };
1821
+ const handleClose = () => {
1822
+ setDialogId(null);
1823
+ };
1824
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1825
+ /* @__PURE__ */ jsxRuntime.jsx(
1826
+ designSystem.Button,
1827
+ {
1828
+ flex: "auto",
1829
+ startIcon: action.icon,
1830
+ disabled: action.disabled,
1831
+ onClick: handleClick(action),
1832
+ justifyContent: "center",
1833
+ variant: action.variant || "default",
1834
+ paddingTop: "7px",
1835
+ paddingBottom: "7px",
1836
+ children: action.label
1837
+ }
1838
+ ),
1839
+ action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1840
+ DocumentActionConfirmDialog,
1841
+ {
1842
+ ...action.dialog,
1843
+ variant: action.dialog?.variant ?? action.variant,
1844
+ isOpen: dialogId === action.id,
1845
+ onClose: handleClose
1846
+ }
1847
+ ) : null,
1848
+ action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1849
+ DocumentActionModal,
1850
+ {
1851
+ ...action.dialog,
1852
+ onModalClose: handleClose,
1853
+ isOpen: dialogId === action.id
1854
+ }
1855
+ ) : null
1856
+ ] });
1946
1857
  };
1947
- UpdateAction.type = "update";
1948
- const UNPUBLISH_DRAFT_OPTIONS = {
1949
- KEEP: "keep",
1950
- DISCARD: "discard"
1951
- };
1952
- const UnpublishAction$1 = ({
1953
- activeTab,
1954
- documentId,
1955
- model,
1956
- collectionType,
1957
- document
1858
+ const DocumentActionsMenu = ({
1859
+ actions: actions2,
1860
+ children,
1861
+ label,
1862
+ variant = "tertiary"
1958
1863
  }) => {
1864
+ const [isOpen, setIsOpen] = React__namespace.useState(false);
1865
+ const [dialogId, setDialogId] = React__namespace.useState(null);
1959
1866
  const { formatMessage } = reactIntl.useIntl();
1960
- const { schema } = useDoc();
1961
- const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1962
- const { unpublish } = useDocumentActions();
1963
- const [{ query }] = strapiAdmin.useQueryParams();
1964
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1965
1867
  const { toggleNotification } = strapiAdmin.useNotification();
1966
- const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1967
- const isDocumentModified = document?.status === "modified";
1968
- const handleChange = (value) => {
1969
- setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1970
- };
1971
- if (!schema?.options?.draftAndPublish) {
1972
- return null;
1973
- }
1974
- return {
1975
- disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
1976
- label: formatMessage({
1977
- id: "app.utils.unpublish",
1978
- defaultMessage: "Unpublish"
1979
- }),
1980
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
1981
- onClick: async () => {
1982
- if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1983
- if (!documentId) {
1984
- console.error(
1985
- "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
1986
- );
1868
+ const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
1869
+ const handleClick = (action) => async (e) => {
1870
+ const { onClick = () => false, dialog, id } = action;
1871
+ const muteDialog = await onClick(e);
1872
+ if (dialog && !muteDialog) {
1873
+ switch (dialog.type) {
1874
+ case "notification":
1987
1875
  toggleNotification({
1988
- message: formatMessage({
1989
- id: "content-manager.actions.unpublish.error",
1990
- defaultMessage: "An error occurred while trying to unpublish the document."
1991
- }),
1992
- type: "danger"
1876
+ title: dialog.title,
1877
+ message: dialog.content,
1878
+ type: dialog.status,
1879
+ timeout: dialog.timeout,
1880
+ onClose: dialog.onClose
1993
1881
  });
1994
- }
1995
- return;
1882
+ break;
1883
+ case "dialog":
1884
+ case "modal":
1885
+ setDialogId(id);
1996
1886
  }
1997
- await unpublish({
1998
- collectionType,
1999
- model,
2000
- documentId,
2001
- params
2002
- });
2003
- },
2004
- dialog: isDocumentModified ? {
2005
- type: "dialog",
2006
- title: formatMessage({
2007
- id: "app.components.ConfirmDialog.title",
2008
- defaultMessage: "Confirmation"
2009
- }),
2010
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
2011
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
2012
- /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2013
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2014
- id: "content-manager.actions.unpublish.dialog.body",
2015
- defaultMessage: "Are you sure?"
1887
+ }
1888
+ };
1889
+ const handleClose = () => {
1890
+ setDialogId(null);
1891
+ setIsOpen(false);
1892
+ };
1893
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1894
+ /* @__PURE__ */ jsxRuntime.jsxs(
1895
+ designSystem.Menu.Trigger,
1896
+ {
1897
+ disabled: isDisabled,
1898
+ size: "S",
1899
+ endIcon: null,
1900
+ paddingTop: "4px",
1901
+ paddingLeft: "7px",
1902
+ paddingRight: "7px",
1903
+ variant,
1904
+ children: [
1905
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1906
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1907
+ id: "content-manager.containers.edit.panels.default.more-actions",
1908
+ defaultMessage: "More document actions"
2016
1909
  }) })
2017
- ] }),
2018
- /* @__PURE__ */ jsxRuntime.jsxs(
2019
- designSystem.Radio.Group,
2020
- {
2021
- defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2022
- name: "discard-options",
2023
- "aria-label": formatMessage({
2024
- id: "content-manager.actions.unpublish.dialog.radio-label",
2025
- defaultMessage: "Choose an option to unpublish the document."
2026
- }),
2027
- onValueChange: handleChange,
2028
- children: [
2029
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2030
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2031
- defaultMessage: "Keep draft"
2032
- }) }),
2033
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2034
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2035
- defaultMessage: "Replace draft"
2036
- }) })
2037
- ]
2038
- }
2039
- )
2040
- ] }),
2041
- onConfirm: async () => {
2042
- if (!documentId && collectionType !== SINGLE_TYPES) {
2043
- console.error(
2044
- "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2045
- );
2046
- toggleNotification({
2047
- message: formatMessage({
2048
- id: "content-manager.actions.unpublish.error",
2049
- defaultMessage: "An error occurred while trying to unpublish the document."
2050
- }),
2051
- type: "danger"
2052
- });
2053
- }
2054
- await unpublish(
1910
+ ]
1911
+ }
1912
+ ),
1913
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1914
+ actions2.map((action) => {
1915
+ return /* @__PURE__ */ jsxRuntime.jsx(
1916
+ designSystem.Menu.Item,
2055
1917
  {
2056
- collectionType,
2057
- model,
2058
- documentId,
2059
- params
1918
+ disabled: action.disabled,
1919
+ onSelect: handleClick(action),
1920
+ display: "block",
1921
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
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
+ ),
1941
+ action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1942
+ designSystem.Flex,
1943
+ {
1944
+ alignItems: "center",
1945
+ background: "alternative100",
1946
+ borderStyle: "solid",
1947
+ borderColor: "alternative200",
1948
+ borderWidth: "1px",
1949
+ height: 5,
1950
+ paddingLeft: 2,
1951
+ paddingRight: 2,
1952
+ hasRadius: true,
1953
+ color: "alternative600",
1954
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1955
+ }
1956
+ )
1957
+ ] })
2060
1958
  },
2061
- !shouldKeepDraft
1959
+ action.id
2062
1960
  );
2063
- }
2064
- } : void 0,
2065
- variant: "danger",
2066
- position: ["panel", "table-row"]
1961
+ }),
1962
+ children
1963
+ ] }),
1964
+ actions2.map((action) => {
1965
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
1966
+ action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1967
+ DocumentActionConfirmDialog,
1968
+ {
1969
+ ...action.dialog,
1970
+ variant: action.variant,
1971
+ isOpen: dialogId === action.id,
1972
+ onClose: handleClose
1973
+ }
1974
+ ) : null,
1975
+ action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1976
+ DocumentActionModal,
1977
+ {
1978
+ ...action.dialog,
1979
+ onModalClose: handleClose,
1980
+ isOpen: dialogId === action.id
1981
+ }
1982
+ ) : null
1983
+ ] }, action.id);
1984
+ })
1985
+ ] });
1986
+ };
1987
+ const convertActionVariantToColor = (variant = "secondary") => {
1988
+ switch (variant) {
1989
+ case "danger":
1990
+ return "danger600";
1991
+ case "secondary":
1992
+ return void 0;
1993
+ case "success":
1994
+ return "success600";
1995
+ default:
1996
+ return "primary600";
1997
+ }
1998
+ };
1999
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2000
+ switch (variant) {
2001
+ case "danger":
2002
+ return "danger600";
2003
+ case "secondary":
2004
+ return "neutral500";
2005
+ case "success":
2006
+ return "success600";
2007
+ default:
2008
+ return "primary600";
2009
+ }
2010
+ };
2011
+ const DocumentActionConfirmDialog = ({
2012
+ onClose,
2013
+ onCancel,
2014
+ onConfirm,
2015
+ title,
2016
+ content,
2017
+ isOpen,
2018
+ variant = "secondary"
2019
+ }) => {
2020
+ const { formatMessage } = reactIntl.useIntl();
2021
+ const handleClose = async () => {
2022
+ if (onCancel) {
2023
+ await onCancel();
2024
+ }
2025
+ onClose();
2026
+ };
2027
+ const handleConfirm = async () => {
2028
+ if (onConfirm) {
2029
+ await onConfirm();
2030
+ }
2031
+ onClose();
2032
+ };
2033
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2034
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2035
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2036
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2037
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2038
+ id: "app.components.Button.cancel",
2039
+ defaultMessage: "Cancel"
2040
+ }) }) }),
2041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2042
+ id: "app.components.Button.confirm",
2043
+ defaultMessage: "Confirm"
2044
+ }) })
2045
+ ] })
2046
+ ] }) });
2047
+ };
2048
+ const DocumentActionModal = ({
2049
+ isOpen,
2050
+ title,
2051
+ onClose,
2052
+ footer: Footer,
2053
+ content: Content,
2054
+ onModalClose
2055
+ }) => {
2056
+ const handleClose = () => {
2057
+ if (onClose) {
2058
+ onClose();
2059
+ }
2060
+ onModalClose();
2067
2061
  };
2062
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2064
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2065
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2066
+ ] }) });
2068
2067
  };
2069
- UnpublishAction$1.type = "unpublish";
2070
- const DiscardAction = ({
2068
+ const PublishAction$1 = ({
2071
2069
  activeTab,
2072
2070
  documentId,
2073
2071
  model,
2074
2072
  collectionType,
2073
+ meta,
2075
2074
  document
2076
2075
  }) => {
2077
- const { formatMessage } = reactIntl.useIntl();
2078
2076
  const { schema } = useDoc();
2079
- const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
2080
- const { discard } = useDocumentActions();
2081
- const [{ query }] = strapiAdmin.useQueryParams();
2082
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2083
- if (!schema?.options?.draftAndPublish) {
2084
- return null;
2085
- }
2086
- return {
2087
- disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
2088
- label: formatMessage({
2089
- id: "content-manager.actions.discard.label",
2090
- defaultMessage: "Discard changes"
2091
- }),
2092
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2093
- position: ["panel", "table-row"],
2094
- variant: "danger",
2095
- dialog: {
2096
- type: "dialog",
2097
- title: formatMessage({
2098
- id: "app.components.ConfirmDialog.title",
2099
- defaultMessage: "Confirmation"
2100
- }),
2101
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2102
- /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2103
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2104
- id: "content-manager.actions.discard.dialog.body",
2105
- defaultMessage: "Are you sure?"
2106
- }) })
2107
- ] }),
2108
- onConfirm: async () => {
2109
- await discard({
2110
- collectionType,
2111
- model,
2112
- documentId,
2113
- params
2114
- });
2115
- }
2116
- }
2117
- };
2118
- };
2119
- DiscardAction.type = "discard";
2120
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2121
- path {
2122
- fill: currentColor;
2123
- }
2124
- `;
2125
- const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2126
- const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2127
- const RelativeTime = React__namespace.forwardRef(
2128
- ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
2129
- const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
2130
- const interval = dateFns.intervalToDuration({
2131
- start: timestamp,
2132
- end: Date.now()
2133
- // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
2134
- });
2135
- const unit = intervals.find((intervalUnit) => {
2136
- return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2137
- });
2138
- const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2139
- const customInterval = customIntervals.find(
2140
- (custom) => interval[custom.unit] < custom.threshold
2141
- );
2142
- const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
2143
- return /* @__PURE__ */ jsxRuntime.jsx(
2144
- "time",
2145
- {
2146
- ref: forwardedRef,
2147
- dateTime: timestamp.toISOString(),
2148
- role: "time",
2149
- title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
2150
- ...restProps,
2151
- children: displayText
2152
- }
2153
- );
2154
- }
2155
- );
2156
- const getDisplayName = ({
2157
- firstname,
2158
- lastname,
2159
- username,
2160
- email
2161
- } = {}) => {
2162
- if (username) {
2163
- return username;
2164
- }
2165
- if (firstname) {
2166
- return `${firstname} ${lastname ?? ""}`.trim();
2167
- }
2168
- return email ?? "";
2169
- };
2170
- const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2171
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2172
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2173
- 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) }) });
2174
- };
2175
- const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2176
- const { formatMessage } = reactIntl.useIntl();
2077
+ const navigate = reactRouterDom.useNavigate();
2078
+ const { toggleNotification } = strapiAdmin.useNotification();
2079
+ const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2080
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
2177
2081
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2178
- const title = isCreating ? formatMessage({
2179
- id: "content-manager.containers.edit.title.new",
2180
- defaultMessage: "Create an entry"
2181
- }) : documentTitle;
2182
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2183
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2184
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2185
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2186
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2187
- ] }),
2188
- status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2189
- ] });
2190
- };
2191
- const HeaderToolbar = () => {
2192
2082
  const { formatMessage } = reactIntl.useIntl();
2193
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2083
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2084
+ const { publish } = useDocumentActions();
2194
2085
  const [
2195
- {
2196
- query: { status = "draft" }
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);
2091
+ const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
2092
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2093
+ const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
2094
+ const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
2095
+ const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
2096
+ const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
2097
+ const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
2098
+ const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2099
+ React__namespace.useEffect(() => {
2100
+ if (isErrorDraftRelations) {
2101
+ toggleNotification({
2102
+ type: "danger",
2103
+ message: formatMessage({
2104
+ id: getTranslation("error.records.fetch-draft-relatons"),
2105
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2106
+ })
2107
+ });
2197
2108
  }
2198
- ] = strapiAdmin.useQueryParams();
2199
- const { model, id, document, meta, collectionType } = useDoc();
2200
- const plugins = strapiAdmin.useStrapiApp("HeaderToolbar", (state) => state.plugins);
2201
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2202
- /* @__PURE__ */ jsxRuntime.jsx(
2203
- strapiAdmin.DescriptionComponentRenderer,
2204
- {
2205
- props: {
2206
- activeTab: status,
2207
- model,
2208
- documentId: id,
2209
- document: isCloning ? void 0 : document,
2210
- meta: isCloning ? void 0 : meta,
2211
- collectionType
2212
- },
2213
- descriptions: plugins["content-manager"].apis.getHeaderActions(),
2214
- children: (actions2) => {
2215
- if (actions2.length > 0) {
2216
- return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
2217
- } else {
2218
- return null;
2219
- }
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);
2220
2117
  }
2221
- }
2222
- ),
2223
- /* @__PURE__ */ jsxRuntime.jsx(
2224
- strapiAdmin.DescriptionComponentRenderer,
2225
- {
2226
- props: {
2227
- activeTab: status,
2228
- model,
2229
- documentId: id,
2230
- document: isCloning ? void 0 : document,
2231
- meta: isCloning ? void 0 : meta,
2232
- collectionType
2233
- },
2234
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2235
- children: (actions2) => {
2236
- const headerActions = actions2.filter((action) => {
2237
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2238
- return positions.includes("header");
2239
- });
2240
- return /* @__PURE__ */ jsxRuntime.jsx(
2241
- DocumentActionsMenu,
2242
- {
2243
- actions: headerActions,
2244
- label: formatMessage({
2245
- id: "content-manager.containers.edit.header.more-actions",
2246
- defaultMessage: "More actions"
2247
- }),
2248
- children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
2249
- }
2250
- );
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);
2251
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);
2252
2150
  }
2253
- )
2254
- ] });
2255
- };
2256
- const Information = ({ activeTab }) => {
2257
- const { formatMessage } = reactIntl.useIntl();
2258
- const { document, meta } = useDoc();
2259
- if (!document || !document.id) {
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) {
2260
2156
  return null;
2261
2157
  }
2262
- const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
2263
- const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
2264
- const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
2265
- const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
2266
- const information = [
2267
- {
2268
- isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2269
- label: formatMessage({
2270
- id: "content-manager.containers.edit.information.last-published.label",
2271
- defaultMessage: "Last published"
2272
- }),
2273
- value: formatMessage(
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(
2274
2173
  {
2275
- id: "content-manager.containers.edit.information.last-published.value",
2276
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2174
+ collectionType,
2175
+ model,
2176
+ documentId,
2177
+ params
2277
2178
  },
2278
- {
2279
- time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
2280
- isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
2281
- author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
2282
- }
2283
- )
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,
2207
+ label: formatMessage({
2208
+ id: "app.utils.publish",
2209
+ defaultMessage: "Publish"
2210
+ }),
2211
+ onClick: async () => {
2212
+ await performPublish();
2284
2213
  },
2285
- {
2286
- isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2287
- label: formatMessage({
2288
- id: "content-manager.containers.edit.information.last-draft.label",
2289
- defaultMessage: "Last draft"
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"
2290
2221
  }),
2291
- value: formatMessage(
2222
+ content: formatMessage(
2292
2223
  {
2293
- id: "content-manager.containers.edit.information.last-draft.value",
2294
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
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."
2295
2226
  },
2296
2227
  {
2297
- time: /* @__PURE__ */ jsxRuntime.jsx(
2298
- RelativeTime,
2299
- {
2300
- timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
2301
- }
2302
- ),
2303
- isAnonymous: !updator,
2304
- author: updator
2228
+ count: totalDraftRelations
2305
2229
  }
2306
- )
2307
- },
2308
- {
2309
- isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2310
- label: formatMessage({
2311
- id: "content-manager.containers.edit.information.document.label",
2312
- defaultMessage: "Document"
2313
- }),
2314
- value: formatMessage(
2315
- {
2316
- id: "content-manager.containers.edit.information.document.value",
2317
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2318
- },
2319
- {
2320
- time: /* @__PURE__ */ jsxRuntime.jsx(
2321
- RelativeTime,
2230
+ ),
2231
+ onConfirm: async () => {
2232
+ await performPublish();
2233
+ }
2234
+ } : void 0
2235
+ };
2236
+ };
2237
+ PublishAction$1.type = "publish";
2238
+ const UpdateAction = ({
2239
+ activeTab,
2240
+ documentId,
2241
+ model,
2242
+ collectionType
2243
+ }) => {
2244
+ const navigate = reactRouterDom.useNavigate();
2245
+ const { toggleNotification } = strapiAdmin.useNotification();
2246
+ const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2247
+ const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
2248
+ const isCloning = cloneMatch !== null;
2249
+ const { formatMessage } = reactIntl.useIntl();
2250
+ const { create, update, clone } = useDocumentActions();
2251
+ const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
2252
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2253
+ const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
2254
+ const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
2255
+ const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
2256
+ const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
2257
+ const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
2258
+ const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
2259
+ const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
2260
+ return {
2261
+ /**
2262
+ * Disabled when:
2263
+ * - the form is submitting
2264
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2265
+ * - the active tab is the published tab
2266
+ */
2267
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2268
+ label: formatMessage({
2269
+ id: "content-manager.containers.Edit.save",
2270
+ defaultMessage: "Save"
2271
+ }),
2272
+ onClick: async () => {
2273
+ setSubmitting(true);
2274
+ try {
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
+ }
2287
+ }
2288
+ if (isCloning) {
2289
+ const res = await clone(
2322
2290
  {
2323
- timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
2324
- }
2325
- ),
2326
- isAnonymous: !creator,
2327
- author: creator
2291
+ model,
2292
+ documentId: cloneMatch.params.origin,
2293
+ params
2294
+ },
2295
+ document
2296
+ );
2297
+ if ("data" in res) {
2298
+ navigate(
2299
+ {
2300
+ pathname: `../${res.data.documentId}`,
2301
+ search: rawQuery
2302
+ },
2303
+ { relative: "path" }
2304
+ );
2305
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2306
+ setErrors(formatValidationErrors(res.error));
2307
+ }
2308
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2309
+ const res = await update(
2310
+ {
2311
+ collectionType,
2312
+ model,
2313
+ documentId,
2314
+ params
2315
+ },
2316
+ document
2317
+ );
2318
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2319
+ setErrors(formatValidationErrors(res.error));
2320
+ } else {
2321
+ resetForm();
2322
+ }
2323
+ } else {
2324
+ const res = await create(
2325
+ {
2326
+ model,
2327
+ params
2328
+ },
2329
+ document
2330
+ );
2331
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2332
+ navigate(
2333
+ {
2334
+ pathname: `../${res.data.documentId}`,
2335
+ search: rawQuery
2336
+ },
2337
+ { replace: true, relative: "path" }
2338
+ );
2339
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2340
+ setErrors(formatValidationErrors(res.error));
2341
+ }
2328
2342
  }
2329
- )
2330
- }
2331
- ].filter((info) => info.isDisplayed);
2332
- return /* @__PURE__ */ jsxRuntime.jsx(
2333
- designSystem.Flex,
2334
- {
2335
- borderWidth: "1px 0 0 0",
2336
- borderStyle: "solid",
2337
- borderColor: "neutral150",
2338
- direction: "column",
2339
- marginTop: 2,
2340
- tag: "dl",
2341
- padding: 5,
2342
- gap: 3,
2343
- alignItems: "flex-start",
2344
- marginLeft: "-0.4rem",
2345
- marginRight: "-0.4rem",
2346
- width: "calc(100% + 8px)",
2347
- children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2348
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2349
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2350
- ] }, info.label))
2343
+ } finally {
2344
+ setSubmitting(false);
2345
+ }
2351
2346
  }
2352
- );
2347
+ };
2353
2348
  };
2354
- const HeaderActions = ({ actions: actions2 }) => {
2355
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2356
- if ("options" in action) {
2357
- return /* @__PURE__ */ jsxRuntime.jsx(
2358
- designSystem.SingleSelect,
2359
- {
2360
- size: "S",
2361
- disabled: action.disabled,
2362
- "aria-label": action.label,
2363
- onChange: action.onSelect,
2364
- value: action.value,
2365
- children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2366
- },
2367
- action.id
2368
- );
2369
- } else {
2370
- return null;
2371
- }
2372
- }) });
2349
+ UpdateAction.type = "update";
2350
+ const UNPUBLISH_DRAFT_OPTIONS = {
2351
+ KEEP: "keep",
2352
+ DISCARD: "discard"
2373
2353
  };
2374
- const ConfigureTheViewAction = ({ collectionType, model }) => {
2375
- const navigate = reactRouterDom.useNavigate();
2354
+ const UnpublishAction$1 = ({
2355
+ activeTab,
2356
+ documentId,
2357
+ model,
2358
+ collectionType,
2359
+ document
2360
+ }) => {
2376
2361
  const { formatMessage } = reactIntl.useIntl();
2377
- return {
2378
- label: formatMessage({
2379
- id: "app.links.configure-view",
2380
- defaultMessage: "Configure the view"
2381
- }),
2382
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2383
- onClick: () => {
2384
- navigate(`../${collectionType}/${model}/configurations/edit`);
2385
- },
2386
- position: "header"
2362
+ const { schema } = useDoc();
2363
+ const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2364
+ const { unpublish } = useDocumentActions();
2365
+ const [{ query }] = strapiAdmin.useQueryParams();
2366
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2367
+ const { toggleNotification } = strapiAdmin.useNotification();
2368
+ const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
2369
+ const isDocumentModified = document?.status === "modified";
2370
+ const handleChange = (value) => {
2371
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
2387
2372
  };
2388
- };
2389
- ConfigureTheViewAction.type = "configure-the-view";
2390
- const EditTheModelAction = ({ model }) => {
2391
- const navigate = reactRouterDom.useNavigate();
2392
- const { formatMessage } = reactIntl.useIntl();
2373
+ if (!schema?.options?.draftAndPublish) {
2374
+ return null;
2375
+ }
2393
2376
  return {
2377
+ disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
2394
2378
  label: formatMessage({
2395
- id: "content-manager.link-to-ctb",
2396
- defaultMessage: "Edit the model"
2379
+ id: "app.utils.unpublish",
2380
+ defaultMessage: "Unpublish"
2397
2381
  }),
2398
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2399
- onClick: () => {
2400
- navigate(`/plugins/content-type-builder/content-types/${model}`);
2382
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2383
+ onClick: async () => {
2384
+ if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
2385
+ if (!documentId) {
2386
+ console.error(
2387
+ "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2388
+ );
2389
+ toggleNotification({
2390
+ message: formatMessage({
2391
+ id: "content-manager.actions.unpublish.error",
2392
+ defaultMessage: "An error occurred while trying to unpublish the document."
2393
+ }),
2394
+ type: "danger"
2395
+ });
2396
+ }
2397
+ return;
2398
+ }
2399
+ await unpublish({
2400
+ collectionType,
2401
+ model,
2402
+ documentId,
2403
+ params
2404
+ });
2401
2405
  },
2402
- position: "header"
2406
+ dialog: isDocumentModified ? {
2407
+ type: "dialog",
2408
+ title: formatMessage({
2409
+ id: "app.components.ConfirmDialog.title",
2410
+ defaultMessage: "Confirmation"
2411
+ }),
2412
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
2413
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
2414
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2415
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2416
+ id: "content-manager.actions.unpublish.dialog.body",
2417
+ defaultMessage: "Are you sure?"
2418
+ }) })
2419
+ ] }),
2420
+ /* @__PURE__ */ jsxRuntime.jsxs(
2421
+ designSystem.Radio.Group,
2422
+ {
2423
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2424
+ name: "discard-options",
2425
+ "aria-label": formatMessage({
2426
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2427
+ defaultMessage: "Choose an option to unpublish the document."
2428
+ }),
2429
+ onValueChange: handleChange,
2430
+ children: [
2431
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2432
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2433
+ defaultMessage: "Keep draft"
2434
+ }) }),
2435
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2436
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2437
+ defaultMessage: "Replace draft"
2438
+ }) })
2439
+ ]
2440
+ }
2441
+ )
2442
+ ] }),
2443
+ onConfirm: async () => {
2444
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2445
+ console.error(
2446
+ "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2447
+ );
2448
+ toggleNotification({
2449
+ message: formatMessage({
2450
+ id: "content-manager.actions.unpublish.error",
2451
+ defaultMessage: "An error occurred while trying to unpublish the document."
2452
+ }),
2453
+ type: "danger"
2454
+ });
2455
+ }
2456
+ await unpublish(
2457
+ {
2458
+ collectionType,
2459
+ model,
2460
+ documentId,
2461
+ params
2462
+ },
2463
+ !shouldKeepDraft
2464
+ );
2465
+ }
2466
+ } : void 0,
2467
+ variant: "danger",
2468
+ position: ["panel", "table-row"]
2403
2469
  };
2404
2470
  };
2405
- EditTheModelAction.type = "edit-the-model";
2406
- const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2407
- const navigate = reactRouterDom.useNavigate();
2471
+ UnpublishAction$1.type = "unpublish";
2472
+ const DiscardAction = ({
2473
+ activeTab,
2474
+ documentId,
2475
+ model,
2476
+ collectionType,
2477
+ document
2478
+ }) => {
2408
2479
  const { formatMessage } = reactIntl.useIntl();
2409
- const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2410
- const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2411
- const { delete: deleteAction } = useDocumentActions();
2412
- const { toggleNotification } = strapiAdmin.useNotification();
2413
- const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2480
+ const { schema } = useDoc();
2481
+ const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
2482
+ const { discard } = useDocumentActions();
2483
+ const [{ query }] = strapiAdmin.useQueryParams();
2484
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2485
+ if (!schema?.options?.draftAndPublish) {
2486
+ return null;
2487
+ }
2414
2488
  return {
2415
- disabled: !canDelete || !document,
2489
+ disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
2416
2490
  label: formatMessage({
2417
- id: "content-manager.actions.delete.label",
2418
- defaultMessage: "Delete document"
2491
+ id: "content-manager.actions.discard.label",
2492
+ defaultMessage: "Discard changes"
2419
2493
  }),
2420
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2494
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2495
+ position: ["panel", "table-row"],
2496
+ variant: "danger",
2421
2497
  dialog: {
2422
2498
  type: "dialog",
2423
2499
  title: formatMessage({
@@ -2427,92 +2503,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2427
2503
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2428
2504
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2429
2505
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2430
- id: "content-manager.actions.delete.dialog.body",
2506
+ id: "content-manager.actions.discard.dialog.body",
2431
2507
  defaultMessage: "Are you sure?"
2432
2508
  }) })
2433
2509
  ] }),
2434
2510
  onConfirm: async () => {
2435
- if (!listViewPathMatch) {
2436
- setSubmitting(true);
2437
- }
2438
- try {
2439
- if (!documentId && collectionType !== SINGLE_TYPES) {
2440
- console.error(
2441
- "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2442
- );
2443
- toggleNotification({
2444
- message: formatMessage({
2445
- id: "content-manager.actions.delete.error",
2446
- defaultMessage: "An error occurred while trying to delete the document."
2447
- }),
2448
- type: "danger"
2449
- });
2450
- return;
2451
- }
2452
- const res = await deleteAction({
2453
- documentId,
2454
- model,
2455
- collectionType,
2456
- params: {
2457
- locale: "*"
2458
- }
2459
- });
2460
- if (!("error" in res)) {
2461
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2462
- }
2463
- } finally {
2464
- if (!listViewPathMatch) {
2465
- setSubmitting(false);
2466
- }
2467
- }
2511
+ await discard({
2512
+ collectionType,
2513
+ model,
2514
+ documentId,
2515
+ params
2516
+ });
2517
+ }
2518
+ }
2519
+ };
2520
+ };
2521
+ DiscardAction.type = "discard";
2522
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2523
+ const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2524
+ const RelativeTime = React__namespace.forwardRef(
2525
+ ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
2526
+ const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
2527
+ const interval = dateFns.intervalToDuration({
2528
+ start: timestamp,
2529
+ end: Date.now()
2530
+ // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
2531
+ });
2532
+ const unit = intervals.find((intervalUnit) => {
2533
+ return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2534
+ });
2535
+ const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2536
+ const customInterval = customIntervals.find(
2537
+ (custom) => interval[custom.unit] < custom.threshold
2538
+ );
2539
+ const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
2540
+ return /* @__PURE__ */ jsxRuntime.jsx(
2541
+ "time",
2542
+ {
2543
+ ref: forwardedRef,
2544
+ dateTime: timestamp.toISOString(),
2545
+ role: "time",
2546
+ title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
2547
+ ...restProps,
2548
+ children: displayText
2468
2549
  }
2469
- },
2470
- variant: "danger",
2471
- position: ["header", "table-row"]
2472
- };
2550
+ );
2551
+ }
2552
+ );
2553
+ const getDisplayName = ({
2554
+ firstname,
2555
+ lastname,
2556
+ username,
2557
+ email
2558
+ } = {}) => {
2559
+ if (username) {
2560
+ return username;
2561
+ }
2562
+ if (firstname) {
2563
+ return `${firstname} ${lastname ?? ""}`.trim();
2564
+ }
2565
+ return email ?? "";
2473
2566
  };
2474
- DeleteAction$1.type = "delete";
2475
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2476
- const Panels = () => {
2477
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2478
- const [
2479
- {
2480
- query: { status }
2481
- }
2482
- ] = strapiAdmin.useQueryParams({
2483
- status: "draft"
2484
- });
2485
- const { model, id, document, meta, collectionType } = useDoc();
2486
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2487
- const props = {
2488
- activeTab: status,
2489
- model,
2490
- documentId: id,
2491
- document: isCloning ? void 0 : document,
2492
- meta: isCloning ? void 0 : meta,
2493
- collectionType
2494
- };
2495
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2496
- strapiAdmin.DescriptionComponentRenderer,
2497
- {
2498
- props,
2499
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2500
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2501
- }
2502
- ) });
2567
+ const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2568
+ const DocumentStatus = ({ status = "draft", ...restProps }) => {
2569
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
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) }) });
2503
2571
  };
2504
- const ActionsPanel = () => {
2572
+ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2505
2573
  const { formatMessage } = reactIntl.useIntl();
2506
- return {
2507
- title: formatMessage({
2508
- id: "content-manager.containers.edit.panels.default.title",
2509
- defaultMessage: "Document"
2510
- }),
2511
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2512
- };
2574
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2575
+ const title = isCreating ? formatMessage({
2576
+ id: "content-manager.containers.edit.title.new",
2577
+ defaultMessage: "Create an entry"
2578
+ }) : documentTitle;
2579
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2580
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
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
2586
+ ] });
2513
2587
  };
2514
- ActionsPanel.type = "actions";
2515
- const ActionsPanelContent = () => {
2588
+ const HeaderToolbar = () => {
2589
+ const { formatMessage } = reactIntl.useIntl();
2516
2590
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2517
2591
  const [
2518
2592
  {
@@ -2520,355 +2594,433 @@ const ActionsPanelContent = () => {
2520
2594
  }
2521
2595
  ] = strapiAdmin.useQueryParams();
2522
2596
  const { model, id, document, meta, collectionType } = useDoc();
2523
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2524
- const props = {
2525
- activeTab: status,
2526
- model,
2527
- documentId: id,
2528
- document: isCloning ? void 0 : document,
2529
- meta: isCloning ? void 0 : meta,
2530
- collectionType
2531
- };
2532
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2597
+ const plugins = strapiAdmin.useStrapiApp("HeaderToolbar", (state) => state.plugins);
2598
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2533
2599
  /* @__PURE__ */ jsxRuntime.jsx(
2534
2600
  strapiAdmin.DescriptionComponentRenderer,
2535
2601
  {
2536
- props,
2537
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2538
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2602
+ props: {
2603
+ activeTab: status,
2604
+ model,
2605
+ documentId: id,
2606
+ document: isCloning ? void 0 : document,
2607
+ meta: isCloning ? void 0 : meta,
2608
+ collectionType
2609
+ },
2610
+ descriptions: plugins["content-manager"].apis.getHeaderActions(),
2611
+ children: (actions2) => {
2612
+ if (actions2.length > 0) {
2613
+ return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
2614
+ } else {
2615
+ return null;
2616
+ }
2617
+ }
2539
2618
  }
2540
2619
  ),
2541
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2620
+ /* @__PURE__ */ jsxRuntime.jsx(
2621
+ strapiAdmin.DescriptionComponentRenderer,
2622
+ {
2623
+ props: {
2624
+ activeTab: status,
2625
+ model,
2626
+ documentId: id,
2627
+ document: isCloning ? void 0 : document,
2628
+ meta: isCloning ? void 0 : meta,
2629
+ collectionType
2630
+ },
2631
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
2632
+ children: (actions2) => {
2633
+ const headerActions = actions2.filter((action) => {
2634
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
2635
+ return positions.includes("header");
2636
+ });
2637
+ return /* @__PURE__ */ jsxRuntime.jsx(
2638
+ DocumentActionsMenu,
2639
+ {
2640
+ actions: headerActions,
2641
+ label: formatMessage({
2642
+ id: "content-manager.containers.edit.header.more-actions",
2643
+ defaultMessage: "More actions"
2644
+ }),
2645
+ children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
2646
+ }
2647
+ );
2648
+ }
2649
+ }
2650
+ )
2542
2651
  ] });
2543
2652
  };
2544
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2545
- return /* @__PURE__ */ jsxRuntime.jsxs(
2546
- designSystem.Flex,
2653
+ const Information = ({ activeTab }) => {
2654
+ const { formatMessage } = reactIntl.useIntl();
2655
+ const { document, meta } = useDoc();
2656
+ if (!document || !document.id) {
2657
+ return null;
2658
+ }
2659
+ const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
2660
+ const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
2661
+ const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
2662
+ const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
2663
+ const information = [
2547
2664
  {
2548
- ref,
2549
- tag: "aside",
2550
- "aria-labelledby": "additional-information",
2551
- background: "neutral0",
2552
- borderColor: "neutral150",
2553
- hasRadius: true,
2554
- paddingBottom: 4,
2555
- paddingLeft: 4,
2556
- paddingRight: 4,
2557
- paddingTop: 4,
2558
- shadow: "tableShadow",
2559
- gap: 3,
2560
- direction: "column",
2561
- justifyContent: "stretch",
2562
- alignItems: "flex-start",
2563
- children: [
2564
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2565
- children
2566
- ]
2567
- }
2568
- );
2569
- });
2570
- const HOOKS = {
2571
- /**
2572
- * Hook that allows to mutate the displayed headers of the list view table
2573
- * @constant
2574
- * @type {string}
2575
- */
2576
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2577
- /**
2578
- * Hook that allows to mutate the CM's collection types links pre-set filters
2579
- * @constant
2580
- * @type {string}
2581
- */
2582
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2583
- /**
2584
- * Hook that allows to mutate the CM's edit view layout
2585
- * @constant
2586
- * @type {string}
2587
- */
2588
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2589
- /**
2590
- * Hook that allows to mutate the CM's single types links pre-set filters
2591
- * @constant
2592
- * @type {string}
2593
- */
2594
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2595
- };
2596
- const contentTypesApi = contentManagerApi.injectEndpoints({
2597
- endpoints: (builder) => ({
2598
- getContentTypeConfiguration: builder.query({
2599
- query: (uid) => ({
2600
- url: `/content-manager/content-types/${uid}/configuration`,
2601
- method: "GET"
2665
+ isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2666
+ label: formatMessage({
2667
+ id: "content-manager.containers.edit.information.last-published.label",
2668
+ defaultMessage: "Last published"
2602
2669
  }),
2603
- transformResponse: (response) => response.data,
2604
- providesTags: (_result, _error, uid) => [
2605
- { type: "ContentTypesConfiguration", id: uid },
2606
- { type: "ContentTypeSettings", id: "LIST" }
2607
- ]
2608
- }),
2609
- getAllContentTypeSettings: builder.query({
2610
- query: () => "/content-manager/content-types-settings",
2611
- transformResponse: (response) => response.data,
2612
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2613
- }),
2614
- updateContentTypeConfiguration: builder.mutation({
2615
- query: ({ uid, ...body }) => ({
2616
- url: `/content-manager/content-types/${uid}/configuration`,
2617
- method: "PUT",
2618
- data: body
2670
+ value: formatMessage(
2671
+ {
2672
+ id: "content-manager.containers.edit.information.last-published.value",
2673
+ defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2674
+ },
2675
+ {
2676
+ time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
2677
+ isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
2678
+ author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
2679
+ }
2680
+ )
2681
+ },
2682
+ {
2683
+ isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2684
+ label: formatMessage({
2685
+ id: "content-manager.containers.edit.information.last-draft.label",
2686
+ defaultMessage: "Last draft"
2687
+ }),
2688
+ value: formatMessage(
2689
+ {
2690
+ id: "content-manager.containers.edit.information.last-draft.value",
2691
+ defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2692
+ },
2693
+ {
2694
+ time: /* @__PURE__ */ jsxRuntime.jsx(
2695
+ RelativeTime,
2696
+ {
2697
+ timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
2698
+ }
2699
+ ),
2700
+ isAnonymous: !updator,
2701
+ author: updator
2702
+ }
2703
+ )
2704
+ },
2705
+ {
2706
+ isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2707
+ label: formatMessage({
2708
+ id: "content-manager.containers.edit.information.document.label",
2709
+ defaultMessage: "Document"
2619
2710
  }),
2620
- transformResponse: (response) => response.data,
2621
- invalidatesTags: (_result, _error, { uid }) => [
2622
- { type: "ContentTypesConfiguration", id: uid },
2623
- { type: "ContentTypeSettings", id: "LIST" },
2624
- // Is this necessary?
2625
- { type: "InitialData" }
2626
- ]
2627
- })
2628
- })
2629
- });
2630
- const {
2631
- useGetContentTypeConfigurationQuery,
2632
- useGetAllContentTypeSettingsQuery,
2633
- useUpdateContentTypeConfigurationMutation
2634
- } = contentTypesApi;
2635
- const checkIfAttributeIsDisplayable = (attribute) => {
2636
- const { type } = attribute;
2637
- if (type === "relation") {
2638
- return !attribute.relation.toLowerCase().includes("morph");
2639
- }
2640
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2641
- };
2642
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2643
- if (!mainFieldName) {
2644
- return void 0;
2645
- }
2646
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2647
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2648
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2711
+ value: formatMessage(
2712
+ {
2713
+ id: "content-manager.containers.edit.information.document.value",
2714
+ defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2715
+ },
2716
+ {
2717
+ time: /* @__PURE__ */ jsxRuntime.jsx(
2718
+ RelativeTime,
2719
+ {
2720
+ timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
2721
+ }
2722
+ ),
2723
+ isAnonymous: !creator,
2724
+ author: creator
2725
+ }
2726
+ )
2727
+ }
2728
+ ].filter((info) => info.isDisplayed);
2729
+ return /* @__PURE__ */ jsxRuntime.jsx(
2730
+ designSystem.Flex,
2731
+ {
2732
+ borderWidth: "1px 0 0 0",
2733
+ borderStyle: "solid",
2734
+ borderColor: "neutral150",
2735
+ direction: "column",
2736
+ marginTop: 2,
2737
+ tag: "dl",
2738
+ padding: 5,
2739
+ gap: 3,
2740
+ alignItems: "flex-start",
2741
+ marginLeft: "-0.4rem",
2742
+ marginRight: "-0.4rem",
2743
+ width: "calc(100% + 8px)",
2744
+ children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2745
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2746
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2747
+ ] }, info.label))
2748
+ }
2649
2749
  );
2650
- return {
2651
- name: mainFieldName,
2652
- type: mainFieldType ?? "string"
2653
- };
2654
- };
2655
- const DEFAULT_SETTINGS = {
2656
- bulkable: false,
2657
- filterable: false,
2658
- searchable: false,
2659
- pagination: false,
2660
- defaultSortBy: "",
2661
- defaultSortOrder: "asc",
2662
- mainField: "id",
2663
- pageSize: 10
2664
2750
  };
2665
- const useDocumentLayout = (model) => {
2666
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2667
- const [{ query }] = strapiAdmin.useQueryParams();
2668
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2669
- const { toggleNotification } = strapiAdmin.useNotification();
2670
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2671
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2672
- const {
2673
- data,
2674
- isLoading: isLoadingConfigs,
2675
- error,
2676
- isFetching: isFetchingConfigs
2677
- } = useGetContentTypeConfigurationQuery(model);
2678
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2679
- React__namespace.useEffect(() => {
2680
- if (error) {
2681
- toggleNotification({
2682
- type: "danger",
2683
- message: formatAPIError(error)
2684
- });
2751
+ const HeaderActions = ({ actions: actions2 }) => {
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
+ }
2685
2761
  }
2686
- }, [error, formatAPIError, toggleNotification]);
2687
- const editLayout = React__namespace.useMemo(
2688
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2689
- layout: [],
2690
- components: {},
2691
- metadatas: {},
2692
- options: {},
2693
- settings: DEFAULT_SETTINGS
2694
- },
2695
- [data, isLoading, schemas, schema, components]
2696
- );
2697
- const listLayout = React__namespace.useMemo(() => {
2698
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2699
- layout: [],
2700
- metadatas: {},
2701
- options: {},
2702
- settings: DEFAULT_SETTINGS
2703
- };
2704
- }, [data, isLoading, schemas, schema, components]);
2705
- const { layout: edit } = React__namespace.useMemo(
2706
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2707
- layout: editLayout,
2708
- query
2709
- }),
2710
- [editLayout, query, runHookWaterfall]
2711
- );
2712
- return {
2713
- error,
2714
- isLoading,
2715
- edit,
2716
- list: listLayout
2717
2762
  };
2718
- };
2719
- const useDocLayout = () => {
2720
- const { model } = useDoc();
2721
- return useDocumentLayout(model);
2722
- };
2723
- const formatEditLayout = (data, {
2724
- schemas,
2725
- schema,
2726
- components
2727
- }) => {
2728
- let currentPanelIndex = 0;
2729
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2730
- data.contentType.layouts.edit,
2731
- schema?.attributes,
2732
- data.contentType.metadatas,
2733
- { configurations: data.components, schemas: components },
2734
- schemas
2735
- ).reduce((panels, row) => {
2736
- if (row.some((field) => field.type === "dynamiczone")) {
2737
- panels.push([row]);
2738
- currentPanelIndex += 2;
2763
+ const handleClose = () => {
2764
+ setDialogId(null);
2765
+ };
2766
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2767
+ if (action.options) {
2768
+ return /* @__PURE__ */ jsxRuntime.jsx(
2769
+ designSystem.SingleSelect,
2770
+ {
2771
+ size: "S",
2772
+ disabled: action.disabled,
2773
+ "aria-label": action.label,
2774
+ onChange: action.onSelect,
2775
+ value: action.value,
2776
+ children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2777
+ },
2778
+ action.id
2779
+ );
2739
2780
  } else {
2740
- if (!panels[currentPanelIndex]) {
2741
- panels.push([]);
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);
2742
2802
  }
2743
- panels[currentPanelIndex].push(row);
2744
2803
  }
2745
- return panels;
2746
- }, []);
2747
- const componentEditAttributes = Object.entries(data.components).reduce(
2748
- (acc, [uid, configuration]) => {
2749
- acc[uid] = {
2750
- layout: convertEditLayoutToFieldLayouts(
2751
- configuration.layouts.edit,
2752
- components[uid].attributes,
2753
- configuration.metadatas
2754
- ),
2755
- settings: {
2756
- ...configuration.settings,
2757
- icon: components[uid].info.icon,
2758
- displayName: components[uid].info.displayName
2759
- }
2760
- };
2761
- return acc;
2762
- },
2763
- {}
2764
- );
2765
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2766
- (acc, [attribute, metadata]) => {
2767
- return {
2768
- ...acc,
2769
- [attribute]: metadata.edit
2770
- };
2804
+ }) });
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
+ };
2824
+ const ConfigureTheViewAction = ({ collectionType, model }) => {
2825
+ const navigate = reactRouterDom.useNavigate();
2826
+ const { formatMessage } = reactIntl.useIntl();
2827
+ return {
2828
+ label: formatMessage({
2829
+ id: "app.links.configure-view",
2830
+ defaultMessage: "Configure the view"
2831
+ }),
2832
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2833
+ onClick: () => {
2834
+ navigate(`../${collectionType}/${model}/configurations/edit`);
2771
2835
  },
2772
- {}
2773
- );
2836
+ position: "header"
2837
+ };
2838
+ };
2839
+ ConfigureTheViewAction.type = "configure-the-view";
2840
+ const EditTheModelAction = ({ model }) => {
2841
+ const navigate = reactRouterDom.useNavigate();
2842
+ const { formatMessage } = reactIntl.useIntl();
2774
2843
  return {
2775
- layout: panelledEditAttributes,
2776
- components: componentEditAttributes,
2777
- metadatas: editMetadatas,
2778
- settings: {
2779
- ...data.contentType.settings,
2780
- displayName: schema?.info.displayName
2844
+ label: formatMessage({
2845
+ id: "content-manager.link-to-ctb",
2846
+ defaultMessage: "Edit the model"
2847
+ }),
2848
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2849
+ onClick: () => {
2850
+ navigate(`/plugins/content-type-builder/content-types/${model}`);
2781
2851
  },
2782
- options: {
2783
- ...schema?.options,
2784
- ...schema?.pluginOptions,
2785
- ...data.contentType.options
2786
- }
2852
+ position: "header"
2787
2853
  };
2788
2854
  };
2789
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2790
- return rows.map(
2791
- (row) => row.map((field) => {
2792
- const attribute = attributes[field.name];
2793
- if (!attribute) {
2794
- return null;
2855
+ EditTheModelAction.type = "edit-the-model";
2856
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2857
+ const navigate = reactRouterDom.useNavigate();
2858
+ const { formatMessage } = reactIntl.useIntl();
2859
+ const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2860
+ const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2861
+ const { delete: deleteAction } = useDocumentActions();
2862
+ const { toggleNotification } = strapiAdmin.useNotification();
2863
+ const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2864
+ const isLocalized = document?.locale != null;
2865
+ return {
2866
+ disabled: !canDelete || !document,
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
+ ),
2874
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2875
+ dialog: {
2876
+ type: "dialog",
2877
+ title: formatMessage({
2878
+ id: "app.components.ConfirmDialog.title",
2879
+ defaultMessage: "Confirmation"
2880
+ }),
2881
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2882
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2883
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2884
+ id: "content-manager.actions.delete.dialog.body",
2885
+ defaultMessage: "Are you sure?"
2886
+ }) })
2887
+ ] }),
2888
+ onConfirm: async () => {
2889
+ if (!listViewPathMatch) {
2890
+ setSubmitting(true);
2891
+ }
2892
+ try {
2893
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2894
+ console.error(
2895
+ "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2896
+ );
2897
+ toggleNotification({
2898
+ message: formatMessage({
2899
+ id: "content-manager.actions.delete.error",
2900
+ defaultMessage: "An error occurred while trying to delete the document."
2901
+ }),
2902
+ type: "danger"
2903
+ });
2904
+ return;
2905
+ }
2906
+ const res = await deleteAction({
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
+ }
2921
+ }
2795
2922
  }
2796
- const { edit: metadata } = metadatas[field.name];
2797
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2798
- return {
2799
- attribute,
2800
- disabled: !metadata.editable,
2801
- hint: metadata.description,
2802
- label: metadata.label ?? "",
2803
- name: field.name,
2804
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2805
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2806
- schemas,
2807
- components: components?.schemas ?? {}
2808
- }),
2809
- placeholder: metadata.placeholder ?? "",
2810
- required: attribute.required ?? false,
2811
- size: field.size,
2812
- unique: "unique" in attribute ? attribute.unique : false,
2813
- visible: metadata.visible ?? true,
2814
- type: attribute.type
2815
- };
2816
- }).filter((field) => field !== null)
2817
- );
2818
- };
2819
- const formatListLayout = (data, {
2820
- schemas,
2821
- schema,
2822
- components
2823
- }) => {
2824
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2825
- (acc, [attribute, metadata]) => {
2826
- return {
2827
- ...acc,
2828
- [attribute]: metadata.list
2829
- };
2830
2923
  },
2831
- {}
2832
- );
2833
- const listAttributes = convertListLayoutToFieldLayouts(
2834
- data.contentType.layouts.list,
2835
- schema?.attributes,
2836
- listMetadatas,
2837
- { configurations: data.components, schemas: components },
2838
- schemas
2839
- );
2840
- return {
2841
- layout: listAttributes,
2842
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2843
- metadatas: listMetadatas,
2844
- options: {
2845
- ...schema?.options,
2846
- ...schema?.pluginOptions,
2847
- ...data.contentType.options
2924
+ variant: "danger",
2925
+ position: ["header", "table-row"]
2926
+ };
2927
+ };
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))
2848
2955
  }
2956
+ ) });
2957
+ };
2958
+ const ActionsPanel = () => {
2959
+ const { formatMessage } = reactIntl.useIntl();
2960
+ return {
2961
+ title: formatMessage({
2962
+ id: "content-manager.containers.edit.panels.default.title",
2963
+ defaultMessage: "Entry"
2964
+ }),
2965
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2849
2966
  };
2850
2967
  };
2851
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2852
- return columns.map((name) => {
2853
- const attribute = attributes[name];
2854
- if (!attribute) {
2855
- return null;
2968
+ ActionsPanel.type = "actions";
2969
+ const ActionsPanelContent = () => {
2970
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2971
+ const [
2972
+ {
2973
+ query: { status = "draft" }
2856
2974
  }
2857
- const metadata = metadatas[name];
2858
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2859
- return {
2860
- attribute,
2861
- label: metadata.label ?? "",
2862
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2863
- schemas,
2864
- components: components?.schemas ?? {}
2865
- }),
2866
- name,
2867
- searchable: metadata.searchable ?? true,
2868
- sortable: metadata.sortable ?? true
2869
- };
2870
- }).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
+ ] });
2871
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
+ });
2872
3024
  const ConfirmBulkActionDialog = ({
2873
3025
  onToggleDialog,
2874
3026
  isOpen = false,
@@ -2907,6 +3059,7 @@ const ConfirmDialogPublishAll = ({
2907
3059
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2908
3060
  const { model, schema } = useDoc();
2909
3061
  const [{ query }] = strapiAdmin.useQueryParams();
3062
+ const enableDraftRelationsCount = false;
2910
3063
  const {
2911
3064
  data: countDraftRelations = 0,
2912
3065
  isLoading,
@@ -2918,7 +3071,7 @@ const ConfirmDialogPublishAll = ({
2918
3071
  locale: query?.plugins?.i18n?.locale
2919
3072
  },
2920
3073
  {
2921
- skip: selectedEntries.length === 0
3074
+ skip: !enableDraftRelationsCount
2922
3075
  }
2923
3076
  );
2924
3077
  React__namespace.useEffect(() => {
@@ -3103,7 +3256,7 @@ const SelectedEntriesTableContent = ({
3103
3256
  status: row.status
3104
3257
  }
3105
3258
  ) }),
3106
- /* @__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(
3107
3260
  designSystem.IconButton,
3108
3261
  {
3109
3262
  tag: reactRouterDom.Link,
@@ -3126,9 +3279,10 @@ const SelectedEntriesTableContent = ({
3126
3279
  ),
3127
3280
  target: "_blank",
3128
3281
  marginLeft: "auto",
3129
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3282
+ variant: "ghost",
3283
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3130
3284
  }
3131
- ) })
3285
+ ) }) })
3132
3286
  ] }, row.id)) })
3133
3287
  ] });
3134
3288
  };
@@ -3165,7 +3319,13 @@ const SelectedEntriesModalContent = ({
3165
3319
  );
3166
3320
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3167
3321
  if (data.length > 0 && schema) {
3168
- 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
+ );
3169
3329
  const validationErrors2 = {};
3170
3330
  const rows2 = data.map((entry) => {
3171
3331
  try {
@@ -3515,7 +3675,7 @@ const TableActions = ({ document }) => {
3515
3675
  strapiAdmin.DescriptionComponentRenderer,
3516
3676
  {
3517
3677
  props,
3518
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3678
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3519
3679
  children: (actions2) => {
3520
3680
  const tableRowActions = actions2.filter((action) => {
3521
3681
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3626,7 +3786,7 @@ const CloneAction = ({ model, documentId }) => {
3626
3786
  }),
3627
3787
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3628
3788
  footer: ({ onClose }) => {
3629
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3789
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3630
3790
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3631
3791
  id: "cancel",
3632
3792
  defaultMessage: "Cancel"
@@ -3857,7 +4017,7 @@ const index = {
3857
4017
  app.router.addRoute({
3858
4018
  path: "content-manager/*",
3859
4019
  lazy: async () => {
3860
- const { Layout } = await Promise.resolve().then(() => require("./layout-tVvbqota.js"));
4020
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CWgZzMYf.js"));
3861
4021
  return {
3862
4022
  Component: Layout
3863
4023
  };
@@ -3874,7 +4034,7 @@ const index = {
3874
4034
  async registerTrads({ locales }) {
3875
4035
  const importedTrads = await Promise.all(
3876
4036
  locales.map((locale) => {
3877
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-uOUIxfcQ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
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 }) => {
3878
4038
  return {
3879
4039
  data: prefixPluginTranslations(data, PLUGIN_ID),
3880
4040
  locale
@@ -3892,6 +4052,7 @@ const index = {
3892
4052
  };
3893
4053
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3894
4054
  exports.BulkActionsRenderer = BulkActionsRenderer;
4055
+ exports.CLONE_PATH = CLONE_PATH;
3895
4056
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3896
4057
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3897
4058
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3919,6 +4080,7 @@ exports.getMainField = getMainField;
3919
4080
  exports.getTranslation = getTranslation;
3920
4081
  exports.index = index;
3921
4082
  exports.setInitialData = setInitialData;
4083
+ exports.useContentManagerContext = useContentManagerContext;
3922
4084
  exports.useContentTypeSchema = useContentTypeSchema;
3923
4085
  exports.useDoc = useDoc;
3924
4086
  exports.useDocLayout = useDocLayout;
@@ -3931,4 +4093,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3931
4093
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3932
4094
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3933
4095
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3934
- //# sourceMappingURL=index-1zxclxo_.js.map
4096
+ //# sourceMappingURL=index-DTKVhcla.js.map