@strapi/content-manager 0.0.0-experimental.bd712ad3930045f4a5d2144c119e0b7856e97fc4 → 0.0.0-experimental.c222e1c4de12dd05c26938a605a1128fb3481d1d

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-BWQv6yRj.js → ComponentConfigurationPage--MCP7Aew.js} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-BWQv6yRj.js.map → ComponentConfigurationPage--MCP7Aew.js.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-C7ImeKGM.mjs → ComponentConfigurationPage-DT41asyM.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-C7ImeKGM.mjs.map → ComponentConfigurationPage-DT41asyM.mjs.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-MItFGzT9.mjs → EditConfigurationPage-DznPxn9p.mjs} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-MItFGzT9.mjs.map → EditConfigurationPage-DznPxn9p.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-CEGwxV-L.js → EditConfigurationPage-qgnNvv_u.js} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-CEGwxV-L.js.map → EditConfigurationPage-qgnNvv_u.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-DhmAg0NK.mjs → EditViewPage-B_k7z288.mjs} +33 -11
  10. package/dist/_chunks/EditViewPage-B_k7z288.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-CmMi2Xsn.js → EditViewPage-Bb4S7p8c.js} +32 -10
  12. package/dist/_chunks/EditViewPage-Bb4S7p8c.js.map +1 -0
  13. package/dist/_chunks/{Field-1DLtcLAI.js → Field-ByR1mllE.js} +181 -109
  14. package/dist/_chunks/Field-ByR1mllE.js.map +1 -0
  15. package/dist/_chunks/{Field-Cs62u5pl.mjs → Field-DmwbE0TL.mjs} +179 -107
  16. package/dist/_chunks/Field-DmwbE0TL.mjs.map +1 -0
  17. package/dist/_chunks/{Form-CqFA7F_V.js → Form-BpeyAyS1.js} +36 -17
  18. package/dist/_chunks/Form-BpeyAyS1.js.map +1 -0
  19. package/dist/_chunks/{Form-zYHtzGUX.mjs → Form-Dvt5eouJ.mjs} +36 -17
  20. package/dist/_chunks/Form-Dvt5eouJ.mjs.map +1 -0
  21. package/dist/_chunks/{History-DalgFQ3D.mjs → History-CAERKpYl.mjs} +54 -54
  22. package/dist/_chunks/History-CAERKpYl.mjs.map +1 -0
  23. package/dist/_chunks/{History-BblwXv7-.js → History-d-IgDGPl.js} +53 -53
  24. package/dist/_chunks/History-d-IgDGPl.js.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-DWy-vRzs.mjs → ListConfigurationPage-CVVT45M8.mjs} +15 -5
  26. package/dist/_chunks/ListConfigurationPage-CVVT45M8.mjs.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-Cpy4QqNd.js → ListConfigurationPage-DSX98CYb.js} +15 -5
  28. package/dist/_chunks/ListConfigurationPage-DSX98CYb.js.map +1 -0
  29. package/dist/_chunks/{ListViewPage-DFjn1DNW.js → ListViewPage-C9gPPp-V.js} +61 -41
  30. package/dist/_chunks/ListViewPage-C9gPPp-V.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-BkAwIW9s.mjs → ListViewPage-Q4g6kHDl.mjs} +59 -39
  32. package/dist/_chunks/ListViewPage-Q4g6kHDl.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-B9BCNNdL.mjs → NoContentTypePage-BY4YRGs0.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-B9BCNNdL.mjs.map → NoContentTypePage-BY4YRGs0.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-C-3ykoxs.js → NoContentTypePage-D09gppmy.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-C-3ykoxs.js.map → NoContentTypePage-D09gppmy.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DKLmDZnZ.js → NoPermissionsPage-32WgThJG.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DKLmDZnZ.js.map → NoPermissionsPage-32WgThJG.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-Bt_HWGat.mjs → NoPermissionsPage-CyM16RKL.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-Bt_HWGat.mjs.map → NoPermissionsPage-CyM16RKL.mjs.map} +1 -1
  41. package/dist/_chunks/Preview-C2WFq4S8.mjs +267 -0
  42. package/dist/_chunks/Preview-C2WFq4S8.mjs.map +1 -0
  43. package/dist/_chunks/Preview-PpV3g9wJ.js +286 -0
  44. package/dist/_chunks/Preview-PpV3g9wJ.js.map +1 -0
  45. package/dist/_chunks/{Relations-CJmTbZ8T.mjs → Relations-B_Yn9xGB.mjs} +73 -37
  46. package/dist/_chunks/Relations-B_Yn9xGB.mjs.map +1 -0
  47. package/dist/_chunks/{Relations-CrxfoH2n.js → Relations-mWaebC5t.js} +72 -36
  48. package/dist/_chunks/Relations-mWaebC5t.js.map +1 -0
  49. package/dist/_chunks/{en-fbKQxLGn.js → en-CHOp_xJv.js} +27 -16
  50. package/dist/_chunks/{en-fbKQxLGn.js.map → en-CHOp_xJv.js.map} +1 -1
  51. package/dist/_chunks/{en-Ux26r5pl.mjs → en-D_BMf0hT.mjs} +27 -16
  52. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-D_BMf0hT.mjs.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-D1344xdw.mjs → index-CbytGVdz.mjs} +1070 -698
  62. package/dist/_chunks/index-CbytGVdz.mjs.map +1 -0
  63. package/dist/_chunks/{index-Buwn78Rt.js → index-iun2i4xv.js} +1052 -679
  64. package/dist/_chunks/index-iun2i4xv.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-ChVuUpa1.mjs → layout-Btu_cMRF.mjs} +22 -9
  70. package/dist/_chunks/layout-Btu_cMRF.mjs.map +1 -0
  71. package/dist/_chunks/{layout-DRuJUpas.js → layout-CkaP4K5_.js} +21 -8
  72. package/dist/_chunks/layout-CkaP4K5_.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-B-deMCy4.mjs → relations-Cn5re8ia.mjs} +6 -7
  78. package/dist/_chunks/relations-Cn5re8ia.mjs.map +1 -0
  79. package/dist/_chunks/{relations-DuoUwyJr.js → relations-O_v9g0v_.js} +6 -7
  80. package/dist/_chunks/relations-O_v9g0v_.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/index.d.ts +3 -0
  90. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  91. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  92. package/dist/admin/src/index.d.ts +1 -0
  93. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  94. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  95. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  96. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  98. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  99. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  100. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  101. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  102. package/dist/admin/src/preview/constants.d.ts +1 -0
  103. package/dist/admin/src/preview/index.d.ts +4 -0
  104. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  105. package/dist/admin/src/preview/routes.d.ts +3 -0
  106. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  107. package/dist/admin/src/services/api.d.ts +1 -1
  108. package/dist/admin/src/services/components.d.ts +2 -2
  109. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  110. package/dist/admin/src/services/documents.d.ts +19 -17
  111. package/dist/admin/src/services/init.d.ts +1 -1
  112. package/dist/admin/src/services/relations.d.ts +2 -2
  113. package/dist/admin/src/services/uid.d.ts +3 -3
  114. package/dist/admin/src/utils/validation.d.ts +4 -1
  115. package/dist/server/index.js +544 -261
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/index.mjs +545 -262
  118. package/dist/server/index.mjs.map +1 -1
  119. package/dist/server/src/bootstrap.d.ts.map +1 -1
  120. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  121. package/dist/server/src/controllers/index.d.ts.map +1 -1
  122. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  123. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  124. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  125. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  126. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  127. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  128. package/dist/server/src/history/services/history.d.ts.map +1 -1
  129. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  130. package/dist/server/src/history/services/utils.d.ts +4 -4
  131. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  132. package/dist/server/src/index.d.ts +4 -4
  133. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  134. package/dist/server/src/preview/constants.d.ts +2 -0
  135. package/dist/server/src/preview/constants.d.ts.map +1 -0
  136. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  137. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  138. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  139. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  140. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  141. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  142. package/dist/server/src/preview/index.d.ts +4 -0
  143. package/dist/server/src/preview/index.d.ts.map +1 -0
  144. package/dist/server/src/preview/routes/index.d.ts +8 -0
  145. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  146. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  147. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  148. package/dist/server/src/preview/services/index.d.ts +15 -0
  149. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  150. package/dist/server/src/preview/services/preview-config.d.ts +30 -0
  151. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  152. package/dist/server/src/preview/services/preview.d.ts +12 -0
  153. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  154. package/dist/server/src/preview/utils.d.ts +18 -0
  155. package/dist/server/src/preview/utils.d.ts.map +1 -0
  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 +13 -13
  179. package/dist/_chunks/EditViewPage-CmMi2Xsn.js.map +0 -1
  180. package/dist/_chunks/EditViewPage-DhmAg0NK.mjs.map +0 -1
  181. package/dist/_chunks/Field-1DLtcLAI.js.map +0 -1
  182. package/dist/_chunks/Field-Cs62u5pl.mjs.map +0 -1
  183. package/dist/_chunks/Form-CqFA7F_V.js.map +0 -1
  184. package/dist/_chunks/Form-zYHtzGUX.mjs.map +0 -1
  185. package/dist/_chunks/History-BblwXv7-.js.map +0 -1
  186. package/dist/_chunks/History-DalgFQ3D.mjs.map +0 -1
  187. package/dist/_chunks/ListConfigurationPage-Cpy4QqNd.js.map +0 -1
  188. package/dist/_chunks/ListConfigurationPage-DWy-vRzs.mjs.map +0 -1
  189. package/dist/_chunks/ListViewPage-BkAwIW9s.mjs.map +0 -1
  190. package/dist/_chunks/ListViewPage-DFjn1DNW.js.map +0 -1
  191. package/dist/_chunks/Relations-CJmTbZ8T.mjs.map +0 -1
  192. package/dist/_chunks/Relations-CrxfoH2n.js.map +0 -1
  193. package/dist/_chunks/index-Buwn78Rt.js.map +0 -1
  194. package/dist/_chunks/index-D1344xdw.mjs.map +0 -1
  195. package/dist/_chunks/layout-ChVuUpa1.mjs.map +0 -1
  196. package/dist/_chunks/layout-DRuJUpas.js.map +0 -1
  197. package/dist/_chunks/relations-B-deMCy4.mjs.map +0 -1
  198. package/dist/_chunks/relations-DuoUwyJr.js.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,17 +1,18 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
10
- import { styled } from "styled-components";
6
+ import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import mapValues from "lodash/fp/mapValues";
8
+ import { useIntl } from "react-intl";
9
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
12
  import pipe from "lodash/fp/pipe";
14
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { styled } from "styled-components";
15
+ import { stringify } from "qs";
15
16
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
17
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
18
  const v = glob[path];
@@ -49,42 +50,6 @@ const useInjectionZone = (area) => {
49
50
  const [page, position] = area.split(".");
50
51
  return contentManagerPlugin.getInjectedComponents(page, position);
51
52
  };
52
- const HistoryAction = ({ model, document }) => {
53
- const { formatMessage } = useIntl();
54
- const [{ query }] = useQueryParams();
55
- const navigate = useNavigate();
56
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
57
- if (!window.strapi.features.isEnabled("cms-content-history")) {
58
- return null;
59
- }
60
- return {
61
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
62
- label: formatMessage({
63
- id: "content-manager.history.document-action",
64
- defaultMessage: "Content History"
65
- }),
66
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
67
- disabled: (
68
- /**
69
- * The user is creating a new document.
70
- * It hasn't been saved yet, so there's no history to go to
71
- */
72
- !document || /**
73
- * The document has been created but the current dimension has never been saved.
74
- * For example, the user is creating a new locale in an existing document,
75
- * so there's no history for the document in that locale
76
- */
77
- !document.id || /**
78
- * History is only available for content types created by the user.
79
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
80
- * which start with `admin::` or `plugin::`
81
- */
82
- !model.startsWith("api::")
83
- ),
84
- position: "header"
85
- };
86
- };
87
- HistoryAction.type = "history";
88
53
  const ID = "id";
89
54
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
90
55
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -136,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
136
101
  if (!slug) {
137
102
  throw new Error("Cannot find the slug param in the URL");
138
103
  }
104
+ const [{ rawQuery }] = useQueryParams();
139
105
  const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
140
106
  const contentTypePermissions = React.useMemo(() => {
141
107
  const contentTypePermissions2 = userPermissions.filter(
@@ -146,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
146
112
  return { ...acc, [action]: [permission] };
147
113
  }, {});
148
114
  }, [slug, userPermissions]);
149
- 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
+ );
150
123
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
151
124
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
152
125
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -194,7 +167,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
194
167
  "Document",
195
168
  "InitialData",
196
169
  "HistoryVersion",
197
- "Relations"
170
+ "Relations",
171
+ "UidAvailability"
198
172
  ]
199
173
  });
200
174
  const documentApi = contentManagerApi.injectEndpoints({
@@ -208,7 +182,12 @@ const documentApi = contentManagerApi.injectEndpoints({
208
182
  params: query
209
183
  }
210
184
  }),
211
- 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
+ }
212
191
  }),
213
192
  cloneDocument: builder.mutation({
214
193
  query: ({ model, sourceId, data, params }) => ({
@@ -219,7 +198,10 @@ const documentApi = contentManagerApi.injectEndpoints({
219
198
  params
220
199
  }
221
200
  }),
222
- 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
+ ]
223
205
  }),
224
206
  /**
225
207
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -236,7 +218,8 @@ const documentApi = contentManagerApi.injectEndpoints({
236
218
  }),
237
219
  invalidatesTags: (result, _error, { model }) => [
238
220
  { type: "Document", id: `${model}_LIST` },
239
- "Relations"
221
+ "Relations",
222
+ { type: "UidAvailability", id: model }
240
223
  ]
241
224
  }),
242
225
  deleteDocument: builder.mutation({
@@ -277,7 +260,8 @@ const documentApi = contentManagerApi.injectEndpoints({
277
260
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
278
261
  },
279
262
  { type: "Document", id: `${model}_LIST` },
280
- "Relations"
263
+ "Relations",
264
+ { type: "UidAvailability", id: model }
281
265
  ];
282
266
  }
283
267
  }),
@@ -295,6 +279,7 @@ const documentApi = contentManagerApi.injectEndpoints({
295
279
  }),
296
280
  providesTags: (result, _error, arg) => {
297
281
  return [
282
+ { type: "Document", id: `ALL_LIST` },
298
283
  { type: "Document", id: `${arg.model}_LIST` },
299
284
  ...result?.results.map(({ documentId }) => ({
300
285
  type: "Document",
@@ -333,6 +318,11 @@ const documentApi = contentManagerApi.injectEndpoints({
333
318
  {
334
319
  type: "Document",
335
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`
336
326
  }
337
327
  ];
338
328
  }
@@ -396,8 +386,21 @@ const documentApi = contentManagerApi.injectEndpoints({
396
386
  type: "Document",
397
387
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
398
388
  },
399
- "Relations"
389
+ "Relations",
390
+ { type: "UidAvailability", id: model }
400
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
+ }
401
404
  }
402
405
  }),
403
406
  unpublishDocument: builder.mutation({
@@ -467,20 +470,39 @@ const buildValidParams = (query) => {
467
470
  const isBaseQueryError = (error) => {
468
471
  return error.name !== void 0;
469
472
  };
470
- 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 }) => {
471
492
  const createModelSchema = (attributes2) => yup.object().shape(
472
493
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
473
494
  if (DOCUMENT_META_FIELDS.includes(name)) {
474
495
  return acc;
475
496
  }
476
497
  const validations = [
498
+ addNullableValidation,
477
499
  addRequiredValidation,
478
500
  addMinLengthValidation,
479
501
  addMaxLengthValidation,
480
502
  addMinValidation,
481
503
  addMaxValidation,
482
504
  addRegexValidation
483
- ].map((fn) => fn(attribute));
505
+ ].map((fn) => fn(attribute, options));
484
506
  const transformSchema = pipe(...validations);
485
507
  switch (attribute.type) {
486
508
  case "component": {
@@ -490,12 +512,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
490
512
  ...acc,
491
513
  [name]: transformSchema(
492
514
  yup.array().of(createModelSchema(attributes3).nullable(false))
493
- )
515
+ ).test(arrayValidator(attribute, options))
494
516
  };
495
517
  } else {
496
518
  return {
497
519
  ...acc,
498
- [name]: transformSchema(createModelSchema(attributes3))
520
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
499
521
  };
500
522
  }
501
523
  }
@@ -517,7 +539,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
517
539
  }
518
540
  )
519
541
  )
520
- )
542
+ ).test(arrayValidator(attribute, options))
521
543
  };
522
544
  case "relation":
523
545
  return {
@@ -529,7 +551,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
529
551
  } else if (Array.isArray(value)) {
530
552
  return yup.array().of(
531
553
  yup.object().shape({
532
- id: yup.string().required()
554
+ id: yup.number().required()
533
555
  })
534
556
  );
535
557
  } else if (typeof value === "object") {
@@ -581,6 +603,14 @@ const createAttributeSchema = (attribute) => {
581
603
  if (!value || typeof value === "string" && value.length === 0) {
582
604
  return true;
583
605
  }
606
+ if (typeof value === "object") {
607
+ try {
608
+ JSON.stringify(value);
609
+ return true;
610
+ } catch (err) {
611
+ return false;
612
+ }
613
+ }
584
614
  try {
585
615
  JSON.parse(value);
586
616
  return true;
@@ -599,13 +629,7 @@ const createAttributeSchema = (attribute) => {
599
629
  return yup.mixed();
600
630
  }
601
631
  };
602
- const addRequiredValidation = (attribute) => (schema) => {
603
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
604
- return schema.min(1, translatedErrors.required);
605
- }
606
- if (attribute.required && attribute.type !== "relation") {
607
- return schema.required(translatedErrors.required);
608
- }
632
+ const nullableSchema = (schema) => {
609
633
  return schema?.nullable ? schema.nullable() : (
610
634
  // In some cases '.nullable' will not be available on the schema.
611
635
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -613,7 +637,22 @@ const addRequiredValidation = (attribute) => (schema) => {
613
637
  schema
614
638
  );
615
639
  };
616
- 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
+ }
617
656
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
618
657
  return schema.min(attribute.minLength, {
619
658
  ...translatedErrors.minLength,
@@ -635,32 +674,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
635
674
  }
636
675
  return schema;
637
676
  };
638
- const addMinValidation = (attribute) => (schema) => {
639
- 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) {
640
682
  const min = toInteger(attribute.min);
641
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
642
- if (!attribute.required && "test" in schema && min) {
643
- return schema.test(
644
- "custom-min",
645
- {
646
- ...translatedErrors.min,
647
- values: {
648
- min: attribute.min
649
- }
650
- },
651
- (value) => {
652
- if (!value) {
653
- return true;
654
- }
655
- if (Array.isArray(value) && value.length === 0) {
656
- return true;
657
- }
658
- return value.length >= min;
659
- }
660
- );
661
- }
662
- }
663
- if ("min" in schema && min) {
683
+ if (min) {
664
684
  return schema.min(min, {
665
685
  ...translatedErrors.min,
666
686
  values: {
@@ -778,19 +798,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
778
798
  }, {});
779
799
  return componentsByKey;
780
800
  };
781
- 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);
782
900
  const { toggleNotification } = useNotification();
783
901
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
902
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
784
903
  const {
785
- currentData: data,
786
- isLoading: isLoadingDocument,
787
- isFetching: isFetchingDocument,
788
- error
789
- } = useGetDocumentQuery(args, {
790
- ...opts,
791
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
792
- });
793
- 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;
794
910
  React.useEffect(() => {
795
911
  if (error) {
796
912
  toggleNotification({
@@ -798,39 +914,255 @@ const useDocument = (args, opts) => {
798
914
  message: formatAPIError(error)
799
915
  });
800
916
  }
801
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
802
- const validationSchema = React.useMemo(() => {
803
- if (!schema) {
804
- return null;
805
- }
806
- return createYupSchema(schema.attributes, components);
807
- }, [schema, components]);
808
- const validate = React.useCallback(
809
- (document) => {
810
- if (!validationSchema) {
811
- throw new Error(
812
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
813
- );
814
- }
815
- try {
816
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
817
- return null;
818
- } catch (error2) {
819
- if (error2 instanceof ValidationError) {
820
- return getYupValidationErrors(error2);
821
- }
822
- throw error2;
823
- }
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
824
925
  },
825
- [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]
826
942
  );
827
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
828
943
  return {
829
- components,
830
- document: data?.data,
831
- meta: data?.meta,
944
+ error,
945
+ isLoading,
946
+ edit,
947
+ list: listLayout
948
+ };
949
+ };
950
+ const useDocLayout = () => {
951
+ const { model } = useDoc();
952
+ return useDocumentLayout(model);
953
+ };
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,
832
1162
  isLoading,
1163
+ hasError,
833
1164
  schema,
1165
+ schemas,
834
1166
  validate
835
1167
  };
836
1168
  };
@@ -844,22 +1176,60 @@ const useDoc = () => {
844
1176
  if (!slug) {
845
1177
  throw new Error("Could not find model in url params");
846
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;
847
1186
  return {
848
1187
  collectionType,
849
1188
  model: slug,
850
- id: origin || id === "create" ? void 0 : id,
851
- ...useDocument(
852
- { documentId: origin || id, model: slug, collectionType, params },
853
- {
854
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
855
- }
856
- )
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
857
1230
  };
858
1231
  };
859
1232
  const prefixPluginTranslations = (trad, pluginId) => {
860
- if (!pluginId) {
861
- throw new TypeError("pluginId can't be empty");
862
- }
863
1233
  return Object.keys(trad).reduce((acc, current) => {
864
1234
  acc[`${pluginId}.${current}`] = trad[current];
865
1235
  return acc;
@@ -875,6 +1245,8 @@ const useDocumentActions = () => {
875
1245
  const { formatMessage } = useIntl();
876
1246
  const { trackUsage } = useTracking();
877
1247
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1248
+ const navigate = useNavigate();
1249
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
878
1250
  const [deleteDocument] = useDeleteDocumentMutation();
879
1251
  const _delete = React.useCallback(
880
1252
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1189,6 +1561,7 @@ const useDocumentActions = () => {
1189
1561
  defaultMessage: "Saved document"
1190
1562
  })
1191
1563
  });
1564
+ setCurrentStep("contentManager.success");
1192
1565
  return res.data;
1193
1566
  } catch (err) {
1194
1567
  toggleNotification({
@@ -1210,7 +1583,6 @@ const useDocumentActions = () => {
1210
1583
  sourceId
1211
1584
  });
1212
1585
  if ("error" in res) {
1213
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1214
1586
  return { error: res.error };
1215
1587
  }
1216
1588
  toggleNotification({
@@ -1229,7 +1601,7 @@ const useDocumentActions = () => {
1229
1601
  throw err;
1230
1602
  }
1231
1603
  },
1232
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1604
+ [autoCloneDocument, formatMessage, toggleNotification]
1233
1605
  );
1234
1606
  const [cloneDocument] = useCloneDocumentMutation();
1235
1607
  const clone = React.useCallback(
@@ -1255,6 +1627,7 @@ const useDocumentActions = () => {
1255
1627
  defaultMessage: "Cloned document"
1256
1628
  })
1257
1629
  });
1630
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1258
1631
  return res.data;
1259
1632
  } catch (err) {
1260
1633
  toggleNotification({
@@ -1265,7 +1638,7 @@ const useDocumentActions = () => {
1265
1638
  throw err;
1266
1639
  }
1267
1640
  },
1268
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1641
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1269
1642
  );
1270
1643
  const [getDoc] = useLazyGetDocumentQuery();
1271
1644
  const getDocument = React.useCallback(
@@ -1290,10 +1663,10 @@ const useDocumentActions = () => {
1290
1663
  update
1291
1664
  };
1292
1665
  };
1293
- const ProtectedHistoryPage = lazy(
1294
- () => import("./History-DalgFQ3D.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1666
+ const ProtectedHistoryPage = React.lazy(
1667
+ () => import("./History-CAERKpYl.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1295
1668
  );
1296
- const routes$1 = [
1669
+ const routes$2 = [
1297
1670
  {
1298
1671
  path: ":collectionType/:slug/:id/history",
1299
1672
  Component: ProtectedHistoryPage
@@ -1303,32 +1676,45 @@ const routes$1 = [
1303
1676
  Component: ProtectedHistoryPage
1304
1677
  }
1305
1678
  ];
1679
+ const ProtectedPreviewPage = React.lazy(
1680
+ () => import("./Preview-C2WFq4S8.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
+ ];
1306
1692
  const ProtectedEditViewPage = lazy(
1307
- () => import("./EditViewPage-DhmAg0NK.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1693
+ () => import("./EditViewPage-B_k7z288.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1308
1694
  );
1309
1695
  const ProtectedListViewPage = lazy(
1310
- () => import("./ListViewPage-BkAwIW9s.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1696
+ () => import("./ListViewPage-Q4g6kHDl.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1311
1697
  );
1312
1698
  const ProtectedListConfiguration = lazy(
1313
- () => import("./ListConfigurationPage-DWy-vRzs.mjs").then((mod) => ({
1699
+ () => import("./ListConfigurationPage-CVVT45M8.mjs").then((mod) => ({
1314
1700
  default: mod.ProtectedListConfiguration
1315
1701
  }))
1316
1702
  );
1317
1703
  const ProtectedEditConfigurationPage = lazy(
1318
- () => import("./EditConfigurationPage-MItFGzT9.mjs").then((mod) => ({
1704
+ () => import("./EditConfigurationPage-DznPxn9p.mjs").then((mod) => ({
1319
1705
  default: mod.ProtectedEditConfigurationPage
1320
1706
  }))
1321
1707
  );
1322
1708
  const ProtectedComponentConfigurationPage = lazy(
1323
- () => import("./ComponentConfigurationPage-C7ImeKGM.mjs").then((mod) => ({
1709
+ () => import("./ComponentConfigurationPage-DT41asyM.mjs").then((mod) => ({
1324
1710
  default: mod.ProtectedComponentConfigurationPage
1325
1711
  }))
1326
1712
  );
1327
1713
  const NoPermissions = lazy(
1328
- () => import("./NoPermissionsPage-Bt_HWGat.mjs").then((mod) => ({ default: mod.NoPermissions }))
1714
+ () => import("./NoPermissionsPage-CyM16RKL.mjs").then((mod) => ({ default: mod.NoPermissions }))
1329
1715
  );
1330
1716
  const NoContentType = lazy(
1331
- () => import("./NoContentTypePage-B9BCNNdL.mjs").then((mod) => ({ default: mod.NoContentType }))
1717
+ () => import("./NoContentTypePage-BY4YRGs0.mjs").then((mod) => ({ default: mod.NoContentType }))
1332
1718
  );
1333
1719
  const CollectionTypePages = () => {
1334
1720
  const { collectionType } = useParams();
@@ -1374,6 +1760,7 @@ const routes = [
1374
1760
  path: "no-content-types",
1375
1761
  Component: NoContentType
1376
1762
  },
1763
+ ...routes$2,
1377
1764
  ...routes$1
1378
1765
  ];
1379
1766
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1442,12 +1829,14 @@ const DocumentActionButton = (action) => {
1442
1829
  /* @__PURE__ */ jsx(
1443
1830
  Button,
1444
1831
  {
1445
- flex: 1,
1832
+ flex: "auto",
1446
1833
  startIcon: action.icon,
1447
1834
  disabled: action.disabled,
1448
1835
  onClick: handleClick(action),
1449
1836
  justifyContent: "center",
1450
1837
  variant: action.variant || "default",
1838
+ paddingTop: "7px",
1839
+ paddingBottom: "7px",
1451
1840
  children: action.label
1452
1841
  }
1453
1842
  ),
@@ -1455,7 +1844,7 @@ const DocumentActionButton = (action) => {
1455
1844
  DocumentActionConfirmDialog,
1456
1845
  {
1457
1846
  ...action.dialog,
1458
- variant: action.variant,
1847
+ variant: action.dialog?.variant ?? action.variant,
1459
1848
  isOpen: dialogId === action.id,
1460
1849
  onClose: handleClose
1461
1850
  }
@@ -1512,9 +1901,9 @@ const DocumentActionsMenu = ({
1512
1901
  disabled: isDisabled,
1513
1902
  size: "S",
1514
1903
  endIcon: null,
1515
- paddingTop: "7px",
1516
- paddingLeft: "9px",
1517
- paddingRight: "9px",
1904
+ paddingTop: "4px",
1905
+ paddingLeft: "7px",
1906
+ paddingRight: "7px",
1518
1907
  variant,
1519
1908
  children: [
1520
1909
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1525,7 +1914,7 @@ const DocumentActionsMenu = ({
1525
1914
  ]
1526
1915
  }
1527
1916
  ),
1528
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1917
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1529
1918
  actions2.map((action) => {
1530
1919
  return /* @__PURE__ */ jsx(
1531
1920
  Menu.Item,
@@ -1534,10 +1923,25 @@ const DocumentActionsMenu = ({
1534
1923
  onSelect: handleClick(action),
1535
1924
  display: "block",
1536
1925
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1537
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1538
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1539
- action.label
1540
- ] }),
1926
+ /* @__PURE__ */ jsxs(
1927
+ Flex,
1928
+ {
1929
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1930
+ gap: 2,
1931
+ tag: "span",
1932
+ children: [
1933
+ /* @__PURE__ */ jsx(
1934
+ Flex,
1935
+ {
1936
+ tag: "span",
1937
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1938
+ children: action.icon
1939
+ }
1940
+ ),
1941
+ action.label
1942
+ ]
1943
+ }
1944
+ ),
1541
1945
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1542
1946
  Flex,
1543
1947
  {
@@ -1634,11 +2038,11 @@ const DocumentActionConfirmDialog = ({
1634
2038
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1635
2039
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1636
2040
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1637
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
2041
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1638
2042
  id: "app.components.Button.cancel",
1639
2043
  defaultMessage: "Cancel"
1640
2044
  }) }) }),
1641
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
2045
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1642
2046
  id: "app.components.Button.confirm",
1643
2047
  defaultMessage: "Confirm"
1644
2048
  }) })
@@ -1661,10 +2065,22 @@ const DocumentActionModal = ({
1661
2065
  };
1662
2066
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1663
2067
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1664
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1665
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
2068
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
2069
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1666
2070
  ] }) });
1667
2071
  };
2072
+ const transformData = (data) => {
2073
+ if (Array.isArray(data)) {
2074
+ return data.map(transformData);
2075
+ }
2076
+ if (typeof data === "object" && data !== null) {
2077
+ if ("apiData" in data) {
2078
+ return data.apiData;
2079
+ }
2080
+ return mapValues(transformData)(data);
2081
+ }
2082
+ return data;
2083
+ };
1668
2084
  const PublishAction$1 = ({
1669
2085
  activeTab,
1670
2086
  documentId,
@@ -1677,13 +2093,17 @@ const PublishAction$1 = ({
1677
2093
  const navigate = useNavigate();
1678
2094
  const { toggleNotification } = useNotification();
1679
2095
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
2096
+ const isListView = useMatch(LIST_PATH) !== null;
1680
2097
  const isCloning = useMatch(CLONE_PATH) !== null;
1681
2098
  const { formatMessage } = useIntl();
1682
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1683
- "PublishAction",
1684
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1685
- );
2099
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1686
2100
  const { publish } = useDocumentActions();
2101
+ const [
2102
+ countDraftRelations,
2103
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2104
+ ] = useLazyGetDraftRelationCountQuery();
2105
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
2106
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1687
2107
  const [{ query, rawQuery }] = useQueryParams();
1688
2108
  const params = React.useMemo(() => buildValidParams(query), [query]);
1689
2109
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1692,10 +2112,105 @@ const PublishAction$1 = ({
1692
2112
  const validate = useForm("PublishAction", (state) => state.validate);
1693
2113
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1694
2114
  const formValues = useForm("PublishAction", ({ values }) => values);
1695
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1696
- if (!schema?.options?.draftAndPublish) {
1697
- return null;
1698
- }
2115
+ React.useEffect(() => {
2116
+ if (isErrorDraftRelations) {
2117
+ toggleNotification({
2118
+ type: "danger",
2119
+ message: formatMessage({
2120
+ id: getTranslation("error.records.fetch-draft-relatons"),
2121
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2122
+ })
2123
+ });
2124
+ }
2125
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2126
+ React.useEffect(() => {
2127
+ const localDraftRelations = /* @__PURE__ */ new Set();
2128
+ const extractDraftRelations = (data) => {
2129
+ const relations = data.connect || [];
2130
+ relations.forEach((relation) => {
2131
+ if (relation.status === "draft") {
2132
+ localDraftRelations.add(relation.id);
2133
+ }
2134
+ });
2135
+ };
2136
+ const traverseAndExtract = (data) => {
2137
+ Object.entries(data).forEach(([key, value]) => {
2138
+ if (key === "connect" && Array.isArray(value)) {
2139
+ extractDraftRelations({ connect: value });
2140
+ } else if (typeof value === "object" && value !== null) {
2141
+ traverseAndExtract(value);
2142
+ }
2143
+ });
2144
+ };
2145
+ if (!documentId || modified) {
2146
+ traverseAndExtract(formValues);
2147
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2148
+ }
2149
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2150
+ React.useEffect(() => {
2151
+ if (!document || !document.documentId || isListView) {
2152
+ return;
2153
+ }
2154
+ const fetchDraftRelationsCount = async () => {
2155
+ const { data, error } = await countDraftRelations({
2156
+ collectionType,
2157
+ model,
2158
+ documentId,
2159
+ params
2160
+ });
2161
+ if (error) {
2162
+ throw error;
2163
+ }
2164
+ if (data) {
2165
+ setServerCountOfDraftRelations(data.data);
2166
+ }
2167
+ };
2168
+ fetchDraftRelationsCount();
2169
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
2170
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
2171
+ if (!schema?.options?.draftAndPublish) {
2172
+ return null;
2173
+ }
2174
+ const performPublish = async () => {
2175
+ setSubmitting(true);
2176
+ try {
2177
+ const { errors } = await validate(true, {
2178
+ status: "published"
2179
+ });
2180
+ if (errors) {
2181
+ toggleNotification({
2182
+ type: "danger",
2183
+ message: formatMessage({
2184
+ id: "content-manager.validation.error",
2185
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2186
+ })
2187
+ });
2188
+ return;
2189
+ }
2190
+ const res = await publish(
2191
+ {
2192
+ collectionType,
2193
+ model,
2194
+ documentId,
2195
+ params
2196
+ },
2197
+ transformData(formValues)
2198
+ );
2199
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2200
+ navigate({
2201
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2202
+ search: rawQuery
2203
+ });
2204
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2205
+ setErrors(formatValidationErrors(res.error));
2206
+ }
2207
+ } finally {
2208
+ setSubmitting(false);
2209
+ }
2210
+ };
2211
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2212
+ const enableDraftRelationsCount = false;
2213
+ const hasDraftRelations = enableDraftRelationsCount;
1699
2214
  return {
1700
2215
  /**
1701
2216
  * Disabled when:
@@ -1705,49 +2220,36 @@ const PublishAction$1 = ({
1705
2220
  * - the document is already published & not modified
1706
2221
  * - the document is being created & not modified
1707
2222
  * - the user doesn't have the permission to publish
1708
- * - the user doesn't have the permission to create a new document
1709
- * - the user doesn't have the permission to update the document
1710
2223
  */
1711
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2224
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1712
2225
  label: formatMessage({
1713
2226
  id: "app.utils.publish",
1714
2227
  defaultMessage: "Publish"
1715
2228
  }),
1716
2229
  onClick: async () => {
1717
- setSubmitting(true);
1718
- try {
1719
- const { errors } = await validate();
1720
- if (errors) {
1721
- toggleNotification({
1722
- type: "danger",
1723
- message: formatMessage({
1724
- id: "content-manager.validation.error",
1725
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1726
- })
1727
- });
1728
- return;
1729
- }
1730
- const res = await publish(
1731
- {
1732
- collectionType,
1733
- model,
1734
- documentId,
1735
- params
1736
- },
1737
- formValues
1738
- );
1739
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1740
- navigate({
1741
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1742
- search: rawQuery
1743
- });
1744
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1745
- setErrors(formatValidationErrors(res.error));
2230
+ await performPublish();
2231
+ },
2232
+ dialog: hasDraftRelations ? {
2233
+ type: "dialog",
2234
+ variant: "danger",
2235
+ footer: null,
2236
+ title: formatMessage({
2237
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2238
+ defaultMessage: "Confirmation"
2239
+ }),
2240
+ content: formatMessage(
2241
+ {
2242
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2243
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2244
+ },
2245
+ {
2246
+ count: totalDraftRelations
1746
2247
  }
1747
- } finally {
1748
- setSubmitting(false);
2248
+ ),
2249
+ onConfirm: async () => {
2250
+ await performPublish();
1749
2251
  }
1750
- }
2252
+ } : void 0
1751
2253
  };
1752
2254
  };
1753
2255
  PublishAction$1.type = "publish";
@@ -1763,10 +2265,6 @@ const UpdateAction = ({
1763
2265
  const cloneMatch = useMatch(CLONE_PATH);
1764
2266
  const isCloning = cloneMatch !== null;
1765
2267
  const { formatMessage } = useIntl();
1766
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1767
- canCreate: canCreate2,
1768
- canUpdate: canUpdate2
1769
- }));
1770
2268
  const { create, update, clone } = useDocumentActions();
1771
2269
  const [{ query, rawQuery }] = useQueryParams();
1772
2270
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1783,10 +2281,8 @@ const UpdateAction = ({
1783
2281
  * - the form is submitting
1784
2282
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1785
2283
  * - the active tab is the published tab
1786
- * - the user doesn't have the permission to create a new document
1787
- * - the user doesn't have the permission to update the document
1788
2284
  */
1789
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2285
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1790
2286
  label: formatMessage({
1791
2287
  id: "content-manager.containers.Edit.save",
1792
2288
  defaultMessage: "Save"
@@ -1794,7 +2290,9 @@ const UpdateAction = ({
1794
2290
  onClick: async () => {
1795
2291
  setSubmitting(true);
1796
2292
  try {
1797
- const { errors } = await validate();
2293
+ const { errors } = await validate(true, {
2294
+ status: "draft"
2295
+ });
1798
2296
  if (errors) {
1799
2297
  toggleNotification({
1800
2298
  type: "danger",
@@ -1812,13 +2310,16 @@ const UpdateAction = ({
1812
2310
  documentId: cloneMatch.params.origin,
1813
2311
  params
1814
2312
  },
1815
- document
2313
+ transformData(document)
1816
2314
  );
1817
2315
  if ("data" in res) {
1818
- navigate({
1819
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1820
- search: rawQuery
1821
- });
2316
+ navigate(
2317
+ {
2318
+ pathname: `../${res.data.documentId}`,
2319
+ search: rawQuery
2320
+ },
2321
+ { relative: "path" }
2322
+ );
1822
2323
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1823
2324
  setErrors(formatValidationErrors(res.error));
1824
2325
  }
@@ -1830,7 +2331,7 @@ const UpdateAction = ({
1830
2331
  documentId,
1831
2332
  params
1832
2333
  },
1833
- document
2334
+ transformData(document)
1834
2335
  );
1835
2336
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1836
2337
  setErrors(formatValidationErrors(res.error));
@@ -1843,15 +2344,15 @@ const UpdateAction = ({
1843
2344
  model,
1844
2345
  params
1845
2346
  },
1846
- document
2347
+ transformData(document)
1847
2348
  );
1848
2349
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1849
2350
  navigate(
1850
2351
  {
1851
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2352
+ pathname: `../${res.data.documentId}`,
1852
2353
  search: rawQuery
1853
2354
  },
1854
- { replace: true }
2355
+ { replace: true, relative: "path" }
1855
2356
  );
1856
2357
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1857
2358
  setErrors(formatValidationErrors(res.error));
@@ -1896,7 +2397,7 @@ const UnpublishAction$1 = ({
1896
2397
  id: "app.utils.unpublish",
1897
2398
  defaultMessage: "Unpublish"
1898
2399
  }),
1899
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2400
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1900
2401
  onClick: async () => {
1901
2402
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1902
2403
  if (!documentId) {
@@ -2008,7 +2509,7 @@ const DiscardAction = ({
2008
2509
  id: "content-manager.actions.discard.label",
2009
2510
  defaultMessage: "Discard changes"
2010
2511
  }),
2011
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2512
+ icon: /* @__PURE__ */ jsx(Cross, {}),
2012
2513
  position: ["panel", "table-row"],
2013
2514
  variant: "danger",
2014
2515
  dialog: {
@@ -2036,11 +2537,6 @@ const DiscardAction = ({
2036
2537
  };
2037
2538
  };
2038
2539
  DiscardAction.type = "discard";
2039
- const StyledCrossCircle = styled(CrossCircle)`
2040
- path {
2041
- fill: currentColor;
2042
- }
2043
- `;
2044
2540
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2045
2541
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2046
2542
  const RelativeTime = React.forwardRef(
@@ -2088,8 +2584,12 @@ const getDisplayName = ({
2088
2584
  };
2089
2585
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2090
2586
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2091
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2092
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2587
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2588
+ const { formatMessage } = useIntl();
2589
+ return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2590
+ id: `content-manager.containers.List.${status}`,
2591
+ defaultMessage: capitalise(status)
2592
+ }) }) });
2093
2593
  };
2094
2594
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2095
2595
  const { formatMessage } = useIntl();
@@ -2098,23 +2598,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2098
2598
  id: "content-manager.containers.edit.title.new",
2099
2599
  defaultMessage: "Create an entry"
2100
2600
  }) : documentTitle;
2101
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2601
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2102
2602
  /* @__PURE__ */ jsx(BackButton, {}),
2103
- /* @__PURE__ */ jsxs(
2104
- Flex,
2105
- {
2106
- width: "100%",
2107
- justifyContent: "space-between",
2108
- paddingTop: 1,
2109
- gap: "80px",
2110
- alignItems: "flex-start",
2111
- children: [
2112
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2113
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2114
- ]
2115
- }
2116
- ),
2117
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2603
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2604
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2605
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2606
+ ] }),
2607
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2118
2608
  ] });
2119
2609
  };
2120
2610
  const HeaderToolbar = () => {
@@ -2197,12 +2687,12 @@ const Information = ({ activeTab }) => {
2197
2687
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2198
2688
  label: formatMessage({
2199
2689
  id: "content-manager.containers.edit.information.last-published.label",
2200
- defaultMessage: "Last published"
2690
+ defaultMessage: "Published"
2201
2691
  }),
2202
2692
  value: formatMessage(
2203
2693
  {
2204
2694
  id: "content-manager.containers.edit.information.last-published.value",
2205
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2695
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2206
2696
  },
2207
2697
  {
2208
2698
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2215,12 +2705,12 @@ const Information = ({ activeTab }) => {
2215
2705
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2216
2706
  label: formatMessage({
2217
2707
  id: "content-manager.containers.edit.information.last-draft.label",
2218
- defaultMessage: "Last draft"
2708
+ defaultMessage: "Updated"
2219
2709
  }),
2220
2710
  value: formatMessage(
2221
2711
  {
2222
2712
  id: "content-manager.containers.edit.information.last-draft.value",
2223
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2713
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2224
2714
  },
2225
2715
  {
2226
2716
  time: /* @__PURE__ */ jsx(
@@ -2238,12 +2728,12 @@ const Information = ({ activeTab }) => {
2238
2728
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2239
2729
  label: formatMessage({
2240
2730
  id: "content-manager.containers.edit.information.document.label",
2241
- defaultMessage: "Document"
2731
+ defaultMessage: "Created"
2242
2732
  }),
2243
2733
  value: formatMessage(
2244
2734
  {
2245
2735
  id: "content-manager.containers.edit.information.document.value",
2246
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2736
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2247
2737
  },
2248
2738
  {
2249
2739
  time: /* @__PURE__ */ jsx(
@@ -2281,25 +2771,77 @@ const Information = ({ activeTab }) => {
2281
2771
  );
2282
2772
  };
2283
2773
  const HeaderActions = ({ actions: actions2 }) => {
2284
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2285
- if ("options" in action) {
2774
+ const [dialogId, setDialogId] = React.useState(null);
2775
+ const handleClick = (action) => async (e) => {
2776
+ if (!("options" in action)) {
2777
+ const { onClick = () => false, dialog, id } = action;
2778
+ const muteDialog = await onClick(e);
2779
+ if (dialog && !muteDialog) {
2780
+ e.preventDefault();
2781
+ setDialogId(id);
2782
+ }
2783
+ }
2784
+ };
2785
+ const handleClose = () => {
2786
+ setDialogId(null);
2787
+ };
2788
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2789
+ if (action.options) {
2286
2790
  return /* @__PURE__ */ jsx(
2287
2791
  SingleSelect,
2288
2792
  {
2289
2793
  size: "S",
2290
- disabled: action.disabled,
2291
- "aria-label": action.label,
2292
2794
  onChange: action.onSelect,
2293
- value: action.value,
2795
+ "aria-label": action.label,
2796
+ ...action,
2294
2797
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2295
2798
  },
2296
2799
  action.id
2297
2800
  );
2298
2801
  } else {
2299
- return null;
2802
+ if (action.type === "icon") {
2803
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2804
+ /* @__PURE__ */ jsx(
2805
+ IconButton,
2806
+ {
2807
+ disabled: action.disabled,
2808
+ label: action.label,
2809
+ size: "S",
2810
+ onClick: handleClick(action),
2811
+ children: action.icon
2812
+ }
2813
+ ),
2814
+ action.dialog ? /* @__PURE__ */ jsx(
2815
+ HeaderActionDialog,
2816
+ {
2817
+ ...action.dialog,
2818
+ isOpen: dialogId === action.id,
2819
+ onClose: handleClose
2820
+ }
2821
+ ) : null
2822
+ ] }, action.id);
2823
+ }
2300
2824
  }
2301
2825
  }) });
2302
2826
  };
2827
+ const HeaderActionDialog = ({
2828
+ onClose,
2829
+ onCancel,
2830
+ title,
2831
+ content: Content,
2832
+ isOpen
2833
+ }) => {
2834
+ const handleClose = async () => {
2835
+ if (onCancel) {
2836
+ await onCancel();
2837
+ }
2838
+ onClose();
2839
+ };
2840
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2841
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2842
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2843
+ ] }) });
2844
+ };
2303
2845
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2304
2846
  const navigate = useNavigate();
2305
2847
  const { formatMessage } = useIntl();
@@ -2340,12 +2882,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2340
2882
  const { delete: deleteAction } = useDocumentActions();
2341
2883
  const { toggleNotification } = useNotification();
2342
2884
  const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2885
+ const isLocalized = document?.locale != null;
2343
2886
  return {
2344
2887
  disabled: !canDelete || !document,
2345
- label: formatMessage({
2346
- id: "content-manager.actions.delete.label",
2347
- defaultMessage: "Delete document"
2348
- }),
2888
+ label: formatMessage(
2889
+ {
2890
+ id: "content-manager.actions.delete.label",
2891
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2892
+ },
2893
+ { isLocalized }
2894
+ ),
2349
2895
  icon: /* @__PURE__ */ jsx(Trash, {}),
2350
2896
  dialog: {
2351
2897
  type: "dialog",
@@ -2385,419 +2931,117 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2385
2931
  params: {
2386
2932
  locale: "*"
2387
2933
  }
2388
- });
2389
- if (!("error" in res)) {
2390
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2391
- }
2392
- } finally {
2393
- if (!listViewPathMatch) {
2394
- setSubmitting(false);
2395
- }
2396
- }
2397
- }
2398
- },
2399
- variant: "danger",
2400
- position: ["header", "table-row"]
2401
- };
2402
- };
2403
- DeleteAction$1.type = "delete";
2404
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2405
- const Panels = () => {
2406
- const isCloning = useMatch(CLONE_PATH) !== null;
2407
- const [
2408
- {
2409
- query: { status }
2410
- }
2411
- ] = useQueryParams({
2412
- status: "draft"
2413
- });
2414
- const { model, id, document, meta, collectionType } = useDoc();
2415
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2416
- const props = {
2417
- activeTab: status,
2418
- model,
2419
- documentId: id,
2420
- document: isCloning ? void 0 : document,
2421
- meta: isCloning ? void 0 : meta,
2422
- collectionType
2423
- };
2424
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2425
- DescriptionComponentRenderer,
2426
- {
2427
- props,
2428
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2429
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2430
- }
2431
- ) });
2432
- };
2433
- const ActionsPanel = () => {
2434
- const { formatMessage } = useIntl();
2435
- return {
2436
- title: formatMessage({
2437
- id: "content-manager.containers.edit.panels.default.title",
2438
- defaultMessage: "Document"
2439
- }),
2440
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2441
- };
2442
- };
2443
- ActionsPanel.type = "actions";
2444
- const ActionsPanelContent = () => {
2445
- const isCloning = useMatch(CLONE_PATH) !== null;
2446
- const [
2447
- {
2448
- query: { status = "draft" }
2449
- }
2450
- ] = useQueryParams();
2451
- const { model, id, document, meta, collectionType } = useDoc();
2452
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2453
- const props = {
2454
- activeTab: status,
2455
- model,
2456
- documentId: id,
2457
- document: isCloning ? void 0 : document,
2458
- meta: isCloning ? void 0 : meta,
2459
- collectionType
2460
- };
2461
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2462
- /* @__PURE__ */ jsx(
2463
- DescriptionComponentRenderer,
2464
- {
2465
- props,
2466
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2467
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2468
- }
2469
- ),
2470
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2471
- ] });
2472
- };
2473
- const Panel = React.forwardRef(({ children, title }, ref) => {
2474
- return /* @__PURE__ */ jsxs(
2475
- Flex,
2476
- {
2477
- ref,
2478
- tag: "aside",
2479
- "aria-labelledby": "additional-information",
2480
- background: "neutral0",
2481
- borderColor: "neutral150",
2482
- hasRadius: true,
2483
- paddingBottom: 4,
2484
- paddingLeft: 4,
2485
- paddingRight: 4,
2486
- paddingTop: 4,
2487
- shadow: "tableShadow",
2488
- gap: 3,
2489
- direction: "column",
2490
- justifyContent: "stretch",
2491
- alignItems: "flex-start",
2492
- children: [
2493
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2494
- children
2495
- ]
2496
- }
2497
- );
2498
- });
2499
- const HOOKS = {
2500
- /**
2501
- * Hook that allows to mutate the displayed headers of the list view table
2502
- * @constant
2503
- * @type {string}
2504
- */
2505
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2506
- /**
2507
- * Hook that allows to mutate the CM's collection types links pre-set filters
2508
- * @constant
2509
- * @type {string}
2510
- */
2511
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2512
- /**
2513
- * Hook that allows to mutate the CM's edit view layout
2514
- * @constant
2515
- * @type {string}
2516
- */
2517
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2518
- /**
2519
- * Hook that allows to mutate the CM's single types links pre-set filters
2520
- * @constant
2521
- * @type {string}
2522
- */
2523
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2524
- };
2525
- const contentTypesApi = contentManagerApi.injectEndpoints({
2526
- endpoints: (builder) => ({
2527
- getContentTypeConfiguration: builder.query({
2528
- query: (uid) => ({
2529
- url: `/content-manager/content-types/${uid}/configuration`,
2530
- method: "GET"
2531
- }),
2532
- transformResponse: (response) => response.data,
2533
- providesTags: (_result, _error, uid) => [
2534
- { type: "ContentTypesConfiguration", id: uid },
2535
- { type: "ContentTypeSettings", id: "LIST" }
2536
- ]
2537
- }),
2538
- getAllContentTypeSettings: builder.query({
2539
- query: () => "/content-manager/content-types-settings",
2540
- transformResponse: (response) => response.data,
2541
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2542
- }),
2543
- updateContentTypeConfiguration: builder.mutation({
2544
- query: ({ uid, ...body }) => ({
2545
- url: `/content-manager/content-types/${uid}/configuration`,
2546
- method: "PUT",
2547
- data: body
2548
- }),
2549
- transformResponse: (response) => response.data,
2550
- invalidatesTags: (_result, _error, { uid }) => [
2551
- { type: "ContentTypesConfiguration", id: uid },
2552
- { type: "ContentTypeSettings", id: "LIST" },
2553
- // Is this necessary?
2554
- { type: "InitialData" }
2555
- ]
2556
- })
2557
- })
2558
- });
2559
- const {
2560
- useGetContentTypeConfigurationQuery,
2561
- useGetAllContentTypeSettingsQuery,
2562
- useUpdateContentTypeConfigurationMutation
2563
- } = contentTypesApi;
2564
- const checkIfAttributeIsDisplayable = (attribute) => {
2565
- const { type } = attribute;
2566
- if (type === "relation") {
2567
- return !attribute.relation.toLowerCase().includes("morph");
2568
- }
2569
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2570
- };
2571
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2572
- if (!mainFieldName) {
2573
- return void 0;
2574
- }
2575
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2576
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2577
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2578
- );
2579
- return {
2580
- name: mainFieldName,
2581
- type: mainFieldType ?? "string"
2582
- };
2583
- };
2584
- const DEFAULT_SETTINGS = {
2585
- bulkable: false,
2586
- filterable: false,
2587
- searchable: false,
2588
- pagination: false,
2589
- defaultSortBy: "",
2590
- defaultSortOrder: "asc",
2591
- mainField: "id",
2592
- pageSize: 10
2593
- };
2594
- const useDocumentLayout = (model) => {
2595
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2596
- const [{ query }] = useQueryParams();
2597
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2598
- const { toggleNotification } = useNotification();
2599
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2600
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2601
- const {
2602
- data,
2603
- isLoading: isLoadingConfigs,
2604
- error,
2605
- isFetching: isFetchingConfigs
2606
- } = useGetContentTypeConfigurationQuery(model);
2607
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2608
- React.useEffect(() => {
2609
- if (error) {
2610
- toggleNotification({
2611
- type: "danger",
2612
- message: formatAPIError(error)
2613
- });
2614
- }
2615
- }, [error, formatAPIError, toggleNotification]);
2616
- const editLayout = React.useMemo(
2617
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2618
- layout: [],
2619
- components: {},
2620
- metadatas: {},
2621
- options: {},
2622
- settings: DEFAULT_SETTINGS
2623
- },
2624
- [data, isLoading, schemas, schema, components]
2625
- );
2626
- const listLayout = React.useMemo(() => {
2627
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2628
- layout: [],
2629
- metadatas: {},
2630
- options: {},
2631
- settings: DEFAULT_SETTINGS
2632
- };
2633
- }, [data, isLoading, schemas, schema, components]);
2634
- const { layout: edit } = React.useMemo(
2635
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2636
- layout: editLayout,
2637
- query
2638
- }),
2639
- [editLayout, query, runHookWaterfall]
2640
- );
2641
- return {
2642
- error,
2643
- isLoading,
2644
- edit,
2645
- list: listLayout
2646
- };
2647
- };
2648
- const useDocLayout = () => {
2649
- const { model } = useDoc();
2650
- return useDocumentLayout(model);
2651
- };
2652
- const formatEditLayout = (data, {
2653
- schemas,
2654
- schema,
2655
- components
2656
- }) => {
2657
- let currentPanelIndex = 0;
2658
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2659
- data.contentType.layouts.edit,
2660
- schema?.attributes,
2661
- data.contentType.metadatas,
2662
- { configurations: data.components, schemas: components },
2663
- schemas
2664
- ).reduce((panels, row) => {
2665
- if (row.some((field) => field.type === "dynamiczone")) {
2666
- panels.push([row]);
2667
- currentPanelIndex += 2;
2668
- } else {
2669
- if (!panels[currentPanelIndex]) {
2670
- panels.push([]);
2671
- }
2672
- panels[currentPanelIndex].push(row);
2673
- }
2674
- return panels;
2675
- }, []);
2676
- const componentEditAttributes = Object.entries(data.components).reduce(
2677
- (acc, [uid, configuration]) => {
2678
- acc[uid] = {
2679
- layout: convertEditLayoutToFieldLayouts(
2680
- configuration.layouts.edit,
2681
- components[uid].attributes,
2682
- configuration.metadatas
2683
- ),
2684
- settings: {
2685
- ...configuration.settings,
2686
- icon: components[uid].info.icon,
2687
- displayName: components[uid].info.displayName
2688
- }
2689
- };
2690
- return acc;
2691
- },
2692
- {}
2693
- );
2694
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2695
- (acc, [attribute, metadata]) => {
2696
- return {
2697
- ...acc,
2698
- [attribute]: metadata.edit
2699
- };
2700
- },
2701
- {}
2702
- );
2703
- return {
2704
- layout: panelledEditAttributes,
2705
- components: componentEditAttributes,
2706
- metadatas: editMetadatas,
2707
- settings: {
2708
- ...data.contentType.settings,
2709
- displayName: schema?.info.displayName
2934
+ });
2935
+ if (!("error" in res)) {
2936
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2937
+ }
2938
+ } finally {
2939
+ if (!listViewPathMatch) {
2940
+ setSubmitting(false);
2941
+ }
2942
+ }
2943
+ }
2710
2944
  },
2711
- options: {
2712
- ...schema?.options,
2713
- ...schema?.pluginOptions,
2714
- ...data.contentType.options
2715
- }
2945
+ variant: "danger",
2946
+ position: ["header", "table-row"]
2716
2947
  };
2717
2948
  };
2718
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2719
- return rows.map(
2720
- (row) => row.map((field) => {
2721
- const attribute = attributes[field.name];
2722
- if (!attribute) {
2723
- return null;
2724
- }
2725
- const { edit: metadata } = metadatas[field.name];
2726
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2727
- return {
2728
- attribute,
2729
- disabled: !metadata.editable,
2730
- hint: metadata.description,
2731
- label: metadata.label ?? "",
2732
- name: field.name,
2733
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2734
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2735
- schemas,
2736
- components: components?.schemas ?? {}
2737
- }),
2738
- placeholder: metadata.placeholder ?? "",
2739
- required: attribute.required ?? false,
2740
- size: field.size,
2741
- unique: "unique" in attribute ? attribute.unique : false,
2742
- visible: metadata.visible ?? true,
2743
- type: attribute.type
2744
- };
2745
- }).filter((field) => field !== null)
2746
- );
2949
+ DeleteAction$1.type = "delete";
2950
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2951
+ const Panels = () => {
2952
+ const isCloning = useMatch(CLONE_PATH) !== null;
2953
+ const [
2954
+ {
2955
+ query: { status }
2956
+ }
2957
+ ] = useQueryParams({
2958
+ status: "draft"
2959
+ });
2960
+ const { model, id, document, meta, collectionType } = useDoc();
2961
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
2962
+ const props = {
2963
+ activeTab: status,
2964
+ model,
2965
+ documentId: id,
2966
+ document: isCloning ? void 0 : document,
2967
+ meta: isCloning ? void 0 : meta,
2968
+ collectionType
2969
+ };
2970
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2971
+ DescriptionComponentRenderer,
2972
+ {
2973
+ props,
2974
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2975
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2976
+ }
2977
+ ) });
2747
2978
  };
2748
- const formatListLayout = (data, {
2749
- schemas,
2750
- schema,
2751
- components
2752
- }) => {
2753
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2754
- (acc, [attribute, metadata]) => {
2755
- return {
2756
- ...acc,
2757
- [attribute]: metadata.list
2758
- };
2759
- },
2760
- {}
2761
- );
2762
- const listAttributes = convertListLayoutToFieldLayouts(
2763
- data.contentType.layouts.list,
2764
- schema?.attributes,
2765
- listMetadatas,
2766
- { configurations: data.components, schemas: components },
2767
- schemas
2768
- );
2979
+ const ActionsPanel = () => {
2980
+ const { formatMessage } = useIntl();
2769
2981
  return {
2770
- layout: listAttributes,
2771
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2772
- metadatas: listMetadatas,
2773
- options: {
2774
- ...schema?.options,
2775
- ...schema?.pluginOptions,
2776
- ...data.contentType.options
2777
- }
2982
+ title: formatMessage({
2983
+ id: "content-manager.containers.edit.panels.default.title",
2984
+ defaultMessage: "Entry"
2985
+ }),
2986
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2778
2987
  };
2779
2988
  };
2780
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2781
- return columns.map((name) => {
2782
- const attribute = attributes[name];
2783
- if (!attribute) {
2784
- return null;
2989
+ ActionsPanel.type = "actions";
2990
+ const ActionsPanelContent = () => {
2991
+ const isCloning = useMatch(CLONE_PATH) !== null;
2992
+ const [
2993
+ {
2994
+ query: { status = "draft" }
2785
2995
  }
2786
- const metadata = metadatas[name];
2787
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2788
- return {
2789
- attribute,
2790
- label: metadata.label ?? "",
2791
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2792
- schemas,
2793
- components: components?.schemas ?? {}
2794
- }),
2795
- name,
2796
- searchable: metadata.searchable ?? true,
2797
- sortable: metadata.sortable ?? true
2798
- };
2799
- }).filter((field) => field !== null);
2996
+ ] = useQueryParams();
2997
+ const { model, id, document, meta, collectionType } = useDoc();
2998
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2999
+ const props = {
3000
+ activeTab: status,
3001
+ model,
3002
+ documentId: id,
3003
+ document: isCloning ? void 0 : document,
3004
+ meta: isCloning ? void 0 : meta,
3005
+ collectionType
3006
+ };
3007
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3008
+ /* @__PURE__ */ jsx(
3009
+ DescriptionComponentRenderer,
3010
+ {
3011
+ props,
3012
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3013
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3014
+ }
3015
+ ),
3016
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3017
+ ] });
2800
3018
  };
3019
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3020
+ return /* @__PURE__ */ jsxs(
3021
+ Flex,
3022
+ {
3023
+ ref,
3024
+ tag: "aside",
3025
+ "aria-labelledby": "additional-information",
3026
+ background: "neutral0",
3027
+ borderColor: "neutral150",
3028
+ hasRadius: true,
3029
+ paddingBottom: 4,
3030
+ paddingLeft: 4,
3031
+ paddingRight: 4,
3032
+ paddingTop: 4,
3033
+ shadow: "tableShadow",
3034
+ gap: 3,
3035
+ direction: "column",
3036
+ justifyContent: "stretch",
3037
+ alignItems: "flex-start",
3038
+ children: [
3039
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3040
+ children
3041
+ ]
3042
+ }
3043
+ );
3044
+ });
2801
3045
  const ConfirmBulkActionDialog = ({
2802
3046
  onToggleDialog,
2803
3047
  isOpen = false,
@@ -2805,7 +3049,7 @@ const ConfirmBulkActionDialog = ({
2805
3049
  endAction
2806
3050
  }) => {
2807
3051
  const { formatMessage } = useIntl();
2808
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
3052
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2809
3053
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2810
3054
  id: "app.components.ConfirmDialog.title",
2811
3055
  defaultMessage: "Confirmation"
@@ -2836,6 +3080,7 @@ const ConfirmDialogPublishAll = ({
2836
3080
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2837
3081
  const { model, schema } = useDoc();
2838
3082
  const [{ query }] = useQueryParams();
3083
+ const enableDraftRelationsCount = false;
2839
3084
  const {
2840
3085
  data: countDraftRelations = 0,
2841
3086
  isLoading,
@@ -2847,7 +3092,7 @@ const ConfirmDialogPublishAll = ({
2847
3092
  locale: query?.plugins?.i18n?.locale
2848
3093
  },
2849
3094
  {
2850
- skip: selectedEntries.length === 0
3095
+ skip: !enableDraftRelationsCount
2851
3096
  }
2852
3097
  );
2853
3098
  React.useEffect(() => {
@@ -3032,7 +3277,7 @@ const SelectedEntriesTableContent = ({
3032
3277
  status: row.status
3033
3278
  }
3034
3279
  ) }),
3035
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3280
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3036
3281
  IconButton,
3037
3282
  {
3038
3283
  tag: Link,
@@ -3055,9 +3300,10 @@ const SelectedEntriesTableContent = ({
3055
3300
  ),
3056
3301
  target: "_blank",
3057
3302
  marginLeft: "auto",
3058
- children: /* @__PURE__ */ jsx(Pencil, {})
3303
+ variant: "ghost",
3304
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3059
3305
  }
3060
- ) })
3306
+ ) }) })
3061
3307
  ] }, row.id)) })
3062
3308
  ] });
3063
3309
  };
@@ -3094,7 +3340,13 @@ const SelectedEntriesModalContent = ({
3094
3340
  );
3095
3341
  const { rows, validationErrors } = React.useMemo(() => {
3096
3342
  if (data.length > 0 && schema) {
3097
- const validate = createYupSchema(schema.attributes, components);
3343
+ const validate = createYupSchema(
3344
+ schema.attributes,
3345
+ components,
3346
+ // Since this is the "Publish" action, the validation
3347
+ // schema must enforce the rules for published entities
3348
+ { status: "published" }
3349
+ );
3098
3350
  const validationErrors2 = {};
3099
3351
  const rows2 = data.map((entry) => {
3100
3352
  try {
@@ -3444,7 +3696,7 @@ const TableActions = ({ document }) => {
3444
3696
  DescriptionComponentRenderer,
3445
3697
  {
3446
3698
  props,
3447
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3699
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3448
3700
  children: (actions2) => {
3449
3701
  const tableRowActions = actions2.filter((action) => {
3450
3702
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3555,7 +3807,7 @@ const CloneAction = ({ model, documentId }) => {
3555
3807
  }),
3556
3808
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3557
3809
  footer: ({ onClose }) => {
3558
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3810
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3559
3811
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3560
3812
  id: "cancel",
3561
3813
  defaultMessage: "Cancel"
@@ -3596,8 +3848,7 @@ class ContentManagerPlugin {
3596
3848
  documentActions = [
3597
3849
  ...DEFAULT_ACTIONS,
3598
3850
  ...DEFAULT_TABLE_ROW_ACTIONS,
3599
- ...DEFAULT_HEADER_ACTIONS,
3600
- HistoryAction
3851
+ ...DEFAULT_HEADER_ACTIONS
3601
3852
  ];
3602
3853
  editViewSidePanels = [ActionsPanel];
3603
3854
  headerActions = [];
@@ -3686,6 +3937,52 @@ const getPrintableType = (value) => {
3686
3937
  }
3687
3938
  return nativeType;
3688
3939
  };
3940
+ const HistoryAction = ({ model, document }) => {
3941
+ const { formatMessage } = useIntl();
3942
+ const [{ query }] = useQueryParams();
3943
+ const navigate = useNavigate();
3944
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3945
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3946
+ return null;
3947
+ }
3948
+ return {
3949
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3950
+ label: formatMessage({
3951
+ id: "content-manager.history.document-action",
3952
+ defaultMessage: "Content History"
3953
+ }),
3954
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3955
+ disabled: (
3956
+ /**
3957
+ * The user is creating a new document.
3958
+ * It hasn't been saved yet, so there's no history to go to
3959
+ */
3960
+ !document || /**
3961
+ * The document has been created but the current dimension has never been saved.
3962
+ * For example, the user is creating a new locale in an existing document,
3963
+ * so there's no history for the document in that locale
3964
+ */
3965
+ !document.id || /**
3966
+ * History is only available for content types created by the user.
3967
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3968
+ * which start with `admin::` or `plugin::`
3969
+ */
3970
+ !model.startsWith("api::")
3971
+ ),
3972
+ position: "header"
3973
+ };
3974
+ };
3975
+ HistoryAction.type = "history";
3976
+ const historyAdmin = {
3977
+ bootstrap(app) {
3978
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3979
+ addDocumentAction((actions2) => {
3980
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3981
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3982
+ return actions2;
3983
+ });
3984
+ }
3985
+ };
3689
3986
  const initialState = {
3690
3987
  collectionTypeLinks: [],
3691
3988
  components: [],
@@ -3722,6 +4019,70 @@ const { setInitialData } = actions;
3722
4019
  const reducer = combineReducers({
3723
4020
  app: reducer$1
3724
4021
  });
4022
+ const previewApi = contentManagerApi.injectEndpoints({
4023
+ endpoints: (builder) => ({
4024
+ getPreviewUrl: builder.query({
4025
+ query({ query, params }) {
4026
+ return {
4027
+ url: `/content-manager/preview/url/${params.contentType}`,
4028
+ method: "GET",
4029
+ config: {
4030
+ params: query
4031
+ }
4032
+ };
4033
+ }
4034
+ })
4035
+ })
4036
+ });
4037
+ const { useGetPreviewUrlQuery } = previewApi;
4038
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4039
+ const { formatMessage } = useIntl();
4040
+ const { trackUsage } = useTracking();
4041
+ const [{ query }] = useQueryParams();
4042
+ const { data, error } = useGetPreviewUrlQuery({
4043
+ params: {
4044
+ contentType: model
4045
+ },
4046
+ query: {
4047
+ documentId,
4048
+ locale: document?.locale,
4049
+ status: document?.status
4050
+ }
4051
+ });
4052
+ if (!data?.data?.url || error) {
4053
+ return null;
4054
+ }
4055
+ const handleClick = () => {
4056
+ trackUsage("willOpenPreview");
4057
+ };
4058
+ return {
4059
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4060
+ content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
4061
+ Button,
4062
+ {
4063
+ variant: "tertiary",
4064
+ tag: Link,
4065
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4066
+ onClick: handleClick,
4067
+ flex: "auto",
4068
+ children: formatMessage({
4069
+ id: "content-manager.preview.panel.button",
4070
+ defaultMessage: "Open preview"
4071
+ })
4072
+ }
4073
+ ) })
4074
+ };
4075
+ };
4076
+ const FEATURE_ID = "preview";
4077
+ const previewAdmin = {
4078
+ bootstrap(app) {
4079
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4080
+ return;
4081
+ }
4082
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4083
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4084
+ }
4085
+ };
3725
4086
  const index = {
3726
4087
  register(app) {
3727
4088
  const cm = new ContentManagerPlugin();
@@ -3741,7 +4102,7 @@ const index = {
3741
4102
  app.router.addRoute({
3742
4103
  path: "content-manager/*",
3743
4104
  lazy: async () => {
3744
- const { Layout } = await import("./layout-ChVuUpa1.mjs");
4105
+ const { Layout } = await import("./layout-Btu_cMRF.mjs");
3745
4106
  return {
3746
4107
  Component: Layout
3747
4108
  };
@@ -3750,10 +4111,18 @@ const index = {
3750
4111
  });
3751
4112
  app.registerPlugin(cm.config);
3752
4113
  },
4114
+ bootstrap(app) {
4115
+ if (typeof historyAdmin.bootstrap === "function") {
4116
+ historyAdmin.bootstrap(app);
4117
+ }
4118
+ if (typeof previewAdmin.bootstrap === "function") {
4119
+ previewAdmin.bootstrap(app);
4120
+ }
4121
+ },
3753
4122
  async registerTrads({ locales }) {
3754
4123
  const importedTrads = await Promise.all(
3755
4124
  locales.map((locale) => {
3756
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Ux26r5pl.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4125
+ 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-D_BMf0hT.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 }) => {
3757
4126
  return {
3758
4127
  data: prefixPluginTranslations(data, PLUGIN_ID),
3759
4128
  locale
@@ -3774,13 +4143,16 @@ export {
3774
4143
  BulkActionsRenderer as B,
3775
4144
  COLLECTION_TYPES as C,
3776
4145
  DocumentStatus as D,
3777
- DEFAULT_SETTINGS as E,
3778
- convertEditLayoutToFieldLayouts as F,
3779
- useDocument as G,
4146
+ extractContentTypeComponents as E,
4147
+ DEFAULT_SETTINGS as F,
4148
+ convertEditLayoutToFieldLayouts as G,
3780
4149
  HOOKS as H,
3781
4150
  InjectionZone as I,
3782
- index as J,
3783
- useDocumentActions as K,
4151
+ useDocument as J,
4152
+ useGetPreviewUrlQuery as K,
4153
+ index as L,
4154
+ useContentManagerContext as M,
4155
+ useDocumentActions as N,
3784
4156
  Panels as P,
3785
4157
  RelativeTime as R,
3786
4158
  SINGLE_TYPES as S,
@@ -3798,18 +4170,18 @@ export {
3798
4170
  PERMISSIONS as k,
3799
4171
  DocumentRBAC as l,
3800
4172
  DOCUMENT_META_FIELDS as m,
3801
- useDocLayout as n,
3802
- useGetContentTypeConfigurationQuery as o,
3803
- CREATOR_FIELDS as p,
3804
- getMainField as q,
3805
- getDisplayName as r,
4173
+ CLONE_PATH as n,
4174
+ useDocLayout as o,
4175
+ useGetContentTypeConfigurationQuery as p,
4176
+ CREATOR_FIELDS as q,
4177
+ getMainField as r,
3806
4178
  setInitialData as s,
3807
- checkIfAttributeIsDisplayable as t,
4179
+ getDisplayName as t,
3808
4180
  useContentTypeSchema as u,
3809
- useGetAllDocumentsQuery as v,
3810
- convertListLayoutToFieldLayouts as w,
3811
- capitalise as x,
3812
- useUpdateContentTypeConfigurationMutation as y,
3813
- extractContentTypeComponents as z
4181
+ checkIfAttributeIsDisplayable as v,
4182
+ useGetAllDocumentsQuery as w,
4183
+ convertListLayoutToFieldLayouts as x,
4184
+ capitalise as y,
4185
+ useUpdateContentTypeConfigurationMutation as z
3814
4186
  };
3815
- //# sourceMappingURL=index-D1344xdw.mjs.map
4187
+ //# sourceMappingURL=index-CbytGVdz.mjs.map