@strapi/content-manager 0.0.0-experimental.32c4b04580cc12400710050c8198e46b3644cfd4 → 0.0.0-experimental.332a7d5b6b1d23635d7e205657f0ff39ec133c9e

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 (215) hide show
  1. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  2. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-DdkVGfXC.js} +5 -6
  6. package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
  7. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  9. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  10. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-D1nvB7Br.mjs} +4 -4
  11. package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-LYEvR4fW.js} +5 -6
  13. package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-Bcnff6Vd.mjs} +34 -46
  15. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
  16. package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-DqelJ9UK.js} +36 -49
  17. package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
  18. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  19. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  20. package/dist/_chunks/{Form-CPYqIWDG.js → Form-CnHfBeiB.js} +39 -21
  21. package/dist/_chunks/Form-CnHfBeiB.js.map +1 -0
  22. package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-CzPCJi3B.mjs} +37 -18
  23. package/dist/_chunks/Form-CzPCJi3B.mjs.map +1 -0
  24. package/dist/_chunks/{History-wrnHqf09.mjs → History-CcmSn3Mj.mjs} +71 -104
  25. package/dist/_chunks/History-CcmSn3Mj.mjs.map +1 -0
  26. package/dist/_chunks/{History-DNQkXANT.js → History-zArjENzj.js} +81 -115
  27. package/dist/_chunks/History-zArjENzj.js.map +1 -0
  28. package/dist/_chunks/{Field-Bfph5SOd.js → Input-CDHKQd7o.js} +1334 -1239
  29. package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
  30. package/dist/_chunks/{Field-Cs7duwWd.mjs → Input-aV8SSoTa.mjs} +1192 -1097
  31. package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-BPvzENJJ.mjs} +19 -8
  33. package/dist/_chunks/ListConfigurationPage-BPvzENJJ.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-ByZAO_9H.js} +19 -9
  35. package/dist/_chunks/ListConfigurationPage-ByZAO_9H.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-BVKBeQAA.js} +108 -74
  37. package/dist/_chunks/ListViewPage-BVKBeQAA.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-HljQVnFH.mjs} +109 -74
  39. package/dist/_chunks/ListViewPage-HljQVnFH.mjs.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-BV5zfDxr.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
  48. package/dist/_chunks/Preview-DEHdENT1.js +305 -0
  49. package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
  50. package/dist/_chunks/Preview-vfWOtPG5.mjs +287 -0
  51. package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-B7_hbF0w.mjs} +79 -44
  53. package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
  54. package/dist/_chunks/{Relations-CtELXYIK.js → Relations-DcoOBejP.js} +79 -45
  55. package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
  56. package/dist/_chunks/{en-uOUIxfcQ.js → en-BR48D_RH.js} +35 -15
  57. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BR48D_RH.js.map} +1 -1
  58. package/dist/_chunks/{en-BrCTWlZv.mjs → en-D65uIF6Y.mjs} +35 -15
  59. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  60. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  61. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  62. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  63. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  64. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  65. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  66. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  67. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  68. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  69. package/dist/_chunks/{index-OerGjbAN.js → index-CxLSGwnk.js} +1304 -750
  70. package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
  71. package/dist/_chunks/{index-c_5DdJi-.mjs → index-EH8ZtHd5.mjs} +1323 -769
  72. package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
  73. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  74. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  75. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  77. package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-CxDMdJ13.mjs} +23 -10
  78. package/dist/_chunks/layout-CxDMdJ13.mjs.map +1 -0
  79. package/dist/_chunks/{layout-Ci7qHlFb.js → layout-DSeUTfMv.js} +23 -11
  80. package/dist/_chunks/layout-DSeUTfMv.js.map +1 -0
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-B8_Uu38Q.mjs} +21 -8
  86. package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
  87. package/dist/_chunks/{relations-COBpStiF.js → relations-S5nNKdN3.js} +20 -7
  88. package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
  89. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  91. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  93. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -1
  94. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -1
  95. package/dist/admin/index.js +3 -1
  96. package/dist/admin/index.js.map +1 -1
  97. package/dist/admin/index.mjs +6 -4
  98. package/dist/admin/src/content-manager.d.ts +3 -2
  99. package/dist/admin/src/exports.d.ts +2 -1
  100. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  101. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  102. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  103. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  104. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  105. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  106. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  107. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  108. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  109. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  110. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  111. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  112. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  113. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  114. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  115. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  116. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  117. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  118. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  119. package/dist/admin/src/preview/index.d.ts +4 -0
  120. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  121. package/dist/admin/src/preview/routes.d.ts +3 -0
  122. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  123. package/dist/admin/src/router.d.ts +1 -1
  124. package/dist/admin/src/services/api.d.ts +1 -1
  125. package/dist/admin/src/services/components.d.ts +2 -2
  126. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  127. package/dist/admin/src/services/documents.d.ts +19 -20
  128. package/dist/admin/src/services/init.d.ts +1 -1
  129. package/dist/admin/src/services/relations.d.ts +2 -2
  130. package/dist/admin/src/services/uid.d.ts +3 -3
  131. package/dist/admin/src/utils/validation.d.ts +4 -1
  132. package/dist/server/index.js +727 -406
  133. package/dist/server/index.js.map +1 -1
  134. package/dist/server/index.mjs +728 -406
  135. package/dist/server/index.mjs.map +1 -1
  136. package/dist/server/src/bootstrap.d.ts.map +1 -1
  137. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  138. package/dist/server/src/controllers/index.d.ts.map +1 -1
  139. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  140. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  141. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  142. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  143. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  144. package/dist/server/src/history/services/history.d.ts +3 -3
  145. package/dist/server/src/history/services/history.d.ts.map +1 -1
  146. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  147. package/dist/server/src/history/services/utils.d.ts +8 -12
  148. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  149. package/dist/server/src/index.d.ts +7 -6
  150. package/dist/server/src/index.d.ts.map +1 -1
  151. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  152. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  153. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  154. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  155. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  156. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  157. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  158. package/dist/server/src/preview/index.d.ts +4 -0
  159. package/dist/server/src/preview/index.d.ts.map +1 -0
  160. package/dist/server/src/preview/routes/index.d.ts +8 -0
  161. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  162. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  163. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  164. package/dist/server/src/preview/services/index.d.ts +16 -0
  165. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  166. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  167. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  168. package/dist/server/src/preview/services/preview.d.ts +12 -0
  169. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  170. package/dist/server/src/preview/utils.d.ts +19 -0
  171. package/dist/server/src/preview/utils.d.ts.map +1 -0
  172. package/dist/server/src/register.d.ts.map +1 -1
  173. package/dist/server/src/routes/index.d.ts.map +1 -1
  174. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  175. package/dist/server/src/services/document-metadata.d.ts +12 -10
  176. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  177. package/dist/server/src/services/index.d.ts +7 -6
  178. package/dist/server/src/services/index.d.ts.map +1 -1
  179. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  180. package/dist/server/src/services/utils/populate.d.ts +2 -2
  181. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  182. package/dist/server/src/utils/index.d.ts +2 -0
  183. package/dist/server/src/utils/index.d.ts.map +1 -1
  184. package/dist/shared/contracts/collection-types.d.ts +3 -1
  185. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  186. package/dist/shared/contracts/index.d.ts +1 -0
  187. package/dist/shared/contracts/index.d.ts.map +1 -1
  188. package/dist/shared/contracts/preview.d.ts +27 -0
  189. package/dist/shared/contracts/preview.d.ts.map +1 -0
  190. package/dist/shared/index.js +4 -0
  191. package/dist/shared/index.js.map +1 -1
  192. package/dist/shared/index.mjs +4 -0
  193. package/dist/shared/index.mjs.map +1 -1
  194. package/package.json +17 -16
  195. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
  196. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
  197. package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
  198. package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
  199. package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
  200. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
  201. package/dist/_chunks/History-DNQkXANT.js.map +0 -1
  202. package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
  203. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
  204. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
  205. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
  206. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
  207. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
  208. package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
  209. package/dist/_chunks/index-OerGjbAN.js.map +0 -1
  210. package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
  211. package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
  212. package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
  213. package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
  214. package/dist/_chunks/relations-COBpStiF.js.map +0 -1
  215. package/strapi-server.js +0 -3
@@ -4,18 +4,19 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
5
  const React = require("react");
6
6
  const designSystem = require("@strapi/design-system");
7
+ const mapValues = require("lodash/fp/mapValues");
7
8
  const reactIntl = require("react-intl");
8
9
  const reactRouterDom = require("react-router-dom");
9
10
  const styledComponents = require("styled-components");
10
11
  const yup = require("yup");
12
+ const fractionalIndexing = require("fractional-indexing");
11
13
  const pipe = require("lodash/fp/pipe");
12
- const dateFns = require("date-fns");
13
14
  const qs = require("qs");
15
+ const dateFns = require("date-fns");
14
16
  const toolkit = require("@reduxjs/toolkit");
15
17
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
18
  function _interopNamespace(e) {
17
- if (e && e.__esModule)
18
- return e;
19
+ if (e && e.__esModule) return e;
19
20
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
21
  if (e) {
21
22
  for (const k in e) {
@@ -32,15 +33,23 @@ function _interopNamespace(e) {
32
33
  return Object.freeze(n);
33
34
  }
34
35
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
36
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
37
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
38
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
39
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
38
40
  const v = glob[path];
39
41
  if (v) {
40
42
  return typeof v === "function" ? v() : Promise.resolve(v);
41
43
  }
42
44
  return new Promise((_, reject) => {
43
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
45
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
46
+ reject.bind(
47
+ null,
48
+ new Error(
49
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
50
+ )
51
+ )
52
+ );
44
53
  });
45
54
  };
46
55
  const PLUGIN_ID = "content-manager";
@@ -121,6 +130,7 @@ const DocumentRBAC = ({ children, permissions }) => {
121
130
  if (!slug) {
122
131
  throw new Error("Cannot find the slug param in the URL");
123
132
  }
133
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
124
134
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
125
135
  const contentTypePermissions = React__namespace.useMemo(() => {
126
136
  const contentTypePermissions2 = userPermissions.filter(
@@ -131,7 +141,14 @@ const DocumentRBAC = ({ children, permissions }) => {
131
141
  return { ...acc, [action]: [permission] };
132
142
  }, {});
133
143
  }, [slug, userPermissions]);
134
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
144
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
145
+ contentTypePermissions,
146
+ permissions ?? void 0,
147
+ // TODO: useRBAC context should be typed and built differently
148
+ // We are passing raw query as context to the hook so that it can
149
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
150
+ rawQuery
151
+ );
135
152
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
136
153
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
137
154
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -171,6 +188,113 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
171
188
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
172
189
  );
173
190
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
191
+ const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
192
+ const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
193
+ const traverse = (datum, attributes) => {
194
+ return Object.entries(datum).reduce((acc, [key, value]) => {
195
+ const attribute = attributes[key];
196
+ if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
197
+ acc[key] = value;
198
+ return acc;
199
+ }
200
+ if (attribute.type === "component") {
201
+ if (attribute.repeatable) {
202
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
203
+ acc[key] = componentValue.map(
204
+ (componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
205
+ );
206
+ } else {
207
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
208
+ acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
209
+ }
210
+ } else if (attribute.type === "dynamiczone") {
211
+ const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
212
+ acc[key] = dynamicZoneValue.map(
213
+ (componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
214
+ );
215
+ } else if (predicate(attribute, value)) {
216
+ acc[key] = transform(value, attribute);
217
+ } else {
218
+ acc[key] = value;
219
+ }
220
+ return acc;
221
+ }, {});
222
+ };
223
+ return traverse(data, schema.attributes);
224
+ };
225
+ const removeProhibitedFields = (prohibitedFields) => traverseData(
226
+ (attribute) => prohibitedFields.includes(attribute.type),
227
+ () => ""
228
+ );
229
+ const prepareRelations = traverseData(
230
+ (attribute) => attribute.type === "relation",
231
+ () => ({
232
+ connect: [],
233
+ disconnect: []
234
+ })
235
+ );
236
+ const prepareTempKeys = traverseData(
237
+ (attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
238
+ (data) => {
239
+ if (Array.isArray(data) && data.length > 0) {
240
+ const keys = fractionalIndexing.generateNKeysBetween(void 0, void 0, data.length);
241
+ return data.map((datum, index2) => ({
242
+ ...datum,
243
+ __temp_key__: keys[index2]
244
+ }));
245
+ }
246
+ return data;
247
+ }
248
+ );
249
+ const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
250
+ const schemaKeys = Object.keys(schema.attributes);
251
+ const dataKeys = Object.keys(data);
252
+ const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
253
+ const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
254
+ delete acc[key];
255
+ return acc;
256
+ }, structuredClone(data));
257
+ return revisedData;
258
+ };
259
+ const removeNullValues = (data) => {
260
+ return Object.entries(data).reduce((acc, [key, value]) => {
261
+ if (value === null) {
262
+ return acc;
263
+ }
264
+ acc[key] = value;
265
+ return acc;
266
+ }, {});
267
+ };
268
+ const transformDocument = (schema, components = {}) => (document) => {
269
+ const transformations = pipe__default.default(
270
+ removeFieldsThatDontExistOnSchema(schema),
271
+ removeProhibitedFields(["password"])(schema, components),
272
+ removeNullValues,
273
+ prepareRelations(schema, components),
274
+ prepareTempKeys(schema, components)
275
+ );
276
+ return transformations(document);
277
+ };
278
+ const createDefaultForm = (contentType, components = {}) => {
279
+ const traverseSchema = (attributes) => {
280
+ return Object.entries(attributes).reduce((acc, [key, attribute]) => {
281
+ if ("default" in attribute) {
282
+ acc[key] = attribute.default;
283
+ } else if (attribute.type === "component" && attribute.required) {
284
+ const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
285
+ if (attribute.repeatable) {
286
+ acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
287
+ } else {
288
+ acc[key] = defaultComponentForm;
289
+ }
290
+ } else if (attribute.type === "dynamiczone" && attribute.required) {
291
+ acc[key] = [];
292
+ }
293
+ return acc;
294
+ }, {});
295
+ };
296
+ return traverseSchema(contentType.attributes);
297
+ };
174
298
  const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
175
299
  addTagTypes: [
176
300
  "ComponentConfiguration",
@@ -179,7 +303,9 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
179
303
  "Document",
180
304
  "InitialData",
181
305
  "HistoryVersion",
182
- "Relations"
306
+ "Relations",
307
+ "UidAvailability",
308
+ "RecentDocumentList"
183
309
  ]
184
310
  });
185
311
  const documentApi = contentManagerApi.injectEndpoints({
@@ -197,7 +323,7 @@ const documentApi = contentManagerApi.injectEndpoints({
197
323
  if (error) {
198
324
  return [];
199
325
  }
200
- return [{ type: "Document", id: `${model}_LIST` }];
326
+ return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
201
327
  }
202
328
  }),
203
329
  cloneDocument: builder.mutation({
@@ -209,7 +335,11 @@ const documentApi = contentManagerApi.injectEndpoints({
209
335
  params
210
336
  }
211
337
  }),
212
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
338
+ invalidatesTags: (_result, _error, { model }) => [
339
+ { type: "Document", id: `${model}_LIST` },
340
+ { type: "UidAvailability", id: model },
341
+ "RecentDocumentList"
342
+ ]
213
343
  }),
214
344
  /**
215
345
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -226,8 +356,22 @@ const documentApi = contentManagerApi.injectEndpoints({
226
356
  }),
227
357
  invalidatesTags: (result, _error, { model }) => [
228
358
  { type: "Document", id: `${model}_LIST` },
229
- "Relations"
230
- ]
359
+ "Relations",
360
+ { type: "UidAvailability", id: model },
361
+ "RecentDocumentList"
362
+ ],
363
+ transformResponse: (response, meta, arg) => {
364
+ if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
365
+ return {
366
+ data: response,
367
+ meta: {
368
+ availableStatus: [],
369
+ availableLocales: []
370
+ }
371
+ };
372
+ }
373
+ return response;
374
+ }
231
375
  }),
232
376
  deleteDocument: builder.mutation({
233
377
  query: ({ collectionType, model, documentId, params }) => ({
@@ -238,7 +382,8 @@ const documentApi = contentManagerApi.injectEndpoints({
238
382
  }
239
383
  }),
240
384
  invalidatesTags: (_result, _error, { collectionType, model }) => [
241
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
385
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
386
+ "RecentDocumentList"
242
387
  ]
243
388
  }),
244
389
  deleteManyDocuments: builder.mutation({
@@ -250,7 +395,10 @@ const documentApi = contentManagerApi.injectEndpoints({
250
395
  params
251
396
  }
252
397
  }),
253
- invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
398
+ invalidatesTags: (_res, _error, { model }) => [
399
+ { type: "Document", id: `${model}_LIST` },
400
+ "RecentDocumentList"
401
+ ]
254
402
  }),
255
403
  discardDocument: builder.mutation({
256
404
  query: ({ collectionType, model, documentId, params }) => ({
@@ -267,7 +415,9 @@ const documentApi = contentManagerApi.injectEndpoints({
267
415
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
268
416
  },
269
417
  { type: "Document", id: `${model}_LIST` },
270
- "Relations"
418
+ "Relations",
419
+ { type: "UidAvailability", id: model },
420
+ "RecentDocumentList"
271
421
  ];
272
422
  }
273
423
  }),
@@ -280,11 +430,12 @@ const documentApi = contentManagerApi.injectEndpoints({
280
430
  url: `/content-manager/collection-types/${model}`,
281
431
  method: "GET",
282
432
  config: {
283
- params
433
+ params: qs.stringify(params, { encode: true })
284
434
  }
285
435
  }),
286
436
  providesTags: (result, _error, arg) => {
287
437
  return [
438
+ { type: "Document", id: `ALL_LIST` },
288
439
  { type: "Document", id: `${arg.model}_LIST` },
289
440
  ...result?.results.map(({ documentId }) => ({
290
441
  type: "Document",
@@ -323,6 +474,11 @@ const documentApi = contentManagerApi.injectEndpoints({
323
474
  {
324
475
  type: "Document",
325
476
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
477
+ },
478
+ // Make it easy to invalidate all individual documents queries for a model
479
+ {
480
+ type: "Document",
481
+ id: `${model}_ALL_ITEMS`
326
482
  }
327
483
  ];
328
484
  }
@@ -356,7 +512,8 @@ const documentApi = contentManagerApi.injectEndpoints({
356
512
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
357
513
  },
358
514
  { type: "Document", id: `${model}_LIST` },
359
- "Relations"
515
+ "Relations",
516
+ "RecentDocumentList"
360
517
  ];
361
518
  }
362
519
  }),
@@ -386,7 +543,10 @@ const documentApi = contentManagerApi.injectEndpoints({
386
543
  type: "Document",
387
544
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
388
545
  },
389
- "Relations"
546
+ "Relations",
547
+ { type: "UidAvailability", id: model },
548
+ "RecentDocumentList",
549
+ "RecentDocumentList"
390
550
  ];
391
551
  },
392
552
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -416,7 +576,8 @@ const documentApi = contentManagerApi.injectEndpoints({
416
576
  {
417
577
  type: "Document",
418
578
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
419
- }
579
+ },
580
+ "RecentDocumentList"
420
581
  ];
421
582
  }
422
583
  }),
@@ -429,7 +590,10 @@ const documentApi = contentManagerApi.injectEndpoints({
429
590
  params
430
591
  }
431
592
  }),
432
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
593
+ invalidatesTags: (_res, _error, { model, documentIds }) => [
594
+ ...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
595
+ "RecentDocumentList"
596
+ ]
433
597
  })
434
598
  })
435
599
  });
@@ -452,8 +616,7 @@ const {
452
616
  useUnpublishManyDocumentsMutation
453
617
  } = documentApi;
454
618
  const buildValidParams = (query) => {
455
- if (!query)
456
- return query;
619
+ if (!query) return query;
457
620
  const { plugins: _, ...validQueryParams } = {
458
621
  ...query,
459
622
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -461,28 +624,44 @@ const buildValidParams = (query) => {
461
624
  {}
462
625
  )
463
626
  };
464
- if ("_q" in validQueryParams) {
465
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
466
- }
467
627
  return validQueryParams;
468
628
  };
469
629
  const isBaseQueryError = (error) => {
470
630
  return error.name !== void 0;
471
631
  };
472
- const createYupSchema = (attributes = {}, components = {}) => {
632
+ const arrayValidator = (attribute, options) => ({
633
+ message: strapiAdmin.translatedErrors.required,
634
+ test(value) {
635
+ if (options.status === "draft") {
636
+ return true;
637
+ }
638
+ if (!attribute.required) {
639
+ return true;
640
+ }
641
+ if (!value) {
642
+ return false;
643
+ }
644
+ if (Array.isArray(value) && value.length === 0) {
645
+ return false;
646
+ }
647
+ return true;
648
+ }
649
+ });
650
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
473
651
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
474
652
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
475
653
  if (DOCUMENT_META_FIELDS.includes(name)) {
476
654
  return acc;
477
655
  }
478
656
  const validations = [
657
+ addNullableValidation,
479
658
  addRequiredValidation,
480
659
  addMinLengthValidation,
481
660
  addMaxLengthValidation,
482
661
  addMinValidation,
483
662
  addMaxValidation,
484
663
  addRegexValidation
485
- ].map((fn) => fn(attribute));
664
+ ].map((fn) => fn(attribute, options));
486
665
  const transformSchema = pipe__default.default(...validations);
487
666
  switch (attribute.type) {
488
667
  case "component": {
@@ -492,12 +671,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
492
671
  ...acc,
493
672
  [name]: transformSchema(
494
673
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
495
- )
674
+ ).test(arrayValidator(attribute, options))
496
675
  };
497
676
  } else {
498
677
  return {
499
678
  ...acc,
500
- [name]: transformSchema(createModelSchema(attributes3))
679
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
501
680
  };
502
681
  }
503
682
  }
@@ -519,7 +698,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
519
698
  }
520
699
  )
521
700
  )
522
- )
701
+ ).test(arrayValidator(attribute, options))
523
702
  };
524
703
  case "relation":
525
704
  return {
@@ -531,7 +710,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
531
710
  } else if (Array.isArray(value)) {
532
711
  return yup__namespace.array().of(
533
712
  yup__namespace.object().shape({
534
- id: yup__namespace.string().required()
713
+ id: yup__namespace.number().required()
535
714
  })
536
715
  );
537
716
  } else if (typeof value === "object") {
@@ -583,6 +762,14 @@ const createAttributeSchema = (attribute) => {
583
762
  if (!value || typeof value === "string" && value.length === 0) {
584
763
  return true;
585
764
  }
765
+ if (typeof value === "object") {
766
+ try {
767
+ JSON.stringify(value);
768
+ return true;
769
+ } catch (err) {
770
+ return false;
771
+ }
772
+ }
586
773
  try {
587
774
  JSON.parse(value);
588
775
  return true;
@@ -601,13 +788,7 @@ const createAttributeSchema = (attribute) => {
601
788
  return yup__namespace.mixed();
602
789
  }
603
790
  };
604
- const addRequiredValidation = (attribute) => (schema) => {
605
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
606
- return schema.min(1, strapiAdmin.translatedErrors.required);
607
- }
608
- if (attribute.required && attribute.type !== "relation") {
609
- return schema.required(strapiAdmin.translatedErrors.required);
610
- }
791
+ const nullableSchema = (schema) => {
611
792
  return schema?.nullable ? schema.nullable() : (
612
793
  // In some cases '.nullable' will not be available on the schema.
613
794
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -615,7 +796,22 @@ const addRequiredValidation = (attribute) => (schema) => {
615
796
  schema
616
797
  );
617
798
  };
618
- const addMinLengthValidation = (attribute) => (schema) => {
799
+ const addNullableValidation = () => (schema) => {
800
+ return nullableSchema(schema);
801
+ };
802
+ const addRequiredValidation = (attribute, options) => (schema) => {
803
+ if (options.status === "draft" || !attribute.required) {
804
+ return schema;
805
+ }
806
+ if (attribute.required && "required" in schema) {
807
+ return schema.required(strapiAdmin.translatedErrors.required);
808
+ }
809
+ return schema;
810
+ };
811
+ const addMinLengthValidation = (attribute, options) => (schema) => {
812
+ if (options.status === "draft") {
813
+ return schema;
814
+ }
619
815
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
620
816
  return schema.min(attribute.minLength, {
621
817
  ...strapiAdmin.translatedErrors.minLength,
@@ -637,32 +833,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
637
833
  }
638
834
  return schema;
639
835
  };
640
- const addMinValidation = (attribute) => (schema) => {
641
- if ("min" in attribute) {
836
+ const addMinValidation = (attribute, options) => (schema) => {
837
+ if (options.status === "draft") {
838
+ return schema;
839
+ }
840
+ if ("min" in attribute && "min" in schema) {
642
841
  const min = toInteger(attribute.min);
643
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
644
- if (!attribute.required && "test" in schema && min) {
645
- return schema.test(
646
- "custom-min",
647
- {
648
- ...strapiAdmin.translatedErrors.min,
649
- values: {
650
- min: attribute.min
651
- }
652
- },
653
- (value) => {
654
- if (!value) {
655
- return true;
656
- }
657
- if (Array.isArray(value) && value.length === 0) {
658
- return true;
659
- }
660
- return value.length >= min;
661
- }
662
- );
663
- }
664
- }
665
- if ("min" in schema && min) {
842
+ if (min) {
666
843
  return schema.min(min, {
667
844
  ...strapiAdmin.translatedErrors.min,
668
845
  values: {
@@ -780,19 +957,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
780
957
  }, {});
781
958
  return componentsByKey;
782
959
  };
783
- const useDocument = (args, opts) => {
960
+ const HOOKS = {
961
+ /**
962
+ * Hook that allows to mutate the displayed headers of the list view table
963
+ * @constant
964
+ * @type {string}
965
+ */
966
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
967
+ /**
968
+ * Hook that allows to mutate the CM's collection types links pre-set filters
969
+ * @constant
970
+ * @type {string}
971
+ */
972
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
973
+ /**
974
+ * Hook that allows to mutate the CM's edit view layout
975
+ * @constant
976
+ * @type {string}
977
+ */
978
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
979
+ /**
980
+ * Hook that allows to mutate the CM's single types links pre-set filters
981
+ * @constant
982
+ * @type {string}
983
+ */
984
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
985
+ };
986
+ const contentTypesApi = contentManagerApi.injectEndpoints({
987
+ endpoints: (builder) => ({
988
+ getContentTypeConfiguration: builder.query({
989
+ query: (uid) => ({
990
+ url: `/content-manager/content-types/${uid}/configuration`,
991
+ method: "GET"
992
+ }),
993
+ transformResponse: (response) => response.data,
994
+ providesTags: (_result, _error, uid) => [
995
+ { type: "ContentTypesConfiguration", id: uid },
996
+ { type: "ContentTypeSettings", id: "LIST" }
997
+ ]
998
+ }),
999
+ getAllContentTypeSettings: builder.query({
1000
+ query: () => "/content-manager/content-types-settings",
1001
+ transformResponse: (response) => response.data,
1002
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
1003
+ }),
1004
+ updateContentTypeConfiguration: builder.mutation({
1005
+ query: ({ uid, ...body }) => ({
1006
+ url: `/content-manager/content-types/${uid}/configuration`,
1007
+ method: "PUT",
1008
+ data: body
1009
+ }),
1010
+ transformResponse: (response) => response.data,
1011
+ invalidatesTags: (_result, _error, { uid }) => [
1012
+ { type: "ContentTypesConfiguration", id: uid },
1013
+ { type: "ContentTypeSettings", id: "LIST" },
1014
+ // Is this necessary?
1015
+ { type: "InitialData" }
1016
+ ]
1017
+ })
1018
+ })
1019
+ });
1020
+ const {
1021
+ useGetContentTypeConfigurationQuery,
1022
+ useGetAllContentTypeSettingsQuery,
1023
+ useUpdateContentTypeConfigurationMutation
1024
+ } = contentTypesApi;
1025
+ const checkIfAttributeIsDisplayable = (attribute) => {
1026
+ const { type } = attribute;
1027
+ if (type === "relation") {
1028
+ return !attribute.relation.toLowerCase().includes("morph");
1029
+ }
1030
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
1031
+ };
1032
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
1033
+ if (!mainFieldName) {
1034
+ return void 0;
1035
+ }
1036
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
1037
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
1038
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
1039
+ );
1040
+ return {
1041
+ name: mainFieldName,
1042
+ type: mainFieldType ?? "string"
1043
+ };
1044
+ };
1045
+ const DEFAULT_SETTINGS = {
1046
+ bulkable: false,
1047
+ filterable: false,
1048
+ searchable: false,
1049
+ pagination: false,
1050
+ defaultSortBy: "",
1051
+ defaultSortOrder: "asc",
1052
+ mainField: "id",
1053
+ pageSize: 10
1054
+ };
1055
+ const useDocumentLayout = (model) => {
1056
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
1057
+ const [{ query }] = strapiAdmin.useQueryParams();
1058
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
784
1059
  const { toggleNotification } = strapiAdmin.useNotification();
785
1060
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1061
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
786
1062
  const {
787
- currentData: data,
788
- isLoading: isLoadingDocument,
789
- isFetching: isFetchingDocument,
790
- error
791
- } = useGetDocumentQuery(args, {
792
- ...opts,
793
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
794
- });
795
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
1063
+ data,
1064
+ isLoading: isLoadingConfigs,
1065
+ error,
1066
+ isFetching: isFetchingConfigs
1067
+ } = useGetContentTypeConfigurationQuery(model);
1068
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
796
1069
  React__namespace.useEffect(() => {
797
1070
  if (error) {
798
1071
  toggleNotification({
@@ -800,40 +1073,284 @@ const useDocument = (args, opts) => {
800
1073
  message: formatAPIError(error)
801
1074
  });
802
1075
  }
803
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
804
- const validationSchema = React__namespace.useMemo(() => {
805
- if (!schema) {
806
- return null;
807
- }
808
- return createYupSchema(schema.attributes, components);
809
- }, [schema, components]);
810
- const validate = React__namespace.useCallback(
811
- (document) => {
812
- if (!validationSchema) {
813
- throw new Error(
814
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
815
- );
816
- }
817
- try {
818
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
819
- return null;
820
- } catch (error2) {
821
- if (error2 instanceof yup.ValidationError) {
822
- return strapiAdmin.getYupValidationErrors(error2);
823
- }
824
- throw error2;
825
- }
1076
+ }, [error, formatAPIError, toggleNotification]);
1077
+ const editLayout = React__namespace.useMemo(
1078
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
1079
+ layout: [],
1080
+ components: {},
1081
+ metadatas: {},
1082
+ options: {},
1083
+ settings: DEFAULT_SETTINGS
826
1084
  },
827
- [validationSchema]
1085
+ [data, isLoading, schemas, schema, components]
1086
+ );
1087
+ const listLayout = React__namespace.useMemo(() => {
1088
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
1089
+ layout: [],
1090
+ metadatas: {},
1091
+ options: {},
1092
+ settings: DEFAULT_SETTINGS
1093
+ };
1094
+ }, [data, isLoading, schemas, schema, components]);
1095
+ const { layout: edit } = React__namespace.useMemo(
1096
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
1097
+ layout: editLayout,
1098
+ query
1099
+ }),
1100
+ [editLayout, query, runHookWaterfall]
828
1101
  );
829
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
830
1102
  return {
831
- components,
832
- document: data?.data,
833
- meta: data?.meta,
1103
+ error,
1104
+ isLoading,
1105
+ edit,
1106
+ list: listLayout
1107
+ };
1108
+ };
1109
+ const useDocLayout = () => {
1110
+ const { model } = useDoc();
1111
+ return useDocumentLayout(model);
1112
+ };
1113
+ const formatEditLayout = (data, {
1114
+ schemas,
1115
+ schema,
1116
+ components
1117
+ }) => {
1118
+ let currentPanelIndex = 0;
1119
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
1120
+ data.contentType.layouts.edit,
1121
+ schema?.attributes,
1122
+ data.contentType.metadatas,
1123
+ { configurations: data.components, schemas: components },
1124
+ schemas
1125
+ ).reduce((panels, row) => {
1126
+ if (row.some((field) => field.type === "dynamiczone")) {
1127
+ panels.push([row]);
1128
+ currentPanelIndex += 2;
1129
+ } else {
1130
+ if (!panels[currentPanelIndex]) {
1131
+ panels.push([row]);
1132
+ } else {
1133
+ panels[currentPanelIndex].push(row);
1134
+ }
1135
+ }
1136
+ return panels;
1137
+ }, []);
1138
+ const componentEditAttributes = Object.entries(data.components).reduce(
1139
+ (acc, [uid, configuration]) => {
1140
+ acc[uid] = {
1141
+ layout: convertEditLayoutToFieldLayouts(
1142
+ configuration.layouts.edit,
1143
+ components[uid].attributes,
1144
+ configuration.metadatas,
1145
+ { configurations: data.components, schemas: components }
1146
+ ),
1147
+ settings: {
1148
+ ...configuration.settings,
1149
+ icon: components[uid].info.icon,
1150
+ displayName: components[uid].info.displayName
1151
+ }
1152
+ };
1153
+ return acc;
1154
+ },
1155
+ {}
1156
+ );
1157
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1158
+ (acc, [attribute, metadata]) => {
1159
+ return {
1160
+ ...acc,
1161
+ [attribute]: metadata.edit
1162
+ };
1163
+ },
1164
+ {}
1165
+ );
1166
+ return {
1167
+ layout: panelledEditAttributes,
1168
+ components: componentEditAttributes,
1169
+ metadatas: editMetadatas,
1170
+ settings: {
1171
+ ...data.contentType.settings,
1172
+ displayName: schema?.info.displayName
1173
+ },
1174
+ options: {
1175
+ ...schema?.options,
1176
+ ...schema?.pluginOptions,
1177
+ ...data.contentType.options
1178
+ }
1179
+ };
1180
+ };
1181
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1182
+ return rows.map(
1183
+ (row) => row.map((field) => {
1184
+ const attribute = attributes[field.name];
1185
+ if (!attribute) {
1186
+ return null;
1187
+ }
1188
+ const { edit: metadata } = metadatas[field.name];
1189
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1190
+ return {
1191
+ attribute,
1192
+ disabled: !metadata.editable,
1193
+ hint: metadata.description,
1194
+ label: metadata.label ?? "",
1195
+ name: field.name,
1196
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1197
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1198
+ schemas,
1199
+ components: components?.schemas ?? {}
1200
+ }),
1201
+ placeholder: metadata.placeholder ?? "",
1202
+ required: attribute.required ?? false,
1203
+ size: field.size,
1204
+ unique: "unique" in attribute ? attribute.unique : false,
1205
+ visible: metadata.visible ?? true,
1206
+ type: attribute.type
1207
+ };
1208
+ }).filter((field) => field !== null)
1209
+ );
1210
+ };
1211
+ const formatListLayout = (data, {
1212
+ schemas,
1213
+ schema,
1214
+ components
1215
+ }) => {
1216
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1217
+ (acc, [attribute, metadata]) => {
1218
+ return {
1219
+ ...acc,
1220
+ [attribute]: metadata.list
1221
+ };
1222
+ },
1223
+ {}
1224
+ );
1225
+ const listAttributes = convertListLayoutToFieldLayouts(
1226
+ data.contentType.layouts.list,
1227
+ schema?.attributes,
1228
+ listMetadatas,
1229
+ { configurations: data.components, schemas: components },
1230
+ schemas
1231
+ );
1232
+ return {
1233
+ layout: listAttributes,
1234
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1235
+ metadatas: listMetadatas,
1236
+ options: {
1237
+ ...schema?.options,
1238
+ ...schema?.pluginOptions,
1239
+ ...data.contentType.options
1240
+ }
1241
+ };
1242
+ };
1243
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1244
+ return columns.map((name) => {
1245
+ const attribute = attributes[name];
1246
+ if (!attribute) {
1247
+ return null;
1248
+ }
1249
+ const metadata = metadatas[name];
1250
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1251
+ return {
1252
+ attribute,
1253
+ label: metadata.label ?? "",
1254
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1255
+ schemas,
1256
+ components: components?.schemas ?? {}
1257
+ }),
1258
+ name,
1259
+ searchable: metadata.searchable ?? true,
1260
+ sortable: metadata.sortable ?? true
1261
+ };
1262
+ }).filter((field) => field !== null);
1263
+ };
1264
+ const useDocument = (args, opts) => {
1265
+ const { toggleNotification } = strapiAdmin.useNotification();
1266
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1267
+ const { formatMessage } = reactIntl.useIntl();
1268
+ const {
1269
+ currentData: data,
1270
+ isLoading: isLoadingDocument,
1271
+ isFetching: isFetchingDocument,
1272
+ error
1273
+ } = useGetDocumentQuery(args, {
1274
+ ...opts,
1275
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1276
+ });
1277
+ const document = data?.data;
1278
+ const meta = data?.meta;
1279
+ const {
1280
+ components,
1281
+ schema,
1282
+ schemas,
1283
+ isLoading: isLoadingSchema
1284
+ } = useContentTypeSchema(args.model);
1285
+ const isSingleType = schema?.kind === "singleType";
1286
+ const getTitle = (mainField) => {
1287
+ if (mainField !== "id" && document?.[mainField]) {
1288
+ return document[mainField];
1289
+ }
1290
+ if (isSingleType && schema?.info.displayName) {
1291
+ return schema.info.displayName;
1292
+ }
1293
+ return formatMessage({
1294
+ id: "content-manager.containers.untitled",
1295
+ defaultMessage: "Untitled"
1296
+ });
1297
+ };
1298
+ React__namespace.useEffect(() => {
1299
+ if (error) {
1300
+ toggleNotification({
1301
+ type: "danger",
1302
+ message: formatAPIError(error)
1303
+ });
1304
+ }
1305
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1306
+ const validationSchema = React__namespace.useMemo(() => {
1307
+ if (!schema) {
1308
+ return null;
1309
+ }
1310
+ return createYupSchema(schema.attributes, components);
1311
+ }, [schema, components]);
1312
+ const validate = React__namespace.useCallback(
1313
+ (document2) => {
1314
+ if (!validationSchema) {
1315
+ throw new Error(
1316
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1317
+ );
1318
+ }
1319
+ try {
1320
+ validationSchema.validateSync(document2, { abortEarly: false, strict: true });
1321
+ return null;
1322
+ } catch (error2) {
1323
+ if (error2 instanceof yup.ValidationError) {
1324
+ return strapiAdmin.getYupValidationErrors(error2);
1325
+ }
1326
+ throw error2;
1327
+ }
1328
+ },
1329
+ [validationSchema]
1330
+ );
1331
+ const getInitialFormValues = React__namespace.useCallback(
1332
+ (isCreatingDocument = false) => {
1333
+ if (!document && !isCreatingDocument && !isSingleType || !schema) {
1334
+ return void 0;
1335
+ }
1336
+ const form = document?.id ? document : createDefaultForm(schema, components);
1337
+ return transformDocument(schema, components)(form);
1338
+ },
1339
+ [document, isSingleType, schema, components]
1340
+ );
1341
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1342
+ const hasError = !!error;
1343
+ return {
1344
+ components,
1345
+ document,
1346
+ meta,
834
1347
  isLoading,
1348
+ hasError,
835
1349
  schema,
836
- validate
1350
+ schemas,
1351
+ validate,
1352
+ getTitle,
1353
+ getInitialFormValues
837
1354
  };
838
1355
  };
839
1356
  const useDoc = () => {
@@ -846,22 +1363,60 @@ const useDoc = () => {
846
1363
  if (!slug) {
847
1364
  throw new Error("Could not find model in url params");
848
1365
  }
1366
+ const document = useDocument(
1367
+ { documentId: origin || id, model: slug, collectionType, params },
1368
+ {
1369
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1370
+ }
1371
+ );
1372
+ const returnId = origin || id === "create" ? void 0 : id;
849
1373
  return {
850
1374
  collectionType,
851
1375
  model: slug,
852
- id: origin || id === "create" ? void 0 : id,
853
- ...useDocument(
854
- { documentId: origin || id, model: slug, collectionType, params },
855
- {
856
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
857
- }
858
- )
1376
+ id: returnId,
1377
+ ...document
1378
+ };
1379
+ };
1380
+ const useContentManagerContext = () => {
1381
+ const {
1382
+ collectionType,
1383
+ model,
1384
+ id,
1385
+ components,
1386
+ isLoading: isLoadingDoc,
1387
+ schema,
1388
+ schemas
1389
+ } = useDoc();
1390
+ const layout = useDocumentLayout(model);
1391
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1392
+ const isSingleType = collectionType === SINGLE_TYPES;
1393
+ const slug = model;
1394
+ const isCreatingEntry = id === "create";
1395
+ useContentTypeSchema();
1396
+ const isLoading = isLoadingDoc || layout.isLoading;
1397
+ const error = layout.error;
1398
+ return {
1399
+ error,
1400
+ isLoading,
1401
+ // Base metadata
1402
+ model,
1403
+ collectionType,
1404
+ id,
1405
+ slug,
1406
+ isCreatingEntry,
1407
+ isSingleType,
1408
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1409
+ // All schema infos
1410
+ components,
1411
+ contentType: schema,
1412
+ contentTypes: schemas,
1413
+ // Form state
1414
+ form,
1415
+ // layout infos
1416
+ layout
859
1417
  };
860
1418
  };
861
1419
  const prefixPluginTranslations = (trad, pluginId) => {
862
- if (!pluginId) {
863
- throw new TypeError("pluginId can't be empty");
864
- }
865
1420
  return Object.keys(trad).reduce((acc, current) => {
866
1421
  acc[`${pluginId}.${current}`] = trad[current];
867
1422
  return acc;
@@ -877,6 +1432,8 @@ const useDocumentActions = () => {
877
1432
  const { formatMessage } = reactIntl.useIntl();
878
1433
  const { trackUsage } = strapiAdmin.useTracking();
879
1434
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1435
+ const navigate = reactRouterDom.useNavigate();
1436
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
880
1437
  const [deleteDocument] = useDeleteDocumentMutation();
881
1438
  const _delete = React__namespace.useCallback(
882
1439
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1191,6 +1748,7 @@ const useDocumentActions = () => {
1191
1748
  defaultMessage: "Saved document"
1192
1749
  })
1193
1750
  });
1751
+ setCurrentStep("contentManager.success");
1194
1752
  return res.data;
1195
1753
  } catch (err) {
1196
1754
  toggleNotification({
@@ -1230,7 +1788,7 @@ const useDocumentActions = () => {
1230
1788
  throw err;
1231
1789
  }
1232
1790
  },
1233
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1791
+ [autoCloneDocument, formatMessage, toggleNotification]
1234
1792
  );
1235
1793
  const [cloneDocument] = useCloneDocumentMutation();
1236
1794
  const clone = React__namespace.useCallback(
@@ -1256,6 +1814,7 @@ const useDocumentActions = () => {
1256
1814
  defaultMessage: "Cloned document"
1257
1815
  })
1258
1816
  });
1817
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1259
1818
  return res.data;
1260
1819
  } catch (err) {
1261
1820
  toggleNotification({
@@ -1266,7 +1825,7 @@ const useDocumentActions = () => {
1266
1825
  throw err;
1267
1826
  }
1268
1827
  },
1269
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1828
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1270
1829
  );
1271
1830
  const [getDoc] = useLazyGetDocumentQuery();
1272
1831
  const getDocument = React__namespace.useCallback(
@@ -1291,10 +1850,10 @@ const useDocumentActions = () => {
1291
1850
  update
1292
1851
  };
1293
1852
  };
1294
- const ProtectedHistoryPage = React.lazy(
1295
- () => Promise.resolve().then(() => require("./History-DNQkXANT.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1853
+ const ProtectedHistoryPage = React__namespace.lazy(
1854
+ () => Promise.resolve().then(() => require("./History-zArjENzj.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1296
1855
  );
1297
- const routes$1 = [
1856
+ const routes$2 = [
1298
1857
  {
1299
1858
  path: ":collectionType/:slug/:id/history",
1300
1859
  Component: ProtectedHistoryPage
@@ -1304,32 +1863,45 @@ const routes$1 = [
1304
1863
  Component: ProtectedHistoryPage
1305
1864
  }
1306
1865
  ];
1866
+ const ProtectedPreviewPage = React__namespace.lazy(
1867
+ () => Promise.resolve().then(() => require("./Preview-DEHdENT1.js")).then((mod) => ({ default: mod.ProtectedPreviewPage }))
1868
+ );
1869
+ const routes$1 = [
1870
+ {
1871
+ path: ":collectionType/:slug/:id/preview",
1872
+ Component: ProtectedPreviewPage
1873
+ },
1874
+ {
1875
+ path: ":collectionType/:slug/preview",
1876
+ Component: ProtectedPreviewPage
1877
+ }
1878
+ ];
1307
1879
  const ProtectedEditViewPage = React.lazy(
1308
- () => Promise.resolve().then(() => require("./EditViewPage-C-ukDOB7.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1880
+ () => Promise.resolve().then(() => require("./EditViewPage-DqelJ9UK.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1309
1881
  );
1310
1882
  const ProtectedListViewPage = React.lazy(
1311
- () => Promise.resolve().then(() => require("./ListViewPage-BsLiH2-2.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1883
+ () => Promise.resolve().then(() => require("./ListViewPage-BVKBeQAA.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1312
1884
  );
1313
1885
  const ProtectedListConfiguration = React.lazy(
1314
- () => Promise.resolve().then(() => require("./ListConfigurationPage-CUQxfpjT.js")).then((mod) => ({
1886
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-ByZAO_9H.js")).then((mod) => ({
1315
1887
  default: mod.ProtectedListConfiguration
1316
1888
  }))
1317
1889
  );
1318
1890
  const ProtectedEditConfigurationPage = React.lazy(
1319
- () => Promise.resolve().then(() => require("./EditConfigurationPage-Xp7lun0f.js")).then((mod) => ({
1891
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-LYEvR4fW.js")).then((mod) => ({
1320
1892
  default: mod.ProtectedEditConfigurationPage
1321
1893
  }))
1322
1894
  );
1323
1895
  const ProtectedComponentConfigurationPage = React.lazy(
1324
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-5ukroXAh.js")).then((mod) => ({
1896
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DdkVGfXC.js")).then((mod) => ({
1325
1897
  default: mod.ProtectedComponentConfigurationPage
1326
1898
  }))
1327
1899
  );
1328
1900
  const NoPermissions = React.lazy(
1329
- () => Promise.resolve().then(() => require("./NoPermissionsPage-_lUqjGW3.js")).then((mod) => ({ default: mod.NoPermissions }))
1901
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-vdNpc6jb.js")).then((mod) => ({ default: mod.NoPermissions }))
1330
1902
  );
1331
1903
  const NoContentType = React.lazy(
1332
- () => Promise.resolve().then(() => require("./NoContentTypePage-BZ-PnGAf.js")).then((mod) => ({ default: mod.NoContentType }))
1904
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BV5zfDxr.js")).then((mod) => ({ default: mod.NoContentType }))
1333
1905
  );
1334
1906
  const CollectionTypePages = () => {
1335
1907
  const { collectionType } = reactRouterDom.useParams();
@@ -1341,7 +1913,7 @@ const CollectionTypePages = () => {
1341
1913
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1342
1914
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1343
1915
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1344
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1916
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1345
1917
  const routes = [
1346
1918
  {
1347
1919
  path: LIST_RELATIVE_PATH,
@@ -1375,6 +1947,7 @@ const routes = [
1375
1947
  path: "no-content-types",
1376
1948
  Component: NoContentType
1377
1949
  },
1950
+ ...routes$2,
1378
1951
  ...routes$1
1379
1952
  ];
1380
1953
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1443,12 +2016,14 @@ const DocumentActionButton = (action) => {
1443
2016
  /* @__PURE__ */ jsxRuntime.jsx(
1444
2017
  designSystem.Button,
1445
2018
  {
1446
- flex: 1,
2019
+ flex: "auto",
1447
2020
  startIcon: action.icon,
1448
2021
  disabled: action.disabled,
1449
2022
  onClick: handleClick(action),
1450
2023
  justifyContent: "center",
1451
2024
  variant: action.variant || "default",
2025
+ paddingTop: "7px",
2026
+ paddingBottom: "7px",
1452
2027
  children: action.label
1453
2028
  }
1454
2029
  ),
@@ -1471,6 +2046,11 @@ const DocumentActionButton = (action) => {
1471
2046
  ) : null
1472
2047
  ] });
1473
2048
  };
2049
+ const MenuItem = styledComponents.styled(designSystem.Menu.Item)`
2050
+ &:hover {
2051
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
2052
+ }
2053
+ `;
1474
2054
  const DocumentActionsMenu = ({
1475
2055
  actions: actions2,
1476
2056
  children,
@@ -1513,9 +2093,9 @@ const DocumentActionsMenu = ({
1513
2093
  disabled: isDisabled,
1514
2094
  size: "S",
1515
2095
  endIcon: null,
1516
- paddingTop: "7px",
1517
- paddingLeft: "9px",
1518
- paddingRight: "9px",
2096
+ paddingTop: "4px",
2097
+ paddingLeft: "7px",
2098
+ paddingRight: "7px",
1519
2099
  variant,
1520
2100
  children: [
1521
2101
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1526,36 +2106,35 @@ const DocumentActionsMenu = ({
1526
2106
  ]
1527
2107
  }
1528
2108
  ),
1529
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
2109
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1530
2110
  actions2.map((action) => {
1531
2111
  return /* @__PURE__ */ jsxRuntime.jsx(
1532
- designSystem.Menu.Item,
2112
+ MenuItem,
1533
2113
  {
1534
2114
  disabled: action.disabled,
1535
2115
  onSelect: handleClick(action),
1536
2116
  display: "block",
1537
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1538
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1539
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1540
- action.label
1541
- ] }),
1542
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1543
- designSystem.Flex,
1544
- {
1545
- alignItems: "center",
1546
- background: "alternative100",
1547
- borderStyle: "solid",
1548
- borderColor: "alternative200",
1549
- borderWidth: "1px",
1550
- height: 5,
1551
- paddingLeft: 2,
1552
- paddingRight: 2,
1553
- hasRadius: true,
1554
- color: "alternative600",
1555
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1556
- }
1557
- )
1558
- ] })
2117
+ isVariantDanger: action.variant === "danger",
2118
+ isDisabled: action.disabled,
2119
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(
2120
+ designSystem.Flex,
2121
+ {
2122
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
2123
+ gap: 2,
2124
+ tag: "span",
2125
+ children: [
2126
+ /* @__PURE__ */ jsxRuntime.jsx(
2127
+ designSystem.Flex,
2128
+ {
2129
+ tag: "span",
2130
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
2131
+ children: action.icon
2132
+ }
2133
+ ),
2134
+ action.label
2135
+ ]
2136
+ }
2137
+ ) })
1559
2138
  },
1560
2139
  action.id
1561
2140
  );
@@ -1635,11 +2214,11 @@ const DocumentActionConfirmDialog = ({
1635
2214
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1636
2215
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1637
2216
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1638
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
2217
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1639
2218
  id: "app.components.Button.cancel",
1640
2219
  defaultMessage: "Cancel"
1641
2220
  }) }) }),
1642
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
2221
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1643
2222
  id: "app.components.Button.confirm",
1644
2223
  defaultMessage: "Confirm"
1645
2224
  }) })
@@ -1666,8 +2245,20 @@ const DocumentActionModal = ({
1666
2245
  typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1667
2246
  ] }) });
1668
2247
  };
1669
- const PublishAction$1 = ({
1670
- activeTab,
2248
+ const transformData = (data) => {
2249
+ if (Array.isArray(data)) {
2250
+ return data.map(transformData);
2251
+ }
2252
+ if (typeof data === "object" && data !== null) {
2253
+ if ("apiData" in data) {
2254
+ return data.apiData;
2255
+ }
2256
+ return mapValues__default.default(transformData)(data);
2257
+ }
2258
+ return data;
2259
+ };
2260
+ const PublishAction$1 = ({
2261
+ activeTab,
1671
2262
  documentId,
1672
2263
  model,
1673
2264
  collectionType,
@@ -1678,12 +2269,11 @@ const PublishAction$1 = ({
1678
2269
  const navigate = reactRouterDom.useNavigate();
1679
2270
  const { toggleNotification } = strapiAdmin.useNotification();
1680
2271
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2272
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1681
2273
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2274
+ const { id } = reactRouterDom.useParams();
1682
2275
  const { formatMessage } = reactIntl.useIntl();
1683
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1684
- "PublishAction",
1685
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1686
- );
2276
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1687
2277
  const { publish } = useDocumentActions();
1688
2278
  const [
1689
2279
  countDraftRelations,
@@ -1735,24 +2325,25 @@ const PublishAction$1 = ({
1735
2325
  }
1736
2326
  }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1737
2327
  React__namespace.useEffect(() => {
1738
- if (documentId) {
1739
- const fetchDraftRelationsCount = async () => {
1740
- const { data, error } = await countDraftRelations({
1741
- collectionType,
1742
- model,
1743
- documentId,
1744
- params
1745
- });
1746
- if (error) {
1747
- throw error;
1748
- }
1749
- if (data) {
1750
- setServerCountOfDraftRelations(data.data);
1751
- }
1752
- };
1753
- fetchDraftRelationsCount();
2328
+ if (!document || !document.documentId || isListView) {
2329
+ return;
1754
2330
  }
1755
- }, [documentId, countDraftRelations, collectionType, model, params]);
2331
+ const fetchDraftRelationsCount = async () => {
2332
+ const { data, error } = await countDraftRelations({
2333
+ collectionType,
2334
+ model,
2335
+ documentId,
2336
+ params
2337
+ });
2338
+ if (error) {
2339
+ throw error;
2340
+ }
2341
+ if (data) {
2342
+ setServerCountOfDraftRelations(data.data);
2343
+ }
2344
+ };
2345
+ fetchDraftRelationsCount();
2346
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1756
2347
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1757
2348
  if (!schema?.options?.draftAndPublish) {
1758
2349
  return null;
@@ -1760,7 +2351,9 @@ const PublishAction$1 = ({
1760
2351
  const performPublish = async () => {
1761
2352
  setSubmitting(true);
1762
2353
  try {
1763
- const { errors } = await validate();
2354
+ const { errors } = await validate(true, {
2355
+ status: "published"
2356
+ });
1764
2357
  if (errors) {
1765
2358
  toggleNotification({
1766
2359
  type: "danger",
@@ -1778,13 +2371,15 @@ const PublishAction$1 = ({
1778
2371
  documentId,
1779
2372
  params
1780
2373
  },
1781
- formValues
2374
+ transformData(formValues)
1782
2375
  );
1783
2376
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1784
- navigate({
1785
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1786
- search: rawQuery
1787
- });
2377
+ if (id === "create") {
2378
+ navigate({
2379
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2380
+ search: rawQuery
2381
+ });
2382
+ }
1788
2383
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1789
2384
  setErrors(formatValidationErrors(res.error));
1790
2385
  }
@@ -1793,7 +2388,8 @@ const PublishAction$1 = ({
1793
2388
  }
1794
2389
  };
1795
2390
  const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1796
- const hasDraftRelations = totalDraftRelations > 0;
2391
+ const enableDraftRelationsCount = false;
2392
+ const hasDraftRelations = enableDraftRelationsCount;
1797
2393
  return {
1798
2394
  /**
1799
2395
  * Disabled when:
@@ -1803,18 +2399,13 @@ const PublishAction$1 = ({
1803
2399
  * - the document is already published & not modified
1804
2400
  * - the document is being created & not modified
1805
2401
  * - the user doesn't have the permission to publish
1806
- * - the user doesn't have the permission to create a new document
1807
- * - the user doesn't have the permission to update the document
1808
2402
  */
1809
- disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2403
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1810
2404
  label: formatMessage({
1811
2405
  id: "app.utils.publish",
1812
2406
  defaultMessage: "Publish"
1813
2407
  }),
1814
2408
  onClick: async () => {
1815
- if (hasDraftRelations) {
1816
- return;
1817
- }
1818
2409
  await performPublish();
1819
2410
  },
1820
2411
  dialog: hasDraftRelations ? {
@@ -1841,6 +2432,7 @@ const PublishAction$1 = ({
1841
2432
  };
1842
2433
  };
1843
2434
  PublishAction$1.type = "publish";
2435
+ PublishAction$1.position = "panel";
1844
2436
  const UpdateAction = ({
1845
2437
  activeTab,
1846
2438
  documentId,
@@ -1853,10 +2445,6 @@ const UpdateAction = ({
1853
2445
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1854
2446
  const isCloning = cloneMatch !== null;
1855
2447
  const { formatMessage } = reactIntl.useIntl();
1856
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1857
- canCreate: canCreate2,
1858
- canUpdate: canUpdate2
1859
- }));
1860
2448
  const { create, update, clone } = useDocumentActions();
1861
2449
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1862
2450
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1867,96 +2455,134 @@ const UpdateAction = ({
1867
2455
  const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1868
2456
  const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1869
2457
  const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1870
- return {
1871
- /**
1872
- * Disabled when:
1873
- * - the form is submitting
1874
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1875
- * - the active tab is the published tab
1876
- * - the user doesn't have the permission to create a new document
1877
- * - the user doesn't have the permission to update the document
1878
- */
1879
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1880
- label: formatMessage({
1881
- id: "content-manager.containers.Edit.save",
1882
- defaultMessage: "Save"
1883
- }),
1884
- onClick: async () => {
1885
- setSubmitting(true);
1886
- try {
1887
- const { errors } = await validate();
1888
- if (errors) {
1889
- toggleNotification({
1890
- type: "danger",
1891
- message: formatMessage({
1892
- id: "content-manager.validation.error",
1893
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1894
- })
1895
- });
1896
- return;
1897
- }
1898
- if (isCloning) {
1899
- const res = await clone(
1900
- {
1901
- model,
1902
- documentId: cloneMatch.params.origin,
1903
- params
1904
- },
1905
- document
1906
- );
1907
- if ("data" in res) {
1908
- navigate(
1909
- {
1910
- pathname: `../${res.data.documentId}`,
1911
- search: rawQuery
1912
- },
1913
- { relative: "path" }
1914
- );
1915
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1916
- setErrors(formatValidationErrors(res.error));
1917
- }
1918
- } else if (documentId || collectionType === SINGLE_TYPES) {
1919
- const res = await update(
2458
+ const handleUpdate = React__namespace.useCallback(async () => {
2459
+ setSubmitting(true);
2460
+ try {
2461
+ if (!modified) {
2462
+ return;
2463
+ }
2464
+ const { errors } = await validate(true, {
2465
+ status: "draft"
2466
+ });
2467
+ if (errors) {
2468
+ toggleNotification({
2469
+ type: "danger",
2470
+ message: formatMessage({
2471
+ id: "content-manager.validation.error",
2472
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2473
+ })
2474
+ });
2475
+ return;
2476
+ }
2477
+ if (isCloning) {
2478
+ const res = await clone(
2479
+ {
2480
+ model,
2481
+ documentId: cloneMatch.params.origin,
2482
+ params
2483
+ },
2484
+ transformData(document)
2485
+ );
2486
+ if ("data" in res) {
2487
+ navigate(
1920
2488
  {
1921
- collectionType,
1922
- model,
1923
- documentId,
1924
- params
2489
+ pathname: `../${res.data.documentId}`,
2490
+ search: rawQuery
1925
2491
  },
1926
- document
2492
+ { relative: "path" }
1927
2493
  );
1928
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1929
- setErrors(formatValidationErrors(res.error));
1930
- } else {
1931
- resetForm();
1932
- }
2494
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2495
+ setErrors(formatValidationErrors(res.error));
2496
+ }
2497
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2498
+ const res = await update(
2499
+ {
2500
+ collectionType,
2501
+ model,
2502
+ documentId,
2503
+ params
2504
+ },
2505
+ transformData(document)
2506
+ );
2507
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2508
+ setErrors(formatValidationErrors(res.error));
1933
2509
  } else {
1934
- const res = await create(
2510
+ resetForm();
2511
+ }
2512
+ } else {
2513
+ const res = await create(
2514
+ {
2515
+ model,
2516
+ params
2517
+ },
2518
+ transformData(document)
2519
+ );
2520
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2521
+ navigate(
1935
2522
  {
1936
- model,
1937
- params
2523
+ pathname: `../${res.data.documentId}`,
2524
+ search: rawQuery
1938
2525
  },
1939
- document
2526
+ { replace: true, relative: "path" }
1940
2527
  );
1941
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1942
- navigate(
1943
- {
1944
- pathname: `../${res.data.documentId}`,
1945
- search: rawQuery
1946
- },
1947
- { replace: true, relative: "path" }
1948
- );
1949
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1950
- setErrors(formatValidationErrors(res.error));
1951
- }
2528
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2529
+ setErrors(formatValidationErrors(res.error));
1952
2530
  }
1953
- } finally {
1954
- setSubmitting(false);
1955
2531
  }
2532
+ } finally {
2533
+ setSubmitting(false);
1956
2534
  }
2535
+ }, [
2536
+ clone,
2537
+ cloneMatch?.params.origin,
2538
+ collectionType,
2539
+ create,
2540
+ document,
2541
+ documentId,
2542
+ formatMessage,
2543
+ formatValidationErrors,
2544
+ isCloning,
2545
+ model,
2546
+ modified,
2547
+ navigate,
2548
+ params,
2549
+ rawQuery,
2550
+ resetForm,
2551
+ setErrors,
2552
+ setSubmitting,
2553
+ toggleNotification,
2554
+ update,
2555
+ validate
2556
+ ]);
2557
+ React__namespace.useEffect(() => {
2558
+ const handleKeyDown = (e) => {
2559
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2560
+ e.preventDefault();
2561
+ handleUpdate();
2562
+ }
2563
+ };
2564
+ window.addEventListener("keydown", handleKeyDown);
2565
+ return () => {
2566
+ window.removeEventListener("keydown", handleKeyDown);
2567
+ };
2568
+ }, [handleUpdate]);
2569
+ return {
2570
+ /**
2571
+ * Disabled when:
2572
+ * - the form is submitting
2573
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2574
+ * - the active tab is the published tab
2575
+ */
2576
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2577
+ label: formatMessage({
2578
+ id: "global.save",
2579
+ defaultMessage: "Save"
2580
+ }),
2581
+ onClick: handleUpdate
1957
2582
  };
1958
2583
  };
1959
2584
  UpdateAction.type = "update";
2585
+ UpdateAction.position = "panel";
1960
2586
  const UNPUBLISH_DRAFT_OPTIONS = {
1961
2587
  KEEP: "keep",
1962
2588
  DISCARD: "discard"
@@ -1989,7 +2615,7 @@ const UnpublishAction$1 = ({
1989
2615
  id: "app.utils.unpublish",
1990
2616
  defaultMessage: "Unpublish"
1991
2617
  }),
1992
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2618
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1993
2619
  onClick: async () => {
1994
2620
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1995
2621
  if (!documentId) {
@@ -2079,6 +2705,7 @@ const UnpublishAction$1 = ({
2079
2705
  };
2080
2706
  };
2081
2707
  UnpublishAction$1.type = "unpublish";
2708
+ UnpublishAction$1.position = "panel";
2082
2709
  const DiscardAction = ({
2083
2710
  activeTab,
2084
2711
  documentId,
@@ -2101,7 +2728,7 @@ const DiscardAction = ({
2101
2728
  id: "content-manager.actions.discard.label",
2102
2729
  defaultMessage: "Discard changes"
2103
2730
  }),
2104
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2731
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2105
2732
  position: ["panel", "table-row"],
2106
2733
  variant: "danger",
2107
2734
  dialog: {
@@ -2129,11 +2756,7 @@ const DiscardAction = ({
2129
2756
  };
2130
2757
  };
2131
2758
  DiscardAction.type = "discard";
2132
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2133
- path {
2134
- fill: currentColor;
2135
- }
2136
- `;
2759
+ DiscardAction.position = "panel";
2137
2760
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2138
2761
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2139
2762
  const RelativeTime = React__namespace.forwardRef(
@@ -2146,7 +2769,7 @@ const RelativeTime = React__namespace.forwardRef(
2146
2769
  });
2147
2770
  const unit = intervals.find((intervalUnit) => {
2148
2771
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2149
- });
2772
+ }) ?? "seconds";
2150
2773
  const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2151
2774
  const customInterval = customIntervals.find(
2152
2775
  (custom) => interval[custom.unit] < custom.threshold
@@ -2180,19 +2803,29 @@ const getDisplayName = ({
2180
2803
  return email ?? "";
2181
2804
  };
2182
2805
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2183
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2184
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2185
- 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) }) });
2806
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2807
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2808
+ const { formatMessage } = reactIntl.useIntl();
2809
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2810
+ id: `content-manager.containers.List.${status}`,
2811
+ defaultMessage: capitalise(status)
2812
+ }) }) });
2186
2813
  };
2187
2814
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2188
2815
  const { formatMessage } = reactIntl.useIntl();
2189
2816
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2817
+ const params = reactRouterDom.useParams();
2190
2818
  const title = isCreating ? formatMessage({
2191
2819
  id: "content-manager.containers.edit.title.new",
2192
2820
  defaultMessage: "Create an entry"
2193
2821
  }) : documentTitle;
2194
2822
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2195
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2823
+ /* @__PURE__ */ jsxRuntime.jsx(
2824
+ strapiAdmin.BackButton,
2825
+ {
2826
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2827
+ }
2828
+ ),
2196
2829
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2197
2830
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2198
2831
  /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
@@ -2243,7 +2876,7 @@ const HeaderToolbar = () => {
2243
2876
  meta: isCloning ? void 0 : meta,
2244
2877
  collectionType
2245
2878
  },
2246
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2879
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2247
2880
  children: (actions2) => {
2248
2881
  const headerActions = actions2.filter((action) => {
2249
2882
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2280,12 +2913,12 @@ const Information = ({ activeTab }) => {
2280
2913
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2281
2914
  label: formatMessage({
2282
2915
  id: "content-manager.containers.edit.information.last-published.label",
2283
- defaultMessage: "Last published"
2916
+ defaultMessage: "Published"
2284
2917
  }),
2285
2918
  value: formatMessage(
2286
2919
  {
2287
2920
  id: "content-manager.containers.edit.information.last-published.value",
2288
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2921
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2289
2922
  },
2290
2923
  {
2291
2924
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2298,12 +2931,12 @@ const Information = ({ activeTab }) => {
2298
2931
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2299
2932
  label: formatMessage({
2300
2933
  id: "content-manager.containers.edit.information.last-draft.label",
2301
- defaultMessage: "Last draft"
2934
+ defaultMessage: "Updated"
2302
2935
  }),
2303
2936
  value: formatMessage(
2304
2937
  {
2305
2938
  id: "content-manager.containers.edit.information.last-draft.value",
2306
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2939
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2307
2940
  },
2308
2941
  {
2309
2942
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2321,12 +2954,12 @@ const Information = ({ activeTab }) => {
2321
2954
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2322
2955
  label: formatMessage({
2323
2956
  id: "content-manager.containers.edit.information.document.label",
2324
- defaultMessage: "Document"
2957
+ defaultMessage: "Created"
2325
2958
  }),
2326
2959
  value: formatMessage(
2327
2960
  {
2328
2961
  id: "content-manager.containers.edit.information.document.value",
2329
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2962
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2330
2963
  },
2331
2964
  {
2332
2965
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2364,25 +2997,77 @@ const Information = ({ activeTab }) => {
2364
2997
  );
2365
2998
  };
2366
2999
  const HeaderActions = ({ actions: actions2 }) => {
2367
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2368
- if ("options" in action) {
3000
+ const [dialogId, setDialogId] = React__namespace.useState(null);
3001
+ const handleClick = (action) => async (e) => {
3002
+ if (!("options" in action)) {
3003
+ const { onClick = () => false, dialog, id } = action;
3004
+ const muteDialog = await onClick(e);
3005
+ if (dialog && !muteDialog) {
3006
+ e.preventDefault();
3007
+ setDialogId(id);
3008
+ }
3009
+ }
3010
+ };
3011
+ const handleClose = () => {
3012
+ setDialogId(null);
3013
+ };
3014
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
3015
+ if (action.options) {
2369
3016
  return /* @__PURE__ */ jsxRuntime.jsx(
2370
3017
  designSystem.SingleSelect,
2371
3018
  {
2372
3019
  size: "S",
2373
- disabled: action.disabled,
2374
- "aria-label": action.label,
2375
3020
  onChange: action.onSelect,
2376
- value: action.value,
3021
+ "aria-label": action.label,
3022
+ ...action,
2377
3023
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2378
3024
  },
2379
3025
  action.id
2380
3026
  );
2381
3027
  } else {
2382
- return null;
3028
+ if (action.type === "icon") {
3029
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
3030
+ /* @__PURE__ */ jsxRuntime.jsx(
3031
+ designSystem.IconButton,
3032
+ {
3033
+ disabled: action.disabled,
3034
+ label: action.label,
3035
+ size: "S",
3036
+ onClick: handleClick(action),
3037
+ children: action.icon
3038
+ }
3039
+ ),
3040
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
3041
+ HeaderActionDialog,
3042
+ {
3043
+ ...action.dialog,
3044
+ isOpen: dialogId === action.id,
3045
+ onClose: handleClose
3046
+ }
3047
+ ) : null
3048
+ ] }, action.id);
3049
+ }
2383
3050
  }
2384
3051
  }) });
2385
3052
  };
3053
+ const HeaderActionDialog = ({
3054
+ onClose,
3055
+ onCancel,
3056
+ title,
3057
+ content: Content,
3058
+ isOpen
3059
+ }) => {
3060
+ const handleClose = async () => {
3061
+ if (onCancel) {
3062
+ await onCancel();
3063
+ }
3064
+ onClose();
3065
+ };
3066
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3067
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
3068
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
3069
+ ] }) });
3070
+ };
2386
3071
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2387
3072
  const navigate = reactRouterDom.useNavigate();
2388
3073
  const { formatMessage } = reactIntl.useIntl();
@@ -2399,6 +3084,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2399
3084
  };
2400
3085
  };
2401
3086
  ConfigureTheViewAction.type = "configure-the-view";
3087
+ ConfigureTheViewAction.position = "header";
2402
3088
  const EditTheModelAction = ({ model }) => {
2403
3089
  const navigate = reactRouterDom.useNavigate();
2404
3090
  const { formatMessage } = reactIntl.useIntl();
@@ -2415,6 +3101,7 @@ const EditTheModelAction = ({ model }) => {
2415
3101
  };
2416
3102
  };
2417
3103
  EditTheModelAction.type = "edit-the-model";
3104
+ EditTheModelAction.position = "header";
2418
3105
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2419
3106
  const navigate = reactRouterDom.useNavigate();
2420
3107
  const { formatMessage } = reactIntl.useIntl();
@@ -2423,12 +3110,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2423
3110
  const { delete: deleteAction } = useDocumentActions();
2424
3111
  const { toggleNotification } = strapiAdmin.useNotification();
2425
3112
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
3113
+ const isLocalized = document?.locale != null;
2426
3114
  return {
2427
3115
  disabled: !canDelete || !document,
2428
- label: formatMessage({
2429
- id: "content-manager.actions.delete.label",
2430
- defaultMessage: "Delete document"
2431
- }),
3116
+ label: formatMessage(
3117
+ {
3118
+ id: "content-manager.actions.delete.label",
3119
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
3120
+ },
3121
+ { isLocalized }
3122
+ ),
2432
3123
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2433
3124
  dialog: {
2434
3125
  type: "dialog",
@@ -2484,6 +3175,7 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2484
3175
  };
2485
3176
  };
2486
3177
  DeleteAction$1.type = "delete";
3178
+ DeleteAction$1.position = ["header", "table-row"];
2487
3179
  const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2488
3180
  const Panels = () => {
2489
3181
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
@@ -2498,389 +3190,87 @@ const Panels = () => {
2498
3190
  const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2499
3191
  const props = {
2500
3192
  activeTab: status,
2501
- model,
2502
- documentId: id,
2503
- document: isCloning ? void 0 : document,
2504
- meta: isCloning ? void 0 : meta,
2505
- collectionType
2506
- };
2507
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2508
- strapiAdmin.DescriptionComponentRenderer,
2509
- {
2510
- props,
2511
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2512
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2513
- }
2514
- ) });
2515
- };
2516
- const ActionsPanel = () => {
2517
- const { formatMessage } = reactIntl.useIntl();
2518
- return {
2519
- title: formatMessage({
2520
- id: "content-manager.containers.edit.panels.default.title",
2521
- defaultMessage: "Document"
2522
- }),
2523
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2524
- };
2525
- };
2526
- ActionsPanel.type = "actions";
2527
- const ActionsPanelContent = () => {
2528
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2529
- const [
2530
- {
2531
- query: { status = "draft" }
2532
- }
2533
- ] = strapiAdmin.useQueryParams();
2534
- const { model, id, document, meta, collectionType } = useDoc();
2535
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2536
- const props = {
2537
- activeTab: status,
2538
- model,
2539
- documentId: id,
2540
- document: isCloning ? void 0 : document,
2541
- meta: isCloning ? void 0 : meta,
2542
- collectionType
2543
- };
2544
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2545
- /* @__PURE__ */ jsxRuntime.jsx(
2546
- strapiAdmin.DescriptionComponentRenderer,
2547
- {
2548
- props,
2549
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2550
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2551
- }
2552
- ),
2553
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2554
- ] });
2555
- };
2556
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2557
- return /* @__PURE__ */ jsxRuntime.jsxs(
2558
- designSystem.Flex,
2559
- {
2560
- ref,
2561
- tag: "aside",
2562
- "aria-labelledby": "additional-information",
2563
- background: "neutral0",
2564
- borderColor: "neutral150",
2565
- hasRadius: true,
2566
- paddingBottom: 4,
2567
- paddingLeft: 4,
2568
- paddingRight: 4,
2569
- paddingTop: 4,
2570
- shadow: "tableShadow",
2571
- gap: 3,
2572
- direction: "column",
2573
- justifyContent: "stretch",
2574
- alignItems: "flex-start",
2575
- children: [
2576
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2577
- children
2578
- ]
2579
- }
2580
- );
2581
- });
2582
- const HOOKS = {
2583
- /**
2584
- * Hook that allows to mutate the displayed headers of the list view table
2585
- * @constant
2586
- * @type {string}
2587
- */
2588
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2589
- /**
2590
- * Hook that allows to mutate the CM's collection types links pre-set filters
2591
- * @constant
2592
- * @type {string}
2593
- */
2594
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2595
- /**
2596
- * Hook that allows to mutate the CM's edit view layout
2597
- * @constant
2598
- * @type {string}
2599
- */
2600
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2601
- /**
2602
- * Hook that allows to mutate the CM's single types links pre-set filters
2603
- * @constant
2604
- * @type {string}
2605
- */
2606
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2607
- };
2608
- const contentTypesApi = contentManagerApi.injectEndpoints({
2609
- endpoints: (builder) => ({
2610
- getContentTypeConfiguration: builder.query({
2611
- query: (uid) => ({
2612
- url: `/content-manager/content-types/${uid}/configuration`,
2613
- method: "GET"
2614
- }),
2615
- transformResponse: (response) => response.data,
2616
- providesTags: (_result, _error, uid) => [
2617
- { type: "ContentTypesConfiguration", id: uid },
2618
- { type: "ContentTypeSettings", id: "LIST" }
2619
- ]
2620
- }),
2621
- getAllContentTypeSettings: builder.query({
2622
- query: () => "/content-manager/content-types-settings",
2623
- transformResponse: (response) => response.data,
2624
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2625
- }),
2626
- updateContentTypeConfiguration: builder.mutation({
2627
- query: ({ uid, ...body }) => ({
2628
- url: `/content-manager/content-types/${uid}/configuration`,
2629
- method: "PUT",
2630
- data: body
2631
- }),
2632
- transformResponse: (response) => response.data,
2633
- invalidatesTags: (_result, _error, { uid }) => [
2634
- { type: "ContentTypesConfiguration", id: uid },
2635
- { type: "ContentTypeSettings", id: "LIST" },
2636
- // Is this necessary?
2637
- { type: "InitialData" }
2638
- ]
2639
- })
2640
- })
2641
- });
2642
- const {
2643
- useGetContentTypeConfigurationQuery,
2644
- useGetAllContentTypeSettingsQuery,
2645
- useUpdateContentTypeConfigurationMutation
2646
- } = contentTypesApi;
2647
- const checkIfAttributeIsDisplayable = (attribute) => {
2648
- const { type } = attribute;
2649
- if (type === "relation") {
2650
- return !attribute.relation.toLowerCase().includes("morph");
2651
- }
2652
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2653
- };
2654
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2655
- if (!mainFieldName) {
2656
- return void 0;
2657
- }
2658
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2659
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2660
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2661
- );
2662
- return {
2663
- name: mainFieldName,
2664
- type: mainFieldType ?? "string"
2665
- };
2666
- };
2667
- const DEFAULT_SETTINGS = {
2668
- bulkable: false,
2669
- filterable: false,
2670
- searchable: false,
2671
- pagination: false,
2672
- defaultSortBy: "",
2673
- defaultSortOrder: "asc",
2674
- mainField: "id",
2675
- pageSize: 10
2676
- };
2677
- const useDocumentLayout = (model) => {
2678
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2679
- const [{ query }] = strapiAdmin.useQueryParams();
2680
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2681
- const { toggleNotification } = strapiAdmin.useNotification();
2682
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2683
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2684
- const {
2685
- data,
2686
- isLoading: isLoadingConfigs,
2687
- error,
2688
- isFetching: isFetchingConfigs
2689
- } = useGetContentTypeConfigurationQuery(model);
2690
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2691
- React__namespace.useEffect(() => {
2692
- if (error) {
2693
- toggleNotification({
2694
- type: "danger",
2695
- message: formatAPIError(error)
2696
- });
2697
- }
2698
- }, [error, formatAPIError, toggleNotification]);
2699
- const editLayout = React__namespace.useMemo(
2700
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2701
- layout: [],
2702
- components: {},
2703
- metadatas: {},
2704
- options: {},
2705
- settings: DEFAULT_SETTINGS
2706
- },
2707
- [data, isLoading, schemas, schema, components]
2708
- );
2709
- const listLayout = React__namespace.useMemo(() => {
2710
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2711
- layout: [],
2712
- metadatas: {},
2713
- options: {},
2714
- settings: DEFAULT_SETTINGS
2715
- };
2716
- }, [data, isLoading, schemas, schema, components]);
2717
- const { layout: edit } = React__namespace.useMemo(
2718
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2719
- layout: editLayout,
2720
- query
2721
- }),
2722
- [editLayout, query, runHookWaterfall]
2723
- );
2724
- return {
2725
- error,
2726
- isLoading,
2727
- edit,
2728
- list: listLayout
2729
- };
2730
- };
2731
- const useDocLayout = () => {
2732
- const { model } = useDoc();
2733
- return useDocumentLayout(model);
2734
- };
2735
- const formatEditLayout = (data, {
2736
- schemas,
2737
- schema,
2738
- components
2739
- }) => {
2740
- let currentPanelIndex = 0;
2741
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2742
- data.contentType.layouts.edit,
2743
- schema?.attributes,
2744
- data.contentType.metadatas,
2745
- { configurations: data.components, schemas: components },
2746
- schemas
2747
- ).reduce((panels, row) => {
2748
- if (row.some((field) => field.type === "dynamiczone")) {
2749
- panels.push([row]);
2750
- currentPanelIndex += 2;
2751
- } else {
2752
- if (!panels[currentPanelIndex]) {
2753
- panels.push([]);
2754
- }
2755
- panels[currentPanelIndex].push(row);
2756
- }
2757
- return panels;
2758
- }, []);
2759
- const componentEditAttributes = Object.entries(data.components).reduce(
2760
- (acc, [uid, configuration]) => {
2761
- acc[uid] = {
2762
- layout: convertEditLayoutToFieldLayouts(
2763
- configuration.layouts.edit,
2764
- components[uid].attributes,
2765
- configuration.metadatas
2766
- ),
2767
- settings: {
2768
- ...configuration.settings,
2769
- icon: components[uid].info.icon,
2770
- displayName: components[uid].info.displayName
2771
- }
2772
- };
2773
- return acc;
2774
- },
2775
- {}
2776
- );
2777
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2778
- (acc, [attribute, metadata]) => {
2779
- return {
2780
- ...acc,
2781
- [attribute]: metadata.edit
2782
- };
2783
- },
2784
- {}
2785
- );
2786
- return {
2787
- layout: panelledEditAttributes,
2788
- components: componentEditAttributes,
2789
- metadatas: editMetadatas,
2790
- settings: {
2791
- ...data.contentType.settings,
2792
- displayName: schema?.info.displayName
2793
- },
2794
- options: {
2795
- ...schema?.options,
2796
- ...schema?.pluginOptions,
2797
- ...data.contentType.options
2798
- }
3193
+ model,
3194
+ documentId: id,
3195
+ document: isCloning ? void 0 : document,
3196
+ meta: isCloning ? void 0 : meta,
3197
+ collectionType
2799
3198
  };
3199
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3200
+ strapiAdmin.DescriptionComponentRenderer,
3201
+ {
3202
+ props,
3203
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
3204
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
3205
+ }
3206
+ ) });
2800
3207
  };
2801
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2802
- return rows.map(
2803
- (row) => row.map((field) => {
2804
- const attribute = attributes[field.name];
2805
- if (!attribute) {
2806
- return null;
2807
- }
2808
- const { edit: metadata } = metadatas[field.name];
2809
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2810
- return {
2811
- attribute,
2812
- disabled: !metadata.editable,
2813
- hint: metadata.description,
2814
- label: metadata.label ?? "",
2815
- name: field.name,
2816
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2817
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2818
- schemas,
2819
- components: components?.schemas ?? {}
2820
- }),
2821
- placeholder: metadata.placeholder ?? "",
2822
- required: attribute.required ?? false,
2823
- size: field.size,
2824
- unique: "unique" in attribute ? attribute.unique : false,
2825
- visible: metadata.visible ?? true,
2826
- type: attribute.type
2827
- };
2828
- }).filter((field) => field !== null)
2829
- );
2830
- };
2831
- const formatListLayout = (data, {
2832
- schemas,
2833
- schema,
2834
- components
2835
- }) => {
2836
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2837
- (acc, [attribute, metadata]) => {
2838
- return {
2839
- ...acc,
2840
- [attribute]: metadata.list
2841
- };
2842
- },
2843
- {}
2844
- );
2845
- const listAttributes = convertListLayoutToFieldLayouts(
2846
- data.contentType.layouts.list,
2847
- schema?.attributes,
2848
- listMetadatas,
2849
- { configurations: data.components, schemas: components },
2850
- schemas
2851
- );
3208
+ const ActionsPanel = () => {
3209
+ const { formatMessage } = reactIntl.useIntl();
2852
3210
  return {
2853
- layout: listAttributes,
2854
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2855
- metadatas: listMetadatas,
2856
- options: {
2857
- ...schema?.options,
2858
- ...schema?.pluginOptions,
2859
- ...data.contentType.options
2860
- }
3211
+ title: formatMessage({
3212
+ id: "content-manager.containers.edit.panels.default.title",
3213
+ defaultMessage: "Entry"
3214
+ }),
3215
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2861
3216
  };
2862
3217
  };
2863
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2864
- return columns.map((name) => {
2865
- const attribute = attributes[name];
2866
- if (!attribute) {
2867
- return null;
3218
+ ActionsPanel.type = "actions";
3219
+ const ActionsPanelContent = () => {
3220
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
3221
+ const [
3222
+ {
3223
+ query: { status = "draft" }
2868
3224
  }
2869
- const metadata = metadatas[name];
2870
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2871
- return {
2872
- attribute,
2873
- label: metadata.label ?? "",
2874
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2875
- schemas,
2876
- components: components?.schemas ?? {}
2877
- }),
2878
- name,
2879
- searchable: metadata.searchable ?? true,
2880
- sortable: metadata.sortable ?? true
2881
- };
2882
- }).filter((field) => field !== null);
3225
+ ] = strapiAdmin.useQueryParams();
3226
+ const { model, id, document, meta, collectionType } = useDoc();
3227
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
3228
+ const props = {
3229
+ activeTab: status,
3230
+ model,
3231
+ documentId: id,
3232
+ document: isCloning ? void 0 : document,
3233
+ meta: isCloning ? void 0 : meta,
3234
+ collectionType
3235
+ };
3236
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3237
+ /* @__PURE__ */ jsxRuntime.jsx(
3238
+ strapiAdmin.DescriptionComponentRenderer,
3239
+ {
3240
+ props,
3241
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
3242
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3243
+ }
3244
+ ),
3245
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3246
+ ] });
2883
3247
  };
3248
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3249
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3250
+ designSystem.Flex,
3251
+ {
3252
+ ref,
3253
+ tag: "aside",
3254
+ "aria-labelledby": "additional-information",
3255
+ background: "neutral0",
3256
+ borderColor: "neutral150",
3257
+ hasRadius: true,
3258
+ paddingBottom: 4,
3259
+ paddingLeft: 4,
3260
+ paddingRight: 4,
3261
+ paddingTop: 4,
3262
+ shadow: "tableShadow",
3263
+ gap: 3,
3264
+ direction: "column",
3265
+ justifyContent: "stretch",
3266
+ alignItems: "flex-start",
3267
+ children: [
3268
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3269
+ children
3270
+ ]
3271
+ }
3272
+ );
3273
+ });
2884
3274
  const ConfirmBulkActionDialog = ({
2885
3275
  onToggleDialog,
2886
3276
  isOpen = false,
@@ -2906,7 +3296,7 @@ const ConfirmBulkActionDialog = ({
2906
3296
  ] })
2907
3297
  ] }) });
2908
3298
  };
2909
- const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3299
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2910
3300
  const ConfirmDialogPublishAll = ({
2911
3301
  isOpen,
2912
3302
  onToggleDialog,
@@ -2919,6 +3309,7 @@ const ConfirmDialogPublishAll = ({
2919
3309
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2920
3310
  const { model, schema } = useDoc();
2921
3311
  const [{ query }] = strapiAdmin.useQueryParams();
3312
+ const enableDraftRelationsCount = false;
2922
3313
  const {
2923
3314
  data: countDraftRelations = 0,
2924
3315
  isLoading,
@@ -2930,7 +3321,7 @@ const ConfirmDialogPublishAll = ({
2930
3321
  locale: query?.plugins?.i18n?.locale
2931
3322
  },
2932
3323
  {
2933
- skip: selectedEntries.length === 0
3324
+ skip: !enableDraftRelationsCount
2934
3325
  }
2935
3326
  );
2936
3327
  React__namespace.useEffect(() => {
@@ -2954,7 +3345,7 @@ const ConfirmDialogPublishAll = ({
2954
3345
  defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
2955
3346
  },
2956
3347
  {
2957
- b: BoldChunk$1,
3348
+ b: BoldChunk,
2958
3349
  count: countDraftRelations,
2959
3350
  entities: selectedEntries.length
2960
3351
  }
@@ -2993,6 +3384,16 @@ const ConfirmDialogPublishAll = ({
2993
3384
  const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
2994
3385
  max-width: 300px;
2995
3386
  `;
3387
+ const TableComponent = styledComponents.styled(designSystem.RawTable)`
3388
+ width: 100%;
3389
+ table-layout: fixed;
3390
+ td:first-child {
3391
+ border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
3392
+ }
3393
+ td:first-of-type {
3394
+ padding: ${({ theme }) => theme.spaces[4]};
3395
+ }
3396
+ `;
2996
3397
  const formatErrorMessages = (errors, parentKey, formatMessage) => {
2997
3398
  const messages = [];
2998
3399
  Object.entries(errors).forEach(([key, value]) => {
@@ -3097,7 +3498,7 @@ const SelectedEntriesTableContent = ({
3097
3498
  )
3098
3499
  ] }),
3099
3500
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3100
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3501
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3101
3502
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3102
3503
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3103
3504
  shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
@@ -3115,7 +3516,7 @@ const SelectedEntriesTableContent = ({
3115
3516
  status: row.status
3116
3517
  }
3117
3518
  ) }),
3118
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3519
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3119
3520
  designSystem.IconButton,
3120
3521
  {
3121
3522
  tag: reactRouterDom.Link,
@@ -3124,27 +3525,86 @@ const SelectedEntriesTableContent = ({
3124
3525
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3125
3526
  },
3126
3527
  state: { from: pathname },
3127
- label: formatMessage(
3128
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3129
- {
3130
- target: formatMessage(
3131
- {
3132
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3133
- defaultMessage: "item line {number}"
3134
- },
3135
- { number: index2 + 1 }
3136
- )
3137
- }
3138
- ),
3528
+ label: formatMessage({
3529
+ id: "content-manager.bulk-publish.edit",
3530
+ defaultMessage: "Edit"
3531
+ }),
3139
3532
  target: "_blank",
3140
3533
  marginLeft: "auto",
3141
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3534
+ variant: "ghost",
3535
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3142
3536
  }
3143
- ) })
3537
+ ) }) })
3144
3538
  ] }, row.id)) })
3145
3539
  ] });
3146
3540
  };
3147
- const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3541
+ const PublicationStatusSummary = ({ count, icon, message }) => {
3542
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", flex: 1, gap: 3, children: [
3543
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3544
+ icon,
3545
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: message })
3546
+ ] }),
3547
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: count })
3548
+ ] });
3549
+ };
3550
+ const PublicationStatusGrid = ({
3551
+ entriesReadyToPublishCount,
3552
+ entriesPublishedCount,
3553
+ entriesModifiedCount,
3554
+ entriesWithErrorsCount
3555
+ }) => {
3556
+ const { formatMessage } = reactIntl.useIntl();
3557
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { hasRadius: true, borderColor: "neutral150", children: /* @__PURE__ */ jsxRuntime.jsx(TableComponent, { colCount: 2, rowCount: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
3558
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
3559
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
3560
+ PublicationStatusSummary,
3561
+ {
3562
+ count: entriesReadyToPublishCount,
3563
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3564
+ message: formatMessage({
3565
+ id: "app.utils.ready-to-publish",
3566
+ defaultMessage: "Ready to publish"
3567
+ })
3568
+ }
3569
+ ) }),
3570
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
3571
+ PublicationStatusSummary,
3572
+ {
3573
+ count: entriesPublishedCount,
3574
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3575
+ message: formatMessage({
3576
+ id: "app.utils.already-published",
3577
+ defaultMessage: "Already published"
3578
+ })
3579
+ }
3580
+ ) })
3581
+ ] }),
3582
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
3583
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
3584
+ PublicationStatusSummary,
3585
+ {
3586
+ count: entriesModifiedCount,
3587
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3588
+ message: formatMessage({
3589
+ id: "content-manager.bulk-publish.modified",
3590
+ defaultMessage: "Ready to publish changes"
3591
+ })
3592
+ }
3593
+ ) }),
3594
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
3595
+ PublicationStatusSummary,
3596
+ {
3597
+ count: entriesWithErrorsCount,
3598
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
3599
+ message: formatMessage({
3600
+ id: "content-manager.bulk-publish.waiting-for-action",
3601
+ defaultMessage: "Waiting for action"
3602
+ })
3603
+ }
3604
+ ) })
3605
+ ] })
3606
+ ] }) }) });
3607
+ };
3148
3608
  const SelectedEntriesModalContent = ({
3149
3609
  listViewSelectedEntries,
3150
3610
  toggleModal,
@@ -3177,7 +3637,13 @@ const SelectedEntriesModalContent = ({
3177
3637
  );
3178
3638
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3179
3639
  if (data.length > 0 && schema) {
3180
- const validate = createYupSchema(schema.attributes, components);
3640
+ const validate = createYupSchema(
3641
+ schema.attributes,
3642
+ components,
3643
+ // Since this is the "Publish" action, the validation
3644
+ // schema must enforce the rules for published entities
3645
+ { status: "published" }
3646
+ );
3181
3647
  const validationErrors2 = {};
3182
3648
  const rows2 = data.map((entry) => {
3183
3649
  try {
@@ -3197,7 +3663,6 @@ const SelectedEntriesModalContent = ({
3197
3663
  validationErrors: {}
3198
3664
  };
3199
3665
  }, [components, data, schema]);
3200
- const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3201
3666
  const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3202
3667
  const { publishMany: bulkPublishAction } = useDocumentActions();
3203
3668
  const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
@@ -3209,53 +3674,36 @@ const SelectedEntriesModalContent = ({
3209
3674
  const selectedEntriesWithErrorsCount = selectedEntries.filter(
3210
3675
  ({ documentId }) => validationErrors[documentId]
3211
3676
  ).length;
3212
- const selectedEntriesPublished = selectedEntries.filter(
3677
+ const selectedEntriesPublishedCount = selectedEntries.filter(
3213
3678
  ({ status }) => status === "published"
3214
3679
  ).length;
3215
- const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3680
+ const selectedEntriesModifiedCount = selectedEntries.filter(
3681
+ ({ status, documentId }) => status === "modified" && !validationErrors[documentId]
3682
+ ).length;
3683
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublishedCount;
3216
3684
  const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3217
3685
  const handleConfirmBulkPublish = async () => {
3218
3686
  toggleDialog();
3219
3687
  const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3220
3688
  if (!("error" in res)) {
3221
- setPublishedCount(res.count);
3222
3689
  const unpublishedEntries = rows.filter((row) => {
3223
3690
  return !entriesToPublish.includes(row.documentId);
3224
3691
  });
3225
3692
  setListViewSelectedDocuments(unpublishedEntries);
3226
3693
  }
3227
3694
  };
3228
- const getFormattedCountMessage = () => {
3229
- if (publishedCount) {
3230
- return formatMessage(
3231
- {
3232
- id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3233
- defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3234
- },
3235
- {
3236
- publishedCount,
3237
- withErrorsCount: selectedEntriesWithErrorsCount,
3238
- b: BoldChunk
3239
- }
3240
- );
3241
- }
3242
- return formatMessage(
3243
- {
3244
- id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3245
- defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3246
- },
3247
- {
3248
- readyToPublishCount: selectedEntriesWithNoErrorsCount,
3249
- withErrorsCount: selectedEntriesWithErrorsCount,
3250
- alreadyPublishedCount: selectedEntriesPublished,
3251
- b: BoldChunk
3252
- }
3253
- );
3254
- };
3255
3695
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3256
3696
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3257
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3258
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3697
+ /* @__PURE__ */ jsxRuntime.jsx(
3698
+ PublicationStatusGrid,
3699
+ {
3700
+ entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
3701
+ entriesPublishedCount: selectedEntriesPublishedCount,
3702
+ entriesModifiedCount: selectedEntriesModifiedCount,
3703
+ entriesWithErrorsCount: selectedEntriesWithErrorsCount
3704
+ }
3705
+ ),
3706
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 7, children: /* @__PURE__ */ jsxRuntime.jsx(
3259
3707
  SelectedEntriesTableContent,
3260
3708
  {
3261
3709
  isPublishing: isSubmittingForm,
@@ -3276,7 +3724,7 @@ const SelectedEntriesModalContent = ({
3276
3724
  designSystem.Button,
3277
3725
  {
3278
3726
  onClick: toggleDialog,
3279
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3727
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
3280
3728
  loading: isSubmittingForm,
3281
3729
  children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3282
3730
  }
@@ -3302,8 +3750,7 @@ const PublishAction = ({ documents, model }) => {
3302
3750
  const refetchList = () => {
3303
3751
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3304
3752
  };
3305
- if (!showPublishButton)
3306
- return null;
3753
+ if (!showPublishButton) return null;
3307
3754
  return {
3308
3755
  actionType: "publish",
3309
3756
  variant: "tertiary",
@@ -3371,8 +3818,7 @@ const DeleteAction = ({ documents, model }) => {
3371
3818
  selectRow([]);
3372
3819
  }
3373
3820
  };
3374
- if (!hasDeletePermission)
3375
- return null;
3821
+ if (!hasDeletePermission) return null;
3376
3822
  return {
3377
3823
  variant: "danger-light",
3378
3824
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3421,8 +3867,7 @@ const UnpublishAction = ({ documents, model }) => {
3421
3867
  }
3422
3868
  };
3423
3869
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3424
- if (!showUnpublishButton)
3425
- return null;
3870
+ if (!showUnpublishButton) return null;
3426
3871
  return {
3427
3872
  variant: "tertiary",
3428
3873
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3527,7 +3972,7 @@ const TableActions = ({ document }) => {
3527
3972
  strapiAdmin.DescriptionComponentRenderer,
3528
3973
  {
3529
3974
  props,
3530
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3975
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3531
3976
  children: (actions2) => {
3532
3977
  const tableRowActions = actions2.filter((action) => {
3533
3978
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3586,6 +4031,7 @@ const EditAction = ({ documentId }) => {
3586
4031
  };
3587
4032
  };
3588
4033
  EditAction.type = "edit";
4034
+ EditAction.position = "table-row";
3589
4035
  const StyledPencil = styledComponents.styled(Icons.Pencil)`
3590
4036
  path {
3591
4037
  fill: currentColor;
@@ -3638,7 +4084,7 @@ const CloneAction = ({ model, documentId }) => {
3638
4084
  }),
3639
4085
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3640
4086
  footer: ({ onClose }) => {
3641
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
4087
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3642
4088
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3643
4089
  id: "cancel",
3644
4090
  defaultMessage: "Cancel"
@@ -3662,6 +4108,7 @@ const CloneAction = ({ model, documentId }) => {
3662
4108
  };
3663
4109
  };
3664
4110
  CloneAction.type = "clone";
4111
+ CloneAction.position = "table-row";
3665
4112
  const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
3666
4113
  path {
3667
4114
  fill: currentColor;
@@ -3748,7 +4195,14 @@ class ContentManagerPlugin {
3748
4195
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3749
4196
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3750
4197
  getBulkActions: () => this.bulkActions,
3751
- getDocumentActions: () => this.documentActions,
4198
+ getDocumentActions: (position) => {
4199
+ if (position) {
4200
+ return this.documentActions.filter(
4201
+ (action) => action.position == void 0 || [action.position].flat().includes(position)
4202
+ );
4203
+ }
4204
+ return this.documentActions;
4205
+ },
3752
4206
  getEditViewSidePanels: () => this.editViewSidePanels,
3753
4207
  getHeaderActions: () => this.headerActions
3754
4208
  }
@@ -3758,10 +4212,8 @@ class ContentManagerPlugin {
3758
4212
  const getPrintableType = (value) => {
3759
4213
  const nativeType = typeof value;
3760
4214
  if (nativeType === "object") {
3761
- if (value === null)
3762
- return "null";
3763
- if (Array.isArray(value))
3764
- return "array";
4215
+ if (value === null) return "null";
4216
+ if (Array.isArray(value)) return "array";
3765
4217
  if (value instanceof Object && value.constructor.name !== "Object") {
3766
4218
  return value.constructor.name;
3767
4219
  }
@@ -3772,17 +4224,27 @@ const HistoryAction = ({ model, document }) => {
3772
4224
  const { formatMessage } = reactIntl.useIntl();
3773
4225
  const [{ query }] = strapiAdmin.useQueryParams();
3774
4226
  const navigate = reactRouterDom.useNavigate();
4227
+ const { trackUsage } = strapiAdmin.useTracking();
4228
+ const { pathname } = reactRouterDom.useLocation();
3775
4229
  const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3776
4230
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3777
4231
  return null;
3778
4232
  }
4233
+ const handleOnClick = () => {
4234
+ const destination = { pathname: "history", search: pluginsQueryParams };
4235
+ trackUsage("willNavigate", {
4236
+ from: pathname,
4237
+ to: `${pathname}/${destination.pathname}`
4238
+ });
4239
+ navigate(destination);
4240
+ };
3779
4241
  return {
3780
4242
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3781
4243
  label: formatMessage({
3782
4244
  id: "content-manager.history.document-action",
3783
4245
  defaultMessage: "Content History"
3784
4246
  }),
3785
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
4247
+ onClick: handleOnClick,
3786
4248
  disabled: (
3787
4249
  /**
3788
4250
  * The user is creating a new document.
@@ -3804,6 +4266,7 @@ const HistoryAction = ({ model, document }) => {
3804
4266
  };
3805
4267
  };
3806
4268
  HistoryAction.type = "history";
4269
+ HistoryAction.position = "header";
3807
4270
  const historyAdmin = {
3808
4271
  bootstrap(app) {
3809
4272
  const { addDocumentAction } = app.getPlugin("content-manager").apis;
@@ -3850,6 +4313,88 @@ const { setInitialData } = actions;
3850
4313
  const reducer = toolkit.combineReducers({
3851
4314
  app: reducer$1
3852
4315
  });
4316
+ const previewApi = contentManagerApi.injectEndpoints({
4317
+ endpoints: (builder) => ({
4318
+ getPreviewUrl: builder.query({
4319
+ query({ query, params }) {
4320
+ return {
4321
+ url: `/content-manager/preview/url/${params.contentType}`,
4322
+ method: "GET",
4323
+ config: {
4324
+ params: query
4325
+ }
4326
+ };
4327
+ }
4328
+ })
4329
+ })
4330
+ });
4331
+ const { useGetPreviewUrlQuery } = previewApi;
4332
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4333
+ if (isShown) {
4334
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label, children });
4335
+ }
4336
+ return children;
4337
+ };
4338
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4339
+ const { formatMessage } = reactIntl.useIntl();
4340
+ const { trackUsage } = strapiAdmin.useTracking();
4341
+ const { pathname } = reactRouterDom.useLocation();
4342
+ const [{ query }] = strapiAdmin.useQueryParams();
4343
+ const isModified = strapiAdmin.useForm("PreviewSidePanel", (state) => state.modified);
4344
+ const { data, error } = useGetPreviewUrlQuery({
4345
+ params: {
4346
+ contentType: model
4347
+ },
4348
+ query: {
4349
+ documentId,
4350
+ locale: document?.locale,
4351
+ status: document?.status
4352
+ }
4353
+ });
4354
+ if (!data?.data?.url || error) {
4355
+ return null;
4356
+ }
4357
+ const trackNavigation = () => {
4358
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4359
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4360
+ };
4361
+ return {
4362
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4363
+ content: /* @__PURE__ */ jsxRuntime.jsx(
4364
+ ConditionalTooltip,
4365
+ {
4366
+ label: formatMessage({
4367
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4368
+ defaultMessage: "Please save to open the preview"
4369
+ }),
4370
+ isShown: isModified,
4371
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
4372
+ designSystem.Button,
4373
+ {
4374
+ variant: "tertiary",
4375
+ tag: reactRouterDom.Link,
4376
+ to: { pathname: "preview", search: qs.stringify(query, { encode: false }) },
4377
+ onClick: trackNavigation,
4378
+ width: "100%",
4379
+ disabled: isModified,
4380
+ pointerEvents: isModified ? "none" : void 0,
4381
+ tabIndex: isModified ? -1 : void 0,
4382
+ children: formatMessage({
4383
+ id: "content-manager.preview.panel.button",
4384
+ defaultMessage: "Open preview"
4385
+ })
4386
+ }
4387
+ ) })
4388
+ }
4389
+ )
4390
+ };
4391
+ };
4392
+ const previewAdmin = {
4393
+ bootstrap(app) {
4394
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4395
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4396
+ }
4397
+ };
3853
4398
  const index = {
3854
4399
  register(app) {
3855
4400
  const cm = new ContentManagerPlugin();
@@ -3869,7 +4414,7 @@ const index = {
3869
4414
  app.router.addRoute({
3870
4415
  path: "content-manager/*",
3871
4416
  lazy: async () => {
3872
- const { Layout } = await Promise.resolve().then(() => require("./layout-Ci7qHlFb.js"));
4417
+ const { Layout } = await Promise.resolve().then(() => require("./layout-DSeUTfMv.js"));
3873
4418
  return {
3874
4419
  Component: Layout
3875
4420
  };
@@ -3882,11 +4427,14 @@ const index = {
3882
4427
  if (typeof historyAdmin.bootstrap === "function") {
3883
4428
  historyAdmin.bootstrap(app);
3884
4429
  }
4430
+ if (typeof previewAdmin.bootstrap === "function") {
4431
+ previewAdmin.bootstrap(app);
4432
+ }
3885
4433
  },
3886
4434
  async registerTrads({ locales }) {
3887
4435
  const importedTrads = await Promise.all(
3888
4436
  locales.map((locale) => {
3889
- 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 }) => {
4437
+ 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-BR48D_RH.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-9K52xZIr.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-C43IbhA_.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-7sfIbjxE.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
3890
4438
  return {
3891
4439
  data: prefixPluginTranslations(data, PLUGIN_ID),
3892
4440
  locale
@@ -3904,10 +4452,10 @@ const index = {
3904
4452
  };
3905
4453
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3906
4454
  exports.BulkActionsRenderer = BulkActionsRenderer;
4455
+ exports.CLONE_PATH = CLONE_PATH;
3907
4456
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3908
4457
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3909
4458
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
3910
- exports.DOCUMENT_META_FIELDS = DOCUMENT_META_FIELDS;
3911
4459
  exports.DocumentRBAC = DocumentRBAC;
3912
4460
  exports.DocumentStatus = DocumentStatus;
3913
4461
  exports.HOOKS = HOOKS;
@@ -3924,13 +4472,18 @@ exports.checkIfAttributeIsDisplayable = checkIfAttributeIsDisplayable;
3924
4472
  exports.contentManagerApi = contentManagerApi;
3925
4473
  exports.convertEditLayoutToFieldLayouts = convertEditLayoutToFieldLayouts;
3926
4474
  exports.convertListLayoutToFieldLayouts = convertListLayoutToFieldLayouts;
4475
+ exports.createDefaultForm = createDefaultForm;
3927
4476
  exports.createYupSchema = createYupSchema;
3928
4477
  exports.extractContentTypeComponents = extractContentTypeComponents;
3929
4478
  exports.getDisplayName = getDisplayName;
3930
4479
  exports.getMainField = getMainField;
3931
4480
  exports.getTranslation = getTranslation;
3932
4481
  exports.index = index;
4482
+ exports.prepareTempKeys = prepareTempKeys;
4483
+ exports.removeFieldsThatDontExistOnSchema = removeFieldsThatDontExistOnSchema;
3933
4484
  exports.setInitialData = setInitialData;
4485
+ exports.transformDocument = transformDocument;
4486
+ exports.useContentManagerContext = useContentManagerContext;
3934
4487
  exports.useContentTypeSchema = useContentTypeSchema;
3935
4488
  exports.useDoc = useDoc;
3936
4489
  exports.useDocLayout = useDocLayout;
@@ -3942,5 +4495,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
3942
4495
  exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3943
4496
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3944
4497
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
4498
+ exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
3945
4499
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3946
- //# sourceMappingURL=index-OerGjbAN.js.map
4500
+ //# sourceMappingURL=index-CxLSGwnk.js.map