@strapi/content-manager 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78 → 0.0.0-experimental.fb442e5e12dd3f611303691bf85a249520ba348b

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 (110) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs → ComponentConfigurationPage-B3yDbeU1.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs.map → ComponentConfigurationPage-B3yDbeU1.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js → ComponentConfigurationPage-KXSuLnQD.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js.map → ComponentConfigurationPage-KXSuLnQD.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js → EditConfigurationPage-BQ17--5R.js} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js.map → EditConfigurationPage-BQ17--5R.js.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs → EditConfigurationPage-D7PrLO8j.mjs} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs.map → EditConfigurationPage-D7PrLO8j.mjs.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-dFPBya9U.mjs → EditViewPage-B7VgwJaG.mjs} +57 -46
  11. package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-ChgloMyO.js → EditViewPage-BgjdnGz2.js} +56 -45
  13. package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +1 -0
  14. package/dist/_chunks/{Field-dLk-vgLL.js → Field-CdK7ZLmv.js} +504 -165
  15. package/dist/_chunks/Field-CdK7ZLmv.js.map +1 -0
  16. package/dist/_chunks/{Field-C1nUKcdS.mjs → Field-tHCw4lGA.mjs} +505 -166
  17. package/dist/_chunks/Field-tHCw4lGA.mjs.map +1 -0
  18. package/dist/_chunks/{Form-DOlpi7Js.mjs → Form-BJxdTv3Q.mjs} +40 -30
  19. package/dist/_chunks/Form-BJxdTv3Q.mjs.map +1 -0
  20. package/dist/_chunks/{Form-CbXtmHC_.js → Form-C_0KTVvV.js} +38 -28
  21. package/dist/_chunks/Form-C_0KTVvV.js.map +1 -0
  22. package/dist/_chunks/{History-BFNUAiGc.mjs → History-DR2txJLE.mjs} +142 -37
  23. package/dist/_chunks/History-DR2txJLE.mjs.map +1 -0
  24. package/dist/_chunks/{History-BjDfohBr.js → History-nuEzM5qm.js} +141 -36
  25. package/dist/_chunks/History-nuEzM5qm.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-IQBgWTaa.js → ListConfigurationPage-CnB86Psm.js} +57 -46
  27. package/dist/_chunks/ListConfigurationPage-CnB86Psm.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-DDi0KqFm.mjs → ListConfigurationPage-voFVtXu6.mjs} +58 -48
  29. package/dist/_chunks/ListConfigurationPage-voFVtXu6.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-BPjljUsH.mjs → ListViewPage-B_GaWgRH.mjs} +80 -71
  31. package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +1 -0
  32. package/dist/_chunks/{ListViewPage-CZYGqlvF.js → ListViewPage-SXIXm-RM.js} +78 -69
  33. package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js → NoContentTypePage-BzsQ3hLZ.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js.map → NoContentTypePage-BzsQ3hLZ.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs → NoContentTypePage-CYiGpsbj.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs.map → NoContentTypePage-CYiGpsbj.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs → NoPermissionsPage-B5baIHal.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs.map → NoPermissionsPage-B5baIHal.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js → NoPermissionsPage-IGkId4C5.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js.map → NoPermissionsPage-IGkId4C5.js.map} +1 -1
  42. package/dist/_chunks/{Relations-DTowyge2.mjs → Relations-CIYDdKU-.mjs} +5 -5
  43. package/dist/_chunks/Relations-CIYDdKU-.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-DU6B7irU.js → Relations-Dhuurpx2.js} +5 -5
  45. package/dist/_chunks/Relations-Dhuurpx2.js.map +1 -0
  46. package/dist/_chunks/{en-GCOTL6jR.mjs → en-BrCTWlZv.mjs} +9 -4
  47. package/dist/_chunks/{en-GCOTL6jR.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  48. package/dist/_chunks/{en-DTULi5-d.js → en-uOUIxfcQ.js} +9 -4
  49. package/dist/_chunks/{en-DTULi5-d.js.map → en-uOUIxfcQ.js.map} +1 -1
  50. package/dist/_chunks/{index-BaGHmIir.mjs → index-C9TJPyni.mjs} +1542 -1063
  51. package/dist/_chunks/index-C9TJPyni.mjs.map +1 -0
  52. package/dist/_chunks/{index-CCJeB7Rw.js → index-CdT0kHZ8.js} +1510 -1031
  53. package/dist/_chunks/index-CdT0kHZ8.js.map +1 -0
  54. package/dist/_chunks/{layout-BinjszSQ.mjs → layout-BNqvLR_b.mjs} +39 -22
  55. package/dist/_chunks/layout-BNqvLR_b.mjs.map +1 -0
  56. package/dist/_chunks/{layout-ni_L9kT1.js → layout-C6dxWYT7.js} +37 -20
  57. package/dist/_chunks/layout-C6dxWYT7.js.map +1 -0
  58. package/dist/_chunks/{relations-c91ji5eR.mjs → relations-CkKqKw65.mjs} +2 -2
  59. package/dist/_chunks/{relations-c91ji5eR.mjs.map → relations-CkKqKw65.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CeJAJc5I.js → relations-DtFaDnP1.js} +2 -2
  61. package/dist/_chunks/{relations-CeJAJc5I.js.map → relations-DtFaDnP1.js.map} +1 -1
  62. package/dist/admin/index.js +1 -1
  63. package/dist/admin/index.mjs +8 -8
  64. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  65. package/dist/admin/src/history/index.d.ts +3 -0
  66. package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -1
  67. package/dist/admin/src/index.d.ts +1 -0
  68. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  69. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  70. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  73. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +12 -32
  74. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  75. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  76. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +14 -0
  77. package/dist/server/index.js +147 -93
  78. package/dist/server/index.js.map +1 -1
  79. package/dist/server/index.mjs +148 -94
  80. package/dist/server/index.mjs.map +1 -1
  81. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  82. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  83. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  84. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  85. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  86. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  87. package/dist/server/src/history/services/utils.d.ts +1 -1
  88. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  89. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  90. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  91. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  92. package/package.json +8 -8
  93. package/dist/_chunks/EditViewPage-ChgloMyO.js.map +0 -1
  94. package/dist/_chunks/EditViewPage-dFPBya9U.mjs.map +0 -1
  95. package/dist/_chunks/Field-C1nUKcdS.mjs.map +0 -1
  96. package/dist/_chunks/Field-dLk-vgLL.js.map +0 -1
  97. package/dist/_chunks/Form-CbXtmHC_.js.map +0 -1
  98. package/dist/_chunks/Form-DOlpi7Js.mjs.map +0 -1
  99. package/dist/_chunks/History-BFNUAiGc.mjs.map +0 -1
  100. package/dist/_chunks/History-BjDfohBr.js.map +0 -1
  101. package/dist/_chunks/ListConfigurationPage-DDi0KqFm.mjs.map +0 -1
  102. package/dist/_chunks/ListConfigurationPage-IQBgWTaa.js.map +0 -1
  103. package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +0 -1
  104. package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +0 -1
  105. package/dist/_chunks/Relations-DTowyge2.mjs.map +0 -1
  106. package/dist/_chunks/Relations-DU6B7irU.js.map +0 -1
  107. package/dist/_chunks/index-BaGHmIir.mjs.map +0 -1
  108. package/dist/_chunks/index-CCJeB7Rw.js.map +0 -1
  109. package/dist/_chunks/layout-BinjszSQ.mjs.map +0 -1
  110. package/dist/_chunks/layout-ni_L9kT1.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Menu, VisuallyHidden, Flex, Typography, Dialog, DialogBody, DialogFooter, Button, ModalLayout, ModalHeader, ModalBody, Box, Radio, Status, SingleSelect, SingleSelectOption, LinkButton } from "@strapi/design-system";
6
+ import { Menu, Button, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import { useIntl } from "react-intl";
8
+ import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
9
  import { styled } from "styled-components";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
12
  import pipe from "lodash/fp/pipe";
14
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { stringify } from "qs";
15
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
17
  const v = glob[path];
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
49
49
  const [page, position] = area.split(".");
50
50
  return contentManagerPlugin.getInjectedComponents(page, position);
51
51
  };
52
- const HistoryAction = ({ model, document }) => {
53
- const { formatMessage } = useIntl();
54
- const [{ query }] = useQueryParams();
55
- const navigate = useNavigate();
56
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
57
- if (!window.strapi.features.isEnabled("cms-content-history")) {
58
- return null;
59
- }
60
- return {
61
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
62
- label: formatMessage({
63
- id: "content-manager.history.document-action",
64
- defaultMessage: "Content History"
65
- }),
66
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
67
- disabled: (
68
- /**
69
- * The user is creating a new document.
70
- * It hasn't been saved yet, so there's no history to go to
71
- */
72
- !document || /**
73
- * The document has been created but the current dimension has never been saved.
74
- * For example, the user is creating a new locale in an existing document,
75
- * so there's no history for the document in that locale
76
- */
77
- !document.id || /**
78
- * History is only available for content types created by the user.
79
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
80
- * which start with `admin::` or `plugin::`
81
- */
82
- !model.startsWith("api::")
83
- ),
84
- position: "header"
85
- };
86
- };
87
- HistoryAction.type = "history";
88
52
  const ID = "id";
89
53
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
90
54
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -198,6 +162,7 @@ const contentManagerApi = adminApi.enhanceEndpoints({
198
162
  ]
199
163
  });
200
164
  const documentApi = contentManagerApi.injectEndpoints({
165
+ overrideExisting: true,
201
166
  endpoints: (builder) => ({
202
167
  autoCloneDocument: builder.mutation({
203
168
  query: ({ model, sourceId, query }) => ({
@@ -207,7 +172,12 @@ const documentApi = contentManagerApi.injectEndpoints({
207
172
  params: query
208
173
  }
209
174
  }),
210
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
175
+ invalidatesTags: (_result, error, { model }) => {
176
+ if (error) {
177
+ return [];
178
+ }
179
+ return [{ type: "Document", id: `${model}_LIST` }];
180
+ }
211
181
  }),
212
182
  cloneDocument: builder.mutation({
213
183
  query: ({ model, sourceId, data, params }) => ({
@@ -294,6 +264,7 @@ const documentApi = contentManagerApi.injectEndpoints({
294
264
  }),
295
265
  providesTags: (result, _error, arg) => {
296
266
  return [
267
+ { type: "Document", id: `ALL_LIST` },
297
268
  { type: "Document", id: `${arg.model}_LIST` },
298
269
  ...result?.results.map(({ documentId }) => ({
299
270
  type: "Document",
@@ -332,6 +303,11 @@ const documentApi = contentManagerApi.injectEndpoints({
332
303
  {
333
304
  type: "Document",
334
305
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
306
+ },
307
+ // Make it easy to invalidate all individual documents queries for a model
308
+ {
309
+ type: "Document",
310
+ id: `${model}_ALL_ITEMS`
335
311
  }
336
312
  ];
337
313
  }
@@ -397,6 +373,18 @@ const documentApi = contentManagerApi.injectEndpoints({
397
373
  },
398
374
  "Relations"
399
375
  ];
376
+ },
377
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
378
+ const patchResult = dispatch(
379
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
380
+ Object.assign(draft.data, data);
381
+ })
382
+ );
383
+ try {
384
+ await queryFulfilled;
385
+ } catch {
386
+ patchResult.undo();
387
+ }
400
388
  }
401
389
  }),
402
390
  unpublishDocument: builder.mutation({
@@ -580,6 +568,14 @@ const createAttributeSchema = (attribute) => {
580
568
  if (!value || typeof value === "string" && value.length === 0) {
581
569
  return true;
582
570
  }
571
+ if (typeof value === "object") {
572
+ try {
573
+ JSON.stringify(value);
574
+ return true;
575
+ } catch (err) {
576
+ return false;
577
+ }
578
+ }
583
579
  try {
584
580
  JSON.parse(value);
585
581
  return true;
@@ -599,11 +595,11 @@ const createAttributeSchema = (attribute) => {
599
595
  }
600
596
  };
601
597
  const addRequiredValidation = (attribute) => (schema) => {
602
- if (attribute.required) {
603
- return schema.required({
604
- id: translatedErrors.required.id,
605
- defaultMessage: "This field is required."
606
- });
598
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
599
+ return schema.min(1, translatedErrors.required);
600
+ }
601
+ if (attribute.required && attribute.type !== "relation") {
602
+ return schema.required(translatedErrors.required);
607
603
  }
608
604
  return schema?.nullable ? schema.nullable() : (
609
605
  // In some cases '.nullable' will not be available on the schema.
@@ -637,6 +633,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
637
633
  const addMinValidation = (attribute) => (schema) => {
638
634
  if ("min" in attribute) {
639
635
  const min = toInteger(attribute.min);
636
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
637
+ if (!attribute.required && "test" in schema && min) {
638
+ return schema.test(
639
+ "custom-min",
640
+ {
641
+ ...translatedErrors.min,
642
+ values: {
643
+ min: attribute.min
644
+ }
645
+ },
646
+ (value) => {
647
+ if (!value) {
648
+ return true;
649
+ }
650
+ if (Array.isArray(value) && value.length === 0) {
651
+ return true;
652
+ }
653
+ return value.length >= min;
654
+ }
655
+ );
656
+ }
657
+ }
640
658
  if ("min" in schema && min) {
641
659
  return schema.min(min, {
642
660
  ...translatedErrors.min,
@@ -763,7 +781,10 @@ const useDocument = (args, opts) => {
763
781
  isLoading: isLoadingDocument,
764
782
  isFetching: isFetchingDocument,
765
783
  error
766
- } = useGetDocumentQuery(args, opts);
784
+ } = useGetDocumentQuery(args, {
785
+ ...opts,
786
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
787
+ });
767
788
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
768
789
  React.useEffect(() => {
769
790
  if (error) {
@@ -927,12 +948,13 @@ const useDocumentActions = () => {
927
948
  );
928
949
  const [discardDocument] = useDiscardDocumentMutation();
929
950
  const discard = React.useCallback(
930
- async ({ collectionType, model, documentId }) => {
951
+ async ({ collectionType, model, documentId, params }) => {
931
952
  try {
932
953
  const res = await discardDocument({
933
954
  collectionType,
934
955
  model,
935
- documentId
956
+ documentId,
957
+ params
936
958
  });
937
959
  if ("error" in res) {
938
960
  toggleNotification({
@@ -1183,7 +1205,6 @@ const useDocumentActions = () => {
1183
1205
  sourceId
1184
1206
  });
1185
1207
  if ("error" in res) {
1186
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1187
1208
  return { error: res.error };
1188
1209
  }
1189
1210
  toggleNotification({
@@ -1264,7 +1285,7 @@ const useDocumentActions = () => {
1264
1285
  };
1265
1286
  };
1266
1287
  const ProtectedHistoryPage = lazy(
1267
- () => import("./History-BFNUAiGc.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1288
+ () => import("./History-DR2txJLE.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1268
1289
  );
1269
1290
  const routes$1 = [
1270
1291
  {
@@ -1277,31 +1298,31 @@ const routes$1 = [
1277
1298
  }
1278
1299
  ];
1279
1300
  const ProtectedEditViewPage = lazy(
1280
- () => import("./EditViewPage-dFPBya9U.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1301
+ () => import("./EditViewPage-B7VgwJaG.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1281
1302
  );
1282
1303
  const ProtectedListViewPage = lazy(
1283
- () => import("./ListViewPage-BPjljUsH.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1304
+ () => import("./ListViewPage-B_GaWgRH.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1284
1305
  );
1285
1306
  const ProtectedListConfiguration = lazy(
1286
- () => import("./ListConfigurationPage-DDi0KqFm.mjs").then((mod) => ({
1307
+ () => import("./ListConfigurationPage-voFVtXu6.mjs").then((mod) => ({
1287
1308
  default: mod.ProtectedListConfiguration
1288
1309
  }))
1289
1310
  );
1290
1311
  const ProtectedEditConfigurationPage = lazy(
1291
- () => import("./EditConfigurationPage-DbI4KMyz.mjs").then((mod) => ({
1312
+ () => import("./EditConfigurationPage-D7PrLO8j.mjs").then((mod) => ({
1292
1313
  default: mod.ProtectedEditConfigurationPage
1293
1314
  }))
1294
1315
  );
1295
1316
  const ProtectedComponentConfigurationPage = lazy(
1296
- () => import("./ComponentConfigurationPage-CuWgXugY.mjs").then((mod) => ({
1317
+ () => import("./ComponentConfigurationPage-B3yDbeU1.mjs").then((mod) => ({
1297
1318
  default: mod.ProtectedComponentConfigurationPage
1298
1319
  }))
1299
1320
  );
1300
1321
  const NoPermissions = lazy(
1301
- () => import("./NoPermissionsPage-CZrJH00p.mjs").then((mod) => ({ default: mod.NoPermissions }))
1322
+ () => import("./NoPermissionsPage-B5baIHal.mjs").then((mod) => ({ default: mod.NoPermissions }))
1302
1323
  );
1303
1324
  const NoContentType = lazy(
1304
- () => import("./NoContentTypePage-DaWw67K-.mjs").then((mod) => ({ default: mod.NoContentType }))
1325
+ () => import("./NoContentTypePage-CYiGpsbj.mjs").then((mod) => ({ default: mod.NoContentType }))
1305
1326
  );
1306
1327
  const CollectionTypePages = () => {
1307
1328
  const { collectionType } = useParams();
@@ -1415,12 +1436,14 @@ const DocumentActionButton = (action) => {
1415
1436
  /* @__PURE__ */ jsx(
1416
1437
  Button,
1417
1438
  {
1418
- flex: 1,
1439
+ flex: "auto",
1419
1440
  startIcon: action.icon,
1420
1441
  disabled: action.disabled,
1421
1442
  onClick: handleClick(action),
1422
1443
  justifyContent: "center",
1423
1444
  variant: action.variant || "default",
1445
+ paddingTop: "7px",
1446
+ paddingBottom: "7px",
1424
1447
  children: action.label
1425
1448
  }
1426
1449
  ),
@@ -1428,7 +1451,7 @@ const DocumentActionButton = (action) => {
1428
1451
  DocumentActionConfirmDialog,
1429
1452
  {
1430
1453
  ...action.dialog,
1431
- variant: action.variant,
1454
+ variant: action.dialog?.variant ?? action.variant,
1432
1455
  isOpen: dialogId === action.id,
1433
1456
  onClose: handleClose
1434
1457
  }
@@ -1480,14 +1503,14 @@ const DocumentActionsMenu = ({
1480
1503
  };
1481
1504
  return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1482
1505
  /* @__PURE__ */ jsxs(
1483
- Menu.Trigger,
1506
+ StyledMoreButton,
1484
1507
  {
1485
1508
  disabled: isDisabled,
1486
1509
  size: "S",
1487
1510
  endIcon: null,
1488
- paddingTop: "7px",
1489
- paddingLeft: "9px",
1490
- paddingRight: "9px",
1511
+ paddingTop: "4px",
1512
+ paddingLeft: "7px",
1513
+ paddingRight: "7px",
1491
1514
  variant,
1492
1515
  children: [
1493
1516
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1507,10 +1530,25 @@ const DocumentActionsMenu = ({
1507
1530
  onSelect: handleClick(action),
1508
1531
  display: "block",
1509
1532
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1510
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1511
- action.icon,
1512
- action.label
1513
- ] }),
1533
+ /* @__PURE__ */ jsxs(
1534
+ Flex,
1535
+ {
1536
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1537
+ gap: 2,
1538
+ tag: "span",
1539
+ children: [
1540
+ /* @__PURE__ */ jsx(
1541
+ Flex,
1542
+ {
1543
+ tag: "span",
1544
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1545
+ children: action.icon
1546
+ }
1547
+ ),
1548
+ action.label
1549
+ ]
1550
+ }
1551
+ ),
1514
1552
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1515
1553
  Flex,
1516
1554
  {
@@ -1569,6 +1607,23 @@ const convertActionVariantToColor = (variant = "secondary") => {
1569
1607
  return "primary600";
1570
1608
  }
1571
1609
  };
1610
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1611
+ switch (variant) {
1612
+ case "danger":
1613
+ return "danger600";
1614
+ case "secondary":
1615
+ return "neutral500";
1616
+ case "success":
1617
+ return "success600";
1618
+ default:
1619
+ return "primary600";
1620
+ }
1621
+ };
1622
+ const StyledMoreButton = styled(Menu.Trigger)`
1623
+ & > span {
1624
+ display: flex;
1625
+ }
1626
+ `;
1572
1627
  const DocumentActionConfirmDialog = ({
1573
1628
  onClose,
1574
1629
  onCancel,
@@ -1591,22 +1646,20 @@ const DocumentActionConfirmDialog = ({
1591
1646
  }
1592
1647
  onClose();
1593
1648
  };
1594
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
1595
- /* @__PURE__ */ jsx(DialogBody, { children: content }),
1596
- /* @__PURE__ */ jsx(
1597
- DialogFooter,
1598
- {
1599
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1600
- id: "app.components.Button.cancel",
1601
- defaultMessage: "Cancel"
1602
- }) }),
1603
- endAction: /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1604
- id: "app.components.Button.confirm",
1605
- defaultMessage: "Confirm"
1606
- }) })
1607
- }
1608
- )
1609
- ] });
1649
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1650
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1651
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1652
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1653
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1654
+ id: "app.components.Button.cancel",
1655
+ defaultMessage: "Cancel"
1656
+ }) }) }),
1657
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1658
+ id: "app.components.Button.confirm",
1659
+ defaultMessage: "Confirm"
1660
+ }) })
1661
+ ] })
1662
+ ] }) });
1610
1663
  };
1611
1664
  const DocumentActionModal = ({
1612
1665
  isOpen,
@@ -1616,36 +1669,19 @@ const DocumentActionModal = ({
1616
1669
  content: Content,
1617
1670
  onModalClose
1618
1671
  }) => {
1619
- const id = React.useId();
1620
- if (!isOpen) {
1621
- return null;
1622
- }
1623
1672
  const handleClose = () => {
1624
1673
  if (onClose) {
1625
1674
  onClose();
1626
1675
  }
1627
1676
  onModalClose();
1628
1677
  };
1629
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1630
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1631
- /* @__PURE__ */ jsx(ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1632
- /* @__PURE__ */ jsx(
1633
- Box,
1634
- {
1635
- paddingTop: 4,
1636
- paddingBottom: 4,
1637
- paddingLeft: 5,
1638
- paddingRight: 5,
1639
- borderWidth: "1px 0 0 0",
1640
- borderStyle: "solid",
1641
- borderColor: "neutral150",
1642
- background: "neutral100",
1643
- children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1644
- }
1645
- )
1646
- ] });
1678
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1679
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1680
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1681
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1682
+ ] }) });
1647
1683
  };
1648
- const PublishAction = ({
1684
+ const PublishAction$1 = ({
1649
1685
  activeTab,
1650
1686
  documentId,
1651
1687
  model,
@@ -1664,6 +1700,12 @@ const PublishAction = ({
1664
1700
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1665
1701
  );
1666
1702
  const { publish } = useDocumentActions();
1703
+ const [
1704
+ countDraftRelations,
1705
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1706
+ ] = useLazyGetDraftRelationCountQuery();
1707
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1708
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1667
1709
  const [{ query, rawQuery }] = useQueryParams();
1668
1710
  const params = React.useMemo(() => buildValidParams(query), [query]);
1669
1711
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1672,10 +1714,101 @@ const PublishAction = ({
1672
1714
  const validate = useForm("PublishAction", (state) => state.validate);
1673
1715
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1674
1716
  const formValues = useForm("PublishAction", ({ values }) => values);
1717
+ React.useEffect(() => {
1718
+ if (isErrorDraftRelations) {
1719
+ toggleNotification({
1720
+ type: "danger",
1721
+ message: formatMessage({
1722
+ id: getTranslation("error.records.fetch-draft-relatons"),
1723
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1724
+ })
1725
+ });
1726
+ }
1727
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1728
+ React.useEffect(() => {
1729
+ const localDraftRelations = /* @__PURE__ */ new Set();
1730
+ const extractDraftRelations = (data) => {
1731
+ const relations = data.connect || [];
1732
+ relations.forEach((relation) => {
1733
+ if (relation.status === "draft") {
1734
+ localDraftRelations.add(relation.id);
1735
+ }
1736
+ });
1737
+ };
1738
+ const traverseAndExtract = (data) => {
1739
+ Object.entries(data).forEach(([key, value]) => {
1740
+ if (key === "connect" && Array.isArray(value)) {
1741
+ extractDraftRelations({ connect: value });
1742
+ } else if (typeof value === "object" && value !== null) {
1743
+ traverseAndExtract(value);
1744
+ }
1745
+ });
1746
+ };
1747
+ if (!documentId || modified) {
1748
+ traverseAndExtract(formValues);
1749
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1750
+ }
1751
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1752
+ React.useEffect(() => {
1753
+ if (documentId) {
1754
+ const fetchDraftRelationsCount = async () => {
1755
+ const { data, error } = await countDraftRelations({
1756
+ collectionType,
1757
+ model,
1758
+ documentId,
1759
+ params
1760
+ });
1761
+ if (error) {
1762
+ throw error;
1763
+ }
1764
+ if (data) {
1765
+ setServerCountOfDraftRelations(data.data);
1766
+ }
1767
+ };
1768
+ fetchDraftRelationsCount();
1769
+ }
1770
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1675
1771
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1676
1772
  if (!schema?.options?.draftAndPublish) {
1677
1773
  return null;
1678
1774
  }
1775
+ const performPublish = async () => {
1776
+ setSubmitting(true);
1777
+ try {
1778
+ const { errors } = await validate();
1779
+ if (errors) {
1780
+ toggleNotification({
1781
+ type: "danger",
1782
+ message: formatMessage({
1783
+ id: "content-manager.validation.error",
1784
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1785
+ })
1786
+ });
1787
+ return;
1788
+ }
1789
+ const res = await publish(
1790
+ {
1791
+ collectionType,
1792
+ model,
1793
+ documentId,
1794
+ params
1795
+ },
1796
+ formValues
1797
+ );
1798
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1799
+ navigate({
1800
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1801
+ search: rawQuery
1802
+ });
1803
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1804
+ setErrors(formatValidationErrors(res.error));
1805
+ }
1806
+ } finally {
1807
+ setSubmitting(false);
1808
+ }
1809
+ };
1810
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1811
+ const hasDraftRelations = totalDraftRelations > 0;
1679
1812
  return {
1680
1813
  /**
1681
1814
  * Disabled when:
@@ -1685,52 +1818,42 @@ const PublishAction = ({
1685
1818
  * - the document is already published & not modified
1686
1819
  * - the document is being created & not modified
1687
1820
  * - the user doesn't have the permission to publish
1688
- * - the user doesn't have the permission to create a new document
1689
- * - the user doesn't have the permission to update the document
1690
1821
  */
1691
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1822
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1692
1823
  label: formatMessage({
1693
1824
  id: "app.utils.publish",
1694
1825
  defaultMessage: "Publish"
1695
1826
  }),
1696
1827
  onClick: async () => {
1697
- setSubmitting(true);
1698
- try {
1699
- const { errors } = await validate();
1700
- if (errors) {
1701
- toggleNotification({
1702
- type: "danger",
1703
- message: formatMessage({
1704
- id: "content-manager.validation.error",
1705
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1706
- })
1707
- });
1708
- return;
1709
- }
1710
- const res = await publish(
1711
- {
1712
- collectionType,
1713
- model,
1714
- documentId,
1715
- params
1716
- },
1717
- formValues
1718
- );
1719
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1720
- navigate({
1721
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1722
- search: rawQuery
1723
- });
1724
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1725
- setErrors(formatValidationErrors(res.error));
1828
+ if (hasDraftRelations) {
1829
+ return;
1830
+ }
1831
+ await performPublish();
1832
+ },
1833
+ dialog: hasDraftRelations ? {
1834
+ type: "dialog",
1835
+ variant: "danger",
1836
+ footer: null,
1837
+ title: formatMessage({
1838
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1839
+ defaultMessage: "Confirmation"
1840
+ }),
1841
+ content: formatMessage(
1842
+ {
1843
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1844
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1845
+ },
1846
+ {
1847
+ count: totalDraftRelations
1726
1848
  }
1727
- } finally {
1728
- setSubmitting(false);
1849
+ ),
1850
+ onConfirm: async () => {
1851
+ await performPublish();
1729
1852
  }
1730
- }
1853
+ } : void 0
1731
1854
  };
1732
1855
  };
1733
- PublishAction.type = "publish";
1856
+ PublishAction$1.type = "publish";
1734
1857
  const UpdateAction = ({
1735
1858
  activeTab,
1736
1859
  documentId,
@@ -1743,7 +1866,7 @@ const UpdateAction = ({
1743
1866
  const cloneMatch = useMatch(CLONE_PATH);
1744
1867
  const isCloning = cloneMatch !== null;
1745
1868
  const { formatMessage } = useIntl();
1746
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1869
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1747
1870
  canCreate: canCreate2,
1748
1871
  canUpdate: canUpdate2
1749
1872
  }));
@@ -1763,10 +1886,8 @@ const UpdateAction = ({
1763
1886
  * - the form is submitting
1764
1887
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1765
1888
  * - the active tab is the published tab
1766
- * - the user doesn't have the permission to create a new document
1767
- * - the user doesn't have the permission to update the document
1768
1889
  */
1769
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1890
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1770
1891
  label: formatMessage({
1771
1892
  id: "content-manager.containers.Edit.save",
1772
1893
  defaultMessage: "Save"
@@ -1795,10 +1916,13 @@ const UpdateAction = ({
1795
1916
  document
1796
1917
  );
1797
1918
  if ("data" in res) {
1798
- navigate({
1799
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1800
- search: rawQuery
1801
- });
1919
+ navigate(
1920
+ {
1921
+ pathname: `../${res.data.documentId}`,
1922
+ search: rawQuery
1923
+ },
1924
+ { relative: "path" }
1925
+ );
1802
1926
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1803
1927
  setErrors(formatValidationErrors(res.error));
1804
1928
  }
@@ -1826,10 +1950,13 @@ const UpdateAction = ({
1826
1950
  document
1827
1951
  );
1828
1952
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1829
- navigate({
1830
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1831
- search: rawQuery
1832
- });
1953
+ navigate(
1954
+ {
1955
+ pathname: `../${res.data.documentId}`,
1956
+ search: rawQuery
1957
+ },
1958
+ { replace: true, relative: "path" }
1959
+ );
1833
1960
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1834
1961
  setErrors(formatValidationErrors(res.error));
1835
1962
  }
@@ -1861,10 +1988,8 @@ const UnpublishAction$1 = ({
1861
1988
  const { toggleNotification } = useNotification();
1862
1989
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1863
1990
  const isDocumentModified = document?.status === "modified";
1864
- const handleChange = (e) => {
1865
- if ("value" in e.target) {
1866
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1867
- }
1991
+ const handleChange = (value) => {
1992
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1868
1993
  };
1869
1994
  if (!schema?.options?.draftAndPublish) {
1870
1995
  return null;
@@ -1914,40 +2039,24 @@ const UnpublishAction$1 = ({
1914
2039
  }) })
1915
2040
  ] }),
1916
2041
  /* @__PURE__ */ jsxs(
1917
- Flex,
2042
+ Radio.Group,
1918
2043
  {
1919
- onChange: handleChange,
1920
- direction: "column",
1921
- alignItems: "flex-start",
1922
- tag: "fieldset",
1923
- borderWidth: 0,
1924
- gap: 3,
2044
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2045
+ name: "discard-options",
2046
+ "aria-label": formatMessage({
2047
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2048
+ defaultMessage: "Choose an option to unpublish the document."
2049
+ }),
2050
+ onValueChange: handleChange,
1925
2051
  children: [
1926
- /* @__PURE__ */ jsx(VisuallyHidden, { tag: "legend" }),
1927
- /* @__PURE__ */ jsx(
1928
- Radio,
1929
- {
1930
- checked: shouldKeepDraft,
1931
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1932
- name: "discard-options",
1933
- children: formatMessage({
1934
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1935
- defaultMessage: "Keep draft"
1936
- })
1937
- }
1938
- ),
1939
- /* @__PURE__ */ jsx(
1940
- Radio,
1941
- {
1942
- checked: !shouldKeepDraft,
1943
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1944
- name: "discard-options",
1945
- children: formatMessage({
1946
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1947
- defaultMessage: "Replace draft"
1948
- })
1949
- }
1950
- )
2052
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2053
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2054
+ defaultMessage: "Keep draft"
2055
+ }) }),
2056
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2057
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2058
+ defaultMessage: "Replace draft"
2059
+ }) })
1951
2060
  ]
1952
2061
  }
1953
2062
  )
@@ -2036,7 +2145,7 @@ const StyledCrossCircle = styled(CrossCircle)`
2036
2145
  fill: currentColor;
2037
2146
  }
2038
2147
  `;
2039
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction$1, DiscardAction];
2148
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2040
2149
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2041
2150
  const RelativeTime = React.forwardRef(
2042
2151
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2093,23 +2202,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2093
2202
  id: "content-manager.containers.edit.title.new",
2094
2203
  defaultMessage: "Create an entry"
2095
2204
  }) : documentTitle;
2096
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2205
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2097
2206
  /* @__PURE__ */ jsx(BackButton, {}),
2098
- /* @__PURE__ */ jsxs(
2099
- Flex,
2100
- {
2101
- width: "100%",
2102
- justifyContent: "space-between",
2103
- paddingTop: 1,
2104
- gap: "80px",
2105
- alignItems: "flex-start",
2106
- children: [
2107
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2108
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2109
- ]
2110
- }
2111
- ),
2112
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2207
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2208
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2209
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2210
+ ] }),
2211
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2113
2212
  ] });
2114
2213
  };
2115
2214
  const HeaderToolbar = () => {
@@ -2491,280 +2590,904 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2491
2590
  }
2492
2591
  );
2493
2592
  });
2494
- const BulkActionsRenderer = () => {
2495
- const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
2496
- const { model, collectionType } = useDoc();
2497
- const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
2498
- return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
2499
- DescriptionComponentRenderer,
2500
- {
2501
- props: {
2502
- model,
2503
- collectionType,
2504
- documents: selectedRows
2505
- },
2506
- descriptions: plugins["content-manager"].apis.getBulkActions(),
2507
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(BulkActionAction, { ...action }, action.id))
2508
- }
2509
- ) });
2593
+ const HOOKS = {
2594
+ /**
2595
+ * Hook that allows to mutate the displayed headers of the list view table
2596
+ * @constant
2597
+ * @type {string}
2598
+ */
2599
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2600
+ /**
2601
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2602
+ * @constant
2603
+ * @type {string}
2604
+ */
2605
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2606
+ /**
2607
+ * Hook that allows to mutate the CM's edit view layout
2608
+ * @constant
2609
+ * @type {string}
2610
+ */
2611
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2612
+ /**
2613
+ * Hook that allows to mutate the CM's single types links pre-set filters
2614
+ * @constant
2615
+ * @type {string}
2616
+ */
2617
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2510
2618
  };
2511
- const BulkActionAction = (action) => {
2512
- const [dialogId, setDialogId] = React.useState(null);
2513
- const { toggleNotification } = useNotification();
2514
- const handleClick = (action2) => (e) => {
2515
- const { onClick, dialog, id } = action2;
2516
- if (onClick) {
2517
- onClick(e);
2518
- }
2519
- if (dialog) {
2520
- switch (dialog.type) {
2521
- case "notification":
2522
- toggleNotification({
2523
- title: dialog.title,
2524
- message: dialog.content,
2525
- type: dialog.status,
2526
- timeout: dialog.timeout,
2527
- onClose: dialog.onClose
2528
- });
2529
- break;
2530
- case "dialog":
2531
- case "modal": {
2532
- e.preventDefault();
2533
- setDialogId(id);
2534
- }
2535
- }
2536
- }
2537
- };
2538
- const handleClose = () => {
2539
- setDialogId(null);
2540
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
2541
- action.dialog.onClose();
2542
- }
2543
- };
2544
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2545
- /* @__PURE__ */ jsx(
2546
- Button,
2547
- {
2548
- disabled: action.disabled,
2549
- startIcon: action.icon,
2550
- variant: action.variant,
2551
- onClick: handleClick(action),
2552
- children: action.label
2553
- }
2554
- ),
2555
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
2556
- BulkActionConfirmDialog,
2557
- {
2558
- ...action.dialog,
2559
- variant: action.variant,
2560
- isOpen: dialogId === action.id,
2561
- onClose: handleClose
2562
- }
2563
- ) : null,
2564
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
2565
- BulkActionModal,
2566
- {
2567
- ...action.dialog,
2568
- onModalClose: handleClose,
2569
- isOpen: dialogId === action.id
2570
- }
2571
- ) : null
2572
- ] });
2573
- };
2574
- const BulkActionConfirmDialog = ({
2575
- onClose,
2576
- onCancel,
2577
- onConfirm,
2578
- title,
2579
- content,
2580
- confirmButton,
2581
- isOpen,
2582
- variant = "secondary"
2583
- }) => {
2584
- const { formatMessage } = useIntl();
2585
- const handleClose = async () => {
2586
- if (onCancel) {
2587
- await onCancel();
2588
- }
2589
- onClose();
2590
- };
2591
- const handleConfirm = async () => {
2592
- if (onConfirm) {
2593
- await onConfirm();
2594
- }
2595
- onClose();
2596
- };
2597
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
2598
- /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
2599
- /* @__PURE__ */ jsx(
2600
- DialogFooter,
2601
- {
2602
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
2603
- id: "app.components.Button.cancel",
2604
- defaultMessage: "Cancel"
2605
- }) }),
2606
- endAction: /* @__PURE__ */ jsx(
2607
- Button,
2608
- {
2609
- onClick: handleConfirm,
2610
- variant: variant === "danger-light" ? variant : "secondary",
2611
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
2612
- children: confirmButton ? confirmButton : formatMessage({
2613
- id: "app.components.Button.confirm",
2614
- defaultMessage: "Confirm"
2615
- })
2616
- }
2617
- )
2618
- }
2619
- )
2620
- ] });
2619
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2620
+ endpoints: (builder) => ({
2621
+ getContentTypeConfiguration: builder.query({
2622
+ query: (uid) => ({
2623
+ url: `/content-manager/content-types/${uid}/configuration`,
2624
+ method: "GET"
2625
+ }),
2626
+ transformResponse: (response) => response.data,
2627
+ providesTags: (_result, _error, uid) => [
2628
+ { type: "ContentTypesConfiguration", id: uid },
2629
+ { type: "ContentTypeSettings", id: "LIST" }
2630
+ ]
2631
+ }),
2632
+ getAllContentTypeSettings: builder.query({
2633
+ query: () => "/content-manager/content-types-settings",
2634
+ transformResponse: (response) => response.data,
2635
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2636
+ }),
2637
+ updateContentTypeConfiguration: builder.mutation({
2638
+ query: ({ uid, ...body }) => ({
2639
+ url: `/content-manager/content-types/${uid}/configuration`,
2640
+ method: "PUT",
2641
+ data: body
2642
+ }),
2643
+ transformResponse: (response) => response.data,
2644
+ invalidatesTags: (_result, _error, { uid }) => [
2645
+ { type: "ContentTypesConfiguration", id: uid },
2646
+ { type: "ContentTypeSettings", id: "LIST" },
2647
+ // Is this necessary?
2648
+ { type: "InitialData" }
2649
+ ]
2650
+ })
2651
+ })
2652
+ });
2653
+ const {
2654
+ useGetContentTypeConfigurationQuery,
2655
+ useGetAllContentTypeSettingsQuery,
2656
+ useUpdateContentTypeConfigurationMutation
2657
+ } = contentTypesApi;
2658
+ const checkIfAttributeIsDisplayable = (attribute) => {
2659
+ const { type } = attribute;
2660
+ if (type === "relation") {
2661
+ return !attribute.relation.toLowerCase().includes("morph");
2662
+ }
2663
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2621
2664
  };
2622
- const BulkActionModal = ({
2623
- isOpen,
2624
- title,
2625
- onClose,
2626
- content: Content,
2627
- onModalClose
2628
- }) => {
2629
- const id = React.useId();
2630
- if (!isOpen) {
2631
- return null;
2665
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2666
+ if (!mainFieldName) {
2667
+ return void 0;
2632
2668
  }
2633
- const handleClose = () => {
2634
- if (onClose) {
2635
- onClose();
2636
- }
2637
- onModalClose();
2669
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2670
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2671
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2672
+ );
2673
+ return {
2674
+ name: mainFieldName,
2675
+ type: mainFieldType ?? "string"
2638
2676
  };
2639
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
2640
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
2641
- /* @__PURE__ */ jsx(Content, { onClose: handleClose })
2642
- ] });
2643
2677
  };
2644
- const DeleteAction = ({ documents, model }) => {
2645
- const { formatMessage } = useIntl();
2646
- const { schema: contentType } = useDoc();
2647
- const selectRow = useTable("DeleteAction", (state) => state.selectRow);
2648
- const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
2678
+ const DEFAULT_SETTINGS = {
2679
+ bulkable: false,
2680
+ filterable: false,
2681
+ searchable: false,
2682
+ pagination: false,
2683
+ defaultSortBy: "",
2684
+ defaultSortOrder: "asc",
2685
+ mainField: "id",
2686
+ pageSize: 10
2687
+ };
2688
+ const useDocumentLayout = (model) => {
2689
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2649
2690
  const [{ query }] = useQueryParams();
2650
- const params = React.useMemo(() => buildValidParams(query), [query]);
2651
- const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
2652
- const { deleteMany: bulkDeleteAction } = useDocumentActions();
2653
- const documentIds = documents.map(({ documentId }) => documentId);
2654
- const handleConfirmBulkDelete = async () => {
2655
- const res = await bulkDeleteAction({
2656
- documentIds,
2657
- model,
2658
- params
2659
- });
2660
- if (!("error" in res)) {
2661
- selectRow([]);
2691
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2692
+ const { toggleNotification } = useNotification();
2693
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2694
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2695
+ const {
2696
+ data,
2697
+ isLoading: isLoadingConfigs,
2698
+ error,
2699
+ isFetching: isFetchingConfigs
2700
+ } = useGetContentTypeConfigurationQuery(model);
2701
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2702
+ React.useEffect(() => {
2703
+ if (error) {
2704
+ toggleNotification({
2705
+ type: "danger",
2706
+ message: formatAPIError(error)
2707
+ });
2662
2708
  }
2663
- };
2664
- if (!hasDeletePermission)
2665
- return null;
2709
+ }, [error, formatAPIError, toggleNotification]);
2710
+ const editLayout = React.useMemo(
2711
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2712
+ layout: [],
2713
+ components: {},
2714
+ metadatas: {},
2715
+ options: {},
2716
+ settings: DEFAULT_SETTINGS
2717
+ },
2718
+ [data, isLoading, schemas, schema, components]
2719
+ );
2720
+ const listLayout = React.useMemo(() => {
2721
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2722
+ layout: [],
2723
+ metadatas: {},
2724
+ options: {},
2725
+ settings: DEFAULT_SETTINGS
2726
+ };
2727
+ }, [data, isLoading, schemas, schema, components]);
2728
+ const { layout: edit } = React.useMemo(
2729
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2730
+ layout: editLayout,
2731
+ query
2732
+ }),
2733
+ [editLayout, query, runHookWaterfall]
2734
+ );
2666
2735
  return {
2667
- variant: "danger-light",
2668
- label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
2669
- dialog: {
2670
- type: "dialog",
2671
- title: formatMessage({
2672
- id: "app.components.ConfirmDialog.title",
2673
- defaultMessage: "Confirmation"
2674
- }),
2675
- content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2676
- /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
2677
- id: "popUpWarning.bodyMessage.contentType.delete.all",
2678
- defaultMessage: "Are you sure you want to delete these entries?"
2679
- }) }),
2680
- hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
2681
- {
2682
- id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
2683
- defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
2684
- },
2685
- {
2686
- em: Emphasis
2687
- }
2688
- ) }) })
2689
- ] }),
2690
- onConfirm: handleConfirmBulkDelete
2691
- }
2736
+ error,
2737
+ isLoading,
2738
+ edit,
2739
+ list: listLayout
2692
2740
  };
2693
2741
  };
2694
- DeleteAction.type = "delete";
2695
- const UnpublishAction = ({ documents, model }) => {
2696
- const { formatMessage } = useIntl();
2697
- const { schema } = useDoc();
2698
- const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
2699
- const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
2700
- const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
2701
- const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
2702
- const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
2703
- const documentIds = documents.map(({ documentId }) => documentId);
2704
- const [{ query }] = useQueryParams();
2705
- const params = React.useMemo(() => buildValidParams(query), [query]);
2706
- const handleConfirmBulkUnpublish = async () => {
2707
- const data = await bulkUnpublishAction({ documentIds, model, params });
2708
- if (!("error" in data)) {
2709
- selectRow([]);
2742
+ const useDocLayout = () => {
2743
+ const { model } = useDoc();
2744
+ return useDocumentLayout(model);
2745
+ };
2746
+ const formatEditLayout = (data, {
2747
+ schemas,
2748
+ schema,
2749
+ components
2750
+ }) => {
2751
+ let currentPanelIndex = 0;
2752
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2753
+ data.contentType.layouts.edit,
2754
+ schema?.attributes,
2755
+ data.contentType.metadatas,
2756
+ { configurations: data.components, schemas: components },
2757
+ schemas
2758
+ ).reduce((panels, row) => {
2759
+ if (row.some((field) => field.type === "dynamiczone")) {
2760
+ panels.push([row]);
2761
+ currentPanelIndex += 2;
2762
+ } else {
2763
+ if (!panels[currentPanelIndex]) {
2764
+ panels.push([]);
2765
+ }
2766
+ panels[currentPanelIndex].push(row);
2767
+ }
2768
+ return panels;
2769
+ }, []);
2770
+ const componentEditAttributes = Object.entries(data.components).reduce(
2771
+ (acc, [uid, configuration]) => {
2772
+ acc[uid] = {
2773
+ layout: convertEditLayoutToFieldLayouts(
2774
+ configuration.layouts.edit,
2775
+ components[uid].attributes,
2776
+ configuration.metadatas
2777
+ ),
2778
+ settings: {
2779
+ ...configuration.settings,
2780
+ icon: components[uid].info.icon,
2781
+ displayName: components[uid].info.displayName
2782
+ }
2783
+ };
2784
+ return acc;
2785
+ },
2786
+ {}
2787
+ );
2788
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2789
+ (acc, [attribute, metadata]) => {
2790
+ return {
2791
+ ...acc,
2792
+ [attribute]: metadata.edit
2793
+ };
2794
+ },
2795
+ {}
2796
+ );
2797
+ return {
2798
+ layout: panelledEditAttributes,
2799
+ components: componentEditAttributes,
2800
+ metadatas: editMetadatas,
2801
+ settings: {
2802
+ ...data.contentType.settings,
2803
+ displayName: schema?.info.displayName
2804
+ },
2805
+ options: {
2806
+ ...schema?.options,
2807
+ ...schema?.pluginOptions,
2808
+ ...data.contentType.options
2710
2809
  }
2711
2810
  };
2712
- const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
2713
- if (!showUnpublishButton)
2714
- return null;
2811
+ };
2812
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2813
+ return rows.map(
2814
+ (row) => row.map((field) => {
2815
+ const attribute = attributes[field.name];
2816
+ if (!attribute) {
2817
+ return null;
2818
+ }
2819
+ const { edit: metadata } = metadatas[field.name];
2820
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2821
+ return {
2822
+ attribute,
2823
+ disabled: !metadata.editable,
2824
+ hint: metadata.description,
2825
+ label: metadata.label ?? "",
2826
+ name: field.name,
2827
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2828
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2829
+ schemas,
2830
+ components: components?.schemas ?? {}
2831
+ }),
2832
+ placeholder: metadata.placeholder ?? "",
2833
+ required: attribute.required ?? false,
2834
+ size: field.size,
2835
+ unique: "unique" in attribute ? attribute.unique : false,
2836
+ visible: metadata.visible ?? true,
2837
+ type: attribute.type
2838
+ };
2839
+ }).filter((field) => field !== null)
2840
+ );
2841
+ };
2842
+ const formatListLayout = (data, {
2843
+ schemas,
2844
+ schema,
2845
+ components
2846
+ }) => {
2847
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2848
+ (acc, [attribute, metadata]) => {
2849
+ return {
2850
+ ...acc,
2851
+ [attribute]: metadata.list
2852
+ };
2853
+ },
2854
+ {}
2855
+ );
2856
+ const listAttributes = convertListLayoutToFieldLayouts(
2857
+ data.contentType.layouts.list,
2858
+ schema?.attributes,
2859
+ listMetadatas,
2860
+ { configurations: data.components, schemas: components },
2861
+ schemas
2862
+ );
2715
2863
  return {
2716
- variant: "tertiary",
2717
- label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
2718
- dialog: {
2719
- type: "dialog",
2720
- title: formatMessage({
2721
- id: "app.components.ConfirmDialog.title",
2722
- defaultMessage: "Confirmation"
2864
+ layout: listAttributes,
2865
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2866
+ metadatas: listMetadatas,
2867
+ options: {
2868
+ ...schema?.options,
2869
+ ...schema?.pluginOptions,
2870
+ ...data.contentType.options
2871
+ }
2872
+ };
2873
+ };
2874
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2875
+ return columns.map((name) => {
2876
+ const attribute = attributes[name];
2877
+ if (!attribute) {
2878
+ return null;
2879
+ }
2880
+ const metadata = metadatas[name];
2881
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2882
+ return {
2883
+ attribute,
2884
+ label: metadata.label ?? "",
2885
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2886
+ schemas,
2887
+ components: components?.schemas ?? {}
2723
2888
  }),
2724
- content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2725
- /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
2726
- id: "popUpWarning.bodyMessage.contentType.unpublish.all",
2727
- defaultMessage: "Are you sure you want to unpublish these entries?"
2728
- }) }),
2729
- hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
2889
+ name,
2890
+ searchable: metadata.searchable ?? true,
2891
+ sortable: metadata.sortable ?? true
2892
+ };
2893
+ }).filter((field) => field !== null);
2894
+ };
2895
+ const ConfirmBulkActionDialog = ({
2896
+ onToggleDialog,
2897
+ isOpen = false,
2898
+ dialogBody,
2899
+ endAction
2900
+ }) => {
2901
+ const { formatMessage } = useIntl();
2902
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2903
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2904
+ id: "app.components.ConfirmDialog.title",
2905
+ defaultMessage: "Confirmation"
2906
+ }) }),
2907
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2908
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2909
+ dialogBody
2910
+ ] }) }),
2911
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2912
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2913
+ id: "app.components.Button.cancel",
2914
+ defaultMessage: "Cancel"
2915
+ }) }) }),
2916
+ endAction
2917
+ ] })
2918
+ ] }) });
2919
+ };
2920
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2921
+ const ConfirmDialogPublishAll = ({
2922
+ isOpen,
2923
+ onToggleDialog,
2924
+ isConfirmButtonLoading = false,
2925
+ onConfirm
2926
+ }) => {
2927
+ const { formatMessage } = useIntl();
2928
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2929
+ const { toggleNotification } = useNotification();
2930
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2931
+ const { model, schema } = useDoc();
2932
+ const [{ query }] = useQueryParams();
2933
+ const {
2934
+ data: countDraftRelations = 0,
2935
+ isLoading,
2936
+ error
2937
+ } = useGetManyDraftRelationCountQuery(
2938
+ {
2939
+ model,
2940
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2941
+ locale: query?.plugins?.i18n?.locale
2942
+ },
2943
+ {
2944
+ skip: selectedEntries.length === 0
2945
+ }
2946
+ );
2947
+ React.useEffect(() => {
2948
+ if (error) {
2949
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2950
+ }
2951
+ }, [error, formatAPIError, toggleNotification]);
2952
+ if (error) {
2953
+ return null;
2954
+ }
2955
+ return /* @__PURE__ */ jsx(
2956
+ ConfirmBulkActionDialog,
2957
+ {
2958
+ isOpen: isOpen && !isLoading,
2959
+ onToggleDialog,
2960
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2961
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2962
+ countDraftRelations > 0 && formatMessage(
2963
+ {
2964
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2965
+ defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
2966
+ },
2967
+ {
2968
+ b: BoldChunk$1,
2969
+ count: countDraftRelations,
2970
+ entities: selectedEntries.length
2971
+ }
2972
+ ),
2973
+ formatMessage({
2974
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2975
+ defaultMessage: "Are you sure you want to publish these entries?"
2976
+ })
2977
+ ] }),
2978
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2730
2979
  {
2731
- id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
2732
- defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
2980
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2981
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2733
2982
  },
2734
2983
  {
2735
2984
  em: Emphasis
2736
2985
  }
2737
- ) }) })
2986
+ ) })
2738
2987
  ] }),
2739
- confirmButton: formatMessage({
2740
- id: "app.utils.unpublish",
2741
- defaultMessage: "Unpublish"
2742
- }),
2743
- onConfirm: handleConfirmBulkUnpublish
2988
+ endAction: /* @__PURE__ */ jsx(
2989
+ Button,
2990
+ {
2991
+ onClick: onConfirm,
2992
+ variant: "secondary",
2993
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2994
+ loading: isConfirmButtonLoading,
2995
+ children: formatMessage({
2996
+ id: "app.utils.publish",
2997
+ defaultMessage: "Publish"
2998
+ })
2999
+ }
3000
+ )
2744
3001
  }
2745
- };
3002
+ );
2746
3003
  };
2747
- UnpublishAction.type = "unpublish";
2748
- const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
2749
- const DEFAULT_BULK_ACTIONS = [UnpublishAction, DeleteAction];
2750
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3004
+ const TypographyMaxWidth = styled(Typography)`
3005
+ max-width: 300px;
3006
+ `;
3007
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3008
+ const messages = [];
3009
+ Object.entries(errors).forEach(([key, value]) => {
3010
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3011
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3012
+ if ("id" in value && "defaultMessage" in value) {
3013
+ messages.push(
3014
+ formatMessage(
3015
+ {
3016
+ id: `${value.id}.withField`,
3017
+ defaultMessage: value.defaultMessage
3018
+ },
3019
+ { field: currentKey }
3020
+ )
3021
+ );
3022
+ } else {
3023
+ messages.push(
3024
+ ...formatErrorMessages(
3025
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3026
+ value,
3027
+ currentKey,
3028
+ formatMessage
3029
+ )
3030
+ );
3031
+ }
3032
+ } else {
3033
+ messages.push(
3034
+ formatMessage(
3035
+ {
3036
+ id: `${value}.withField`,
3037
+ defaultMessage: value
3038
+ },
3039
+ { field: currentKey }
3040
+ )
3041
+ );
3042
+ }
3043
+ });
3044
+ return messages;
3045
+ };
3046
+ const EntryValidationText = ({ validationErrors, status }) => {
2751
3047
  const { formatMessage } = useIntl();
2752
- const getDefaultErrorMessage = (reason) => {
2753
- switch (reason) {
2754
- case "relation":
2755
- return "Duplicating the relation could remove it from the original entry.";
2756
- case "unique":
2757
- return "Identical values in a unique field are not allowed";
2758
- default:
2759
- return reason;
3048
+ if (validationErrors) {
3049
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3050
+ " "
3051
+ );
3052
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3053
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3054
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3055
+ ] });
3056
+ }
3057
+ if (status === "published") {
3058
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3059
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3060
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3061
+ id: "content-manager.bulk-publish.already-published",
3062
+ defaultMessage: "Already Published"
3063
+ }) })
3064
+ ] });
3065
+ }
3066
+ if (status === "modified") {
3067
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3068
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3069
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3070
+ id: "content-manager.bulk-publish.modified",
3071
+ defaultMessage: "Ready to publish changes"
3072
+ }) })
3073
+ ] });
3074
+ }
3075
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3076
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3077
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3078
+ id: "app.utils.ready-to-publish",
3079
+ defaultMessage: "Ready to publish"
3080
+ }) })
3081
+ ] });
3082
+ };
3083
+ const TABLE_HEADERS = [
3084
+ { name: "id", label: "id" },
3085
+ { name: "name", label: "name" },
3086
+ { name: "status", label: "status" },
3087
+ { name: "publicationStatus", label: "Publication status" }
3088
+ ];
3089
+ const SelectedEntriesTableContent = ({
3090
+ isPublishing,
3091
+ rowsToDisplay = [],
3092
+ entriesToPublish = [],
3093
+ validationErrors = {}
3094
+ }) => {
3095
+ const { pathname } = useLocation();
3096
+ const { formatMessage } = useIntl();
3097
+ const {
3098
+ list: {
3099
+ settings: { mainField }
2760
3100
  }
2761
- };
2762
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2763
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
2764
- id: getTranslation("containers.list.autoCloneModal.title"),
2765
- defaultMessage: "This entry can't be duplicated directly."
2766
- }) }),
2767
- /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3101
+ } = useDocLayout();
3102
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3103
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3104
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3105
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3106
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3107
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3108
+ )
3109
+ ] }),
3110
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3111
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3112
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3113
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3114
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3115
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3116
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3117
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3118
+ id: "content-manager.success.record.publishing",
3119
+ defaultMessage: "Publishing..."
3120
+ }) }),
3121
+ /* @__PURE__ */ jsx(Loader, { small: true })
3122
+ ] }) : /* @__PURE__ */ jsx(
3123
+ EntryValidationText,
3124
+ {
3125
+ validationErrors: validationErrors[row.documentId],
3126
+ status: row.status
3127
+ }
3128
+ ) }),
3129
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3130
+ IconButton,
3131
+ {
3132
+ tag: Link,
3133
+ to: {
3134
+ pathname: `${pathname}/${row.documentId}`,
3135
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3136
+ },
3137
+ state: { from: pathname },
3138
+ label: formatMessage(
3139
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3140
+ {
3141
+ target: formatMessage(
3142
+ {
3143
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3144
+ defaultMessage: "item line {number}"
3145
+ },
3146
+ { number: index2 + 1 }
3147
+ )
3148
+ }
3149
+ ),
3150
+ target: "_blank",
3151
+ marginLeft: "auto",
3152
+ children: /* @__PURE__ */ jsx(Pencil, {})
3153
+ }
3154
+ ) })
3155
+ ] }, row.id)) })
3156
+ ] });
3157
+ };
3158
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3159
+ const SelectedEntriesModalContent = ({
3160
+ listViewSelectedEntries,
3161
+ toggleModal,
3162
+ setListViewSelectedDocuments,
3163
+ model
3164
+ }) => {
3165
+ const { formatMessage } = useIntl();
3166
+ const { schema, components } = useContentTypeSchema(model);
3167
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3168
+ const [{ query }] = useQueryParams();
3169
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3170
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3171
+ {
3172
+ model,
3173
+ params: {
3174
+ page: "1",
3175
+ pageSize: documentIds.length.toString(),
3176
+ sort: query.sort,
3177
+ filters: {
3178
+ documentId: {
3179
+ $in: documentIds
3180
+ }
3181
+ },
3182
+ locale: query.plugins?.i18n?.locale
3183
+ }
3184
+ },
3185
+ {
3186
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3187
+ }
3188
+ );
3189
+ const { rows, validationErrors } = React.useMemo(() => {
3190
+ if (data.length > 0 && schema) {
3191
+ const validate = createYupSchema(schema.attributes, components);
3192
+ const validationErrors2 = {};
3193
+ const rows2 = data.map((entry) => {
3194
+ try {
3195
+ validate.validateSync(entry, { abortEarly: false });
3196
+ return entry;
3197
+ } catch (e) {
3198
+ if (e instanceof ValidationError) {
3199
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3200
+ }
3201
+ return entry;
3202
+ }
3203
+ });
3204
+ return { rows: rows2, validationErrors: validationErrors2 };
3205
+ }
3206
+ return {
3207
+ rows: [],
3208
+ validationErrors: {}
3209
+ };
3210
+ }, [components, data, schema]);
3211
+ const [publishedCount, setPublishedCount] = React.useState(0);
3212
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3213
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3214
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3215
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3216
+ const selectedEntries = rows.filter(
3217
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3218
+ );
3219
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3220
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3221
+ ({ documentId }) => validationErrors[documentId]
3222
+ ).length;
3223
+ const selectedEntriesPublished = selectedEntries.filter(
3224
+ ({ status }) => status === "published"
3225
+ ).length;
3226
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3227
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3228
+ const handleConfirmBulkPublish = async () => {
3229
+ toggleDialog();
3230
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3231
+ if (!("error" in res)) {
3232
+ setPublishedCount(res.count);
3233
+ const unpublishedEntries = rows.filter((row) => {
3234
+ return !entriesToPublish.includes(row.documentId);
3235
+ });
3236
+ setListViewSelectedDocuments(unpublishedEntries);
3237
+ }
3238
+ };
3239
+ const getFormattedCountMessage = () => {
3240
+ if (publishedCount) {
3241
+ return formatMessage(
3242
+ {
3243
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3244
+ defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3245
+ },
3246
+ {
3247
+ publishedCount,
3248
+ withErrorsCount: selectedEntriesWithErrorsCount,
3249
+ b: BoldChunk
3250
+ }
3251
+ );
3252
+ }
3253
+ return formatMessage(
3254
+ {
3255
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3256
+ defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3257
+ },
3258
+ {
3259
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3260
+ withErrorsCount: selectedEntriesWithErrorsCount,
3261
+ alreadyPublishedCount: selectedEntriesPublished,
3262
+ b: BoldChunk
3263
+ }
3264
+ );
3265
+ };
3266
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3267
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3268
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3269
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3270
+ SelectedEntriesTableContent,
3271
+ {
3272
+ isPublishing: isSubmittingForm,
3273
+ rowsToDisplay: rows,
3274
+ entriesToPublish,
3275
+ validationErrors
3276
+ }
3277
+ ) })
3278
+ ] }),
3279
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3280
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3281
+ id: "app.components.Button.cancel",
3282
+ defaultMessage: "Cancel"
3283
+ }) }),
3284
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3285
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3286
+ /* @__PURE__ */ jsx(
3287
+ Button,
3288
+ {
3289
+ onClick: toggleDialog,
3290
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3291
+ loading: isSubmittingForm,
3292
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3293
+ }
3294
+ )
3295
+ ] })
3296
+ ] }),
3297
+ /* @__PURE__ */ jsx(
3298
+ ConfirmDialogPublishAll,
3299
+ {
3300
+ isOpen: isDialogOpen,
3301
+ onToggleDialog: toggleDialog,
3302
+ isConfirmButtonLoading: isSubmittingForm,
3303
+ onConfirm: handleConfirmBulkPublish
3304
+ }
3305
+ )
3306
+ ] });
3307
+ };
3308
+ const PublishAction = ({ documents, model }) => {
3309
+ const { formatMessage } = useIntl();
3310
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3311
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3312
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3313
+ const refetchList = () => {
3314
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3315
+ };
3316
+ if (!showPublishButton)
3317
+ return null;
3318
+ return {
3319
+ actionType: "publish",
3320
+ variant: "tertiary",
3321
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3322
+ dialog: {
3323
+ type: "modal",
3324
+ title: formatMessage({
3325
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3326
+ defaultMessage: "Publish entries"
3327
+ }),
3328
+ content: ({ onClose }) => {
3329
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3330
+ SelectedEntriesModalContent,
3331
+ {
3332
+ listViewSelectedEntries: documents,
3333
+ toggleModal: () => {
3334
+ onClose();
3335
+ refetchList();
3336
+ },
3337
+ setListViewSelectedDocuments,
3338
+ model
3339
+ }
3340
+ ) });
3341
+ },
3342
+ onClose: () => {
3343
+ refetchList();
3344
+ }
3345
+ }
3346
+ };
3347
+ };
3348
+ const BulkActionsRenderer = () => {
3349
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3350
+ const { model, collectionType } = useDoc();
3351
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3352
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3353
+ DescriptionComponentRenderer,
3354
+ {
3355
+ props: {
3356
+ model,
3357
+ collectionType,
3358
+ documents: selectedRows
3359
+ },
3360
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3361
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3362
+ }
3363
+ ) });
3364
+ };
3365
+ const DeleteAction = ({ documents, model }) => {
3366
+ const { formatMessage } = useIntl();
3367
+ const { schema: contentType } = useDoc();
3368
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3369
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3370
+ const [{ query }] = useQueryParams();
3371
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3372
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3373
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3374
+ const documentIds = documents.map(({ documentId }) => documentId);
3375
+ const handleConfirmBulkDelete = async () => {
3376
+ const res = await bulkDeleteAction({
3377
+ documentIds,
3378
+ model,
3379
+ params
3380
+ });
3381
+ if (!("error" in res)) {
3382
+ selectRow([]);
3383
+ }
3384
+ };
3385
+ if (!hasDeletePermission)
3386
+ return null;
3387
+ return {
3388
+ variant: "danger-light",
3389
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3390
+ dialog: {
3391
+ type: "dialog",
3392
+ title: formatMessage({
3393
+ id: "app.components.ConfirmDialog.title",
3394
+ defaultMessage: "Confirmation"
3395
+ }),
3396
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3397
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3398
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3399
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3400
+ defaultMessage: "Are you sure you want to delete these entries?"
3401
+ }) }),
3402
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3403
+ {
3404
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3405
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3406
+ },
3407
+ {
3408
+ em: Emphasis
3409
+ }
3410
+ ) }) })
3411
+ ] }),
3412
+ onConfirm: handleConfirmBulkDelete
3413
+ }
3414
+ };
3415
+ };
3416
+ DeleteAction.type = "delete";
3417
+ const UnpublishAction = ({ documents, model }) => {
3418
+ const { formatMessage } = useIntl();
3419
+ const { schema } = useDoc();
3420
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3421
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3422
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3423
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3424
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3425
+ const documentIds = documents.map(({ documentId }) => documentId);
3426
+ const [{ query }] = useQueryParams();
3427
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3428
+ const handleConfirmBulkUnpublish = async () => {
3429
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3430
+ if (!("error" in data)) {
3431
+ selectRow([]);
3432
+ }
3433
+ };
3434
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3435
+ if (!showUnpublishButton)
3436
+ return null;
3437
+ return {
3438
+ variant: "tertiary",
3439
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3440
+ dialog: {
3441
+ type: "dialog",
3442
+ title: formatMessage({
3443
+ id: "app.components.ConfirmDialog.title",
3444
+ defaultMessage: "Confirmation"
3445
+ }),
3446
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3447
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3448
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3449
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3450
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3451
+ }) }),
3452
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3453
+ {
3454
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3455
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3456
+ },
3457
+ {
3458
+ em: Emphasis
3459
+ }
3460
+ ) }) })
3461
+ ] }),
3462
+ confirmButton: formatMessage({
3463
+ id: "app.utils.unpublish",
3464
+ defaultMessage: "Unpublish"
3465
+ }),
3466
+ onConfirm: handleConfirmBulkUnpublish
3467
+ }
3468
+ };
3469
+ };
3470
+ UnpublishAction.type = "unpublish";
3471
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3472
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3473
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3474
+ const { formatMessage } = useIntl();
3475
+ const getDefaultErrorMessage = (reason) => {
3476
+ switch (reason) {
3477
+ case "relation":
3478
+ return "Duplicating the relation could remove it from the original entry.";
3479
+ case "unique":
3480
+ return "Identical values in a unique field are not allowed";
3481
+ default:
3482
+ return reason;
3483
+ }
3484
+ };
3485
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3486
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3487
+ id: getTranslation("containers.list.autoCloneModal.title"),
3488
+ defaultMessage: "This entry can't be duplicated directly."
3489
+ }) }),
3490
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
2768
3491
  id: getTranslation("containers.list.autoCloneModal.description"),
2769
3492
  defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2770
3493
  }) }) }),
@@ -2805,596 +3528,339 @@ const TableActions = ({ document }) => {
2805
3528
  const { model, collectionType } = useDoc();
2806
3529
  const plugins = useStrapiApp("TableActions", (state) => state.plugins);
2807
3530
  const props = {
2808
- activeTab: null,
2809
- model,
2810
- documentId: document.documentId,
2811
- collectionType,
2812
- document
2813
- };
2814
- return /* @__PURE__ */ jsx(
2815
- DescriptionComponentRenderer,
2816
- {
2817
- props,
2818
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2819
- children: (actions2) => {
2820
- const tableRowActions = actions2.filter((action) => {
2821
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2822
- return positions.includes("table-row");
2823
- });
2824
- return /* @__PURE__ */ jsx(
2825
- DocumentActionsMenu,
2826
- {
2827
- actions: tableRowActions,
2828
- label: formatMessage({
2829
- id: "content-manager.containers.list.table.row-actions",
2830
- defaultMessage: "Row action"
2831
- }),
2832
- variant: "ghost"
2833
- }
2834
- );
2835
- }
2836
- }
2837
- );
2838
- };
2839
- const EditAction = ({ documentId }) => {
2840
- const navigate = useNavigate();
2841
- const { formatMessage } = useIntl();
2842
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2843
- const { toggleNotification } = useNotification();
2844
- const [{ query }] = useQueryParams();
2845
- return {
2846
- disabled: !canRead,
2847
- icon: /* @__PURE__ */ jsx(StyledPencil, {}),
2848
- label: formatMessage({
2849
- id: "content-manager.actions.edit.label",
2850
- defaultMessage: "Edit"
2851
- }),
2852
- position: "table-row",
2853
- onClick: async () => {
2854
- if (!documentId) {
2855
- console.error(
2856
- "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
2857
- );
2858
- toggleNotification({
2859
- message: formatMessage({
2860
- id: "content-manager.actions.edit.error",
2861
- defaultMessage: "An error occurred while trying to edit the document."
2862
- }),
2863
- type: "danger"
2864
- });
2865
- return;
2866
- }
2867
- navigate({
2868
- pathname: documentId,
2869
- search: stringify({
2870
- plugins: query.plugins
2871
- })
2872
- });
2873
- }
2874
- };
2875
- };
2876
- EditAction.type = "edit";
2877
- const StyledPencil = styled(Pencil)`
2878
- path {
2879
- fill: currentColor;
2880
- }
2881
- `;
2882
- const CloneAction = ({ model, documentId }) => {
2883
- const navigate = useNavigate();
2884
- const { formatMessage } = useIntl();
2885
- const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
2886
- const { toggleNotification } = useNotification();
2887
- const { autoClone } = useDocumentActions();
2888
- const [prohibitedFields, setProhibitedFields] = React.useState([]);
2889
- return {
2890
- disabled: !canCreate,
2891
- icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
2892
- label: formatMessage({
2893
- id: "content-manager.actions.clone.label",
2894
- defaultMessage: "Duplicate"
2895
- }),
2896
- position: "table-row",
2897
- onClick: async () => {
2898
- if (!documentId) {
2899
- console.error(
2900
- "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
2901
- );
2902
- toggleNotification({
2903
- message: formatMessage({
2904
- id: "content-manager.actions.clone.error",
2905
- defaultMessage: "An error occurred while trying to clone the document."
2906
- }),
2907
- type: "danger"
2908
- });
2909
- return;
2910
- }
2911
- const res = await autoClone({ model, sourceId: documentId });
2912
- if ("data" in res) {
2913
- navigate(res.data.documentId);
2914
- return true;
2915
- }
2916
- if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
2917
- const prohibitedFields2 = res.error.details.prohibitedFields;
2918
- setProhibitedFields(prohibitedFields2);
2919
- }
2920
- },
2921
- dialog: {
2922
- type: "modal",
2923
- title: formatMessage({
2924
- id: "content-manager.containers.list.autoCloneModal.header",
2925
- defaultMessage: "Duplicate"
2926
- }),
2927
- content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2928
- footer: ({ onClose }) => {
2929
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
2930
- /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2931
- id: "cancel",
2932
- defaultMessage: "Cancel"
2933
- }) }),
2934
- /* @__PURE__ */ jsx(
2935
- LinkButton,
2936
- {
2937
- tag: NavLink,
2938
- to: {
2939
- pathname: `clone/${documentId}`
2940
- },
2941
- children: formatMessage({
2942
- id: "content-manager.containers.list.autoCloneModal.create",
2943
- defaultMessage: "Create"
2944
- })
2945
- }
2946
- )
2947
- ] });
2948
- }
2949
- }
2950
- };
2951
- };
2952
- CloneAction.type = "clone";
2953
- const StyledDuplicate = styled(Duplicate)`
2954
- path {
2955
- fill: currentColor;
2956
- }
2957
- `;
2958
- const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
2959
- class ContentManagerPlugin {
2960
- /**
2961
- * The following properties are the stored ones provided by any plugins registering with
2962
- * the content-manager. The function calls however, need to be called at runtime in the
2963
- * application, so instead we collate them and run them later with the complete list incl.
2964
- * ones already registered & the context of the view.
2965
- */
2966
- bulkActions = [...DEFAULT_BULK_ACTIONS];
2967
- documentActions = [
2968
- ...DEFAULT_ACTIONS,
2969
- ...DEFAULT_TABLE_ROW_ACTIONS,
2970
- ...DEFAULT_HEADER_ACTIONS,
2971
- HistoryAction
2972
- ];
2973
- editViewSidePanels = [ActionsPanel];
2974
- headerActions = [];
2975
- constructor() {
2976
- }
2977
- addEditViewSidePanel(panels) {
2978
- if (Array.isArray(panels)) {
2979
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2980
- } else if (typeof panels === "function") {
2981
- this.editViewSidePanels = panels(this.editViewSidePanels);
2982
- } else {
2983
- throw new Error(
2984
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2985
- panels
2986
- )}`
2987
- );
2988
- }
2989
- }
2990
- addDocumentAction(actions2) {
2991
- if (Array.isArray(actions2)) {
2992
- this.documentActions = [...this.documentActions, ...actions2];
2993
- } else if (typeof actions2 === "function") {
2994
- this.documentActions = actions2(this.documentActions);
2995
- } else {
2996
- throw new Error(
2997
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2998
- actions2
2999
- )}`
3000
- );
3001
- }
3002
- }
3003
- addDocumentHeaderAction(actions2) {
3004
- if (Array.isArray(actions2)) {
3005
- this.headerActions = [...this.headerActions, ...actions2];
3006
- } else if (typeof actions2 === "function") {
3007
- this.headerActions = actions2(this.headerActions);
3008
- } else {
3009
- throw new Error(
3010
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3011
- actions2
3012
- )}`
3013
- );
3014
- }
3015
- }
3016
- addBulkAction(actions2) {
3017
- if (Array.isArray(actions2)) {
3018
- this.bulkActions = [...this.bulkActions, ...actions2];
3019
- } else if (typeof actions2 === "function") {
3020
- this.bulkActions = actions2(this.bulkActions);
3021
- } else {
3022
- throw new Error(
3023
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3024
- actions2
3025
- )}`
3026
- );
3027
- }
3028
- }
3029
- get config() {
3030
- return {
3031
- id: PLUGIN_ID,
3032
- name: "Content Manager",
3033
- injectionZones: INJECTION_ZONES,
3034
- apis: {
3035
- addBulkAction: this.addBulkAction.bind(this),
3036
- addDocumentAction: this.addDocumentAction.bind(this),
3037
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3038
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3039
- getBulkActions: () => this.bulkActions,
3040
- getDocumentActions: () => this.documentActions,
3041
- getEditViewSidePanels: () => this.editViewSidePanels,
3042
- getHeaderActions: () => this.headerActions
3043
- }
3044
- };
3045
- }
3046
- }
3047
- const getPrintableType = (value) => {
3048
- const nativeType = typeof value;
3049
- if (nativeType === "object") {
3050
- if (value === null)
3051
- return "null";
3052
- if (Array.isArray(value))
3053
- return "array";
3054
- if (value instanceof Object && value.constructor.name !== "Object") {
3055
- return value.constructor.name;
3056
- }
3057
- }
3058
- return nativeType;
3059
- };
3060
- const initialState = {
3061
- collectionTypeLinks: [],
3062
- components: [],
3063
- fieldSizes: {},
3064
- models: [],
3065
- singleTypeLinks: [],
3066
- isLoading: true
3067
- };
3068
- const appSlice = createSlice({
3069
- name: "app",
3070
- initialState,
3071
- reducers: {
3072
- setInitialData(state, action) {
3073
- const {
3074
- authorizedCollectionTypeLinks,
3075
- authorizedSingleTypeLinks,
3076
- components,
3077
- contentTypeSchemas,
3078
- fieldSizes
3079
- } = action.payload;
3080
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3081
- ({ isDisplayed }) => isDisplayed
3082
- );
3083
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3084
- state.components = components;
3085
- state.models = contentTypeSchemas;
3086
- state.fieldSizes = fieldSizes;
3087
- state.isLoading = false;
3088
- }
3089
- }
3090
- });
3091
- const { actions, reducer: reducer$1 } = appSlice;
3092
- const { setInitialData } = actions;
3093
- const reducer = combineReducers({
3094
- app: reducer$1
3095
- });
3096
- const HOOKS = {
3097
- /**
3098
- * Hook that allows to mutate the displayed headers of the list view table
3099
- * @constant
3100
- * @type {string}
3101
- */
3102
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
3103
- /**
3104
- * Hook that allows to mutate the CM's collection types links pre-set filters
3105
- * @constant
3106
- * @type {string}
3107
- */
3108
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
3109
- /**
3110
- * Hook that allows to mutate the CM's edit view layout
3111
- * @constant
3112
- * @type {string}
3113
- */
3114
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
3115
- /**
3116
- * Hook that allows to mutate the CM's single types links pre-set filters
3117
- * @constant
3118
- * @type {string}
3119
- */
3120
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
3121
- };
3122
- const contentTypesApi = contentManagerApi.injectEndpoints({
3123
- endpoints: (builder) => ({
3124
- getContentTypeConfiguration: builder.query({
3125
- query: (uid) => ({
3126
- url: `/content-manager/content-types/${uid}/configuration`,
3127
- method: "GET"
3128
- }),
3129
- transformResponse: (response) => response.data,
3130
- providesTags: (_result, _error, uid) => [
3131
- { type: "ContentTypesConfiguration", id: uid },
3132
- { type: "ContentTypeSettings", id: "LIST" }
3133
- ]
3134
- }),
3135
- getAllContentTypeSettings: builder.query({
3136
- query: () => "/content-manager/content-types-settings",
3137
- transformResponse: (response) => response.data,
3138
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
3139
- }),
3140
- updateContentTypeConfiguration: builder.mutation({
3141
- query: ({ uid, ...body }) => ({
3142
- url: `/content-manager/content-types/${uid}/configuration`,
3143
- method: "PUT",
3144
- data: body
3145
- }),
3146
- transformResponse: (response) => response.data,
3147
- invalidatesTags: (_result, _error, { uid }) => [
3148
- { type: "ContentTypesConfiguration", id: uid },
3149
- { type: "ContentTypeSettings", id: "LIST" },
3150
- // Is this necessary?
3151
- { type: "InitialData" }
3152
- ]
3153
- })
3154
- })
3155
- });
3156
- const {
3157
- useGetContentTypeConfigurationQuery,
3158
- useGetAllContentTypeSettingsQuery,
3159
- useUpdateContentTypeConfigurationMutation
3160
- } = contentTypesApi;
3161
- const checkIfAttributeIsDisplayable = (attribute) => {
3162
- const { type } = attribute;
3163
- if (type === "relation") {
3164
- return !attribute.relation.toLowerCase().includes("morph");
3165
- }
3166
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
3167
- };
3168
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
3169
- if (!mainFieldName) {
3170
- return void 0;
3171
- }
3172
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
3173
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
3174
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
3175
- );
3176
- return {
3177
- name: mainFieldName,
3178
- type: mainFieldType ?? "string"
3531
+ activeTab: null,
3532
+ model,
3533
+ documentId: document.documentId,
3534
+ collectionType,
3535
+ document
3179
3536
  };
3537
+ return /* @__PURE__ */ jsx(
3538
+ DescriptionComponentRenderer,
3539
+ {
3540
+ props,
3541
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3542
+ children: (actions2) => {
3543
+ const tableRowActions = actions2.filter((action) => {
3544
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3545
+ return positions.includes("table-row");
3546
+ });
3547
+ return /* @__PURE__ */ jsx(
3548
+ DocumentActionsMenu,
3549
+ {
3550
+ actions: tableRowActions,
3551
+ label: formatMessage({
3552
+ id: "content-manager.containers.list.table.row-actions",
3553
+ defaultMessage: "Row action"
3554
+ }),
3555
+ variant: "ghost"
3556
+ }
3557
+ );
3558
+ }
3559
+ }
3560
+ );
3180
3561
  };
3181
- const DEFAULT_SETTINGS = {
3182
- bulkable: false,
3183
- filterable: false,
3184
- searchable: false,
3185
- pagination: false,
3186
- defaultSortBy: "",
3187
- defaultSortOrder: "asc",
3188
- mainField: "id",
3189
- pageSize: 10
3190
- };
3191
- const useDocumentLayout = (model) => {
3192
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
3193
- const [{ query }] = useQueryParams();
3194
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
3562
+ const EditAction = ({ documentId }) => {
3563
+ const navigate = useNavigate();
3564
+ const { formatMessage } = useIntl();
3565
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3195
3566
  const { toggleNotification } = useNotification();
3196
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
3197
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
3198
- const {
3199
- data,
3200
- isLoading: isLoadingConfigs,
3201
- error,
3202
- isFetching: isFetchingConfigs
3203
- } = useGetContentTypeConfigurationQuery(model);
3204
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
3205
- React.useEffect(() => {
3206
- if (error) {
3207
- toggleNotification({
3208
- type: "danger",
3209
- message: formatAPIError(error)
3567
+ const [{ query }] = useQueryParams();
3568
+ return {
3569
+ disabled: !canRead,
3570
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3571
+ label: formatMessage({
3572
+ id: "content-manager.actions.edit.label",
3573
+ defaultMessage: "Edit"
3574
+ }),
3575
+ position: "table-row",
3576
+ onClick: async () => {
3577
+ if (!documentId) {
3578
+ console.error(
3579
+ "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
3580
+ );
3581
+ toggleNotification({
3582
+ message: formatMessage({
3583
+ id: "content-manager.actions.edit.error",
3584
+ defaultMessage: "An error occurred while trying to edit the document."
3585
+ }),
3586
+ type: "danger"
3587
+ });
3588
+ return;
3589
+ }
3590
+ navigate({
3591
+ pathname: documentId,
3592
+ search: stringify({
3593
+ plugins: query.plugins
3594
+ })
3210
3595
  });
3211
3596
  }
3212
- }, [error, formatAPIError, toggleNotification]);
3213
- const editLayout = React.useMemo(
3214
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
3215
- layout: [],
3216
- components: {},
3217
- metadatas: {},
3218
- options: {},
3219
- settings: DEFAULT_SETTINGS
3220
- },
3221
- [data, isLoading, schemas, schema, components]
3222
- );
3223
- const listLayout = React.useMemo(() => {
3224
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
3225
- layout: [],
3226
- metadatas: {},
3227
- options: {},
3228
- settings: DEFAULT_SETTINGS
3229
- };
3230
- }, [data, isLoading, schemas, schema, components]);
3231
- const { layout: edit } = React.useMemo(
3232
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
3233
- layout: editLayout,
3234
- query
3235
- }),
3236
- [editLayout, query, runHookWaterfall]
3237
- );
3238
- return {
3239
- error,
3240
- isLoading,
3241
- edit,
3242
- list: listLayout
3243
3597
  };
3244
3598
  };
3245
- const useDocLayout = () => {
3246
- const { model } = useDoc();
3247
- return useDocumentLayout(model);
3248
- };
3249
- const formatEditLayout = (data, {
3250
- schemas,
3251
- schema,
3252
- components
3253
- }) => {
3254
- let currentPanelIndex = 0;
3255
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
3256
- data.contentType.layouts.edit,
3257
- schema?.attributes,
3258
- data.contentType.metadatas,
3259
- { configurations: data.components, schemas: components },
3260
- schemas
3261
- ).reduce((panels, row) => {
3262
- if (row.some((field) => field.type === "dynamiczone")) {
3263
- panels.push([row]);
3264
- currentPanelIndex += 2;
3265
- } else {
3266
- if (!panels[currentPanelIndex]) {
3267
- panels.push([]);
3268
- }
3269
- panels[currentPanelIndex].push(row);
3270
- }
3271
- return panels;
3272
- }, []);
3273
- const componentEditAttributes = Object.entries(data.components).reduce(
3274
- (acc, [uid, configuration]) => {
3275
- acc[uid] = {
3276
- layout: convertEditLayoutToFieldLayouts(
3277
- configuration.layouts.edit,
3278
- components[uid].attributes,
3279
- configuration.metadatas
3280
- ),
3281
- settings: {
3282
- ...configuration.settings,
3283
- icon: components[uid].info.icon,
3284
- displayName: components[uid].info.displayName
3285
- }
3286
- };
3287
- return acc;
3288
- },
3289
- {}
3290
- );
3291
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
3292
- (acc, [attribute, metadata]) => {
3293
- return {
3294
- ...acc,
3295
- [attribute]: metadata.edit
3296
- };
3297
- },
3298
- {}
3299
- );
3599
+ EditAction.type = "edit";
3600
+ const StyledPencil = styled(Pencil)`
3601
+ path {
3602
+ fill: currentColor;
3603
+ }
3604
+ `;
3605
+ const CloneAction = ({ model, documentId }) => {
3606
+ const navigate = useNavigate();
3607
+ const { formatMessage } = useIntl();
3608
+ const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
3609
+ const { toggleNotification } = useNotification();
3610
+ const { autoClone } = useDocumentActions();
3611
+ const [prohibitedFields, setProhibitedFields] = React.useState([]);
3300
3612
  return {
3301
- layout: panelledEditAttributes,
3302
- components: componentEditAttributes,
3303
- metadatas: editMetadatas,
3304
- settings: {
3305
- ...data.contentType.settings,
3306
- displayName: schema?.info.displayName
3613
+ disabled: !canCreate,
3614
+ icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
3615
+ label: formatMessage({
3616
+ id: "content-manager.actions.clone.label",
3617
+ defaultMessage: "Duplicate"
3618
+ }),
3619
+ position: "table-row",
3620
+ onClick: async () => {
3621
+ if (!documentId) {
3622
+ console.error(
3623
+ "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
3624
+ );
3625
+ toggleNotification({
3626
+ message: formatMessage({
3627
+ id: "content-manager.actions.clone.error",
3628
+ defaultMessage: "An error occurred while trying to clone the document."
3629
+ }),
3630
+ type: "danger"
3631
+ });
3632
+ return;
3633
+ }
3634
+ const res = await autoClone({ model, sourceId: documentId });
3635
+ if ("data" in res) {
3636
+ navigate(res.data.documentId);
3637
+ return true;
3638
+ }
3639
+ if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
3640
+ const prohibitedFields2 = res.error.details.prohibitedFields;
3641
+ setProhibitedFields(prohibitedFields2);
3642
+ }
3307
3643
  },
3308
- options: {
3309
- ...schema?.options,
3310
- ...schema?.pluginOptions,
3311
- ...data.contentType.options
3644
+ dialog: {
3645
+ type: "modal",
3646
+ title: formatMessage({
3647
+ id: "content-manager.containers.list.autoCloneModal.header",
3648
+ defaultMessage: "Duplicate"
3649
+ }),
3650
+ content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3651
+ footer: ({ onClose }) => {
3652
+ return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3653
+ /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3654
+ id: "cancel",
3655
+ defaultMessage: "Cancel"
3656
+ }) }),
3657
+ /* @__PURE__ */ jsx(
3658
+ LinkButton,
3659
+ {
3660
+ tag: NavLink,
3661
+ to: {
3662
+ pathname: `clone/${documentId}`
3663
+ },
3664
+ children: formatMessage({
3665
+ id: "content-manager.containers.list.autoCloneModal.create",
3666
+ defaultMessage: "Create"
3667
+ })
3668
+ }
3669
+ )
3670
+ ] });
3671
+ }
3312
3672
  }
3313
3673
  };
3314
3674
  };
3315
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3316
- return rows.map(
3317
- (row) => row.map((field) => {
3318
- const attribute = attributes[field.name];
3319
- if (!attribute) {
3320
- return null;
3675
+ CloneAction.type = "clone";
3676
+ const StyledDuplicate = styled(Duplicate)`
3677
+ path {
3678
+ fill: currentColor;
3679
+ }
3680
+ `;
3681
+ const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
3682
+ class ContentManagerPlugin {
3683
+ /**
3684
+ * The following properties are the stored ones provided by any plugins registering with
3685
+ * the content-manager. The function calls however, need to be called at runtime in the
3686
+ * application, so instead we collate them and run them later with the complete list incl.
3687
+ * ones already registered & the context of the view.
3688
+ */
3689
+ bulkActions = [...DEFAULT_BULK_ACTIONS];
3690
+ documentActions = [
3691
+ ...DEFAULT_ACTIONS,
3692
+ ...DEFAULT_TABLE_ROW_ACTIONS,
3693
+ ...DEFAULT_HEADER_ACTIONS
3694
+ ];
3695
+ editViewSidePanels = [ActionsPanel];
3696
+ headerActions = [];
3697
+ constructor() {
3698
+ }
3699
+ addEditViewSidePanel(panels) {
3700
+ if (Array.isArray(panels)) {
3701
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3702
+ } else if (typeof panels === "function") {
3703
+ this.editViewSidePanels = panels(this.editViewSidePanels);
3704
+ } else {
3705
+ throw new Error(
3706
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3707
+ panels
3708
+ )}`
3709
+ );
3710
+ }
3711
+ }
3712
+ addDocumentAction(actions2) {
3713
+ if (Array.isArray(actions2)) {
3714
+ this.documentActions = [...this.documentActions, ...actions2];
3715
+ } else if (typeof actions2 === "function") {
3716
+ this.documentActions = actions2(this.documentActions);
3717
+ } else {
3718
+ throw new Error(
3719
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
3720
+ actions2
3721
+ )}`
3722
+ );
3723
+ }
3724
+ }
3725
+ addDocumentHeaderAction(actions2) {
3726
+ if (Array.isArray(actions2)) {
3727
+ this.headerActions = [...this.headerActions, ...actions2];
3728
+ } else if (typeof actions2 === "function") {
3729
+ this.headerActions = actions2(this.headerActions);
3730
+ } else {
3731
+ throw new Error(
3732
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3733
+ actions2
3734
+ )}`
3735
+ );
3736
+ }
3737
+ }
3738
+ addBulkAction(actions2) {
3739
+ if (Array.isArray(actions2)) {
3740
+ this.bulkActions = [...this.bulkActions, ...actions2];
3741
+ } else if (typeof actions2 === "function") {
3742
+ this.bulkActions = actions2(this.bulkActions);
3743
+ } else {
3744
+ throw new Error(
3745
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3746
+ actions2
3747
+ )}`
3748
+ );
3749
+ }
3750
+ }
3751
+ get config() {
3752
+ return {
3753
+ id: PLUGIN_ID,
3754
+ name: "Content Manager",
3755
+ injectionZones: INJECTION_ZONES,
3756
+ apis: {
3757
+ addBulkAction: this.addBulkAction.bind(this),
3758
+ addDocumentAction: this.addDocumentAction.bind(this),
3759
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3760
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3761
+ getBulkActions: () => this.bulkActions,
3762
+ getDocumentActions: () => this.documentActions,
3763
+ getEditViewSidePanels: () => this.editViewSidePanels,
3764
+ getHeaderActions: () => this.headerActions
3321
3765
  }
3322
- const { edit: metadata } = metadatas[field.name];
3323
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3324
- return {
3325
- attribute,
3326
- disabled: !metadata.editable,
3327
- hint: metadata.description,
3328
- label: metadata.label ?? "",
3329
- name: field.name,
3330
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3331
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3332
- schemas,
3333
- components: components?.schemas ?? {}
3334
- }),
3335
- placeholder: metadata.placeholder ?? "",
3336
- required: attribute.required ?? false,
3337
- size: field.size,
3338
- unique: "unique" in attribute ? attribute.unique : false,
3339
- visible: metadata.visible ?? true,
3340
- type: attribute.type
3341
- };
3342
- }).filter((field) => field !== null)
3343
- );
3766
+ };
3767
+ }
3768
+ }
3769
+ const getPrintableType = (value) => {
3770
+ const nativeType = typeof value;
3771
+ if (nativeType === "object") {
3772
+ if (value === null)
3773
+ return "null";
3774
+ if (Array.isArray(value))
3775
+ return "array";
3776
+ if (value instanceof Object && value.constructor.name !== "Object") {
3777
+ return value.constructor.name;
3778
+ }
3779
+ }
3780
+ return nativeType;
3344
3781
  };
3345
- const formatListLayout = (data, {
3346
- schemas,
3347
- schema,
3348
- components
3349
- }) => {
3350
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3351
- (acc, [attribute, metadata]) => {
3352
- return {
3353
- ...acc,
3354
- [attribute]: metadata.list
3355
- };
3356
- },
3357
- {}
3358
- );
3359
- const listAttributes = convertListLayoutToFieldLayouts(
3360
- data.contentType.layouts.list,
3361
- schema?.attributes,
3362
- listMetadatas,
3363
- { configurations: data.components, schemas: components },
3364
- schemas
3365
- );
3782
+ const HistoryAction = ({ model, document }) => {
3783
+ const { formatMessage } = useIntl();
3784
+ const [{ query }] = useQueryParams();
3785
+ const navigate = useNavigate();
3786
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3787
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3788
+ return null;
3789
+ }
3366
3790
  return {
3367
- layout: listAttributes,
3368
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3369
- metadatas: listMetadatas,
3370
- options: {
3371
- ...schema?.options,
3372
- ...schema?.pluginOptions,
3373
- ...data.contentType.options
3374
- }
3791
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3792
+ label: formatMessage({
3793
+ id: "content-manager.history.document-action",
3794
+ defaultMessage: "Content History"
3795
+ }),
3796
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3797
+ disabled: (
3798
+ /**
3799
+ * The user is creating a new document.
3800
+ * It hasn't been saved yet, so there's no history to go to
3801
+ */
3802
+ !document || /**
3803
+ * The document has been created but the current dimension has never been saved.
3804
+ * For example, the user is creating a new locale in an existing document,
3805
+ * so there's no history for the document in that locale
3806
+ */
3807
+ !document.id || /**
3808
+ * History is only available for content types created by the user.
3809
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3810
+ * which start with `admin::` or `plugin::`
3811
+ */
3812
+ !model.startsWith("api::")
3813
+ ),
3814
+ position: "header"
3375
3815
  };
3376
3816
  };
3377
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3378
- return columns.map((name) => {
3379
- const attribute = attributes[name];
3380
- if (!attribute) {
3381
- return null;
3382
- }
3383
- const metadata = metadatas[name];
3384
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3385
- return {
3386
- attribute,
3387
- label: metadata.label ?? "",
3388
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3389
- schemas,
3390
- components: components?.schemas ?? {}
3391
- }),
3392
- name,
3393
- searchable: metadata.searchable ?? true,
3394
- sortable: metadata.sortable ?? true
3395
- };
3396
- }).filter((field) => field !== null);
3817
+ HistoryAction.type = "history";
3818
+ const historyAdmin = {
3819
+ bootstrap(app) {
3820
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3821
+ addDocumentAction((actions2) => {
3822
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3823
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3824
+ return actions2;
3825
+ });
3826
+ }
3827
+ };
3828
+ const initialState = {
3829
+ collectionTypeLinks: [],
3830
+ components: [],
3831
+ fieldSizes: {},
3832
+ models: [],
3833
+ singleTypeLinks: [],
3834
+ isLoading: true
3397
3835
  };
3836
+ const appSlice = createSlice({
3837
+ name: "app",
3838
+ initialState,
3839
+ reducers: {
3840
+ setInitialData(state, action) {
3841
+ const {
3842
+ authorizedCollectionTypeLinks,
3843
+ authorizedSingleTypeLinks,
3844
+ components,
3845
+ contentTypeSchemas,
3846
+ fieldSizes
3847
+ } = action.payload;
3848
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3849
+ ({ isDisplayed }) => isDisplayed
3850
+ );
3851
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3852
+ state.components = components;
3853
+ state.models = contentTypeSchemas;
3854
+ state.fieldSizes = fieldSizes;
3855
+ state.isLoading = false;
3856
+ }
3857
+ }
3858
+ });
3859
+ const { actions, reducer: reducer$1 } = appSlice;
3860
+ const { setInitialData } = actions;
3861
+ const reducer = combineReducers({
3862
+ app: reducer$1
3863
+ });
3398
3864
  const index = {
3399
3865
  register(app) {
3400
3866
  const cm = new ContentManagerPlugin();
@@ -3409,15 +3875,29 @@ const index = {
3409
3875
  defaultMessage: "Content Manager"
3410
3876
  },
3411
3877
  permissions: [],
3412
- Component: () => import("./layout-BinjszSQ.mjs").then((mod) => ({ default: mod.Layout })),
3413
3878
  position: 1
3414
3879
  });
3880
+ app.router.addRoute({
3881
+ path: "content-manager/*",
3882
+ lazy: async () => {
3883
+ const { Layout } = await import("./layout-BNqvLR_b.mjs");
3884
+ return {
3885
+ Component: Layout
3886
+ };
3887
+ },
3888
+ children: routes
3889
+ });
3415
3890
  app.registerPlugin(cm.config);
3416
3891
  },
3892
+ bootstrap(app) {
3893
+ if (typeof historyAdmin.bootstrap === "function") {
3894
+ historyAdmin.bootstrap(app);
3895
+ }
3896
+ },
3417
3897
  async registerTrads({ locales }) {
3418
3898
  const importedTrads = await Promise.all(
3419
3899
  locales.map((locale) => {
3420
- 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-GCOTL6jR.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 }) => {
3900
+ 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-BrCTWlZv.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 }) => {
3421
3901
  return {
3422
3902
  data: prefixPluginTranslations(data, PLUGIN_ID),
3423
3903
  locale
@@ -3438,43 +3918,42 @@ export {
3438
3918
  BulkActionsRenderer as B,
3439
3919
  COLLECTION_TYPES as C,
3440
3920
  DocumentStatus as D,
3441
- extractContentTypeComponents as E,
3442
- DEFAULT_SETTINGS as F,
3443
- convertEditLayoutToFieldLayouts as G,
3921
+ DEFAULT_SETTINGS as E,
3922
+ convertEditLayoutToFieldLayouts as F,
3923
+ useDocument as G,
3444
3924
  HOOKS as H,
3445
3925
  InjectionZone as I,
3446
- useDocument as J,
3447
- index as K,
3448
- useDocumentActions as L,
3926
+ index as J,
3927
+ useDocumentActions as K,
3449
3928
  Panels as P,
3450
3929
  RelativeTime as R,
3451
3930
  SINGLE_TYPES as S,
3452
3931
  TableActions as T,
3453
- useGetAllContentTypeSettingsQuery as a,
3454
- useDoc as b,
3455
- buildValidParams as c,
3456
- contentManagerApi as d,
3457
- useDocumentRBAC as e,
3458
- useDocumentLayout as f,
3932
+ useGetInitialDataQuery as a,
3933
+ useGetAllContentTypeSettingsQuery as b,
3934
+ useDoc as c,
3935
+ buildValidParams as d,
3936
+ contentManagerApi as e,
3937
+ useDocumentRBAC as f,
3459
3938
  getTranslation as g,
3460
- createYupSchema as h,
3461
- Header as i,
3462
- PERMISSIONS as j,
3463
- DocumentRBAC as k,
3464
- DOCUMENT_META_FIELDS as l,
3465
- useDocLayout as m,
3466
- useContentTypeSchema as n,
3939
+ useDocumentLayout as h,
3940
+ createYupSchema as i,
3941
+ Header as j,
3942
+ PERMISSIONS as k,
3943
+ DocumentRBAC as l,
3944
+ DOCUMENT_META_FIELDS as m,
3945
+ useDocLayout as n,
3467
3946
  useGetContentTypeConfigurationQuery as o,
3468
3947
  CREATOR_FIELDS as p,
3469
3948
  getMainField as q,
3470
- routes as r,
3949
+ getDisplayName as r,
3471
3950
  setInitialData as s,
3472
- getDisplayName as t,
3473
- useGetInitialDataQuery as u,
3474
- checkIfAttributeIsDisplayable as v,
3475
- useGetAllDocumentsQuery as w,
3476
- convertListLayoutToFieldLayouts as x,
3477
- capitalise as y,
3478
- useUpdateContentTypeConfigurationMutation as z
3479
- };
3480
- //# sourceMappingURL=index-BaGHmIir.mjs.map
3951
+ checkIfAttributeIsDisplayable as t,
3952
+ useContentTypeSchema as u,
3953
+ useGetAllDocumentsQuery as v,
3954
+ convertListLayoutToFieldLayouts as w,
3955
+ capitalise as x,
3956
+ useUpdateContentTypeConfigurationMutation as y,
3957
+ extractContentTypeComponents as z
3958
+ };
3959
+ //# sourceMappingURL=index-C9TJPyni.mjs.map