@strapi/content-manager 0.0.0-experimental.25e22c6cc9bc6b35392bb55d09f641a0a65e7403 → 0.0.0-experimental.32c4b04580cc12400710050c8198e46b3644cfd4

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 (97) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js → ComponentConfigurationPage-5ukroXAh.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js.map → ComponentConfigurationPage-5ukroXAh.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-gdUj_t-O.mjs → ComponentConfigurationPage-BAgyHiMm.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-gdUj_t-O.mjs.map → ComponentConfigurationPage-BAgyHiMm.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs → EditConfigurationPage-DmoXawIh.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs.map → EditConfigurationPage-DmoXawIh.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js → EditConfigurationPage-Xp7lun0f.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js.map → EditConfigurationPage-Xp7lun0f.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-0MiFkXa8.mjs → EditViewPage-BLsjc5F-.mjs} +3 -3
  11. package/dist/_chunks/{EditViewPage-0MiFkXa8.mjs.map → EditViewPage-BLsjc5F-.mjs.map} +1 -1
  12. package/dist/_chunks/{EditViewPage-DbcGfyqK.js → EditViewPage-C-ukDOB7.js} +3 -3
  13. package/dist/_chunks/{EditViewPage-DbcGfyqK.js.map → EditViewPage-C-ukDOB7.js.map} +1 -1
  14. package/dist/_chunks/{Field-BG1xu38N.js → Field-Bfph5SOd.js} +348 -56
  15. package/dist/_chunks/Field-Bfph5SOd.js.map +1 -0
  16. package/dist/_chunks/{Field-BDMSCcy5.mjs → Field-Cs7duwWd.mjs} +349 -57
  17. package/dist/_chunks/Field-Cs7duwWd.mjs.map +1 -0
  18. package/dist/_chunks/{Form-9BnFyUjy.js → Form-CPYqIWDG.js} +6 -3
  19. package/dist/_chunks/Form-CPYqIWDG.js.map +1 -0
  20. package/dist/_chunks/{Form-CPVWavB8.mjs → Form-Dg_GS5TQ.mjs} +6 -3
  21. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +1 -0
  22. package/dist/_chunks/{History-BWWxLt2Z.js → History-DNQkXANT.js} +44 -19
  23. package/dist/_chunks/History-DNQkXANT.js.map +1 -0
  24. package/dist/_chunks/{History-BVpd8LP3.mjs → History-wrnHqf09.mjs} +44 -19
  25. package/dist/_chunks/History-wrnHqf09.mjs.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-6swzjdAZ.js → ListConfigurationPage-CUQxfpjT.js} +8 -6
  27. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-DozVMKcR.mjs → ListConfigurationPage-DScmJVkW.mjs} +8 -6
  29. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-BlzfjS2Q.js → ListViewPage-BsLiH2-2.js} +15 -6
  31. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-Ds0ulgfG.mjs → ListViewPage-C4IvrMgY.mjs} +15 -6
  33. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js → NoContentTypePage-BZ-PnGAf.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js.map → NoContentTypePage-BZ-PnGAf.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs → NoContentTypePage-Djg8nPlj.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs.map → NoContentTypePage-Djg8nPlj.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs → NoPermissionsPage-DSP7R-hv.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs.map → NoPermissionsPage-DSP7R-hv.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js → NoPermissionsPage-_lUqjGW3.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js.map → NoPermissionsPage-_lUqjGW3.js.map} +1 -1
  42. package/dist/_chunks/{Relations-Dnag3fhV.mjs → Relations-BZr8tL0R.mjs} +3 -3
  43. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-CcgFTcWo.js → Relations-CtELXYIK.js} +3 -3
  45. package/dist/_chunks/Relations-CtELXYIK.js.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-CWpLBSt0.js → index-OerGjbAN.js} +290 -122
  51. package/dist/_chunks/index-OerGjbAN.js.map +1 -0
  52. package/dist/_chunks/{index-JNNNKUHs.mjs → index-c_5DdJi-.mjs} +305 -137
  53. package/dist/_chunks/index-c_5DdJi-.mjs.map +1 -0
  54. package/dist/_chunks/{layout--iHdZzRk.js → layout-Ci7qHlFb.js} +7 -7
  55. package/dist/_chunks/layout-Ci7qHlFb.js.map +1 -0
  56. package/dist/_chunks/{layout-DC503LnF.mjs → layout-oPBiO7RY.mjs} +8 -8
  57. package/dist/_chunks/layout-oPBiO7RY.mjs.map +1 -0
  58. package/dist/_chunks/{relations-CTje5t-a.mjs → relations-BIdWFjdq.mjs} +2 -2
  59. package/dist/_chunks/{relations-CTje5t-a.mjs.map → relations-BIdWFjdq.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-BbHizA5K.js → relations-COBpStiF.js} +2 -2
  61. package/dist/_chunks/{relations-BbHizA5K.js.map → relations-COBpStiF.js.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 +1 -0
  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/server/index.js +41 -34
  70. package/dist/server/index.js.map +1 -1
  71. package/dist/server/index.mjs +41 -34
  72. package/dist/server/index.mjs.map +1 -1
  73. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  74. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  75. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  76. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  77. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  78. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  79. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  80. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  81. package/package.json +8 -8
  82. package/dist/_chunks/Field-BDMSCcy5.mjs.map +0 -1
  83. package/dist/_chunks/Field-BG1xu38N.js.map +0 -1
  84. package/dist/_chunks/Form-9BnFyUjy.js.map +0 -1
  85. package/dist/_chunks/Form-CPVWavB8.mjs.map +0 -1
  86. package/dist/_chunks/History-BVpd8LP3.mjs.map +0 -1
  87. package/dist/_chunks/History-BWWxLt2Z.js.map +0 -1
  88. package/dist/_chunks/ListConfigurationPage-6swzjdAZ.js.map +0 -1
  89. package/dist/_chunks/ListConfigurationPage-DozVMKcR.mjs.map +0 -1
  90. package/dist/_chunks/ListViewPage-BlzfjS2Q.js.map +0 -1
  91. package/dist/_chunks/ListViewPage-Ds0ulgfG.mjs.map +0 -1
  92. package/dist/_chunks/Relations-CcgFTcWo.js.map +0 -1
  93. package/dist/_chunks/Relations-Dnag3fhV.mjs.map +0 -1
  94. package/dist/_chunks/index-CWpLBSt0.js.map +0 -1
  95. package/dist/_chunks/index-JNNNKUHs.mjs.map +0 -1
  96. package/dist/_chunks/layout--iHdZzRk.js.map +0 -1
  97. package/dist/_chunks/layout-DC503LnF.mjs.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 { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption, Box, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, 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 }) => ({
@@ -397,6 +367,18 @@ const documentApi = contentManagerApi.injectEndpoints({
397
367
  },
398
368
  "Relations"
399
369
  ];
370
+ },
371
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
372
+ const patchResult = dispatch(
373
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
374
+ Object.assign(draft.data, data);
375
+ })
376
+ );
377
+ try {
378
+ await queryFulfilled;
379
+ } catch {
380
+ patchResult.undo();
381
+ }
400
382
  }
401
383
  }),
402
384
  unpublishDocument: builder.mutation({
@@ -599,11 +581,11 @@ const createAttributeSchema = (attribute) => {
599
581
  }
600
582
  };
601
583
  const addRequiredValidation = (attribute) => (schema) => {
602
- if (attribute.required) {
603
- return schema.required({
604
- id: translatedErrors.required.id,
605
- defaultMessage: "This field is required."
606
- });
584
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
585
+ return schema.min(1, translatedErrors.required);
586
+ }
587
+ if (attribute.required && attribute.type !== "relation") {
588
+ return schema.required(translatedErrors.required);
607
589
  }
608
590
  return schema?.nullable ? schema.nullable() : (
609
591
  // In some cases '.nullable' will not be available on the schema.
@@ -637,6 +619,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
637
619
  const addMinValidation = (attribute) => (schema) => {
638
620
  if ("min" in attribute) {
639
621
  const min = toInteger(attribute.min);
622
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
623
+ if (!attribute.required && "test" in schema && min) {
624
+ return schema.test(
625
+ "custom-min",
626
+ {
627
+ ...translatedErrors.min,
628
+ values: {
629
+ min: attribute.min
630
+ }
631
+ },
632
+ (value) => {
633
+ if (!value) {
634
+ return true;
635
+ }
636
+ if (Array.isArray(value) && value.length === 0) {
637
+ return true;
638
+ }
639
+ return value.length >= min;
640
+ }
641
+ );
642
+ }
643
+ }
640
644
  if ("min" in schema && min) {
641
645
  return schema.min(min, {
642
646
  ...translatedErrors.min,
@@ -763,7 +767,10 @@ const useDocument = (args, opts) => {
763
767
  isLoading: isLoadingDocument,
764
768
  isFetching: isFetchingDocument,
765
769
  error
766
- } = useGetDocumentQuery(args, opts);
770
+ } = useGetDocumentQuery(args, {
771
+ ...opts,
772
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
773
+ });
767
774
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
768
775
  React.useEffect(() => {
769
776
  if (error) {
@@ -1184,7 +1191,6 @@ const useDocumentActions = () => {
1184
1191
  sourceId
1185
1192
  });
1186
1193
  if ("error" in res) {
1187
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1188
1194
  return { error: res.error };
1189
1195
  }
1190
1196
  toggleNotification({
@@ -1265,7 +1271,7 @@ const useDocumentActions = () => {
1265
1271
  };
1266
1272
  };
1267
1273
  const ProtectedHistoryPage = lazy(
1268
- () => import("./History-BVpd8LP3.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1274
+ () => import("./History-wrnHqf09.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1269
1275
  );
1270
1276
  const routes$1 = [
1271
1277
  {
@@ -1278,31 +1284,31 @@ const routes$1 = [
1278
1284
  }
1279
1285
  ];
1280
1286
  const ProtectedEditViewPage = lazy(
1281
- () => import("./EditViewPage-0MiFkXa8.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1287
+ () => import("./EditViewPage-BLsjc5F-.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1282
1288
  );
1283
1289
  const ProtectedListViewPage = lazy(
1284
- () => import("./ListViewPage-Ds0ulgfG.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1290
+ () => import("./ListViewPage-C4IvrMgY.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1285
1291
  );
1286
1292
  const ProtectedListConfiguration = lazy(
1287
- () => import("./ListConfigurationPage-DozVMKcR.mjs").then((mod) => ({
1293
+ () => import("./ListConfigurationPage-DScmJVkW.mjs").then((mod) => ({
1288
1294
  default: mod.ProtectedListConfiguration
1289
1295
  }))
1290
1296
  );
1291
1297
  const ProtectedEditConfigurationPage = lazy(
1292
- () => import("./EditConfigurationPage-BwuIPOJG.mjs").then((mod) => ({
1298
+ () => import("./EditConfigurationPage-DmoXawIh.mjs").then((mod) => ({
1293
1299
  default: mod.ProtectedEditConfigurationPage
1294
1300
  }))
1295
1301
  );
1296
1302
  const ProtectedComponentConfigurationPage = lazy(
1297
- () => import("./ComponentConfigurationPage-gdUj_t-O.mjs").then((mod) => ({
1303
+ () => import("./ComponentConfigurationPage-BAgyHiMm.mjs").then((mod) => ({
1298
1304
  default: mod.ProtectedComponentConfigurationPage
1299
1305
  }))
1300
1306
  );
1301
1307
  const NoPermissions = lazy(
1302
- () => import("./NoPermissionsPage-BT2Tn0D_.mjs").then((mod) => ({ default: mod.NoPermissions }))
1308
+ () => import("./NoPermissionsPage-DSP7R-hv.mjs").then((mod) => ({ default: mod.NoPermissions }))
1303
1309
  );
1304
1310
  const NoContentType = lazy(
1305
- () => import("./NoContentTypePage-BH11kaKt.mjs").then((mod) => ({ default: mod.NoContentType }))
1311
+ () => import("./NoContentTypePage-Djg8nPlj.mjs").then((mod) => ({ default: mod.NoContentType }))
1306
1312
  );
1307
1313
  const CollectionTypePages = () => {
1308
1314
  const { collectionType } = useParams();
@@ -1429,7 +1435,7 @@ const DocumentActionButton = (action) => {
1429
1435
  DocumentActionConfirmDialog,
1430
1436
  {
1431
1437
  ...action.dialog,
1432
- variant: action.variant,
1438
+ variant: action.dialog?.variant ?? action.variant,
1433
1439
  isOpen: dialogId === action.id,
1434
1440
  onClose: handleClose
1435
1441
  }
@@ -1509,7 +1515,7 @@ const DocumentActionsMenu = ({
1509
1515
  display: "block",
1510
1516
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1511
1517
  /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1512
- action.icon,
1518
+ /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1513
1519
  action.label
1514
1520
  ] }),
1515
1521
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
@@ -1570,6 +1576,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1570
1576
  return "primary600";
1571
1577
  }
1572
1578
  };
1579
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1580
+ switch (variant) {
1581
+ case "danger":
1582
+ return "danger600";
1583
+ case "secondary":
1584
+ return "neutral500";
1585
+ case "success":
1586
+ return "success600";
1587
+ default:
1588
+ return "primary600";
1589
+ }
1590
+ };
1573
1591
  const DocumentActionConfirmDialog = ({
1574
1592
  onClose,
1575
1593
  onCancel,
@@ -1646,6 +1664,12 @@ const PublishAction$1 = ({
1646
1664
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1647
1665
  );
1648
1666
  const { publish } = useDocumentActions();
1667
+ const [
1668
+ countDraftRelations,
1669
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1670
+ ] = useLazyGetDraftRelationCountQuery();
1671
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1672
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1649
1673
  const [{ query, rawQuery }] = useQueryParams();
1650
1674
  const params = React.useMemo(() => buildValidParams(query), [query]);
1651
1675
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1654,10 +1678,101 @@ const PublishAction$1 = ({
1654
1678
  const validate = useForm("PublishAction", (state) => state.validate);
1655
1679
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1656
1680
  const formValues = useForm("PublishAction", ({ values }) => values);
1681
+ React.useEffect(() => {
1682
+ if (isErrorDraftRelations) {
1683
+ toggleNotification({
1684
+ type: "danger",
1685
+ message: formatMessage({
1686
+ id: getTranslation("error.records.fetch-draft-relatons"),
1687
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1688
+ })
1689
+ });
1690
+ }
1691
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1692
+ React.useEffect(() => {
1693
+ const localDraftRelations = /* @__PURE__ */ new Set();
1694
+ const extractDraftRelations = (data) => {
1695
+ const relations = data.connect || [];
1696
+ relations.forEach((relation) => {
1697
+ if (relation.status === "draft") {
1698
+ localDraftRelations.add(relation.id);
1699
+ }
1700
+ });
1701
+ };
1702
+ const traverseAndExtract = (data) => {
1703
+ Object.entries(data).forEach(([key, value]) => {
1704
+ if (key === "connect" && Array.isArray(value)) {
1705
+ extractDraftRelations({ connect: value });
1706
+ } else if (typeof value === "object" && value !== null) {
1707
+ traverseAndExtract(value);
1708
+ }
1709
+ });
1710
+ };
1711
+ if (!documentId || modified) {
1712
+ traverseAndExtract(formValues);
1713
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1714
+ }
1715
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1716
+ React.useEffect(() => {
1717
+ if (documentId) {
1718
+ const fetchDraftRelationsCount = async () => {
1719
+ const { data, error } = await countDraftRelations({
1720
+ collectionType,
1721
+ model,
1722
+ documentId,
1723
+ params
1724
+ });
1725
+ if (error) {
1726
+ throw error;
1727
+ }
1728
+ if (data) {
1729
+ setServerCountOfDraftRelations(data.data);
1730
+ }
1731
+ };
1732
+ fetchDraftRelationsCount();
1733
+ }
1734
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1657
1735
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1658
1736
  if (!schema?.options?.draftAndPublish) {
1659
1737
  return null;
1660
1738
  }
1739
+ const performPublish = async () => {
1740
+ setSubmitting(true);
1741
+ try {
1742
+ const { errors } = await validate();
1743
+ if (errors) {
1744
+ toggleNotification({
1745
+ type: "danger",
1746
+ message: formatMessage({
1747
+ id: "content-manager.validation.error",
1748
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1749
+ })
1750
+ });
1751
+ return;
1752
+ }
1753
+ const res = await publish(
1754
+ {
1755
+ collectionType,
1756
+ model,
1757
+ documentId,
1758
+ params
1759
+ },
1760
+ formValues
1761
+ );
1762
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1763
+ navigate({
1764
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1765
+ search: rawQuery
1766
+ });
1767
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1768
+ setErrors(formatValidationErrors(res.error));
1769
+ }
1770
+ } finally {
1771
+ setSubmitting(false);
1772
+ }
1773
+ };
1774
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1775
+ const hasDraftRelations = totalDraftRelations > 0;
1661
1776
  return {
1662
1777
  /**
1663
1778
  * Disabled when:
@@ -1670,46 +1785,38 @@ const PublishAction$1 = ({
1670
1785
  * - the user doesn't have the permission to create a new document
1671
1786
  * - the user doesn't have the permission to update the document
1672
1787
  */
1673
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1788
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1674
1789
  label: formatMessage({
1675
1790
  id: "app.utils.publish",
1676
1791
  defaultMessage: "Publish"
1677
1792
  }),
1678
1793
  onClick: async () => {
1679
- setSubmitting(true);
1680
- try {
1681
- const { errors } = await validate();
1682
- if (errors) {
1683
- toggleNotification({
1684
- type: "danger",
1685
- message: formatMessage({
1686
- id: "content-manager.validation.error",
1687
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1688
- })
1689
- });
1690
- return;
1691
- }
1692
- const res = await publish(
1693
- {
1694
- collectionType,
1695
- model,
1696
- documentId,
1697
- params
1698
- },
1699
- formValues
1700
- );
1701
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1702
- navigate({
1703
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1704
- search: rawQuery
1705
- });
1706
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1707
- setErrors(formatValidationErrors(res.error));
1794
+ if (hasDraftRelations) {
1795
+ return;
1796
+ }
1797
+ await performPublish();
1798
+ },
1799
+ dialog: hasDraftRelations ? {
1800
+ type: "dialog",
1801
+ variant: "danger",
1802
+ footer: null,
1803
+ title: formatMessage({
1804
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1805
+ defaultMessage: "Confirmation"
1806
+ }),
1807
+ content: formatMessage(
1808
+ {
1809
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1810
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1811
+ },
1812
+ {
1813
+ count: totalDraftRelations
1708
1814
  }
1709
- } finally {
1710
- setSubmitting(false);
1815
+ ),
1816
+ onConfirm: async () => {
1817
+ await performPublish();
1711
1818
  }
1712
- }
1819
+ } : void 0
1713
1820
  };
1714
1821
  };
1715
1822
  PublishAction$1.type = "publish";
@@ -1777,10 +1884,13 @@ const UpdateAction = ({
1777
1884
  document
1778
1885
  );
1779
1886
  if ("data" in res) {
1780
- navigate({
1781
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1782
- search: rawQuery
1783
- });
1887
+ navigate(
1888
+ {
1889
+ pathname: `../${res.data.documentId}`,
1890
+ search: rawQuery
1891
+ },
1892
+ { relative: "path" }
1893
+ );
1784
1894
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1785
1895
  setErrors(formatValidationErrors(res.error));
1786
1896
  }
@@ -1808,10 +1918,13 @@ const UpdateAction = ({
1808
1918
  document
1809
1919
  );
1810
1920
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1811
- navigate({
1812
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1813
- search: rawQuery
1814
- });
1921
+ navigate(
1922
+ {
1923
+ pathname: `../${res.data.documentId}`,
1924
+ search: rawQuery
1925
+ },
1926
+ { replace: true, relative: "path" }
1927
+ );
1815
1928
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1816
1929
  setErrors(formatValidationErrors(res.error));
1817
1930
  }
@@ -2057,23 +2170,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2057
2170
  id: "content-manager.containers.edit.title.new",
2058
2171
  defaultMessage: "Create an entry"
2059
2172
  }) : documentTitle;
2060
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2173
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2061
2174
  /* @__PURE__ */ jsx(BackButton, {}),
2062
- /* @__PURE__ */ jsxs(
2063
- Flex,
2064
- {
2065
- width: "100%",
2066
- justifyContent: "space-between",
2067
- paddingTop: 1,
2068
- gap: "80px",
2069
- alignItems: "flex-start",
2070
- children: [
2071
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2072
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2073
- ]
2074
- }
2075
- ),
2076
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2175
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2176
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2177
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2178
+ ] }),
2179
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2077
2180
  ] });
2078
2181
  };
2079
2182
  const HeaderToolbar = () => {
@@ -2764,7 +2867,7 @@ const ConfirmBulkActionDialog = ({
2764
2867
  endAction
2765
2868
  }) => {
2766
2869
  const { formatMessage } = useIntl();
2767
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2870
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2768
2871
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2769
2872
  id: "app.components.ConfirmDialog.title",
2770
2873
  defaultMessage: "Confirmation"
@@ -2885,7 +2988,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2885
2988
  )
2886
2989
  );
2887
2990
  } else {
2888
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
2991
+ messages.push(
2992
+ ...formatErrorMessages(
2993
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
2994
+ value,
2995
+ currentKey,
2996
+ formatMessage
2997
+ )
2998
+ );
2889
2999
  }
2890
3000
  } else {
2891
3001
  messages.push(
@@ -3548,8 +3658,7 @@ class ContentManagerPlugin {
3548
3658
  documentActions = [
3549
3659
  ...DEFAULT_ACTIONS,
3550
3660
  ...DEFAULT_TABLE_ROW_ACTIONS,
3551
- ...DEFAULT_HEADER_ACTIONS,
3552
- HistoryAction
3661
+ ...DEFAULT_HEADER_ACTIONS
3553
3662
  ];
3554
3663
  editViewSidePanels = [ActionsPanel];
3555
3664
  headerActions = [];
@@ -3638,6 +3747,52 @@ const getPrintableType = (value) => {
3638
3747
  }
3639
3748
  return nativeType;
3640
3749
  };
3750
+ const HistoryAction = ({ model, document }) => {
3751
+ const { formatMessage } = useIntl();
3752
+ const [{ query }] = useQueryParams();
3753
+ const navigate = useNavigate();
3754
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3755
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3756
+ return null;
3757
+ }
3758
+ return {
3759
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3760
+ label: formatMessage({
3761
+ id: "content-manager.history.document-action",
3762
+ defaultMessage: "Content History"
3763
+ }),
3764
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3765
+ disabled: (
3766
+ /**
3767
+ * The user is creating a new document.
3768
+ * It hasn't been saved yet, so there's no history to go to
3769
+ */
3770
+ !document || /**
3771
+ * The document has been created but the current dimension has never been saved.
3772
+ * For example, the user is creating a new locale in an existing document,
3773
+ * so there's no history for the document in that locale
3774
+ */
3775
+ !document.id || /**
3776
+ * History is only available for content types created by the user.
3777
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3778
+ * which start with `admin::` or `plugin::`
3779
+ */
3780
+ !model.startsWith("api::")
3781
+ ),
3782
+ position: "header"
3783
+ };
3784
+ };
3785
+ HistoryAction.type = "history";
3786
+ const historyAdmin = {
3787
+ bootstrap(app) {
3788
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3789
+ addDocumentAction((actions2) => {
3790
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3791
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3792
+ return actions2;
3793
+ });
3794
+ }
3795
+ };
3641
3796
  const initialState = {
3642
3797
  collectionTypeLinks: [],
3643
3798
  components: [],
@@ -3688,15 +3843,29 @@ const index = {
3688
3843
  defaultMessage: "Content Manager"
3689
3844
  },
3690
3845
  permissions: [],
3691
- Component: () => import("./layout-DC503LnF.mjs").then((mod) => ({ default: mod.Layout })),
3692
3846
  position: 1
3693
3847
  });
3848
+ app.router.addRoute({
3849
+ path: "content-manager/*",
3850
+ lazy: async () => {
3851
+ const { Layout } = await import("./layout-oPBiO7RY.mjs");
3852
+ return {
3853
+ Component: Layout
3854
+ };
3855
+ },
3856
+ children: routes
3857
+ });
3694
3858
  app.registerPlugin(cm.config);
3695
3859
  },
3860
+ bootstrap(app) {
3861
+ if (typeof historyAdmin.bootstrap === "function") {
3862
+ historyAdmin.bootstrap(app);
3863
+ }
3864
+ },
3696
3865
  async registerTrads({ locales }) {
3697
3866
  const importedTrads = await Promise.all(
3698
3867
  locales.map((locale) => {
3699
- 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 }) => {
3868
+ 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 }) => {
3700
3869
  return {
3701
3870
  data: prefixPluginTranslations(data, PLUGIN_ID),
3702
3871
  locale
@@ -3717,14 +3886,13 @@ export {
3717
3886
  BulkActionsRenderer as B,
3718
3887
  COLLECTION_TYPES as C,
3719
3888
  DocumentStatus as D,
3720
- extractContentTypeComponents as E,
3721
- DEFAULT_SETTINGS as F,
3722
- convertEditLayoutToFieldLayouts as G,
3889
+ DEFAULT_SETTINGS as E,
3890
+ convertEditLayoutToFieldLayouts as F,
3891
+ useDocument as G,
3723
3892
  HOOKS as H,
3724
3893
  InjectionZone as I,
3725
- useDocument as J,
3726
- index as K,
3727
- useDocumentActions as L,
3894
+ index as J,
3895
+ useDocumentActions as K,
3728
3896
  Panels as P,
3729
3897
  RelativeTime as R,
3730
3898
  SINGLE_TYPES as S,
@@ -3746,14 +3914,14 @@ export {
3746
3914
  useGetContentTypeConfigurationQuery as o,
3747
3915
  CREATOR_FIELDS as p,
3748
3916
  getMainField as q,
3749
- routes as r,
3917
+ getDisplayName as r,
3750
3918
  setInitialData as s,
3751
- getDisplayName as t,
3919
+ checkIfAttributeIsDisplayable as t,
3752
3920
  useContentTypeSchema as u,
3753
- checkIfAttributeIsDisplayable as v,
3754
- useGetAllDocumentsQuery as w,
3755
- convertListLayoutToFieldLayouts as x,
3756
- capitalise as y,
3757
- useUpdateContentTypeConfigurationMutation as z
3921
+ useGetAllDocumentsQuery as v,
3922
+ convertListLayoutToFieldLayouts as w,
3923
+ capitalise as x,
3924
+ useUpdateContentTypeConfigurationMutation as y,
3925
+ extractContentTypeComponents as z
3758
3926
  };
3759
- //# sourceMappingURL=index-JNNNKUHs.mjs.map
3927
+ //# sourceMappingURL=index-c_5DdJi-.mjs.map