@strapi/content-manager 0.0.0-experimental.cb311d9fcfbd8e441f790aea232f0a39bdd90e16 → 0.0.0-experimental.cb74730ce5154c26404d4dccca14976a22319002

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-D0dyDTwq.mjs → ComponentConfigurationPage-BgCLcjXO.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-D0dyDTwq.mjs.map → ComponentConfigurationPage-BgCLcjXO.mjs.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-DL1MHO8i.js → ComponentConfigurationPage-DywpTZeV.js} +5 -6
  6. package/dist/_chunks/{ComponentConfigurationPage-DL1MHO8i.js.map → ComponentConfigurationPage-DywpTZeV.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-13b7S5Cq.mjs → EditConfigurationPage-BNjOAHNS.mjs} +4 -4
  11. package/dist/_chunks/{EditConfigurationPage-13b7S5Cq.mjs.map → EditConfigurationPage-BNjOAHNS.mjs.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-CMaOf-A-.js → EditConfigurationPage-CxRlP5if.js} +5 -6
  13. package/dist/_chunks/{EditConfigurationPage-CMaOf-A-.js.map → EditConfigurationPage-CxRlP5if.js.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-BSVmMpRd.js → EditViewPage-BRewdTqE.js} +63 -13
  15. package/dist/_chunks/EditViewPage-BRewdTqE.js.map +1 -0
  16. package/dist/_chunks/{EditViewPage-C3tIZ8F5.mjs → EditViewPage-CD_hqc1J.mjs} +63 -12
  17. package/dist/_chunks/EditViewPage-CD_hqc1J.mjs.map +1 -0
  18. package/dist/_chunks/{Field-BvuT8cGL.mjs → Field-BPkQ-3Ku.mjs} +230 -158
  19. package/dist/_chunks/Field-BPkQ-3Ku.mjs.map +1 -0
  20. package/dist/_chunks/{Field-DUCVth4C.js → Field-DwvmENVf.js} +233 -162
  21. package/dist/_chunks/Field-DwvmENVf.js.map +1 -0
  22. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  23. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  24. package/dist/_chunks/{Form-Cpl4W1ak.js → Form-C_Gwv8P_.js} +39 -21
  25. package/dist/_chunks/Form-C_Gwv8P_.js.map +1 -0
  26. package/dist/_chunks/{Form-BZmDNVr9.mjs → Form-Czi0cf_2.mjs} +37 -18
  27. package/dist/_chunks/Form-Czi0cf_2.mjs.map +1 -0
  28. package/dist/_chunks/{History-D4U2YISB.js → History-C1TKAig-.js} +42 -100
  29. package/dist/_chunks/History-C1TKAig-.js.map +1 -0
  30. package/dist/_chunks/{History-Cq_Hrzuu.mjs → History-CIQHyi4T.mjs} +43 -100
  31. package/dist/_chunks/History-CIQHyi4T.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-Bny6CdWe.js → ListConfigurationPage-D-NGRLYu.js} +19 -9
  33. package/dist/_chunks/ListConfigurationPage-D-NGRLYu.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-W-KQHmBv.mjs → ListConfigurationPage-DcZsfyEL.mjs} +19 -8
  35. package/dist/_chunks/ListConfigurationPage-DcZsfyEL.mjs.map +1 -0
  36. package/dist/_chunks/{ListViewPage-HBBnJa8K.mjs → ListViewPage-C10McTK1.mjs} +99 -72
  37. package/dist/_chunks/ListViewPage-C10McTK1.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-O8F1pBJo.js → ListViewPage-xv5IQoZp.js} +103 -77
  39. package/dist/_chunks/ListViewPage-xv5IQoZp.js.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-B-gIhHWM.mjs → NoContentTypePage-CPc0Cd3S.mjs} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-B-gIhHWM.mjs.map → NoContentTypePage-CPc0Cd3S.mjs.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-CQWChGPw.js → NoContentTypePage-Dzw5Yj5u.js} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-CQWChGPw.js.map → NoContentTypePage-Dzw5Yj5u.js.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-CY46zxnM.js → NoPermissionsPage-DAe5CDCC.js} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-CY46zxnM.js.map → NoPermissionsPage-DAe5CDCC.js.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-XhOPl8wx.mjs → NoPermissionsPage-wfPBh2_0.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-XhOPl8wx.mjs.map → NoPermissionsPage-wfPBh2_0.mjs.map} +1 -1
  48. package/dist/_chunks/Preview-B7LyGT_b.js +290 -0
  49. package/dist/_chunks/Preview-B7LyGT_b.js.map +1 -0
  50. package/dist/_chunks/Preview-BVFFm7uB.mjs +272 -0
  51. package/dist/_chunks/Preview-BVFFm7uB.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-C4gGfZRv.js → Relations-BmYR1AjY.js} +76 -43
  53. package/dist/_chunks/Relations-BmYR1AjY.js.map +1 -0
  54. package/dist/_chunks/{Relations-vFZ6Wasg.mjs → Relations-JPhWxk-s.mjs} +76 -42
  55. package/dist/_chunks/Relations-JPhWxk-s.mjs.map +1 -0
  56. package/dist/_chunks/{en-uOUIxfcQ.js → en-BK8Xyl5I.js} +28 -15
  57. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BK8Xyl5I.js.map} +1 -1
  58. package/dist/_chunks/{en-BrCTWlZv.mjs → en-Dtk_ot79.mjs} +28 -15
  59. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-Dtk_ot79.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-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  65. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  66. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  67. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  68. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  69. package/dist/_chunks/{index-5EMXLEM_.js → index-C2Q_PLWj.js} +1199 -927
  70. package/dist/_chunks/index-C2Q_PLWj.js.map +1 -0
  71. package/dist/_chunks/{index-Dpxg3ctD.mjs → index-DLIkNVnQ.mjs} +1217 -945
  72. package/dist/_chunks/index-DLIkNVnQ.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-P3eKO1Qy.js → layout-7AsWJzZJ.js} +10 -10
  78. package/dist/_chunks/layout-7AsWJzZJ.js.map +1 -0
  79. package/dist/_chunks/{layout-C0INpKap.mjs → layout-qE8qkNH_.mjs} +9 -8
  80. package/dist/_chunks/layout-qE8qkNH_.mjs.map +1 -0
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-FBRRBWeO.mjs → relations-BjHH_1Am.mjs} +6 -7
  86. package/dist/_chunks/relations-BjHH_1Am.mjs.map +1 -0
  87. package/dist/_chunks/{relations-B1y0K6LE.js → relations-EifVzf_2.js} +6 -7
  88. package/dist/_chunks/relations-EifVzf_2.js.map +1 -0
  89. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  90. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  91. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  92. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  93. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  94. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  95. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  96. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  97. package/dist/admin/index.js +2 -1
  98. package/dist/admin/index.js.map +1 -1
  99. package/dist/admin/index.mjs +5 -4
  100. package/dist/admin/src/exports.d.ts +1 -1
  101. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  102. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  103. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  104. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
  105. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  106. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  107. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  108. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  109. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  110. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  111. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  112. package/dist/admin/src/preview/constants.d.ts +1 -0
  113. package/dist/admin/src/preview/index.d.ts +4 -0
  114. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  115. package/dist/admin/src/preview/routes.d.ts +3 -0
  116. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  117. package/dist/admin/src/router.d.ts +1 -1
  118. package/dist/admin/src/services/api.d.ts +1 -1
  119. package/dist/admin/src/services/components.d.ts +2 -2
  120. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  121. package/dist/admin/src/services/documents.d.ts +19 -20
  122. package/dist/admin/src/services/init.d.ts +1 -1
  123. package/dist/admin/src/services/relations.d.ts +2 -2
  124. package/dist/admin/src/services/uid.d.ts +3 -3
  125. package/dist/admin/src/utils/validation.d.ts +4 -1
  126. package/dist/server/index.js +486 -219
  127. package/dist/server/index.js.map +1 -1
  128. package/dist/server/index.mjs +486 -218
  129. package/dist/server/index.mjs.map +1 -1
  130. package/dist/server/src/bootstrap.d.ts.map +1 -1
  131. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  132. package/dist/server/src/controllers/index.d.ts.map +1 -1
  133. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  134. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  135. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  136. package/dist/server/src/history/services/history.d.ts.map +1 -1
  137. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  138. package/dist/server/src/history/services/utils.d.ts +3 -3
  139. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  140. package/dist/server/src/index.d.ts +4 -4
  141. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  142. package/dist/server/src/preview/constants.d.ts +2 -0
  143. package/dist/server/src/preview/constants.d.ts.map +1 -0
  144. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  145. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  146. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  147. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  148. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  149. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  150. package/dist/server/src/preview/index.d.ts +4 -0
  151. package/dist/server/src/preview/index.d.ts.map +1 -0
  152. package/dist/server/src/preview/routes/index.d.ts +8 -0
  153. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  154. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  155. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  156. package/dist/server/src/preview/services/index.d.ts +16 -0
  157. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  158. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  159. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  160. package/dist/server/src/preview/services/preview.d.ts +12 -0
  161. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  162. package/dist/server/src/preview/utils.d.ts +19 -0
  163. package/dist/server/src/preview/utils.d.ts.map +1 -0
  164. package/dist/server/src/register.d.ts.map +1 -1
  165. package/dist/server/src/routes/index.d.ts.map +1 -1
  166. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  167. package/dist/server/src/services/document-metadata.d.ts +8 -8
  168. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  169. package/dist/server/src/services/index.d.ts +4 -4
  170. package/dist/server/src/services/index.d.ts.map +1 -1
  171. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  172. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  173. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  174. package/dist/server/src/utils/index.d.ts +2 -0
  175. package/dist/server/src/utils/index.d.ts.map +1 -1
  176. package/dist/shared/contracts/collection-types.d.ts +3 -1
  177. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  178. package/dist/shared/contracts/index.d.ts +1 -0
  179. package/dist/shared/contracts/index.d.ts.map +1 -1
  180. package/dist/shared/contracts/preview.d.ts +27 -0
  181. package/dist/shared/contracts/preview.d.ts.map +1 -0
  182. package/dist/shared/index.js +4 -0
  183. package/dist/shared/index.js.map +1 -1
  184. package/dist/shared/index.mjs +4 -0
  185. package/dist/shared/index.mjs.map +1 -1
  186. package/package.json +15 -15
  187. package/dist/_chunks/EditViewPage-BSVmMpRd.js.map +0 -1
  188. package/dist/_chunks/EditViewPage-C3tIZ8F5.mjs.map +0 -1
  189. package/dist/_chunks/Field-BvuT8cGL.mjs.map +0 -1
  190. package/dist/_chunks/Field-DUCVth4C.js.map +0 -1
  191. package/dist/_chunks/Form-BZmDNVr9.mjs.map +0 -1
  192. package/dist/_chunks/Form-Cpl4W1ak.js.map +0 -1
  193. package/dist/_chunks/History-Cq_Hrzuu.mjs.map +0 -1
  194. package/dist/_chunks/History-D4U2YISB.js.map +0 -1
  195. package/dist/_chunks/ListConfigurationPage-Bny6CdWe.js.map +0 -1
  196. package/dist/_chunks/ListConfigurationPage-W-KQHmBv.mjs.map +0 -1
  197. package/dist/_chunks/ListViewPage-HBBnJa8K.mjs.map +0 -1
  198. package/dist/_chunks/ListViewPage-O8F1pBJo.js.map +0 -1
  199. package/dist/_chunks/Relations-C4gGfZRv.js.map +0 -1
  200. package/dist/_chunks/Relations-vFZ6Wasg.mjs.map +0 -1
  201. package/dist/_chunks/index-5EMXLEM_.js.map +0 -1
  202. package/dist/_chunks/index-Dpxg3ctD.mjs.map +0 -1
  203. package/dist/_chunks/layout-C0INpKap.mjs.map +0 -1
  204. package/dist/_chunks/layout-P3eKO1Qy.js.map +0 -1
  205. package/dist/_chunks/relations-B1y0K6LE.js.map +0 -1
  206. package/dist/_chunks/relations-FBRRBWeO.mjs.map +0 -1
  207. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  208. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  209. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  210. package/strapi-server.js +0 -3
@@ -1,25 +1,33 @@
1
- import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
1
+ import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
3
+ import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import * as React from "react";
5
5
  import { lazy } from "react";
6
- import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import mapValues from "lodash/fp/mapValues";
7
8
  import { useIntl } from "react-intl";
8
- import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
10
  import { styled } from "styled-components";
10
11
  import * as yup from "yup";
11
12
  import { ValidationError } from "yup";
13
+ import { stringify } from "qs";
12
14
  import pipe from "lodash/fp/pipe";
13
15
  import { intervalToDuration, isPast } from "date-fns";
14
- import { stringify } from "qs";
15
16
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
17
18
  const v = glob[path];
18
19
  if (v) {
19
20
  return typeof v === "function" ? v() : Promise.resolve(v);
20
21
  }
21
22
  return new Promise((_, reject) => {
22
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
23
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
24
+ reject.bind(
25
+ null,
26
+ new Error(
27
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
28
+ )
29
+ )
30
+ );
23
31
  });
24
32
  };
25
33
  const PLUGIN_ID = "content-manager";
@@ -100,6 +108,7 @@ const DocumentRBAC = ({ children, permissions }) => {
100
108
  if (!slug) {
101
109
  throw new Error("Cannot find the slug param in the URL");
102
110
  }
111
+ const [{ rawQuery }] = useQueryParams();
103
112
  const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
104
113
  const contentTypePermissions = React.useMemo(() => {
105
114
  const contentTypePermissions2 = userPermissions.filter(
@@ -110,7 +119,14 @@ const DocumentRBAC = ({ children, permissions }) => {
110
119
  return { ...acc, [action]: [permission] };
111
120
  }, {});
112
121
  }, [slug, userPermissions]);
113
- const { isLoading, allowedActions } = useRBAC(contentTypePermissions, permissions ?? void 0);
122
+ const { isLoading, allowedActions } = useRBAC(
123
+ contentTypePermissions,
124
+ permissions ?? void 0,
125
+ // TODO: useRBAC context should be typed and built differently
126
+ // We are passing raw query as context to the hook so that it can
127
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
128
+ rawQuery
129
+ );
114
130
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
115
131
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
116
132
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -158,7 +174,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
158
174
  "Document",
159
175
  "InitialData",
160
176
  "HistoryVersion",
161
- "Relations"
177
+ "Relations",
178
+ "UidAvailability"
162
179
  ]
163
180
  });
164
181
  const documentApi = contentManagerApi.injectEndpoints({
@@ -188,7 +205,10 @@ const documentApi = contentManagerApi.injectEndpoints({
188
205
  params
189
206
  }
190
207
  }),
191
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
208
+ invalidatesTags: (_result, _error, { model }) => [
209
+ { type: "Document", id: `${model}_LIST` },
210
+ { type: "UidAvailability", id: model }
211
+ ]
192
212
  }),
193
213
  /**
194
214
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -205,7 +225,8 @@ const documentApi = contentManagerApi.injectEndpoints({
205
225
  }),
206
226
  invalidatesTags: (result, _error, { model }) => [
207
227
  { type: "Document", id: `${model}_LIST` },
208
- "Relations"
228
+ "Relations",
229
+ { type: "UidAvailability", id: model }
209
230
  ]
210
231
  }),
211
232
  deleteDocument: builder.mutation({
@@ -246,7 +267,8 @@ const documentApi = contentManagerApi.injectEndpoints({
246
267
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
247
268
  },
248
269
  { type: "Document", id: `${model}_LIST` },
249
- "Relations"
270
+ "Relations",
271
+ { type: "UidAvailability", id: model }
250
272
  ];
251
273
  }
252
274
  }),
@@ -259,7 +281,7 @@ const documentApi = contentManagerApi.injectEndpoints({
259
281
  url: `/content-manager/collection-types/${model}`,
260
282
  method: "GET",
261
283
  config: {
262
- params
284
+ params: stringify(params, { encode: true })
263
285
  }
264
286
  }),
265
287
  providesTags: (result, _error, arg) => {
@@ -371,7 +393,8 @@ const documentApi = contentManagerApi.injectEndpoints({
371
393
  type: "Document",
372
394
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
373
395
  },
374
- "Relations"
396
+ "Relations",
397
+ { type: "UidAvailability", id: model }
375
398
  ];
376
399
  },
377
400
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -437,8 +460,7 @@ const {
437
460
  useUnpublishManyDocumentsMutation
438
461
  } = documentApi;
439
462
  const buildValidParams = (query) => {
440
- if (!query)
441
- return query;
463
+ if (!query) return query;
442
464
  const { plugins: _, ...validQueryParams } = {
443
465
  ...query,
444
466
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -446,28 +468,44 @@ const buildValidParams = (query) => {
446
468
  {}
447
469
  )
448
470
  };
449
- if ("_q" in validQueryParams) {
450
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
451
- }
452
471
  return validQueryParams;
453
472
  };
454
473
  const isBaseQueryError = (error) => {
455
474
  return error.name !== void 0;
456
475
  };
457
- const createYupSchema = (attributes = {}, components = {}) => {
476
+ const arrayValidator = (attribute, options) => ({
477
+ message: translatedErrors.required,
478
+ test(value) {
479
+ if (options.status === "draft") {
480
+ return true;
481
+ }
482
+ if (!attribute.required) {
483
+ return true;
484
+ }
485
+ if (!value) {
486
+ return false;
487
+ }
488
+ if (Array.isArray(value) && value.length === 0) {
489
+ return false;
490
+ }
491
+ return true;
492
+ }
493
+ });
494
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
458
495
  const createModelSchema = (attributes2) => yup.object().shape(
459
496
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
460
497
  if (DOCUMENT_META_FIELDS.includes(name)) {
461
498
  return acc;
462
499
  }
463
500
  const validations = [
501
+ addNullableValidation,
464
502
  addRequiredValidation,
465
503
  addMinLengthValidation,
466
504
  addMaxLengthValidation,
467
505
  addMinValidation,
468
506
  addMaxValidation,
469
507
  addRegexValidation
470
- ].map((fn) => fn(attribute));
508
+ ].map((fn) => fn(attribute, options));
471
509
  const transformSchema = pipe(...validations);
472
510
  switch (attribute.type) {
473
511
  case "component": {
@@ -477,12 +515,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
477
515
  ...acc,
478
516
  [name]: transformSchema(
479
517
  yup.array().of(createModelSchema(attributes3).nullable(false))
480
- )
518
+ ).test(arrayValidator(attribute, options))
481
519
  };
482
520
  } else {
483
521
  return {
484
522
  ...acc,
485
- [name]: transformSchema(createModelSchema(attributes3))
523
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
486
524
  };
487
525
  }
488
526
  }
@@ -504,7 +542,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
504
542
  }
505
543
  )
506
544
  )
507
- )
545
+ ).test(arrayValidator(attribute, options))
508
546
  };
509
547
  case "relation":
510
548
  return {
@@ -516,7 +554,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
516
554
  } else if (Array.isArray(value)) {
517
555
  return yup.array().of(
518
556
  yup.object().shape({
519
- id: yup.string().required()
557
+ id: yup.number().required()
520
558
  })
521
559
  );
522
560
  } else if (typeof value === "object") {
@@ -594,13 +632,7 @@ const createAttributeSchema = (attribute) => {
594
632
  return yup.mixed();
595
633
  }
596
634
  };
597
- const addRequiredValidation = (attribute) => (schema) => {
598
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
599
- return schema.min(1, translatedErrors.required);
600
- }
601
- if (attribute.required && attribute.type !== "relation") {
602
- return schema.required(translatedErrors.required);
603
- }
635
+ const nullableSchema = (schema) => {
604
636
  return schema?.nullable ? schema.nullable() : (
605
637
  // In some cases '.nullable' will not be available on the schema.
606
638
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -608,7 +640,22 @@ const addRequiredValidation = (attribute) => (schema) => {
608
640
  schema
609
641
  );
610
642
  };
611
- const addMinLengthValidation = (attribute) => (schema) => {
643
+ const addNullableValidation = () => (schema) => {
644
+ return nullableSchema(schema);
645
+ };
646
+ const addRequiredValidation = (attribute, options) => (schema) => {
647
+ if (options.status === "draft" || !attribute.required) {
648
+ return schema;
649
+ }
650
+ if (attribute.required && "required" in schema) {
651
+ return schema.required(translatedErrors.required);
652
+ }
653
+ return schema;
654
+ };
655
+ const addMinLengthValidation = (attribute, options) => (schema) => {
656
+ if (options.status === "draft") {
657
+ return schema;
658
+ }
612
659
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
613
660
  return schema.min(attribute.minLength, {
614
661
  ...translatedErrors.minLength,
@@ -630,32 +677,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
630
677
  }
631
678
  return schema;
632
679
  };
633
- const addMinValidation = (attribute) => (schema) => {
634
- if ("min" in attribute) {
680
+ const addMinValidation = (attribute, options) => (schema) => {
681
+ if (options.status === "draft") {
682
+ return schema;
683
+ }
684
+ if ("min" in attribute && "min" in schema) {
635
685
  const min = toInteger(attribute.min);
636
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
637
- if (!attribute.required && "test" in schema && min) {
638
- return schema.test(
639
- "custom-min",
640
- {
641
- ...translatedErrors.min,
642
- values: {
643
- min: attribute.min
644
- }
645
- },
646
- (value) => {
647
- if (!value) {
648
- return true;
649
- }
650
- if (Array.isArray(value) && value.length === 0) {
651
- return true;
652
- }
653
- return value.length >= min;
654
- }
655
- );
656
- }
657
- }
658
- if ("min" in schema && min) {
686
+ if (min) {
659
687
  return schema.min(min, {
660
688
  ...translatedErrors.min,
661
689
  values: {
@@ -773,19 +801,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
773
801
  }, {});
774
802
  return componentsByKey;
775
803
  };
776
- const useDocument = (args, opts) => {
804
+ const HOOKS = {
805
+ /**
806
+ * Hook that allows to mutate the displayed headers of the list view table
807
+ * @constant
808
+ * @type {string}
809
+ */
810
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
811
+ /**
812
+ * Hook that allows to mutate the CM's collection types links pre-set filters
813
+ * @constant
814
+ * @type {string}
815
+ */
816
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
817
+ /**
818
+ * Hook that allows to mutate the CM's edit view layout
819
+ * @constant
820
+ * @type {string}
821
+ */
822
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
823
+ /**
824
+ * Hook that allows to mutate the CM's single types links pre-set filters
825
+ * @constant
826
+ * @type {string}
827
+ */
828
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
829
+ };
830
+ const contentTypesApi = contentManagerApi.injectEndpoints({
831
+ endpoints: (builder) => ({
832
+ getContentTypeConfiguration: builder.query({
833
+ query: (uid) => ({
834
+ url: `/content-manager/content-types/${uid}/configuration`,
835
+ method: "GET"
836
+ }),
837
+ transformResponse: (response) => response.data,
838
+ providesTags: (_result, _error, uid) => [
839
+ { type: "ContentTypesConfiguration", id: uid },
840
+ { type: "ContentTypeSettings", id: "LIST" }
841
+ ]
842
+ }),
843
+ getAllContentTypeSettings: builder.query({
844
+ query: () => "/content-manager/content-types-settings",
845
+ transformResponse: (response) => response.data,
846
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
847
+ }),
848
+ updateContentTypeConfiguration: builder.mutation({
849
+ query: ({ uid, ...body }) => ({
850
+ url: `/content-manager/content-types/${uid}/configuration`,
851
+ method: "PUT",
852
+ data: body
853
+ }),
854
+ transformResponse: (response) => response.data,
855
+ invalidatesTags: (_result, _error, { uid }) => [
856
+ { type: "ContentTypesConfiguration", id: uid },
857
+ { type: "ContentTypeSettings", id: "LIST" },
858
+ // Is this necessary?
859
+ { type: "InitialData" }
860
+ ]
861
+ })
862
+ })
863
+ });
864
+ const {
865
+ useGetContentTypeConfigurationQuery,
866
+ useGetAllContentTypeSettingsQuery,
867
+ useUpdateContentTypeConfigurationMutation
868
+ } = contentTypesApi;
869
+ const checkIfAttributeIsDisplayable = (attribute) => {
870
+ const { type } = attribute;
871
+ if (type === "relation") {
872
+ return !attribute.relation.toLowerCase().includes("morph");
873
+ }
874
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
875
+ };
876
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
877
+ if (!mainFieldName) {
878
+ return void 0;
879
+ }
880
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
881
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
882
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
883
+ );
884
+ return {
885
+ name: mainFieldName,
886
+ type: mainFieldType ?? "string"
887
+ };
888
+ };
889
+ const DEFAULT_SETTINGS = {
890
+ bulkable: false,
891
+ filterable: false,
892
+ searchable: false,
893
+ pagination: false,
894
+ defaultSortBy: "",
895
+ defaultSortOrder: "asc",
896
+ mainField: "id",
897
+ pageSize: 10
898
+ };
899
+ const useDocumentLayout = (model) => {
900
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
901
+ const [{ query }] = useQueryParams();
902
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
777
903
  const { toggleNotification } = useNotification();
778
904
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
905
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
779
906
  const {
780
- currentData: data,
781
- isLoading: isLoadingDocument,
782
- isFetching: isFetchingDocument,
783
- error
784
- } = useGetDocumentQuery(args, {
785
- ...opts,
786
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
787
- });
788
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
907
+ data,
908
+ isLoading: isLoadingConfigs,
909
+ error,
910
+ isFetching: isFetchingConfigs
911
+ } = useGetContentTypeConfigurationQuery(model);
912
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
789
913
  React.useEffect(() => {
790
914
  if (error) {
791
915
  toggleNotification({
@@ -793,397 +917,654 @@ const useDocument = (args, opts) => {
793
917
  message: formatAPIError(error)
794
918
  });
795
919
  }
796
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
797
- const validationSchema = React.useMemo(() => {
798
- if (!schema) {
799
- return null;
800
- }
801
- return createYupSchema(schema.attributes, components);
802
- }, [schema, components]);
803
- const validate = React.useCallback(
804
- (document) => {
805
- if (!validationSchema) {
806
- throw new Error(
807
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
808
- );
809
- }
810
- try {
811
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
812
- return null;
813
- } catch (error2) {
814
- if (error2 instanceof ValidationError) {
815
- return getYupValidationErrors(error2);
816
- }
817
- throw error2;
818
- }
920
+ }, [error, formatAPIError, toggleNotification]);
921
+ const editLayout = React.useMemo(
922
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
923
+ layout: [],
924
+ components: {},
925
+ metadatas: {},
926
+ options: {},
927
+ settings: DEFAULT_SETTINGS
819
928
  },
820
- [validationSchema]
929
+ [data, isLoading, schemas, schema, components]
930
+ );
931
+ const listLayout = React.useMemo(() => {
932
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
933
+ layout: [],
934
+ metadatas: {},
935
+ options: {},
936
+ settings: DEFAULT_SETTINGS
937
+ };
938
+ }, [data, isLoading, schemas, schema, components]);
939
+ const { layout: edit } = React.useMemo(
940
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
941
+ layout: editLayout,
942
+ query
943
+ }),
944
+ [editLayout, query, runHookWaterfall]
821
945
  );
822
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
823
946
  return {
824
- components,
825
- document: data?.data,
826
- meta: data?.meta,
947
+ error,
827
948
  isLoading,
828
- schema,
829
- validate
830
- };
831
- };
832
- const useDoc = () => {
833
- const { id, slug, collectionType, origin } = useParams();
834
- const [{ query }] = useQueryParams();
835
- const params = React.useMemo(() => buildValidParams(query), [query]);
836
- if (!collectionType) {
837
- throw new Error("Could not find collectionType in url params");
838
- }
839
- if (!slug) {
840
- throw new Error("Could not find model in url params");
841
- }
842
- return {
843
- collectionType,
844
- model: slug,
845
- id: origin || id === "create" ? void 0 : id,
846
- ...useDocument(
847
- { documentId: origin || id, model: slug, collectionType, params },
848
- {
849
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
850
- }
851
- )
949
+ edit,
950
+ list: listLayout
852
951
  };
853
952
  };
854
- const prefixPluginTranslations = (trad, pluginId) => {
855
- if (!pluginId) {
856
- throw new TypeError("pluginId can't be empty");
857
- }
858
- return Object.keys(trad).reduce((acc, current) => {
859
- acc[`${pluginId}.${current}`] = trad[current];
860
- return acc;
861
- }, {});
862
- };
863
- const getTranslation = (id) => `content-manager.${id}`;
864
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
865
- id: "notification.error",
866
- defaultMessage: "An error occurred, please try again"
953
+ const useDocLayout = () => {
954
+ const { model } = useDoc();
955
+ return useDocumentLayout(model);
867
956
  };
868
- const useDocumentActions = () => {
869
- const { toggleNotification } = useNotification();
870
- const { formatMessage } = useIntl();
871
- const { trackUsage } = useTracking();
872
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
873
- const [deleteDocument] = useDeleteDocumentMutation();
874
- const _delete = React.useCallback(
875
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
876
- try {
877
- trackUsage("willDeleteEntry", trackerProperty);
878
- const res = await deleteDocument({
879
- collectionType,
880
- model,
881
- documentId,
882
- params
883
- });
884
- if ("error" in res) {
885
- toggleNotification({
886
- type: "danger",
887
- message: formatAPIError(res.error)
888
- });
889
- return { error: res.error };
890
- }
891
- toggleNotification({
892
- type: "success",
893
- message: formatMessage({
894
- id: getTranslation("success.record.delete"),
895
- defaultMessage: "Deleted document"
896
- })
897
- });
898
- trackUsage("didDeleteEntry", trackerProperty);
899
- return res.data;
900
- } catch (err) {
901
- toggleNotification({
902
- type: "danger",
903
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
904
- });
905
- trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
906
- throw err;
957
+ const formatEditLayout = (data, {
958
+ schemas,
959
+ schema,
960
+ components
961
+ }) => {
962
+ let currentPanelIndex = 0;
963
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
964
+ data.contentType.layouts.edit,
965
+ schema?.attributes,
966
+ data.contentType.metadatas,
967
+ { configurations: data.components, schemas: components },
968
+ schemas
969
+ ).reduce((panels, row) => {
970
+ if (row.some((field) => field.type === "dynamiczone")) {
971
+ panels.push([row]);
972
+ currentPanelIndex += 2;
973
+ } else {
974
+ if (!panels[currentPanelIndex]) {
975
+ panels.push([row]);
976
+ } else {
977
+ panels[currentPanelIndex].push(row);
907
978
  }
908
- },
909
- [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
910
- );
911
- const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
912
- const deleteMany = React.useCallback(
913
- async ({ model, documentIds, params }) => {
914
- try {
915
- trackUsage("willBulkDeleteEntries");
916
- const res = await deleteManyDocuments({
917
- model,
918
- documentIds,
919
- params
920
- });
921
- if ("error" in res) {
922
- toggleNotification({
923
- type: "danger",
924
- message: formatAPIError(res.error)
925
- });
926
- return { error: res.error };
979
+ }
980
+ return panels;
981
+ }, []);
982
+ const componentEditAttributes = Object.entries(data.components).reduce(
983
+ (acc, [uid, configuration]) => {
984
+ acc[uid] = {
985
+ layout: convertEditLayoutToFieldLayouts(
986
+ configuration.layouts.edit,
987
+ components[uid].attributes,
988
+ configuration.metadatas,
989
+ { configurations: data.components, schemas: components }
990
+ ),
991
+ settings: {
992
+ ...configuration.settings,
993
+ icon: components[uid].info.icon,
994
+ displayName: components[uid].info.displayName
927
995
  }
928
- toggleNotification({
929
- type: "success",
930
- title: formatMessage({
931
- id: getTranslation("success.records.delete"),
932
- defaultMessage: "Successfully deleted."
933
- }),
934
- message: ""
935
- });
936
- trackUsage("didBulkDeleteEntries");
937
- return res.data;
938
- } catch (err) {
939
- toggleNotification({
940
- type: "danger",
941
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
942
- });
943
- trackUsage("didNotBulkDeleteEntries");
944
- throw err;
945
- }
996
+ };
997
+ return acc;
946
998
  },
947
- [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
999
+ {}
948
1000
  );
949
- const [discardDocument] = useDiscardDocumentMutation();
950
- const discard = React.useCallback(
951
- async ({ collectionType, model, documentId, params }) => {
952
- try {
953
- const res = await discardDocument({
954
- collectionType,
955
- model,
956
- documentId,
957
- params
958
- });
959
- if ("error" in res) {
960
- toggleNotification({
961
- type: "danger",
962
- message: formatAPIError(res.error)
963
- });
964
- return { error: res.error };
965
- }
966
- toggleNotification({
967
- type: "success",
968
- message: formatMessage({
969
- id: "content-manager.success.record.discard",
970
- defaultMessage: "Changes discarded"
971
- })
972
- });
973
- return res.data;
974
- } catch (err) {
975
- toggleNotification({
976
- type: "danger",
977
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
978
- });
979
- throw err;
980
- }
1001
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1002
+ (acc, [attribute, metadata]) => {
1003
+ return {
1004
+ ...acc,
1005
+ [attribute]: metadata.edit
1006
+ };
981
1007
  },
982
- [discardDocument, formatAPIError, formatMessage, toggleNotification]
1008
+ {}
983
1009
  );
984
- const [publishDocument] = usePublishDocumentMutation();
985
- const publish = React.useCallback(
986
- async ({ collectionType, model, documentId, params }, data) => {
987
- try {
988
- trackUsage("willPublishEntry");
989
- const res = await publishDocument({
990
- collectionType,
991
- model,
992
- documentId,
993
- data,
994
- params
995
- });
996
- if ("error" in res) {
997
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
998
- return { error: res.error };
999
- }
1000
- trackUsage("didPublishEntry");
1001
- toggleNotification({
1002
- type: "success",
1003
- message: formatMessage({
1004
- id: getTranslation("success.record.publish"),
1005
- defaultMessage: "Published document"
1006
- })
1007
- });
1008
- return res.data;
1009
- } catch (err) {
1010
- toggleNotification({
1011
- type: "danger",
1012
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1013
- });
1014
- throw err;
1015
- }
1010
+ return {
1011
+ layout: panelledEditAttributes,
1012
+ components: componentEditAttributes,
1013
+ metadatas: editMetadatas,
1014
+ settings: {
1015
+ ...data.contentType.settings,
1016
+ displayName: schema?.info.displayName
1016
1017
  },
1017
- [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1018
- );
1019
- const [publishManyDocuments] = usePublishManyDocumentsMutation();
1020
- const publishMany = React.useCallback(
1021
- async ({ model, documentIds, params }) => {
1022
- try {
1023
- const res = await publishManyDocuments({
1024
- model,
1025
- documentIds,
1026
- params
1027
- });
1028
- if ("error" in res) {
1029
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1030
- return { error: res.error };
1031
- }
1032
- toggleNotification({
1033
- type: "success",
1034
- message: formatMessage({
1035
- id: getTranslation("success.record.publish"),
1036
- defaultMessage: "Published document"
1037
- })
1038
- });
1039
- return res.data;
1040
- } catch (err) {
1041
- toggleNotification({
1042
- type: "danger",
1043
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1044
- });
1045
- throw err;
1018
+ options: {
1019
+ ...schema?.options,
1020
+ ...schema?.pluginOptions,
1021
+ ...data.contentType.options
1022
+ }
1023
+ };
1024
+ };
1025
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1026
+ return rows.map(
1027
+ (row) => row.map((field) => {
1028
+ const attribute = attributes[field.name];
1029
+ if (!attribute) {
1030
+ return null;
1046
1031
  }
1047
- },
1048
- [
1049
- // trackUsage,
1050
- publishManyDocuments,
1051
- toggleNotification,
1052
- formatMessage,
1053
- formatAPIError
1054
- ]
1032
+ const { edit: metadata } = metadatas[field.name];
1033
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1034
+ return {
1035
+ attribute,
1036
+ disabled: !metadata.editable,
1037
+ hint: metadata.description,
1038
+ label: metadata.label ?? "",
1039
+ name: field.name,
1040
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1041
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1042
+ schemas,
1043
+ components: components?.schemas ?? {}
1044
+ }),
1045
+ placeholder: metadata.placeholder ?? "",
1046
+ required: attribute.required ?? false,
1047
+ size: field.size,
1048
+ unique: "unique" in attribute ? attribute.unique : false,
1049
+ visible: metadata.visible ?? true,
1050
+ type: attribute.type
1051
+ };
1052
+ }).filter((field) => field !== null)
1055
1053
  );
1056
- const [updateDocument] = useUpdateDocumentMutation();
1057
- const update = React.useCallback(
1058
- async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1054
+ };
1055
+ const formatListLayout = (data, {
1056
+ schemas,
1057
+ schema,
1058
+ components
1059
+ }) => {
1060
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1061
+ (acc, [attribute, metadata]) => {
1062
+ return {
1063
+ ...acc,
1064
+ [attribute]: metadata.list
1065
+ };
1066
+ },
1067
+ {}
1068
+ );
1069
+ const listAttributes = convertListLayoutToFieldLayouts(
1070
+ data.contentType.layouts.list,
1071
+ schema?.attributes,
1072
+ listMetadatas,
1073
+ { configurations: data.components, schemas: components },
1074
+ schemas
1075
+ );
1076
+ return {
1077
+ layout: listAttributes,
1078
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1079
+ metadatas: listMetadatas,
1080
+ options: {
1081
+ ...schema?.options,
1082
+ ...schema?.pluginOptions,
1083
+ ...data.contentType.options
1084
+ }
1085
+ };
1086
+ };
1087
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1088
+ return columns.map((name) => {
1089
+ const attribute = attributes[name];
1090
+ if (!attribute) {
1091
+ return null;
1092
+ }
1093
+ const metadata = metadatas[name];
1094
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1095
+ return {
1096
+ attribute,
1097
+ label: metadata.label ?? "",
1098
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1099
+ schemas,
1100
+ components: components?.schemas ?? {}
1101
+ }),
1102
+ name,
1103
+ searchable: metadata.searchable ?? true,
1104
+ sortable: metadata.sortable ?? true
1105
+ };
1106
+ }).filter((field) => field !== null);
1107
+ };
1108
+ const useDocument = (args, opts) => {
1109
+ const { toggleNotification } = useNotification();
1110
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1111
+ const {
1112
+ currentData: data,
1113
+ isLoading: isLoadingDocument,
1114
+ isFetching: isFetchingDocument,
1115
+ error
1116
+ } = useGetDocumentQuery(args, {
1117
+ ...opts,
1118
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1119
+ });
1120
+ const {
1121
+ components,
1122
+ schema,
1123
+ schemas,
1124
+ isLoading: isLoadingSchema
1125
+ } = useContentTypeSchema(args.model);
1126
+ React.useEffect(() => {
1127
+ if (error) {
1128
+ toggleNotification({
1129
+ type: "danger",
1130
+ message: formatAPIError(error)
1131
+ });
1132
+ }
1133
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1134
+ const validationSchema = React.useMemo(() => {
1135
+ if (!schema) {
1136
+ return null;
1137
+ }
1138
+ return createYupSchema(schema.attributes, components);
1139
+ }, [schema, components]);
1140
+ const validate = React.useCallback(
1141
+ (document) => {
1142
+ if (!validationSchema) {
1143
+ throw new Error(
1144
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1145
+ );
1146
+ }
1059
1147
  try {
1060
- trackUsage("willEditEntry", trackerProperty);
1061
- const res = await updateDocument({
1062
- collectionType,
1063
- model,
1064
- documentId,
1065
- data,
1066
- params
1067
- });
1068
- if ("error" in res) {
1069
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1070
- trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1071
- return { error: res.error };
1148
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1149
+ return null;
1150
+ } catch (error2) {
1151
+ if (error2 instanceof ValidationError) {
1152
+ return getYupValidationErrors(error2);
1072
1153
  }
1073
- trackUsage("didEditEntry", trackerProperty);
1074
- toggleNotification({
1075
- type: "success",
1076
- message: formatMessage({
1077
- id: getTranslation("success.record.save"),
1078
- defaultMessage: "Saved document"
1079
- })
1080
- });
1081
- return res.data;
1082
- } catch (err) {
1083
- trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1084
- toggleNotification({
1085
- type: "danger",
1086
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1087
- });
1088
- throw err;
1154
+ throw error2;
1089
1155
  }
1090
1156
  },
1091
- [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1157
+ [validationSchema]
1092
1158
  );
1093
- const [unpublishDocument] = useUnpublishDocumentMutation();
1094
- const unpublish = React.useCallback(
1095
- async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1159
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1160
+ const hasError = !!error;
1161
+ return {
1162
+ components,
1163
+ document: data?.data,
1164
+ meta: data?.meta,
1165
+ isLoading,
1166
+ hasError,
1167
+ schema,
1168
+ schemas,
1169
+ validate
1170
+ };
1171
+ };
1172
+ const useDoc = () => {
1173
+ const { id, slug, collectionType, origin } = useParams();
1174
+ const [{ query }] = useQueryParams();
1175
+ const params = React.useMemo(() => buildValidParams(query), [query]);
1176
+ if (!collectionType) {
1177
+ throw new Error("Could not find collectionType in url params");
1178
+ }
1179
+ if (!slug) {
1180
+ throw new Error("Could not find model in url params");
1181
+ }
1182
+ const document = useDocument(
1183
+ { documentId: origin || id, model: slug, collectionType, params },
1184
+ {
1185
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1186
+ }
1187
+ );
1188
+ const returnId = origin || id === "create" ? void 0 : id;
1189
+ return {
1190
+ collectionType,
1191
+ model: slug,
1192
+ id: returnId,
1193
+ ...document
1194
+ };
1195
+ };
1196
+ const useContentManagerContext = () => {
1197
+ const {
1198
+ collectionType,
1199
+ model,
1200
+ id,
1201
+ components,
1202
+ isLoading: isLoadingDoc,
1203
+ schema,
1204
+ schemas
1205
+ } = useDoc();
1206
+ const layout = useDocumentLayout(model);
1207
+ const form = useForm("useContentManagerContext", (state) => state);
1208
+ const isSingleType = collectionType === SINGLE_TYPES;
1209
+ const slug = model;
1210
+ const isCreatingEntry = id === "create";
1211
+ useContentTypeSchema();
1212
+ const isLoading = isLoadingDoc || layout.isLoading;
1213
+ const error = layout.error;
1214
+ return {
1215
+ error,
1216
+ isLoading,
1217
+ // Base metadata
1218
+ model,
1219
+ collectionType,
1220
+ id,
1221
+ slug,
1222
+ isCreatingEntry,
1223
+ isSingleType,
1224
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1225
+ // All schema infos
1226
+ components,
1227
+ contentType: schema,
1228
+ contentTypes: schemas,
1229
+ // Form state
1230
+ form,
1231
+ // layout infos
1232
+ layout
1233
+ };
1234
+ };
1235
+ const prefixPluginTranslations = (trad, pluginId) => {
1236
+ return Object.keys(trad).reduce((acc, current) => {
1237
+ acc[`${pluginId}.${current}`] = trad[current];
1238
+ return acc;
1239
+ }, {});
1240
+ };
1241
+ const getTranslation = (id) => `content-manager.${id}`;
1242
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1243
+ id: "notification.error",
1244
+ defaultMessage: "An error occurred, please try again"
1245
+ };
1246
+ const useDocumentActions = () => {
1247
+ const { toggleNotification } = useNotification();
1248
+ const { formatMessage } = useIntl();
1249
+ const { trackUsage } = useTracking();
1250
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1251
+ const navigate = useNavigate();
1252
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1253
+ const [deleteDocument] = useDeleteDocumentMutation();
1254
+ const _delete = React.useCallback(
1255
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1096
1256
  try {
1097
- trackUsage("willUnpublishEntry");
1098
- const res = await unpublishDocument({
1257
+ trackUsage("willDeleteEntry", trackerProperty);
1258
+ const res = await deleteDocument({
1099
1259
  collectionType,
1100
1260
  model,
1101
1261
  documentId,
1102
- params,
1103
- data: {
1104
- discardDraft
1105
- }
1262
+ params
1106
1263
  });
1107
1264
  if ("error" in res) {
1108
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1265
+ toggleNotification({
1266
+ type: "danger",
1267
+ message: formatAPIError(res.error)
1268
+ });
1109
1269
  return { error: res.error };
1110
1270
  }
1111
- trackUsage("didUnpublishEntry");
1112
1271
  toggleNotification({
1113
1272
  type: "success",
1114
1273
  message: formatMessage({
1115
- id: getTranslation("success.record.unpublish"),
1116
- defaultMessage: "Unpublished document"
1274
+ id: getTranslation("success.record.delete"),
1275
+ defaultMessage: "Deleted document"
1117
1276
  })
1118
1277
  });
1278
+ trackUsage("didDeleteEntry", trackerProperty);
1119
1279
  return res.data;
1120
1280
  } catch (err) {
1121
1281
  toggleNotification({
1122
1282
  type: "danger",
1123
1283
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1124
1284
  });
1285
+ trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
1125
1286
  throw err;
1126
1287
  }
1127
1288
  },
1128
- [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1289
+ [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
1129
1290
  );
1130
- const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1131
- const unpublishMany = React.useCallback(
1291
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1292
+ const deleteMany = React.useCallback(
1132
1293
  async ({ model, documentIds, params }) => {
1133
1294
  try {
1134
- trackUsage("willBulkUnpublishEntries");
1135
- const res = await unpublishManyDocuments({
1295
+ trackUsage("willBulkDeleteEntries");
1296
+ const res = await deleteManyDocuments({
1136
1297
  model,
1137
1298
  documentIds,
1138
1299
  params
1139
1300
  });
1140
1301
  if ("error" in res) {
1141
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1302
+ toggleNotification({
1303
+ type: "danger",
1304
+ message: formatAPIError(res.error)
1305
+ });
1142
1306
  return { error: res.error };
1143
1307
  }
1144
- trackUsage("didBulkUnpublishEntries");
1145
1308
  toggleNotification({
1146
1309
  type: "success",
1147
1310
  title: formatMessage({
1148
- id: getTranslation("success.records.unpublish"),
1149
- defaultMessage: "Successfully unpublished."
1311
+ id: getTranslation("success.records.delete"),
1312
+ defaultMessage: "Successfully deleted."
1150
1313
  }),
1151
1314
  message: ""
1152
1315
  });
1316
+ trackUsage("didBulkDeleteEntries");
1153
1317
  return res.data;
1154
1318
  } catch (err) {
1155
1319
  toggleNotification({
1156
1320
  type: "danger",
1157
1321
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1158
1322
  });
1159
- trackUsage("didNotBulkUnpublishEntries");
1323
+ trackUsage("didNotBulkDeleteEntries");
1160
1324
  throw err;
1161
1325
  }
1162
1326
  },
1163
- [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1327
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1164
1328
  );
1165
- const [createDocument] = useCreateDocumentMutation();
1166
- const create = React.useCallback(
1167
- async ({ model, params }, data, trackerProperty) => {
1329
+ const [discardDocument] = useDiscardDocumentMutation();
1330
+ const discard = React.useCallback(
1331
+ async ({ collectionType, model, documentId, params }) => {
1168
1332
  try {
1169
- const res = await createDocument({
1333
+ const res = await discardDocument({
1334
+ collectionType,
1170
1335
  model,
1171
- data,
1336
+ documentId,
1172
1337
  params
1173
1338
  });
1174
1339
  if ("error" in res) {
1175
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1176
- trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1340
+ toggleNotification({
1341
+ type: "danger",
1342
+ message: formatAPIError(res.error)
1343
+ });
1177
1344
  return { error: res.error };
1178
1345
  }
1179
- trackUsage("didCreateEntry", trackerProperty);
1180
1346
  toggleNotification({
1181
1347
  type: "success",
1182
1348
  message: formatMessage({
1183
- id: getTranslation("success.record.save"),
1349
+ id: "content-manager.success.record.discard",
1350
+ defaultMessage: "Changes discarded"
1351
+ })
1352
+ });
1353
+ return res.data;
1354
+ } catch (err) {
1355
+ toggleNotification({
1356
+ type: "danger",
1357
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1358
+ });
1359
+ throw err;
1360
+ }
1361
+ },
1362
+ [discardDocument, formatAPIError, formatMessage, toggleNotification]
1363
+ );
1364
+ const [publishDocument] = usePublishDocumentMutation();
1365
+ const publish = React.useCallback(
1366
+ async ({ collectionType, model, documentId, params }, data) => {
1367
+ try {
1368
+ trackUsage("willPublishEntry");
1369
+ const res = await publishDocument({
1370
+ collectionType,
1371
+ model,
1372
+ documentId,
1373
+ data,
1374
+ params
1375
+ });
1376
+ if ("error" in res) {
1377
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1378
+ return { error: res.error };
1379
+ }
1380
+ trackUsage("didPublishEntry");
1381
+ toggleNotification({
1382
+ type: "success",
1383
+ message: formatMessage({
1384
+ id: getTranslation("success.record.publish"),
1385
+ defaultMessage: "Published document"
1386
+ })
1387
+ });
1388
+ return res.data;
1389
+ } catch (err) {
1390
+ toggleNotification({
1391
+ type: "danger",
1392
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1393
+ });
1394
+ throw err;
1395
+ }
1396
+ },
1397
+ [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1398
+ );
1399
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1400
+ const publishMany = React.useCallback(
1401
+ async ({ model, documentIds, params }) => {
1402
+ try {
1403
+ const res = await publishManyDocuments({
1404
+ model,
1405
+ documentIds,
1406
+ params
1407
+ });
1408
+ if ("error" in res) {
1409
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1410
+ return { error: res.error };
1411
+ }
1412
+ toggleNotification({
1413
+ type: "success",
1414
+ message: formatMessage({
1415
+ id: getTranslation("success.record.publish"),
1416
+ defaultMessage: "Published document"
1417
+ })
1418
+ });
1419
+ return res.data;
1420
+ } catch (err) {
1421
+ toggleNotification({
1422
+ type: "danger",
1423
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1424
+ });
1425
+ throw err;
1426
+ }
1427
+ },
1428
+ [
1429
+ // trackUsage,
1430
+ publishManyDocuments,
1431
+ toggleNotification,
1432
+ formatMessage,
1433
+ formatAPIError
1434
+ ]
1435
+ );
1436
+ const [updateDocument] = useUpdateDocumentMutation();
1437
+ const update = React.useCallback(
1438
+ async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1439
+ try {
1440
+ trackUsage("willEditEntry", trackerProperty);
1441
+ const res = await updateDocument({
1442
+ collectionType,
1443
+ model,
1444
+ documentId,
1445
+ data,
1446
+ params
1447
+ });
1448
+ if ("error" in res) {
1449
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1450
+ trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1451
+ return { error: res.error };
1452
+ }
1453
+ trackUsage("didEditEntry", trackerProperty);
1454
+ toggleNotification({
1455
+ type: "success",
1456
+ message: formatMessage({
1457
+ id: getTranslation("success.record.save"),
1458
+ defaultMessage: "Saved document"
1459
+ })
1460
+ });
1461
+ return res.data;
1462
+ } catch (err) {
1463
+ trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1464
+ toggleNotification({
1465
+ type: "danger",
1466
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1467
+ });
1468
+ throw err;
1469
+ }
1470
+ },
1471
+ [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1472
+ );
1473
+ const [unpublishDocument] = useUnpublishDocumentMutation();
1474
+ const unpublish = React.useCallback(
1475
+ async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1476
+ try {
1477
+ trackUsage("willUnpublishEntry");
1478
+ const res = await unpublishDocument({
1479
+ collectionType,
1480
+ model,
1481
+ documentId,
1482
+ params,
1483
+ data: {
1484
+ discardDraft
1485
+ }
1486
+ });
1487
+ if ("error" in res) {
1488
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1489
+ return { error: res.error };
1490
+ }
1491
+ trackUsage("didUnpublishEntry");
1492
+ toggleNotification({
1493
+ type: "success",
1494
+ message: formatMessage({
1495
+ id: getTranslation("success.record.unpublish"),
1496
+ defaultMessage: "Unpublished document"
1497
+ })
1498
+ });
1499
+ return res.data;
1500
+ } catch (err) {
1501
+ toggleNotification({
1502
+ type: "danger",
1503
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1504
+ });
1505
+ throw err;
1506
+ }
1507
+ },
1508
+ [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1509
+ );
1510
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1511
+ const unpublishMany = React.useCallback(
1512
+ async ({ model, documentIds, params }) => {
1513
+ try {
1514
+ trackUsage("willBulkUnpublishEntries");
1515
+ const res = await unpublishManyDocuments({
1516
+ model,
1517
+ documentIds,
1518
+ params
1519
+ });
1520
+ if ("error" in res) {
1521
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1522
+ return { error: res.error };
1523
+ }
1524
+ trackUsage("didBulkUnpublishEntries");
1525
+ toggleNotification({
1526
+ type: "success",
1527
+ title: formatMessage({
1528
+ id: getTranslation("success.records.unpublish"),
1529
+ defaultMessage: "Successfully unpublished."
1530
+ }),
1531
+ message: ""
1532
+ });
1533
+ return res.data;
1534
+ } catch (err) {
1535
+ toggleNotification({
1536
+ type: "danger",
1537
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1538
+ });
1539
+ trackUsage("didNotBulkUnpublishEntries");
1540
+ throw err;
1541
+ }
1542
+ },
1543
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1544
+ );
1545
+ const [createDocument] = useCreateDocumentMutation();
1546
+ const create = React.useCallback(
1547
+ async ({ model, params }, data, trackerProperty) => {
1548
+ try {
1549
+ const res = await createDocument({
1550
+ model,
1551
+ data,
1552
+ params
1553
+ });
1554
+ if ("error" in res) {
1555
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1556
+ trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
1557
+ return { error: res.error };
1558
+ }
1559
+ trackUsage("didCreateEntry", trackerProperty);
1560
+ toggleNotification({
1561
+ type: "success",
1562
+ message: formatMessage({
1563
+ id: getTranslation("success.record.save"),
1184
1564
  defaultMessage: "Saved document"
1185
1565
  })
1186
1566
  });
1567
+ setCurrentStep("contentManager.success");
1187
1568
  return res.data;
1188
1569
  } catch (err) {
1189
1570
  toggleNotification({
@@ -1223,7 +1604,7 @@ const useDocumentActions = () => {
1223
1604
  throw err;
1224
1605
  }
1225
1606
  },
1226
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1607
+ [autoCloneDocument, formatMessage, toggleNotification]
1227
1608
  );
1228
1609
  const [cloneDocument] = useCloneDocumentMutation();
1229
1610
  const clone = React.useCallback(
@@ -1249,6 +1630,7 @@ const useDocumentActions = () => {
1249
1630
  defaultMessage: "Cloned document"
1250
1631
  })
1251
1632
  });
1633
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1252
1634
  return res.data;
1253
1635
  } catch (err) {
1254
1636
  toggleNotification({
@@ -1259,7 +1641,7 @@ const useDocumentActions = () => {
1259
1641
  throw err;
1260
1642
  }
1261
1643
  },
1262
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1644
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1263
1645
  );
1264
1646
  const [getDoc] = useLazyGetDocumentQuery();
1265
1647
  const getDocument = React.useCallback(
@@ -1284,10 +1666,10 @@ const useDocumentActions = () => {
1284
1666
  update
1285
1667
  };
1286
1668
  };
1287
- const ProtectedHistoryPage = lazy(
1288
- () => import("./History-Cq_Hrzuu.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1669
+ const ProtectedHistoryPage = React.lazy(
1670
+ () => import("./History-CIQHyi4T.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1289
1671
  );
1290
- const routes$1 = [
1672
+ const routes$2 = [
1291
1673
  {
1292
1674
  path: ":collectionType/:slug/:id/history",
1293
1675
  Component: ProtectedHistoryPage
@@ -1297,32 +1679,45 @@ const routes$1 = [
1297
1679
  Component: ProtectedHistoryPage
1298
1680
  }
1299
1681
  ];
1682
+ const ProtectedPreviewPage = React.lazy(
1683
+ () => import("./Preview-BVFFm7uB.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1684
+ );
1685
+ const routes$1 = [
1686
+ {
1687
+ path: ":collectionType/:slug/:id/preview",
1688
+ Component: ProtectedPreviewPage
1689
+ },
1690
+ {
1691
+ path: ":collectionType/:slug/preview",
1692
+ Component: ProtectedPreviewPage
1693
+ }
1694
+ ];
1300
1695
  const ProtectedEditViewPage = lazy(
1301
- () => import("./EditViewPage-C3tIZ8F5.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1696
+ () => import("./EditViewPage-CD_hqc1J.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1302
1697
  );
1303
1698
  const ProtectedListViewPage = lazy(
1304
- () => import("./ListViewPage-HBBnJa8K.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1699
+ () => import("./ListViewPage-C10McTK1.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1305
1700
  );
1306
1701
  const ProtectedListConfiguration = lazy(
1307
- () => import("./ListConfigurationPage-W-KQHmBv.mjs").then((mod) => ({
1702
+ () => import("./ListConfigurationPage-DcZsfyEL.mjs").then((mod) => ({
1308
1703
  default: mod.ProtectedListConfiguration
1309
1704
  }))
1310
1705
  );
1311
1706
  const ProtectedEditConfigurationPage = lazy(
1312
- () => import("./EditConfigurationPage-13b7S5Cq.mjs").then((mod) => ({
1707
+ () => import("./EditConfigurationPage-BNjOAHNS.mjs").then((mod) => ({
1313
1708
  default: mod.ProtectedEditConfigurationPage
1314
1709
  }))
1315
1710
  );
1316
1711
  const ProtectedComponentConfigurationPage = lazy(
1317
- () => import("./ComponentConfigurationPage-D0dyDTwq.mjs").then((mod) => ({
1712
+ () => import("./ComponentConfigurationPage-BgCLcjXO.mjs").then((mod) => ({
1318
1713
  default: mod.ProtectedComponentConfigurationPage
1319
1714
  }))
1320
1715
  );
1321
1716
  const NoPermissions = lazy(
1322
- () => import("./NoPermissionsPage-XhOPl8wx.mjs").then((mod) => ({ default: mod.NoPermissions }))
1717
+ () => import("./NoPermissionsPage-wfPBh2_0.mjs").then((mod) => ({ default: mod.NoPermissions }))
1323
1718
  );
1324
1719
  const NoContentType = lazy(
1325
- () => import("./NoContentTypePage-B-gIhHWM.mjs").then((mod) => ({ default: mod.NoContentType }))
1720
+ () => import("./NoContentTypePage-CPc0Cd3S.mjs").then((mod) => ({ default: mod.NoContentType }))
1326
1721
  );
1327
1722
  const CollectionTypePages = () => {
1328
1723
  const { collectionType } = useParams();
@@ -1334,7 +1729,7 @@ const CollectionTypePages = () => {
1334
1729
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1335
1730
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1336
1731
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1337
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1732
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1338
1733
  const routes = [
1339
1734
  {
1340
1735
  path: LIST_RELATIVE_PATH,
@@ -1368,6 +1763,7 @@ const routes = [
1368
1763
  path: "no-content-types",
1369
1764
  Component: NoContentType
1370
1765
  },
1766
+ ...routes$2,
1371
1767
  ...routes$1
1372
1768
  ];
1373
1769
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1442,6 +1838,8 @@ const DocumentActionButton = (action) => {
1442
1838
  onClick: handleClick(action),
1443
1839
  justifyContent: "center",
1444
1840
  variant: action.variant || "default",
1841
+ paddingTop: "7px",
1842
+ paddingBottom: "7px",
1445
1843
  children: action.label
1446
1844
  }
1447
1845
  ),
@@ -1464,6 +1862,11 @@ const DocumentActionButton = (action) => {
1464
1862
  ) : null
1465
1863
  ] });
1466
1864
  };
1865
+ const MenuItem = styled(Menu.Item)`
1866
+ &:hover {
1867
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1868
+ }
1869
+ `;
1467
1870
  const DocumentActionsMenu = ({
1468
1871
  actions: actions2,
1469
1872
  children,
@@ -1519,44 +1922,35 @@ const DocumentActionsMenu = ({
1519
1922
  ]
1520
1923
  }
1521
1924
  ),
1522
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1925
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1523
1926
  actions2.map((action) => {
1524
1927
  return /* @__PURE__ */ jsx(
1525
- Menu.Item,
1928
+ MenuItem,
1526
1929
  {
1527
1930
  disabled: action.disabled,
1528
1931
  onSelect: handleClick(action),
1529
1932
  display: "block",
1530
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1531
- /* @__PURE__ */ jsxs(
1532
- Flex,
1533
- {
1534
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1535
- gap: 2,
1536
- tag: "span",
1537
- children: [
1538
- /* @__PURE__ */ jsx("span", { children: action.icon }),
1539
- action.label
1540
- ]
1541
- }
1542
- ),
1543
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1544
- Flex,
1545
- {
1546
- alignItems: "center",
1547
- background: "alternative100",
1548
- borderStyle: "solid",
1549
- borderColor: "alternative200",
1550
- borderWidth: "1px",
1551
- height: 5,
1552
- paddingLeft: 2,
1553
- paddingRight: 2,
1554
- hasRadius: true,
1555
- color: "alternative600",
1556
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1557
- }
1558
- )
1559
- ] })
1933
+ isVariantDanger: action.variant === "danger",
1934
+ isDisabled: action.disabled,
1935
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
1936
+ Flex,
1937
+ {
1938
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1939
+ gap: 2,
1940
+ tag: "span",
1941
+ children: [
1942
+ /* @__PURE__ */ jsx(
1943
+ Flex,
1944
+ {
1945
+ tag: "span",
1946
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1947
+ children: action.icon
1948
+ }
1949
+ ),
1950
+ action.label
1951
+ ]
1952
+ }
1953
+ ) })
1560
1954
  },
1561
1955
  action.id
1562
1956
  );
@@ -1598,6 +1992,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1598
1992
  return "primary600";
1599
1993
  }
1600
1994
  };
1995
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1996
+ switch (variant) {
1997
+ case "danger":
1998
+ return "danger600";
1999
+ case "secondary":
2000
+ return "neutral500";
2001
+ case "success":
2002
+ return "success600";
2003
+ default:
2004
+ return "primary600";
2005
+ }
2006
+ };
1601
2007
  const DocumentActionConfirmDialog = ({
1602
2008
  onClose,
1603
2009
  onCancel,
@@ -1624,11 +2030,11 @@ const DocumentActionConfirmDialog = ({
1624
2030
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1625
2031
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1626
2032
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1627
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
2033
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1628
2034
  id: "app.components.Button.cancel",
1629
2035
  defaultMessage: "Cancel"
1630
2036
  }) }) }),
1631
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
2037
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1632
2038
  id: "app.components.Button.confirm",
1633
2039
  defaultMessage: "Confirm"
1634
2040
  }) })
@@ -1655,6 +2061,18 @@ const DocumentActionModal = ({
1655
2061
  typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1656
2062
  ] }) });
1657
2063
  };
2064
+ const transformData = (data) => {
2065
+ if (Array.isArray(data)) {
2066
+ return data.map(transformData);
2067
+ }
2068
+ if (typeof data === "object" && data !== null) {
2069
+ if ("apiData" in data) {
2070
+ return data.apiData;
2071
+ }
2072
+ return mapValues(transformData)(data);
2073
+ }
2074
+ return data;
2075
+ };
1658
2076
  const PublishAction$1 = ({
1659
2077
  activeTab,
1660
2078
  documentId,
@@ -1667,12 +2085,11 @@ const PublishAction$1 = ({
1667
2085
  const navigate = useNavigate();
1668
2086
  const { toggleNotification } = useNotification();
1669
2087
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
2088
+ const isListView = useMatch(LIST_PATH) !== null;
1670
2089
  const isCloning = useMatch(CLONE_PATH) !== null;
2090
+ const { id } = useParams();
1671
2091
  const { formatMessage } = useIntl();
1672
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1673
- "PublishAction",
1674
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1675
- );
2092
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1676
2093
  const { publish } = useDocumentActions();
1677
2094
  const [
1678
2095
  countDraftRelations,
@@ -1724,32 +2141,35 @@ const PublishAction$1 = ({
1724
2141
  }
1725
2142
  }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1726
2143
  React.useEffect(() => {
1727
- if (documentId) {
1728
- const fetchDraftRelationsCount = async () => {
1729
- const { data, error } = await countDraftRelations({
1730
- collectionType,
1731
- model,
1732
- documentId,
1733
- params
1734
- });
1735
- if (error) {
1736
- throw error;
1737
- }
1738
- if (data) {
1739
- setServerCountOfDraftRelations(data.data);
1740
- }
1741
- };
1742
- fetchDraftRelationsCount();
2144
+ if (!document || !document.documentId || isListView) {
2145
+ return;
1743
2146
  }
1744
- }, [documentId, countDraftRelations, collectionType, model, params]);
1745
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
2147
+ const fetchDraftRelationsCount = async () => {
2148
+ const { data, error } = await countDraftRelations({
2149
+ collectionType,
2150
+ model,
2151
+ documentId,
2152
+ params
2153
+ });
2154
+ if (error) {
2155
+ throw error;
2156
+ }
2157
+ if (data) {
2158
+ setServerCountOfDraftRelations(data.data);
2159
+ }
2160
+ };
2161
+ fetchDraftRelationsCount();
2162
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
2163
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1746
2164
  if (!schema?.options?.draftAndPublish) {
1747
2165
  return null;
1748
2166
  }
1749
2167
  const performPublish = async () => {
1750
2168
  setSubmitting(true);
1751
2169
  try {
1752
- const { errors } = await validate();
2170
+ const { errors } = await validate(true, {
2171
+ status: "published"
2172
+ });
1753
2173
  if (errors) {
1754
2174
  toggleNotification({
1755
2175
  type: "danger",
@@ -1767,13 +2187,15 @@ const PublishAction$1 = ({
1767
2187
  documentId,
1768
2188
  params
1769
2189
  },
1770
- formValues
2190
+ transformData(formValues)
1771
2191
  );
1772
2192
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1773
- navigate({
1774
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1775
- search: rawQuery
1776
- });
2193
+ if (id === "create") {
2194
+ navigate({
2195
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2196
+ search: rawQuery
2197
+ });
2198
+ }
1777
2199
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1778
2200
  setErrors(formatValidationErrors(res.error));
1779
2201
  }
@@ -1782,7 +2204,8 @@ const PublishAction$1 = ({
1782
2204
  }
1783
2205
  };
1784
2206
  const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1785
- const hasDraftRelations = totalDraftRelations > 0;
2207
+ const enableDraftRelationsCount = false;
2208
+ const hasDraftRelations = enableDraftRelationsCount;
1786
2209
  return {
1787
2210
  /**
1788
2211
  * Disabled when:
@@ -1799,9 +2222,6 @@ const PublishAction$1 = ({
1799
2222
  defaultMessage: "Publish"
1800
2223
  }),
1801
2224
  onClick: async () => {
1802
- if (hasDraftRelations) {
1803
- return;
1804
- }
1805
2225
  await performPublish();
1806
2226
  },
1807
2227
  dialog: hasDraftRelations ? {
@@ -1840,10 +2260,6 @@ const UpdateAction = ({
1840
2260
  const cloneMatch = useMatch(CLONE_PATH);
1841
2261
  const isCloning = cloneMatch !== null;
1842
2262
  const { formatMessage } = useIntl();
1843
- useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1844
- canCreate: canCreate2,
1845
- canUpdate: canUpdate2
1846
- }));
1847
2263
  const { create, update, clone } = useDocumentActions();
1848
2264
  const [{ query, rawQuery }] = useQueryParams();
1849
2265
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1863,13 +2279,15 @@ const UpdateAction = ({
1863
2279
  */
1864
2280
  disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1865
2281
  label: formatMessage({
1866
- id: "content-manager.containers.Edit.save",
2282
+ id: "global.save",
1867
2283
  defaultMessage: "Save"
1868
2284
  }),
1869
2285
  onClick: async () => {
1870
2286
  setSubmitting(true);
1871
2287
  try {
1872
- const { errors } = await validate();
2288
+ const { errors } = await validate(true, {
2289
+ status: "draft"
2290
+ });
1873
2291
  if (errors) {
1874
2292
  toggleNotification({
1875
2293
  type: "danger",
@@ -1887,7 +2305,7 @@ const UpdateAction = ({
1887
2305
  documentId: cloneMatch.params.origin,
1888
2306
  params
1889
2307
  },
1890
- document
2308
+ transformData(document)
1891
2309
  );
1892
2310
  if ("data" in res) {
1893
2311
  navigate(
@@ -1908,7 +2326,7 @@ const UpdateAction = ({
1908
2326
  documentId,
1909
2327
  params
1910
2328
  },
1911
- document
2329
+ transformData(document)
1912
2330
  );
1913
2331
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1914
2332
  setErrors(formatValidationErrors(res.error));
@@ -1921,7 +2339,7 @@ const UpdateAction = ({
1921
2339
  model,
1922
2340
  params
1923
2341
  },
1924
- document
2342
+ transformData(document)
1925
2343
  );
1926
2344
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1927
2345
  navigate(
@@ -1974,7 +2392,7 @@ const UnpublishAction$1 = ({
1974
2392
  id: "app.utils.unpublish",
1975
2393
  defaultMessage: "Unpublish"
1976
2394
  }),
1977
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2395
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1978
2396
  onClick: async () => {
1979
2397
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1980
2398
  if (!documentId) {
@@ -2086,7 +2504,7 @@ const DiscardAction = ({
2086
2504
  id: "content-manager.actions.discard.label",
2087
2505
  defaultMessage: "Discard changes"
2088
2506
  }),
2089
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2507
+ icon: /* @__PURE__ */ jsx(Cross, {}),
2090
2508
  position: ["panel", "table-row"],
2091
2509
  variant: "danger",
2092
2510
  dialog: {
@@ -2114,11 +2532,6 @@ const DiscardAction = ({
2114
2532
  };
2115
2533
  };
2116
2534
  DiscardAction.type = "discard";
2117
- const StyledCrossCircle = styled(CrossCircle)`
2118
- path {
2119
- fill: currentColor;
2120
- }
2121
- `;
2122
2535
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2123
2536
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2124
2537
  const RelativeTime = React.forwardRef(
@@ -2131,7 +2544,7 @@ const RelativeTime = React.forwardRef(
2131
2544
  });
2132
2545
  const unit = intervals.find((intervalUnit) => {
2133
2546
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2134
- });
2547
+ }) ?? "seconds";
2135
2548
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2136
2549
  const customInterval = customIntervals.find(
2137
2550
  (custom) => interval[custom.unit] < custom.threshold
@@ -2165,19 +2578,29 @@ const getDisplayName = ({
2165
2578
  return email ?? "";
2166
2579
  };
2167
2580
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2168
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2169
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2170
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2581
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2582
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2583
+ const { formatMessage } = useIntl();
2584
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2585
+ id: `content-manager.containers.List.${status}`,
2586
+ defaultMessage: capitalise(status)
2587
+ }) }) });
2171
2588
  };
2172
2589
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2173
2590
  const { formatMessage } = useIntl();
2174
2591
  const isCloning = useMatch(CLONE_PATH) !== null;
2592
+ const params = useParams();
2175
2593
  const title = isCreating ? formatMessage({
2176
2594
  id: "content-manager.containers.edit.title.new",
2177
2595
  defaultMessage: "Create an entry"
2178
2596
  }) : documentTitle;
2179
2597
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2180
- /* @__PURE__ */ jsx(BackButton, {}),
2598
+ /* @__PURE__ */ jsx(
2599
+ BackButton,
2600
+ {
2601
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2602
+ }
2603
+ ),
2181
2604
  /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2182
2605
  /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2183
2606
  /* @__PURE__ */ jsx(HeaderToolbar, {})
@@ -2265,12 +2688,12 @@ const Information = ({ activeTab }) => {
2265
2688
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2266
2689
  label: formatMessage({
2267
2690
  id: "content-manager.containers.edit.information.last-published.label",
2268
- defaultMessage: "Last published"
2691
+ defaultMessage: "Published"
2269
2692
  }),
2270
2693
  value: formatMessage(
2271
2694
  {
2272
2695
  id: "content-manager.containers.edit.information.last-published.value",
2273
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2696
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2274
2697
  },
2275
2698
  {
2276
2699
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2283,12 +2706,12 @@ const Information = ({ activeTab }) => {
2283
2706
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2284
2707
  label: formatMessage({
2285
2708
  id: "content-manager.containers.edit.information.last-draft.label",
2286
- defaultMessage: "Last draft"
2709
+ defaultMessage: "Updated"
2287
2710
  }),
2288
2711
  value: formatMessage(
2289
2712
  {
2290
2713
  id: "content-manager.containers.edit.information.last-draft.value",
2291
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2714
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2292
2715
  },
2293
2716
  {
2294
2717
  time: /* @__PURE__ */ jsx(
@@ -2306,12 +2729,12 @@ const Information = ({ activeTab }) => {
2306
2729
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2307
2730
  label: formatMessage({
2308
2731
  id: "content-manager.containers.edit.information.document.label",
2309
- defaultMessage: "Document"
2732
+ defaultMessage: "Created"
2310
2733
  }),
2311
2734
  value: formatMessage(
2312
2735
  {
2313
2736
  id: "content-manager.containers.edit.information.document.value",
2314
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2737
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2315
2738
  },
2316
2739
  {
2317
2740
  time: /* @__PURE__ */ jsx(
@@ -2349,25 +2772,77 @@ const Information = ({ activeTab }) => {
2349
2772
  );
2350
2773
  };
2351
2774
  const HeaderActions = ({ actions: actions2 }) => {
2352
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2353
- if ("options" in action) {
2775
+ const [dialogId, setDialogId] = React.useState(null);
2776
+ const handleClick = (action) => async (e) => {
2777
+ if (!("options" in action)) {
2778
+ const { onClick = () => false, dialog, id } = action;
2779
+ const muteDialog = await onClick(e);
2780
+ if (dialog && !muteDialog) {
2781
+ e.preventDefault();
2782
+ setDialogId(id);
2783
+ }
2784
+ }
2785
+ };
2786
+ const handleClose = () => {
2787
+ setDialogId(null);
2788
+ };
2789
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2790
+ if (action.options) {
2354
2791
  return /* @__PURE__ */ jsx(
2355
2792
  SingleSelect,
2356
2793
  {
2357
2794
  size: "S",
2358
- disabled: action.disabled,
2359
- "aria-label": action.label,
2360
2795
  onChange: action.onSelect,
2361
- value: action.value,
2796
+ "aria-label": action.label,
2797
+ ...action,
2362
2798
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2363
2799
  },
2364
2800
  action.id
2365
2801
  );
2366
2802
  } else {
2367
- return null;
2803
+ if (action.type === "icon") {
2804
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2805
+ /* @__PURE__ */ jsx(
2806
+ IconButton,
2807
+ {
2808
+ disabled: action.disabled,
2809
+ label: action.label,
2810
+ size: "S",
2811
+ onClick: handleClick(action),
2812
+ children: action.icon
2813
+ }
2814
+ ),
2815
+ action.dialog ? /* @__PURE__ */ jsx(
2816
+ HeaderActionDialog,
2817
+ {
2818
+ ...action.dialog,
2819
+ isOpen: dialogId === action.id,
2820
+ onClose: handleClose
2821
+ }
2822
+ ) : null
2823
+ ] }, action.id);
2824
+ }
2368
2825
  }
2369
2826
  }) });
2370
2827
  };
2828
+ const HeaderActionDialog = ({
2829
+ onClose,
2830
+ onCancel,
2831
+ title,
2832
+ content: Content,
2833
+ isOpen
2834
+ }) => {
2835
+ const handleClose = async () => {
2836
+ if (onCancel) {
2837
+ await onCancel();
2838
+ }
2839
+ onClose();
2840
+ };
2841
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2842
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2843
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2844
+ ] }) });
2845
+ };
2371
2846
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2372
2847
  const navigate = useNavigate();
2373
2848
  const { formatMessage } = useIntl();
@@ -2408,12 +2883,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2408
2883
  const { delete: deleteAction } = useDocumentActions();
2409
2884
  const { toggleNotification } = useNotification();
2410
2885
  const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2886
+ const isLocalized = document?.locale != null;
2411
2887
  return {
2412
2888
  disabled: !canDelete || !document,
2413
- label: formatMessage({
2414
- id: "content-manager.actions.delete.label",
2415
- defaultMessage: "Delete document"
2416
- }),
2889
+ label: formatMessage(
2890
+ {
2891
+ id: "content-manager.actions.delete.label",
2892
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2893
+ },
2894
+ { isLocalized }
2895
+ ),
2417
2896
  icon: /* @__PURE__ */ jsx(Trash, {}),
2418
2897
  dialog: {
2419
2898
  type: "dialog",
@@ -2453,419 +2932,117 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2453
2932
  params: {
2454
2933
  locale: "*"
2455
2934
  }
2456
- });
2457
- if (!("error" in res)) {
2458
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2459
- }
2460
- } finally {
2461
- if (!listViewPathMatch) {
2462
- setSubmitting(false);
2463
- }
2464
- }
2465
- }
2466
- },
2467
- variant: "danger",
2468
- position: ["header", "table-row"]
2469
- };
2470
- };
2471
- DeleteAction$1.type = "delete";
2472
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2473
- const Panels = () => {
2474
- const isCloning = useMatch(CLONE_PATH) !== null;
2475
- const [
2476
- {
2477
- query: { status }
2478
- }
2479
- ] = useQueryParams({
2480
- status: "draft"
2481
- });
2482
- const { model, id, document, meta, collectionType } = useDoc();
2483
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2484
- const props = {
2485
- activeTab: status,
2486
- model,
2487
- documentId: id,
2488
- document: isCloning ? void 0 : document,
2489
- meta: isCloning ? void 0 : meta,
2490
- collectionType
2491
- };
2492
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2493
- DescriptionComponentRenderer,
2494
- {
2495
- props,
2496
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2497
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2498
- }
2499
- ) });
2500
- };
2501
- const ActionsPanel = () => {
2502
- const { formatMessage } = useIntl();
2503
- return {
2504
- title: formatMessage({
2505
- id: "content-manager.containers.edit.panels.default.title",
2506
- defaultMessage: "Document"
2507
- }),
2508
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2509
- };
2510
- };
2511
- ActionsPanel.type = "actions";
2512
- const ActionsPanelContent = () => {
2513
- const isCloning = useMatch(CLONE_PATH) !== null;
2514
- const [
2515
- {
2516
- query: { status = "draft" }
2517
- }
2518
- ] = useQueryParams();
2519
- const { model, id, document, meta, collectionType } = useDoc();
2520
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2521
- const props = {
2522
- activeTab: status,
2523
- model,
2524
- documentId: id,
2525
- document: isCloning ? void 0 : document,
2526
- meta: isCloning ? void 0 : meta,
2527
- collectionType
2528
- };
2529
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2530
- /* @__PURE__ */ jsx(
2531
- DescriptionComponentRenderer,
2532
- {
2533
- props,
2534
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2535
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2536
- }
2537
- ),
2538
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2539
- ] });
2540
- };
2541
- const Panel = React.forwardRef(({ children, title }, ref) => {
2542
- return /* @__PURE__ */ jsxs(
2543
- Flex,
2544
- {
2545
- ref,
2546
- tag: "aside",
2547
- "aria-labelledby": "additional-information",
2548
- background: "neutral0",
2549
- borderColor: "neutral150",
2550
- hasRadius: true,
2551
- paddingBottom: 4,
2552
- paddingLeft: 4,
2553
- paddingRight: 4,
2554
- paddingTop: 4,
2555
- shadow: "tableShadow",
2556
- gap: 3,
2557
- direction: "column",
2558
- justifyContent: "stretch",
2559
- alignItems: "flex-start",
2560
- children: [
2561
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2562
- children
2563
- ]
2564
- }
2565
- );
2566
- });
2567
- const HOOKS = {
2568
- /**
2569
- * Hook that allows to mutate the displayed headers of the list view table
2570
- * @constant
2571
- * @type {string}
2572
- */
2573
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2574
- /**
2575
- * Hook that allows to mutate the CM's collection types links pre-set filters
2576
- * @constant
2577
- * @type {string}
2578
- */
2579
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2580
- /**
2581
- * Hook that allows to mutate the CM's edit view layout
2582
- * @constant
2583
- * @type {string}
2584
- */
2585
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2586
- /**
2587
- * Hook that allows to mutate the CM's single types links pre-set filters
2588
- * @constant
2589
- * @type {string}
2590
- */
2591
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2592
- };
2593
- const contentTypesApi = contentManagerApi.injectEndpoints({
2594
- endpoints: (builder) => ({
2595
- getContentTypeConfiguration: builder.query({
2596
- query: (uid) => ({
2597
- url: `/content-manager/content-types/${uid}/configuration`,
2598
- method: "GET"
2599
- }),
2600
- transformResponse: (response) => response.data,
2601
- providesTags: (_result, _error, uid) => [
2602
- { type: "ContentTypesConfiguration", id: uid },
2603
- { type: "ContentTypeSettings", id: "LIST" }
2604
- ]
2605
- }),
2606
- getAllContentTypeSettings: builder.query({
2607
- query: () => "/content-manager/content-types-settings",
2608
- transformResponse: (response) => response.data,
2609
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2610
- }),
2611
- updateContentTypeConfiguration: builder.mutation({
2612
- query: ({ uid, ...body }) => ({
2613
- url: `/content-manager/content-types/${uid}/configuration`,
2614
- method: "PUT",
2615
- data: body
2616
- }),
2617
- transformResponse: (response) => response.data,
2618
- invalidatesTags: (_result, _error, { uid }) => [
2619
- { type: "ContentTypesConfiguration", id: uid },
2620
- { type: "ContentTypeSettings", id: "LIST" },
2621
- // Is this necessary?
2622
- { type: "InitialData" }
2623
- ]
2624
- })
2625
- })
2626
- });
2627
- const {
2628
- useGetContentTypeConfigurationQuery,
2629
- useGetAllContentTypeSettingsQuery,
2630
- useUpdateContentTypeConfigurationMutation
2631
- } = contentTypesApi;
2632
- const checkIfAttributeIsDisplayable = (attribute) => {
2633
- const { type } = attribute;
2634
- if (type === "relation") {
2635
- return !attribute.relation.toLowerCase().includes("morph");
2636
- }
2637
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2638
- };
2639
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2640
- if (!mainFieldName) {
2641
- return void 0;
2642
- }
2643
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2644
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2645
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2646
- );
2647
- return {
2648
- name: mainFieldName,
2649
- type: mainFieldType ?? "string"
2650
- };
2651
- };
2652
- const DEFAULT_SETTINGS = {
2653
- bulkable: false,
2654
- filterable: false,
2655
- searchable: false,
2656
- pagination: false,
2657
- defaultSortBy: "",
2658
- defaultSortOrder: "asc",
2659
- mainField: "id",
2660
- pageSize: 10
2661
- };
2662
- const useDocumentLayout = (model) => {
2663
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2664
- const [{ query }] = useQueryParams();
2665
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2666
- const { toggleNotification } = useNotification();
2667
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2668
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2669
- const {
2670
- data,
2671
- isLoading: isLoadingConfigs,
2672
- error,
2673
- isFetching: isFetchingConfigs
2674
- } = useGetContentTypeConfigurationQuery(model);
2675
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2676
- React.useEffect(() => {
2677
- if (error) {
2678
- toggleNotification({
2679
- type: "danger",
2680
- message: formatAPIError(error)
2681
- });
2682
- }
2683
- }, [error, formatAPIError, toggleNotification]);
2684
- const editLayout = React.useMemo(
2685
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2686
- layout: [],
2687
- components: {},
2688
- metadatas: {},
2689
- options: {},
2690
- settings: DEFAULT_SETTINGS
2691
- },
2692
- [data, isLoading, schemas, schema, components]
2693
- );
2694
- const listLayout = React.useMemo(() => {
2695
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2696
- layout: [],
2697
- metadatas: {},
2698
- options: {},
2699
- settings: DEFAULT_SETTINGS
2700
- };
2701
- }, [data, isLoading, schemas, schema, components]);
2702
- const { layout: edit } = React.useMemo(
2703
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2704
- layout: editLayout,
2705
- query
2706
- }),
2707
- [editLayout, query, runHookWaterfall]
2708
- );
2709
- return {
2710
- error,
2711
- isLoading,
2712
- edit,
2713
- list: listLayout
2714
- };
2715
- };
2716
- const useDocLayout = () => {
2717
- const { model } = useDoc();
2718
- return useDocumentLayout(model);
2719
- };
2720
- const formatEditLayout = (data, {
2721
- schemas,
2722
- schema,
2723
- components
2724
- }) => {
2725
- let currentPanelIndex = 0;
2726
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2727
- data.contentType.layouts.edit,
2728
- schema?.attributes,
2729
- data.contentType.metadatas,
2730
- { configurations: data.components, schemas: components },
2731
- schemas
2732
- ).reduce((panels, row) => {
2733
- if (row.some((field) => field.type === "dynamiczone")) {
2734
- panels.push([row]);
2735
- currentPanelIndex += 2;
2736
- } else {
2737
- if (!panels[currentPanelIndex]) {
2738
- panels.push([]);
2739
- }
2740
- panels[currentPanelIndex].push(row);
2741
- }
2742
- return panels;
2743
- }, []);
2744
- const componentEditAttributes = Object.entries(data.components).reduce(
2745
- (acc, [uid, configuration]) => {
2746
- acc[uid] = {
2747
- layout: convertEditLayoutToFieldLayouts(
2748
- configuration.layouts.edit,
2749
- components[uid].attributes,
2750
- configuration.metadatas
2751
- ),
2752
- settings: {
2753
- ...configuration.settings,
2754
- icon: components[uid].info.icon,
2755
- displayName: components[uid].info.displayName
2935
+ });
2936
+ if (!("error" in res)) {
2937
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2938
+ }
2939
+ } finally {
2940
+ if (!listViewPathMatch) {
2941
+ setSubmitting(false);
2942
+ }
2756
2943
  }
2757
- };
2758
- return acc;
2759
- },
2760
- {}
2761
- );
2762
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2763
- (acc, [attribute, metadata]) => {
2764
- return {
2765
- ...acc,
2766
- [attribute]: metadata.edit
2767
- };
2768
- },
2769
- {}
2770
- );
2771
- return {
2772
- layout: panelledEditAttributes,
2773
- components: componentEditAttributes,
2774
- metadatas: editMetadatas,
2775
- settings: {
2776
- ...data.contentType.settings,
2777
- displayName: schema?.info.displayName
2944
+ }
2778
2945
  },
2779
- options: {
2780
- ...schema?.options,
2781
- ...schema?.pluginOptions,
2782
- ...data.contentType.options
2783
- }
2946
+ variant: "danger",
2947
+ position: ["header", "table-row"]
2784
2948
  };
2785
2949
  };
2786
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2787
- return rows.map(
2788
- (row) => row.map((field) => {
2789
- const attribute = attributes[field.name];
2790
- if (!attribute) {
2791
- return null;
2792
- }
2793
- const { edit: metadata } = metadatas[field.name];
2794
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2795
- return {
2796
- attribute,
2797
- disabled: !metadata.editable,
2798
- hint: metadata.description,
2799
- label: metadata.label ?? "",
2800
- name: field.name,
2801
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2802
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2803
- schemas,
2804
- components: components?.schemas ?? {}
2805
- }),
2806
- placeholder: metadata.placeholder ?? "",
2807
- required: attribute.required ?? false,
2808
- size: field.size,
2809
- unique: "unique" in attribute ? attribute.unique : false,
2810
- visible: metadata.visible ?? true,
2811
- type: attribute.type
2812
- };
2813
- }).filter((field) => field !== null)
2814
- );
2950
+ DeleteAction$1.type = "delete";
2951
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2952
+ const Panels = () => {
2953
+ const isCloning = useMatch(CLONE_PATH) !== null;
2954
+ const [
2955
+ {
2956
+ query: { status }
2957
+ }
2958
+ ] = useQueryParams({
2959
+ status: "draft"
2960
+ });
2961
+ const { model, id, document, meta, collectionType } = useDoc();
2962
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
2963
+ const props = {
2964
+ activeTab: status,
2965
+ model,
2966
+ documentId: id,
2967
+ document: isCloning ? void 0 : document,
2968
+ meta: isCloning ? void 0 : meta,
2969
+ collectionType
2970
+ };
2971
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2972
+ DescriptionComponentRenderer,
2973
+ {
2974
+ props,
2975
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2976
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2977
+ }
2978
+ ) });
2815
2979
  };
2816
- const formatListLayout = (data, {
2817
- schemas,
2818
- schema,
2819
- components
2820
- }) => {
2821
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2822
- (acc, [attribute, metadata]) => {
2823
- return {
2824
- ...acc,
2825
- [attribute]: metadata.list
2826
- };
2827
- },
2828
- {}
2829
- );
2830
- const listAttributes = convertListLayoutToFieldLayouts(
2831
- data.contentType.layouts.list,
2832
- schema?.attributes,
2833
- listMetadatas,
2834
- { configurations: data.components, schemas: components },
2835
- schemas
2836
- );
2980
+ const ActionsPanel = () => {
2981
+ const { formatMessage } = useIntl();
2837
2982
  return {
2838
- layout: listAttributes,
2839
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2840
- metadatas: listMetadatas,
2841
- options: {
2842
- ...schema?.options,
2843
- ...schema?.pluginOptions,
2844
- ...data.contentType.options
2845
- }
2983
+ title: formatMessage({
2984
+ id: "content-manager.containers.edit.panels.default.title",
2985
+ defaultMessage: "Entry"
2986
+ }),
2987
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2846
2988
  };
2847
2989
  };
2848
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2849
- return columns.map((name) => {
2850
- const attribute = attributes[name];
2851
- if (!attribute) {
2852
- return null;
2990
+ ActionsPanel.type = "actions";
2991
+ const ActionsPanelContent = () => {
2992
+ const isCloning = useMatch(CLONE_PATH) !== null;
2993
+ const [
2994
+ {
2995
+ query: { status = "draft" }
2853
2996
  }
2854
- const metadata = metadatas[name];
2855
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2856
- return {
2857
- attribute,
2858
- label: metadata.label ?? "",
2859
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2860
- schemas,
2861
- components: components?.schemas ?? {}
2862
- }),
2863
- name,
2864
- searchable: metadata.searchable ?? true,
2865
- sortable: metadata.sortable ?? true
2866
- };
2867
- }).filter((field) => field !== null);
2997
+ ] = useQueryParams();
2998
+ const { model, id, document, meta, collectionType } = useDoc();
2999
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
3000
+ const props = {
3001
+ activeTab: status,
3002
+ model,
3003
+ documentId: id,
3004
+ document: isCloning ? void 0 : document,
3005
+ meta: isCloning ? void 0 : meta,
3006
+ collectionType
3007
+ };
3008
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3009
+ /* @__PURE__ */ jsx(
3010
+ DescriptionComponentRenderer,
3011
+ {
3012
+ props,
3013
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3014
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3015
+ }
3016
+ ),
3017
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3018
+ ] });
2868
3019
  };
3020
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3021
+ return /* @__PURE__ */ jsxs(
3022
+ Flex,
3023
+ {
3024
+ ref,
3025
+ tag: "aside",
3026
+ "aria-labelledby": "additional-information",
3027
+ background: "neutral0",
3028
+ borderColor: "neutral150",
3029
+ hasRadius: true,
3030
+ paddingBottom: 4,
3031
+ paddingLeft: 4,
3032
+ paddingRight: 4,
3033
+ paddingTop: 4,
3034
+ shadow: "tableShadow",
3035
+ gap: 3,
3036
+ direction: "column",
3037
+ justifyContent: "stretch",
3038
+ alignItems: "flex-start",
3039
+ children: [
3040
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3041
+ children
3042
+ ]
3043
+ }
3044
+ );
3045
+ });
2869
3046
  const ConfirmBulkActionDialog = ({
2870
3047
  onToggleDialog,
2871
3048
  isOpen = false,
@@ -2904,6 +3081,7 @@ const ConfirmDialogPublishAll = ({
2904
3081
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2905
3082
  const { model, schema } = useDoc();
2906
3083
  const [{ query }] = useQueryParams();
3084
+ const enableDraftRelationsCount = false;
2907
3085
  const {
2908
3086
  data: countDraftRelations = 0,
2909
3087
  isLoading,
@@ -2915,7 +3093,7 @@ const ConfirmDialogPublishAll = ({
2915
3093
  locale: query?.plugins?.i18n?.locale
2916
3094
  },
2917
3095
  {
2918
- skip: selectedEntries.length === 0
3096
+ skip: !enableDraftRelationsCount
2919
3097
  }
2920
3098
  );
2921
3099
  React.useEffect(() => {
@@ -3100,7 +3278,7 @@ const SelectedEntriesTableContent = ({
3100
3278
  status: row.status
3101
3279
  }
3102
3280
  ) }),
3103
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3281
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3104
3282
  IconButton,
3105
3283
  {
3106
3284
  tag: Link,
@@ -3109,23 +3287,16 @@ const SelectedEntriesTableContent = ({
3109
3287
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3110
3288
  },
3111
3289
  state: { from: pathname },
3112
- label: formatMessage(
3113
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3114
- {
3115
- target: formatMessage(
3116
- {
3117
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3118
- defaultMessage: "item line {number}"
3119
- },
3120
- { number: index2 + 1 }
3121
- )
3122
- }
3123
- ),
3290
+ label: formatMessage({
3291
+ id: "content-manager.bulk-publish.edit",
3292
+ defaultMessage: "Edit"
3293
+ }),
3124
3294
  target: "_blank",
3125
3295
  marginLeft: "auto",
3126
- children: /* @__PURE__ */ jsx(Pencil, {})
3296
+ variant: "ghost",
3297
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3127
3298
  }
3128
- ) })
3299
+ ) }) })
3129
3300
  ] }, row.id)) })
3130
3301
  ] });
3131
3302
  };
@@ -3162,7 +3333,13 @@ const SelectedEntriesModalContent = ({
3162
3333
  );
3163
3334
  const { rows, validationErrors } = React.useMemo(() => {
3164
3335
  if (data.length > 0 && schema) {
3165
- const validate = createYupSchema(schema.attributes, components);
3336
+ const validate = createYupSchema(
3337
+ schema.attributes,
3338
+ components,
3339
+ // Since this is the "Publish" action, the validation
3340
+ // schema must enforce the rules for published entities
3341
+ { status: "published" }
3342
+ );
3166
3343
  const validationErrors2 = {};
3167
3344
  const rows2 = data.map((entry) => {
3168
3345
  try {
@@ -3287,8 +3464,7 @@ const PublishAction = ({ documents, model }) => {
3287
3464
  const refetchList = () => {
3288
3465
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3289
3466
  };
3290
- if (!showPublishButton)
3291
- return null;
3467
+ if (!showPublishButton) return null;
3292
3468
  return {
3293
3469
  actionType: "publish",
3294
3470
  variant: "tertiary",
@@ -3356,8 +3532,7 @@ const DeleteAction = ({ documents, model }) => {
3356
3532
  selectRow([]);
3357
3533
  }
3358
3534
  };
3359
- if (!hasDeletePermission)
3360
- return null;
3535
+ if (!hasDeletePermission) return null;
3361
3536
  return {
3362
3537
  variant: "danger-light",
3363
3538
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3406,8 +3581,7 @@ const UnpublishAction = ({ documents, model }) => {
3406
3581
  }
3407
3582
  };
3408
3583
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3409
- if (!showUnpublishButton)
3410
- return null;
3584
+ if (!showUnpublishButton) return null;
3411
3585
  return {
3412
3586
  variant: "tertiary",
3413
3587
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3512,7 +3686,7 @@ const TableActions = ({ document }) => {
3512
3686
  DescriptionComponentRenderer,
3513
3687
  {
3514
3688
  props,
3515
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3689
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3516
3690
  children: (actions2) => {
3517
3691
  const tableRowActions = actions2.filter((action) => {
3518
3692
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3623,7 +3797,7 @@ const CloneAction = ({ model, documentId }) => {
3623
3797
  }),
3624
3798
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3625
3799
  footer: ({ onClose }) => {
3626
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3800
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3627
3801
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3628
3802
  id: "cancel",
3629
3803
  defaultMessage: "Cancel"
@@ -3743,10 +3917,8 @@ class ContentManagerPlugin {
3743
3917
  const getPrintableType = (value) => {
3744
3918
  const nativeType = typeof value;
3745
3919
  if (nativeType === "object") {
3746
- if (value === null)
3747
- return "null";
3748
- if (Array.isArray(value))
3749
- return "array";
3920
+ if (value === null) return "null";
3921
+ if (Array.isArray(value)) return "array";
3750
3922
  if (value instanceof Object && value.constructor.name !== "Object") {
3751
3923
  return value.constructor.name;
3752
3924
  }
@@ -3757,17 +3929,27 @@ const HistoryAction = ({ model, document }) => {
3757
3929
  const { formatMessage } = useIntl();
3758
3930
  const [{ query }] = useQueryParams();
3759
3931
  const navigate = useNavigate();
3932
+ const { trackUsage } = useTracking();
3933
+ const { pathname } = useLocation();
3760
3934
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3761
3935
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3762
3936
  return null;
3763
3937
  }
3938
+ const handleOnClick = () => {
3939
+ const destination = { pathname: "history", search: pluginsQueryParams };
3940
+ trackUsage("willNavigate", {
3941
+ from: pathname,
3942
+ to: `${pathname}/${destination.pathname}`
3943
+ });
3944
+ navigate(destination);
3945
+ };
3764
3946
  return {
3765
3947
  icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3766
3948
  label: formatMessage({
3767
3949
  id: "content-manager.history.document-action",
3768
3950
  defaultMessage: "Content History"
3769
3951
  }),
3770
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3952
+ onClick: handleOnClick,
3771
3953
  disabled: (
3772
3954
  /**
3773
3955
  * The user is creating a new document.
@@ -3835,6 +4017,90 @@ const { setInitialData } = actions;
3835
4017
  const reducer = combineReducers({
3836
4018
  app: reducer$1
3837
4019
  });
4020
+ const previewApi = contentManagerApi.injectEndpoints({
4021
+ endpoints: (builder) => ({
4022
+ getPreviewUrl: builder.query({
4023
+ query({ query, params }) {
4024
+ return {
4025
+ url: `/content-manager/preview/url/${params.contentType}`,
4026
+ method: "GET",
4027
+ config: {
4028
+ params: query
4029
+ }
4030
+ };
4031
+ }
4032
+ })
4033
+ })
4034
+ });
4035
+ const { useGetPreviewUrlQuery } = previewApi;
4036
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4037
+ if (isShown) {
4038
+ return /* @__PURE__ */ jsx(Tooltip, { label, children });
4039
+ }
4040
+ return children;
4041
+ };
4042
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4043
+ const { formatMessage } = useIntl();
4044
+ const { trackUsage } = useTracking();
4045
+ const { pathname } = useLocation();
4046
+ const [{ query }] = useQueryParams();
4047
+ const isModified = useForm("PreviewSidePanel", (state) => state.modified);
4048
+ const { data, error } = useGetPreviewUrlQuery({
4049
+ params: {
4050
+ contentType: model
4051
+ },
4052
+ query: {
4053
+ documentId,
4054
+ locale: document?.locale,
4055
+ status: document?.status
4056
+ }
4057
+ });
4058
+ if (!data?.data?.url || error) {
4059
+ return null;
4060
+ }
4061
+ const trackNavigation = () => {
4062
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4063
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4064
+ };
4065
+ return {
4066
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4067
+ content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
4068
+ ConditionalTooltip,
4069
+ {
4070
+ label: formatMessage({
4071
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4072
+ defaultMessage: "Please save to open the preview"
4073
+ }),
4074
+ isShown: isModified,
4075
+ children: /* @__PURE__ */ jsx(
4076
+ Button,
4077
+ {
4078
+ variant: "tertiary",
4079
+ tag: Link,
4080
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4081
+ onClick: trackNavigation,
4082
+ flex: "auto",
4083
+ disabled: isModified,
4084
+ children: formatMessage({
4085
+ id: "content-manager.preview.panel.button",
4086
+ defaultMessage: "Open preview"
4087
+ })
4088
+ }
4089
+ )
4090
+ }
4091
+ ) })
4092
+ };
4093
+ };
4094
+ const FEATURE_ID = "preview";
4095
+ const previewAdmin = {
4096
+ bootstrap(app) {
4097
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4098
+ return;
4099
+ }
4100
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4101
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4102
+ }
4103
+ };
3838
4104
  const index = {
3839
4105
  register(app) {
3840
4106
  const cm = new ContentManagerPlugin();
@@ -3854,7 +4120,7 @@ const index = {
3854
4120
  app.router.addRoute({
3855
4121
  path: "content-manager/*",
3856
4122
  lazy: async () => {
3857
- const { Layout } = await import("./layout-C0INpKap.mjs");
4123
+ const { Layout } = await import("./layout-qE8qkNH_.mjs");
3858
4124
  return {
3859
4125
  Component: Layout
3860
4126
  };
@@ -3867,11 +4133,14 @@ const index = {
3867
4133
  if (typeof historyAdmin.bootstrap === "function") {
3868
4134
  historyAdmin.bootstrap(app);
3869
4135
  }
4136
+ if (typeof previewAdmin.bootstrap === "function") {
4137
+ previewAdmin.bootstrap(app);
4138
+ }
3870
4139
  },
3871
4140
  async registerTrads({ locales }) {
3872
4141
  const importedTrads = await Promise.all(
3873
4142
  locales.map((locale) => {
3874
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-BrCTWlZv.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4143
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Dtk_ot79.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
3875
4144
  return {
3876
4145
  data: prefixPluginTranslations(data, PLUGIN_ID),
3877
4146
  locale
@@ -3892,13 +4161,16 @@ export {
3892
4161
  BulkActionsRenderer as B,
3893
4162
  COLLECTION_TYPES as C,
3894
4163
  DocumentStatus as D,
3895
- DEFAULT_SETTINGS as E,
3896
- convertEditLayoutToFieldLayouts as F,
3897
- useDocument as G,
4164
+ extractContentTypeComponents as E,
4165
+ DEFAULT_SETTINGS as F,
4166
+ convertEditLayoutToFieldLayouts as G,
3898
4167
  HOOKS as H,
3899
4168
  InjectionZone as I,
3900
- index as J,
3901
- useDocumentActions as K,
4169
+ useDocument as J,
4170
+ useGetPreviewUrlQuery as K,
4171
+ index as L,
4172
+ useContentManagerContext as M,
4173
+ useDocumentActions as N,
3902
4174
  Panels as P,
3903
4175
  RelativeTime as R,
3904
4176
  SINGLE_TYPES as S,
@@ -3916,18 +4188,18 @@ export {
3916
4188
  PERMISSIONS as k,
3917
4189
  DocumentRBAC as l,
3918
4190
  DOCUMENT_META_FIELDS as m,
3919
- useDocLayout as n,
3920
- useGetContentTypeConfigurationQuery as o,
3921
- CREATOR_FIELDS as p,
3922
- getMainField as q,
3923
- getDisplayName as r,
4191
+ CLONE_PATH as n,
4192
+ useDocLayout as o,
4193
+ useGetContentTypeConfigurationQuery as p,
4194
+ CREATOR_FIELDS as q,
4195
+ getMainField as r,
3924
4196
  setInitialData as s,
3925
- checkIfAttributeIsDisplayable as t,
4197
+ getDisplayName as t,
3926
4198
  useContentTypeSchema as u,
3927
- useGetAllDocumentsQuery as v,
3928
- convertListLayoutToFieldLayouts as w,
3929
- capitalise as x,
3930
- useUpdateContentTypeConfigurationMutation as y,
3931
- extractContentTypeComponents as z
4199
+ checkIfAttributeIsDisplayable as v,
4200
+ useGetAllDocumentsQuery as w,
4201
+ convertListLayoutToFieldLayouts as x,
4202
+ capitalise as y,
4203
+ useUpdateContentTypeConfigurationMutation as z
3932
4204
  };
3933
- //# sourceMappingURL=index-Dpxg3ctD.mjs.map
4205
+ //# sourceMappingURL=index-DLIkNVnQ.mjs.map