@strapi/content-manager 0.0.0-experimental.779667bd163026468f566293decf331a0246fff9 → 0.0.0-experimental.780730225a7b82dc9f04ceb9ef60710e52d832ab

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 (202) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-Bqgx7Mes.js → ComponentConfigurationPage-ClKl_TA2.js} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-Bqgx7Mes.js.map → ComponentConfigurationPage-ClKl_TA2.js.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-B1bIXVuX.mjs → ComponentConfigurationPage-D3ZWDAHG.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-B1bIXVuX.mjs.map → ComponentConfigurationPage-D3ZWDAHG.mjs.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs → EditConfigurationPage-BYCBSJxP.mjs} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs.map → EditConfigurationPage-BYCBSJxP.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js → EditConfigurationPage-OWez0Kxp.js} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js.map → EditConfigurationPage-OWez0Kxp.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-DlLEyUL6.mjs → EditViewPage-5pdbvsO_.mjs} +63 -12
  10. package/dist/_chunks/EditViewPage-5pdbvsO_.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-DA95Ha6J.js → EditViewPage-BEs5iGDi.js} +62 -11
  12. package/dist/_chunks/EditViewPage-BEs5iGDi.js.map +1 -0
  13. package/dist/_chunks/{Field-CnK8dO8N.js → Field-DNHm4wHx.js} +215 -124
  14. package/dist/_chunks/Field-DNHm4wHx.js.map +1 -0
  15. package/dist/_chunks/{Field-Dq7bDnuh.mjs → Field-DcKuFHYK.mjs} +213 -122
  16. package/dist/_chunks/Field-DcKuFHYK.mjs.map +1 -0
  17. package/dist/_chunks/{Form-B_JE0dbz.mjs → Form-CGwM_-5c.mjs} +36 -17
  18. package/dist/_chunks/Form-CGwM_-5c.mjs.map +1 -0
  19. package/dist/_chunks/{Form-BpiR4piS.js → Form-CoRxWJOz.js} +36 -17
  20. package/dist/_chunks/Form-CoRxWJOz.js.map +1 -0
  21. package/dist/_chunks/{History-DdIstl8b.js → History-BcUTQrfG.js} +56 -103
  22. package/dist/_chunks/History-BcUTQrfG.js.map +1 -0
  23. package/dist/_chunks/{History-CBNGU7a-.mjs → History-DEvr3Q_V.mjs} +58 -105
  24. package/dist/_chunks/History-DEvr3Q_V.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-DkKRparB.js → ListConfigurationPage-BE_Ho7tV.js} +17 -6
  26. package/dist/_chunks/ListConfigurationPage-BE_Ho7tV.js.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-5dr4qpue.mjs → ListConfigurationPage-BM4zZZcM.mjs} +18 -7
  28. package/dist/_chunks/ListConfigurationPage-BM4zZZcM.mjs.map +1 -0
  29. package/dist/_chunks/{ListViewPage-DecLrYV6.mjs → ListViewPage-BK2mkrql.mjs} +72 -41
  30. package/dist/_chunks/ListViewPage-BK2mkrql.mjs.map +1 -0
  31. package/dist/_chunks/{ListViewPage-wE0lXqoD.js → ListViewPage-BkT8Eao0.js} +74 -43
  32. package/dist/_chunks/ListViewPage-BkT8Eao0.js.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs → NoContentTypePage-BvcAutu9.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs.map → NoContentTypePage-BvcAutu9.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js → NoContentTypePage-C8mtyc4H.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js.map → NoContentTypePage-C8mtyc4H.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js → NoPermissionsPage-B5Y9Y78B.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js.map → NoPermissionsPage-B5Y9Y78B.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs → NoPermissionsPage-BmbRz7PR.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs.map → NoPermissionsPage-BmbRz7PR.mjs.map} +1 -1
  41. package/dist/_chunks/Preview-BF8ZDYqS.js +286 -0
  42. package/dist/_chunks/Preview-BF8ZDYqS.js.map +1 -0
  43. package/dist/_chunks/Preview-DcexhKJE.mjs +267 -0
  44. package/dist/_chunks/Preview-DcexhKJE.mjs.map +1 -0
  45. package/dist/_chunks/{Relations-L0xYRoSQ.js → Relations-BKnoK1R0.js} +72 -36
  46. package/dist/_chunks/Relations-BKnoK1R0.js.map +1 -0
  47. package/dist/_chunks/{Relations-Dqz0C1fz.mjs → Relations-BjIzc4EK.mjs} +73 -37
  48. package/dist/_chunks/Relations-BjIzc4EK.mjs.map +1 -0
  49. package/dist/_chunks/{en-BrCTWlZv.mjs → en-CfIXaZf9.mjs} +26 -14
  50. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-CfIXaZf9.mjs.map} +1 -1
  51. package/dist/_chunks/{en-uOUIxfcQ.js → en-DTWPCdTS.js} +26 -14
  52. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-DTWPCdTS.js.map} +1 -1
  53. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  54. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  55. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  56. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  57. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  58. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  59. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  60. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  61. package/dist/_chunks/{index-BSn97i8U.mjs → index-BW-rXkjn.mjs} +981 -703
  62. package/dist/_chunks/index-BW-rXkjn.mjs.map +1 -0
  63. package/dist/_chunks/{index-DyvUPg1a.js → index-DOzAG2cq.js} +962 -683
  64. package/dist/_chunks/index-DOzAG2cq.js.map +1 -0
  65. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  66. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  67. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  68. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  69. package/dist/_chunks/{layout-DPaHUusj.mjs → layout-DFVbgjp2.mjs} +22 -9
  70. package/dist/_chunks/layout-DFVbgjp2.mjs.map +1 -0
  71. package/dist/_chunks/{layout-TPqF2oJ5.js → layout-RC3W2obV.js} +21 -8
  72. package/dist/_chunks/layout-RC3W2obV.js.map +1 -0
  73. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  74. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  75. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  76. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  77. package/dist/_chunks/{relations-Ck7-ecDT.mjs → relations-Dogh8HWI.mjs} +6 -7
  78. package/dist/_chunks/relations-Dogh8HWI.mjs.map +1 -0
  79. package/dist/_chunks/{relations-BWYS9gkn.js → relations-zam7-5H7.js} +6 -7
  80. package/dist/_chunks/relations-zam7-5H7.js.map +1 -0
  81. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  82. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  83. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  84. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  85. package/dist/admin/index.js +2 -1
  86. package/dist/admin/index.js.map +1 -1
  87. package/dist/admin/index.mjs +5 -4
  88. package/dist/admin/src/exports.d.ts +1 -1
  89. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  90. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  91. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  92. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
  93. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  96. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  97. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  98. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  99. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  100. package/dist/admin/src/preview/constants.d.ts +1 -0
  101. package/dist/admin/src/preview/index.d.ts +4 -0
  102. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  103. package/dist/admin/src/preview/routes.d.ts +3 -0
  104. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  105. package/dist/admin/src/router.d.ts +1 -1
  106. package/dist/admin/src/services/api.d.ts +1 -1
  107. package/dist/admin/src/services/components.d.ts +2 -2
  108. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  109. package/dist/admin/src/services/documents.d.ts +19 -17
  110. package/dist/admin/src/services/init.d.ts +1 -1
  111. package/dist/admin/src/services/relations.d.ts +2 -2
  112. package/dist/admin/src/services/uid.d.ts +3 -3
  113. package/dist/admin/src/utils/validation.d.ts +4 -1
  114. package/dist/server/index.js +591 -261
  115. package/dist/server/index.js.map +1 -1
  116. package/dist/server/index.mjs +592 -262
  117. package/dist/server/index.mjs.map +1 -1
  118. package/dist/server/src/bootstrap.d.ts.map +1 -1
  119. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  120. package/dist/server/src/controllers/index.d.ts.map +1 -1
  121. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  122. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  123. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  124. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  125. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  126. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  127. package/dist/server/src/history/services/history.d.ts.map +1 -1
  128. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  129. package/dist/server/src/history/services/utils.d.ts +4 -4
  130. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  131. package/dist/server/src/index.d.ts +4 -4
  132. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  133. package/dist/server/src/preview/constants.d.ts +2 -0
  134. package/dist/server/src/preview/constants.d.ts.map +1 -0
  135. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  136. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  137. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  138. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  139. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  140. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  141. package/dist/server/src/preview/index.d.ts +4 -0
  142. package/dist/server/src/preview/index.d.ts.map +1 -0
  143. package/dist/server/src/preview/routes/index.d.ts +8 -0
  144. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  145. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  146. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  147. package/dist/server/src/preview/services/index.d.ts +16 -0
  148. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  149. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  150. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  151. package/dist/server/src/preview/services/preview.d.ts +12 -0
  152. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  153. package/dist/server/src/preview/utils.d.ts +19 -0
  154. package/dist/server/src/preview/utils.d.ts.map +1 -0
  155. package/dist/server/src/register.d.ts.map +1 -1
  156. package/dist/server/src/routes/index.d.ts.map +1 -1
  157. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  158. package/dist/server/src/services/document-metadata.d.ts +8 -8
  159. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  160. package/dist/server/src/services/index.d.ts +4 -4
  161. package/dist/server/src/services/index.d.ts.map +1 -1
  162. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  163. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  164. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  165. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  166. package/dist/server/src/utils/index.d.ts +2 -0
  167. package/dist/server/src/utils/index.d.ts.map +1 -1
  168. package/dist/shared/contracts/collection-types.d.ts +3 -1
  169. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  170. package/dist/shared/contracts/index.d.ts +1 -0
  171. package/dist/shared/contracts/index.d.ts.map +1 -1
  172. package/dist/shared/contracts/preview.d.ts +27 -0
  173. package/dist/shared/contracts/preview.d.ts.map +1 -0
  174. package/dist/shared/index.js +4 -0
  175. package/dist/shared/index.js.map +1 -1
  176. package/dist/shared/index.mjs +4 -0
  177. package/dist/shared/index.mjs.map +1 -1
  178. package/package.json +14 -14
  179. package/dist/_chunks/EditViewPage-DA95Ha6J.js.map +0 -1
  180. package/dist/_chunks/EditViewPage-DlLEyUL6.mjs.map +0 -1
  181. package/dist/_chunks/Field-CnK8dO8N.js.map +0 -1
  182. package/dist/_chunks/Field-Dq7bDnuh.mjs.map +0 -1
  183. package/dist/_chunks/Form-B_JE0dbz.mjs.map +0 -1
  184. package/dist/_chunks/Form-BpiR4piS.js.map +0 -1
  185. package/dist/_chunks/History-CBNGU7a-.mjs.map +0 -1
  186. package/dist/_chunks/History-DdIstl8b.js.map +0 -1
  187. package/dist/_chunks/ListConfigurationPage-5dr4qpue.mjs.map +0 -1
  188. package/dist/_chunks/ListConfigurationPage-DkKRparB.js.map +0 -1
  189. package/dist/_chunks/ListViewPage-DecLrYV6.mjs.map +0 -1
  190. package/dist/_chunks/ListViewPage-wE0lXqoD.js.map +0 -1
  191. package/dist/_chunks/Relations-Dqz0C1fz.mjs.map +0 -1
  192. package/dist/_chunks/Relations-L0xYRoSQ.js.map +0 -1
  193. package/dist/_chunks/index-BSn97i8U.mjs.map +0 -1
  194. package/dist/_chunks/index-DyvUPg1a.js.map +0 -1
  195. package/dist/_chunks/layout-DPaHUusj.mjs.map +0 -1
  196. package/dist/_chunks/layout-TPqF2oJ5.js.map +0 -1
  197. package/dist/_chunks/relations-BWYS9gkn.js.map +0 -1
  198. package/dist/_chunks/relations-Ck7-ecDT.mjs.map +0 -1
  199. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  200. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  201. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  202. package/strapi-server.js +0 -3
@@ -1,11 +1,12 @@
1
- import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
1
+ import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
3
+ import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import * as React from "react";
5
5
  import { lazy } from "react";
6
- import { Button, Menu, VisuallyHidden, Flex, 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";
7
8
  import { useIntl } from "react-intl";
8
- import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
10
  import { styled } from "styled-components";
10
11
  import * as yup from "yup";
11
12
  import { ValidationError } from "yup";
@@ -100,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
100
101
  if (!slug) {
101
102
  throw new Error("Cannot find the slug param in the URL");
102
103
  }
104
+ const [{ rawQuery }] = useQueryParams();
103
105
  const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
104
106
  const contentTypePermissions = React.useMemo(() => {
105
107
  const contentTypePermissions2 = userPermissions.filter(
@@ -110,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
110
112
  return { ...acc, [action]: [permission] };
111
113
  }, {});
112
114
  }, [slug, userPermissions]);
113
- const { isLoading, allowedActions } = useRBAC(contentTypePermissions, permissions ?? void 0);
115
+ const { isLoading, allowedActions } = useRBAC(
116
+ contentTypePermissions,
117
+ permissions ?? void 0,
118
+ // TODO: useRBAC context should be typed and built differently
119
+ // We are passing raw query as context to the hook so that it can
120
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
121
+ rawQuery
122
+ );
114
123
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
115
124
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
116
125
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -158,7 +167,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
158
167
  "Document",
159
168
  "InitialData",
160
169
  "HistoryVersion",
161
- "Relations"
170
+ "Relations",
171
+ "UidAvailability"
162
172
  ]
163
173
  });
164
174
  const documentApi = contentManagerApi.injectEndpoints({
@@ -172,7 +182,12 @@ const documentApi = contentManagerApi.injectEndpoints({
172
182
  params: query
173
183
  }
174
184
  }),
175
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
185
+ invalidatesTags: (_result, error, { model }) => {
186
+ if (error) {
187
+ return [];
188
+ }
189
+ return [{ type: "Document", id: `${model}_LIST` }];
190
+ }
176
191
  }),
177
192
  cloneDocument: builder.mutation({
178
193
  query: ({ model, sourceId, data, params }) => ({
@@ -183,7 +198,10 @@ const documentApi = contentManagerApi.injectEndpoints({
183
198
  params
184
199
  }
185
200
  }),
186
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
201
+ invalidatesTags: (_result, _error, { model }) => [
202
+ { type: "Document", id: `${model}_LIST` },
203
+ { type: "UidAvailability", id: model }
204
+ ]
187
205
  }),
188
206
  /**
189
207
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -200,7 +218,8 @@ const documentApi = contentManagerApi.injectEndpoints({
200
218
  }),
201
219
  invalidatesTags: (result, _error, { model }) => [
202
220
  { type: "Document", id: `${model}_LIST` },
203
- "Relations"
221
+ "Relations",
222
+ { type: "UidAvailability", id: model }
204
223
  ]
205
224
  }),
206
225
  deleteDocument: builder.mutation({
@@ -241,7 +260,8 @@ const documentApi = contentManagerApi.injectEndpoints({
241
260
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
242
261
  },
243
262
  { type: "Document", id: `${model}_LIST` },
244
- "Relations"
263
+ "Relations",
264
+ { type: "UidAvailability", id: model }
245
265
  ];
246
266
  }
247
267
  }),
@@ -259,6 +279,7 @@ const documentApi = contentManagerApi.injectEndpoints({
259
279
  }),
260
280
  providesTags: (result, _error, arg) => {
261
281
  return [
282
+ { type: "Document", id: `ALL_LIST` },
262
283
  { type: "Document", id: `${arg.model}_LIST` },
263
284
  ...result?.results.map(({ documentId }) => ({
264
285
  type: "Document",
@@ -297,6 +318,11 @@ const documentApi = contentManagerApi.injectEndpoints({
297
318
  {
298
319
  type: "Document",
299
320
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
321
+ },
322
+ // Make it easy to invalidate all individual documents queries for a model
323
+ {
324
+ type: "Document",
325
+ id: `${model}_ALL_ITEMS`
300
326
  }
301
327
  ];
302
328
  }
@@ -360,8 +386,21 @@ const documentApi = contentManagerApi.injectEndpoints({
360
386
  type: "Document",
361
387
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
362
388
  },
363
- "Relations"
389
+ "Relations",
390
+ { type: "UidAvailability", id: model }
364
391
  ];
392
+ },
393
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
394
+ const patchResult = dispatch(
395
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
396
+ Object.assign(draft.data, data);
397
+ })
398
+ );
399
+ try {
400
+ await queryFulfilled;
401
+ } catch {
402
+ patchResult.undo();
403
+ }
365
404
  }
366
405
  }),
367
406
  unpublishDocument: builder.mutation({
@@ -431,20 +470,39 @@ const buildValidParams = (query) => {
431
470
  const isBaseQueryError = (error) => {
432
471
  return error.name !== void 0;
433
472
  };
434
- const createYupSchema = (attributes = {}, components = {}) => {
473
+ const arrayValidator = (attribute, options) => ({
474
+ message: translatedErrors.required,
475
+ test(value) {
476
+ if (options.status === "draft") {
477
+ return true;
478
+ }
479
+ if (!attribute.required) {
480
+ return true;
481
+ }
482
+ if (!value) {
483
+ return false;
484
+ }
485
+ if (Array.isArray(value) && value.length === 0) {
486
+ return false;
487
+ }
488
+ return true;
489
+ }
490
+ });
491
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
435
492
  const createModelSchema = (attributes2) => yup.object().shape(
436
493
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
437
494
  if (DOCUMENT_META_FIELDS.includes(name)) {
438
495
  return acc;
439
496
  }
440
497
  const validations = [
498
+ addNullableValidation,
441
499
  addRequiredValidation,
442
500
  addMinLengthValidation,
443
501
  addMaxLengthValidation,
444
502
  addMinValidation,
445
503
  addMaxValidation,
446
504
  addRegexValidation
447
- ].map((fn) => fn(attribute));
505
+ ].map((fn) => fn(attribute, options));
448
506
  const transformSchema = pipe(...validations);
449
507
  switch (attribute.type) {
450
508
  case "component": {
@@ -454,12 +512,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
454
512
  ...acc,
455
513
  [name]: transformSchema(
456
514
  yup.array().of(createModelSchema(attributes3).nullable(false))
457
- )
515
+ ).test(arrayValidator(attribute, options))
458
516
  };
459
517
  } else {
460
518
  return {
461
519
  ...acc,
462
- [name]: transformSchema(createModelSchema(attributes3))
520
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
463
521
  };
464
522
  }
465
523
  }
@@ -481,7 +539,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
481
539
  }
482
540
  )
483
541
  )
484
- )
542
+ ).test(arrayValidator(attribute, options))
485
543
  };
486
544
  case "relation":
487
545
  return {
@@ -493,7 +551,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
493
551
  } else if (Array.isArray(value)) {
494
552
  return yup.array().of(
495
553
  yup.object().shape({
496
- id: yup.string().required()
554
+ id: yup.number().required()
497
555
  })
498
556
  );
499
557
  } else if (typeof value === "object") {
@@ -545,6 +603,14 @@ const createAttributeSchema = (attribute) => {
545
603
  if (!value || typeof value === "string" && value.length === 0) {
546
604
  return true;
547
605
  }
606
+ if (typeof value === "object") {
607
+ try {
608
+ JSON.stringify(value);
609
+ return true;
610
+ } catch (err) {
611
+ return false;
612
+ }
613
+ }
548
614
  try {
549
615
  JSON.parse(value);
550
616
  return true;
@@ -563,13 +629,7 @@ const createAttributeSchema = (attribute) => {
563
629
  return yup.mixed();
564
630
  }
565
631
  };
566
- const addRequiredValidation = (attribute) => (schema) => {
567
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
568
- return schema.min(1, translatedErrors.required);
569
- }
570
- if (attribute.required && attribute.type !== "relation") {
571
- return schema.required(translatedErrors.required);
572
- }
632
+ const nullableSchema = (schema) => {
573
633
  return schema?.nullable ? schema.nullable() : (
574
634
  // In some cases '.nullable' will not be available on the schema.
575
635
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -577,7 +637,22 @@ const addRequiredValidation = (attribute) => (schema) => {
577
637
  schema
578
638
  );
579
639
  };
580
- const addMinLengthValidation = (attribute) => (schema) => {
640
+ const addNullableValidation = () => (schema) => {
641
+ return nullableSchema(schema);
642
+ };
643
+ const addRequiredValidation = (attribute, options) => (schema) => {
644
+ if (options.status === "draft" || !attribute.required) {
645
+ return schema;
646
+ }
647
+ if (attribute.required && "required" in schema) {
648
+ return schema.required(translatedErrors.required);
649
+ }
650
+ return schema;
651
+ };
652
+ const addMinLengthValidation = (attribute, options) => (schema) => {
653
+ if (options.status === "draft") {
654
+ return schema;
655
+ }
581
656
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
582
657
  return schema.min(attribute.minLength, {
583
658
  ...translatedErrors.minLength,
@@ -599,32 +674,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
599
674
  }
600
675
  return schema;
601
676
  };
602
- const addMinValidation = (attribute) => (schema) => {
603
- if ("min" in attribute) {
677
+ const addMinValidation = (attribute, options) => (schema) => {
678
+ if (options.status === "draft") {
679
+ return schema;
680
+ }
681
+ if ("min" in attribute && "min" in schema) {
604
682
  const min = toInteger(attribute.min);
605
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
606
- if (!attribute.required && "test" in schema && min) {
607
- return schema.test(
608
- "custom-min",
609
- {
610
- ...translatedErrors.min,
611
- values: {
612
- min: attribute.min
613
- }
614
- },
615
- (value) => {
616
- if (!value) {
617
- return true;
618
- }
619
- if (Array.isArray(value) && value.length === 0) {
620
- return true;
621
- }
622
- return value.length >= min;
623
- }
624
- );
625
- }
626
- }
627
- if ("min" in schema && min) {
683
+ if (min) {
628
684
  return schema.min(min, {
629
685
  ...translatedErrors.min,
630
686
  values: {
@@ -742,19 +798,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
742
798
  }, {});
743
799
  return componentsByKey;
744
800
  };
745
- const useDocument = (args, opts) => {
801
+ const HOOKS = {
802
+ /**
803
+ * Hook that allows to mutate the displayed headers of the list view table
804
+ * @constant
805
+ * @type {string}
806
+ */
807
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
808
+ /**
809
+ * Hook that allows to mutate the CM's collection types links pre-set filters
810
+ * @constant
811
+ * @type {string}
812
+ */
813
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
814
+ /**
815
+ * Hook that allows to mutate the CM's edit view layout
816
+ * @constant
817
+ * @type {string}
818
+ */
819
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
820
+ /**
821
+ * Hook that allows to mutate the CM's single types links pre-set filters
822
+ * @constant
823
+ * @type {string}
824
+ */
825
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
826
+ };
827
+ const contentTypesApi = contentManagerApi.injectEndpoints({
828
+ endpoints: (builder) => ({
829
+ getContentTypeConfiguration: builder.query({
830
+ query: (uid) => ({
831
+ url: `/content-manager/content-types/${uid}/configuration`,
832
+ method: "GET"
833
+ }),
834
+ transformResponse: (response) => response.data,
835
+ providesTags: (_result, _error, uid) => [
836
+ { type: "ContentTypesConfiguration", id: uid },
837
+ { type: "ContentTypeSettings", id: "LIST" }
838
+ ]
839
+ }),
840
+ getAllContentTypeSettings: builder.query({
841
+ query: () => "/content-manager/content-types-settings",
842
+ transformResponse: (response) => response.data,
843
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
844
+ }),
845
+ updateContentTypeConfiguration: builder.mutation({
846
+ query: ({ uid, ...body }) => ({
847
+ url: `/content-manager/content-types/${uid}/configuration`,
848
+ method: "PUT",
849
+ data: body
850
+ }),
851
+ transformResponse: (response) => response.data,
852
+ invalidatesTags: (_result, _error, { uid }) => [
853
+ { type: "ContentTypesConfiguration", id: uid },
854
+ { type: "ContentTypeSettings", id: "LIST" },
855
+ // Is this necessary?
856
+ { type: "InitialData" }
857
+ ]
858
+ })
859
+ })
860
+ });
861
+ const {
862
+ useGetContentTypeConfigurationQuery,
863
+ useGetAllContentTypeSettingsQuery,
864
+ useUpdateContentTypeConfigurationMutation
865
+ } = contentTypesApi;
866
+ const checkIfAttributeIsDisplayable = (attribute) => {
867
+ const { type } = attribute;
868
+ if (type === "relation") {
869
+ return !attribute.relation.toLowerCase().includes("morph");
870
+ }
871
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
872
+ };
873
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
874
+ if (!mainFieldName) {
875
+ return void 0;
876
+ }
877
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
878
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
879
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
880
+ );
881
+ return {
882
+ name: mainFieldName,
883
+ type: mainFieldType ?? "string"
884
+ };
885
+ };
886
+ const DEFAULT_SETTINGS = {
887
+ bulkable: false,
888
+ filterable: false,
889
+ searchable: false,
890
+ pagination: false,
891
+ defaultSortBy: "",
892
+ defaultSortOrder: "asc",
893
+ mainField: "id",
894
+ pageSize: 10
895
+ };
896
+ const useDocumentLayout = (model) => {
897
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
898
+ const [{ query }] = useQueryParams();
899
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
746
900
  const { toggleNotification } = useNotification();
747
901
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
902
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
748
903
  const {
749
- currentData: data,
750
- isLoading: isLoadingDocument,
751
- isFetching: isFetchingDocument,
752
- error
753
- } = useGetDocumentQuery(args, {
754
- ...opts,
755
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
756
- });
757
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
904
+ data,
905
+ isLoading: isLoadingConfigs,
906
+ error,
907
+ isFetching: isFetchingConfigs
908
+ } = useGetContentTypeConfigurationQuery(model);
909
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
758
910
  React.useEffect(() => {
759
911
  if (error) {
760
912
  toggleNotification({
@@ -762,83 +914,339 @@ const useDocument = (args, opts) => {
762
914
  message: formatAPIError(error)
763
915
  });
764
916
  }
765
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
766
- const validationSchema = React.useMemo(() => {
767
- if (!schema) {
768
- return null;
769
- }
770
- return createYupSchema(schema.attributes, components);
771
- }, [schema, components]);
772
- const validate = React.useCallback(
773
- (document) => {
774
- if (!validationSchema) {
775
- throw new Error(
776
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
777
- );
778
- }
779
- try {
780
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
781
- return null;
782
- } catch (error2) {
783
- if (error2 instanceof ValidationError) {
784
- return getYupValidationErrors(error2);
785
- }
786
- throw error2;
787
- }
917
+ }, [error, formatAPIError, toggleNotification]);
918
+ const editLayout = React.useMemo(
919
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
920
+ layout: [],
921
+ components: {},
922
+ metadatas: {},
923
+ options: {},
924
+ settings: DEFAULT_SETTINGS
788
925
  },
789
- [validationSchema]
926
+ [data, isLoading, schemas, schema, components]
927
+ );
928
+ const listLayout = React.useMemo(() => {
929
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
930
+ layout: [],
931
+ metadatas: {},
932
+ options: {},
933
+ settings: DEFAULT_SETTINGS
934
+ };
935
+ }, [data, isLoading, schemas, schema, components]);
936
+ const { layout: edit } = React.useMemo(
937
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
938
+ layout: editLayout,
939
+ query
940
+ }),
941
+ [editLayout, query, runHookWaterfall]
790
942
  );
791
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
792
943
  return {
793
- components,
794
- document: data?.data,
795
- meta: data?.meta,
944
+ error,
796
945
  isLoading,
797
- schema,
798
- validate
799
- };
800
- };
801
- const useDoc = () => {
802
- const { id, slug, collectionType, origin } = useParams();
803
- const [{ query }] = useQueryParams();
804
- const params = React.useMemo(() => buildValidParams(query), [query]);
805
- if (!collectionType) {
806
- throw new Error("Could not find collectionType in url params");
807
- }
808
- if (!slug) {
809
- throw new Error("Could not find model in url params");
810
- }
811
- return {
812
- collectionType,
813
- model: slug,
814
- id: origin || id === "create" ? void 0 : id,
815
- ...useDocument(
816
- { documentId: origin || id, model: slug, collectionType, params },
817
- {
818
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
819
- }
820
- )
946
+ edit,
947
+ list: listLayout
821
948
  };
822
949
  };
823
- const prefixPluginTranslations = (trad, pluginId) => {
824
- if (!pluginId) {
825
- throw new TypeError("pluginId can't be empty");
826
- }
827
- return Object.keys(trad).reduce((acc, current) => {
828
- acc[`${pluginId}.${current}`] = trad[current];
829
- return acc;
830
- }, {});
831
- };
832
- const getTranslation = (id) => `content-manager.${id}`;
833
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
834
- id: "notification.error",
835
- defaultMessage: "An error occurred, please try again"
950
+ const useDocLayout = () => {
951
+ const { model } = useDoc();
952
+ return useDocumentLayout(model);
836
953
  };
837
- const useDocumentActions = () => {
838
- const { toggleNotification } = useNotification();
839
- const { formatMessage } = useIntl();
840
- const { trackUsage } = useTracking();
954
+ const formatEditLayout = (data, {
955
+ schemas,
956
+ schema,
957
+ components
958
+ }) => {
959
+ let currentPanelIndex = 0;
960
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
961
+ data.contentType.layouts.edit,
962
+ schema?.attributes,
963
+ data.contentType.metadatas,
964
+ { configurations: data.components, schemas: components },
965
+ schemas
966
+ ).reduce((panels, row) => {
967
+ if (row.some((field) => field.type === "dynamiczone")) {
968
+ panels.push([row]);
969
+ currentPanelIndex += 2;
970
+ } else {
971
+ if (!panels[currentPanelIndex]) {
972
+ panels.push([row]);
973
+ } else {
974
+ panels[currentPanelIndex].push(row);
975
+ }
976
+ }
977
+ return panels;
978
+ }, []);
979
+ const componentEditAttributes = Object.entries(data.components).reduce(
980
+ (acc, [uid, configuration]) => {
981
+ acc[uid] = {
982
+ layout: convertEditLayoutToFieldLayouts(
983
+ configuration.layouts.edit,
984
+ components[uid].attributes,
985
+ configuration.metadatas,
986
+ { configurations: data.components, schemas: components }
987
+ ),
988
+ settings: {
989
+ ...configuration.settings,
990
+ icon: components[uid].info.icon,
991
+ displayName: components[uid].info.displayName
992
+ }
993
+ };
994
+ return acc;
995
+ },
996
+ {}
997
+ );
998
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
999
+ (acc, [attribute, metadata]) => {
1000
+ return {
1001
+ ...acc,
1002
+ [attribute]: metadata.edit
1003
+ };
1004
+ },
1005
+ {}
1006
+ );
1007
+ return {
1008
+ layout: panelledEditAttributes,
1009
+ components: componentEditAttributes,
1010
+ metadatas: editMetadatas,
1011
+ settings: {
1012
+ ...data.contentType.settings,
1013
+ displayName: schema?.info.displayName
1014
+ },
1015
+ options: {
1016
+ ...schema?.options,
1017
+ ...schema?.pluginOptions,
1018
+ ...data.contentType.options
1019
+ }
1020
+ };
1021
+ };
1022
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1023
+ return rows.map(
1024
+ (row) => row.map((field) => {
1025
+ const attribute = attributes[field.name];
1026
+ if (!attribute) {
1027
+ return null;
1028
+ }
1029
+ const { edit: metadata } = metadatas[field.name];
1030
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1031
+ return {
1032
+ attribute,
1033
+ disabled: !metadata.editable,
1034
+ hint: metadata.description,
1035
+ label: metadata.label ?? "",
1036
+ name: field.name,
1037
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1038
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1039
+ schemas,
1040
+ components: components?.schemas ?? {}
1041
+ }),
1042
+ placeholder: metadata.placeholder ?? "",
1043
+ required: attribute.required ?? false,
1044
+ size: field.size,
1045
+ unique: "unique" in attribute ? attribute.unique : false,
1046
+ visible: metadata.visible ?? true,
1047
+ type: attribute.type
1048
+ };
1049
+ }).filter((field) => field !== null)
1050
+ );
1051
+ };
1052
+ const formatListLayout = (data, {
1053
+ schemas,
1054
+ schema,
1055
+ components
1056
+ }) => {
1057
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1058
+ (acc, [attribute, metadata]) => {
1059
+ return {
1060
+ ...acc,
1061
+ [attribute]: metadata.list
1062
+ };
1063
+ },
1064
+ {}
1065
+ );
1066
+ const listAttributes = convertListLayoutToFieldLayouts(
1067
+ data.contentType.layouts.list,
1068
+ schema?.attributes,
1069
+ listMetadatas,
1070
+ { configurations: data.components, schemas: components },
1071
+ schemas
1072
+ );
1073
+ return {
1074
+ layout: listAttributes,
1075
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1076
+ metadatas: listMetadatas,
1077
+ options: {
1078
+ ...schema?.options,
1079
+ ...schema?.pluginOptions,
1080
+ ...data.contentType.options
1081
+ }
1082
+ };
1083
+ };
1084
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1085
+ return columns.map((name) => {
1086
+ const attribute = attributes[name];
1087
+ if (!attribute) {
1088
+ return null;
1089
+ }
1090
+ const metadata = metadatas[name];
1091
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1092
+ return {
1093
+ attribute,
1094
+ label: metadata.label ?? "",
1095
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1096
+ schemas,
1097
+ components: components?.schemas ?? {}
1098
+ }),
1099
+ name,
1100
+ searchable: metadata.searchable ?? true,
1101
+ sortable: metadata.sortable ?? true
1102
+ };
1103
+ }).filter((field) => field !== null);
1104
+ };
1105
+ const useDocument = (args, opts) => {
1106
+ const { toggleNotification } = useNotification();
1107
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1108
+ const {
1109
+ currentData: data,
1110
+ isLoading: isLoadingDocument,
1111
+ isFetching: isFetchingDocument,
1112
+ error
1113
+ } = useGetDocumentQuery(args, {
1114
+ ...opts,
1115
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1116
+ });
1117
+ const {
1118
+ components,
1119
+ schema,
1120
+ schemas,
1121
+ isLoading: isLoadingSchema
1122
+ } = useContentTypeSchema(args.model);
1123
+ React.useEffect(() => {
1124
+ if (error) {
1125
+ toggleNotification({
1126
+ type: "danger",
1127
+ message: formatAPIError(error)
1128
+ });
1129
+ }
1130
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1131
+ const validationSchema = React.useMemo(() => {
1132
+ if (!schema) {
1133
+ return null;
1134
+ }
1135
+ return createYupSchema(schema.attributes, components);
1136
+ }, [schema, components]);
1137
+ const validate = React.useCallback(
1138
+ (document) => {
1139
+ if (!validationSchema) {
1140
+ throw new Error(
1141
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1142
+ );
1143
+ }
1144
+ try {
1145
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1146
+ return null;
1147
+ } catch (error2) {
1148
+ if (error2 instanceof ValidationError) {
1149
+ return getYupValidationErrors(error2);
1150
+ }
1151
+ throw error2;
1152
+ }
1153
+ },
1154
+ [validationSchema]
1155
+ );
1156
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1157
+ const hasError = !!error;
1158
+ return {
1159
+ components,
1160
+ document: data?.data,
1161
+ meta: data?.meta,
1162
+ isLoading,
1163
+ hasError,
1164
+ schema,
1165
+ schemas,
1166
+ validate
1167
+ };
1168
+ };
1169
+ const useDoc = () => {
1170
+ const { id, slug, collectionType, origin } = useParams();
1171
+ const [{ query }] = useQueryParams();
1172
+ const params = React.useMemo(() => buildValidParams(query), [query]);
1173
+ if (!collectionType) {
1174
+ throw new Error("Could not find collectionType in url params");
1175
+ }
1176
+ if (!slug) {
1177
+ throw new Error("Could not find model in url params");
1178
+ }
1179
+ const document = useDocument(
1180
+ { documentId: origin || id, model: slug, collectionType, params },
1181
+ {
1182
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1183
+ }
1184
+ );
1185
+ const returnId = origin || id === "create" ? void 0 : id;
1186
+ return {
1187
+ collectionType,
1188
+ model: slug,
1189
+ id: returnId,
1190
+ ...document
1191
+ };
1192
+ };
1193
+ const useContentManagerContext = () => {
1194
+ const {
1195
+ collectionType,
1196
+ model,
1197
+ id,
1198
+ components,
1199
+ isLoading: isLoadingDoc,
1200
+ schema,
1201
+ schemas
1202
+ } = useDoc();
1203
+ const layout = useDocumentLayout(model);
1204
+ const form = useForm("useContentManagerContext", (state) => state);
1205
+ const isSingleType = collectionType === SINGLE_TYPES;
1206
+ const slug = model;
1207
+ const isCreatingEntry = id === "create";
1208
+ useContentTypeSchema();
1209
+ const isLoading = isLoadingDoc || layout.isLoading;
1210
+ const error = layout.error;
1211
+ return {
1212
+ error,
1213
+ isLoading,
1214
+ // Base metadata
1215
+ model,
1216
+ collectionType,
1217
+ id,
1218
+ slug,
1219
+ isCreatingEntry,
1220
+ isSingleType,
1221
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1222
+ // All schema infos
1223
+ components,
1224
+ contentType: schema,
1225
+ contentTypes: schemas,
1226
+ // Form state
1227
+ form,
1228
+ // layout infos
1229
+ layout
1230
+ };
1231
+ };
1232
+ const prefixPluginTranslations = (trad, pluginId) => {
1233
+ return Object.keys(trad).reduce((acc, current) => {
1234
+ acc[`${pluginId}.${current}`] = trad[current];
1235
+ return acc;
1236
+ }, {});
1237
+ };
1238
+ const getTranslation = (id) => `content-manager.${id}`;
1239
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1240
+ id: "notification.error",
1241
+ defaultMessage: "An error occurred, please try again"
1242
+ };
1243
+ const useDocumentActions = () => {
1244
+ const { toggleNotification } = useNotification();
1245
+ const { formatMessage } = useIntl();
1246
+ const { trackUsage } = useTracking();
841
1247
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1248
+ const navigate = useNavigate();
1249
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
842
1250
  const [deleteDocument] = useDeleteDocumentMutation();
843
1251
  const _delete = React.useCallback(
844
1252
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1153,6 +1561,7 @@ const useDocumentActions = () => {
1153
1561
  defaultMessage: "Saved document"
1154
1562
  })
1155
1563
  });
1564
+ setCurrentStep("contentManager.success");
1156
1565
  return res.data;
1157
1566
  } catch (err) {
1158
1567
  toggleNotification({
@@ -1174,7 +1583,6 @@ const useDocumentActions = () => {
1174
1583
  sourceId
1175
1584
  });
1176
1585
  if ("error" in res) {
1177
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1178
1586
  return { error: res.error };
1179
1587
  }
1180
1588
  toggleNotification({
@@ -1193,7 +1601,7 @@ const useDocumentActions = () => {
1193
1601
  throw err;
1194
1602
  }
1195
1603
  },
1196
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1604
+ [autoCloneDocument, formatMessage, toggleNotification]
1197
1605
  );
1198
1606
  const [cloneDocument] = useCloneDocumentMutation();
1199
1607
  const clone = React.useCallback(
@@ -1219,6 +1627,7 @@ const useDocumentActions = () => {
1219
1627
  defaultMessage: "Cloned document"
1220
1628
  })
1221
1629
  });
1630
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1222
1631
  return res.data;
1223
1632
  } catch (err) {
1224
1633
  toggleNotification({
@@ -1229,7 +1638,7 @@ const useDocumentActions = () => {
1229
1638
  throw err;
1230
1639
  }
1231
1640
  },
1232
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1641
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1233
1642
  );
1234
1643
  const [getDoc] = useLazyGetDocumentQuery();
1235
1644
  const getDocument = React.useCallback(
@@ -1254,10 +1663,10 @@ const useDocumentActions = () => {
1254
1663
  update
1255
1664
  };
1256
1665
  };
1257
- const ProtectedHistoryPage = lazy(
1258
- () => import("./History-CBNGU7a-.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1666
+ const ProtectedHistoryPage = React.lazy(
1667
+ () => import("./History-DEvr3Q_V.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1259
1668
  );
1260
- const routes$1 = [
1669
+ const routes$2 = [
1261
1670
  {
1262
1671
  path: ":collectionType/:slug/:id/history",
1263
1672
  Component: ProtectedHistoryPage
@@ -1267,32 +1676,45 @@ const routes$1 = [
1267
1676
  Component: ProtectedHistoryPage
1268
1677
  }
1269
1678
  ];
1270
- const ProtectedEditViewPage = lazy(
1271
- () => import("./EditViewPage-DlLEyUL6.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1679
+ const ProtectedPreviewPage = React.lazy(
1680
+ () => import("./Preview-DcexhKJE.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1681
+ );
1682
+ const routes$1 = [
1683
+ {
1684
+ path: ":collectionType/:slug/:id/preview",
1685
+ Component: ProtectedPreviewPage
1686
+ },
1687
+ {
1688
+ path: ":collectionType/:slug/preview",
1689
+ Component: ProtectedPreviewPage
1690
+ }
1691
+ ];
1692
+ const ProtectedEditViewPage = lazy(
1693
+ () => import("./EditViewPage-5pdbvsO_.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1272
1694
  );
1273
1695
  const ProtectedListViewPage = lazy(
1274
- () => import("./ListViewPage-DecLrYV6.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1696
+ () => import("./ListViewPage-BK2mkrql.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1275
1697
  );
1276
1698
  const ProtectedListConfiguration = lazy(
1277
- () => import("./ListConfigurationPage-5dr4qpue.mjs").then((mod) => ({
1699
+ () => import("./ListConfigurationPage-BM4zZZcM.mjs").then((mod) => ({
1278
1700
  default: mod.ProtectedListConfiguration
1279
1701
  }))
1280
1702
  );
1281
1703
  const ProtectedEditConfigurationPage = lazy(
1282
- () => import("./EditConfigurationPage-ZO0vOO8q.mjs").then((mod) => ({
1704
+ () => import("./EditConfigurationPage-BYCBSJxP.mjs").then((mod) => ({
1283
1705
  default: mod.ProtectedEditConfigurationPage
1284
1706
  }))
1285
1707
  );
1286
1708
  const ProtectedComponentConfigurationPage = lazy(
1287
- () => import("./ComponentConfigurationPage-B1bIXVuX.mjs").then((mod) => ({
1709
+ () => import("./ComponentConfigurationPage-D3ZWDAHG.mjs").then((mod) => ({
1288
1710
  default: mod.ProtectedComponentConfigurationPage
1289
1711
  }))
1290
1712
  );
1291
1713
  const NoPermissions = lazy(
1292
- () => import("./NoPermissionsPage-CM5UD8ee.mjs").then((mod) => ({ default: mod.NoPermissions }))
1714
+ () => import("./NoPermissionsPage-BmbRz7PR.mjs").then((mod) => ({ default: mod.NoPermissions }))
1293
1715
  );
1294
1716
  const NoContentType = lazy(
1295
- () => import("./NoContentTypePage-CiIcfYsd.mjs").then((mod) => ({ default: mod.NoContentType }))
1717
+ () => import("./NoContentTypePage-BvcAutu9.mjs").then((mod) => ({ default: mod.NoContentType }))
1296
1718
  );
1297
1719
  const CollectionTypePages = () => {
1298
1720
  const { collectionType } = useParams();
@@ -1304,7 +1726,7 @@ const CollectionTypePages = () => {
1304
1726
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1305
1727
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1306
1728
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1307
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1729
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1308
1730
  const routes = [
1309
1731
  {
1310
1732
  path: LIST_RELATIVE_PATH,
@@ -1338,6 +1760,7 @@ const routes = [
1338
1760
  path: "no-content-types",
1339
1761
  Component: NoContentType
1340
1762
  },
1763
+ ...routes$2,
1341
1764
  ...routes$1
1342
1765
  ];
1343
1766
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1406,12 +1829,14 @@ const DocumentActionButton = (action) => {
1406
1829
  /* @__PURE__ */ jsx(
1407
1830
  Button,
1408
1831
  {
1409
- flex: 1,
1832
+ flex: "auto",
1410
1833
  startIcon: action.icon,
1411
1834
  disabled: action.disabled,
1412
1835
  onClick: handleClick(action),
1413
1836
  justifyContent: "center",
1414
1837
  variant: action.variant || "default",
1838
+ paddingTop: "7px",
1839
+ paddingBottom: "7px",
1415
1840
  children: action.label
1416
1841
  }
1417
1842
  ),
@@ -1434,6 +1859,11 @@ const DocumentActionButton = (action) => {
1434
1859
  ) : null
1435
1860
  ] });
1436
1861
  };
1862
+ const MenuItem = styled(Menu.Item)`
1863
+ &:hover {
1864
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1865
+ }
1866
+ `;
1437
1867
  const DocumentActionsMenu = ({
1438
1868
  actions: actions2,
1439
1869
  children,
@@ -1476,9 +1906,9 @@ const DocumentActionsMenu = ({
1476
1906
  disabled: isDisabled,
1477
1907
  size: "S",
1478
1908
  endIcon: null,
1479
- paddingTop: "7px",
1480
- paddingLeft: "9px",
1481
- paddingRight: "9px",
1909
+ paddingTop: "4px",
1910
+ paddingLeft: "7px",
1911
+ paddingRight: "7px",
1482
1912
  variant,
1483
1913
  children: [
1484
1914
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1489,36 +1919,35 @@ const DocumentActionsMenu = ({
1489
1919
  ]
1490
1920
  }
1491
1921
  ),
1492
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1922
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1493
1923
  actions2.map((action) => {
1494
1924
  return /* @__PURE__ */ jsx(
1495
- Menu.Item,
1925
+ MenuItem,
1496
1926
  {
1497
1927
  disabled: action.disabled,
1498
1928
  onSelect: handleClick(action),
1499
1929
  display: "block",
1500
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1501
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1502
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1503
- action.label
1504
- ] }),
1505
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1506
- Flex,
1507
- {
1508
- alignItems: "center",
1509
- background: "alternative100",
1510
- borderStyle: "solid",
1511
- borderColor: "alternative200",
1512
- borderWidth: "1px",
1513
- height: 5,
1514
- paddingLeft: 2,
1515
- paddingRight: 2,
1516
- hasRadius: true,
1517
- color: "alternative600",
1518
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1519
- }
1520
- )
1521
- ] })
1930
+ isVariantDanger: action.variant === "danger",
1931
+ isDisabled: action.disabled,
1932
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
1933
+ Flex,
1934
+ {
1935
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1936
+ gap: 2,
1937
+ tag: "span",
1938
+ children: [
1939
+ /* @__PURE__ */ jsx(
1940
+ Flex,
1941
+ {
1942
+ tag: "span",
1943
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1944
+ children: action.icon
1945
+ }
1946
+ ),
1947
+ action.label
1948
+ ]
1949
+ }
1950
+ ) })
1522
1951
  },
1523
1952
  action.id
1524
1953
  );
@@ -1598,11 +2027,11 @@ const DocumentActionConfirmDialog = ({
1598
2027
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1599
2028
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1600
2029
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1601
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
2030
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1602
2031
  id: "app.components.Button.cancel",
1603
2032
  defaultMessage: "Cancel"
1604
2033
  }) }) }),
1605
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
2034
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1606
2035
  id: "app.components.Button.confirm",
1607
2036
  defaultMessage: "Confirm"
1608
2037
  }) })
@@ -1625,10 +2054,22 @@ const DocumentActionModal = ({
1625
2054
  };
1626
2055
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1627
2056
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1628
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1629
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
2057
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
2058
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1630
2059
  ] }) });
1631
2060
  };
2061
+ const transformData = (data) => {
2062
+ if (Array.isArray(data)) {
2063
+ return data.map(transformData);
2064
+ }
2065
+ if (typeof data === "object" && data !== null) {
2066
+ if ("apiData" in data) {
2067
+ return data.apiData;
2068
+ }
2069
+ return mapValues(transformData)(data);
2070
+ }
2071
+ return data;
2072
+ };
1632
2073
  const PublishAction$1 = ({
1633
2074
  activeTab,
1634
2075
  documentId,
@@ -1641,12 +2082,10 @@ const PublishAction$1 = ({
1641
2082
  const navigate = useNavigate();
1642
2083
  const { toggleNotification } = useNotification();
1643
2084
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
2085
+ const isListView = useMatch(LIST_PATH) !== null;
1644
2086
  const isCloning = useMatch(CLONE_PATH) !== null;
1645
2087
  const { formatMessage } = useIntl();
1646
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1647
- "PublishAction",
1648
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1649
- );
2088
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1650
2089
  const { publish } = useDocumentActions();
1651
2090
  const [
1652
2091
  countDraftRelations,
@@ -1698,24 +2137,25 @@ const PublishAction$1 = ({
1698
2137
  }
1699
2138
  }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1700
2139
  React.useEffect(() => {
1701
- if (documentId) {
1702
- const fetchDraftRelationsCount = async () => {
1703
- const { data, error } = await countDraftRelations({
1704
- collectionType,
1705
- model,
1706
- documentId,
1707
- params
1708
- });
1709
- if (error) {
1710
- throw error;
1711
- }
1712
- if (data) {
1713
- setServerCountOfDraftRelations(data.data);
1714
- }
1715
- };
1716
- fetchDraftRelationsCount();
2140
+ if (!document || !document.documentId || isListView) {
2141
+ return;
1717
2142
  }
1718
- }, [documentId, countDraftRelations, collectionType, model, params]);
2143
+ const fetchDraftRelationsCount = async () => {
2144
+ const { data, error } = await countDraftRelations({
2145
+ collectionType,
2146
+ model,
2147
+ documentId,
2148
+ params
2149
+ });
2150
+ if (error) {
2151
+ throw error;
2152
+ }
2153
+ if (data) {
2154
+ setServerCountOfDraftRelations(data.data);
2155
+ }
2156
+ };
2157
+ fetchDraftRelationsCount();
2158
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1719
2159
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1720
2160
  if (!schema?.options?.draftAndPublish) {
1721
2161
  return null;
@@ -1723,7 +2163,9 @@ const PublishAction$1 = ({
1723
2163
  const performPublish = async () => {
1724
2164
  setSubmitting(true);
1725
2165
  try {
1726
- const { errors } = await validate();
2166
+ const { errors } = await validate(true, {
2167
+ status: "published"
2168
+ });
1727
2169
  if (errors) {
1728
2170
  toggleNotification({
1729
2171
  type: "danger",
@@ -1741,7 +2183,7 @@ const PublishAction$1 = ({
1741
2183
  documentId,
1742
2184
  params
1743
2185
  },
1744
- formValues
2186
+ transformData(formValues)
1745
2187
  );
1746
2188
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1747
2189
  navigate({
@@ -1756,7 +2198,8 @@ const PublishAction$1 = ({
1756
2198
  }
1757
2199
  };
1758
2200
  const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1759
- const hasDraftRelations = totalDraftRelations > 0;
2201
+ const enableDraftRelationsCount = false;
2202
+ const hasDraftRelations = enableDraftRelationsCount;
1760
2203
  return {
1761
2204
  /**
1762
2205
  * Disabled when:
@@ -1766,18 +2209,13 @@ const PublishAction$1 = ({
1766
2209
  * - the document is already published & not modified
1767
2210
  * - the document is being created & not modified
1768
2211
  * - the user doesn't have the permission to publish
1769
- * - the user doesn't have the permission to create a new document
1770
- * - the user doesn't have the permission to update the document
1771
2212
  */
1772
- disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2213
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1773
2214
  label: formatMessage({
1774
2215
  id: "app.utils.publish",
1775
2216
  defaultMessage: "Publish"
1776
2217
  }),
1777
2218
  onClick: async () => {
1778
- if (hasDraftRelations) {
1779
- return;
1780
- }
1781
2219
  await performPublish();
1782
2220
  },
1783
2221
  dialog: hasDraftRelations ? {
@@ -1816,10 +2254,6 @@ const UpdateAction = ({
1816
2254
  const cloneMatch = useMatch(CLONE_PATH);
1817
2255
  const isCloning = cloneMatch !== null;
1818
2256
  const { formatMessage } = useIntl();
1819
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1820
- canCreate: canCreate2,
1821
- canUpdate: canUpdate2
1822
- }));
1823
2257
  const { create, update, clone } = useDocumentActions();
1824
2258
  const [{ query, rawQuery }] = useQueryParams();
1825
2259
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1836,18 +2270,18 @@ const UpdateAction = ({
1836
2270
  * - the form is submitting
1837
2271
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1838
2272
  * - the active tab is the published tab
1839
- * - the user doesn't have the permission to create a new document
1840
- * - the user doesn't have the permission to update the document
1841
2273
  */
1842
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2274
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1843
2275
  label: formatMessage({
1844
- id: "content-manager.containers.Edit.save",
2276
+ id: "global.save",
1845
2277
  defaultMessage: "Save"
1846
2278
  }),
1847
2279
  onClick: async () => {
1848
2280
  setSubmitting(true);
1849
2281
  try {
1850
- const { errors } = await validate();
2282
+ const { errors } = await validate(true, {
2283
+ status: "draft"
2284
+ });
1851
2285
  if (errors) {
1852
2286
  toggleNotification({
1853
2287
  type: "danger",
@@ -1865,13 +2299,16 @@ const UpdateAction = ({
1865
2299
  documentId: cloneMatch.params.origin,
1866
2300
  params
1867
2301
  },
1868
- document
2302
+ transformData(document)
1869
2303
  );
1870
2304
  if ("data" in res) {
1871
- navigate({
1872
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1873
- search: rawQuery
1874
- });
2305
+ navigate(
2306
+ {
2307
+ pathname: `../${res.data.documentId}`,
2308
+ search: rawQuery
2309
+ },
2310
+ { relative: "path" }
2311
+ );
1875
2312
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1876
2313
  setErrors(formatValidationErrors(res.error));
1877
2314
  }
@@ -1883,7 +2320,7 @@ const UpdateAction = ({
1883
2320
  documentId,
1884
2321
  params
1885
2322
  },
1886
- document
2323
+ transformData(document)
1887
2324
  );
1888
2325
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1889
2326
  setErrors(formatValidationErrors(res.error));
@@ -1896,15 +2333,15 @@ const UpdateAction = ({
1896
2333
  model,
1897
2334
  params
1898
2335
  },
1899
- document
2336
+ transformData(document)
1900
2337
  );
1901
2338
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1902
2339
  navigate(
1903
2340
  {
1904
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2341
+ pathname: `../${res.data.documentId}`,
1905
2342
  search: rawQuery
1906
2343
  },
1907
- { replace: true }
2344
+ { replace: true, relative: "path" }
1908
2345
  );
1909
2346
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1910
2347
  setErrors(formatValidationErrors(res.error));
@@ -1949,7 +2386,7 @@ const UnpublishAction$1 = ({
1949
2386
  id: "app.utils.unpublish",
1950
2387
  defaultMessage: "Unpublish"
1951
2388
  }),
1952
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2389
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1953
2390
  onClick: async () => {
1954
2391
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1955
2392
  if (!documentId) {
@@ -2061,7 +2498,7 @@ const DiscardAction = ({
2061
2498
  id: "content-manager.actions.discard.label",
2062
2499
  defaultMessage: "Discard changes"
2063
2500
  }),
2064
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2501
+ icon: /* @__PURE__ */ jsx(Cross, {}),
2065
2502
  position: ["panel", "table-row"],
2066
2503
  variant: "danger",
2067
2504
  dialog: {
@@ -2089,11 +2526,6 @@ const DiscardAction = ({
2089
2526
  };
2090
2527
  };
2091
2528
  DiscardAction.type = "discard";
2092
- const StyledCrossCircle = styled(CrossCircle)`
2093
- path {
2094
- fill: currentColor;
2095
- }
2096
- `;
2097
2529
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2098
2530
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2099
2531
  const RelativeTime = React.forwardRef(
@@ -2106,7 +2538,7 @@ const RelativeTime = React.forwardRef(
2106
2538
  });
2107
2539
  const unit = intervals.find((intervalUnit) => {
2108
2540
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2109
- });
2541
+ }) ?? "seconds";
2110
2542
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2111
2543
  const customInterval = customIntervals.find(
2112
2544
  (custom) => interval[custom.unit] < custom.threshold
@@ -2140,19 +2572,29 @@ const getDisplayName = ({
2140
2572
  return email ?? "";
2141
2573
  };
2142
2574
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2143
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2144
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2145
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2575
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2576
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2577
+ const { formatMessage } = useIntl();
2578
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2579
+ id: `content-manager.containers.List.${status}`,
2580
+ defaultMessage: capitalise(status)
2581
+ }) }) });
2146
2582
  };
2147
2583
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2148
2584
  const { formatMessage } = useIntl();
2149
2585
  const isCloning = useMatch(CLONE_PATH) !== null;
2586
+ const params = useParams();
2150
2587
  const title = isCreating ? formatMessage({
2151
2588
  id: "content-manager.containers.edit.title.new",
2152
2589
  defaultMessage: "Create an entry"
2153
2590
  }) : documentTitle;
2154
2591
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2155
- /* @__PURE__ */ jsx(BackButton, {}),
2592
+ /* @__PURE__ */ jsx(
2593
+ BackButton,
2594
+ {
2595
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2596
+ }
2597
+ ),
2156
2598
  /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2157
2599
  /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2158
2600
  /* @__PURE__ */ jsx(HeaderToolbar, {})
@@ -2240,12 +2682,12 @@ const Information = ({ activeTab }) => {
2240
2682
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2241
2683
  label: formatMessage({
2242
2684
  id: "content-manager.containers.edit.information.last-published.label",
2243
- defaultMessage: "Last published"
2685
+ defaultMessage: "Published"
2244
2686
  }),
2245
2687
  value: formatMessage(
2246
2688
  {
2247
2689
  id: "content-manager.containers.edit.information.last-published.value",
2248
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2690
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2249
2691
  },
2250
2692
  {
2251
2693
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2258,12 +2700,12 @@ const Information = ({ activeTab }) => {
2258
2700
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2259
2701
  label: formatMessage({
2260
2702
  id: "content-manager.containers.edit.information.last-draft.label",
2261
- defaultMessage: "Last draft"
2703
+ defaultMessage: "Updated"
2262
2704
  }),
2263
2705
  value: formatMessage(
2264
2706
  {
2265
2707
  id: "content-manager.containers.edit.information.last-draft.value",
2266
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2708
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2267
2709
  },
2268
2710
  {
2269
2711
  time: /* @__PURE__ */ jsx(
@@ -2281,12 +2723,12 @@ const Information = ({ activeTab }) => {
2281
2723
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2282
2724
  label: formatMessage({
2283
2725
  id: "content-manager.containers.edit.information.document.label",
2284
- defaultMessage: "Document"
2726
+ defaultMessage: "Created"
2285
2727
  }),
2286
2728
  value: formatMessage(
2287
2729
  {
2288
2730
  id: "content-manager.containers.edit.information.document.value",
2289
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2731
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2290
2732
  },
2291
2733
  {
2292
2734
  time: /* @__PURE__ */ jsx(
@@ -2324,25 +2766,77 @@ const Information = ({ activeTab }) => {
2324
2766
  );
2325
2767
  };
2326
2768
  const HeaderActions = ({ actions: actions2 }) => {
2327
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2328
- if ("options" in action) {
2769
+ const [dialogId, setDialogId] = React.useState(null);
2770
+ const handleClick = (action) => async (e) => {
2771
+ if (!("options" in action)) {
2772
+ const { onClick = () => false, dialog, id } = action;
2773
+ const muteDialog = await onClick(e);
2774
+ if (dialog && !muteDialog) {
2775
+ e.preventDefault();
2776
+ setDialogId(id);
2777
+ }
2778
+ }
2779
+ };
2780
+ const handleClose = () => {
2781
+ setDialogId(null);
2782
+ };
2783
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2784
+ if (action.options) {
2329
2785
  return /* @__PURE__ */ jsx(
2330
2786
  SingleSelect,
2331
2787
  {
2332
2788
  size: "S",
2333
- disabled: action.disabled,
2334
- "aria-label": action.label,
2335
2789
  onChange: action.onSelect,
2336
- value: action.value,
2790
+ "aria-label": action.label,
2791
+ ...action,
2337
2792
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2338
2793
  },
2339
2794
  action.id
2340
2795
  );
2341
2796
  } else {
2342
- return null;
2797
+ if (action.type === "icon") {
2798
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2799
+ /* @__PURE__ */ jsx(
2800
+ IconButton,
2801
+ {
2802
+ disabled: action.disabled,
2803
+ label: action.label,
2804
+ size: "S",
2805
+ onClick: handleClick(action),
2806
+ children: action.icon
2807
+ }
2808
+ ),
2809
+ action.dialog ? /* @__PURE__ */ jsx(
2810
+ HeaderActionDialog,
2811
+ {
2812
+ ...action.dialog,
2813
+ isOpen: dialogId === action.id,
2814
+ onClose: handleClose
2815
+ }
2816
+ ) : null
2817
+ ] }, action.id);
2818
+ }
2343
2819
  }
2344
2820
  }) });
2345
2821
  };
2822
+ const HeaderActionDialog = ({
2823
+ onClose,
2824
+ onCancel,
2825
+ title,
2826
+ content: Content,
2827
+ isOpen
2828
+ }) => {
2829
+ const handleClose = async () => {
2830
+ if (onCancel) {
2831
+ await onCancel();
2832
+ }
2833
+ onClose();
2834
+ };
2835
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2836
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2837
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2838
+ ] }) });
2839
+ };
2346
2840
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2347
2841
  const navigate = useNavigate();
2348
2842
  const { formatMessage } = useIntl();
@@ -2383,12 +2877,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2383
2877
  const { delete: deleteAction } = useDocumentActions();
2384
2878
  const { toggleNotification } = useNotification();
2385
2879
  const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2880
+ const isLocalized = document?.locale != null;
2386
2881
  return {
2387
2882
  disabled: !canDelete || !document,
2388
- label: formatMessage({
2389
- id: "content-manager.actions.delete.label",
2390
- defaultMessage: "Delete document"
2391
- }),
2883
+ label: formatMessage(
2884
+ {
2885
+ id: "content-manager.actions.delete.label",
2886
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2887
+ },
2888
+ { isLocalized }
2889
+ ),
2392
2890
  icon: /* @__PURE__ */ jsx(Trash, {}),
2393
2891
  dialog: {
2394
2892
  type: "dialog",
@@ -2419,428 +2917,126 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2419
2917
  }),
2420
2918
  type: "danger"
2421
2919
  });
2422
- return;
2423
- }
2424
- const res = await deleteAction({
2425
- documentId,
2426
- model,
2427
- collectionType,
2428
- params: {
2429
- locale: "*"
2430
- }
2431
- });
2432
- if (!("error" in res)) {
2433
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2434
- }
2435
- } finally {
2436
- if (!listViewPathMatch) {
2437
- setSubmitting(false);
2438
- }
2439
- }
2440
- }
2441
- },
2442
- variant: "danger",
2443
- position: ["header", "table-row"]
2444
- };
2445
- };
2446
- DeleteAction$1.type = "delete";
2447
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2448
- const Panels = () => {
2449
- const isCloning = useMatch(CLONE_PATH) !== null;
2450
- const [
2451
- {
2452
- query: { status }
2453
- }
2454
- ] = useQueryParams({
2455
- status: "draft"
2456
- });
2457
- const { model, id, document, meta, collectionType } = useDoc();
2458
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2459
- const props = {
2460
- activeTab: status,
2461
- model,
2462
- documentId: id,
2463
- document: isCloning ? void 0 : document,
2464
- meta: isCloning ? void 0 : meta,
2465
- collectionType
2466
- };
2467
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2468
- DescriptionComponentRenderer,
2469
- {
2470
- props,
2471
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2472
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2473
- }
2474
- ) });
2475
- };
2476
- const ActionsPanel = () => {
2477
- const { formatMessage } = useIntl();
2478
- return {
2479
- title: formatMessage({
2480
- id: "content-manager.containers.edit.panels.default.title",
2481
- defaultMessage: "Document"
2482
- }),
2483
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2484
- };
2485
- };
2486
- ActionsPanel.type = "actions";
2487
- const ActionsPanelContent = () => {
2488
- const isCloning = useMatch(CLONE_PATH) !== null;
2489
- const [
2490
- {
2491
- query: { status = "draft" }
2492
- }
2493
- ] = useQueryParams();
2494
- const { model, id, document, meta, collectionType } = useDoc();
2495
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2496
- const props = {
2497
- activeTab: status,
2498
- model,
2499
- documentId: id,
2500
- document: isCloning ? void 0 : document,
2501
- meta: isCloning ? void 0 : meta,
2502
- collectionType
2503
- };
2504
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2505
- /* @__PURE__ */ jsx(
2506
- DescriptionComponentRenderer,
2507
- {
2508
- props,
2509
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2510
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2511
- }
2512
- ),
2513
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2514
- ] });
2515
- };
2516
- const Panel = React.forwardRef(({ children, title }, ref) => {
2517
- return /* @__PURE__ */ jsxs(
2518
- Flex,
2519
- {
2520
- ref,
2521
- tag: "aside",
2522
- "aria-labelledby": "additional-information",
2523
- background: "neutral0",
2524
- borderColor: "neutral150",
2525
- hasRadius: true,
2526
- paddingBottom: 4,
2527
- paddingLeft: 4,
2528
- paddingRight: 4,
2529
- paddingTop: 4,
2530
- shadow: "tableShadow",
2531
- gap: 3,
2532
- direction: "column",
2533
- justifyContent: "stretch",
2534
- alignItems: "flex-start",
2535
- children: [
2536
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2537
- children
2538
- ]
2539
- }
2540
- );
2541
- });
2542
- const HOOKS = {
2543
- /**
2544
- * Hook that allows to mutate the displayed headers of the list view table
2545
- * @constant
2546
- * @type {string}
2547
- */
2548
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2549
- /**
2550
- * Hook that allows to mutate the CM's collection types links pre-set filters
2551
- * @constant
2552
- * @type {string}
2553
- */
2554
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2555
- /**
2556
- * Hook that allows to mutate the CM's edit view layout
2557
- * @constant
2558
- * @type {string}
2559
- */
2560
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2561
- /**
2562
- * Hook that allows to mutate the CM's single types links pre-set filters
2563
- * @constant
2564
- * @type {string}
2565
- */
2566
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2567
- };
2568
- const contentTypesApi = contentManagerApi.injectEndpoints({
2569
- endpoints: (builder) => ({
2570
- getContentTypeConfiguration: builder.query({
2571
- query: (uid) => ({
2572
- url: `/content-manager/content-types/${uid}/configuration`,
2573
- method: "GET"
2574
- }),
2575
- transformResponse: (response) => response.data,
2576
- providesTags: (_result, _error, uid) => [
2577
- { type: "ContentTypesConfiguration", id: uid },
2578
- { type: "ContentTypeSettings", id: "LIST" }
2579
- ]
2580
- }),
2581
- getAllContentTypeSettings: builder.query({
2582
- query: () => "/content-manager/content-types-settings",
2583
- transformResponse: (response) => response.data,
2584
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2585
- }),
2586
- updateContentTypeConfiguration: builder.mutation({
2587
- query: ({ uid, ...body }) => ({
2588
- url: `/content-manager/content-types/${uid}/configuration`,
2589
- method: "PUT",
2590
- data: body
2591
- }),
2592
- transformResponse: (response) => response.data,
2593
- invalidatesTags: (_result, _error, { uid }) => [
2594
- { type: "ContentTypesConfiguration", id: uid },
2595
- { type: "ContentTypeSettings", id: "LIST" },
2596
- // Is this necessary?
2597
- { type: "InitialData" }
2598
- ]
2599
- })
2600
- })
2601
- });
2602
- const {
2603
- useGetContentTypeConfigurationQuery,
2604
- useGetAllContentTypeSettingsQuery,
2605
- useUpdateContentTypeConfigurationMutation
2606
- } = contentTypesApi;
2607
- const checkIfAttributeIsDisplayable = (attribute) => {
2608
- const { type } = attribute;
2609
- if (type === "relation") {
2610
- return !attribute.relation.toLowerCase().includes("morph");
2611
- }
2612
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2613
- };
2614
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2615
- if (!mainFieldName) {
2616
- return void 0;
2617
- }
2618
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2619
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2620
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2621
- );
2622
- return {
2623
- name: mainFieldName,
2624
- type: mainFieldType ?? "string"
2625
- };
2626
- };
2627
- const DEFAULT_SETTINGS = {
2628
- bulkable: false,
2629
- filterable: false,
2630
- searchable: false,
2631
- pagination: false,
2632
- defaultSortBy: "",
2633
- defaultSortOrder: "asc",
2634
- mainField: "id",
2635
- pageSize: 10
2636
- };
2637
- const useDocumentLayout = (model) => {
2638
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2639
- const [{ query }] = useQueryParams();
2640
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2641
- const { toggleNotification } = useNotification();
2642
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2643
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2644
- const {
2645
- data,
2646
- isLoading: isLoadingConfigs,
2647
- error,
2648
- isFetching: isFetchingConfigs
2649
- } = useGetContentTypeConfigurationQuery(model);
2650
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2651
- React.useEffect(() => {
2652
- if (error) {
2653
- toggleNotification({
2654
- type: "danger",
2655
- message: formatAPIError(error)
2656
- });
2657
- }
2658
- }, [error, formatAPIError, toggleNotification]);
2659
- const editLayout = React.useMemo(
2660
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2661
- layout: [],
2662
- components: {},
2663
- metadatas: {},
2664
- options: {},
2665
- settings: DEFAULT_SETTINGS
2666
- },
2667
- [data, isLoading, schemas, schema, components]
2668
- );
2669
- const listLayout = React.useMemo(() => {
2670
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2671
- layout: [],
2672
- metadatas: {},
2673
- options: {},
2674
- settings: DEFAULT_SETTINGS
2675
- };
2676
- }, [data, isLoading, schemas, schema, components]);
2677
- const { layout: edit } = React.useMemo(
2678
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2679
- layout: editLayout,
2680
- query
2681
- }),
2682
- [editLayout, query, runHookWaterfall]
2683
- );
2684
- return {
2685
- error,
2686
- isLoading,
2687
- edit,
2688
- list: listLayout
2689
- };
2690
- };
2691
- const useDocLayout = () => {
2692
- const { model } = useDoc();
2693
- return useDocumentLayout(model);
2694
- };
2695
- const formatEditLayout = (data, {
2696
- schemas,
2697
- schema,
2698
- components
2699
- }) => {
2700
- let currentPanelIndex = 0;
2701
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2702
- data.contentType.layouts.edit,
2703
- schema?.attributes,
2704
- data.contentType.metadatas,
2705
- { configurations: data.components, schemas: components },
2706
- schemas
2707
- ).reduce((panels, row) => {
2708
- if (row.some((field) => field.type === "dynamiczone")) {
2709
- panels.push([row]);
2710
- currentPanelIndex += 2;
2711
- } else {
2712
- if (!panels[currentPanelIndex]) {
2713
- panels.push([]);
2714
- }
2715
- panels[currentPanelIndex].push(row);
2716
- }
2717
- return panels;
2718
- }, []);
2719
- const componentEditAttributes = Object.entries(data.components).reduce(
2720
- (acc, [uid, configuration]) => {
2721
- acc[uid] = {
2722
- layout: convertEditLayoutToFieldLayouts(
2723
- configuration.layouts.edit,
2724
- components[uid].attributes,
2725
- configuration.metadatas
2726
- ),
2727
- settings: {
2728
- ...configuration.settings,
2729
- icon: components[uid].info.icon,
2730
- displayName: components[uid].info.displayName
2920
+ return;
2921
+ }
2922
+ const res = await deleteAction({
2923
+ documentId,
2924
+ model,
2925
+ collectionType,
2926
+ params: {
2927
+ locale: "*"
2928
+ }
2929
+ });
2930
+ if (!("error" in res)) {
2931
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2932
+ }
2933
+ } finally {
2934
+ if (!listViewPathMatch) {
2935
+ setSubmitting(false);
2936
+ }
2731
2937
  }
2732
- };
2733
- return acc;
2734
- },
2735
- {}
2736
- );
2737
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2738
- (acc, [attribute, metadata]) => {
2739
- return {
2740
- ...acc,
2741
- [attribute]: metadata.edit
2742
- };
2743
- },
2744
- {}
2745
- );
2746
- return {
2747
- layout: panelledEditAttributes,
2748
- components: componentEditAttributes,
2749
- metadatas: editMetadatas,
2750
- settings: {
2751
- ...data.contentType.settings,
2752
- displayName: schema?.info.displayName
2938
+ }
2753
2939
  },
2754
- options: {
2755
- ...schema?.options,
2756
- ...schema?.pluginOptions,
2757
- ...data.contentType.options
2758
- }
2940
+ variant: "danger",
2941
+ position: ["header", "table-row"]
2759
2942
  };
2760
2943
  };
2761
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2762
- return rows.map(
2763
- (row) => row.map((field) => {
2764
- const attribute = attributes[field.name];
2765
- if (!attribute) {
2766
- return null;
2767
- }
2768
- const { edit: metadata } = metadatas[field.name];
2769
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2770
- return {
2771
- attribute,
2772
- disabled: !metadata.editable,
2773
- hint: metadata.description,
2774
- label: metadata.label ?? "",
2775
- name: field.name,
2776
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2777
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2778
- schemas,
2779
- components: components?.schemas ?? {}
2780
- }),
2781
- placeholder: metadata.placeholder ?? "",
2782
- required: attribute.required ?? false,
2783
- size: field.size,
2784
- unique: "unique" in attribute ? attribute.unique : false,
2785
- visible: metadata.visible ?? true,
2786
- type: attribute.type
2787
- };
2788
- }).filter((field) => field !== null)
2789
- );
2944
+ DeleteAction$1.type = "delete";
2945
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2946
+ const Panels = () => {
2947
+ const isCloning = useMatch(CLONE_PATH) !== null;
2948
+ const [
2949
+ {
2950
+ query: { status }
2951
+ }
2952
+ ] = useQueryParams({
2953
+ status: "draft"
2954
+ });
2955
+ const { model, id, document, meta, collectionType } = useDoc();
2956
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
2957
+ const props = {
2958
+ activeTab: status,
2959
+ model,
2960
+ documentId: id,
2961
+ document: isCloning ? void 0 : document,
2962
+ meta: isCloning ? void 0 : meta,
2963
+ collectionType
2964
+ };
2965
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2966
+ DescriptionComponentRenderer,
2967
+ {
2968
+ props,
2969
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2970
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2971
+ }
2972
+ ) });
2790
2973
  };
2791
- const formatListLayout = (data, {
2792
- schemas,
2793
- schema,
2794
- components
2795
- }) => {
2796
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2797
- (acc, [attribute, metadata]) => {
2798
- return {
2799
- ...acc,
2800
- [attribute]: metadata.list
2801
- };
2802
- },
2803
- {}
2804
- );
2805
- const listAttributes = convertListLayoutToFieldLayouts(
2806
- data.contentType.layouts.list,
2807
- schema?.attributes,
2808
- listMetadatas,
2809
- { configurations: data.components, schemas: components },
2810
- schemas
2811
- );
2974
+ const ActionsPanel = () => {
2975
+ const { formatMessage } = useIntl();
2812
2976
  return {
2813
- layout: listAttributes,
2814
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2815
- metadatas: listMetadatas,
2816
- options: {
2817
- ...schema?.options,
2818
- ...schema?.pluginOptions,
2819
- ...data.contentType.options
2820
- }
2977
+ title: formatMessage({
2978
+ id: "content-manager.containers.edit.panels.default.title",
2979
+ defaultMessage: "Entry"
2980
+ }),
2981
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2821
2982
  };
2822
2983
  };
2823
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2824
- return columns.map((name) => {
2825
- const attribute = attributes[name];
2826
- if (!attribute) {
2827
- return null;
2984
+ ActionsPanel.type = "actions";
2985
+ const ActionsPanelContent = () => {
2986
+ const isCloning = useMatch(CLONE_PATH) !== null;
2987
+ const [
2988
+ {
2989
+ query: { status = "draft" }
2828
2990
  }
2829
- const metadata = metadatas[name];
2830
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2831
- return {
2832
- attribute,
2833
- label: metadata.label ?? "",
2834
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2835
- schemas,
2836
- components: components?.schemas ?? {}
2837
- }),
2838
- name,
2839
- searchable: metadata.searchable ?? true,
2840
- sortable: metadata.sortable ?? true
2841
- };
2842
- }).filter((field) => field !== null);
2991
+ ] = useQueryParams();
2992
+ const { model, id, document, meta, collectionType } = useDoc();
2993
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2994
+ const props = {
2995
+ activeTab: status,
2996
+ model,
2997
+ documentId: id,
2998
+ document: isCloning ? void 0 : document,
2999
+ meta: isCloning ? void 0 : meta,
3000
+ collectionType
3001
+ };
3002
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3003
+ /* @__PURE__ */ jsx(
3004
+ DescriptionComponentRenderer,
3005
+ {
3006
+ props,
3007
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3008
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3009
+ }
3010
+ ),
3011
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3012
+ ] });
2843
3013
  };
3014
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3015
+ return /* @__PURE__ */ jsxs(
3016
+ Flex,
3017
+ {
3018
+ ref,
3019
+ tag: "aside",
3020
+ "aria-labelledby": "additional-information",
3021
+ background: "neutral0",
3022
+ borderColor: "neutral150",
3023
+ hasRadius: true,
3024
+ paddingBottom: 4,
3025
+ paddingLeft: 4,
3026
+ paddingRight: 4,
3027
+ paddingTop: 4,
3028
+ shadow: "tableShadow",
3029
+ gap: 3,
3030
+ direction: "column",
3031
+ justifyContent: "stretch",
3032
+ alignItems: "flex-start",
3033
+ children: [
3034
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3035
+ children
3036
+ ]
3037
+ }
3038
+ );
3039
+ });
2844
3040
  const ConfirmBulkActionDialog = ({
2845
3041
  onToggleDialog,
2846
3042
  isOpen = false,
@@ -2879,6 +3075,7 @@ const ConfirmDialogPublishAll = ({
2879
3075
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2880
3076
  const { model, schema } = useDoc();
2881
3077
  const [{ query }] = useQueryParams();
3078
+ const enableDraftRelationsCount = false;
2882
3079
  const {
2883
3080
  data: countDraftRelations = 0,
2884
3081
  isLoading,
@@ -2890,7 +3087,7 @@ const ConfirmDialogPublishAll = ({
2890
3087
  locale: query?.plugins?.i18n?.locale
2891
3088
  },
2892
3089
  {
2893
- skip: selectedEntries.length === 0
3090
+ skip: !enableDraftRelationsCount
2894
3091
  }
2895
3092
  );
2896
3093
  React.useEffect(() => {
@@ -3075,7 +3272,7 @@ const SelectedEntriesTableContent = ({
3075
3272
  status: row.status
3076
3273
  }
3077
3274
  ) }),
3078
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3275
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3079
3276
  IconButton,
3080
3277
  {
3081
3278
  tag: Link,
@@ -3084,23 +3281,16 @@ const SelectedEntriesTableContent = ({
3084
3281
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3085
3282
  },
3086
3283
  state: { from: pathname },
3087
- label: formatMessage(
3088
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3089
- {
3090
- target: formatMessage(
3091
- {
3092
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3093
- defaultMessage: "item line {number}"
3094
- },
3095
- { number: index2 + 1 }
3096
- )
3097
- }
3098
- ),
3284
+ label: formatMessage({
3285
+ id: "content-manager.bulk-publish.edit",
3286
+ defaultMessage: "Edit"
3287
+ }),
3099
3288
  target: "_blank",
3100
3289
  marginLeft: "auto",
3101
- children: /* @__PURE__ */ jsx(Pencil, {})
3290
+ variant: "ghost",
3291
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3102
3292
  }
3103
- ) })
3293
+ ) }) })
3104
3294
  ] }, row.id)) })
3105
3295
  ] });
3106
3296
  };
@@ -3137,7 +3327,13 @@ const SelectedEntriesModalContent = ({
3137
3327
  );
3138
3328
  const { rows, validationErrors } = React.useMemo(() => {
3139
3329
  if (data.length > 0 && schema) {
3140
- const validate = createYupSchema(schema.attributes, components);
3330
+ const validate = createYupSchema(
3331
+ schema.attributes,
3332
+ components,
3333
+ // Since this is the "Publish" action, the validation
3334
+ // schema must enforce the rules for published entities
3335
+ { status: "published" }
3336
+ );
3141
3337
  const validationErrors2 = {};
3142
3338
  const rows2 = data.map((entry) => {
3143
3339
  try {
@@ -3487,7 +3683,7 @@ const TableActions = ({ document }) => {
3487
3683
  DescriptionComponentRenderer,
3488
3684
  {
3489
3685
  props,
3490
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3686
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3491
3687
  children: (actions2) => {
3492
3688
  const tableRowActions = actions2.filter((action) => {
3493
3689
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3598,7 +3794,7 @@ const CloneAction = ({ model, documentId }) => {
3598
3794
  }),
3599
3795
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3600
3796
  footer: ({ onClose }) => {
3601
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3797
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3602
3798
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3603
3799
  id: "cancel",
3604
3800
  defaultMessage: "Cancel"
@@ -3732,17 +3928,27 @@ const HistoryAction = ({ model, document }) => {
3732
3928
  const { formatMessage } = useIntl();
3733
3929
  const [{ query }] = useQueryParams();
3734
3930
  const navigate = useNavigate();
3931
+ const { trackUsage } = useTracking();
3932
+ const { pathname } = useLocation();
3735
3933
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3736
3934
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3737
3935
  return null;
3738
3936
  }
3937
+ const handleOnClick = () => {
3938
+ const destination = { pathname: "history", search: pluginsQueryParams };
3939
+ trackUsage("willNavigate", {
3940
+ from: pathname,
3941
+ to: `${pathname}/${destination.pathname}`
3942
+ });
3943
+ navigate(destination);
3944
+ };
3739
3945
  return {
3740
3946
  icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3741
3947
  label: formatMessage({
3742
3948
  id: "content-manager.history.document-action",
3743
3949
  defaultMessage: "Content History"
3744
3950
  }),
3745
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3951
+ onClick: handleOnClick,
3746
3952
  disabled: (
3747
3953
  /**
3748
3954
  * The user is creating a new document.
@@ -3810,6 +4016,72 @@ const { setInitialData } = actions;
3810
4016
  const reducer = combineReducers({
3811
4017
  app: reducer$1
3812
4018
  });
4019
+ const previewApi = contentManagerApi.injectEndpoints({
4020
+ endpoints: (builder) => ({
4021
+ getPreviewUrl: builder.query({
4022
+ query({ query, params }) {
4023
+ return {
4024
+ url: `/content-manager/preview/url/${params.contentType}`,
4025
+ method: "GET",
4026
+ config: {
4027
+ params: query
4028
+ }
4029
+ };
4030
+ }
4031
+ })
4032
+ })
4033
+ });
4034
+ const { useGetPreviewUrlQuery } = previewApi;
4035
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4036
+ const { formatMessage } = useIntl();
4037
+ const { trackUsage } = useTracking();
4038
+ const { pathname } = useLocation();
4039
+ const [{ query }] = useQueryParams();
4040
+ const { data, error } = useGetPreviewUrlQuery({
4041
+ params: {
4042
+ contentType: model
4043
+ },
4044
+ query: {
4045
+ documentId,
4046
+ locale: document?.locale,
4047
+ status: document?.status
4048
+ }
4049
+ });
4050
+ if (!data?.data?.url || error) {
4051
+ return null;
4052
+ }
4053
+ const trackNavigation = () => {
4054
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4055
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4056
+ };
4057
+ return {
4058
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4059
+ content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
4060
+ Button,
4061
+ {
4062
+ variant: "tertiary",
4063
+ tag: Link,
4064
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4065
+ onClick: trackNavigation,
4066
+ flex: "auto",
4067
+ children: formatMessage({
4068
+ id: "content-manager.preview.panel.button",
4069
+ defaultMessage: "Open preview"
4070
+ })
4071
+ }
4072
+ ) })
4073
+ };
4074
+ };
4075
+ const FEATURE_ID = "preview";
4076
+ const previewAdmin = {
4077
+ bootstrap(app) {
4078
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4079
+ return;
4080
+ }
4081
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4082
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4083
+ }
4084
+ };
3813
4085
  const index = {
3814
4086
  register(app) {
3815
4087
  const cm = new ContentManagerPlugin();
@@ -3829,7 +4101,7 @@ const index = {
3829
4101
  app.router.addRoute({
3830
4102
  path: "content-manager/*",
3831
4103
  lazy: async () => {
3832
- const { Layout } = await import("./layout-DPaHUusj.mjs");
4104
+ const { Layout } = await import("./layout-DFVbgjp2.mjs");
3833
4105
  return {
3834
4106
  Component: Layout
3835
4107
  };
@@ -3842,11 +4114,14 @@ const index = {
3842
4114
  if (typeof historyAdmin.bootstrap === "function") {
3843
4115
  historyAdmin.bootstrap(app);
3844
4116
  }
4117
+ if (typeof previewAdmin.bootstrap === "function") {
4118
+ previewAdmin.bootstrap(app);
4119
+ }
3845
4120
  },
3846
4121
  async registerTrads({ locales }) {
3847
4122
  const importedTrads = await Promise.all(
3848
4123
  locales.map((locale) => {
3849
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-BrCTWlZv.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4124
+ 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-CfIXaZf9.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`).then(({ default: data }) => {
3850
4125
  return {
3851
4126
  data: prefixPluginTranslations(data, PLUGIN_ID),
3852
4127
  locale
@@ -3867,13 +4142,16 @@ export {
3867
4142
  BulkActionsRenderer as B,
3868
4143
  COLLECTION_TYPES as C,
3869
4144
  DocumentStatus as D,
3870
- DEFAULT_SETTINGS as E,
3871
- convertEditLayoutToFieldLayouts as F,
3872
- useDocument as G,
4145
+ extractContentTypeComponents as E,
4146
+ DEFAULT_SETTINGS as F,
4147
+ convertEditLayoutToFieldLayouts as G,
3873
4148
  HOOKS as H,
3874
4149
  InjectionZone as I,
3875
- index as J,
3876
- useDocumentActions as K,
4150
+ useDocument as J,
4151
+ useGetPreviewUrlQuery as K,
4152
+ index as L,
4153
+ useContentManagerContext as M,
4154
+ useDocumentActions as N,
3877
4155
  Panels as P,
3878
4156
  RelativeTime as R,
3879
4157
  SINGLE_TYPES as S,
@@ -3891,18 +4169,18 @@ export {
3891
4169
  PERMISSIONS as k,
3892
4170
  DocumentRBAC as l,
3893
4171
  DOCUMENT_META_FIELDS as m,
3894
- useDocLayout as n,
3895
- useGetContentTypeConfigurationQuery as o,
3896
- CREATOR_FIELDS as p,
3897
- getMainField as q,
3898
- getDisplayName as r,
4172
+ CLONE_PATH as n,
4173
+ useDocLayout as o,
4174
+ useGetContentTypeConfigurationQuery as p,
4175
+ CREATOR_FIELDS as q,
4176
+ getMainField as r,
3899
4177
  setInitialData as s,
3900
- checkIfAttributeIsDisplayable as t,
4178
+ getDisplayName as t,
3901
4179
  useContentTypeSchema as u,
3902
- useGetAllDocumentsQuery as v,
3903
- convertListLayoutToFieldLayouts as w,
3904
- capitalise as x,
3905
- useUpdateContentTypeConfigurationMutation as y,
3906
- extractContentTypeComponents as z
4180
+ checkIfAttributeIsDisplayable as v,
4181
+ useGetAllDocumentsQuery as w,
4182
+ convertListLayoutToFieldLayouts as x,
4183
+ capitalise as y,
4184
+ useUpdateContentTypeConfigurationMutation as z
3907
4185
  };
3908
- //# sourceMappingURL=index-BSn97i8U.mjs.map
4186
+ //# sourceMappingURL=index-BW-rXkjn.mjs.map