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

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