@strapi/content-manager 0.0.0-experimental.145e7d7ddefd1aef71aaf3d9bb86440d013035bf → 0.0.0-experimental.1610404a03d98b65f497f9adda35815021b8fd76

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 (125) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-DJEJ49QD.mjs → ComponentConfigurationPage-C5xJlht8.mjs} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-DJEJ49QD.mjs.map → ComponentConfigurationPage-C5xJlht8.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-D_g11bYV.js → ComponentConfigurationPage-CyzIs3Wp.js} +5 -6
  4. package/dist/_chunks/{ComponentConfigurationPage-D_g11bYV.js.map → ComponentConfigurationPage-CyzIs3Wp.js.map} +1 -1
  5. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  6. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-QBZdUYyG.mjs → EditConfigurationPage-B1JTGbDa.mjs} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-QBZdUYyG.mjs.map → EditConfigurationPage-B1JTGbDa.mjs.map} +1 -1
  9. package/dist/_chunks/{EditConfigurationPage-CeL712KW.js → EditConfigurationPage-BoY4_TQp.js} +5 -6
  10. package/dist/_chunks/{EditConfigurationPage-CeL712KW.js.map → EditConfigurationPage-BoY4_TQp.js.map} +1 -1
  11. package/dist/_chunks/{EditViewPage-CvRUUpVh.mjs → EditViewPage-B8Uz26ZK.mjs} +15 -5
  12. package/dist/_chunks/EditViewPage-B8Uz26ZK.mjs.map +1 -0
  13. package/dist/_chunks/{EditViewPage-g5TwrgRY.js → EditViewPage-DxszpwJd.js} +16 -7
  14. package/dist/_chunks/EditViewPage-DxszpwJd.js.map +1 -0
  15. package/dist/_chunks/{Field-reyvfnop.mjs → Field-CquZadQb.mjs} +93 -78
  16. package/dist/_chunks/Field-CquZadQb.mjs.map +1 -0
  17. package/dist/_chunks/{Field-ncdInvxS.js → Field-DzgX4ael.js} +99 -85
  18. package/dist/_chunks/Field-DzgX4ael.js.map +1 -0
  19. package/dist/_chunks/{Form-BJ7bYiUx.js → Form-C8a2ftQg.js} +17 -12
  20. package/dist/_chunks/Form-C8a2ftQg.js.map +1 -0
  21. package/dist/_chunks/{Form-DoMGsYxH.mjs → Form-DuJm__5A.mjs} +15 -9
  22. package/dist/_chunks/Form-DuJm__5A.mjs.map +1 -0
  23. package/dist/_chunks/{History-pbhkxIrf.js → History-B1sa22d-.js} +25 -13
  24. package/dist/_chunks/History-B1sa22d-.js.map +1 -0
  25. package/dist/_chunks/{History-BseDJOrj.mjs → History-C7xPTX16.mjs} +25 -12
  26. package/dist/_chunks/History-C7xPTX16.mjs.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-DWE_fr5B.mjs → ListConfigurationPage-C6zgYhFZ.mjs} +4 -4
  28. package/dist/_chunks/{ListConfigurationPage-DWE_fr5B.mjs.map → ListConfigurationPage-C6zgYhFZ.mjs.map} +1 -1
  29. package/dist/_chunks/{ListConfigurationPage-Bna8zfjr.js → ListConfigurationPage-CYWB9ZNc.js} +5 -6
  30. package/dist/_chunks/{ListConfigurationPage-Bna8zfjr.js.map → ListConfigurationPage-CYWB9ZNc.js.map} +1 -1
  31. package/dist/_chunks/{ListViewPage-lQ-VLV2G.mjs → ListViewPage-BkzGZ8pS.mjs} +36 -13
  32. package/dist/_chunks/ListViewPage-BkzGZ8pS.mjs.map +1 -0
  33. package/dist/_chunks/{ListViewPage-Dymsvnv6.js → ListViewPage-D7jZkQ1q.js} +41 -19
  34. package/dist/_chunks/ListViewPage-D7jZkQ1q.js.map +1 -0
  35. package/dist/_chunks/{NoContentTypePage-B4t_OsDR.js → NoContentTypePage-C-eluJ5b.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-B4t_OsDR.js.map → NoContentTypePage-C-eluJ5b.js.map} +1 -1
  37. package/dist/_chunks/{NoContentTypePage-VCQOMwlf.mjs → NoContentTypePage-CNTp9Je-.mjs} +2 -2
  38. package/dist/_chunks/{NoContentTypePage-VCQOMwlf.mjs.map → NoContentTypePage-CNTp9Je-.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-BOwB6hki.js → NoPermissionsPage-5BRSh_ql.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-BOwB6hki.js.map → NoPermissionsPage-5BRSh_ql.js.map} +1 -1
  41. package/dist/_chunks/{NoPermissionsPage-TV830k4P.mjs → NoPermissionsPage-B1-Nl_T8.mjs} +2 -2
  42. package/dist/_chunks/{NoPermissionsPage-TV830k4P.mjs.map → NoPermissionsPage-B1-Nl_T8.mjs.map} +1 -1
  43. package/dist/_chunks/{Relations-DdlstXTu.js → Relations-CXy88hPa.js} +72 -42
  44. package/dist/_chunks/Relations-CXy88hPa.js.map +1 -0
  45. package/dist/_chunks/{Relations-D6NAlnsl.mjs → Relations-DqHS7-Cx.mjs} +72 -41
  46. package/dist/_chunks/Relations-DqHS7-Cx.mjs.map +1 -0
  47. package/dist/_chunks/{en-Cf41pH5f.js → en-Bm0D0IWz.js} +9 -9
  48. package/dist/_chunks/{en-Cf41pH5f.js.map → en-Bm0D0IWz.js.map} +1 -1
  49. package/dist/_chunks/{en-DCszE74t.mjs → en-DKV44jRb.mjs} +9 -9
  50. package/dist/_chunks/{en-DCszE74t.mjs.map → en-DKV44jRb.mjs.map} +1 -1
  51. package/dist/_chunks/{index-CQos-KS0.js → index-BwWfprNi.js} +1905 -1763
  52. package/dist/_chunks/index-BwWfprNi.js.map +1 -0
  53. package/dist/_chunks/{index-BYSWwHBJ.mjs → index-LwSbWlvf.mjs} +1906 -1764
  54. package/dist/_chunks/index-LwSbWlvf.mjs.map +1 -0
  55. package/dist/_chunks/{layout-0TY7UtKO.mjs → layout-BS7u3JUZ.mjs} +6 -5
  56. package/dist/_chunks/{layout-0TY7UtKO.mjs.map → layout-BS7u3JUZ.mjs.map} +1 -1
  57. package/dist/_chunks/{layout-B4XAqu1v.js → layout-a7hNwceU.js} +7 -7
  58. package/dist/_chunks/{layout-B4XAqu1v.js.map → layout-a7hNwceU.js.map} +1 -1
  59. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  60. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  61. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  62. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  63. package/dist/_chunks/{relations-xZ2tMj1G.js → relations-DedckVWc.js} +3 -7
  64. package/dist/_chunks/relations-DedckVWc.js.map +1 -0
  65. package/dist/_chunks/{relations-DFDWfa0s.mjs → relations-L9TlNEnv.mjs} +3 -7
  66. package/dist/_chunks/relations-L9TlNEnv.mjs.map +1 -0
  67. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  68. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  69. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  70. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  71. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  72. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  73. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  74. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  75. package/dist/admin/index.js +2 -1
  76. package/dist/admin/index.js.map +1 -1
  77. package/dist/admin/index.mjs +3 -2
  78. package/dist/admin/src/exports.d.ts +1 -1
  79. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  80. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  81. package/dist/admin/src/preview/constants.d.ts +1 -0
  82. package/dist/admin/src/preview/index.d.ts +4 -0
  83. package/dist/server/index.js +104 -69
  84. package/dist/server/index.js.map +1 -1
  85. package/dist/server/index.mjs +103 -67
  86. package/dist/server/index.mjs.map +1 -1
  87. package/dist/server/src/bootstrap.d.ts.map +1 -1
  88. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  89. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  90. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  91. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  92. package/dist/server/src/history/services/history.d.ts.map +1 -1
  93. package/dist/server/src/index.d.ts +4 -4
  94. package/dist/server/src/preview/constants.d.ts +2 -0
  95. package/dist/server/src/preview/constants.d.ts.map +1 -0
  96. package/dist/server/src/preview/index.d.ts +4 -0
  97. package/dist/server/src/preview/index.d.ts.map +1 -0
  98. package/dist/server/src/services/document-metadata.d.ts +8 -8
  99. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  100. package/dist/server/src/services/index.d.ts +4 -4
  101. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  102. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  103. package/dist/server/src/utils/index.d.ts +2 -0
  104. package/dist/server/src/utils/index.d.ts.map +1 -1
  105. package/package.json +13 -13
  106. package/dist/_chunks/EditViewPage-CvRUUpVh.mjs.map +0 -1
  107. package/dist/_chunks/EditViewPage-g5TwrgRY.js.map +0 -1
  108. package/dist/_chunks/Field-ncdInvxS.js.map +0 -1
  109. package/dist/_chunks/Field-reyvfnop.mjs.map +0 -1
  110. package/dist/_chunks/Form-BJ7bYiUx.js.map +0 -1
  111. package/dist/_chunks/Form-DoMGsYxH.mjs.map +0 -1
  112. package/dist/_chunks/History-BseDJOrj.mjs.map +0 -1
  113. package/dist/_chunks/History-pbhkxIrf.js.map +0 -1
  114. package/dist/_chunks/ListViewPage-Dymsvnv6.js.map +0 -1
  115. package/dist/_chunks/ListViewPage-lQ-VLV2G.mjs.map +0 -1
  116. package/dist/_chunks/Relations-D6NAlnsl.mjs.map +0 -1
  117. package/dist/_chunks/Relations-DdlstXTu.js.map +0 -1
  118. package/dist/_chunks/index-BYSWwHBJ.mjs.map +0 -1
  119. package/dist/_chunks/index-CQos-KS0.js.map +0 -1
  120. package/dist/_chunks/relations-DFDWfa0s.mjs.map +0 -1
  121. package/dist/_chunks/relations-xZ2tMj1G.js.map +0 -1
  122. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  123. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  124. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  125. package/strapi-server.js +0 -3
@@ -4,6 +4,7 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
5
  const React = require("react");
6
6
  const designSystem = require("@strapi/design-system");
7
+ const mapValues = require("lodash/fp/mapValues");
7
8
  const reactIntl = require("react-intl");
8
9
  const reactRouterDom = require("react-router-dom");
9
10
  const yup = require("yup");
@@ -14,8 +15,7 @@ const qs = require("qs");
14
15
  const toolkit = require("@reduxjs/toolkit");
15
16
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
17
  function _interopNamespace(e) {
17
- if (e && e.__esModule)
18
- return e;
18
+ if (e && e.__esModule) return e;
19
19
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
20
  if (e) {
21
21
  for (const k in e) {
@@ -32,15 +32,23 @@ function _interopNamespace(e) {
32
32
  return Object.freeze(n);
33
33
  }
34
34
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
35
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
36
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
37
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
38
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
38
39
  const v = glob[path];
39
40
  if (v) {
40
41
  return typeof v === "function" ? v() : Promise.resolve(v);
41
42
  }
42
43
  return new Promise((_, reject) => {
43
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
44
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
45
+ reject.bind(
46
+ null,
47
+ new Error(
48
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
49
+ )
50
+ )
51
+ );
44
52
  });
45
53
  };
46
54
  const PLUGIN_ID = "content-manager";
@@ -121,6 +129,7 @@ const DocumentRBAC = ({ children, permissions }) => {
121
129
  if (!slug) {
122
130
  throw new Error("Cannot find the slug param in the URL");
123
131
  }
132
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
124
133
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
125
134
  const contentTypePermissions = React__namespace.useMemo(() => {
126
135
  const contentTypePermissions2 = userPermissions.filter(
@@ -131,7 +140,14 @@ const DocumentRBAC = ({ children, permissions }) => {
131
140
  return { ...acc, [action]: [permission] };
132
141
  }, {});
133
142
  }, [slug, userPermissions]);
134
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
143
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
144
+ contentTypePermissions,
145
+ permissions ?? void 0,
146
+ // TODO: useRBAC context should be typed and built differently
147
+ // We are passing raw query as context to the hook so that it can
148
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
149
+ rawQuery
150
+ );
135
151
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
136
152
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
137
153
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -283,7 +299,7 @@ const documentApi = contentManagerApi.injectEndpoints({
283
299
  */
284
300
  getAllDocuments: builder.query({
285
301
  query: ({ model, params }) => ({
286
- url: `/content-manager/collection-types/${model}`,
302
+ url: `/content-manager/collection-types/${model}${params ? `?${params}` : ""}`,
287
303
  method: "GET",
288
304
  config: {
289
305
  params
@@ -465,8 +481,7 @@ const {
465
481
  useUnpublishManyDocumentsMutation
466
482
  } = documentApi;
467
483
  const buildValidParams = (query) => {
468
- if (!query)
469
- return query;
484
+ if (!query) return query;
470
485
  const { plugins: _, ...validQueryParams } = {
471
486
  ...query,
472
487
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -482,6 +497,24 @@ const buildValidParams = (query) => {
482
497
  const isBaseQueryError = (error) => {
483
498
  return error.name !== void 0;
484
499
  };
500
+ const arrayValidator = (attribute, options) => ({
501
+ message: strapiAdmin.translatedErrors.required,
502
+ test(value) {
503
+ if (options.status === "draft") {
504
+ return true;
505
+ }
506
+ if (!attribute.required) {
507
+ return true;
508
+ }
509
+ if (!value) {
510
+ return false;
511
+ }
512
+ if (Array.isArray(value) && value.length === 0) {
513
+ return false;
514
+ }
515
+ return true;
516
+ }
517
+ });
485
518
  const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
486
519
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
487
520
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -489,6 +522,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
489
522
  return acc;
490
523
  }
491
524
  const validations = [
525
+ addNullableValidation,
492
526
  addRequiredValidation,
493
527
  addMinLengthValidation,
494
528
  addMaxLengthValidation,
@@ -505,12 +539,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
505
539
  ...acc,
506
540
  [name]: transformSchema(
507
541
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
508
- )
542
+ ).test(arrayValidator(attribute, options))
509
543
  };
510
544
  } else {
511
545
  return {
512
546
  ...acc,
513
- [name]: transformSchema(createModelSchema(attributes3))
547
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
514
548
  };
515
549
  }
516
550
  }
@@ -532,7 +566,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
532
566
  }
533
567
  )
534
568
  )
535
- )
569
+ ).test(arrayValidator(attribute, options))
536
570
  };
537
571
  case "relation":
538
572
  return {
@@ -544,7 +578,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
544
578
  } else if (Array.isArray(value)) {
545
579
  return yup__namespace.array().of(
546
580
  yup__namespace.object().shape({
547
- id: yup__namespace.string().required()
581
+ id: yup__namespace.number().required()
548
582
  })
549
583
  );
550
584
  } else if (typeof value === "object") {
@@ -630,17 +664,17 @@ const nullableSchema = (schema) => {
630
664
  schema
631
665
  );
632
666
  };
667
+ const addNullableValidation = () => (schema) => {
668
+ return nullableSchema(schema);
669
+ };
633
670
  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);
671
+ if (options.status === "draft" || !attribute.required) {
672
+ return schema;
639
673
  }
640
- if (attribute.required && attribute.type !== "relation") {
674
+ if (attribute.required && "required" in schema) {
641
675
  return schema.required(strapiAdmin.translatedErrors.required);
642
676
  }
643
- return nullableSchema(schema);
677
+ return schema;
644
678
  };
645
679
  const addMinLengthValidation = (attribute, options) => (schema) => {
646
680
  if (options.status === "draft") {
@@ -668,31 +702,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
668
702
  return schema;
669
703
  };
670
704
  const addMinValidation = (attribute, options) => (schema) => {
671
- if ("min" in attribute) {
705
+ if (options.status === "draft") {
706
+ return schema;
707
+ }
708
+ if ("min" in attribute && "min" in schema) {
672
709
  const min = toInteger(attribute.min);
673
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
- if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
- return schema.test(
676
- "custom-min",
677
- {
678
- ...strapiAdmin.translatedErrors.min,
679
- values: {
680
- min: attribute.min
681
- }
682
- },
683
- (value) => {
684
- if (!value) {
685
- return true;
686
- }
687
- if (Array.isArray(value) && value.length === 0) {
688
- return true;
689
- }
690
- return value.length >= min;
691
- }
692
- );
693
- }
694
- }
695
- if ("min" in schema && min) {
710
+ if (min) {
696
711
  return schema.min(min, {
697
712
  ...strapiAdmin.translatedErrors.min,
698
713
  values: {
@@ -810,19 +825,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
810
825
  }, {});
811
826
  return componentsByKey;
812
827
  };
813
- const useDocument = (args, opts) => {
828
+ const HOOKS = {
829
+ /**
830
+ * Hook that allows to mutate the displayed headers of the list view table
831
+ * @constant
832
+ * @type {string}
833
+ */
834
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
835
+ /**
836
+ * Hook that allows to mutate the CM's collection types links pre-set filters
837
+ * @constant
838
+ * @type {string}
839
+ */
840
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
841
+ /**
842
+ * Hook that allows to mutate the CM's edit view layout
843
+ * @constant
844
+ * @type {string}
845
+ */
846
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
847
+ /**
848
+ * Hook that allows to mutate the CM's single types links pre-set filters
849
+ * @constant
850
+ * @type {string}
851
+ */
852
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
853
+ };
854
+ const contentTypesApi = contentManagerApi.injectEndpoints({
855
+ endpoints: (builder) => ({
856
+ getContentTypeConfiguration: builder.query({
857
+ query: (uid) => ({
858
+ url: `/content-manager/content-types/${uid}/configuration`,
859
+ method: "GET"
860
+ }),
861
+ transformResponse: (response) => response.data,
862
+ providesTags: (_result, _error, uid) => [
863
+ { type: "ContentTypesConfiguration", id: uid },
864
+ { type: "ContentTypeSettings", id: "LIST" }
865
+ ]
866
+ }),
867
+ getAllContentTypeSettings: builder.query({
868
+ query: () => "/content-manager/content-types-settings",
869
+ transformResponse: (response) => response.data,
870
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
871
+ }),
872
+ updateContentTypeConfiguration: builder.mutation({
873
+ query: ({ uid, ...body }) => ({
874
+ url: `/content-manager/content-types/${uid}/configuration`,
875
+ method: "PUT",
876
+ data: body
877
+ }),
878
+ transformResponse: (response) => response.data,
879
+ invalidatesTags: (_result, _error, { uid }) => [
880
+ { type: "ContentTypesConfiguration", id: uid },
881
+ { type: "ContentTypeSettings", id: "LIST" },
882
+ // Is this necessary?
883
+ { type: "InitialData" }
884
+ ]
885
+ })
886
+ })
887
+ });
888
+ const {
889
+ useGetContentTypeConfigurationQuery,
890
+ useGetAllContentTypeSettingsQuery,
891
+ useUpdateContentTypeConfigurationMutation
892
+ } = contentTypesApi;
893
+ const checkIfAttributeIsDisplayable = (attribute) => {
894
+ const { type } = attribute;
895
+ if (type === "relation") {
896
+ return !attribute.relation.toLowerCase().includes("morph");
897
+ }
898
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
899
+ };
900
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
901
+ if (!mainFieldName) {
902
+ return void 0;
903
+ }
904
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
905
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
906
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
907
+ );
908
+ return {
909
+ name: mainFieldName,
910
+ type: mainFieldType ?? "string"
911
+ };
912
+ };
913
+ const DEFAULT_SETTINGS = {
914
+ bulkable: false,
915
+ filterable: false,
916
+ searchable: false,
917
+ pagination: false,
918
+ defaultSortBy: "",
919
+ defaultSortOrder: "asc",
920
+ mainField: "id",
921
+ pageSize: 10
922
+ };
923
+ const useDocumentLayout = (model) => {
924
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
925
+ const [{ query }] = strapiAdmin.useQueryParams();
926
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
814
927
  const { toggleNotification } = strapiAdmin.useNotification();
815
928
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
929
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
816
930
  const {
817
- currentData: data,
818
- isLoading: isLoadingDocument,
819
- isFetching: isFetchingDocument,
820
- error
821
- } = useGetDocumentQuery(args, {
822
- ...opts,
823
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
824
- });
825
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
931
+ data,
932
+ isLoading: isLoadingConfigs,
933
+ error,
934
+ isFetching: isFetchingConfigs
935
+ } = useGetContentTypeConfigurationQuery(model);
936
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
826
937
  React__namespace.useEffect(() => {
827
938
  if (error) {
828
939
  toggleNotification({
@@ -830,399 +941,655 @@ const useDocument = (args, opts) => {
830
941
  message: formatAPIError(error)
831
942
  });
832
943
  }
833
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
834
- const validationSchema = React__namespace.useMemo(() => {
835
- if (!schema) {
836
- return null;
837
- }
838
- return createYupSchema(schema.attributes, components);
839
- }, [schema, components]);
840
- const validate = React__namespace.useCallback(
841
- (document) => {
842
- if (!validationSchema) {
843
- throw new Error(
844
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
845
- );
846
- }
847
- try {
848
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
849
- return null;
850
- } catch (error2) {
851
- if (error2 instanceof yup.ValidationError) {
852
- return strapiAdmin.getYupValidationErrors(error2);
853
- }
854
- throw error2;
855
- }
944
+ }, [error, formatAPIError, toggleNotification]);
945
+ const editLayout = React__namespace.useMemo(
946
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
947
+ layout: [],
948
+ components: {},
949
+ metadatas: {},
950
+ options: {},
951
+ settings: DEFAULT_SETTINGS
856
952
  },
857
- [validationSchema]
953
+ [data, isLoading, schemas, schema, components]
954
+ );
955
+ const listLayout = React__namespace.useMemo(() => {
956
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
957
+ layout: [],
958
+ metadatas: {},
959
+ options: {},
960
+ settings: DEFAULT_SETTINGS
961
+ };
962
+ }, [data, isLoading, schemas, schema, components]);
963
+ const { layout: edit } = React__namespace.useMemo(
964
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
965
+ layout: editLayout,
966
+ query
967
+ }),
968
+ [editLayout, query, runHookWaterfall]
858
969
  );
859
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
860
970
  return {
861
- components,
862
- document: data?.data,
863
- meta: data?.meta,
971
+ error,
864
972
  isLoading,
865
- schema,
866
- validate
867
- };
868
- };
869
- const useDoc = () => {
870
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
871
- const [{ query }] = strapiAdmin.useQueryParams();
872
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
873
- if (!collectionType) {
874
- throw new Error("Could not find collectionType in url params");
875
- }
876
- if (!slug) {
877
- throw new Error("Could not find model in url params");
878
- }
879
- return {
880
- collectionType,
881
- model: slug,
882
- id: origin || id === "create" ? void 0 : id,
883
- ...useDocument(
884
- { documentId: origin || id, model: slug, collectionType, params },
885
- {
886
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
887
- }
888
- )
973
+ edit,
974
+ list: listLayout
889
975
  };
890
976
  };
891
- const prefixPluginTranslations = (trad, pluginId) => {
892
- if (!pluginId) {
893
- throw new TypeError("pluginId can't be empty");
894
- }
895
- return Object.keys(trad).reduce((acc, current) => {
896
- acc[`${pluginId}.${current}`] = trad[current];
897
- return acc;
898
- }, {});
899
- };
900
- const getTranslation = (id) => `content-manager.${id}`;
901
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
902
- id: "notification.error",
903
- defaultMessage: "An error occurred, please try again"
977
+ const useDocLayout = () => {
978
+ const { model } = useDoc();
979
+ return useDocumentLayout(model);
904
980
  };
905
- const useDocumentActions = () => {
906
- const { toggleNotification } = strapiAdmin.useNotification();
907
- const { formatMessage } = reactIntl.useIntl();
908
- const { trackUsage } = strapiAdmin.useTracking();
909
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
910
- const navigate = reactRouterDom.useNavigate();
911
- const [deleteDocument] = useDeleteDocumentMutation();
912
- const _delete = React__namespace.useCallback(
913
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
914
- try {
915
- trackUsage("willDeleteEntry", trackerProperty);
916
- const res = await deleteDocument({
917
- collectionType,
918
- model,
919
- documentId,
920
- params
921
- });
922
- if ("error" in res) {
923
- toggleNotification({
924
- type: "danger",
925
- message: formatAPIError(res.error)
926
- });
927
- return { error: res.error };
928
- }
929
- toggleNotification({
930
- type: "success",
931
- message: formatMessage({
932
- id: getTranslation("success.record.delete"),
933
- defaultMessage: "Deleted document"
934
- })
935
- });
936
- trackUsage("didDeleteEntry", trackerProperty);
937
- return res.data;
938
- } catch (err) {
939
- toggleNotification({
940
- type: "danger",
941
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
942
- });
943
- trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
944
- throw err;
981
+ const formatEditLayout = (data, {
982
+ schemas,
983
+ schema,
984
+ components
985
+ }) => {
986
+ let currentPanelIndex = 0;
987
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
988
+ data.contentType.layouts.edit,
989
+ schema?.attributes,
990
+ data.contentType.metadatas,
991
+ { configurations: data.components, schemas: components },
992
+ schemas
993
+ ).reduce((panels, row) => {
994
+ if (row.some((field) => field.type === "dynamiczone")) {
995
+ panels.push([row]);
996
+ currentPanelIndex += 2;
997
+ } else {
998
+ if (!panels[currentPanelIndex]) {
999
+ panels.push([row]);
1000
+ } else {
1001
+ panels[currentPanelIndex].push(row);
945
1002
  }
946
- },
947
- [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
948
- );
949
- const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
950
- const deleteMany = React__namespace.useCallback(
951
- async ({ model, documentIds, params }) => {
952
- try {
953
- trackUsage("willBulkDeleteEntries");
954
- const res = await deleteManyDocuments({
955
- model,
956
- documentIds,
957
- params
958
- });
959
- if ("error" in res) {
960
- toggleNotification({
961
- type: "danger",
962
- message: formatAPIError(res.error)
963
- });
964
- return { error: res.error };
1003
+ }
1004
+ return panels;
1005
+ }, []);
1006
+ const componentEditAttributes = Object.entries(data.components).reduce(
1007
+ (acc, [uid, configuration]) => {
1008
+ acc[uid] = {
1009
+ layout: convertEditLayoutToFieldLayouts(
1010
+ configuration.layouts.edit,
1011
+ components[uid].attributes,
1012
+ configuration.metadatas,
1013
+ { configurations: data.components, schemas: components }
1014
+ ),
1015
+ settings: {
1016
+ ...configuration.settings,
1017
+ icon: components[uid].info.icon,
1018
+ displayName: components[uid].info.displayName
965
1019
  }
966
- toggleNotification({
967
- type: "success",
968
- title: formatMessage({
969
- id: getTranslation("success.records.delete"),
970
- defaultMessage: "Successfully deleted."
971
- }),
972
- message: ""
973
- });
974
- trackUsage("didBulkDeleteEntries");
975
- return res.data;
976
- } catch (err) {
977
- toggleNotification({
978
- type: "danger",
979
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
980
- });
981
- trackUsage("didNotBulkDeleteEntries");
982
- throw err;
983
- }
1020
+ };
1021
+ return acc;
984
1022
  },
985
- [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1023
+ {}
986
1024
  );
987
- const [discardDocument] = useDiscardDocumentMutation();
988
- const discard = React__namespace.useCallback(
989
- async ({ collectionType, model, documentId, params }) => {
990
- try {
991
- const res = await discardDocument({
992
- collectionType,
993
- model,
994
- documentId,
995
- params
996
- });
997
- if ("error" in res) {
998
- toggleNotification({
999
- type: "danger",
1000
- message: formatAPIError(res.error)
1001
- });
1002
- return { error: res.error };
1003
- }
1004
- toggleNotification({
1005
- type: "success",
1006
- message: formatMessage({
1007
- id: "content-manager.success.record.discard",
1008
- defaultMessage: "Changes discarded"
1009
- })
1010
- });
1011
- return res.data;
1012
- } catch (err) {
1013
- toggleNotification({
1014
- type: "danger",
1015
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1016
- });
1017
- throw err;
1018
- }
1025
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1026
+ (acc, [attribute, metadata]) => {
1027
+ return {
1028
+ ...acc,
1029
+ [attribute]: metadata.edit
1030
+ };
1019
1031
  },
1020
- [discardDocument, formatAPIError, formatMessage, toggleNotification]
1032
+ {}
1021
1033
  );
1022
- const [publishDocument] = usePublishDocumentMutation();
1023
- const publish = React__namespace.useCallback(
1024
- async ({ collectionType, model, documentId, params }, data) => {
1025
- try {
1026
- trackUsage("willPublishEntry");
1027
- const res = await publishDocument({
1028
- collectionType,
1029
- model,
1030
- documentId,
1031
- data,
1032
- params
1033
- });
1034
- if ("error" in res) {
1035
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1036
- return { error: res.error };
1037
- }
1038
- trackUsage("didPublishEntry");
1039
- toggleNotification({
1040
- type: "success",
1041
- message: formatMessage({
1042
- id: getTranslation("success.record.publish"),
1043
- defaultMessage: "Published document"
1044
- })
1045
- });
1046
- return res.data;
1047
- } catch (err) {
1048
- toggleNotification({
1049
- type: "danger",
1050
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1051
- });
1052
- throw err;
1053
- }
1034
+ return {
1035
+ layout: panelledEditAttributes,
1036
+ components: componentEditAttributes,
1037
+ metadatas: editMetadatas,
1038
+ settings: {
1039
+ ...data.contentType.settings,
1040
+ displayName: schema?.info.displayName
1054
1041
  },
1055
- [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1056
- );
1057
- const [publishManyDocuments] = usePublishManyDocumentsMutation();
1058
- const publishMany = React__namespace.useCallback(
1059
- async ({ model, documentIds, params }) => {
1060
- try {
1061
- const res = await publishManyDocuments({
1062
- model,
1063
- documentIds,
1064
- params
1065
- });
1066
- if ("error" in res) {
1067
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1068
- return { error: res.error };
1069
- }
1070
- toggleNotification({
1071
- type: "success",
1072
- message: formatMessage({
1073
- id: getTranslation("success.record.publish"),
1074
- defaultMessage: "Published document"
1075
- })
1076
- });
1077
- return res.data;
1078
- } catch (err) {
1079
- toggleNotification({
1080
- type: "danger",
1081
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1082
- });
1083
- throw err;
1042
+ options: {
1043
+ ...schema?.options,
1044
+ ...schema?.pluginOptions,
1045
+ ...data.contentType.options
1046
+ }
1047
+ };
1048
+ };
1049
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1050
+ return rows.map(
1051
+ (row) => row.map((field) => {
1052
+ const attribute = attributes[field.name];
1053
+ if (!attribute) {
1054
+ return null;
1084
1055
  }
1085
- },
1086
- [
1087
- // trackUsage,
1088
- publishManyDocuments,
1089
- toggleNotification,
1090
- formatMessage,
1091
- formatAPIError
1092
- ]
1056
+ const { edit: metadata } = metadatas[field.name];
1057
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1058
+ return {
1059
+ attribute,
1060
+ disabled: !metadata.editable,
1061
+ hint: metadata.description,
1062
+ label: metadata.label ?? "",
1063
+ name: field.name,
1064
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1065
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1066
+ schemas,
1067
+ components: components?.schemas ?? {}
1068
+ }),
1069
+ placeholder: metadata.placeholder ?? "",
1070
+ required: attribute.required ?? false,
1071
+ size: field.size,
1072
+ unique: "unique" in attribute ? attribute.unique : false,
1073
+ visible: metadata.visible ?? true,
1074
+ type: attribute.type
1075
+ };
1076
+ }).filter((field) => field !== null)
1093
1077
  );
1094
- const [updateDocument] = useUpdateDocumentMutation();
1095
- const update = React__namespace.useCallback(
1096
- async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1097
- try {
1098
- trackUsage("willEditEntry", trackerProperty);
1099
- const res = await updateDocument({
1100
- collectionType,
1101
- model,
1102
- documentId,
1103
- data,
1104
- params
1105
- });
1106
- if ("error" in res) {
1107
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1108
- trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1109
- return { error: res.error };
1078
+ };
1079
+ const formatListLayout = (data, {
1080
+ schemas,
1081
+ schema,
1082
+ components
1083
+ }) => {
1084
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1085
+ (acc, [attribute, metadata]) => {
1086
+ return {
1087
+ ...acc,
1088
+ [attribute]: metadata.list
1089
+ };
1090
+ },
1091
+ {}
1092
+ );
1093
+ const listAttributes = convertListLayoutToFieldLayouts(
1094
+ data.contentType.layouts.list,
1095
+ schema?.attributes,
1096
+ listMetadatas,
1097
+ { configurations: data.components, schemas: components },
1098
+ schemas
1099
+ );
1100
+ return {
1101
+ layout: listAttributes,
1102
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1103
+ metadatas: listMetadatas,
1104
+ options: {
1105
+ ...schema?.options,
1106
+ ...schema?.pluginOptions,
1107
+ ...data.contentType.options
1108
+ }
1109
+ };
1110
+ };
1111
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1112
+ return columns.map((name) => {
1113
+ const attribute = attributes[name];
1114
+ if (!attribute) {
1115
+ return null;
1116
+ }
1117
+ const metadata = metadatas[name];
1118
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1119
+ return {
1120
+ attribute,
1121
+ label: metadata.label ?? "",
1122
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1123
+ schemas,
1124
+ components: components?.schemas ?? {}
1125
+ }),
1126
+ name,
1127
+ searchable: metadata.searchable ?? true,
1128
+ sortable: metadata.sortable ?? true
1129
+ };
1130
+ }).filter((field) => field !== null);
1131
+ };
1132
+ const useDocument = (args, opts) => {
1133
+ const { toggleNotification } = strapiAdmin.useNotification();
1134
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1135
+ const {
1136
+ currentData: data,
1137
+ isLoading: isLoadingDocument,
1138
+ isFetching: isFetchingDocument,
1139
+ error
1140
+ } = useGetDocumentQuery(args, {
1141
+ ...opts,
1142
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1143
+ });
1144
+ const {
1145
+ components,
1146
+ schema,
1147
+ schemas,
1148
+ isLoading: isLoadingSchema
1149
+ } = useContentTypeSchema(args.model);
1150
+ React__namespace.useEffect(() => {
1151
+ if (error) {
1152
+ toggleNotification({
1153
+ type: "danger",
1154
+ message: formatAPIError(error)
1155
+ });
1156
+ }
1157
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1158
+ const validationSchema = React__namespace.useMemo(() => {
1159
+ if (!schema) {
1160
+ return null;
1161
+ }
1162
+ return createYupSchema(schema.attributes, components);
1163
+ }, [schema, components]);
1164
+ const validate = React__namespace.useCallback(
1165
+ (document) => {
1166
+ if (!validationSchema) {
1167
+ throw new Error(
1168
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1169
+ );
1170
+ }
1171
+ try {
1172
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1173
+ return null;
1174
+ } catch (error2) {
1175
+ if (error2 instanceof yup.ValidationError) {
1176
+ return strapiAdmin.getYupValidationErrors(error2);
1110
1177
  }
1111
- trackUsage("didEditEntry", trackerProperty);
1112
- toggleNotification({
1113
- type: "success",
1114
- message: formatMessage({
1115
- id: getTranslation("success.record.save"),
1116
- defaultMessage: "Saved document"
1117
- })
1118
- });
1119
- return res.data;
1120
- } catch (err) {
1121
- trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1122
- toggleNotification({
1123
- type: "danger",
1124
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1125
- });
1126
- throw err;
1178
+ throw error2;
1127
1179
  }
1128
1180
  },
1129
- [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1181
+ [validationSchema]
1130
1182
  );
1131
- const [unpublishDocument] = useUnpublishDocumentMutation();
1132
- const unpublish = React__namespace.useCallback(
1133
- async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1183
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1184
+ const hasError = !!error;
1185
+ return {
1186
+ components,
1187
+ document: data?.data,
1188
+ meta: data?.meta,
1189
+ isLoading,
1190
+ hasError,
1191
+ schema,
1192
+ schemas,
1193
+ validate
1194
+ };
1195
+ };
1196
+ const useDoc = () => {
1197
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1198
+ const [{ query }] = strapiAdmin.useQueryParams();
1199
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1200
+ if (!collectionType) {
1201
+ throw new Error("Could not find collectionType in url params");
1202
+ }
1203
+ if (!slug) {
1204
+ throw new Error("Could not find model in url params");
1205
+ }
1206
+ const document = useDocument(
1207
+ { documentId: origin || id, model: slug, collectionType, params },
1208
+ {
1209
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1210
+ }
1211
+ );
1212
+ const returnId = origin || id === "create" ? void 0 : id;
1213
+ return {
1214
+ collectionType,
1215
+ model: slug,
1216
+ id: returnId,
1217
+ ...document
1218
+ };
1219
+ };
1220
+ const useContentManagerContext = () => {
1221
+ const {
1222
+ collectionType,
1223
+ model,
1224
+ id,
1225
+ components,
1226
+ isLoading: isLoadingDoc,
1227
+ schema,
1228
+ schemas
1229
+ } = useDoc();
1230
+ const layout = useDocumentLayout(model);
1231
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1232
+ const isSingleType = collectionType === SINGLE_TYPES;
1233
+ const slug = model;
1234
+ const isCreatingEntry = id === "create";
1235
+ useContentTypeSchema();
1236
+ const isLoading = isLoadingDoc || layout.isLoading;
1237
+ const error = layout.error;
1238
+ return {
1239
+ error,
1240
+ isLoading,
1241
+ // Base metadata
1242
+ model,
1243
+ collectionType,
1244
+ id,
1245
+ slug,
1246
+ isCreatingEntry,
1247
+ isSingleType,
1248
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1249
+ // All schema infos
1250
+ components,
1251
+ contentType: schema,
1252
+ contentTypes: schemas,
1253
+ // Form state
1254
+ form,
1255
+ // layout infos
1256
+ layout
1257
+ };
1258
+ };
1259
+ const prefixPluginTranslations = (trad, pluginId) => {
1260
+ return Object.keys(trad).reduce((acc, current) => {
1261
+ acc[`${pluginId}.${current}`] = trad[current];
1262
+ return acc;
1263
+ }, {});
1264
+ };
1265
+ const getTranslation = (id) => `content-manager.${id}`;
1266
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1267
+ id: "notification.error",
1268
+ defaultMessage: "An error occurred, please try again"
1269
+ };
1270
+ const useDocumentActions = () => {
1271
+ const { toggleNotification } = strapiAdmin.useNotification();
1272
+ const { formatMessage } = reactIntl.useIntl();
1273
+ const { trackUsage } = strapiAdmin.useTracking();
1274
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1275
+ const navigate = reactRouterDom.useNavigate();
1276
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1277
+ const [deleteDocument] = useDeleteDocumentMutation();
1278
+ const _delete = React__namespace.useCallback(
1279
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1134
1280
  try {
1135
- trackUsage("willUnpublishEntry");
1136
- const res = await unpublishDocument({
1281
+ trackUsage("willDeleteEntry", trackerProperty);
1282
+ const res = await deleteDocument({
1137
1283
  collectionType,
1138
1284
  model,
1139
1285
  documentId,
1140
- params,
1141
- data: {
1142
- discardDraft
1143
- }
1286
+ params
1144
1287
  });
1145
1288
  if ("error" in res) {
1146
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1289
+ toggleNotification({
1290
+ type: "danger",
1291
+ message: formatAPIError(res.error)
1292
+ });
1147
1293
  return { error: res.error };
1148
1294
  }
1149
- trackUsage("didUnpublishEntry");
1150
1295
  toggleNotification({
1151
1296
  type: "success",
1152
1297
  message: formatMessage({
1153
- id: getTranslation("success.record.unpublish"),
1154
- defaultMessage: "Unpublished document"
1298
+ id: getTranslation("success.record.delete"),
1299
+ defaultMessage: "Deleted document"
1155
1300
  })
1156
1301
  });
1302
+ trackUsage("didDeleteEntry", trackerProperty);
1157
1303
  return res.data;
1158
1304
  } catch (err) {
1159
1305
  toggleNotification({
1160
1306
  type: "danger",
1161
1307
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1162
1308
  });
1309
+ trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
1163
1310
  throw err;
1164
1311
  }
1165
1312
  },
1166
- [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1313
+ [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
1167
1314
  );
1168
- const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1169
- const unpublishMany = React__namespace.useCallback(
1315
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1316
+ const deleteMany = React__namespace.useCallback(
1170
1317
  async ({ model, documentIds, params }) => {
1171
1318
  try {
1172
- trackUsage("willBulkUnpublishEntries");
1173
- const res = await unpublishManyDocuments({
1319
+ trackUsage("willBulkDeleteEntries");
1320
+ const res = await deleteManyDocuments({
1174
1321
  model,
1175
1322
  documentIds,
1176
1323
  params
1177
1324
  });
1178
1325
  if ("error" in res) {
1179
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1326
+ toggleNotification({
1327
+ type: "danger",
1328
+ message: formatAPIError(res.error)
1329
+ });
1180
1330
  return { error: res.error };
1181
1331
  }
1182
- trackUsage("didBulkUnpublishEntries");
1183
1332
  toggleNotification({
1184
1333
  type: "success",
1185
1334
  title: formatMessage({
1186
- id: getTranslation("success.records.unpublish"),
1187
- defaultMessage: "Successfully unpublished."
1335
+ id: getTranslation("success.records.delete"),
1336
+ defaultMessage: "Successfully deleted."
1188
1337
  }),
1189
1338
  message: ""
1190
1339
  });
1340
+ trackUsage("didBulkDeleteEntries");
1191
1341
  return res.data;
1192
1342
  } catch (err) {
1193
1343
  toggleNotification({
1194
1344
  type: "danger",
1195
1345
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1196
1346
  });
1197
- trackUsage("didNotBulkUnpublishEntries");
1347
+ trackUsage("didNotBulkDeleteEntries");
1198
1348
  throw err;
1199
1349
  }
1200
1350
  },
1201
- [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1351
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1202
1352
  );
1203
- const [createDocument] = useCreateDocumentMutation();
1204
- const create = React__namespace.useCallback(
1205
- async ({ model, params }, data, trackerProperty) => {
1353
+ const [discardDocument] = useDiscardDocumentMutation();
1354
+ const discard = React__namespace.useCallback(
1355
+ async ({ collectionType, model, documentId, params }) => {
1206
1356
  try {
1207
- const res = await createDocument({
1357
+ const res = await discardDocument({
1358
+ collectionType,
1208
1359
  model,
1209
- data,
1360
+ documentId,
1210
1361
  params
1211
1362
  });
1212
1363
  if ("error" in res) {
1213
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1214
- trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1364
+ toggleNotification({
1365
+ type: "danger",
1366
+ message: formatAPIError(res.error)
1367
+ });
1215
1368
  return { error: res.error };
1216
1369
  }
1217
- trackUsage("didCreateEntry", trackerProperty);
1218
1370
  toggleNotification({
1219
1371
  type: "success",
1220
1372
  message: formatMessage({
1221
- id: getTranslation("success.record.save"),
1222
- defaultMessage: "Saved document"
1373
+ id: "content-manager.success.record.discard",
1374
+ defaultMessage: "Changes discarded"
1223
1375
  })
1224
1376
  });
1225
1377
  return res.data;
1378
+ } catch (err) {
1379
+ toggleNotification({
1380
+ type: "danger",
1381
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1382
+ });
1383
+ throw err;
1384
+ }
1385
+ },
1386
+ [discardDocument, formatAPIError, formatMessage, toggleNotification]
1387
+ );
1388
+ const [publishDocument] = usePublishDocumentMutation();
1389
+ const publish = React__namespace.useCallback(
1390
+ async ({ collectionType, model, documentId, params }, data) => {
1391
+ try {
1392
+ trackUsage("willPublishEntry");
1393
+ const res = await publishDocument({
1394
+ collectionType,
1395
+ model,
1396
+ documentId,
1397
+ data,
1398
+ params
1399
+ });
1400
+ if ("error" in res) {
1401
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1402
+ return { error: res.error };
1403
+ }
1404
+ trackUsage("didPublishEntry");
1405
+ toggleNotification({
1406
+ type: "success",
1407
+ message: formatMessage({
1408
+ id: getTranslation("success.record.publish"),
1409
+ defaultMessage: "Published document"
1410
+ })
1411
+ });
1412
+ return res.data;
1413
+ } catch (err) {
1414
+ toggleNotification({
1415
+ type: "danger",
1416
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1417
+ });
1418
+ throw err;
1419
+ }
1420
+ },
1421
+ [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1422
+ );
1423
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1424
+ const publishMany = React__namespace.useCallback(
1425
+ async ({ model, documentIds, params }) => {
1426
+ try {
1427
+ const res = await publishManyDocuments({
1428
+ model,
1429
+ documentIds,
1430
+ params
1431
+ });
1432
+ if ("error" in res) {
1433
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1434
+ return { error: res.error };
1435
+ }
1436
+ toggleNotification({
1437
+ type: "success",
1438
+ message: formatMessage({
1439
+ id: getTranslation("success.record.publish"),
1440
+ defaultMessage: "Published document"
1441
+ })
1442
+ });
1443
+ return res.data;
1444
+ } catch (err) {
1445
+ toggleNotification({
1446
+ type: "danger",
1447
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1448
+ });
1449
+ throw err;
1450
+ }
1451
+ },
1452
+ [
1453
+ // trackUsage,
1454
+ publishManyDocuments,
1455
+ toggleNotification,
1456
+ formatMessage,
1457
+ formatAPIError
1458
+ ]
1459
+ );
1460
+ const [updateDocument] = useUpdateDocumentMutation();
1461
+ const update = React__namespace.useCallback(
1462
+ async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1463
+ try {
1464
+ trackUsage("willEditEntry", trackerProperty);
1465
+ const res = await updateDocument({
1466
+ collectionType,
1467
+ model,
1468
+ documentId,
1469
+ data,
1470
+ params
1471
+ });
1472
+ if ("error" in res) {
1473
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1474
+ trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1475
+ return { error: res.error };
1476
+ }
1477
+ trackUsage("didEditEntry", trackerProperty);
1478
+ toggleNotification({
1479
+ type: "success",
1480
+ message: formatMessage({
1481
+ id: getTranslation("success.record.save"),
1482
+ defaultMessage: "Saved document"
1483
+ })
1484
+ });
1485
+ return res.data;
1486
+ } catch (err) {
1487
+ trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1488
+ toggleNotification({
1489
+ type: "danger",
1490
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1491
+ });
1492
+ throw err;
1493
+ }
1494
+ },
1495
+ [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1496
+ );
1497
+ const [unpublishDocument] = useUnpublishDocumentMutation();
1498
+ const unpublish = React__namespace.useCallback(
1499
+ async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1500
+ try {
1501
+ trackUsage("willUnpublishEntry");
1502
+ const res = await unpublishDocument({
1503
+ collectionType,
1504
+ model,
1505
+ documentId,
1506
+ params,
1507
+ data: {
1508
+ discardDraft
1509
+ }
1510
+ });
1511
+ if ("error" in res) {
1512
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1513
+ return { error: res.error };
1514
+ }
1515
+ trackUsage("didUnpublishEntry");
1516
+ toggleNotification({
1517
+ type: "success",
1518
+ message: formatMessage({
1519
+ id: getTranslation("success.record.unpublish"),
1520
+ defaultMessage: "Unpublished document"
1521
+ })
1522
+ });
1523
+ return res.data;
1524
+ } catch (err) {
1525
+ toggleNotification({
1526
+ type: "danger",
1527
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1528
+ });
1529
+ throw err;
1530
+ }
1531
+ },
1532
+ [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1533
+ );
1534
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1535
+ const unpublishMany = React__namespace.useCallback(
1536
+ async ({ model, documentIds, params }) => {
1537
+ try {
1538
+ trackUsage("willBulkUnpublishEntries");
1539
+ const res = await unpublishManyDocuments({
1540
+ model,
1541
+ documentIds,
1542
+ params
1543
+ });
1544
+ if ("error" in res) {
1545
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1546
+ return { error: res.error };
1547
+ }
1548
+ trackUsage("didBulkUnpublishEntries");
1549
+ toggleNotification({
1550
+ type: "success",
1551
+ title: formatMessage({
1552
+ id: getTranslation("success.records.unpublish"),
1553
+ defaultMessage: "Successfully unpublished."
1554
+ }),
1555
+ message: ""
1556
+ });
1557
+ return res.data;
1558
+ } catch (err) {
1559
+ toggleNotification({
1560
+ type: "danger",
1561
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1562
+ });
1563
+ trackUsage("didNotBulkUnpublishEntries");
1564
+ throw err;
1565
+ }
1566
+ },
1567
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1568
+ );
1569
+ const [createDocument] = useCreateDocumentMutation();
1570
+ const create = React__namespace.useCallback(
1571
+ async ({ model, params }, data, trackerProperty) => {
1572
+ try {
1573
+ const res = await createDocument({
1574
+ model,
1575
+ data,
1576
+ params
1577
+ });
1578
+ if ("error" in res) {
1579
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1580
+ trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1581
+ return { error: res.error };
1582
+ }
1583
+ trackUsage("didCreateEntry", trackerProperty);
1584
+ toggleNotification({
1585
+ type: "success",
1586
+ message: formatMessage({
1587
+ id: getTranslation("success.record.save"),
1588
+ defaultMessage: "Saved document"
1589
+ })
1590
+ });
1591
+ setCurrentStep("contentManager.success");
1592
+ return res.data;
1226
1593
  } catch (err) {
1227
1594
  toggleNotification({
1228
1595
  type: "danger",
@@ -1324,7 +1691,7 @@ const useDocumentActions = () => {
1324
1691
  };
1325
1692
  };
1326
1693
  const ProtectedHistoryPage = React.lazy(
1327
- () => Promise.resolve().then(() => require("./History-pbhkxIrf.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1694
+ () => Promise.resolve().then(() => require("./History-B1sa22d-.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1328
1695
  );
1329
1696
  const routes$1 = [
1330
1697
  {
@@ -1337,31 +1704,31 @@ const routes$1 = [
1337
1704
  }
1338
1705
  ];
1339
1706
  const ProtectedEditViewPage = React.lazy(
1340
- () => Promise.resolve().then(() => require("./EditViewPage-g5TwrgRY.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1707
+ () => Promise.resolve().then(() => require("./EditViewPage-DxszpwJd.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1341
1708
  );
1342
1709
  const ProtectedListViewPage = React.lazy(
1343
- () => Promise.resolve().then(() => require("./ListViewPage-Dymsvnv6.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1710
+ () => Promise.resolve().then(() => require("./ListViewPage-D7jZkQ1q.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1344
1711
  );
1345
1712
  const ProtectedListConfiguration = React.lazy(
1346
- () => Promise.resolve().then(() => require("./ListConfigurationPage-Bna8zfjr.js")).then((mod) => ({
1713
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-CYWB9ZNc.js")).then((mod) => ({
1347
1714
  default: mod.ProtectedListConfiguration
1348
1715
  }))
1349
1716
  );
1350
1717
  const ProtectedEditConfigurationPage = React.lazy(
1351
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CeL712KW.js")).then((mod) => ({
1718
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-BoY4_TQp.js")).then((mod) => ({
1352
1719
  default: mod.ProtectedEditConfigurationPage
1353
1720
  }))
1354
1721
  );
1355
1722
  const ProtectedComponentConfigurationPage = React.lazy(
1356
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-D_g11bYV.js")).then((mod) => ({
1723
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-CyzIs3Wp.js")).then((mod) => ({
1357
1724
  default: mod.ProtectedComponentConfigurationPage
1358
1725
  }))
1359
1726
  );
1360
1727
  const NoPermissions = React.lazy(
1361
- () => Promise.resolve().then(() => require("./NoPermissionsPage-BOwB6hki.js")).then((mod) => ({ default: mod.NoPermissions }))
1728
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-5BRSh_ql.js")).then((mod) => ({ default: mod.NoPermissions }))
1362
1729
  );
1363
1730
  const NoContentType = React.lazy(
1364
- () => Promise.resolve().then(() => require("./NoContentTypePage-B4t_OsDR.js")).then((mod) => ({ default: mod.NoContentType }))
1731
+ () => Promise.resolve().then(() => require("./NoContentTypePage-C-eluJ5b.js")).then((mod) => ({ default: mod.NoContentType }))
1365
1732
  );
1366
1733
  const CollectionTypePages = () => {
1367
1734
  const { collectionType } = reactRouterDom.useParams();
@@ -1426,1045 +1793,738 @@ const DocumentActions = ({ actions: actions2 }) => {
1426
1793
  /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
1427
1794
  restActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
1428
1795
  DocumentActionsMenu,
1429
- {
1430
- actions: restActions,
1431
- label: formatMessage({
1432
- id: "content-manager.containers.edit.panels.default.more-actions",
1433
- defaultMessage: "More document actions"
1434
- })
1435
- }
1436
- ) : null
1437
- ] }),
1438
- secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
1439
- DocumentActionButton,
1440
- {
1441
- ...secondaryAction,
1442
- variant: secondaryAction.variant || "secondary"
1443
- }
1444
- ) : null
1445
- ] });
1446
- };
1447
- const DocumentActionButton = (action) => {
1448
- const [dialogId, setDialogId] = React__namespace.useState(null);
1449
- const { toggleNotification } = strapiAdmin.useNotification();
1450
- const handleClick = (action2) => async (e) => {
1451
- const { onClick = () => false, dialog, id } = action2;
1452
- const muteDialog = await onClick(e);
1453
- if (dialog && !muteDialog) {
1454
- switch (dialog.type) {
1455
- case "notification":
1456
- toggleNotification({
1457
- title: dialog.title,
1458
- message: dialog.content,
1459
- type: dialog.status,
1460
- timeout: dialog.timeout,
1461
- onClose: dialog.onClose
1462
- });
1463
- break;
1464
- case "dialog":
1465
- case "modal":
1466
- e.preventDefault();
1467
- setDialogId(id);
1468
- }
1469
- }
1470
- };
1471
- const handleClose = () => {
1472
- setDialogId(null);
1473
- };
1474
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1475
- /* @__PURE__ */ jsxRuntime.jsx(
1476
- designSystem.Button,
1477
- {
1478
- flex: "auto",
1479
- startIcon: action.icon,
1480
- disabled: action.disabled,
1481
- onClick: handleClick(action),
1482
- justifyContent: "center",
1483
- variant: action.variant || "default",
1484
- paddingTop: "7px",
1485
- paddingBottom: "7px",
1486
- children: action.label
1487
- }
1488
- ),
1489
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1490
- DocumentActionConfirmDialog,
1491
- {
1492
- ...action.dialog,
1493
- variant: action.dialog?.variant ?? action.variant,
1494
- isOpen: dialogId === action.id,
1495
- onClose: handleClose
1496
- }
1497
- ) : null,
1498
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1499
- DocumentActionModal,
1500
- {
1501
- ...action.dialog,
1502
- onModalClose: handleClose,
1503
- isOpen: dialogId === action.id
1504
- }
1505
- ) : null
1506
- ] });
1507
- };
1508
- const DocumentActionsMenu = ({
1509
- actions: actions2,
1510
- children,
1511
- label,
1512
- variant = "tertiary"
1513
- }) => {
1514
- const [isOpen, setIsOpen] = React__namespace.useState(false);
1515
- const [dialogId, setDialogId] = React__namespace.useState(null);
1516
- const { formatMessage } = reactIntl.useIntl();
1517
- const { toggleNotification } = strapiAdmin.useNotification();
1518
- const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
1519
- const handleClick = (action) => async (e) => {
1520
- const { onClick = () => false, dialog, id } = action;
1521
- const muteDialog = await onClick(e);
1522
- if (dialog && !muteDialog) {
1523
- switch (dialog.type) {
1524
- case "notification":
1525
- toggleNotification({
1526
- title: dialog.title,
1527
- message: dialog.content,
1528
- type: dialog.status,
1529
- timeout: dialog.timeout,
1530
- onClose: dialog.onClose
1531
- });
1532
- break;
1533
- case "dialog":
1534
- case "modal":
1535
- setDialogId(id);
1536
- }
1537
- }
1538
- };
1539
- const handleClose = () => {
1540
- setDialogId(null);
1541
- setIsOpen(false);
1542
- };
1543
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1544
- /* @__PURE__ */ jsxRuntime.jsxs(
1545
- designSystem.Menu.Trigger,
1546
- {
1547
- disabled: isDisabled,
1548
- size: "S",
1549
- endIcon: null,
1550
- paddingTop: "4px",
1551
- paddingLeft: "7px",
1552
- paddingRight: "7px",
1553
- variant,
1554
- children: [
1555
- /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1556
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1557
- id: "content-manager.containers.edit.panels.default.more-actions",
1558
- defaultMessage: "More document actions"
1559
- }) })
1560
- ]
1561
- }
1562
- ),
1563
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1564
- actions2.map((action) => {
1565
- return /* @__PURE__ */ jsxRuntime.jsx(
1566
- designSystem.Menu.Item,
1567
- {
1568
- disabled: action.disabled,
1569
- onSelect: handleClick(action),
1570
- display: "block",
1571
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1572
- /* @__PURE__ */ jsxRuntime.jsxs(
1573
- designSystem.Flex,
1574
- {
1575
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1576
- gap: 2,
1577
- tag: "span",
1578
- children: [
1579
- /* @__PURE__ */ jsxRuntime.jsx(
1580
- designSystem.Flex,
1581
- {
1582
- tag: "span",
1583
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1584
- children: action.icon
1585
- }
1586
- ),
1587
- action.label
1588
- ]
1589
- }
1590
- ),
1591
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1592
- designSystem.Flex,
1593
- {
1594
- alignItems: "center",
1595
- background: "alternative100",
1596
- borderStyle: "solid",
1597
- borderColor: "alternative200",
1598
- borderWidth: "1px",
1599
- height: 5,
1600
- paddingLeft: 2,
1601
- paddingRight: 2,
1602
- hasRadius: true,
1603
- color: "alternative600",
1604
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1605
- }
1606
- )
1607
- ] })
1608
- },
1609
- action.id
1610
- );
1611
- }),
1612
- children
1613
- ] }),
1614
- actions2.map((action) => {
1615
- return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
1616
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1617
- DocumentActionConfirmDialog,
1618
- {
1619
- ...action.dialog,
1620
- variant: action.variant,
1621
- isOpen: dialogId === action.id,
1622
- onClose: handleClose
1623
- }
1624
- ) : null,
1625
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1626
- DocumentActionModal,
1627
- {
1628
- ...action.dialog,
1629
- onModalClose: handleClose,
1630
- isOpen: dialogId === action.id
1631
- }
1632
- ) : null
1633
- ] }, action.id);
1634
- })
1635
- ] });
1636
- };
1637
- const convertActionVariantToColor = (variant = "secondary") => {
1638
- switch (variant) {
1639
- case "danger":
1640
- return "danger600";
1641
- case "secondary":
1642
- return void 0;
1643
- case "success":
1644
- return "success600";
1645
- default:
1646
- return "primary600";
1647
- }
1648
- };
1649
- const convertActionVariantToIconColor = (variant = "secondary") => {
1650
- switch (variant) {
1651
- case "danger":
1652
- return "danger600";
1653
- case "secondary":
1654
- return "neutral500";
1655
- case "success":
1656
- return "success600";
1657
- default:
1658
- return "primary600";
1659
- }
1660
- };
1661
- const DocumentActionConfirmDialog = ({
1662
- onClose,
1663
- onCancel,
1664
- onConfirm,
1665
- title,
1666
- content,
1667
- isOpen,
1668
- variant = "secondary"
1669
- }) => {
1670
- const { formatMessage } = reactIntl.useIntl();
1671
- const handleClose = async () => {
1672
- if (onCancel) {
1673
- await onCancel();
1674
- }
1675
- onClose();
1676
- };
1677
- const handleConfirm = async () => {
1678
- if (onConfirm) {
1679
- await onConfirm();
1680
- }
1681
- onClose();
1682
- };
1683
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1684
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1685
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1686
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1687
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
1688
- id: "app.components.Button.cancel",
1689
- defaultMessage: "Cancel"
1690
- }) }) }),
1691
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1692
- id: "app.components.Button.confirm",
1693
- defaultMessage: "Confirm"
1694
- }) })
1695
- ] })
1696
- ] }) });
1697
- };
1698
- const DocumentActionModal = ({
1699
- isOpen,
1700
- title,
1701
- onClose,
1702
- footer: Footer,
1703
- content: Content,
1704
- onModalClose
1705
- }) => {
1706
- const handleClose = () => {
1707
- if (onClose) {
1708
- onClose();
1709
- }
1710
- onModalClose();
1711
- };
1712
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1713
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1714
- typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1715
- typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1716
- ] }) });
1717
- };
1718
- const PublishAction$1 = ({
1719
- activeTab,
1720
- documentId,
1721
- model,
1722
- collectionType,
1723
- meta,
1724
- document
1725
- }) => {
1726
- const { schema } = useDoc();
1727
- const navigate = reactRouterDom.useNavigate();
1728
- const { toggleNotification } = strapiAdmin.useNotification();
1729
- const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1730
- const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1731
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1732
- const { formatMessage } = reactIntl.useIntl();
1733
- const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1734
- const { publish } = useDocumentActions();
1735
- const [
1736
- countDraftRelations,
1737
- { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1738
- ] = useLazyGetDraftRelationCountQuery();
1739
- const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1740
- const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1741
- const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1742
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1743
- const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
1744
- const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
1745
- const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
1746
- const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1747
- const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1748
- const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1749
- React__namespace.useEffect(() => {
1750
- if (isErrorDraftRelations) {
1751
- toggleNotification({
1752
- type: "danger",
1753
- message: formatMessage({
1754
- id: getTranslation("error.records.fetch-draft-relatons"),
1755
- defaultMessage: "An error occurred while fetching draft relations on this document."
1756
- })
1757
- });
1758
- }
1759
- }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1760
- React__namespace.useEffect(() => {
1761
- const localDraftRelations = /* @__PURE__ */ new Set();
1762
- const extractDraftRelations = (data) => {
1763
- const relations = data.connect || [];
1764
- relations.forEach((relation) => {
1765
- if (relation.status === "draft") {
1766
- localDraftRelations.add(relation.id);
1767
- }
1768
- });
1769
- };
1770
- const traverseAndExtract = (data) => {
1771
- Object.entries(data).forEach(([key, value]) => {
1772
- if (key === "connect" && Array.isArray(value)) {
1773
- extractDraftRelations({ connect: value });
1774
- } else if (typeof value === "object" && value !== null) {
1775
- traverseAndExtract(value);
1776
- }
1777
- });
1778
- };
1779
- if (!documentId || modified) {
1780
- traverseAndExtract(formValues);
1781
- setLocalCountOfDraftRelations(localDraftRelations.size);
1782
- }
1783
- }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1784
- React__namespace.useEffect(() => {
1785
- if (!document || !document.documentId || isListView) {
1786
- return;
1787
- }
1788
- const fetchDraftRelationsCount = async () => {
1789
- const { data, error } = await countDraftRelations({
1790
- collectionType,
1791
- model,
1792
- documentId,
1793
- params
1794
- });
1795
- if (error) {
1796
- throw error;
1797
- }
1798
- if (data) {
1799
- setServerCountOfDraftRelations(data.data);
1800
- }
1801
- };
1802
- fetchDraftRelationsCount();
1803
- }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1804
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1805
- if (!schema?.options?.draftAndPublish) {
1806
- return null;
1807
- }
1808
- const performPublish = async () => {
1809
- setSubmitting(true);
1810
- try {
1811
- const { errors } = await validate();
1812
- if (errors) {
1813
- toggleNotification({
1814
- type: "danger",
1815
- message: formatMessage({
1816
- id: "content-manager.validation.error",
1817
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1796
+ {
1797
+ actions: restActions,
1798
+ label: formatMessage({
1799
+ id: "content-manager.containers.edit.panels.default.more-actions",
1800
+ defaultMessage: "More document actions"
1818
1801
  })
1819
- });
1820
- return;
1802
+ }
1803
+ ) : null
1804
+ ] }),
1805
+ secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
1806
+ DocumentActionButton,
1807
+ {
1808
+ ...secondaryAction,
1809
+ variant: secondaryAction.variant || "secondary"
1821
1810
  }
1822
- const res = await publish(
1823
- {
1824
- collectionType,
1825
- model,
1826
- documentId,
1827
- params
1828
- },
1829
- formValues
1830
- );
1831
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1832
- navigate({
1833
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1834
- search: rawQuery
1835
- });
1836
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
- setErrors(formatValidationErrors(res.error));
1811
+ ) : null
1812
+ ] });
1813
+ };
1814
+ const DocumentActionButton = (action) => {
1815
+ const [dialogId, setDialogId] = React__namespace.useState(null);
1816
+ const { toggleNotification } = strapiAdmin.useNotification();
1817
+ const handleClick = (action2) => async (e) => {
1818
+ const { onClick = () => false, dialog, id } = action2;
1819
+ const muteDialog = await onClick(e);
1820
+ if (dialog && !muteDialog) {
1821
+ switch (dialog.type) {
1822
+ case "notification":
1823
+ toggleNotification({
1824
+ title: dialog.title,
1825
+ message: dialog.content,
1826
+ type: dialog.status,
1827
+ timeout: dialog.timeout,
1828
+ onClose: dialog.onClose
1829
+ });
1830
+ break;
1831
+ case "dialog":
1832
+ case "modal":
1833
+ e.preventDefault();
1834
+ setDialogId(id);
1838
1835
  }
1839
- } finally {
1840
- setSubmitting(false);
1841
1836
  }
1842
1837
  };
1843
- const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1844
- const enableDraftRelationsCount = false;
1845
- const hasDraftRelations = enableDraftRelationsCount;
1846
- return {
1847
- /**
1848
- * Disabled when:
1849
- * - currently if you're cloning a document we don't support publish & clone at the same time.
1850
- * - the form is submitting
1851
- * - the active tab is the published tab
1852
- * - the document is already published & not modified
1853
- * - the document is being created & not modified
1854
- * - the user doesn't have the permission to publish
1855
- */
1856
- disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1857
- label: formatMessage({
1858
- id: "app.utils.publish",
1859
- defaultMessage: "Publish"
1860
- }),
1861
- onClick: async () => {
1862
- await performPublish();
1863
- },
1864
- dialog: hasDraftRelations ? {
1865
- type: "dialog",
1866
- variant: "danger",
1867
- footer: null,
1868
- title: formatMessage({
1869
- id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1870
- defaultMessage: "Confirmation"
1871
- }),
1872
- content: formatMessage(
1873
- {
1874
- id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1875
- defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1876
- },
1877
- {
1878
- count: totalDraftRelations
1879
- }
1880
- ),
1881
- onConfirm: async () => {
1882
- await performPublish();
1883
- }
1884
- } : void 0
1838
+ const handleClose = () => {
1839
+ setDialogId(null);
1885
1840
  };
1841
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1842
+ /* @__PURE__ */ jsxRuntime.jsx(
1843
+ designSystem.Button,
1844
+ {
1845
+ flex: "auto",
1846
+ startIcon: action.icon,
1847
+ disabled: action.disabled,
1848
+ onClick: handleClick(action),
1849
+ justifyContent: "center",
1850
+ variant: action.variant || "default",
1851
+ paddingTop: "7px",
1852
+ paddingBottom: "7px",
1853
+ children: action.label
1854
+ }
1855
+ ),
1856
+ action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1857
+ DocumentActionConfirmDialog,
1858
+ {
1859
+ ...action.dialog,
1860
+ variant: action.dialog?.variant ?? action.variant,
1861
+ isOpen: dialogId === action.id,
1862
+ onClose: handleClose
1863
+ }
1864
+ ) : null,
1865
+ action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1866
+ DocumentActionModal,
1867
+ {
1868
+ ...action.dialog,
1869
+ onModalClose: handleClose,
1870
+ isOpen: dialogId === action.id
1871
+ }
1872
+ ) : null
1873
+ ] });
1886
1874
  };
1887
- PublishAction$1.type = "publish";
1888
- const UpdateAction = ({
1889
- activeTab,
1890
- documentId,
1891
- model,
1892
- collectionType
1875
+ const DocumentActionsMenu = ({
1876
+ actions: actions2,
1877
+ children,
1878
+ label,
1879
+ variant = "tertiary"
1893
1880
  }) => {
1894
- const navigate = reactRouterDom.useNavigate();
1895
- const { toggleNotification } = strapiAdmin.useNotification();
1896
- const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1897
- const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1898
- const isCloning = cloneMatch !== null;
1881
+ const [isOpen, setIsOpen] = React__namespace.useState(false);
1882
+ const [dialogId, setDialogId] = React__namespace.useState(null);
1899
1883
  const { formatMessage } = reactIntl.useIntl();
1900
- const { create, update, clone } = useDocumentActions();
1901
- const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1902
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1903
- const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
1904
- const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
1905
- const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
1906
- const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
1907
- const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1908
- const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1909
- const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1910
- return {
1911
- /**
1912
- * Disabled when:
1913
- * - the form is submitting
1914
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1915
- * - the active tab is the published tab
1916
- */
1917
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1918
- label: formatMessage({
1919
- id: "content-manager.containers.Edit.save",
1920
- defaultMessage: "Save"
1921
- }),
1922
- onClick: async () => {
1923
- setSubmitting(true);
1924
- try {
1925
- if (activeTab !== "draft") {
1926
- const { errors } = await validate();
1927
- if (errors) {
1928
- toggleNotification({
1929
- type: "danger",
1930
- message: formatMessage({
1931
- id: "content-manager.validation.error",
1932
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1933
- })
1934
- });
1935
- return;
1936
- }
1937
- }
1938
- if (isCloning) {
1939
- const res = await clone(
1940
- {
1941
- model,
1942
- documentId: cloneMatch.params.origin,
1943
- params
1944
- },
1945
- document
1946
- );
1947
- if ("data" in res) {
1948
- navigate(
1949
- {
1950
- pathname: `../${res.data.documentId}`,
1951
- search: rawQuery
1952
- },
1953
- { relative: "path" }
1954
- );
1955
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1956
- setErrors(formatValidationErrors(res.error));
1957
- }
1958
- } else if (documentId || collectionType === SINGLE_TYPES) {
1959
- const res = await update(
1960
- {
1961
- collectionType,
1962
- model,
1963
- documentId,
1964
- params
1965
- },
1966
- document
1967
- );
1968
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1969
- setErrors(formatValidationErrors(res.error));
1970
- } else {
1971
- resetForm();
1972
- }
1973
- } else {
1974
- const res = await create(
1975
- {
1976
- model,
1977
- params
1978
- },
1979
- document
1980
- );
1981
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1982
- navigate(
1983
- {
1984
- pathname: `../${res.data.documentId}`,
1985
- search: rawQuery
1986
- },
1987
- { replace: true, relative: "path" }
1988
- );
1989
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1990
- setErrors(formatValidationErrors(res.error));
1991
- }
1992
- }
1993
- } finally {
1994
- setSubmitting(false);
1884
+ const { toggleNotification } = strapiAdmin.useNotification();
1885
+ const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
1886
+ const handleClick = (action) => async (e) => {
1887
+ const { onClick = () => false, dialog, id } = action;
1888
+ const muteDialog = await onClick(e);
1889
+ if (dialog && !muteDialog) {
1890
+ switch (dialog.type) {
1891
+ case "notification":
1892
+ toggleNotification({
1893
+ title: dialog.title,
1894
+ message: dialog.content,
1895
+ type: dialog.status,
1896
+ timeout: dialog.timeout,
1897
+ onClose: dialog.onClose
1898
+ });
1899
+ break;
1900
+ case "dialog":
1901
+ case "modal":
1902
+ setDialogId(id);
1995
1903
  }
1996
1904
  }
1997
1905
  };
1998
- };
1999
- UpdateAction.type = "update";
2000
- const UNPUBLISH_DRAFT_OPTIONS = {
2001
- KEEP: "keep",
2002
- DISCARD: "discard"
2003
- };
2004
- const UnpublishAction$1 = ({
2005
- activeTab,
2006
- documentId,
2007
- model,
2008
- collectionType,
2009
- document
2010
- }) => {
2011
- const { formatMessage } = reactIntl.useIntl();
2012
- const { schema } = useDoc();
2013
- const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2014
- const { unpublish } = useDocumentActions();
2015
- const [{ query }] = strapiAdmin.useQueryParams();
2016
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2017
- const { toggleNotification } = strapiAdmin.useNotification();
2018
- const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
2019
- const isDocumentModified = document?.status === "modified";
2020
- const handleChange = (value) => {
2021
- setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1906
+ const handleClose = () => {
1907
+ setDialogId(null);
1908
+ setIsOpen(false);
2022
1909
  };
2023
- if (!schema?.options?.draftAndPublish) {
2024
- return null;
2025
- }
2026
- return {
2027
- disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
2028
- label: formatMessage({
2029
- id: "app.utils.unpublish",
2030
- defaultMessage: "Unpublish"
2031
- }),
2032
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2033
- onClick: async () => {
2034
- if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
2035
- if (!documentId) {
2036
- console.error(
2037
- "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2038
- );
2039
- toggleNotification({
2040
- message: formatMessage({
2041
- id: "content-manager.actions.unpublish.error",
2042
- defaultMessage: "An error occurred while trying to unpublish the document."
2043
- }),
2044
- type: "danger"
2045
- });
2046
- }
2047
- return;
1910
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1911
+ /* @__PURE__ */ jsxRuntime.jsxs(
1912
+ designSystem.Menu.Trigger,
1913
+ {
1914
+ disabled: isDisabled,
1915
+ size: "S",
1916
+ endIcon: null,
1917
+ paddingTop: "4px",
1918
+ paddingLeft: "7px",
1919
+ paddingRight: "7px",
1920
+ variant,
1921
+ children: [
1922
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1923
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1924
+ id: "content-manager.containers.edit.panels.default.more-actions",
1925
+ defaultMessage: "More document actions"
1926
+ }) })
1927
+ ]
2048
1928
  }
2049
- await unpublish({
2050
- collectionType,
2051
- model,
2052
- documentId,
2053
- params
2054
- });
2055
- },
2056
- dialog: isDocumentModified ? {
2057
- type: "dialog",
2058
- title: formatMessage({
2059
- id: "app.components.ConfirmDialog.title",
2060
- defaultMessage: "Confirmation"
1929
+ ),
1930
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1931
+ actions2.map((action) => {
1932
+ return /* @__PURE__ */ jsxRuntime.jsx(
1933
+ designSystem.Menu.Item,
1934
+ {
1935
+ disabled: action.disabled,
1936
+ onSelect: handleClick(action),
1937
+ display: "block",
1938
+ children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsxs(
1940
+ designSystem.Flex,
1941
+ {
1942
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1943
+ gap: 2,
1944
+ tag: "span",
1945
+ children: [
1946
+ /* @__PURE__ */ jsxRuntime.jsx(
1947
+ designSystem.Flex,
1948
+ {
1949
+ tag: "span",
1950
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1951
+ children: action.icon
1952
+ }
1953
+ ),
1954
+ action.label
1955
+ ]
1956
+ }
1957
+ ),
1958
+ action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1959
+ designSystem.Flex,
1960
+ {
1961
+ alignItems: "center",
1962
+ background: "alternative100",
1963
+ borderStyle: "solid",
1964
+ borderColor: "alternative200",
1965
+ borderWidth: "1px",
1966
+ height: 5,
1967
+ paddingLeft: 2,
1968
+ paddingRight: 2,
1969
+ hasRadius: true,
1970
+ color: "alternative600",
1971
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1972
+ }
1973
+ )
1974
+ ] })
1975
+ },
1976
+ action.id
1977
+ );
2061
1978
  }),
2062
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
2063
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
2064
- /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2065
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2066
- id: "content-manager.actions.unpublish.dialog.body",
2067
- defaultMessage: "Are you sure?"
2068
- }) })
2069
- ] }),
2070
- /* @__PURE__ */ jsxRuntime.jsxs(
2071
- designSystem.Radio.Group,
1979
+ children
1980
+ ] }),
1981
+ actions2.map((action) => {
1982
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
1983
+ action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
1984
+ DocumentActionConfirmDialog,
2072
1985
  {
2073
- defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2074
- name: "discard-options",
2075
- "aria-label": formatMessage({
2076
- id: "content-manager.actions.unpublish.dialog.radio-label",
2077
- defaultMessage: "Choose an option to unpublish the document."
2078
- }),
2079
- onValueChange: handleChange,
2080
- children: [
2081
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2082
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2083
- defaultMessage: "Keep draft"
2084
- }) }),
2085
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2086
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2087
- defaultMessage: "Replace draft"
2088
- }) })
2089
- ]
1986
+ ...action.dialog,
1987
+ variant: action.variant,
1988
+ isOpen: dialogId === action.id,
1989
+ onClose: handleClose
2090
1990
  }
2091
- )
2092
- ] }),
2093
- onConfirm: async () => {
2094
- if (!documentId && collectionType !== SINGLE_TYPES) {
2095
- console.error(
2096
- "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2097
- );
2098
- toggleNotification({
2099
- message: formatMessage({
2100
- id: "content-manager.actions.unpublish.error",
2101
- defaultMessage: "An error occurred while trying to unpublish the document."
2102
- }),
2103
- type: "danger"
2104
- });
2105
- }
2106
- await unpublish(
1991
+ ) : null,
1992
+ action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
1993
+ DocumentActionModal,
2107
1994
  {
2108
- collectionType,
2109
- model,
2110
- documentId,
2111
- params
2112
- },
2113
- !shouldKeepDraft
2114
- );
2115
- }
2116
- } : void 0,
2117
- variant: "danger",
2118
- position: ["panel", "table-row"]
1995
+ ...action.dialog,
1996
+ onModalClose: handleClose,
1997
+ isOpen: dialogId === action.id
1998
+ }
1999
+ ) : null
2000
+ ] }, action.id);
2001
+ })
2002
+ ] });
2003
+ };
2004
+ const convertActionVariantToColor = (variant = "secondary") => {
2005
+ switch (variant) {
2006
+ case "danger":
2007
+ return "danger600";
2008
+ case "secondary":
2009
+ return void 0;
2010
+ case "success":
2011
+ return "success600";
2012
+ default:
2013
+ return "primary600";
2014
+ }
2015
+ };
2016
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2017
+ switch (variant) {
2018
+ case "danger":
2019
+ return "danger600";
2020
+ case "secondary":
2021
+ return "neutral500";
2022
+ case "success":
2023
+ return "success600";
2024
+ default:
2025
+ return "primary600";
2026
+ }
2027
+ };
2028
+ const DocumentActionConfirmDialog = ({
2029
+ onClose,
2030
+ onCancel,
2031
+ onConfirm,
2032
+ title,
2033
+ content,
2034
+ isOpen,
2035
+ variant = "secondary"
2036
+ }) => {
2037
+ const { formatMessage } = reactIntl.useIntl();
2038
+ const handleClose = async () => {
2039
+ if (onCancel) {
2040
+ await onCancel();
2041
+ }
2042
+ onClose();
2043
+ };
2044
+ const handleConfirm = async () => {
2045
+ if (onConfirm) {
2046
+ await onConfirm();
2047
+ }
2048
+ onClose();
2049
+ };
2050
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2051
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2052
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2053
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2054
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2055
+ id: "app.components.Button.cancel",
2056
+ defaultMessage: "Cancel"
2057
+ }) }) }),
2058
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2059
+ id: "app.components.Button.confirm",
2060
+ defaultMessage: "Confirm"
2061
+ }) })
2062
+ ] })
2063
+ ] }) });
2064
+ };
2065
+ const DocumentActionModal = ({
2066
+ isOpen,
2067
+ title,
2068
+ onClose,
2069
+ footer: Footer,
2070
+ content: Content,
2071
+ onModalClose
2072
+ }) => {
2073
+ const handleClose = () => {
2074
+ if (onClose) {
2075
+ onClose();
2076
+ }
2077
+ onModalClose();
2119
2078
  };
2079
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2080
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2081
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2082
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2083
+ ] }) });
2120
2084
  };
2121
- UnpublishAction$1.type = "unpublish";
2122
- const DiscardAction = ({
2085
+ const transformData = (data) => {
2086
+ if (Array.isArray(data)) {
2087
+ return data.map(transformData);
2088
+ }
2089
+ if (typeof data === "object" && data !== null) {
2090
+ if ("apiData" in data) {
2091
+ return data.apiData;
2092
+ }
2093
+ return mapValues__default.default(transformData)(data);
2094
+ }
2095
+ return data;
2096
+ };
2097
+ const PublishAction$1 = ({
2123
2098
  activeTab,
2124
2099
  documentId,
2125
2100
  model,
2126
2101
  collectionType,
2102
+ meta,
2127
2103
  document
2128
2104
  }) => {
2129
- const { formatMessage } = reactIntl.useIntl();
2130
2105
  const { schema } = useDoc();
2131
- const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
2132
- const { discard } = useDocumentActions();
2133
- const [{ query }] = strapiAdmin.useQueryParams();
2134
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2135
- if (!schema?.options?.draftAndPublish) {
2136
- return null;
2137
- }
2138
- return {
2139
- disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
2140
- label: formatMessage({
2141
- id: "content-manager.actions.discard.label",
2142
- defaultMessage: "Discard changes"
2143
- }),
2144
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2145
- position: ["panel", "table-row"],
2146
- variant: "danger",
2147
- dialog: {
2148
- type: "dialog",
2149
- title: formatMessage({
2150
- id: "app.components.ConfirmDialog.title",
2151
- defaultMessage: "Confirmation"
2152
- }),
2153
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2154
- /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2155
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2156
- id: "content-manager.actions.discard.dialog.body",
2157
- defaultMessage: "Are you sure?"
2158
- }) })
2159
- ] }),
2160
- onConfirm: async () => {
2161
- await discard({
2162
- collectionType,
2163
- model,
2164
- documentId,
2165
- params
2166
- });
2167
- }
2168
- }
2169
- };
2170
- };
2171
- DiscardAction.type = "discard";
2172
- const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2173
- const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2174
- const RelativeTime = React__namespace.forwardRef(
2175
- ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
2176
- const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
2177
- const interval = dateFns.intervalToDuration({
2178
- start: timestamp,
2179
- end: Date.now()
2180
- // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
2181
- });
2182
- const unit = intervals.find((intervalUnit) => {
2183
- return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2184
- });
2185
- const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2186
- const customInterval = customIntervals.find(
2187
- (custom) => interval[custom.unit] < custom.threshold
2188
- );
2189
- const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
2190
- return /* @__PURE__ */ jsxRuntime.jsx(
2191
- "time",
2192
- {
2193
- ref: forwardedRef,
2194
- dateTime: timestamp.toISOString(),
2195
- role: "time",
2196
- title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
2197
- ...restProps,
2198
- children: displayText
2199
- }
2200
- );
2201
- }
2202
- );
2203
- const getDisplayName = ({
2204
- firstname,
2205
- lastname,
2206
- username,
2207
- email
2208
- } = {}) => {
2209
- if (username) {
2210
- return username;
2211
- }
2212
- if (firstname) {
2213
- return `${firstname} ${lastname ?? ""}`.trim();
2214
- }
2215
- return email ?? "";
2216
- };
2217
- const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2218
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2219
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2220
- 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) }) });
2221
- };
2222
- const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2223
- const { formatMessage } = reactIntl.useIntl();
2106
+ const navigate = reactRouterDom.useNavigate();
2107
+ const { toggleNotification } = strapiAdmin.useNotification();
2108
+ const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2109
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
2224
2110
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2225
- const title = isCreating ? formatMessage({
2226
- id: "content-manager.containers.edit.title.new",
2227
- defaultMessage: "Create an entry"
2228
- }) : documentTitle;
2229
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2230
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2231
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2232
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2233
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2234
- ] }),
2235
- status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2236
- ] });
2237
- };
2238
- const HeaderToolbar = () => {
2239
2111
  const { formatMessage } = reactIntl.useIntl();
2240
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2112
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2113
+ const { publish } = useDocumentActions();
2241
2114
  const [
2242
- {
2243
- query: { status = "draft" }
2115
+ countDraftRelations,
2116
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2117
+ ] = useLazyGetDraftRelationCountQuery();
2118
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2119
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
2120
+ const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
2121
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2122
+ const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
2123
+ const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
2124
+ const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
2125
+ const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
2126
+ const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
2127
+ const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2128
+ React__namespace.useEffect(() => {
2129
+ if (isErrorDraftRelations) {
2130
+ toggleNotification({
2131
+ type: "danger",
2132
+ message: formatMessage({
2133
+ id: getTranslation("error.records.fetch-draft-relatons"),
2134
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2135
+ })
2136
+ });
2244
2137
  }
2245
- ] = strapiAdmin.useQueryParams();
2246
- const { model, id, document, meta, collectionType } = useDoc();
2247
- const plugins = strapiAdmin.useStrapiApp("HeaderToolbar", (state) => state.plugins);
2248
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2249
- /* @__PURE__ */ jsxRuntime.jsx(
2250
- strapiAdmin.DescriptionComponentRenderer,
2251
- {
2252
- props: {
2253
- activeTab: status,
2254
- model,
2255
- documentId: id,
2256
- document: isCloning ? void 0 : document,
2257
- meta: isCloning ? void 0 : meta,
2258
- collectionType
2259
- },
2260
- descriptions: plugins["content-manager"].apis.getHeaderActions(),
2261
- children: (actions2) => {
2262
- if (actions2.length > 0) {
2263
- return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
2264
- } else {
2265
- return null;
2266
- }
2138
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2139
+ React__namespace.useEffect(() => {
2140
+ const localDraftRelations = /* @__PURE__ */ new Set();
2141
+ const extractDraftRelations = (data) => {
2142
+ const relations = data.connect || [];
2143
+ relations.forEach((relation) => {
2144
+ if (relation.status === "draft") {
2145
+ localDraftRelations.add(relation.id);
2267
2146
  }
2268
- }
2269
- ),
2270
- /* @__PURE__ */ jsxRuntime.jsx(
2271
- strapiAdmin.DescriptionComponentRenderer,
2272
- {
2273
- props: {
2274
- activeTab: status,
2275
- model,
2276
- documentId: id,
2277
- document: isCloning ? void 0 : document,
2278
- meta: isCloning ? void 0 : meta,
2279
- collectionType
2280
- },
2281
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2282
- children: (actions2) => {
2283
- const headerActions = actions2.filter((action) => {
2284
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2285
- return positions.includes("header");
2286
- });
2287
- return /* @__PURE__ */ jsxRuntime.jsx(
2288
- DocumentActionsMenu,
2289
- {
2290
- actions: headerActions,
2291
- label: formatMessage({
2292
- id: "content-manager.containers.edit.header.more-actions",
2293
- defaultMessage: "More actions"
2294
- }),
2295
- children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
2296
- }
2297
- );
2147
+ });
2148
+ };
2149
+ const traverseAndExtract = (data) => {
2150
+ Object.entries(data).forEach(([key, value]) => {
2151
+ if (key === "connect" && Array.isArray(value)) {
2152
+ extractDraftRelations({ connect: value });
2153
+ } else if (typeof value === "object" && value !== null) {
2154
+ traverseAndExtract(value);
2298
2155
  }
2156
+ });
2157
+ };
2158
+ if (!documentId || modified) {
2159
+ traverseAndExtract(formValues);
2160
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2161
+ }
2162
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2163
+ React__namespace.useEffect(() => {
2164
+ if (!document || !document.documentId || isListView) {
2165
+ return;
2166
+ }
2167
+ const fetchDraftRelationsCount = async () => {
2168
+ const { data, error } = await countDraftRelations({
2169
+ collectionType,
2170
+ model,
2171
+ documentId,
2172
+ params
2173
+ });
2174
+ if (error) {
2175
+ throw error;
2299
2176
  }
2300
- )
2301
- ] });
2302
- };
2303
- const Information = ({ activeTab }) => {
2304
- const { formatMessage } = reactIntl.useIntl();
2305
- const { document, meta } = useDoc();
2306
- if (!document || !document.id) {
2177
+ if (data) {
2178
+ setServerCountOfDraftRelations(data.data);
2179
+ }
2180
+ };
2181
+ fetchDraftRelationsCount();
2182
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
2183
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
2184
+ if (!schema?.options?.draftAndPublish) {
2307
2185
  return null;
2308
2186
  }
2309
- const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
2310
- const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
2311
- const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
2312
- const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
2313
- const information = [
2314
- {
2315
- isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2316
- label: formatMessage({
2317
- id: "content-manager.containers.edit.information.last-published.label",
2318
- defaultMessage: "Last published"
2319
- }),
2320
- value: formatMessage(
2187
+ const performPublish = async () => {
2188
+ setSubmitting(true);
2189
+ try {
2190
+ const { errors } = await validate(true, {
2191
+ status: "published"
2192
+ });
2193
+ if (errors) {
2194
+ toggleNotification({
2195
+ type: "danger",
2196
+ message: formatMessage({
2197
+ id: "content-manager.validation.error",
2198
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2199
+ })
2200
+ });
2201
+ return;
2202
+ }
2203
+ const res = await publish(
2321
2204
  {
2322
- id: "content-manager.containers.edit.information.last-published.value",
2323
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2205
+ collectionType,
2206
+ model,
2207
+ documentId,
2208
+ params
2324
2209
  },
2325
- {
2326
- time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
2327
- isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
2328
- author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
2329
- }
2330
- )
2210
+ transformData(formValues)
2211
+ );
2212
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2213
+ navigate({
2214
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2215
+ search: rawQuery
2216
+ });
2217
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2218
+ setErrors(formatValidationErrors(res.error));
2219
+ }
2220
+ } finally {
2221
+ setSubmitting(false);
2222
+ }
2223
+ };
2224
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2225
+ const enableDraftRelationsCount = false;
2226
+ const hasDraftRelations = enableDraftRelationsCount;
2227
+ return {
2228
+ /**
2229
+ * Disabled when:
2230
+ * - currently if you're cloning a document we don't support publish & clone at the same time.
2231
+ * - the form is submitting
2232
+ * - the active tab is the published tab
2233
+ * - the document is already published & not modified
2234
+ * - the document is being created & not modified
2235
+ * - the user doesn't have the permission to publish
2236
+ */
2237
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
2238
+ label: formatMessage({
2239
+ id: "app.utils.publish",
2240
+ defaultMessage: "Publish"
2241
+ }),
2242
+ onClick: async () => {
2243
+ await performPublish();
2331
2244
  },
2332
- {
2333
- isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2334
- label: formatMessage({
2335
- id: "content-manager.containers.edit.information.last-draft.label",
2336
- defaultMessage: "Last draft"
2245
+ dialog: hasDraftRelations ? {
2246
+ type: "dialog",
2247
+ variant: "danger",
2248
+ footer: null,
2249
+ title: formatMessage({
2250
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2251
+ defaultMessage: "Confirmation"
2337
2252
  }),
2338
- value: formatMessage(
2253
+ content: formatMessage(
2339
2254
  {
2340
- id: "content-manager.containers.edit.information.last-draft.value",
2341
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2255
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2256
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2342
2257
  },
2343
2258
  {
2344
- time: /* @__PURE__ */ jsxRuntime.jsx(
2345
- RelativeTime,
2346
- {
2347
- timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
2348
- }
2349
- ),
2350
- isAnonymous: !updator,
2351
- author: updator
2259
+ count: totalDraftRelations
2352
2260
  }
2353
- )
2354
- },
2355
- {
2356
- isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2357
- label: formatMessage({
2358
- id: "content-manager.containers.edit.information.document.label",
2359
- defaultMessage: "Document"
2360
- }),
2361
- value: formatMessage(
2362
- {
2363
- id: "content-manager.containers.edit.information.document.value",
2364
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2365
- },
2366
- {
2367
- time: /* @__PURE__ */ jsxRuntime.jsx(
2368
- RelativeTime,
2369
- {
2370
- timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
2371
- }
2372
- ),
2373
- isAnonymous: !creator,
2374
- author: creator
2261
+ ),
2262
+ onConfirm: async () => {
2263
+ await performPublish();
2264
+ }
2265
+ } : void 0
2266
+ };
2267
+ };
2268
+ PublishAction$1.type = "publish";
2269
+ const UpdateAction = ({
2270
+ activeTab,
2271
+ documentId,
2272
+ model,
2273
+ collectionType
2274
+ }) => {
2275
+ const navigate = reactRouterDom.useNavigate();
2276
+ const { toggleNotification } = strapiAdmin.useNotification();
2277
+ const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2278
+ const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
2279
+ const isCloning = cloneMatch !== null;
2280
+ const { formatMessage } = reactIntl.useIntl();
2281
+ const { create, update, clone } = useDocumentActions();
2282
+ const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
2283
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2284
+ const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
2285
+ const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
2286
+ const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
2287
+ const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
2288
+ const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
2289
+ const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
2290
+ const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
2291
+ return {
2292
+ /**
2293
+ * Disabled when:
2294
+ * - the form is submitting
2295
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2296
+ * - the active tab is the published tab
2297
+ */
2298
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2299
+ label: formatMessage({
2300
+ id: "content-manager.containers.Edit.save",
2301
+ defaultMessage: "Save"
2302
+ }),
2303
+ onClick: async () => {
2304
+ setSubmitting(true);
2305
+ try {
2306
+ const { errors } = await validate(true, {
2307
+ status: "draft"
2308
+ });
2309
+ if (errors) {
2310
+ toggleNotification({
2311
+ type: "danger",
2312
+ message: formatMessage({
2313
+ id: "content-manager.validation.error",
2314
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2315
+ })
2316
+ });
2317
+ return;
2375
2318
  }
2376
- )
2377
- }
2378
- ].filter((info) => info.isDisplayed);
2379
- return /* @__PURE__ */ jsxRuntime.jsx(
2380
- designSystem.Flex,
2381
- {
2382
- borderWidth: "1px 0 0 0",
2383
- borderStyle: "solid",
2384
- borderColor: "neutral150",
2385
- direction: "column",
2386
- marginTop: 2,
2387
- tag: "dl",
2388
- padding: 5,
2389
- gap: 3,
2390
- alignItems: "flex-start",
2391
- marginLeft: "-0.4rem",
2392
- marginRight: "-0.4rem",
2393
- width: "calc(100% + 8px)",
2394
- children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2395
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2396
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2397
- ] }, info.label))
2319
+ if (isCloning) {
2320
+ const res = await clone(
2321
+ {
2322
+ model,
2323
+ documentId: cloneMatch.params.origin,
2324
+ params
2325
+ },
2326
+ transformData(document)
2327
+ );
2328
+ if ("data" in res) {
2329
+ navigate(
2330
+ {
2331
+ pathname: `../${res.data.documentId}`,
2332
+ search: rawQuery
2333
+ },
2334
+ { relative: "path" }
2335
+ );
2336
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2337
+ setErrors(formatValidationErrors(res.error));
2338
+ }
2339
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2340
+ const res = await update(
2341
+ {
2342
+ collectionType,
2343
+ model,
2344
+ documentId,
2345
+ params
2346
+ },
2347
+ transformData(document)
2348
+ );
2349
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2350
+ setErrors(formatValidationErrors(res.error));
2351
+ } else {
2352
+ resetForm();
2353
+ }
2354
+ } else {
2355
+ const res = await create(
2356
+ {
2357
+ model,
2358
+ params
2359
+ },
2360
+ transformData(document)
2361
+ );
2362
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2363
+ navigate(
2364
+ {
2365
+ pathname: `../${res.data.documentId}`,
2366
+ search: rawQuery
2367
+ },
2368
+ { replace: true, relative: "path" }
2369
+ );
2370
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2371
+ setErrors(formatValidationErrors(res.error));
2372
+ }
2373
+ }
2374
+ } finally {
2375
+ setSubmitting(false);
2376
+ }
2398
2377
  }
2399
- );
2378
+ };
2400
2379
  };
2401
- const HeaderActions = ({ actions: actions2 }) => {
2402
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2403
- if ("options" in action) {
2404
- return /* @__PURE__ */ jsxRuntime.jsx(
2405
- designSystem.SingleSelect,
2406
- {
2407
- size: "S",
2408
- disabled: action.disabled,
2409
- "aria-label": action.label,
2410
- onChange: action.onSelect,
2411
- value: action.value,
2412
- children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2413
- },
2414
- action.id
2415
- );
2416
- } else {
2417
- return null;
2418
- }
2419
- }) });
2380
+ UpdateAction.type = "update";
2381
+ const UNPUBLISH_DRAFT_OPTIONS = {
2382
+ KEEP: "keep",
2383
+ DISCARD: "discard"
2420
2384
  };
2421
- const ConfigureTheViewAction = ({ collectionType, model }) => {
2422
- const navigate = reactRouterDom.useNavigate();
2385
+ const UnpublishAction$1 = ({
2386
+ activeTab,
2387
+ documentId,
2388
+ model,
2389
+ collectionType,
2390
+ document
2391
+ }) => {
2423
2392
  const { formatMessage } = reactIntl.useIntl();
2424
- return {
2425
- label: formatMessage({
2426
- id: "app.links.configure-view",
2427
- defaultMessage: "Configure the view"
2428
- }),
2429
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2430
- onClick: () => {
2431
- navigate(`../${collectionType}/${model}/configurations/edit`);
2432
- },
2433
- position: "header"
2393
+ const { schema } = useDoc();
2394
+ const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2395
+ const { unpublish } = useDocumentActions();
2396
+ const [{ query }] = strapiAdmin.useQueryParams();
2397
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2398
+ const { toggleNotification } = strapiAdmin.useNotification();
2399
+ const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
2400
+ const isDocumentModified = document?.status === "modified";
2401
+ const handleChange = (value) => {
2402
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
2434
2403
  };
2435
- };
2436
- ConfigureTheViewAction.type = "configure-the-view";
2437
- const EditTheModelAction = ({ model }) => {
2438
- const navigate = reactRouterDom.useNavigate();
2439
- const { formatMessage } = reactIntl.useIntl();
2404
+ if (!schema?.options?.draftAndPublish) {
2405
+ return null;
2406
+ }
2440
2407
  return {
2408
+ disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
2441
2409
  label: formatMessage({
2442
- id: "content-manager.link-to-ctb",
2443
- defaultMessage: "Edit the model"
2410
+ id: "app.utils.unpublish",
2411
+ defaultMessage: "Unpublish"
2444
2412
  }),
2445
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2446
- onClick: () => {
2447
- navigate(`/plugins/content-type-builder/content-types/${model}`);
2413
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2414
+ onClick: async () => {
2415
+ if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
2416
+ if (!documentId) {
2417
+ console.error(
2418
+ "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2419
+ );
2420
+ toggleNotification({
2421
+ message: formatMessage({
2422
+ id: "content-manager.actions.unpublish.error",
2423
+ defaultMessage: "An error occurred while trying to unpublish the document."
2424
+ }),
2425
+ type: "danger"
2426
+ });
2427
+ }
2428
+ return;
2429
+ }
2430
+ await unpublish({
2431
+ collectionType,
2432
+ model,
2433
+ documentId,
2434
+ params
2435
+ });
2448
2436
  },
2449
- position: "header"
2437
+ dialog: isDocumentModified ? {
2438
+ type: "dialog",
2439
+ title: formatMessage({
2440
+ id: "app.components.ConfirmDialog.title",
2441
+ defaultMessage: "Confirmation"
2442
+ }),
2443
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
2444
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
2445
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2446
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2447
+ id: "content-manager.actions.unpublish.dialog.body",
2448
+ defaultMessage: "Are you sure?"
2449
+ }) })
2450
+ ] }),
2451
+ /* @__PURE__ */ jsxRuntime.jsxs(
2452
+ designSystem.Radio.Group,
2453
+ {
2454
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2455
+ name: "discard-options",
2456
+ "aria-label": formatMessage({
2457
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2458
+ defaultMessage: "Choose an option to unpublish the document."
2459
+ }),
2460
+ onValueChange: handleChange,
2461
+ children: [
2462
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2463
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2464
+ defaultMessage: "Keep draft"
2465
+ }) }),
2466
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2467
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2468
+ defaultMessage: "Replace draft"
2469
+ }) })
2470
+ ]
2471
+ }
2472
+ )
2473
+ ] }),
2474
+ onConfirm: async () => {
2475
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2476
+ console.error(
2477
+ "You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
2478
+ );
2479
+ toggleNotification({
2480
+ message: formatMessage({
2481
+ id: "content-manager.actions.unpublish.error",
2482
+ defaultMessage: "An error occurred while trying to unpublish the document."
2483
+ }),
2484
+ type: "danger"
2485
+ });
2486
+ }
2487
+ await unpublish(
2488
+ {
2489
+ collectionType,
2490
+ model,
2491
+ documentId,
2492
+ params
2493
+ },
2494
+ !shouldKeepDraft
2495
+ );
2496
+ }
2497
+ } : void 0,
2498
+ variant: "danger",
2499
+ position: ["panel", "table-row"]
2450
2500
  };
2451
2501
  };
2452
- EditTheModelAction.type = "edit-the-model";
2453
- const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2454
- const navigate = reactRouterDom.useNavigate();
2502
+ UnpublishAction$1.type = "unpublish";
2503
+ const DiscardAction = ({
2504
+ activeTab,
2505
+ documentId,
2506
+ model,
2507
+ collectionType,
2508
+ document
2509
+ }) => {
2455
2510
  const { formatMessage } = reactIntl.useIntl();
2456
- const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2457
- const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2458
- const { delete: deleteAction } = useDocumentActions();
2459
- const { toggleNotification } = strapiAdmin.useNotification();
2460
- const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2511
+ const { schema } = useDoc();
2512
+ const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
2513
+ const { discard } = useDocumentActions();
2514
+ const [{ query }] = strapiAdmin.useQueryParams();
2515
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
2516
+ if (!schema?.options?.draftAndPublish) {
2517
+ return null;
2518
+ }
2461
2519
  return {
2462
- disabled: !canDelete || !document,
2520
+ disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
2463
2521
  label: formatMessage({
2464
- id: "content-manager.actions.delete.label",
2465
- defaultMessage: "Delete document"
2522
+ id: "content-manager.actions.discard.label",
2523
+ defaultMessage: "Discard changes"
2466
2524
  }),
2467
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2525
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2526
+ position: ["panel", "table-row"],
2527
+ variant: "danger",
2468
2528
  dialog: {
2469
2529
  type: "dialog",
2470
2530
  title: formatMessage({
@@ -2474,92 +2534,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2474
2534
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2475
2535
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2476
2536
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2477
- id: "content-manager.actions.delete.dialog.body",
2537
+ id: "content-manager.actions.discard.dialog.body",
2478
2538
  defaultMessage: "Are you sure?"
2479
2539
  }) })
2480
2540
  ] }),
2481
2541
  onConfirm: async () => {
2482
- if (!listViewPathMatch) {
2483
- setSubmitting(true);
2484
- }
2485
- try {
2486
- if (!documentId && collectionType !== SINGLE_TYPES) {
2487
- console.error(
2488
- "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2489
- );
2490
- toggleNotification({
2491
- message: formatMessage({
2492
- id: "content-manager.actions.delete.error",
2493
- defaultMessage: "An error occurred while trying to delete the document."
2494
- }),
2495
- type: "danger"
2496
- });
2497
- return;
2498
- }
2499
- const res = await deleteAction({
2500
- documentId,
2501
- model,
2502
- collectionType,
2503
- params: {
2504
- locale: "*"
2505
- }
2506
- });
2507
- if (!("error" in res)) {
2508
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2509
- }
2510
- } finally {
2511
- if (!listViewPathMatch) {
2512
- setSubmitting(false);
2513
- }
2514
- }
2542
+ await discard({
2543
+ collectionType,
2544
+ model,
2545
+ documentId,
2546
+ params
2547
+ });
2548
+ }
2549
+ }
2550
+ };
2551
+ };
2552
+ DiscardAction.type = "discard";
2553
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2554
+ const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2555
+ const RelativeTime = React__namespace.forwardRef(
2556
+ ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
2557
+ const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
2558
+ const interval = dateFns.intervalToDuration({
2559
+ start: timestamp,
2560
+ end: Date.now()
2561
+ // see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
2562
+ });
2563
+ const unit = intervals.find((intervalUnit) => {
2564
+ return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2565
+ });
2566
+ const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2567
+ const customInterval = customIntervals.find(
2568
+ (custom) => interval[custom.unit] < custom.threshold
2569
+ );
2570
+ const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
2571
+ return /* @__PURE__ */ jsxRuntime.jsx(
2572
+ "time",
2573
+ {
2574
+ ref: forwardedRef,
2575
+ dateTime: timestamp.toISOString(),
2576
+ role: "time",
2577
+ title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
2578
+ ...restProps,
2579
+ children: displayText
2515
2580
  }
2516
- },
2517
- variant: "danger",
2518
- position: ["header", "table-row"]
2519
- };
2581
+ );
2582
+ }
2583
+ );
2584
+ const getDisplayName = ({
2585
+ firstname,
2586
+ lastname,
2587
+ username,
2588
+ email
2589
+ } = {}) => {
2590
+ if (username) {
2591
+ return username;
2592
+ }
2593
+ if (firstname) {
2594
+ return `${firstname} ${lastname ?? ""}`.trim();
2595
+ }
2596
+ return email ?? "";
2520
2597
  };
2521
- DeleteAction$1.type = "delete";
2522
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2523
- const Panels = () => {
2524
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2525
- const [
2526
- {
2527
- query: { status }
2528
- }
2529
- ] = strapiAdmin.useQueryParams({
2530
- status: "draft"
2531
- });
2532
- const { model, id, document, meta, collectionType } = useDoc();
2533
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2534
- const props = {
2535
- activeTab: status,
2536
- model,
2537
- documentId: id,
2538
- document: isCloning ? void 0 : document,
2539
- meta: isCloning ? void 0 : meta,
2540
- collectionType
2541
- };
2542
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2543
- strapiAdmin.DescriptionComponentRenderer,
2544
- {
2545
- props,
2546
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2547
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2548
- }
2549
- ) });
2598
+ const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2599
+ const DocumentStatus = ({ status = "draft", ...restProps }) => {
2600
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2601
+ 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) }) });
2550
2602
  };
2551
- const ActionsPanel = () => {
2603
+ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2552
2604
  const { formatMessage } = reactIntl.useIntl();
2553
- return {
2554
- title: formatMessage({
2555
- id: "content-manager.containers.edit.panels.default.title",
2556
- defaultMessage: "Document"
2557
- }),
2558
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2559
- };
2605
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2606
+ const title = isCreating ? formatMessage({
2607
+ id: "content-manager.containers.edit.title.new",
2608
+ defaultMessage: "Create an entry"
2609
+ }) : documentTitle;
2610
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2611
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2612
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2613
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2614
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2615
+ ] }),
2616
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2617
+ ] });
2560
2618
  };
2561
- ActionsPanel.type = "actions";
2562
- const ActionsPanelContent = () => {
2619
+ const HeaderToolbar = () => {
2620
+ const { formatMessage } = reactIntl.useIntl();
2563
2621
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2564
2622
  const [
2565
2623
  {
@@ -2567,356 +2625,432 @@ const ActionsPanelContent = () => {
2567
2625
  }
2568
2626
  ] = strapiAdmin.useQueryParams();
2569
2627
  const { model, id, document, meta, collectionType } = useDoc();
2570
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2571
- const props = {
2572
- activeTab: status,
2573
- model,
2574
- documentId: id,
2575
- document: isCloning ? void 0 : document,
2576
- meta: isCloning ? void 0 : meta,
2577
- collectionType
2578
- };
2579
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2628
+ const plugins = strapiAdmin.useStrapiApp("HeaderToolbar", (state) => state.plugins);
2629
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2580
2630
  /* @__PURE__ */ jsxRuntime.jsx(
2581
2631
  strapiAdmin.DescriptionComponentRenderer,
2582
2632
  {
2583
- props,
2584
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2585
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2633
+ props: {
2634
+ activeTab: status,
2635
+ model,
2636
+ documentId: id,
2637
+ document: isCloning ? void 0 : document,
2638
+ meta: isCloning ? void 0 : meta,
2639
+ collectionType
2640
+ },
2641
+ descriptions: plugins["content-manager"].apis.getHeaderActions(),
2642
+ children: (actions2) => {
2643
+ if (actions2.length > 0) {
2644
+ return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
2645
+ } else {
2646
+ return null;
2647
+ }
2648
+ }
2586
2649
  }
2587
2650
  ),
2588
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2651
+ /* @__PURE__ */ jsxRuntime.jsx(
2652
+ strapiAdmin.DescriptionComponentRenderer,
2653
+ {
2654
+ props: {
2655
+ activeTab: status,
2656
+ model,
2657
+ documentId: id,
2658
+ document: isCloning ? void 0 : document,
2659
+ meta: isCloning ? void 0 : meta,
2660
+ collectionType
2661
+ },
2662
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
2663
+ children: (actions2) => {
2664
+ const headerActions = actions2.filter((action) => {
2665
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
2666
+ return positions.includes("header");
2667
+ });
2668
+ return /* @__PURE__ */ jsxRuntime.jsx(
2669
+ DocumentActionsMenu,
2670
+ {
2671
+ actions: headerActions,
2672
+ label: formatMessage({
2673
+ id: "content-manager.containers.edit.header.more-actions",
2674
+ defaultMessage: "More actions"
2675
+ }),
2676
+ children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
2677
+ }
2678
+ );
2679
+ }
2680
+ }
2681
+ )
2589
2682
  ] });
2590
2683
  };
2591
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2592
- return /* @__PURE__ */ jsxRuntime.jsxs(
2593
- designSystem.Flex,
2684
+ const Information = ({ activeTab }) => {
2685
+ const { formatMessage } = reactIntl.useIntl();
2686
+ const { document, meta } = useDoc();
2687
+ if (!document || !document.id) {
2688
+ return null;
2689
+ }
2690
+ const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
2691
+ const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
2692
+ const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
2693
+ const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
2694
+ const information = [
2594
2695
  {
2595
- ref,
2596
- tag: "aside",
2597
- "aria-labelledby": "additional-information",
2598
- background: "neutral0",
2599
- borderColor: "neutral150",
2600
- hasRadius: true,
2601
- paddingBottom: 4,
2602
- paddingLeft: 4,
2603
- paddingRight: 4,
2604
- paddingTop: 4,
2605
- shadow: "tableShadow",
2606
- gap: 3,
2607
- direction: "column",
2608
- justifyContent: "stretch",
2609
- alignItems: "flex-start",
2610
- children: [
2611
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2612
- children
2613
- ]
2614
- }
2615
- );
2616
- });
2617
- const HOOKS = {
2618
- /**
2619
- * Hook that allows to mutate the displayed headers of the list view table
2620
- * @constant
2621
- * @type {string}
2622
- */
2623
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2624
- /**
2625
- * Hook that allows to mutate the CM's collection types links pre-set filters
2626
- * @constant
2627
- * @type {string}
2628
- */
2629
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2630
- /**
2631
- * Hook that allows to mutate the CM's edit view layout
2632
- * @constant
2633
- * @type {string}
2634
- */
2635
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2636
- /**
2637
- * Hook that allows to mutate the CM's single types links pre-set filters
2638
- * @constant
2639
- * @type {string}
2640
- */
2641
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2642
- };
2643
- const contentTypesApi = contentManagerApi.injectEndpoints({
2644
- endpoints: (builder) => ({
2645
- getContentTypeConfiguration: builder.query({
2646
- query: (uid) => ({
2647
- url: `/content-manager/content-types/${uid}/configuration`,
2648
- method: "GET"
2696
+ isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2697
+ label: formatMessage({
2698
+ id: "content-manager.containers.edit.information.last-published.label",
2699
+ defaultMessage: "Published"
2649
2700
  }),
2650
- transformResponse: (response) => response.data,
2651
- providesTags: (_result, _error, uid) => [
2652
- { type: "ContentTypesConfiguration", id: uid },
2653
- { type: "ContentTypeSettings", id: "LIST" }
2654
- ]
2655
- }),
2656
- getAllContentTypeSettings: builder.query({
2657
- query: () => "/content-manager/content-types-settings",
2658
- transformResponse: (response) => response.data,
2659
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2660
- }),
2661
- updateContentTypeConfiguration: builder.mutation({
2662
- query: ({ uid, ...body }) => ({
2663
- url: `/content-manager/content-types/${uid}/configuration`,
2664
- method: "PUT",
2665
- data: body
2701
+ value: formatMessage(
2702
+ {
2703
+ id: "content-manager.containers.edit.information.last-published.value",
2704
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2705
+ },
2706
+ {
2707
+ time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
2708
+ isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
2709
+ author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
2710
+ }
2711
+ )
2712
+ },
2713
+ {
2714
+ isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2715
+ label: formatMessage({
2716
+ id: "content-manager.containers.edit.information.last-draft.label",
2717
+ defaultMessage: "Updated"
2718
+ }),
2719
+ value: formatMessage(
2720
+ {
2721
+ id: "content-manager.containers.edit.information.last-draft.value",
2722
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2723
+ },
2724
+ {
2725
+ time: /* @__PURE__ */ jsxRuntime.jsx(
2726
+ RelativeTime,
2727
+ {
2728
+ timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
2729
+ }
2730
+ ),
2731
+ isAnonymous: !updator,
2732
+ author: updator
2733
+ }
2734
+ )
2735
+ },
2736
+ {
2737
+ isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2738
+ label: formatMessage({
2739
+ id: "content-manager.containers.edit.information.document.label",
2740
+ defaultMessage: "Created"
2666
2741
  }),
2667
- transformResponse: (response) => response.data,
2668
- invalidatesTags: (_result, _error, { uid }) => [
2669
- { type: "ContentTypesConfiguration", id: uid },
2670
- { type: "ContentTypeSettings", id: "LIST" },
2671
- // Is this necessary?
2672
- { type: "InitialData" }
2673
- ]
2674
- })
2675
- })
2676
- });
2677
- const {
2678
- useGetContentTypeConfigurationQuery,
2679
- useGetAllContentTypeSettingsQuery,
2680
- useUpdateContentTypeConfigurationMutation
2681
- } = contentTypesApi;
2682
- const checkIfAttributeIsDisplayable = (attribute) => {
2683
- const { type } = attribute;
2684
- if (type === "relation") {
2685
- return !attribute.relation.toLowerCase().includes("morph");
2686
- }
2687
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2688
- };
2689
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2690
- if (!mainFieldName) {
2691
- return void 0;
2692
- }
2693
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2694
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2695
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2742
+ value: formatMessage(
2743
+ {
2744
+ id: "content-manager.containers.edit.information.document.value",
2745
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2746
+ },
2747
+ {
2748
+ time: /* @__PURE__ */ jsxRuntime.jsx(
2749
+ RelativeTime,
2750
+ {
2751
+ timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
2752
+ }
2753
+ ),
2754
+ isAnonymous: !creator,
2755
+ author: creator
2756
+ }
2757
+ )
2758
+ }
2759
+ ].filter((info) => info.isDisplayed);
2760
+ return /* @__PURE__ */ jsxRuntime.jsx(
2761
+ designSystem.Flex,
2762
+ {
2763
+ borderWidth: "1px 0 0 0",
2764
+ borderStyle: "solid",
2765
+ borderColor: "neutral150",
2766
+ direction: "column",
2767
+ marginTop: 2,
2768
+ tag: "dl",
2769
+ padding: 5,
2770
+ gap: 3,
2771
+ alignItems: "flex-start",
2772
+ marginLeft: "-0.4rem",
2773
+ marginRight: "-0.4rem",
2774
+ width: "calc(100% + 8px)",
2775
+ children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2776
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2777
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2778
+ ] }, info.label))
2779
+ }
2696
2780
  );
2697
- return {
2698
- name: mainFieldName,
2699
- type: mainFieldType ?? "string"
2700
- };
2701
- };
2702
- const DEFAULT_SETTINGS = {
2703
- bulkable: false,
2704
- filterable: false,
2705
- searchable: false,
2706
- pagination: false,
2707
- defaultSortBy: "",
2708
- defaultSortOrder: "asc",
2709
- mainField: "id",
2710
- pageSize: 10
2711
2781
  };
2712
- const useDocumentLayout = (model) => {
2713
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2714
- const [{ query }] = strapiAdmin.useQueryParams();
2715
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2716
- const { toggleNotification } = strapiAdmin.useNotification();
2717
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2718
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2719
- const {
2720
- data,
2721
- isLoading: isLoadingConfigs,
2722
- error,
2723
- isFetching: isFetchingConfigs
2724
- } = useGetContentTypeConfigurationQuery(model);
2725
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2726
- React__namespace.useEffect(() => {
2727
- if (error) {
2728
- toggleNotification({
2729
- type: "danger",
2730
- message: formatAPIError(error)
2731
- });
2782
+ const HeaderActions = ({ actions: actions2 }) => {
2783
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2784
+ const handleClick = (action) => async (e) => {
2785
+ if (!("options" in action)) {
2786
+ const { onClick = () => false, dialog, id } = action;
2787
+ const muteDialog = await onClick(e);
2788
+ if (dialog && !muteDialog) {
2789
+ e.preventDefault();
2790
+ setDialogId(id);
2791
+ }
2732
2792
  }
2733
- }, [error, formatAPIError, toggleNotification]);
2734
- const editLayout = React__namespace.useMemo(
2735
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2736
- layout: [],
2737
- components: {},
2738
- metadatas: {},
2739
- options: {},
2740
- settings: DEFAULT_SETTINGS
2741
- },
2742
- [data, isLoading, schemas, schema, components]
2743
- );
2744
- const listLayout = React__namespace.useMemo(() => {
2745
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2746
- layout: [],
2747
- metadatas: {},
2748
- options: {},
2749
- settings: DEFAULT_SETTINGS
2750
- };
2751
- }, [data, isLoading, schemas, schema, components]);
2752
- const { layout: edit } = React__namespace.useMemo(
2753
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2754
- layout: editLayout,
2755
- query
2756
- }),
2757
- [editLayout, query, runHookWaterfall]
2758
- );
2759
- return {
2760
- error,
2761
- isLoading,
2762
- edit,
2763
- list: listLayout
2764
2793
  };
2765
- };
2766
- const useDocLayout = () => {
2767
- const { model } = useDoc();
2768
- return useDocumentLayout(model);
2769
- };
2770
- const formatEditLayout = (data, {
2771
- schemas,
2772
- schema,
2773
- components
2774
- }) => {
2775
- let currentPanelIndex = 0;
2776
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2777
- data.contentType.layouts.edit,
2778
- schema?.attributes,
2779
- data.contentType.metadatas,
2780
- { configurations: data.components, schemas: components },
2781
- schemas
2782
- ).reduce((panels, row) => {
2783
- if (row.some((field) => field.type === "dynamiczone")) {
2784
- panels.push([row]);
2785
- currentPanelIndex += 2;
2794
+ const handleClose = () => {
2795
+ setDialogId(null);
2796
+ };
2797
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2798
+ if (action.options) {
2799
+ return /* @__PURE__ */ jsxRuntime.jsx(
2800
+ designSystem.SingleSelect,
2801
+ {
2802
+ size: "S",
2803
+ onChange: action.onSelect,
2804
+ "aria-label": action.label,
2805
+ ...action,
2806
+ children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2807
+ },
2808
+ action.id
2809
+ );
2786
2810
  } else {
2787
- if (!panels[currentPanelIndex]) {
2788
- panels.push([]);
2811
+ if (action.type === "icon") {
2812
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2813
+ /* @__PURE__ */ jsxRuntime.jsx(
2814
+ designSystem.IconButton,
2815
+ {
2816
+ disabled: action.disabled,
2817
+ label: action.label,
2818
+ size: "S",
2819
+ onClick: handleClick(action),
2820
+ children: action.icon
2821
+ }
2822
+ ),
2823
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2824
+ HeaderActionDialog,
2825
+ {
2826
+ ...action.dialog,
2827
+ isOpen: dialogId === action.id,
2828
+ onClose: handleClose
2829
+ }
2830
+ ) : null
2831
+ ] }, action.id);
2789
2832
  }
2790
- panels[currentPanelIndex].push(row);
2791
2833
  }
2792
- return panels;
2793
- }, []);
2794
- const componentEditAttributes = Object.entries(data.components).reduce(
2795
- (acc, [uid, configuration]) => {
2796
- acc[uid] = {
2797
- layout: convertEditLayoutToFieldLayouts(
2798
- configuration.layouts.edit,
2799
- components[uid].attributes,
2800
- configuration.metadatas,
2801
- { configurations: data.components, schemas: components }
2802
- ),
2803
- settings: {
2804
- ...configuration.settings,
2805
- icon: components[uid].info.icon,
2806
- displayName: components[uid].info.displayName
2807
- }
2808
- };
2809
- return acc;
2834
+ }) });
2835
+ };
2836
+ const HeaderActionDialog = ({
2837
+ onClose,
2838
+ onCancel,
2839
+ title,
2840
+ content: Content,
2841
+ isOpen
2842
+ }) => {
2843
+ const handleClose = async () => {
2844
+ if (onCancel) {
2845
+ await onCancel();
2846
+ }
2847
+ onClose();
2848
+ };
2849
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2850
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2851
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2852
+ ] }) });
2853
+ };
2854
+ const ConfigureTheViewAction = ({ collectionType, model }) => {
2855
+ const navigate = reactRouterDom.useNavigate();
2856
+ const { formatMessage } = reactIntl.useIntl();
2857
+ return {
2858
+ label: formatMessage({
2859
+ id: "app.links.configure-view",
2860
+ defaultMessage: "Configure the view"
2861
+ }),
2862
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2863
+ onClick: () => {
2864
+ navigate(`../${collectionType}/${model}/configurations/edit`);
2810
2865
  },
2811
- {}
2812
- );
2813
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2814
- (acc, [attribute, metadata]) => {
2815
- return {
2816
- ...acc,
2817
- [attribute]: metadata.edit
2818
- };
2866
+ position: "header"
2867
+ };
2868
+ };
2869
+ ConfigureTheViewAction.type = "configure-the-view";
2870
+ const EditTheModelAction = ({ model }) => {
2871
+ const navigate = reactRouterDom.useNavigate();
2872
+ const { formatMessage } = reactIntl.useIntl();
2873
+ return {
2874
+ label: formatMessage({
2875
+ id: "content-manager.link-to-ctb",
2876
+ defaultMessage: "Edit the model"
2877
+ }),
2878
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2879
+ onClick: () => {
2880
+ navigate(`/plugins/content-type-builder/content-types/${model}`);
2819
2881
  },
2820
- {}
2821
- );
2882
+ position: "header"
2883
+ };
2884
+ };
2885
+ EditTheModelAction.type = "edit-the-model";
2886
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2887
+ const navigate = reactRouterDom.useNavigate();
2888
+ const { formatMessage } = reactIntl.useIntl();
2889
+ const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2890
+ const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2891
+ const { delete: deleteAction } = useDocumentActions();
2892
+ const { toggleNotification } = strapiAdmin.useNotification();
2893
+ const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2894
+ const isLocalized = document?.locale != null;
2822
2895
  return {
2823
- layout: panelledEditAttributes,
2824
- components: componentEditAttributes,
2825
- metadatas: editMetadatas,
2826
- settings: {
2827
- ...data.contentType.settings,
2828
- displayName: schema?.info.displayName
2896
+ disabled: !canDelete || !document,
2897
+ label: formatMessage(
2898
+ {
2899
+ id: "content-manager.actions.delete.label",
2900
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2901
+ },
2902
+ { isLocalized }
2903
+ ),
2904
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2905
+ dialog: {
2906
+ type: "dialog",
2907
+ title: formatMessage({
2908
+ id: "app.components.ConfirmDialog.title",
2909
+ defaultMessage: "Confirmation"
2910
+ }),
2911
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2912
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2913
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2914
+ id: "content-manager.actions.delete.dialog.body",
2915
+ defaultMessage: "Are you sure?"
2916
+ }) })
2917
+ ] }),
2918
+ onConfirm: async () => {
2919
+ if (!listViewPathMatch) {
2920
+ setSubmitting(true);
2921
+ }
2922
+ try {
2923
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2924
+ console.error(
2925
+ "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2926
+ );
2927
+ toggleNotification({
2928
+ message: formatMessage({
2929
+ id: "content-manager.actions.delete.error",
2930
+ defaultMessage: "An error occurred while trying to delete the document."
2931
+ }),
2932
+ type: "danger"
2933
+ });
2934
+ return;
2935
+ }
2936
+ const res = await deleteAction({
2937
+ documentId,
2938
+ model,
2939
+ collectionType,
2940
+ params: {
2941
+ locale: "*"
2942
+ }
2943
+ });
2944
+ if (!("error" in res)) {
2945
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2946
+ }
2947
+ } finally {
2948
+ if (!listViewPathMatch) {
2949
+ setSubmitting(false);
2950
+ }
2951
+ }
2952
+ }
2829
2953
  },
2830
- options: {
2831
- ...schema?.options,
2832
- ...schema?.pluginOptions,
2833
- ...data.contentType.options
2834
- }
2954
+ variant: "danger",
2955
+ position: ["header", "table-row"]
2835
2956
  };
2836
2957
  };
2837
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2838
- return rows.map(
2839
- (row) => row.map((field) => {
2840
- const attribute = attributes[field.name];
2841
- if (!attribute) {
2842
- return null;
2843
- }
2844
- const { edit: metadata } = metadatas[field.name];
2845
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2846
- return {
2847
- attribute,
2848
- disabled: !metadata.editable,
2849
- hint: metadata.description,
2850
- label: metadata.label ?? "",
2851
- name: field.name,
2852
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2853
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2854
- schemas,
2855
- components: components?.schemas ?? {}
2856
- }),
2857
- placeholder: metadata.placeholder ?? "",
2858
- required: attribute.required ?? false,
2859
- size: field.size,
2860
- unique: "unique" in attribute ? attribute.unique : false,
2861
- visible: metadata.visible ?? true,
2862
- type: attribute.type
2863
- };
2864
- }).filter((field) => field !== null)
2865
- );
2958
+ DeleteAction$1.type = "delete";
2959
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2960
+ const Panels = () => {
2961
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2962
+ const [
2963
+ {
2964
+ query: { status }
2965
+ }
2966
+ ] = strapiAdmin.useQueryParams({
2967
+ status: "draft"
2968
+ });
2969
+ const { model, id, document, meta, collectionType } = useDoc();
2970
+ const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2971
+ const props = {
2972
+ activeTab: status,
2973
+ model,
2974
+ documentId: id,
2975
+ document: isCloning ? void 0 : document,
2976
+ meta: isCloning ? void 0 : meta,
2977
+ collectionType
2978
+ };
2979
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2980
+ strapiAdmin.DescriptionComponentRenderer,
2981
+ {
2982
+ props,
2983
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2984
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2985
+ }
2986
+ ) });
2866
2987
  };
2867
- const formatListLayout = (data, {
2868
- schemas,
2869
- schema,
2870
- components
2871
- }) => {
2872
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2873
- (acc, [attribute, metadata]) => {
2874
- return {
2875
- ...acc,
2876
- [attribute]: metadata.list
2877
- };
2878
- },
2879
- {}
2880
- );
2881
- const listAttributes = convertListLayoutToFieldLayouts(
2882
- data.contentType.layouts.list,
2883
- schema?.attributes,
2884
- listMetadatas,
2885
- { configurations: data.components, schemas: components },
2886
- schemas
2887
- );
2988
+ const ActionsPanel = () => {
2989
+ const { formatMessage } = reactIntl.useIntl();
2888
2990
  return {
2889
- layout: listAttributes,
2890
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2891
- metadatas: listMetadatas,
2892
- options: {
2893
- ...schema?.options,
2894
- ...schema?.pluginOptions,
2895
- ...data.contentType.options
2896
- }
2991
+ title: formatMessage({
2992
+ id: "content-manager.containers.edit.panels.default.title",
2993
+ defaultMessage: "Entry"
2994
+ }),
2995
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2897
2996
  };
2898
2997
  };
2899
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2900
- return columns.map((name) => {
2901
- const attribute = attributes[name];
2902
- if (!attribute) {
2903
- return null;
2998
+ ActionsPanel.type = "actions";
2999
+ const ActionsPanelContent = () => {
3000
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
3001
+ const [
3002
+ {
3003
+ query: { status = "draft" }
2904
3004
  }
2905
- const metadata = metadatas[name];
2906
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2907
- return {
2908
- attribute,
2909
- label: metadata.label ?? "",
2910
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2911
- schemas,
2912
- components: components?.schemas ?? {}
2913
- }),
2914
- name,
2915
- searchable: metadata.searchable ?? true,
2916
- sortable: metadata.sortable ?? true
2917
- };
2918
- }).filter((field) => field !== null);
3005
+ ] = strapiAdmin.useQueryParams();
3006
+ const { model, id, document, meta, collectionType } = useDoc();
3007
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
3008
+ const props = {
3009
+ activeTab: status,
3010
+ model,
3011
+ documentId: id,
3012
+ document: isCloning ? void 0 : document,
3013
+ meta: isCloning ? void 0 : meta,
3014
+ collectionType
3015
+ };
3016
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3017
+ /* @__PURE__ */ jsxRuntime.jsx(
3018
+ strapiAdmin.DescriptionComponentRenderer,
3019
+ {
3020
+ props,
3021
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3022
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3023
+ }
3024
+ ),
3025
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3026
+ ] });
2919
3027
  };
3028
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3029
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3030
+ designSystem.Flex,
3031
+ {
3032
+ ref,
3033
+ tag: "aside",
3034
+ "aria-labelledby": "additional-information",
3035
+ background: "neutral0",
3036
+ borderColor: "neutral150",
3037
+ hasRadius: true,
3038
+ paddingBottom: 4,
3039
+ paddingLeft: 4,
3040
+ paddingRight: 4,
3041
+ paddingTop: 4,
3042
+ shadow: "tableShadow",
3043
+ gap: 3,
3044
+ direction: "column",
3045
+ justifyContent: "stretch",
3046
+ alignItems: "flex-start",
3047
+ children: [
3048
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3049
+ children
3050
+ ]
3051
+ }
3052
+ );
3053
+ });
2920
3054
  const ConfirmBulkActionDialog = ({
2921
3055
  onToggleDialog,
2922
3056
  isOpen = false,
@@ -3346,8 +3480,7 @@ const PublishAction = ({ documents, model }) => {
3346
3480
  const refetchList = () => {
3347
3481
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3348
3482
  };
3349
- if (!showPublishButton)
3350
- return null;
3483
+ if (!showPublishButton) return null;
3351
3484
  return {
3352
3485
  actionType: "publish",
3353
3486
  variant: "tertiary",
@@ -3415,8 +3548,7 @@ const DeleteAction = ({ documents, model }) => {
3415
3548
  selectRow([]);
3416
3549
  }
3417
3550
  };
3418
- if (!hasDeletePermission)
3419
- return null;
3551
+ if (!hasDeletePermission) return null;
3420
3552
  return {
3421
3553
  variant: "danger-light",
3422
3554
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3465,8 +3597,7 @@ const UnpublishAction = ({ documents, model }) => {
3465
3597
  }
3466
3598
  };
3467
3599
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3468
- if (!showUnpublishButton)
3469
- return null;
3600
+ if (!showUnpublishButton) return null;
3470
3601
  return {
3471
3602
  variant: "tertiary",
3472
3603
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3802,10 +3933,8 @@ class ContentManagerPlugin {
3802
3933
  const getPrintableType = (value) => {
3803
3934
  const nativeType = typeof value;
3804
3935
  if (nativeType === "object") {
3805
- if (value === null)
3806
- return "null";
3807
- if (Array.isArray(value))
3808
- return "array";
3936
+ if (value === null) return "null";
3937
+ if (Array.isArray(value)) return "array";
3809
3938
  if (value instanceof Object && value.constructor.name !== "Object") {
3810
3939
  return value.constructor.name;
3811
3940
  }
@@ -3894,6 +4023,15 @@ const { setInitialData } = actions;
3894
4023
  const reducer = toolkit.combineReducers({
3895
4024
  app: reducer$1
3896
4025
  });
4026
+ const FEATURE_ID = "preview";
4027
+ const previewAdmin = {
4028
+ bootstrap(app) {
4029
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4030
+ return {};
4031
+ }
4032
+ console.log("Bootstrapping preview admin");
4033
+ }
4034
+ };
3897
4035
  const index = {
3898
4036
  register(app) {
3899
4037
  const cm = new ContentManagerPlugin();
@@ -3913,7 +4051,7 @@ const index = {
3913
4051
  app.router.addRoute({
3914
4052
  path: "content-manager/*",
3915
4053
  lazy: async () => {
3916
- const { Layout } = await Promise.resolve().then(() => require("./layout-B4XAqu1v.js"));
4054
+ const { Layout } = await Promise.resolve().then(() => require("./layout-a7hNwceU.js"));
3917
4055
  return {
3918
4056
  Component: Layout
3919
4057
  };
@@ -3926,11 +4064,14 @@ const index = {
3926
4064
  if (typeof historyAdmin.bootstrap === "function") {
3927
4065
  historyAdmin.bootstrap(app);
3928
4066
  }
4067
+ if (typeof previewAdmin.bootstrap === "function") {
4068
+ previewAdmin.bootstrap(app);
4069
+ }
3929
4070
  },
3930
4071
  async registerTrads({ locales }) {
3931
4072
  const importedTrads = await Promise.all(
3932
4073
  locales.map((locale) => {
3933
- 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-Cf41pH5f.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 }) => {
4074
+ 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-Bm0D0IWz.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`, 3).then(({ default: data }) => {
3934
4075
  return {
3935
4076
  data: prefixPluginTranslations(data, PLUGIN_ID),
3936
4077
  locale
@@ -3976,6 +4117,7 @@ exports.getMainField = getMainField;
3976
4117
  exports.getTranslation = getTranslation;
3977
4118
  exports.index = index;
3978
4119
  exports.setInitialData = setInitialData;
4120
+ exports.useContentManagerContext = useContentManagerContext;
3979
4121
  exports.useContentTypeSchema = useContentTypeSchema;
3980
4122
  exports.useDoc = useDoc;
3981
4123
  exports.useDocLayout = useDocLayout;
@@ -3988,4 +4130,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3988
4130
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3989
4131
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3990
4132
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3991
- //# sourceMappingURL=index-CQos-KS0.js.map
4133
+ //# sourceMappingURL=index-BwWfprNi.js.map