@strapi/content-manager 0.0.0-experimental.826f263c58b6886b849d3f03b81f7a530bc51c91 → 0.0.0-experimental.8e52d29d243dccc7c24beb53412cf1c9c0b36d11

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 (207) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js → ComponentConfigurationPage--MCP7Aew.js} +4 -4
  3. package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js.map → ComponentConfigurationPage--MCP7Aew.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs → ComponentConfigurationPage-DT41asyM.mjs} +4 -4
  5. package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs.map → ComponentConfigurationPage-DT41asyM.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs → EditConfigurationPage-DznPxn9p.mjs} +4 -4
  7. package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs.map → EditConfigurationPage-DznPxn9p.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js → EditConfigurationPage-qgnNvv_u.js} +4 -4
  9. package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js.map → EditConfigurationPage-qgnNvv_u.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-DvaV7U9b.mjs → EditViewPage-B_k7z288.mjs} +72 -50
  11. package/dist/_chunks/EditViewPage-B_k7z288.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CoQEnFlC.js → EditViewPage-Bb4S7p8c.js} +70 -48
  13. package/dist/_chunks/EditViewPage-Bb4S7p8c.js.map +1 -0
  14. package/dist/_chunks/{Field-ZdrmmQ4Y.js → Field-ByR1mllE.js} +582 -230
  15. package/dist/_chunks/Field-ByR1mllE.js.map +1 -0
  16. package/dist/_chunks/{Field-Cz_J9551.mjs → Field-DmwbE0TL.mjs} +580 -228
  17. package/dist/_chunks/Field-DmwbE0TL.mjs.map +1 -0
  18. package/dist/_chunks/{Form-Bpig5rch.js → Form-BpeyAyS1.js} +52 -34
  19. package/dist/_chunks/Form-BpeyAyS1.js.map +1 -0
  20. package/dist/_chunks/{Form-Dxmihyw8.mjs → Form-Dvt5eouJ.mjs} +54 -36
  21. package/dist/_chunks/Form-Dvt5eouJ.mjs.map +1 -0
  22. package/dist/_chunks/{History-BZP8n7KT.mjs → History-CAERKpYl.mjs} +171 -77
  23. package/dist/_chunks/History-CAERKpYl.mjs.map +1 -0
  24. package/dist/_chunks/{History-BfX6XmZK.js → History-d-IgDGPl.js} +170 -76
  25. package/dist/_chunks/History-d-IgDGPl.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DxKuVkKz.mjs → ListConfigurationPage-CVVT45M8.mjs} +59 -49
  27. package/dist/_chunks/ListConfigurationPage-CVVT45M8.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-B3CXj8PY.js → ListConfigurationPage-DSX98CYb.js} +58 -47
  29. package/dist/_chunks/ListConfigurationPage-DSX98CYb.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-Bk9VO__I.js → ListViewPage-C9gPPp-V.js} +117 -105
  31. package/dist/_chunks/ListViewPage-C9gPPp-V.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-D5D3tVPq.mjs → ListViewPage-Q4g6kHDl.mjs} +115 -103
  33. package/dist/_chunks/ListViewPage-Q4g6kHDl.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs → NoContentTypePage-BY4YRGs0.mjs} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs.map → NoContentTypePage-BY4YRGs0.mjs.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js → NoContentTypePage-D09gppmy.js} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js.map → NoContentTypePage-D09gppmy.js.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js → NoPermissionsPage-32WgThJG.js} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js.map → NoPermissionsPage-32WgThJG.js.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs → NoPermissionsPage-CyM16RKL.mjs} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs.map → NoPermissionsPage-CyM16RKL.mjs.map} +1 -1
  42. package/dist/_chunks/Preview-C2WFq4S8.mjs +267 -0
  43. package/dist/_chunks/Preview-C2WFq4S8.mjs.map +1 -0
  44. package/dist/_chunks/Preview-PpV3g9wJ.js +286 -0
  45. package/dist/_chunks/Preview-PpV3g9wJ.js.map +1 -0
  46. package/dist/_chunks/{Relations-BOYZmuWy.mjs → Relations-B_Yn9xGB.mjs} +73 -37
  47. package/dist/_chunks/Relations-B_Yn9xGB.mjs.map +1 -0
  48. package/dist/_chunks/{Relations-B6B3A3mb.js → Relations-mWaebC5t.js} +72 -36
  49. package/dist/_chunks/Relations-mWaebC5t.js.map +1 -0
  50. package/dist/_chunks/{en-BN1bvFK7.js → en-CHOp_xJv.js} +30 -16
  51. package/dist/_chunks/{en-BN1bvFK7.js.map → en-CHOp_xJv.js.map} +1 -1
  52. package/dist/_chunks/{en-Dzv55oQw.mjs → en-D_BMf0hT.mjs} +30 -16
  53. package/dist/_chunks/{en-Dzv55oQw.mjs.map → en-D_BMf0hT.mjs.map} +1 -1
  54. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  55. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  56. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  57. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  58. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  59. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  60. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  61. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  62. package/dist/_chunks/{index-VHviNMeW.mjs → index-CbytGVdz.mjs} +1154 -887
  63. package/dist/_chunks/index-CbytGVdz.mjs.map +1 -0
  64. package/dist/_chunks/{index-DzN3kBgx.js → index-iun2i4xv.js} +1133 -865
  65. package/dist/_chunks/index-iun2i4xv.js.map +1 -0
  66. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  67. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  68. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  69. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  70. package/dist/_chunks/{layout-CPn1PM6x.mjs → layout-Btu_cMRF.mjs} +41 -23
  71. package/dist/_chunks/layout-Btu_cMRF.mjs.map +1 -0
  72. package/dist/_chunks/{layout-b91XRlD2.js → layout-CkaP4K5_.js} +39 -21
  73. package/dist/_chunks/layout-CkaP4K5_.js.map +1 -0
  74. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  75. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  76. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  77. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  78. package/dist/_chunks/{relations-BsqxS6tR.mjs → relations-Cn5re8ia.mjs} +6 -7
  79. package/dist/_chunks/relations-Cn5re8ia.mjs.map +1 -0
  80. package/dist/_chunks/{relations-CA7IYmcP.js → relations-O_v9g0v_.js} +6 -7
  81. package/dist/_chunks/relations-O_v9g0v_.js.map +1 -0
  82. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  83. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  84. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  85. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  86. package/dist/admin/index.js +2 -1
  87. package/dist/admin/index.js.map +1 -1
  88. package/dist/admin/index.mjs +8 -7
  89. package/dist/admin/src/exports.d.ts +1 -1
  90. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  91. package/dist/admin/src/history/index.d.ts +3 -0
  92. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  93. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  94. package/dist/admin/src/index.d.ts +1 -0
  95. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  96. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  97. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  98. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  102. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  103. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  104. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  105. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  106. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  107. package/dist/admin/src/preview/constants.d.ts +1 -0
  108. package/dist/admin/src/preview/index.d.ts +4 -0
  109. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  110. package/dist/admin/src/preview/routes.d.ts +3 -0
  111. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  112. package/dist/admin/src/services/api.d.ts +1 -1
  113. package/dist/admin/src/services/components.d.ts +2 -2
  114. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  115. package/dist/admin/src/services/documents.d.ts +19 -17
  116. package/dist/admin/src/services/init.d.ts +1 -1
  117. package/dist/admin/src/services/relations.d.ts +2 -2
  118. package/dist/admin/src/services/uid.d.ts +3 -3
  119. package/dist/admin/src/utils/validation.d.ts +4 -1
  120. package/dist/server/index.js +551 -263
  121. package/dist/server/index.js.map +1 -1
  122. package/dist/server/index.mjs +552 -264
  123. package/dist/server/index.mjs.map +1 -1
  124. package/dist/server/src/bootstrap.d.ts.map +1 -1
  125. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  126. package/dist/server/src/controllers/index.d.ts.map +1 -1
  127. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  128. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  129. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  130. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  131. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  132. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  133. package/dist/server/src/history/services/history.d.ts.map +1 -1
  134. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  135. package/dist/server/src/history/services/utils.d.ts +4 -4
  136. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  137. package/dist/server/src/index.d.ts +4 -4
  138. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  139. package/dist/server/src/preview/constants.d.ts +2 -0
  140. package/dist/server/src/preview/constants.d.ts.map +1 -0
  141. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  142. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  143. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  144. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  145. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  146. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  147. package/dist/server/src/preview/index.d.ts +4 -0
  148. package/dist/server/src/preview/index.d.ts.map +1 -0
  149. package/dist/server/src/preview/routes/index.d.ts +8 -0
  150. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  151. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  152. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  153. package/dist/server/src/preview/services/index.d.ts +15 -0
  154. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  155. package/dist/server/src/preview/services/preview-config.d.ts +30 -0
  156. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  157. package/dist/server/src/preview/services/preview.d.ts +12 -0
  158. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  159. package/dist/server/src/preview/utils.d.ts +18 -0
  160. package/dist/server/src/preview/utils.d.ts.map +1 -0
  161. package/dist/server/src/routes/index.d.ts.map +1 -1
  162. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  163. package/dist/server/src/services/document-metadata.d.ts +8 -8
  164. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  165. package/dist/server/src/services/index.d.ts +4 -4
  166. package/dist/server/src/services/index.d.ts.map +1 -1
  167. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  168. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  169. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  170. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  171. package/dist/server/src/utils/index.d.ts +2 -0
  172. package/dist/server/src/utils/index.d.ts.map +1 -1
  173. package/dist/shared/contracts/collection-types.d.ts +3 -1
  174. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  175. package/dist/shared/contracts/index.d.ts +1 -0
  176. package/dist/shared/contracts/index.d.ts.map +1 -1
  177. package/dist/shared/contracts/preview.d.ts +27 -0
  178. package/dist/shared/contracts/preview.d.ts.map +1 -0
  179. package/dist/shared/index.js +4 -0
  180. package/dist/shared/index.js.map +1 -1
  181. package/dist/shared/index.mjs +4 -0
  182. package/dist/shared/index.mjs.map +1 -1
  183. package/package.json +13 -13
  184. package/dist/_chunks/EditViewPage-CoQEnFlC.js.map +0 -1
  185. package/dist/_chunks/EditViewPage-DvaV7U9b.mjs.map +0 -1
  186. package/dist/_chunks/Field-Cz_J9551.mjs.map +0 -1
  187. package/dist/_chunks/Field-ZdrmmQ4Y.js.map +0 -1
  188. package/dist/_chunks/Form-Bpig5rch.js.map +0 -1
  189. package/dist/_chunks/Form-Dxmihyw8.mjs.map +0 -1
  190. package/dist/_chunks/History-BZP8n7KT.mjs.map +0 -1
  191. package/dist/_chunks/History-BfX6XmZK.js.map +0 -1
  192. package/dist/_chunks/ListConfigurationPage-B3CXj8PY.js.map +0 -1
  193. package/dist/_chunks/ListConfigurationPage-DxKuVkKz.mjs.map +0 -1
  194. package/dist/_chunks/ListViewPage-Bk9VO__I.js.map +0 -1
  195. package/dist/_chunks/ListViewPage-D5D3tVPq.mjs.map +0 -1
  196. package/dist/_chunks/Relations-B6B3A3mb.js.map +0 -1
  197. package/dist/_chunks/Relations-BOYZmuWy.mjs.map +0 -1
  198. package/dist/_chunks/index-DzN3kBgx.js.map +0 -1
  199. package/dist/_chunks/index-VHviNMeW.mjs.map +0 -1
  200. package/dist/_chunks/layout-CPn1PM6x.mjs.map +0 -1
  201. package/dist/_chunks/layout-b91XRlD2.js.map +0 -1
  202. package/dist/_chunks/relations-BsqxS6tR.mjs.map +0 -1
  203. package/dist/_chunks/relations-CA7IYmcP.js.map +0 -1
  204. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  205. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  206. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  207. package/strapi-server.js +0 -3
@@ -2,15 +2,16 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
10
- const styledComponents = require("styled-components");
7
+ const mapValues = require("lodash/fp/mapValues");
8
+ const reactIntl = require("react-intl");
9
+ const reactRouterDom = require("react-router-dom");
11
10
  const yup = require("yup");
12
11
  const pipe = require("lodash/fp/pipe");
13
12
  const dateFns = require("date-fns");
13
+ const styledComponents = require("styled-components");
14
+ const qs = require("qs");
14
15
  const toolkit = require("@reduxjs/toolkit");
15
16
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
17
  function _interopNamespace(e) {
@@ -32,6 +33,7 @@ function _interopNamespace(e) {
32
33
  return Object.freeze(n);
33
34
  }
34
35
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
36
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
37
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
38
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
39
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
@@ -70,42 +72,6 @@ const useInjectionZone = (area) => {
70
72
  const [page, position] = area.split(".");
71
73
  return contentManagerPlugin.getInjectedComponents(page, position);
72
74
  };
73
- const HistoryAction = ({ model, document }) => {
74
- const { formatMessage } = reactIntl.useIntl();
75
- const [{ query }] = strapiAdmin.useQueryParams();
76
- const navigate = reactRouterDom.useNavigate();
77
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
78
- if (!window.strapi.features.isEnabled("cms-content-history")) {
79
- return null;
80
- }
81
- return {
82
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
83
- label: formatMessage({
84
- id: "content-manager.history.document-action",
85
- defaultMessage: "Content History"
86
- }),
87
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
88
- disabled: (
89
- /**
90
- * The user is creating a new document.
91
- * It hasn't been saved yet, so there's no history to go to
92
- */
93
- !document || /**
94
- * The document has been created but the current dimension has never been saved.
95
- * For example, the user is creating a new locale in an existing document,
96
- * so there's no history for the document in that locale
97
- */
98
- !document.id || /**
99
- * History is only available for content types created by the user.
100
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
101
- * which start with `admin::` or `plugin::`
102
- */
103
- !model.startsWith("api::")
104
- ),
105
- position: "header"
106
- };
107
- };
108
- HistoryAction.type = "history";
109
75
  const ID = "id";
110
76
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
111
77
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -157,6 +123,7 @@ const DocumentRBAC = ({ children, permissions }) => {
157
123
  if (!slug) {
158
124
  throw new Error("Cannot find the slug param in the URL");
159
125
  }
126
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
160
127
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
161
128
  const contentTypePermissions = React__namespace.useMemo(() => {
162
129
  const contentTypePermissions2 = userPermissions.filter(
@@ -167,7 +134,14 @@ const DocumentRBAC = ({ children, permissions }) => {
167
134
  return { ...acc, [action]: [permission] };
168
135
  }, {});
169
136
  }, [slug, userPermissions]);
170
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
137
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
138
+ contentTypePermissions,
139
+ permissions ?? void 0,
140
+ // TODO: useRBAC context should be typed and built differently
141
+ // We are passing raw query as context to the hook so that it can
142
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
143
+ rawQuery
144
+ );
171
145
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
172
146
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
173
147
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -215,10 +189,12 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
215
189
  "Document",
216
190
  "InitialData",
217
191
  "HistoryVersion",
218
- "Relations"
192
+ "Relations",
193
+ "UidAvailability"
219
194
  ]
220
195
  });
221
196
  const documentApi = contentManagerApi.injectEndpoints({
197
+ overrideExisting: true,
222
198
  endpoints: (builder) => ({
223
199
  autoCloneDocument: builder.mutation({
224
200
  query: ({ model, sourceId, query }) => ({
@@ -228,7 +204,12 @@ const documentApi = contentManagerApi.injectEndpoints({
228
204
  params: query
229
205
  }
230
206
  }),
231
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
207
+ invalidatesTags: (_result, error, { model }) => {
208
+ if (error) {
209
+ return [];
210
+ }
211
+ return [{ type: "Document", id: `${model}_LIST` }];
212
+ }
232
213
  }),
233
214
  cloneDocument: builder.mutation({
234
215
  query: ({ model, sourceId, data, params }) => ({
@@ -239,7 +220,10 @@ const documentApi = contentManagerApi.injectEndpoints({
239
220
  params
240
221
  }
241
222
  }),
242
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
223
+ invalidatesTags: (_result, _error, { model }) => [
224
+ { type: "Document", id: `${model}_LIST` },
225
+ { type: "UidAvailability", id: model }
226
+ ]
243
227
  }),
244
228
  /**
245
229
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -256,7 +240,8 @@ const documentApi = contentManagerApi.injectEndpoints({
256
240
  }),
257
241
  invalidatesTags: (result, _error, { model }) => [
258
242
  { type: "Document", id: `${model}_LIST` },
259
- "Relations"
243
+ "Relations",
244
+ { type: "UidAvailability", id: model }
260
245
  ]
261
246
  }),
262
247
  deleteDocument: builder.mutation({
@@ -297,7 +282,8 @@ const documentApi = contentManagerApi.injectEndpoints({
297
282
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
298
283
  },
299
284
  { type: "Document", id: `${model}_LIST` },
300
- "Relations"
285
+ "Relations",
286
+ { type: "UidAvailability", id: model }
301
287
  ];
302
288
  }
303
289
  }),
@@ -315,6 +301,7 @@ const documentApi = contentManagerApi.injectEndpoints({
315
301
  }),
316
302
  providesTags: (result, _error, arg) => {
317
303
  return [
304
+ { type: "Document", id: `ALL_LIST` },
318
305
  { type: "Document", id: `${arg.model}_LIST` },
319
306
  ...result?.results.map(({ documentId }) => ({
320
307
  type: "Document",
@@ -353,6 +340,11 @@ const documentApi = contentManagerApi.injectEndpoints({
353
340
  {
354
341
  type: "Document",
355
342
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
343
+ },
344
+ // Make it easy to invalidate all individual documents queries for a model
345
+ {
346
+ type: "Document",
347
+ id: `${model}_ALL_ITEMS`
356
348
  }
357
349
  ];
358
350
  }
@@ -416,8 +408,21 @@ const documentApi = contentManagerApi.injectEndpoints({
416
408
  type: "Document",
417
409
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
418
410
  },
419
- "Relations"
411
+ "Relations",
412
+ { type: "UidAvailability", id: model }
420
413
  ];
414
+ },
415
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
416
+ const patchResult = dispatch(
417
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
418
+ Object.assign(draft.data, data);
419
+ })
420
+ );
421
+ try {
422
+ await queryFulfilled;
423
+ } catch {
424
+ patchResult.undo();
425
+ }
421
426
  }
422
427
  }),
423
428
  unpublishDocument: builder.mutation({
@@ -487,20 +492,39 @@ const buildValidParams = (query) => {
487
492
  const isBaseQueryError = (error) => {
488
493
  return error.name !== void 0;
489
494
  };
490
- const createYupSchema = (attributes = {}, components = {}) => {
495
+ const arrayValidator = (attribute, options) => ({
496
+ message: strapiAdmin.translatedErrors.required,
497
+ test(value) {
498
+ if (options.status === "draft") {
499
+ return true;
500
+ }
501
+ if (!attribute.required) {
502
+ return true;
503
+ }
504
+ if (!value) {
505
+ return false;
506
+ }
507
+ if (Array.isArray(value) && value.length === 0) {
508
+ return false;
509
+ }
510
+ return true;
511
+ }
512
+ });
513
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
491
514
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
492
515
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
493
516
  if (DOCUMENT_META_FIELDS.includes(name)) {
494
517
  return acc;
495
518
  }
496
519
  const validations = [
520
+ addNullableValidation,
497
521
  addRequiredValidation,
498
522
  addMinLengthValidation,
499
523
  addMaxLengthValidation,
500
524
  addMinValidation,
501
525
  addMaxValidation,
502
526
  addRegexValidation
503
- ].map((fn) => fn(attribute));
527
+ ].map((fn) => fn(attribute, options));
504
528
  const transformSchema = pipe__default.default(...validations);
505
529
  switch (attribute.type) {
506
530
  case "component": {
@@ -510,12 +534,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
510
534
  ...acc,
511
535
  [name]: transformSchema(
512
536
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
513
- )
537
+ ).test(arrayValidator(attribute, options))
514
538
  };
515
539
  } else {
516
540
  return {
517
541
  ...acc,
518
- [name]: transformSchema(createModelSchema(attributes3))
542
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
519
543
  };
520
544
  }
521
545
  }
@@ -537,7 +561,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
537
561
  }
538
562
  )
539
563
  )
540
- )
564
+ ).test(arrayValidator(attribute, options))
541
565
  };
542
566
  case "relation":
543
567
  return {
@@ -549,7 +573,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
549
573
  } else if (Array.isArray(value)) {
550
574
  return yup__namespace.array().of(
551
575
  yup__namespace.object().shape({
552
- id: yup__namespace.string().required()
576
+ id: yup__namespace.number().required()
553
577
  })
554
578
  );
555
579
  } else if (typeof value === "object") {
@@ -601,6 +625,14 @@ const createAttributeSchema = (attribute) => {
601
625
  if (!value || typeof value === "string" && value.length === 0) {
602
626
  return true;
603
627
  }
628
+ if (typeof value === "object") {
629
+ try {
630
+ JSON.stringify(value);
631
+ return true;
632
+ } catch (err) {
633
+ return false;
634
+ }
635
+ }
604
636
  try {
605
637
  JSON.parse(value);
606
638
  return true;
@@ -619,13 +651,7 @@ const createAttributeSchema = (attribute) => {
619
651
  return yup__namespace.mixed();
620
652
  }
621
653
  };
622
- const addRequiredValidation = (attribute) => (schema) => {
623
- if (attribute.required) {
624
- return schema.required({
625
- id: strapiAdmin.translatedErrors.required.id,
626
- defaultMessage: "This field is required."
627
- });
628
- }
654
+ const nullableSchema = (schema) => {
629
655
  return schema?.nullable ? schema.nullable() : (
630
656
  // In some cases '.nullable' will not be available on the schema.
631
657
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -633,7 +659,22 @@ const addRequiredValidation = (attribute) => (schema) => {
633
659
  schema
634
660
  );
635
661
  };
636
- const addMinLengthValidation = (attribute) => (schema) => {
662
+ const addNullableValidation = () => (schema) => {
663
+ return nullableSchema(schema);
664
+ };
665
+ const addRequiredValidation = (attribute, options) => (schema) => {
666
+ if (options.status === "draft" || !attribute.required) {
667
+ return schema;
668
+ }
669
+ if (attribute.required && "required" in schema) {
670
+ return schema.required(strapiAdmin.translatedErrors.required);
671
+ }
672
+ return schema;
673
+ };
674
+ const addMinLengthValidation = (attribute, options) => (schema) => {
675
+ if (options.status === "draft") {
676
+ return schema;
677
+ }
637
678
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
638
679
  return schema.min(attribute.minLength, {
639
680
  ...strapiAdmin.translatedErrors.minLength,
@@ -655,10 +696,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
655
696
  }
656
697
  return schema;
657
698
  };
658
- const addMinValidation = (attribute) => (schema) => {
659
- if ("min" in attribute) {
699
+ const addMinValidation = (attribute, options) => (schema) => {
700
+ if (options.status === "draft") {
701
+ return schema;
702
+ }
703
+ if ("min" in attribute && "min" in schema) {
660
704
  const min = toInteger(attribute.min);
661
- if ("min" in schema && min) {
705
+ if (min) {
662
706
  return schema.min(min, {
663
707
  ...strapiAdmin.translatedErrors.min,
664
708
  values: {
@@ -776,16 +820,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
776
820
  }, {});
777
821
  return componentsByKey;
778
822
  };
779
- const useDocument = (args, opts) => {
823
+ const HOOKS = {
824
+ /**
825
+ * Hook that allows to mutate the displayed headers of the list view table
826
+ * @constant
827
+ * @type {string}
828
+ */
829
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
830
+ /**
831
+ * Hook that allows to mutate the CM's collection types links pre-set filters
832
+ * @constant
833
+ * @type {string}
834
+ */
835
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
836
+ /**
837
+ * Hook that allows to mutate the CM's edit view layout
838
+ * @constant
839
+ * @type {string}
840
+ */
841
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
842
+ /**
843
+ * Hook that allows to mutate the CM's single types links pre-set filters
844
+ * @constant
845
+ * @type {string}
846
+ */
847
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
848
+ };
849
+ const contentTypesApi = contentManagerApi.injectEndpoints({
850
+ endpoints: (builder) => ({
851
+ getContentTypeConfiguration: builder.query({
852
+ query: (uid) => ({
853
+ url: `/content-manager/content-types/${uid}/configuration`,
854
+ method: "GET"
855
+ }),
856
+ transformResponse: (response) => response.data,
857
+ providesTags: (_result, _error, uid) => [
858
+ { type: "ContentTypesConfiguration", id: uid },
859
+ { type: "ContentTypeSettings", id: "LIST" }
860
+ ]
861
+ }),
862
+ getAllContentTypeSettings: builder.query({
863
+ query: () => "/content-manager/content-types-settings",
864
+ transformResponse: (response) => response.data,
865
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
866
+ }),
867
+ updateContentTypeConfiguration: builder.mutation({
868
+ query: ({ uid, ...body }) => ({
869
+ url: `/content-manager/content-types/${uid}/configuration`,
870
+ method: "PUT",
871
+ data: body
872
+ }),
873
+ transformResponse: (response) => response.data,
874
+ invalidatesTags: (_result, _error, { uid }) => [
875
+ { type: "ContentTypesConfiguration", id: uid },
876
+ { type: "ContentTypeSettings", id: "LIST" },
877
+ // Is this necessary?
878
+ { type: "InitialData" }
879
+ ]
880
+ })
881
+ })
882
+ });
883
+ const {
884
+ useGetContentTypeConfigurationQuery,
885
+ useGetAllContentTypeSettingsQuery,
886
+ useUpdateContentTypeConfigurationMutation
887
+ } = contentTypesApi;
888
+ const checkIfAttributeIsDisplayable = (attribute) => {
889
+ const { type } = attribute;
890
+ if (type === "relation") {
891
+ return !attribute.relation.toLowerCase().includes("morph");
892
+ }
893
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
894
+ };
895
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
896
+ if (!mainFieldName) {
897
+ return void 0;
898
+ }
899
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
900
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
901
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
902
+ );
903
+ return {
904
+ name: mainFieldName,
905
+ type: mainFieldType ?? "string"
906
+ };
907
+ };
908
+ const DEFAULT_SETTINGS = {
909
+ bulkable: false,
910
+ filterable: false,
911
+ searchable: false,
912
+ pagination: false,
913
+ defaultSortBy: "",
914
+ defaultSortOrder: "asc",
915
+ mainField: "id",
916
+ pageSize: 10
917
+ };
918
+ const useDocumentLayout = (model) => {
919
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
920
+ const [{ query }] = strapiAdmin.useQueryParams();
921
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
780
922
  const { toggleNotification } = strapiAdmin.useNotification();
781
923
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
924
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
782
925
  const {
783
- currentData: data,
784
- isLoading: isLoadingDocument,
785
- isFetching: isFetchingDocument,
786
- error
787
- } = useGetDocumentQuery(args, opts);
788
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
926
+ data,
927
+ isLoading: isLoadingConfigs,
928
+ error,
929
+ isFetching: isFetchingConfigs
930
+ } = useGetContentTypeConfigurationQuery(model);
931
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
789
932
  React__namespace.useEffect(() => {
790
933
  if (error) {
791
934
  toggleNotification({
@@ -793,68 +936,322 @@ const useDocument = (args, opts) => {
793
936
  message: formatAPIError(error)
794
937
  });
795
938
  }
796
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
797
- const validationSchema = React__namespace.useMemo(() => {
798
- if (!schema) {
799
- return null;
800
- }
801
- return createYupSchema(schema.attributes, components);
802
- }, [schema, components]);
803
- const validate = React__namespace.useCallback(
804
- (document) => {
805
- if (!validationSchema) {
806
- throw new Error(
807
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
808
- );
809
- }
810
- try {
811
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
812
- return null;
813
- } catch (error2) {
814
- if (error2 instanceof yup.ValidationError) {
815
- return strapiAdmin.getYupValidationErrors(error2);
816
- }
817
- throw error2;
818
- }
939
+ }, [error, formatAPIError, toggleNotification]);
940
+ const editLayout = React__namespace.useMemo(
941
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
942
+ layout: [],
943
+ components: {},
944
+ metadatas: {},
945
+ options: {},
946
+ settings: DEFAULT_SETTINGS
819
947
  },
820
- [validationSchema]
948
+ [data, isLoading, schemas, schema, components]
949
+ );
950
+ const listLayout = React__namespace.useMemo(() => {
951
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
952
+ layout: [],
953
+ metadatas: {},
954
+ options: {},
955
+ settings: DEFAULT_SETTINGS
956
+ };
957
+ }, [data, isLoading, schemas, schema, components]);
958
+ const { layout: edit } = React__namespace.useMemo(
959
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
960
+ layout: editLayout,
961
+ query
962
+ }),
963
+ [editLayout, query, runHookWaterfall]
821
964
  );
822
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
823
965
  return {
824
- components,
825
- document: data?.data,
826
- meta: data?.meta,
966
+ error,
827
967
  isLoading,
828
- schema,
829
- validate
968
+ edit,
969
+ list: listLayout
830
970
  };
831
971
  };
832
- const useDoc = () => {
833
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
834
- const [{ query }] = strapiAdmin.useQueryParams();
835
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
836
- if (!collectionType) {
837
- throw new Error("Could not find collectionType in url params");
838
- }
839
- if (!slug) {
972
+ const useDocLayout = () => {
973
+ const { model } = useDoc();
974
+ return useDocumentLayout(model);
975
+ };
976
+ const formatEditLayout = (data, {
977
+ schemas,
978
+ schema,
979
+ components
980
+ }) => {
981
+ let currentPanelIndex = 0;
982
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
983
+ data.contentType.layouts.edit,
984
+ schema?.attributes,
985
+ data.contentType.metadatas,
986
+ { configurations: data.components, schemas: components },
987
+ schemas
988
+ ).reduce((panels, row) => {
989
+ if (row.some((field) => field.type === "dynamiczone")) {
990
+ panels.push([row]);
991
+ currentPanelIndex += 2;
992
+ } else {
993
+ if (!panels[currentPanelIndex]) {
994
+ panels.push([row]);
995
+ } else {
996
+ panels[currentPanelIndex].push(row);
997
+ }
998
+ }
999
+ return panels;
1000
+ }, []);
1001
+ const componentEditAttributes = Object.entries(data.components).reduce(
1002
+ (acc, [uid, configuration]) => {
1003
+ acc[uid] = {
1004
+ layout: convertEditLayoutToFieldLayouts(
1005
+ configuration.layouts.edit,
1006
+ components[uid].attributes,
1007
+ configuration.metadatas,
1008
+ { configurations: data.components, schemas: components }
1009
+ ),
1010
+ settings: {
1011
+ ...configuration.settings,
1012
+ icon: components[uid].info.icon,
1013
+ displayName: components[uid].info.displayName
1014
+ }
1015
+ };
1016
+ return acc;
1017
+ },
1018
+ {}
1019
+ );
1020
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1021
+ (acc, [attribute, metadata]) => {
1022
+ return {
1023
+ ...acc,
1024
+ [attribute]: metadata.edit
1025
+ };
1026
+ },
1027
+ {}
1028
+ );
1029
+ return {
1030
+ layout: panelledEditAttributes,
1031
+ components: componentEditAttributes,
1032
+ metadatas: editMetadatas,
1033
+ settings: {
1034
+ ...data.contentType.settings,
1035
+ displayName: schema?.info.displayName
1036
+ },
1037
+ options: {
1038
+ ...schema?.options,
1039
+ ...schema?.pluginOptions,
1040
+ ...data.contentType.options
1041
+ }
1042
+ };
1043
+ };
1044
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1045
+ return rows.map(
1046
+ (row) => row.map((field) => {
1047
+ const attribute = attributes[field.name];
1048
+ if (!attribute) {
1049
+ return null;
1050
+ }
1051
+ const { edit: metadata } = metadatas[field.name];
1052
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1053
+ return {
1054
+ attribute,
1055
+ disabled: !metadata.editable,
1056
+ hint: metadata.description,
1057
+ label: metadata.label ?? "",
1058
+ name: field.name,
1059
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1060
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1061
+ schemas,
1062
+ components: components?.schemas ?? {}
1063
+ }),
1064
+ placeholder: metadata.placeholder ?? "",
1065
+ required: attribute.required ?? false,
1066
+ size: field.size,
1067
+ unique: "unique" in attribute ? attribute.unique : false,
1068
+ visible: metadata.visible ?? true,
1069
+ type: attribute.type
1070
+ };
1071
+ }).filter((field) => field !== null)
1072
+ );
1073
+ };
1074
+ const formatListLayout = (data, {
1075
+ schemas,
1076
+ schema,
1077
+ components
1078
+ }) => {
1079
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1080
+ (acc, [attribute, metadata]) => {
1081
+ return {
1082
+ ...acc,
1083
+ [attribute]: metadata.list
1084
+ };
1085
+ },
1086
+ {}
1087
+ );
1088
+ const listAttributes = convertListLayoutToFieldLayouts(
1089
+ data.contentType.layouts.list,
1090
+ schema?.attributes,
1091
+ listMetadatas,
1092
+ { configurations: data.components, schemas: components },
1093
+ schemas
1094
+ );
1095
+ return {
1096
+ layout: listAttributes,
1097
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1098
+ metadatas: listMetadatas,
1099
+ options: {
1100
+ ...schema?.options,
1101
+ ...schema?.pluginOptions,
1102
+ ...data.contentType.options
1103
+ }
1104
+ };
1105
+ };
1106
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1107
+ return columns.map((name) => {
1108
+ const attribute = attributes[name];
1109
+ if (!attribute) {
1110
+ return null;
1111
+ }
1112
+ const metadata = metadatas[name];
1113
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1114
+ return {
1115
+ attribute,
1116
+ label: metadata.label ?? "",
1117
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1118
+ schemas,
1119
+ components: components?.schemas ?? {}
1120
+ }),
1121
+ name,
1122
+ searchable: metadata.searchable ?? true,
1123
+ sortable: metadata.sortable ?? true
1124
+ };
1125
+ }).filter((field) => field !== null);
1126
+ };
1127
+ const useDocument = (args, opts) => {
1128
+ const { toggleNotification } = strapiAdmin.useNotification();
1129
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1130
+ const {
1131
+ currentData: data,
1132
+ isLoading: isLoadingDocument,
1133
+ isFetching: isFetchingDocument,
1134
+ error
1135
+ } = useGetDocumentQuery(args, {
1136
+ ...opts,
1137
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1138
+ });
1139
+ const {
1140
+ components,
1141
+ schema,
1142
+ schemas,
1143
+ isLoading: isLoadingSchema
1144
+ } = useContentTypeSchema(args.model);
1145
+ React__namespace.useEffect(() => {
1146
+ if (error) {
1147
+ toggleNotification({
1148
+ type: "danger",
1149
+ message: formatAPIError(error)
1150
+ });
1151
+ }
1152
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1153
+ const validationSchema = React__namespace.useMemo(() => {
1154
+ if (!schema) {
1155
+ return null;
1156
+ }
1157
+ return createYupSchema(schema.attributes, components);
1158
+ }, [schema, components]);
1159
+ const validate = React__namespace.useCallback(
1160
+ (document) => {
1161
+ if (!validationSchema) {
1162
+ throw new Error(
1163
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1164
+ );
1165
+ }
1166
+ try {
1167
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1168
+ return null;
1169
+ } catch (error2) {
1170
+ if (error2 instanceof yup.ValidationError) {
1171
+ return strapiAdmin.getYupValidationErrors(error2);
1172
+ }
1173
+ throw error2;
1174
+ }
1175
+ },
1176
+ [validationSchema]
1177
+ );
1178
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1179
+ const hasError = !!error;
1180
+ return {
1181
+ components,
1182
+ document: data?.data,
1183
+ meta: data?.meta,
1184
+ isLoading,
1185
+ hasError,
1186
+ schema,
1187
+ schemas,
1188
+ validate
1189
+ };
1190
+ };
1191
+ const useDoc = () => {
1192
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1193
+ const [{ query }] = strapiAdmin.useQueryParams();
1194
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1195
+ if (!collectionType) {
1196
+ throw new Error("Could not find collectionType in url params");
1197
+ }
1198
+ if (!slug) {
840
1199
  throw new Error("Could not find model in url params");
841
1200
  }
1201
+ const document = useDocument(
1202
+ { documentId: origin || id, model: slug, collectionType, params },
1203
+ {
1204
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1205
+ }
1206
+ );
1207
+ const returnId = origin || id === "create" ? void 0 : id;
842
1208
  return {
843
1209
  collectionType,
844
1210
  model: slug,
845
- id: origin || id === "create" ? void 0 : id,
846
- ...useDocument(
847
- { documentId: origin || id, model: slug, collectionType, params },
848
- {
849
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
850
- }
851
- )
1211
+ id: returnId,
1212
+ ...document
1213
+ };
1214
+ };
1215
+ const useContentManagerContext = () => {
1216
+ const {
1217
+ collectionType,
1218
+ model,
1219
+ id,
1220
+ components,
1221
+ isLoading: isLoadingDoc,
1222
+ schema,
1223
+ schemas
1224
+ } = useDoc();
1225
+ const layout = useDocumentLayout(model);
1226
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1227
+ const isSingleType = collectionType === SINGLE_TYPES;
1228
+ const slug = model;
1229
+ const isCreatingEntry = id === "create";
1230
+ useContentTypeSchema();
1231
+ const isLoading = isLoadingDoc || layout.isLoading;
1232
+ const error = layout.error;
1233
+ return {
1234
+ error,
1235
+ isLoading,
1236
+ // Base metadata
1237
+ model,
1238
+ collectionType,
1239
+ id,
1240
+ slug,
1241
+ isCreatingEntry,
1242
+ isSingleType,
1243
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1244
+ // All schema infos
1245
+ components,
1246
+ contentType: schema,
1247
+ contentTypes: schemas,
1248
+ // Form state
1249
+ form,
1250
+ // layout infos
1251
+ layout
852
1252
  };
853
1253
  };
854
1254
  const prefixPluginTranslations = (trad, pluginId) => {
855
- if (!pluginId) {
856
- throw new TypeError("pluginId can't be empty");
857
- }
858
1255
  return Object.keys(trad).reduce((acc, current) => {
859
1256
  acc[`${pluginId}.${current}`] = trad[current];
860
1257
  return acc;
@@ -870,6 +1267,8 @@ const useDocumentActions = () => {
870
1267
  const { formatMessage } = reactIntl.useIntl();
871
1268
  const { trackUsage } = strapiAdmin.useTracking();
872
1269
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1270
+ const navigate = reactRouterDom.useNavigate();
1271
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
873
1272
  const [deleteDocument] = useDeleteDocumentMutation();
874
1273
  const _delete = React__namespace.useCallback(
875
1274
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -948,12 +1347,13 @@ const useDocumentActions = () => {
948
1347
  );
949
1348
  const [discardDocument] = useDiscardDocumentMutation();
950
1349
  const discard = React__namespace.useCallback(
951
- async ({ collectionType, model, documentId }) => {
1350
+ async ({ collectionType, model, documentId, params }) => {
952
1351
  try {
953
1352
  const res = await discardDocument({
954
1353
  collectionType,
955
1354
  model,
956
- documentId
1355
+ documentId,
1356
+ params
957
1357
  });
958
1358
  if ("error" in res) {
959
1359
  toggleNotification({
@@ -1183,6 +1583,7 @@ const useDocumentActions = () => {
1183
1583
  defaultMessage: "Saved document"
1184
1584
  })
1185
1585
  });
1586
+ setCurrentStep("contentManager.success");
1186
1587
  return res.data;
1187
1588
  } catch (err) {
1188
1589
  toggleNotification({
@@ -1204,7 +1605,6 @@ const useDocumentActions = () => {
1204
1605
  sourceId
1205
1606
  });
1206
1607
  if ("error" in res) {
1207
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1208
1608
  return { error: res.error };
1209
1609
  }
1210
1610
  toggleNotification({
@@ -1223,7 +1623,7 @@ const useDocumentActions = () => {
1223
1623
  throw err;
1224
1624
  }
1225
1625
  },
1226
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1626
+ [autoCloneDocument, formatMessage, toggleNotification]
1227
1627
  );
1228
1628
  const [cloneDocument] = useCloneDocumentMutation();
1229
1629
  const clone = React__namespace.useCallback(
@@ -1249,6 +1649,7 @@ const useDocumentActions = () => {
1249
1649
  defaultMessage: "Cloned document"
1250
1650
  })
1251
1651
  });
1652
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1252
1653
  return res.data;
1253
1654
  } catch (err) {
1254
1655
  toggleNotification({
@@ -1259,7 +1660,7 @@ const useDocumentActions = () => {
1259
1660
  throw err;
1260
1661
  }
1261
1662
  },
1262
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1663
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1263
1664
  );
1264
1665
  const [getDoc] = useLazyGetDocumentQuery();
1265
1666
  const getDocument = React__namespace.useCallback(
@@ -1284,10 +1685,10 @@ const useDocumentActions = () => {
1284
1685
  update
1285
1686
  };
1286
1687
  };
1287
- const ProtectedHistoryPage = React.lazy(
1288
- () => Promise.resolve().then(() => require("./History-BfX6XmZK.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1688
+ const ProtectedHistoryPage = React__namespace.lazy(
1689
+ () => Promise.resolve().then(() => require("./History-d-IgDGPl.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1289
1690
  );
1290
- const routes$1 = [
1691
+ const routes$2 = [
1291
1692
  {
1292
1693
  path: ":collectionType/:slug/:id/history",
1293
1694
  Component: ProtectedHistoryPage
@@ -1297,32 +1698,45 @@ const routes$1 = [
1297
1698
  Component: ProtectedHistoryPage
1298
1699
  }
1299
1700
  ];
1701
+ const ProtectedPreviewPage = React__namespace.lazy(
1702
+ () => Promise.resolve().then(() => require("./Preview-PpV3g9wJ.js")).then((mod) => ({ default: mod.ProtectedPreviewPage }))
1703
+ );
1704
+ const routes$1 = [
1705
+ {
1706
+ path: ":collectionType/:slug/:id/preview",
1707
+ Component: ProtectedPreviewPage
1708
+ },
1709
+ {
1710
+ path: ":collectionType/:slug/preview",
1711
+ Component: ProtectedPreviewPage
1712
+ }
1713
+ ];
1300
1714
  const ProtectedEditViewPage = React.lazy(
1301
- () => Promise.resolve().then(() => require("./EditViewPage-CoQEnFlC.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1715
+ () => Promise.resolve().then(() => require("./EditViewPage-Bb4S7p8c.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1302
1716
  );
1303
1717
  const ProtectedListViewPage = React.lazy(
1304
- () => Promise.resolve().then(() => require("./ListViewPage-Bk9VO__I.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1718
+ () => Promise.resolve().then(() => require("./ListViewPage-C9gPPp-V.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1305
1719
  );
1306
1720
  const ProtectedListConfiguration = React.lazy(
1307
- () => Promise.resolve().then(() => require("./ListConfigurationPage-B3CXj8PY.js")).then((mod) => ({
1721
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-DSX98CYb.js")).then((mod) => ({
1308
1722
  default: mod.ProtectedListConfiguration
1309
1723
  }))
1310
1724
  );
1311
1725
  const ProtectedEditConfigurationPage = React.lazy(
1312
- () => Promise.resolve().then(() => require("./EditConfigurationPage-tDtWj7R2.js")).then((mod) => ({
1726
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-qgnNvv_u.js")).then((mod) => ({
1313
1727
  default: mod.ProtectedEditConfigurationPage
1314
1728
  }))
1315
1729
  );
1316
1730
  const ProtectedComponentConfigurationPage = React.lazy(
1317
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DJcn1DrO.js")).then((mod) => ({
1731
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage--MCP7Aew.js")).then((mod) => ({
1318
1732
  default: mod.ProtectedComponentConfigurationPage
1319
1733
  }))
1320
1734
  );
1321
1735
  const NoPermissions = React.lazy(
1322
- () => Promise.resolve().then(() => require("./NoPermissionsPage-BQDM64_b.js")).then((mod) => ({ default: mod.NoPermissions }))
1736
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-32WgThJG.js")).then((mod) => ({ default: mod.NoPermissions }))
1323
1737
  );
1324
1738
  const NoContentType = React.lazy(
1325
- () => Promise.resolve().then(() => require("./NoContentTypePage-DsB2F7Z1.js")).then((mod) => ({ default: mod.NoContentType }))
1739
+ () => Promise.resolve().then(() => require("./NoContentTypePage-D09gppmy.js")).then((mod) => ({ default: mod.NoContentType }))
1326
1740
  );
1327
1741
  const CollectionTypePages = () => {
1328
1742
  const { collectionType } = reactRouterDom.useParams();
@@ -1368,6 +1782,7 @@ const routes = [
1368
1782
  path: "no-content-types",
1369
1783
  Component: NoContentType
1370
1784
  },
1785
+ ...routes$2,
1371
1786
  ...routes$1
1372
1787
  ];
1373
1788
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1436,12 +1851,14 @@ const DocumentActionButton = (action) => {
1436
1851
  /* @__PURE__ */ jsxRuntime.jsx(
1437
1852
  designSystem.Button,
1438
1853
  {
1439
- flex: 1,
1854
+ flex: "auto",
1440
1855
  startIcon: action.icon,
1441
1856
  disabled: action.disabled,
1442
1857
  onClick: handleClick(action),
1443
1858
  justifyContent: "center",
1444
1859
  variant: action.variant || "default",
1860
+ paddingTop: "7px",
1861
+ paddingBottom: "7px",
1445
1862
  children: action.label
1446
1863
  }
1447
1864
  ),
@@ -1449,7 +1866,7 @@ const DocumentActionButton = (action) => {
1449
1866
  DocumentActionConfirmDialog,
1450
1867
  {
1451
1868
  ...action.dialog,
1452
- variant: action.variant,
1869
+ variant: action.dialog?.variant ?? action.variant,
1453
1870
  isOpen: dialogId === action.id,
1454
1871
  onClose: handleClose
1455
1872
  }
@@ -1506,9 +1923,9 @@ const DocumentActionsMenu = ({
1506
1923
  disabled: isDisabled,
1507
1924
  size: "S",
1508
1925
  endIcon: null,
1509
- paddingTop: "7px",
1510
- paddingLeft: "9px",
1511
- paddingRight: "9px",
1926
+ paddingTop: "4px",
1927
+ paddingLeft: "7px",
1928
+ paddingRight: "7px",
1512
1929
  variant,
1513
1930
  children: [
1514
1931
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1519,7 +1936,7 @@ const DocumentActionsMenu = ({
1519
1936
  ]
1520
1937
  }
1521
1938
  ),
1522
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1939
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1523
1940
  actions2.map((action) => {
1524
1941
  return /* @__PURE__ */ jsxRuntime.jsx(
1525
1942
  designSystem.Menu.Item,
@@ -1528,10 +1945,25 @@ const DocumentActionsMenu = ({
1528
1945
  onSelect: handleClick(action),
1529
1946
  display: "block",
1530
1947
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1531
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1532
- action.icon,
1533
- action.label
1534
- ] }),
1948
+ /* @__PURE__ */ jsxRuntime.jsxs(
1949
+ designSystem.Flex,
1950
+ {
1951
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1952
+ gap: 2,
1953
+ tag: "span",
1954
+ children: [
1955
+ /* @__PURE__ */ jsxRuntime.jsx(
1956
+ designSystem.Flex,
1957
+ {
1958
+ tag: "span",
1959
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1960
+ children: action.icon
1961
+ }
1962
+ ),
1963
+ action.label
1964
+ ]
1965
+ }
1966
+ ),
1535
1967
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1536
1968
  designSystem.Flex,
1537
1969
  {
@@ -1590,9 +2022,21 @@ const convertActionVariantToColor = (variant = "secondary") => {
1590
2022
  return "primary600";
1591
2023
  }
1592
2024
  };
1593
- const DocumentActionConfirmDialog = ({
1594
- onClose,
1595
- onCancel,
2025
+ const convertActionVariantToIconColor = (variant = "secondary") => {
2026
+ switch (variant) {
2027
+ case "danger":
2028
+ return "danger600";
2029
+ case "secondary":
2030
+ return "neutral500";
2031
+ case "success":
2032
+ return "success600";
2033
+ default:
2034
+ return "primary600";
2035
+ }
2036
+ };
2037
+ const DocumentActionConfirmDialog = ({
2038
+ onClose,
2039
+ onCancel,
1596
2040
  onConfirm,
1597
2041
  title,
1598
2042
  content,
@@ -1612,22 +2056,20 @@ const DocumentActionConfirmDialog = ({
1612
2056
  }
1613
2057
  onClose();
1614
2058
  };
1615
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1616
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1617
- /* @__PURE__ */ jsxRuntime.jsx(
1618
- designSystem.DialogFooter,
1619
- {
1620
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1621
- id: "app.components.Button.cancel",
1622
- defaultMessage: "Cancel"
1623
- }) }),
1624
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1625
- id: "app.components.Button.confirm",
1626
- defaultMessage: "Confirm"
1627
- }) })
1628
- }
1629
- )
1630
- ] });
2059
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2060
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2061
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
2062
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2063
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
2064
+ id: "app.components.Button.cancel",
2065
+ defaultMessage: "Cancel"
2066
+ }) }) }),
2067
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
2068
+ id: "app.components.Button.confirm",
2069
+ defaultMessage: "Confirm"
2070
+ }) })
2071
+ ] })
2072
+ ] }) });
1631
2073
  };
1632
2074
  const DocumentActionModal = ({
1633
2075
  isOpen,
@@ -1637,34 +2079,29 @@ const DocumentActionModal = ({
1637
2079
  content: Content,
1638
2080
  onModalClose
1639
2081
  }) => {
1640
- const id = React__namespace.useId();
1641
- if (!isOpen) {
1642
- return null;
1643
- }
1644
2082
  const handleClose = () => {
1645
2083
  if (onClose) {
1646
2084
  onClose();
1647
2085
  }
1648
2086
  onModalClose();
1649
2087
  };
1650
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1651
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(
1654
- designSystem.Box,
1655
- {
1656
- paddingTop: 4,
1657
- paddingBottom: 4,
1658
- paddingLeft: 5,
1659
- paddingRight: 5,
1660
- borderWidth: "1px 0 0 0",
1661
- borderStyle: "solid",
1662
- borderColor: "neutral150",
1663
- background: "neutral100",
1664
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1665
- }
1666
- )
1667
- ] });
2088
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
2089
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
2090
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
2091
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
2092
+ ] }) });
2093
+ };
2094
+ const transformData = (data) => {
2095
+ if (Array.isArray(data)) {
2096
+ return data.map(transformData);
2097
+ }
2098
+ if (typeof data === "object" && data !== null) {
2099
+ if ("apiData" in data) {
2100
+ return data.apiData;
2101
+ }
2102
+ return mapValues__default.default(transformData)(data);
2103
+ }
2104
+ return data;
1668
2105
  };
1669
2106
  const PublishAction$1 = ({
1670
2107
  activeTab,
@@ -1678,13 +2115,17 @@ const PublishAction$1 = ({
1678
2115
  const navigate = reactRouterDom.useNavigate();
1679
2116
  const { toggleNotification } = strapiAdmin.useNotification();
1680
2117
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2118
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1681
2119
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1682
2120
  const { formatMessage } = reactIntl.useIntl();
1683
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1684
- "PublishAction",
1685
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1686
- );
2121
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1687
2122
  const { publish } = useDocumentActions();
2123
+ const [
2124
+ countDraftRelations,
2125
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
2126
+ ] = useLazyGetDraftRelationCountQuery();
2127
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
2128
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1688
2129
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1689
2130
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1690
2131
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1693,10 +2134,105 @@ const PublishAction$1 = ({
1693
2134
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1694
2135
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1695
2136
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
2137
+ React__namespace.useEffect(() => {
2138
+ if (isErrorDraftRelations) {
2139
+ toggleNotification({
2140
+ type: "danger",
2141
+ message: formatMessage({
2142
+ id: getTranslation("error.records.fetch-draft-relatons"),
2143
+ defaultMessage: "An error occurred while fetching draft relations on this document."
2144
+ })
2145
+ });
2146
+ }
2147
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
2148
+ React__namespace.useEffect(() => {
2149
+ const localDraftRelations = /* @__PURE__ */ new Set();
2150
+ const extractDraftRelations = (data) => {
2151
+ const relations = data.connect || [];
2152
+ relations.forEach((relation) => {
2153
+ if (relation.status === "draft") {
2154
+ localDraftRelations.add(relation.id);
2155
+ }
2156
+ });
2157
+ };
2158
+ const traverseAndExtract = (data) => {
2159
+ Object.entries(data).forEach(([key, value]) => {
2160
+ if (key === "connect" && Array.isArray(value)) {
2161
+ extractDraftRelations({ connect: value });
2162
+ } else if (typeof value === "object" && value !== null) {
2163
+ traverseAndExtract(value);
2164
+ }
2165
+ });
2166
+ };
2167
+ if (!documentId || modified) {
2168
+ traverseAndExtract(formValues);
2169
+ setLocalCountOfDraftRelations(localDraftRelations.size);
2170
+ }
2171
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
2172
+ React__namespace.useEffect(() => {
2173
+ if (!document || !document.documentId || isListView) {
2174
+ return;
2175
+ }
2176
+ const fetchDraftRelationsCount = async () => {
2177
+ const { data, error } = await countDraftRelations({
2178
+ collectionType,
2179
+ model,
2180
+ documentId,
2181
+ params
2182
+ });
2183
+ if (error) {
2184
+ throw error;
2185
+ }
2186
+ if (data) {
2187
+ setServerCountOfDraftRelations(data.data);
2188
+ }
2189
+ };
2190
+ fetchDraftRelationsCount();
2191
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1696
2192
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1697
2193
  if (!schema?.options?.draftAndPublish) {
1698
2194
  return null;
1699
2195
  }
2196
+ const performPublish = async () => {
2197
+ setSubmitting(true);
2198
+ try {
2199
+ const { errors } = await validate(true, {
2200
+ status: "published"
2201
+ });
2202
+ if (errors) {
2203
+ toggleNotification({
2204
+ type: "danger",
2205
+ message: formatMessage({
2206
+ id: "content-manager.validation.error",
2207
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2208
+ })
2209
+ });
2210
+ return;
2211
+ }
2212
+ const res = await publish(
2213
+ {
2214
+ collectionType,
2215
+ model,
2216
+ documentId,
2217
+ params
2218
+ },
2219
+ transformData(formValues)
2220
+ );
2221
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2222
+ navigate({
2223
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2224
+ search: rawQuery
2225
+ });
2226
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2227
+ setErrors(formatValidationErrors(res.error));
2228
+ }
2229
+ } finally {
2230
+ setSubmitting(false);
2231
+ }
2232
+ };
2233
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
2234
+ const enableDraftRelationsCount = false;
2235
+ const hasDraftRelations = enableDraftRelationsCount;
1700
2236
  return {
1701
2237
  /**
1702
2238
  * Disabled when:
@@ -1706,49 +2242,36 @@ const PublishAction$1 = ({
1706
2242
  * - the document is already published & not modified
1707
2243
  * - the document is being created & not modified
1708
2244
  * - the user doesn't have the permission to publish
1709
- * - the user doesn't have the permission to create a new document
1710
- * - the user doesn't have the permission to update the document
1711
2245
  */
1712
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
2246
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1713
2247
  label: formatMessage({
1714
2248
  id: "app.utils.publish",
1715
2249
  defaultMessage: "Publish"
1716
2250
  }),
1717
2251
  onClick: async () => {
1718
- setSubmitting(true);
1719
- try {
1720
- const { errors } = await validate();
1721
- if (errors) {
1722
- toggleNotification({
1723
- type: "danger",
1724
- message: formatMessage({
1725
- id: "content-manager.validation.error",
1726
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1727
- })
1728
- });
1729
- return;
1730
- }
1731
- const res = await publish(
1732
- {
1733
- collectionType,
1734
- model,
1735
- documentId,
1736
- params
1737
- },
1738
- formValues
1739
- );
1740
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1741
- navigate({
1742
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1743
- search: rawQuery
1744
- });
1745
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1746
- setErrors(formatValidationErrors(res.error));
2252
+ await performPublish();
2253
+ },
2254
+ dialog: hasDraftRelations ? {
2255
+ type: "dialog",
2256
+ variant: "danger",
2257
+ footer: null,
2258
+ title: formatMessage({
2259
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
2260
+ defaultMessage: "Confirmation"
2261
+ }),
2262
+ content: formatMessage(
2263
+ {
2264
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2265
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
2266
+ },
2267
+ {
2268
+ count: totalDraftRelations
1747
2269
  }
1748
- } finally {
1749
- setSubmitting(false);
2270
+ ),
2271
+ onConfirm: async () => {
2272
+ await performPublish();
1750
2273
  }
1751
- }
2274
+ } : void 0
1752
2275
  };
1753
2276
  };
1754
2277
  PublishAction$1.type = "publish";
@@ -1764,10 +2287,6 @@ const UpdateAction = ({
1764
2287
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1765
2288
  const isCloning = cloneMatch !== null;
1766
2289
  const { formatMessage } = reactIntl.useIntl();
1767
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1768
- canCreate: canCreate2,
1769
- canUpdate: canUpdate2
1770
- }));
1771
2290
  const { create, update, clone } = useDocumentActions();
1772
2291
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1773
2292
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1784,10 +2303,8 @@ const UpdateAction = ({
1784
2303
  * - the form is submitting
1785
2304
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1786
2305
  * - the active tab is the published tab
1787
- * - the user doesn't have the permission to create a new document
1788
- * - the user doesn't have the permission to update the document
1789
2306
  */
1790
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
2307
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1791
2308
  label: formatMessage({
1792
2309
  id: "content-manager.containers.Edit.save",
1793
2310
  defaultMessage: "Save"
@@ -1795,7 +2312,9 @@ const UpdateAction = ({
1795
2312
  onClick: async () => {
1796
2313
  setSubmitting(true);
1797
2314
  try {
1798
- const { errors } = await validate();
2315
+ const { errors } = await validate(true, {
2316
+ status: "draft"
2317
+ });
1799
2318
  if (errors) {
1800
2319
  toggleNotification({
1801
2320
  type: "danger",
@@ -1813,13 +2332,16 @@ const UpdateAction = ({
1813
2332
  documentId: cloneMatch.params.origin,
1814
2333
  params
1815
2334
  },
1816
- document
2335
+ transformData(document)
1817
2336
  );
1818
2337
  if ("data" in res) {
1819
- navigate({
1820
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1821
- search: rawQuery
1822
- });
2338
+ navigate(
2339
+ {
2340
+ pathname: `../${res.data.documentId}`,
2341
+ search: rawQuery
2342
+ },
2343
+ { relative: "path" }
2344
+ );
1823
2345
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1824
2346
  setErrors(formatValidationErrors(res.error));
1825
2347
  }
@@ -1831,7 +2353,7 @@ const UpdateAction = ({
1831
2353
  documentId,
1832
2354
  params
1833
2355
  },
1834
- document
2356
+ transformData(document)
1835
2357
  );
1836
2358
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
2359
  setErrors(formatValidationErrors(res.error));
@@ -1844,13 +2366,16 @@ const UpdateAction = ({
1844
2366
  model,
1845
2367
  params
1846
2368
  },
1847
- document
2369
+ transformData(document)
1848
2370
  );
1849
2371
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1850
- navigate({
1851
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1852
- search: rawQuery
1853
- });
2372
+ navigate(
2373
+ {
2374
+ pathname: `../${res.data.documentId}`,
2375
+ search: rawQuery
2376
+ },
2377
+ { replace: true, relative: "path" }
2378
+ );
1854
2379
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1855
2380
  setErrors(formatValidationErrors(res.error));
1856
2381
  }
@@ -1882,10 +2407,8 @@ const UnpublishAction$1 = ({
1882
2407
  const { toggleNotification } = strapiAdmin.useNotification();
1883
2408
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1884
2409
  const isDocumentModified = document?.status === "modified";
1885
- const handleChange = (e) => {
1886
- if ("value" in e.target) {
1887
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1888
- }
2410
+ const handleChange = (value) => {
2411
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
2412
  };
1890
2413
  if (!schema?.options?.draftAndPublish) {
1891
2414
  return null;
@@ -1896,7 +2419,7 @@ const UnpublishAction$1 = ({
1896
2419
  id: "app.utils.unpublish",
1897
2420
  defaultMessage: "Unpublish"
1898
2421
  }),
1899
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2422
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1900
2423
  onClick: async () => {
1901
2424
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1902
2425
  if (!documentId) {
@@ -1935,40 +2458,24 @@ const UnpublishAction$1 = ({
1935
2458
  }) })
1936
2459
  ] }),
1937
2460
  /* @__PURE__ */ jsxRuntime.jsxs(
1938
- designSystem.Flex,
2461
+ designSystem.Radio.Group,
1939
2462
  {
1940
- onChange: handleChange,
1941
- direction: "column",
1942
- alignItems: "flex-start",
1943
- tag: "fieldset",
1944
- borderWidth: 0,
1945
- gap: 3,
2463
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2464
+ name: "discard-options",
2465
+ "aria-label": formatMessage({
2466
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2467
+ defaultMessage: "Choose an option to unpublish the document."
2468
+ }),
2469
+ onValueChange: handleChange,
1946
2470
  children: [
1947
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1948
- /* @__PURE__ */ jsxRuntime.jsx(
1949
- designSystem.Radio,
1950
- {
1951
- checked: shouldKeepDraft,
1952
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1953
- name: "discard-options",
1954
- children: formatMessage({
1955
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1956
- defaultMessage: "Keep draft"
1957
- })
1958
- }
1959
- ),
1960
- /* @__PURE__ */ jsxRuntime.jsx(
1961
- designSystem.Radio,
1962
- {
1963
- checked: !shouldKeepDraft,
1964
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1965
- name: "discard-options",
1966
- children: formatMessage({
1967
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1968
- defaultMessage: "Replace draft"
1969
- })
1970
- }
1971
- )
2471
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2472
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2473
+ defaultMessage: "Keep draft"
2474
+ }) }),
2475
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2476
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2477
+ defaultMessage: "Replace draft"
2478
+ }) })
1972
2479
  ]
1973
2480
  }
1974
2481
  )
@@ -2024,7 +2531,7 @@ const DiscardAction = ({
2024
2531
  id: "content-manager.actions.discard.label",
2025
2532
  defaultMessage: "Discard changes"
2026
2533
  }),
2027
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2534
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2028
2535
  position: ["panel", "table-row"],
2029
2536
  variant: "danger",
2030
2537
  dialog: {
@@ -2052,11 +2559,6 @@ const DiscardAction = ({
2052
2559
  };
2053
2560
  };
2054
2561
  DiscardAction.type = "discard";
2055
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2056
- path {
2057
- fill: currentColor;
2058
- }
2059
- `;
2060
2562
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2061
2563
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2062
2564
  const RelativeTime = React__namespace.forwardRef(
@@ -2104,8 +2606,12 @@ const getDisplayName = ({
2104
2606
  };
2105
2607
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2106
2608
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2107
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2108
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2609
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2610
+ const { formatMessage } = reactIntl.useIntl();
2611
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2612
+ id: `content-manager.containers.List.${status}`,
2613
+ defaultMessage: capitalise(status)
2614
+ }) }) });
2109
2615
  };
2110
2616
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2111
2617
  const { formatMessage } = reactIntl.useIntl();
@@ -2114,23 +2620,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2114
2620
  id: "content-manager.containers.edit.title.new",
2115
2621
  defaultMessage: "Create an entry"
2116
2622
  }) : documentTitle;
2117
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2623
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2118
2624
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2119
- /* @__PURE__ */ jsxRuntime.jsxs(
2120
- designSystem.Flex,
2121
- {
2122
- width: "100%",
2123
- justifyContent: "space-between",
2124
- paddingTop: 1,
2125
- gap: "80px",
2126
- alignItems: "flex-start",
2127
- children: [
2128
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2129
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2130
- ]
2131
- }
2132
- ),
2133
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2625
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2626
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2627
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2628
+ ] }),
2629
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2134
2630
  ] });
2135
2631
  };
2136
2632
  const HeaderToolbar = () => {
@@ -2213,12 +2709,12 @@ const Information = ({ activeTab }) => {
2213
2709
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2214
2710
  label: formatMessage({
2215
2711
  id: "content-manager.containers.edit.information.last-published.label",
2216
- defaultMessage: "Last published"
2712
+ defaultMessage: "Published"
2217
2713
  }),
2218
2714
  value: formatMessage(
2219
2715
  {
2220
2716
  id: "content-manager.containers.edit.information.last-published.value",
2221
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2717
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2222
2718
  },
2223
2719
  {
2224
2720
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2231,12 +2727,12 @@ const Information = ({ activeTab }) => {
2231
2727
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2232
2728
  label: formatMessage({
2233
2729
  id: "content-manager.containers.edit.information.last-draft.label",
2234
- defaultMessage: "Last draft"
2730
+ defaultMessage: "Updated"
2235
2731
  }),
2236
2732
  value: formatMessage(
2237
2733
  {
2238
2734
  id: "content-manager.containers.edit.information.last-draft.value",
2239
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2735
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2240
2736
  },
2241
2737
  {
2242
2738
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2254,12 +2750,12 @@ const Information = ({ activeTab }) => {
2254
2750
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2255
2751
  label: formatMessage({
2256
2752
  id: "content-manager.containers.edit.information.document.label",
2257
- defaultMessage: "Document"
2753
+ defaultMessage: "Created"
2258
2754
  }),
2259
2755
  value: formatMessage(
2260
2756
  {
2261
2757
  id: "content-manager.containers.edit.information.document.value",
2262
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2758
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2263
2759
  },
2264
2760
  {
2265
2761
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2297,25 +2793,77 @@ const Information = ({ activeTab }) => {
2297
2793
  );
2298
2794
  };
2299
2795
  const HeaderActions = ({ actions: actions2 }) => {
2300
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2301
- if ("options" in action) {
2796
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2797
+ const handleClick = (action) => async (e) => {
2798
+ if (!("options" in action)) {
2799
+ const { onClick = () => false, dialog, id } = action;
2800
+ const muteDialog = await onClick(e);
2801
+ if (dialog && !muteDialog) {
2802
+ e.preventDefault();
2803
+ setDialogId(id);
2804
+ }
2805
+ }
2806
+ };
2807
+ const handleClose = () => {
2808
+ setDialogId(null);
2809
+ };
2810
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2811
+ if (action.options) {
2302
2812
  return /* @__PURE__ */ jsxRuntime.jsx(
2303
2813
  designSystem.SingleSelect,
2304
2814
  {
2305
2815
  size: "S",
2306
- disabled: action.disabled,
2307
- "aria-label": action.label,
2308
2816
  onChange: action.onSelect,
2309
- value: action.value,
2817
+ "aria-label": action.label,
2818
+ ...action,
2310
2819
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2311
2820
  },
2312
2821
  action.id
2313
2822
  );
2314
2823
  } else {
2315
- return null;
2824
+ if (action.type === "icon") {
2825
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2826
+ /* @__PURE__ */ jsxRuntime.jsx(
2827
+ designSystem.IconButton,
2828
+ {
2829
+ disabled: action.disabled,
2830
+ label: action.label,
2831
+ size: "S",
2832
+ onClick: handleClick(action),
2833
+ children: action.icon
2834
+ }
2835
+ ),
2836
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2837
+ HeaderActionDialog,
2838
+ {
2839
+ ...action.dialog,
2840
+ isOpen: dialogId === action.id,
2841
+ onClose: handleClose
2842
+ }
2843
+ ) : null
2844
+ ] }, action.id);
2845
+ }
2316
2846
  }
2317
2847
  }) });
2318
2848
  };
2849
+ const HeaderActionDialog = ({
2850
+ onClose,
2851
+ onCancel,
2852
+ title,
2853
+ content: Content,
2854
+ isOpen
2855
+ }) => {
2856
+ const handleClose = async () => {
2857
+ if (onCancel) {
2858
+ await onCancel();
2859
+ }
2860
+ onClose();
2861
+ };
2862
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2863
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2864
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2865
+ ] }) });
2866
+ };
2319
2867
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2320
2868
  const navigate = reactRouterDom.useNavigate();
2321
2869
  const { formatMessage } = reactIntl.useIntl();
@@ -2356,12 +2904,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2356
2904
  const { delete: deleteAction } = useDocumentActions();
2357
2905
  const { toggleNotification } = strapiAdmin.useNotification();
2358
2906
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2907
+ const isLocalized = document?.locale != null;
2359
2908
  return {
2360
2909
  disabled: !canDelete || !document,
2361
- label: formatMessage({
2362
- id: "content-manager.actions.delete.label",
2363
- defaultMessage: "Delete document"
2364
- }),
2910
+ label: formatMessage(
2911
+ {
2912
+ id: "content-manager.actions.delete.label",
2913
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2914
+ },
2915
+ { isLocalized }
2916
+ ),
2365
2917
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2366
2918
  dialog: {
2367
2919
  type: "dialog",
@@ -2451,7 +3003,7 @@ const ActionsPanel = () => {
2451
3003
  return {
2452
3004
  title: formatMessage({
2453
3005
  id: "content-manager.containers.edit.panels.default.title",
2454
- defaultMessage: "Document"
3006
+ defaultMessage: "Entry"
2455
3007
  }),
2456
3008
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2457
3009
  };
@@ -2470,350 +3022,48 @@ const ActionsPanelContent = () => {
2470
3022
  activeTab: status,
2471
3023
  model,
2472
3024
  documentId: id,
2473
- document: isCloning ? void 0 : document,
2474
- meta: isCloning ? void 0 : meta,
2475
- collectionType
2476
- };
2477
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2478
- /* @__PURE__ */ jsxRuntime.jsx(
2479
- strapiAdmin.DescriptionComponentRenderer,
2480
- {
2481
- props,
2482
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2483
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2484
- }
2485
- ),
2486
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2487
- ] });
2488
- };
2489
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2490
- return /* @__PURE__ */ jsxRuntime.jsxs(
2491
- designSystem.Flex,
2492
- {
2493
- ref,
2494
- tag: "aside",
2495
- "aria-labelledby": "additional-information",
2496
- background: "neutral0",
2497
- borderColor: "neutral150",
2498
- hasRadius: true,
2499
- paddingBottom: 4,
2500
- paddingLeft: 4,
2501
- paddingRight: 4,
2502
- paddingTop: 4,
2503
- shadow: "tableShadow",
2504
- gap: 3,
2505
- direction: "column",
2506
- justifyContent: "stretch",
2507
- alignItems: "flex-start",
2508
- children: [
2509
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2510
- children
2511
- ]
2512
- }
2513
- );
2514
- });
2515
- const HOOKS = {
2516
- /**
2517
- * Hook that allows to mutate the displayed headers of the list view table
2518
- * @constant
2519
- * @type {string}
2520
- */
2521
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2522
- /**
2523
- * Hook that allows to mutate the CM's collection types links pre-set filters
2524
- * @constant
2525
- * @type {string}
2526
- */
2527
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2528
- /**
2529
- * Hook that allows to mutate the CM's edit view layout
2530
- * @constant
2531
- * @type {string}
2532
- */
2533
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2534
- /**
2535
- * Hook that allows to mutate the CM's single types links pre-set filters
2536
- * @constant
2537
- * @type {string}
2538
- */
2539
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2540
- };
2541
- const contentTypesApi = contentManagerApi.injectEndpoints({
2542
- endpoints: (builder) => ({
2543
- getContentTypeConfiguration: builder.query({
2544
- query: (uid) => ({
2545
- url: `/content-manager/content-types/${uid}/configuration`,
2546
- method: "GET"
2547
- }),
2548
- transformResponse: (response) => response.data,
2549
- providesTags: (_result, _error, uid) => [
2550
- { type: "ContentTypesConfiguration", id: uid },
2551
- { type: "ContentTypeSettings", id: "LIST" }
2552
- ]
2553
- }),
2554
- getAllContentTypeSettings: builder.query({
2555
- query: () => "/content-manager/content-types-settings",
2556
- transformResponse: (response) => response.data,
2557
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2558
- }),
2559
- updateContentTypeConfiguration: builder.mutation({
2560
- query: ({ uid, ...body }) => ({
2561
- url: `/content-manager/content-types/${uid}/configuration`,
2562
- method: "PUT",
2563
- data: body
2564
- }),
2565
- transformResponse: (response) => response.data,
2566
- invalidatesTags: (_result, _error, { uid }) => [
2567
- { type: "ContentTypesConfiguration", id: uid },
2568
- { type: "ContentTypeSettings", id: "LIST" },
2569
- // Is this necessary?
2570
- { type: "InitialData" }
2571
- ]
2572
- })
2573
- })
2574
- });
2575
- const {
2576
- useGetContentTypeConfigurationQuery,
2577
- useGetAllContentTypeSettingsQuery,
2578
- useUpdateContentTypeConfigurationMutation
2579
- } = contentTypesApi;
2580
- const checkIfAttributeIsDisplayable = (attribute) => {
2581
- const { type } = attribute;
2582
- if (type === "relation") {
2583
- return !attribute.relation.toLowerCase().includes("morph");
2584
- }
2585
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2586
- };
2587
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2588
- if (!mainFieldName) {
2589
- return void 0;
2590
- }
2591
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2592
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2593
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2594
- );
2595
- return {
2596
- name: mainFieldName,
2597
- type: mainFieldType ?? "string"
2598
- };
2599
- };
2600
- const DEFAULT_SETTINGS = {
2601
- bulkable: false,
2602
- filterable: false,
2603
- searchable: false,
2604
- pagination: false,
2605
- defaultSortBy: "",
2606
- defaultSortOrder: "asc",
2607
- mainField: "id",
2608
- pageSize: 10
2609
- };
2610
- const useDocumentLayout = (model) => {
2611
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2612
- const [{ query }] = strapiAdmin.useQueryParams();
2613
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2614
- const { toggleNotification } = strapiAdmin.useNotification();
2615
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2616
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2617
- const {
2618
- data,
2619
- isLoading: isLoadingConfigs,
2620
- error,
2621
- isFetching: isFetchingConfigs
2622
- } = useGetContentTypeConfigurationQuery(model);
2623
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2624
- React__namespace.useEffect(() => {
2625
- if (error) {
2626
- toggleNotification({
2627
- type: "danger",
2628
- message: formatAPIError(error)
2629
- });
2630
- }
2631
- }, [error, formatAPIError, toggleNotification]);
2632
- const editLayout = React__namespace.useMemo(
2633
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2634
- layout: [],
2635
- components: {},
2636
- metadatas: {},
2637
- options: {},
2638
- settings: DEFAULT_SETTINGS
2639
- },
2640
- [data, isLoading, schemas, schema, components]
2641
- );
2642
- const listLayout = React__namespace.useMemo(() => {
2643
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2644
- layout: [],
2645
- metadatas: {},
2646
- options: {},
2647
- settings: DEFAULT_SETTINGS
2648
- };
2649
- }, [data, isLoading, schemas, schema, components]);
2650
- const { layout: edit } = React__namespace.useMemo(
2651
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2652
- layout: editLayout,
2653
- query
2654
- }),
2655
- [editLayout, query, runHookWaterfall]
2656
- );
2657
- return {
2658
- error,
2659
- isLoading,
2660
- edit,
2661
- list: listLayout
2662
- };
2663
- };
2664
- const useDocLayout = () => {
2665
- const { model } = useDoc();
2666
- return useDocumentLayout(model);
2667
- };
2668
- const formatEditLayout = (data, {
2669
- schemas,
2670
- schema,
2671
- components
2672
- }) => {
2673
- let currentPanelIndex = 0;
2674
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2675
- data.contentType.layouts.edit,
2676
- schema?.attributes,
2677
- data.contentType.metadatas,
2678
- { configurations: data.components, schemas: components },
2679
- schemas
2680
- ).reduce((panels, row) => {
2681
- if (row.some((field) => field.type === "dynamiczone")) {
2682
- panels.push([row]);
2683
- currentPanelIndex += 2;
2684
- } else {
2685
- if (!panels[currentPanelIndex]) {
2686
- panels.push([]);
2687
- }
2688
- panels[currentPanelIndex].push(row);
2689
- }
2690
- return panels;
2691
- }, []);
2692
- const componentEditAttributes = Object.entries(data.components).reduce(
2693
- (acc, [uid, configuration]) => {
2694
- acc[uid] = {
2695
- layout: convertEditLayoutToFieldLayouts(
2696
- configuration.layouts.edit,
2697
- components[uid].attributes,
2698
- configuration.metadatas
2699
- ),
2700
- settings: {
2701
- ...configuration.settings,
2702
- icon: components[uid].info.icon,
2703
- displayName: components[uid].info.displayName
2704
- }
2705
- };
2706
- return acc;
2707
- },
2708
- {}
2709
- );
2710
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2711
- (acc, [attribute, metadata]) => {
2712
- return {
2713
- ...acc,
2714
- [attribute]: metadata.edit
2715
- };
2716
- },
2717
- {}
2718
- );
2719
- return {
2720
- layout: panelledEditAttributes,
2721
- components: componentEditAttributes,
2722
- metadatas: editMetadatas,
2723
- settings: {
2724
- ...data.contentType.settings,
2725
- displayName: schema?.info.displayName
2726
- },
2727
- options: {
2728
- ...schema?.options,
2729
- ...schema?.pluginOptions,
2730
- ...data.contentType.options
2731
- }
2732
- };
2733
- };
2734
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2735
- return rows.map(
2736
- (row) => row.map((field) => {
2737
- const attribute = attributes[field.name];
2738
- if (!attribute) {
2739
- return null;
2740
- }
2741
- const { edit: metadata } = metadatas[field.name];
2742
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2743
- return {
2744
- attribute,
2745
- disabled: !metadata.editable,
2746
- hint: metadata.description,
2747
- label: metadata.label ?? "",
2748
- name: field.name,
2749
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2750
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2751
- schemas,
2752
- components: components?.schemas ?? {}
2753
- }),
2754
- placeholder: metadata.placeholder ?? "",
2755
- required: attribute.required ?? false,
2756
- size: field.size,
2757
- unique: "unique" in attribute ? attribute.unique : false,
2758
- visible: metadata.visible ?? true,
2759
- type: attribute.type
2760
- };
2761
- }).filter((field) => field !== null)
2762
- );
2763
- };
2764
- const formatListLayout = (data, {
2765
- schemas,
2766
- schema,
2767
- components
2768
- }) => {
2769
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2770
- (acc, [attribute, metadata]) => {
2771
- return {
2772
- ...acc,
2773
- [attribute]: metadata.list
2774
- };
2775
- },
2776
- {}
2777
- );
2778
- const listAttributes = convertListLayoutToFieldLayouts(
2779
- data.contentType.layouts.list,
2780
- schema?.attributes,
2781
- listMetadatas,
2782
- { configurations: data.components, schemas: components },
2783
- schemas
2784
- );
2785
- return {
2786
- layout: listAttributes,
2787
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2788
- metadatas: listMetadatas,
2789
- options: {
2790
- ...schema?.options,
2791
- ...schema?.pluginOptions,
2792
- ...data.contentType.options
2793
- }
2794
- };
2795
- };
2796
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2797
- return columns.map((name) => {
2798
- const attribute = attributes[name];
2799
- if (!attribute) {
2800
- return null;
2801
- }
2802
- const metadata = metadatas[name];
2803
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2804
- return {
2805
- attribute,
2806
- label: metadata.label ?? "",
2807
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2808
- schemas,
2809
- components: components?.schemas ?? {}
2810
- }),
2811
- name,
2812
- searchable: metadata.searchable ?? true,
2813
- sortable: metadata.sortable ?? true
2814
- };
2815
- }).filter((field) => field !== null);
3025
+ document: isCloning ? void 0 : document,
3026
+ meta: isCloning ? void 0 : meta,
3027
+ collectionType
3028
+ };
3029
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3030
+ /* @__PURE__ */ jsxRuntime.jsx(
3031
+ strapiAdmin.DescriptionComponentRenderer,
3032
+ {
3033
+ props,
3034
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3035
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3036
+ }
3037
+ ),
3038
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3039
+ ] });
2816
3040
  };
3041
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3042
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3043
+ designSystem.Flex,
3044
+ {
3045
+ ref,
3046
+ tag: "aside",
3047
+ "aria-labelledby": "additional-information",
3048
+ background: "neutral0",
3049
+ borderColor: "neutral150",
3050
+ hasRadius: true,
3051
+ paddingBottom: 4,
3052
+ paddingLeft: 4,
3053
+ paddingRight: 4,
3054
+ paddingTop: 4,
3055
+ shadow: "tableShadow",
3056
+ gap: 3,
3057
+ direction: "column",
3058
+ justifyContent: "stretch",
3059
+ alignItems: "flex-start",
3060
+ children: [
3061
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3062
+ children
3063
+ ]
3064
+ }
3065
+ );
3066
+ });
2817
3067
  const ConfirmBulkActionDialog = ({
2818
3068
  onToggleDialog,
2819
3069
  isOpen = false,
@@ -2821,30 +3071,23 @@ const ConfirmBulkActionDialog = ({
2821
3071
  endAction
2822
3072
  }) => {
2823
3073
  const { formatMessage } = reactIntl.useIntl();
2824
- return /* @__PURE__ */ jsxRuntime.jsxs(
2825
- designSystem.Dialog,
2826
- {
2827
- onClose: onToggleDialog,
2828
- title: formatMessage({
2829
- id: "app.components.ConfirmDialog.title",
2830
- defaultMessage: "Confirmation"
2831
- }),
2832
- isOpen,
2833
- children: [
2834
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2835
- /* @__PURE__ */ jsxRuntime.jsx(
2836
- designSystem.DialogFooter,
2837
- {
2838
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2839
- id: "app.components.Button.cancel",
2840
- defaultMessage: "Cancel"
2841
- }) }),
2842
- endAction
2843
- }
2844
- )
2845
- ]
2846
- }
2847
- );
3074
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
3075
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
3076
+ id: "app.components.ConfirmDialog.title",
3077
+ defaultMessage: "Confirmation"
3078
+ }) }),
3079
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3080
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3081
+ dialogBody
3082
+ ] }) }),
3083
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
3084
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
3085
+ id: "app.components.Button.cancel",
3086
+ defaultMessage: "Cancel"
3087
+ }) }) }),
3088
+ endAction
3089
+ ] })
3090
+ ] }) });
2848
3091
  };
2849
3092
  const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2850
3093
  const ConfirmDialogPublishAll = ({
@@ -2859,6 +3102,7 @@ const ConfirmDialogPublishAll = ({
2859
3102
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2860
3103
  const { model, schema } = useDoc();
2861
3104
  const [{ query }] = strapiAdmin.useQueryParams();
3105
+ const enableDraftRelationsCount = false;
2862
3106
  const {
2863
3107
  data: countDraftRelations = 0,
2864
3108
  isLoading,
@@ -2870,7 +3114,7 @@ const ConfirmDialogPublishAll = ({
2870
3114
  locale: query?.plugins?.i18n?.locale
2871
3115
  },
2872
3116
  {
2873
- skip: selectedEntries.length === 0
3117
+ skip: !enableDraftRelationsCount
2874
3118
  }
2875
3119
  );
2876
3120
  React__namespace.useEffect(() => {
@@ -2949,16 +3193,30 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2949
3193
  )
2950
3194
  );
2951
3195
  } else {
2952
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3196
+ messages.push(
3197
+ ...formatErrorMessages(
3198
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3199
+ value,
3200
+ currentKey,
3201
+ formatMessage
3202
+ )
3203
+ );
2953
3204
  }
3205
+ } else {
3206
+ messages.push(
3207
+ formatMessage(
3208
+ {
3209
+ id: `${value}.withField`,
3210
+ defaultMessage: value
3211
+ },
3212
+ { field: currentKey }
3213
+ )
3214
+ );
2954
3215
  }
2955
3216
  });
2956
3217
  return messages;
2957
3218
  };
2958
- const EntryValidationText = ({
2959
- validationErrors,
2960
- isPublished = false
2961
- }) => {
3219
+ const EntryValidationText = ({ validationErrors, status }) => {
2962
3220
  const { formatMessage } = reactIntl.useIntl();
2963
3221
  if (validationErrors) {
2964
3222
  const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
@@ -2969,7 +3227,7 @@ const EntryValidationText = ({
2969
3227
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
2970
3228
  ] });
2971
3229
  }
2972
- if (isPublished) {
3230
+ if (status === "published") {
2973
3231
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2974
3232
  /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
2975
3233
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
@@ -2978,6 +3236,15 @@ const EntryValidationText = ({
2978
3236
  }) })
2979
3237
  ] });
2980
3238
  }
3239
+ if (status === "modified") {
3240
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3241
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3242
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3243
+ id: "content-manager.bulk-publish.modified",
3244
+ defaultMessage: "Ready to publish changes"
3245
+ }) })
3246
+ ] });
3247
+ }
2981
3248
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
2982
3249
  /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
2983
3250
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
@@ -3029,10 +3296,10 @@ const SelectedEntriesTableContent = ({
3029
3296
  EntryValidationText,
3030
3297
  {
3031
3298
  validationErrors: validationErrors[row.documentId],
3032
- isPublished: row.status === "published"
3299
+ status: row.status
3033
3300
  }
3034
3301
  ) }),
3035
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3302
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3036
3303
  designSystem.IconButton,
3037
3304
  {
3038
3305
  tag: reactRouterDom.Link,
@@ -3055,9 +3322,10 @@ const SelectedEntriesTableContent = ({
3055
3322
  ),
3056
3323
  target: "_blank",
3057
3324
  marginLeft: "auto",
3058
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3325
+ variant: "ghost",
3326
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3059
3327
  }
3060
- ) })
3328
+ ) }) })
3061
3329
  ] }, row.id)) })
3062
3330
  ] });
3063
3331
  };
@@ -3094,7 +3362,13 @@ const SelectedEntriesModalContent = ({
3094
3362
  );
3095
3363
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3096
3364
  if (data.length > 0 && schema) {
3097
- const validate = createYupSchema(schema.attributes, components);
3365
+ const validate = createYupSchema(
3366
+ schema.attributes,
3367
+ components,
3368
+ // Since this is the "Publish" action, the validation
3369
+ // schema must enforce the rules for published entities
3370
+ { status: "published" }
3371
+ );
3098
3372
  const validationErrors2 = {};
3099
3373
  const rows2 = data.map((entry) => {
3100
3374
  try {
@@ -3170,7 +3444,7 @@ const SelectedEntriesModalContent = ({
3170
3444
  );
3171
3445
  };
3172
3446
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3173
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalBody, { children: [
3447
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3174
3448
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3175
3449
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3176
3450
  SelectedEntriesTableContent,
@@ -3182,27 +3456,24 @@ const SelectedEntriesModalContent = ({
3182
3456
  }
3183
3457
  ) })
3184
3458
  ] }),
3185
- /* @__PURE__ */ jsxRuntime.jsx(
3186
- designSystem.ModalFooter,
3187
- {
3188
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3189
- id: "app.components.Button.cancel",
3190
- defaultMessage: "Cancel"
3191
- }) }),
3192
- endActions: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3193
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3194
- /* @__PURE__ */ jsxRuntime.jsx(
3195
- designSystem.Button,
3196
- {
3197
- onClick: toggleDialog,
3198
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3199
- loading: isSubmittingForm,
3200
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3201
- }
3202
- )
3203
- ] })
3204
- }
3205
- ),
3459
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3460
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3461
+ id: "app.components.Button.cancel",
3462
+ defaultMessage: "Cancel"
3463
+ }) }),
3464
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3465
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3466
+ /* @__PURE__ */ jsxRuntime.jsx(
3467
+ designSystem.Button,
3468
+ {
3469
+ onClick: toggleDialog,
3470
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3471
+ loading: isSubmittingForm,
3472
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3473
+ }
3474
+ )
3475
+ ] })
3476
+ ] }),
3206
3477
  /* @__PURE__ */ jsxRuntime.jsx(
3207
3478
  ConfirmDialogPublishAll,
3208
3479
  {
@@ -3267,143 +3538,10 @@ const BulkActionsRenderer = () => {
3267
3538
  documents: selectedRows
3268
3539
  },
3269
3540
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3270
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
3541
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3271
3542
  }
3272
3543
  ) });
3273
3544
  };
3274
- const BulkActionAction = (action) => {
3275
- const [dialogId, setDialogId] = React__namespace.useState(null);
3276
- const { toggleNotification } = strapiAdmin.useNotification();
3277
- const handleClick = (action2) => (e) => {
3278
- const { onClick, dialog, id } = action2;
3279
- if (onClick) {
3280
- onClick(e);
3281
- }
3282
- if (dialog) {
3283
- switch (dialog.type) {
3284
- case "notification":
3285
- toggleNotification({
3286
- title: dialog.title,
3287
- message: dialog.content,
3288
- type: dialog.status,
3289
- timeout: dialog.timeout,
3290
- onClose: dialog.onClose
3291
- });
3292
- break;
3293
- case "dialog":
3294
- case "modal": {
3295
- e.preventDefault();
3296
- setDialogId(id);
3297
- }
3298
- }
3299
- }
3300
- };
3301
- const handleClose = () => {
3302
- setDialogId(null);
3303
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3304
- action.dialog.onClose();
3305
- }
3306
- };
3307
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3308
- /* @__PURE__ */ jsxRuntime.jsx(
3309
- designSystem.Button,
3310
- {
3311
- disabled: action.disabled,
3312
- startIcon: action.icon,
3313
- variant: action.variant,
3314
- onClick: handleClick(action),
3315
- children: action.label
3316
- }
3317
- ),
3318
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
3319
- BulkActionConfirmDialog,
3320
- {
3321
- ...action.dialog,
3322
- variant: action.variant,
3323
- isOpen: dialogId === action.id,
3324
- onClose: handleClose
3325
- }
3326
- ) : null,
3327
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
3328
- BulkActionModal,
3329
- {
3330
- ...action.dialog,
3331
- onModalClose: handleClose,
3332
- isOpen: dialogId === action.id
3333
- }
3334
- ) : null
3335
- ] });
3336
- };
3337
- const BulkActionConfirmDialog = ({
3338
- onClose,
3339
- onCancel,
3340
- onConfirm,
3341
- title,
3342
- content,
3343
- confirmButton,
3344
- isOpen,
3345
- variant = "secondary"
3346
- }) => {
3347
- const { formatMessage } = reactIntl.useIntl();
3348
- const handleClose = async () => {
3349
- if (onCancel) {
3350
- await onCancel();
3351
- }
3352
- onClose();
3353
- };
3354
- const handleConfirm = async () => {
3355
- if (onConfirm) {
3356
- await onConfirm();
3357
- }
3358
- onClose();
3359
- };
3360
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
3361
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
3362
- /* @__PURE__ */ jsxRuntime.jsx(
3363
- designSystem.DialogFooter,
3364
- {
3365
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3366
- id: "app.components.Button.cancel",
3367
- defaultMessage: "Cancel"
3368
- }) }),
3369
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
3370
- designSystem.Button,
3371
- {
3372
- onClick: handleConfirm,
3373
- variant: variant === "danger-light" ? variant : "secondary",
3374
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3375
- children: confirmButton ? confirmButton : formatMessage({
3376
- id: "app.components.Button.confirm",
3377
- defaultMessage: "Confirm"
3378
- })
3379
- }
3380
- )
3381
- }
3382
- )
3383
- ] });
3384
- };
3385
- const BulkActionModal = ({
3386
- isOpen,
3387
- title,
3388
- onClose,
3389
- content: Content,
3390
- onModalClose
3391
- }) => {
3392
- const id = React__namespace.useId();
3393
- if (!isOpen) {
3394
- return null;
3395
- }
3396
- const handleClose = () => {
3397
- if (onClose) {
3398
- onClose();
3399
- }
3400
- onModalClose();
3401
- };
3402
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3403
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3404
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
3405
- ] });
3406
- };
3407
3545
  const DeleteAction = ({ documents, model }) => {
3408
3546
  const { formatMessage } = reactIntl.useIntl();
3409
3547
  const { schema: contentType } = useDoc();
@@ -3436,6 +3574,7 @@ const DeleteAction = ({ documents, model }) => {
3436
3574
  defaultMessage: "Confirmation"
3437
3575
  }),
3438
3576
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3577
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3439
3578
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3440
3579
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3441
3580
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3472,7 +3611,7 @@ const UnpublishAction = ({ documents, model }) => {
3472
3611
  selectRow([]);
3473
3612
  }
3474
3613
  };
3475
- const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
3614
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3476
3615
  if (!showUnpublishButton)
3477
3616
  return null;
3478
3617
  return {
@@ -3485,6 +3624,7 @@ const UnpublishAction = ({ documents, model }) => {
3485
3624
  defaultMessage: "Confirmation"
3486
3625
  }),
3487
3626
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3627
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3488
3628
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3489
3629
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3490
3630
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3578,7 +3718,7 @@ const TableActions = ({ document }) => {
3578
3718
  strapiAdmin.DescriptionComponentRenderer,
3579
3719
  {
3580
3720
  props,
3581
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3721
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3582
3722
  children: (actions2) => {
3583
3723
  const tableRowActions = actions2.filter((action) => {
3584
3724
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3689,7 +3829,7 @@ const CloneAction = ({ model, documentId }) => {
3689
3829
  }),
3690
3830
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3691
3831
  footer: ({ onClose }) => {
3692
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3832
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3693
3833
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3694
3834
  id: "cancel",
3695
3835
  defaultMessage: "Cancel"
@@ -3730,8 +3870,7 @@ class ContentManagerPlugin {
3730
3870
  documentActions = [
3731
3871
  ...DEFAULT_ACTIONS,
3732
3872
  ...DEFAULT_TABLE_ROW_ACTIONS,
3733
- ...DEFAULT_HEADER_ACTIONS,
3734
- HistoryAction
3873
+ ...DEFAULT_HEADER_ACTIONS
3735
3874
  ];
3736
3875
  editViewSidePanels = [ActionsPanel];
3737
3876
  headerActions = [];
@@ -3820,6 +3959,52 @@ const getPrintableType = (value) => {
3820
3959
  }
3821
3960
  return nativeType;
3822
3961
  };
3962
+ const HistoryAction = ({ model, document }) => {
3963
+ const { formatMessage } = reactIntl.useIntl();
3964
+ const [{ query }] = strapiAdmin.useQueryParams();
3965
+ const navigate = reactRouterDom.useNavigate();
3966
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3967
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3968
+ return null;
3969
+ }
3970
+ return {
3971
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3972
+ label: formatMessage({
3973
+ id: "content-manager.history.document-action",
3974
+ defaultMessage: "Content History"
3975
+ }),
3976
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3977
+ disabled: (
3978
+ /**
3979
+ * The user is creating a new document.
3980
+ * It hasn't been saved yet, so there's no history to go to
3981
+ */
3982
+ !document || /**
3983
+ * The document has been created but the current dimension has never been saved.
3984
+ * For example, the user is creating a new locale in an existing document,
3985
+ * so there's no history for the document in that locale
3986
+ */
3987
+ !document.id || /**
3988
+ * History is only available for content types created by the user.
3989
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3990
+ * which start with `admin::` or `plugin::`
3991
+ */
3992
+ !model.startsWith("api::")
3993
+ ),
3994
+ position: "header"
3995
+ };
3996
+ };
3997
+ HistoryAction.type = "history";
3998
+ const historyAdmin = {
3999
+ bootstrap(app) {
4000
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
4001
+ addDocumentAction((actions2) => {
4002
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
4003
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
4004
+ return actions2;
4005
+ });
4006
+ }
4007
+ };
3823
4008
  const initialState = {
3824
4009
  collectionTypeLinks: [],
3825
4010
  components: [],
@@ -3856,6 +4041,70 @@ const { setInitialData } = actions;
3856
4041
  const reducer = toolkit.combineReducers({
3857
4042
  app: reducer$1
3858
4043
  });
4044
+ const previewApi = contentManagerApi.injectEndpoints({
4045
+ endpoints: (builder) => ({
4046
+ getPreviewUrl: builder.query({
4047
+ query({ query, params }) {
4048
+ return {
4049
+ url: `/content-manager/preview/url/${params.contentType}`,
4050
+ method: "GET",
4051
+ config: {
4052
+ params: query
4053
+ }
4054
+ };
4055
+ }
4056
+ })
4057
+ })
4058
+ });
4059
+ const { useGetPreviewUrlQuery } = previewApi;
4060
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4061
+ const { formatMessage } = reactIntl.useIntl();
4062
+ const { trackUsage } = strapiAdmin.useTracking();
4063
+ const [{ query }] = strapiAdmin.useQueryParams();
4064
+ const { data, error } = useGetPreviewUrlQuery({
4065
+ params: {
4066
+ contentType: model
4067
+ },
4068
+ query: {
4069
+ documentId,
4070
+ locale: document?.locale,
4071
+ status: document?.status
4072
+ }
4073
+ });
4074
+ if (!data?.data?.url || error) {
4075
+ return null;
4076
+ }
4077
+ const handleClick = () => {
4078
+ trackUsage("willOpenPreview");
4079
+ };
4080
+ return {
4081
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4082
+ content: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
4083
+ designSystem.Button,
4084
+ {
4085
+ variant: "tertiary",
4086
+ tag: reactRouterDom.Link,
4087
+ to: { pathname: "preview", search: qs.stringify(query, { encode: false }) },
4088
+ onClick: handleClick,
4089
+ flex: "auto",
4090
+ children: formatMessage({
4091
+ id: "content-manager.preview.panel.button",
4092
+ defaultMessage: "Open preview"
4093
+ })
4094
+ }
4095
+ ) })
4096
+ };
4097
+ };
4098
+ const FEATURE_ID = "preview";
4099
+ const previewAdmin = {
4100
+ bootstrap(app) {
4101
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4102
+ return;
4103
+ }
4104
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4105
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4106
+ }
4107
+ };
3859
4108
  const index = {
3860
4109
  register(app) {
3861
4110
  const cm = new ContentManagerPlugin();
@@ -3870,15 +4119,32 @@ const index = {
3870
4119
  defaultMessage: "Content Manager"
3871
4120
  },
3872
4121
  permissions: [],
3873
- Component: () => Promise.resolve().then(() => require("./layout-b91XRlD2.js")).then((mod) => ({ default: mod.Layout })),
3874
4122
  position: 1
3875
4123
  });
4124
+ app.router.addRoute({
4125
+ path: "content-manager/*",
4126
+ lazy: async () => {
4127
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CkaP4K5_.js"));
4128
+ return {
4129
+ Component: Layout
4130
+ };
4131
+ },
4132
+ children: routes
4133
+ });
3876
4134
  app.registerPlugin(cm.config);
3877
4135
  },
4136
+ bootstrap(app) {
4137
+ if (typeof historyAdmin.bootstrap === "function") {
4138
+ historyAdmin.bootstrap(app);
4139
+ }
4140
+ if (typeof previewAdmin.bootstrap === "function") {
4141
+ previewAdmin.bootstrap(app);
4142
+ }
4143
+ },
3878
4144
  async registerTrads({ locales }) {
3879
4145
  const importedTrads = await Promise.all(
3880
4146
  locales.map((locale) => {
3881
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BN1bvFK7.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
4147
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-CHOp_xJv.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-9K52xZIr.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B2Kyv8Z9.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-7sfIbjxE.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3882
4148
  return {
3883
4149
  data: prefixPluginTranslations(data, PLUGIN_ID),
3884
4150
  locale
@@ -3896,6 +4162,7 @@ const index = {
3896
4162
  };
3897
4163
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3898
4164
  exports.BulkActionsRenderer = BulkActionsRenderer;
4165
+ exports.CLONE_PATH = CLONE_PATH;
3899
4166
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3900
4167
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3901
4168
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3922,8 +4189,8 @@ exports.getDisplayName = getDisplayName;
3922
4189
  exports.getMainField = getMainField;
3923
4190
  exports.getTranslation = getTranslation;
3924
4191
  exports.index = index;
3925
- exports.routes = routes;
3926
4192
  exports.setInitialData = setInitialData;
4193
+ exports.useContentManagerContext = useContentManagerContext;
3927
4194
  exports.useContentTypeSchema = useContentTypeSchema;
3928
4195
  exports.useDoc = useDoc;
3929
4196
  exports.useDocLayout = useDocLayout;
@@ -3935,5 +4202,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
3935
4202
  exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3936
4203
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3937
4204
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
4205
+ exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
3938
4206
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3939
- //# sourceMappingURL=index-DzN3kBgx.js.map
4207
+ //# sourceMappingURL=index-iun2i4xv.js.map