@strapi/content-manager 0.0.0-experimental.f6c00790e260ea5a9b6b86abac5fea02b05d569c → 0.0.0-experimental.f6f58027a6338ed795382f2d1c8882158b242361

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 (210) hide show
  1. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  2. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-CnL10QYC.mjs → ComponentConfigurationPage-D4H-v0et.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-CnL10QYC.mjs.map → ComponentConfigurationPage-D4H-v0et.mjs.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-G4EIirP8.js → ComponentConfigurationPage-DdkVGfXC.js} +5 -6
  6. package/dist/_chunks/{ComponentConfigurationPage-G4EIirP8.js.map → ComponentConfigurationPage-DdkVGfXC.js.map} +1 -1
  7. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  9. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  10. package/dist/_chunks/{EditConfigurationPage-I2kKh9dx.mjs → EditConfigurationPage-D1nvB7Br.mjs} +4 -4
  11. package/dist/_chunks/{EditConfigurationPage-I2kKh9dx.mjs.map → EditConfigurationPage-D1nvB7Br.mjs.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-B2AA1kVF.js → EditConfigurationPage-LYEvR4fW.js} +5 -6
  13. package/dist/_chunks/{EditConfigurationPage-B2AA1kVF.js.map → EditConfigurationPage-LYEvR4fW.js.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-zFjJK0s8.mjs → EditViewPage-Bcnff6Vd.mjs} +32 -55
  15. package/dist/_chunks/EditViewPage-Bcnff6Vd.mjs.map +1 -0
  16. package/dist/_chunks/{EditViewPage-CHgoNwlc.js → EditViewPage-DqelJ9UK.js} +34 -58
  17. package/dist/_chunks/EditViewPage-DqelJ9UK.js.map +1 -0
  18. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  19. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  20. package/dist/_chunks/{Form-DPm-KZ1A.js → Form-CnHfBeiB.js} +6 -7
  21. package/dist/_chunks/Form-CnHfBeiB.js.map +1 -0
  22. package/dist/_chunks/{Form-CEkENbkF.mjs → Form-CzPCJi3B.mjs} +4 -4
  23. package/dist/_chunks/Form-CzPCJi3B.mjs.map +1 -0
  24. package/dist/_chunks/{History-utls71em.mjs → History-CcmSn3Mj.mjs} +71 -104
  25. package/dist/_chunks/History-CcmSn3Mj.mjs.map +1 -0
  26. package/dist/_chunks/{History-DXSbTWez.js → History-zArjENzj.js} +81 -115
  27. package/dist/_chunks/History-zArjENzj.js.map +1 -0
  28. package/dist/_chunks/{Field-9DePZh-0.js → Input-CDHKQd7o.js} +1304 -1237
  29. package/dist/_chunks/Input-CDHKQd7o.js.map +1 -0
  30. package/dist/_chunks/{Field-DPAzUS1M.mjs → Input-aV8SSoTa.mjs} +1288 -1221
  31. package/dist/_chunks/Input-aV8SSoTa.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-CuMXWWqb.mjs → ListConfigurationPage-BPvzENJJ.mjs} +7 -6
  33. package/dist/_chunks/ListConfigurationPage-BPvzENJJ.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-D5C7ACZ_.js → ListConfigurationPage-ByZAO_9H.js} +7 -7
  35. package/dist/_chunks/ListConfigurationPage-ByZAO_9H.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-DfuwH1tt.js → ListViewPage-BVKBeQAA.js} +74 -49
  37. package/dist/_chunks/ListViewPage-BVKBeQAA.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-CdKd-PS_.mjs → ListViewPage-HljQVnFH.mjs} +68 -42
  39. package/dist/_chunks/ListViewPage-HljQVnFH.mjs.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-BIxlkWWi.js → NoContentTypePage-BV5zfDxr.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-BIxlkWWi.js.map → NoContentTypePage-BV5zfDxr.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-DkToTT7u.mjs → NoContentTypePage-BfHaSM-K.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-DkToTT7u.mjs.map → NoContentTypePage-BfHaSM-K.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-DlWi4BAH.mjs → NoPermissionsPage-D6ze2nQL.mjs} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-DlWi4BAH.mjs.map → NoPermissionsPage-D6ze2nQL.mjs.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-Bu4GWYb-.js → NoPermissionsPage-vdNpc6jb.js} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-Bu4GWYb-.js.map → NoPermissionsPage-vdNpc6jb.js.map} +1 -1
  48. package/dist/_chunks/Preview-DEHdENT1.js +305 -0
  49. package/dist/_chunks/Preview-DEHdENT1.js.map +1 -0
  50. package/dist/_chunks/Preview-vfWOtPG5.mjs +287 -0
  51. package/dist/_chunks/Preview-vfWOtPG5.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-QP5yn9_z.mjs → Relations-B7_hbF0w.mjs} +78 -43
  53. package/dist/_chunks/Relations-B7_hbF0w.mjs.map +1 -0
  54. package/dist/_chunks/{Relations-CFjTESWQ.js → Relations-DcoOBejP.js} +78 -44
  55. package/dist/_chunks/Relations-DcoOBejP.js.map +1 -0
  56. package/dist/_chunks/{en-BVzUkPxZ.js → en-BR48D_RH.js} +30 -11
  57. package/dist/_chunks/{en-BVzUkPxZ.js.map → en-BR48D_RH.js.map} +1 -1
  58. package/dist/_chunks/{en-CPTj6CjC.mjs → en-D65uIF6Y.mjs} +30 -11
  59. package/dist/_chunks/{en-CPTj6CjC.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  60. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  61. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  62. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  63. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  64. package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
  65. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
  66. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
  67. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  68. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  69. package/dist/_chunks/{index-DXiHxy70.js → index-CxLSGwnk.js} +1162 -706
  70. package/dist/_chunks/index-CxLSGwnk.js.map +1 -0
  71. package/dist/_chunks/{index-BHfS6_D5.mjs → index-EH8ZtHd5.mjs} +1178 -722
  72. package/dist/_chunks/index-EH8ZtHd5.mjs.map +1 -0
  73. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  74. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  75. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  77. package/dist/_chunks/{layout-DX_52HSH.mjs → layout-CxDMdJ13.mjs} +4 -4
  78. package/dist/_chunks/{layout-DX_52HSH.mjs.map → layout-CxDMdJ13.mjs.map} +1 -1
  79. package/dist/_chunks/{layout-bE-WUnQ0.js → layout-DSeUTfMv.js} +5 -6
  80. package/dist/_chunks/{layout-bE-WUnQ0.js.map → layout-DSeUTfMv.js.map} +1 -1
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-SCVAL_aJ.mjs → relations-B8_Uu38Q.mjs} +21 -8
  86. package/dist/_chunks/relations-B8_Uu38Q.mjs.map +1 -0
  87. package/dist/_chunks/{relations-D706vblp.js → relations-S5nNKdN3.js} +20 -7
  88. package/dist/_chunks/relations-S5nNKdN3.js.map +1 -0
  89. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  90. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  91. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  92. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  93. package/dist/_chunks/{useDebounce-CtcjDB3L.js → usePrev-B9w_-eYc.js} +1 -14
  94. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  95. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  96. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  97. package/dist/admin/index.js +3 -1
  98. package/dist/admin/index.js.map +1 -1
  99. package/dist/admin/index.mjs +6 -4
  100. package/dist/admin/src/content-manager.d.ts +3 -2
  101. package/dist/admin/src/exports.d.ts +2 -1
  102. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  103. package/dist/admin/src/hooks/useDocument.d.ts +49 -1
  104. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  105. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  106. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  107. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  108. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  109. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  110. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  111. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  112. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  113. package/dist/admin/src/pages/EditView/components/Header.d.ts +1 -0
  114. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  115. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  116. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  117. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  118. package/dist/admin/src/preview/index.d.ts +4 -0
  119. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  120. package/dist/admin/src/preview/routes.d.ts +3 -0
  121. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  122. package/dist/admin/src/router.d.ts +1 -1
  123. package/dist/admin/src/services/api.d.ts +1 -1
  124. package/dist/admin/src/services/components.d.ts +2 -2
  125. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  126. package/dist/admin/src/services/documents.d.ts +16 -19
  127. package/dist/admin/src/services/init.d.ts +1 -1
  128. package/dist/admin/src/services/relations.d.ts +2 -2
  129. package/dist/admin/src/services/uid.d.ts +3 -3
  130. package/dist/server/index.js +590 -333
  131. package/dist/server/index.js.map +1 -1
  132. package/dist/server/index.mjs +591 -333
  133. package/dist/server/index.mjs.map +1 -1
  134. package/dist/server/src/bootstrap.d.ts.map +1 -1
  135. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  136. package/dist/server/src/controllers/index.d.ts.map +1 -1
  137. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  138. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  139. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  140. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  141. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  142. package/dist/server/src/history/services/history.d.ts +3 -3
  143. package/dist/server/src/history/services/history.d.ts.map +1 -1
  144. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  145. package/dist/server/src/history/services/utils.d.ts +6 -11
  146. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  147. package/dist/server/src/index.d.ts +7 -6
  148. package/dist/server/src/index.d.ts.map +1 -1
  149. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  150. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  151. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  152. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  153. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  154. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  155. package/dist/server/src/preview/index.d.ts +4 -0
  156. package/dist/server/src/preview/index.d.ts.map +1 -0
  157. package/dist/server/src/preview/routes/index.d.ts +8 -0
  158. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  159. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  160. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  161. package/dist/server/src/preview/services/index.d.ts +16 -0
  162. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  163. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  164. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  165. package/dist/server/src/preview/services/preview.d.ts +12 -0
  166. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  167. package/dist/server/src/preview/utils.d.ts +19 -0
  168. package/dist/server/src/preview/utils.d.ts.map +1 -0
  169. package/dist/server/src/register.d.ts.map +1 -1
  170. package/dist/server/src/routes/index.d.ts.map +1 -1
  171. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  172. package/dist/server/src/services/document-metadata.d.ts +12 -10
  173. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  174. package/dist/server/src/services/index.d.ts +7 -6
  175. package/dist/server/src/services/index.d.ts.map +1 -1
  176. package/dist/server/src/services/utils/populate.d.ts +2 -2
  177. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  178. package/dist/server/src/utils/index.d.ts +2 -0
  179. package/dist/server/src/utils/index.d.ts.map +1 -1
  180. package/dist/shared/contracts/index.d.ts +1 -0
  181. package/dist/shared/contracts/index.d.ts.map +1 -1
  182. package/dist/shared/contracts/preview.d.ts +27 -0
  183. package/dist/shared/contracts/preview.d.ts.map +1 -0
  184. package/dist/shared/index.js +4 -0
  185. package/dist/shared/index.js.map +1 -1
  186. package/dist/shared/index.mjs +4 -0
  187. package/dist/shared/index.mjs.map +1 -1
  188. package/package.json +16 -15
  189. package/dist/_chunks/EditViewPage-CHgoNwlc.js.map +0 -1
  190. package/dist/_chunks/EditViewPage-zFjJK0s8.mjs.map +0 -1
  191. package/dist/_chunks/Field-9DePZh-0.js.map +0 -1
  192. package/dist/_chunks/Field-DPAzUS1M.mjs.map +0 -1
  193. package/dist/_chunks/Form-CEkENbkF.mjs.map +0 -1
  194. package/dist/_chunks/Form-DPm-KZ1A.js.map +0 -1
  195. package/dist/_chunks/History-DXSbTWez.js.map +0 -1
  196. package/dist/_chunks/History-utls71em.mjs.map +0 -1
  197. package/dist/_chunks/ListConfigurationPage-CuMXWWqb.mjs.map +0 -1
  198. package/dist/_chunks/ListConfigurationPage-D5C7ACZ_.js.map +0 -1
  199. package/dist/_chunks/ListViewPage-CdKd-PS_.mjs.map +0 -1
  200. package/dist/_chunks/ListViewPage-DfuwH1tt.js.map +0 -1
  201. package/dist/_chunks/Relations-CFjTESWQ.js.map +0 -1
  202. package/dist/_chunks/Relations-QP5yn9_z.mjs.map +0 -1
  203. package/dist/_chunks/index-BHfS6_D5.mjs.map +0 -1
  204. package/dist/_chunks/index-DXiHxy70.js.map +0 -1
  205. package/dist/_chunks/relations-D706vblp.js.map +0 -1
  206. package/dist/_chunks/relations-SCVAL_aJ.mjs.map +0 -1
  207. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +0 -1
  208. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +0 -29
  209. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +0 -1
  210. package/strapi-server.js +0 -3
@@ -4,18 +4,19 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
5
  const React = require("react");
6
6
  const designSystem = require("@strapi/design-system");
7
+ const mapValues = require("lodash/fp/mapValues");
7
8
  const reactIntl = require("react-intl");
8
9
  const reactRouterDom = require("react-router-dom");
10
+ const styledComponents = require("styled-components");
9
11
  const yup = require("yup");
12
+ const fractionalIndexing = require("fractional-indexing");
10
13
  const pipe = require("lodash/fp/pipe");
11
- const dateFns = require("date-fns");
12
- const styledComponents = require("styled-components");
13
14
  const qs = require("qs");
15
+ const dateFns = require("date-fns");
14
16
  const toolkit = require("@reduxjs/toolkit");
15
17
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
18
  function _interopNamespace(e) {
17
- if (e && e.__esModule)
18
- return e;
19
+ if (e && e.__esModule) return e;
19
20
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
21
  if (e) {
21
22
  for (const k in e) {
@@ -32,15 +33,23 @@ function _interopNamespace(e) {
32
33
  return Object.freeze(n);
33
34
  }
34
35
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
36
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
37
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
38
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
39
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
38
40
  const v = glob[path];
39
41
  if (v) {
40
42
  return typeof v === "function" ? v() : Promise.resolve(v);
41
43
  }
42
44
  return new Promise((_, reject) => {
43
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
45
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
46
+ reject.bind(
47
+ null,
48
+ new Error(
49
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
50
+ )
51
+ )
52
+ );
44
53
  });
45
54
  };
46
55
  const PLUGIN_ID = "content-manager";
@@ -121,6 +130,7 @@ const DocumentRBAC = ({ children, permissions }) => {
121
130
  if (!slug) {
122
131
  throw new Error("Cannot find the slug param in the URL");
123
132
  }
133
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
124
134
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
125
135
  const contentTypePermissions = React__namespace.useMemo(() => {
126
136
  const contentTypePermissions2 = userPermissions.filter(
@@ -131,7 +141,14 @@ const DocumentRBAC = ({ children, permissions }) => {
131
141
  return { ...acc, [action]: [permission] };
132
142
  }, {});
133
143
  }, [slug, userPermissions]);
134
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
144
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
145
+ contentTypePermissions,
146
+ permissions ?? void 0,
147
+ // TODO: useRBAC context should be typed and built differently
148
+ // We are passing raw query as context to the hook so that it can
149
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
150
+ rawQuery
151
+ );
135
152
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
136
153
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
137
154
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -171,6 +188,113 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
171
188
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
172
189
  );
173
190
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
191
+ const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
192
+ const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
193
+ const traverse = (datum, attributes) => {
194
+ return Object.entries(datum).reduce((acc, [key, value]) => {
195
+ const attribute = attributes[key];
196
+ if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
197
+ acc[key] = value;
198
+ return acc;
199
+ }
200
+ if (attribute.type === "component") {
201
+ if (attribute.repeatable) {
202
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
203
+ acc[key] = componentValue.map(
204
+ (componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
205
+ );
206
+ } else {
207
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
208
+ acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
209
+ }
210
+ } else if (attribute.type === "dynamiczone") {
211
+ const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
212
+ acc[key] = dynamicZoneValue.map(
213
+ (componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
214
+ );
215
+ } else if (predicate(attribute, value)) {
216
+ acc[key] = transform(value, attribute);
217
+ } else {
218
+ acc[key] = value;
219
+ }
220
+ return acc;
221
+ }, {});
222
+ };
223
+ return traverse(data, schema.attributes);
224
+ };
225
+ const removeProhibitedFields = (prohibitedFields) => traverseData(
226
+ (attribute) => prohibitedFields.includes(attribute.type),
227
+ () => ""
228
+ );
229
+ const prepareRelations = traverseData(
230
+ (attribute) => attribute.type === "relation",
231
+ () => ({
232
+ connect: [],
233
+ disconnect: []
234
+ })
235
+ );
236
+ const prepareTempKeys = traverseData(
237
+ (attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
238
+ (data) => {
239
+ if (Array.isArray(data) && data.length > 0) {
240
+ const keys = fractionalIndexing.generateNKeysBetween(void 0, void 0, data.length);
241
+ return data.map((datum, index2) => ({
242
+ ...datum,
243
+ __temp_key__: keys[index2]
244
+ }));
245
+ }
246
+ return data;
247
+ }
248
+ );
249
+ const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
250
+ const schemaKeys = Object.keys(schema.attributes);
251
+ const dataKeys = Object.keys(data);
252
+ const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
253
+ const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
254
+ delete acc[key];
255
+ return acc;
256
+ }, structuredClone(data));
257
+ return revisedData;
258
+ };
259
+ const removeNullValues = (data) => {
260
+ return Object.entries(data).reduce((acc, [key, value]) => {
261
+ if (value === null) {
262
+ return acc;
263
+ }
264
+ acc[key] = value;
265
+ return acc;
266
+ }, {});
267
+ };
268
+ const transformDocument = (schema, components = {}) => (document) => {
269
+ const transformations = pipe__default.default(
270
+ removeFieldsThatDontExistOnSchema(schema),
271
+ removeProhibitedFields(["password"])(schema, components),
272
+ removeNullValues,
273
+ prepareRelations(schema, components),
274
+ prepareTempKeys(schema, components)
275
+ );
276
+ return transformations(document);
277
+ };
278
+ const createDefaultForm = (contentType, components = {}) => {
279
+ const traverseSchema = (attributes) => {
280
+ return Object.entries(attributes).reduce((acc, [key, attribute]) => {
281
+ if ("default" in attribute) {
282
+ acc[key] = attribute.default;
283
+ } else if (attribute.type === "component" && attribute.required) {
284
+ const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
285
+ if (attribute.repeatable) {
286
+ acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
287
+ } else {
288
+ acc[key] = defaultComponentForm;
289
+ }
290
+ } else if (attribute.type === "dynamiczone" && attribute.required) {
291
+ acc[key] = [];
292
+ }
293
+ return acc;
294
+ }, {});
295
+ };
296
+ return traverseSchema(contentType.attributes);
297
+ };
174
298
  const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
175
299
  addTagTypes: [
176
300
  "ComponentConfiguration",
@@ -180,7 +304,8 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
180
304
  "InitialData",
181
305
  "HistoryVersion",
182
306
  "Relations",
183
- "UidAvailability"
307
+ "UidAvailability",
308
+ "RecentDocumentList"
184
309
  ]
185
310
  });
186
311
  const documentApi = contentManagerApi.injectEndpoints({
@@ -198,7 +323,7 @@ const documentApi = contentManagerApi.injectEndpoints({
198
323
  if (error) {
199
324
  return [];
200
325
  }
201
- return [{ type: "Document", id: `${model}_LIST` }];
326
+ return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
202
327
  }
203
328
  }),
204
329
  cloneDocument: builder.mutation({
@@ -212,7 +337,8 @@ const documentApi = contentManagerApi.injectEndpoints({
212
337
  }),
213
338
  invalidatesTags: (_result, _error, { model }) => [
214
339
  { type: "Document", id: `${model}_LIST` },
215
- { type: "UidAvailability", id: model }
340
+ { type: "UidAvailability", id: model },
341
+ "RecentDocumentList"
216
342
  ]
217
343
  }),
218
344
  /**
@@ -231,8 +357,21 @@ const documentApi = contentManagerApi.injectEndpoints({
231
357
  invalidatesTags: (result, _error, { model }) => [
232
358
  { type: "Document", id: `${model}_LIST` },
233
359
  "Relations",
234
- { type: "UidAvailability", id: model }
235
- ]
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
+ }
236
375
  }),
237
376
  deleteDocument: builder.mutation({
238
377
  query: ({ collectionType, model, documentId, params }) => ({
@@ -243,7 +382,8 @@ const documentApi = contentManagerApi.injectEndpoints({
243
382
  }
244
383
  }),
245
384
  invalidatesTags: (_result, _error, { collectionType, model }) => [
246
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
385
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
386
+ "RecentDocumentList"
247
387
  ]
248
388
  }),
249
389
  deleteManyDocuments: builder.mutation({
@@ -255,7 +395,10 @@ const documentApi = contentManagerApi.injectEndpoints({
255
395
  params
256
396
  }
257
397
  }),
258
- invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
398
+ invalidatesTags: (_res, _error, { model }) => [
399
+ { type: "Document", id: `${model}_LIST` },
400
+ "RecentDocumentList"
401
+ ]
259
402
  }),
260
403
  discardDocument: builder.mutation({
261
404
  query: ({ collectionType, model, documentId, params }) => ({
@@ -273,7 +416,8 @@ const documentApi = contentManagerApi.injectEndpoints({
273
416
  },
274
417
  { type: "Document", id: `${model}_LIST` },
275
418
  "Relations",
276
- { type: "UidAvailability", id: model }
419
+ { type: "UidAvailability", id: model },
420
+ "RecentDocumentList"
277
421
  ];
278
422
  }
279
423
  }),
@@ -286,7 +430,7 @@ const documentApi = contentManagerApi.injectEndpoints({
286
430
  url: `/content-manager/collection-types/${model}`,
287
431
  method: "GET",
288
432
  config: {
289
- params
433
+ params: qs.stringify(params, { encode: true })
290
434
  }
291
435
  }),
292
436
  providesTags: (result, _error, arg) => {
@@ -368,7 +512,8 @@ const documentApi = contentManagerApi.injectEndpoints({
368
512
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
369
513
  },
370
514
  { type: "Document", id: `${model}_LIST` },
371
- "Relations"
515
+ "Relations",
516
+ "RecentDocumentList"
372
517
  ];
373
518
  }
374
519
  }),
@@ -399,7 +544,9 @@ const documentApi = contentManagerApi.injectEndpoints({
399
544
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
400
545
  },
401
546
  "Relations",
402
- { type: "UidAvailability", id: model }
547
+ { type: "UidAvailability", id: model },
548
+ "RecentDocumentList",
549
+ "RecentDocumentList"
403
550
  ];
404
551
  },
405
552
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -429,7 +576,8 @@ const documentApi = contentManagerApi.injectEndpoints({
429
576
  {
430
577
  type: "Document",
431
578
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
432
- }
579
+ },
580
+ "RecentDocumentList"
433
581
  ];
434
582
  }
435
583
  }),
@@ -442,7 +590,10 @@ const documentApi = contentManagerApi.injectEndpoints({
442
590
  params
443
591
  }
444
592
  }),
445
- 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
+ ]
446
597
  })
447
598
  })
448
599
  });
@@ -465,8 +616,7 @@ const {
465
616
  useUnpublishManyDocumentsMutation
466
617
  } = documentApi;
467
618
  const buildValidParams = (query) => {
468
- if (!query)
469
- return query;
619
+ if (!query) return query;
470
620
  const { plugins: _, ...validQueryParams } = {
471
621
  ...query,
472
622
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -474,14 +624,29 @@ const buildValidParams = (query) => {
474
624
  {}
475
625
  )
476
626
  };
477
- if ("_q" in validQueryParams) {
478
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
479
- }
480
627
  return validQueryParams;
481
628
  };
482
629
  const isBaseQueryError = (error) => {
483
630
  return error.name !== void 0;
484
631
  };
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
+ });
485
650
  const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
486
651
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
487
652
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -489,6 +654,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
489
654
  return acc;
490
655
  }
491
656
  const validations = [
657
+ addNullableValidation,
492
658
  addRequiredValidation,
493
659
  addMinLengthValidation,
494
660
  addMaxLengthValidation,
@@ -505,12 +671,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
505
671
  ...acc,
506
672
  [name]: transformSchema(
507
673
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
508
- )
674
+ ).test(arrayValidator(attribute, options))
509
675
  };
510
676
  } else {
511
677
  return {
512
678
  ...acc,
513
- [name]: transformSchema(createModelSchema(attributes3))
679
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
514
680
  };
515
681
  }
516
682
  }
@@ -532,7 +698,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
532
698
  }
533
699
  )
534
700
  )
535
- )
701
+ ).test(arrayValidator(attribute, options))
536
702
  };
537
703
  case "relation":
538
704
  return {
@@ -544,7 +710,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
544
710
  } else if (Array.isArray(value)) {
545
711
  return yup__namespace.array().of(
546
712
  yup__namespace.object().shape({
547
- id: yup__namespace.string().required()
713
+ id: yup__namespace.number().required()
548
714
  })
549
715
  );
550
716
  } else if (typeof value === "object") {
@@ -630,17 +796,17 @@ const nullableSchema = (schema) => {
630
796
  schema
631
797
  );
632
798
  };
799
+ const addNullableValidation = () => (schema) => {
800
+ return nullableSchema(schema);
801
+ };
633
802
  const addRequiredValidation = (attribute, options) => (schema) => {
634
- if (options.status === "draft") {
635
- return nullableSchema(schema);
636
- }
637
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
638
- return schema.min(1, strapiAdmin.translatedErrors.required);
803
+ if (options.status === "draft" || !attribute.required) {
804
+ return schema;
639
805
  }
640
- if (attribute.required && attribute.type !== "relation") {
806
+ if (attribute.required && "required" in schema) {
641
807
  return schema.required(strapiAdmin.translatedErrors.required);
642
808
  }
643
- return nullableSchema(schema);
809
+ return schema;
644
810
  };
645
811
  const addMinLengthValidation = (attribute, options) => (schema) => {
646
812
  if (options.status === "draft") {
@@ -668,31 +834,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
668
834
  return schema;
669
835
  };
670
836
  const addMinValidation = (attribute, options) => (schema) => {
671
- if ("min" in attribute) {
837
+ if (options.status === "draft") {
838
+ return schema;
839
+ }
840
+ if ("min" in attribute && "min" in schema) {
672
841
  const min = toInteger(attribute.min);
673
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
- if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
- return schema.test(
676
- "custom-min",
677
- {
678
- ...strapiAdmin.translatedErrors.min,
679
- values: {
680
- min: attribute.min
681
- }
682
- },
683
- (value) => {
684
- if (!value) {
685
- return true;
686
- }
687
- if (Array.isArray(value) && value.length === 0) {
688
- return true;
689
- }
690
- return value.length >= min;
691
- }
692
- );
693
- }
694
- }
695
- if ("min" in schema && min) {
842
+ if (min) {
696
843
  return schema.min(min, {
697
844
  ...strapiAdmin.translatedErrors.min,
698
845
  values: {
@@ -810,19 +957,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
810
957
  }, {});
811
958
  return componentsByKey;
812
959
  };
813
- 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);
814
1059
  const { toggleNotification } = strapiAdmin.useNotification();
815
1060
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1061
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
816
1062
  const {
817
- currentData: data,
818
- isLoading: isLoadingDocument,
819
- isFetching: isFetchingDocument,
820
- error
821
- } = useGetDocumentQuery(args, {
822
- ...opts,
823
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
824
- });
825
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
1063
+ data,
1064
+ isLoading: isLoadingConfigs,
1065
+ error,
1066
+ isFetching: isFetchingConfigs
1067
+ } = useGetContentTypeConfigurationQuery(model);
1068
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
826
1069
  React__namespace.useEffect(() => {
827
1070
  if (error) {
828
1071
  toggleNotification({
@@ -830,40 +1073,284 @@ const useDocument = (args, opts) => {
830
1073
  message: formatAPIError(error)
831
1074
  });
832
1075
  }
833
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
834
- const validationSchema = React__namespace.useMemo(() => {
835
- if (!schema) {
836
- return null;
837
- }
838
- return createYupSchema(schema.attributes, components);
839
- }, [schema, components]);
840
- const validate = React__namespace.useCallback(
841
- (document) => {
842
- if (!validationSchema) {
843
- throw new Error(
844
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
845
- );
846
- }
847
- try {
848
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
849
- return null;
850
- } catch (error2) {
851
- if (error2 instanceof yup.ValidationError) {
852
- return strapiAdmin.getYupValidationErrors(error2);
853
- }
854
- throw error2;
855
- }
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
856
1084
  },
857
- [validationSchema]
1085
+ [data, isLoading, schemas, schema, components]
1086
+ );
1087
+ const listLayout = React__namespace.useMemo(() => {
1088
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
1089
+ layout: [],
1090
+ metadatas: {},
1091
+ options: {},
1092
+ settings: DEFAULT_SETTINGS
1093
+ };
1094
+ }, [data, isLoading, schemas, schema, components]);
1095
+ const { layout: edit } = React__namespace.useMemo(
1096
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
1097
+ layout: editLayout,
1098
+ query
1099
+ }),
1100
+ [editLayout, query, runHookWaterfall]
858
1101
  );
859
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
860
1102
  return {
861
- components,
862
- document: data?.data,
863
- meta: data?.meta,
1103
+ error,
864
1104
  isLoading,
865
- schema,
866
- validate
1105
+ edit,
1106
+ list: listLayout
1107
+ };
1108
+ };
1109
+ const useDocLayout = () => {
1110
+ const { model } = useDoc();
1111
+ return useDocumentLayout(model);
1112
+ };
1113
+ const formatEditLayout = (data, {
1114
+ schemas,
1115
+ schema,
1116
+ components
1117
+ }) => {
1118
+ let currentPanelIndex = 0;
1119
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
1120
+ data.contentType.layouts.edit,
1121
+ schema?.attributes,
1122
+ data.contentType.metadatas,
1123
+ { configurations: data.components, schemas: components },
1124
+ schemas
1125
+ ).reduce((panels, row) => {
1126
+ if (row.some((field) => field.type === "dynamiczone")) {
1127
+ panels.push([row]);
1128
+ currentPanelIndex += 2;
1129
+ } else {
1130
+ if (!panels[currentPanelIndex]) {
1131
+ panels.push([row]);
1132
+ } else {
1133
+ panels[currentPanelIndex].push(row);
1134
+ }
1135
+ }
1136
+ return panels;
1137
+ }, []);
1138
+ const componentEditAttributes = Object.entries(data.components).reduce(
1139
+ (acc, [uid, configuration]) => {
1140
+ acc[uid] = {
1141
+ layout: convertEditLayoutToFieldLayouts(
1142
+ configuration.layouts.edit,
1143
+ components[uid].attributes,
1144
+ configuration.metadatas,
1145
+ { configurations: data.components, schemas: components }
1146
+ ),
1147
+ settings: {
1148
+ ...configuration.settings,
1149
+ icon: components[uid].info.icon,
1150
+ displayName: components[uid].info.displayName
1151
+ }
1152
+ };
1153
+ return acc;
1154
+ },
1155
+ {}
1156
+ );
1157
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1158
+ (acc, [attribute, metadata]) => {
1159
+ return {
1160
+ ...acc,
1161
+ [attribute]: metadata.edit
1162
+ };
1163
+ },
1164
+ {}
1165
+ );
1166
+ return {
1167
+ layout: panelledEditAttributes,
1168
+ components: componentEditAttributes,
1169
+ metadatas: editMetadatas,
1170
+ settings: {
1171
+ ...data.contentType.settings,
1172
+ displayName: schema?.info.displayName
1173
+ },
1174
+ options: {
1175
+ ...schema?.options,
1176
+ ...schema?.pluginOptions,
1177
+ ...data.contentType.options
1178
+ }
1179
+ };
1180
+ };
1181
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1182
+ return rows.map(
1183
+ (row) => row.map((field) => {
1184
+ const attribute = attributes[field.name];
1185
+ if (!attribute) {
1186
+ return null;
1187
+ }
1188
+ const { edit: metadata } = metadatas[field.name];
1189
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1190
+ return {
1191
+ attribute,
1192
+ disabled: !metadata.editable,
1193
+ hint: metadata.description,
1194
+ label: metadata.label ?? "",
1195
+ name: field.name,
1196
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1197
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1198
+ schemas,
1199
+ components: components?.schemas ?? {}
1200
+ }),
1201
+ placeholder: metadata.placeholder ?? "",
1202
+ required: attribute.required ?? false,
1203
+ size: field.size,
1204
+ unique: "unique" in attribute ? attribute.unique : false,
1205
+ visible: metadata.visible ?? true,
1206
+ type: attribute.type
1207
+ };
1208
+ }).filter((field) => field !== null)
1209
+ );
1210
+ };
1211
+ const formatListLayout = (data, {
1212
+ schemas,
1213
+ schema,
1214
+ components
1215
+ }) => {
1216
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1217
+ (acc, [attribute, metadata]) => {
1218
+ return {
1219
+ ...acc,
1220
+ [attribute]: metadata.list
1221
+ };
1222
+ },
1223
+ {}
1224
+ );
1225
+ const listAttributes = convertListLayoutToFieldLayouts(
1226
+ data.contentType.layouts.list,
1227
+ schema?.attributes,
1228
+ listMetadatas,
1229
+ { configurations: data.components, schemas: components },
1230
+ schemas
1231
+ );
1232
+ return {
1233
+ layout: listAttributes,
1234
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1235
+ metadatas: listMetadatas,
1236
+ options: {
1237
+ ...schema?.options,
1238
+ ...schema?.pluginOptions,
1239
+ ...data.contentType.options
1240
+ }
1241
+ };
1242
+ };
1243
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1244
+ return columns.map((name) => {
1245
+ const attribute = attributes[name];
1246
+ if (!attribute) {
1247
+ return null;
1248
+ }
1249
+ const metadata = metadatas[name];
1250
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1251
+ return {
1252
+ attribute,
1253
+ label: metadata.label ?? "",
1254
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1255
+ schemas,
1256
+ components: components?.schemas ?? {}
1257
+ }),
1258
+ name,
1259
+ searchable: metadata.searchable ?? true,
1260
+ sortable: metadata.sortable ?? true
1261
+ };
1262
+ }).filter((field) => field !== null);
1263
+ };
1264
+ const useDocument = (args, opts) => {
1265
+ const { toggleNotification } = strapiAdmin.useNotification();
1266
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1267
+ const { formatMessage } = reactIntl.useIntl();
1268
+ const {
1269
+ currentData: data,
1270
+ isLoading: isLoadingDocument,
1271
+ isFetching: isFetchingDocument,
1272
+ error
1273
+ } = useGetDocumentQuery(args, {
1274
+ ...opts,
1275
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1276
+ });
1277
+ const document = data?.data;
1278
+ const meta = data?.meta;
1279
+ const {
1280
+ components,
1281
+ schema,
1282
+ schemas,
1283
+ isLoading: isLoadingSchema
1284
+ } = useContentTypeSchema(args.model);
1285
+ const isSingleType = schema?.kind === "singleType";
1286
+ const getTitle = (mainField) => {
1287
+ if (mainField !== "id" && document?.[mainField]) {
1288
+ return document[mainField];
1289
+ }
1290
+ if (isSingleType && schema?.info.displayName) {
1291
+ return schema.info.displayName;
1292
+ }
1293
+ return formatMessage({
1294
+ id: "content-manager.containers.untitled",
1295
+ defaultMessage: "Untitled"
1296
+ });
1297
+ };
1298
+ React__namespace.useEffect(() => {
1299
+ if (error) {
1300
+ toggleNotification({
1301
+ type: "danger",
1302
+ message: formatAPIError(error)
1303
+ });
1304
+ }
1305
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1306
+ const validationSchema = React__namespace.useMemo(() => {
1307
+ if (!schema) {
1308
+ return null;
1309
+ }
1310
+ return createYupSchema(schema.attributes, components);
1311
+ }, [schema, components]);
1312
+ const validate = React__namespace.useCallback(
1313
+ (document2) => {
1314
+ if (!validationSchema) {
1315
+ throw new Error(
1316
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1317
+ );
1318
+ }
1319
+ try {
1320
+ validationSchema.validateSync(document2, { abortEarly: false, strict: true });
1321
+ return null;
1322
+ } catch (error2) {
1323
+ if (error2 instanceof yup.ValidationError) {
1324
+ return strapiAdmin.getYupValidationErrors(error2);
1325
+ }
1326
+ throw error2;
1327
+ }
1328
+ },
1329
+ [validationSchema]
1330
+ );
1331
+ const getInitialFormValues = React__namespace.useCallback(
1332
+ (isCreatingDocument = false) => {
1333
+ if (!document && !isCreatingDocument && !isSingleType || !schema) {
1334
+ return void 0;
1335
+ }
1336
+ const form = document?.id ? document : createDefaultForm(schema, components);
1337
+ return transformDocument(schema, components)(form);
1338
+ },
1339
+ [document, isSingleType, schema, components]
1340
+ );
1341
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1342
+ const hasError = !!error;
1343
+ return {
1344
+ components,
1345
+ document,
1346
+ meta,
1347
+ isLoading,
1348
+ hasError,
1349
+ schema,
1350
+ schemas,
1351
+ validate,
1352
+ getTitle,
1353
+ getInitialFormValues
867
1354
  };
868
1355
  };
869
1356
  const useDoc = () => {
@@ -876,22 +1363,60 @@ const useDoc = () => {
876
1363
  if (!slug) {
877
1364
  throw new Error("Could not find model in url params");
878
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;
879
1373
  return {
880
1374
  collectionType,
881
1375
  model: slug,
882
- id: origin || id === "create" ? void 0 : id,
883
- ...useDocument(
884
- { documentId: origin || id, model: slug, collectionType, params },
885
- {
886
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
887
- }
888
- )
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
889
1417
  };
890
1418
  };
891
1419
  const prefixPluginTranslations = (trad, pluginId) => {
892
- if (!pluginId) {
893
- throw new TypeError("pluginId can't be empty");
894
- }
895
1420
  return Object.keys(trad).reduce((acc, current) => {
896
1421
  acc[`${pluginId}.${current}`] = trad[current];
897
1422
  return acc;
@@ -908,6 +1433,7 @@ const useDocumentActions = () => {
908
1433
  const { trackUsage } = strapiAdmin.useTracking();
909
1434
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
910
1435
  const navigate = reactRouterDom.useNavigate();
1436
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
911
1437
  const [deleteDocument] = useDeleteDocumentMutation();
912
1438
  const _delete = React__namespace.useCallback(
913
1439
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1222,6 +1748,7 @@ const useDocumentActions = () => {
1222
1748
  defaultMessage: "Saved document"
1223
1749
  })
1224
1750
  });
1751
+ setCurrentStep("contentManager.success");
1225
1752
  return res.data;
1226
1753
  } catch (err) {
1227
1754
  toggleNotification({
@@ -1323,10 +1850,10 @@ const useDocumentActions = () => {
1323
1850
  update
1324
1851
  };
1325
1852
  };
1326
- const ProtectedHistoryPage = React.lazy(
1327
- () => Promise.resolve().then(() => require("./History-DXSbTWez.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 }))
1328
1855
  );
1329
- const routes$1 = [
1856
+ const routes$2 = [
1330
1857
  {
1331
1858
  path: ":collectionType/:slug/:id/history",
1332
1859
  Component: ProtectedHistoryPage
@@ -1336,32 +1863,45 @@ const routes$1 = [
1336
1863
  Component: ProtectedHistoryPage
1337
1864
  }
1338
1865
  ];
1866
+ const ProtectedPreviewPage = React__namespace.lazy(
1867
+ () => Promise.resolve().then(() => require("./Preview-DEHdENT1.js")).then((mod) => ({ default: mod.ProtectedPreviewPage }))
1868
+ );
1869
+ const routes$1 = [
1870
+ {
1871
+ path: ":collectionType/:slug/:id/preview",
1872
+ Component: ProtectedPreviewPage
1873
+ },
1874
+ {
1875
+ path: ":collectionType/:slug/preview",
1876
+ Component: ProtectedPreviewPage
1877
+ }
1878
+ ];
1339
1879
  const ProtectedEditViewPage = React.lazy(
1340
- () => Promise.resolve().then(() => require("./EditViewPage-CHgoNwlc.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1880
+ () => Promise.resolve().then(() => require("./EditViewPage-DqelJ9UK.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1341
1881
  );
1342
1882
  const ProtectedListViewPage = React.lazy(
1343
- () => Promise.resolve().then(() => require("./ListViewPage-DfuwH1tt.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1883
+ () => Promise.resolve().then(() => require("./ListViewPage-BVKBeQAA.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1344
1884
  );
1345
1885
  const ProtectedListConfiguration = React.lazy(
1346
- () => Promise.resolve().then(() => require("./ListConfigurationPage-D5C7ACZ_.js")).then((mod) => ({
1886
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-ByZAO_9H.js")).then((mod) => ({
1347
1887
  default: mod.ProtectedListConfiguration
1348
1888
  }))
1349
1889
  );
1350
1890
  const ProtectedEditConfigurationPage = React.lazy(
1351
- () => Promise.resolve().then(() => require("./EditConfigurationPage-B2AA1kVF.js")).then((mod) => ({
1891
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-LYEvR4fW.js")).then((mod) => ({
1352
1892
  default: mod.ProtectedEditConfigurationPage
1353
1893
  }))
1354
1894
  );
1355
1895
  const ProtectedComponentConfigurationPage = React.lazy(
1356
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-G4EIirP8.js")).then((mod) => ({
1896
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DdkVGfXC.js")).then((mod) => ({
1357
1897
  default: mod.ProtectedComponentConfigurationPage
1358
1898
  }))
1359
1899
  );
1360
1900
  const NoPermissions = React.lazy(
1361
- () => Promise.resolve().then(() => require("./NoPermissionsPage-Bu4GWYb-.js")).then((mod) => ({ default: mod.NoPermissions }))
1901
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-vdNpc6jb.js")).then((mod) => ({ default: mod.NoPermissions }))
1362
1902
  );
1363
1903
  const NoContentType = React.lazy(
1364
- () => Promise.resolve().then(() => require("./NoContentTypePage-BIxlkWWi.js")).then((mod) => ({ default: mod.NoContentType }))
1904
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BV5zfDxr.js")).then((mod) => ({ default: mod.NoContentType }))
1365
1905
  );
1366
1906
  const CollectionTypePages = () => {
1367
1907
  const { collectionType } = reactRouterDom.useParams();
@@ -1373,7 +1913,7 @@ const CollectionTypePages = () => {
1373
1913
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1374
1914
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1375
1915
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1376
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1916
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1377
1917
  const routes = [
1378
1918
  {
1379
1919
  path: LIST_RELATIVE_PATH,
@@ -1407,6 +1947,7 @@ const routes = [
1407
1947
  path: "no-content-types",
1408
1948
  Component: NoContentType
1409
1949
  },
1950
+ ...routes$2,
1410
1951
  ...routes$1
1411
1952
  ];
1412
1953
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1505,6 +2046,11 @@ const DocumentActionButton = (action) => {
1505
2046
  ) : null
1506
2047
  ] });
1507
2048
  };
2049
+ const MenuItem = styledComponents.styled(designSystem.Menu.Item)`
2050
+ &:hover {
2051
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
2052
+ }
2053
+ `;
1508
2054
  const DocumentActionsMenu = ({
1509
2055
  actions: actions2,
1510
2056
  children,
@@ -1563,48 +2109,32 @@ const DocumentActionsMenu = ({
1563
2109
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1564
2110
  actions2.map((action) => {
1565
2111
  return /* @__PURE__ */ jsxRuntime.jsx(
1566
- designSystem.Menu.Item,
2112
+ MenuItem,
1567
2113
  {
1568
2114
  disabled: action.disabled,
1569
2115
  onSelect: handleClick(action),
1570
2116
  display: "block",
1571
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1572
- /* @__PURE__ */ jsxRuntime.jsxs(
1573
- designSystem.Flex,
1574
- {
1575
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1576
- gap: 2,
1577
- tag: "span",
1578
- children: [
1579
- /* @__PURE__ */ jsxRuntime.jsx(
1580
- designSystem.Flex,
1581
- {
1582
- tag: "span",
1583
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1584
- children: action.icon
1585
- }
1586
- ),
1587
- action.label
1588
- ]
1589
- }
1590
- ),
1591
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1592
- designSystem.Flex,
1593
- {
1594
- alignItems: "center",
1595
- background: "alternative100",
1596
- borderStyle: "solid",
1597
- borderColor: "alternative200",
1598
- borderWidth: "1px",
1599
- height: 5,
1600
- paddingLeft: 2,
1601
- paddingRight: 2,
1602
- hasRadius: true,
1603
- color: "alternative600",
1604
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1605
- }
1606
- )
1607
- ] })
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
+ ) })
1608
2138
  },
1609
2139
  action.id
1610
2140
  );
@@ -1715,6 +2245,18 @@ const DocumentActionModal = ({
1715
2245
  typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1716
2246
  ] }) });
1717
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;
2259
+ };
1718
2260
  const PublishAction$1 = ({
1719
2261
  activeTab,
1720
2262
  documentId,
@@ -1729,6 +2271,7 @@ const PublishAction$1 = ({
1729
2271
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1730
2272
  const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1731
2273
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2274
+ const { id } = reactRouterDom.useParams();
1732
2275
  const { formatMessage } = reactIntl.useIntl();
1733
2276
  const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1734
2277
  const { publish } = useDocumentActions();
@@ -1808,7 +2351,9 @@ const PublishAction$1 = ({
1808
2351
  const performPublish = async () => {
1809
2352
  setSubmitting(true);
1810
2353
  try {
1811
- const { errors } = await validate();
2354
+ const { errors } = await validate(true, {
2355
+ status: "published"
2356
+ });
1812
2357
  if (errors) {
1813
2358
  toggleNotification({
1814
2359
  type: "danger",
@@ -1826,13 +2371,15 @@ const PublishAction$1 = ({
1826
2371
  documentId,
1827
2372
  params
1828
2373
  },
1829
- formValues
2374
+ transformData(formValues)
1830
2375
  );
1831
2376
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1832
- navigate({
1833
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1834
- search: rawQuery
1835
- });
2377
+ if (id === "create") {
2378
+ navigate({
2379
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2380
+ search: rawQuery
2381
+ });
2382
+ }
1836
2383
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
2384
  setErrors(formatValidationErrors(res.error));
1838
2385
  }
@@ -1885,6 +2432,7 @@ const PublishAction$1 = ({
1885
2432
  };
1886
2433
  };
1887
2434
  PublishAction$1.type = "publish";
2435
+ PublishAction$1.position = "panel";
1888
2436
  const UpdateAction = ({
1889
2437
  activeTab,
1890
2438
  documentId,
@@ -1907,6 +2455,117 @@ const UpdateAction = ({
1907
2455
  const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1908
2456
  const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1909
2457
  const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
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(
2488
+ {
2489
+ pathname: `../${res.data.documentId}`,
2490
+ search: rawQuery
2491
+ },
2492
+ { relative: "path" }
2493
+ );
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));
2509
+ } else {
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(
2522
+ {
2523
+ pathname: `../${res.data.documentId}`,
2524
+ search: rawQuery
2525
+ },
2526
+ { replace: true, relative: "path" }
2527
+ );
2528
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2529
+ setErrors(formatValidationErrors(res.error));
2530
+ }
2531
+ }
2532
+ } finally {
2533
+ setSubmitting(false);
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]);
1910
2569
  return {
1911
2570
  /**
1912
2571
  * Disabled when:
@@ -1916,87 +2575,14 @@ const UpdateAction = ({
1916
2575
  */
1917
2576
  disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1918
2577
  label: formatMessage({
1919
- id: "content-manager.containers.Edit.save",
2578
+ id: "global.save",
1920
2579
  defaultMessage: "Save"
1921
2580
  }),
1922
- onClick: async () => {
1923
- setSubmitting(true);
1924
- try {
1925
- if (activeTab !== "draft") {
1926
- const { errors } = await validate();
1927
- if (errors) {
1928
- toggleNotification({
1929
- type: "danger",
1930
- message: formatMessage({
1931
- id: "content-manager.validation.error",
1932
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1933
- })
1934
- });
1935
- return;
1936
- }
1937
- }
1938
- if (isCloning) {
1939
- const res = await clone(
1940
- {
1941
- model,
1942
- documentId: cloneMatch.params.origin,
1943
- params
1944
- },
1945
- document
1946
- );
1947
- if ("data" in res) {
1948
- navigate(
1949
- {
1950
- pathname: `../${res.data.documentId}`,
1951
- search: rawQuery
1952
- },
1953
- { relative: "path" }
1954
- );
1955
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1956
- setErrors(formatValidationErrors(res.error));
1957
- }
1958
- } else if (documentId || collectionType === SINGLE_TYPES) {
1959
- const res = await update(
1960
- {
1961
- collectionType,
1962
- model,
1963
- documentId,
1964
- params
1965
- },
1966
- document
1967
- );
1968
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1969
- setErrors(formatValidationErrors(res.error));
1970
- } else {
1971
- resetForm();
1972
- }
1973
- } else {
1974
- const res = await create(
1975
- {
1976
- model,
1977
- params
1978
- },
1979
- document
1980
- );
1981
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1982
- navigate(
1983
- {
1984
- pathname: `../${res.data.documentId}`,
1985
- search: rawQuery
1986
- },
1987
- { replace: true, relative: "path" }
1988
- );
1989
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1990
- setErrors(formatValidationErrors(res.error));
1991
- }
1992
- }
1993
- } finally {
1994
- setSubmitting(false);
1995
- }
1996
- }
2581
+ onClick: handleUpdate
1997
2582
  };
1998
2583
  };
1999
2584
  UpdateAction.type = "update";
2585
+ UpdateAction.position = "panel";
2000
2586
  const UNPUBLISH_DRAFT_OPTIONS = {
2001
2587
  KEEP: "keep",
2002
2588
  DISCARD: "discard"
@@ -2119,6 +2705,7 @@ const UnpublishAction$1 = ({
2119
2705
  };
2120
2706
  };
2121
2707
  UnpublishAction$1.type = "unpublish";
2708
+ UnpublishAction$1.position = "panel";
2122
2709
  const DiscardAction = ({
2123
2710
  activeTab,
2124
2711
  documentId,
@@ -2169,6 +2756,7 @@ const DiscardAction = ({
2169
2756
  };
2170
2757
  };
2171
2758
  DiscardAction.type = "discard";
2759
+ DiscardAction.position = "panel";
2172
2760
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2173
2761
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2174
2762
  const RelativeTime = React__namespace.forwardRef(
@@ -2181,7 +2769,7 @@ const RelativeTime = React__namespace.forwardRef(
2181
2769
  });
2182
2770
  const unit = intervals.find((intervalUnit) => {
2183
2771
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2184
- });
2772
+ }) ?? "seconds";
2185
2773
  const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2186
2774
  const customInterval = customIntervals.find(
2187
2775
  (custom) => interval[custom.unit] < custom.threshold
@@ -2215,19 +2803,29 @@ const getDisplayName = ({
2215
2803
  return email ?? "";
2216
2804
  };
2217
2805
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2218
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2806
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2219
2807
  const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2220
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
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
+ }) }) });
2221
2813
  };
2222
2814
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2223
2815
  const { formatMessage } = reactIntl.useIntl();
2224
2816
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2817
+ const params = reactRouterDom.useParams();
2225
2818
  const title = isCreating ? formatMessage({
2226
2819
  id: "content-manager.containers.edit.title.new",
2227
2820
  defaultMessage: "Create an entry"
2228
2821
  }) : documentTitle;
2229
2822
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2230
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2823
+ /* @__PURE__ */ jsxRuntime.jsx(
2824
+ strapiAdmin.BackButton,
2825
+ {
2826
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2827
+ }
2828
+ ),
2231
2829
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2232
2830
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2233
2831
  /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
@@ -2278,7 +2876,7 @@ const HeaderToolbar = () => {
2278
2876
  meta: isCloning ? void 0 : meta,
2279
2877
  collectionType
2280
2878
  },
2281
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2879
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2282
2880
  children: (actions2) => {
2283
2881
  const headerActions = actions2.filter((action) => {
2284
2882
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2315,12 +2913,12 @@ const Information = ({ activeTab }) => {
2315
2913
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2316
2914
  label: formatMessage({
2317
2915
  id: "content-manager.containers.edit.information.last-published.label",
2318
- defaultMessage: "Last published"
2916
+ defaultMessage: "Published"
2319
2917
  }),
2320
2918
  value: formatMessage(
2321
2919
  {
2322
2920
  id: "content-manager.containers.edit.information.last-published.value",
2323
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2921
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2324
2922
  },
2325
2923
  {
2326
2924
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2333,12 +2931,12 @@ const Information = ({ activeTab }) => {
2333
2931
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2334
2932
  label: formatMessage({
2335
2933
  id: "content-manager.containers.edit.information.last-draft.label",
2336
- defaultMessage: "Last draft"
2934
+ defaultMessage: "Updated"
2337
2935
  }),
2338
2936
  value: formatMessage(
2339
2937
  {
2340
2938
  id: "content-manager.containers.edit.information.last-draft.value",
2341
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2939
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2342
2940
  },
2343
2941
  {
2344
2942
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2356,12 +2954,12 @@ const Information = ({ activeTab }) => {
2356
2954
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2357
2955
  label: formatMessage({
2358
2956
  id: "content-manager.containers.edit.information.document.label",
2359
- defaultMessage: "Document"
2957
+ defaultMessage: "Created"
2360
2958
  }),
2361
2959
  value: formatMessage(
2362
2960
  {
2363
2961
  id: "content-manager.containers.edit.information.document.value",
2364
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2962
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2365
2963
  },
2366
2964
  {
2367
2965
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2419,10 +3017,9 @@ const HeaderActions = ({ actions: actions2 }) => {
2419
3017
  designSystem.SingleSelect,
2420
3018
  {
2421
3019
  size: "S",
2422
- disabled: action.disabled,
2423
- "aria-label": action.label,
2424
3020
  onChange: action.onSelect,
2425
- value: action.value,
3021
+ "aria-label": action.label,
3022
+ ...action,
2426
3023
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2427
3024
  },
2428
3025
  action.id
@@ -2487,6 +3084,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2487
3084
  };
2488
3085
  };
2489
3086
  ConfigureTheViewAction.type = "configure-the-view";
3087
+ ConfigureTheViewAction.position = "header";
2490
3088
  const EditTheModelAction = ({ model }) => {
2491
3089
  const navigate = reactRouterDom.useNavigate();
2492
3090
  const { formatMessage } = reactIntl.useIntl();
@@ -2503,6 +3101,7 @@ const EditTheModelAction = ({ model }) => {
2503
3101
  };
2504
3102
  };
2505
3103
  EditTheModelAction.type = "edit-the-model";
3104
+ EditTheModelAction.position = "header";
2506
3105
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2507
3106
  const navigate = reactRouterDom.useNavigate();
2508
3107
  const { formatMessage } = reactIntl.useIntl();
@@ -2511,12 +3110,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2511
3110
  const { delete: deleteAction } = useDocumentActions();
2512
3111
  const { toggleNotification } = strapiAdmin.useNotification();
2513
3112
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
3113
+ const isLocalized = document?.locale != null;
2514
3114
  return {
2515
3115
  disabled: !canDelete || !document,
2516
- label: formatMessage({
2517
- id: "content-manager.actions.delete.label",
2518
- defaultMessage: "Delete document"
2519
- }),
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
+ ),
2520
3123
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2521
3124
  dialog: {
2522
3125
  type: "dialog",
@@ -2572,6 +3175,7 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2572
3175
  };
2573
3176
  };
2574
3177
  DeleteAction$1.type = "delete";
3178
+ DeleteAction$1.position = ["header", "table-row"];
2575
3179
  const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2576
3180
  const Panels = () => {
2577
3181
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
@@ -2583,393 +3187,90 @@ const Panels = () => {
2583
3187
  status: "draft"
2584
3188
  });
2585
3189
  const { model, id, document, meta, collectionType } = useDoc();
2586
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2587
- const props = {
2588
- activeTab: status,
2589
- model,
2590
- documentId: id,
2591
- document: isCloning ? void 0 : document,
2592
- meta: isCloning ? void 0 : meta,
2593
- collectionType
2594
- };
2595
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2596
- strapiAdmin.DescriptionComponentRenderer,
2597
- {
2598
- props,
2599
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2600
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2601
- }
2602
- ) });
2603
- };
2604
- const ActionsPanel = () => {
2605
- const { formatMessage } = reactIntl.useIntl();
2606
- return {
2607
- title: formatMessage({
2608
- id: "content-manager.containers.edit.panels.default.title",
2609
- defaultMessage: "Entry"
2610
- }),
2611
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2612
- };
2613
- };
2614
- ActionsPanel.type = "actions";
2615
- const ActionsPanelContent = () => {
2616
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2617
- const [
2618
- {
2619
- query: { status = "draft" }
2620
- }
2621
- ] = strapiAdmin.useQueryParams();
2622
- const { model, id, document, meta, collectionType } = useDoc();
2623
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2624
- const props = {
2625
- activeTab: status,
2626
- model,
2627
- documentId: id,
2628
- document: isCloning ? void 0 : document,
2629
- meta: isCloning ? void 0 : meta,
2630
- collectionType
2631
- };
2632
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2633
- /* @__PURE__ */ jsxRuntime.jsx(
2634
- strapiAdmin.DescriptionComponentRenderer,
2635
- {
2636
- props,
2637
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2638
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2639
- }
2640
- ),
2641
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2642
- ] });
2643
- };
2644
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2645
- return /* @__PURE__ */ jsxRuntime.jsxs(
2646
- designSystem.Flex,
2647
- {
2648
- ref,
2649
- tag: "aside",
2650
- "aria-labelledby": "additional-information",
2651
- background: "neutral0",
2652
- borderColor: "neutral150",
2653
- hasRadius: true,
2654
- paddingBottom: 4,
2655
- paddingLeft: 4,
2656
- paddingRight: 4,
2657
- paddingTop: 4,
2658
- shadow: "tableShadow",
2659
- gap: 3,
2660
- direction: "column",
2661
- justifyContent: "stretch",
2662
- alignItems: "flex-start",
2663
- children: [
2664
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2665
- children
2666
- ]
2667
- }
2668
- );
2669
- });
2670
- const HOOKS = {
2671
- /**
2672
- * Hook that allows to mutate the displayed headers of the list view table
2673
- * @constant
2674
- * @type {string}
2675
- */
2676
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2677
- /**
2678
- * Hook that allows to mutate the CM's collection types links pre-set filters
2679
- * @constant
2680
- * @type {string}
2681
- */
2682
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2683
- /**
2684
- * Hook that allows to mutate the CM's edit view layout
2685
- * @constant
2686
- * @type {string}
2687
- */
2688
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2689
- /**
2690
- * Hook that allows to mutate the CM's single types links pre-set filters
2691
- * @constant
2692
- * @type {string}
2693
- */
2694
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2695
- };
2696
- const contentTypesApi = contentManagerApi.injectEndpoints({
2697
- endpoints: (builder) => ({
2698
- getContentTypeConfiguration: builder.query({
2699
- query: (uid) => ({
2700
- url: `/content-manager/content-types/${uid}/configuration`,
2701
- method: "GET"
2702
- }),
2703
- transformResponse: (response) => response.data,
2704
- providesTags: (_result, _error, uid) => [
2705
- { type: "ContentTypesConfiguration", id: uid },
2706
- { type: "ContentTypeSettings", id: "LIST" }
2707
- ]
2708
- }),
2709
- getAllContentTypeSettings: builder.query({
2710
- query: () => "/content-manager/content-types-settings",
2711
- transformResponse: (response) => response.data,
2712
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2713
- }),
2714
- updateContentTypeConfiguration: builder.mutation({
2715
- query: ({ uid, ...body }) => ({
2716
- url: `/content-manager/content-types/${uid}/configuration`,
2717
- method: "PUT",
2718
- data: body
2719
- }),
2720
- transformResponse: (response) => response.data,
2721
- invalidatesTags: (_result, _error, { uid }) => [
2722
- { type: "ContentTypesConfiguration", id: uid },
2723
- { type: "ContentTypeSettings", id: "LIST" },
2724
- // Is this necessary?
2725
- { type: "InitialData" }
2726
- ]
2727
- })
2728
- })
2729
- });
2730
- const {
2731
- useGetContentTypeConfigurationQuery,
2732
- useGetAllContentTypeSettingsQuery,
2733
- useUpdateContentTypeConfigurationMutation
2734
- } = contentTypesApi;
2735
- const checkIfAttributeIsDisplayable = (attribute) => {
2736
- const { type } = attribute;
2737
- if (type === "relation") {
2738
- return !attribute.relation.toLowerCase().includes("morph");
2739
- }
2740
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2741
- };
2742
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2743
- if (!mainFieldName) {
2744
- return void 0;
2745
- }
2746
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2747
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2748
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2749
- );
2750
- return {
2751
- name: mainFieldName,
2752
- type: mainFieldType ?? "string"
2753
- };
2754
- };
2755
- const DEFAULT_SETTINGS = {
2756
- bulkable: false,
2757
- filterable: false,
2758
- searchable: false,
2759
- pagination: false,
2760
- defaultSortBy: "",
2761
- defaultSortOrder: "asc",
2762
- mainField: "id",
2763
- pageSize: 10
2764
- };
2765
- const useDocumentLayout = (model) => {
2766
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2767
- const [{ query }] = strapiAdmin.useQueryParams();
2768
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2769
- const { toggleNotification } = strapiAdmin.useNotification();
2770
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2771
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2772
- const {
2773
- data,
2774
- isLoading: isLoadingConfigs,
2775
- error,
2776
- isFetching: isFetchingConfigs
2777
- } = useGetContentTypeConfigurationQuery(model);
2778
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2779
- React__namespace.useEffect(() => {
2780
- if (error) {
2781
- toggleNotification({
2782
- type: "danger",
2783
- message: formatAPIError(error)
2784
- });
2785
- }
2786
- }, [error, formatAPIError, toggleNotification]);
2787
- const editLayout = React__namespace.useMemo(
2788
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2789
- layout: [],
2790
- components: {},
2791
- metadatas: {},
2792
- options: {},
2793
- settings: DEFAULT_SETTINGS
2794
- },
2795
- [data, isLoading, schemas, schema, components]
2796
- );
2797
- const listLayout = React__namespace.useMemo(() => {
2798
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2799
- layout: [],
2800
- metadatas: {},
2801
- options: {},
2802
- settings: DEFAULT_SETTINGS
2803
- };
2804
- }, [data, isLoading, schemas, schema, components]);
2805
- const { layout: edit } = React__namespace.useMemo(
2806
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2807
- layout: editLayout,
2808
- query
2809
- }),
2810
- [editLayout, query, runHookWaterfall]
2811
- );
2812
- return {
2813
- error,
2814
- isLoading,
2815
- edit,
2816
- list: listLayout
2817
- };
2818
- };
2819
- const useDocLayout = () => {
2820
- const { model } = useDoc();
2821
- return useDocumentLayout(model);
2822
- };
2823
- const formatEditLayout = (data, {
2824
- schemas,
2825
- schema,
2826
- components
2827
- }) => {
2828
- let currentPanelIndex = 0;
2829
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2830
- data.contentType.layouts.edit,
2831
- schema?.attributes,
2832
- data.contentType.metadatas,
2833
- { configurations: data.components, schemas: components },
2834
- schemas
2835
- ).reduce((panels, row) => {
2836
- if (row.some((field) => field.type === "dynamiczone")) {
2837
- panels.push([row]);
2838
- currentPanelIndex += 2;
2839
- } else {
2840
- if (!panels[currentPanelIndex]) {
2841
- panels.push([]);
2842
- }
2843
- panels[currentPanelIndex].push(row);
2844
- }
2845
- return panels;
2846
- }, []);
2847
- const componentEditAttributes = Object.entries(data.components).reduce(
2848
- (acc, [uid, configuration]) => {
2849
- acc[uid] = {
2850
- layout: convertEditLayoutToFieldLayouts(
2851
- configuration.layouts.edit,
2852
- components[uid].attributes,
2853
- configuration.metadatas,
2854
- { configurations: data.components, schemas: components }
2855
- ),
2856
- settings: {
2857
- ...configuration.settings,
2858
- icon: components[uid].info.icon,
2859
- displayName: components[uid].info.displayName
2860
- }
2861
- };
2862
- return acc;
2863
- },
2864
- {}
2865
- );
2866
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2867
- (acc, [attribute, metadata]) => {
2868
- return {
2869
- ...acc,
2870
- [attribute]: metadata.edit
2871
- };
2872
- },
2873
- {}
2874
- );
2875
- return {
2876
- layout: panelledEditAttributes,
2877
- components: componentEditAttributes,
2878
- metadatas: editMetadatas,
2879
- settings: {
2880
- ...data.contentType.settings,
2881
- displayName: schema?.info.displayName
2882
- },
2883
- options: {
2884
- ...schema?.options,
2885
- ...schema?.pluginOptions,
2886
- ...data.contentType.options
2887
- }
3190
+ const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
3191
+ const props = {
3192
+ activeTab: status,
3193
+ model,
3194
+ documentId: id,
3195
+ document: isCloning ? void 0 : document,
3196
+ meta: isCloning ? void 0 : meta,
3197
+ collectionType
2888
3198
  };
3199
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3200
+ strapiAdmin.DescriptionComponentRenderer,
3201
+ {
3202
+ props,
3203
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
3204
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
3205
+ }
3206
+ ) });
2889
3207
  };
2890
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2891
- return rows.map(
2892
- (row) => row.map((field) => {
2893
- const attribute = attributes[field.name];
2894
- if (!attribute) {
2895
- return null;
2896
- }
2897
- const { edit: metadata } = metadatas[field.name];
2898
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2899
- return {
2900
- attribute,
2901
- disabled: !metadata.editable,
2902
- hint: metadata.description,
2903
- label: metadata.label ?? "",
2904
- name: field.name,
2905
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2906
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2907
- schemas,
2908
- components: components?.schemas ?? {}
2909
- }),
2910
- placeholder: metadata.placeholder ?? "",
2911
- required: attribute.required ?? false,
2912
- size: field.size,
2913
- unique: "unique" in attribute ? attribute.unique : false,
2914
- visible: metadata.visible ?? true,
2915
- type: attribute.type
2916
- };
2917
- }).filter((field) => field !== null)
2918
- );
2919
- };
2920
- const formatListLayout = (data, {
2921
- schemas,
2922
- schema,
2923
- components
2924
- }) => {
2925
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2926
- (acc, [attribute, metadata]) => {
2927
- return {
2928
- ...acc,
2929
- [attribute]: metadata.list
2930
- };
2931
- },
2932
- {}
2933
- );
2934
- const listAttributes = convertListLayoutToFieldLayouts(
2935
- data.contentType.layouts.list,
2936
- schema?.attributes,
2937
- listMetadatas,
2938
- { configurations: data.components, schemas: components },
2939
- schemas
2940
- );
3208
+ const ActionsPanel = () => {
3209
+ const { formatMessage } = reactIntl.useIntl();
2941
3210
  return {
2942
- layout: listAttributes,
2943
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2944
- metadatas: listMetadatas,
2945
- options: {
2946
- ...schema?.options,
2947
- ...schema?.pluginOptions,
2948
- ...data.contentType.options
2949
- }
3211
+ title: formatMessage({
3212
+ id: "content-manager.containers.edit.panels.default.title",
3213
+ defaultMessage: "Entry"
3214
+ }),
3215
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2950
3216
  };
2951
3217
  };
2952
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2953
- return columns.map((name) => {
2954
- const attribute = attributes[name];
2955
- if (!attribute) {
2956
- return null;
3218
+ ActionsPanel.type = "actions";
3219
+ const ActionsPanelContent = () => {
3220
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
3221
+ const [
3222
+ {
3223
+ query: { status = "draft" }
2957
3224
  }
2958
- const metadata = metadatas[name];
2959
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2960
- return {
2961
- attribute,
2962
- label: metadata.label ?? "",
2963
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2964
- schemas,
2965
- components: components?.schemas ?? {}
2966
- }),
2967
- name,
2968
- searchable: metadata.searchable ?? true,
2969
- sortable: metadata.sortable ?? true
2970
- };
2971
- }).filter((field) => field !== null);
3225
+ ] = strapiAdmin.useQueryParams();
3226
+ const { model, id, document, meta, collectionType } = useDoc();
3227
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
3228
+ const props = {
3229
+ activeTab: status,
3230
+ model,
3231
+ documentId: id,
3232
+ document: isCloning ? void 0 : document,
3233
+ meta: isCloning ? void 0 : meta,
3234
+ collectionType
3235
+ };
3236
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3237
+ /* @__PURE__ */ jsxRuntime.jsx(
3238
+ strapiAdmin.DescriptionComponentRenderer,
3239
+ {
3240
+ props,
3241
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
3242
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3243
+ }
3244
+ ),
3245
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3246
+ ] });
2972
3247
  };
3248
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3249
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3250
+ designSystem.Flex,
3251
+ {
3252
+ ref,
3253
+ tag: "aside",
3254
+ "aria-labelledby": "additional-information",
3255
+ background: "neutral0",
3256
+ borderColor: "neutral150",
3257
+ hasRadius: true,
3258
+ paddingBottom: 4,
3259
+ paddingLeft: 4,
3260
+ paddingRight: 4,
3261
+ paddingTop: 4,
3262
+ shadow: "tableShadow",
3263
+ gap: 3,
3264
+ direction: "column",
3265
+ justifyContent: "stretch",
3266
+ alignItems: "flex-start",
3267
+ children: [
3268
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3269
+ children
3270
+ ]
3271
+ }
3272
+ );
3273
+ });
2973
3274
  const ConfirmBulkActionDialog = ({
2974
3275
  onToggleDialog,
2975
3276
  isOpen = false,
@@ -2995,7 +3296,7 @@ const ConfirmBulkActionDialog = ({
2995
3296
  ] })
2996
3297
  ] }) });
2997
3298
  };
2998
- 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 });
2999
3300
  const ConfirmDialogPublishAll = ({
3000
3301
  isOpen,
3001
3302
  onToggleDialog,
@@ -3044,7 +3345,7 @@ const ConfirmDialogPublishAll = ({
3044
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. "
3045
3346
  },
3046
3347
  {
3047
- b: BoldChunk$1,
3348
+ b: BoldChunk,
3048
3349
  count: countDraftRelations,
3049
3350
  entities: selectedEntries.length
3050
3351
  }
@@ -3083,6 +3384,16 @@ const ConfirmDialogPublishAll = ({
3083
3384
  const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
3084
3385
  max-width: 300px;
3085
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
+ `;
3086
3397
  const formatErrorMessages = (errors, parentKey, formatMessage) => {
3087
3398
  const messages = [];
3088
3399
  Object.entries(errors).forEach(([key, value]) => {
@@ -3187,7 +3498,7 @@ const SelectedEntriesTableContent = ({
3187
3498
  )
3188
3499
  ] }),
3189
3500
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3190
- /* @__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: [
3191
3502
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3192
3503
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3193
3504
  shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
@@ -3214,18 +3525,10 @@ const SelectedEntriesTableContent = ({
3214
3525
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3215
3526
  },
3216
3527
  state: { from: pathname },
3217
- label: formatMessage(
3218
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3219
- {
3220
- target: formatMessage(
3221
- {
3222
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3223
- defaultMessage: "item line {number}"
3224
- },
3225
- { number: index2 + 1 }
3226
- )
3227
- }
3228
- ),
3528
+ label: formatMessage({
3529
+ id: "content-manager.bulk-publish.edit",
3530
+ defaultMessage: "Edit"
3531
+ }),
3229
3532
  target: "_blank",
3230
3533
  marginLeft: "auto",
3231
3534
  variant: "ghost",
@@ -3235,7 +3538,73 @@ const SelectedEntriesTableContent = ({
3235
3538
  ] }, row.id)) })
3236
3539
  ] });
3237
3540
  };
3238
- 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
+ };
3239
3608
  const SelectedEntriesModalContent = ({
3240
3609
  listViewSelectedEntries,
3241
3610
  toggleModal,
@@ -3294,7 +3663,6 @@ const SelectedEntriesModalContent = ({
3294
3663
  validationErrors: {}
3295
3664
  };
3296
3665
  }, [components, data, schema]);
3297
- const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3298
3666
  const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3299
3667
  const { publishMany: bulkPublishAction } = useDocumentActions();
3300
3668
  const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
@@ -3306,53 +3674,36 @@ const SelectedEntriesModalContent = ({
3306
3674
  const selectedEntriesWithErrorsCount = selectedEntries.filter(
3307
3675
  ({ documentId }) => validationErrors[documentId]
3308
3676
  ).length;
3309
- const selectedEntriesPublished = selectedEntries.filter(
3677
+ const selectedEntriesPublishedCount = selectedEntries.filter(
3310
3678
  ({ status }) => status === "published"
3311
3679
  ).length;
3312
- 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;
3313
3684
  const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3314
3685
  const handleConfirmBulkPublish = async () => {
3315
3686
  toggleDialog();
3316
3687
  const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3317
3688
  if (!("error" in res)) {
3318
- setPublishedCount(res.count);
3319
3689
  const unpublishedEntries = rows.filter((row) => {
3320
3690
  return !entriesToPublish.includes(row.documentId);
3321
3691
  });
3322
3692
  setListViewSelectedDocuments(unpublishedEntries);
3323
3693
  }
3324
3694
  };
3325
- const getFormattedCountMessage = () => {
3326
- if (publishedCount) {
3327
- return formatMessage(
3328
- {
3329
- id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3330
- 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."
3331
- },
3332
- {
3333
- publishedCount,
3334
- withErrorsCount: selectedEntriesWithErrorsCount,
3335
- b: BoldChunk
3336
- }
3337
- );
3338
- }
3339
- return formatMessage(
3340
- {
3341
- id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3342
- 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."
3343
- },
3344
- {
3345
- readyToPublishCount: selectedEntriesWithNoErrorsCount,
3346
- withErrorsCount: selectedEntriesWithErrorsCount,
3347
- alreadyPublishedCount: selectedEntriesPublished,
3348
- b: BoldChunk
3349
- }
3350
- );
3351
- };
3352
3695
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3353
3696
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3354
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3355
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3697
+ /* @__PURE__ */ jsxRuntime.jsx(
3698
+ PublicationStatusGrid,
3699
+ {
3700
+ entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
3701
+ entriesPublishedCount: selectedEntriesPublishedCount,
3702
+ entriesModifiedCount: selectedEntriesModifiedCount,
3703
+ entriesWithErrorsCount: selectedEntriesWithErrorsCount
3704
+ }
3705
+ ),
3706
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 7, children: /* @__PURE__ */ jsxRuntime.jsx(
3356
3707
  SelectedEntriesTableContent,
3357
3708
  {
3358
3709
  isPublishing: isSubmittingForm,
@@ -3373,7 +3724,7 @@ const SelectedEntriesModalContent = ({
3373
3724
  designSystem.Button,
3374
3725
  {
3375
3726
  onClick: toggleDialog,
3376
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3727
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
3377
3728
  loading: isSubmittingForm,
3378
3729
  children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3379
3730
  }
@@ -3399,8 +3750,7 @@ const PublishAction = ({ documents, model }) => {
3399
3750
  const refetchList = () => {
3400
3751
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3401
3752
  };
3402
- if (!showPublishButton)
3403
- return null;
3753
+ if (!showPublishButton) return null;
3404
3754
  return {
3405
3755
  actionType: "publish",
3406
3756
  variant: "tertiary",
@@ -3468,8 +3818,7 @@ const DeleteAction = ({ documents, model }) => {
3468
3818
  selectRow([]);
3469
3819
  }
3470
3820
  };
3471
- if (!hasDeletePermission)
3472
- return null;
3821
+ if (!hasDeletePermission) return null;
3473
3822
  return {
3474
3823
  variant: "danger-light",
3475
3824
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3518,8 +3867,7 @@ const UnpublishAction = ({ documents, model }) => {
3518
3867
  }
3519
3868
  };
3520
3869
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3521
- if (!showUnpublishButton)
3522
- return null;
3870
+ if (!showUnpublishButton) return null;
3523
3871
  return {
3524
3872
  variant: "tertiary",
3525
3873
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3624,7 +3972,7 @@ const TableActions = ({ document }) => {
3624
3972
  strapiAdmin.DescriptionComponentRenderer,
3625
3973
  {
3626
3974
  props,
3627
- descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3975
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3628
3976
  children: (actions2) => {
3629
3977
  const tableRowActions = actions2.filter((action) => {
3630
3978
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3683,6 +4031,7 @@ const EditAction = ({ documentId }) => {
3683
4031
  };
3684
4032
  };
3685
4033
  EditAction.type = "edit";
4034
+ EditAction.position = "table-row";
3686
4035
  const StyledPencil = styledComponents.styled(Icons.Pencil)`
3687
4036
  path {
3688
4037
  fill: currentColor;
@@ -3759,6 +4108,7 @@ const CloneAction = ({ model, documentId }) => {
3759
4108
  };
3760
4109
  };
3761
4110
  CloneAction.type = "clone";
4111
+ CloneAction.position = "table-row";
3762
4112
  const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
3763
4113
  path {
3764
4114
  fill: currentColor;
@@ -3845,7 +4195,14 @@ class ContentManagerPlugin {
3845
4195
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3846
4196
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3847
4197
  getBulkActions: () => this.bulkActions,
3848
- 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
+ },
3849
4206
  getEditViewSidePanels: () => this.editViewSidePanels,
3850
4207
  getHeaderActions: () => this.headerActions
3851
4208
  }
@@ -3855,10 +4212,8 @@ class ContentManagerPlugin {
3855
4212
  const getPrintableType = (value) => {
3856
4213
  const nativeType = typeof value;
3857
4214
  if (nativeType === "object") {
3858
- if (value === null)
3859
- return "null";
3860
- if (Array.isArray(value))
3861
- return "array";
4215
+ if (value === null) return "null";
4216
+ if (Array.isArray(value)) return "array";
3862
4217
  if (value instanceof Object && value.constructor.name !== "Object") {
3863
4218
  return value.constructor.name;
3864
4219
  }
@@ -3869,17 +4224,27 @@ const HistoryAction = ({ model, document }) => {
3869
4224
  const { formatMessage } = reactIntl.useIntl();
3870
4225
  const [{ query }] = strapiAdmin.useQueryParams();
3871
4226
  const navigate = reactRouterDom.useNavigate();
4227
+ const { trackUsage } = strapiAdmin.useTracking();
4228
+ const { pathname } = reactRouterDom.useLocation();
3872
4229
  const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3873
4230
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3874
4231
  return null;
3875
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
+ };
3876
4241
  return {
3877
4242
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3878
4243
  label: formatMessage({
3879
4244
  id: "content-manager.history.document-action",
3880
4245
  defaultMessage: "Content History"
3881
4246
  }),
3882
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
4247
+ onClick: handleOnClick,
3883
4248
  disabled: (
3884
4249
  /**
3885
4250
  * The user is creating a new document.
@@ -3901,6 +4266,7 @@ const HistoryAction = ({ model, document }) => {
3901
4266
  };
3902
4267
  };
3903
4268
  HistoryAction.type = "history";
4269
+ HistoryAction.position = "header";
3904
4270
  const historyAdmin = {
3905
4271
  bootstrap(app) {
3906
4272
  const { addDocumentAction } = app.getPlugin("content-manager").apis;
@@ -3947,6 +4313,88 @@ const { setInitialData } = actions;
3947
4313
  const reducer = toolkit.combineReducers({
3948
4314
  app: reducer$1
3949
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
+ };
3950
4398
  const index = {
3951
4399
  register(app) {
3952
4400
  const cm = new ContentManagerPlugin();
@@ -3966,7 +4414,7 @@ const index = {
3966
4414
  app.router.addRoute({
3967
4415
  path: "content-manager/*",
3968
4416
  lazy: async () => {
3969
- const { Layout } = await Promise.resolve().then(() => require("./layout-bE-WUnQ0.js"));
4417
+ const { Layout } = await Promise.resolve().then(() => require("./layout-DSeUTfMv.js"));
3970
4418
  return {
3971
4419
  Component: Layout
3972
4420
  };
@@ -3979,11 +4427,14 @@ const index = {
3979
4427
  if (typeof historyAdmin.bootstrap === "function") {
3980
4428
  historyAdmin.bootstrap(app);
3981
4429
  }
4430
+ if (typeof previewAdmin.bootstrap === "function") {
4431
+ previewAdmin.bootstrap(app);
4432
+ }
3982
4433
  },
3983
4434
  async registerTrads({ locales }) {
3984
4435
  const importedTrads = await Promise.all(
3985
4436
  locales.map((locale) => {
3986
- 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-BVzUkPxZ.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 }) => {
3987
4438
  return {
3988
4439
  data: prefixPluginTranslations(data, PLUGIN_ID),
3989
4440
  locale
@@ -4005,7 +4456,6 @@ exports.CLONE_PATH = CLONE_PATH;
4005
4456
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
4006
4457
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
4007
4458
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
4008
- exports.DOCUMENT_META_FIELDS = DOCUMENT_META_FIELDS;
4009
4459
  exports.DocumentRBAC = DocumentRBAC;
4010
4460
  exports.DocumentStatus = DocumentStatus;
4011
4461
  exports.HOOKS = HOOKS;
@@ -4022,13 +4472,18 @@ exports.checkIfAttributeIsDisplayable = checkIfAttributeIsDisplayable;
4022
4472
  exports.contentManagerApi = contentManagerApi;
4023
4473
  exports.convertEditLayoutToFieldLayouts = convertEditLayoutToFieldLayouts;
4024
4474
  exports.convertListLayoutToFieldLayouts = convertListLayoutToFieldLayouts;
4475
+ exports.createDefaultForm = createDefaultForm;
4025
4476
  exports.createYupSchema = createYupSchema;
4026
4477
  exports.extractContentTypeComponents = extractContentTypeComponents;
4027
4478
  exports.getDisplayName = getDisplayName;
4028
4479
  exports.getMainField = getMainField;
4029
4480
  exports.getTranslation = getTranslation;
4030
4481
  exports.index = index;
4482
+ exports.prepareTempKeys = prepareTempKeys;
4483
+ exports.removeFieldsThatDontExistOnSchema = removeFieldsThatDontExistOnSchema;
4031
4484
  exports.setInitialData = setInitialData;
4485
+ exports.transformDocument = transformDocument;
4486
+ exports.useContentManagerContext = useContentManagerContext;
4032
4487
  exports.useContentTypeSchema = useContentTypeSchema;
4033
4488
  exports.useDoc = useDoc;
4034
4489
  exports.useDocLayout = useDocLayout;
@@ -4040,5 +4495,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
4040
4495
  exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
4041
4496
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
4042
4497
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
4498
+ exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
4043
4499
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
4044
- //# sourceMappingURL=index-DXiHxy70.js.map
4500
+ //# sourceMappingURL=index-CxLSGwnk.js.map