@strapi/content-manager 0.0.0-experimental.93a73ca8c7b85667fe8e46c0cb6627506570a02f → 0.0.0-experimental.953e1857bbad81a3c34f5d6511736c1bc8b91dcb

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 (179) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-KXSuLnQD.js → ComponentConfigurationPage-CpJNPBgk.js} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-KXSuLnQD.js.map → ComponentConfigurationPage-CpJNPBgk.js.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-B3yDbeU1.mjs → ComponentConfigurationPage-TYDPg5WG.mjs} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-B3yDbeU1.mjs.map → ComponentConfigurationPage-TYDPg5WG.mjs.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-BQ17--5R.js → EditConfigurationPage-CFDe6SA1.js} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-BQ17--5R.js.map → EditConfigurationPage-CFDe6SA1.js.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-D7PrLO8j.mjs → EditConfigurationPage-DqL8Pq5r.mjs} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-D7PrLO8j.mjs.map → EditConfigurationPage-DqL8Pq5r.mjs.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-B7VgwJaG.mjs → EditViewPage-RXrFLav2.mjs} +15 -5
  10. package/dist/_chunks/EditViewPage-RXrFLav2.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-BgjdnGz2.js → EditViewPage-khfP2CR3.js} +15 -5
  12. package/dist/_chunks/EditViewPage-khfP2CR3.js.map +1 -0
  13. package/dist/_chunks/{Field-tHCw4lGA.mjs → Field--rQeS6Zj.mjs} +99 -86
  14. package/dist/_chunks/Field--rQeS6Zj.mjs.map +1 -0
  15. package/dist/_chunks/{Field-CdK7ZLmv.js → Field-C1ftmTe9.js} +102 -89
  16. package/dist/_chunks/Field-C1ftmTe9.js.map +1 -0
  17. package/dist/_chunks/{Form-BJxdTv3Q.mjs → Form-COtGXyUE.mjs} +16 -8
  18. package/dist/_chunks/Form-COtGXyUE.mjs.map +1 -0
  19. package/dist/_chunks/{Form-C_0KTVvV.js → Form-CwdX5oLw.js} +16 -8
  20. package/dist/_chunks/Form-CwdX5oLw.js.map +1 -0
  21. package/dist/_chunks/{History-DR2txJLE.mjs → History-BevwkPO1.mjs} +38 -41
  22. package/dist/_chunks/History-BevwkPO1.mjs.map +1 -0
  23. package/dist/_chunks/{History-nuEzM5qm.js → History-DKS2aqqM.js} +37 -40
  24. package/dist/_chunks/History-DKS2aqqM.js.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-voFVtXu6.mjs → ListConfigurationPage-DNfZDtDA.mjs} +3 -3
  26. package/dist/_chunks/{ListConfigurationPage-voFVtXu6.mjs.map → ListConfigurationPage-DNfZDtDA.mjs.map} +1 -1
  27. package/dist/_chunks/{ListConfigurationPage-CnB86Psm.js → ListConfigurationPage-LSYSPZHH.js} +3 -3
  28. package/dist/_chunks/{ListConfigurationPage-CnB86Psm.js.map → ListConfigurationPage-LSYSPZHH.js.map} +1 -1
  29. package/dist/_chunks/{ListViewPage-B_GaWgRH.mjs → ListViewPage-C1PyuYRS.mjs} +52 -37
  30. package/dist/_chunks/ListViewPage-C1PyuYRS.mjs.map +1 -0
  31. package/dist/_chunks/{ListViewPage-SXIXm-RM.js → ListViewPage-DlUpqLIo.js} +55 -40
  32. package/dist/_chunks/ListViewPage-DlUpqLIo.js.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-CYiGpsbj.mjs → NoContentTypePage-C9q744z1.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-CYiGpsbj.mjs.map → NoContentTypePage-C9q744z1.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-BzsQ3hLZ.js → NoContentTypePage-m8wt3sf6.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-BzsQ3hLZ.js.map → NoContentTypePage-m8wt3sf6.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-B5baIHal.mjs → NoPermissionsPage-8BM-LWta.mjs} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-B5baIHal.mjs.map → NoPermissionsPage-8BM-LWta.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-IGkId4C5.js → NoPermissionsPage-DLfPsA0Q.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-IGkId4C5.js.map → NoPermissionsPage-DLfPsA0Q.js.map} +1 -1
  41. package/dist/_chunks/{Relations-CIYDdKU-.mjs → Relations-D25xRcFy.mjs} +72 -36
  42. package/dist/_chunks/Relations-D25xRcFy.mjs.map +1 -0
  43. package/dist/_chunks/{Relations-Dhuurpx2.js → Relations-OMriCP_L.js} +71 -35
  44. package/dist/_chunks/Relations-OMriCP_L.js.map +1 -0
  45. package/dist/_chunks/{en-uOUIxfcQ.js → en-Bdpa50w3.js} +18 -13
  46. package/dist/_chunks/{en-uOUIxfcQ.js.map → en-Bdpa50w3.js.map} +1 -1
  47. package/dist/_chunks/{en-BrCTWlZv.mjs → en-CZw4xdPY.mjs} +18 -13
  48. package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-CZw4xdPY.mjs.map} +1 -1
  49. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  50. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  51. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  52. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  53. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  54. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  55. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  56. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  57. package/dist/_chunks/{index-C9TJPyni.mjs → index-BvGihCJp.mjs} +954 -718
  58. package/dist/_chunks/index-BvGihCJp.mjs.map +1 -0
  59. package/dist/_chunks/{index-CdT0kHZ8.js → index-DqZnjo8F.js} +935 -698
  60. package/dist/_chunks/index-DqZnjo8F.js.map +1 -0
  61. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  62. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  63. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  64. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  65. package/dist/_chunks/{layout-C6dxWYT7.js → layout-CmaemAO3.js} +5 -4
  66. package/dist/_chunks/{layout-C6dxWYT7.js.map → layout-CmaemAO3.js.map} +1 -1
  67. package/dist/_chunks/{layout-BNqvLR_b.mjs → layout-ykHSe2KQ.mjs} +5 -4
  68. package/dist/_chunks/{layout-BNqvLR_b.mjs.map → layout-ykHSe2KQ.mjs.map} +1 -1
  69. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  70. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  71. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  72. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  73. package/dist/_chunks/{relations-DtFaDnP1.js → relations-D9fKsCLY.js} +3 -7
  74. package/dist/_chunks/relations-D9fKsCLY.js.map +1 -0
  75. package/dist/_chunks/{relations-CkKqKw65.mjs → relations-u-Vz51Ea.mjs} +3 -7
  76. package/dist/_chunks/relations-u-Vz51Ea.mjs.map +1 -0
  77. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  78. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  79. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  80. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  81. package/dist/admin/index.js +2 -1
  82. package/dist/admin/index.js.map +1 -1
  83. package/dist/admin/index.mjs +5 -4
  84. package/dist/admin/src/exports.d.ts +1 -1
  85. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  86. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  87. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +0 -32
  88. package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
  89. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  90. package/dist/admin/src/preview/constants.d.ts +1 -0
  91. package/dist/admin/src/preview/index.d.ts +4 -0
  92. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  93. package/dist/admin/src/services/api.d.ts +1 -1
  94. package/dist/admin/src/services/components.d.ts +2 -2
  95. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  96. package/dist/admin/src/services/documents.d.ts +19 -17
  97. package/dist/admin/src/services/init.d.ts +1 -1
  98. package/dist/admin/src/services/relations.d.ts +2 -2
  99. package/dist/admin/src/services/uid.d.ts +3 -3
  100. package/dist/admin/src/utils/validation.d.ts +4 -1
  101. package/dist/server/index.js +421 -183
  102. package/dist/server/index.js.map +1 -1
  103. package/dist/server/index.mjs +421 -183
  104. package/dist/server/index.mjs.map +1 -1
  105. package/dist/server/src/bootstrap.d.ts.map +1 -1
  106. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  107. package/dist/server/src/controllers/index.d.ts.map +1 -1
  108. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  109. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  110. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  111. package/dist/server/src/history/services/history.d.ts.map +1 -1
  112. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  113. package/dist/server/src/history/services/utils.d.ts +3 -3
  114. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  115. package/dist/server/src/index.d.ts +4 -4
  116. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  117. package/dist/server/src/preview/constants.d.ts +2 -0
  118. package/dist/server/src/preview/constants.d.ts.map +1 -0
  119. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  120. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  121. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  122. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  123. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  124. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  125. package/dist/server/src/preview/index.d.ts +4 -0
  126. package/dist/server/src/preview/index.d.ts.map +1 -0
  127. package/dist/server/src/preview/routes/index.d.ts +8 -0
  128. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  129. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  130. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  131. package/dist/server/src/preview/services/index.d.ts +15 -0
  132. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  133. package/dist/server/src/preview/services/preview-config.d.ts +30 -0
  134. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  135. package/dist/server/src/preview/services/preview.d.ts +12 -0
  136. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  137. package/dist/server/src/preview/utils.d.ts +18 -0
  138. package/dist/server/src/preview/utils.d.ts.map +1 -0
  139. package/dist/server/src/routes/index.d.ts.map +1 -1
  140. package/dist/server/src/services/document-metadata.d.ts +8 -8
  141. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  142. package/dist/server/src/services/index.d.ts +4 -4
  143. package/dist/server/src/services/index.d.ts.map +1 -1
  144. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  145. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  146. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  147. package/dist/server/src/utils/index.d.ts +2 -0
  148. package/dist/server/src/utils/index.d.ts.map +1 -1
  149. package/dist/shared/contracts/collection-types.d.ts +3 -1
  150. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  151. package/dist/shared/contracts/index.d.ts +1 -0
  152. package/dist/shared/contracts/index.d.ts.map +1 -1
  153. package/dist/shared/contracts/preview.d.ts +27 -0
  154. package/dist/shared/contracts/preview.d.ts.map +1 -0
  155. package/dist/shared/index.js +4 -0
  156. package/dist/shared/index.js.map +1 -1
  157. package/dist/shared/index.mjs +4 -0
  158. package/dist/shared/index.mjs.map +1 -1
  159. package/package.json +13 -13
  160. package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +0 -1
  161. package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +0 -1
  162. package/dist/_chunks/Field-CdK7ZLmv.js.map +0 -1
  163. package/dist/_chunks/Field-tHCw4lGA.mjs.map +0 -1
  164. package/dist/_chunks/Form-BJxdTv3Q.mjs.map +0 -1
  165. package/dist/_chunks/Form-C_0KTVvV.js.map +0 -1
  166. package/dist/_chunks/History-DR2txJLE.mjs.map +0 -1
  167. package/dist/_chunks/History-nuEzM5qm.js.map +0 -1
  168. package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +0 -1
  169. package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +0 -1
  170. package/dist/_chunks/Relations-CIYDdKU-.mjs.map +0 -1
  171. package/dist/_chunks/Relations-Dhuurpx2.js.map +0 -1
  172. package/dist/_chunks/index-C9TJPyni.mjs.map +0 -1
  173. package/dist/_chunks/index-CdT0kHZ8.js.map +0 -1
  174. package/dist/_chunks/relations-CkKqKw65.mjs.map +0 -1
  175. package/dist/_chunks/relations-DtFaDnP1.js.map +0 -1
  176. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  177. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  178. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
  179. package/strapi-server.js +0 -3
@@ -4,12 +4,13 @@ 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");
9
- const styledComponents = require("styled-components");
10
10
  const yup = require("yup");
11
11
  const pipe = require("lodash/fp/pipe");
12
12
  const dateFns = require("date-fns");
13
+ const styledComponents = require("styled-components");
13
14
  const qs = require("qs");
14
15
  const toolkit = require("@reduxjs/toolkit");
15
16
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
@@ -32,6 +33,7 @@ function _interopNamespace(e) {
32
33
  return Object.freeze(n);
33
34
  }
34
35
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
36
+ const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
35
37
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
36
38
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
37
39
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
@@ -121,6 +123,7 @@ const DocumentRBAC = ({ children, permissions }) => {
121
123
  if (!slug) {
122
124
  throw new Error("Cannot find the slug param in the URL");
123
125
  }
126
+ const [{ rawQuery }] = strapiAdmin.useQueryParams();
124
127
  const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
125
128
  const contentTypePermissions = React__namespace.useMemo(() => {
126
129
  const contentTypePermissions2 = userPermissions.filter(
@@ -131,7 +134,14 @@ const DocumentRBAC = ({ children, permissions }) => {
131
134
  return { ...acc, [action]: [permission] };
132
135
  }, {});
133
136
  }, [slug, userPermissions]);
134
- const { isLoading, allowedActions } = strapiAdmin.useRBAC(contentTypePermissions, permissions ?? void 0);
137
+ const { isLoading, allowedActions } = strapiAdmin.useRBAC(
138
+ contentTypePermissions,
139
+ permissions ?? void 0,
140
+ // TODO: useRBAC context should be typed and built differently
141
+ // We are passing raw query as context to the hook so that it can
142
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
143
+ rawQuery
144
+ );
135
145
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
136
146
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
137
147
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -179,7 +189,8 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
179
189
  "Document",
180
190
  "InitialData",
181
191
  "HistoryVersion",
182
- "Relations"
192
+ "Relations",
193
+ "UidAvailability"
183
194
  ]
184
195
  });
185
196
  const documentApi = contentManagerApi.injectEndpoints({
@@ -209,7 +220,10 @@ const documentApi = contentManagerApi.injectEndpoints({
209
220
  params
210
221
  }
211
222
  }),
212
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
223
+ invalidatesTags: (_result, _error, { model }) => [
224
+ { type: "Document", id: `${model}_LIST` },
225
+ { type: "UidAvailability", id: model }
226
+ ]
213
227
  }),
214
228
  /**
215
229
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -226,7 +240,8 @@ const documentApi = contentManagerApi.injectEndpoints({
226
240
  }),
227
241
  invalidatesTags: (result, _error, { model }) => [
228
242
  { type: "Document", id: `${model}_LIST` },
229
- "Relations"
243
+ "Relations",
244
+ { type: "UidAvailability", id: model }
230
245
  ]
231
246
  }),
232
247
  deleteDocument: builder.mutation({
@@ -267,7 +282,8 @@ const documentApi = contentManagerApi.injectEndpoints({
267
282
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
268
283
  },
269
284
  { type: "Document", id: `${model}_LIST` },
270
- "Relations"
285
+ "Relations",
286
+ { type: "UidAvailability", id: model }
271
287
  ];
272
288
  }
273
289
  }),
@@ -392,7 +408,8 @@ const documentApi = contentManagerApi.injectEndpoints({
392
408
  type: "Document",
393
409
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
394
410
  },
395
- "Relations"
411
+ "Relations",
412
+ { type: "UidAvailability", id: model }
396
413
  ];
397
414
  },
398
415
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -475,20 +492,39 @@ const buildValidParams = (query) => {
475
492
  const isBaseQueryError = (error) => {
476
493
  return error.name !== void 0;
477
494
  };
478
- const createYupSchema = (attributes = {}, components = {}) => {
495
+ const arrayValidator = (attribute, options) => ({
496
+ message: strapiAdmin.translatedErrors.required,
497
+ test(value) {
498
+ if (options.status === "draft") {
499
+ return true;
500
+ }
501
+ if (!attribute.required) {
502
+ return true;
503
+ }
504
+ if (!value) {
505
+ return false;
506
+ }
507
+ if (Array.isArray(value) && value.length === 0) {
508
+ return false;
509
+ }
510
+ return true;
511
+ }
512
+ });
513
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
479
514
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
480
515
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
481
516
  if (DOCUMENT_META_FIELDS.includes(name)) {
482
517
  return acc;
483
518
  }
484
519
  const validations = [
520
+ addNullableValidation,
485
521
  addRequiredValidation,
486
522
  addMinLengthValidation,
487
523
  addMaxLengthValidation,
488
524
  addMinValidation,
489
525
  addMaxValidation,
490
526
  addRegexValidation
491
- ].map((fn) => fn(attribute));
527
+ ].map((fn) => fn(attribute, options));
492
528
  const transformSchema = pipe__default.default(...validations);
493
529
  switch (attribute.type) {
494
530
  case "component": {
@@ -498,12 +534,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
498
534
  ...acc,
499
535
  [name]: transformSchema(
500
536
  yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
501
- )
537
+ ).test(arrayValidator(attribute, options))
502
538
  };
503
539
  } else {
504
540
  return {
505
541
  ...acc,
506
- [name]: transformSchema(createModelSchema(attributes3))
542
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
507
543
  };
508
544
  }
509
545
  }
@@ -525,7 +561,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
525
561
  }
526
562
  )
527
563
  )
528
- )
564
+ ).test(arrayValidator(attribute, options))
529
565
  };
530
566
  case "relation":
531
567
  return {
@@ -537,7 +573,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
537
573
  } else if (Array.isArray(value)) {
538
574
  return yup__namespace.array().of(
539
575
  yup__namespace.object().shape({
540
- id: yup__namespace.string().required()
576
+ id: yup__namespace.number().required()
541
577
  })
542
578
  );
543
579
  } else if (typeof value === "object") {
@@ -615,13 +651,7 @@ const createAttributeSchema = (attribute) => {
615
651
  return yup__namespace.mixed();
616
652
  }
617
653
  };
618
- const addRequiredValidation = (attribute) => (schema) => {
619
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
620
- return schema.min(1, strapiAdmin.translatedErrors.required);
621
- }
622
- if (attribute.required && attribute.type !== "relation") {
623
- return schema.required(strapiAdmin.translatedErrors.required);
624
- }
654
+ const nullableSchema = (schema) => {
625
655
  return schema?.nullable ? schema.nullable() : (
626
656
  // In some cases '.nullable' will not be available on the schema.
627
657
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -629,7 +659,22 @@ const addRequiredValidation = (attribute) => (schema) => {
629
659
  schema
630
660
  );
631
661
  };
632
- const addMinLengthValidation = (attribute) => (schema) => {
662
+ const addNullableValidation = () => (schema) => {
663
+ return nullableSchema(schema);
664
+ };
665
+ const addRequiredValidation = (attribute, options) => (schema) => {
666
+ if (options.status === "draft" || !attribute.required) {
667
+ return schema;
668
+ }
669
+ if (attribute.required && "required" in schema) {
670
+ return schema.required(strapiAdmin.translatedErrors.required);
671
+ }
672
+ return schema;
673
+ };
674
+ const addMinLengthValidation = (attribute, options) => (schema) => {
675
+ if (options.status === "draft") {
676
+ return schema;
677
+ }
633
678
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
634
679
  return schema.min(attribute.minLength, {
635
680
  ...strapiAdmin.translatedErrors.minLength,
@@ -651,32 +696,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
651
696
  }
652
697
  return schema;
653
698
  };
654
- const addMinValidation = (attribute) => (schema) => {
655
- if ("min" in attribute) {
699
+ const addMinValidation = (attribute, options) => (schema) => {
700
+ if (options.status === "draft") {
701
+ return schema;
702
+ }
703
+ if ("min" in attribute && "min" in schema) {
656
704
  const min = toInteger(attribute.min);
657
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
658
- if (!attribute.required && "test" in schema && min) {
659
- return schema.test(
660
- "custom-min",
661
- {
662
- ...strapiAdmin.translatedErrors.min,
663
- values: {
664
- min: attribute.min
665
- }
666
- },
667
- (value) => {
668
- if (!value) {
669
- return true;
670
- }
671
- if (Array.isArray(value) && value.length === 0) {
672
- return true;
673
- }
674
- return value.length >= min;
675
- }
676
- );
677
- }
678
- }
679
- if ("min" in schema && min) {
705
+ if (min) {
680
706
  return schema.min(min, {
681
707
  ...strapiAdmin.translatedErrors.min,
682
708
  values: {
@@ -794,19 +820,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
794
820
  }, {});
795
821
  return componentsByKey;
796
822
  };
797
- const useDocument = (args, opts) => {
823
+ const HOOKS = {
824
+ /**
825
+ * Hook that allows to mutate the displayed headers of the list view table
826
+ * @constant
827
+ * @type {string}
828
+ */
829
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
830
+ /**
831
+ * Hook that allows to mutate the CM's collection types links pre-set filters
832
+ * @constant
833
+ * @type {string}
834
+ */
835
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
836
+ /**
837
+ * Hook that allows to mutate the CM's edit view layout
838
+ * @constant
839
+ * @type {string}
840
+ */
841
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
842
+ /**
843
+ * Hook that allows to mutate the CM's single types links pre-set filters
844
+ * @constant
845
+ * @type {string}
846
+ */
847
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
848
+ };
849
+ const contentTypesApi = contentManagerApi.injectEndpoints({
850
+ endpoints: (builder) => ({
851
+ getContentTypeConfiguration: builder.query({
852
+ query: (uid) => ({
853
+ url: `/content-manager/content-types/${uid}/configuration`,
854
+ method: "GET"
855
+ }),
856
+ transformResponse: (response) => response.data,
857
+ providesTags: (_result, _error, uid) => [
858
+ { type: "ContentTypesConfiguration", id: uid },
859
+ { type: "ContentTypeSettings", id: "LIST" }
860
+ ]
861
+ }),
862
+ getAllContentTypeSettings: builder.query({
863
+ query: () => "/content-manager/content-types-settings",
864
+ transformResponse: (response) => response.data,
865
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
866
+ }),
867
+ updateContentTypeConfiguration: builder.mutation({
868
+ query: ({ uid, ...body }) => ({
869
+ url: `/content-manager/content-types/${uid}/configuration`,
870
+ method: "PUT",
871
+ data: body
872
+ }),
873
+ transformResponse: (response) => response.data,
874
+ invalidatesTags: (_result, _error, { uid }) => [
875
+ { type: "ContentTypesConfiguration", id: uid },
876
+ { type: "ContentTypeSettings", id: "LIST" },
877
+ // Is this necessary?
878
+ { type: "InitialData" }
879
+ ]
880
+ })
881
+ })
882
+ });
883
+ const {
884
+ useGetContentTypeConfigurationQuery,
885
+ useGetAllContentTypeSettingsQuery,
886
+ useUpdateContentTypeConfigurationMutation
887
+ } = contentTypesApi;
888
+ const checkIfAttributeIsDisplayable = (attribute) => {
889
+ const { type } = attribute;
890
+ if (type === "relation") {
891
+ return !attribute.relation.toLowerCase().includes("morph");
892
+ }
893
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
894
+ };
895
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
896
+ if (!mainFieldName) {
897
+ return void 0;
898
+ }
899
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
900
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
901
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
902
+ );
903
+ return {
904
+ name: mainFieldName,
905
+ type: mainFieldType ?? "string"
906
+ };
907
+ };
908
+ const DEFAULT_SETTINGS = {
909
+ bulkable: false,
910
+ filterable: false,
911
+ searchable: false,
912
+ pagination: false,
913
+ defaultSortBy: "",
914
+ defaultSortOrder: "asc",
915
+ mainField: "id",
916
+ pageSize: 10
917
+ };
918
+ const useDocumentLayout = (model) => {
919
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
920
+ const [{ query }] = strapiAdmin.useQueryParams();
921
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
798
922
  const { toggleNotification } = strapiAdmin.useNotification();
799
923
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
924
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
800
925
  const {
801
- currentData: data,
802
- isLoading: isLoadingDocument,
803
- isFetching: isFetchingDocument,
804
- error
805
- } = useGetDocumentQuery(args, {
806
- ...opts,
807
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
808
- });
809
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
926
+ data,
927
+ isLoading: isLoadingConfigs,
928
+ error,
929
+ isFetching: isFetchingConfigs
930
+ } = useGetContentTypeConfigurationQuery(model);
931
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
810
932
  React__namespace.useEffect(() => {
811
933
  if (error) {
812
934
  toggleNotification({
@@ -814,93 +936,349 @@ const useDocument = (args, opts) => {
814
936
  message: formatAPIError(error)
815
937
  });
816
938
  }
817
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
818
- const validationSchema = React__namespace.useMemo(() => {
819
- if (!schema) {
820
- return null;
821
- }
822
- return createYupSchema(schema.attributes, components);
823
- }, [schema, components]);
824
- const validate = React__namespace.useCallback(
825
- (document) => {
826
- if (!validationSchema) {
827
- throw new Error(
828
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
829
- );
830
- }
831
- try {
832
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
833
- return null;
834
- } catch (error2) {
835
- if (error2 instanceof yup.ValidationError) {
836
- return strapiAdmin.getYupValidationErrors(error2);
837
- }
838
- throw error2;
839
- }
939
+ }, [error, formatAPIError, toggleNotification]);
940
+ const editLayout = React__namespace.useMemo(
941
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
942
+ layout: [],
943
+ components: {},
944
+ metadatas: {},
945
+ options: {},
946
+ settings: DEFAULT_SETTINGS
840
947
  },
841
- [validationSchema]
948
+ [data, isLoading, schemas, schema, components]
949
+ );
950
+ const listLayout = React__namespace.useMemo(() => {
951
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
952
+ layout: [],
953
+ metadatas: {},
954
+ options: {},
955
+ settings: DEFAULT_SETTINGS
956
+ };
957
+ }, [data, isLoading, schemas, schema, components]);
958
+ const { layout: edit } = React__namespace.useMemo(
959
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
960
+ layout: editLayout,
961
+ query
962
+ }),
963
+ [editLayout, query, runHookWaterfall]
842
964
  );
843
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
844
965
  return {
845
- components,
846
- document: data?.data,
847
- meta: data?.meta,
966
+ error,
848
967
  isLoading,
849
- schema,
850
- validate
851
- };
852
- };
853
- const useDoc = () => {
854
- const { id, slug, collectionType, origin } = reactRouterDom.useParams();
855
- const [{ query }] = strapiAdmin.useQueryParams();
856
- const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
857
- if (!collectionType) {
858
- throw new Error("Could not find collectionType in url params");
859
- }
860
- if (!slug) {
861
- throw new Error("Could not find model in url params");
862
- }
863
- return {
864
- collectionType,
865
- model: slug,
866
- id: origin || id === "create" ? void 0 : id,
867
- ...useDocument(
868
- { documentId: origin || id, model: slug, collectionType, params },
869
- {
870
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
871
- }
872
- )
968
+ edit,
969
+ list: listLayout
873
970
  };
874
971
  };
875
- const prefixPluginTranslations = (trad, pluginId) => {
876
- if (!pluginId) {
877
- throw new TypeError("pluginId can't be empty");
878
- }
879
- return Object.keys(trad).reduce((acc, current) => {
880
- acc[`${pluginId}.${current}`] = trad[current];
881
- return acc;
882
- }, {});
883
- };
884
- const getTranslation = (id) => `content-manager.${id}`;
885
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
886
- id: "notification.error",
887
- defaultMessage: "An error occurred, please try again"
972
+ const useDocLayout = () => {
973
+ const { model } = useDoc();
974
+ return useDocumentLayout(model);
888
975
  };
889
- const useDocumentActions = () => {
890
- const { toggleNotification } = strapiAdmin.useNotification();
891
- const { formatMessage } = reactIntl.useIntl();
892
- const { trackUsage } = strapiAdmin.useTracking();
893
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
894
- const [deleteDocument] = useDeleteDocumentMutation();
895
- const _delete = React__namespace.useCallback(
896
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
897
- try {
898
- trackUsage("willDeleteEntry", trackerProperty);
899
- const res = await deleteDocument({
900
- collectionType,
901
- model,
902
- documentId,
903
- params
976
+ const formatEditLayout = (data, {
977
+ schemas,
978
+ schema,
979
+ components
980
+ }) => {
981
+ let currentPanelIndex = 0;
982
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
983
+ data.contentType.layouts.edit,
984
+ schema?.attributes,
985
+ data.contentType.metadatas,
986
+ { configurations: data.components, schemas: components },
987
+ schemas
988
+ ).reduce((panels, row) => {
989
+ if (row.some((field) => field.type === "dynamiczone")) {
990
+ panels.push([row]);
991
+ currentPanelIndex += 2;
992
+ } else {
993
+ if (!panels[currentPanelIndex]) {
994
+ panels.push([row]);
995
+ } else {
996
+ panels[currentPanelIndex].push(row);
997
+ }
998
+ }
999
+ return panels;
1000
+ }, []);
1001
+ const componentEditAttributes = Object.entries(data.components).reduce(
1002
+ (acc, [uid, configuration]) => {
1003
+ acc[uid] = {
1004
+ layout: convertEditLayoutToFieldLayouts(
1005
+ configuration.layouts.edit,
1006
+ components[uid].attributes,
1007
+ configuration.metadatas,
1008
+ { configurations: data.components, schemas: components }
1009
+ ),
1010
+ settings: {
1011
+ ...configuration.settings,
1012
+ icon: components[uid].info.icon,
1013
+ displayName: components[uid].info.displayName
1014
+ }
1015
+ };
1016
+ return acc;
1017
+ },
1018
+ {}
1019
+ );
1020
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
1021
+ (acc, [attribute, metadata]) => {
1022
+ return {
1023
+ ...acc,
1024
+ [attribute]: metadata.edit
1025
+ };
1026
+ },
1027
+ {}
1028
+ );
1029
+ return {
1030
+ layout: panelledEditAttributes,
1031
+ components: componentEditAttributes,
1032
+ metadatas: editMetadatas,
1033
+ settings: {
1034
+ ...data.contentType.settings,
1035
+ displayName: schema?.info.displayName
1036
+ },
1037
+ options: {
1038
+ ...schema?.options,
1039
+ ...schema?.pluginOptions,
1040
+ ...data.contentType.options
1041
+ }
1042
+ };
1043
+ };
1044
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1045
+ return rows.map(
1046
+ (row) => row.map((field) => {
1047
+ const attribute = attributes[field.name];
1048
+ if (!attribute) {
1049
+ return null;
1050
+ }
1051
+ const { edit: metadata } = metadatas[field.name];
1052
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1053
+ return {
1054
+ attribute,
1055
+ disabled: !metadata.editable,
1056
+ hint: metadata.description,
1057
+ label: metadata.label ?? "",
1058
+ name: field.name,
1059
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1060
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1061
+ schemas,
1062
+ components: components?.schemas ?? {}
1063
+ }),
1064
+ placeholder: metadata.placeholder ?? "",
1065
+ required: attribute.required ?? false,
1066
+ size: field.size,
1067
+ unique: "unique" in attribute ? attribute.unique : false,
1068
+ visible: metadata.visible ?? true,
1069
+ type: attribute.type
1070
+ };
1071
+ }).filter((field) => field !== null)
1072
+ );
1073
+ };
1074
+ const formatListLayout = (data, {
1075
+ schemas,
1076
+ schema,
1077
+ components
1078
+ }) => {
1079
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1080
+ (acc, [attribute, metadata]) => {
1081
+ return {
1082
+ ...acc,
1083
+ [attribute]: metadata.list
1084
+ };
1085
+ },
1086
+ {}
1087
+ );
1088
+ const listAttributes = convertListLayoutToFieldLayouts(
1089
+ data.contentType.layouts.list,
1090
+ schema?.attributes,
1091
+ listMetadatas,
1092
+ { configurations: data.components, schemas: components },
1093
+ schemas
1094
+ );
1095
+ return {
1096
+ layout: listAttributes,
1097
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1098
+ metadatas: listMetadatas,
1099
+ options: {
1100
+ ...schema?.options,
1101
+ ...schema?.pluginOptions,
1102
+ ...data.contentType.options
1103
+ }
1104
+ };
1105
+ };
1106
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1107
+ return columns.map((name) => {
1108
+ const attribute = attributes[name];
1109
+ if (!attribute) {
1110
+ return null;
1111
+ }
1112
+ const metadata = metadatas[name];
1113
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1114
+ return {
1115
+ attribute,
1116
+ label: metadata.label ?? "",
1117
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1118
+ schemas,
1119
+ components: components?.schemas ?? {}
1120
+ }),
1121
+ name,
1122
+ searchable: metadata.searchable ?? true,
1123
+ sortable: metadata.sortable ?? true
1124
+ };
1125
+ }).filter((field) => field !== null);
1126
+ };
1127
+ const useDocument = (args, opts) => {
1128
+ const { toggleNotification } = strapiAdmin.useNotification();
1129
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1130
+ const {
1131
+ currentData: data,
1132
+ isLoading: isLoadingDocument,
1133
+ isFetching: isFetchingDocument,
1134
+ error
1135
+ } = useGetDocumentQuery(args, {
1136
+ ...opts,
1137
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1138
+ });
1139
+ const {
1140
+ components,
1141
+ schema,
1142
+ schemas,
1143
+ isLoading: isLoadingSchema
1144
+ } = useContentTypeSchema(args.model);
1145
+ React__namespace.useEffect(() => {
1146
+ if (error) {
1147
+ toggleNotification({
1148
+ type: "danger",
1149
+ message: formatAPIError(error)
1150
+ });
1151
+ }
1152
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1153
+ const validationSchema = React__namespace.useMemo(() => {
1154
+ if (!schema) {
1155
+ return null;
1156
+ }
1157
+ return createYupSchema(schema.attributes, components);
1158
+ }, [schema, components]);
1159
+ const validate = React__namespace.useCallback(
1160
+ (document) => {
1161
+ if (!validationSchema) {
1162
+ throw new Error(
1163
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1164
+ );
1165
+ }
1166
+ try {
1167
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1168
+ return null;
1169
+ } catch (error2) {
1170
+ if (error2 instanceof yup.ValidationError) {
1171
+ return strapiAdmin.getYupValidationErrors(error2);
1172
+ }
1173
+ throw error2;
1174
+ }
1175
+ },
1176
+ [validationSchema]
1177
+ );
1178
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1179
+ const hasError = !!error;
1180
+ return {
1181
+ components,
1182
+ document: data?.data,
1183
+ meta: data?.meta,
1184
+ isLoading,
1185
+ hasError,
1186
+ schema,
1187
+ schemas,
1188
+ validate
1189
+ };
1190
+ };
1191
+ const useDoc = () => {
1192
+ const { id, slug, collectionType, origin } = reactRouterDom.useParams();
1193
+ const [{ query }] = strapiAdmin.useQueryParams();
1194
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1195
+ if (!collectionType) {
1196
+ throw new Error("Could not find collectionType in url params");
1197
+ }
1198
+ if (!slug) {
1199
+ throw new Error("Could not find model in url params");
1200
+ }
1201
+ const document = useDocument(
1202
+ { documentId: origin || id, model: slug, collectionType, params },
1203
+ {
1204
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1205
+ }
1206
+ );
1207
+ const returnId = origin || id === "create" ? void 0 : id;
1208
+ return {
1209
+ collectionType,
1210
+ model: slug,
1211
+ id: returnId,
1212
+ ...document
1213
+ };
1214
+ };
1215
+ const useContentManagerContext = () => {
1216
+ const {
1217
+ collectionType,
1218
+ model,
1219
+ id,
1220
+ components,
1221
+ isLoading: isLoadingDoc,
1222
+ schema,
1223
+ schemas
1224
+ } = useDoc();
1225
+ const layout = useDocumentLayout(model);
1226
+ const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
1227
+ const isSingleType = collectionType === SINGLE_TYPES;
1228
+ const slug = model;
1229
+ const isCreatingEntry = id === "create";
1230
+ useContentTypeSchema();
1231
+ const isLoading = isLoadingDoc || layout.isLoading;
1232
+ const error = layout.error;
1233
+ return {
1234
+ error,
1235
+ isLoading,
1236
+ // Base metadata
1237
+ model,
1238
+ collectionType,
1239
+ id,
1240
+ slug,
1241
+ isCreatingEntry,
1242
+ isSingleType,
1243
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1244
+ // All schema infos
1245
+ components,
1246
+ contentType: schema,
1247
+ contentTypes: schemas,
1248
+ // Form state
1249
+ form,
1250
+ // layout infos
1251
+ layout
1252
+ };
1253
+ };
1254
+ const prefixPluginTranslations = (trad, pluginId) => {
1255
+ return Object.keys(trad).reduce((acc, current) => {
1256
+ acc[`${pluginId}.${current}`] = trad[current];
1257
+ return acc;
1258
+ }, {});
1259
+ };
1260
+ const getTranslation = (id) => `content-manager.${id}`;
1261
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1262
+ id: "notification.error",
1263
+ defaultMessage: "An error occurred, please try again"
1264
+ };
1265
+ const useDocumentActions = () => {
1266
+ const { toggleNotification } = strapiAdmin.useNotification();
1267
+ const { formatMessage } = reactIntl.useIntl();
1268
+ const { trackUsage } = strapiAdmin.useTracking();
1269
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
1270
+ const navigate = reactRouterDom.useNavigate();
1271
+ const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1272
+ const [deleteDocument] = useDeleteDocumentMutation();
1273
+ const _delete = React__namespace.useCallback(
1274
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1275
+ try {
1276
+ trackUsage("willDeleteEntry", trackerProperty);
1277
+ const res = await deleteDocument({
1278
+ collectionType,
1279
+ model,
1280
+ documentId,
1281
+ params
904
1282
  });
905
1283
  if ("error" in res) {
906
1284
  toggleNotification({
@@ -1205,6 +1583,7 @@ const useDocumentActions = () => {
1205
1583
  defaultMessage: "Saved document"
1206
1584
  })
1207
1585
  });
1586
+ setCurrentStep("contentManager.success");
1208
1587
  return res.data;
1209
1588
  } catch (err) {
1210
1589
  toggleNotification({
@@ -1244,7 +1623,7 @@ const useDocumentActions = () => {
1244
1623
  throw err;
1245
1624
  }
1246
1625
  },
1247
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1626
+ [autoCloneDocument, formatMessage, toggleNotification]
1248
1627
  );
1249
1628
  const [cloneDocument] = useCloneDocumentMutation();
1250
1629
  const clone = React__namespace.useCallback(
@@ -1270,6 +1649,7 @@ const useDocumentActions = () => {
1270
1649
  defaultMessage: "Cloned document"
1271
1650
  })
1272
1651
  });
1652
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1273
1653
  return res.data;
1274
1654
  } catch (err) {
1275
1655
  toggleNotification({
@@ -1280,7 +1660,7 @@ const useDocumentActions = () => {
1280
1660
  throw err;
1281
1661
  }
1282
1662
  },
1283
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1663
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1284
1664
  );
1285
1665
  const [getDoc] = useLazyGetDocumentQuery();
1286
1666
  const getDocument = React__namespace.useCallback(
@@ -1306,7 +1686,7 @@ const useDocumentActions = () => {
1306
1686
  };
1307
1687
  };
1308
1688
  const ProtectedHistoryPage = React.lazy(
1309
- () => Promise.resolve().then(() => require("./History-nuEzM5qm.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1689
+ () => Promise.resolve().then(() => require("./History-DKS2aqqM.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1310
1690
  );
1311
1691
  const routes$1 = [
1312
1692
  {
@@ -1319,31 +1699,31 @@ const routes$1 = [
1319
1699
  }
1320
1700
  ];
1321
1701
  const ProtectedEditViewPage = React.lazy(
1322
- () => Promise.resolve().then(() => require("./EditViewPage-BgjdnGz2.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1702
+ () => Promise.resolve().then(() => require("./EditViewPage-khfP2CR3.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1323
1703
  );
1324
1704
  const ProtectedListViewPage = React.lazy(
1325
- () => Promise.resolve().then(() => require("./ListViewPage-SXIXm-RM.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1705
+ () => Promise.resolve().then(() => require("./ListViewPage-DlUpqLIo.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1326
1706
  );
1327
1707
  const ProtectedListConfiguration = React.lazy(
1328
- () => Promise.resolve().then(() => require("./ListConfigurationPage-CnB86Psm.js")).then((mod) => ({
1708
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-LSYSPZHH.js")).then((mod) => ({
1329
1709
  default: mod.ProtectedListConfiguration
1330
1710
  }))
1331
1711
  );
1332
1712
  const ProtectedEditConfigurationPage = React.lazy(
1333
- () => Promise.resolve().then(() => require("./EditConfigurationPage-BQ17--5R.js")).then((mod) => ({
1713
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-CFDe6SA1.js")).then((mod) => ({
1334
1714
  default: mod.ProtectedEditConfigurationPage
1335
1715
  }))
1336
1716
  );
1337
1717
  const ProtectedComponentConfigurationPage = React.lazy(
1338
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-KXSuLnQD.js")).then((mod) => ({
1718
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-CpJNPBgk.js")).then((mod) => ({
1339
1719
  default: mod.ProtectedComponentConfigurationPage
1340
1720
  }))
1341
1721
  );
1342
1722
  const NoPermissions = React.lazy(
1343
- () => Promise.resolve().then(() => require("./NoPermissionsPage-IGkId4C5.js")).then((mod) => ({ default: mod.NoPermissions }))
1723
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-DLfPsA0Q.js")).then((mod) => ({ default: mod.NoPermissions }))
1344
1724
  );
1345
1725
  const NoContentType = React.lazy(
1346
- () => Promise.resolve().then(() => require("./NoContentTypePage-BzsQ3hLZ.js")).then((mod) => ({ default: mod.NoContentType }))
1726
+ () => Promise.resolve().then(() => require("./NoContentTypePage-m8wt3sf6.js")).then((mod) => ({ default: mod.NoContentType }))
1347
1727
  );
1348
1728
  const CollectionTypePages = () => {
1349
1729
  const { collectionType } = reactRouterDom.useParams();
@@ -1524,7 +1904,7 @@ const DocumentActionsMenu = ({
1524
1904
  };
1525
1905
  return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1526
1906
  /* @__PURE__ */ jsxRuntime.jsxs(
1527
- StyledMoreButton,
1907
+ designSystem.Menu.Trigger,
1528
1908
  {
1529
1909
  disabled: isDisabled,
1530
1910
  size: "S",
@@ -1542,7 +1922,7 @@ const DocumentActionsMenu = ({
1542
1922
  ]
1543
1923
  }
1544
1924
  ),
1545
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1925
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1546
1926
  actions2.map((action) => {
1547
1927
  return /* @__PURE__ */ jsxRuntime.jsx(
1548
1928
  designSystem.Menu.Item,
@@ -1640,11 +2020,6 @@ const convertActionVariantToIconColor = (variant = "secondary") => {
1640
2020
  return "primary600";
1641
2021
  }
1642
2022
  };
1643
- const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
1644
- & > span {
1645
- display: flex;
1646
- }
1647
- `;
1648
2023
  const DocumentActionConfirmDialog = ({
1649
2024
  onClose,
1650
2025
  onCancel,
@@ -1671,11 +2046,11 @@ const DocumentActionConfirmDialog = ({
1671
2046
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1672
2047
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1673
2048
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1674
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
2049
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1675
2050
  id: "app.components.Button.cancel",
1676
2051
  defaultMessage: "Cancel"
1677
2052
  }) }) }),
1678
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
2053
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1679
2054
  id: "app.components.Button.confirm",
1680
2055
  defaultMessage: "Confirm"
1681
2056
  }) })
@@ -1702,6 +2077,18 @@ const DocumentActionModal = ({
1702
2077
  typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1703
2078
  ] }) });
1704
2079
  };
2080
+ const transformData = (data) => {
2081
+ if (Array.isArray(data)) {
2082
+ return data.map(transformData);
2083
+ }
2084
+ if (typeof data === "object" && data !== null) {
2085
+ if ("apiData" in data) {
2086
+ return data.apiData;
2087
+ }
2088
+ return mapValues__default.default(transformData)(data);
2089
+ }
2090
+ return data;
2091
+ };
1705
2092
  const PublishAction$1 = ({
1706
2093
  activeTab,
1707
2094
  documentId,
@@ -1714,12 +2101,10 @@ const PublishAction$1 = ({
1714
2101
  const navigate = reactRouterDom.useNavigate();
1715
2102
  const { toggleNotification } = strapiAdmin.useNotification();
1716
2103
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
2104
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1717
2105
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1718
2106
  const { formatMessage } = reactIntl.useIntl();
1719
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1720
- "PublishAction",
1721
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1722
- );
2107
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1723
2108
  const { publish } = useDocumentActions();
1724
2109
  const [
1725
2110
  countDraftRelations,
@@ -1771,24 +2156,25 @@ const PublishAction$1 = ({
1771
2156
  }
1772
2157
  }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1773
2158
  React__namespace.useEffect(() => {
1774
- if (documentId) {
1775
- const fetchDraftRelationsCount = async () => {
1776
- const { data, error } = await countDraftRelations({
1777
- collectionType,
1778
- model,
1779
- documentId,
1780
- params
1781
- });
1782
- if (error) {
1783
- throw error;
1784
- }
1785
- if (data) {
1786
- setServerCountOfDraftRelations(data.data);
1787
- }
1788
- };
1789
- fetchDraftRelationsCount();
2159
+ if (!document || !document.documentId || isListView) {
2160
+ return;
1790
2161
  }
1791
- }, [documentId, countDraftRelations, collectionType, model, params]);
2162
+ const fetchDraftRelationsCount = async () => {
2163
+ const { data, error } = await countDraftRelations({
2164
+ collectionType,
2165
+ model,
2166
+ documentId,
2167
+ params
2168
+ });
2169
+ if (error) {
2170
+ throw error;
2171
+ }
2172
+ if (data) {
2173
+ setServerCountOfDraftRelations(data.data);
2174
+ }
2175
+ };
2176
+ fetchDraftRelationsCount();
2177
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1792
2178
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1793
2179
  if (!schema?.options?.draftAndPublish) {
1794
2180
  return null;
@@ -1796,7 +2182,9 @@ const PublishAction$1 = ({
1796
2182
  const performPublish = async () => {
1797
2183
  setSubmitting(true);
1798
2184
  try {
1799
- const { errors } = await validate();
2185
+ const { errors } = await validate(true, {
2186
+ status: "published"
2187
+ });
1800
2188
  if (errors) {
1801
2189
  toggleNotification({
1802
2190
  type: "danger",
@@ -1814,7 +2202,7 @@ const PublishAction$1 = ({
1814
2202
  documentId,
1815
2203
  params
1816
2204
  },
1817
- formValues
2205
+ transformData(formValues)
1818
2206
  );
1819
2207
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1820
2208
  navigate({
@@ -1829,7 +2217,8 @@ const PublishAction$1 = ({
1829
2217
  }
1830
2218
  };
1831
2219
  const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1832
- const hasDraftRelations = totalDraftRelations > 0;
2220
+ const enableDraftRelationsCount = false;
2221
+ const hasDraftRelations = enableDraftRelationsCount;
1833
2222
  return {
1834
2223
  /**
1835
2224
  * Disabled when:
@@ -1846,9 +2235,6 @@ const PublishAction$1 = ({
1846
2235
  defaultMessage: "Publish"
1847
2236
  }),
1848
2237
  onClick: async () => {
1849
- if (hasDraftRelations) {
1850
- return;
1851
- }
1852
2238
  await performPublish();
1853
2239
  },
1854
2240
  dialog: hasDraftRelations ? {
@@ -1887,10 +2273,6 @@ const UpdateAction = ({
1887
2273
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1888
2274
  const isCloning = cloneMatch !== null;
1889
2275
  const { formatMessage } = reactIntl.useIntl();
1890
- useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1891
- canCreate: canCreate2,
1892
- canUpdate: canUpdate2
1893
- }));
1894
2276
  const { create, update, clone } = useDocumentActions();
1895
2277
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1896
2278
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1916,7 +2298,9 @@ const UpdateAction = ({
1916
2298
  onClick: async () => {
1917
2299
  setSubmitting(true);
1918
2300
  try {
1919
- const { errors } = await validate();
2301
+ const { errors } = await validate(true, {
2302
+ status: "draft"
2303
+ });
1920
2304
  if (errors) {
1921
2305
  toggleNotification({
1922
2306
  type: "danger",
@@ -1934,7 +2318,7 @@ const UpdateAction = ({
1934
2318
  documentId: cloneMatch.params.origin,
1935
2319
  params
1936
2320
  },
1937
- document
2321
+ transformData(document)
1938
2322
  );
1939
2323
  if ("data" in res) {
1940
2324
  navigate(
@@ -1955,7 +2339,7 @@ const UpdateAction = ({
1955
2339
  documentId,
1956
2340
  params
1957
2341
  },
1958
- document
2342
+ transformData(document)
1959
2343
  );
1960
2344
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1961
2345
  setErrors(formatValidationErrors(res.error));
@@ -1968,7 +2352,7 @@ const UpdateAction = ({
1968
2352
  model,
1969
2353
  params
1970
2354
  },
1971
- document
2355
+ transformData(document)
1972
2356
  );
1973
2357
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1974
2358
  navigate(
@@ -2021,7 +2405,7 @@ const UnpublishAction$1 = ({
2021
2405
  id: "app.utils.unpublish",
2022
2406
  defaultMessage: "Unpublish"
2023
2407
  }),
2024
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2408
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2025
2409
  onClick: async () => {
2026
2410
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
2027
2411
  if (!documentId) {
@@ -2133,7 +2517,7 @@ const DiscardAction = ({
2133
2517
  id: "content-manager.actions.discard.label",
2134
2518
  defaultMessage: "Discard changes"
2135
2519
  }),
2136
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2520
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2137
2521
  position: ["panel", "table-row"],
2138
2522
  variant: "danger",
2139
2523
  dialog: {
@@ -2161,11 +2545,6 @@ const DiscardAction = ({
2161
2545
  };
2162
2546
  };
2163
2547
  DiscardAction.type = "discard";
2164
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2165
- path {
2166
- fill: currentColor;
2167
- }
2168
- `;
2169
2548
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2170
2549
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2171
2550
  const RelativeTime = React__namespace.forwardRef(
@@ -2213,7 +2592,7 @@ const getDisplayName = ({
2213
2592
  };
2214
2593
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2215
2594
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2216
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2595
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2217
2596
  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) }) });
2218
2597
  };
2219
2598
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2312,12 +2691,12 @@ const Information = ({ activeTab }) => {
2312
2691
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2313
2692
  label: formatMessage({
2314
2693
  id: "content-manager.containers.edit.information.last-published.label",
2315
- defaultMessage: "Last published"
2694
+ defaultMessage: "Published"
2316
2695
  }),
2317
2696
  value: formatMessage(
2318
2697
  {
2319
2698
  id: "content-manager.containers.edit.information.last-published.value",
2320
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2699
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2321
2700
  },
2322
2701
  {
2323
2702
  time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2330,12 +2709,12 @@ const Information = ({ activeTab }) => {
2330
2709
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2331
2710
  label: formatMessage({
2332
2711
  id: "content-manager.containers.edit.information.last-draft.label",
2333
- defaultMessage: "Last draft"
2712
+ defaultMessage: "Updated"
2334
2713
  }),
2335
2714
  value: formatMessage(
2336
2715
  {
2337
2716
  id: "content-manager.containers.edit.information.last-draft.value",
2338
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2717
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2339
2718
  },
2340
2719
  {
2341
2720
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2353,12 +2732,12 @@ const Information = ({ activeTab }) => {
2353
2732
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2354
2733
  label: formatMessage({
2355
2734
  id: "content-manager.containers.edit.information.document.label",
2356
- defaultMessage: "Document"
2735
+ defaultMessage: "Created"
2357
2736
  }),
2358
2737
  value: formatMessage(
2359
2738
  {
2360
2739
  id: "content-manager.containers.edit.information.document.value",
2361
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2740
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2362
2741
  },
2363
2742
  {
2364
2743
  time: /* @__PURE__ */ jsxRuntime.jsx(
@@ -2396,523 +2775,277 @@ const Information = ({ activeTab }) => {
2396
2775
  );
2397
2776
  };
2398
2777
  const HeaderActions = ({ actions: actions2 }) => {
2399
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2400
- if ("options" in action) {
2778
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2779
+ const handleClick = (action) => async (e) => {
2780
+ if (!("options" in action)) {
2781
+ const { onClick = () => false, dialog, id } = action;
2782
+ const muteDialog = await onClick(e);
2783
+ if (dialog && !muteDialog) {
2784
+ e.preventDefault();
2785
+ setDialogId(id);
2786
+ }
2787
+ }
2788
+ };
2789
+ const handleClose = () => {
2790
+ setDialogId(null);
2791
+ };
2792
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2793
+ if (action.options) {
2401
2794
  return /* @__PURE__ */ jsxRuntime.jsx(
2402
2795
  designSystem.SingleSelect,
2403
2796
  {
2404
2797
  size: "S",
2405
- disabled: action.disabled,
2406
- "aria-label": action.label,
2407
2798
  onChange: action.onSelect,
2408
- value: action.value,
2799
+ "aria-label": action.label,
2800
+ ...action,
2409
2801
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
2410
2802
  },
2411
2803
  action.id
2412
2804
  );
2413
2805
  } else {
2414
- return null;
2415
- }
2416
- }) });
2417
- };
2418
- const ConfigureTheViewAction = ({ collectionType, model }) => {
2419
- const navigate = reactRouterDom.useNavigate();
2420
- const { formatMessage } = reactIntl.useIntl();
2421
- return {
2422
- label: formatMessage({
2423
- id: "app.links.configure-view",
2424
- defaultMessage: "Configure the view"
2425
- }),
2426
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2427
- onClick: () => {
2428
- navigate(`../${collectionType}/${model}/configurations/edit`);
2429
- },
2430
- position: "header"
2431
- };
2432
- };
2433
- ConfigureTheViewAction.type = "configure-the-view";
2434
- const EditTheModelAction = ({ model }) => {
2435
- const navigate = reactRouterDom.useNavigate();
2436
- const { formatMessage } = reactIntl.useIntl();
2437
- return {
2438
- label: formatMessage({
2439
- id: "content-manager.link-to-ctb",
2440
- defaultMessage: "Edit the model"
2441
- }),
2442
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2443
- onClick: () => {
2444
- navigate(`/plugins/content-type-builder/content-types/${model}`);
2445
- },
2446
- position: "header"
2447
- };
2448
- };
2449
- EditTheModelAction.type = "edit-the-model";
2450
- const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2451
- const navigate = reactRouterDom.useNavigate();
2452
- const { formatMessage } = reactIntl.useIntl();
2453
- const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2454
- const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2455
- const { delete: deleteAction } = useDocumentActions();
2456
- const { toggleNotification } = strapiAdmin.useNotification();
2457
- const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2458
- return {
2459
- disabled: !canDelete || !document,
2460
- label: formatMessage({
2461
- id: "content-manager.actions.delete.label",
2462
- defaultMessage: "Delete document"
2463
- }),
2464
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2465
- dialog: {
2466
- type: "dialog",
2467
- title: formatMessage({
2468
- id: "app.components.ConfirmDialog.title",
2469
- defaultMessage: "Confirmation"
2470
- }),
2471
- content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2472
- /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2473
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2474
- id: "content-manager.actions.delete.dialog.body",
2475
- defaultMessage: "Are you sure?"
2476
- }) })
2477
- ] }),
2478
- onConfirm: async () => {
2479
- if (!listViewPathMatch) {
2480
- setSubmitting(true);
2481
- }
2482
- try {
2483
- if (!documentId && collectionType !== SINGLE_TYPES) {
2484
- console.error(
2485
- "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2486
- );
2487
- toggleNotification({
2488
- message: formatMessage({
2489
- id: "content-manager.actions.delete.error",
2490
- defaultMessage: "An error occurred while trying to delete the document."
2491
- }),
2492
- type: "danger"
2493
- });
2494
- return;
2495
- }
2496
- const res = await deleteAction({
2497
- documentId,
2498
- model,
2499
- collectionType,
2500
- params: {
2501
- locale: "*"
2806
+ if (action.type === "icon") {
2807
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2808
+ /* @__PURE__ */ jsxRuntime.jsx(
2809
+ designSystem.IconButton,
2810
+ {
2811
+ disabled: action.disabled,
2812
+ label: action.label,
2813
+ size: "S",
2814
+ onClick: handleClick(action),
2815
+ children: action.icon
2502
2816
  }
2503
- });
2504
- if (!("error" in res)) {
2505
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2506
- }
2507
- } finally {
2508
- if (!listViewPathMatch) {
2509
- setSubmitting(false);
2510
- }
2511
- }
2817
+ ),
2818
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2819
+ HeaderActionDialog,
2820
+ {
2821
+ ...action.dialog,
2822
+ isOpen: dialogId === action.id,
2823
+ onClose: handleClose
2824
+ }
2825
+ ) : null
2826
+ ] }, action.id);
2512
2827
  }
2513
- },
2514
- variant: "danger",
2515
- position: ["header", "table-row"]
2516
- };
2517
- };
2518
- DeleteAction$1.type = "delete";
2519
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2520
- const Panels = () => {
2521
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2522
- const [
2523
- {
2524
- query: { status }
2525
- }
2526
- ] = strapiAdmin.useQueryParams({
2527
- status: "draft"
2528
- });
2529
- const { model, id, document, meta, collectionType } = useDoc();
2530
- const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2531
- const props = {
2532
- activeTab: status,
2533
- model,
2534
- documentId: id,
2535
- document: isCloning ? void 0 : document,
2536
- meta: isCloning ? void 0 : meta,
2537
- collectionType
2538
- };
2539
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2540
- strapiAdmin.DescriptionComponentRenderer,
2541
- {
2542
- props,
2543
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2544
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2545
2828
  }
2546
- ) });
2547
- };
2548
- const ActionsPanel = () => {
2549
- const { formatMessage } = reactIntl.useIntl();
2550
- return {
2551
- title: formatMessage({
2552
- id: "content-manager.containers.edit.panels.default.title",
2553
- defaultMessage: "Document"
2554
- }),
2555
- content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2556
- };
2557
- };
2558
- ActionsPanel.type = "actions";
2559
- const ActionsPanelContent = () => {
2560
- const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2561
- const [
2562
- {
2563
- query: { status = "draft" }
2564
- }
2565
- ] = strapiAdmin.useQueryParams();
2566
- const { model, id, document, meta, collectionType } = useDoc();
2567
- const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
2568
- const props = {
2569
- activeTab: status,
2570
- model,
2571
- documentId: id,
2572
- document: isCloning ? void 0 : document,
2573
- meta: isCloning ? void 0 : meta,
2574
- collectionType
2575
- };
2576
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
2577
- /* @__PURE__ */ jsxRuntime.jsx(
2578
- strapiAdmin.DescriptionComponentRenderer,
2579
- {
2580
- props,
2581
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2582
- children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
2583
- }
2584
- ),
2585
- /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
2586
- ] });
2829
+ }) });
2587
2830
  };
2588
- const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2589
- return /* @__PURE__ */ jsxRuntime.jsxs(
2590
- designSystem.Flex,
2591
- {
2592
- ref,
2593
- tag: "aside",
2594
- "aria-labelledby": "additional-information",
2595
- background: "neutral0",
2596
- borderColor: "neutral150",
2597
- hasRadius: true,
2598
- paddingBottom: 4,
2599
- paddingLeft: 4,
2600
- paddingRight: 4,
2601
- paddingTop: 4,
2602
- shadow: "tableShadow",
2603
- gap: 3,
2604
- direction: "column",
2605
- justifyContent: "stretch",
2606
- alignItems: "flex-start",
2607
- children: [
2608
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2609
- children
2610
- ]
2831
+ const HeaderActionDialog = ({
2832
+ onClose,
2833
+ onCancel,
2834
+ title,
2835
+ content: Content,
2836
+ isOpen
2837
+ }) => {
2838
+ const handleClose = async () => {
2839
+ if (onCancel) {
2840
+ await onCancel();
2611
2841
  }
2612
- );
2613
- });
2614
- const HOOKS = {
2615
- /**
2616
- * Hook that allows to mutate the displayed headers of the list view table
2617
- * @constant
2618
- * @type {string}
2619
- */
2620
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2621
- /**
2622
- * Hook that allows to mutate the CM's collection types links pre-set filters
2623
- * @constant
2624
- * @type {string}
2625
- */
2626
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2627
- /**
2628
- * Hook that allows to mutate the CM's edit view layout
2629
- * @constant
2630
- * @type {string}
2631
- */
2632
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2633
- /**
2634
- * Hook that allows to mutate the CM's single types links pre-set filters
2635
- * @constant
2636
- * @type {string}
2637
- */
2638
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2842
+ onClose();
2843
+ };
2844
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2845
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2846
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2847
+ ] }) });
2639
2848
  };
2640
- const contentTypesApi = contentManagerApi.injectEndpoints({
2641
- endpoints: (builder) => ({
2642
- getContentTypeConfiguration: builder.query({
2643
- query: (uid) => ({
2644
- url: `/content-manager/content-types/${uid}/configuration`,
2645
- method: "GET"
2646
- }),
2647
- transformResponse: (response) => response.data,
2648
- providesTags: (_result, _error, uid) => [
2649
- { type: "ContentTypesConfiguration", id: uid },
2650
- { type: "ContentTypeSettings", id: "LIST" }
2651
- ]
2652
- }),
2653
- getAllContentTypeSettings: builder.query({
2654
- query: () => "/content-manager/content-types-settings",
2655
- transformResponse: (response) => response.data,
2656
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2849
+ const ConfigureTheViewAction = ({ collectionType, model }) => {
2850
+ const navigate = reactRouterDom.useNavigate();
2851
+ const { formatMessage } = reactIntl.useIntl();
2852
+ return {
2853
+ label: formatMessage({
2854
+ id: "app.links.configure-view",
2855
+ defaultMessage: "Configure the view"
2657
2856
  }),
2658
- updateContentTypeConfiguration: builder.mutation({
2659
- query: ({ uid, ...body }) => ({
2660
- url: `/content-manager/content-types/${uid}/configuration`,
2661
- method: "PUT",
2662
- data: body
2663
- }),
2664
- transformResponse: (response) => response.data,
2665
- invalidatesTags: (_result, _error, { uid }) => [
2666
- { type: "ContentTypesConfiguration", id: uid },
2667
- { type: "ContentTypeSettings", id: "LIST" },
2668
- // Is this necessary?
2669
- { type: "InitialData" }
2670
- ]
2671
- })
2672
- })
2673
- });
2674
- const {
2675
- useGetContentTypeConfigurationQuery,
2676
- useGetAllContentTypeSettingsQuery,
2677
- useUpdateContentTypeConfigurationMutation
2678
- } = contentTypesApi;
2679
- const checkIfAttributeIsDisplayable = (attribute) => {
2680
- const { type } = attribute;
2681
- if (type === "relation") {
2682
- return !attribute.relation.toLowerCase().includes("morph");
2683
- }
2684
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2857
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2858
+ onClick: () => {
2859
+ navigate(`../${collectionType}/${model}/configurations/edit`);
2860
+ },
2861
+ position: "header"
2862
+ };
2685
2863
  };
2686
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2687
- if (!mainFieldName) {
2688
- return void 0;
2689
- }
2690
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2691
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2692
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2693
- );
2864
+ ConfigureTheViewAction.type = "configure-the-view";
2865
+ const EditTheModelAction = ({ model }) => {
2866
+ const navigate = reactRouterDom.useNavigate();
2867
+ const { formatMessage } = reactIntl.useIntl();
2694
2868
  return {
2695
- name: mainFieldName,
2696
- type: mainFieldType ?? "string"
2869
+ label: formatMessage({
2870
+ id: "content-manager.link-to-ctb",
2871
+ defaultMessage: "Edit the model"
2872
+ }),
2873
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2874
+ onClick: () => {
2875
+ navigate(`/plugins/content-type-builder/content-types/${model}`);
2876
+ },
2877
+ position: "header"
2697
2878
  };
2698
2879
  };
2699
- const DEFAULT_SETTINGS = {
2700
- bulkable: false,
2701
- filterable: false,
2702
- searchable: false,
2703
- pagination: false,
2704
- defaultSortBy: "",
2705
- defaultSortOrder: "asc",
2706
- mainField: "id",
2707
- pageSize: 10
2708
- };
2709
- const useDocumentLayout = (model) => {
2710
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2711
- const [{ query }] = strapiAdmin.useQueryParams();
2712
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2880
+ EditTheModelAction.type = "edit-the-model";
2881
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2882
+ const navigate = reactRouterDom.useNavigate();
2883
+ const { formatMessage } = reactIntl.useIntl();
2884
+ const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
2885
+ const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2886
+ const { delete: deleteAction } = useDocumentActions();
2713
2887
  const { toggleNotification } = strapiAdmin.useNotification();
2714
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2715
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2716
- const {
2717
- data,
2718
- isLoading: isLoadingConfigs,
2719
- error,
2720
- isFetching: isFetchingConfigs
2721
- } = useGetContentTypeConfigurationQuery(model);
2722
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2723
- React__namespace.useEffect(() => {
2724
- if (error) {
2725
- toggleNotification({
2726
- type: "danger",
2727
- message: formatAPIError(error)
2728
- });
2729
- }
2730
- }, [error, formatAPIError, toggleNotification]);
2731
- const editLayout = React__namespace.useMemo(
2732
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2733
- layout: [],
2734
- components: {},
2735
- metadatas: {},
2736
- options: {},
2737
- settings: DEFAULT_SETTINGS
2738
- },
2739
- [data, isLoading, schemas, schema, components]
2740
- );
2741
- const listLayout = React__namespace.useMemo(() => {
2742
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2743
- layout: [],
2744
- metadatas: {},
2745
- options: {},
2746
- settings: DEFAULT_SETTINGS
2747
- };
2748
- }, [data, isLoading, schemas, schema, components]);
2749
- const { layout: edit } = React__namespace.useMemo(
2750
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2751
- layout: editLayout,
2752
- query
2753
- }),
2754
- [editLayout, query, runHookWaterfall]
2755
- );
2888
+ const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
2889
+ const isLocalized = document?.locale != null;
2756
2890
  return {
2757
- error,
2758
- isLoading,
2759
- edit,
2760
- list: listLayout
2761
- };
2762
- };
2763
- const useDocLayout = () => {
2764
- const { model } = useDoc();
2765
- return useDocumentLayout(model);
2766
- };
2767
- const formatEditLayout = (data, {
2768
- schemas,
2769
- schema,
2770
- components
2771
- }) => {
2772
- let currentPanelIndex = 0;
2773
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2774
- data.contentType.layouts.edit,
2775
- schema?.attributes,
2776
- data.contentType.metadatas,
2777
- { configurations: data.components, schemas: components },
2778
- schemas
2779
- ).reduce((panels, row) => {
2780
- if (row.some((field) => field.type === "dynamiczone")) {
2781
- panels.push([row]);
2782
- currentPanelIndex += 2;
2783
- } else {
2784
- if (!panels[currentPanelIndex]) {
2785
- panels.push([]);
2786
- }
2787
- panels[currentPanelIndex].push(row);
2788
- }
2789
- return panels;
2790
- }, []);
2791
- const componentEditAttributes = Object.entries(data.components).reduce(
2792
- (acc, [uid, configuration]) => {
2793
- acc[uid] = {
2794
- layout: convertEditLayoutToFieldLayouts(
2795
- configuration.layouts.edit,
2796
- components[uid].attributes,
2797
- configuration.metadatas
2798
- ),
2799
- settings: {
2800
- ...configuration.settings,
2801
- icon: components[uid].info.icon,
2802
- displayName: components[uid].info.displayName
2891
+ disabled: !canDelete || !document,
2892
+ label: formatMessage(
2893
+ {
2894
+ id: "content-manager.actions.delete.label",
2895
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2896
+ },
2897
+ { isLocalized }
2898
+ ),
2899
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2900
+ dialog: {
2901
+ type: "dialog",
2902
+ title: formatMessage({
2903
+ id: "app.components.ConfirmDialog.title",
2904
+ defaultMessage: "Confirmation"
2905
+ }),
2906
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2907
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2908
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2909
+ id: "content-manager.actions.delete.dialog.body",
2910
+ defaultMessage: "Are you sure?"
2911
+ }) })
2912
+ ] }),
2913
+ onConfirm: async () => {
2914
+ if (!listViewPathMatch) {
2915
+ setSubmitting(true);
2916
+ }
2917
+ try {
2918
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2919
+ console.error(
2920
+ "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2921
+ );
2922
+ toggleNotification({
2923
+ message: formatMessage({
2924
+ id: "content-manager.actions.delete.error",
2925
+ defaultMessage: "An error occurred while trying to delete the document."
2926
+ }),
2927
+ type: "danger"
2928
+ });
2929
+ return;
2930
+ }
2931
+ const res = await deleteAction({
2932
+ documentId,
2933
+ model,
2934
+ collectionType,
2935
+ params: {
2936
+ locale: "*"
2937
+ }
2938
+ });
2939
+ if (!("error" in res)) {
2940
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2941
+ }
2942
+ } finally {
2943
+ if (!listViewPathMatch) {
2944
+ setSubmitting(false);
2945
+ }
2803
2946
  }
2804
- };
2805
- return acc;
2806
- },
2807
- {}
2808
- );
2809
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2810
- (acc, [attribute, metadata]) => {
2811
- return {
2812
- ...acc,
2813
- [attribute]: metadata.edit
2814
- };
2815
- },
2816
- {}
2817
- );
2818
- return {
2819
- layout: panelledEditAttributes,
2820
- components: componentEditAttributes,
2821
- metadatas: editMetadatas,
2822
- settings: {
2823
- ...data.contentType.settings,
2824
- displayName: schema?.info.displayName
2947
+ }
2825
2948
  },
2826
- options: {
2827
- ...schema?.options,
2828
- ...schema?.pluginOptions,
2829
- ...data.contentType.options
2830
- }
2949
+ variant: "danger",
2950
+ position: ["header", "table-row"]
2831
2951
  };
2832
2952
  };
2833
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2834
- return rows.map(
2835
- (row) => row.map((field) => {
2836
- const attribute = attributes[field.name];
2837
- if (!attribute) {
2838
- return null;
2839
- }
2840
- const { edit: metadata } = metadatas[field.name];
2841
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2842
- return {
2843
- attribute,
2844
- disabled: !metadata.editable,
2845
- hint: metadata.description,
2846
- label: metadata.label ?? "",
2847
- name: field.name,
2848
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2849
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2850
- schemas,
2851
- components: components?.schemas ?? {}
2852
- }),
2853
- placeholder: metadata.placeholder ?? "",
2854
- required: attribute.required ?? false,
2855
- size: field.size,
2856
- unique: "unique" in attribute ? attribute.unique : false,
2857
- visible: metadata.visible ?? true,
2858
- type: attribute.type
2859
- };
2860
- }).filter((field) => field !== null)
2861
- );
2953
+ DeleteAction$1.type = "delete";
2954
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2955
+ const Panels = () => {
2956
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2957
+ const [
2958
+ {
2959
+ query: { status }
2960
+ }
2961
+ ] = strapiAdmin.useQueryParams({
2962
+ status: "draft"
2963
+ });
2964
+ const { model, id, document, meta, collectionType } = useDoc();
2965
+ const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
2966
+ const props = {
2967
+ activeTab: status,
2968
+ model,
2969
+ documentId: id,
2970
+ document: isCloning ? void 0 : document,
2971
+ meta: isCloning ? void 0 : meta,
2972
+ collectionType
2973
+ };
2974
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
2975
+ strapiAdmin.DescriptionComponentRenderer,
2976
+ {
2977
+ props,
2978
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2979
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
2980
+ }
2981
+ ) });
2862
2982
  };
2863
- const formatListLayout = (data, {
2864
- schemas,
2865
- schema,
2866
- components
2867
- }) => {
2868
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2869
- (acc, [attribute, metadata]) => {
2870
- return {
2871
- ...acc,
2872
- [attribute]: metadata.list
2873
- };
2874
- },
2875
- {}
2876
- );
2877
- const listAttributes = convertListLayoutToFieldLayouts(
2878
- data.contentType.layouts.list,
2879
- schema?.attributes,
2880
- listMetadatas,
2881
- { configurations: data.components, schemas: components },
2882
- schemas
2883
- );
2983
+ const ActionsPanel = () => {
2984
+ const { formatMessage } = reactIntl.useIntl();
2884
2985
  return {
2885
- layout: listAttributes,
2886
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2887
- metadatas: listMetadatas,
2888
- options: {
2889
- ...schema?.options,
2890
- ...schema?.pluginOptions,
2891
- ...data.contentType.options
2892
- }
2986
+ title: formatMessage({
2987
+ id: "content-manager.containers.edit.panels.default.title",
2988
+ defaultMessage: "Entry"
2989
+ }),
2990
+ content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2893
2991
  };
2894
2992
  };
2895
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2896
- return columns.map((name) => {
2897
- const attribute = attributes[name];
2898
- if (!attribute) {
2899
- return null;
2993
+ ActionsPanel.type = "actions";
2994
+ const ActionsPanelContent = () => {
2995
+ const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2996
+ const [
2997
+ {
2998
+ query: { status = "draft" }
2900
2999
  }
2901
- const metadata = metadatas[name];
2902
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2903
- return {
2904
- attribute,
2905
- label: metadata.label ?? "",
2906
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2907
- schemas,
2908
- components: components?.schemas ?? {}
2909
- }),
2910
- name,
2911
- searchable: metadata.searchable ?? true,
2912
- sortable: metadata.sortable ?? true
2913
- };
2914
- }).filter((field) => field !== null);
3000
+ ] = strapiAdmin.useQueryParams();
3001
+ const { model, id, document, meta, collectionType } = useDoc();
3002
+ const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
3003
+ const props = {
3004
+ activeTab: status,
3005
+ model,
3006
+ documentId: id,
3007
+ document: isCloning ? void 0 : document,
3008
+ meta: isCloning ? void 0 : meta,
3009
+ collectionType
3010
+ };
3011
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
3012
+ /* @__PURE__ */ jsxRuntime.jsx(
3013
+ strapiAdmin.DescriptionComponentRenderer,
3014
+ {
3015
+ props,
3016
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3017
+ children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
3018
+ }
3019
+ ),
3020
+ /* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
3021
+ ] });
2915
3022
  };
3023
+ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
3024
+ return /* @__PURE__ */ jsxRuntime.jsxs(
3025
+ designSystem.Flex,
3026
+ {
3027
+ ref,
3028
+ tag: "aside",
3029
+ "aria-labelledby": "additional-information",
3030
+ background: "neutral0",
3031
+ borderColor: "neutral150",
3032
+ hasRadius: true,
3033
+ paddingBottom: 4,
3034
+ paddingLeft: 4,
3035
+ paddingRight: 4,
3036
+ paddingTop: 4,
3037
+ shadow: "tableShadow",
3038
+ gap: 3,
3039
+ direction: "column",
3040
+ justifyContent: "stretch",
3041
+ alignItems: "flex-start",
3042
+ children: [
3043
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3044
+ children
3045
+ ]
3046
+ }
3047
+ );
3048
+ });
2916
3049
  const ConfirmBulkActionDialog = ({
2917
3050
  onToggleDialog,
2918
3051
  isOpen = false,
@@ -2951,6 +3084,7 @@ const ConfirmDialogPublishAll = ({
2951
3084
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2952
3085
  const { model, schema } = useDoc();
2953
3086
  const [{ query }] = strapiAdmin.useQueryParams();
3087
+ const enableDraftRelationsCount = false;
2954
3088
  const {
2955
3089
  data: countDraftRelations = 0,
2956
3090
  isLoading,
@@ -2962,7 +3096,7 @@ const ConfirmDialogPublishAll = ({
2962
3096
  locale: query?.plugins?.i18n?.locale
2963
3097
  },
2964
3098
  {
2965
- skip: selectedEntries.length === 0
3099
+ skip: !enableDraftRelationsCount
2966
3100
  }
2967
3101
  );
2968
3102
  React__namespace.useEffect(() => {
@@ -3147,7 +3281,7 @@ const SelectedEntriesTableContent = ({
3147
3281
  status: row.status
3148
3282
  }
3149
3283
  ) }),
3150
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3284
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3151
3285
  designSystem.IconButton,
3152
3286
  {
3153
3287
  tag: reactRouterDom.Link,
@@ -3170,9 +3304,10 @@ const SelectedEntriesTableContent = ({
3170
3304
  ),
3171
3305
  target: "_blank",
3172
3306
  marginLeft: "auto",
3173
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3307
+ variant: "ghost",
3308
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3174
3309
  }
3175
- ) })
3310
+ ) }) })
3176
3311
  ] }, row.id)) })
3177
3312
  ] });
3178
3313
  };
@@ -3209,7 +3344,13 @@ const SelectedEntriesModalContent = ({
3209
3344
  );
3210
3345
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3211
3346
  if (data.length > 0 && schema) {
3212
- const validate = createYupSchema(schema.attributes, components);
3347
+ const validate = createYupSchema(
3348
+ schema.attributes,
3349
+ components,
3350
+ // Since this is the "Publish" action, the validation
3351
+ // schema must enforce the rules for published entities
3352
+ { status: "published" }
3353
+ );
3213
3354
  const validationErrors2 = {};
3214
3355
  const rows2 = data.map((entry) => {
3215
3356
  try {
@@ -3559,7 +3700,7 @@ const TableActions = ({ document }) => {
3559
3700
  strapiAdmin.DescriptionComponentRenderer,
3560
3701
  {
3561
3702
  props,
3562
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3703
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3563
3704
  children: (actions2) => {
3564
3705
  const tableRowActions = actions2.filter((action) => {
3565
3706
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3670,7 +3811,7 @@ const CloneAction = ({ model, documentId }) => {
3670
3811
  }),
3671
3812
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3672
3813
  footer: ({ onClose }) => {
3673
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3814
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3674
3815
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3675
3816
  id: "cancel",
3676
3817
  defaultMessage: "Cancel"
@@ -3882,6 +4023,97 @@ const { setInitialData } = actions;
3882
4023
  const reducer = toolkit.combineReducers({
3883
4024
  app: reducer$1
3884
4025
  });
4026
+ const previewApi = contentManagerApi.injectEndpoints({
4027
+ endpoints: (builder) => ({
4028
+ getPreviewUrl: builder.query({
4029
+ query({ query, params }) {
4030
+ return {
4031
+ url: `/content-manager/preview/url/${params.contentType}`,
4032
+ method: "GET",
4033
+ config: {
4034
+ params: query
4035
+ }
4036
+ };
4037
+ }
4038
+ })
4039
+ })
4040
+ });
4041
+ const { useGetPreviewUrlQuery } = previewApi;
4042
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4043
+ const { formatMessage } = reactIntl.useIntl();
4044
+ const { toggleNotification } = strapiAdmin.useNotification();
4045
+ const { copy } = strapiAdmin.useClipboard();
4046
+ const { trackUsage } = strapiAdmin.useTracking();
4047
+ const { data, error } = useGetPreviewUrlQuery({
4048
+ params: {
4049
+ contentType: model
4050
+ },
4051
+ query: {
4052
+ documentId,
4053
+ locale: document?.locale,
4054
+ status: document?.status
4055
+ }
4056
+ });
4057
+ if (!data?.data?.url || error) {
4058
+ return null;
4059
+ }
4060
+ const { url } = data.data;
4061
+ const handleCopyLink = () => {
4062
+ copy(url);
4063
+ toggleNotification({
4064
+ message: formatMessage({
4065
+ id: "content-manager.preview.copy.success",
4066
+ defaultMessage: "Copied preview link"
4067
+ }),
4068
+ type: "success"
4069
+ });
4070
+ };
4071
+ const handleClick = () => {
4072
+ trackUsage("willOpenPreview");
4073
+ };
4074
+ return {
4075
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4076
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, width: "100%", children: [
4077
+ /* @__PURE__ */ jsxRuntime.jsx(
4078
+ designSystem.Button,
4079
+ {
4080
+ variant: "tertiary",
4081
+ tag: reactRouterDom.Link,
4082
+ to: url,
4083
+ onClick: handleClick,
4084
+ target: "_blank",
4085
+ flex: "auto",
4086
+ children: formatMessage({
4087
+ id: "content-manager.preview.panel.button",
4088
+ defaultMessage: "Open preview"
4089
+ })
4090
+ }
4091
+ ),
4092
+ /* @__PURE__ */ jsxRuntime.jsx(
4093
+ designSystem.IconButton,
4094
+ {
4095
+ type: "button",
4096
+ label: formatMessage({
4097
+ id: "preview.copy.label",
4098
+ defaultMessage: "Copy preview link"
4099
+ }),
4100
+ onClick: handleCopyLink,
4101
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Link, {})
4102
+ }
4103
+ )
4104
+ ] })
4105
+ };
4106
+ };
4107
+ const FEATURE_ID = "preview";
4108
+ const previewAdmin = {
4109
+ bootstrap(app) {
4110
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4111
+ return;
4112
+ }
4113
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4114
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4115
+ }
4116
+ };
3885
4117
  const index = {
3886
4118
  register(app) {
3887
4119
  const cm = new ContentManagerPlugin();
@@ -3901,7 +4133,7 @@ const index = {
3901
4133
  app.router.addRoute({
3902
4134
  path: "content-manager/*",
3903
4135
  lazy: async () => {
3904
- const { Layout } = await Promise.resolve().then(() => require("./layout-C6dxWYT7.js"));
4136
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CmaemAO3.js"));
3905
4137
  return {
3906
4138
  Component: Layout
3907
4139
  };
@@ -3914,11 +4146,14 @@ const index = {
3914
4146
  if (typeof historyAdmin.bootstrap === "function") {
3915
4147
  historyAdmin.bootstrap(app);
3916
4148
  }
4149
+ if (typeof previewAdmin.bootstrap === "function") {
4150
+ previewAdmin.bootstrap(app);
4151
+ }
3917
4152
  },
3918
4153
  async registerTrads({ locales }) {
3919
4154
  const importedTrads = await Promise.all(
3920
4155
  locales.map((locale) => {
3921
- 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-uOUIxfcQ.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 }) => {
4156
+ 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-Bdpa50w3.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-9K52xZIr.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B2Kyv8Z9.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-7sfIbjxE.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3922
4157
  return {
3923
4158
  data: prefixPluginTranslations(data, PLUGIN_ID),
3924
4159
  locale
@@ -3936,6 +4171,7 @@ const index = {
3936
4171
  };
3937
4172
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3938
4173
  exports.BulkActionsRenderer = BulkActionsRenderer;
4174
+ exports.CLONE_PATH = CLONE_PATH;
3939
4175
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3940
4176
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3941
4177
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3963,6 +4199,7 @@ exports.getMainField = getMainField;
3963
4199
  exports.getTranslation = getTranslation;
3964
4200
  exports.index = index;
3965
4201
  exports.setInitialData = setInitialData;
4202
+ exports.useContentManagerContext = useContentManagerContext;
3966
4203
  exports.useContentTypeSchema = useContentTypeSchema;
3967
4204
  exports.useDoc = useDoc;
3968
4205
  exports.useDocLayout = useDocLayout;
@@ -3975,4 +4212,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3975
4212
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3976
4213
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3977
4214
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3978
- //# sourceMappingURL=index-CdT0kHZ8.js.map
4215
+ //# sourceMappingURL=index-DqZnjo8F.js.map