@strapi/content-manager 0.0.0-experimental.c3e9d4b26f9fd3d9eb530b5c11f9baa1d09b13ad → 0.0.0-experimental.cb311d9fcfbd8e441f790aea232f0a39bdd90e16

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 (104) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs → ComponentConfigurationPage-D0dyDTwq.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs.map → ComponentConfigurationPage-D0dyDTwq.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js → ComponentConfigurationPage-DL1MHO8i.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js.map → ComponentConfigurationPage-DL1MHO8i.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs → EditConfigurationPage-13b7S5Cq.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs.map → EditConfigurationPage-13b7S5Cq.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js → EditConfigurationPage-CMaOf-A-.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js.map → EditConfigurationPage-CMaOf-A-.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-CTTDHKkQ.js → EditViewPage-BSVmMpRd.js} +45 -45
  11. package/dist/_chunks/EditViewPage-BSVmMpRd.js.map +1 -0
  12. package/dist/_chunks/{EditViewPage-DWb0DE7R.mjs → EditViewPage-C3tIZ8F5.mjs} +46 -46
  13. package/dist/_chunks/EditViewPage-C3tIZ8F5.mjs.map +1 -0
  14. package/dist/_chunks/{Field-DnStdvQw.mjs → Field-BvuT8cGL.mjs} +422 -142
  15. package/dist/_chunks/Field-BvuT8cGL.mjs.map +1 -0
  16. package/dist/_chunks/{Field-C5Z1Ivdv.js → Field-DUCVth4C.js} +421 -141
  17. package/dist/_chunks/Field-DUCVth4C.js.map +1 -0
  18. package/dist/_chunks/{Form-DqGgE55Q.mjs → Form-BZmDNVr9.mjs} +27 -28
  19. package/dist/_chunks/Form-BZmDNVr9.mjs.map +1 -0
  20. package/dist/_chunks/{Form-B81OtW-k.js → Form-Cpl4W1ak.js} +25 -26
  21. package/dist/_chunks/Form-Cpl4W1ak.js.map +1 -0
  22. package/dist/_chunks/{History-DS6-HCYX.mjs → History-Cq_Hrzuu.mjs} +52 -29
  23. package/dist/_chunks/History-Cq_Hrzuu.mjs.map +1 -0
  24. package/dist/_chunks/{History-4NbOq2dX.js → History-D4U2YISB.js} +51 -28
  25. package/dist/_chunks/History-D4U2YISB.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-CpfstlYY.js → ListConfigurationPage-Bny6CdWe.js} +48 -47
  27. package/dist/_chunks/ListConfigurationPage-Bny6CdWe.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-DQJJltko.mjs → ListConfigurationPage-W-KQHmBv.mjs} +49 -49
  29. package/dist/_chunks/ListConfigurationPage-W-KQHmBv.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-nQrOQuVo.mjs → ListViewPage-HBBnJa8K.mjs} +67 -70
  31. package/dist/_chunks/ListViewPage-HBBnJa8K.mjs.map +1 -0
  32. package/dist/_chunks/{ListViewPage-CA3I75m5.js → ListViewPage-O8F1pBJo.js} +65 -68
  33. package/dist/_chunks/ListViewPage-O8F1pBJo.js.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs → NoContentTypePage-B-gIhHWM.mjs} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs.map → NoContentTypePage-B-gIhHWM.mjs.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js → NoContentTypePage-CQWChGPw.js} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js.map → NoContentTypePage-CQWChGPw.js.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-CO2MK200.js → NoPermissionsPage-CY46zxnM.js} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-CO2MK200.js.map → NoPermissionsPage-CY46zxnM.js.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs → NoPermissionsPage-XhOPl8wx.mjs} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs.map → NoPermissionsPage-XhOPl8wx.mjs.map} +1 -1
  42. package/dist/_chunks/{Relations-DG2jnOcr.js → Relations-C4gGfZRv.js} +3 -3
  43. package/dist/_chunks/Relations-C4gGfZRv.js.map +1 -0
  44. package/dist/_chunks/{Relations-BDRl99Ux.mjs → Relations-vFZ6Wasg.mjs} +3 -3
  45. package/dist/_chunks/Relations-vFZ6Wasg.mjs.map +1 -0
  46. package/dist/_chunks/{en-Ux26r5pl.mjs → en-BrCTWlZv.mjs} +5 -4
  47. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  48. package/dist/_chunks/{en-fbKQxLGn.js → en-uOUIxfcQ.js} +5 -4
  49. package/dist/_chunks/{en-fbKQxLGn.js.map → en-uOUIxfcQ.js.map} +1 -1
  50. package/dist/_chunks/{index-BZoNZMXL.js → index-5EMXLEM_.js} +384 -388
  51. package/dist/_chunks/index-5EMXLEM_.js.map +1 -0
  52. package/dist/_chunks/{index-Drt2DN7v.mjs → index-Dpxg3ctD.mjs} +399 -403
  53. package/dist/_chunks/index-Dpxg3ctD.mjs.map +1 -0
  54. package/dist/_chunks/{layout-BzAbmoO6.mjs → layout-C0INpKap.mjs} +22 -10
  55. package/dist/_chunks/layout-C0INpKap.mjs.map +1 -0
  56. package/dist/_chunks/{layout-DEYBqgF1.js → layout-P3eKO1Qy.js} +20 -8
  57. package/dist/_chunks/layout-P3eKO1Qy.js.map +1 -0
  58. package/dist/_chunks/{relations-D0eZ4VWw.js → relations-B1y0K6LE.js} +2 -2
  59. package/dist/_chunks/{relations-D0eZ4VWw.js.map → relations-B1y0K6LE.js.map} +1 -1
  60. package/dist/_chunks/{relations-D26zVRdi.mjs → relations-FBRRBWeO.mjs} +2 -2
  61. package/dist/_chunks/{relations-D26zVRdi.mjs.map → relations-FBRRBWeO.mjs.map} +1 -1
  62. package/dist/admin/index.js +1 -1
  63. package/dist/admin/index.mjs +4 -4
  64. package/dist/admin/src/history/index.d.ts +3 -0
  65. package/dist/admin/src/index.d.ts +1 -0
  66. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  67. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  68. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  69. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +2 -10
  70. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  71. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  72. package/dist/server/index.js +137 -87
  73. package/dist/server/index.js.map +1 -1
  74. package/dist/server/index.mjs +138 -88
  75. package/dist/server/index.mjs.map +1 -1
  76. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  77. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  78. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  79. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  80. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  81. package/dist/server/src/history/services/utils.d.ts +1 -1
  82. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  83. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  84. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  85. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  86. package/package.json +8 -8
  87. package/dist/_chunks/EditViewPage-CTTDHKkQ.js.map +0 -1
  88. package/dist/_chunks/EditViewPage-DWb0DE7R.mjs.map +0 -1
  89. package/dist/_chunks/Field-C5Z1Ivdv.js.map +0 -1
  90. package/dist/_chunks/Field-DnStdvQw.mjs.map +0 -1
  91. package/dist/_chunks/Form-B81OtW-k.js.map +0 -1
  92. package/dist/_chunks/Form-DqGgE55Q.mjs.map +0 -1
  93. package/dist/_chunks/History-4NbOq2dX.js.map +0 -1
  94. package/dist/_chunks/History-DS6-HCYX.mjs.map +0 -1
  95. package/dist/_chunks/ListConfigurationPage-CpfstlYY.js.map +0 -1
  96. package/dist/_chunks/ListConfigurationPage-DQJJltko.mjs.map +0 -1
  97. package/dist/_chunks/ListViewPage-CA3I75m5.js.map +0 -1
  98. package/dist/_chunks/ListViewPage-nQrOQuVo.mjs.map +0 -1
  99. package/dist/_chunks/Relations-BDRl99Ux.mjs.map +0 -1
  100. package/dist/_chunks/Relations-DG2jnOcr.js.map +0 -1
  101. package/dist/_chunks/index-BZoNZMXL.js.map +0 -1
  102. package/dist/_chunks/index-Drt2DN7v.mjs.map +0 -1
  103. package/dist/_chunks/layout-BzAbmoO6.mjs.map +0 -1
  104. package/dist/_chunks/layout-DEYBqgF1.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, 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, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, 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, ModalFooter, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Button, Menu, 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) {
@@ -1184,7 +1205,6 @@ const useDocumentActions = () => {
1184
1205
  sourceId
1185
1206
  });
1186
1207
  if ("error" in res) {
1187
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1188
1208
  return { error: res.error };
1189
1209
  }
1190
1210
  toggleNotification({
@@ -1265,7 +1285,7 @@ const useDocumentActions = () => {
1265
1285
  };
1266
1286
  };
1267
1287
  const ProtectedHistoryPage = lazy(
1268
- () => import("./History-DS6-HCYX.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1288
+ () => import("./History-Cq_Hrzuu.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1269
1289
  );
1270
1290
  const routes$1 = [
1271
1291
  {
@@ -1278,31 +1298,31 @@ const routes$1 = [
1278
1298
  }
1279
1299
  ];
1280
1300
  const ProtectedEditViewPage = lazy(
1281
- () => import("./EditViewPage-DWb0DE7R.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1301
+ () => import("./EditViewPage-C3tIZ8F5.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1282
1302
  );
1283
1303
  const ProtectedListViewPage = lazy(
1284
- () => import("./ListViewPage-nQrOQuVo.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1304
+ () => import("./ListViewPage-HBBnJa8K.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1285
1305
  );
1286
1306
  const ProtectedListConfiguration = lazy(
1287
- () => import("./ListConfigurationPage-DQJJltko.mjs").then((mod) => ({
1307
+ () => import("./ListConfigurationPage-W-KQHmBv.mjs").then((mod) => ({
1288
1308
  default: mod.ProtectedListConfiguration
1289
1309
  }))
1290
1310
  );
1291
1311
  const ProtectedEditConfigurationPage = lazy(
1292
- () => import("./EditConfigurationPage-CcOoD26O.mjs").then((mod) => ({
1312
+ () => import("./EditConfigurationPage-13b7S5Cq.mjs").then((mod) => ({
1293
1313
  default: mod.ProtectedEditConfigurationPage
1294
1314
  }))
1295
1315
  );
1296
1316
  const ProtectedComponentConfigurationPage = lazy(
1297
- () => import("./ComponentConfigurationPage-BMajAl1u.mjs").then((mod) => ({
1317
+ () => import("./ComponentConfigurationPage-D0dyDTwq.mjs").then((mod) => ({
1298
1318
  default: mod.ProtectedComponentConfigurationPage
1299
1319
  }))
1300
1320
  );
1301
1321
  const NoPermissions = lazy(
1302
- () => import("./NoPermissionsPage-fOIkQM0v.mjs").then((mod) => ({ default: mod.NoPermissions }))
1322
+ () => import("./NoPermissionsPage-XhOPl8wx.mjs").then((mod) => ({ default: mod.NoPermissions }))
1303
1323
  );
1304
1324
  const NoContentType = lazy(
1305
- () => import("./NoContentTypePage-DbnHE22g.mjs").then((mod) => ({ default: mod.NoContentType }))
1325
+ () => import("./NoContentTypePage-B-gIhHWM.mjs").then((mod) => ({ default: mod.NoContentType }))
1306
1326
  );
1307
1327
  const CollectionTypePages = () => {
1308
1328
  const { collectionType } = useParams();
@@ -1416,7 +1436,7 @@ const DocumentActionButton = (action) => {
1416
1436
  /* @__PURE__ */ jsx(
1417
1437
  Button,
1418
1438
  {
1419
- flex: 1,
1439
+ flex: "auto",
1420
1440
  startIcon: action.icon,
1421
1441
  disabled: action.disabled,
1422
1442
  onClick: handleClick(action),
@@ -1429,7 +1449,7 @@ const DocumentActionButton = (action) => {
1429
1449
  DocumentActionConfirmDialog,
1430
1450
  {
1431
1451
  ...action.dialog,
1432
- variant: action.variant,
1452
+ variant: action.dialog?.variant ?? action.variant,
1433
1453
  isOpen: dialogId === action.id,
1434
1454
  onClose: handleClose
1435
1455
  }
@@ -1486,9 +1506,9 @@ const DocumentActionsMenu = ({
1486
1506
  disabled: isDisabled,
1487
1507
  size: "S",
1488
1508
  endIcon: null,
1489
- paddingTop: "7px",
1490
- paddingLeft: "9px",
1491
- paddingRight: "9px",
1509
+ paddingTop: "4px",
1510
+ paddingLeft: "7px",
1511
+ paddingRight: "7px",
1492
1512
  variant,
1493
1513
  children: [
1494
1514
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1508,10 +1528,18 @@ const DocumentActionsMenu = ({
1508
1528
  onSelect: handleClick(action),
1509
1529
  display: "block",
1510
1530
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1511
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1512
- action.icon,
1513
- action.label
1514
- ] }),
1531
+ /* @__PURE__ */ jsxs(
1532
+ Flex,
1533
+ {
1534
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1535
+ gap: 2,
1536
+ tag: "span",
1537
+ children: [
1538
+ /* @__PURE__ */ jsx("span", { children: action.icon }),
1539
+ action.label
1540
+ ]
1541
+ }
1542
+ ),
1515
1543
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1516
1544
  Flex,
1517
1545
  {
@@ -1592,22 +1620,20 @@ const DocumentActionConfirmDialog = ({
1592
1620
  }
1593
1621
  onClose();
1594
1622
  };
1595
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
1596
- /* @__PURE__ */ jsx(DialogBody, { children: content }),
1597
- /* @__PURE__ */ jsx(
1598
- DialogFooter,
1599
- {
1600
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1601
- id: "app.components.Button.cancel",
1602
- defaultMessage: "Cancel"
1603
- }) }),
1604
- endAction: /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1605
- id: "app.components.Button.confirm",
1606
- defaultMessage: "Confirm"
1607
- }) })
1608
- }
1609
- )
1610
- ] });
1623
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1624
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1625
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1626
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1627
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1628
+ id: "app.components.Button.cancel",
1629
+ defaultMessage: "Cancel"
1630
+ }) }) }),
1631
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1632
+ id: "app.components.Button.confirm",
1633
+ defaultMessage: "Confirm"
1634
+ }) })
1635
+ ] })
1636
+ ] }) });
1611
1637
  };
1612
1638
  const DocumentActionModal = ({
1613
1639
  isOpen,
@@ -1617,34 +1643,17 @@ const DocumentActionModal = ({
1617
1643
  content: Content,
1618
1644
  onModalClose
1619
1645
  }) => {
1620
- const id = React.useId();
1621
- if (!isOpen) {
1622
- return null;
1623
- }
1624
1646
  const handleClose = () => {
1625
1647
  if (onClose) {
1626
1648
  onClose();
1627
1649
  }
1628
1650
  onModalClose();
1629
1651
  };
1630
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1631
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1632
- /* @__PURE__ */ jsx(ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1633
- /* @__PURE__ */ jsx(
1634
- Box,
1635
- {
1636
- paddingTop: 4,
1637
- paddingBottom: 4,
1638
- paddingLeft: 5,
1639
- paddingRight: 5,
1640
- borderWidth: "1px 0 0 0",
1641
- borderStyle: "solid",
1642
- borderColor: "neutral150",
1643
- background: "neutral100",
1644
- children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1645
- }
1646
- )
1647
- ] });
1652
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1653
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1654
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1655
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1656
+ ] }) });
1648
1657
  };
1649
1658
  const PublishAction$1 = ({
1650
1659
  activeTab,
@@ -1665,6 +1674,12 @@ const PublishAction$1 = ({
1665
1674
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1666
1675
  );
1667
1676
  const { publish } = useDocumentActions();
1677
+ const [
1678
+ countDraftRelations,
1679
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1680
+ ] = useLazyGetDraftRelationCountQuery();
1681
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1682
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1668
1683
  const [{ query, rawQuery }] = useQueryParams();
1669
1684
  const params = React.useMemo(() => buildValidParams(query), [query]);
1670
1685
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1673,10 +1688,101 @@ const PublishAction$1 = ({
1673
1688
  const validate = useForm("PublishAction", (state) => state.validate);
1674
1689
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1675
1690
  const formValues = useForm("PublishAction", ({ values }) => values);
1691
+ React.useEffect(() => {
1692
+ if (isErrorDraftRelations) {
1693
+ toggleNotification({
1694
+ type: "danger",
1695
+ message: formatMessage({
1696
+ id: getTranslation("error.records.fetch-draft-relatons"),
1697
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1698
+ })
1699
+ });
1700
+ }
1701
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1702
+ React.useEffect(() => {
1703
+ const localDraftRelations = /* @__PURE__ */ new Set();
1704
+ const extractDraftRelations = (data) => {
1705
+ const relations = data.connect || [];
1706
+ relations.forEach((relation) => {
1707
+ if (relation.status === "draft") {
1708
+ localDraftRelations.add(relation.id);
1709
+ }
1710
+ });
1711
+ };
1712
+ const traverseAndExtract = (data) => {
1713
+ Object.entries(data).forEach(([key, value]) => {
1714
+ if (key === "connect" && Array.isArray(value)) {
1715
+ extractDraftRelations({ connect: value });
1716
+ } else if (typeof value === "object" && value !== null) {
1717
+ traverseAndExtract(value);
1718
+ }
1719
+ });
1720
+ };
1721
+ if (!documentId || modified) {
1722
+ traverseAndExtract(formValues);
1723
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1724
+ }
1725
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1726
+ React.useEffect(() => {
1727
+ if (documentId) {
1728
+ const fetchDraftRelationsCount = async () => {
1729
+ const { data, error } = await countDraftRelations({
1730
+ collectionType,
1731
+ model,
1732
+ documentId,
1733
+ params
1734
+ });
1735
+ if (error) {
1736
+ throw error;
1737
+ }
1738
+ if (data) {
1739
+ setServerCountOfDraftRelations(data.data);
1740
+ }
1741
+ };
1742
+ fetchDraftRelationsCount();
1743
+ }
1744
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1676
1745
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1677
1746
  if (!schema?.options?.draftAndPublish) {
1678
1747
  return null;
1679
1748
  }
1749
+ const performPublish = async () => {
1750
+ setSubmitting(true);
1751
+ try {
1752
+ const { errors } = await validate();
1753
+ if (errors) {
1754
+ toggleNotification({
1755
+ type: "danger",
1756
+ message: formatMessage({
1757
+ id: "content-manager.validation.error",
1758
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1759
+ })
1760
+ });
1761
+ return;
1762
+ }
1763
+ const res = await publish(
1764
+ {
1765
+ collectionType,
1766
+ model,
1767
+ documentId,
1768
+ params
1769
+ },
1770
+ formValues
1771
+ );
1772
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1773
+ navigate({
1774
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1775
+ search: rawQuery
1776
+ });
1777
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1778
+ setErrors(formatValidationErrors(res.error));
1779
+ }
1780
+ } finally {
1781
+ setSubmitting(false);
1782
+ }
1783
+ };
1784
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1785
+ const hasDraftRelations = totalDraftRelations > 0;
1680
1786
  return {
1681
1787
  /**
1682
1788
  * Disabled when:
@@ -1686,49 +1792,39 @@ const PublishAction$1 = ({
1686
1792
  * - the document is already published & not modified
1687
1793
  * - the document is being created & not modified
1688
1794
  * - the user doesn't have the permission to publish
1689
- * - the user doesn't have the permission to create a new document
1690
- * - the user doesn't have the permission to update the document
1691
1795
  */
1692
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1796
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1693
1797
  label: formatMessage({
1694
1798
  id: "app.utils.publish",
1695
1799
  defaultMessage: "Publish"
1696
1800
  }),
1697
1801
  onClick: async () => {
1698
- setSubmitting(true);
1699
- try {
1700
- const { errors } = await validate();
1701
- if (errors) {
1702
- toggleNotification({
1703
- type: "danger",
1704
- message: formatMessage({
1705
- id: "content-manager.validation.error",
1706
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1707
- })
1708
- });
1709
- return;
1710
- }
1711
- const res = await publish(
1712
- {
1713
- collectionType,
1714
- model,
1715
- documentId,
1716
- params
1717
- },
1718
- formValues
1719
- );
1720
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1721
- navigate({
1722
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1723
- search: rawQuery
1724
- });
1725
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1726
- setErrors(formatValidationErrors(res.error));
1802
+ if (hasDraftRelations) {
1803
+ return;
1804
+ }
1805
+ await performPublish();
1806
+ },
1807
+ dialog: hasDraftRelations ? {
1808
+ type: "dialog",
1809
+ variant: "danger",
1810
+ footer: null,
1811
+ title: formatMessage({
1812
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1813
+ defaultMessage: "Confirmation"
1814
+ }),
1815
+ content: formatMessage(
1816
+ {
1817
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1818
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1819
+ },
1820
+ {
1821
+ count: totalDraftRelations
1727
1822
  }
1728
- } finally {
1729
- setSubmitting(false);
1823
+ ),
1824
+ onConfirm: async () => {
1825
+ await performPublish();
1730
1826
  }
1731
- }
1827
+ } : void 0
1732
1828
  };
1733
1829
  };
1734
1830
  PublishAction$1.type = "publish";
@@ -1744,7 +1840,7 @@ const UpdateAction = ({
1744
1840
  const cloneMatch = useMatch(CLONE_PATH);
1745
1841
  const isCloning = cloneMatch !== null;
1746
1842
  const { formatMessage } = useIntl();
1747
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1843
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1748
1844
  canCreate: canCreate2,
1749
1845
  canUpdate: canUpdate2
1750
1846
  }));
@@ -1764,10 +1860,8 @@ const UpdateAction = ({
1764
1860
  * - the form is submitting
1765
1861
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1766
1862
  * - the active tab is the published tab
1767
- * - the user doesn't have the permission to create a new document
1768
- * - the user doesn't have the permission to update the document
1769
1863
  */
1770
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1864
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1771
1865
  label: formatMessage({
1772
1866
  id: "content-manager.containers.Edit.save",
1773
1867
  defaultMessage: "Save"
@@ -1796,10 +1890,13 @@ const UpdateAction = ({
1796
1890
  document
1797
1891
  );
1798
1892
  if ("data" in res) {
1799
- navigate({
1800
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1801
- search: rawQuery
1802
- });
1893
+ navigate(
1894
+ {
1895
+ pathname: `../${res.data.documentId}`,
1896
+ search: rawQuery
1897
+ },
1898
+ { relative: "path" }
1899
+ );
1803
1900
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1804
1901
  setErrors(formatValidationErrors(res.error));
1805
1902
  }
@@ -1827,10 +1924,13 @@ const UpdateAction = ({
1827
1924
  document
1828
1925
  );
1829
1926
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1830
- navigate({
1831
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1832
- search: rawQuery
1833
- });
1927
+ navigate(
1928
+ {
1929
+ pathname: `../${res.data.documentId}`,
1930
+ search: rawQuery
1931
+ },
1932
+ { replace: true, relative: "path" }
1933
+ );
1834
1934
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1835
1935
  setErrors(formatValidationErrors(res.error));
1836
1936
  }
@@ -1862,10 +1962,8 @@ const UnpublishAction$1 = ({
1862
1962
  const { toggleNotification } = useNotification();
1863
1963
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1864
1964
  const isDocumentModified = document?.status === "modified";
1865
- const handleChange = (e) => {
1866
- if ("value" in e.target) {
1867
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1868
- }
1965
+ const handleChange = (value) => {
1966
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1869
1967
  };
1870
1968
  if (!schema?.options?.draftAndPublish) {
1871
1969
  return null;
@@ -1915,40 +2013,24 @@ const UnpublishAction$1 = ({
1915
2013
  }) })
1916
2014
  ] }),
1917
2015
  /* @__PURE__ */ jsxs(
1918
- Flex,
2016
+ Radio.Group,
1919
2017
  {
1920
- onChange: handleChange,
1921
- direction: "column",
1922
- alignItems: "flex-start",
1923
- tag: "fieldset",
1924
- borderWidth: 0,
1925
- gap: 3,
2018
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2019
+ name: "discard-options",
2020
+ "aria-label": formatMessage({
2021
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2022
+ defaultMessage: "Choose an option to unpublish the document."
2023
+ }),
2024
+ onValueChange: handleChange,
1926
2025
  children: [
1927
- /* @__PURE__ */ jsx(VisuallyHidden, { tag: "legend" }),
1928
- /* @__PURE__ */ jsx(
1929
- Radio,
1930
- {
1931
- checked: shouldKeepDraft,
1932
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1933
- name: "discard-options",
1934
- children: formatMessage({
1935
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1936
- defaultMessage: "Keep draft"
1937
- })
1938
- }
1939
- ),
1940
- /* @__PURE__ */ jsx(
1941
- Radio,
1942
- {
1943
- checked: !shouldKeepDraft,
1944
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1945
- name: "discard-options",
1946
- children: formatMessage({
1947
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1948
- defaultMessage: "Replace draft"
1949
- })
1950
- }
1951
- )
2026
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2027
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2028
+ defaultMessage: "Keep draft"
2029
+ }) }),
2030
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2031
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2032
+ defaultMessage: "Replace draft"
2033
+ }) })
1952
2034
  ]
1953
2035
  }
1954
2036
  )
@@ -2094,23 +2176,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2094
2176
  id: "content-manager.containers.edit.title.new",
2095
2177
  defaultMessage: "Create an entry"
2096
2178
  }) : documentTitle;
2097
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2179
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2098
2180
  /* @__PURE__ */ jsx(BackButton, {}),
2099
- /* @__PURE__ */ jsxs(
2100
- Flex,
2101
- {
2102
- width: "100%",
2103
- justifyContent: "space-between",
2104
- paddingTop: 1,
2105
- gap: "80px",
2106
- alignItems: "flex-start",
2107
- children: [
2108
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2109
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2110
- ]
2111
- }
2112
- ),
2113
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2181
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2182
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2183
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2184
+ ] }),
2185
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2114
2186
  ] });
2115
2187
  };
2116
2188
  const HeaderToolbar = () => {
@@ -2801,30 +2873,23 @@ const ConfirmBulkActionDialog = ({
2801
2873
  endAction
2802
2874
  }) => {
2803
2875
  const { formatMessage } = useIntl();
2804
- return /* @__PURE__ */ jsxs(
2805
- Dialog,
2806
- {
2807
- onClose: onToggleDialog,
2808
- title: formatMessage({
2809
- id: "app.components.ConfirmDialog.title",
2810
- defaultMessage: "Confirmation"
2811
- }),
2812
- isOpen,
2813
- children: [
2814
- /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2815
- /* @__PURE__ */ jsx(
2816
- DialogFooter,
2817
- {
2818
- startAction: /* @__PURE__ */ jsx(Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2819
- id: "app.components.Button.cancel",
2820
- defaultMessage: "Cancel"
2821
- }) }),
2822
- endAction
2823
- }
2824
- )
2825
- ]
2826
- }
2827
- );
2876
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2877
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2878
+ id: "app.components.ConfirmDialog.title",
2879
+ defaultMessage: "Confirmation"
2880
+ }) }),
2881
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2882
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2883
+ dialogBody
2884
+ ] }) }),
2885
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2886
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2887
+ id: "app.components.Button.cancel",
2888
+ defaultMessage: "Cancel"
2889
+ }) }) }),
2890
+ endAction
2891
+ ] })
2892
+ ] }) });
2828
2893
  };
2829
2894
  const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2830
2895
  const ConfirmDialogPublishAll = ({
@@ -2929,7 +2994,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2929
2994
  )
2930
2995
  );
2931
2996
  } else {
2932
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
2997
+ messages.push(
2998
+ ...formatErrorMessages(
2999
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3000
+ value,
3001
+ currentKey,
3002
+ formatMessage
3003
+ )
3004
+ );
2933
3005
  }
2934
3006
  } else {
2935
3007
  messages.push(
@@ -3166,7 +3238,7 @@ const SelectedEntriesModalContent = ({
3166
3238
  );
3167
3239
  };
3168
3240
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3169
- /* @__PURE__ */ jsxs(ModalBody, { children: [
3241
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3170
3242
  /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3171
3243
  /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3172
3244
  SelectedEntriesTableContent,
@@ -3178,27 +3250,24 @@ const SelectedEntriesModalContent = ({
3178
3250
  }
3179
3251
  ) })
3180
3252
  ] }),
3181
- /* @__PURE__ */ jsx(
3182
- ModalFooter,
3183
- {
3184
- startActions: /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3185
- id: "app.components.Button.cancel",
3186
- defaultMessage: "Cancel"
3187
- }) }),
3188
- endActions: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3189
- /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3190
- /* @__PURE__ */ jsx(
3191
- Button,
3192
- {
3193
- onClick: toggleDialog,
3194
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3195
- loading: isSubmittingForm,
3196
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3197
- }
3198
- )
3199
- ] })
3200
- }
3201
- ),
3253
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3254
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3255
+ id: "app.components.Button.cancel",
3256
+ defaultMessage: "Cancel"
3257
+ }) }),
3258
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3259
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3260
+ /* @__PURE__ */ jsx(
3261
+ Button,
3262
+ {
3263
+ onClick: toggleDialog,
3264
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3265
+ loading: isSubmittingForm,
3266
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3267
+ }
3268
+ )
3269
+ ] })
3270
+ ] }),
3202
3271
  /* @__PURE__ */ jsx(
3203
3272
  ConfirmDialogPublishAll,
3204
3273
  {
@@ -3263,143 +3332,10 @@ const BulkActionsRenderer = () => {
3263
3332
  documents: selectedRows
3264
3333
  },
3265
3334
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3266
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(BulkActionAction, { ...action }, action.id))
3335
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3267
3336
  }
3268
3337
  ) });
3269
3338
  };
3270
- const BulkActionAction = (action) => {
3271
- const [dialogId, setDialogId] = React.useState(null);
3272
- const { toggleNotification } = useNotification();
3273
- const handleClick = (action2) => (e) => {
3274
- const { onClick, dialog, id } = action2;
3275
- if (onClick) {
3276
- onClick(e);
3277
- }
3278
- if (dialog) {
3279
- switch (dialog.type) {
3280
- case "notification":
3281
- toggleNotification({
3282
- title: dialog.title,
3283
- message: dialog.content,
3284
- type: dialog.status,
3285
- timeout: dialog.timeout,
3286
- onClose: dialog.onClose
3287
- });
3288
- break;
3289
- case "dialog":
3290
- case "modal": {
3291
- e.preventDefault();
3292
- setDialogId(id);
3293
- }
3294
- }
3295
- }
3296
- };
3297
- const handleClose = () => {
3298
- setDialogId(null);
3299
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3300
- action.dialog.onClose();
3301
- }
3302
- };
3303
- return /* @__PURE__ */ jsxs(Fragment, { children: [
3304
- /* @__PURE__ */ jsx(
3305
- Button,
3306
- {
3307
- disabled: action.disabled,
3308
- startIcon: action.icon,
3309
- variant: action.variant,
3310
- onClick: handleClick(action),
3311
- children: action.label
3312
- }
3313
- ),
3314
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
3315
- BulkActionConfirmDialog,
3316
- {
3317
- ...action.dialog,
3318
- variant: action.variant,
3319
- isOpen: dialogId === action.id,
3320
- onClose: handleClose
3321
- }
3322
- ) : null,
3323
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
3324
- BulkActionModal,
3325
- {
3326
- ...action.dialog,
3327
- onModalClose: handleClose,
3328
- isOpen: dialogId === action.id
3329
- }
3330
- ) : null
3331
- ] });
3332
- };
3333
- const BulkActionConfirmDialog = ({
3334
- onClose,
3335
- onCancel,
3336
- onConfirm,
3337
- title,
3338
- content,
3339
- confirmButton,
3340
- isOpen,
3341
- variant = "secondary"
3342
- }) => {
3343
- const { formatMessage } = useIntl();
3344
- const handleClose = async () => {
3345
- if (onCancel) {
3346
- await onCancel();
3347
- }
3348
- onClose();
3349
- };
3350
- const handleConfirm = async () => {
3351
- if (onConfirm) {
3352
- await onConfirm();
3353
- }
3354
- onClose();
3355
- };
3356
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
3357
- /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
3358
- /* @__PURE__ */ jsx(
3359
- DialogFooter,
3360
- {
3361
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3362
- id: "app.components.Button.cancel",
3363
- defaultMessage: "Cancel"
3364
- }) }),
3365
- endAction: /* @__PURE__ */ jsx(
3366
- Button,
3367
- {
3368
- onClick: handleConfirm,
3369
- variant: variant === "danger-light" ? variant : "secondary",
3370
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
3371
- children: confirmButton ? confirmButton : formatMessage({
3372
- id: "app.components.Button.confirm",
3373
- defaultMessage: "Confirm"
3374
- })
3375
- }
3376
- )
3377
- }
3378
- )
3379
- ] });
3380
- };
3381
- const BulkActionModal = ({
3382
- isOpen,
3383
- title,
3384
- onClose,
3385
- content: Content,
3386
- onModalClose
3387
- }) => {
3388
- const id = React.useId();
3389
- if (!isOpen) {
3390
- return null;
3391
- }
3392
- const handleClose = () => {
3393
- if (onClose) {
3394
- onClose();
3395
- }
3396
- onModalClose();
3397
- };
3398
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3399
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3400
- /* @__PURE__ */ jsx(Content, { onClose: handleClose })
3401
- ] });
3402
- };
3403
3339
  const DeleteAction = ({ documents, model }) => {
3404
3340
  const { formatMessage } = useIntl();
3405
3341
  const { schema: contentType } = useDoc();
@@ -3432,6 +3368,7 @@ const DeleteAction = ({ documents, model }) => {
3432
3368
  defaultMessage: "Confirmation"
3433
3369
  }),
3434
3370
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3371
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3435
3372
  /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3436
3373
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3437
3374
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3481,6 +3418,7 @@ const UnpublishAction = ({ documents, model }) => {
3481
3418
  defaultMessage: "Confirmation"
3482
3419
  }),
3483
3420
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3421
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3484
3422
  /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3485
3423
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3486
3424
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3726,8 +3664,7 @@ class ContentManagerPlugin {
3726
3664
  documentActions = [
3727
3665
  ...DEFAULT_ACTIONS,
3728
3666
  ...DEFAULT_TABLE_ROW_ACTIONS,
3729
- ...DEFAULT_HEADER_ACTIONS,
3730
- HistoryAction
3667
+ ...DEFAULT_HEADER_ACTIONS
3731
3668
  ];
3732
3669
  editViewSidePanels = [ActionsPanel];
3733
3670
  headerActions = [];
@@ -3816,6 +3753,52 @@ const getPrintableType = (value) => {
3816
3753
  }
3817
3754
  return nativeType;
3818
3755
  };
3756
+ const HistoryAction = ({ model, document }) => {
3757
+ const { formatMessage } = useIntl();
3758
+ const [{ query }] = useQueryParams();
3759
+ const navigate = useNavigate();
3760
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3761
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3762
+ return null;
3763
+ }
3764
+ return {
3765
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3766
+ label: formatMessage({
3767
+ id: "content-manager.history.document-action",
3768
+ defaultMessage: "Content History"
3769
+ }),
3770
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3771
+ disabled: (
3772
+ /**
3773
+ * The user is creating a new document.
3774
+ * It hasn't been saved yet, so there's no history to go to
3775
+ */
3776
+ !document || /**
3777
+ * The document has been created but the current dimension has never been saved.
3778
+ * For example, the user is creating a new locale in an existing document,
3779
+ * so there's no history for the document in that locale
3780
+ */
3781
+ !document.id || /**
3782
+ * History is only available for content types created by the user.
3783
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3784
+ * which start with `admin::` or `plugin::`
3785
+ */
3786
+ !model.startsWith("api::")
3787
+ ),
3788
+ position: "header"
3789
+ };
3790
+ };
3791
+ HistoryAction.type = "history";
3792
+ const historyAdmin = {
3793
+ bootstrap(app) {
3794
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3795
+ addDocumentAction((actions2) => {
3796
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3797
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3798
+ return actions2;
3799
+ });
3800
+ }
3801
+ };
3819
3802
  const initialState = {
3820
3803
  collectionTypeLinks: [],
3821
3804
  components: [],
@@ -3866,15 +3849,29 @@ const index = {
3866
3849
  defaultMessage: "Content Manager"
3867
3850
  },
3868
3851
  permissions: [],
3869
- Component: () => import("./layout-BzAbmoO6.mjs").then((mod) => ({ default: mod.Layout })),
3870
3852
  position: 1
3871
3853
  });
3854
+ app.router.addRoute({
3855
+ path: "content-manager/*",
3856
+ lazy: async () => {
3857
+ const { Layout } = await import("./layout-C0INpKap.mjs");
3858
+ return {
3859
+ Component: Layout
3860
+ };
3861
+ },
3862
+ children: routes
3863
+ });
3872
3864
  app.registerPlugin(cm.config);
3873
3865
  },
3866
+ bootstrap(app) {
3867
+ if (typeof historyAdmin.bootstrap === "function") {
3868
+ historyAdmin.bootstrap(app);
3869
+ }
3870
+ },
3874
3871
  async registerTrads({ locales }) {
3875
3872
  const importedTrads = await Promise.all(
3876
3873
  locales.map((locale) => {
3877
- 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-Ux26r5pl.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 }) => {
3874
+ 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 }) => {
3878
3875
  return {
3879
3876
  data: prefixPluginTranslations(data, PLUGIN_ID),
3880
3877
  locale
@@ -3895,14 +3892,13 @@ export {
3895
3892
  BulkActionsRenderer as B,
3896
3893
  COLLECTION_TYPES as C,
3897
3894
  DocumentStatus as D,
3898
- extractContentTypeComponents as E,
3899
- DEFAULT_SETTINGS as F,
3900
- convertEditLayoutToFieldLayouts as G,
3895
+ DEFAULT_SETTINGS as E,
3896
+ convertEditLayoutToFieldLayouts as F,
3897
+ useDocument as G,
3901
3898
  HOOKS as H,
3902
3899
  InjectionZone as I,
3903
- useDocument as J,
3904
- index as K,
3905
- useDocumentActions as L,
3900
+ index as J,
3901
+ useDocumentActions as K,
3906
3902
  Panels as P,
3907
3903
  RelativeTime as R,
3908
3904
  SINGLE_TYPES as S,
@@ -3924,14 +3920,14 @@ export {
3924
3920
  useGetContentTypeConfigurationQuery as o,
3925
3921
  CREATOR_FIELDS as p,
3926
3922
  getMainField as q,
3927
- routes as r,
3923
+ getDisplayName as r,
3928
3924
  setInitialData as s,
3929
- getDisplayName as t,
3925
+ checkIfAttributeIsDisplayable as t,
3930
3926
  useContentTypeSchema as u,
3931
- checkIfAttributeIsDisplayable as v,
3932
- useGetAllDocumentsQuery as w,
3933
- convertListLayoutToFieldLayouts as x,
3934
- capitalise as y,
3935
- useUpdateContentTypeConfigurationMutation as z
3927
+ useGetAllDocumentsQuery as v,
3928
+ convertListLayoutToFieldLayouts as w,
3929
+ capitalise as x,
3930
+ useUpdateContentTypeConfigurationMutation as y,
3931
+ extractContentTypeComponents as z
3936
3932
  };
3937
- //# sourceMappingURL=index-Drt2DN7v.mjs.map
3933
+ //# sourceMappingURL=index-Dpxg3ctD.mjs.map