@strapi/content-manager 0.0.0-experimental.145e7d7ddefd1aef71aaf3d9bb86440d013035bf → 0.0.0-experimental.146a31b564bc8232686331f6b28f7ff966817963

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 (196) hide show
  1. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  2. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-D_g11bYV.js → ComponentConfigurationPage-BSEZcJVB.js} +5 -6
  4. package/dist/_chunks/{ComponentConfigurationPage-D_g11bYV.js.map → ComponentConfigurationPage-BSEZcJVB.js.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-DJEJ49QD.mjs → ComponentConfigurationPage-BiASGi7x.mjs} +4 -4
  6. package/dist/_chunks/{ComponentConfigurationPage-DJEJ49QD.mjs.map → ComponentConfigurationPage-BiASGi7x.mjs.map} +1 -1
  7. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  9. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  10. package/dist/_chunks/{EditConfigurationPage-CeL712KW.js → EditConfigurationPage-D2rtvneE.js} +5 -6
  11. package/dist/_chunks/{EditConfigurationPage-CeL712KW.js.map → EditConfigurationPage-D2rtvneE.js.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-QBZdUYyG.mjs → EditConfigurationPage-vN4zupij.mjs} +4 -4
  13. package/dist/_chunks/{EditConfigurationPage-QBZdUYyG.mjs.map → EditConfigurationPage-vN4zupij.mjs.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-g5TwrgRY.js → EditViewPage-BwisF04Q.js} +50 -11
  15. package/dist/_chunks/EditViewPage-BwisF04Q.js.map +1 -0
  16. package/dist/_chunks/{EditViewPage-CvRUUpVh.mjs → EditViewPage-_A31Cl4g.mjs} +50 -10
  17. package/dist/_chunks/EditViewPage-_A31Cl4g.mjs.map +1 -0
  18. package/dist/_chunks/{Field-reyvfnop.mjs → Field-CvIunNOj.mjs} +238 -152
  19. package/dist/_chunks/Field-CvIunNOj.mjs.map +1 -0
  20. package/dist/_chunks/{Field-ncdInvxS.js → Field-Dsu6-FrM.js} +244 -158
  21. package/dist/_chunks/Field-Dsu6-FrM.js.map +1 -0
  22. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  23. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  24. package/dist/_chunks/{Form-DoMGsYxH.mjs → Form-DK0fG0Gj.mjs} +15 -9
  25. package/dist/_chunks/Form-DK0fG0Gj.mjs.map +1 -0
  26. package/dist/_chunks/{Form-BJ7bYiUx.js → Form-DUwWcCmA.js} +17 -12
  27. package/dist/_chunks/Form-DUwWcCmA.js.map +1 -0
  28. package/dist/_chunks/{History-pbhkxIrf.js → History-CeCDhoJG.js} +42 -100
  29. package/dist/_chunks/History-CeCDhoJG.js.map +1 -0
  30. package/dist/_chunks/{History-BseDJOrj.mjs → History-DP8gmXpm.mjs} +43 -100
  31. package/dist/_chunks/History-DP8gmXpm.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-DWE_fr5B.mjs → ListConfigurationPage-BCkO5iuN.mjs} +7 -6
  33. package/dist/_chunks/ListConfigurationPage-BCkO5iuN.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-Bna8zfjr.js → ListConfigurationPage-C-bAd44a.js} +7 -7
  35. package/dist/_chunks/ListConfigurationPage-C-bAd44a.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-Dymsvnv6.js → ListViewPage-BKTZFhsM.js} +88 -54
  37. package/dist/_chunks/ListViewPage-BKTZFhsM.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-lQ-VLV2G.mjs → ListViewPage-Cf_DgaFV.mjs} +83 -48
  39. package/dist/_chunks/ListViewPage-Cf_DgaFV.mjs.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-B4t_OsDR.js → NoContentTypePage-D3Cm3v3q.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-B4t_OsDR.js.map → NoContentTypePage-D3Cm3v3q.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-VCQOMwlf.mjs → NoContentTypePage-nHIyvJcB.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-VCQOMwlf.mjs.map → NoContentTypePage-nHIyvJcB.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-TV830k4P.mjs → NoPermissionsPage-BALVSJ7x.mjs} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-TV830k4P.mjs.map → NoPermissionsPage-BALVSJ7x.mjs.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-BOwB6hki.js → NoPermissionsPage-CChGWBj5.js} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-BOwB6hki.js.map → NoPermissionsPage-CChGWBj5.js.map} +1 -1
  48. package/dist/_chunks/Preview-C4NBzKUV.mjs +294 -0
  49. package/dist/_chunks/Preview-C4NBzKUV.mjs.map +1 -0
  50. package/dist/_chunks/Preview-CT28Ckpg.js +312 -0
  51. package/dist/_chunks/Preview-CT28Ckpg.js.map +1 -0
  52. package/dist/_chunks/{Relations-D6NAlnsl.mjs → Relations-C8uC89cT.mjs} +75 -41
  53. package/dist/_chunks/Relations-C8uC89cT.mjs.map +1 -0
  54. package/dist/_chunks/{Relations-DdlstXTu.js → Relations-CvkPCng_.js} +75 -42
  55. package/dist/_chunks/Relations-CvkPCng_.js.map +1 -0
  56. package/dist/_chunks/{en-Cf41pH5f.js → en-BK8Xyl5I.js} +24 -12
  57. package/dist/_chunks/{en-Cf41pH5f.js.map → en-BK8Xyl5I.js.map} +1 -1
  58. package/dist/_chunks/{en-DCszE74t.mjs → en-Dtk_ot79.mjs} +24 -12
  59. package/dist/_chunks/{en-DCszE74t.mjs.map → en-Dtk_ot79.mjs.map} +1 -1
  60. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  61. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  62. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  63. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  64. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  65. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  66. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  67. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  68. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  69. package/dist/_chunks/{index-CQos-KS0.js → index-CnX_j5h-.js} +1239 -942
  70. package/dist/_chunks/index-CnX_j5h-.js.map +1 -0
  71. package/dist/_chunks/{index-BYSWwHBJ.mjs → index-Dh2aGTGJ.mjs} +1241 -944
  72. package/dist/_chunks/index-Dh2aGTGJ.mjs.map +1 -0
  73. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  74. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  75. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  76. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  77. package/dist/_chunks/{layout-0TY7UtKO.mjs → layout-B5qsPihj.mjs} +6 -5
  78. package/dist/_chunks/{layout-0TY7UtKO.mjs.map → layout-B5qsPihj.mjs.map} +1 -1
  79. package/dist/_chunks/{layout-B4XAqu1v.js → layout-B_qdWGny.js} +7 -7
  80. package/dist/_chunks/{layout-B4XAqu1v.js.map → layout-B_qdWGny.js.map} +1 -1
  81. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  82. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  83. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  84. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  85. package/dist/_chunks/{relations-xZ2tMj1G.js → relations-ChcieiF5.js} +6 -7
  86. package/dist/_chunks/relations-ChcieiF5.js.map +1 -0
  87. package/dist/_chunks/{relations-DFDWfa0s.mjs → relations-DMXpNY-e.mjs} +6 -7
  88. package/dist/_chunks/relations-DMXpNY-e.mjs.map +1 -0
  89. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  90. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  91. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  92. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  93. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  94. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  95. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  96. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  97. package/dist/admin/index.js +2 -1
  98. package/dist/admin/index.js.map +1 -1
  99. package/dist/admin/index.mjs +4 -3
  100. package/dist/admin/src/content-manager.d.ts +3 -2
  101. package/dist/admin/src/exports.d.ts +1 -1
  102. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  103. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  104. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  105. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
  106. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  107. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  108. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  109. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  110. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  111. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  112. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  113. package/dist/admin/src/preview/index.d.ts +4 -0
  114. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  115. package/dist/admin/src/preview/routes.d.ts +3 -0
  116. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  117. package/dist/admin/src/router.d.ts +1 -1
  118. package/dist/admin/src/services/documents.d.ts +0 -3
  119. package/dist/server/index.js +513 -260
  120. package/dist/server/index.js.map +1 -1
  121. package/dist/server/index.mjs +514 -260
  122. package/dist/server/index.mjs.map +1 -1
  123. package/dist/server/src/bootstrap.d.ts.map +1 -1
  124. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  125. package/dist/server/src/controllers/index.d.ts.map +1 -1
  126. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  127. package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
  128. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  129. package/dist/server/src/history/services/history.d.ts.map +1 -1
  130. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  131. package/dist/server/src/history/services/utils.d.ts +2 -3
  132. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  133. package/dist/server/src/index.d.ts +7 -6
  134. package/dist/server/src/index.d.ts.map +1 -1
  135. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  136. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  137. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  138. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  139. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  140. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  141. package/dist/server/src/preview/index.d.ts +4 -0
  142. package/dist/server/src/preview/index.d.ts.map +1 -0
  143. package/dist/server/src/preview/routes/index.d.ts +8 -0
  144. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  145. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  146. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  147. package/dist/server/src/preview/services/index.d.ts +16 -0
  148. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  149. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  150. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  151. package/dist/server/src/preview/services/preview.d.ts +12 -0
  152. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  153. package/dist/server/src/preview/utils.d.ts +19 -0
  154. package/dist/server/src/preview/utils.d.ts.map +1 -0
  155. package/dist/server/src/register.d.ts.map +1 -1
  156. package/dist/server/src/routes/index.d.ts.map +1 -1
  157. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  158. package/dist/server/src/services/document-metadata.d.ts +12 -10
  159. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  160. package/dist/server/src/services/index.d.ts +7 -6
  161. package/dist/server/src/services/index.d.ts.map +1 -1
  162. package/dist/server/src/services/utils/populate.d.ts +2 -2
  163. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  164. package/dist/server/src/utils/index.d.ts +2 -0
  165. package/dist/server/src/utils/index.d.ts.map +1 -1
  166. package/dist/shared/contracts/index.d.ts +1 -0
  167. package/dist/shared/contracts/index.d.ts.map +1 -1
  168. package/dist/shared/contracts/preview.d.ts +27 -0
  169. package/dist/shared/contracts/preview.d.ts.map +1 -0
  170. package/dist/shared/index.js +4 -0
  171. package/dist/shared/index.js.map +1 -1
  172. package/dist/shared/index.mjs +4 -0
  173. package/dist/shared/index.mjs.map +1 -1
  174. package/package.json +17 -15
  175. package/dist/_chunks/EditViewPage-CvRUUpVh.mjs.map +0 -1
  176. package/dist/_chunks/EditViewPage-g5TwrgRY.js.map +0 -1
  177. package/dist/_chunks/Field-ncdInvxS.js.map +0 -1
  178. package/dist/_chunks/Field-reyvfnop.mjs.map +0 -1
  179. package/dist/_chunks/Form-BJ7bYiUx.js.map +0 -1
  180. package/dist/_chunks/Form-DoMGsYxH.mjs.map +0 -1
  181. package/dist/_chunks/History-BseDJOrj.mjs.map +0 -1
  182. package/dist/_chunks/History-pbhkxIrf.js.map +0 -1
  183. package/dist/_chunks/ListConfigurationPage-Bna8zfjr.js.map +0 -1
  184. package/dist/_chunks/ListConfigurationPage-DWE_fr5B.mjs.map +0 -1
  185. package/dist/_chunks/ListViewPage-Dymsvnv6.js.map +0 -1
  186. package/dist/_chunks/ListViewPage-lQ-VLV2G.mjs.map +0 -1
  187. package/dist/_chunks/Relations-D6NAlnsl.mjs.map +0 -1
  188. package/dist/_chunks/Relations-DdlstXTu.js.map +0 -1
  189. package/dist/_chunks/index-BYSWwHBJ.mjs.map +0 -1
  190. package/dist/_chunks/index-CQos-KS0.js.map +0 -1
  191. package/dist/_chunks/relations-DFDWfa0s.mjs.map +0 -1
  192. package/dist/_chunks/relations-xZ2tMj1G.js.map +0 -1
  193. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  194. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  195. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  196. package/strapi-server.js +0 -3
@@ -4,18 +4,18 @@ const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
5
  const React = require("react");
6
6
  const designSystem = require("@strapi/design-system");
7
+ const mapValues = require("lodash/fp/mapValues");
7
8
  const reactIntl = require("react-intl");
8
9
  const reactRouterDom = require("react-router-dom");
10
+ const styledComponents = require("styled-components");
9
11
  const yup = require("yup");
12
+ const qs = require("qs");
10
13
  const pipe = require("lodash/fp/pipe");
11
14
  const dateFns = require("date-fns");
12
- const styledComponents = require("styled-components");
13
- 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) {
17
- if (e && e.__esModule)
18
- return e;
18
+ if (e && e.__esModule) return e;
19
19
  const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
20
20
  if (e) {
21
21
  for (const k in e) {
@@ -32,15 +32,23 @@ function _interopNamespace(e) {
32
32
  return Object.freeze(n);
33
33
  }
34
34
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
35
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
36
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
37
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
38
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
38
39
  const v = glob[path];
39
40
  if (v) {
40
41
  return typeof v === "function" ? v() : Promise.resolve(v);
41
42
  }
42
43
  return new Promise((_, reject) => {
43
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
44
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
45
+ reject.bind(
46
+ null,
47
+ new Error(
48
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
49
+ )
50
+ )
51
+ );
44
52
  });
45
53
  };
46
54
  const PLUGIN_ID = "content-manager";
@@ -121,6 +129,7 @@ const DocumentRBAC = ({ children, permissions }) => {
121
129
  if (!slug) {
122
130
  throw new Error("Cannot find the slug param in the URL");
123
131
  }
132
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
124
133
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
125
134
  const contentTypePermissions = React__namespace.useMemo(() => {
126
135
  const contentTypePermissions2 = userPermissions.filter(
@@ -131,7 +140,14 @@ const DocumentRBAC = ({ children, permissions }) => {
131
140
  return { ...acc, [action]: [permission] };
132
141
  }, {});
133
142
  }, [slug, userPermissions]);
134
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
143
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
144
+ contentTypePermissions,
145
+ permissions ?? void 0,
146
+ // TODO: useRBAC context should be typed and built differently
147
+ // We are passing raw query as context to the hook so that it can
148
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
149
+ rawQuery
150
+ );
135
151
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
136
152
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
137
153
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -232,7 +248,19 @@ const documentApi = contentManagerApi.injectEndpoints({
232
248
  { type: "Document", id: `${model}_LIST` },
233
249
  "Relations",
234
250
  { type: "UidAvailability", id: model }
235
- ]
251
+ ],
252
+ transformResponse: (response, meta, arg) => {
253
+ if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
254
+ return {
255
+ data: response,
256
+ meta: {
257
+ availableStatus: [],
258
+ availableLocales: []
259
+ }
260
+ };
261
+ }
262
+ return response;
263
+ }
236
264
  }),
237
265
  deleteDocument: builder.mutation({
238
266
  query: ({ collectionType, model, documentId, params }) => ({
@@ -286,7 +314,7 @@ const documentApi = contentManagerApi.injectEndpoints({
286
314
  url: `/content-manager/collection-types/${model}`,
287
315
  method: "GET",
288
316
  config: {
289
- params
317
+ params: qs.stringify(params, { encode: true })
290
318
  }
291
319
  }),
292
320
  providesTags: (result, _error, arg) => {
@@ -465,8 +493,7 @@ const {
465
493
  useUnpublishManyDocumentsMutation
466
494
  } = documentApi;
467
495
  const buildValidParams = (query) => {
468
- if (!query)
469
- return query;
496
+ if (!query) return query;
470
497
  const { plugins: _, ...validQueryParams } = {
471
498
  ...query,
472
499
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -474,14 +501,29 @@ const buildValidParams = (query) => {
474
501
  {}
475
502
  )
476
503
  };
477
- if ("_q" in validQueryParams) {
478
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
479
- }
480
504
  return validQueryParams;
481
505
  };
482
506
  const isBaseQueryError = (error) => {
483
507
  return error.name !== void 0;
484
508
  };
509
+ const arrayValidator = (attribute, options) => ({
510
+ message: strapiAdmin.translatedErrors.required,
511
+ test(value) {
512
+ if (options.status === "draft") {
513
+ return true;
514
+ }
515
+ if (!attribute.required) {
516
+ return true;
517
+ }
518
+ if (!value) {
519
+ return false;
520
+ }
521
+ if (Array.isArray(value) && value.length === 0) {
522
+ return false;
523
+ }
524
+ return true;
525
+ }
526
+ });
485
527
  const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
486
528
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
487
529
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -489,6 +531,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
489
531
  return acc;
490
532
  }
491
533
  const validations = [
534
+ addNullableValidation,
492
535
  addRequiredValidation,
493
536
  addMinLengthValidation,
494
537
  addMaxLengthValidation,
@@ -505,12 +548,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
505
548
  ...acc,
506
549
  [name]: transformSchema(
507
550
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
508
- )
551
+ ).test(arrayValidator(attribute, options))
509
552
  };
510
553
  } else {
511
554
  return {
512
555
  ...acc,
513
- [name]: transformSchema(createModelSchema(attributes3))
556
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
514
557
  };
515
558
  }
516
559
  }
@@ -532,7 +575,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
532
575
  }
533
576
  )
534
577
  )
535
- )
578
+ ).test(arrayValidator(attribute, options))
536
579
  };
537
580
  case "relation":
538
581
  return {
@@ -544,7 +587,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
544
587
  } else if (Array.isArray(value)) {
545
588
  return yup__namespace.array().of(
546
589
  yup__namespace.object().shape({
547
- id: yup__namespace.string().required()
590
+ id: yup__namespace.number().required()
548
591
  })
549
592
  );
550
593
  } else if (typeof value === "object") {
@@ -630,17 +673,17 @@ const nullableSchema = (schema) => {
630
673
  schema
631
674
  );
632
675
  };
676
+ const addNullableValidation = () => (schema) => {
677
+ return nullableSchema(schema);
678
+ };
633
679
  const addRequiredValidation = (attribute, options) => (schema) => {
634
- if (options.status === "draft") {
635
- return nullableSchema(schema);
636
- }
637
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
638
- return schema.min(1, strapiAdmin.translatedErrors.required);
680
+ if (options.status === "draft" || !attribute.required) {
681
+ return schema;
639
682
  }
640
- if (attribute.required && attribute.type !== "relation") {
683
+ if (attribute.required && "required" in schema) {
641
684
  return schema.required(strapiAdmin.translatedErrors.required);
642
685
  }
643
- return nullableSchema(schema);
686
+ return schema;
644
687
  };
645
688
  const addMinLengthValidation = (attribute, options) => (schema) => {
646
689
  if (options.status === "draft") {
@@ -668,31 +711,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
668
711
  return schema;
669
712
  };
670
713
  const addMinValidation = (attribute, options) => (schema) => {
671
- if ("min" in attribute) {
714
+ if (options.status === "draft") {
715
+ return schema;
716
+ }
717
+ if ("min" in attribute && "min" in schema) {
672
718
  const min = toInteger(attribute.min);
673
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
- if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
- return schema.test(
676
- "custom-min",
677
- {
678
- ...strapiAdmin.translatedErrors.min,
679
- values: {
680
- min: attribute.min
681
- }
682
- },
683
- (value) => {
684
- if (!value) {
685
- return true;
686
- }
687
- if (Array.isArray(value) && value.length === 0) {
688
- return true;
689
- }
690
- return value.length >= min;
691
- }
692
- );
693
- }
694
- }
695
- if ("min" in schema && min) {
719
+ if (min) {
696
720
  return schema.min(min, {
697
721
  ...strapiAdmin.translatedErrors.min,
698
722
  values: {
@@ -810,19 +834,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
810
834
  }, {});
811
835
  return componentsByKey;
812
836
  };
813
- const useDocument = (args, opts) => {
837
+ const HOOKS = {
838
+ /**
839
+ * Hook that allows to mutate the displayed headers of the list view table
840
+ * @constant
841
+ * @type {string}
842
+ */
843
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
844
+ /**
845
+ * Hook that allows to mutate the CM's collection types links pre-set filters
846
+ * @constant
847
+ * @type {string}
848
+ */
849
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
850
+ /**
851
+ * Hook that allows to mutate the CM's edit view layout
852
+ * @constant
853
+ * @type {string}
854
+ */
855
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
856
+ /**
857
+ * Hook that allows to mutate the CM's single types links pre-set filters
858
+ * @constant
859
+ * @type {string}
860
+ */
861
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
862
+ };
863
+ const contentTypesApi = contentManagerApi.injectEndpoints({
864
+ endpoints: (builder) => ({
865
+ getContentTypeConfiguration: builder.query({
866
+ query: (uid) => ({
867
+ url: `/content-manager/content-types/${uid}/configuration`,
868
+ method: "GET"
869
+ }),
870
+ transformResponse: (response) => response.data,
871
+ providesTags: (_result, _error, uid) => [
872
+ { type: "ContentTypesConfiguration", id: uid },
873
+ { type: "ContentTypeSettings", id: "LIST" }
874
+ ]
875
+ }),
876
+ getAllContentTypeSettings: builder.query({
877
+ query: () => "/content-manager/content-types-settings",
878
+ transformResponse: (response) => response.data,
879
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
880
+ }),
881
+ updateContentTypeConfiguration: builder.mutation({
882
+ query: ({ uid, ...body }) => ({
883
+ url: `/content-manager/content-types/${uid}/configuration`,
884
+ method: "PUT",
885
+ data: body
886
+ }),
887
+ transformResponse: (response) => response.data,
888
+ invalidatesTags: (_result, _error, { uid }) => [
889
+ { type: "ContentTypesConfiguration", id: uid },
890
+ { type: "ContentTypeSettings", id: "LIST" },
891
+ // Is this necessary?
892
+ { type: "InitialData" }
893
+ ]
894
+ })
895
+ })
896
+ });
897
+ const {
898
+ useGetContentTypeConfigurationQuery,
899
+ useGetAllContentTypeSettingsQuery,
900
+ useUpdateContentTypeConfigurationMutation
901
+ } = contentTypesApi;
902
+ const checkIfAttributeIsDisplayable = (attribute) => {
903
+ const { type } = attribute;
904
+ if (type === "relation") {
905
+ return !attribute.relation.toLowerCase().includes("morph");
906
+ }
907
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
908
+ };
909
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
910
+ if (!mainFieldName) {
911
+ return void 0;
912
+ }
913
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
914
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
915
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
916
+ );
917
+ return {
918
+ name: mainFieldName,
919
+ type: mainFieldType ?? "string"
920
+ };
921
+ };
922
+ const DEFAULT_SETTINGS = {
923
+ bulkable: false,
924
+ filterable: false,
925
+ searchable: false,
926
+ pagination: false,
927
+ defaultSortBy: "",
928
+ defaultSortOrder: "asc",
929
+ mainField: "id",
930
+ pageSize: 10
931
+ };
932
+ const useDocumentLayout = (model) => {
933
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
934
+ const [{ query }] = strapiAdmin.useQueryParams();
935
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
814
936
  const { toggleNotification } = strapiAdmin.useNotification();
815
937
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
938
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
816
939
  const {
817
- currentData: data,
818
- isLoading: isLoadingDocument,
819
- isFetching: isFetchingDocument,
820
- error
821
- } = useGetDocumentQuery(args, {
822
- ...opts,
823
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
824
- });
825
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
940
+ data,
941
+ isLoading: isLoadingConfigs,
942
+ error,
943
+ isFetching: isFetchingConfigs
944
+ } = useGetContentTypeConfigurationQuery(model);
945
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
826
946
  React__namespace.useEffect(() => {
827
947
  if (error) {
828
948
  toggleNotification({
@@ -830,363 +950,438 @@ const useDocument = (args, opts) => {
830
950
  message: formatAPIError(error)
831
951
  });
832
952
  }
833
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
834
- const validationSchema = React__namespace.useMemo(() => {
835
- if (!schema) {
836
- return null;
837
- }
838
- return createYupSchema(schema.attributes, components);
839
- }, [schema, components]);
840
- const validate = React__namespace.useCallback(
841
- (document) => {
842
- if (!validationSchema) {
843
- throw new Error(
844
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
845
- );
846
- }
847
- try {
848
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
849
- return null;
850
- } catch (error2) {
851
- if (error2 instanceof yup.ValidationError) {
852
- return strapiAdmin.getYupValidationErrors(error2);
853
- }
854
- throw error2;
855
- }
953
+ }, [error, formatAPIError, toggleNotification]);
954
+ const editLayout = React__namespace.useMemo(
955
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
956
+ layout: [],
957
+ components: {},
958
+ metadatas: {},
959
+ options: {},
960
+ settings: DEFAULT_SETTINGS
856
961
  },
857
- [validationSchema]
962
+ [data, isLoading, schemas, schema, components]
963
+ );
964
+ const listLayout = React__namespace.useMemo(() => {
965
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
966
+ layout: [],
967
+ metadatas: {},
968
+ options: {},
969
+ settings: DEFAULT_SETTINGS
970
+ };
971
+ }, [data, isLoading, schemas, schema, components]);
972
+ const { layout: edit } = React__namespace.useMemo(
973
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
974
+ layout: editLayout,
975
+ query
976
+ }),
977
+ [editLayout, query, runHookWaterfall]
858
978
  );
859
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
860
979
  return {
861
- components,
862
- document: data?.data,
863
- meta: data?.meta,
980
+ error,
864
981
  isLoading,
865
- schema,
866
- validate
867
- };
868
- };
869
- const useDoc = () => {
870
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
871
- const [{ query }] = strapiAdmin.useQueryParams();
872
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
873
- if (!collectionType) {
874
- throw new Error("Could not find collectionType in url params");
875
- }
876
- if (!slug) {
877
- throw new Error("Could not find model in url params");
878
- }
879
- return {
880
- collectionType,
881
- model: slug,
882
- id: origin || id === "create" ? void 0 : id,
883
- ...useDocument(
884
- { documentId: origin || id, model: slug, collectionType, params },
885
- {
886
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
887
- }
888
- )
982
+ edit,
983
+ list: listLayout
889
984
  };
890
985
  };
891
- const prefixPluginTranslations = (trad, pluginId) => {
892
- if (!pluginId) {
893
- throw new TypeError("pluginId can't be empty");
894
- }
895
- return Object.keys(trad).reduce((acc, current) => {
896
- acc[`${pluginId}.${current}`] = trad[current];
897
- return acc;
898
- }, {});
899
- };
900
- const getTranslation = (id) => `content-manager.${id}`;
901
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
902
- id: "notification.error",
903
- defaultMessage: "An error occurred, please try again"
986
+ const useDocLayout = () => {
987
+ const { model } = useDoc();
988
+ return useDocumentLayout(model);
904
989
  };
905
- const useDocumentActions = () => {
906
- const { toggleNotification } = strapiAdmin.useNotification();
907
- const { formatMessage } = reactIntl.useIntl();
908
- const { trackUsage } = strapiAdmin.useTracking();
909
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
910
- const navigate = reactRouterDom.useNavigate();
911
- const [deleteDocument] = useDeleteDocumentMutation();
912
- const _delete = React__namespace.useCallback(
913
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
914
- try {
915
- trackUsage("willDeleteEntry", trackerProperty);
916
- const res = await deleteDocument({
917
- collectionType,
918
- model,
919
- documentId,
920
- params
921
- });
922
- if ("error" in res) {
923
- toggleNotification({
924
- type: "danger",
925
- message: formatAPIError(res.error)
926
- });
927
- return { error: res.error };
928
- }
929
- toggleNotification({
930
- type: "success",
931
- message: formatMessage({
932
- id: getTranslation("success.record.delete"),
933
- defaultMessage: "Deleted document"
934
- })
935
- });
936
- trackUsage("didDeleteEntry", trackerProperty);
937
- return res.data;
938
- } catch (err) {
939
- toggleNotification({
940
- type: "danger",
941
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
942
- });
943
- trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
944
- throw err;
990
+ const formatEditLayout = (data, {
991
+ schemas,
992
+ schema,
993
+ components
994
+ }) => {
995
+ let currentPanelIndex = 0;
996
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
997
+ data.contentType.layouts.edit,
998
+ schema?.attributes,
999
+ data.contentType.metadatas,
1000
+ { configurations: data.components, schemas: components },
1001
+ schemas
1002
+ ).reduce((panels, row) => {
1003
+ if (row.some((field) => field.type === "dynamiczone")) {
1004
+ panels.push([row]);
1005
+ currentPanelIndex += 2;
1006
+ } else {
1007
+ if (!panels[currentPanelIndex]) {
1008
+ panels.push([row]);
1009
+ } else {
1010
+ panels[currentPanelIndex].push(row);
945
1011
  }
946
- },
947
- [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
948
- );
949
- const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
950
- const deleteMany = React__namespace.useCallback(
951
- async ({ model, documentIds, params }) => {
952
- try {
953
- trackUsage("willBulkDeleteEntries");
954
- const res = await deleteManyDocuments({
955
- model,
956
- documentIds,
957
- params
958
- });
959
- if ("error" in res) {
960
- toggleNotification({
961
- type: "danger",
962
- message: formatAPIError(res.error)
963
- });
964
- return { error: res.error };
1012
+ }
1013
+ return panels;
1014
+ }, []);
1015
+ const componentEditAttributes = Object.entries(data.components).reduce(
1016
+ (acc, [uid, configuration]) => {
1017
+ acc[uid] = {
1018
+ layout: convertEditLayoutToFieldLayouts(
1019
+ configuration.layouts.edit,
1020
+ components[uid].attributes,
1021
+ configuration.metadatas,
1022
+ { configurations: data.components, schemas: components }
1023
+ ),
1024
+ settings: {
1025
+ ...configuration.settings,
1026
+ icon: components[uid].info.icon,
1027
+ displayName: components[uid].info.displayName
965
1028
  }
966
- toggleNotification({
967
- type: "success",
968
- title: formatMessage({
969
- id: getTranslation("success.records.delete"),
970
- defaultMessage: "Successfully deleted."
971
- }),
972
- message: ""
973
- });
974
- trackUsage("didBulkDeleteEntries");
975
- return res.data;
976
- } catch (err) {
977
- toggleNotification({
978
- type: "danger",
979
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
980
- });
981
- trackUsage("didNotBulkDeleteEntries");
982
- throw err;
983
- }
1029
+ };
1030
+ return acc;
984
1031
  },
985
- [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1032
+ {}
986
1033
  );
987
- const [discardDocument] = useDiscardDocumentMutation();
988
- const discard = React__namespace.useCallback(
989
- async ({ collectionType, model, documentId, params }) => {
990
- try {
991
- const res = await discardDocument({
992
- collectionType,
993
- model,
994
- documentId,
995
- params
996
- });
997
- if ("error" in res) {
998
- toggleNotification({
999
- type: "danger",
1000
- message: formatAPIError(res.error)
1001
- });
1002
- return { error: res.error };
1003
- }
1004
- toggleNotification({
1005
- type: "success",
1006
- message: formatMessage({
1007
- id: "content-manager.success.record.discard",
1008
- defaultMessage: "Changes discarded"
1009
- })
1010
- });
1011
- return res.data;
1012
- } catch (err) {
1013
- toggleNotification({
1014
- type: "danger",
1015
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1016
- });
1017
- throw err;
1018
- }
1034
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1035
+ (acc, [attribute, metadata]) => {
1036
+ return {
1037
+ ...acc,
1038
+ [attribute]: metadata.edit
1039
+ };
1019
1040
  },
1020
- [discardDocument, formatAPIError, formatMessage, toggleNotification]
1041
+ {}
1021
1042
  );
1022
- const [publishDocument] = usePublishDocumentMutation();
1023
- const publish = React__namespace.useCallback(
1024
- async ({ collectionType, model, documentId, params }, data) => {
1025
- try {
1026
- trackUsage("willPublishEntry");
1027
- const res = await publishDocument({
1028
- collectionType,
1029
- model,
1030
- documentId,
1031
- data,
1032
- params
1033
- });
1034
- if ("error" in res) {
1035
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1036
- return { error: res.error };
1037
- }
1038
- trackUsage("didPublishEntry");
1039
- toggleNotification({
1040
- type: "success",
1041
- message: formatMessage({
1042
- id: getTranslation("success.record.publish"),
1043
- defaultMessage: "Published document"
1044
- })
1045
- });
1046
- return res.data;
1047
- } catch (err) {
1048
- toggleNotification({
1049
- type: "danger",
1050
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1051
- });
1052
- throw err;
1043
+ return {
1044
+ layout: panelledEditAttributes,
1045
+ components: componentEditAttributes,
1046
+ metadatas: editMetadatas,
1047
+ settings: {
1048
+ ...data.contentType.settings,
1049
+ displayName: schema?.info.displayName
1050
+ },
1051
+ options: {
1052
+ ...schema?.options,
1053
+ ...schema?.pluginOptions,
1054
+ ...data.contentType.options
1055
+ }
1056
+ };
1057
+ };
1058
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1059
+ return rows.map(
1060
+ (row) => row.map((field) => {
1061
+ const attribute = attributes[field.name];
1062
+ if (!attribute) {
1063
+ return null;
1053
1064
  }
1065
+ const { edit: metadata } = metadatas[field.name];
1066
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1067
+ return {
1068
+ attribute,
1069
+ disabled: !metadata.editable,
1070
+ hint: metadata.description,
1071
+ label: metadata.label ?? "",
1072
+ name: field.name,
1073
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1074
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1075
+ schemas,
1076
+ components: components?.schemas ?? {}
1077
+ }),
1078
+ placeholder: metadata.placeholder ?? "",
1079
+ required: attribute.required ?? false,
1080
+ size: field.size,
1081
+ unique: "unique" in attribute ? attribute.unique : false,
1082
+ visible: metadata.visible ?? true,
1083
+ type: attribute.type
1084
+ };
1085
+ }).filter((field) => field !== null)
1086
+ );
1087
+ };
1088
+ const formatListLayout = (data, {
1089
+ schemas,
1090
+ schema,
1091
+ components
1092
+ }) => {
1093
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1094
+ (acc, [attribute, metadata]) => {
1095
+ return {
1096
+ ...acc,
1097
+ [attribute]: metadata.list
1098
+ };
1054
1099
  },
1055
- [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1100
+ {}
1056
1101
  );
1057
- const [publishManyDocuments] = usePublishManyDocumentsMutation();
1058
- const publishMany = React__namespace.useCallback(
1059
- async ({ model, documentIds, params }) => {
1060
- try {
1061
- const res = await publishManyDocuments({
1062
- model,
1063
- documentIds,
1064
- params
1065
- });
1066
- if ("error" in res) {
1067
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1068
- return { error: res.error };
1069
- }
1070
- toggleNotification({
1071
- type: "success",
1072
- message: formatMessage({
1073
- id: getTranslation("success.record.publish"),
1074
- defaultMessage: "Published document"
1075
- })
1076
- });
1077
- return res.data;
1078
- } catch (err) {
1079
- toggleNotification({
1080
- type: "danger",
1081
- message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1082
- });
1083
- throw err;
1102
+ const listAttributes = convertListLayoutToFieldLayouts(
1103
+ data.contentType.layouts.list,
1104
+ schema?.attributes,
1105
+ listMetadatas,
1106
+ { configurations: data.components, schemas: components },
1107
+ schemas
1108
+ );
1109
+ return {
1110
+ layout: listAttributes,
1111
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1112
+ metadatas: listMetadatas,
1113
+ options: {
1114
+ ...schema?.options,
1115
+ ...schema?.pluginOptions,
1116
+ ...data.contentType.options
1117
+ }
1118
+ };
1119
+ };
1120
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1121
+ return columns.map((name) => {
1122
+ const attribute = attributes[name];
1123
+ if (!attribute) {
1124
+ return null;
1125
+ }
1126
+ const metadata = metadatas[name];
1127
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1128
+ return {
1129
+ attribute,
1130
+ label: metadata.label ?? "",
1131
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1132
+ schemas,
1133
+ components: components?.schemas ?? {}
1134
+ }),
1135
+ name,
1136
+ searchable: metadata.searchable ?? true,
1137
+ sortable: metadata.sortable ?? true
1138
+ };
1139
+ }).filter((field) => field !== null);
1140
+ };
1141
+ const useDocument = (args, opts) => {
1142
+ const { toggleNotification } = strapiAdmin.useNotification();
1143
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1144
+ const {
1145
+ currentData: data,
1146
+ isLoading: isLoadingDocument,
1147
+ isFetching: isFetchingDocument,
1148
+ error
1149
+ } = useGetDocumentQuery(args, {
1150
+ ...opts,
1151
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1152
+ });
1153
+ const {
1154
+ components,
1155
+ schema,
1156
+ schemas,
1157
+ isLoading: isLoadingSchema
1158
+ } = useContentTypeSchema(args.model);
1159
+ React__namespace.useEffect(() => {
1160
+ if (error) {
1161
+ toggleNotification({
1162
+ type: "danger",
1163
+ message: formatAPIError(error)
1164
+ });
1165
+ }
1166
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1167
+ const validationSchema = React__namespace.useMemo(() => {
1168
+ if (!schema) {
1169
+ return null;
1170
+ }
1171
+ return createYupSchema(schema.attributes, components);
1172
+ }, [schema, components]);
1173
+ const validate = React__namespace.useCallback(
1174
+ (document) => {
1175
+ if (!validationSchema) {
1176
+ throw new Error(
1177
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1178
+ );
1179
+ }
1180
+ try {
1181
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1182
+ return null;
1183
+ } catch (error2) {
1184
+ if (error2 instanceof yup.ValidationError) {
1185
+ return strapiAdmin.getYupValidationErrors(error2);
1186
+ }
1187
+ throw error2;
1084
1188
  }
1085
1189
  },
1086
- [
1087
- // trackUsage,
1088
- publishManyDocuments,
1089
- toggleNotification,
1090
- formatMessage,
1091
- formatAPIError
1092
- ]
1190
+ [validationSchema]
1093
1191
  );
1094
- const [updateDocument] = useUpdateDocumentMutation();
1095
- const update = React__namespace.useCallback(
1096
- async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1192
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1193
+ const hasError = !!error;
1194
+ return {
1195
+ components,
1196
+ document: data?.data,
1197
+ meta: data?.meta,
1198
+ isLoading,
1199
+ hasError,
1200
+ schema,
1201
+ schemas,
1202
+ validate
1203
+ };
1204
+ };
1205
+ const useDoc = () => {
1206
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1207
+ const [{ query }] = strapiAdmin.useQueryParams();
1208
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1209
+ if (!collectionType) {
1210
+ throw new Error("Could not find collectionType in url params");
1211
+ }
1212
+ if (!slug) {
1213
+ throw new Error("Could not find model in url params");
1214
+ }
1215
+ const document = useDocument(
1216
+ { documentId: origin || id, model: slug, collectionType, params },
1217
+ {
1218
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1219
+ }
1220
+ );
1221
+ const returnId = origin || id === "create" ? void 0 : id;
1222
+ return {
1223
+ collectionType,
1224
+ model: slug,
1225
+ id: returnId,
1226
+ ...document
1227
+ };
1228
+ };
1229
+ const useContentManagerContext = () => {
1230
+ const {
1231
+ collectionType,
1232
+ model,
1233
+ id,
1234
+ components,
1235
+ isLoading: isLoadingDoc,
1236
+ schema,
1237
+ schemas
1238
+ } = useDoc();
1239
+ const layout = useDocumentLayout(model);
1240
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1241
+ const isSingleType = collectionType === SINGLE_TYPES;
1242
+ const slug = model;
1243
+ const isCreatingEntry = id === "create";
1244
+ useContentTypeSchema();
1245
+ const isLoading = isLoadingDoc || layout.isLoading;
1246
+ const error = layout.error;
1247
+ return {
1248
+ error,
1249
+ isLoading,
1250
+ // Base metadata
1251
+ model,
1252
+ collectionType,
1253
+ id,
1254
+ slug,
1255
+ isCreatingEntry,
1256
+ isSingleType,
1257
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1258
+ // All schema infos
1259
+ components,
1260
+ contentType: schema,
1261
+ contentTypes: schemas,
1262
+ // Form state
1263
+ form,
1264
+ // layout infos
1265
+ layout
1266
+ };
1267
+ };
1268
+ const prefixPluginTranslations = (trad, pluginId) => {
1269
+ return Object.keys(trad).reduce((acc, current) => {
1270
+ acc[`${pluginId}.${current}`] = trad[current];
1271
+ return acc;
1272
+ }, {});
1273
+ };
1274
+ const getTranslation = (id) => `content-manager.${id}`;
1275
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1276
+ id: "notification.error",
1277
+ defaultMessage: "An error occurred, please try again"
1278
+ };
1279
+ const useDocumentActions = () => {
1280
+ const { toggleNotification } = strapiAdmin.useNotification();
1281
+ const { formatMessage } = reactIntl.useIntl();
1282
+ const { trackUsage } = strapiAdmin.useTracking();
1283
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1284
+ const navigate = reactRouterDom.useNavigate();
1285
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1286
+ const [deleteDocument] = useDeleteDocumentMutation();
1287
+ const _delete = React__namespace.useCallback(
1288
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1097
1289
  try {
1098
- trackUsage("willEditEntry", trackerProperty);
1099
- const res = await updateDocument({
1290
+ trackUsage("willDeleteEntry", trackerProperty);
1291
+ const res = await deleteDocument({
1100
1292
  collectionType,
1101
1293
  model,
1102
1294
  documentId,
1103
- data,
1104
1295
  params
1105
1296
  });
1106
1297
  if ("error" in res) {
1107
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1108
- trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1298
+ toggleNotification({
1299
+ type: "danger",
1300
+ message: formatAPIError(res.error)
1301
+ });
1109
1302
  return { error: res.error };
1110
1303
  }
1111
- trackUsage("didEditEntry", trackerProperty);
1112
1304
  toggleNotification({
1113
1305
  type: "success",
1114
1306
  message: formatMessage({
1115
- id: getTranslation("success.record.save"),
1116
- defaultMessage: "Saved document"
1307
+ id: getTranslation("success.record.delete"),
1308
+ defaultMessage: "Deleted document"
1117
1309
  })
1118
1310
  });
1311
+ trackUsage("didDeleteEntry", trackerProperty);
1119
1312
  return res.data;
1120
1313
  } catch (err) {
1121
- trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1122
1314
  toggleNotification({
1123
1315
  type: "danger",
1124
1316
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1125
1317
  });
1318
+ trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
1126
1319
  throw err;
1127
1320
  }
1128
1321
  },
1129
- [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1322
+ [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
1130
1323
  );
1131
- const [unpublishDocument] = useUnpublishDocumentMutation();
1132
- const unpublish = React__namespace.useCallback(
1133
- async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1324
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
1325
+ const deleteMany = React__namespace.useCallback(
1326
+ async ({ model, documentIds, params }) => {
1134
1327
  try {
1135
- trackUsage("willUnpublishEntry");
1136
- const res = await unpublishDocument({
1137
- collectionType,
1328
+ trackUsage("willBulkDeleteEntries");
1329
+ const res = await deleteManyDocuments({
1138
1330
  model,
1139
- documentId,
1140
- params,
1141
- data: {
1142
- discardDraft
1143
- }
1331
+ documentIds,
1332
+ params
1144
1333
  });
1145
1334
  if ("error" in res) {
1146
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1335
+ toggleNotification({
1336
+ type: "danger",
1337
+ message: formatAPIError(res.error)
1338
+ });
1147
1339
  return { error: res.error };
1148
1340
  }
1149
- trackUsage("didUnpublishEntry");
1150
1341
  toggleNotification({
1151
1342
  type: "success",
1152
- message: formatMessage({
1153
- id: getTranslation("success.record.unpublish"),
1154
- defaultMessage: "Unpublished document"
1155
- })
1343
+ title: formatMessage({
1344
+ id: getTranslation("success.records.delete"),
1345
+ defaultMessage: "Successfully deleted."
1346
+ }),
1347
+ message: ""
1156
1348
  });
1349
+ trackUsage("didBulkDeleteEntries");
1157
1350
  return res.data;
1158
1351
  } catch (err) {
1159
1352
  toggleNotification({
1160
1353
  type: "danger",
1161
1354
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1162
1355
  });
1356
+ trackUsage("didNotBulkDeleteEntries");
1163
1357
  throw err;
1164
1358
  }
1165
1359
  },
1166
- [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1360
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
1167
1361
  );
1168
- const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1169
- const unpublishMany = React__namespace.useCallback(
1170
- async ({ model, documentIds, params }) => {
1362
+ const [discardDocument] = useDiscardDocumentMutation();
1363
+ const discard = React__namespace.useCallback(
1364
+ async ({ collectionType, model, documentId, params }) => {
1171
1365
  try {
1172
- trackUsage("willBulkUnpublishEntries");
1173
- const res = await unpublishManyDocuments({
1366
+ const res = await discardDocument({
1367
+ collectionType,
1174
1368
  model,
1175
- documentIds,
1369
+ documentId,
1176
1370
  params
1177
1371
  });
1178
1372
  if ("error" in res) {
1179
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1373
+ toggleNotification({
1374
+ type: "danger",
1375
+ message: formatAPIError(res.error)
1376
+ });
1180
1377
  return { error: res.error };
1181
1378
  }
1182
- trackUsage("didBulkUnpublishEntries");
1183
1379
  toggleNotification({
1184
1380
  type: "success",
1185
- title: formatMessage({
1186
- id: getTranslation("success.records.unpublish"),
1187
- defaultMessage: "Successfully unpublished."
1188
- }),
1189
- message: ""
1381
+ message: formatMessage({
1382
+ id: "content-manager.success.record.discard",
1383
+ defaultMessage: "Changes discarded"
1384
+ })
1190
1385
  });
1191
1386
  return res.data;
1192
1387
  } catch (err) {
@@ -1194,16 +1389,196 @@ const useDocumentActions = () => {
1194
1389
  type: "danger",
1195
1390
  message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1196
1391
  });
1197
- trackUsage("didNotBulkUnpublishEntries");
1198
1392
  throw err;
1199
1393
  }
1200
1394
  },
1201
- [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1395
+ [discardDocument, formatAPIError, formatMessage, toggleNotification]
1202
1396
  );
1203
- const [createDocument] = useCreateDocumentMutation();
1204
- const create = React__namespace.useCallback(
1205
- async ({ model, params }, data, trackerProperty) => {
1206
- try {
1397
+ const [publishDocument] = usePublishDocumentMutation();
1398
+ const publish = React__namespace.useCallback(
1399
+ async ({ collectionType, model, documentId, params }, data) => {
1400
+ try {
1401
+ trackUsage("willPublishEntry");
1402
+ const res = await publishDocument({
1403
+ collectionType,
1404
+ model,
1405
+ documentId,
1406
+ data,
1407
+ params
1408
+ });
1409
+ if ("error" in res) {
1410
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1411
+ return { error: res.error };
1412
+ }
1413
+ trackUsage("didPublishEntry");
1414
+ toggleNotification({
1415
+ type: "success",
1416
+ message: formatMessage({
1417
+ id: getTranslation("success.record.publish"),
1418
+ defaultMessage: "Published document"
1419
+ })
1420
+ });
1421
+ return res.data;
1422
+ } catch (err) {
1423
+ toggleNotification({
1424
+ type: "danger",
1425
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1426
+ });
1427
+ throw err;
1428
+ }
1429
+ },
1430
+ [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1431
+ );
1432
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1433
+ const publishMany = React__namespace.useCallback(
1434
+ async ({ model, documentIds, params }) => {
1435
+ try {
1436
+ const res = await publishManyDocuments({
1437
+ model,
1438
+ documentIds,
1439
+ params
1440
+ });
1441
+ if ("error" in res) {
1442
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1443
+ return { error: res.error };
1444
+ }
1445
+ toggleNotification({
1446
+ type: "success",
1447
+ message: formatMessage({
1448
+ id: getTranslation("success.record.publish"),
1449
+ defaultMessage: "Published document"
1450
+ })
1451
+ });
1452
+ return res.data;
1453
+ } catch (err) {
1454
+ toggleNotification({
1455
+ type: "danger",
1456
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1457
+ });
1458
+ throw err;
1459
+ }
1460
+ },
1461
+ [
1462
+ // trackUsage,
1463
+ publishManyDocuments,
1464
+ toggleNotification,
1465
+ formatMessage,
1466
+ formatAPIError
1467
+ ]
1468
+ );
1469
+ const [updateDocument] = useUpdateDocumentMutation();
1470
+ const update = React__namespace.useCallback(
1471
+ async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
1472
+ try {
1473
+ trackUsage("willEditEntry", trackerProperty);
1474
+ const res = await updateDocument({
1475
+ collectionType,
1476
+ model,
1477
+ documentId,
1478
+ data,
1479
+ params
1480
+ });
1481
+ if ("error" in res) {
1482
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1483
+ trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
1484
+ return { error: res.error };
1485
+ }
1486
+ trackUsage("didEditEntry", trackerProperty);
1487
+ toggleNotification({
1488
+ type: "success",
1489
+ message: formatMessage({
1490
+ id: getTranslation("success.record.save"),
1491
+ defaultMessage: "Saved document"
1492
+ })
1493
+ });
1494
+ return res.data;
1495
+ } catch (err) {
1496
+ trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
1497
+ toggleNotification({
1498
+ type: "danger",
1499
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1500
+ });
1501
+ throw err;
1502
+ }
1503
+ },
1504
+ [trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
1505
+ );
1506
+ const [unpublishDocument] = useUnpublishDocumentMutation();
1507
+ const unpublish = React__namespace.useCallback(
1508
+ async ({ collectionType, model, documentId, params }, discardDraft = false) => {
1509
+ try {
1510
+ trackUsage("willUnpublishEntry");
1511
+ const res = await unpublishDocument({
1512
+ collectionType,
1513
+ model,
1514
+ documentId,
1515
+ params,
1516
+ data: {
1517
+ discardDraft
1518
+ }
1519
+ });
1520
+ if ("error" in res) {
1521
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1522
+ return { error: res.error };
1523
+ }
1524
+ trackUsage("didUnpublishEntry");
1525
+ toggleNotification({
1526
+ type: "success",
1527
+ message: formatMessage({
1528
+ id: getTranslation("success.record.unpublish"),
1529
+ defaultMessage: "Unpublished document"
1530
+ })
1531
+ });
1532
+ return res.data;
1533
+ } catch (err) {
1534
+ toggleNotification({
1535
+ type: "danger",
1536
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1537
+ });
1538
+ throw err;
1539
+ }
1540
+ },
1541
+ [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1542
+ );
1543
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1544
+ const unpublishMany = React__namespace.useCallback(
1545
+ async ({ model, documentIds, params }) => {
1546
+ try {
1547
+ trackUsage("willBulkUnpublishEntries");
1548
+ const res = await unpublishManyDocuments({
1549
+ model,
1550
+ documentIds,
1551
+ params
1552
+ });
1553
+ if ("error" in res) {
1554
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1555
+ return { error: res.error };
1556
+ }
1557
+ trackUsage("didBulkUnpublishEntries");
1558
+ toggleNotification({
1559
+ type: "success",
1560
+ title: formatMessage({
1561
+ id: getTranslation("success.records.unpublish"),
1562
+ defaultMessage: "Successfully unpublished."
1563
+ }),
1564
+ message: ""
1565
+ });
1566
+ return res.data;
1567
+ } catch (err) {
1568
+ toggleNotification({
1569
+ type: "danger",
1570
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1571
+ });
1572
+ trackUsage("didNotBulkUnpublishEntries");
1573
+ throw err;
1574
+ }
1575
+ },
1576
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1577
+ );
1578
+ const [createDocument] = useCreateDocumentMutation();
1579
+ const create = React__namespace.useCallback(
1580
+ async ({ model, params }, data, trackerProperty) => {
1581
+ try {
1207
1582
  const res = await createDocument({
1208
1583
  model,
1209
1584
  data,
@@ -1222,6 +1597,7 @@ const useDocumentActions = () => {
1222
1597
  defaultMessage: "Saved document"
1223
1598
  })
1224
1599
  });
1600
+ setCurrentStep("contentManager.success");
1225
1601
  return res.data;
1226
1602
  } catch (err) {
1227
1603
  toggleNotification({
@@ -1323,10 +1699,10 @@ const useDocumentActions = () => {
1323
1699
  update
1324
1700
  };
1325
1701
  };
1326
- const ProtectedHistoryPage = React.lazy(
1327
- () => Promise.resolve().then(() => require("./History-pbhkxIrf.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1702
+ const ProtectedHistoryPage = React__namespace.lazy(
1703
+ () => Promise.resolve().then(() => require("./History-CeCDhoJG.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1328
1704
  );
1329
- const routes$1 = [
1705
+ const routes$2 = [
1330
1706
  {
1331
1707
  path: ":collectionType/:slug/:id/history",
1332
1708
  Component: ProtectedHistoryPage
@@ -1336,32 +1712,45 @@ const routes$1 = [
1336
1712
  Component: ProtectedHistoryPage
1337
1713
  }
1338
1714
  ];
1715
+ const ProtectedPreviewPage = React__namespace.lazy(
1716
+ () => Promise.resolve().then(() => require("./Preview-CT28Ckpg.js")).then((mod) => ({ default: mod.ProtectedPreviewPage }))
1717
+ );
1718
+ const routes$1 = [
1719
+ {
1720
+ path: ":collectionType/:slug/:id/preview",
1721
+ Component: ProtectedPreviewPage
1722
+ },
1723
+ {
1724
+ path: ":collectionType/:slug/preview",
1725
+ Component: ProtectedPreviewPage
1726
+ }
1727
+ ];
1339
1728
  const ProtectedEditViewPage = React.lazy(
1340
- () => Promise.resolve().then(() => require("./EditViewPage-g5TwrgRY.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1729
+ () => Promise.resolve().then(() => require("./EditViewPage-BwisF04Q.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1341
1730
  );
1342
1731
  const ProtectedListViewPage = React.lazy(
1343
- () => Promise.resolve().then(() => require("./ListViewPage-Dymsvnv6.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1732
+ () => Promise.resolve().then(() => require("./ListViewPage-BKTZFhsM.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1344
1733
  );
1345
1734
  const ProtectedListConfiguration = React.lazy(
1346
- () => Promise.resolve().then(() => require("./ListConfigurationPage-Bna8zfjr.js")).then((mod) => ({
1735
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-C-bAd44a.js")).then((mod) => ({
1347
1736
  default: mod.ProtectedListConfiguration
1348
1737
  }))
1349
1738
  );
1350
1739
  const ProtectedEditConfigurationPage = React.lazy(
1351
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CeL712KW.js")).then((mod) => ({
1740
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-D2rtvneE.js")).then((mod) => ({
1352
1741
  default: mod.ProtectedEditConfigurationPage
1353
1742
  }))
1354
1743
  );
1355
1744
  const ProtectedComponentConfigurationPage = React.lazy(
1356
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-D_g11bYV.js")).then((mod) => ({
1745
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-BSEZcJVB.js")).then((mod) => ({
1357
1746
  default: mod.ProtectedComponentConfigurationPage
1358
1747
  }))
1359
1748
  );
1360
1749
  const NoPermissions = React.lazy(
1361
- () => Promise.resolve().then(() => require("./NoPermissionsPage-BOwB6hki.js")).then((mod) => ({ default: mod.NoPermissions }))
1750
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-CChGWBj5.js")).then((mod) => ({ default: mod.NoPermissions }))
1362
1751
  );
1363
1752
  const NoContentType = React.lazy(
1364
- () => Promise.resolve().then(() => require("./NoContentTypePage-B4t_OsDR.js")).then((mod) => ({ default: mod.NoContentType }))
1753
+ () => Promise.resolve().then(() => require("./NoContentTypePage-D3Cm3v3q.js")).then((mod) => ({ default: mod.NoContentType }))
1365
1754
  );
1366
1755
  const CollectionTypePages = () => {
1367
1756
  const { collectionType } = reactRouterDom.useParams();
@@ -1373,7 +1762,7 @@ const CollectionTypePages = () => {
1373
1762
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1374
1763
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1375
1764
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1376
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1765
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1377
1766
  const routes = [
1378
1767
  {
1379
1768
  path: LIST_RELATIVE_PATH,
@@ -1407,6 +1796,7 @@ const routes = [
1407
1796
  path: "no-content-types",
1408
1797
  Component: NoContentType
1409
1798
  },
1799
+ ...routes$2,
1410
1800
  ...routes$1
1411
1801
  ];
1412
1802
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1505,6 +1895,11 @@ const DocumentActionButton = (action) => {
1505
1895
  ) : null
1506
1896
  ] });
1507
1897
  };
1898
+ const MenuItem = styledComponents.styled(designSystem.Menu.Item)`
1899
+ &:hover {
1900
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1901
+ }
1902
+ `;
1508
1903
  const DocumentActionsMenu = ({
1509
1904
  actions: actions2,
1510
1905
  children,
@@ -1560,51 +1955,35 @@ const DocumentActionsMenu = ({
1560
1955
  ]
1561
1956
  }
1562
1957
  ),
1563
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1958
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1564
1959
  actions2.map((action) => {
1565
1960
  return /* @__PURE__ */ jsxRuntime.jsx(
1566
- designSystem.Menu.Item,
1961
+ MenuItem,
1567
1962
  {
1568
1963
  disabled: action.disabled,
1569
1964
  onSelect: handleClick(action),
1570
1965
  display: "block",
1571
- children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1572
- /* @__PURE__ */ jsxRuntime.jsxs(
1573
- designSystem.Flex,
1574
- {
1575
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1576
- gap: 2,
1577
- tag: "span",
1578
- children: [
1579
- /* @__PURE__ */ jsxRuntime.jsx(
1580
- designSystem.Flex,
1581
- {
1582
- tag: "span",
1583
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1584
- children: action.icon
1585
- }
1586
- ),
1587
- action.label
1588
- ]
1589
- }
1590
- ),
1591
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1592
- designSystem.Flex,
1593
- {
1594
- alignItems: "center",
1595
- background: "alternative100",
1596
- borderStyle: "solid",
1597
- borderColor: "alternative200",
1598
- borderWidth: "1px",
1599
- height: 5,
1600
- paddingLeft: 2,
1601
- paddingRight: 2,
1602
- hasRadius: true,
1603
- color: "alternative600",
1604
- children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1605
- }
1606
- )
1607
- ] })
1966
+ isVariantDanger: action.variant === "danger",
1967
+ isDisabled: action.disabled,
1968
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(
1969
+ designSystem.Flex,
1970
+ {
1971
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1972
+ gap: 2,
1973
+ tag: "span",
1974
+ children: [
1975
+ /* @__PURE__ */ jsxRuntime.jsx(
1976
+ designSystem.Flex,
1977
+ {
1978
+ tag: "span",
1979
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1980
+ children: action.icon
1981
+ }
1982
+ ),
1983
+ action.label
1984
+ ]
1985
+ }
1986
+ ) })
1608
1987
  },
1609
1988
  action.id
1610
1989
  );
@@ -1684,11 +2063,11 @@ const DocumentActionConfirmDialog = ({
1684
2063
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1685
2064
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1686
2065
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1687
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
2066
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1688
2067
  id: "app.components.Button.cancel",
1689
2068
  defaultMessage: "Cancel"
1690
2069
  }) }) }),
1691
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
2070
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1692
2071
  id: "app.components.Button.confirm",
1693
2072
  defaultMessage: "Confirm"
1694
2073
  }) })
@@ -1715,6 +2094,18 @@ const DocumentActionModal = ({
1715
2094
  typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1716
2095
  ] }) });
1717
2096
  };
2097
+ const transformData = (data) => {
2098
+ if (Array.isArray(data)) {
2099
+ return data.map(transformData);
2100
+ }
2101
+ if (typeof data === "object" && data !== null) {
2102
+ if ("apiData" in data) {
2103
+ return data.apiData;
2104
+ }
2105
+ return mapValues__default.default(transformData)(data);
2106
+ }
2107
+ return data;
2108
+ };
1718
2109
  const PublishAction$1 = ({
1719
2110
  activeTab,
1720
2111
  documentId,
@@ -1729,6 +2120,7 @@ const PublishAction$1 = ({
1729
2120
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1730
2121
  const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1731
2122
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2123
+ const { id } = reactRouterDom.useParams();
1732
2124
  const { formatMessage } = reactIntl.useIntl();
1733
2125
  const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1734
2126
  const { publish } = useDocumentActions();
@@ -1808,7 +2200,9 @@ const PublishAction$1 = ({
1808
2200
  const performPublish = async () => {
1809
2201
  setSubmitting(true);
1810
2202
  try {
1811
- const { errors } = await validate();
2203
+ const { errors } = await validate(true, {
2204
+ status: "published"
2205
+ });
1812
2206
  if (errors) {
1813
2207
  toggleNotification({
1814
2208
  type: "danger",
@@ -1826,13 +2220,15 @@ const PublishAction$1 = ({
1826
2220
  documentId,
1827
2221
  params
1828
2222
  },
1829
- formValues
2223
+ transformData(formValues)
1830
2224
  );
1831
2225
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1832
- navigate({
1833
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1834
- search: rawQuery
1835
- });
2226
+ if (id === "create") {
2227
+ navigate({
2228
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2229
+ search: rawQuery
2230
+ });
2231
+ }
1836
2232
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
2233
  setErrors(formatValidationErrors(res.error));
1838
2234
  }
@@ -1885,6 +2281,7 @@ const PublishAction$1 = ({
1885
2281
  };
1886
2282
  };
1887
2283
  PublishAction$1.type = "publish";
2284
+ PublishAction$1.position = "panel";
1888
2285
  const UpdateAction = ({
1889
2286
  activeTab,
1890
2287
  documentId,
@@ -1907,96 +2304,134 @@ const UpdateAction = ({
1907
2304
  const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
1908
2305
  const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
1909
2306
  const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
1910
- return {
1911
- /**
1912
- * Disabled when:
1913
- * - the form is submitting
1914
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1915
- * - the active tab is the published tab
1916
- */
1917
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1918
- label: formatMessage({
1919
- id: "content-manager.containers.Edit.save",
1920
- defaultMessage: "Save"
1921
- }),
1922
- onClick: async () => {
1923
- setSubmitting(true);
1924
- try {
1925
- if (activeTab !== "draft") {
1926
- const { errors } = await validate();
1927
- if (errors) {
1928
- toggleNotification({
1929
- type: "danger",
1930
- message: formatMessage({
1931
- id: "content-manager.validation.error",
1932
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1933
- })
1934
- });
1935
- return;
1936
- }
1937
- }
1938
- if (isCloning) {
1939
- const res = await clone(
1940
- {
1941
- model,
1942
- documentId: cloneMatch.params.origin,
1943
- params
1944
- },
1945
- document
1946
- );
1947
- if ("data" in res) {
1948
- navigate(
1949
- {
1950
- pathname: `../${res.data.documentId}`,
1951
- search: rawQuery
1952
- },
1953
- { relative: "path" }
1954
- );
1955
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1956
- setErrors(formatValidationErrors(res.error));
1957
- }
1958
- } else if (documentId || collectionType === SINGLE_TYPES) {
1959
- const res = await update(
2307
+ const handleUpdate = React__namespace.useCallback(async () => {
2308
+ setSubmitting(true);
2309
+ try {
2310
+ if (!modified) {
2311
+ return;
2312
+ }
2313
+ const { errors } = await validate(true, {
2314
+ status: "draft"
2315
+ });
2316
+ if (errors) {
2317
+ toggleNotification({
2318
+ type: "danger",
2319
+ message: formatMessage({
2320
+ id: "content-manager.validation.error",
2321
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2322
+ })
2323
+ });
2324
+ return;
2325
+ }
2326
+ if (isCloning) {
2327
+ const res = await clone(
2328
+ {
2329
+ model,
2330
+ documentId: cloneMatch.params.origin,
2331
+ params
2332
+ },
2333
+ transformData(document)
2334
+ );
2335
+ if ("data" in res) {
2336
+ navigate(
1960
2337
  {
1961
- collectionType,
1962
- model,
1963
- documentId,
1964
- params
2338
+ pathname: `../${res.data.documentId}`,
2339
+ search: rawQuery
1965
2340
  },
1966
- document
2341
+ { relative: "path" }
1967
2342
  );
1968
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1969
- setErrors(formatValidationErrors(res.error));
1970
- } else {
1971
- resetForm();
1972
- }
2343
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2344
+ setErrors(formatValidationErrors(res.error));
2345
+ }
2346
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2347
+ const res = await update(
2348
+ {
2349
+ collectionType,
2350
+ model,
2351
+ documentId,
2352
+ params
2353
+ },
2354
+ transformData(document)
2355
+ );
2356
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2357
+ setErrors(formatValidationErrors(res.error));
1973
2358
  } else {
1974
- const res = await create(
2359
+ resetForm();
2360
+ }
2361
+ } else {
2362
+ const res = await create(
2363
+ {
2364
+ model,
2365
+ params
2366
+ },
2367
+ transformData(document)
2368
+ );
2369
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2370
+ navigate(
1975
2371
  {
1976
- model,
1977
- params
2372
+ pathname: `../${res.data.documentId}`,
2373
+ search: rawQuery
1978
2374
  },
1979
- document
2375
+ { replace: true, relative: "path" }
1980
2376
  );
1981
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1982
- navigate(
1983
- {
1984
- pathname: `../${res.data.documentId}`,
1985
- search: rawQuery
1986
- },
1987
- { replace: true, relative: "path" }
1988
- );
1989
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1990
- setErrors(formatValidationErrors(res.error));
1991
- }
2377
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2378
+ setErrors(formatValidationErrors(res.error));
1992
2379
  }
1993
- } finally {
1994
- setSubmitting(false);
1995
2380
  }
2381
+ } finally {
2382
+ setSubmitting(false);
1996
2383
  }
2384
+ }, [
2385
+ clone,
2386
+ cloneMatch?.params.origin,
2387
+ collectionType,
2388
+ create,
2389
+ document,
2390
+ documentId,
2391
+ formatMessage,
2392
+ formatValidationErrors,
2393
+ isCloning,
2394
+ model,
2395
+ modified,
2396
+ navigate,
2397
+ params,
2398
+ rawQuery,
2399
+ resetForm,
2400
+ setErrors,
2401
+ setSubmitting,
2402
+ toggleNotification,
2403
+ update,
2404
+ validate
2405
+ ]);
2406
+ React__namespace.useEffect(() => {
2407
+ const handleKeyDown = (e) => {
2408
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2409
+ e.preventDefault();
2410
+ handleUpdate();
2411
+ }
2412
+ };
2413
+ window.addEventListener("keydown", handleKeyDown);
2414
+ return () => {
2415
+ window.removeEventListener("keydown", handleKeyDown);
2416
+ };
2417
+ }, [handleUpdate]);
2418
+ return {
2419
+ /**
2420
+ * Disabled when:
2421
+ * - the form is submitting
2422
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2423
+ * - the active tab is the published tab
2424
+ */
2425
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2426
+ label: formatMessage({
2427
+ id: "global.save",
2428
+ defaultMessage: "Save"
2429
+ }),
2430
+ onClick: handleUpdate
1997
2431
  };
1998
2432
  };
1999
2433
  UpdateAction.type = "update";
2434
+ UpdateAction.position = "panel";
2000
2435
  const UNPUBLISH_DRAFT_OPTIONS = {
2001
2436
  KEEP: "keep",
2002
2437
  DISCARD: "discard"
@@ -2119,6 +2554,7 @@ const UnpublishAction$1 = ({
2119
2554
  };
2120
2555
  };
2121
2556
  UnpublishAction$1.type = "unpublish";
2557
+ UnpublishAction$1.position = "panel";
2122
2558
  const DiscardAction = ({
2123
2559
  activeTab,
2124
2560
  documentId,
@@ -2169,6 +2605,7 @@ const DiscardAction = ({
2169
2605
  };
2170
2606
  };
2171
2607
  DiscardAction.type = "discard";
2608
+ DiscardAction.position = "panel";
2172
2609
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2173
2610
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2174
2611
  const RelativeTime = React__namespace.forwardRef(
@@ -2181,7 +2618,7 @@ const RelativeTime = React__namespace.forwardRef(
2181
2618
  });
2182
2619
  const unit = intervals.find((intervalUnit) => {
2183
2620
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2184
- });
2621
+ }) ?? "seconds";
2185
2622
  const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
2186
2623
  const customInterval = customIntervals.find(
2187
2624
  (custom) => interval[custom.unit] < custom.threshold
@@ -2215,19 +2652,29 @@ const getDisplayName = ({
2215
2652
  return email ?? "";
2216
2653
  };
2217
2654
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2218
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2219
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2220
- 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) }) });
2655
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2656
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2657
+ const { formatMessage } = reactIntl.useIntl();
2658
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2659
+ id: `content-manager.containers.List.${status}`,
2660
+ defaultMessage: capitalise(status)
2661
+ }) }) });
2221
2662
  };
2222
2663
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2223
2664
  const { formatMessage } = reactIntl.useIntl();
2224
2665
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2666
+ const params = reactRouterDom.useParams();
2225
2667
  const title = isCreating ? formatMessage({
2226
2668
  id: "content-manager.containers.edit.title.new",
2227
2669
  defaultMessage: "Create an entry"
2228
2670
  }) : documentTitle;
2229
2671
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2230
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2672
+ /* @__PURE__ */ jsxRuntime.jsx(
2673
+ strapiAdmin.BackButton,
2674
+ {
2675
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2676
+ }
2677
+ ),
2231
2678
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2232
2679
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2233
2680
  /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
@@ -2278,7 +2725,7 @@ const HeaderToolbar = () => {
2278
2725
  meta: isCloning ? void 0 : meta,
2279
2726
  collectionType
2280
2727
  },
2281
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2728
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2282
2729
  children: (actions2) => {
2283
2730
  const headerActions = actions2.filter((action) => {
2284
2731
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2315,12 +2762,12 @@ const Information = ({ activeTab }) => {
2315
2762
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2316
2763
  label: formatMessage({
2317
2764
  id: "content-manager.containers.edit.information.last-published.label",
2318
- defaultMessage: "Last published"
2765
+ defaultMessage: "Published"
2319
2766
  }),
2320
2767
  value: formatMessage(
2321
2768
  {
2322
2769
  id: "content-manager.containers.edit.information.last-published.value",
2323
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2770
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2324
2771
  },
2325
2772
  {
2326
2773
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2333,12 +2780,12 @@ const Information = ({ activeTab }) => {
2333
2780
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2334
2781
  label: formatMessage({
2335
2782
  id: "content-manager.containers.edit.information.last-draft.label",
2336
- defaultMessage: "Last draft"
2783
+ defaultMessage: "Updated"
2337
2784
  }),
2338
2785
  value: formatMessage(
2339
2786
  {
2340
2787
  id: "content-manager.containers.edit.information.last-draft.value",
2341
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2788
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2342
2789
  },
2343
2790
  {
2344
2791
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2356,12 +2803,12 @@ const Information = ({ activeTab }) => {
2356
2803
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2357
2804
  label: formatMessage({
2358
2805
  id: "content-manager.containers.edit.information.document.label",
2359
- defaultMessage: "Document"
2806
+ defaultMessage: "Created"
2360
2807
  }),
2361
2808
  value: formatMessage(
2362
2809
  {
2363
2810
  id: "content-manager.containers.edit.information.document.value",
2364
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2811
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2365
2812
  },
2366
2813
  {
2367
2814
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2399,25 +2846,77 @@ const Information = ({ activeTab }) => {
2399
2846
  );
2400
2847
  };
2401
2848
  const HeaderActions = ({ actions: actions2 }) => {
2402
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2403
- if ("options" in action) {
2849
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2850
+ const handleClick = (action) => async (e) => {
2851
+ if (!("options" in action)) {
2852
+ const { onClick = () => false, dialog, id } = action;
2853
+ const muteDialog = await onClick(e);
2854
+ if (dialog && !muteDialog) {
2855
+ e.preventDefault();
2856
+ setDialogId(id);
2857
+ }
2858
+ }
2859
+ };
2860
+ const handleClose = () => {
2861
+ setDialogId(null);
2862
+ };
2863
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2864
+ if (action.options) {
2404
2865
  return /* @__PURE__ */ jsxRuntime.jsx(
2405
2866
  designSystem.SingleSelect,
2406
2867
  {
2407
2868
  size: "S",
2408
- disabled: action.disabled,
2409
- "aria-label": action.label,
2410
2869
  onChange: action.onSelect,
2411
- value: action.value,
2870
+ "aria-label": action.label,
2871
+ ...action,
2412
2872
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2413
2873
  },
2414
2874
  action.id
2415
2875
  );
2416
2876
  } else {
2417
- return null;
2877
+ if (action.type === "icon") {
2878
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2879
+ /* @__PURE__ */ jsxRuntime.jsx(
2880
+ designSystem.IconButton,
2881
+ {
2882
+ disabled: action.disabled,
2883
+ label: action.label,
2884
+ size: "S",
2885
+ onClick: handleClick(action),
2886
+ children: action.icon
2887
+ }
2888
+ ),
2889
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2890
+ HeaderActionDialog,
2891
+ {
2892
+ ...action.dialog,
2893
+ isOpen: dialogId === action.id,
2894
+ onClose: handleClose
2895
+ }
2896
+ ) : null
2897
+ ] }, action.id);
2898
+ }
2418
2899
  }
2419
2900
  }) });
2420
2901
  };
2902
+ const HeaderActionDialog = ({
2903
+ onClose,
2904
+ onCancel,
2905
+ title,
2906
+ content: Content,
2907
+ isOpen
2908
+ }) => {
2909
+ const handleClose = async () => {
2910
+ if (onCancel) {
2911
+ await onCancel();
2912
+ }
2913
+ onClose();
2914
+ };
2915
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2916
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2917
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2918
+ ] }) });
2919
+ };
2421
2920
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2422
2921
  const navigate = reactRouterDom.useNavigate();
2423
2922
  const { formatMessage } = reactIntl.useIntl();
@@ -2434,6 +2933,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2434
2933
  };
2435
2934
  };
2436
2935
  ConfigureTheViewAction.type = "configure-the-view";
2936
+ ConfigureTheViewAction.position = "header";
2437
2937
  const EditTheModelAction = ({ model }) => {
2438
2938
  const navigate = reactRouterDom.useNavigate();
2439
2939
  const { formatMessage } = reactIntl.useIntl();
@@ -2450,6 +2950,7 @@ const EditTheModelAction = ({ model }) => {
2450
2950
  };
2451
2951
  };
2452
2952
  EditTheModelAction.type = "edit-the-model";
2953
+ EditTheModelAction.position = "header";
2453
2954
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2454
2955
  const navigate = reactRouterDom.useNavigate();
2455
2956
  const { formatMessage } = reactIntl.useIntl();
@@ -2458,12 +2959,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2458
2959
  const { delete: deleteAction } = useDocumentActions();
2459
2960
  const { toggleNotification } = strapiAdmin.useNotification();
2460
2961
  const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2962
+ const isLocalized = document?.locale != null;
2461
2963
  return {
2462
2964
  disabled: !canDelete || !document,
2463
- label: formatMessage({
2464
- id: "content-manager.actions.delete.label",
2465
- defaultMessage: "Delete document"
2466
- }),
2965
+ label: formatMessage(
2966
+ {
2967
+ id: "content-manager.actions.delete.label",
2968
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2969
+ },
2970
+ { isLocalized }
2971
+ ),
2467
2972
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2468
2973
  dialog: {
2469
2974
  type: "dialog",
@@ -2501,422 +3006,120 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2501
3006
  model,
2502
3007
  collectionType,
2503
3008
  params: {
2504
- locale: "*"
2505
- }
2506
- });
2507
- if (!("error" in res)) {
2508
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2509
- }
2510
- } finally {
2511
- if (!listViewPathMatch) {
2512
- setSubmitting(false);
2513
- }
2514
- }
2515
- }
2516
- },
2517
- variant: "danger",
2518
- position: ["header", "table-row"]
2519
- };
2520
- };
2521
- DeleteAction$1.type = "delete";
2522
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2523
- const Panels = () => {
2524
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2525
- const [
2526
- {
2527
- query: { status }
2528
- }
2529
- ] = strapiAdmin.useQueryParams({
2530
- status: "draft"
2531
- });
2532
- const { model, id, document, meta, collectionType } = useDoc();
2533
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2534
- const props = {
2535
- activeTab: status,
2536
- model,
2537
- documentId: id,
2538
- document: isCloning ? void 0 : document,
2539
- meta: isCloning ? void 0 : meta,
2540
- collectionType
2541
- };
2542
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2543
- strapiAdmin.DescriptionComponentRenderer,
2544
- {
2545
- props,
2546
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2547
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2548
- }
2549
- ) });
2550
- };
2551
- const ActionsPanel = () => {
2552
- const { formatMessage } = reactIntl.useIntl();
2553
- return {
2554
- title: formatMessage({
2555
- id: "content-manager.containers.edit.panels.default.title",
2556
- defaultMessage: "Document"
2557
- }),
2558
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2559
- };
2560
- };
2561
- ActionsPanel.type = "actions";
2562
- const ActionsPanelContent = () => {
2563
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2564
- const [
2565
- {
2566
- query: { status = "draft" }
2567
- }
2568
- ] = strapiAdmin.useQueryParams();
2569
- const { model, id, document, meta, collectionType } = useDoc();
2570
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2571
- const props = {
2572
- activeTab: status,
2573
- model,
2574
- documentId: id,
2575
- document: isCloning ? void 0 : document,
2576
- meta: isCloning ? void 0 : meta,
2577
- collectionType
2578
- };
2579
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2580
- /* @__PURE__ */ jsxRuntime.jsx(
2581
- strapiAdmin.DescriptionComponentRenderer,
2582
- {
2583
- props,
2584
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2585
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2586
- }
2587
- ),
2588
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2589
- ] });
2590
- };
2591
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2592
- return /* @__PURE__ */ jsxRuntime.jsxs(
2593
- designSystem.Flex,
2594
- {
2595
- ref,
2596
- tag: "aside",
2597
- "aria-labelledby": "additional-information",
2598
- background: "neutral0",
2599
- borderColor: "neutral150",
2600
- hasRadius: true,
2601
- paddingBottom: 4,
2602
- paddingLeft: 4,
2603
- paddingRight: 4,
2604
- paddingTop: 4,
2605
- shadow: "tableShadow",
2606
- gap: 3,
2607
- direction: "column",
2608
- justifyContent: "stretch",
2609
- alignItems: "flex-start",
2610
- children: [
2611
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2612
- children
2613
- ]
2614
- }
2615
- );
2616
- });
2617
- const HOOKS = {
2618
- /**
2619
- * Hook that allows to mutate the displayed headers of the list view table
2620
- * @constant
2621
- * @type {string}
2622
- */
2623
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2624
- /**
2625
- * Hook that allows to mutate the CM's collection types links pre-set filters
2626
- * @constant
2627
- * @type {string}
2628
- */
2629
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2630
- /**
2631
- * Hook that allows to mutate the CM's edit view layout
2632
- * @constant
2633
- * @type {string}
2634
- */
2635
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2636
- /**
2637
- * Hook that allows to mutate the CM's single types links pre-set filters
2638
- * @constant
2639
- * @type {string}
2640
- */
2641
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2642
- };
2643
- const contentTypesApi = contentManagerApi.injectEndpoints({
2644
- endpoints: (builder) => ({
2645
- getContentTypeConfiguration: builder.query({
2646
- query: (uid) => ({
2647
- url: `/content-manager/content-types/${uid}/configuration`,
2648
- method: "GET"
2649
- }),
2650
- transformResponse: (response) => response.data,
2651
- providesTags: (_result, _error, uid) => [
2652
- { type: "ContentTypesConfiguration", id: uid },
2653
- { type: "ContentTypeSettings", id: "LIST" }
2654
- ]
2655
- }),
2656
- getAllContentTypeSettings: builder.query({
2657
- query: () => "/content-manager/content-types-settings",
2658
- transformResponse: (response) => response.data,
2659
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2660
- }),
2661
- updateContentTypeConfiguration: builder.mutation({
2662
- query: ({ uid, ...body }) => ({
2663
- url: `/content-manager/content-types/${uid}/configuration`,
2664
- method: "PUT",
2665
- data: body
2666
- }),
2667
- transformResponse: (response) => response.data,
2668
- invalidatesTags: (_result, _error, { uid }) => [
2669
- { type: "ContentTypesConfiguration", id: uid },
2670
- { type: "ContentTypeSettings", id: "LIST" },
2671
- // Is this necessary?
2672
- { type: "InitialData" }
2673
- ]
2674
- })
2675
- })
2676
- });
2677
- const {
2678
- useGetContentTypeConfigurationQuery,
2679
- useGetAllContentTypeSettingsQuery,
2680
- useUpdateContentTypeConfigurationMutation
2681
- } = contentTypesApi;
2682
- const checkIfAttributeIsDisplayable = (attribute) => {
2683
- const { type } = attribute;
2684
- if (type === "relation") {
2685
- return !attribute.relation.toLowerCase().includes("morph");
2686
- }
2687
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2688
- };
2689
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2690
- if (!mainFieldName) {
2691
- return void 0;
2692
- }
2693
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2694
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2695
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2696
- );
2697
- return {
2698
- name: mainFieldName,
2699
- type: mainFieldType ?? "string"
2700
- };
2701
- };
2702
- const DEFAULT_SETTINGS = {
2703
- bulkable: false,
2704
- filterable: false,
2705
- searchable: false,
2706
- pagination: false,
2707
- defaultSortBy: "",
2708
- defaultSortOrder: "asc",
2709
- mainField: "id",
2710
- pageSize: 10
2711
- };
2712
- const useDocumentLayout = (model) => {
2713
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2714
- const [{ query }] = strapiAdmin.useQueryParams();
2715
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2716
- const { toggleNotification } = strapiAdmin.useNotification();
2717
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2718
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2719
- const {
2720
- data,
2721
- isLoading: isLoadingConfigs,
2722
- error,
2723
- isFetching: isFetchingConfigs
2724
- } = useGetContentTypeConfigurationQuery(model);
2725
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2726
- React__namespace.useEffect(() => {
2727
- if (error) {
2728
- toggleNotification({
2729
- type: "danger",
2730
- message: formatAPIError(error)
2731
- });
2732
- }
2733
- }, [error, formatAPIError, toggleNotification]);
2734
- const editLayout = React__namespace.useMemo(
2735
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2736
- layout: [],
2737
- components: {},
2738
- metadatas: {},
2739
- options: {},
2740
- settings: DEFAULT_SETTINGS
2741
- },
2742
- [data, isLoading, schemas, schema, components]
2743
- );
2744
- const listLayout = React__namespace.useMemo(() => {
2745
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2746
- layout: [],
2747
- metadatas: {},
2748
- options: {},
2749
- settings: DEFAULT_SETTINGS
2750
- };
2751
- }, [data, isLoading, schemas, schema, components]);
2752
- const { layout: edit } = React__namespace.useMemo(
2753
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2754
- layout: editLayout,
2755
- query
2756
- }),
2757
- [editLayout, query, runHookWaterfall]
2758
- );
2759
- return {
2760
- error,
2761
- isLoading,
2762
- edit,
2763
- list: listLayout
2764
- };
2765
- };
2766
- const useDocLayout = () => {
2767
- const { model } = useDoc();
2768
- return useDocumentLayout(model);
2769
- };
2770
- const formatEditLayout = (data, {
2771
- schemas,
2772
- schema,
2773
- components
2774
- }) => {
2775
- let currentPanelIndex = 0;
2776
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2777
- data.contentType.layouts.edit,
2778
- schema?.attributes,
2779
- data.contentType.metadatas,
2780
- { configurations: data.components, schemas: components },
2781
- schemas
2782
- ).reduce((panels, row) => {
2783
- if (row.some((field) => field.type === "dynamiczone")) {
2784
- panels.push([row]);
2785
- currentPanelIndex += 2;
2786
- } else {
2787
- if (!panels[currentPanelIndex]) {
2788
- panels.push([]);
2789
- }
2790
- panels[currentPanelIndex].push(row);
2791
- }
2792
- return panels;
2793
- }, []);
2794
- const componentEditAttributes = Object.entries(data.components).reduce(
2795
- (acc, [uid, configuration]) => {
2796
- acc[uid] = {
2797
- layout: convertEditLayoutToFieldLayouts(
2798
- configuration.layouts.edit,
2799
- components[uid].attributes,
2800
- configuration.metadatas,
2801
- { configurations: data.components, schemas: components }
2802
- ),
2803
- settings: {
2804
- ...configuration.settings,
2805
- icon: components[uid].info.icon,
2806
- displayName: components[uid].info.displayName
3009
+ locale: "*"
3010
+ }
3011
+ });
3012
+ if (!("error" in res)) {
3013
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
3014
+ }
3015
+ } finally {
3016
+ if (!listViewPathMatch) {
3017
+ setSubmitting(false);
3018
+ }
2807
3019
  }
2808
- };
2809
- return acc;
2810
- },
2811
- {}
2812
- );
2813
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2814
- (acc, [attribute, metadata]) => {
2815
- return {
2816
- ...acc,
2817
- [attribute]: metadata.edit
2818
- };
2819
- },
2820
- {}
2821
- );
2822
- return {
2823
- layout: panelledEditAttributes,
2824
- components: componentEditAttributes,
2825
- metadatas: editMetadatas,
2826
- settings: {
2827
- ...data.contentType.settings,
2828
- displayName: schema?.info.displayName
3020
+ }
2829
3021
  },
2830
- options: {
2831
- ...schema?.options,
2832
- ...schema?.pluginOptions,
2833
- ...data.contentType.options
2834
- }
3022
+ variant: "danger",
3023
+ position: ["header", "table-row"]
2835
3024
  };
2836
3025
  };
2837
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2838
- return rows.map(
2839
- (row) => row.map((field) => {
2840
- const attribute = attributes[field.name];
2841
- if (!attribute) {
2842
- return null;
2843
- }
2844
- const { edit: metadata } = metadatas[field.name];
2845
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2846
- return {
2847
- attribute,
2848
- disabled: !metadata.editable,
2849
- hint: metadata.description,
2850
- label: metadata.label ?? "",
2851
- name: field.name,
2852
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2853
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2854
- schemas,
2855
- components: components?.schemas ?? {}
2856
- }),
2857
- placeholder: metadata.placeholder ?? "",
2858
- required: attribute.required ?? false,
2859
- size: field.size,
2860
- unique: "unique" in attribute ? attribute.unique : false,
2861
- visible: metadata.visible ?? true,
2862
- type: attribute.type
2863
- };
2864
- }).filter((field) => field !== null)
2865
- );
3026
+ DeleteAction$1.type = "delete";
3027
+ DeleteAction$1.position = ["header", "table-row"];
3028
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
3029
+ const Panels = () => {
3030
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
3031
+ const [
3032
+ {
3033
+ query: { status }
3034
+ }
3035
+ ] = strapiAdmin.useQueryParams({
3036
+ status: "draft"
3037
+ });
3038
+ const { model, id, document, meta, collectionType } = useDoc();
3039
+ const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
3040
+ const props = {
3041
+ activeTab: status,
3042
+ model,
3043
+ documentId: id,
3044
+ document: isCloning ? void 0 : document,
3045
+ meta: isCloning ? void 0 : meta,
3046
+ collectionType
3047
+ };
3048
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3049
+ strapiAdmin.DescriptionComponentRenderer,
3050
+ {
3051
+ props,
3052
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
3053
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
3054
+ }
3055
+ ) });
2866
3056
  };
2867
- const formatListLayout = (data, {
2868
- schemas,
2869
- schema,
2870
- components
2871
- }) => {
2872
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2873
- (acc, [attribute, metadata]) => {
2874
- return {
2875
- ...acc,
2876
- [attribute]: metadata.list
2877
- };
2878
- },
2879
- {}
2880
- );
2881
- const listAttributes = convertListLayoutToFieldLayouts(
2882
- data.contentType.layouts.list,
2883
- schema?.attributes,
2884
- listMetadatas,
2885
- { configurations: data.components, schemas: components },
2886
- schemas
2887
- );
3057
+ const ActionsPanel = () => {
3058
+ const { formatMessage } = reactIntl.useIntl();
2888
3059
  return {
2889
- layout: listAttributes,
2890
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2891
- metadatas: listMetadatas,
2892
- options: {
2893
- ...schema?.options,
2894
- ...schema?.pluginOptions,
2895
- ...data.contentType.options
2896
- }
3060
+ title: formatMessage({
3061
+ id: "content-manager.containers.edit.panels.default.title",
3062
+ defaultMessage: "Entry"
3063
+ }),
3064
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2897
3065
  };
2898
3066
  };
2899
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2900
- return columns.map((name) => {
2901
- const attribute = attributes[name];
2902
- if (!attribute) {
2903
- return null;
3067
+ ActionsPanel.type = "actions";
3068
+ const ActionsPanelContent = () => {
3069
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
3070
+ const [
3071
+ {
3072
+ query: { status = "draft" }
2904
3073
  }
2905
- const metadata = metadatas[name];
2906
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2907
- return {
2908
- attribute,
2909
- label: metadata.label ?? "",
2910
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2911
- schemas,
2912
- components: components?.schemas ?? {}
2913
- }),
2914
- name,
2915
- searchable: metadata.searchable ?? true,
2916
- sortable: metadata.sortable ?? true
2917
- };
2918
- }).filter((field) => field !== null);
3074
+ ] = strapiAdmin.useQueryParams();
3075
+ const { model, id, document, meta, collectionType } = useDoc();
3076
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
3077
+ const props = {
3078
+ activeTab: status,
3079
+ model,
3080
+ documentId: id,
3081
+ document: isCloning ? void 0 : document,
3082
+ meta: isCloning ? void 0 : meta,
3083
+ collectionType
3084
+ };
3085
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3086
+ /* @__PURE__ */ jsxRuntime.jsx(
3087
+ strapiAdmin.DescriptionComponentRenderer,
3088
+ {
3089
+ props,
3090
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
3091
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3092
+ }
3093
+ ),
3094
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3095
+ ] });
2919
3096
  };
3097
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3098
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3099
+ designSystem.Flex,
3100
+ {
3101
+ ref,
3102
+ tag: "aside",
3103
+ "aria-labelledby": "additional-information",
3104
+ background: "neutral0",
3105
+ borderColor: "neutral150",
3106
+ hasRadius: true,
3107
+ paddingBottom: 4,
3108
+ paddingLeft: 4,
3109
+ paddingRight: 4,
3110
+ paddingTop: 4,
3111
+ shadow: "tableShadow",
3112
+ gap: 3,
3113
+ direction: "column",
3114
+ justifyContent: "stretch",
3115
+ alignItems: "flex-start",
3116
+ children: [
3117
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3118
+ children
3119
+ ]
3120
+ }
3121
+ );
3122
+ });
2920
3123
  const ConfirmBulkActionDialog = ({
2921
3124
  onToggleDialog,
2922
3125
  isOpen = false,
@@ -3161,18 +3364,10 @@ const SelectedEntriesTableContent = ({
3161
3364
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3162
3365
  },
3163
3366
  state: { from: pathname },
3164
- label: formatMessage(
3165
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3166
- {
3167
- target: formatMessage(
3168
- {
3169
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3170
- defaultMessage: "item line {number}"
3171
- },
3172
- { number: index2 + 1 }
3173
- )
3174
- }
3175
- ),
3367
+ label: formatMessage({
3368
+ id: "content-manager.bulk-publish.edit",
3369
+ defaultMessage: "Edit"
3370
+ }),
3176
3371
  target: "_blank",
3177
3372
  marginLeft: "auto",
3178
3373
  variant: "ghost",
@@ -3346,8 +3541,7 @@ const PublishAction = ({ documents, model }) => {
3346
3541
  const refetchList = () => {
3347
3542
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3348
3543
  };
3349
- if (!showPublishButton)
3350
- return null;
3544
+ if (!showPublishButton) return null;
3351
3545
  return {
3352
3546
  actionType: "publish",
3353
3547
  variant: "tertiary",
@@ -3415,8 +3609,7 @@ const DeleteAction = ({ documents, model }) => {
3415
3609
  selectRow([]);
3416
3610
  }
3417
3611
  };
3418
- if (!hasDeletePermission)
3419
- return null;
3612
+ if (!hasDeletePermission) return null;
3420
3613
  return {
3421
3614
  variant: "danger-light",
3422
3615
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3465,8 +3658,7 @@ const UnpublishAction = ({ documents, model }) => {
3465
3658
  }
3466
3659
  };
3467
3660
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3468
- if (!showUnpublishButton)
3469
- return null;
3661
+ if (!showUnpublishButton) return null;
3470
3662
  return {
3471
3663
  variant: "tertiary",
3472
3664
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3571,7 +3763,7 @@ const TableActions = ({ document }) => {
3571
3763
  strapiAdmin.DescriptionComponentRenderer,
3572
3764
  {
3573
3765
  props,
3574
- descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3766
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3575
3767
  children: (actions2) => {
3576
3768
  const tableRowActions = actions2.filter((action) => {
3577
3769
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3630,6 +3822,7 @@ const EditAction = ({ documentId }) => {
3630
3822
  };
3631
3823
  };
3632
3824
  EditAction.type = "edit";
3825
+ EditAction.position = "table-row";
3633
3826
  const StyledPencil = styledComponents.styled(Icons.Pencil)`
3634
3827
  path {
3635
3828
  fill: currentColor;
@@ -3706,6 +3899,7 @@ const CloneAction = ({ model, documentId }) => {
3706
3899
  };
3707
3900
  };
3708
3901
  CloneAction.type = "clone";
3902
+ CloneAction.position = "table-row";
3709
3903
  const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
3710
3904
  path {
3711
3905
  fill: currentColor;
@@ -3792,7 +3986,14 @@ class ContentManagerPlugin {
3792
3986
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3793
3987
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3794
3988
  getBulkActions: () => this.bulkActions,
3795
- getDocumentActions: () => this.documentActions,
3989
+ getDocumentActions: (position) => {
3990
+ if (position) {
3991
+ return this.documentActions.filter(
3992
+ (action) => action.position == void 0 || [action.position].flat().includes(position)
3993
+ );
3994
+ }
3995
+ return this.documentActions;
3996
+ },
3796
3997
  getEditViewSidePanels: () => this.editViewSidePanels,
3797
3998
  getHeaderActions: () => this.headerActions
3798
3999
  }
@@ -3802,10 +4003,8 @@ class ContentManagerPlugin {
3802
4003
  const getPrintableType = (value) => {
3803
4004
  const nativeType = typeof value;
3804
4005
  if (nativeType === "object") {
3805
- if (value === null)
3806
- return "null";
3807
- if (Array.isArray(value))
3808
- return "array";
4006
+ if (value === null) return "null";
4007
+ if (Array.isArray(value)) return "array";
3809
4008
  if (value instanceof Object && value.constructor.name !== "Object") {
3810
4009
  return value.constructor.name;
3811
4010
  }
@@ -3816,17 +4015,27 @@ const HistoryAction = ({ model, document }) => {
3816
4015
  const { formatMessage } = reactIntl.useIntl();
3817
4016
  const [{ query }] = strapiAdmin.useQueryParams();
3818
4017
  const navigate = reactRouterDom.useNavigate();
4018
+ const { trackUsage } = strapiAdmin.useTracking();
4019
+ const { pathname } = reactRouterDom.useLocation();
3819
4020
  const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3820
4021
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3821
4022
  return null;
3822
4023
  }
4024
+ const handleOnClick = () => {
4025
+ const destination = { pathname: "history", search: pluginsQueryParams };
4026
+ trackUsage("willNavigate", {
4027
+ from: pathname,
4028
+ to: `${pathname}/${destination.pathname}`
4029
+ });
4030
+ navigate(destination);
4031
+ };
3823
4032
  return {
3824
4033
  icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3825
4034
  label: formatMessage({
3826
4035
  id: "content-manager.history.document-action",
3827
4036
  defaultMessage: "Content History"
3828
4037
  }),
3829
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
4038
+ onClick: handleOnClick,
3830
4039
  disabled: (
3831
4040
  /**
3832
4041
  * The user is creating a new document.
@@ -3848,6 +4057,7 @@ const HistoryAction = ({ model, document }) => {
3848
4057
  };
3849
4058
  };
3850
4059
  HistoryAction.type = "history";
4060
+ HistoryAction.position = "header";
3851
4061
  const historyAdmin = {
3852
4062
  bootstrap(app) {
3853
4063
  const { addDocumentAction } = app.getPlugin("content-manager").apis;
@@ -3894,6 +4104,88 @@ const { setInitialData } = actions;
3894
4104
  const reducer = toolkit.combineReducers({
3895
4105
  app: reducer$1
3896
4106
  });
4107
+ const previewApi = contentManagerApi.injectEndpoints({
4108
+ endpoints: (builder) => ({
4109
+ getPreviewUrl: builder.query({
4110
+ query({ query, params }) {
4111
+ return {
4112
+ url: `/content-manager/preview/url/${params.contentType}`,
4113
+ method: "GET",
4114
+ config: {
4115
+ params: query
4116
+ }
4117
+ };
4118
+ }
4119
+ })
4120
+ })
4121
+ });
4122
+ const { useGetPreviewUrlQuery } = previewApi;
4123
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4124
+ if (isShown) {
4125
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label, children });
4126
+ }
4127
+ return children;
4128
+ };
4129
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4130
+ const { formatMessage } = reactIntl.useIntl();
4131
+ const { trackUsage } = strapiAdmin.useTracking();
4132
+ const { pathname } = reactRouterDom.useLocation();
4133
+ const [{ query }] = strapiAdmin.useQueryParams();
4134
+ const isModified = strapiAdmin.useForm("PreviewSidePanel", (state) => state.modified);
4135
+ const { data, error } = useGetPreviewUrlQuery({
4136
+ params: {
4137
+ contentType: model
4138
+ },
4139
+ query: {
4140
+ documentId,
4141
+ locale: document?.locale,
4142
+ status: document?.status
4143
+ }
4144
+ });
4145
+ if (!data?.data?.url || error) {
4146
+ return null;
4147
+ }
4148
+ const trackNavigation = () => {
4149
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4150
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4151
+ };
4152
+ return {
4153
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4154
+ content: /* @__PURE__ */ jsxRuntime.jsx(
4155
+ ConditionalTooltip,
4156
+ {
4157
+ label: formatMessage({
4158
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4159
+ defaultMessage: "Please save to open the preview"
4160
+ }),
4161
+ isShown: isModified,
4162
+ children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
4163
+ designSystem.Button,
4164
+ {
4165
+ variant: "tertiary",
4166
+ tag: reactRouterDom.Link,
4167
+ to: { pathname: "preview", search: qs.stringify(query, { encode: false }) },
4168
+ onClick: trackNavigation,
4169
+ width: "100%",
4170
+ disabled: isModified,
4171
+ pointerEvents: isModified ? "none" : void 0,
4172
+ tabIndex: isModified ? -1 : void 0,
4173
+ children: formatMessage({
4174
+ id: "content-manager.preview.panel.button",
4175
+ defaultMessage: "Open preview"
4176
+ })
4177
+ }
4178
+ ) })
4179
+ }
4180
+ )
4181
+ };
4182
+ };
4183
+ const previewAdmin = {
4184
+ bootstrap(app) {
4185
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4186
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4187
+ }
4188
+ };
3897
4189
  const index = {
3898
4190
  register(app) {
3899
4191
  const cm = new ContentManagerPlugin();
@@ -3913,7 +4205,7 @@ const index = {
3913
4205
  app.router.addRoute({
3914
4206
  path: "content-manager/*",
3915
4207
  lazy: async () => {
3916
- const { Layout } = await Promise.resolve().then(() => require("./layout-B4XAqu1v.js"));
4208
+ const { Layout } = await Promise.resolve().then(() => require("./layout-B_qdWGny.js"));
3917
4209
  return {
3918
4210
  Component: Layout
3919
4211
  };
@@ -3926,11 +4218,14 @@ const index = {
3926
4218
  if (typeof historyAdmin.bootstrap === "function") {
3927
4219
  historyAdmin.bootstrap(app);
3928
4220
  }
4221
+ if (typeof previewAdmin.bootstrap === "function") {
4222
+ previewAdmin.bootstrap(app);
4223
+ }
3929
4224
  },
3930
4225
  async registerTrads({ locales }) {
3931
4226
  const importedTrads = await Promise.all(
3932
4227
  locales.map((locale) => {
3933
- 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-Cf41pH5f.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 }) => {
4228
+ 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-BK8Xyl5I.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`, 3).then(({ default: data }) => {
3934
4229
  return {
3935
4230
  data: prefixPluginTranslations(data, PLUGIN_ID),
3936
4231
  locale
@@ -3976,6 +4271,7 @@ exports.getMainField = getMainField;
3976
4271
  exports.getTranslation = getTranslation;
3977
4272
  exports.index = index;
3978
4273
  exports.setInitialData = setInitialData;
4274
+ exports.useContentManagerContext = useContentManagerContext;
3979
4275
  exports.useContentTypeSchema = useContentTypeSchema;
3980
4276
  exports.useDoc = useDoc;
3981
4277
  exports.useDocLayout = useDocLayout;
@@ -3987,5 +4283,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
3987
4283
  exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3988
4284
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3989
4285
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
4286
+ exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
3990
4287
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3991
- //# sourceMappingURL=index-CQos-KS0.js.map
4288
+ //# sourceMappingURL=index-CnX_j5h-.js.map