@strapi/content-manager 0.0.0-experimental.4ddd402c7194d1a969a797313bf007c93148d59a → 0.0.0-experimental.51e87e311df34df634a6bce7b841df8be31f1efb

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 (226) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  3. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-Cxz51Sve.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +4 -4
  5. package/dist/_chunks/{ComponentConfigurationPage-Cxz51Sve.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
  6. package/dist/_chunks/{ComponentConfigurationPage-BZIaEffq.js → ComponentConfigurationPage-DdkVGfXC.js} +5 -6
  7. package/dist/_chunks/{ComponentConfigurationPage-BZIaEffq.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  9. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  10. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-CZLbgfIp.mjs → EditConfigurationPage-D1nvB7Br.mjs} +4 -4
  12. package/dist/_chunks/{EditConfigurationPage-CZLbgfIp.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
  13. package/dist/_chunks/{EditConfigurationPage-CM62NN0L.js → EditConfigurationPage-LYEvR4fW.js} +5 -6
  14. package/dist/_chunks/{EditConfigurationPage-CM62NN0L.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
  15. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs +191 -0
  16. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
  17. package/dist/_chunks/{EditViewPage-CU7724gt.js → EditViewPage-DqelJ9UK.js} +71 -84
  18. package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
  19. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  20. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  21. package/dist/_chunks/{Form-BOR8NOe1.js → Form-CnHfBeiB.js} +55 -38
  22. package/dist/_chunks/Form-CnHfBeiB.js.map +1 -0
  23. package/dist/_chunks/{Form-COLpvlnv.mjs → Form-CzPCJi3B.mjs} +55 -37
  24. package/dist/_chunks/Form-CzPCJi3B.mjs.map +1 -0
  25. package/dist/_chunks/{History-Bu53Yfw-.mjs → History-CcmSn3Mj.mjs} +201 -130
  26. package/dist/_chunks/History-CcmSn3Mj.mjs.map +1 -0
  27. package/dist/_chunks/{History-CW2akQ6h.js → History-zArjENzj.js} +208 -138
  28. package/dist/_chunks/History-zArjENzj.js.map +1 -0
  29. package/dist/_chunks/{Field-Dh1yZyqy.js → Input-CDHKQd7o.js} +1748 -1373
  30. package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
  31. package/dist/_chunks/{Field-QtUSh5mU.mjs → Input-aV8SSoTa.mjs} +1757 -1382
  32. package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-TqrmwjPN.mjs → ListConfigurationPage-BPvzENJJ.mjs} +63 -52
  34. package/dist/_chunks/ListConfigurationPage-BPvzENJJ.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-jzdhEk_u.js → ListConfigurationPage-ByZAO_9H.js} +62 -51
  36. package/dist/_chunks/ListConfigurationPage-ByZAO_9H.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-B3bMOrMv.js → ListViewPage-BVKBeQAA.js} +154 -128
  38. package/dist/_chunks/ListViewPage-BVKBeQAA.js.map +1 -0
  39. package/dist/_chunks/{ListViewPage-BO_mOXIl.mjs → ListViewPage-HljQVnFH.mjs} +155 -128
  40. package/dist/_chunks/ListViewPage-HljQVnFH.mjs.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-D77xsNHj.js → NoContentTypePage-BV5zfDxr.js} +2 -2
  42. package/dist/_chunks/{NoContentTypePage-D77xsNHj.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
  43. package/dist/_chunks/{NoContentTypePage-DqB0QV0k.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
  44. package/dist/_chunks/{NoContentTypePage-DqB0QV0k.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
  45. package/dist/_chunks/{NoPermissionsPage-DTXi042N.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-DTXi042N.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-C6qTGogm.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-C6qTGogm.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
  49. package/dist/_chunks/Preview-DEHdENT1.js +305 -0
  50. package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
  51. package/dist/_chunks/Preview-vfWOtPG5.mjs +287 -0
  52. package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
  53. package/dist/_chunks/{Relations-CJ4qdkRo.mjs → Relations-B7_hbF0w.mjs} +79 -44
  54. package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
  55. package/dist/_chunks/{Relations-B6fb2POW.js → Relations-DcoOBejP.js} +79 -45
  56. package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
  57. package/dist/_chunks/{en-DZXjRiWA.js → en-BR48D_RH.js} +41 -18
  58. package/dist/_chunks/{en-DZXjRiWA.js.map → en-BR48D_RH.js.map} +1 -1
  59. package/dist/_chunks/{en-9GwRW_ku.mjs → en-D65uIF6Y.mjs} +41 -18
  60. package/dist/_chunks/{en-9GwRW_ku.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  61. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  62. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  63. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  64. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  65. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  66. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  67. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  68. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  69. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  70. package/dist/_chunks/{index-DcUu-_72.js → index-CxLSGwnk.js} +1504 -960
  71. package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
  72. package/dist/_chunks/{index-Dahjdw4h.mjs → index-EH8ZtHd5.mjs} +1524 -980
  73. package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
  74. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  75. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  77. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  78. package/dist/_chunks/{layout-omucV6TV.mjs → layout-CxDMdJ13.mjs} +28 -15
  79. package/dist/_chunks/layout-CxDMdJ13.mjs.map +1 -0
  80. package/dist/_chunks/{layout-jcY4dyUG.js → layout-DSeUTfMv.js} +27 -15
  81. package/dist/_chunks/layout-DSeUTfMv.js.map +1 -0
  82. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  83. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  84. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  85. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  86. package/dist/_chunks/{relations-CN0-aw6p.mjs → relations-B8_Uu38Q.mjs} +21 -8
  87. package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
  88. package/dist/_chunks/{relations-DGzD7ORa.js → relations-S5nNKdN3.js} +20 -7
  89. package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  91. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  93. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  94. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -1
  95. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -1
  96. package/dist/admin/index.js +3 -1
  97. package/dist/admin/index.js.map +1 -1
  98. package/dist/admin/index.mjs +6 -4
  99. package/dist/admin/src/content-manager.d.ts +3 -2
  100. package/dist/admin/src/exports.d.ts +2 -1
  101. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  102. package/dist/admin/src/history/index.d.ts +3 -0
  103. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  104. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  105. package/dist/admin/src/index.d.ts +1 -0
  106. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  107. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +9 -4
  108. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  109. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  110. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  111. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +5 -0
  112. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  113. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  114. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  115. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  116. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  117. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  118. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  119. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  120. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  121. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  122. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  123. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  124. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  125. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  126. package/dist/admin/src/preview/index.d.ts +4 -0
  127. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  128. package/dist/admin/src/preview/routes.d.ts +3 -0
  129. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  130. package/dist/admin/src/router.d.ts +1 -1
  131. package/dist/admin/src/services/api.d.ts +1 -1
  132. package/dist/admin/src/services/components.d.ts +2 -2
  133. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  134. package/dist/admin/src/services/documents.d.ts +19 -20
  135. package/dist/admin/src/services/init.d.ts +1 -1
  136. package/dist/admin/src/services/relations.d.ts +2 -2
  137. package/dist/admin/src/services/uid.d.ts +3 -3
  138. package/dist/admin/src/utils/validation.d.ts +4 -1
  139. package/dist/server/index.js +765 -434
  140. package/dist/server/index.js.map +1 -1
  141. package/dist/server/index.mjs +766 -434
  142. package/dist/server/index.mjs.map +1 -1
  143. package/dist/server/src/bootstrap.d.ts.map +1 -1
  144. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  145. package/dist/server/src/controllers/index.d.ts.map +1 -1
  146. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  147. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  148. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  149. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  150. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  151. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  152. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  153. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  154. package/dist/server/src/history/services/history.d.ts +3 -3
  155. package/dist/server/src/history/services/history.d.ts.map +1 -1
  156. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  157. package/dist/server/src/history/services/utils.d.ts +8 -12
  158. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  159. package/dist/server/src/index.d.ts +7 -6
  160. package/dist/server/src/index.d.ts.map +1 -1
  161. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  162. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  163. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  164. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  165. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  166. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  167. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  168. package/dist/server/src/preview/index.d.ts +4 -0
  169. package/dist/server/src/preview/index.d.ts.map +1 -0
  170. package/dist/server/src/preview/routes/index.d.ts +8 -0
  171. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  172. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  173. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  174. package/dist/server/src/preview/services/index.d.ts +16 -0
  175. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  176. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  177. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  178. package/dist/server/src/preview/services/preview.d.ts +12 -0
  179. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  180. package/dist/server/src/preview/utils.d.ts +19 -0
  181. package/dist/server/src/preview/utils.d.ts.map +1 -0
  182. package/dist/server/src/register.d.ts.map +1 -1
  183. package/dist/server/src/routes/index.d.ts.map +1 -1
  184. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  185. package/dist/server/src/services/document-metadata.d.ts +12 -10
  186. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  187. package/dist/server/src/services/index.d.ts +7 -6
  188. package/dist/server/src/services/index.d.ts.map +1 -1
  189. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  190. package/dist/server/src/services/utils/populate.d.ts +2 -2
  191. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  192. package/dist/server/src/utils/index.d.ts +2 -0
  193. package/dist/server/src/utils/index.d.ts.map +1 -1
  194. package/dist/shared/contracts/collection-types.d.ts +3 -1
  195. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  196. package/dist/shared/contracts/index.d.ts +1 -0
  197. package/dist/shared/contracts/index.d.ts.map +1 -1
  198. package/dist/shared/contracts/preview.d.ts +27 -0
  199. package/dist/shared/contracts/preview.d.ts.map +1 -0
  200. package/dist/shared/index.js +4 -0
  201. package/dist/shared/index.js.map +1 -1
  202. package/dist/shared/index.mjs +4 -0
  203. package/dist/shared/index.mjs.map +1 -1
  204. package/package.json +17 -16
  205. package/dist/_chunks/EditViewPage-CU7724gt.js.map +0 -1
  206. package/dist/_chunks/EditViewPage-CzuJgWWp.mjs +0 -203
  207. package/dist/_chunks/EditViewPage-CzuJgWWp.mjs.map +0 -1
  208. package/dist/_chunks/Field-Dh1yZyqy.js.map +0 -1
  209. package/dist/_chunks/Field-QtUSh5mU.mjs.map +0 -1
  210. package/dist/_chunks/Form-BOR8NOe1.js.map +0 -1
  211. package/dist/_chunks/Form-COLpvlnv.mjs.map +0 -1
  212. package/dist/_chunks/History-Bu53Yfw-.mjs.map +0 -1
  213. package/dist/_chunks/History-CW2akQ6h.js.map +0 -1
  214. package/dist/_chunks/ListConfigurationPage-TqrmwjPN.mjs.map +0 -1
  215. package/dist/_chunks/ListConfigurationPage-jzdhEk_u.js.map +0 -1
  216. package/dist/_chunks/ListViewPage-B3bMOrMv.js.map +0 -1
  217. package/dist/_chunks/ListViewPage-BO_mOXIl.mjs.map +0 -1
  218. package/dist/_chunks/Relations-B6fb2POW.js.map +0 -1
  219. package/dist/_chunks/Relations-CJ4qdkRo.mjs.map +0 -1
  220. package/dist/_chunks/index-Dahjdw4h.mjs.map +0 -1
  221. package/dist/_chunks/index-DcUu-_72.js.map +0 -1
  222. package/dist/_chunks/layout-jcY4dyUG.js.map +0 -1
  223. package/dist/_chunks/layout-omucV6TV.mjs.map +0 -1
  224. package/dist/_chunks/relations-CN0-aw6p.mjs.map +0 -1
  225. package/dist/_chunks/relations-DGzD7ORa.js.map +0 -1
  226. package/strapi-server.js +0 -3
@@ -2,20 +2,21 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
7
+ const mapValues = require("lodash/fp/mapValues");
8
+ const reactIntl = require("react-intl");
9
+ const reactRouterDom = require("react-router-dom");
10
10
  const styledComponents = require("styled-components");
11
11
  const yup = require("yup");
12
+ const fractionalIndexing = require("fractional-indexing");
12
13
  const pipe = require("lodash/fp/pipe");
14
+ const qs = require("qs");
13
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";
@@ -70,42 +79,6 @@ const useInjectionZone = (area) => {
70
79
  const [page, position] = area.split(".");
71
80
  return contentManagerPlugin.getInjectedComponents(page, position);
72
81
  };
73
- const HistoryAction = ({ model, document }) => {
74
- const { formatMessage } = reactIntl.useIntl();
75
- const [{ query }] = strapiAdmin.useQueryParams();
76
- const navigate = reactRouterDom.useNavigate();
77
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
78
- if (!window.strapi.features.isEnabled("cms-content-history")) {
79
- return null;
80
- }
81
- return {
82
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
83
- label: formatMessage({
84
- id: "content-manager.history.document-action",
85
- defaultMessage: "Content History"
86
- }),
87
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
88
- disabled: (
89
- /**
90
- * The user is creating a new document.
91
- * It hasn't been saved yet, so there's no history to go to
92
- */
93
- !document || /**
94
- * The document has been created but the current dimension has never been saved.
95
- * For example, the user is creating a new locale in an existing document,
96
- * so there's no history for the document in that locale
97
- */
98
- !document.id || /**
99
- * History is only available for content types created by the user.
100
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
101
- * which start with `admin::` or `plugin::`
102
- */
103
- !model.startsWith("api::")
104
- ),
105
- position: "header"
106
- };
107
- };
108
- HistoryAction.type = "history";
109
82
  const ID = "id";
110
83
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
111
84
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -157,6 +130,7 @@ const DocumentRBAC = ({ children, permissions }) => {
157
130
  if (!slug) {
158
131
  throw new Error("Cannot find the slug param in the URL");
159
132
  }
133
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
160
134
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
161
135
  const contentTypePermissions = React__namespace.useMemo(() => {
162
136
  const contentTypePermissions2 = userPermissions.filter(
@@ -167,7 +141,14 @@ const DocumentRBAC = ({ children, permissions }) => {
167
141
  return { ...acc, [action]: [permission] };
168
142
  }, {});
169
143
  }, [slug, userPermissions]);
170
- 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
+ );
171
152
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
172
153
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
173
154
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -207,6 +188,113 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
207
188
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
208
189
  );
209
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
+ };
210
298
  const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
211
299
  addTagTypes: [
212
300
  "ComponentConfiguration",
@@ -215,10 +303,13 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
215
303
  "Document",
216
304
  "InitialData",
217
305
  "HistoryVersion",
218
- "Relations"
306
+ "Relations",
307
+ "UidAvailability",
308
+ "RecentDocumentList"
219
309
  ]
220
310
  });
221
311
  const documentApi = contentManagerApi.injectEndpoints({
312
+ overrideExisting: true,
222
313
  endpoints: (builder) => ({
223
314
  autoCloneDocument: builder.mutation({
224
315
  query: ({ model, sourceId, query }) => ({
@@ -228,7 +319,12 @@ const documentApi = contentManagerApi.injectEndpoints({
228
319
  params: query
229
320
  }
230
321
  }),
231
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
322
+ invalidatesTags: (_result, error, { model }) => {
323
+ if (error) {
324
+ return [];
325
+ }
326
+ return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
327
+ }
232
328
  }),
233
329
  cloneDocument: builder.mutation({
234
330
  query: ({ model, sourceId, data, params }) => ({
@@ -239,7 +335,11 @@ const documentApi = contentManagerApi.injectEndpoints({
239
335
  params
240
336
  }
241
337
  }),
242
- 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
+ ]
243
343
  }),
244
344
  /**
245
345
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -256,8 +356,22 @@ const documentApi = contentManagerApi.injectEndpoints({
256
356
  }),
257
357
  invalidatesTags: (result, _error, { model }) => [
258
358
  { type: "Document", id: `${model}_LIST` },
259
- "Relations"
260
- ]
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
+ }
261
375
  }),
262
376
  deleteDocument: builder.mutation({
263
377
  query: ({ collectionType, model, documentId, params }) => ({
@@ -268,7 +382,8 @@ const documentApi = contentManagerApi.injectEndpoints({
268
382
  }
269
383
  }),
270
384
  invalidatesTags: (_result, _error, { collectionType, model }) => [
271
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
385
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
386
+ "RecentDocumentList"
272
387
  ]
273
388
  }),
274
389
  deleteManyDocuments: builder.mutation({
@@ -280,7 +395,10 @@ const documentApi = contentManagerApi.injectEndpoints({
280
395
  params
281
396
  }
282
397
  }),
283
- invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
398
+ invalidatesTags: (_res, _error, { model }) => [
399
+ { type: "Document", id: `${model}_LIST` },
400
+ "RecentDocumentList"
401
+ ]
284
402
  }),
285
403
  discardDocument: builder.mutation({
286
404
  query: ({ collectionType, model, documentId, params }) => ({
@@ -297,7 +415,9 @@ const documentApi = contentManagerApi.injectEndpoints({
297
415
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
298
416
  },
299
417
  { type: "Document", id: `${model}_LIST` },
300
- "Relations"
418
+ "Relations",
419
+ { type: "UidAvailability", id: model },
420
+ "RecentDocumentList"
301
421
  ];
302
422
  }
303
423
  }),
@@ -310,11 +430,12 @@ const documentApi = contentManagerApi.injectEndpoints({
310
430
  url: `/content-manager/collection-types/${model}`,
311
431
  method: "GET",
312
432
  config: {
313
- params
433
+ params: qs.stringify(params, { encode: true })
314
434
  }
315
435
  }),
316
436
  providesTags: (result, _error, arg) => {
317
437
  return [
438
+ { type: "Document", id: `ALL_LIST` },
318
439
  { type: "Document", id: `${arg.model}_LIST` },
319
440
  ...result?.results.map(({ documentId }) => ({
320
441
  type: "Document",
@@ -353,6 +474,11 @@ const documentApi = contentManagerApi.injectEndpoints({
353
474
  {
354
475
  type: "Document",
355
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`
356
482
  }
357
483
  ];
358
484
  }
@@ -386,7 +512,8 @@ const documentApi = contentManagerApi.injectEndpoints({
386
512
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
387
513
  },
388
514
  { type: "Document", id: `${model}_LIST` },
389
- "Relations"
515
+ "Relations",
516
+ "RecentDocumentList"
390
517
  ];
391
518
  }
392
519
  }),
@@ -416,8 +543,23 @@ const documentApi = contentManagerApi.injectEndpoints({
416
543
  type: "Document",
417
544
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
418
545
  },
419
- "Relations"
546
+ "Relations",
547
+ { type: "UidAvailability", id: model },
548
+ "RecentDocumentList",
549
+ "RecentDocumentList"
420
550
  ];
551
+ },
552
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
553
+ const patchResult = dispatch(
554
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
555
+ Object.assign(draft.data, data);
556
+ })
557
+ );
558
+ try {
559
+ await queryFulfilled;
560
+ } catch {
561
+ patchResult.undo();
562
+ }
421
563
  }
422
564
  }),
423
565
  unpublishDocument: builder.mutation({
@@ -434,7 +576,8 @@ const documentApi = contentManagerApi.injectEndpoints({
434
576
  {
435
577
  type: "Document",
436
578
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
437
- }
579
+ },
580
+ "RecentDocumentList"
438
581
  ];
439
582
  }
440
583
  }),
@@ -447,7 +590,10 @@ const documentApi = contentManagerApi.injectEndpoints({
447
590
  params
448
591
  }
449
592
  }),
450
- 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
+ ]
451
597
  })
452
598
  })
453
599
  });
@@ -470,8 +616,7 @@ const {
470
616
  useUnpublishManyDocumentsMutation
471
617
  } = documentApi;
472
618
  const buildValidParams = (query) => {
473
- if (!query)
474
- return query;
619
+ if (!query) return query;
475
620
  const { plugins: _, ...validQueryParams } = {
476
621
  ...query,
477
622
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -479,28 +624,44 @@ const buildValidParams = (query) => {
479
624
  {}
480
625
  )
481
626
  };
482
- if ("_q" in validQueryParams) {
483
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
484
- }
485
627
  return validQueryParams;
486
628
  };
487
629
  const isBaseQueryError = (error) => {
488
630
  return error.name !== void 0;
489
631
  };
490
- 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 }) => {
491
651
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
492
652
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
493
653
  if (DOCUMENT_META_FIELDS.includes(name)) {
494
654
  return acc;
495
655
  }
496
656
  const validations = [
657
+ addNullableValidation,
497
658
  addRequiredValidation,
498
659
  addMinLengthValidation,
499
660
  addMaxLengthValidation,
500
661
  addMinValidation,
501
662
  addMaxValidation,
502
663
  addRegexValidation
503
- ].map((fn) => fn(attribute));
664
+ ].map((fn) => fn(attribute, options));
504
665
  const transformSchema = pipe__default.default(...validations);
505
666
  switch (attribute.type) {
506
667
  case "component": {
@@ -510,12 +671,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
510
671
  ...acc,
511
672
  [name]: transformSchema(
512
673
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
513
- )
674
+ ).test(arrayValidator(attribute, options))
514
675
  };
515
676
  } else {
516
677
  return {
517
678
  ...acc,
518
- [name]: transformSchema(createModelSchema(attributes3))
679
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
519
680
  };
520
681
  }
521
682
  }
@@ -537,7 +698,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
537
698
  }
538
699
  )
539
700
  )
540
- )
701
+ ).test(arrayValidator(attribute, options))
541
702
  };
542
703
  case "relation":
543
704
  return {
@@ -549,7 +710,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
549
710
  } else if (Array.isArray(value)) {
550
711
  return yup__namespace.array().of(
551
712
  yup__namespace.object().shape({
552
- id: yup__namespace.string().required()
713
+ id: yup__namespace.number().required()
553
714
  })
554
715
  );
555
716
  } else if (typeof value === "object") {
@@ -601,6 +762,14 @@ const createAttributeSchema = (attribute) => {
601
762
  if (!value || typeof value === "string" && value.length === 0) {
602
763
  return true;
603
764
  }
765
+ if (typeof value === "object") {
766
+ try {
767
+ JSON.stringify(value);
768
+ return true;
769
+ } catch (err) {
770
+ return false;
771
+ }
772
+ }
604
773
  try {
605
774
  JSON.parse(value);
606
775
  return true;
@@ -619,13 +788,7 @@ const createAttributeSchema = (attribute) => {
619
788
  return yup__namespace.mixed();
620
789
  }
621
790
  };
622
- const addRequiredValidation = (attribute) => (schema) => {
623
- if (attribute.required) {
624
- return schema.required({
625
- id: strapiAdmin.translatedErrors.required.id,
626
- defaultMessage: "This field is required."
627
- });
628
- }
791
+ const nullableSchema = (schema) => {
629
792
  return schema?.nullable ? schema.nullable() : (
630
793
  // In some cases '.nullable' will not be available on the schema.
631
794
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -633,7 +796,22 @@ const addRequiredValidation = (attribute) => (schema) => {
633
796
  schema
634
797
  );
635
798
  };
636
- 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
+ }
637
815
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
638
816
  return schema.min(attribute.minLength, {
639
817
  ...strapiAdmin.translatedErrors.minLength,
@@ -655,10 +833,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
655
833
  }
656
834
  return schema;
657
835
  };
658
- const addMinValidation = (attribute) => (schema) => {
659
- 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) {
660
841
  const min = toInteger(attribute.min);
661
- if ("min" in schema && min) {
842
+ if (min) {
662
843
  return schema.min(min, {
663
844
  ...strapiAdmin.translatedErrors.min,
664
845
  values: {
@@ -776,16 +957,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
776
957
  }, {});
777
958
  return componentsByKey;
778
959
  };
779
- 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);
780
1059
  const { toggleNotification } = strapiAdmin.useNotification();
781
1060
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1061
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
782
1062
  const {
783
- currentData: data,
784
- isLoading: isLoadingDocument,
785
- isFetching: isFetchingDocument,
786
- error
787
- } = useGetDocumentQuery(args, opts);
788
- 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;
789
1069
  React__namespace.useEffect(() => {
790
1070
  if (error) {
791
1071
  toggleNotification({
@@ -793,25 +1073,254 @@ const useDocument = (args, opts) => {
793
1073
  message: formatAPIError(error)
794
1074
  });
795
1075
  }
796
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
797
- const validationSchema = React__namespace.useMemo(() => {
798
- if (!schema) {
799
- return null;
800
- }
801
- return createYupSchema(schema.attributes, components);
802
- }, [schema, components]);
803
- const validate = React__namespace.useCallback(
804
- (document) => {
805
- if (!validationSchema) {
806
- throw new Error(
807
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
808
- );
809
- }
810
- try {
811
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
812
- return null;
813
- } catch (error2) {
814
- if (error2 instanceof yup.ValidationError) {
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
1084
+ },
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]
1101
+ );
1102
+ return {
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) {
815
1324
  return strapiAdmin.getYupValidationErrors(error2);
816
1325
  }
817
1326
  throw error2;
@@ -819,14 +1328,29 @@ const useDocument = (args, opts) => {
819
1328
  },
820
1329
  [validationSchema]
821
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
+ );
822
1341
  const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1342
+ const hasError = !!error;
823
1343
  return {
824
1344
  components,
825
- document: data?.data,
826
- meta: data?.meta,
1345
+ document,
1346
+ meta,
827
1347
  isLoading,
1348
+ hasError,
828
1349
  schema,
829
- validate
1350
+ schemas,
1351
+ validate,
1352
+ getTitle,
1353
+ getInitialFormValues
830
1354
  };
831
1355
  };
832
1356
  const useDoc = () => {
@@ -839,22 +1363,60 @@ const useDoc = () => {
839
1363
  if (!slug) {
840
1364
  throw new Error("Could not find model in url params");
841
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;
842
1373
  return {
843
1374
  collectionType,
844
1375
  model: slug,
845
- id: origin || id === "create" ? void 0 : id,
846
- ...useDocument(
847
- { documentId: origin || id, model: slug, collectionType, params },
848
- {
849
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
850
- }
851
- )
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
852
1417
  };
853
1418
  };
854
1419
  const prefixPluginTranslations = (trad, pluginId) => {
855
- if (!pluginId) {
856
- throw new TypeError("pluginId can't be empty");
857
- }
858
1420
  return Object.keys(trad).reduce((acc, current) => {
859
1421
  acc[`${pluginId}.${current}`] = trad[current];
860
1422
  return acc;
@@ -870,6 +1432,8 @@ const useDocumentActions = () => {
870
1432
  const { formatMessage } = reactIntl.useIntl();
871
1433
  const { trackUsage } = strapiAdmin.useTracking();
872
1434
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1435
+ const navigate = reactRouterDom.useNavigate();
1436
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
873
1437
  const [deleteDocument] = useDeleteDocumentMutation();
874
1438
  const _delete = React__namespace.useCallback(
875
1439
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1184,6 +1748,7 @@ const useDocumentActions = () => {
1184
1748
  defaultMessage: "Saved document"
1185
1749
  })
1186
1750
  });
1751
+ setCurrentStep("contentManager.success");
1187
1752
  return res.data;
1188
1753
  } catch (err) {
1189
1754
  toggleNotification({
@@ -1205,7 +1770,6 @@ const useDocumentActions = () => {
1205
1770
  sourceId
1206
1771
  });
1207
1772
  if ("error" in res) {
1208
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1209
1773
  return { error: res.error };
1210
1774
  }
1211
1775
  toggleNotification({
@@ -1224,7 +1788,7 @@ const useDocumentActions = () => {
1224
1788
  throw err;
1225
1789
  }
1226
1790
  },
1227
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1791
+ [autoCloneDocument, formatMessage, toggleNotification]
1228
1792
  );
1229
1793
  const [cloneDocument] = useCloneDocumentMutation();
1230
1794
  const clone = React__namespace.useCallback(
@@ -1250,6 +1814,7 @@ const useDocumentActions = () => {
1250
1814
  defaultMessage: "Cloned document"
1251
1815
  })
1252
1816
  });
1817
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1253
1818
  return res.data;
1254
1819
  } catch (err) {
1255
1820
  toggleNotification({
@@ -1260,7 +1825,7 @@ const useDocumentActions = () => {
1260
1825
  throw err;
1261
1826
  }
1262
1827
  },
1263
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1828
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1264
1829
  );
1265
1830
  const [getDoc] = useLazyGetDocumentQuery();
1266
1831
  const getDocument = React__namespace.useCallback(
@@ -1285,10 +1850,10 @@ const useDocumentActions = () => {
1285
1850
  update
1286
1851
  };
1287
1852
  };
1288
- const ProtectedHistoryPage = React.lazy(
1289
- () => Promise.resolve().then(() => require("./History-CW2akQ6h.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 }))
1290
1855
  );
1291
- const routes$1 = [
1856
+ const routes$2 = [
1292
1857
  {
1293
1858
  path: ":collectionType/:slug/:id/history",
1294
1859
  Component: ProtectedHistoryPage
@@ -1298,32 +1863,45 @@ const routes$1 = [
1298
1863
  Component: ProtectedHistoryPage
1299
1864
  }
1300
1865
  ];
1301
- const ProtectedEditViewPage = React.lazy(
1302
- () => Promise.resolve().then(() => require("./EditViewPage-CU7724gt.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1303
- );
1304
- const ProtectedListViewPage = React.lazy(
1305
- () => Promise.resolve().then(() => require("./ListViewPage-B3bMOrMv.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
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
+ ];
1879
+ const ProtectedEditViewPage = React.lazy(
1880
+ () => Promise.resolve().then(() => require("./EditViewPage-DqelJ9UK.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1881
+ );
1882
+ const ProtectedListViewPage = React.lazy(
1883
+ () => Promise.resolve().then(() => require("./ListViewPage-BVKBeQAA.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1306
1884
  );
1307
1885
  const ProtectedListConfiguration = React.lazy(
1308
- () => Promise.resolve().then(() => require("./ListConfigurationPage-jzdhEk_u.js")).then((mod) => ({
1886
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-ByZAO_9H.js")).then((mod) => ({
1309
1887
  default: mod.ProtectedListConfiguration
1310
1888
  }))
1311
1889
  );
1312
1890
  const ProtectedEditConfigurationPage = React.lazy(
1313
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CM62NN0L.js")).then((mod) => ({
1891
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-LYEvR4fW.js")).then((mod) => ({
1314
1892
  default: mod.ProtectedEditConfigurationPage
1315
1893
  }))
1316
1894
  );
1317
1895
  const ProtectedComponentConfigurationPage = React.lazy(
1318
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-BZIaEffq.js")).then((mod) => ({
1896
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DdkVGfXC.js")).then((mod) => ({
1319
1897
  default: mod.ProtectedComponentConfigurationPage
1320
1898
  }))
1321
1899
  );
1322
1900
  const NoPermissions = React.lazy(
1323
- () => Promise.resolve().then(() => require("./NoPermissionsPage-C6qTGogm.js")).then((mod) => ({ default: mod.NoPermissions }))
1901
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-vdNpc6jb.js")).then((mod) => ({ default: mod.NoPermissions }))
1324
1902
  );
1325
1903
  const NoContentType = React.lazy(
1326
- () => Promise.resolve().then(() => require("./NoContentTypePage-D77xsNHj.js")).then((mod) => ({ default: mod.NoContentType }))
1904
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BV5zfDxr.js")).then((mod) => ({ default: mod.NoContentType }))
1327
1905
  );
1328
1906
  const CollectionTypePages = () => {
1329
1907
  const { collectionType } = reactRouterDom.useParams();
@@ -1335,7 +1913,7 @@ const CollectionTypePages = () => {
1335
1913
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1336
1914
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1337
1915
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1338
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1916
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1339
1917
  const routes = [
1340
1918
  {
1341
1919
  path: LIST_RELATIVE_PATH,
@@ -1369,6 +1947,7 @@ const routes = [
1369
1947
  path: "no-content-types",
1370
1948
  Component: NoContentType
1371
1949
  },
1950
+ ...routes$2,
1372
1951
  ...routes$1
1373
1952
  ];
1374
1953
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1437,12 +2016,14 @@ const DocumentActionButton = (action) => {
1437
2016
  /* @__PURE__ */ jsxRuntime.jsx(
1438
2017
  designSystem.Button,
1439
2018
  {
1440
- flex: 1,
2019
+ flex: "auto",
1441
2020
  startIcon: action.icon,
1442
2021
  disabled: action.disabled,
1443
2022
  onClick: handleClick(action),
1444
2023
  justifyContent: "center",
1445
2024
  variant: action.variant || "default",
2025
+ paddingTop: "7px",
2026
+ paddingBottom: "7px",
1446
2027
  children: action.label
1447
2028
  }
1448
2029
  ),
@@ -1450,7 +2031,7 @@ const DocumentActionButton = (action) => {
1450
2031
  DocumentActionConfirmDialog,
1451
2032
  {
1452
2033
  ...action.dialog,
1453
- variant: action.variant,
2034
+ variant: action.dialog?.variant ?? action.variant,
1454
2035
  isOpen: dialogId === action.id,
1455
2036
  onClose: handleClose
1456
2037
  }
@@ -1465,6 +2046,11 @@ const DocumentActionButton = (action) => {
1465
2046
  ) : null
1466
2047
  ] });
1467
2048
  };
2049
+ const MenuItem = styledComponents.styled(designSystem.Menu.Item)`
2050
+ &:hover {
2051
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
2052
+ }
2053
+ `;
1468
2054
  const DocumentActionsMenu = ({
1469
2055
  actions: actions2,
1470
2056
  children,
@@ -1507,9 +2093,9 @@ const DocumentActionsMenu = ({
1507
2093
  disabled: isDisabled,
1508
2094
  size: "S",
1509
2095
  endIcon: null,
1510
- paddingTop: "7px",
1511
- paddingLeft: "9px",
1512
- paddingRight: "9px",
2096
+ paddingTop: "4px",
2097
+ paddingLeft: "7px",
2098
+ paddingRight: "7px",
1513
2099
  variant,
1514
2100
  children: [
1515
2101
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1520,36 +2106,35 @@ const DocumentActionsMenu = ({
1520
2106
  ]
1521
2107
  }
1522
2108
  ),
1523
- /* @__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: [
1524
2110
  actions2.map((action) => {
1525
2111
  return /* @__PURE__ */ jsxRuntime.jsx(
1526
- designSystem.Menu.Item,
2112
+ MenuItem,
1527
2113
  {
1528
2114
  disabled: action.disabled,
1529
2115
  onSelect: handleClick(action),
1530
2116
  display: "block",
1531
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1532
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1533
- action.icon,
1534
- action.label
1535
- ] }),
1536
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1537
- designSystem.Flex,
1538
- {
1539
- alignItems: "center",
1540
- background: "alternative100",
1541
- borderStyle: "solid",
1542
- borderColor: "alternative200",
1543
- borderWidth: "1px",
1544
- height: 5,
1545
- paddingLeft: 2,
1546
- paddingRight: 2,
1547
- hasRadius: true,
1548
- color: "alternative600",
1549
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1550
- }
1551
- )
1552
- ] })
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
+ ) })
1553
2138
  },
1554
2139
  action.id
1555
2140
  );
@@ -1591,6 +2176,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1591
2176
  return "primary600";
1592
2177
  }
1593
2178
  };
2179
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2180
+ switch (variant) {
2181
+ case "danger":
2182
+ return "danger600";
2183
+ case "secondary":
2184
+ return "neutral500";
2185
+ case "success":
2186
+ return "success600";
2187
+ default:
2188
+ return "primary600";
2189
+ }
2190
+ };
1594
2191
  const DocumentActionConfirmDialog = ({
1595
2192
  onClose,
1596
2193
  onCancel,
@@ -1613,22 +2210,20 @@ const DocumentActionConfirmDialog = ({
1613
2210
  }
1614
2211
  onClose();
1615
2212
  };
1616
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1617
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1618
- /* @__PURE__ */ jsxRuntime.jsx(
1619
- designSystem.DialogFooter,
1620
- {
1621
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1622
- id: "app.components.Button.cancel",
1623
- defaultMessage: "Cancel"
1624
- }) }),
1625
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1626
- id: "app.components.Button.confirm",
1627
- defaultMessage: "Confirm"
1628
- }) })
1629
- }
1630
- )
1631
- ] });
2213
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2214
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2215
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2216
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2217
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2218
+ id: "app.components.Button.cancel",
2219
+ defaultMessage: "Cancel"
2220
+ }) }) }),
2221
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2222
+ id: "app.components.Button.confirm",
2223
+ defaultMessage: "Confirm"
2224
+ }) })
2225
+ ] })
2226
+ ] }) });
1632
2227
  };
1633
2228
  const DocumentActionModal = ({
1634
2229
  isOpen,
@@ -1638,34 +2233,29 @@ const DocumentActionModal = ({
1638
2233
  content: Content,
1639
2234
  onModalClose
1640
2235
  }) => {
1641
- const id = React__namespace.useId();
1642
- if (!isOpen) {
1643
- return null;
1644
- }
1645
2236
  const handleClose = () => {
1646
2237
  if (onClose) {
1647
2238
  onClose();
1648
2239
  }
1649
2240
  onModalClose();
1650
2241
  };
1651
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1654
- /* @__PURE__ */ jsxRuntime.jsx(
1655
- designSystem.Box,
1656
- {
1657
- paddingTop: 4,
1658
- paddingBottom: 4,
1659
- paddingLeft: 5,
1660
- paddingRight: 5,
1661
- borderWidth: "1px 0 0 0",
1662
- borderStyle: "solid",
1663
- borderColor: "neutral150",
1664
- background: "neutral100",
1665
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1666
- }
1667
- )
1668
- ] });
2242
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2243
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2244
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2245
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2246
+ ] }) });
2247
+ };
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;
1669
2259
  };
1670
2260
  const PublishAction$1 = ({
1671
2261
  activeTab,
@@ -1679,13 +2269,18 @@ const PublishAction$1 = ({
1679
2269
  const navigate = reactRouterDom.useNavigate();
1680
2270
  const { toggleNotification } = strapiAdmin.useNotification();
1681
2271
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2272
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1682
2273
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2274
+ const { id } = reactRouterDom.useParams();
1683
2275
  const { formatMessage } = reactIntl.useIntl();
1684
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1685
- "PublishAction",
1686
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1687
- );
2276
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1688
2277
  const { publish } = useDocumentActions();
2278
+ const [
2279
+ countDraftRelations,
2280
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2281
+ ] = useLazyGetDraftRelationCountQuery();
2282
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2283
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1689
2284
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1690
2285
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1691
2286
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1694,10 +2289,107 @@ const PublishAction$1 = ({
1694
2289
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1695
2290
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1696
2291
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2292
+ React__namespace.useEffect(() => {
2293
+ if (isErrorDraftRelations) {
2294
+ toggleNotification({
2295
+ type: "danger",
2296
+ message: formatMessage({
2297
+ id: getTranslation("error.records.fetch-draft-relatons"),
2298
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2299
+ })
2300
+ });
2301
+ }
2302
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2303
+ React__namespace.useEffect(() => {
2304
+ const localDraftRelations = /* @__PURE__ */ new Set();
2305
+ const extractDraftRelations = (data) => {
2306
+ const relations = data.connect || [];
2307
+ relations.forEach((relation) => {
2308
+ if (relation.status === "draft") {
2309
+ localDraftRelations.add(relation.id);
2310
+ }
2311
+ });
2312
+ };
2313
+ const traverseAndExtract = (data) => {
2314
+ Object.entries(data).forEach(([key, value]) => {
2315
+ if (key === "connect" && Array.isArray(value)) {
2316
+ extractDraftRelations({ connect: value });
2317
+ } else if (typeof value === "object" && value !== null) {
2318
+ traverseAndExtract(value);
2319
+ }
2320
+ });
2321
+ };
2322
+ if (!documentId || modified) {
2323
+ traverseAndExtract(formValues);
2324
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2325
+ }
2326
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2327
+ React__namespace.useEffect(() => {
2328
+ if (!document || !document.documentId || isListView) {
2329
+ return;
2330
+ }
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]);
1697
2347
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1698
2348
  if (!schema?.options?.draftAndPublish) {
1699
2349
  return null;
1700
2350
  }
2351
+ const performPublish = async () => {
2352
+ setSubmitting(true);
2353
+ try {
2354
+ const { errors } = await validate(true, {
2355
+ status: "published"
2356
+ });
2357
+ if (errors) {
2358
+ toggleNotification({
2359
+ type: "danger",
2360
+ message: formatMessage({
2361
+ id: "content-manager.validation.error",
2362
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2363
+ })
2364
+ });
2365
+ return;
2366
+ }
2367
+ const res = await publish(
2368
+ {
2369
+ collectionType,
2370
+ model,
2371
+ documentId,
2372
+ params
2373
+ },
2374
+ transformData(formValues)
2375
+ );
2376
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2377
+ if (id === "create") {
2378
+ navigate({
2379
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2380
+ search: rawQuery
2381
+ });
2382
+ }
2383
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2384
+ setErrors(formatValidationErrors(res.error));
2385
+ }
2386
+ } finally {
2387
+ setSubmitting(false);
2388
+ }
2389
+ };
2390
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2391
+ const enableDraftRelationsCount = false;
2392
+ const hasDraftRelations = enableDraftRelationsCount;
1701
2393
  return {
1702
2394
  /**
1703
2395
  * Disabled when:
@@ -1707,52 +2399,40 @@ const PublishAction$1 = ({
1707
2399
  * - the document is already published & not modified
1708
2400
  * - the document is being created & not modified
1709
2401
  * - the user doesn't have the permission to publish
1710
- * - the user doesn't have the permission to create a new document
1711
- * - the user doesn't have the permission to update the document
1712
2402
  */
1713
- disabled: isCloning || isSubmitting || 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,
1714
2404
  label: formatMessage({
1715
2405
  id: "app.utils.publish",
1716
2406
  defaultMessage: "Publish"
1717
2407
  }),
1718
2408
  onClick: async () => {
1719
- setSubmitting(true);
1720
- try {
1721
- const { errors } = await validate();
1722
- if (errors) {
1723
- toggleNotification({
1724
- type: "danger",
1725
- message: formatMessage({
1726
- id: "content-manager.validation.error",
1727
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1728
- })
1729
- });
1730
- return;
1731
- }
1732
- const res = await publish(
1733
- {
1734
- collectionType,
1735
- model,
1736
- documentId,
1737
- params
1738
- },
1739
- formValues
1740
- );
1741
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1742
- navigate({
1743
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1744
- search: rawQuery
1745
- });
1746
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1747
- setErrors(formatValidationErrors(res.error));
2409
+ await performPublish();
2410
+ },
2411
+ dialog: hasDraftRelations ? {
2412
+ type: "dialog",
2413
+ variant: "danger",
2414
+ footer: null,
2415
+ title: formatMessage({
2416
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2417
+ defaultMessage: "Confirmation"
2418
+ }),
2419
+ content: formatMessage(
2420
+ {
2421
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2422
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2423
+ },
2424
+ {
2425
+ count: totalDraftRelations
1748
2426
  }
1749
- } finally {
1750
- setSubmitting(false);
2427
+ ),
2428
+ onConfirm: async () => {
2429
+ await performPublish();
1751
2430
  }
1752
- }
2431
+ } : void 0
1753
2432
  };
1754
2433
  };
1755
2434
  PublishAction$1.type = "publish";
2435
+ PublishAction$1.position = "panel";
1756
2436
  const UpdateAction = ({
1757
2437
  activeTab,
1758
2438
  documentId,
@@ -1765,10 +2445,6 @@ const UpdateAction = ({
1765
2445
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1766
2446
  const isCloning = cloneMatch !== null;
1767
2447
  const { formatMessage } = reactIntl.useIntl();
1768
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1769
- canCreate: canCreate2,
1770
- canUpdate: canUpdate2
1771
- }));
1772
2448
  const { create, update, clone } = useDocumentActions();
1773
2449
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1774
2450
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1779,90 +2455,134 @@ const UpdateAction = ({
1779
2455
  const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1780
2456
  const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1781
2457
  const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1782
- return {
1783
- /**
1784
- * Disabled when:
1785
- * - the form is submitting
1786
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1787
- * - the active tab is the published tab
1788
- * - the user doesn't have the permission to create a new document
1789
- * - the user doesn't have the permission to update the document
1790
- */
1791
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1792
- label: formatMessage({
1793
- id: "content-manager.containers.Edit.save",
1794
- defaultMessage: "Save"
1795
- }),
1796
- onClick: async () => {
1797
- setSubmitting(true);
1798
- try {
1799
- const { errors } = await validate();
1800
- if (errors) {
1801
- toggleNotification({
1802
- type: "danger",
1803
- message: formatMessage({
1804
- id: "content-manager.validation.error",
1805
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1806
- })
1807
- });
1808
- return;
1809
- }
1810
- if (isCloning) {
1811
- const res = await clone(
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(
1812
2488
  {
1813
- model,
1814
- documentId: cloneMatch.params.origin,
1815
- params
1816
- },
1817
- document
1818
- );
1819
- if ("data" in res) {
1820
- navigate({
1821
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2489
+ pathname: `../${res.data.documentId}`,
1822
2490
  search: rawQuery
1823
- });
1824
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1825
- setErrors(formatValidationErrors(res.error));
1826
- }
1827
- } else if (documentId || collectionType === SINGLE_TYPES) {
1828
- const res = await update(
1829
- {
1830
- collectionType,
1831
- model,
1832
- documentId,
1833
- params
1834
2491
  },
1835
- document
2492
+ { relative: "path" }
1836
2493
  );
1837
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1838
- setErrors(formatValidationErrors(res.error));
1839
- } else {
1840
- resetForm();
1841
- }
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));
1842
2509
  } else {
1843
- 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(
1844
2522
  {
1845
- model,
1846
- params
2523
+ pathname: `../${res.data.documentId}`,
2524
+ search: rawQuery
1847
2525
  },
1848
- document
2526
+ { replace: true, relative: "path" }
1849
2527
  );
1850
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1851
- navigate({
1852
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1853
- search: rawQuery
1854
- });
1855
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1856
- setErrors(formatValidationErrors(res.error));
1857
- }
2528
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2529
+ setErrors(formatValidationErrors(res.error));
1858
2530
  }
1859
- } finally {
1860
- setSubmitting(false);
1861
2531
  }
2532
+ } finally {
2533
+ setSubmitting(false);
1862
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
1863
2582
  };
1864
2583
  };
1865
2584
  UpdateAction.type = "update";
2585
+ UpdateAction.position = "panel";
1866
2586
  const UNPUBLISH_DRAFT_OPTIONS = {
1867
2587
  KEEP: "keep",
1868
2588
  DISCARD: "discard"
@@ -1883,10 +2603,8 @@ const UnpublishAction$1 = ({
1883
2603
  const { toggleNotification } = strapiAdmin.useNotification();
1884
2604
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1885
2605
  const isDocumentModified = document?.status === "modified";
1886
- const handleChange = (e) => {
1887
- if ("value" in e.target) {
1888
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
- }
2606
+ const handleChange = (value) => {
2607
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1890
2608
  };
1891
2609
  if (!schema?.options?.draftAndPublish) {
1892
2610
  return null;
@@ -1897,7 +2615,7 @@ const UnpublishAction$1 = ({
1897
2615
  id: "app.utils.unpublish",
1898
2616
  defaultMessage: "Unpublish"
1899
2617
  }),
1900
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2618
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1901
2619
  onClick: async () => {
1902
2620
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1903
2621
  if (!documentId) {
@@ -1936,40 +2654,24 @@ const UnpublishAction$1 = ({
1936
2654
  }) })
1937
2655
  ] }),
1938
2656
  /* @__PURE__ */ jsxRuntime.jsxs(
1939
- designSystem.Flex,
2657
+ designSystem.Radio.Group,
1940
2658
  {
1941
- onChange: handleChange,
1942
- direction: "column",
1943
- alignItems: "flex-start",
1944
- tag: "fieldset",
1945
- borderWidth: 0,
1946
- gap: 3,
2659
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2660
+ name: "discard-options",
2661
+ "aria-label": formatMessage({
2662
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2663
+ defaultMessage: "Choose an option to unpublish the document."
2664
+ }),
2665
+ onValueChange: handleChange,
1947
2666
  children: [
1948
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1949
- /* @__PURE__ */ jsxRuntime.jsx(
1950
- designSystem.Radio,
1951
- {
1952
- checked: shouldKeepDraft,
1953
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1954
- name: "discard-options",
1955
- children: formatMessage({
1956
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1957
- defaultMessage: "Keep draft"
1958
- })
1959
- }
1960
- ),
1961
- /* @__PURE__ */ jsxRuntime.jsx(
1962
- designSystem.Radio,
1963
- {
1964
- checked: !shouldKeepDraft,
1965
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1966
- name: "discard-options",
1967
- children: formatMessage({
1968
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1969
- defaultMessage: "Replace draft"
1970
- })
1971
- }
1972
- )
2667
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2668
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2669
+ defaultMessage: "Keep draft"
2670
+ }) }),
2671
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2672
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2673
+ defaultMessage: "Replace draft"
2674
+ }) })
1973
2675
  ]
1974
2676
  }
1975
2677
  )
@@ -2003,6 +2705,7 @@ const UnpublishAction$1 = ({
2003
2705
  };
2004
2706
  };
2005
2707
  UnpublishAction$1.type = "unpublish";
2708
+ UnpublishAction$1.position = "panel";
2006
2709
  const DiscardAction = ({
2007
2710
  activeTab,
2008
2711
  documentId,
@@ -2025,7 +2728,7 @@ const DiscardAction = ({
2025
2728
  id: "content-manager.actions.discard.label",
2026
2729
  defaultMessage: "Discard changes"
2027
2730
  }),
2028
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2731
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2029
2732
  position: ["panel", "table-row"],
2030
2733
  variant: "danger",
2031
2734
  dialog: {
@@ -2053,11 +2756,7 @@ const DiscardAction = ({
2053
2756
  };
2054
2757
  };
2055
2758
  DiscardAction.type = "discard";
2056
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2057
- path {
2058
- fill: currentColor;
2059
- }
2060
- `;
2759
+ DiscardAction.position = "panel";
2061
2760
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2062
2761
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2063
2762
  const RelativeTime = React__namespace.forwardRef(
@@ -2070,7 +2769,7 @@ const RelativeTime = React__namespace.forwardRef(
2070
2769
  });
2071
2770
  const unit = intervals.find((intervalUnit) => {
2072
2771
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2073
- });
2772
+ }) ?? "seconds";
2074
2773
  const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2075
2774
  const customInterval = customIntervals.find(
2076
2775
  (custom) => interval[custom.unit] < custom.threshold
@@ -2104,34 +2803,34 @@ const getDisplayName = ({
2104
2803
  return email ?? "";
2105
2804
  };
2106
2805
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2107
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2108
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2109
- 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
+ }) }) });
2110
2813
  };
2111
2814
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2112
2815
  const { formatMessage } = reactIntl.useIntl();
2113
2816
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2817
+ const params = reactRouterDom.useParams();
2114
2818
  const title = isCreating ? formatMessage({
2115
2819
  id: "content-manager.containers.edit.title.new",
2116
2820
  defaultMessage: "Create an entry"
2117
2821
  }) : documentTitle;
2118
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2119
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2120
- /* @__PURE__ */ jsxRuntime.jsxs(
2121
- designSystem.Flex,
2822
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2823
+ /* @__PURE__ */ jsxRuntime.jsx(
2824
+ strapiAdmin.BackButton,
2122
2825
  {
2123
- width: "100%",
2124
- justifyContent: "space-between",
2125
- paddingTop: 1,
2126
- gap: "80px",
2127
- alignItems: "flex-start",
2128
- children: [
2129
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2130
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2131
- ]
2826
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2132
2827
  }
2133
2828
  ),
2134
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2829
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2830
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2831
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2832
+ ] }),
2833
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2135
2834
  ] });
2136
2835
  };
2137
2836
  const HeaderToolbar = () => {
@@ -2177,7 +2876,7 @@ const HeaderToolbar = () => {
2177
2876
  meta: isCloning ? void 0 : meta,
2178
2877
  collectionType
2179
2878
  },
2180
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2879
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2181
2880
  children: (actions2) => {
2182
2881
  const headerActions = actions2.filter((action) => {
2183
2882
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2214,12 +2913,12 @@ const Information = ({ activeTab }) => {
2214
2913
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2215
2914
  label: formatMessage({
2216
2915
  id: "content-manager.containers.edit.information.last-published.label",
2217
- defaultMessage: "Last published"
2916
+ defaultMessage: "Published"
2218
2917
  }),
2219
2918
  value: formatMessage(
2220
2919
  {
2221
2920
  id: "content-manager.containers.edit.information.last-published.value",
2222
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2921
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2223
2922
  },
2224
2923
  {
2225
2924
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2232,12 +2931,12 @@ const Information = ({ activeTab }) => {
2232
2931
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2233
2932
  label: formatMessage({
2234
2933
  id: "content-manager.containers.edit.information.last-draft.label",
2235
- defaultMessage: "Last draft"
2934
+ defaultMessage: "Updated"
2236
2935
  }),
2237
2936
  value: formatMessage(
2238
2937
  {
2239
2938
  id: "content-manager.containers.edit.information.last-draft.value",
2240
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2939
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2241
2940
  },
2242
2941
  {
2243
2942
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2255,12 +2954,12 @@ const Information = ({ activeTab }) => {
2255
2954
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2256
2955
  label: formatMessage({
2257
2956
  id: "content-manager.containers.edit.information.document.label",
2258
- defaultMessage: "Document"
2957
+ defaultMessage: "Created"
2259
2958
  }),
2260
2959
  value: formatMessage(
2261
2960
  {
2262
2961
  id: "content-manager.containers.edit.information.document.value",
2263
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2962
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2264
2963
  },
2265
2964
  {
2266
2965
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2298,33 +2997,85 @@ const Information = ({ activeTab }) => {
2298
2997
  );
2299
2998
  };
2300
2999
  const HeaderActions = ({ actions: actions2 }) => {
2301
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2302
- 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) {
2303
3016
  return /* @__PURE__ */ jsxRuntime.jsx(
2304
3017
  designSystem.SingleSelect,
2305
3018
  {
2306
3019
  size: "S",
2307
- disabled: action.disabled,
2308
- "aria-label": action.label,
2309
3020
  onChange: action.onSelect,
2310
- value: action.value,
3021
+ "aria-label": action.label,
3022
+ ...action,
2311
3023
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2312
3024
  },
2313
3025
  action.id
2314
3026
  );
2315
3027
  } else {
2316
- 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
+ }
2317
3050
  }
2318
3051
  }) });
2319
3052
  };
2320
- const ConfigureTheViewAction = ({ collectionType, model }) => {
2321
- const navigate = reactRouterDom.useNavigate();
2322
- const { formatMessage } = reactIntl.useIntl();
2323
- return {
2324
- label: formatMessage({
2325
- id: "app.links.configure-view",
2326
- defaultMessage: "Configure the view"
2327
- }),
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
+ };
3071
+ const ConfigureTheViewAction = ({ collectionType, model }) => {
3072
+ const navigate = reactRouterDom.useNavigate();
3073
+ const { formatMessage } = reactIntl.useIntl();
3074
+ return {
3075
+ label: formatMessage({
3076
+ id: "app.links.configure-view",
3077
+ defaultMessage: "Configure the view"
3078
+ }),
2328
3079
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2329
3080
  onClick: () => {
2330
3081
  navigate(`../${collectionType}/${model}/configurations/edit`);
@@ -2333,6 +3084,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2333
3084
  };
2334
3085
  };
2335
3086
  ConfigureTheViewAction.type = "configure-the-view";
3087
+ ConfigureTheViewAction.position = "header";
2336
3088
  const EditTheModelAction = ({ model }) => {
2337
3089
  const navigate = reactRouterDom.useNavigate();
2338
3090
  const { formatMessage } = reactIntl.useIntl();
@@ -2349,6 +3101,7 @@ const EditTheModelAction = ({ model }) => {
2349
3101
  };
2350
3102
  };
2351
3103
  EditTheModelAction.type = "edit-the-model";
3104
+ EditTheModelAction.position = "header";
2352
3105
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2353
3106
  const navigate = reactRouterDom.useNavigate();
2354
3107
  const { formatMessage } = reactIntl.useIntl();
@@ -2357,12 +3110,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2357
3110
  const { delete: deleteAction } = useDocumentActions();
2358
3111
  const { toggleNotification } = strapiAdmin.useNotification();
2359
3112
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
3113
+ const isLocalized = document?.locale != null;
2360
3114
  return {
2361
3115
  disabled: !canDelete || !document,
2362
- label: formatMessage({
2363
- id: "content-manager.actions.delete.label",
2364
- defaultMessage: "Delete document"
2365
- }),
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
+ ),
2366
3123
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2367
3124
  dialog: {
2368
3125
  type: "dialog",
@@ -2418,6 +3175,7 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2418
3175
  };
2419
3176
  };
2420
3177
  DeleteAction$1.type = "delete";
3178
+ DeleteAction$1.position = ["header", "table-row"];
2421
3179
  const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2422
3180
  const Panels = () => {
2423
3181
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
@@ -2452,7 +3210,7 @@ const ActionsPanel = () => {
2452
3210
  return {
2453
3211
  title: formatMessage({
2454
3212
  id: "content-manager.containers.edit.panels.default.title",
2455
- defaultMessage: "Document"
3213
+ defaultMessage: "Entry"
2456
3214
  }),
2457
3215
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2458
3216
  };
@@ -2480,7 +3238,7 @@ const ActionsPanelContent = () => {
2480
3238
  strapiAdmin.DescriptionComponentRenderer,
2481
3239
  {
2482
3240
  props,
2483
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3241
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
2484
3242
  children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2485
3243
  }
2486
3244
  ),
@@ -2507,314 +3265,12 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2507
3265
  justifyContent: "stretch",
2508
3266
  alignItems: "flex-start",
2509
3267
  children: [
2510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
3268
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
2511
3269
  children
2512
3270
  ]
2513
3271
  }
2514
3272
  );
2515
3273
  });
2516
- const HOOKS = {
2517
- /**
2518
- * Hook that allows to mutate the displayed headers of the list view table
2519
- * @constant
2520
- * @type {string}
2521
- */
2522
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2523
- /**
2524
- * Hook that allows to mutate the CM's collection types links pre-set filters
2525
- * @constant
2526
- * @type {string}
2527
- */
2528
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2529
- /**
2530
- * Hook that allows to mutate the CM's edit view layout
2531
- * @constant
2532
- * @type {string}
2533
- */
2534
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2535
- /**
2536
- * Hook that allows to mutate the CM's single types links pre-set filters
2537
- * @constant
2538
- * @type {string}
2539
- */
2540
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2541
- };
2542
- const contentTypesApi = contentManagerApi.injectEndpoints({
2543
- endpoints: (builder) => ({
2544
- getContentTypeConfiguration: builder.query({
2545
- query: (uid) => ({
2546
- url: `/content-manager/content-types/${uid}/configuration`,
2547
- method: "GET"
2548
- }),
2549
- transformResponse: (response) => response.data,
2550
- providesTags: (_result, _error, uid) => [
2551
- { type: "ContentTypesConfiguration", id: uid },
2552
- { type: "ContentTypeSettings", id: "LIST" }
2553
- ]
2554
- }),
2555
- getAllContentTypeSettings: builder.query({
2556
- query: () => "/content-manager/content-types-settings",
2557
- transformResponse: (response) => response.data,
2558
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2559
- }),
2560
- updateContentTypeConfiguration: builder.mutation({
2561
- query: ({ uid, ...body }) => ({
2562
- url: `/content-manager/content-types/${uid}/configuration`,
2563
- method: "PUT",
2564
- data: body
2565
- }),
2566
- transformResponse: (response) => response.data,
2567
- invalidatesTags: (_result, _error, { uid }) => [
2568
- { type: "ContentTypesConfiguration", id: uid },
2569
- { type: "ContentTypeSettings", id: "LIST" },
2570
- // Is this necessary?
2571
- { type: "InitialData" }
2572
- ]
2573
- })
2574
- })
2575
- });
2576
- const {
2577
- useGetContentTypeConfigurationQuery,
2578
- useGetAllContentTypeSettingsQuery,
2579
- useUpdateContentTypeConfigurationMutation
2580
- } = contentTypesApi;
2581
- const checkIfAttributeIsDisplayable = (attribute) => {
2582
- const { type } = attribute;
2583
- if (type === "relation") {
2584
- return !attribute.relation.toLowerCase().includes("morph");
2585
- }
2586
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2587
- };
2588
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2589
- if (!mainFieldName) {
2590
- return void 0;
2591
- }
2592
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2593
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2594
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2595
- );
2596
- return {
2597
- name: mainFieldName,
2598
- type: mainFieldType ?? "string"
2599
- };
2600
- };
2601
- const DEFAULT_SETTINGS = {
2602
- bulkable: false,
2603
- filterable: false,
2604
- searchable: false,
2605
- pagination: false,
2606
- defaultSortBy: "",
2607
- defaultSortOrder: "asc",
2608
- mainField: "id",
2609
- pageSize: 10
2610
- };
2611
- const useDocumentLayout = (model) => {
2612
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2613
- const [{ query }] = strapiAdmin.useQueryParams();
2614
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2615
- const { toggleNotification } = strapiAdmin.useNotification();
2616
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2617
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2618
- const {
2619
- data,
2620
- isLoading: isLoadingConfigs,
2621
- error,
2622
- isFetching: isFetchingConfigs
2623
- } = useGetContentTypeConfigurationQuery(model);
2624
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2625
- React__namespace.useEffect(() => {
2626
- if (error) {
2627
- toggleNotification({
2628
- type: "danger",
2629
- message: formatAPIError(error)
2630
- });
2631
- }
2632
- }, [error, formatAPIError, toggleNotification]);
2633
- const editLayout = React__namespace.useMemo(
2634
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2635
- layout: [],
2636
- components: {},
2637
- metadatas: {},
2638
- options: {},
2639
- settings: DEFAULT_SETTINGS
2640
- },
2641
- [data, isLoading, schemas, schema, components]
2642
- );
2643
- const listLayout = React__namespace.useMemo(() => {
2644
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2645
- layout: [],
2646
- metadatas: {},
2647
- options: {},
2648
- settings: DEFAULT_SETTINGS
2649
- };
2650
- }, [data, isLoading, schemas, schema, components]);
2651
- const { layout: edit } = React__namespace.useMemo(
2652
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2653
- layout: editLayout,
2654
- query
2655
- }),
2656
- [editLayout, query, runHookWaterfall]
2657
- );
2658
- return {
2659
- error,
2660
- isLoading,
2661
- edit,
2662
- list: listLayout
2663
- };
2664
- };
2665
- const useDocLayout = () => {
2666
- const { model } = useDoc();
2667
- return useDocumentLayout(model);
2668
- };
2669
- const formatEditLayout = (data, {
2670
- schemas,
2671
- schema,
2672
- components
2673
- }) => {
2674
- let currentPanelIndex = 0;
2675
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2676
- data.contentType.layouts.edit,
2677
- schema?.attributes,
2678
- data.contentType.metadatas,
2679
- { configurations: data.components, schemas: components },
2680
- schemas
2681
- ).reduce((panels, row) => {
2682
- if (row.some((field) => field.type === "dynamiczone")) {
2683
- panels.push([row]);
2684
- currentPanelIndex += 2;
2685
- } else {
2686
- if (!panels[currentPanelIndex]) {
2687
- panels.push([]);
2688
- }
2689
- panels[currentPanelIndex].push(row);
2690
- }
2691
- return panels;
2692
- }, []);
2693
- const componentEditAttributes = Object.entries(data.components).reduce(
2694
- (acc, [uid, configuration]) => {
2695
- acc[uid] = {
2696
- layout: convertEditLayoutToFieldLayouts(
2697
- configuration.layouts.edit,
2698
- components[uid].attributes,
2699
- configuration.metadatas
2700
- ),
2701
- settings: {
2702
- ...configuration.settings,
2703
- icon: components[uid].info.icon,
2704
- displayName: components[uid].info.displayName
2705
- }
2706
- };
2707
- return acc;
2708
- },
2709
- {}
2710
- );
2711
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2712
- (acc, [attribute, metadata]) => {
2713
- return {
2714
- ...acc,
2715
- [attribute]: metadata.edit
2716
- };
2717
- },
2718
- {}
2719
- );
2720
- return {
2721
- layout: panelledEditAttributes,
2722
- components: componentEditAttributes,
2723
- metadatas: editMetadatas,
2724
- settings: {
2725
- ...data.contentType.settings,
2726
- displayName: schema?.info.displayName
2727
- },
2728
- options: {
2729
- ...schema?.options,
2730
- ...schema?.pluginOptions,
2731
- ...data.contentType.options
2732
- }
2733
- };
2734
- };
2735
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2736
- return rows.map(
2737
- (row) => row.map((field) => {
2738
- const attribute = attributes[field.name];
2739
- if (!attribute) {
2740
- return null;
2741
- }
2742
- const { edit: metadata } = metadatas[field.name];
2743
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2744
- return {
2745
- attribute,
2746
- disabled: !metadata.editable,
2747
- hint: metadata.description,
2748
- label: metadata.label ?? "",
2749
- name: field.name,
2750
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2751
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2752
- schemas,
2753
- components: components?.schemas ?? {}
2754
- }),
2755
- placeholder: metadata.placeholder ?? "",
2756
- required: attribute.required ?? false,
2757
- size: field.size,
2758
- unique: "unique" in attribute ? attribute.unique : false,
2759
- visible: metadata.visible ?? true,
2760
- type: attribute.type
2761
- };
2762
- }).filter((field) => field !== null)
2763
- );
2764
- };
2765
- const formatListLayout = (data, {
2766
- schemas,
2767
- schema,
2768
- components
2769
- }) => {
2770
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2771
- (acc, [attribute, metadata]) => {
2772
- return {
2773
- ...acc,
2774
- [attribute]: metadata.list
2775
- };
2776
- },
2777
- {}
2778
- );
2779
- const listAttributes = convertListLayoutToFieldLayouts(
2780
- data.contentType.layouts.list,
2781
- schema?.attributes,
2782
- listMetadatas,
2783
- { configurations: data.components, schemas: components },
2784
- schemas
2785
- );
2786
- return {
2787
- layout: listAttributes,
2788
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2789
- metadatas: listMetadatas,
2790
- options: {
2791
- ...schema?.options,
2792
- ...schema?.pluginOptions,
2793
- ...data.contentType.options
2794
- }
2795
- };
2796
- };
2797
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2798
- return columns.map((name) => {
2799
- const attribute = attributes[name];
2800
- if (!attribute) {
2801
- return null;
2802
- }
2803
- const metadata = metadatas[name];
2804
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2805
- return {
2806
- attribute,
2807
- label: metadata.label ?? "",
2808
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2809
- schemas,
2810
- components: components?.schemas ?? {}
2811
- }),
2812
- name,
2813
- searchable: metadata.searchable ?? true,
2814
- sortable: metadata.sortable ?? true
2815
- };
2816
- }).filter((field) => field !== null);
2817
- };
2818
3274
  const ConfirmBulkActionDialog = ({
2819
3275
  onToggleDialog,
2820
3276
  isOpen = false,
@@ -2822,32 +3278,25 @@ const ConfirmBulkActionDialog = ({
2822
3278
  endAction
2823
3279
  }) => {
2824
3280
  const { formatMessage } = reactIntl.useIntl();
2825
- return /* @__PURE__ */ jsxRuntime.jsxs(
2826
- designSystem.Dialog,
2827
- {
2828
- onClose: onToggleDialog,
2829
- title: formatMessage({
2830
- id: "app.components.ConfirmDialog.title",
2831
- defaultMessage: "Confirmation"
2832
- }),
2833
- isOpen,
2834
- children: [
2835
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2836
- /* @__PURE__ */ jsxRuntime.jsx(
2837
- designSystem.DialogFooter,
2838
- {
2839
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2840
- id: "app.components.Button.cancel",
2841
- defaultMessage: "Cancel"
2842
- }) }),
2843
- endAction
2844
- }
2845
- )
2846
- ]
2847
- }
2848
- );
3281
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3282
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
3283
+ id: "app.components.ConfirmDialog.title",
3284
+ defaultMessage: "Confirmation"
3285
+ }) }),
3286
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3287
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3288
+ dialogBody
3289
+ ] }) }),
3290
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
3291
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
3292
+ id: "app.components.Button.cancel",
3293
+ defaultMessage: "Cancel"
3294
+ }) }) }),
3295
+ endAction
3296
+ ] })
3297
+ ] }) });
2849
3298
  };
2850
- 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 });
2851
3300
  const ConfirmDialogPublishAll = ({
2852
3301
  isOpen,
2853
3302
  onToggleDialog,
@@ -2860,6 +3309,7 @@ const ConfirmDialogPublishAll = ({
2860
3309
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2861
3310
  const { model, schema } = useDoc();
2862
3311
  const [{ query }] = strapiAdmin.useQueryParams();
3312
+ const enableDraftRelationsCount = false;
2863
3313
  const {
2864
3314
  data: countDraftRelations = 0,
2865
3315
  isLoading,
@@ -2871,7 +3321,7 @@ const ConfirmDialogPublishAll = ({
2871
3321
  locale: query?.plugins?.i18n?.locale
2872
3322
  },
2873
3323
  {
2874
- skip: selectedEntries.length === 0
3324
+ skip: !enableDraftRelationsCount
2875
3325
  }
2876
3326
  );
2877
3327
  React__namespace.useEffect(() => {
@@ -2895,7 +3345,7 @@ const ConfirmDialogPublishAll = ({
2895
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. "
2896
3346
  },
2897
3347
  {
2898
- b: BoldChunk$1,
3348
+ b: BoldChunk,
2899
3349
  count: countDraftRelations,
2900
3350
  entities: selectedEntries.length
2901
3351
  }
@@ -2934,6 +3384,16 @@ const ConfirmDialogPublishAll = ({
2934
3384
  const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
2935
3385
  max-width: 300px;
2936
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
+ `;
2937
3397
  const formatErrorMessages = (errors, parentKey, formatMessage) => {
2938
3398
  const messages = [];
2939
3399
  Object.entries(errors).forEach(([key, value]) => {
@@ -2950,7 +3410,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2950
3410
  )
2951
3411
  );
2952
3412
  } else {
2953
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3413
+ messages.push(
3414
+ ...formatErrorMessages(
3415
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3416
+ value,
3417
+ currentKey,
3418
+ formatMessage
3419
+ )
3420
+ );
2954
3421
  }
2955
3422
  } else {
2956
3423
  messages.push(
@@ -3031,7 +3498,7 @@ const SelectedEntriesTableContent = ({
3031
3498
  )
3032
3499
  ] }),
3033
3500
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3034
- /* @__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: [
3035
3502
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3036
3503
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3037
3504
  shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
@@ -3049,7 +3516,7 @@ const SelectedEntriesTableContent = ({
3049
3516
  status: row.status
3050
3517
  }
3051
3518
  ) }),
3052
- /* @__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(
3053
3520
  designSystem.IconButton,
3054
3521
  {
3055
3522
  tag: reactRouterDom.Link,
@@ -3058,27 +3525,86 @@ const SelectedEntriesTableContent = ({
3058
3525
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3059
3526
  },
3060
3527
  state: { from: pathname },
3061
- label: formatMessage(
3062
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3063
- {
3064
- target: formatMessage(
3065
- {
3066
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3067
- defaultMessage: "item line {number}"
3068
- },
3069
- { number: index2 + 1 }
3070
- )
3071
- }
3072
- ),
3528
+ label: formatMessage({
3529
+ id: "content-manager.bulk-publish.edit",
3530
+ defaultMessage: "Edit"
3531
+ }),
3073
3532
  target: "_blank",
3074
3533
  marginLeft: "auto",
3075
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3534
+ variant: "ghost",
3535
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3076
3536
  }
3077
- ) })
3537
+ ) }) })
3078
3538
  ] }, row.id)) })
3079
3539
  ] });
3080
3540
  };
3081
- 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
+ };
3082
3608
  const SelectedEntriesModalContent = ({
3083
3609
  listViewSelectedEntries,
3084
3610
  toggleModal,
@@ -3111,7 +3637,13 @@ const SelectedEntriesModalContent = ({
3111
3637
  );
3112
3638
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3113
3639
  if (data.length > 0 && schema) {
3114
- 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
+ );
3115
3647
  const validationErrors2 = {};
3116
3648
  const rows2 = data.map((entry) => {
3117
3649
  try {
@@ -3131,7 +3663,6 @@ const SelectedEntriesModalContent = ({
3131
3663
  validationErrors: {}
3132
3664
  };
3133
3665
  }, [components, data, schema]);
3134
- const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3135
3666
  const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3136
3667
  const { publishMany: bulkPublishAction } = useDocumentActions();
3137
3668
  const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
@@ -3143,53 +3674,36 @@ const SelectedEntriesModalContent = ({
3143
3674
  const selectedEntriesWithErrorsCount = selectedEntries.filter(
3144
3675
  ({ documentId }) => validationErrors[documentId]
3145
3676
  ).length;
3146
- const selectedEntriesPublished = selectedEntries.filter(
3677
+ const selectedEntriesPublishedCount = selectedEntries.filter(
3147
3678
  ({ status }) => status === "published"
3148
3679
  ).length;
3149
- 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;
3150
3684
  const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3151
3685
  const handleConfirmBulkPublish = async () => {
3152
3686
  toggleDialog();
3153
3687
  const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3154
3688
  if (!("error" in res)) {
3155
- setPublishedCount(res.count);
3156
3689
  const unpublishedEntries = rows.filter((row) => {
3157
3690
  return !entriesToPublish.includes(row.documentId);
3158
3691
  });
3159
3692
  setListViewSelectedDocuments(unpublishedEntries);
3160
3693
  }
3161
3694
  };
3162
- const getFormattedCountMessage = () => {
3163
- if (publishedCount) {
3164
- return formatMessage(
3165
- {
3166
- id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3167
- 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."
3168
- },
3695
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3696
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3697
+ /* @__PURE__ */ jsxRuntime.jsx(
3698
+ PublicationStatusGrid,
3169
3699
  {
3170
- publishedCount,
3171
- withErrorsCount: selectedEntriesWithErrorsCount,
3172
- b: BoldChunk
3700
+ entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
3701
+ entriesPublishedCount: selectedEntriesPublishedCount,
3702
+ entriesModifiedCount: selectedEntriesModifiedCount,
3703
+ entriesWithErrorsCount: selectedEntriesWithErrorsCount
3173
3704
  }
3174
- );
3175
- }
3176
- return formatMessage(
3177
- {
3178
- id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3179
- 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."
3180
- },
3181
- {
3182
- readyToPublishCount: selectedEntriesWithNoErrorsCount,
3183
- withErrorsCount: selectedEntriesWithErrorsCount,
3184
- alreadyPublishedCount: selectedEntriesPublished,
3185
- b: BoldChunk
3186
- }
3187
- );
3188
- };
3189
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3190
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalBody, { children: [
3191
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3192
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3705
+ ),
3706
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 7, children: /* @__PURE__ */ jsxRuntime.jsx(
3193
3707
  SelectedEntriesTableContent,
3194
3708
  {
3195
3709
  isPublishing: isSubmittingForm,
@@ -3199,27 +3713,24 @@ const SelectedEntriesModalContent = ({
3199
3713
  }
3200
3714
  ) })
3201
3715
  ] }),
3202
- /* @__PURE__ */ jsxRuntime.jsx(
3203
- designSystem.ModalFooter,
3204
- {
3205
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3206
- id: "app.components.Button.cancel",
3207
- defaultMessage: "Cancel"
3208
- }) }),
3209
- endActions: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3210
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3211
- /* @__PURE__ */ jsxRuntime.jsx(
3212
- designSystem.Button,
3213
- {
3214
- onClick: toggleDialog,
3215
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3216
- loading: isSubmittingForm,
3217
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3218
- }
3219
- )
3220
- ] })
3221
- }
3222
- ),
3716
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3717
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3718
+ id: "app.components.Button.cancel",
3719
+ defaultMessage: "Cancel"
3720
+ }) }),
3721
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3722
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3723
+ /* @__PURE__ */ jsxRuntime.jsx(
3724
+ designSystem.Button,
3725
+ {
3726
+ onClick: toggleDialog,
3727
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
3728
+ loading: isSubmittingForm,
3729
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3730
+ }
3731
+ )
3732
+ ] })
3733
+ ] }),
3223
3734
  /* @__PURE__ */ jsxRuntime.jsx(
3224
3735
  ConfirmDialogPublishAll,
3225
3736
  {
@@ -3239,8 +3750,7 @@ const PublishAction = ({ documents, model }) => {
3239
3750
  const refetchList = () => {
3240
3751
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3241
3752
  };
3242
- if (!showPublishButton)
3243
- return null;
3753
+ if (!showPublishButton) return null;
3244
3754
  return {
3245
3755
  actionType: "publish",
3246
3756
  variant: "tertiary",
@@ -3284,143 +3794,10 @@ const BulkActionsRenderer = () => {
3284
3794
  documents: selectedRows
3285
3795
  },
3286
3796
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3287
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
3797
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3288
3798
  }
3289
3799
  ) });
3290
3800
  };
3291
- const BulkActionAction = (action) => {
3292
- const [dialogId, setDialogId] = React__namespace.useState(null);
3293
- const { toggleNotification } = strapiAdmin.useNotification();
3294
- const handleClick = (action2) => (e) => {
3295
- const { onClick, dialog, id } = action2;
3296
- if (onClick) {
3297
- onClick(e);
3298
- }
3299
- if (dialog) {
3300
- switch (dialog.type) {
3301
- case "notification":
3302
- toggleNotification({
3303
- title: dialog.title,
3304
- message: dialog.content,
3305
- type: dialog.status,
3306
- timeout: dialog.timeout,
3307
- onClose: dialog.onClose
3308
- });
3309
- break;
3310
- case "dialog":
3311
- case "modal": {
3312
- e.preventDefault();
3313
- setDialogId(id);
3314
- }
3315
- }
3316
- }
3317
- };
3318
- const handleClose = () => {
3319
- setDialogId(null);
3320
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3321
- action.dialog.onClose();
3322
- }
3323
- };
3324
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3325
- /* @__PURE__ */ jsxRuntime.jsx(
3326
- designSystem.Button,
3327
- {
3328
- disabled: action.disabled,
3329
- startIcon: action.icon,
3330
- variant: action.variant,
3331
- onClick: handleClick(action),
3332
- children: action.label
3333
- }
3334
- ),
3335
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
3336
- BulkActionConfirmDialog,
3337
- {
3338
- ...action.dialog,
3339
- variant: action.variant,
3340
- isOpen: dialogId === action.id,
3341
- onClose: handleClose
3342
- }
3343
- ) : null,
3344
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
3345
- BulkActionModal,
3346
- {
3347
- ...action.dialog,
3348
- onModalClose: handleClose,
3349
- isOpen: dialogId === action.id
3350
- }
3351
- ) : null
3352
- ] });
3353
- };
3354
- const BulkActionConfirmDialog = ({
3355
- onClose,
3356
- onCancel,
3357
- onConfirm,
3358
- title,
3359
- content,
3360
- confirmButton,
3361
- isOpen,
3362
- variant = "secondary"
3363
- }) => {
3364
- const { formatMessage } = reactIntl.useIntl();
3365
- const handleClose = async () => {
3366
- if (onCancel) {
3367
- await onCancel();
3368
- }
3369
- onClose();
3370
- };
3371
- const handleConfirm = async () => {
3372
- if (onConfirm) {
3373
- await onConfirm();
3374
- }
3375
- onClose();
3376
- };
3377
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
3378
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
3379
- /* @__PURE__ */ jsxRuntime.jsx(
3380
- designSystem.DialogFooter,
3381
- {
3382
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3383
- id: "app.components.Button.cancel",
3384
- defaultMessage: "Cancel"
3385
- }) }),
3386
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
3387
- designSystem.Button,
3388
- {
3389
- onClick: handleConfirm,
3390
- variant: variant === "danger-light" ? variant : "secondary",
3391
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3392
- children: confirmButton ? confirmButton : formatMessage({
3393
- id: "app.components.Button.confirm",
3394
- defaultMessage: "Confirm"
3395
- })
3396
- }
3397
- )
3398
- }
3399
- )
3400
- ] });
3401
- };
3402
- const BulkActionModal = ({
3403
- isOpen,
3404
- title,
3405
- onClose,
3406
- content: Content,
3407
- onModalClose
3408
- }) => {
3409
- const id = React__namespace.useId();
3410
- if (!isOpen) {
3411
- return null;
3412
- }
3413
- const handleClose = () => {
3414
- if (onClose) {
3415
- onClose();
3416
- }
3417
- onModalClose();
3418
- };
3419
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3420
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3421
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
3422
- ] });
3423
- };
3424
3801
  const DeleteAction = ({ documents, model }) => {
3425
3802
  const { formatMessage } = reactIntl.useIntl();
3426
3803
  const { schema: contentType } = useDoc();
@@ -3441,8 +3818,7 @@ const DeleteAction = ({ documents, model }) => {
3441
3818
  selectRow([]);
3442
3819
  }
3443
3820
  };
3444
- if (!hasDeletePermission)
3445
- return null;
3821
+ if (!hasDeletePermission) return null;
3446
3822
  return {
3447
3823
  variant: "danger-light",
3448
3824
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3453,6 +3829,7 @@ const DeleteAction = ({ documents, model }) => {
3453
3829
  defaultMessage: "Confirmation"
3454
3830
  }),
3455
3831
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3832
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3456
3833
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3457
3834
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3458
3835
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3490,8 +3867,7 @@ const UnpublishAction = ({ documents, model }) => {
3490
3867
  }
3491
3868
  };
3492
3869
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3493
- if (!showUnpublishButton)
3494
- return null;
3870
+ if (!showUnpublishButton) return null;
3495
3871
  return {
3496
3872
  variant: "tertiary",
3497
3873
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3502,6 +3878,7 @@ const UnpublishAction = ({ documents, model }) => {
3502
3878
  defaultMessage: "Confirmation"
3503
3879
  }),
3504
3880
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3881
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3505
3882
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3506
3883
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3507
3884
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3595,7 +3972,7 @@ const TableActions = ({ document }) => {
3595
3972
  strapiAdmin.DescriptionComponentRenderer,
3596
3973
  {
3597
3974
  props,
3598
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3975
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3599
3976
  children: (actions2) => {
3600
3977
  const tableRowActions = actions2.filter((action) => {
3601
3978
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3654,6 +4031,7 @@ const EditAction = ({ documentId }) => {
3654
4031
  };
3655
4032
  };
3656
4033
  EditAction.type = "edit";
4034
+ EditAction.position = "table-row";
3657
4035
  const StyledPencil = styledComponents.styled(Icons.Pencil)`
3658
4036
  path {
3659
4037
  fill: currentColor;
@@ -3706,7 +4084,7 @@ const CloneAction = ({ model, documentId }) => {
3706
4084
  }),
3707
4085
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3708
4086
  footer: ({ onClose }) => {
3709
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
4087
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3710
4088
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3711
4089
  id: "cancel",
3712
4090
  defaultMessage: "Cancel"
@@ -3730,6 +4108,7 @@ const CloneAction = ({ model, documentId }) => {
3730
4108
  };
3731
4109
  };
3732
4110
  CloneAction.type = "clone";
4111
+ CloneAction.position = "table-row";
3733
4112
  const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
3734
4113
  path {
3735
4114
  fill: currentColor;
@@ -3747,8 +4126,7 @@ class ContentManagerPlugin {
3747
4126
  documentActions = [
3748
4127
  ...DEFAULT_ACTIONS,
3749
4128
  ...DEFAULT_TABLE_ROW_ACTIONS,
3750
- ...DEFAULT_HEADER_ACTIONS,
3751
- HistoryAction
4129
+ ...DEFAULT_HEADER_ACTIONS
3752
4130
  ];
3753
4131
  editViewSidePanels = [ActionsPanel];
3754
4132
  headerActions = [];
@@ -3817,7 +4195,14 @@ class ContentManagerPlugin {
3817
4195
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3818
4196
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3819
4197
  getBulkActions: () => this.bulkActions,
3820
- 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
+ },
3821
4206
  getEditViewSidePanels: () => this.editViewSidePanels,
3822
4207
  getHeaderActions: () => this.headerActions
3823
4208
  }
@@ -3827,16 +4212,71 @@ class ContentManagerPlugin {
3827
4212
  const getPrintableType = (value) => {
3828
4213
  const nativeType = typeof value;
3829
4214
  if (nativeType === "object") {
3830
- if (value === null)
3831
- return "null";
3832
- if (Array.isArray(value))
3833
- return "array";
4215
+ if (value === null) return "null";
4216
+ if (Array.isArray(value)) return "array";
3834
4217
  if (value instanceof Object && value.constructor.name !== "Object") {
3835
4218
  return value.constructor.name;
3836
4219
  }
3837
4220
  }
3838
4221
  return nativeType;
3839
4222
  };
4223
+ const HistoryAction = ({ model, document }) => {
4224
+ const { formatMessage } = reactIntl.useIntl();
4225
+ const [{ query }] = strapiAdmin.useQueryParams();
4226
+ const navigate = reactRouterDom.useNavigate();
4227
+ const { trackUsage } = strapiAdmin.useTracking();
4228
+ const { pathname } = reactRouterDom.useLocation();
4229
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
4230
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
4231
+ return null;
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
+ };
4241
+ return {
4242
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
4243
+ label: formatMessage({
4244
+ id: "content-manager.history.document-action",
4245
+ defaultMessage: "Content History"
4246
+ }),
4247
+ onClick: handleOnClick,
4248
+ disabled: (
4249
+ /**
4250
+ * The user is creating a new document.
4251
+ * It hasn't been saved yet, so there's no history to go to
4252
+ */
4253
+ !document || /**
4254
+ * The document has been created but the current dimension has never been saved.
4255
+ * For example, the user is creating a new locale in an existing document,
4256
+ * so there's no history for the document in that locale
4257
+ */
4258
+ !document.id || /**
4259
+ * History is only available for content types created by the user.
4260
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
4261
+ * which start with `admin::` or `plugin::`
4262
+ */
4263
+ !model.startsWith("api::")
4264
+ ),
4265
+ position: "header"
4266
+ };
4267
+ };
4268
+ HistoryAction.type = "history";
4269
+ HistoryAction.position = "header";
4270
+ const historyAdmin = {
4271
+ bootstrap(app) {
4272
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
4273
+ addDocumentAction((actions2) => {
4274
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
4275
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
4276
+ return actions2;
4277
+ });
4278
+ }
4279
+ };
3840
4280
  const initialState = {
3841
4281
  collectionTypeLinks: [],
3842
4282
  components: [],
@@ -3873,6 +4313,88 @@ const { setInitialData } = actions;
3873
4313
  const reducer = toolkit.combineReducers({
3874
4314
  app: reducer$1
3875
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
+ };
3876
4398
  const index = {
3877
4399
  register(app) {
3878
4400
  const cm = new ContentManagerPlugin();
@@ -3887,15 +4409,32 @@ const index = {
3887
4409
  defaultMessage: "Content Manager"
3888
4410
  },
3889
4411
  permissions: [],
3890
- Component: () => Promise.resolve().then(() => require("./layout-jcY4dyUG.js")).then((mod) => ({ default: mod.Layout })),
3891
4412
  position: 1
3892
4413
  });
4414
+ app.router.addRoute({
4415
+ path: "content-manager/*",
4416
+ lazy: async () => {
4417
+ const { Layout } = await Promise.resolve().then(() => require("./layout-DSeUTfMv.js"));
4418
+ return {
4419
+ Component: Layout
4420
+ };
4421
+ },
4422
+ children: routes
4423
+ });
3893
4424
  app.registerPlugin(cm.config);
3894
4425
  },
4426
+ bootstrap(app) {
4427
+ if (typeof historyAdmin.bootstrap === "function") {
4428
+ historyAdmin.bootstrap(app);
4429
+ }
4430
+ if (typeof previewAdmin.bootstrap === "function") {
4431
+ previewAdmin.bootstrap(app);
4432
+ }
4433
+ },
3895
4434
  async registerTrads({ locales }) {
3896
4435
  const importedTrads = await Promise.all(
3897
4436
  locales.map((locale) => {
3898
- 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-DZXjRiWA.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 }) => {
3899
4438
  return {
3900
4439
  data: prefixPluginTranslations(data, PLUGIN_ID),
3901
4440
  locale
@@ -3913,10 +4452,10 @@ const index = {
3913
4452
  };
3914
4453
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3915
4454
  exports.BulkActionsRenderer = BulkActionsRenderer;
4455
+ exports.CLONE_PATH = CLONE_PATH;
3916
4456
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3917
4457
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3918
4458
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
3919
- exports.DOCUMENT_META_FIELDS = DOCUMENT_META_FIELDS;
3920
4459
  exports.DocumentRBAC = DocumentRBAC;
3921
4460
  exports.DocumentStatus = DocumentStatus;
3922
4461
  exports.HOOKS = HOOKS;
@@ -3933,14 +4472,18 @@ exports.checkIfAttributeIsDisplayable = checkIfAttributeIsDisplayable;
3933
4472
  exports.contentManagerApi = contentManagerApi;
3934
4473
  exports.convertEditLayoutToFieldLayouts = convertEditLayoutToFieldLayouts;
3935
4474
  exports.convertListLayoutToFieldLayouts = convertListLayoutToFieldLayouts;
4475
+ exports.createDefaultForm = createDefaultForm;
3936
4476
  exports.createYupSchema = createYupSchema;
3937
4477
  exports.extractContentTypeComponents = extractContentTypeComponents;
3938
4478
  exports.getDisplayName = getDisplayName;
3939
4479
  exports.getMainField = getMainField;
3940
4480
  exports.getTranslation = getTranslation;
3941
4481
  exports.index = index;
3942
- exports.routes = routes;
4482
+ exports.prepareTempKeys = prepareTempKeys;
4483
+ exports.removeFieldsThatDontExistOnSchema = removeFieldsThatDontExistOnSchema;
3943
4484
  exports.setInitialData = setInitialData;
4485
+ exports.transformDocument = transformDocument;
4486
+ exports.useContentManagerContext = useContentManagerContext;
3944
4487
  exports.useContentTypeSchema = useContentTypeSchema;
3945
4488
  exports.useDoc = useDoc;
3946
4489
  exports.useDocLayout = useDocLayout;
@@ -3952,5 +4495,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
3952
4495
  exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3953
4496
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3954
4497
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
4498
+ exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
3955
4499
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3956
- //# sourceMappingURL=index-DcUu-_72.js.map
4500
+ //# sourceMappingURL=index-CxLSGwnk.js.map