@strapi/content-manager 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3 → 0.0.0-experimental.eba25ec571b091c6bde1104eb6c753debdf15462

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 (174) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-CpBFh6_r.mjs → ComponentConfigurationPage-BaJMOQyq.mjs} +4 -4
  2. package/dist/_chunks/{ComponentConfigurationPage-CpBFh6_r.mjs.map → ComponentConfigurationPage-BaJMOQyq.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-_zF8p6CY.js → ComponentConfigurationPage-N-CTtgQa.js} +4 -4
  4. package/dist/_chunks/{ComponentConfigurationPage-_zF8p6CY.js.map → ComponentConfigurationPage-N-CTtgQa.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-_aG2DJSU.js → EditConfigurationPage-BHkjAbxH.js} +4 -4
  6. package/dist/_chunks/{EditConfigurationPage-_aG2DJSU.js.map → EditConfigurationPage-BHkjAbxH.js.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-CE_yavTi.mjs → EditConfigurationPage-CKK-5LfX.mjs} +4 -4
  8. package/dist/_chunks/{EditConfigurationPage-CE_yavTi.mjs.map → EditConfigurationPage-CKK-5LfX.mjs.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-DeTn7rAF.mjs → EditViewPage-B11aeMcf.mjs} +50 -10
  10. package/dist/_chunks/EditViewPage-B11aeMcf.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-G9uNzwYL.js → EditViewPage-QPUftxUd.js} +49 -9
  12. package/dist/_chunks/EditViewPage-QPUftxUd.js.map +1 -0
  13. package/dist/_chunks/{Field-CnCKhI1R.mjs → Field-Bj_RgtGo.mjs} +109 -46
  14. package/dist/_chunks/Field-Bj_RgtGo.mjs.map +1 -0
  15. package/dist/_chunks/{Field-DDHUWEfV.js → Field-DUK83cfh.js} +108 -45
  16. package/dist/_chunks/Field-DUK83cfh.js.map +1 -0
  17. package/dist/_chunks/{Form-DYETaKUX.js → Form-DHmBRlHd.js} +3 -3
  18. package/dist/_chunks/Form-DHmBRlHd.js.map +1 -0
  19. package/dist/_chunks/{Form-IvVVwqRL.mjs → Form-DLMSoXV7.mjs} +3 -3
  20. package/dist/_chunks/Form-DLMSoXV7.mjs.map +1 -0
  21. package/dist/_chunks/{History-BMunT-do.mjs → History-CfCSNlG9.mjs} +43 -100
  22. package/dist/_chunks/History-CfCSNlG9.mjs.map +1 -0
  23. package/dist/_chunks/{History-CnZDctSO.js → History-Di3zm4HT.js} +41 -98
  24. package/dist/_chunks/History-Di3zm4HT.js.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-CDqkCxgV.mjs → ListConfigurationPage-0mtv_iqk.mjs} +6 -5
  26. package/dist/_chunks/ListConfigurationPage-0mtv_iqk.mjs.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-BynalOp8.js → ListConfigurationPage-Cq361KIt.js} +5 -4
  28. package/dist/_chunks/ListConfigurationPage-Cq361KIt.js.map +1 -0
  29. package/dist/_chunks/{ListViewPage-_5gS-DOF.mjs → ListViewPage-BxLVROX8.mjs} +69 -42
  30. package/dist/_chunks/ListViewPage-BxLVROX8.mjs.map +1 -0
  31. package/dist/_chunks/{ListViewPage-I88Ouzoq.js → ListViewPage-DFDcG8gM.js} +69 -42
  32. package/dist/_chunks/ListViewPage-DFDcG8gM.js.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-Dht-55hr.mjs → NoContentTypePage-BRfDd67_.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-Dht-55hr.mjs.map → NoContentTypePage-BRfDd67_.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-BaWQ7HsA.js → NoContentTypePage-BSyvnDZZ.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-BaWQ7HsA.js.map → NoContentTypePage-BSyvnDZZ.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-Bs8D5W_v.mjs → NoPermissionsPage-CV9V8KWa.mjs} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-Bs8D5W_v.mjs.map → NoPermissionsPage-CV9V8KWa.mjs.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-DCVUh5at.js → NoPermissionsPage-DyLphsn_.js} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-DCVUh5at.js.map → NoPermissionsPage-DyLphsn_.js.map} +1 -1
  41. package/dist/_chunks/Preview-C_B1nx3g.mjs +272 -0
  42. package/dist/_chunks/Preview-C_B1nx3g.mjs.map +1 -0
  43. package/dist/_chunks/Preview-D_3aO6Ly.js +291 -0
  44. package/dist/_chunks/Preview-D_3aO6Ly.js.map +1 -0
  45. package/dist/_chunks/{Relations-Chdt5qWc.mjs → Relations-C6pwmDXh.mjs} +72 -36
  46. package/dist/_chunks/Relations-C6pwmDXh.mjs.map +1 -0
  47. package/dist/_chunks/{Relations-BPgFQeGj.js → Relations-Cne2AlrL.js} +71 -35
  48. package/dist/_chunks/Relations-Cne2AlrL.js.map +1 -0
  49. package/dist/_chunks/{en-CPTj6CjC.mjs → en-DhFUjrNW.mjs} +22 -11
  50. package/dist/_chunks/{en-CPTj6CjC.mjs.map → en-DhFUjrNW.mjs.map} +1 -1
  51. package/dist/_chunks/{en-BVzUkPxZ.js → en-Ic0kXjxB.js} +22 -11
  52. package/dist/_chunks/{en-BVzUkPxZ.js.map → en-Ic0kXjxB.js.map} +1 -1
  53. package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
  54. package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
  55. package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
  56. package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
  57. package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
  58. package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
  59. package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
  60. package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
  61. package/dist/_chunks/{index-D4UGPFZC.mjs → index-BpxR3En4.mjs} +887 -726
  62. package/dist/_chunks/index-BpxR3En4.mjs.map +1 -0
  63. package/dist/_chunks/{index-BhbLFX4l.js → index-T-aWjbj2.js} +884 -722
  64. package/dist/_chunks/index-T-aWjbj2.js.map +1 -0
  65. package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
  66. package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
  67. package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
  68. package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
  69. package/dist/_chunks/{layout-CYA7s0qO.js → layout-BEuNwv-F.js} +3 -3
  70. package/dist/_chunks/{layout-CYA7s0qO.js.map → layout-BEuNwv-F.js.map} +1 -1
  71. package/dist/_chunks/{layout-D4HI4_PS.mjs → layout-DhMZ_lDx.mjs} +3 -3
  72. package/dist/_chunks/{layout-D4HI4_PS.mjs.map → layout-DhMZ_lDx.mjs.map} +1 -1
  73. package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
  74. package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
  75. package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
  76. package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
  77. package/dist/_chunks/{relations-1pXaYpBK.mjs → relations-BdnxoX6f.mjs} +6 -7
  78. package/dist/_chunks/relations-BdnxoX6f.mjs.map +1 -0
  79. package/dist/_chunks/{relations-DDZ9OxNo.js → relations-kLcuobLk.js} +6 -7
  80. package/dist/_chunks/relations-kLcuobLk.js.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 +4 -3
  84. package/dist/admin/src/exports.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +32 -1
  86. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  87. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
  88. package/dist/admin/src/pages/EditView/components/Header.d.ts +1 -0
  89. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  90. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  91. package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
  92. package/dist/admin/src/preview/constants.d.ts +1 -0
  93. package/dist/admin/src/preview/index.d.ts +4 -0
  94. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  95. package/dist/admin/src/preview/routes.d.ts +3 -0
  96. package/dist/admin/src/preview/services/preview.d.ts +3 -0
  97. package/dist/admin/src/router.d.ts +1 -1
  98. package/dist/admin/src/services/documents.d.ts +0 -3
  99. package/dist/server/index.js +421 -160
  100. package/dist/server/index.js.map +1 -1
  101. package/dist/server/index.mjs +422 -161
  102. package/dist/server/index.mjs.map +1 -1
  103. package/dist/server/src/bootstrap.d.ts.map +1 -1
  104. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  105. package/dist/server/src/controllers/index.d.ts.map +1 -1
  106. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  107. package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
  108. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  109. package/dist/server/src/history/services/history.d.ts.map +1 -1
  110. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  111. package/dist/server/src/history/services/utils.d.ts +2 -3
  112. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  113. package/dist/server/src/index.d.ts +4 -4
  114. package/dist/server/src/preview/constants.d.ts +2 -0
  115. package/dist/server/src/preview/constants.d.ts.map +1 -0
  116. package/dist/server/src/preview/controllers/index.d.ts +2 -0
  117. package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
  118. package/dist/server/src/preview/controllers/preview.d.ts +13 -0
  119. package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
  120. package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
  121. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
  122. package/dist/server/src/preview/index.d.ts +4 -0
  123. package/dist/server/src/preview/index.d.ts.map +1 -0
  124. package/dist/server/src/preview/routes/index.d.ts +8 -0
  125. package/dist/server/src/preview/routes/index.d.ts.map +1 -0
  126. package/dist/server/src/preview/routes/preview.d.ts +4 -0
  127. package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
  128. package/dist/server/src/preview/services/index.d.ts +16 -0
  129. package/dist/server/src/preview/services/index.d.ts.map +1 -0
  130. package/dist/server/src/preview/services/preview-config.d.ts +32 -0
  131. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
  132. package/dist/server/src/preview/services/preview.d.ts +12 -0
  133. package/dist/server/src/preview/services/preview.d.ts.map +1 -0
  134. package/dist/server/src/preview/utils.d.ts +19 -0
  135. package/dist/server/src/preview/utils.d.ts.map +1 -0
  136. package/dist/server/src/register.d.ts.map +1 -1
  137. package/dist/server/src/routes/index.d.ts.map +1 -1
  138. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  139. package/dist/server/src/services/document-metadata.d.ts +8 -8
  140. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  141. package/dist/server/src/services/index.d.ts +4 -4
  142. package/dist/server/src/services/index.d.ts.map +1 -1
  143. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  144. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  145. package/dist/server/src/utils/index.d.ts +2 -0
  146. package/dist/server/src/utils/index.d.ts.map +1 -1
  147. package/dist/shared/contracts/index.d.ts +1 -0
  148. package/dist/shared/contracts/index.d.ts.map +1 -1
  149. package/dist/shared/contracts/preview.d.ts +27 -0
  150. package/dist/shared/contracts/preview.d.ts.map +1 -0
  151. package/dist/shared/index.js +4 -0
  152. package/dist/shared/index.js.map +1 -1
  153. package/dist/shared/index.mjs +4 -0
  154. package/dist/shared/index.mjs.map +1 -1
  155. package/package.json +13 -13
  156. package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +0 -1
  157. package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +0 -1
  158. package/dist/_chunks/Field-CnCKhI1R.mjs.map +0 -1
  159. package/dist/_chunks/Field-DDHUWEfV.js.map +0 -1
  160. package/dist/_chunks/Form-DYETaKUX.js.map +0 -1
  161. package/dist/_chunks/Form-IvVVwqRL.mjs.map +0 -1
  162. package/dist/_chunks/History-BMunT-do.mjs.map +0 -1
  163. package/dist/_chunks/History-CnZDctSO.js.map +0 -1
  164. package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +0 -1
  165. package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +0 -1
  166. package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +0 -1
  167. package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +0 -1
  168. package/dist/_chunks/Relations-BPgFQeGj.js.map +0 -1
  169. package/dist/_chunks/Relations-Chdt5qWc.mjs.map +0 -1
  170. package/dist/_chunks/index-BhbLFX4l.js.map +0 -1
  171. package/dist/_chunks/index-D4UGPFZC.mjs.map +0 -1
  172. package/dist/_chunks/relations-1pXaYpBK.mjs.map +0 -1
  173. package/dist/_chunks/relations-DDZ9OxNo.js.map +0 -1
  174. package/strapi-server.js +0 -3
@@ -1,17 +1,18 @@
1
1
  import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
3
+ import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import * as React from "react";
5
5
  import { lazy } from "react";
6
- import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import mapValues from "lodash/fp/mapValues";
7
8
  import { useIntl } from "react-intl";
8
9
  import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
+ import { styled } from "styled-components";
9
11
  import * as yup from "yup";
10
12
  import { ValidationError } from "yup";
13
+ import { stringify } from "qs";
11
14
  import pipe from "lodash/fp/pipe";
12
15
  import { intervalToDuration, isPast } from "date-fns";
13
- import { styled } from "styled-components";
14
- import { stringify } from "qs";
15
16
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
17
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
18
  const v = glob[path];
@@ -100,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
100
101
  if (!slug) {
101
102
  throw new Error("Cannot find the slug param in the URL");
102
103
  }
104
+ const [{ rawQuery }] = useQueryParams();
103
105
  const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
104
106
  const contentTypePermissions = React.useMemo(() => {
105
107
  const contentTypePermissions2 = userPermissions.filter(
@@ -110,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
110
112
  return { ...acc, [action]: [permission] };
111
113
  }, {});
112
114
  }, [slug, userPermissions]);
113
- const { isLoading, allowedActions } = useRBAC(contentTypePermissions, permissions ?? void 0);
115
+ const { isLoading, allowedActions } = useRBAC(
116
+ contentTypePermissions,
117
+ permissions ?? void 0,
118
+ // TODO: useRBAC context should be typed and built differently
119
+ // We are passing raw query as context to the hook so that it can
120
+ // rely on the locale provided from DocumentRBAC for its permission calculations.
121
+ rawQuery
122
+ );
114
123
  const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
115
124
  const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
116
125
  const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
@@ -265,7 +274,7 @@ const documentApi = contentManagerApi.injectEndpoints({
265
274
  url: `/content-manager/collection-types/${model}`,
266
275
  method: "GET",
267
276
  config: {
268
- params
277
+ params: stringify(params, { encode: true })
269
278
  }
270
279
  }),
271
280
  providesTags: (result, _error, arg) => {
@@ -453,14 +462,29 @@ const buildValidParams = (query) => {
453
462
  {}
454
463
  )
455
464
  };
456
- if ("_q" in validQueryParams) {
457
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
458
- }
459
465
  return validQueryParams;
460
466
  };
461
467
  const isBaseQueryError = (error) => {
462
468
  return error.name !== void 0;
463
469
  };
470
+ const arrayValidator = (attribute, options) => ({
471
+ message: translatedErrors.required,
472
+ test(value) {
473
+ if (options.status === "draft") {
474
+ return true;
475
+ }
476
+ if (!attribute.required) {
477
+ return true;
478
+ }
479
+ if (!value) {
480
+ return false;
481
+ }
482
+ if (Array.isArray(value) && value.length === 0) {
483
+ return false;
484
+ }
485
+ return true;
486
+ }
487
+ });
464
488
  const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
465
489
  const createModelSchema = (attributes2) => yup.object().shape(
466
490
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -468,6 +492,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
468
492
  return acc;
469
493
  }
470
494
  const validations = [
495
+ addNullableValidation,
471
496
  addRequiredValidation,
472
497
  addMinLengthValidation,
473
498
  addMaxLengthValidation,
@@ -484,12 +509,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
484
509
  ...acc,
485
510
  [name]: transformSchema(
486
511
  yup.array().of(createModelSchema(attributes3).nullable(false))
487
- )
512
+ ).test(arrayValidator(attribute, options))
488
513
  };
489
514
  } else {
490
515
  return {
491
516
  ...acc,
492
- [name]: transformSchema(createModelSchema(attributes3))
517
+ [name]: transformSchema(createModelSchema(attributes3).nullable())
493
518
  };
494
519
  }
495
520
  }
@@ -511,7 +536,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
511
536
  }
512
537
  )
513
538
  )
514
- )
539
+ ).test(arrayValidator(attribute, options))
515
540
  };
516
541
  case "relation":
517
542
  return {
@@ -523,7 +548,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
523
548
  } else if (Array.isArray(value)) {
524
549
  return yup.array().of(
525
550
  yup.object().shape({
526
- id: yup.string().required()
551
+ id: yup.number().required()
527
552
  })
528
553
  );
529
554
  } else if (typeof value === "object") {
@@ -609,17 +634,17 @@ const nullableSchema = (schema) => {
609
634
  schema
610
635
  );
611
636
  };
637
+ const addNullableValidation = () => (schema) => {
638
+ return nullableSchema(schema);
639
+ };
612
640
  const addRequiredValidation = (attribute, options) => (schema) => {
613
- if (options.status === "draft") {
614
- return nullableSchema(schema);
615
- }
616
- if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
617
- return schema.min(1, translatedErrors.required);
641
+ if (options.status === "draft" || !attribute.required) {
642
+ return schema;
618
643
  }
619
- if (attribute.required && attribute.type !== "relation") {
644
+ if (attribute.required && "required" in schema) {
620
645
  return schema.required(translatedErrors.required);
621
646
  }
622
- return nullableSchema(schema);
647
+ return schema;
623
648
  };
624
649
  const addMinLengthValidation = (attribute, options) => (schema) => {
625
650
  if (options.status === "draft") {
@@ -647,31 +672,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
647
672
  return schema;
648
673
  };
649
674
  const addMinValidation = (attribute, options) => (schema) => {
650
- if ("min" in attribute) {
675
+ if (options.status === "draft") {
676
+ return schema;
677
+ }
678
+ if ("min" in attribute && "min" in schema) {
651
679
  const min = toInteger(attribute.min);
652
- if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
653
- if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
654
- return schema.test(
655
- "custom-min",
656
- {
657
- ...translatedErrors.min,
658
- values: {
659
- min: attribute.min
660
- }
661
- },
662
- (value) => {
663
- if (!value) {
664
- return true;
665
- }
666
- if (Array.isArray(value) && value.length === 0) {
667
- return true;
668
- }
669
- return value.length >= min;
670
- }
671
- );
672
- }
673
- }
674
- if ("min" in schema && min) {
680
+ if (min) {
675
681
  return schema.min(min, {
676
682
  ...translatedErrors.min,
677
683
  values: {
@@ -789,19 +795,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
789
795
  }, {});
790
796
  return componentsByKey;
791
797
  };
792
- const useDocument = (args, opts) => {
798
+ const HOOKS = {
799
+ /**
800
+ * Hook that allows to mutate the displayed headers of the list view table
801
+ * @constant
802
+ * @type {string}
803
+ */
804
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
805
+ /**
806
+ * Hook that allows to mutate the CM's collection types links pre-set filters
807
+ * @constant
808
+ * @type {string}
809
+ */
810
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
811
+ /**
812
+ * Hook that allows to mutate the CM's edit view layout
813
+ * @constant
814
+ * @type {string}
815
+ */
816
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
817
+ /**
818
+ * Hook that allows to mutate the CM's single types links pre-set filters
819
+ * @constant
820
+ * @type {string}
821
+ */
822
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
823
+ };
824
+ const contentTypesApi = contentManagerApi.injectEndpoints({
825
+ endpoints: (builder) => ({
826
+ getContentTypeConfiguration: builder.query({
827
+ query: (uid) => ({
828
+ url: `/content-manager/content-types/${uid}/configuration`,
829
+ method: "GET"
830
+ }),
831
+ transformResponse: (response) => response.data,
832
+ providesTags: (_result, _error, uid) => [
833
+ { type: "ContentTypesConfiguration", id: uid },
834
+ { type: "ContentTypeSettings", id: "LIST" }
835
+ ]
836
+ }),
837
+ getAllContentTypeSettings: builder.query({
838
+ query: () => "/content-manager/content-types-settings",
839
+ transformResponse: (response) => response.data,
840
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
841
+ }),
842
+ updateContentTypeConfiguration: builder.mutation({
843
+ query: ({ uid, ...body }) => ({
844
+ url: `/content-manager/content-types/${uid}/configuration`,
845
+ method: "PUT",
846
+ data: body
847
+ }),
848
+ transformResponse: (response) => response.data,
849
+ invalidatesTags: (_result, _error, { uid }) => [
850
+ { type: "ContentTypesConfiguration", id: uid },
851
+ { type: "ContentTypeSettings", id: "LIST" },
852
+ // Is this necessary?
853
+ { type: "InitialData" }
854
+ ]
855
+ })
856
+ })
857
+ });
858
+ const {
859
+ useGetContentTypeConfigurationQuery,
860
+ useGetAllContentTypeSettingsQuery,
861
+ useUpdateContentTypeConfigurationMutation
862
+ } = contentTypesApi;
863
+ const checkIfAttributeIsDisplayable = (attribute) => {
864
+ const { type } = attribute;
865
+ if (type === "relation") {
866
+ return !attribute.relation.toLowerCase().includes("morph");
867
+ }
868
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
869
+ };
870
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
871
+ if (!mainFieldName) {
872
+ return void 0;
873
+ }
874
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
875
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
876
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
877
+ );
878
+ return {
879
+ name: mainFieldName,
880
+ type: mainFieldType ?? "string"
881
+ };
882
+ };
883
+ const DEFAULT_SETTINGS = {
884
+ bulkable: false,
885
+ filterable: false,
886
+ searchable: false,
887
+ pagination: false,
888
+ defaultSortBy: "",
889
+ defaultSortOrder: "asc",
890
+ mainField: "id",
891
+ pageSize: 10
892
+ };
893
+ const useDocumentLayout = (model) => {
894
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
895
+ const [{ query }] = useQueryParams();
896
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
793
897
  const { toggleNotification } = useNotification();
794
898
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
899
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
795
900
  const {
796
- currentData: data,
797
- isLoading: isLoadingDocument,
798
- isFetching: isFetchingDocument,
799
- error
800
- } = useGetDocumentQuery(args, {
801
- ...opts,
802
- skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
803
- });
804
- const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
901
+ data,
902
+ isLoading: isLoadingConfigs,
903
+ error,
904
+ isFetching: isFetchingConfigs
905
+ } = useGetContentTypeConfigurationQuery(model);
906
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
805
907
  React.useEffect(() => {
806
908
  if (error) {
807
909
  toggleNotification({
@@ -809,94 +911,349 @@ const useDocument = (args, opts) => {
809
911
  message: formatAPIError(error)
810
912
  });
811
913
  }
812
- }, [toggleNotification, error, formatAPIError, args.collectionType]);
813
- const validationSchema = React.useMemo(() => {
814
- if (!schema) {
815
- return null;
816
- }
817
- return createYupSchema(schema.attributes, components);
818
- }, [schema, components]);
819
- const validate = React.useCallback(
820
- (document) => {
821
- if (!validationSchema) {
822
- throw new Error(
823
- "There is no validation schema generated, this is likely due to the schema not being loaded yet."
824
- );
825
- }
826
- try {
827
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
828
- return null;
829
- } catch (error2) {
830
- if (error2 instanceof ValidationError) {
831
- return getYupValidationErrors(error2);
832
- }
833
- throw error2;
834
- }
914
+ }, [error, formatAPIError, toggleNotification]);
915
+ const editLayout = React.useMemo(
916
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
917
+ layout: [],
918
+ components: {},
919
+ metadatas: {},
920
+ options: {},
921
+ settings: DEFAULT_SETTINGS
835
922
  },
836
- [validationSchema]
923
+ [data, isLoading, schemas, schema, components]
924
+ );
925
+ const listLayout = React.useMemo(() => {
926
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
927
+ layout: [],
928
+ metadatas: {},
929
+ options: {},
930
+ settings: DEFAULT_SETTINGS
931
+ };
932
+ }, [data, isLoading, schemas, schema, components]);
933
+ const { layout: edit } = React.useMemo(
934
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
935
+ layout: editLayout,
936
+ query
937
+ }),
938
+ [editLayout, query, runHookWaterfall]
837
939
  );
838
- const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
839
940
  return {
840
- components,
841
- document: data?.data,
842
- meta: data?.meta,
941
+ error,
843
942
  isLoading,
844
- schema,
845
- validate
846
- };
847
- };
848
- const useDoc = () => {
849
- const { id, slug, collectionType, origin } = useParams();
850
- const [{ query }] = useQueryParams();
851
- const params = React.useMemo(() => buildValidParams(query), [query]);
852
- if (!collectionType) {
853
- throw new Error("Could not find collectionType in url params");
854
- }
855
- if (!slug) {
856
- throw new Error("Could not find model in url params");
857
- }
858
- return {
859
- collectionType,
860
- model: slug,
861
- id: origin || id === "create" ? void 0 : id,
862
- ...useDocument(
863
- { documentId: origin || id, model: slug, collectionType, params },
864
- {
865
- skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
866
- }
867
- )
943
+ edit,
944
+ list: listLayout
868
945
  };
869
946
  };
870
- const prefixPluginTranslations = (trad, pluginId) => {
871
- if (!pluginId) {
872
- throw new TypeError("pluginId can't be empty");
873
- }
874
- return Object.keys(trad).reduce((acc, current) => {
875
- acc[`${pluginId}.${current}`] = trad[current];
876
- return acc;
877
- }, {});
878
- };
879
- const getTranslation = (id) => `content-manager.${id}`;
880
- const DEFAULT_UNEXPECTED_ERROR_MSG = {
881
- id: "notification.error",
882
- defaultMessage: "An error occurred, please try again"
947
+ const useDocLayout = () => {
948
+ const { model } = useDoc();
949
+ return useDocumentLayout(model);
883
950
  };
884
- const useDocumentActions = () => {
885
- const { toggleNotification } = useNotification();
886
- const { formatMessage } = useIntl();
887
- const { trackUsage } = useTracking();
888
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
- const navigate = useNavigate();
890
- const [deleteDocument] = useDeleteDocumentMutation();
891
- const _delete = React.useCallback(
892
- async ({ collectionType, model, documentId, params }, trackerProperty) => {
893
- try {
894
- trackUsage("willDeleteEntry", trackerProperty);
895
- const res = await deleteDocument({
896
- collectionType,
897
- model,
898
- documentId,
899
- params
951
+ const formatEditLayout = (data, {
952
+ schemas,
953
+ schema,
954
+ components
955
+ }) => {
956
+ let currentPanelIndex = 0;
957
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
958
+ data.contentType.layouts.edit,
959
+ schema?.attributes,
960
+ data.contentType.metadatas,
961
+ { configurations: data.components, schemas: components },
962
+ schemas
963
+ ).reduce((panels, row) => {
964
+ if (row.some((field) => field.type === "dynamiczone")) {
965
+ panels.push([row]);
966
+ currentPanelIndex += 2;
967
+ } else {
968
+ if (!panels[currentPanelIndex]) {
969
+ panels.push([row]);
970
+ } else {
971
+ panels[currentPanelIndex].push(row);
972
+ }
973
+ }
974
+ return panels;
975
+ }, []);
976
+ const componentEditAttributes = Object.entries(data.components).reduce(
977
+ (acc, [uid, configuration]) => {
978
+ acc[uid] = {
979
+ layout: convertEditLayoutToFieldLayouts(
980
+ configuration.layouts.edit,
981
+ components[uid].attributes,
982
+ configuration.metadatas,
983
+ { configurations: data.components, schemas: components }
984
+ ),
985
+ settings: {
986
+ ...configuration.settings,
987
+ icon: components[uid].info.icon,
988
+ displayName: components[uid].info.displayName
989
+ }
990
+ };
991
+ return acc;
992
+ },
993
+ {}
994
+ );
995
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
996
+ (acc, [attribute, metadata]) => {
997
+ return {
998
+ ...acc,
999
+ [attribute]: metadata.edit
1000
+ };
1001
+ },
1002
+ {}
1003
+ );
1004
+ return {
1005
+ layout: panelledEditAttributes,
1006
+ components: componentEditAttributes,
1007
+ metadatas: editMetadatas,
1008
+ settings: {
1009
+ ...data.contentType.settings,
1010
+ displayName: schema?.info.displayName
1011
+ },
1012
+ options: {
1013
+ ...schema?.options,
1014
+ ...schema?.pluginOptions,
1015
+ ...data.contentType.options
1016
+ }
1017
+ };
1018
+ };
1019
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
1020
+ return rows.map(
1021
+ (row) => row.map((field) => {
1022
+ const attribute = attributes[field.name];
1023
+ if (!attribute) {
1024
+ return null;
1025
+ }
1026
+ const { edit: metadata } = metadatas[field.name];
1027
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1028
+ return {
1029
+ attribute,
1030
+ disabled: !metadata.editable,
1031
+ hint: metadata.description,
1032
+ label: metadata.label ?? "",
1033
+ name: field.name,
1034
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
1035
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1036
+ schemas,
1037
+ components: components?.schemas ?? {}
1038
+ }),
1039
+ placeholder: metadata.placeholder ?? "",
1040
+ required: attribute.required ?? false,
1041
+ size: field.size,
1042
+ unique: "unique" in attribute ? attribute.unique : false,
1043
+ visible: metadata.visible ?? true,
1044
+ type: attribute.type
1045
+ };
1046
+ }).filter((field) => field !== null)
1047
+ );
1048
+ };
1049
+ const formatListLayout = (data, {
1050
+ schemas,
1051
+ schema,
1052
+ components
1053
+ }) => {
1054
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
1055
+ (acc, [attribute, metadata]) => {
1056
+ return {
1057
+ ...acc,
1058
+ [attribute]: metadata.list
1059
+ };
1060
+ },
1061
+ {}
1062
+ );
1063
+ const listAttributes = convertListLayoutToFieldLayouts(
1064
+ data.contentType.layouts.list,
1065
+ schema?.attributes,
1066
+ listMetadatas,
1067
+ { configurations: data.components, schemas: components },
1068
+ schemas
1069
+ );
1070
+ return {
1071
+ layout: listAttributes,
1072
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
1073
+ metadatas: listMetadatas,
1074
+ options: {
1075
+ ...schema?.options,
1076
+ ...schema?.pluginOptions,
1077
+ ...data.contentType.options
1078
+ }
1079
+ };
1080
+ };
1081
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
1082
+ return columns.map((name) => {
1083
+ const attribute = attributes[name];
1084
+ if (!attribute) {
1085
+ return null;
1086
+ }
1087
+ const metadata = metadatas[name];
1088
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
1089
+ return {
1090
+ attribute,
1091
+ label: metadata.label ?? "",
1092
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
1093
+ schemas,
1094
+ components: components?.schemas ?? {}
1095
+ }),
1096
+ name,
1097
+ searchable: metadata.searchable ?? true,
1098
+ sortable: metadata.sortable ?? true
1099
+ };
1100
+ }).filter((field) => field !== null);
1101
+ };
1102
+ const useDocument = (args, opts) => {
1103
+ const { toggleNotification } = useNotification();
1104
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1105
+ const {
1106
+ currentData: data,
1107
+ isLoading: isLoadingDocument,
1108
+ isFetching: isFetchingDocument,
1109
+ error
1110
+ } = useGetDocumentQuery(args, {
1111
+ ...opts,
1112
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1113
+ });
1114
+ const {
1115
+ components,
1116
+ schema,
1117
+ schemas,
1118
+ isLoading: isLoadingSchema
1119
+ } = useContentTypeSchema(args.model);
1120
+ React.useEffect(() => {
1121
+ if (error) {
1122
+ toggleNotification({
1123
+ type: "danger",
1124
+ message: formatAPIError(error)
1125
+ });
1126
+ }
1127
+ }, [toggleNotification, error, formatAPIError, args.collectionType]);
1128
+ const validationSchema = React.useMemo(() => {
1129
+ if (!schema) {
1130
+ return null;
1131
+ }
1132
+ return createYupSchema(schema.attributes, components);
1133
+ }, [schema, components]);
1134
+ const validate = React.useCallback(
1135
+ (document) => {
1136
+ if (!validationSchema) {
1137
+ throw new Error(
1138
+ "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1139
+ );
1140
+ }
1141
+ try {
1142
+ validationSchema.validateSync(document, { abortEarly: false, strict: true });
1143
+ return null;
1144
+ } catch (error2) {
1145
+ if (error2 instanceof ValidationError) {
1146
+ return getYupValidationErrors(error2);
1147
+ }
1148
+ throw error2;
1149
+ }
1150
+ },
1151
+ [validationSchema]
1152
+ );
1153
+ const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1154
+ const hasError = !!error;
1155
+ return {
1156
+ components,
1157
+ document: data?.data,
1158
+ meta: data?.meta,
1159
+ isLoading,
1160
+ hasError,
1161
+ schema,
1162
+ schemas,
1163
+ validate
1164
+ };
1165
+ };
1166
+ const useDoc = () => {
1167
+ const { id, slug, collectionType, origin } = useParams();
1168
+ const [{ query }] = useQueryParams();
1169
+ const params = React.useMemo(() => buildValidParams(query), [query]);
1170
+ if (!collectionType) {
1171
+ throw new Error("Could not find collectionType in url params");
1172
+ }
1173
+ if (!slug) {
1174
+ throw new Error("Could not find model in url params");
1175
+ }
1176
+ const document = useDocument(
1177
+ { documentId: origin || id, model: slug, collectionType, params },
1178
+ {
1179
+ skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
1180
+ }
1181
+ );
1182
+ const returnId = origin || id === "create" ? void 0 : id;
1183
+ return {
1184
+ collectionType,
1185
+ model: slug,
1186
+ id: returnId,
1187
+ ...document
1188
+ };
1189
+ };
1190
+ const useContentManagerContext = () => {
1191
+ const {
1192
+ collectionType,
1193
+ model,
1194
+ id,
1195
+ components,
1196
+ isLoading: isLoadingDoc,
1197
+ schema,
1198
+ schemas
1199
+ } = useDoc();
1200
+ const layout = useDocumentLayout(model);
1201
+ const form = useForm("useContentManagerContext", (state) => state);
1202
+ const isSingleType = collectionType === SINGLE_TYPES;
1203
+ const slug = model;
1204
+ const isCreatingEntry = id === "create";
1205
+ useContentTypeSchema();
1206
+ const isLoading = isLoadingDoc || layout.isLoading;
1207
+ const error = layout.error;
1208
+ return {
1209
+ error,
1210
+ isLoading,
1211
+ // Base metadata
1212
+ model,
1213
+ collectionType,
1214
+ id,
1215
+ slug,
1216
+ isCreatingEntry,
1217
+ isSingleType,
1218
+ hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
1219
+ // All schema infos
1220
+ components,
1221
+ contentType: schema,
1222
+ contentTypes: schemas,
1223
+ // Form state
1224
+ form,
1225
+ // layout infos
1226
+ layout
1227
+ };
1228
+ };
1229
+ const prefixPluginTranslations = (trad, pluginId) => {
1230
+ return Object.keys(trad).reduce((acc, current) => {
1231
+ acc[`${pluginId}.${current}`] = trad[current];
1232
+ return acc;
1233
+ }, {});
1234
+ };
1235
+ const getTranslation = (id) => `content-manager.${id}`;
1236
+ const DEFAULT_UNEXPECTED_ERROR_MSG = {
1237
+ id: "notification.error",
1238
+ defaultMessage: "An error occurred, please try again"
1239
+ };
1240
+ const useDocumentActions = () => {
1241
+ const { toggleNotification } = useNotification();
1242
+ const { formatMessage } = useIntl();
1243
+ const { trackUsage } = useTracking();
1244
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1245
+ const navigate = useNavigate();
1246
+ const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
1247
+ const [deleteDocument] = useDeleteDocumentMutation();
1248
+ const _delete = React.useCallback(
1249
+ async ({ collectionType, model, documentId, params }, trackerProperty) => {
1250
+ try {
1251
+ trackUsage("willDeleteEntry", trackerProperty);
1252
+ const res = await deleteDocument({
1253
+ collectionType,
1254
+ model,
1255
+ documentId,
1256
+ params
900
1257
  });
901
1258
  if ("error" in res) {
902
1259
  toggleNotification({
@@ -1201,6 +1558,7 @@ const useDocumentActions = () => {
1201
1558
  defaultMessage: "Saved document"
1202
1559
  })
1203
1560
  });
1561
+ setCurrentStep("contentManager.success");
1204
1562
  return res.data;
1205
1563
  } catch (err) {
1206
1564
  toggleNotification({
@@ -1302,10 +1660,10 @@ const useDocumentActions = () => {
1302
1660
  update
1303
1661
  };
1304
1662
  };
1305
- const ProtectedHistoryPage = lazy(
1306
- () => import("./History-BMunT-do.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1663
+ const ProtectedHistoryPage = React.lazy(
1664
+ () => import("./History-CfCSNlG9.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1307
1665
  );
1308
- const routes$1 = [
1666
+ const routes$2 = [
1309
1667
  {
1310
1668
  path: ":collectionType/:slug/:id/history",
1311
1669
  Component: ProtectedHistoryPage
@@ -1315,32 +1673,45 @@ const routes$1 = [
1315
1673
  Component: ProtectedHistoryPage
1316
1674
  }
1317
1675
  ];
1676
+ const ProtectedPreviewPage = React.lazy(
1677
+ () => import("./Preview-C_B1nx3g.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1678
+ );
1679
+ const routes$1 = [
1680
+ {
1681
+ path: ":collectionType/:slug/:id/preview",
1682
+ Component: ProtectedPreviewPage
1683
+ },
1684
+ {
1685
+ path: ":collectionType/:slug/preview",
1686
+ Component: ProtectedPreviewPage
1687
+ }
1688
+ ];
1318
1689
  const ProtectedEditViewPage = lazy(
1319
- () => import("./EditViewPage-DeTn7rAF.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1690
+ () => import("./EditViewPage-B11aeMcf.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1320
1691
  );
1321
1692
  const ProtectedListViewPage = lazy(
1322
- () => import("./ListViewPage-_5gS-DOF.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1693
+ () => import("./ListViewPage-BxLVROX8.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1323
1694
  );
1324
1695
  const ProtectedListConfiguration = lazy(
1325
- () => import("./ListConfigurationPage-CDqkCxgV.mjs").then((mod) => ({
1696
+ () => import("./ListConfigurationPage-0mtv_iqk.mjs").then((mod) => ({
1326
1697
  default: mod.ProtectedListConfiguration
1327
1698
  }))
1328
1699
  );
1329
1700
  const ProtectedEditConfigurationPage = lazy(
1330
- () => import("./EditConfigurationPage-CE_yavTi.mjs").then((mod) => ({
1701
+ () => import("./EditConfigurationPage-CKK-5LfX.mjs").then((mod) => ({
1331
1702
  default: mod.ProtectedEditConfigurationPage
1332
1703
  }))
1333
1704
  );
1334
1705
  const ProtectedComponentConfigurationPage = lazy(
1335
- () => import("./ComponentConfigurationPage-CpBFh6_r.mjs").then((mod) => ({
1706
+ () => import("./ComponentConfigurationPage-BaJMOQyq.mjs").then((mod) => ({
1336
1707
  default: mod.ProtectedComponentConfigurationPage
1337
1708
  }))
1338
1709
  );
1339
1710
  const NoPermissions = lazy(
1340
- () => import("./NoPermissionsPage-Bs8D5W_v.mjs").then((mod) => ({ default: mod.NoPermissions }))
1711
+ () => import("./NoPermissionsPage-CV9V8KWa.mjs").then((mod) => ({ default: mod.NoPermissions }))
1341
1712
  );
1342
1713
  const NoContentType = lazy(
1343
- () => import("./NoContentTypePage-Dht-55hr.mjs").then((mod) => ({ default: mod.NoContentType }))
1714
+ () => import("./NoContentTypePage-BRfDd67_.mjs").then((mod) => ({ default: mod.NoContentType }))
1344
1715
  );
1345
1716
  const CollectionTypePages = () => {
1346
1717
  const { collectionType } = useParams();
@@ -1352,7 +1723,7 @@ const CollectionTypePages = () => {
1352
1723
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1353
1724
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1354
1725
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1355
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1726
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1356
1727
  const routes = [
1357
1728
  {
1358
1729
  path: LIST_RELATIVE_PATH,
@@ -1386,6 +1757,7 @@ const routes = [
1386
1757
  path: "no-content-types",
1387
1758
  Component: NoContentType
1388
1759
  },
1760
+ ...routes$2,
1389
1761
  ...routes$1
1390
1762
  ];
1391
1763
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1484,6 +1856,11 @@ const DocumentActionButton = (action) => {
1484
1856
  ) : null
1485
1857
  ] });
1486
1858
  };
1859
+ const MenuItem = styled(Menu.Item)`
1860
+ &:hover {
1861
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
1862
+ }
1863
+ `;
1487
1864
  const DocumentActionsMenu = ({
1488
1865
  actions: actions2,
1489
1866
  children,
@@ -1539,51 +1916,35 @@ const DocumentActionsMenu = ({
1539
1916
  ]
1540
1917
  }
1541
1918
  ),
1542
- /* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1919
+ /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1543
1920
  actions2.map((action) => {
1544
1921
  return /* @__PURE__ */ jsx(
1545
- Menu.Item,
1922
+ MenuItem,
1546
1923
  {
1547
1924
  disabled: action.disabled,
1548
1925
  onSelect: handleClick(action),
1549
1926
  display: "block",
1550
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1551
- /* @__PURE__ */ jsxs(
1552
- Flex,
1553
- {
1554
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1555
- gap: 2,
1556
- tag: "span",
1557
- children: [
1558
- /* @__PURE__ */ jsx(
1559
- Flex,
1560
- {
1561
- tag: "span",
1562
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1563
- children: action.icon
1564
- }
1565
- ),
1566
- action.label
1567
- ]
1568
- }
1569
- ),
1570
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1571
- Flex,
1572
- {
1573
- alignItems: "center",
1574
- background: "alternative100",
1575
- borderStyle: "solid",
1576
- borderColor: "alternative200",
1577
- borderWidth: "1px",
1578
- height: 5,
1579
- paddingLeft: 2,
1580
- paddingRight: 2,
1581
- hasRadius: true,
1582
- color: "alternative600",
1583
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1584
- }
1585
- )
1586
- ] })
1927
+ isVariantDanger: action.variant === "danger",
1928
+ isDisabled: action.disabled,
1929
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
1930
+ Flex,
1931
+ {
1932
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1933
+ gap: 2,
1934
+ tag: "span",
1935
+ children: [
1936
+ /* @__PURE__ */ jsx(
1937
+ Flex,
1938
+ {
1939
+ tag: "span",
1940
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1941
+ children: action.icon
1942
+ }
1943
+ ),
1944
+ action.label
1945
+ ]
1946
+ }
1947
+ ) })
1587
1948
  },
1588
1949
  action.id
1589
1950
  );
@@ -1694,6 +2055,18 @@ const DocumentActionModal = ({
1694
2055
  typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1695
2056
  ] }) });
1696
2057
  };
2058
+ const transformData = (data) => {
2059
+ if (Array.isArray(data)) {
2060
+ return data.map(transformData);
2061
+ }
2062
+ if (typeof data === "object" && data !== null) {
2063
+ if ("apiData" in data) {
2064
+ return data.apiData;
2065
+ }
2066
+ return mapValues(transformData)(data);
2067
+ }
2068
+ return data;
2069
+ };
1697
2070
  const PublishAction$1 = ({
1698
2071
  activeTab,
1699
2072
  documentId,
@@ -1708,6 +2081,7 @@ const PublishAction$1 = ({
1708
2081
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1709
2082
  const isListView = useMatch(LIST_PATH) !== null;
1710
2083
  const isCloning = useMatch(CLONE_PATH) !== null;
2084
+ const { id } = useParams();
1711
2085
  const { formatMessage } = useIntl();
1712
2086
  const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1713
2087
  const { publish } = useDocumentActions();
@@ -1787,7 +2161,9 @@ const PublishAction$1 = ({
1787
2161
  const performPublish = async () => {
1788
2162
  setSubmitting(true);
1789
2163
  try {
1790
- const { errors } = await validate();
2164
+ const { errors } = await validate(true, {
2165
+ status: "published"
2166
+ });
1791
2167
  if (errors) {
1792
2168
  toggleNotification({
1793
2169
  type: "danger",
@@ -1805,13 +2181,15 @@ const PublishAction$1 = ({
1805
2181
  documentId,
1806
2182
  params
1807
2183
  },
1808
- formValues
2184
+ transformData(formValues)
1809
2185
  );
1810
2186
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1811
- navigate({
1812
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1813
- search: rawQuery
1814
- });
2187
+ if (id === "create") {
2188
+ navigate({
2189
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2190
+ search: rawQuery
2191
+ });
2192
+ }
1815
2193
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1816
2194
  setErrors(formatValidationErrors(res.error));
1817
2195
  }
@@ -1895,24 +2273,24 @@ const UpdateAction = ({
1895
2273
  */
1896
2274
  disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1897
2275
  label: formatMessage({
1898
- id: "content-manager.containers.Edit.save",
2276
+ id: "global.save",
1899
2277
  defaultMessage: "Save"
1900
2278
  }),
1901
2279
  onClick: async () => {
1902
2280
  setSubmitting(true);
1903
2281
  try {
1904
- if (activeTab !== "draft") {
1905
- const { errors } = await validate();
1906
- if (errors) {
1907
- toggleNotification({
1908
- type: "danger",
1909
- message: formatMessage({
1910
- id: "content-manager.validation.error",
1911
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1912
- })
1913
- });
1914
- return;
1915
- }
2282
+ const { errors } = await validate(true, {
2283
+ status: "draft"
2284
+ });
2285
+ if (errors) {
2286
+ toggleNotification({
2287
+ type: "danger",
2288
+ message: formatMessage({
2289
+ id: "content-manager.validation.error",
2290
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2291
+ })
2292
+ });
2293
+ return;
1916
2294
  }
1917
2295
  if (isCloning) {
1918
2296
  const res = await clone(
@@ -1921,7 +2299,7 @@ const UpdateAction = ({
1921
2299
  documentId: cloneMatch.params.origin,
1922
2300
  params
1923
2301
  },
1924
- document
2302
+ transformData(document)
1925
2303
  );
1926
2304
  if ("data" in res) {
1927
2305
  navigate(
@@ -1942,7 +2320,7 @@ const UpdateAction = ({
1942
2320
  documentId,
1943
2321
  params
1944
2322
  },
1945
- document
2323
+ transformData(document)
1946
2324
  );
1947
2325
  if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1948
2326
  setErrors(formatValidationErrors(res.error));
@@ -1955,7 +2333,7 @@ const UpdateAction = ({
1955
2333
  model,
1956
2334
  params
1957
2335
  },
1958
- document
2336
+ transformData(document)
1959
2337
  );
1960
2338
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1961
2339
  navigate(
@@ -2160,7 +2538,7 @@ const RelativeTime = React.forwardRef(
2160
2538
  });
2161
2539
  const unit = intervals.find((intervalUnit) => {
2162
2540
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2163
- });
2541
+ }) ?? "seconds";
2164
2542
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2165
2543
  const customInterval = customIntervals.find(
2166
2544
  (custom) => interval[custom.unit] < custom.threshold
@@ -2194,19 +2572,29 @@ const getDisplayName = ({
2194
2572
  return email ?? "";
2195
2573
  };
2196
2574
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2197
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2575
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2198
2576
  const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2199
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2577
+ const { formatMessage } = useIntl();
2578
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2579
+ id: `content-manager.containers.List.${status}`,
2580
+ defaultMessage: capitalise(status)
2581
+ }) }) });
2200
2582
  };
2201
2583
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2202
2584
  const { formatMessage } = useIntl();
2203
2585
  const isCloning = useMatch(CLONE_PATH) !== null;
2586
+ const params = useParams();
2204
2587
  const title = isCreating ? formatMessage({
2205
2588
  id: "content-manager.containers.edit.title.new",
2206
2589
  defaultMessage: "Create an entry"
2207
2590
  }) : documentTitle;
2208
2591
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2209
- /* @__PURE__ */ jsx(BackButton, {}),
2592
+ /* @__PURE__ */ jsx(
2593
+ BackButton,
2594
+ {
2595
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2596
+ }
2597
+ ),
2210
2598
  /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2211
2599
  /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2212
2600
  /* @__PURE__ */ jsx(HeaderToolbar, {})
@@ -2294,12 +2682,12 @@ const Information = ({ activeTab }) => {
2294
2682
  isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
2295
2683
  label: formatMessage({
2296
2684
  id: "content-manager.containers.edit.information.last-published.label",
2297
- defaultMessage: "Last published"
2685
+ defaultMessage: "Published"
2298
2686
  }),
2299
2687
  value: formatMessage(
2300
2688
  {
2301
2689
  id: "content-manager.containers.edit.information.last-published.value",
2302
- defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
2690
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2303
2691
  },
2304
2692
  {
2305
2693
  time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
@@ -2312,12 +2700,12 @@ const Information = ({ activeTab }) => {
2312
2700
  isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
2313
2701
  label: formatMessage({
2314
2702
  id: "content-manager.containers.edit.information.last-draft.label",
2315
- defaultMessage: "Last draft"
2703
+ defaultMessage: "Updated"
2316
2704
  }),
2317
2705
  value: formatMessage(
2318
2706
  {
2319
2707
  id: "content-manager.containers.edit.information.last-draft.value",
2320
- defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
2708
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2321
2709
  },
2322
2710
  {
2323
2711
  time: /* @__PURE__ */ jsx(
@@ -2335,12 +2723,12 @@ const Information = ({ activeTab }) => {
2335
2723
  isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
2336
2724
  label: formatMessage({
2337
2725
  id: "content-manager.containers.edit.information.document.label",
2338
- defaultMessage: "Document"
2726
+ defaultMessage: "Created"
2339
2727
  }),
2340
2728
  value: formatMessage(
2341
2729
  {
2342
2730
  id: "content-manager.containers.edit.information.document.value",
2343
- defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
2731
+ defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
2344
2732
  },
2345
2733
  {
2346
2734
  time: /* @__PURE__ */ jsx(
@@ -2398,10 +2786,9 @@ const HeaderActions = ({ actions: actions2 }) => {
2398
2786
  SingleSelect,
2399
2787
  {
2400
2788
  size: "S",
2401
- disabled: action.disabled,
2402
- "aria-label": action.label,
2403
2789
  onChange: action.onSelect,
2404
- value: action.value,
2790
+ "aria-label": action.label,
2791
+ ...action,
2405
2792
  children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
2406
2793
  },
2407
2794
  action.id
@@ -2443,512 +2830,213 @@ const HeaderActionDialog = ({
2443
2830
  if (onCancel) {
2444
2831
  await onCancel();
2445
2832
  }
2446
- onClose();
2447
- };
2448
- return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2449
- /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2450
- typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2451
- ] }) });
2452
- };
2453
- const ConfigureTheViewAction = ({ collectionType, model }) => {
2454
- const navigate = useNavigate();
2455
- const { formatMessage } = useIntl();
2456
- return {
2457
- label: formatMessage({
2458
- id: "app.links.configure-view",
2459
- defaultMessage: "Configure the view"
2460
- }),
2461
- icon: /* @__PURE__ */ jsx(ListPlus, {}),
2462
- onClick: () => {
2463
- navigate(`../${collectionType}/${model}/configurations/edit`);
2464
- },
2465
- position: "header"
2466
- };
2467
- };
2468
- ConfigureTheViewAction.type = "configure-the-view";
2469
- const EditTheModelAction = ({ model }) => {
2470
- const navigate = useNavigate();
2471
- const { formatMessage } = useIntl();
2472
- return {
2473
- label: formatMessage({
2474
- id: "content-manager.link-to-ctb",
2475
- defaultMessage: "Edit the model"
2476
- }),
2477
- icon: /* @__PURE__ */ jsx(Pencil, {}),
2478
- onClick: () => {
2479
- navigate(`/plugins/content-type-builder/content-types/${model}`);
2480
- },
2481
- position: "header"
2482
- };
2483
- };
2484
- EditTheModelAction.type = "edit-the-model";
2485
- const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2486
- const navigate = useNavigate();
2487
- const { formatMessage } = useIntl();
2488
- const listViewPathMatch = useMatch(LIST_PATH);
2489
- const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2490
- const { delete: deleteAction } = useDocumentActions();
2491
- const { toggleNotification } = useNotification();
2492
- const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2493
- return {
2494
- disabled: !canDelete || !document,
2495
- label: formatMessage({
2496
- id: "content-manager.actions.delete.label",
2497
- defaultMessage: "Delete document"
2498
- }),
2499
- icon: /* @__PURE__ */ jsx(Trash, {}),
2500
- dialog: {
2501
- type: "dialog",
2502
- title: formatMessage({
2503
- id: "app.components.ConfirmDialog.title",
2504
- defaultMessage: "Confirmation"
2505
- }),
2506
- content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2507
- /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2508
- /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2509
- id: "content-manager.actions.delete.dialog.body",
2510
- defaultMessage: "Are you sure?"
2511
- }) })
2512
- ] }),
2513
- onConfirm: async () => {
2514
- if (!listViewPathMatch) {
2515
- setSubmitting(true);
2516
- }
2517
- try {
2518
- if (!documentId && collectionType !== SINGLE_TYPES) {
2519
- console.error(
2520
- "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2521
- );
2522
- toggleNotification({
2523
- message: formatMessage({
2524
- id: "content-manager.actions.delete.error",
2525
- defaultMessage: "An error occurred while trying to delete the document."
2526
- }),
2527
- type: "danger"
2528
- });
2529
- return;
2530
- }
2531
- const res = await deleteAction({
2532
- documentId,
2533
- model,
2534
- collectionType,
2535
- params: {
2536
- locale: "*"
2537
- }
2538
- });
2539
- if (!("error" in res)) {
2540
- navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2541
- }
2542
- } finally {
2543
- if (!listViewPathMatch) {
2544
- setSubmitting(false);
2545
- }
2546
- }
2547
- }
2548
- },
2549
- variant: "danger",
2550
- position: ["header", "table-row"]
2551
- };
2552
- };
2553
- DeleteAction$1.type = "delete";
2554
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2555
- const Panels = () => {
2556
- const isCloning = useMatch(CLONE_PATH) !== null;
2557
- const [
2558
- {
2559
- query: { status }
2560
- }
2561
- ] = useQueryParams({
2562
- status: "draft"
2563
- });
2564
- const { model, id, document, meta, collectionType } = useDoc();
2565
- const plugins = useStrapiApp("Panels", (state) => state.plugins);
2566
- const props = {
2567
- activeTab: status,
2568
- model,
2569
- documentId: id,
2570
- document: isCloning ? void 0 : document,
2571
- meta: isCloning ? void 0 : meta,
2572
- collectionType
2573
- };
2574
- return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2575
- DescriptionComponentRenderer,
2576
- {
2577
- props,
2578
- descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2579
- children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2580
- }
2581
- ) });
2582
- };
2583
- const ActionsPanel = () => {
2584
- const { formatMessage } = useIntl();
2585
- return {
2586
- title: formatMessage({
2587
- id: "content-manager.containers.edit.panels.default.title",
2588
- defaultMessage: "Entry"
2589
- }),
2590
- content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2591
- };
2592
- };
2593
- ActionsPanel.type = "actions";
2594
- const ActionsPanelContent = () => {
2595
- const isCloning = useMatch(CLONE_PATH) !== null;
2596
- const [
2597
- {
2598
- query: { status = "draft" }
2599
- }
2600
- ] = useQueryParams();
2601
- const { model, id, document, meta, collectionType } = useDoc();
2602
- const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2603
- const props = {
2604
- activeTab: status,
2605
- model,
2606
- documentId: id,
2607
- document: isCloning ? void 0 : document,
2608
- meta: isCloning ? void 0 : meta,
2609
- collectionType
2610
- };
2611
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
2612
- /* @__PURE__ */ jsx(
2613
- DescriptionComponentRenderer,
2614
- {
2615
- props,
2616
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2617
- children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2618
- }
2619
- ),
2620
- /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
2621
- ] });
2622
- };
2623
- const Panel = React.forwardRef(({ children, title }, ref) => {
2624
- return /* @__PURE__ */ jsxs(
2625
- Flex,
2626
- {
2627
- ref,
2628
- tag: "aside",
2629
- "aria-labelledby": "additional-information",
2630
- background: "neutral0",
2631
- borderColor: "neutral150",
2632
- hasRadius: true,
2633
- paddingBottom: 4,
2634
- paddingLeft: 4,
2635
- paddingRight: 4,
2636
- paddingTop: 4,
2637
- shadow: "tableShadow",
2638
- gap: 3,
2639
- direction: "column",
2640
- justifyContent: "stretch",
2641
- alignItems: "flex-start",
2642
- children: [
2643
- /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2644
- children
2645
- ]
2646
- }
2647
- );
2648
- });
2649
- const HOOKS = {
2650
- /**
2651
- * Hook that allows to mutate the displayed headers of the list view table
2652
- * @constant
2653
- * @type {string}
2654
- */
2655
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2656
- /**
2657
- * Hook that allows to mutate the CM's collection types links pre-set filters
2658
- * @constant
2659
- * @type {string}
2660
- */
2661
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2662
- /**
2663
- * Hook that allows to mutate the CM's edit view layout
2664
- * @constant
2665
- * @type {string}
2666
- */
2667
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2668
- /**
2669
- * Hook that allows to mutate the CM's single types links pre-set filters
2670
- * @constant
2671
- * @type {string}
2672
- */
2673
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2833
+ onClose();
2834
+ };
2835
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2836
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2837
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2838
+ ] }) });
2674
2839
  };
2675
- const contentTypesApi = contentManagerApi.injectEndpoints({
2676
- endpoints: (builder) => ({
2677
- getContentTypeConfiguration: builder.query({
2678
- query: (uid) => ({
2679
- url: `/content-manager/content-types/${uid}/configuration`,
2680
- method: "GET"
2681
- }),
2682
- transformResponse: (response) => response.data,
2683
- providesTags: (_result, _error, uid) => [
2684
- { type: "ContentTypesConfiguration", id: uid },
2685
- { type: "ContentTypeSettings", id: "LIST" }
2686
- ]
2687
- }),
2688
- getAllContentTypeSettings: builder.query({
2689
- query: () => "/content-manager/content-types-settings",
2690
- transformResponse: (response) => response.data,
2691
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2840
+ const ConfigureTheViewAction = ({ collectionType, model }) => {
2841
+ const navigate = useNavigate();
2842
+ const { formatMessage } = useIntl();
2843
+ return {
2844
+ label: formatMessage({
2845
+ id: "app.links.configure-view",
2846
+ defaultMessage: "Configure the view"
2692
2847
  }),
2693
- updateContentTypeConfiguration: builder.mutation({
2694
- query: ({ uid, ...body }) => ({
2695
- url: `/content-manager/content-types/${uid}/configuration`,
2696
- method: "PUT",
2697
- data: body
2698
- }),
2699
- transformResponse: (response) => response.data,
2700
- invalidatesTags: (_result, _error, { uid }) => [
2701
- { type: "ContentTypesConfiguration", id: uid },
2702
- { type: "ContentTypeSettings", id: "LIST" },
2703
- // Is this necessary?
2704
- { type: "InitialData" }
2705
- ]
2706
- })
2707
- })
2708
- });
2709
- const {
2710
- useGetContentTypeConfigurationQuery,
2711
- useGetAllContentTypeSettingsQuery,
2712
- useUpdateContentTypeConfigurationMutation
2713
- } = contentTypesApi;
2714
- const checkIfAttributeIsDisplayable = (attribute) => {
2715
- const { type } = attribute;
2716
- if (type === "relation") {
2717
- return !attribute.relation.toLowerCase().includes("morph");
2718
- }
2719
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2848
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2849
+ onClick: () => {
2850
+ navigate(`../${collectionType}/${model}/configurations/edit`);
2851
+ },
2852
+ position: "header"
2853
+ };
2720
2854
  };
2721
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2722
- if (!mainFieldName) {
2723
- return void 0;
2724
- }
2725
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2726
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2727
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2728
- );
2855
+ ConfigureTheViewAction.type = "configure-the-view";
2856
+ const EditTheModelAction = ({ model }) => {
2857
+ const navigate = useNavigate();
2858
+ const { formatMessage } = useIntl();
2729
2859
  return {
2730
- name: mainFieldName,
2731
- type: mainFieldType ?? "string"
2860
+ label: formatMessage({
2861
+ id: "content-manager.link-to-ctb",
2862
+ defaultMessage: "Edit the model"
2863
+ }),
2864
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2865
+ onClick: () => {
2866
+ navigate(`/plugins/content-type-builder/content-types/${model}`);
2867
+ },
2868
+ position: "header"
2732
2869
  };
2733
2870
  };
2734
- const DEFAULT_SETTINGS = {
2735
- bulkable: false,
2736
- filterable: false,
2737
- searchable: false,
2738
- pagination: false,
2739
- defaultSortBy: "",
2740
- defaultSortOrder: "asc",
2741
- mainField: "id",
2742
- pageSize: 10
2743
- };
2744
- const useDocumentLayout = (model) => {
2745
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2746
- const [{ query }] = useQueryParams();
2747
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2871
+ EditTheModelAction.type = "edit-the-model";
2872
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2873
+ const navigate = useNavigate();
2874
+ const { formatMessage } = useIntl();
2875
+ const listViewPathMatch = useMatch(LIST_PATH);
2876
+ const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
2877
+ const { delete: deleteAction } = useDocumentActions();
2748
2878
  const { toggleNotification } = useNotification();
2749
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2750
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2751
- const {
2752
- data,
2753
- isLoading: isLoadingConfigs,
2754
- error,
2755
- isFetching: isFetchingConfigs
2756
- } = useGetContentTypeConfigurationQuery(model);
2757
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2758
- React.useEffect(() => {
2759
- if (error) {
2760
- toggleNotification({
2761
- type: "danger",
2762
- message: formatAPIError(error)
2763
- });
2764
- }
2765
- }, [error, formatAPIError, toggleNotification]);
2766
- const editLayout = React.useMemo(
2767
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2768
- layout: [],
2769
- components: {},
2770
- metadatas: {},
2771
- options: {},
2772
- settings: DEFAULT_SETTINGS
2773
- },
2774
- [data, isLoading, schemas, schema, components]
2775
- );
2776
- const listLayout = React.useMemo(() => {
2777
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2778
- layout: [],
2779
- metadatas: {},
2780
- options: {},
2781
- settings: DEFAULT_SETTINGS
2782
- };
2783
- }, [data, isLoading, schemas, schema, components]);
2784
- const { layout: edit } = React.useMemo(
2785
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2786
- layout: editLayout,
2787
- query
2788
- }),
2789
- [editLayout, query, runHookWaterfall]
2790
- );
2879
+ const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
2880
+ const isLocalized = document?.locale != null;
2791
2881
  return {
2792
- error,
2793
- isLoading,
2794
- edit,
2795
- list: listLayout
2796
- };
2797
- };
2798
- const useDocLayout = () => {
2799
- const { model } = useDoc();
2800
- return useDocumentLayout(model);
2801
- };
2802
- const formatEditLayout = (data, {
2803
- schemas,
2804
- schema,
2805
- components
2806
- }) => {
2807
- let currentPanelIndex = 0;
2808
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2809
- data.contentType.layouts.edit,
2810
- schema?.attributes,
2811
- data.contentType.metadatas,
2812
- { configurations: data.components, schemas: components },
2813
- schemas
2814
- ).reduce((panels, row) => {
2815
- if (row.some((field) => field.type === "dynamiczone")) {
2816
- panels.push([row]);
2817
- currentPanelIndex += 2;
2818
- } else {
2819
- if (!panels[currentPanelIndex]) {
2820
- panels.push([]);
2821
- }
2822
- panels[currentPanelIndex].push(row);
2823
- }
2824
- return panels;
2825
- }, []);
2826
- const componentEditAttributes = Object.entries(data.components).reduce(
2827
- (acc, [uid, configuration]) => {
2828
- acc[uid] = {
2829
- layout: convertEditLayoutToFieldLayouts(
2830
- configuration.layouts.edit,
2831
- components[uid].attributes,
2832
- configuration.metadatas,
2833
- { configurations: data.components, schemas: components }
2834
- ),
2835
- settings: {
2836
- ...configuration.settings,
2837
- icon: components[uid].info.icon,
2838
- displayName: components[uid].info.displayName
2882
+ disabled: !canDelete || !document,
2883
+ label: formatMessage(
2884
+ {
2885
+ id: "content-manager.actions.delete.label",
2886
+ defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
2887
+ },
2888
+ { isLocalized }
2889
+ ),
2890
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2891
+ dialog: {
2892
+ type: "dialog",
2893
+ title: formatMessage({
2894
+ id: "app.components.ConfirmDialog.title",
2895
+ defaultMessage: "Confirmation"
2896
+ }),
2897
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2898
+ /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2899
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2900
+ id: "content-manager.actions.delete.dialog.body",
2901
+ defaultMessage: "Are you sure?"
2902
+ }) })
2903
+ ] }),
2904
+ onConfirm: async () => {
2905
+ if (!listViewPathMatch) {
2906
+ setSubmitting(true);
2907
+ }
2908
+ try {
2909
+ if (!documentId && collectionType !== SINGLE_TYPES) {
2910
+ console.error(
2911
+ "You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
2912
+ );
2913
+ toggleNotification({
2914
+ message: formatMessage({
2915
+ id: "content-manager.actions.delete.error",
2916
+ defaultMessage: "An error occurred while trying to delete the document."
2917
+ }),
2918
+ type: "danger"
2919
+ });
2920
+ return;
2921
+ }
2922
+ const res = await deleteAction({
2923
+ documentId,
2924
+ model,
2925
+ collectionType,
2926
+ params: {
2927
+ locale: "*"
2928
+ }
2929
+ });
2930
+ if (!("error" in res)) {
2931
+ navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
2932
+ }
2933
+ } finally {
2934
+ if (!listViewPathMatch) {
2935
+ setSubmitting(false);
2936
+ }
2839
2937
  }
2840
- };
2841
- return acc;
2842
- },
2843
- {}
2844
- );
2845
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2846
- (acc, [attribute, metadata]) => {
2847
- return {
2848
- ...acc,
2849
- [attribute]: metadata.edit
2850
- };
2851
- },
2852
- {}
2853
- );
2854
- return {
2855
- layout: panelledEditAttributes,
2856
- components: componentEditAttributes,
2857
- metadatas: editMetadatas,
2858
- settings: {
2859
- ...data.contentType.settings,
2860
- displayName: schema?.info.displayName
2938
+ }
2861
2939
  },
2862
- options: {
2863
- ...schema?.options,
2864
- ...schema?.pluginOptions,
2865
- ...data.contentType.options
2866
- }
2940
+ variant: "danger",
2941
+ position: ["header", "table-row"]
2867
2942
  };
2868
2943
  };
2869
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2870
- return rows.map(
2871
- (row) => row.map((field) => {
2872
- const attribute = attributes[field.name];
2873
- if (!attribute) {
2874
- return null;
2875
- }
2876
- const { edit: metadata } = metadatas[field.name];
2877
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2878
- return {
2879
- attribute,
2880
- disabled: !metadata.editable,
2881
- hint: metadata.description,
2882
- label: metadata.label ?? "",
2883
- name: field.name,
2884
- // @ts-expect-error – mainField does exist on the metadata for a relation.
2885
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2886
- schemas,
2887
- components: components?.schemas ?? {}
2888
- }),
2889
- placeholder: metadata.placeholder ?? "",
2890
- required: attribute.required ?? false,
2891
- size: field.size,
2892
- unique: "unique" in attribute ? attribute.unique : false,
2893
- visible: metadata.visible ?? true,
2894
- type: attribute.type
2895
- };
2896
- }).filter((field) => field !== null)
2897
- );
2944
+ DeleteAction$1.type = "delete";
2945
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2946
+ const Panels = () => {
2947
+ const isCloning = useMatch(CLONE_PATH) !== null;
2948
+ const [
2949
+ {
2950
+ query: { status }
2951
+ }
2952
+ ] = useQueryParams({
2953
+ status: "draft"
2954
+ });
2955
+ const { model, id, document, meta, collectionType } = useDoc();
2956
+ const plugins = useStrapiApp("Panels", (state) => state.plugins);
2957
+ const props = {
2958
+ activeTab: status,
2959
+ model,
2960
+ documentId: id,
2961
+ document: isCloning ? void 0 : document,
2962
+ meta: isCloning ? void 0 : meta,
2963
+ collectionType
2964
+ };
2965
+ return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
2966
+ DescriptionComponentRenderer,
2967
+ {
2968
+ props,
2969
+ descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
2970
+ children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
2971
+ }
2972
+ ) });
2898
2973
  };
2899
- const formatListLayout = (data, {
2900
- schemas,
2901
- schema,
2902
- components
2903
- }) => {
2904
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2905
- (acc, [attribute, metadata]) => {
2906
- return {
2907
- ...acc,
2908
- [attribute]: metadata.list
2909
- };
2910
- },
2911
- {}
2912
- );
2913
- const listAttributes = convertListLayoutToFieldLayouts(
2914
- data.contentType.layouts.list,
2915
- schema?.attributes,
2916
- listMetadatas,
2917
- { configurations: data.components, schemas: components },
2918
- schemas
2919
- );
2974
+ const ActionsPanel = () => {
2975
+ const { formatMessage } = useIntl();
2920
2976
  return {
2921
- layout: listAttributes,
2922
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2923
- metadatas: listMetadatas,
2924
- options: {
2925
- ...schema?.options,
2926
- ...schema?.pluginOptions,
2927
- ...data.contentType.options
2928
- }
2977
+ title: formatMessage({
2978
+ id: "content-manager.containers.edit.panels.default.title",
2979
+ defaultMessage: "Entry"
2980
+ }),
2981
+ content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2929
2982
  };
2930
2983
  };
2931
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2932
- return columns.map((name) => {
2933
- const attribute = attributes[name];
2934
- if (!attribute) {
2935
- return null;
2984
+ ActionsPanel.type = "actions";
2985
+ const ActionsPanelContent = () => {
2986
+ const isCloning = useMatch(CLONE_PATH) !== null;
2987
+ const [
2988
+ {
2989
+ query: { status = "draft" }
2936
2990
  }
2937
- const metadata = metadatas[name];
2938
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2939
- return {
2940
- attribute,
2941
- label: metadata.label ?? "",
2942
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2943
- schemas,
2944
- components: components?.schemas ?? {}
2945
- }),
2946
- name,
2947
- searchable: metadata.searchable ?? true,
2948
- sortable: metadata.sortable ?? true
2949
- };
2950
- }).filter((field) => field !== null);
2991
+ ] = useQueryParams();
2992
+ const { model, id, document, meta, collectionType } = useDoc();
2993
+ const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
2994
+ const props = {
2995
+ activeTab: status,
2996
+ model,
2997
+ documentId: id,
2998
+ document: isCloning ? void 0 : document,
2999
+ meta: isCloning ? void 0 : meta,
3000
+ collectionType
3001
+ };
3002
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
3003
+ /* @__PURE__ */ jsx(
3004
+ DescriptionComponentRenderer,
3005
+ {
3006
+ props,
3007
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3008
+ children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
3009
+ }
3010
+ ),
3011
+ /* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
3012
+ ] });
2951
3013
  };
3014
+ const Panel = React.forwardRef(({ children, title }, ref) => {
3015
+ return /* @__PURE__ */ jsxs(
3016
+ Flex,
3017
+ {
3018
+ ref,
3019
+ tag: "aside",
3020
+ "aria-labelledby": "additional-information",
3021
+ background: "neutral0",
3022
+ borderColor: "neutral150",
3023
+ hasRadius: true,
3024
+ paddingBottom: 4,
3025
+ paddingLeft: 4,
3026
+ paddingRight: 4,
3027
+ paddingTop: 4,
3028
+ shadow: "tableShadow",
3029
+ gap: 3,
3030
+ direction: "column",
3031
+ justifyContent: "stretch",
3032
+ alignItems: "flex-start",
3033
+ children: [
3034
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
3035
+ children
3036
+ ]
3037
+ }
3038
+ );
3039
+ });
2952
3040
  const ConfirmBulkActionDialog = ({
2953
3041
  onToggleDialog,
2954
3042
  isOpen = false,
@@ -3193,18 +3281,10 @@ const SelectedEntriesTableContent = ({
3193
3281
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3194
3282
  },
3195
3283
  state: { from: pathname },
3196
- label: formatMessage(
3197
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3198
- {
3199
- target: formatMessage(
3200
- {
3201
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3202
- defaultMessage: "item line {number}"
3203
- },
3204
- { number: index2 + 1 }
3205
- )
3206
- }
3207
- ),
3284
+ label: formatMessage({
3285
+ id: "content-manager.bulk-publish.edit",
3286
+ defaultMessage: "Edit"
3287
+ }),
3208
3288
  target: "_blank",
3209
3289
  marginLeft: "auto",
3210
3290
  variant: "ghost",
@@ -3848,17 +3928,27 @@ const HistoryAction = ({ model, document }) => {
3848
3928
  const { formatMessage } = useIntl();
3849
3929
  const [{ query }] = useQueryParams();
3850
3930
  const navigate = useNavigate();
3931
+ const { trackUsage } = useTracking();
3932
+ const { pathname } = useLocation();
3851
3933
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3852
3934
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3853
3935
  return null;
3854
3936
  }
3937
+ const handleOnClick = () => {
3938
+ const destination = { pathname: "history", search: pluginsQueryParams };
3939
+ trackUsage("willNavigate", {
3940
+ from: pathname,
3941
+ to: `${pathname}/${destination.pathname}`
3942
+ });
3943
+ navigate(destination);
3944
+ };
3855
3945
  return {
3856
3946
  icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3857
3947
  label: formatMessage({
3858
3948
  id: "content-manager.history.document-action",
3859
3949
  defaultMessage: "Content History"
3860
3950
  }),
3861
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3951
+ onClick: handleOnClick,
3862
3952
  disabled: (
3863
3953
  /**
3864
3954
  * The user is creating a new document.
@@ -3926,6 +4016,72 @@ const { setInitialData } = actions;
3926
4016
  const reducer = combineReducers({
3927
4017
  app: reducer$1
3928
4018
  });
4019
+ const previewApi = contentManagerApi.injectEndpoints({
4020
+ endpoints: (builder) => ({
4021
+ getPreviewUrl: builder.query({
4022
+ query({ query, params }) {
4023
+ return {
4024
+ url: `/content-manager/preview/url/${params.contentType}`,
4025
+ method: "GET",
4026
+ config: {
4027
+ params: query
4028
+ }
4029
+ };
4030
+ }
4031
+ })
4032
+ })
4033
+ });
4034
+ const { useGetPreviewUrlQuery } = previewApi;
4035
+ const PreviewSidePanel = ({ model, documentId, document }) => {
4036
+ const { formatMessage } = useIntl();
4037
+ const { trackUsage } = useTracking();
4038
+ const { pathname } = useLocation();
4039
+ const [{ query }] = useQueryParams();
4040
+ const { data, error } = useGetPreviewUrlQuery({
4041
+ params: {
4042
+ contentType: model
4043
+ },
4044
+ query: {
4045
+ documentId,
4046
+ locale: document?.locale,
4047
+ status: document?.status
4048
+ }
4049
+ });
4050
+ if (!data?.data?.url || error) {
4051
+ return null;
4052
+ }
4053
+ const trackNavigation = () => {
4054
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4055
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4056
+ };
4057
+ return {
4058
+ title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4059
+ content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
4060
+ Button,
4061
+ {
4062
+ variant: "tertiary",
4063
+ tag: Link,
4064
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4065
+ onClick: trackNavigation,
4066
+ flex: "auto",
4067
+ children: formatMessage({
4068
+ id: "content-manager.preview.panel.button",
4069
+ defaultMessage: "Open preview"
4070
+ })
4071
+ }
4072
+ ) })
4073
+ };
4074
+ };
4075
+ const FEATURE_ID = "preview";
4076
+ const previewAdmin = {
4077
+ bootstrap(app) {
4078
+ if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4079
+ return;
4080
+ }
4081
+ const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4082
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4083
+ }
4084
+ };
3929
4085
  const index = {
3930
4086
  register(app) {
3931
4087
  const cm = new ContentManagerPlugin();
@@ -3945,7 +4101,7 @@ const index = {
3945
4101
  app.router.addRoute({
3946
4102
  path: "content-manager/*",
3947
4103
  lazy: async () => {
3948
- const { Layout } = await import("./layout-D4HI4_PS.mjs");
4104
+ const { Layout } = await import("./layout-DhMZ_lDx.mjs");
3949
4105
  return {
3950
4106
  Component: Layout
3951
4107
  };
@@ -3958,11 +4114,14 @@ const index = {
3958
4114
  if (typeof historyAdmin.bootstrap === "function") {
3959
4115
  historyAdmin.bootstrap(app);
3960
4116
  }
4117
+ if (typeof previewAdmin.bootstrap === "function") {
4118
+ previewAdmin.bootstrap(app);
4119
+ }
3961
4120
  },
3962
4121
  async registerTrads({ locales }) {
3963
4122
  const importedTrads = await Promise.all(
3964
4123
  locales.map((locale) => {
3965
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-CPTj6CjC.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4124
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-DhFUjrNW.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3966
4125
  return {
3967
4126
  data: prefixPluginTranslations(data, PLUGIN_ID),
3968
4127
  locale
@@ -3989,8 +4148,10 @@ export {
3989
4148
  HOOKS as H,
3990
4149
  InjectionZone as I,
3991
4150
  useDocument as J,
3992
- index as K,
3993
- useDocumentActions as L,
4151
+ useGetPreviewUrlQuery as K,
4152
+ index as L,
4153
+ useContentManagerContext as M,
4154
+ useDocumentActions as N,
3994
4155
  Panels as P,
3995
4156
  RelativeTime as R,
3996
4157
  SINGLE_TYPES as S,
@@ -4022,4 +4183,4 @@ export {
4022
4183
  capitalise as y,
4023
4184
  useUpdateContentTypeConfigurationMutation as z
4024
4185
  };
4025
- //# sourceMappingURL=index-D4UGPFZC.mjs.map
4186
+ //# sourceMappingURL=index-BpxR3En4.mjs.map