@strapi/content-manager 0.0.0-experimental.da85533897155e719d784f0271223c866d2f69ab → 0.0.0-experimental.dad3c50630ca4fd9eccdcbe549ee632fc572e23d

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-DyDkPajU.js → ComponentConfigurationPage-BLWQy8ru.js} +5 -6
  4. package/dist/_chunks/{ComponentConfigurationPage-DyDkPajU.js.map → ComponentConfigurationPage-BLWQy8ru.js.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-9lRmRdIr.mjs → ComponentConfigurationPage-CtIa3aa2.mjs} +4 -4
  6. package/dist/_chunks/{ComponentConfigurationPage-9lRmRdIr.mjs.map → ComponentConfigurationPage-CtIa3aa2.mjs.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-Bk893vVY.mjs → EditConfigurationPage-DsPR2DVk.mjs} +4 -4
  11. package/dist/_chunks/{EditConfigurationPage-Bk893vVY.mjs.map → EditConfigurationPage-DsPR2DVk.mjs.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-DValmA0m.js → EditConfigurationPage-RQkymxCy.js} +5 -6
  13. package/dist/_chunks/{EditConfigurationPage-DValmA0m.js.map → EditConfigurationPage-RQkymxCy.js.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-Dk7Eaft4.js → EditViewPage-B-kExt8C.js} +50 -11
  15. package/dist/_chunks/EditViewPage-B-kExt8C.js.map +1 -0
  16. package/dist/_chunks/{EditViewPage-DiNFdFqP.mjs → EditViewPage-BPyVuPfM.mjs} +50 -10
  17. package/dist/_chunks/EditViewPage-BPyVuPfM.mjs.map +1 -0
  18. package/dist/_chunks/{Field-DH2OaqUP.js → Field-DPIsQRre.js} +250 -161
  19. package/dist/_chunks/Field-DPIsQRre.js.map +1 -0
  20. package/dist/_chunks/{Field-Dv_HTFTa.mjs → Field-Dltnt1km.mjs} +244 -155
  21. package/dist/_chunks/Field-Dltnt1km.mjs.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-B_dUDizM.js → Form-BFi4MXMT.js} +19 -12
  25. package/dist/_chunks/Form-BFi4MXMT.js.map +1 -0
  26. package/dist/_chunks/{Form-Dy6P4HgH.mjs → Form-C1IcWm1u.mjs} +17 -9
  27. package/dist/_chunks/Form-C1IcWm1u.mjs.map +1 -0
  28. package/dist/_chunks/{History-DrwsD1Vc.mjs → History-04ChQ4pl.mjs} +71 -104
  29. package/dist/_chunks/History-04ChQ4pl.mjs.map +1 -0
  30. package/dist/_chunks/{History-BT4w83Oa.js → History-wjcK4L0C.js} +70 -104
  31. package/dist/_chunks/History-wjcK4L0C.js.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-BxIP0jRy.mjs → ListConfigurationPage-BYqPYLSU.mjs} +7 -6
  33. package/dist/_chunks/ListConfigurationPage-BYqPYLSU.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-CuYrMcW3.js → ListConfigurationPage-CRbxIC3J.js} +7 -7
  35. package/dist/_chunks/ListConfigurationPage-CRbxIC3J.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-BvpwNur7.js → ListViewPage-D5NY9183.js} +88 -54
  37. package/dist/_chunks/ListViewPage-D5NY9183.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-5a1vw-OK.mjs → ListViewPage-FU2LBuhl.mjs} +83 -48
  39. package/dist/_chunks/ListViewPage-FU2LBuhl.mjs.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-UqEiWKkM.js → NoContentTypePage-BgQVE_Qb.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-UqEiWKkM.js.map → NoContentTypePage-BgQVE_Qb.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-Bm6tRcd3.mjs → NoContentTypePage-DCKUkwb8.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-Bm6tRcd3.mjs.map → NoContentTypePage-DCKUkwb8.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-C_vGRo8Q.js → NoPermissionsPage-C5jwn70o.js} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-C_vGRo8Q.js.map → NoPermissionsPage-C5jwn70o.js.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-BHPqn_tQ.mjs → NoPermissionsPage-jqve7C8l.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-BHPqn_tQ.mjs.map → NoPermissionsPage-jqve7C8l.mjs.map} +1 -1
  48. package/dist/_chunks/Preview-BMYN548c.mjs +294 -0
  49. package/dist/_chunks/Preview-BMYN548c.mjs.map +1 -0
  50. package/dist/_chunks/Preview-DaOihysv.js +312 -0
  51. package/dist/_chunks/Preview-DaOihysv.js.map +1 -0
  52. package/dist/_chunks/{Relations-CznVF6LS.js → Relations-CTGM7Hv5.js} +75 -42
  53. package/dist/_chunks/Relations-CTGM7Hv5.js.map +1 -0
  54. package/dist/_chunks/{Relations-C7fPyh5P.mjs → Relations-gscPkxjF.mjs} +75 -41
  55. package/dist/_chunks/Relations-gscPkxjF.mjs.map +1 -0
  56. package/dist/_chunks/{en-otD_UBJi.js → en-BzQmavmK.js} +32 -14
  57. package/dist/_chunks/{en-otD_UBJi.js.map → en-BzQmavmK.js.map} +1 -1
  58. package/dist/_chunks/{en-CbaIuYoB.mjs → en-CSxLmrh1.mjs} +32 -14
  59. package/dist/_chunks/{en-CbaIuYoB.mjs.map → en-CSxLmrh1.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-D9UmmBcM.js → index-Ca7YWlAA.js} +1063 -754
  70. package/dist/_chunks/index-Ca7YWlAA.js.map +1 -0
  71. package/dist/_chunks/{index-BJ6uTqLL.mjs → index-DqasUQ6Q.mjs} +1066 -757
  72. package/dist/_chunks/index-DqasUQ6Q.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-kfu5Wtix.js → layout-BW80JSCd.js} +7 -7
  78. package/dist/_chunks/{layout-kfu5Wtix.js.map → layout-BW80JSCd.js.map} +1 -1
  79. package/dist/_chunks/{layout-uomiIGbG.mjs → layout-W3clJSCy.mjs} +6 -5
  80. package/dist/_chunks/{layout-uomiIGbG.mjs.map → layout-W3clJSCy.mjs.map} +1 -1
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-DiDufGSA.mjs → relations-BlDkoeWh.mjs} +6 -7
  86. package/dist/_chunks/relations-BlDkoeWh.mjs.map +1 -0
  87. package/dist/_chunks/{relations-DKENrxko.js → relations-C9Usz9k5.js} +6 -7
  88. package/dist/_chunks/relations-C9Usz9k5.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 +3 -1
  98. package/dist/admin/index.js.map +1 -1
  99. package/dist/admin/index.mjs +5 -3
  100. package/dist/admin/src/content-manager.d.ts +3 -2
  101. package/dist/admin/src/exports.d.ts +2 -1
  102. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  103. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  104. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  105. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  106. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  107. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  108. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  109. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  110. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  111. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  112. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  113. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  114. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  115. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  116. package/dist/admin/src/preview/index.d.ts +4 -0
  117. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  118. package/dist/admin/src/preview/routes.d.ts +3 -0
  119. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  120. package/dist/admin/src/router.d.ts +1 -1
  121. package/dist/admin/src/services/api.d.ts +1 -1
  122. package/dist/admin/src/services/components.d.ts +2 -2
  123. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  124. package/dist/admin/src/services/documents.d.ts +19 -20
  125. package/dist/admin/src/services/init.d.ts +1 -1
  126. package/dist/admin/src/services/relations.d.ts +2 -2
  127. package/dist/admin/src/services/uid.d.ts +3 -3
  128. package/dist/server/index.js +594 -335
  129. package/dist/server/index.js.map +1 -1
  130. package/dist/server/index.mjs +595 -335
  131. package/dist/server/index.mjs.map +1 -1
  132. package/dist/server/src/bootstrap.d.ts.map +1 -1
  133. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  134. package/dist/server/src/controllers/index.d.ts.map +1 -1
  135. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  136. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  137. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  138. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  139. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  140. package/dist/server/src/history/services/history.d.ts +3 -3
  141. package/dist/server/src/history/services/history.d.ts.map +1 -1
  142. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  143. package/dist/server/src/history/services/utils.d.ts +6 -11
  144. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  145. package/dist/server/src/index.d.ts +7 -6
  146. package/dist/server/src/index.d.ts.map +1 -1
  147. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  148. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  149. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  150. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  151. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  152. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  153. package/dist/server/src/preview/index.d.ts +4 -0
  154. package/dist/server/src/preview/index.d.ts.map +1 -0
  155. package/dist/server/src/preview/routes/index.d.ts +8 -0
  156. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  157. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  158. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  159. package/dist/server/src/preview/services/index.d.ts +16 -0
  160. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  161. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  162. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  163. package/dist/server/src/preview/services/preview.d.ts +12 -0
  164. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  165. package/dist/server/src/preview/utils.d.ts +19 -0
  166. package/dist/server/src/preview/utils.d.ts.map +1 -0
  167. package/dist/server/src/register.d.ts.map +1 -1
  168. package/dist/server/src/routes/index.d.ts.map +1 -1
  169. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  170. package/dist/server/src/services/document-metadata.d.ts +12 -10
  171. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  172. package/dist/server/src/services/index.d.ts +7 -6
  173. package/dist/server/src/services/index.d.ts.map +1 -1
  174. package/dist/server/src/services/utils/populate.d.ts +2 -2
  175. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  176. package/dist/server/src/utils/index.d.ts +2 -0
  177. package/dist/server/src/utils/index.d.ts.map +1 -1
  178. package/dist/shared/contracts/collection-types.d.ts +3 -1
  179. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  180. package/dist/shared/contracts/index.d.ts +1 -0
  181. package/dist/shared/contracts/index.d.ts.map +1 -1
  182. package/dist/shared/contracts/preview.d.ts +27 -0
  183. package/dist/shared/contracts/preview.d.ts.map +1 -0
  184. package/dist/shared/index.js +4 -0
  185. package/dist/shared/index.js.map +1 -1
  186. package/dist/shared/index.mjs +4 -0
  187. package/dist/shared/index.mjs.map +1 -1
  188. package/package.json +17 -15
  189. package/dist/_chunks/EditViewPage-DiNFdFqP.mjs.map +0 -1
  190. package/dist/_chunks/EditViewPage-Dk7Eaft4.js.map +0 -1
  191. package/dist/_chunks/Field-DH2OaqUP.js.map +0 -1
  192. package/dist/_chunks/Field-Dv_HTFTa.mjs.map +0 -1
  193. package/dist/_chunks/Form-B_dUDizM.js.map +0 -1
  194. package/dist/_chunks/Form-Dy6P4HgH.mjs.map +0 -1
  195. package/dist/_chunks/History-BT4w83Oa.js.map +0 -1
  196. package/dist/_chunks/History-DrwsD1Vc.mjs.map +0 -1
  197. package/dist/_chunks/ListConfigurationPage-BxIP0jRy.mjs.map +0 -1
  198. package/dist/_chunks/ListConfigurationPage-CuYrMcW3.js.map +0 -1
  199. package/dist/_chunks/ListViewPage-5a1vw-OK.mjs.map +0 -1
  200. package/dist/_chunks/ListViewPage-BvpwNur7.js.map +0 -1
  201. package/dist/_chunks/Relations-C7fPyh5P.mjs.map +0 -1
  202. package/dist/_chunks/Relations-CznVF6LS.js.map +0 -1
  203. package/dist/_chunks/index-BJ6uTqLL.mjs.map +0 -1
  204. package/dist/_chunks/index-D9UmmBcM.js.map +0 -1
  205. package/dist/_chunks/relations-DKENrxko.js.map +0 -1
  206. package/dist/_chunks/relations-DiDufGSA.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
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) : [];
@@ -159,7 +175,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
159
175
  "InitialData",
160
176
  "HistoryVersion",
161
177
  "Relations",
162
- "UidAvailability"
178
+ "UidAvailability",
179
+ "RecentDocumentList"
163
180
  ]
164
181
  });
165
182
  const documentApi = contentManagerApi.injectEndpoints({
@@ -177,7 +194,7 @@ const documentApi = contentManagerApi.injectEndpoints({
177
194
  if (error) {
178
195
  return [];
179
196
  }
180
- return [{ type: "Document", id: `${model}_LIST` }];
197
+ return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
181
198
  }
182
199
  }),
183
200
  cloneDocument: builder.mutation({
@@ -191,7 +208,8 @@ const documentApi = contentManagerApi.injectEndpoints({
191
208
  }),
192
209
  invalidatesTags: (_result, _error, { model }) => [
193
210
  { type: "Document", id: `${model}_LIST` },
194
- { type: "UidAvailability", id: model }
211
+ { type: "UidAvailability", id: model },
212
+ "RecentDocumentList"
195
213
  ]
196
214
  }),
197
215
  /**
@@ -210,8 +228,21 @@ const documentApi = contentManagerApi.injectEndpoints({
210
228
  invalidatesTags: (result, _error, { model }) => [
211
229
  { type: "Document", id: `${model}_LIST` },
212
230
  "Relations",
213
- { type: "UidAvailability", id: model }
214
- ]
231
+ { type: "UidAvailability", id: model },
232
+ "RecentDocumentList"
233
+ ],
234
+ transformResponse: (response, meta, arg) => {
235
+ if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
236
+ return {
237
+ data: response,
238
+ meta: {
239
+ availableStatus: [],
240
+ availableLocales: []
241
+ }
242
+ };
243
+ }
244
+ return response;
245
+ }
215
246
  }),
216
247
  deleteDocument: builder.mutation({
217
248
  query: ({ collectionType, model, documentId, params }) => ({
@@ -222,7 +253,8 @@ const documentApi = contentManagerApi.injectEndpoints({
222
253
  }
223
254
  }),
224
255
  invalidatesTags: (_result, _error, { collectionType, model }) => [
225
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
256
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
257
+ "RecentDocumentList"
226
258
  ]
227
259
  }),
228
260
  deleteManyDocuments: builder.mutation({
@@ -234,7 +266,10 @@ const documentApi = contentManagerApi.injectEndpoints({
234
266
  params
235
267
  }
236
268
  }),
237
- invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
269
+ invalidatesTags: (_res, _error, { model }) => [
270
+ { type: "Document", id: `${model}_LIST` },
271
+ "RecentDocumentList"
272
+ ]
238
273
  }),
239
274
  discardDocument: builder.mutation({
240
275
  query: ({ collectionType, model, documentId, params }) => ({
@@ -252,7 +287,8 @@ const documentApi = contentManagerApi.injectEndpoints({
252
287
  },
253
288
  { type: "Document", id: `${model}_LIST` },
254
289
  "Relations",
255
- { type: "UidAvailability", id: model }
290
+ { type: "UidAvailability", id: model },
291
+ "RecentDocumentList"
256
292
  ];
257
293
  }
258
294
  }),
@@ -265,7 +301,7 @@ const documentApi = contentManagerApi.injectEndpoints({
265
301
  url: `/content-manager/collection-types/${model}`,
266
302
  method: "GET",
267
303
  config: {
268
- params
304
+ params: stringify(params, { encode: true })
269
305
  }
270
306
  }),
271
307
  providesTags: (result, _error, arg) => {
@@ -347,7 +383,8 @@ const documentApi = contentManagerApi.injectEndpoints({
347
383
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
348
384
  },
349
385
  { type: "Document", id: `${model}_LIST` },
350
- "Relations"
386
+ "Relations",
387
+ "RecentDocumentList"
351
388
  ];
352
389
  }
353
390
  }),
@@ -378,7 +415,9 @@ const documentApi = contentManagerApi.injectEndpoints({
378
415
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
379
416
  },
380
417
  "Relations",
381
- { type: "UidAvailability", id: model }
418
+ { type: "UidAvailability", id: model },
419
+ "RecentDocumentList",
420
+ "RecentDocumentList"
382
421
  ];
383
422
  },
384
423
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -408,7 +447,8 @@ const documentApi = contentManagerApi.injectEndpoints({
408
447
  {
409
448
  type: "Document",
410
449
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
411
- }
450
+ },
451
+ "RecentDocumentList"
412
452
  ];
413
453
  }
414
454
  }),
@@ -421,7 +461,10 @@ const documentApi = contentManagerApi.injectEndpoints({
421
461
  params
422
462
  }
423
463
  }),
424
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
464
+ invalidatesTags: (_res, _error, { model, documentIds }) => [
465
+ ...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
466
+ "RecentDocumentList"
467
+ ]
425
468
  })
426
469
  })
427
470
  });
@@ -444,8 +487,7 @@ const {
444
487
  useUnpublishManyDocumentsMutation
445
488
  } = documentApi;
446
489
  const buildValidParams = (query) => {
447
- if (!query)
448
- return query;
490
+ if (!query) return query;
449
491
  const { plugins: _, ...validQueryParams } = {
450
492
  ...query,
451
493
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -453,14 +495,29 @@ const buildValidParams = (query) => {
453
495
  {}
454
496
  )
455
497
  };
456
- if ("_q" in validQueryParams) {
457
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
458
- }
459
498
  return validQueryParams;
460
499
  };
461
500
  const isBaseQueryError = (error) => {
462
501
  return error.name !== void 0;
463
502
  };
503
+ const arrayValidator = (attribute, options) => ({
504
+ message: translatedErrors.required,
505
+ test(value) {
506
+ if (options.status === "draft") {
507
+ return true;
508
+ }
509
+ if (!attribute.required) {
510
+ return true;
511
+ }
512
+ if (!value) {
513
+ return false;
514
+ }
515
+ if (Array.isArray(value) && value.length === 0) {
516
+ return false;
517
+ }
518
+ return true;
519
+ }
520
+ });
464
521
  const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
465
522
  const createModelSchema = (attributes2) => yup.object().shape(
466
523
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -468,6 +525,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
468
525
  return acc;
469
526
  }
470
527
  const validations = [
528
+ addNullableValidation,
471
529
  addRequiredValidation,
472
530
  addMinLengthValidation,
473
531
  addMaxLengthValidation,
@@ -484,12 +542,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
484
542
  ...acc,
485
543
  [name]: transformSchema(
486
544
  yup.array().of(createModelSchema(attributes3).nullable(false))
487
- )
545
+ ).test(arrayValidator(attribute, options))
488
546
  };
489
547
  } else {
490
548
  return {
491
549
  ...acc,
492
- [name]: transformSchema(createModelSchema(attributes3))
550
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
493
551
  };
494
552
  }
495
553
  }
@@ -511,7 +569,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
511
569
  }
512
570
  )
513
571
  )
514
- )
572
+ ).test(arrayValidator(attribute, options))
515
573
  };
516
574
  case "relation":
517
575
  return {
@@ -523,7 +581,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
523
581
  } else if (Array.isArray(value)) {
524
582
  return yup.array().of(
525
583
  yup.object().shape({
526
- id: yup.string().required()
584
+ id: yup.number().required()
527
585
  })
528
586
  );
529
587
  } else if (typeof value === "object") {
@@ -609,17 +667,17 @@ const nullableSchema = (schema) => {
609
667
  schema
610
668
  );
611
669
  };
670
+ const addNullableValidation = () => (schema) => {
671
+ return nullableSchema(schema);
672
+ };
612
673
  const addRequiredValidation = (attribute, options) => (schema) => {
613
- if (options.status === "draft") {
614
- return nullableSchema(schema);
615
- }
616
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
617
- return schema.min(1, translatedErrors.required);
674
+ if (options.status === "draft" || !attribute.required) {
675
+ return schema;
618
676
  }
619
- if (attribute.required && attribute.type !== "relation") {
677
+ if (attribute.required && "required" in schema) {
620
678
  return schema.required(translatedErrors.required);
621
679
  }
622
- return nullableSchema(schema);
680
+ return schema;
623
681
  };
624
682
  const addMinLengthValidation = (attribute, options) => (schema) => {
625
683
  if (options.status === "draft") {
@@ -647,31 +705,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
647
705
  return schema;
648
706
  };
649
707
  const addMinValidation = (attribute, options) => (schema) => {
650
- if ("min" in attribute) {
708
+ if (options.status === "draft") {
709
+ return schema;
710
+ }
711
+ if ("min" in attribute && "min" in schema) {
651
712
  const min = toInteger(attribute.min);
652
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
653
- if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
654
- return schema.test(
655
- "custom-min",
656
- {
657
- ...translatedErrors.min,
658
- values: {
659
- min: attribute.min
660
- }
661
- },
662
- (value) => {
663
- if (!value) {
664
- return true;
665
- }
666
- if (Array.isArray(value) && value.length === 0) {
667
- return true;
668
- }
669
- return value.length >= min;
670
- }
671
- );
672
- }
673
- }
674
- if ("min" in schema && min) {
713
+ if (min) {
675
714
  return schema.min(min, {
676
715
  ...translatedErrors.min,
677
716
  values: {
@@ -789,19 +828,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
789
828
  }, {});
790
829
  return componentsByKey;
791
830
  };
792
- const useDocument = (args, opts) => {
831
+ const HOOKS = {
832
+ /**
833
+ * Hook that allows to mutate the displayed headers of the list view table
834
+ * @constant
835
+ * @type {string}
836
+ */
837
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
838
+ /**
839
+ * Hook that allows to mutate the CM's collection types links pre-set filters
840
+ * @constant
841
+ * @type {string}
842
+ */
843
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
844
+ /**
845
+ * Hook that allows to mutate the CM's edit view layout
846
+ * @constant
847
+ * @type {string}
848
+ */
849
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
850
+ /**
851
+ * Hook that allows to mutate the CM's single types links pre-set filters
852
+ * @constant
853
+ * @type {string}
854
+ */
855
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
856
+ };
857
+ const contentTypesApi = contentManagerApi.injectEndpoints({
858
+ endpoints: (builder) => ({
859
+ getContentTypeConfiguration: builder.query({
860
+ query: (uid) => ({
861
+ url: `/content-manager/content-types/${uid}/configuration`,
862
+ method: "GET"
863
+ }),
864
+ transformResponse: (response) => response.data,
865
+ providesTags: (_result, _error, uid) => [
866
+ { type: "ContentTypesConfiguration", id: uid },
867
+ { type: "ContentTypeSettings", id: "LIST" }
868
+ ]
869
+ }),
870
+ getAllContentTypeSettings: builder.query({
871
+ query: () => "/content-manager/content-types-settings",
872
+ transformResponse: (response) => response.data,
873
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
874
+ }),
875
+ updateContentTypeConfiguration: builder.mutation({
876
+ query: ({ uid, ...body }) => ({
877
+ url: `/content-manager/content-types/${uid}/configuration`,
878
+ method: "PUT",
879
+ data: body
880
+ }),
881
+ transformResponse: (response) => response.data,
882
+ invalidatesTags: (_result, _error, { uid }) => [
883
+ { type: "ContentTypesConfiguration", id: uid },
884
+ { type: "ContentTypeSettings", id: "LIST" },
885
+ // Is this necessary?
886
+ { type: "InitialData" }
887
+ ]
888
+ })
889
+ })
890
+ });
891
+ const {
892
+ useGetContentTypeConfigurationQuery,
893
+ useGetAllContentTypeSettingsQuery,
894
+ useUpdateContentTypeConfigurationMutation
895
+ } = contentTypesApi;
896
+ const checkIfAttributeIsDisplayable = (attribute) => {
897
+ const { type } = attribute;
898
+ if (type === "relation") {
899
+ return !attribute.relation.toLowerCase().includes("morph");
900
+ }
901
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
902
+ };
903
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
904
+ if (!mainFieldName) {
905
+ return void 0;
906
+ }
907
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
908
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
909
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
910
+ );
911
+ return {
912
+ name: mainFieldName,
913
+ type: mainFieldType ?? "string"
914
+ };
915
+ };
916
+ const DEFAULT_SETTINGS = {
917
+ bulkable: false,
918
+ filterable: false,
919
+ searchable: false,
920
+ pagination: false,
921
+ defaultSortBy: "",
922
+ defaultSortOrder: "asc",
923
+ mainField: "id",
924
+ pageSize: 10
925
+ };
926
+ const useDocumentLayout = (model) => {
927
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
928
+ const [{ query }] = useQueryParams();
929
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
793
930
  const { toggleNotification } = useNotification();
794
931
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
932
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
795
933
  const {
796
- currentData: data,
797
- isLoading: isLoadingDocument,
798
- isFetching: isFetchingDocument,
799
- error
800
- } = useGetDocumentQuery(args, {
801
- ...opts,
802
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
803
- });
804
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
934
+ data,
935
+ isLoading: isLoadingConfigs,
936
+ error,
937
+ isFetching: isFetchingConfigs
938
+ } = useGetContentTypeConfigurationQuery(model);
939
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
805
940
  React.useEffect(() => {
806
941
  if (error) {
807
942
  toggleNotification({
@@ -809,84 +944,339 @@ const useDocument = (args, opts) => {
809
944
  message: formatAPIError(error)
810
945
  });
811
946
  }
812
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
813
- const validationSchema = React.useMemo(() => {
814
- if (!schema) {
815
- return null;
816
- }
817
- return createYupSchema(schema.attributes, components);
818
- }, [schema, components]);
819
- const validate = React.useCallback(
820
- (document) => {
821
- if (!validationSchema) {
822
- throw new Error(
823
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
824
- );
825
- }
826
- try {
827
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
828
- return null;
829
- } catch (error2) {
830
- if (error2 instanceof ValidationError) {
831
- return getYupValidationErrors(error2);
832
- }
833
- throw error2;
834
- }
947
+ }, [error, formatAPIError, toggleNotification]);
948
+ const editLayout = React.useMemo(
949
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
950
+ layout: [],
951
+ components: {},
952
+ metadatas: {},
953
+ options: {},
954
+ settings: DEFAULT_SETTINGS
835
955
  },
836
- [validationSchema]
956
+ [data, isLoading, schemas, schema, components]
957
+ );
958
+ const listLayout = React.useMemo(() => {
959
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
960
+ layout: [],
961
+ metadatas: {},
962
+ options: {},
963
+ settings: DEFAULT_SETTINGS
964
+ };
965
+ }, [data, isLoading, schemas, schema, components]);
966
+ const { layout: edit } = React.useMemo(
967
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
968
+ layout: editLayout,
969
+ query
970
+ }),
971
+ [editLayout, query, runHookWaterfall]
837
972
  );
838
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
839
973
  return {
840
- components,
841
- document: data?.data,
842
- meta: data?.meta,
974
+ error,
843
975
  isLoading,
844
- schema,
845
- validate
846
- };
847
- };
848
- const useDoc = () => {
849
- const { id, slug, collectionType, origin } = useParams();
850
- const [{ query }] = useQueryParams();
851
- const params = React.useMemo(() => buildValidParams(query), [query]);
852
- if (!collectionType) {
853
- throw new Error("Could not find collectionType in url params");
854
- }
855
- if (!slug) {
856
- throw new Error("Could not find model in url params");
857
- }
858
- return {
859
- collectionType,
860
- model: slug,
861
- id: origin || id === "create" ? void 0 : id,
862
- ...useDocument(
863
- { documentId: origin || id, model: slug, collectionType, params },
864
- {
865
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
866
- }
867
- )
976
+ edit,
977
+ list: listLayout
868
978
  };
869
979
  };
870
- const prefixPluginTranslations = (trad, pluginId) => {
871
- if (!pluginId) {
872
- throw new TypeError("pluginId can't be empty");
873
- }
874
- return Object.keys(trad).reduce((acc, current) => {
875
- acc[`${pluginId}.${current}`] = trad[current];
876
- return acc;
877
- }, {});
878
- };
879
- const getTranslation = (id) => `content-manager.${id}`;
880
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
881
- id: "notification.error",
882
- defaultMessage: "An error occurred, please try again"
980
+ const useDocLayout = () => {
981
+ const { model } = useDoc();
982
+ return useDocumentLayout(model);
883
983
  };
884
- const useDocumentActions = () => {
885
- const { toggleNotification } = useNotification();
984
+ const formatEditLayout = (data, {
985
+ schemas,
986
+ schema,
987
+ components
988
+ }) => {
989
+ let currentPanelIndex = 0;
990
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
991
+ data.contentType.layouts.edit,
992
+ schema?.attributes,
993
+ data.contentType.metadatas,
994
+ { configurations: data.components, schemas: components },
995
+ schemas
996
+ ).reduce((panels, row) => {
997
+ if (row.some((field) => field.type === "dynamiczone")) {
998
+ panels.push([row]);
999
+ currentPanelIndex += 2;
1000
+ } else {
1001
+ if (!panels[currentPanelIndex]) {
1002
+ panels.push([row]);
1003
+ } else {
1004
+ panels[currentPanelIndex].push(row);
1005
+ }
1006
+ }
1007
+ return panels;
1008
+ }, []);
1009
+ const componentEditAttributes = Object.entries(data.components).reduce(
1010
+ (acc, [uid, configuration]) => {
1011
+ acc[uid] = {
1012
+ layout: convertEditLayoutToFieldLayouts(
1013
+ configuration.layouts.edit,
1014
+ components[uid].attributes,
1015
+ configuration.metadatas,
1016
+ { configurations: data.components, schemas: components }
1017
+ ),
1018
+ settings: {
1019
+ ...configuration.settings,
1020
+ icon: components[uid].info.icon,
1021
+ displayName: components[uid].info.displayName
1022
+ }
1023
+ };
1024
+ return acc;
1025
+ },
1026
+ {}
1027
+ );
1028
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1029
+ (acc, [attribute, metadata]) => {
1030
+ return {
1031
+ ...acc,
1032
+ [attribute]: metadata.edit
1033
+ };
1034
+ },
1035
+ {}
1036
+ );
1037
+ return {
1038
+ layout: panelledEditAttributes,
1039
+ components: componentEditAttributes,
1040
+ metadatas: editMetadatas,
1041
+ settings: {
1042
+ ...data.contentType.settings,
1043
+ displayName: schema?.info.displayName
1044
+ },
1045
+ options: {
1046
+ ...schema?.options,
1047
+ ...schema?.pluginOptions,
1048
+ ...data.contentType.options
1049
+ }
1050
+ };
1051
+ };
1052
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1053
+ return rows.map(
1054
+ (row) => row.map((field) => {
1055
+ const attribute = attributes[field.name];
1056
+ if (!attribute) {
1057
+ return null;
1058
+ }
1059
+ const { edit: metadata } = metadatas[field.name];
1060
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1061
+ return {
1062
+ attribute,
1063
+ disabled: !metadata.editable,
1064
+ hint: metadata.description,
1065
+ label: metadata.label ?? "",
1066
+ name: field.name,
1067
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1068
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1069
+ schemas,
1070
+ components: components?.schemas ?? {}
1071
+ }),
1072
+ placeholder: metadata.placeholder ?? "",
1073
+ required: attribute.required ?? false,
1074
+ size: field.size,
1075
+ unique: "unique" in attribute ? attribute.unique : false,
1076
+ visible: metadata.visible ?? true,
1077
+ type: attribute.type
1078
+ };
1079
+ }).filter((field) => field !== null)
1080
+ );
1081
+ };
1082
+ const formatListLayout = (data, {
1083
+ schemas,
1084
+ schema,
1085
+ components
1086
+ }) => {
1087
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1088
+ (acc, [attribute, metadata]) => {
1089
+ return {
1090
+ ...acc,
1091
+ [attribute]: metadata.list
1092
+ };
1093
+ },
1094
+ {}
1095
+ );
1096
+ const listAttributes = convertListLayoutToFieldLayouts(
1097
+ data.contentType.layouts.list,
1098
+ schema?.attributes,
1099
+ listMetadatas,
1100
+ { configurations: data.components, schemas: components },
1101
+ schemas
1102
+ );
1103
+ return {
1104
+ layout: listAttributes,
1105
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1106
+ metadatas: listMetadatas,
1107
+ options: {
1108
+ ...schema?.options,
1109
+ ...schema?.pluginOptions,
1110
+ ...data.contentType.options
1111
+ }
1112
+ };
1113
+ };
1114
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1115
+ return columns.map((name) => {
1116
+ const attribute = attributes[name];
1117
+ if (!attribute) {
1118
+ return null;
1119
+ }
1120
+ const metadata = metadatas[name];
1121
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1122
+ return {
1123
+ attribute,
1124
+ label: metadata.label ?? "",
1125
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1126
+ schemas,
1127
+ components: components?.schemas ?? {}
1128
+ }),
1129
+ name,
1130
+ searchable: metadata.searchable ?? true,
1131
+ sortable: metadata.sortable ?? true
1132
+ };
1133
+ }).filter((field) => field !== null);
1134
+ };
1135
+ const useDocument = (args, opts) => {
1136
+ const { toggleNotification } = useNotification();
1137
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1138
+ const {
1139
+ currentData: data,
1140
+ isLoading: isLoadingDocument,
1141
+ isFetching: isFetchingDocument,
1142
+ error
1143
+ } = useGetDocumentQuery(args, {
1144
+ ...opts,
1145
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1146
+ });
1147
+ const {
1148
+ components,
1149
+ schema,
1150
+ schemas,
1151
+ isLoading: isLoadingSchema
1152
+ } = useContentTypeSchema(args.model);
1153
+ React.useEffect(() => {
1154
+ if (error) {
1155
+ toggleNotification({
1156
+ type: "danger",
1157
+ message: formatAPIError(error)
1158
+ });
1159
+ }
1160
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1161
+ const validationSchema = React.useMemo(() => {
1162
+ if (!schema) {
1163
+ return null;
1164
+ }
1165
+ return createYupSchema(schema.attributes, components);
1166
+ }, [schema, components]);
1167
+ const validate = React.useCallback(
1168
+ (document) => {
1169
+ if (!validationSchema) {
1170
+ throw new Error(
1171
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1172
+ );
1173
+ }
1174
+ try {
1175
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1176
+ return null;
1177
+ } catch (error2) {
1178
+ if (error2 instanceof ValidationError) {
1179
+ return getYupValidationErrors(error2);
1180
+ }
1181
+ throw error2;
1182
+ }
1183
+ },
1184
+ [validationSchema]
1185
+ );
1186
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1187
+ const hasError = !!error;
1188
+ return {
1189
+ components,
1190
+ document: data?.data,
1191
+ meta: data?.meta,
1192
+ isLoading,
1193
+ hasError,
1194
+ schema,
1195
+ schemas,
1196
+ validate
1197
+ };
1198
+ };
1199
+ const useDoc = () => {
1200
+ const { id, slug, collectionType, origin } = useParams();
1201
+ const [{ query }] = useQueryParams();
1202
+ const params = React.useMemo(() => buildValidParams(query), [query]);
1203
+ if (!collectionType) {
1204
+ throw new Error("Could not find collectionType in url params");
1205
+ }
1206
+ if (!slug) {
1207
+ throw new Error("Could not find model in url params");
1208
+ }
1209
+ const document = useDocument(
1210
+ { documentId: origin || id, model: slug, collectionType, params },
1211
+ {
1212
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1213
+ }
1214
+ );
1215
+ const returnId = origin || id === "create" ? void 0 : id;
1216
+ return {
1217
+ collectionType,
1218
+ model: slug,
1219
+ id: returnId,
1220
+ ...document
1221
+ };
1222
+ };
1223
+ const useContentManagerContext = () => {
1224
+ const {
1225
+ collectionType,
1226
+ model,
1227
+ id,
1228
+ components,
1229
+ isLoading: isLoadingDoc,
1230
+ schema,
1231
+ schemas
1232
+ } = useDoc();
1233
+ const layout = useDocumentLayout(model);
1234
+ const form = useForm("useContentManagerContext", (state) => state);
1235
+ const isSingleType = collectionType === SINGLE_TYPES;
1236
+ const slug = model;
1237
+ const isCreatingEntry = id === "create";
1238
+ useContentTypeSchema();
1239
+ const isLoading = isLoadingDoc || layout.isLoading;
1240
+ const error = layout.error;
1241
+ return {
1242
+ error,
1243
+ isLoading,
1244
+ // Base metadata
1245
+ model,
1246
+ collectionType,
1247
+ id,
1248
+ slug,
1249
+ isCreatingEntry,
1250
+ isSingleType,
1251
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1252
+ // All schema infos
1253
+ components,
1254
+ contentType: schema,
1255
+ contentTypes: schemas,
1256
+ // Form state
1257
+ form,
1258
+ // layout infos
1259
+ layout
1260
+ };
1261
+ };
1262
+ const prefixPluginTranslations = (trad, pluginId) => {
1263
+ return Object.keys(trad).reduce((acc, current) => {
1264
+ acc[`${pluginId}.${current}`] = trad[current];
1265
+ return acc;
1266
+ }, {});
1267
+ };
1268
+ const getTranslation = (id) => `content-manager.${id}`;
1269
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1270
+ id: "notification.error",
1271
+ defaultMessage: "An error occurred, please try again"
1272
+ };
1273
+ const useDocumentActions = () => {
1274
+ const { toggleNotification } = useNotification();
886
1275
  const { formatMessage } = useIntl();
887
1276
  const { trackUsage } = useTracking();
888
1277
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
1278
  const navigate = useNavigate();
1279
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
890
1280
  const [deleteDocument] = useDeleteDocumentMutation();
891
1281
  const _delete = React.useCallback(
892
1282
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1201,6 +1591,7 @@ const useDocumentActions = () => {
1201
1591
  defaultMessage: "Saved document"
1202
1592
  })
1203
1593
  });
1594
+ setCurrentStep("contentManager.success");
1204
1595
  return res.data;
1205
1596
  } catch (err) {
1206
1597
  toggleNotification({
@@ -1302,10 +1693,10 @@ const useDocumentActions = () => {
1302
1693
  update
1303
1694
  };
1304
1695
  };
1305
- const ProtectedHistoryPage = lazy(
1306
- () => import("./History-DrwsD1Vc.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1696
+ const ProtectedHistoryPage = React.lazy(
1697
+ () => import("./History-04ChQ4pl.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1307
1698
  );
1308
- const routes$1 = [
1699
+ const routes$2 = [
1309
1700
  {
1310
1701
  path: ":collectionType/:slug/:id/history",
1311
1702
  Component: ProtectedHistoryPage
@@ -1315,32 +1706,45 @@ const routes$1 = [
1315
1706
  Component: ProtectedHistoryPage
1316
1707
  }
1317
1708
  ];
1318
- const ProtectedEditViewPage = lazy(
1319
- () => import("./EditViewPage-DiNFdFqP.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1709
+ const ProtectedPreviewPage = React.lazy(
1710
+ () => import("./Preview-BMYN548c.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1320
1711
  );
1321
- const ProtectedListViewPage = lazy(
1322
- () => import("./ListViewPage-5a1vw-OK.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1323
- );
1324
- const ProtectedListConfiguration = lazy(
1325
- () => import("./ListConfigurationPage-BxIP0jRy.mjs").then((mod) => ({
1326
- default: mod.ProtectedListConfiguration
1712
+ const routes$1 = [
1713
+ {
1714
+ path: ":collectionType/:slug/:id/preview",
1715
+ Component: ProtectedPreviewPage
1716
+ },
1717
+ {
1718
+ path: ":collectionType/:slug/preview",
1719
+ Component: ProtectedPreviewPage
1720
+ }
1721
+ ];
1722
+ const ProtectedEditViewPage = lazy(
1723
+ () => import("./EditViewPage-BPyVuPfM.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1724
+ );
1725
+ const ProtectedListViewPage = lazy(
1726
+ () => import("./ListViewPage-FU2LBuhl.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1727
+ );
1728
+ const ProtectedListConfiguration = lazy(
1729
+ () => import("./ListConfigurationPage-BYqPYLSU.mjs").then((mod) => ({
1730
+ default: mod.ProtectedListConfiguration
1327
1731
  }))
1328
1732
  );
1329
1733
  const ProtectedEditConfigurationPage = lazy(
1330
- () => import("./EditConfigurationPage-Bk893vVY.mjs").then((mod) => ({
1734
+ () => import("./EditConfigurationPage-DsPR2DVk.mjs").then((mod) => ({
1331
1735
  default: mod.ProtectedEditConfigurationPage
1332
1736
  }))
1333
1737
  );
1334
1738
  const ProtectedComponentConfigurationPage = lazy(
1335
- () => import("./ComponentConfigurationPage-9lRmRdIr.mjs").then((mod) => ({
1739
+ () => import("./ComponentConfigurationPage-CtIa3aa2.mjs").then((mod) => ({
1336
1740
  default: mod.ProtectedComponentConfigurationPage
1337
1741
  }))
1338
1742
  );
1339
1743
  const NoPermissions = lazy(
1340
- () => import("./NoPermissionsPage-BHPqn_tQ.mjs").then((mod) => ({ default: mod.NoPermissions }))
1744
+ () => import("./NoPermissionsPage-jqve7C8l.mjs").then((mod) => ({ default: mod.NoPermissions }))
1341
1745
  );
1342
1746
  const NoContentType = lazy(
1343
- () => import("./NoContentTypePage-Bm6tRcd3.mjs").then((mod) => ({ default: mod.NoContentType }))
1747
+ () => import("./NoContentTypePage-DCKUkwb8.mjs").then((mod) => ({ default: mod.NoContentType }))
1344
1748
  );
1345
1749
  const CollectionTypePages = () => {
1346
1750
  const { collectionType } = useParams();
@@ -1352,7 +1756,7 @@ const CollectionTypePages = () => {
1352
1756
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1353
1757
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1354
1758
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1355
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1759
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1356
1760
  const routes = [
1357
1761
  {
1358
1762
  path: LIST_RELATIVE_PATH,
@@ -1386,6 +1790,7 @@ const routes = [
1386
1790
  path: "no-content-types",
1387
1791
  Component: NoContentType
1388
1792
  },
1793
+ ...routes$2,
1389
1794
  ...routes$1
1390
1795
  ];
1391
1796
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1484,6 +1889,11 @@ const DocumentActionButton = (action) => {
1484
1889
  ) : null
1485
1890
  ] });
1486
1891
  };
1892
+ const MenuItem = styled(Menu.Item)`
1893
+ &:hover {
1894
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1895
+ }
1896
+ `;
1487
1897
  const DocumentActionsMenu = ({
1488
1898
  actions: actions2,
1489
1899
  children,
@@ -1539,51 +1949,35 @@ const DocumentActionsMenu = ({
1539
1949
  ]
1540
1950
  }
1541
1951
  ),
1542
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1952
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1543
1953
  actions2.map((action) => {
1544
1954
  return /* @__PURE__ */ jsx(
1545
- Menu.Item,
1955
+ MenuItem,
1546
1956
  {
1547
1957
  disabled: action.disabled,
1548
1958
  onSelect: handleClick(action),
1549
1959
  display: "block",
1550
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1551
- /* @__PURE__ */ jsxs(
1552
- Flex,
1553
- {
1554
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1555
- gap: 2,
1556
- tag: "span",
1557
- children: [
1558
- /* @__PURE__ */ jsx(
1559
- Flex,
1560
- {
1561
- tag: "span",
1562
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1563
- children: action.icon
1564
- }
1565
- ),
1566
- action.label
1567
- ]
1568
- }
1569
- ),
1570
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1571
- Flex,
1572
- {
1573
- alignItems: "center",
1574
- background: "alternative100",
1575
- borderStyle: "solid",
1576
- borderColor: "alternative200",
1577
- borderWidth: "1px",
1578
- height: 5,
1579
- paddingLeft: 2,
1580
- paddingRight: 2,
1581
- hasRadius: true,
1582
- color: "alternative600",
1583
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1584
- }
1585
- )
1586
- ] })
1960
+ isVariantDanger: action.variant === "danger",
1961
+ isDisabled: action.disabled,
1962
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
1963
+ Flex,
1964
+ {
1965
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1966
+ gap: 2,
1967
+ tag: "span",
1968
+ children: [
1969
+ /* @__PURE__ */ jsx(
1970
+ Flex,
1971
+ {
1972
+ tag: "span",
1973
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1974
+ children: action.icon
1975
+ }
1976
+ ),
1977
+ action.label
1978
+ ]
1979
+ }
1980
+ ) })
1587
1981
  },
1588
1982
  action.id
1589
1983
  );
@@ -1663,11 +2057,11 @@ const DocumentActionConfirmDialog = ({
1663
2057
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1664
2058
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1665
2059
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1666
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
2060
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1667
2061
  id: "app.components.Button.cancel",
1668
2062
  defaultMessage: "Cancel"
1669
2063
  }) }) }),
1670
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
2064
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1671
2065
  id: "app.components.Button.confirm",
1672
2066
  defaultMessage: "Confirm"
1673
2067
  }) })
@@ -1694,6 +2088,18 @@ const DocumentActionModal = ({
1694
2088
  typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1695
2089
  ] }) });
1696
2090
  };
2091
+ const transformData = (data) => {
2092
+ if (Array.isArray(data)) {
2093
+ return data.map(transformData);
2094
+ }
2095
+ if (typeof data === "object" && data !== null) {
2096
+ if ("apiData" in data) {
2097
+ return data.apiData;
2098
+ }
2099
+ return mapValues(transformData)(data);
2100
+ }
2101
+ return data;
2102
+ };
1697
2103
  const PublishAction$1 = ({
1698
2104
  activeTab,
1699
2105
  documentId,
@@ -1708,6 +2114,7 @@ const PublishAction$1 = ({
1708
2114
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1709
2115
  const isListView = useMatch(LIST_PATH) !== null;
1710
2116
  const isCloning = useMatch(CLONE_PATH) !== null;
2117
+ const { id } = useParams();
1711
2118
  const { formatMessage } = useIntl();
1712
2119
  const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1713
2120
  const { publish } = useDocumentActions();
@@ -1761,24 +2168,25 @@ const PublishAction$1 = ({
1761
2168
  }
1762
2169
  }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1763
2170
  React.useEffect(() => {
1764
- if (documentId && !isListView) {
1765
- const fetchDraftRelationsCount = async () => {
1766
- const { data, error } = await countDraftRelations({
1767
- collectionType,
1768
- model,
1769
- documentId,
1770
- params
1771
- });
1772
- if (error) {
1773
- throw error;
1774
- }
1775
- if (data) {
1776
- setServerCountOfDraftRelations(data.data);
1777
- }
1778
- };
1779
- fetchDraftRelationsCount();
2171
+ if (!document || !document.documentId || isListView) {
2172
+ return;
1780
2173
  }
1781
- }, [isListView, documentId, countDraftRelations, collectionType, model, params]);
2174
+ const fetchDraftRelationsCount = async () => {
2175
+ const { data, error } = await countDraftRelations({
2176
+ collectionType,
2177
+ model,
2178
+ documentId,
2179
+ params
2180
+ });
2181
+ if (error) {
2182
+ throw error;
2183
+ }
2184
+ if (data) {
2185
+ setServerCountOfDraftRelations(data.data);
2186
+ }
2187
+ };
2188
+ fetchDraftRelationsCount();
2189
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1782
2190
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1783
2191
  if (!schema?.options?.draftAndPublish) {
1784
2192
  return null;
@@ -1786,7 +2194,9 @@ const PublishAction$1 = ({
1786
2194
  const performPublish = async () => {
1787
2195
  setSubmitting(true);
1788
2196
  try {
1789
- const { errors } = await validate();
2197
+ const { errors } = await validate(true, {
2198
+ status: "published"
2199
+ });
1790
2200
  if (errors) {
1791
2201
  toggleNotification({
1792
2202
  type: "danger",
@@ -1804,13 +2214,15 @@ const PublishAction$1 = ({
1804
2214
  documentId,
1805
2215
  params
1806
2216
  },
1807
- formValues
2217
+ transformData(formValues)
1808
2218
  );
1809
2219
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1810
- navigate({
1811
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1812
- search: rawQuery
1813
- });
2220
+ if (id === "create") {
2221
+ navigate({
2222
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2223
+ search: rawQuery
2224
+ });
2225
+ }
1814
2226
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1815
2227
  setErrors(formatValidationErrors(res.error));
1816
2228
  }
@@ -1863,6 +2275,7 @@ const PublishAction$1 = ({
1863
2275
  };
1864
2276
  };
1865
2277
  PublishAction$1.type = "publish";
2278
+ PublishAction$1.position = "panel";
1866
2279
  const UpdateAction = ({
1867
2280
  activeTab,
1868
2281
  documentId,
@@ -1885,6 +2298,117 @@ const UpdateAction = ({
1885
2298
  const validate = useForm("UpdateAction", (state) => state.validate);
1886
2299
  const setErrors = useForm("UpdateAction", (state) => state.setErrors);
1887
2300
  const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
2301
+ const handleUpdate = React.useCallback(async () => {
2302
+ setSubmitting(true);
2303
+ try {
2304
+ if (!modified) {
2305
+ return;
2306
+ }
2307
+ const { errors } = await validate(true, {
2308
+ status: "draft"
2309
+ });
2310
+ if (errors) {
2311
+ toggleNotification({
2312
+ type: "danger",
2313
+ message: formatMessage({
2314
+ id: "content-manager.validation.error",
2315
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2316
+ })
2317
+ });
2318
+ return;
2319
+ }
2320
+ if (isCloning) {
2321
+ const res = await clone(
2322
+ {
2323
+ model,
2324
+ documentId: cloneMatch.params.origin,
2325
+ params
2326
+ },
2327
+ transformData(document)
2328
+ );
2329
+ if ("data" in res) {
2330
+ navigate(
2331
+ {
2332
+ pathname: `../${res.data.documentId}`,
2333
+ search: rawQuery
2334
+ },
2335
+ { relative: "path" }
2336
+ );
2337
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2338
+ setErrors(formatValidationErrors(res.error));
2339
+ }
2340
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2341
+ const res = await update(
2342
+ {
2343
+ collectionType,
2344
+ model,
2345
+ documentId,
2346
+ params
2347
+ },
2348
+ transformData(document)
2349
+ );
2350
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2351
+ setErrors(formatValidationErrors(res.error));
2352
+ } else {
2353
+ resetForm();
2354
+ }
2355
+ } else {
2356
+ const res = await create(
2357
+ {
2358
+ model,
2359
+ params
2360
+ },
2361
+ transformData(document)
2362
+ );
2363
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2364
+ navigate(
2365
+ {
2366
+ pathname: `../${res.data.documentId}`,
2367
+ search: rawQuery
2368
+ },
2369
+ { replace: true, relative: "path" }
2370
+ );
2371
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2372
+ setErrors(formatValidationErrors(res.error));
2373
+ }
2374
+ }
2375
+ } finally {
2376
+ setSubmitting(false);
2377
+ }
2378
+ }, [
2379
+ clone,
2380
+ cloneMatch?.params.origin,
2381
+ collectionType,
2382
+ create,
2383
+ document,
2384
+ documentId,
2385
+ formatMessage,
2386
+ formatValidationErrors,
2387
+ isCloning,
2388
+ model,
2389
+ modified,
2390
+ navigate,
2391
+ params,
2392
+ rawQuery,
2393
+ resetForm,
2394
+ setErrors,
2395
+ setSubmitting,
2396
+ toggleNotification,
2397
+ update,
2398
+ validate
2399
+ ]);
2400
+ React.useEffect(() => {
2401
+ const handleKeyDown = (e) => {
2402
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2403
+ e.preventDefault();
2404
+ handleUpdate();
2405
+ }
2406
+ };
2407
+ window.addEventListener("keydown", handleKeyDown);
2408
+ return () => {
2409
+ window.removeEventListener("keydown", handleKeyDown);
2410
+ };
2411
+ }, [handleUpdate]);
1888
2412
  return {
1889
2413
  /**
1890
2414
  * Disabled when:
@@ -1894,87 +2418,14 @@ const UpdateAction = ({
1894
2418
  */
1895
2419
  disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1896
2420
  label: formatMessage({
1897
- id: "content-manager.containers.Edit.save",
2421
+ id: "global.save",
1898
2422
  defaultMessage: "Save"
1899
2423
  }),
1900
- onClick: async () => {
1901
- setSubmitting(true);
1902
- try {
1903
- if (activeTab !== "draft") {
1904
- const { errors } = await validate();
1905
- if (errors) {
1906
- toggleNotification({
1907
- type: "danger",
1908
- message: formatMessage({
1909
- id: "content-manager.validation.error",
1910
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1911
- })
1912
- });
1913
- return;
1914
- }
1915
- }
1916
- if (isCloning) {
1917
- const res = await clone(
1918
- {
1919
- model,
1920
- documentId: cloneMatch.params.origin,
1921
- params
1922
- },
1923
- document
1924
- );
1925
- if ("data" in res) {
1926
- navigate(
1927
- {
1928
- pathname: `../${res.data.documentId}`,
1929
- search: rawQuery
1930
- },
1931
- { relative: "path" }
1932
- );
1933
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1934
- setErrors(formatValidationErrors(res.error));
1935
- }
1936
- } else if (documentId || collectionType === SINGLE_TYPES) {
1937
- const res = await update(
1938
- {
1939
- collectionType,
1940
- model,
1941
- documentId,
1942
- params
1943
- },
1944
- document
1945
- );
1946
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1947
- setErrors(formatValidationErrors(res.error));
1948
- } else {
1949
- resetForm();
1950
- }
1951
- } else {
1952
- const res = await create(
1953
- {
1954
- model,
1955
- params
1956
- },
1957
- document
1958
- );
1959
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1960
- navigate(
1961
- {
1962
- pathname: `../${res.data.documentId}`,
1963
- search: rawQuery
1964
- },
1965
- { replace: true, relative: "path" }
1966
- );
1967
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1968
- setErrors(formatValidationErrors(res.error));
1969
- }
1970
- }
1971
- } finally {
1972
- setSubmitting(false);
1973
- }
1974
- }
2424
+ onClick: handleUpdate
1975
2425
  };
1976
2426
  };
1977
2427
  UpdateAction.type = "update";
2428
+ UpdateAction.position = "panel";
1978
2429
  const UNPUBLISH_DRAFT_OPTIONS = {
1979
2430
  KEEP: "keep",
1980
2431
  DISCARD: "discard"
@@ -2007,7 +2458,7 @@ const UnpublishAction$1 = ({
2007
2458
  id: "app.utils.unpublish",
2008
2459
  defaultMessage: "Unpublish"
2009
2460
  }),
2010
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2461
+ icon: /* @__PURE__ */ jsx(Cross, {}),
2011
2462
  onClick: async () => {
2012
2463
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
2013
2464
  if (!documentId) {
@@ -2097,6 +2548,7 @@ const UnpublishAction$1 = ({
2097
2548
  };
2098
2549
  };
2099
2550
  UnpublishAction$1.type = "unpublish";
2551
+ UnpublishAction$1.position = "panel";
2100
2552
  const DiscardAction = ({
2101
2553
  activeTab,
2102
2554
  documentId,
@@ -2119,7 +2571,7 @@ const DiscardAction = ({
2119
2571
  id: "content-manager.actions.discard.label",
2120
2572
  defaultMessage: "Discard changes"
2121
2573
  }),
2122
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2574
+ icon: /* @__PURE__ */ jsx(Cross, {}),
2123
2575
  position: ["panel", "table-row"],
2124
2576
  variant: "danger",
2125
2577
  dialog: {
@@ -2147,11 +2599,7 @@ const DiscardAction = ({
2147
2599
  };
2148
2600
  };
2149
2601
  DiscardAction.type = "discard";
2150
- const StyledCrossCircle = styled(CrossCircle)`
2151
- path {
2152
- fill: currentColor;
2153
- }
2154
- `;
2602
+ DiscardAction.position = "panel";
2155
2603
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2156
2604
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2157
2605
  const RelativeTime = React.forwardRef(
@@ -2164,7 +2612,7 @@ const RelativeTime = React.forwardRef(
2164
2612
  });
2165
2613
  const unit = intervals.find((intervalUnit) => {
2166
2614
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2167
- });
2615
+ }) ?? "seconds";
2168
2616
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2169
2617
  const customInterval = customIntervals.find(
2170
2618
  (custom) => interval[custom.unit] < custom.threshold
@@ -2198,19 +2646,29 @@ const getDisplayName = ({
2198
2646
  return email ?? "";
2199
2647
  };
2200
2648
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2201
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2202
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2203
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2649
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2650
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2651
+ const { formatMessage } = useIntl();
2652
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2653
+ id: `content-manager.containers.List.${status}`,
2654
+ defaultMessage: capitalise(status)
2655
+ }) }) });
2204
2656
  };
2205
2657
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2206
2658
  const { formatMessage } = useIntl();
2207
2659
  const isCloning = useMatch(CLONE_PATH) !== null;
2660
+ const params = useParams();
2208
2661
  const title = isCreating ? formatMessage({
2209
2662
  id: "content-manager.containers.edit.title.new",
2210
2663
  defaultMessage: "Create an entry"
2211
2664
  }) : documentTitle;
2212
2665
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2213
- /* @__PURE__ */ jsx(BackButton, {}),
2666
+ /* @__PURE__ */ jsx(
2667
+ BackButton,
2668
+ {
2669
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2670
+ }
2671
+ ),
2214
2672
  /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2215
2673
  /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2216
2674
  /* @__PURE__ */ jsx(HeaderToolbar, {})
@@ -2261,7 +2719,7 @@ const HeaderToolbar = () => {
2261
2719
  meta: isCloning ? void 0 : meta,
2262
2720
  collectionType
2263
2721
  },
2264
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2722
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2265
2723
  children: (actions2) => {
2266
2724
  const headerActions = actions2.filter((action) => {
2267
2725
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2298,12 +2756,12 @@ const Information = ({ activeTab }) => {
2298
2756
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2299
2757
  label: formatMessage({
2300
2758
  id: "content-manager.containers.edit.information.last-published.label",
2301
- defaultMessage: "Last published"
2759
+ defaultMessage: "Published"
2302
2760
  }),
2303
2761
  value: formatMessage(
2304
2762
  {
2305
2763
  id: "content-manager.containers.edit.information.last-published.value",
2306
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2764
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2307
2765
  },
2308
2766
  {
2309
2767
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2316,12 +2774,12 @@ const Information = ({ activeTab }) => {
2316
2774
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2317
2775
  label: formatMessage({
2318
2776
  id: "content-manager.containers.edit.information.last-draft.label",
2319
- defaultMessage: "Last draft"
2777
+ defaultMessage: "Updated"
2320
2778
  }),
2321
2779
  value: formatMessage(
2322
2780
  {
2323
2781
  id: "content-manager.containers.edit.information.last-draft.value",
2324
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2782
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2325
2783
  },
2326
2784
  {
2327
2785
  time: /* @__PURE__ */ jsx(
@@ -2339,12 +2797,12 @@ const Information = ({ activeTab }) => {
2339
2797
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2340
2798
  label: formatMessage({
2341
2799
  id: "content-manager.containers.edit.information.document.label",
2342
- defaultMessage: "Document"
2800
+ defaultMessage: "Created"
2343
2801
  }),
2344
2802
  value: formatMessage(
2345
2803
  {
2346
2804
  id: "content-manager.containers.edit.information.document.value",
2347
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2805
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2348
2806
  },
2349
2807
  {
2350
2808
  time: /* @__PURE__ */ jsx(
@@ -2382,25 +2840,77 @@ const Information = ({ activeTab }) => {
2382
2840
  );
2383
2841
  };
2384
2842
  const HeaderActions = ({ actions: actions2 }) => {
2385
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2386
- if ("options" in action) {
2843
+ const [dialogId, setDialogId] = React.useState(null);
2844
+ const handleClick = (action) => async (e) => {
2845
+ if (!("options" in action)) {
2846
+ const { onClick = () => false, dialog, id } = action;
2847
+ const muteDialog = await onClick(e);
2848
+ if (dialog && !muteDialog) {
2849
+ e.preventDefault();
2850
+ setDialogId(id);
2851
+ }
2852
+ }
2853
+ };
2854
+ const handleClose = () => {
2855
+ setDialogId(null);
2856
+ };
2857
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2858
+ if (action.options) {
2387
2859
  return /* @__PURE__ */ jsx(
2388
2860
  SingleSelect,
2389
2861
  {
2390
2862
  size: "S",
2391
- disabled: action.disabled,
2392
- "aria-label": action.label,
2393
2863
  onChange: action.onSelect,
2394
- value: action.value,
2864
+ "aria-label": action.label,
2865
+ ...action,
2395
2866
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2396
2867
  },
2397
2868
  action.id
2398
2869
  );
2399
2870
  } else {
2400
- return null;
2871
+ if (action.type === "icon") {
2872
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2873
+ /* @__PURE__ */ jsx(
2874
+ IconButton,
2875
+ {
2876
+ disabled: action.disabled,
2877
+ label: action.label,
2878
+ size: "S",
2879
+ onClick: handleClick(action),
2880
+ children: action.icon
2881
+ }
2882
+ ),
2883
+ action.dialog ? /* @__PURE__ */ jsx(
2884
+ HeaderActionDialog,
2885
+ {
2886
+ ...action.dialog,
2887
+ isOpen: dialogId === action.id,
2888
+ onClose: handleClose
2889
+ }
2890
+ ) : null
2891
+ ] }, action.id);
2892
+ }
2401
2893
  }
2402
2894
  }) });
2403
2895
  };
2896
+ const HeaderActionDialog = ({
2897
+ onClose,
2898
+ onCancel,
2899
+ title,
2900
+ content: Content,
2901
+ isOpen
2902
+ }) => {
2903
+ const handleClose = async () => {
2904
+ if (onCancel) {
2905
+ await onCancel();
2906
+ }
2907
+ onClose();
2908
+ };
2909
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2910
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2911
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2912
+ ] }) });
2913
+ };
2404
2914
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2405
2915
  const navigate = useNavigate();
2406
2916
  const { formatMessage } = useIntl();
@@ -2417,6 +2927,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2417
2927
  };
2418
2928
  };
2419
2929
  ConfigureTheViewAction.type = "configure-the-view";
2930
+ ConfigureTheViewAction.position = "header";
2420
2931
  const EditTheModelAction = ({ model }) => {
2421
2932
  const navigate = useNavigate();
2422
2933
  const { formatMessage } = useIntl();
@@ -2433,6 +2944,7 @@ const EditTheModelAction = ({ model }) => {
2433
2944
  };
2434
2945
  };
2435
2946
  EditTheModelAction.type = "edit-the-model";
2947
+ EditTheModelAction.position = "header";
2436
2948
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2437
2949
  const navigate = useNavigate();
2438
2950
  const { formatMessage } = useIntl();
@@ -2441,12 +2953,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2441
2953
  const { delete: deleteAction } = useDocumentActions();
2442
2954
  const { toggleNotification } = useNotification();
2443
2955
  const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2956
+ const isLocalized = document?.locale != null;
2444
2957
  return {
2445
2958
  disabled: !canDelete || !document,
2446
- label: formatMessage({
2447
- id: "content-manager.actions.delete.label",
2448
- defaultMessage: "Delete document"
2449
- }),
2959
+ label: formatMessage(
2960
+ {
2961
+ id: "content-manager.actions.delete.label",
2962
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2963
+ },
2964
+ { isLocalized }
2965
+ ),
2450
2966
  icon: /* @__PURE__ */ jsx(Trash, {}),
2451
2967
  dialog: {
2452
2968
  type: "dialog",
@@ -2484,421 +3000,120 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2484
3000
  model,
2485
3001
  collectionType,
2486
3002
  params: {
2487
- locale: "*"
2488
- }
2489
- });
2490
- if (!("error" in res)) {
2491
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2492
- }
2493
- } finally {
2494
- if (!listViewPathMatch) {
2495
- setSubmitting(false);
2496
- }
2497
- }
2498
- }
2499
- },
2500
- variant: "danger",
2501
- position: ["header", "table-row"]
2502
- };
2503
- };
2504
- DeleteAction$1.type = "delete";
2505
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2506
- const Panels = () => {
2507
- const isCloning = useMatch(CLONE_PATH) !== null;
2508
- const [
2509
- {
2510
- query: { status }
2511
- }
2512
- ] = useQueryParams({
2513
- status: "draft"
2514
- });
2515
- const { model, id, document, meta, collectionType } = useDoc();
2516
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2517
- const props = {
2518
- activeTab: status,
2519
- model,
2520
- documentId: id,
2521
- document: isCloning ? void 0 : document,
2522
- meta: isCloning ? void 0 : meta,
2523
- collectionType
2524
- };
2525
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2526
- DescriptionComponentRenderer,
2527
- {
2528
- props,
2529
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2530
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2531
- }
2532
- ) });
2533
- };
2534
- const ActionsPanel = () => {
2535
- const { formatMessage } = useIntl();
2536
- return {
2537
- title: formatMessage({
2538
- id: "content-manager.containers.edit.panels.default.title",
2539
- defaultMessage: "Document"
2540
- }),
2541
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2542
- };
2543
- };
2544
- ActionsPanel.type = "actions";
2545
- const ActionsPanelContent = () => {
2546
- const isCloning = useMatch(CLONE_PATH) !== null;
2547
- const [
2548
- {
2549
- query: { status = "draft" }
2550
- }
2551
- ] = useQueryParams();
2552
- const { model, id, document, meta, collectionType } = useDoc();
2553
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2554
- const props = {
2555
- activeTab: status,
2556
- model,
2557
- documentId: id,
2558
- document: isCloning ? void 0 : document,
2559
- meta: isCloning ? void 0 : meta,
2560
- collectionType
2561
- };
2562
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2563
- /* @__PURE__ */ jsx(
2564
- DescriptionComponentRenderer,
2565
- {
2566
- props,
2567
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2568
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2569
- }
2570
- ),
2571
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2572
- ] });
2573
- };
2574
- const Panel = React.forwardRef(({ children, title }, ref) => {
2575
- return /* @__PURE__ */ jsxs(
2576
- Flex,
2577
- {
2578
- ref,
2579
- tag: "aside",
2580
- "aria-labelledby": "additional-information",
2581
- background: "neutral0",
2582
- borderColor: "neutral150",
2583
- hasRadius: true,
2584
- paddingBottom: 4,
2585
- paddingLeft: 4,
2586
- paddingRight: 4,
2587
- paddingTop: 4,
2588
- shadow: "tableShadow",
2589
- gap: 3,
2590
- direction: "column",
2591
- justifyContent: "stretch",
2592
- alignItems: "flex-start",
2593
- children: [
2594
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2595
- children
2596
- ]
2597
- }
2598
- );
2599
- });
2600
- const HOOKS = {
2601
- /**
2602
- * Hook that allows to mutate the displayed headers of the list view table
2603
- * @constant
2604
- * @type {string}
2605
- */
2606
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2607
- /**
2608
- * Hook that allows to mutate the CM's collection types links pre-set filters
2609
- * @constant
2610
- * @type {string}
2611
- */
2612
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2613
- /**
2614
- * Hook that allows to mutate the CM's edit view layout
2615
- * @constant
2616
- * @type {string}
2617
- */
2618
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2619
- /**
2620
- * Hook that allows to mutate the CM's single types links pre-set filters
2621
- * @constant
2622
- * @type {string}
2623
- */
2624
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2625
- };
2626
- const contentTypesApi = contentManagerApi.injectEndpoints({
2627
- endpoints: (builder) => ({
2628
- getContentTypeConfiguration: builder.query({
2629
- query: (uid) => ({
2630
- url: `/content-manager/content-types/${uid}/configuration`,
2631
- method: "GET"
2632
- }),
2633
- transformResponse: (response) => response.data,
2634
- providesTags: (_result, _error, uid) => [
2635
- { type: "ContentTypesConfiguration", id: uid },
2636
- { type: "ContentTypeSettings", id: "LIST" }
2637
- ]
2638
- }),
2639
- getAllContentTypeSettings: builder.query({
2640
- query: () => "/content-manager/content-types-settings",
2641
- transformResponse: (response) => response.data,
2642
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2643
- }),
2644
- updateContentTypeConfiguration: builder.mutation({
2645
- query: ({ uid, ...body }) => ({
2646
- url: `/content-manager/content-types/${uid}/configuration`,
2647
- method: "PUT",
2648
- data: body
2649
- }),
2650
- transformResponse: (response) => response.data,
2651
- invalidatesTags: (_result, _error, { uid }) => [
2652
- { type: "ContentTypesConfiguration", id: uid },
2653
- { type: "ContentTypeSettings", id: "LIST" },
2654
- // Is this necessary?
2655
- { type: "InitialData" }
2656
- ]
2657
- })
2658
- })
2659
- });
2660
- const {
2661
- useGetContentTypeConfigurationQuery,
2662
- useGetAllContentTypeSettingsQuery,
2663
- useUpdateContentTypeConfigurationMutation
2664
- } = contentTypesApi;
2665
- const checkIfAttributeIsDisplayable = (attribute) => {
2666
- const { type } = attribute;
2667
- if (type === "relation") {
2668
- return !attribute.relation.toLowerCase().includes("morph");
2669
- }
2670
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2671
- };
2672
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2673
- if (!mainFieldName) {
2674
- return void 0;
2675
- }
2676
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2677
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2678
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2679
- );
2680
- return {
2681
- name: mainFieldName,
2682
- type: mainFieldType ?? "string"
2683
- };
2684
- };
2685
- const DEFAULT_SETTINGS = {
2686
- bulkable: false,
2687
- filterable: false,
2688
- searchable: false,
2689
- pagination: false,
2690
- defaultSortBy: "",
2691
- defaultSortOrder: "asc",
2692
- mainField: "id",
2693
- pageSize: 10
2694
- };
2695
- const useDocumentLayout = (model) => {
2696
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2697
- const [{ query }] = useQueryParams();
2698
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2699
- const { toggleNotification } = useNotification();
2700
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2701
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2702
- const {
2703
- data,
2704
- isLoading: isLoadingConfigs,
2705
- error,
2706
- isFetching: isFetchingConfigs
2707
- } = useGetContentTypeConfigurationQuery(model);
2708
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2709
- React.useEffect(() => {
2710
- if (error) {
2711
- toggleNotification({
2712
- type: "danger",
2713
- message: formatAPIError(error)
2714
- });
2715
- }
2716
- }, [error, formatAPIError, toggleNotification]);
2717
- const editLayout = React.useMemo(
2718
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2719
- layout: [],
2720
- components: {},
2721
- metadatas: {},
2722
- options: {},
2723
- settings: DEFAULT_SETTINGS
2724
- },
2725
- [data, isLoading, schemas, schema, components]
2726
- );
2727
- const listLayout = React.useMemo(() => {
2728
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2729
- layout: [],
2730
- metadatas: {},
2731
- options: {},
2732
- settings: DEFAULT_SETTINGS
2733
- };
2734
- }, [data, isLoading, schemas, schema, components]);
2735
- const { layout: edit } = React.useMemo(
2736
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2737
- layout: editLayout,
2738
- query
2739
- }),
2740
- [editLayout, query, runHookWaterfall]
2741
- );
2742
- return {
2743
- error,
2744
- isLoading,
2745
- edit,
2746
- list: listLayout
2747
- };
2748
- };
2749
- const useDocLayout = () => {
2750
- const { model } = useDoc();
2751
- return useDocumentLayout(model);
2752
- };
2753
- const formatEditLayout = (data, {
2754
- schemas,
2755
- schema,
2756
- components
2757
- }) => {
2758
- let currentPanelIndex = 0;
2759
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2760
- data.contentType.layouts.edit,
2761
- schema?.attributes,
2762
- data.contentType.metadatas,
2763
- { configurations: data.components, schemas: components },
2764
- schemas
2765
- ).reduce((panels, row) => {
2766
- if (row.some((field) => field.type === "dynamiczone")) {
2767
- panels.push([row]);
2768
- currentPanelIndex += 2;
2769
- } else {
2770
- if (!panels[currentPanelIndex]) {
2771
- panels.push([]);
2772
- }
2773
- panels[currentPanelIndex].push(row);
2774
- }
2775
- return panels;
2776
- }, []);
2777
- const componentEditAttributes = Object.entries(data.components).reduce(
2778
- (acc, [uid, configuration]) => {
2779
- acc[uid] = {
2780
- layout: convertEditLayoutToFieldLayouts(
2781
- configuration.layouts.edit,
2782
- components[uid].attributes,
2783
- configuration.metadatas
2784
- ),
2785
- settings: {
2786
- ...configuration.settings,
2787
- icon: components[uid].info.icon,
2788
- displayName: components[uid].info.displayName
3003
+ locale: "*"
3004
+ }
3005
+ });
3006
+ if (!("error" in res)) {
3007
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
3008
+ }
3009
+ } finally {
3010
+ if (!listViewPathMatch) {
3011
+ setSubmitting(false);
3012
+ }
2789
3013
  }
2790
- };
2791
- return acc;
2792
- },
2793
- {}
2794
- );
2795
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2796
- (acc, [attribute, metadata]) => {
2797
- return {
2798
- ...acc,
2799
- [attribute]: metadata.edit
2800
- };
2801
- },
2802
- {}
2803
- );
2804
- return {
2805
- layout: panelledEditAttributes,
2806
- components: componentEditAttributes,
2807
- metadatas: editMetadatas,
2808
- settings: {
2809
- ...data.contentType.settings,
2810
- displayName: schema?.info.displayName
3014
+ }
2811
3015
  },
2812
- options: {
2813
- ...schema?.options,
2814
- ...schema?.pluginOptions,
2815
- ...data.contentType.options
2816
- }
3016
+ variant: "danger",
3017
+ position: ["header", "table-row"]
2817
3018
  };
2818
3019
  };
2819
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2820
- return rows.map(
2821
- (row) => row.map((field) => {
2822
- const attribute = attributes[field.name];
2823
- if (!attribute) {
2824
- return null;
2825
- }
2826
- const { edit: metadata } = metadatas[field.name];
2827
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2828
- return {
2829
- attribute,
2830
- disabled: !metadata.editable,
2831
- hint: metadata.description,
2832
- label: metadata.label ?? "",
2833
- name: field.name,
2834
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2835
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2836
- schemas,
2837
- components: components?.schemas ?? {}
2838
- }),
2839
- placeholder: metadata.placeholder ?? "",
2840
- required: attribute.required ?? false,
2841
- size: field.size,
2842
- unique: "unique" in attribute ? attribute.unique : false,
2843
- visible: metadata.visible ?? true,
2844
- type: attribute.type
2845
- };
2846
- }).filter((field) => field !== null)
2847
- );
3020
+ DeleteAction$1.type = "delete";
3021
+ DeleteAction$1.position = ["header", "table-row"];
3022
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
3023
+ const Panels = () => {
3024
+ const isCloning = useMatch(CLONE_PATH) !== null;
3025
+ const [
3026
+ {
3027
+ query: { status }
3028
+ }
3029
+ ] = useQueryParams({
3030
+ status: "draft"
3031
+ });
3032
+ const { model, id, document, meta, collectionType } = useDoc();
3033
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
3034
+ const props = {
3035
+ activeTab: status,
3036
+ model,
3037
+ documentId: id,
3038
+ document: isCloning ? void 0 : document,
3039
+ meta: isCloning ? void 0 : meta,
3040
+ collectionType
3041
+ };
3042
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
3043
+ DescriptionComponentRenderer,
3044
+ {
3045
+ props,
3046
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
3047
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
3048
+ }
3049
+ ) });
2848
3050
  };
2849
- const formatListLayout = (data, {
2850
- schemas,
2851
- schema,
2852
- components
2853
- }) => {
2854
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2855
- (acc, [attribute, metadata]) => {
2856
- return {
2857
- ...acc,
2858
- [attribute]: metadata.list
2859
- };
2860
- },
2861
- {}
2862
- );
2863
- const listAttributes = convertListLayoutToFieldLayouts(
2864
- data.contentType.layouts.list,
2865
- schema?.attributes,
2866
- listMetadatas,
2867
- { configurations: data.components, schemas: components },
2868
- schemas
2869
- );
3051
+ const ActionsPanel = () => {
3052
+ const { formatMessage } = useIntl();
2870
3053
  return {
2871
- layout: listAttributes,
2872
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2873
- metadatas: listMetadatas,
2874
- options: {
2875
- ...schema?.options,
2876
- ...schema?.pluginOptions,
2877
- ...data.contentType.options
2878
- }
3054
+ title: formatMessage({
3055
+ id: "content-manager.containers.edit.panels.default.title",
3056
+ defaultMessage: "Entry"
3057
+ }),
3058
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2879
3059
  };
2880
3060
  };
2881
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2882
- return columns.map((name) => {
2883
- const attribute = attributes[name];
2884
- if (!attribute) {
2885
- return null;
3061
+ ActionsPanel.type = "actions";
3062
+ const ActionsPanelContent = () => {
3063
+ const isCloning = useMatch(CLONE_PATH) !== null;
3064
+ const [
3065
+ {
3066
+ query: { status = "draft" }
2886
3067
  }
2887
- const metadata = metadatas[name];
2888
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2889
- return {
2890
- attribute,
2891
- label: metadata.label ?? "",
2892
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2893
- schemas,
2894
- components: components?.schemas ?? {}
2895
- }),
2896
- name,
2897
- searchable: metadata.searchable ?? true,
2898
- sortable: metadata.sortable ?? true
2899
- };
2900
- }).filter((field) => field !== null);
3068
+ ] = useQueryParams();
3069
+ const { model, id, document, meta, collectionType } = useDoc();
3070
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
3071
+ const props = {
3072
+ activeTab: status,
3073
+ model,
3074
+ documentId: id,
3075
+ document: isCloning ? void 0 : document,
3076
+ meta: isCloning ? void 0 : meta,
3077
+ collectionType
3078
+ };
3079
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3080
+ /* @__PURE__ */ jsx(
3081
+ DescriptionComponentRenderer,
3082
+ {
3083
+ props,
3084
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
3085
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3086
+ }
3087
+ ),
3088
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3089
+ ] });
2901
3090
  };
3091
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3092
+ return /* @__PURE__ */ jsxs(
3093
+ Flex,
3094
+ {
3095
+ ref,
3096
+ tag: "aside",
3097
+ "aria-labelledby": "additional-information",
3098
+ background: "neutral0",
3099
+ borderColor: "neutral150",
3100
+ hasRadius: true,
3101
+ paddingBottom: 4,
3102
+ paddingLeft: 4,
3103
+ paddingRight: 4,
3104
+ paddingTop: 4,
3105
+ shadow: "tableShadow",
3106
+ gap: 3,
3107
+ direction: "column",
3108
+ justifyContent: "stretch",
3109
+ alignItems: "flex-start",
3110
+ children: [
3111
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3112
+ children
3113
+ ]
3114
+ }
3115
+ );
3116
+ });
2902
3117
  const ConfirmBulkActionDialog = ({
2903
3118
  onToggleDialog,
2904
3119
  isOpen = false,
@@ -3143,18 +3358,10 @@ const SelectedEntriesTableContent = ({
3143
3358
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3144
3359
  },
3145
3360
  state: { from: pathname },
3146
- label: formatMessage(
3147
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3148
- {
3149
- target: formatMessage(
3150
- {
3151
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3152
- defaultMessage: "item line {number}"
3153
- },
3154
- { number: index2 + 1 }
3155
- )
3156
- }
3157
- ),
3361
+ label: formatMessage({
3362
+ id: "content-manager.bulk-publish.edit",
3363
+ defaultMessage: "Edit"
3364
+ }),
3158
3365
  target: "_blank",
3159
3366
  marginLeft: "auto",
3160
3367
  variant: "ghost",
@@ -3328,8 +3535,7 @@ const PublishAction = ({ documents, model }) => {
3328
3535
  const refetchList = () => {
3329
3536
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3330
3537
  };
3331
- if (!showPublishButton)
3332
- return null;
3538
+ if (!showPublishButton) return null;
3333
3539
  return {
3334
3540
  actionType: "publish",
3335
3541
  variant: "tertiary",
@@ -3397,8 +3603,7 @@ const DeleteAction = ({ documents, model }) => {
3397
3603
  selectRow([]);
3398
3604
  }
3399
3605
  };
3400
- if (!hasDeletePermission)
3401
- return null;
3606
+ if (!hasDeletePermission) return null;
3402
3607
  return {
3403
3608
  variant: "danger-light",
3404
3609
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3447,8 +3652,7 @@ const UnpublishAction = ({ documents, model }) => {
3447
3652
  }
3448
3653
  };
3449
3654
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3450
- if (!showUnpublishButton)
3451
- return null;
3655
+ if (!showUnpublishButton) return null;
3452
3656
  return {
3453
3657
  variant: "tertiary",
3454
3658
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3553,7 +3757,7 @@ const TableActions = ({ document }) => {
3553
3757
  DescriptionComponentRenderer,
3554
3758
  {
3555
3759
  props,
3556
- descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3760
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3557
3761
  children: (actions2) => {
3558
3762
  const tableRowActions = actions2.filter((action) => {
3559
3763
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3612,6 +3816,7 @@ const EditAction = ({ documentId }) => {
3612
3816
  };
3613
3817
  };
3614
3818
  EditAction.type = "edit";
3819
+ EditAction.position = "table-row";
3615
3820
  const StyledPencil = styled(Pencil)`
3616
3821
  path {
3617
3822
  fill: currentColor;
@@ -3688,6 +3893,7 @@ const CloneAction = ({ model, documentId }) => {
3688
3893
  };
3689
3894
  };
3690
3895
  CloneAction.type = "clone";
3896
+ CloneAction.position = "table-row";
3691
3897
  const StyledDuplicate = styled(Duplicate)`
3692
3898
  path {
3693
3899
  fill: currentColor;
@@ -3774,7 +3980,14 @@ class ContentManagerPlugin {
3774
3980
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3775
3981
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3776
3982
  getBulkActions: () => this.bulkActions,
3777
- getDocumentActions: () => this.documentActions,
3983
+ getDocumentActions: (position) => {
3984
+ if (position) {
3985
+ return this.documentActions.filter(
3986
+ (action) => action.position == void 0 || [action.position].flat().includes(position)
3987
+ );
3988
+ }
3989
+ return this.documentActions;
3990
+ },
3778
3991
  getEditViewSidePanels: () => this.editViewSidePanels,
3779
3992
  getHeaderActions: () => this.headerActions
3780
3993
  }
@@ -3784,10 +3997,8 @@ class ContentManagerPlugin {
3784
3997
  const getPrintableType = (value) => {
3785
3998
  const nativeType = typeof value;
3786
3999
  if (nativeType === "object") {
3787
- if (value === null)
3788
- return "null";
3789
- if (Array.isArray(value))
3790
- return "array";
4000
+ if (value === null) return "null";
4001
+ if (Array.isArray(value)) return "array";
3791
4002
  if (value instanceof Object && value.constructor.name !== "Object") {
3792
4003
  return value.constructor.name;
3793
4004
  }
@@ -3798,17 +4009,27 @@ const HistoryAction = ({ model, document }) => {
3798
4009
  const { formatMessage } = useIntl();
3799
4010
  const [{ query }] = useQueryParams();
3800
4011
  const navigate = useNavigate();
4012
+ const { trackUsage } = useTracking();
4013
+ const { pathname } = useLocation();
3801
4014
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3802
4015
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3803
4016
  return null;
3804
4017
  }
4018
+ const handleOnClick = () => {
4019
+ const destination = { pathname: "history", search: pluginsQueryParams };
4020
+ trackUsage("willNavigate", {
4021
+ from: pathname,
4022
+ to: `${pathname}/${destination.pathname}`
4023
+ });
4024
+ navigate(destination);
4025
+ };
3805
4026
  return {
3806
4027
  icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3807
4028
  label: formatMessage({
3808
4029
  id: "content-manager.history.document-action",
3809
4030
  defaultMessage: "Content History"
3810
4031
  }),
3811
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
4032
+ onClick: handleOnClick,
3812
4033
  disabled: (
3813
4034
  /**
3814
4035
  * The user is creating a new document.
@@ -3830,6 +4051,7 @@ const HistoryAction = ({ model, document }) => {
3830
4051
  };
3831
4052
  };
3832
4053
  HistoryAction.type = "history";
4054
+ HistoryAction.position = "header";
3833
4055
  const historyAdmin = {
3834
4056
  bootstrap(app) {
3835
4057
  const { addDocumentAction } = app.getPlugin("content-manager").apis;
@@ -3876,6 +4098,88 @@ const { setInitialData } = actions;
3876
4098
  const reducer = combineReducers({
3877
4099
  app: reducer$1
3878
4100
  });
4101
+ const previewApi = contentManagerApi.injectEndpoints({
4102
+ endpoints: (builder) => ({
4103
+ getPreviewUrl: builder.query({
4104
+ query({ query, params }) {
4105
+ return {
4106
+ url: `/content-manager/preview/url/${params.contentType}`,
4107
+ method: "GET",
4108
+ config: {
4109
+ params: query
4110
+ }
4111
+ };
4112
+ }
4113
+ })
4114
+ })
4115
+ });
4116
+ const { useGetPreviewUrlQuery } = previewApi;
4117
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4118
+ if (isShown) {
4119
+ return /* @__PURE__ */ jsx(Tooltip, { label, children });
4120
+ }
4121
+ return children;
4122
+ };
4123
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4124
+ const { formatMessage } = useIntl();
4125
+ const { trackUsage } = useTracking();
4126
+ const { pathname } = useLocation();
4127
+ const [{ query }] = useQueryParams();
4128
+ const isModified = useForm("PreviewSidePanel", (state) => state.modified);
4129
+ const { data, error } = useGetPreviewUrlQuery({
4130
+ params: {
4131
+ contentType: model
4132
+ },
4133
+ query: {
4134
+ documentId,
4135
+ locale: document?.locale,
4136
+ status: document?.status
4137
+ }
4138
+ });
4139
+ if (!data?.data?.url || error) {
4140
+ return null;
4141
+ }
4142
+ const trackNavigation = () => {
4143
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4144
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4145
+ };
4146
+ return {
4147
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4148
+ content: /* @__PURE__ */ jsx(
4149
+ ConditionalTooltip,
4150
+ {
4151
+ label: formatMessage({
4152
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4153
+ defaultMessage: "Please save to open the preview"
4154
+ }),
4155
+ isShown: isModified,
4156
+ children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
4157
+ Button,
4158
+ {
4159
+ variant: "tertiary",
4160
+ tag: Link,
4161
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4162
+ onClick: trackNavigation,
4163
+ width: "100%",
4164
+ disabled: isModified,
4165
+ pointerEvents: isModified ? "none" : void 0,
4166
+ tabIndex: isModified ? -1 : void 0,
4167
+ children: formatMessage({
4168
+ id: "content-manager.preview.panel.button",
4169
+ defaultMessage: "Open preview"
4170
+ })
4171
+ }
4172
+ ) })
4173
+ }
4174
+ )
4175
+ };
4176
+ };
4177
+ const previewAdmin = {
4178
+ bootstrap(app) {
4179
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4180
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4181
+ }
4182
+ };
3879
4183
  const index = {
3880
4184
  register(app) {
3881
4185
  const cm = new ContentManagerPlugin();
@@ -3895,7 +4199,7 @@ const index = {
3895
4199
  app.router.addRoute({
3896
4200
  path: "content-manager/*",
3897
4201
  lazy: async () => {
3898
- const { Layout } = await import("./layout-uomiIGbG.mjs");
4202
+ const { Layout } = await import("./layout-W3clJSCy.mjs");
3899
4203
  return {
3900
4204
  Component: Layout
3901
4205
  };
@@ -3908,11 +4212,14 @@ const index = {
3908
4212
  if (typeof historyAdmin.bootstrap === "function") {
3909
4213
  historyAdmin.bootstrap(app);
3910
4214
  }
4215
+ if (typeof previewAdmin.bootstrap === "function") {
4216
+ previewAdmin.bootstrap(app);
4217
+ }
3911
4218
  },
3912
4219
  async registerTrads({ locales }) {
3913
4220
  const importedTrads = await Promise.all(
3914
4221
  locales.map((locale) => {
3915
- 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-CbaIuYoB.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 }) => {
4222
+ 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-CSxLmrh1.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 }) => {
3916
4223
  return {
3917
4224
  data: prefixPluginTranslations(data, PLUGIN_ID),
3918
4225
  locale
@@ -3939,8 +4246,10 @@ export {
3939
4246
  HOOKS as H,
3940
4247
  InjectionZone as I,
3941
4248
  useDocument as J,
3942
- index as K,
3943
- useDocumentActions as L,
4249
+ useGetPreviewUrlQuery as K,
4250
+ index as L,
4251
+ useContentManagerContext as M,
4252
+ useDocumentActions as N,
3944
4253
  Panels as P,
3945
4254
  RelativeTime as R,
3946
4255
  SINGLE_TYPES as S,
@@ -3972,4 +4281,4 @@ export {
3972
4281
  capitalise as y,
3973
4282
  useUpdateContentTypeConfigurationMutation as z
3974
4283
  };
3975
- //# sourceMappingURL=index-BJ6uTqLL.mjs.map
4284
+ //# sourceMappingURL=index-DqasUQ6Q.mjs.map