@strapi/content-manager 0.0.0-experimental.9df68962083938acba06546a7901c68a63266aec → 0.0.0-experimental.9f812af47f0e9db3d5531382c836c2ac0776afdf

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 (220) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  3. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-BSEZcJVB.js} +5 -6
  5. package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-BSEZcJVB.js.map} +1 -1
  6. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-BiASGi7x.mjs} +4 -4
  7. package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-BiASGi7x.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  9. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  10. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-D2rtvneE.js} +5 -6
  12. package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-D2rtvneE.js.map} +1 -1
  13. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-vN4zupij.mjs} +4 -4
  14. package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-vN4zupij.mjs.map} +1 -1
  15. package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-BwisF04Q.js} +63 -13
  16. package/dist/_chunks/EditViewPage-BwisF04Q.js.map +1 -0
  17. package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-_A31Cl4g.mjs} +63 -12
  18. package/dist/_chunks/EditViewPage-_A31Cl4g.mjs.map +1 -0
  19. package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-CvIunNOj.mjs} +405 -256
  20. package/dist/_chunks/Field-CvIunNOj.mjs.map +1 -0
  21. package/dist/_chunks/{Field-Boxf9Ajp.js → Field-Dsu6-FrM.js} +409 -260
  22. package/dist/_chunks/Field-Dsu6-FrM.js.map +1 -0
  23. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  24. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  25. package/dist/_chunks/{Form-DHrru2AV.mjs → Form-DK0fG0Gj.mjs} +37 -18
  26. package/dist/_chunks/Form-DK0fG0Gj.mjs.map +1 -0
  27. package/dist/_chunks/{Form-y5g1SRsh.js → Form-DUwWcCmA.js} +39 -21
  28. package/dist/_chunks/Form-DUwWcCmA.js.map +1 -0
  29. package/dist/_chunks/{History-CqN6K7SX.js → History-CeCDhoJG.js} +81 -114
  30. package/dist/_chunks/History-CeCDhoJG.js.map +1 -0
  31. package/dist/_chunks/{History-Bru_KoeP.mjs → History-DP8gmXpm.mjs} +82 -114
  32. package/dist/_chunks/History-DP8gmXpm.mjs.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BCkO5iuN.mjs} +25 -12
  34. package/dist/_chunks/ListConfigurationPage-BCkO5iuN.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-C-bAd44a.js} +25 -13
  36. package/dist/_chunks/ListConfigurationPage-C-bAd44a.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-BKTZFhsM.js} +121 -81
  38. package/dist/_chunks/ListViewPage-BKTZFhsM.js.map +1 -0
  39. package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-Cf_DgaFV.mjs} +118 -77
  40. package/dist/_chunks/ListViewPage-Cf_DgaFV.mjs.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-D3Cm3v3q.js} +2 -2
  42. package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-D3Cm3v3q.js.map} +1 -1
  43. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-nHIyvJcB.mjs} +2 -2
  44. package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-nHIyvJcB.mjs.map} +1 -1
  45. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-BALVSJ7x.mjs} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-BALVSJ7x.mjs.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-CChGWBj5.js} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-CChGWBj5.js.map} +1 -1
  49. package/dist/_chunks/Preview-C4NBzKUV.mjs +294 -0
  50. package/dist/_chunks/Preview-C4NBzKUV.mjs.map +1 -0
  51. package/dist/_chunks/Preview-CT28Ckpg.js +312 -0
  52. package/dist/_chunks/Preview-CT28Ckpg.js.map +1 -0
  53. package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-C8uC89cT.mjs} +76 -42
  54. package/dist/_chunks/Relations-C8uC89cT.mjs.map +1 -0
  55. package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-CvkPCng_.js} +76 -43
  56. package/dist/_chunks/Relations-CvkPCng_.js.map +1 -0
  57. package/dist/_chunks/{en-fbKQxLGn.js → en-BK8Xyl5I.js} +32 -18
  58. package/dist/_chunks/{en-fbKQxLGn.js.map → en-BK8Xyl5I.js.map} +1 -1
  59. package/dist/_chunks/{en-Ux26r5pl.mjs → en-Dtk_ot79.mjs} +32 -18
  60. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-Dtk_ot79.mjs.map} +1 -1
  61. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  62. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  63. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  64. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  65. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  66. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  67. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  68. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  69. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  70. package/dist/_chunks/{index-DVPWZkbS.js → index-CnX_j5h-.js} +1235 -746
  71. package/dist/_chunks/index-CnX_j5h-.js.map +1 -0
  72. package/dist/_chunks/{index-DJXJw9V5.mjs → index-Dh2aGTGJ.mjs} +1252 -763
  73. package/dist/_chunks/index-Dh2aGTGJ.mjs.map +1 -0
  74. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  75. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  77. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  78. package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-B5qsPihj.mjs} +26 -13
  79. package/dist/_chunks/layout-B5qsPihj.mjs.map +1 -0
  80. package/dist/_chunks/{layout-Dm6fbiQj.js → layout-B_qdWGny.js} +26 -14
  81. package/dist/_chunks/layout-B_qdWGny.js.map +1 -0
  82. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  83. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  84. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  85. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  86. package/dist/_chunks/{relations-CKnpRgrN.js → relations-ChcieiF5.js} +6 -7
  87. package/dist/_chunks/relations-ChcieiF5.js.map +1 -0
  88. package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-DMXpNY-e.mjs} +6 -7
  89. package/dist/_chunks/relations-DMXpNY-e.mjs.map +1 -0
  90. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  91. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  92. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  93. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  94. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  95. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  96. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  97. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  98. package/dist/admin/index.js +2 -1
  99. package/dist/admin/index.js.map +1 -1
  100. package/dist/admin/index.mjs +5 -4
  101. package/dist/admin/src/content-manager.d.ts +3 -2
  102. package/dist/admin/src/exports.d.ts +1 -1
  103. package/dist/admin/src/history/index.d.ts +3 -0
  104. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  105. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  106. package/dist/admin/src/index.d.ts +1 -0
  107. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  108. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
  109. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
  110. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  111. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  112. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  113. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  114. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  115. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  116. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  117. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  118. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  119. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  120. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  121. package/dist/admin/src/preview/index.d.ts +4 -0
  122. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  123. package/dist/admin/src/preview/routes.d.ts +3 -0
  124. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  125. package/dist/admin/src/router.d.ts +1 -1
  126. package/dist/admin/src/services/api.d.ts +1 -1
  127. package/dist/admin/src/services/components.d.ts +2 -2
  128. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  129. package/dist/admin/src/services/documents.d.ts +19 -20
  130. package/dist/admin/src/services/init.d.ts +1 -1
  131. package/dist/admin/src/services/relations.d.ts +2 -2
  132. package/dist/admin/src/services/uid.d.ts +3 -3
  133. package/dist/admin/src/utils/validation.d.ts +4 -1
  134. package/dist/server/index.js +686 -360
  135. package/dist/server/index.js.map +1 -1
  136. package/dist/server/index.mjs +687 -360
  137. package/dist/server/index.mjs.map +1 -1
  138. package/dist/server/src/bootstrap.d.ts.map +1 -1
  139. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  140. package/dist/server/src/controllers/index.d.ts.map +1 -1
  141. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  142. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  143. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  144. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  145. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  146. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  147. package/dist/server/src/history/services/history.d.ts.map +1 -1
  148. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  149. package/dist/server/src/history/services/utils.d.ts +4 -4
  150. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  151. package/dist/server/src/index.d.ts +7 -6
  152. package/dist/server/src/index.d.ts.map +1 -1
  153. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  154. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  155. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  156. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  157. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  158. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  159. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  160. package/dist/server/src/preview/index.d.ts +4 -0
  161. package/dist/server/src/preview/index.d.ts.map +1 -0
  162. package/dist/server/src/preview/routes/index.d.ts +8 -0
  163. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  164. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  165. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  166. package/dist/server/src/preview/services/index.d.ts +16 -0
  167. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  168. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  169. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  170. package/dist/server/src/preview/services/preview.d.ts +12 -0
  171. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  172. package/dist/server/src/preview/utils.d.ts +19 -0
  173. package/dist/server/src/preview/utils.d.ts.map +1 -0
  174. package/dist/server/src/register.d.ts.map +1 -1
  175. package/dist/server/src/routes/index.d.ts.map +1 -1
  176. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  177. package/dist/server/src/services/document-metadata.d.ts +12 -10
  178. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  179. package/dist/server/src/services/index.d.ts +7 -6
  180. package/dist/server/src/services/index.d.ts.map +1 -1
  181. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  182. package/dist/server/src/services/utils/populate.d.ts +2 -2
  183. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  184. package/dist/server/src/utils/index.d.ts +2 -0
  185. package/dist/server/src/utils/index.d.ts.map +1 -1
  186. package/dist/shared/contracts/collection-types.d.ts +3 -1
  187. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  188. package/dist/shared/contracts/index.d.ts +1 -0
  189. package/dist/shared/contracts/index.d.ts.map +1 -1
  190. package/dist/shared/contracts/preview.d.ts +27 -0
  191. package/dist/shared/contracts/preview.d.ts.map +1 -0
  192. package/dist/shared/index.js +4 -0
  193. package/dist/shared/index.js.map +1 -1
  194. package/dist/shared/index.mjs +4 -0
  195. package/dist/shared/index.mjs.map +1 -1
  196. package/package.json +17 -15
  197. package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
  198. package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
  199. package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
  200. package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
  201. package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
  202. package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
  203. package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
  204. package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
  205. package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
  206. package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
  207. package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
  208. package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
  209. package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
  210. package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
  211. package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
  212. package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
  213. package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
  214. package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
  215. package/dist/_chunks/relations-BH_kBSJ0.mjs.map +0 -1
  216. package/dist/_chunks/relations-CKnpRgrN.js.map +0 -1
  217. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  218. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  219. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  220. package/strapi-server.js +0 -3
@@ -1,25 +1,33 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, 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, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
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";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, 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";
8
+ import { useIntl } from "react-intl";
9
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
10
  import { styled } from "styled-components";
11
11
  import * as yup from "yup";
12
12
  import { ValidationError } from "yup";
13
+ import { stringify } from "qs";
13
14
  import pipe from "lodash/fp/pipe";
14
15
  import { intervalToDuration, isPast } from "date-fns";
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";
@@ -49,42 +57,6 @@ const useInjectionZone = (area) => {
49
57
  const [page, position] = area.split(".");
50
58
  return contentManagerPlugin.getInjectedComponents(page, position);
51
59
  };
52
- const HistoryAction = ({ model, document }) => {
53
- const { formatMessage } = useIntl();
54
- const [{ query }] = useQueryParams();
55
- const navigate = useNavigate();
56
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
57
- if (!window.strapi.features.isEnabled("cms-content-history")) {
58
- return null;
59
- }
60
- return {
61
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
62
- label: formatMessage({
63
- id: "content-manager.history.document-action",
64
- defaultMessage: "Content History"
65
- }),
66
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
67
- disabled: (
68
- /**
69
- * The user is creating a new document.
70
- * It hasn't been saved yet, so there's no history to go to
71
- */
72
- !document || /**
73
- * The document has been created but the current dimension has never been saved.
74
- * For example, the user is creating a new locale in an existing document,
75
- * so there's no history for the document in that locale
76
- */
77
- !document.id || /**
78
- * History is only available for content types created by the user.
79
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
80
- * which start with `admin::` or `plugin::`
81
- */
82
- !model.startsWith("api::")
83
- ),
84
- position: "header"
85
- };
86
- };
87
- HistoryAction.type = "history";
88
60
  const ID = "id";
89
61
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
90
62
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -136,6 +108,7 @@ const DocumentRBAC = ({ children, permissions }) => {
136
108
  if (!slug) {
137
109
  throw new Error("Cannot find the slug param in the URL");
138
110
  }
111
+ const [{ rawQuery }] = useQueryParams();
139
112
  const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
140
113
  const contentTypePermissions = React.useMemo(() => {
141
114
  const contentTypePermissions2 = userPermissions.filter(
@@ -146,7 +119,14 @@ const DocumentRBAC = ({ children, permissions }) => {
146
119
  return { ...acc, [action]: [permission] };
147
120
  }, {});
148
121
  }, [slug, userPermissions]);
149
- 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
+ );
150
130
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
151
131
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
152
132
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -194,7 +174,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
194
174
  "Document",
195
175
  "InitialData",
196
176
  "HistoryVersion",
197
- "Relations"
177
+ "Relations",
178
+ "UidAvailability"
198
179
  ]
199
180
  });
200
181
  const documentApi = contentManagerApi.injectEndpoints({
@@ -208,7 +189,12 @@ const documentApi = contentManagerApi.injectEndpoints({
208
189
  params: query
209
190
  }
210
191
  }),
211
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
192
+ invalidatesTags: (_result, error, { model }) => {
193
+ if (error) {
194
+ return [];
195
+ }
196
+ return [{ type: "Document", id: `${model}_LIST` }];
197
+ }
212
198
  }),
213
199
  cloneDocument: builder.mutation({
214
200
  query: ({ model, sourceId, data, params }) => ({
@@ -219,7 +205,10 @@ const documentApi = contentManagerApi.injectEndpoints({
219
205
  params
220
206
  }
221
207
  }),
222
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
208
+ invalidatesTags: (_result, _error, { model }) => [
209
+ { type: "Document", id: `${model}_LIST` },
210
+ { type: "UidAvailability", id: model }
211
+ ]
223
212
  }),
224
213
  /**
225
214
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -236,8 +225,21 @@ const documentApi = contentManagerApi.injectEndpoints({
236
225
  }),
237
226
  invalidatesTags: (result, _error, { model }) => [
238
227
  { type: "Document", id: `${model}_LIST` },
239
- "Relations"
240
- ]
228
+ "Relations",
229
+ { type: "UidAvailability", id: model }
230
+ ],
231
+ transformResponse: (response, meta, arg) => {
232
+ if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
233
+ return {
234
+ data: response,
235
+ meta: {
236
+ availableStatus: [],
237
+ availableLocales: []
238
+ }
239
+ };
240
+ }
241
+ return response;
242
+ }
241
243
  }),
242
244
  deleteDocument: builder.mutation({
243
245
  query: ({ collectionType, model, documentId, params }) => ({
@@ -277,7 +279,8 @@ const documentApi = contentManagerApi.injectEndpoints({
277
279
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
278
280
  },
279
281
  { type: "Document", id: `${model}_LIST` },
280
- "Relations"
282
+ "Relations",
283
+ { type: "UidAvailability", id: model }
281
284
  ];
282
285
  }
283
286
  }),
@@ -290,11 +293,12 @@ const documentApi = contentManagerApi.injectEndpoints({
290
293
  url: `/content-manager/collection-types/${model}`,
291
294
  method: "GET",
292
295
  config: {
293
- params
296
+ params: stringify(params, { encode: true })
294
297
  }
295
298
  }),
296
299
  providesTags: (result, _error, arg) => {
297
300
  return [
301
+ { type: "Document", id: `ALL_LIST` },
298
302
  { type: "Document", id: `${arg.model}_LIST` },
299
303
  ...result?.results.map(({ documentId }) => ({
300
304
  type: "Document",
@@ -333,6 +337,11 @@ const documentApi = contentManagerApi.injectEndpoints({
333
337
  {
334
338
  type: "Document",
335
339
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
340
+ },
341
+ // Make it easy to invalidate all individual documents queries for a model
342
+ {
343
+ type: "Document",
344
+ id: `${model}_ALL_ITEMS`
336
345
  }
337
346
  ];
338
347
  }
@@ -396,8 +405,21 @@ const documentApi = contentManagerApi.injectEndpoints({
396
405
  type: "Document",
397
406
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
398
407
  },
399
- "Relations"
408
+ "Relations",
409
+ { type: "UidAvailability", id: model }
400
410
  ];
411
+ },
412
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
413
+ const patchResult = dispatch(
414
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
415
+ Object.assign(draft.data, data);
416
+ })
417
+ );
418
+ try {
419
+ await queryFulfilled;
420
+ } catch {
421
+ patchResult.undo();
422
+ }
401
423
  }
402
424
  }),
403
425
  unpublishDocument: builder.mutation({
@@ -450,8 +472,7 @@ const {
450
472
  useUnpublishManyDocumentsMutation
451
473
  } = documentApi;
452
474
  const buildValidParams = (query) => {
453
- if (!query)
454
- return query;
475
+ if (!query) return query;
455
476
  const { plugins: _, ...validQueryParams } = {
456
477
  ...query,
457
478
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -459,28 +480,44 @@ const buildValidParams = (query) => {
459
480
  {}
460
481
  )
461
482
  };
462
- if ("_q" in validQueryParams) {
463
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
464
- }
465
483
  return validQueryParams;
466
484
  };
467
485
  const isBaseQueryError = (error) => {
468
486
  return error.name !== void 0;
469
487
  };
470
- const createYupSchema = (attributes = {}, components = {}) => {
488
+ const arrayValidator = (attribute, options) => ({
489
+ message: translatedErrors.required,
490
+ test(value) {
491
+ if (options.status === "draft") {
492
+ return true;
493
+ }
494
+ if (!attribute.required) {
495
+ return true;
496
+ }
497
+ if (!value) {
498
+ return false;
499
+ }
500
+ if (Array.isArray(value) && value.length === 0) {
501
+ return false;
502
+ }
503
+ return true;
504
+ }
505
+ });
506
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
471
507
  const createModelSchema = (attributes2) => yup.object().shape(
472
508
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
473
509
  if (DOCUMENT_META_FIELDS.includes(name)) {
474
510
  return acc;
475
511
  }
476
512
  const validations = [
513
+ addNullableValidation,
477
514
  addRequiredValidation,
478
515
  addMinLengthValidation,
479
516
  addMaxLengthValidation,
480
517
  addMinValidation,
481
518
  addMaxValidation,
482
519
  addRegexValidation
483
- ].map((fn) => fn(attribute));
520
+ ].map((fn) => fn(attribute, options));
484
521
  const transformSchema = pipe(...validations);
485
522
  switch (attribute.type) {
486
523
  case "component": {
@@ -490,12 +527,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
490
527
  ...acc,
491
528
  [name]: transformSchema(
492
529
  yup.array().of(createModelSchema(attributes3).nullable(false))
493
- )
530
+ ).test(arrayValidator(attribute, options))
494
531
  };
495
532
  } else {
496
533
  return {
497
534
  ...acc,
498
- [name]: transformSchema(createModelSchema(attributes3))
535
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
499
536
  };
500
537
  }
501
538
  }
@@ -517,7 +554,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
517
554
  }
518
555
  )
519
556
  )
520
- )
557
+ ).test(arrayValidator(attribute, options))
521
558
  };
522
559
  case "relation":
523
560
  return {
@@ -529,7 +566,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
529
566
  } else if (Array.isArray(value)) {
530
567
  return yup.array().of(
531
568
  yup.object().shape({
532
- id: yup.string().required()
569
+ id: yup.number().required()
533
570
  })
534
571
  );
535
572
  } else if (typeof value === "object") {
@@ -581,6 +618,14 @@ const createAttributeSchema = (attribute) => {
581
618
  if (!value || typeof value === "string" && value.length === 0) {
582
619
  return true;
583
620
  }
621
+ if (typeof value === "object") {
622
+ try {
623
+ JSON.stringify(value);
624
+ return true;
625
+ } catch (err) {
626
+ return false;
627
+ }
628
+ }
584
629
  try {
585
630
  JSON.parse(value);
586
631
  return true;
@@ -599,13 +644,7 @@ const createAttributeSchema = (attribute) => {
599
644
  return yup.mixed();
600
645
  }
601
646
  };
602
- const addRequiredValidation = (attribute) => (schema) => {
603
- if (attribute.required) {
604
- return schema.required({
605
- id: translatedErrors.required.id,
606
- defaultMessage: "This field is required."
607
- });
608
- }
647
+ const nullableSchema = (schema) => {
609
648
  return schema?.nullable ? schema.nullable() : (
610
649
  // In some cases '.nullable' will not be available on the schema.
611
650
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -613,7 +652,22 @@ const addRequiredValidation = (attribute) => (schema) => {
613
652
  schema
614
653
  );
615
654
  };
616
- const addMinLengthValidation = (attribute) => (schema) => {
655
+ const addNullableValidation = () => (schema) => {
656
+ return nullableSchema(schema);
657
+ };
658
+ const addRequiredValidation = (attribute, options) => (schema) => {
659
+ if (options.status === "draft" || !attribute.required) {
660
+ return schema;
661
+ }
662
+ if (attribute.required && "required" in schema) {
663
+ return schema.required(translatedErrors.required);
664
+ }
665
+ return schema;
666
+ };
667
+ const addMinLengthValidation = (attribute, options) => (schema) => {
668
+ if (options.status === "draft") {
669
+ return schema;
670
+ }
617
671
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
618
672
  return schema.min(attribute.minLength, {
619
673
  ...translatedErrors.minLength,
@@ -635,10 +689,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
635
689
  }
636
690
  return schema;
637
691
  };
638
- const addMinValidation = (attribute) => (schema) => {
639
- if ("min" in attribute) {
692
+ const addMinValidation = (attribute, options) => (schema) => {
693
+ if (options.status === "draft") {
694
+ return schema;
695
+ }
696
+ if ("min" in attribute && "min" in schema) {
640
697
  const min = toInteger(attribute.min);
641
- if ("min" in schema && min) {
698
+ if (min) {
642
699
  return schema.min(min, {
643
700
  ...translatedErrors.min,
644
701
  values: {
@@ -756,16 +813,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
756
813
  }, {});
757
814
  return componentsByKey;
758
815
  };
759
- const useDocument = (args, opts) => {
816
+ const HOOKS = {
817
+ /**
818
+ * Hook that allows to mutate the displayed headers of the list view table
819
+ * @constant
820
+ * @type {string}
821
+ */
822
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
823
+ /**
824
+ * Hook that allows to mutate the CM's collection types links pre-set filters
825
+ * @constant
826
+ * @type {string}
827
+ */
828
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
829
+ /**
830
+ * Hook that allows to mutate the CM's edit view layout
831
+ * @constant
832
+ * @type {string}
833
+ */
834
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
835
+ /**
836
+ * Hook that allows to mutate the CM's single types links pre-set filters
837
+ * @constant
838
+ * @type {string}
839
+ */
840
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
841
+ };
842
+ const contentTypesApi = contentManagerApi.injectEndpoints({
843
+ endpoints: (builder) => ({
844
+ getContentTypeConfiguration: builder.query({
845
+ query: (uid) => ({
846
+ url: `/content-manager/content-types/${uid}/configuration`,
847
+ method: "GET"
848
+ }),
849
+ transformResponse: (response) => response.data,
850
+ providesTags: (_result, _error, uid) => [
851
+ { type: "ContentTypesConfiguration", id: uid },
852
+ { type: "ContentTypeSettings", id: "LIST" }
853
+ ]
854
+ }),
855
+ getAllContentTypeSettings: builder.query({
856
+ query: () => "/content-manager/content-types-settings",
857
+ transformResponse: (response) => response.data,
858
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
859
+ }),
860
+ updateContentTypeConfiguration: builder.mutation({
861
+ query: ({ uid, ...body }) => ({
862
+ url: `/content-manager/content-types/${uid}/configuration`,
863
+ method: "PUT",
864
+ data: body
865
+ }),
866
+ transformResponse: (response) => response.data,
867
+ invalidatesTags: (_result, _error, { uid }) => [
868
+ { type: "ContentTypesConfiguration", id: uid },
869
+ { type: "ContentTypeSettings", id: "LIST" },
870
+ // Is this necessary?
871
+ { type: "InitialData" }
872
+ ]
873
+ })
874
+ })
875
+ });
876
+ const {
877
+ useGetContentTypeConfigurationQuery,
878
+ useGetAllContentTypeSettingsQuery,
879
+ useUpdateContentTypeConfigurationMutation
880
+ } = contentTypesApi;
881
+ const checkIfAttributeIsDisplayable = (attribute) => {
882
+ const { type } = attribute;
883
+ if (type === "relation") {
884
+ return !attribute.relation.toLowerCase().includes("morph");
885
+ }
886
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
887
+ };
888
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
889
+ if (!mainFieldName) {
890
+ return void 0;
891
+ }
892
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
893
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
894
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
895
+ );
896
+ return {
897
+ name: mainFieldName,
898
+ type: mainFieldType ?? "string"
899
+ };
900
+ };
901
+ const DEFAULT_SETTINGS = {
902
+ bulkable: false,
903
+ filterable: false,
904
+ searchable: false,
905
+ pagination: false,
906
+ defaultSortBy: "",
907
+ defaultSortOrder: "asc",
908
+ mainField: "id",
909
+ pageSize: 10
910
+ };
911
+ const useDocumentLayout = (model) => {
912
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
913
+ const [{ query }] = useQueryParams();
914
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
760
915
  const { toggleNotification } = useNotification();
761
916
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
917
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
762
918
  const {
763
- currentData: data,
764
- isLoading: isLoadingDocument,
765
- isFetching: isFetchingDocument,
766
- error
767
- } = useGetDocumentQuery(args, opts);
768
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
919
+ data,
920
+ isLoading: isLoadingConfigs,
921
+ error,
922
+ isFetching: isFetchingConfigs
923
+ } = useGetContentTypeConfigurationQuery(model);
924
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
769
925
  React.useEffect(() => {
770
926
  if (error) {
771
927
  toggleNotification({
@@ -773,44 +929,260 @@ const useDocument = (args, opts) => {
773
929
  message: formatAPIError(error)
774
930
  });
775
931
  }
776
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
777
- const validationSchema = React.useMemo(() => {
778
- if (!schema) {
779
- return null;
780
- }
781
- return createYupSchema(schema.attributes, components);
782
- }, [schema, components]);
783
- const validate = React.useCallback(
784
- (document) => {
785
- if (!validationSchema) {
786
- throw new Error(
787
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
788
- );
789
- }
790
- try {
791
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
792
- return null;
793
- } catch (error2) {
794
- if (error2 instanceof ValidationError) {
795
- return getYupValidationErrors(error2);
796
- }
797
- throw error2;
798
- }
932
+ }, [error, formatAPIError, toggleNotification]);
933
+ const editLayout = React.useMemo(
934
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
935
+ layout: [],
936
+ components: {},
937
+ metadatas: {},
938
+ options: {},
939
+ settings: DEFAULT_SETTINGS
799
940
  },
800
- [validationSchema]
941
+ [data, isLoading, schemas, schema, components]
942
+ );
943
+ const listLayout = React.useMemo(() => {
944
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
945
+ layout: [],
946
+ metadatas: {},
947
+ options: {},
948
+ settings: DEFAULT_SETTINGS
949
+ };
950
+ }, [data, isLoading, schemas, schema, components]);
951
+ const { layout: edit } = React.useMemo(
952
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
953
+ layout: editLayout,
954
+ query
955
+ }),
956
+ [editLayout, query, runHookWaterfall]
801
957
  );
802
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
803
958
  return {
804
- components,
805
- document: data?.data,
806
- meta: data?.meta,
959
+ error,
807
960
  isLoading,
808
- schema,
809
- validate
961
+ edit,
962
+ list: listLayout
810
963
  };
811
964
  };
812
- const useDoc = () => {
813
- const { id, slug, collectionType, origin } = useParams();
965
+ const useDocLayout = () => {
966
+ const { model } = useDoc();
967
+ return useDocumentLayout(model);
968
+ };
969
+ const formatEditLayout = (data, {
970
+ schemas,
971
+ schema,
972
+ components
973
+ }) => {
974
+ let currentPanelIndex = 0;
975
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
976
+ data.contentType.layouts.edit,
977
+ schema?.attributes,
978
+ data.contentType.metadatas,
979
+ { configurations: data.components, schemas: components },
980
+ schemas
981
+ ).reduce((panels, row) => {
982
+ if (row.some((field) => field.type === "dynamiczone")) {
983
+ panels.push([row]);
984
+ currentPanelIndex += 2;
985
+ } else {
986
+ if (!panels[currentPanelIndex]) {
987
+ panels.push([row]);
988
+ } else {
989
+ panels[currentPanelIndex].push(row);
990
+ }
991
+ }
992
+ return panels;
993
+ }, []);
994
+ const componentEditAttributes = Object.entries(data.components).reduce(
995
+ (acc, [uid, configuration]) => {
996
+ acc[uid] = {
997
+ layout: convertEditLayoutToFieldLayouts(
998
+ configuration.layouts.edit,
999
+ components[uid].attributes,
1000
+ configuration.metadatas,
1001
+ { configurations: data.components, schemas: components }
1002
+ ),
1003
+ settings: {
1004
+ ...configuration.settings,
1005
+ icon: components[uid].info.icon,
1006
+ displayName: components[uid].info.displayName
1007
+ }
1008
+ };
1009
+ return acc;
1010
+ },
1011
+ {}
1012
+ );
1013
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1014
+ (acc, [attribute, metadata]) => {
1015
+ return {
1016
+ ...acc,
1017
+ [attribute]: metadata.edit
1018
+ };
1019
+ },
1020
+ {}
1021
+ );
1022
+ return {
1023
+ layout: panelledEditAttributes,
1024
+ components: componentEditAttributes,
1025
+ metadatas: editMetadatas,
1026
+ settings: {
1027
+ ...data.contentType.settings,
1028
+ displayName: schema?.info.displayName
1029
+ },
1030
+ options: {
1031
+ ...schema?.options,
1032
+ ...schema?.pluginOptions,
1033
+ ...data.contentType.options
1034
+ }
1035
+ };
1036
+ };
1037
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1038
+ return rows.map(
1039
+ (row) => row.map((field) => {
1040
+ const attribute = attributes[field.name];
1041
+ if (!attribute) {
1042
+ return null;
1043
+ }
1044
+ const { edit: metadata } = metadatas[field.name];
1045
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1046
+ return {
1047
+ attribute,
1048
+ disabled: !metadata.editable,
1049
+ hint: metadata.description,
1050
+ label: metadata.label ?? "",
1051
+ name: field.name,
1052
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1053
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1054
+ schemas,
1055
+ components: components?.schemas ?? {}
1056
+ }),
1057
+ placeholder: metadata.placeholder ?? "",
1058
+ required: attribute.required ?? false,
1059
+ size: field.size,
1060
+ unique: "unique" in attribute ? attribute.unique : false,
1061
+ visible: metadata.visible ?? true,
1062
+ type: attribute.type
1063
+ };
1064
+ }).filter((field) => field !== null)
1065
+ );
1066
+ };
1067
+ const formatListLayout = (data, {
1068
+ schemas,
1069
+ schema,
1070
+ components
1071
+ }) => {
1072
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1073
+ (acc, [attribute, metadata]) => {
1074
+ return {
1075
+ ...acc,
1076
+ [attribute]: metadata.list
1077
+ };
1078
+ },
1079
+ {}
1080
+ );
1081
+ const listAttributes = convertListLayoutToFieldLayouts(
1082
+ data.contentType.layouts.list,
1083
+ schema?.attributes,
1084
+ listMetadatas,
1085
+ { configurations: data.components, schemas: components },
1086
+ schemas
1087
+ );
1088
+ return {
1089
+ layout: listAttributes,
1090
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1091
+ metadatas: listMetadatas,
1092
+ options: {
1093
+ ...schema?.options,
1094
+ ...schema?.pluginOptions,
1095
+ ...data.contentType.options
1096
+ }
1097
+ };
1098
+ };
1099
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1100
+ return columns.map((name) => {
1101
+ const attribute = attributes[name];
1102
+ if (!attribute) {
1103
+ return null;
1104
+ }
1105
+ const metadata = metadatas[name];
1106
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1107
+ return {
1108
+ attribute,
1109
+ label: metadata.label ?? "",
1110
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1111
+ schemas,
1112
+ components: components?.schemas ?? {}
1113
+ }),
1114
+ name,
1115
+ searchable: metadata.searchable ?? true,
1116
+ sortable: metadata.sortable ?? true
1117
+ };
1118
+ }).filter((field) => field !== null);
1119
+ };
1120
+ const useDocument = (args, opts) => {
1121
+ const { toggleNotification } = useNotification();
1122
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1123
+ const {
1124
+ currentData: data,
1125
+ isLoading: isLoadingDocument,
1126
+ isFetching: isFetchingDocument,
1127
+ error
1128
+ } = useGetDocumentQuery(args, {
1129
+ ...opts,
1130
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1131
+ });
1132
+ const {
1133
+ components,
1134
+ schema,
1135
+ schemas,
1136
+ isLoading: isLoadingSchema
1137
+ } = useContentTypeSchema(args.model);
1138
+ React.useEffect(() => {
1139
+ if (error) {
1140
+ toggleNotification({
1141
+ type: "danger",
1142
+ message: formatAPIError(error)
1143
+ });
1144
+ }
1145
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1146
+ const validationSchema = React.useMemo(() => {
1147
+ if (!schema) {
1148
+ return null;
1149
+ }
1150
+ return createYupSchema(schema.attributes, components);
1151
+ }, [schema, components]);
1152
+ const validate = React.useCallback(
1153
+ (document) => {
1154
+ if (!validationSchema) {
1155
+ throw new Error(
1156
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1157
+ );
1158
+ }
1159
+ try {
1160
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1161
+ return null;
1162
+ } catch (error2) {
1163
+ if (error2 instanceof ValidationError) {
1164
+ return getYupValidationErrors(error2);
1165
+ }
1166
+ throw error2;
1167
+ }
1168
+ },
1169
+ [validationSchema]
1170
+ );
1171
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1172
+ const hasError = !!error;
1173
+ return {
1174
+ components,
1175
+ document: data?.data,
1176
+ meta: data?.meta,
1177
+ isLoading,
1178
+ hasError,
1179
+ schema,
1180
+ schemas,
1181
+ validate
1182
+ };
1183
+ };
1184
+ const useDoc = () => {
1185
+ const { id, slug, collectionType, origin } = useParams();
814
1186
  const [{ query }] = useQueryParams();
815
1187
  const params = React.useMemo(() => buildValidParams(query), [query]);
816
1188
  if (!collectionType) {
@@ -819,22 +1191,60 @@ const useDoc = () => {
819
1191
  if (!slug) {
820
1192
  throw new Error("Could not find model in url params");
821
1193
  }
1194
+ const document = useDocument(
1195
+ { documentId: origin || id, model: slug, collectionType, params },
1196
+ {
1197
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1198
+ }
1199
+ );
1200
+ const returnId = origin || id === "create" ? void 0 : id;
822
1201
  return {
823
1202
  collectionType,
824
1203
  model: slug,
825
- id: origin || id === "create" ? void 0 : id,
826
- ...useDocument(
827
- { documentId: origin || id, model: slug, collectionType, params },
828
- {
829
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
830
- }
831
- )
1204
+ id: returnId,
1205
+ ...document
1206
+ };
1207
+ };
1208
+ const useContentManagerContext = () => {
1209
+ const {
1210
+ collectionType,
1211
+ model,
1212
+ id,
1213
+ components,
1214
+ isLoading: isLoadingDoc,
1215
+ schema,
1216
+ schemas
1217
+ } = useDoc();
1218
+ const layout = useDocumentLayout(model);
1219
+ const form = useForm("useContentManagerContext", (state) => state);
1220
+ const isSingleType = collectionType === SINGLE_TYPES;
1221
+ const slug = model;
1222
+ const isCreatingEntry = id === "create";
1223
+ useContentTypeSchema();
1224
+ const isLoading = isLoadingDoc || layout.isLoading;
1225
+ const error = layout.error;
1226
+ return {
1227
+ error,
1228
+ isLoading,
1229
+ // Base metadata
1230
+ model,
1231
+ collectionType,
1232
+ id,
1233
+ slug,
1234
+ isCreatingEntry,
1235
+ isSingleType,
1236
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1237
+ // All schema infos
1238
+ components,
1239
+ contentType: schema,
1240
+ contentTypes: schemas,
1241
+ // Form state
1242
+ form,
1243
+ // layout infos
1244
+ layout
832
1245
  };
833
1246
  };
834
1247
  const prefixPluginTranslations = (trad, pluginId) => {
835
- if (!pluginId) {
836
- throw new TypeError("pluginId can't be empty");
837
- }
838
1248
  return Object.keys(trad).reduce((acc, current) => {
839
1249
  acc[`${pluginId}.${current}`] = trad[current];
840
1250
  return acc;
@@ -850,6 +1260,8 @@ const useDocumentActions = () => {
850
1260
  const { formatMessage } = useIntl();
851
1261
  const { trackUsage } = useTracking();
852
1262
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1263
+ const navigate = useNavigate();
1264
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
853
1265
  const [deleteDocument] = useDeleteDocumentMutation();
854
1266
  const _delete = React.useCallback(
855
1267
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1164,6 +1576,7 @@ const useDocumentActions = () => {
1164
1576
  defaultMessage: "Saved document"
1165
1577
  })
1166
1578
  });
1579
+ setCurrentStep("contentManager.success");
1167
1580
  return res.data;
1168
1581
  } catch (err) {
1169
1582
  toggleNotification({
@@ -1185,7 +1598,6 @@ const useDocumentActions = () => {
1185
1598
  sourceId
1186
1599
  });
1187
1600
  if ("error" in res) {
1188
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1189
1601
  return { error: res.error };
1190
1602
  }
1191
1603
  toggleNotification({
@@ -1204,7 +1616,7 @@ const useDocumentActions = () => {
1204
1616
  throw err;
1205
1617
  }
1206
1618
  },
1207
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1619
+ [autoCloneDocument, formatMessage, toggleNotification]
1208
1620
  );
1209
1621
  const [cloneDocument] = useCloneDocumentMutation();
1210
1622
  const clone = React.useCallback(
@@ -1230,6 +1642,7 @@ const useDocumentActions = () => {
1230
1642
  defaultMessage: "Cloned document"
1231
1643
  })
1232
1644
  });
1645
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1233
1646
  return res.data;
1234
1647
  } catch (err) {
1235
1648
  toggleNotification({
@@ -1240,7 +1653,7 @@ const useDocumentActions = () => {
1240
1653
  throw err;
1241
1654
  }
1242
1655
  },
1243
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1656
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1244
1657
  );
1245
1658
  const [getDoc] = useLazyGetDocumentQuery();
1246
1659
  const getDocument = React.useCallback(
@@ -1265,10 +1678,10 @@ const useDocumentActions = () => {
1265
1678
  update
1266
1679
  };
1267
1680
  };
1268
- const ProtectedHistoryPage = lazy(
1269
- () => import("./History-Bru_KoeP.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1681
+ const ProtectedHistoryPage = React.lazy(
1682
+ () => import("./History-DP8gmXpm.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1270
1683
  );
1271
- const routes$1 = [
1684
+ const routes$2 = [
1272
1685
  {
1273
1686
  path: ":collectionType/:slug/:id/history",
1274
1687
  Component: ProtectedHistoryPage
@@ -1278,32 +1691,45 @@ const routes$1 = [
1278
1691
  Component: ProtectedHistoryPage
1279
1692
  }
1280
1693
  ];
1694
+ const ProtectedPreviewPage = React.lazy(
1695
+ () => import("./Preview-C4NBzKUV.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1696
+ );
1697
+ const routes$1 = [
1698
+ {
1699
+ path: ":collectionType/:slug/:id/preview",
1700
+ Component: ProtectedPreviewPage
1701
+ },
1702
+ {
1703
+ path: ":collectionType/:slug/preview",
1704
+ Component: ProtectedPreviewPage
1705
+ }
1706
+ ];
1281
1707
  const ProtectedEditViewPage = lazy(
1282
- () => import("./EditViewPage-CPj61RMh.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1708
+ () => import("./EditViewPage-_A31Cl4g.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1283
1709
  );
1284
1710
  const ProtectedListViewPage = lazy(
1285
- () => import("./ListViewPage-SID6TRb9.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1711
+ () => import("./ListViewPage-Cf_DgaFV.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1286
1712
  );
1287
1713
  const ProtectedListConfiguration = lazy(
1288
- () => import("./ListConfigurationPage-D8wGABj0.mjs").then((mod) => ({
1714
+ () => import("./ListConfigurationPage-BCkO5iuN.mjs").then((mod) => ({
1289
1715
  default: mod.ProtectedListConfiguration
1290
1716
  }))
1291
1717
  );
1292
1718
  const ProtectedEditConfigurationPage = lazy(
1293
- () => import("./EditConfigurationPage-JT3E7NZy.mjs").then((mod) => ({
1719
+ () => import("./EditConfigurationPage-vN4zupij.mjs").then((mod) => ({
1294
1720
  default: mod.ProtectedEditConfigurationPage
1295
1721
  }))
1296
1722
  );
1297
1723
  const ProtectedComponentConfigurationPage = lazy(
1298
- () => import("./ComponentConfigurationPage-DmwmiFQy.mjs").then((mod) => ({
1724
+ () => import("./ComponentConfigurationPage-BiASGi7x.mjs").then((mod) => ({
1299
1725
  default: mod.ProtectedComponentConfigurationPage
1300
1726
  }))
1301
1727
  );
1302
1728
  const NoPermissions = lazy(
1303
- () => import("./NoPermissionsPage-B7syEq5E.mjs").then((mod) => ({ default: mod.NoPermissions }))
1729
+ () => import("./NoPermissionsPage-BALVSJ7x.mjs").then((mod) => ({ default: mod.NoPermissions }))
1304
1730
  );
1305
1731
  const NoContentType = lazy(
1306
- () => import("./NoContentTypePage-CJ7UXwrQ.mjs").then((mod) => ({ default: mod.NoContentType }))
1732
+ () => import("./NoContentTypePage-nHIyvJcB.mjs").then((mod) => ({ default: mod.NoContentType }))
1307
1733
  );
1308
1734
  const CollectionTypePages = () => {
1309
1735
  const { collectionType } = useParams();
@@ -1315,7 +1741,7 @@ const CollectionTypePages = () => {
1315
1741
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1316
1742
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1317
1743
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1318
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1744
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1319
1745
  const routes = [
1320
1746
  {
1321
1747
  path: LIST_RELATIVE_PATH,
@@ -1349,6 +1775,7 @@ const routes = [
1349
1775
  path: "no-content-types",
1350
1776
  Component: NoContentType
1351
1777
  },
1778
+ ...routes$2,
1352
1779
  ...routes$1
1353
1780
  ];
1354
1781
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1417,12 +1844,14 @@ const DocumentActionButton = (action) => {
1417
1844
  /* @__PURE__ */ jsx(
1418
1845
  Button,
1419
1846
  {
1420
- flex: 1,
1847
+ flex: "auto",
1421
1848
  startIcon: action.icon,
1422
1849
  disabled: action.disabled,
1423
1850
  onClick: handleClick(action),
1424
1851
  justifyContent: "center",
1425
1852
  variant: action.variant || "default",
1853
+ paddingTop: "7px",
1854
+ paddingBottom: "7px",
1426
1855
  children: action.label
1427
1856
  }
1428
1857
  ),
@@ -1430,7 +1859,7 @@ const DocumentActionButton = (action) => {
1430
1859
  DocumentActionConfirmDialog,
1431
1860
  {
1432
1861
  ...action.dialog,
1433
- variant: action.variant,
1862
+ variant: action.dialog?.variant ?? action.variant,
1434
1863
  isOpen: dialogId === action.id,
1435
1864
  onClose: handleClose
1436
1865
  }
@@ -1445,6 +1874,11 @@ const DocumentActionButton = (action) => {
1445
1874
  ) : null
1446
1875
  ] });
1447
1876
  };
1877
+ const MenuItem = styled(Menu.Item)`
1878
+ &:hover {
1879
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1880
+ }
1881
+ `;
1448
1882
  const DocumentActionsMenu = ({
1449
1883
  actions: actions2,
1450
1884
  children,
@@ -1487,9 +1921,9 @@ const DocumentActionsMenu = ({
1487
1921
  disabled: isDisabled,
1488
1922
  size: "S",
1489
1923
  endIcon: null,
1490
- paddingTop: "7px",
1491
- paddingLeft: "9px",
1492
- paddingRight: "9px",
1924
+ paddingTop: "4px",
1925
+ paddingLeft: "7px",
1926
+ paddingRight: "7px",
1493
1927
  variant,
1494
1928
  children: [
1495
1929
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1500,36 +1934,35 @@ const DocumentActionsMenu = ({
1500
1934
  ]
1501
1935
  }
1502
1936
  ),
1503
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1937
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1504
1938
  actions2.map((action) => {
1505
1939
  return /* @__PURE__ */ jsx(
1506
- Menu.Item,
1940
+ MenuItem,
1507
1941
  {
1508
1942
  disabled: action.disabled,
1509
1943
  onSelect: handleClick(action),
1510
1944
  display: "block",
1511
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1512
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1513
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1514
- action.label
1515
- ] }),
1516
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1517
- Flex,
1518
- {
1519
- alignItems: "center",
1520
- background: "alternative100",
1521
- borderStyle: "solid",
1522
- borderColor: "alternative200",
1523
- borderWidth: "1px",
1524
- height: 5,
1525
- paddingLeft: 2,
1526
- paddingRight: 2,
1527
- hasRadius: true,
1528
- color: "alternative600",
1529
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1530
- }
1531
- )
1532
- ] })
1945
+ isVariantDanger: action.variant === "danger",
1946
+ isDisabled: action.disabled,
1947
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
1948
+ Flex,
1949
+ {
1950
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1951
+ gap: 2,
1952
+ tag: "span",
1953
+ children: [
1954
+ /* @__PURE__ */ jsx(
1955
+ Flex,
1956
+ {
1957
+ tag: "span",
1958
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1959
+ children: action.icon
1960
+ }
1961
+ ),
1962
+ action.label
1963
+ ]
1964
+ }
1965
+ ) })
1533
1966
  },
1534
1967
  action.id
1535
1968
  );
@@ -1609,11 +2042,11 @@ const DocumentActionConfirmDialog = ({
1609
2042
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1610
2043
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1611
2044
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1612
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
2045
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1613
2046
  id: "app.components.Button.cancel",
1614
2047
  defaultMessage: "Cancel"
1615
2048
  }) }) }),
1616
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
2049
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1617
2050
  id: "app.components.Button.confirm",
1618
2051
  defaultMessage: "Confirm"
1619
2052
  }) })
@@ -1640,6 +2073,18 @@ const DocumentActionModal = ({
1640
2073
  typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1641
2074
  ] }) });
1642
2075
  };
2076
+ const transformData = (data) => {
2077
+ if (Array.isArray(data)) {
2078
+ return data.map(transformData);
2079
+ }
2080
+ if (typeof data === "object" && data !== null) {
2081
+ if ("apiData" in data) {
2082
+ return data.apiData;
2083
+ }
2084
+ return mapValues(transformData)(data);
2085
+ }
2086
+ return data;
2087
+ };
1643
2088
  const PublishAction$1 = ({
1644
2089
  activeTab,
1645
2090
  documentId,
@@ -1652,13 +2097,18 @@ const PublishAction$1 = ({
1652
2097
  const navigate = useNavigate();
1653
2098
  const { toggleNotification } = useNotification();
1654
2099
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
2100
+ const isListView = useMatch(LIST_PATH) !== null;
1655
2101
  const isCloning = useMatch(CLONE_PATH) !== null;
2102
+ const { id } = useParams();
1656
2103
  const { formatMessage } = useIntl();
1657
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1658
- "PublishAction",
1659
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1660
- );
2104
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1661
2105
  const { publish } = useDocumentActions();
2106
+ const [
2107
+ countDraftRelations,
2108
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2109
+ ] = useLazyGetDraftRelationCountQuery();
2110
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
2111
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1662
2112
  const [{ query, rawQuery }] = useQueryParams();
1663
2113
  const params = React.useMemo(() => buildValidParams(query), [query]);
1664
2114
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1667,10 +2117,107 @@ const PublishAction$1 = ({
1667
2117
  const validate = useForm("PublishAction", (state) => state.validate);
1668
2118
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1669
2119
  const formValues = useForm("PublishAction", ({ values }) => values);
1670
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1671
- if (!schema?.options?.draftAndPublish) {
2120
+ React.useEffect(() => {
2121
+ if (isErrorDraftRelations) {
2122
+ toggleNotification({
2123
+ type: "danger",
2124
+ message: formatMessage({
2125
+ id: getTranslation("error.records.fetch-draft-relatons"),
2126
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2127
+ })
2128
+ });
2129
+ }
2130
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2131
+ React.useEffect(() => {
2132
+ const localDraftRelations = /* @__PURE__ */ new Set();
2133
+ const extractDraftRelations = (data) => {
2134
+ const relations = data.connect || [];
2135
+ relations.forEach((relation) => {
2136
+ if (relation.status === "draft") {
2137
+ localDraftRelations.add(relation.id);
2138
+ }
2139
+ });
2140
+ };
2141
+ const traverseAndExtract = (data) => {
2142
+ Object.entries(data).forEach(([key, value]) => {
2143
+ if (key === "connect" && Array.isArray(value)) {
2144
+ extractDraftRelations({ connect: value });
2145
+ } else if (typeof value === "object" && value !== null) {
2146
+ traverseAndExtract(value);
2147
+ }
2148
+ });
2149
+ };
2150
+ if (!documentId || modified) {
2151
+ traverseAndExtract(formValues);
2152
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2153
+ }
2154
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2155
+ React.useEffect(() => {
2156
+ if (!document || !document.documentId || isListView) {
2157
+ return;
2158
+ }
2159
+ const fetchDraftRelationsCount = async () => {
2160
+ const { data, error } = await countDraftRelations({
2161
+ collectionType,
2162
+ model,
2163
+ documentId,
2164
+ params
2165
+ });
2166
+ if (error) {
2167
+ throw error;
2168
+ }
2169
+ if (data) {
2170
+ setServerCountOfDraftRelations(data.data);
2171
+ }
2172
+ };
2173
+ fetchDraftRelationsCount();
2174
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
2175
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
2176
+ if (!schema?.options?.draftAndPublish) {
1672
2177
  return null;
1673
2178
  }
2179
+ const performPublish = async () => {
2180
+ setSubmitting(true);
2181
+ try {
2182
+ const { errors } = await validate(true, {
2183
+ status: "published"
2184
+ });
2185
+ if (errors) {
2186
+ toggleNotification({
2187
+ type: "danger",
2188
+ message: formatMessage({
2189
+ id: "content-manager.validation.error",
2190
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2191
+ })
2192
+ });
2193
+ return;
2194
+ }
2195
+ const res = await publish(
2196
+ {
2197
+ collectionType,
2198
+ model,
2199
+ documentId,
2200
+ params
2201
+ },
2202
+ transformData(formValues)
2203
+ );
2204
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2205
+ if (id === "create") {
2206
+ navigate({
2207
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2208
+ search: rawQuery
2209
+ });
2210
+ }
2211
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2212
+ setErrors(formatValidationErrors(res.error));
2213
+ }
2214
+ } finally {
2215
+ setSubmitting(false);
2216
+ }
2217
+ };
2218
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2219
+ const enableDraftRelationsCount = false;
2220
+ const hasDraftRelations = enableDraftRelationsCount;
1674
2221
  return {
1675
2222
  /**
1676
2223
  * Disabled when:
@@ -1680,52 +2227,40 @@ const PublishAction$1 = ({
1680
2227
  * - the document is already published & not modified
1681
2228
  * - the document is being created & not modified
1682
2229
  * - the user doesn't have the permission to publish
1683
- * - the user doesn't have the permission to create a new document
1684
- * - the user doesn't have the permission to update the document
1685
2230
  */
1686
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2231
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1687
2232
  label: formatMessage({
1688
2233
  id: "app.utils.publish",
1689
2234
  defaultMessage: "Publish"
1690
2235
  }),
1691
2236
  onClick: async () => {
1692
- setSubmitting(true);
1693
- try {
1694
- const { errors } = await validate();
1695
- if (errors) {
1696
- toggleNotification({
1697
- type: "danger",
1698
- message: formatMessage({
1699
- id: "content-manager.validation.error",
1700
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1701
- })
1702
- });
1703
- return;
1704
- }
1705
- const res = await publish(
1706
- {
1707
- collectionType,
1708
- model,
1709
- documentId,
1710
- params
1711
- },
1712
- formValues
1713
- );
1714
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1715
- navigate({
1716
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1717
- search: rawQuery
1718
- });
1719
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1720
- setErrors(formatValidationErrors(res.error));
2237
+ await performPublish();
2238
+ },
2239
+ dialog: hasDraftRelations ? {
2240
+ type: "dialog",
2241
+ variant: "danger",
2242
+ footer: null,
2243
+ title: formatMessage({
2244
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2245
+ defaultMessage: "Confirmation"
2246
+ }),
2247
+ content: formatMessage(
2248
+ {
2249
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2250
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2251
+ },
2252
+ {
2253
+ count: totalDraftRelations
1721
2254
  }
1722
- } finally {
1723
- setSubmitting(false);
2255
+ ),
2256
+ onConfirm: async () => {
2257
+ await performPublish();
1724
2258
  }
1725
- }
2259
+ } : void 0
1726
2260
  };
1727
2261
  };
1728
2262
  PublishAction$1.type = "publish";
2263
+ PublishAction$1.position = "panel";
1729
2264
  const UpdateAction = ({
1730
2265
  activeTab,
1731
2266
  documentId,
@@ -1738,10 +2273,6 @@ const UpdateAction = ({
1738
2273
  const cloneMatch = useMatch(CLONE_PATH);
1739
2274
  const isCloning = cloneMatch !== null;
1740
2275
  const { formatMessage } = useIntl();
1741
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1742
- canCreate: canCreate2,
1743
- canUpdate: canUpdate2
1744
- }));
1745
2276
  const { create, update, clone } = useDocumentActions();
1746
2277
  const [{ query, rawQuery }] = useQueryParams();
1747
2278
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1752,90 +2283,134 @@ const UpdateAction = ({
1752
2283
  const validate = useForm("UpdateAction", (state) => state.validate);
1753
2284
  const setErrors = useForm("UpdateAction", (state) => state.setErrors);
1754
2285
  const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1755
- return {
1756
- /**
1757
- * Disabled when:
1758
- * - the form is submitting
1759
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1760
- * - the active tab is the published tab
1761
- * - the user doesn't have the permission to create a new document
1762
- * - the user doesn't have the permission to update the document
1763
- */
1764
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1765
- label: formatMessage({
1766
- id: "content-manager.containers.Edit.save",
1767
- defaultMessage: "Save"
1768
- }),
1769
- onClick: async () => {
1770
- setSubmitting(true);
1771
- try {
1772
- const { errors } = await validate();
1773
- if (errors) {
1774
- toggleNotification({
1775
- type: "danger",
1776
- message: formatMessage({
1777
- id: "content-manager.validation.error",
1778
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1779
- })
1780
- });
1781
- return;
1782
- }
1783
- if (isCloning) {
1784
- const res = await clone(
2286
+ const handleUpdate = React.useCallback(async () => {
2287
+ setSubmitting(true);
2288
+ try {
2289
+ if (!modified) {
2290
+ return;
2291
+ }
2292
+ const { errors } = await validate(true, {
2293
+ status: "draft"
2294
+ });
2295
+ if (errors) {
2296
+ toggleNotification({
2297
+ type: "danger",
2298
+ message: formatMessage({
2299
+ id: "content-manager.validation.error",
2300
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2301
+ })
2302
+ });
2303
+ return;
2304
+ }
2305
+ if (isCloning) {
2306
+ const res = await clone(
2307
+ {
2308
+ model,
2309
+ documentId: cloneMatch.params.origin,
2310
+ params
2311
+ },
2312
+ transformData(document)
2313
+ );
2314
+ if ("data" in res) {
2315
+ navigate(
1785
2316
  {
1786
- model,
1787
- documentId: cloneMatch.params.origin,
1788
- params
1789
- },
1790
- document
1791
- );
1792
- if ("data" in res) {
1793
- navigate({
1794
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2317
+ pathname: `../${res.data.documentId}`,
1795
2318
  search: rawQuery
1796
- });
1797
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1798
- setErrors(formatValidationErrors(res.error));
1799
- }
1800
- } else if (documentId || collectionType === SINGLE_TYPES) {
1801
- const res = await update(
1802
- {
1803
- collectionType,
1804
- model,
1805
- documentId,
1806
- params
1807
2319
  },
1808
- document
2320
+ { relative: "path" }
1809
2321
  );
1810
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1811
- setErrors(formatValidationErrors(res.error));
1812
- } else {
1813
- resetForm();
1814
- }
2322
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2323
+ setErrors(formatValidationErrors(res.error));
2324
+ }
2325
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2326
+ const res = await update(
2327
+ {
2328
+ collectionType,
2329
+ model,
2330
+ documentId,
2331
+ params
2332
+ },
2333
+ transformData(document)
2334
+ );
2335
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2336
+ setErrors(formatValidationErrors(res.error));
1815
2337
  } else {
1816
- const res = await create(
2338
+ resetForm();
2339
+ }
2340
+ } else {
2341
+ const res = await create(
2342
+ {
2343
+ model,
2344
+ params
2345
+ },
2346
+ transformData(document)
2347
+ );
2348
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2349
+ navigate(
1817
2350
  {
1818
- model,
1819
- params
2351
+ pathname: `../${res.data.documentId}`,
2352
+ search: rawQuery
1820
2353
  },
1821
- document
2354
+ { replace: true, relative: "path" }
1822
2355
  );
1823
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1824
- navigate({
1825
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1826
- search: rawQuery
1827
- });
1828
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1829
- setErrors(formatValidationErrors(res.error));
1830
- }
2356
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2357
+ setErrors(formatValidationErrors(res.error));
1831
2358
  }
1832
- } finally {
1833
- setSubmitting(false);
1834
2359
  }
2360
+ } finally {
2361
+ setSubmitting(false);
1835
2362
  }
2363
+ }, [
2364
+ clone,
2365
+ cloneMatch?.params.origin,
2366
+ collectionType,
2367
+ create,
2368
+ document,
2369
+ documentId,
2370
+ formatMessage,
2371
+ formatValidationErrors,
2372
+ isCloning,
2373
+ model,
2374
+ modified,
2375
+ navigate,
2376
+ params,
2377
+ rawQuery,
2378
+ resetForm,
2379
+ setErrors,
2380
+ setSubmitting,
2381
+ toggleNotification,
2382
+ update,
2383
+ validate
2384
+ ]);
2385
+ React.useEffect(() => {
2386
+ const handleKeyDown = (e) => {
2387
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2388
+ e.preventDefault();
2389
+ handleUpdate();
2390
+ }
2391
+ };
2392
+ window.addEventListener("keydown", handleKeyDown);
2393
+ return () => {
2394
+ window.removeEventListener("keydown", handleKeyDown);
2395
+ };
2396
+ }, [handleUpdate]);
2397
+ return {
2398
+ /**
2399
+ * Disabled when:
2400
+ * - the form is submitting
2401
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2402
+ * - the active tab is the published tab
2403
+ */
2404
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2405
+ label: formatMessage({
2406
+ id: "global.save",
2407
+ defaultMessage: "Save"
2408
+ }),
2409
+ onClick: handleUpdate
1836
2410
  };
1837
2411
  };
1838
2412
  UpdateAction.type = "update";
2413
+ UpdateAction.position = "panel";
1839
2414
  const UNPUBLISH_DRAFT_OPTIONS = {
1840
2415
  KEEP: "keep",
1841
2416
  DISCARD: "discard"
@@ -1868,7 +2443,7 @@ const UnpublishAction$1 = ({
1868
2443
  id: "app.utils.unpublish",
1869
2444
  defaultMessage: "Unpublish"
1870
2445
  }),
1871
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2446
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1872
2447
  onClick: async () => {
1873
2448
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1874
2449
  if (!documentId) {
@@ -1958,6 +2533,7 @@ const UnpublishAction$1 = ({
1958
2533
  };
1959
2534
  };
1960
2535
  UnpublishAction$1.type = "unpublish";
2536
+ UnpublishAction$1.position = "panel";
1961
2537
  const DiscardAction = ({
1962
2538
  activeTab,
1963
2539
  documentId,
@@ -1980,7 +2556,7 @@ const DiscardAction = ({
1980
2556
  id: "content-manager.actions.discard.label",
1981
2557
  defaultMessage: "Discard changes"
1982
2558
  }),
1983
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2559
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1984
2560
  position: ["panel", "table-row"],
1985
2561
  variant: "danger",
1986
2562
  dialog: {
@@ -2008,11 +2584,7 @@ const DiscardAction = ({
2008
2584
  };
2009
2585
  };
2010
2586
  DiscardAction.type = "discard";
2011
- const StyledCrossCircle = styled(CrossCircle)`
2012
- path {
2013
- fill: currentColor;
2014
- }
2015
- `;
2587
+ DiscardAction.position = "panel";
2016
2588
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2017
2589
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2018
2590
  const RelativeTime = React.forwardRef(
@@ -2025,7 +2597,7 @@ const RelativeTime = React.forwardRef(
2025
2597
  });
2026
2598
  const unit = intervals.find((intervalUnit) => {
2027
2599
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2028
- });
2600
+ }) ?? "seconds";
2029
2601
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2030
2602
  const customInterval = customIntervals.find(
2031
2603
  (custom) => interval[custom.unit] < custom.threshold
@@ -2059,34 +2631,34 @@ const getDisplayName = ({
2059
2631
  return email ?? "";
2060
2632
  };
2061
2633
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2062
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2063
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2064
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2634
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2635
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2636
+ const { formatMessage } = useIntl();
2637
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2638
+ id: `content-manager.containers.List.${status}`,
2639
+ defaultMessage: capitalise(status)
2640
+ }) }) });
2065
2641
  };
2066
2642
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2067
2643
  const { formatMessage } = useIntl();
2068
2644
  const isCloning = useMatch(CLONE_PATH) !== null;
2645
+ const params = useParams();
2069
2646
  const title = isCreating ? formatMessage({
2070
2647
  id: "content-manager.containers.edit.title.new",
2071
2648
  defaultMessage: "Create an entry"
2072
2649
  }) : documentTitle;
2073
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2074
- /* @__PURE__ */ jsx(BackButton, {}),
2075
- /* @__PURE__ */ jsxs(
2076
- Flex,
2650
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2651
+ /* @__PURE__ */ jsx(
2652
+ BackButton,
2077
2653
  {
2078
- width: "100%",
2079
- justifyContent: "space-between",
2080
- paddingTop: 1,
2081
- gap: "80px",
2082
- alignItems: "flex-start",
2083
- children: [
2084
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2085
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2086
- ]
2654
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2087
2655
  }
2088
2656
  ),
2089
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2657
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2658
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2659
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2660
+ ] }),
2661
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2090
2662
  ] });
2091
2663
  };
2092
2664
  const HeaderToolbar = () => {
@@ -2132,7 +2704,7 @@ const HeaderToolbar = () => {
2132
2704
  meta: isCloning ? void 0 : meta,
2133
2705
  collectionType
2134
2706
  },
2135
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2707
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2136
2708
  children: (actions2) => {
2137
2709
  const headerActions = actions2.filter((action) => {
2138
2710
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2169,12 +2741,12 @@ const Information = ({ activeTab }) => {
2169
2741
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2170
2742
  label: formatMessage({
2171
2743
  id: "content-manager.containers.edit.information.last-published.label",
2172
- defaultMessage: "Last published"
2744
+ defaultMessage: "Published"
2173
2745
  }),
2174
2746
  value: formatMessage(
2175
2747
  {
2176
2748
  id: "content-manager.containers.edit.information.last-published.value",
2177
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2749
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2178
2750
  },
2179
2751
  {
2180
2752
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2187,12 +2759,12 @@ const Information = ({ activeTab }) => {
2187
2759
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2188
2760
  label: formatMessage({
2189
2761
  id: "content-manager.containers.edit.information.last-draft.label",
2190
- defaultMessage: "Last draft"
2762
+ defaultMessage: "Updated"
2191
2763
  }),
2192
2764
  value: formatMessage(
2193
2765
  {
2194
2766
  id: "content-manager.containers.edit.information.last-draft.value",
2195
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2767
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2196
2768
  },
2197
2769
  {
2198
2770
  time: /* @__PURE__ */ jsx(
@@ -2210,12 +2782,12 @@ const Information = ({ activeTab }) => {
2210
2782
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2211
2783
  label: formatMessage({
2212
2784
  id: "content-manager.containers.edit.information.document.label",
2213
- defaultMessage: "Document"
2785
+ defaultMessage: "Created"
2214
2786
  }),
2215
2787
  value: formatMessage(
2216
2788
  {
2217
2789
  id: "content-manager.containers.edit.information.document.value",
2218
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2790
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2219
2791
  },
2220
2792
  {
2221
2793
  time: /* @__PURE__ */ jsx(
@@ -2253,25 +2825,77 @@ const Information = ({ activeTab }) => {
2253
2825
  );
2254
2826
  };
2255
2827
  const HeaderActions = ({ actions: actions2 }) => {
2256
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2257
- if ("options" in action) {
2828
+ const [dialogId, setDialogId] = React.useState(null);
2829
+ const handleClick = (action) => async (e) => {
2830
+ if (!("options" in action)) {
2831
+ const { onClick = () => false, dialog, id } = action;
2832
+ const muteDialog = await onClick(e);
2833
+ if (dialog && !muteDialog) {
2834
+ e.preventDefault();
2835
+ setDialogId(id);
2836
+ }
2837
+ }
2838
+ };
2839
+ const handleClose = () => {
2840
+ setDialogId(null);
2841
+ };
2842
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2843
+ if (action.options) {
2258
2844
  return /* @__PURE__ */ jsx(
2259
2845
  SingleSelect,
2260
2846
  {
2261
2847
  size: "S",
2262
- disabled: action.disabled,
2263
- "aria-label": action.label,
2264
2848
  onChange: action.onSelect,
2265
- value: action.value,
2849
+ "aria-label": action.label,
2850
+ ...action,
2266
2851
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2267
2852
  },
2268
2853
  action.id
2269
2854
  );
2270
2855
  } else {
2271
- return null;
2856
+ if (action.type === "icon") {
2857
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2858
+ /* @__PURE__ */ jsx(
2859
+ IconButton,
2860
+ {
2861
+ disabled: action.disabled,
2862
+ label: action.label,
2863
+ size: "S",
2864
+ onClick: handleClick(action),
2865
+ children: action.icon
2866
+ }
2867
+ ),
2868
+ action.dialog ? /* @__PURE__ */ jsx(
2869
+ HeaderActionDialog,
2870
+ {
2871
+ ...action.dialog,
2872
+ isOpen: dialogId === action.id,
2873
+ onClose: handleClose
2874
+ }
2875
+ ) : null
2876
+ ] }, action.id);
2877
+ }
2272
2878
  }
2273
2879
  }) });
2274
2880
  };
2881
+ const HeaderActionDialog = ({
2882
+ onClose,
2883
+ onCancel,
2884
+ title,
2885
+ content: Content,
2886
+ isOpen
2887
+ }) => {
2888
+ const handleClose = async () => {
2889
+ if (onCancel) {
2890
+ await onCancel();
2891
+ }
2892
+ onClose();
2893
+ };
2894
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2895
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2896
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2897
+ ] }) });
2898
+ };
2275
2899
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2276
2900
  const navigate = useNavigate();
2277
2901
  const { formatMessage } = useIntl();
@@ -2288,6 +2912,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2288
2912
  };
2289
2913
  };
2290
2914
  ConfigureTheViewAction.type = "configure-the-view";
2915
+ ConfigureTheViewAction.position = "header";
2291
2916
  const EditTheModelAction = ({ model }) => {
2292
2917
  const navigate = useNavigate();
2293
2918
  const { formatMessage } = useIntl();
@@ -2304,6 +2929,7 @@ const EditTheModelAction = ({ model }) => {
2304
2929
  };
2305
2930
  };
2306
2931
  EditTheModelAction.type = "edit-the-model";
2932
+ EditTheModelAction.position = "header";
2307
2933
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2308
2934
  const navigate = useNavigate();
2309
2935
  const { formatMessage } = useIntl();
@@ -2312,12 +2938,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2312
2938
  const { delete: deleteAction } = useDocumentActions();
2313
2939
  const { toggleNotification } = useNotification();
2314
2940
  const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2941
+ const isLocalized = document?.locale != null;
2315
2942
  return {
2316
2943
  disabled: !canDelete || !document,
2317
- label: formatMessage({
2318
- id: "content-manager.actions.delete.label",
2319
- defaultMessage: "Delete document"
2320
- }),
2944
+ label: formatMessage(
2945
+ {
2946
+ id: "content-manager.actions.delete.label",
2947
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2948
+ },
2949
+ { isLocalized }
2950
+ ),
2321
2951
  icon: /* @__PURE__ */ jsx(Trash, {}),
2322
2952
  dialog: {
2323
2953
  type: "dialog",
@@ -2373,403 +3003,102 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2373
3003
  };
2374
3004
  };
2375
3005
  DeleteAction$1.type = "delete";
3006
+ DeleteAction$1.position = ["header", "table-row"];
2376
3007
  const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2377
3008
  const Panels = () => {
2378
3009
  const isCloning = useMatch(CLONE_PATH) !== null;
2379
3010
  const [
2380
3011
  {
2381
- query: { status }
2382
- }
2383
- ] = useQueryParams({
2384
- status: "draft"
2385
- });
2386
- const { model, id, document, meta, collectionType } = useDoc();
2387
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2388
- const props = {
2389
- activeTab: status,
2390
- model,
2391
- documentId: id,
2392
- document: isCloning ? void 0 : document,
2393
- meta: isCloning ? void 0 : meta,
2394
- collectionType
2395
- };
2396
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2397
- DescriptionComponentRenderer,
2398
- {
2399
- props,
2400
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2401
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2402
- }
2403
- ) });
2404
- };
2405
- const ActionsPanel = () => {
2406
- const { formatMessage } = useIntl();
2407
- return {
2408
- title: formatMessage({
2409
- id: "content-manager.containers.edit.panels.default.title",
2410
- defaultMessage: "Document"
2411
- }),
2412
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2413
- };
2414
- };
2415
- ActionsPanel.type = "actions";
2416
- const ActionsPanelContent = () => {
2417
- const isCloning = useMatch(CLONE_PATH) !== null;
2418
- const [
2419
- {
2420
- query: { status = "draft" }
2421
- }
2422
- ] = useQueryParams();
2423
- const { model, id, document, meta, collectionType } = useDoc();
2424
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2425
- const props = {
2426
- activeTab: status,
2427
- model,
2428
- documentId: id,
2429
- document: isCloning ? void 0 : document,
2430
- meta: isCloning ? void 0 : meta,
2431
- collectionType
2432
- };
2433
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2434
- /* @__PURE__ */ jsx(
2435
- DescriptionComponentRenderer,
2436
- {
2437
- props,
2438
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2439
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2440
- }
2441
- ),
2442
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2443
- ] });
2444
- };
2445
- const Panel = React.forwardRef(({ children, title }, ref) => {
2446
- return /* @__PURE__ */ jsxs(
2447
- Flex,
2448
- {
2449
- ref,
2450
- tag: "aside",
2451
- "aria-labelledby": "additional-information",
2452
- background: "neutral0",
2453
- borderColor: "neutral150",
2454
- hasRadius: true,
2455
- paddingBottom: 4,
2456
- paddingLeft: 4,
2457
- paddingRight: 4,
2458
- paddingTop: 4,
2459
- shadow: "tableShadow",
2460
- gap: 3,
2461
- direction: "column",
2462
- justifyContent: "stretch",
2463
- alignItems: "flex-start",
2464
- children: [
2465
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2466
- children
2467
- ]
2468
- }
2469
- );
2470
- });
2471
- const HOOKS = {
2472
- /**
2473
- * Hook that allows to mutate the displayed headers of the list view table
2474
- * @constant
2475
- * @type {string}
2476
- */
2477
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2478
- /**
2479
- * Hook that allows to mutate the CM's collection types links pre-set filters
2480
- * @constant
2481
- * @type {string}
2482
- */
2483
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2484
- /**
2485
- * Hook that allows to mutate the CM's edit view layout
2486
- * @constant
2487
- * @type {string}
2488
- */
2489
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2490
- /**
2491
- * Hook that allows to mutate the CM's single types links pre-set filters
2492
- * @constant
2493
- * @type {string}
2494
- */
2495
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2496
- };
2497
- const contentTypesApi = contentManagerApi.injectEndpoints({
2498
- endpoints: (builder) => ({
2499
- getContentTypeConfiguration: builder.query({
2500
- query: (uid) => ({
2501
- url: `/content-manager/content-types/${uid}/configuration`,
2502
- method: "GET"
2503
- }),
2504
- transformResponse: (response) => response.data,
2505
- providesTags: (_result, _error, uid) => [
2506
- { type: "ContentTypesConfiguration", id: uid },
2507
- { type: "ContentTypeSettings", id: "LIST" }
2508
- ]
2509
- }),
2510
- getAllContentTypeSettings: builder.query({
2511
- query: () => "/content-manager/content-types-settings",
2512
- transformResponse: (response) => response.data,
2513
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2514
- }),
2515
- updateContentTypeConfiguration: builder.mutation({
2516
- query: ({ uid, ...body }) => ({
2517
- url: `/content-manager/content-types/${uid}/configuration`,
2518
- method: "PUT",
2519
- data: body
2520
- }),
2521
- transformResponse: (response) => response.data,
2522
- invalidatesTags: (_result, _error, { uid }) => [
2523
- { type: "ContentTypesConfiguration", id: uid },
2524
- { type: "ContentTypeSettings", id: "LIST" },
2525
- // Is this necessary?
2526
- { type: "InitialData" }
2527
- ]
2528
- })
2529
- })
2530
- });
2531
- const {
2532
- useGetContentTypeConfigurationQuery,
2533
- useGetAllContentTypeSettingsQuery,
2534
- useUpdateContentTypeConfigurationMutation
2535
- } = contentTypesApi;
2536
- const checkIfAttributeIsDisplayable = (attribute) => {
2537
- const { type } = attribute;
2538
- if (type === "relation") {
2539
- return !attribute.relation.toLowerCase().includes("morph");
2540
- }
2541
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2542
- };
2543
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2544
- if (!mainFieldName) {
2545
- return void 0;
2546
- }
2547
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2548
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2549
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2550
- );
2551
- return {
2552
- name: mainFieldName,
2553
- type: mainFieldType ?? "string"
2554
- };
2555
- };
2556
- const DEFAULT_SETTINGS = {
2557
- bulkable: false,
2558
- filterable: false,
2559
- searchable: false,
2560
- pagination: false,
2561
- defaultSortBy: "",
2562
- defaultSortOrder: "asc",
2563
- mainField: "id",
2564
- pageSize: 10
2565
- };
2566
- const useDocumentLayout = (model) => {
2567
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2568
- const [{ query }] = useQueryParams();
2569
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2570
- const { toggleNotification } = useNotification();
2571
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2572
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2573
- const {
2574
- data,
2575
- isLoading: isLoadingConfigs,
2576
- error,
2577
- isFetching: isFetchingConfigs
2578
- } = useGetContentTypeConfigurationQuery(model);
2579
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2580
- React.useEffect(() => {
2581
- if (error) {
2582
- toggleNotification({
2583
- type: "danger",
2584
- message: formatAPIError(error)
2585
- });
2586
- }
2587
- }, [error, formatAPIError, toggleNotification]);
2588
- const editLayout = React.useMemo(
2589
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2590
- layout: [],
2591
- components: {},
2592
- metadatas: {},
2593
- options: {},
2594
- settings: DEFAULT_SETTINGS
2595
- },
2596
- [data, isLoading, schemas, schema, components]
2597
- );
2598
- const listLayout = React.useMemo(() => {
2599
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2600
- layout: [],
2601
- metadatas: {},
2602
- options: {},
2603
- settings: DEFAULT_SETTINGS
2604
- };
2605
- }, [data, isLoading, schemas, schema, components]);
2606
- const { layout: edit } = React.useMemo(
2607
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2608
- layout: editLayout,
2609
- query
2610
- }),
2611
- [editLayout, query, runHookWaterfall]
2612
- );
2613
- return {
2614
- error,
2615
- isLoading,
2616
- edit,
2617
- list: listLayout
2618
- };
2619
- };
2620
- const useDocLayout = () => {
2621
- const { model } = useDoc();
2622
- return useDocumentLayout(model);
2623
- };
2624
- const formatEditLayout = (data, {
2625
- schemas,
2626
- schema,
2627
- components
2628
- }) => {
2629
- let currentPanelIndex = 0;
2630
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2631
- data.contentType.layouts.edit,
2632
- schema?.attributes,
2633
- data.contentType.metadatas,
2634
- { configurations: data.components, schemas: components },
2635
- schemas
2636
- ).reduce((panels, row) => {
2637
- if (row.some((field) => field.type === "dynamiczone")) {
2638
- panels.push([row]);
2639
- currentPanelIndex += 2;
2640
- } else {
2641
- if (!panels[currentPanelIndex]) {
2642
- panels.push([]);
2643
- }
2644
- panels[currentPanelIndex].push(row);
2645
- }
2646
- return panels;
2647
- }, []);
2648
- const componentEditAttributes = Object.entries(data.components).reduce(
2649
- (acc, [uid, configuration]) => {
2650
- acc[uid] = {
2651
- layout: convertEditLayoutToFieldLayouts(
2652
- configuration.layouts.edit,
2653
- components[uid].attributes,
2654
- configuration.metadatas
2655
- ),
2656
- settings: {
2657
- ...configuration.settings,
2658
- icon: components[uid].info.icon,
2659
- displayName: components[uid].info.displayName
2660
- }
2661
- };
2662
- return acc;
2663
- },
2664
- {}
2665
- );
2666
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2667
- (acc, [attribute, metadata]) => {
2668
- return {
2669
- ...acc,
2670
- [attribute]: metadata.edit
2671
- };
2672
- },
2673
- {}
2674
- );
2675
- return {
2676
- layout: panelledEditAttributes,
2677
- components: componentEditAttributes,
2678
- metadatas: editMetadatas,
2679
- settings: {
2680
- ...data.contentType.settings,
2681
- displayName: schema?.info.displayName
2682
- },
2683
- options: {
2684
- ...schema?.options,
2685
- ...schema?.pluginOptions,
2686
- ...data.contentType.options
3012
+ query: { status }
2687
3013
  }
3014
+ ] = useQueryParams({
3015
+ status: "draft"
3016
+ });
3017
+ const { model, id, document, meta, collectionType } = useDoc();
3018
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
3019
+ const props = {
3020
+ activeTab: status,
3021
+ model,
3022
+ documentId: id,
3023
+ document: isCloning ? void 0 : document,
3024
+ meta: isCloning ? void 0 : meta,
3025
+ collectionType
2688
3026
  };
3027
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
3028
+ DescriptionComponentRenderer,
3029
+ {
3030
+ props,
3031
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
3032
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
3033
+ }
3034
+ ) });
2689
3035
  };
2690
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2691
- return rows.map(
2692
- (row) => row.map((field) => {
2693
- const attribute = attributes[field.name];
2694
- if (!attribute) {
2695
- return null;
2696
- }
2697
- const { edit: metadata } = metadatas[field.name];
2698
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2699
- return {
2700
- attribute,
2701
- disabled: !metadata.editable,
2702
- hint: metadata.description,
2703
- label: metadata.label ?? "",
2704
- name: field.name,
2705
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2706
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2707
- schemas,
2708
- components: components?.schemas ?? {}
2709
- }),
2710
- placeholder: metadata.placeholder ?? "",
2711
- required: attribute.required ?? false,
2712
- size: field.size,
2713
- unique: "unique" in attribute ? attribute.unique : false,
2714
- visible: metadata.visible ?? true,
2715
- type: attribute.type
2716
- };
2717
- }).filter((field) => field !== null)
2718
- );
2719
- };
2720
- const formatListLayout = (data, {
2721
- schemas,
2722
- schema,
2723
- components
2724
- }) => {
2725
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2726
- (acc, [attribute, metadata]) => {
2727
- return {
2728
- ...acc,
2729
- [attribute]: metadata.list
2730
- };
2731
- },
2732
- {}
2733
- );
2734
- const listAttributes = convertListLayoutToFieldLayouts(
2735
- data.contentType.layouts.list,
2736
- schema?.attributes,
2737
- listMetadatas,
2738
- { configurations: data.components, schemas: components },
2739
- schemas
2740
- );
3036
+ const ActionsPanel = () => {
3037
+ const { formatMessage } = useIntl();
2741
3038
  return {
2742
- layout: listAttributes,
2743
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2744
- metadatas: listMetadatas,
2745
- options: {
2746
- ...schema?.options,
2747
- ...schema?.pluginOptions,
2748
- ...data.contentType.options
2749
- }
3039
+ title: formatMessage({
3040
+ id: "content-manager.containers.edit.panels.default.title",
3041
+ defaultMessage: "Entry"
3042
+ }),
3043
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2750
3044
  };
2751
3045
  };
2752
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2753
- return columns.map((name) => {
2754
- const attribute = attributes[name];
2755
- if (!attribute) {
2756
- return null;
3046
+ ActionsPanel.type = "actions";
3047
+ const ActionsPanelContent = () => {
3048
+ const isCloning = useMatch(CLONE_PATH) !== null;
3049
+ const [
3050
+ {
3051
+ query: { status = "draft" }
2757
3052
  }
2758
- const metadata = metadatas[name];
2759
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2760
- return {
2761
- attribute,
2762
- label: metadata.label ?? "",
2763
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2764
- schemas,
2765
- components: components?.schemas ?? {}
2766
- }),
2767
- name,
2768
- searchable: metadata.searchable ?? true,
2769
- sortable: metadata.sortable ?? true
2770
- };
2771
- }).filter((field) => field !== null);
3053
+ ] = useQueryParams();
3054
+ const { model, id, document, meta, collectionType } = useDoc();
3055
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
3056
+ const props = {
3057
+ activeTab: status,
3058
+ model,
3059
+ documentId: id,
3060
+ document: isCloning ? void 0 : document,
3061
+ meta: isCloning ? void 0 : meta,
3062
+ collectionType
3063
+ };
3064
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3065
+ /* @__PURE__ */ jsx(
3066
+ DescriptionComponentRenderer,
3067
+ {
3068
+ props,
3069
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
3070
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3071
+ }
3072
+ ),
3073
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3074
+ ] });
2772
3075
  };
3076
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3077
+ return /* @__PURE__ */ jsxs(
3078
+ Flex,
3079
+ {
3080
+ ref,
3081
+ tag: "aside",
3082
+ "aria-labelledby": "additional-information",
3083
+ background: "neutral0",
3084
+ borderColor: "neutral150",
3085
+ hasRadius: true,
3086
+ paddingBottom: 4,
3087
+ paddingLeft: 4,
3088
+ paddingRight: 4,
3089
+ paddingTop: 4,
3090
+ shadow: "tableShadow",
3091
+ gap: 3,
3092
+ direction: "column",
3093
+ justifyContent: "stretch",
3094
+ alignItems: "flex-start",
3095
+ children: [
3096
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3097
+ children
3098
+ ]
3099
+ }
3100
+ );
3101
+ });
2773
3102
  const ConfirmBulkActionDialog = ({
2774
3103
  onToggleDialog,
2775
3104
  isOpen = false,
@@ -2777,7 +3106,7 @@ const ConfirmBulkActionDialog = ({
2777
3106
  endAction
2778
3107
  }) => {
2779
3108
  const { formatMessage } = useIntl();
2780
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
3109
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2781
3110
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2782
3111
  id: "app.components.ConfirmDialog.title",
2783
3112
  defaultMessage: "Confirmation"
@@ -2808,6 +3137,7 @@ const ConfirmDialogPublishAll = ({
2808
3137
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2809
3138
  const { model, schema } = useDoc();
2810
3139
  const [{ query }] = useQueryParams();
3140
+ const enableDraftRelationsCount = false;
2811
3141
  const {
2812
3142
  data: countDraftRelations = 0,
2813
3143
  isLoading,
@@ -2819,7 +3149,7 @@ const ConfirmDialogPublishAll = ({
2819
3149
  locale: query?.plugins?.i18n?.locale
2820
3150
  },
2821
3151
  {
2822
- skip: selectedEntries.length === 0
3152
+ skip: !enableDraftRelationsCount
2823
3153
  }
2824
3154
  );
2825
3155
  React.useEffect(() => {
@@ -2898,7 +3228,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2898
3228
  )
2899
3229
  );
2900
3230
  } else {
2901
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3231
+ messages.push(
3232
+ ...formatErrorMessages(
3233
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3234
+ value,
3235
+ currentKey,
3236
+ formatMessage
3237
+ )
3238
+ );
2902
3239
  }
2903
3240
  } else {
2904
3241
  messages.push(
@@ -2997,7 +3334,7 @@ const SelectedEntriesTableContent = ({
2997
3334
  status: row.status
2998
3335
  }
2999
3336
  ) }),
3000
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3337
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3001
3338
  IconButton,
3002
3339
  {
3003
3340
  tag: Link,
@@ -3006,23 +3343,16 @@ const SelectedEntriesTableContent = ({
3006
3343
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3007
3344
  },
3008
3345
  state: { from: pathname },
3009
- label: formatMessage(
3010
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3011
- {
3012
- target: formatMessage(
3013
- {
3014
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3015
- defaultMessage: "item line {number}"
3016
- },
3017
- { number: index2 + 1 }
3018
- )
3019
- }
3020
- ),
3346
+ label: formatMessage({
3347
+ id: "content-manager.bulk-publish.edit",
3348
+ defaultMessage: "Edit"
3349
+ }),
3021
3350
  target: "_blank",
3022
3351
  marginLeft: "auto",
3023
- children: /* @__PURE__ */ jsx(Pencil, {})
3352
+ variant: "ghost",
3353
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3024
3354
  }
3025
- ) })
3355
+ ) }) })
3026
3356
  ] }, row.id)) })
3027
3357
  ] });
3028
3358
  };
@@ -3059,7 +3389,13 @@ const SelectedEntriesModalContent = ({
3059
3389
  );
3060
3390
  const { rows, validationErrors } = React.useMemo(() => {
3061
3391
  if (data.length > 0 && schema) {
3062
- const validate = createYupSchema(schema.attributes, components);
3392
+ const validate = createYupSchema(
3393
+ schema.attributes,
3394
+ components,
3395
+ // Since this is the "Publish" action, the validation
3396
+ // schema must enforce the rules for published entities
3397
+ { status: "published" }
3398
+ );
3063
3399
  const validationErrors2 = {};
3064
3400
  const rows2 = data.map((entry) => {
3065
3401
  try {
@@ -3184,8 +3520,7 @@ const PublishAction = ({ documents, model }) => {
3184
3520
  const refetchList = () => {
3185
3521
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3186
3522
  };
3187
- if (!showPublishButton)
3188
- return null;
3523
+ if (!showPublishButton) return null;
3189
3524
  return {
3190
3525
  actionType: "publish",
3191
3526
  variant: "tertiary",
@@ -3253,8 +3588,7 @@ const DeleteAction = ({ documents, model }) => {
3253
3588
  selectRow([]);
3254
3589
  }
3255
3590
  };
3256
- if (!hasDeletePermission)
3257
- return null;
3591
+ if (!hasDeletePermission) return null;
3258
3592
  return {
3259
3593
  variant: "danger-light",
3260
3594
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3303,8 +3637,7 @@ const UnpublishAction = ({ documents, model }) => {
3303
3637
  }
3304
3638
  };
3305
3639
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3306
- if (!showUnpublishButton)
3307
- return null;
3640
+ if (!showUnpublishButton) return null;
3308
3641
  return {
3309
3642
  variant: "tertiary",
3310
3643
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3409,7 +3742,7 @@ const TableActions = ({ document }) => {
3409
3742
  DescriptionComponentRenderer,
3410
3743
  {
3411
3744
  props,
3412
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3745
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3413
3746
  children: (actions2) => {
3414
3747
  const tableRowActions = actions2.filter((action) => {
3415
3748
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3468,6 +3801,7 @@ const EditAction = ({ documentId }) => {
3468
3801
  };
3469
3802
  };
3470
3803
  EditAction.type = "edit";
3804
+ EditAction.position = "table-row";
3471
3805
  const StyledPencil = styled(Pencil)`
3472
3806
  path {
3473
3807
  fill: currentColor;
@@ -3520,7 +3854,7 @@ const CloneAction = ({ model, documentId }) => {
3520
3854
  }),
3521
3855
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3522
3856
  footer: ({ onClose }) => {
3523
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3857
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3524
3858
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3525
3859
  id: "cancel",
3526
3860
  defaultMessage: "Cancel"
@@ -3544,6 +3878,7 @@ const CloneAction = ({ model, documentId }) => {
3544
3878
  };
3545
3879
  };
3546
3880
  CloneAction.type = "clone";
3881
+ CloneAction.position = "table-row";
3547
3882
  const StyledDuplicate = styled(Duplicate)`
3548
3883
  path {
3549
3884
  fill: currentColor;
@@ -3561,8 +3896,7 @@ class ContentManagerPlugin {
3561
3896
  documentActions = [
3562
3897
  ...DEFAULT_ACTIONS,
3563
3898
  ...DEFAULT_TABLE_ROW_ACTIONS,
3564
- ...DEFAULT_HEADER_ACTIONS,
3565
- HistoryAction
3899
+ ...DEFAULT_HEADER_ACTIONS
3566
3900
  ];
3567
3901
  editViewSidePanels = [ActionsPanel];
3568
3902
  headerActions = [];
@@ -3631,7 +3965,14 @@ class ContentManagerPlugin {
3631
3965
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3632
3966
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3633
3967
  getBulkActions: () => this.bulkActions,
3634
- getDocumentActions: () => this.documentActions,
3968
+ getDocumentActions: (position) => {
3969
+ if (position) {
3970
+ return this.documentActions.filter(
3971
+ (action) => action.position == void 0 || [action.position].flat().includes(position)
3972
+ );
3973
+ }
3974
+ return this.documentActions;
3975
+ },
3635
3976
  getEditViewSidePanels: () => this.editViewSidePanels,
3636
3977
  getHeaderActions: () => this.headerActions
3637
3978
  }
@@ -3641,16 +3982,71 @@ class ContentManagerPlugin {
3641
3982
  const getPrintableType = (value) => {
3642
3983
  const nativeType = typeof value;
3643
3984
  if (nativeType === "object") {
3644
- if (value === null)
3645
- return "null";
3646
- if (Array.isArray(value))
3647
- return "array";
3985
+ if (value === null) return "null";
3986
+ if (Array.isArray(value)) return "array";
3648
3987
  if (value instanceof Object && value.constructor.name !== "Object") {
3649
3988
  return value.constructor.name;
3650
3989
  }
3651
3990
  }
3652
3991
  return nativeType;
3653
3992
  };
3993
+ const HistoryAction = ({ model, document }) => {
3994
+ const { formatMessage } = useIntl();
3995
+ const [{ query }] = useQueryParams();
3996
+ const navigate = useNavigate();
3997
+ const { trackUsage } = useTracking();
3998
+ const { pathname } = useLocation();
3999
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
4000
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
4001
+ return null;
4002
+ }
4003
+ const handleOnClick = () => {
4004
+ const destination = { pathname: "history", search: pluginsQueryParams };
4005
+ trackUsage("willNavigate", {
4006
+ from: pathname,
4007
+ to: `${pathname}/${destination.pathname}`
4008
+ });
4009
+ navigate(destination);
4010
+ };
4011
+ return {
4012
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
4013
+ label: formatMessage({
4014
+ id: "content-manager.history.document-action",
4015
+ defaultMessage: "Content History"
4016
+ }),
4017
+ onClick: handleOnClick,
4018
+ disabled: (
4019
+ /**
4020
+ * The user is creating a new document.
4021
+ * It hasn't been saved yet, so there's no history to go to
4022
+ */
4023
+ !document || /**
4024
+ * The document has been created but the current dimension has never been saved.
4025
+ * For example, the user is creating a new locale in an existing document,
4026
+ * so there's no history for the document in that locale
4027
+ */
4028
+ !document.id || /**
4029
+ * History is only available for content types created by the user.
4030
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
4031
+ * which start with `admin::` or `plugin::`
4032
+ */
4033
+ !model.startsWith("api::")
4034
+ ),
4035
+ position: "header"
4036
+ };
4037
+ };
4038
+ HistoryAction.type = "history";
4039
+ HistoryAction.position = "header";
4040
+ const historyAdmin = {
4041
+ bootstrap(app) {
4042
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
4043
+ addDocumentAction((actions2) => {
4044
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
4045
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
4046
+ return actions2;
4047
+ });
4048
+ }
4049
+ };
3654
4050
  const initialState = {
3655
4051
  collectionTypeLinks: [],
3656
4052
  components: [],
@@ -3687,6 +4083,88 @@ const { setInitialData } = actions;
3687
4083
  const reducer = combineReducers({
3688
4084
  app: reducer$1
3689
4085
  });
4086
+ const previewApi = contentManagerApi.injectEndpoints({
4087
+ endpoints: (builder) => ({
4088
+ getPreviewUrl: builder.query({
4089
+ query({ query, params }) {
4090
+ return {
4091
+ url: `/content-manager/preview/url/${params.contentType}`,
4092
+ method: "GET",
4093
+ config: {
4094
+ params: query
4095
+ }
4096
+ };
4097
+ }
4098
+ })
4099
+ })
4100
+ });
4101
+ const { useGetPreviewUrlQuery } = previewApi;
4102
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4103
+ if (isShown) {
4104
+ return /* @__PURE__ */ jsx(Tooltip, { label, children });
4105
+ }
4106
+ return children;
4107
+ };
4108
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4109
+ const { formatMessage } = useIntl();
4110
+ const { trackUsage } = useTracking();
4111
+ const { pathname } = useLocation();
4112
+ const [{ query }] = useQueryParams();
4113
+ const isModified = useForm("PreviewSidePanel", (state) => state.modified);
4114
+ const { data, error } = useGetPreviewUrlQuery({
4115
+ params: {
4116
+ contentType: model
4117
+ },
4118
+ query: {
4119
+ documentId,
4120
+ locale: document?.locale,
4121
+ status: document?.status
4122
+ }
4123
+ });
4124
+ if (!data?.data?.url || error) {
4125
+ return null;
4126
+ }
4127
+ const trackNavigation = () => {
4128
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4129
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4130
+ };
4131
+ return {
4132
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4133
+ content: /* @__PURE__ */ jsx(
4134
+ ConditionalTooltip,
4135
+ {
4136
+ label: formatMessage({
4137
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4138
+ defaultMessage: "Please save to open the preview"
4139
+ }),
4140
+ isShown: isModified,
4141
+ children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
4142
+ Button,
4143
+ {
4144
+ variant: "tertiary",
4145
+ tag: Link,
4146
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4147
+ onClick: trackNavigation,
4148
+ width: "100%",
4149
+ disabled: isModified,
4150
+ pointerEvents: isModified ? "none" : void 0,
4151
+ tabIndex: isModified ? -1 : void 0,
4152
+ children: formatMessage({
4153
+ id: "content-manager.preview.panel.button",
4154
+ defaultMessage: "Open preview"
4155
+ })
4156
+ }
4157
+ ) })
4158
+ }
4159
+ )
4160
+ };
4161
+ };
4162
+ const previewAdmin = {
4163
+ bootstrap(app) {
4164
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4165
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4166
+ }
4167
+ };
3690
4168
  const index = {
3691
4169
  register(app) {
3692
4170
  const cm = new ContentManagerPlugin();
@@ -3706,7 +4184,7 @@ const index = {
3706
4184
  app.router.addRoute({
3707
4185
  path: "content-manager/*",
3708
4186
  lazy: async () => {
3709
- const { Layout } = await import("./layout-Bau7ZfLV.mjs");
4187
+ const { Layout } = await import("./layout-B5qsPihj.mjs");
3710
4188
  return {
3711
4189
  Component: Layout
3712
4190
  };
@@ -3715,10 +4193,18 @@ const index = {
3715
4193
  });
3716
4194
  app.registerPlugin(cm.config);
3717
4195
  },
4196
+ bootstrap(app) {
4197
+ if (typeof historyAdmin.bootstrap === "function") {
4198
+ historyAdmin.bootstrap(app);
4199
+ }
4200
+ if (typeof previewAdmin.bootstrap === "function") {
4201
+ previewAdmin.bootstrap(app);
4202
+ }
4203
+ },
3718
4204
  async registerTrads({ locales }) {
3719
4205
  const importedTrads = await Promise.all(
3720
4206
  locales.map((locale) => {
3721
- 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-Ux26r5pl.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 }) => {
4207
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Dtk_ot79.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
3722
4208
  return {
3723
4209
  data: prefixPluginTranslations(data, PLUGIN_ID),
3724
4210
  locale
@@ -3739,13 +4225,16 @@ export {
3739
4225
  BulkActionsRenderer as B,
3740
4226
  COLLECTION_TYPES as C,
3741
4227
  DocumentStatus as D,
3742
- DEFAULT_SETTINGS as E,
3743
- convertEditLayoutToFieldLayouts as F,
3744
- useDocument as G,
4228
+ extractContentTypeComponents as E,
4229
+ DEFAULT_SETTINGS as F,
4230
+ convertEditLayoutToFieldLayouts as G,
3745
4231
  HOOKS as H,
3746
4232
  InjectionZone as I,
3747
- index as J,
3748
- useDocumentActions as K,
4233
+ useDocument as J,
4234
+ useGetPreviewUrlQuery as K,
4235
+ index as L,
4236
+ useContentManagerContext as M,
4237
+ useDocumentActions as N,
3749
4238
  Panels as P,
3750
4239
  RelativeTime as R,
3751
4240
  SINGLE_TYPES as S,
@@ -3763,18 +4252,18 @@ export {
3763
4252
  PERMISSIONS as k,
3764
4253
  DocumentRBAC as l,
3765
4254
  DOCUMENT_META_FIELDS as m,
3766
- useDocLayout as n,
3767
- useGetContentTypeConfigurationQuery as o,
3768
- CREATOR_FIELDS as p,
3769
- getMainField as q,
3770
- getDisplayName as r,
4255
+ CLONE_PATH as n,
4256
+ useDocLayout as o,
4257
+ useGetContentTypeConfigurationQuery as p,
4258
+ CREATOR_FIELDS as q,
4259
+ getMainField as r,
3771
4260
  setInitialData as s,
3772
- checkIfAttributeIsDisplayable as t,
4261
+ getDisplayName as t,
3773
4262
  useContentTypeSchema as u,
3774
- useGetAllDocumentsQuery as v,
3775
- convertListLayoutToFieldLayouts as w,
3776
- capitalise as x,
3777
- useUpdateContentTypeConfigurationMutation as y,
3778
- extractContentTypeComponents as z
4263
+ checkIfAttributeIsDisplayable as v,
4264
+ useGetAllDocumentsQuery as w,
4265
+ convertListLayoutToFieldLayouts as x,
4266
+ capitalise as y,
4267
+ useUpdateContentTypeConfigurationMutation as z
3779
4268
  };
3780
- //# sourceMappingURL=index-DJXJw9V5.mjs.map
4269
+ //# sourceMappingURL=index-Dh2aGTGJ.mjs.map