@strapi/content-manager 0.0.0-experimental.2a7cb5ff33df35e8ccde5ef918f9f9a4a3ee9a08 → 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 (90) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js → ComponentConfigurationPage-5ukroXAh.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js.map → ComponentConfigurationPage-5ukroXAh.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs → ComponentConfigurationPage-BAgyHiMm.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs.map → ComponentConfigurationPage-BAgyHiMm.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs → EditConfigurationPage-DmoXawIh.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs.map → EditConfigurationPage-DmoXawIh.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js → EditConfigurationPage-Xp7lun0f.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js.map → EditConfigurationPage-Xp7lun0f.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-BtkEx339.mjs → EditViewPage-BLsjc5F-.mjs} +3 -3
  11. package/dist/_chunks/{EditViewPage-BtkEx339.mjs.map → EditViewPage-BLsjc5F-.mjs.map} +1 -1
  12. package/dist/_chunks/{EditViewPage-BqNpC6hO.js → EditViewPage-C-ukDOB7.js} +3 -3
  13. package/dist/_chunks/{EditViewPage-BqNpC6hO.js.map → EditViewPage-C-ukDOB7.js.map} +1 -1
  14. package/dist/_chunks/{Field-lsPFnAmH.js → Field-Bfph5SOd.js} +79 -54
  15. package/dist/_chunks/Field-Bfph5SOd.js.map +1 -0
  16. package/dist/_chunks/{Field-R5NbffTB.mjs → Field-Cs7duwWd.mjs} +79 -54
  17. package/dist/_chunks/Field-Cs7duwWd.mjs.map +1 -0
  18. package/dist/_chunks/{Form-CcGboku8.js → Form-CPYqIWDG.js} +2 -2
  19. package/dist/_chunks/{Form-CcGboku8.js.map → Form-CPYqIWDG.js.map} +1 -1
  20. package/dist/_chunks/{Form-BHmXSfyy.mjs → Form-Dg_GS5TQ.mjs} +2 -2
  21. package/dist/_chunks/{Form-BHmXSfyy.mjs.map → Form-Dg_GS5TQ.mjs.map} +1 -1
  22. package/dist/_chunks/{History-Bsud8jwh.js → History-DNQkXANT.js} +28 -18
  23. package/dist/_chunks/History-DNQkXANT.js.map +1 -0
  24. package/dist/_chunks/{History-ByUPL3T3.mjs → History-wrnHqf09.mjs} +28 -18
  25. package/dist/_chunks/History-wrnHqf09.mjs.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DiT463qx.js → ListConfigurationPage-CUQxfpjT.js} +8 -6
  27. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-Bm5HACXf.mjs → ListConfigurationPage-DScmJVkW.mjs} +8 -6
  29. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-CsrC9L_d.js → ListViewPage-BsLiH2-2.js} +3 -3
  31. package/dist/_chunks/{ListViewPage-CsrC9L_d.js.map → ListViewPage-BsLiH2-2.js.map} +1 -1
  32. package/dist/_chunks/{ListViewPage-JSyNAAYu.mjs → ListViewPage-C4IvrMgY.mjs} +3 -3
  33. package/dist/_chunks/{ListViewPage-JSyNAAYu.mjs.map → ListViewPage-C4IvrMgY.mjs.map} +1 -1
  34. package/dist/_chunks/{NoContentTypePage-Bsvng4II.js → NoContentTypePage-BZ-PnGAf.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-Bsvng4II.js.map → NoContentTypePage-BZ-PnGAf.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs → NoContentTypePage-Djg8nPlj.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs.map → NoContentTypePage-Djg8nPlj.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs → NoPermissionsPage-DSP7R-hv.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs.map → NoPermissionsPage-DSP7R-hv.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js → NoPermissionsPage-_lUqjGW3.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js.map → NoPermissionsPage-_lUqjGW3.js.map} +1 -1
  42. package/dist/_chunks/{Relations-u8-37jK0.mjs → Relations-BZr8tL0R.mjs} +3 -3
  43. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-CghaPv2D.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-BOZx6IMg.js → index-OerGjbAN.js} +251 -117
  51. package/dist/_chunks/index-OerGjbAN.js.map +1 -0
  52. package/dist/_chunks/{index-CaE6NG4a.mjs → index-c_5DdJi-.mjs} +253 -119
  53. package/dist/_chunks/index-c_5DdJi-.mjs.map +1 -0
  54. package/dist/_chunks/{layout-Ciz224q5.js → layout-Ci7qHlFb.js} +4 -4
  55. package/dist/_chunks/layout-Ci7qHlFb.js.map +1 -0
  56. package/dist/_chunks/{layout-Bx7svTbY.mjs → layout-oPBiO7RY.mjs} +4 -4
  57. package/dist/_chunks/layout-oPBiO7RY.mjs.map +1 -0
  58. package/dist/_chunks/{relations-Cxc1cEv3.mjs → relations-BIdWFjdq.mjs} +2 -2
  59. package/dist/_chunks/{relations-Cxc1cEv3.mjs.map → relations-BIdWFjdq.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CP8sB2YZ.js → relations-COBpStiF.js} +2 -2
  61. package/dist/_chunks/{relations-CP8sB2YZ.js.map → relations-COBpStiF.js.map} +1 -1
  62. package/dist/admin/index.js +1 -1
  63. package/dist/admin/index.mjs +1 -1
  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/Relations.d.ts +20 -0
  68. package/dist/server/index.js +33 -28
  69. package/dist/server/index.js.map +1 -1
  70. package/dist/server/index.mjs +33 -28
  71. package/dist/server/index.mjs.map +1 -1
  72. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  73. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  74. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  75. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  76. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  77. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  78. package/package.json +6 -6
  79. package/dist/_chunks/Field-R5NbffTB.mjs.map +0 -1
  80. package/dist/_chunks/Field-lsPFnAmH.js.map +0 -1
  81. package/dist/_chunks/History-Bsud8jwh.js.map +0 -1
  82. package/dist/_chunks/History-ByUPL3T3.mjs.map +0 -1
  83. package/dist/_chunks/ListConfigurationPage-Bm5HACXf.mjs.map +0 -1
  84. package/dist/_chunks/ListConfigurationPage-DiT463qx.js.map +0 -1
  85. package/dist/_chunks/Relations-CghaPv2D.js.map +0 -1
  86. package/dist/_chunks/Relations-u8-37jK0.mjs.map +0 -1
  87. package/dist/_chunks/index-BOZx6IMg.js.map +0 -1
  88. package/dist/_chunks/index-CaE6NG4a.mjs.map +0 -1
  89. package/dist/_chunks/layout-Bx7svTbY.mjs.map +0 -1
  90. package/dist/_chunks/layout-Ciz224q5.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
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";
@@ -208,7 +172,12 @@ const documentApi = contentManagerApi.injectEndpoints({
208
172
  params: query
209
173
  }
210
174
  }),
211
- 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
+ }
212
181
  }),
213
182
  cloneDocument: builder.mutation({
214
183
  query: ({ model, sourceId, data, params }) => ({
@@ -398,6 +367,18 @@ const documentApi = contentManagerApi.injectEndpoints({
398
367
  },
399
368
  "Relations"
400
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
+ }
401
382
  }
402
383
  }),
403
384
  unpublishDocument: builder.mutation({
@@ -600,11 +581,11 @@ const createAttributeSchema = (attribute) => {
600
581
  }
601
582
  };
602
583
  const addRequiredValidation = (attribute) => (schema) => {
584
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
585
+ return schema.min(1, translatedErrors.required);
586
+ }
603
587
  if (attribute.required && attribute.type !== "relation") {
604
- return schema.required({
605
- id: translatedErrors.required.id,
606
- defaultMessage: "This field is required."
607
- });
588
+ return schema.required(translatedErrors.required);
608
589
  }
609
590
  return schema?.nullable ? schema.nullable() : (
610
591
  // In some cases '.nullable' will not be available on the schema.
@@ -638,6 +619,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
638
619
  const addMinValidation = (attribute) => (schema) => {
639
620
  if ("min" in attribute) {
640
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
+ }
641
644
  if ("min" in schema && min) {
642
645
  return schema.min(min, {
643
646
  ...translatedErrors.min,
@@ -1188,7 +1191,6 @@ const useDocumentActions = () => {
1188
1191
  sourceId
1189
1192
  });
1190
1193
  if ("error" in res) {
1191
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1192
1194
  return { error: res.error };
1193
1195
  }
1194
1196
  toggleNotification({
@@ -1269,7 +1271,7 @@ const useDocumentActions = () => {
1269
1271
  };
1270
1272
  };
1271
1273
  const ProtectedHistoryPage = lazy(
1272
- () => import("./History-ByUPL3T3.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1274
+ () => import("./History-wrnHqf09.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1273
1275
  );
1274
1276
  const routes$1 = [
1275
1277
  {
@@ -1282,31 +1284,31 @@ const routes$1 = [
1282
1284
  }
1283
1285
  ];
1284
1286
  const ProtectedEditViewPage = lazy(
1285
- () => import("./EditViewPage-BtkEx339.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1287
+ () => import("./EditViewPage-BLsjc5F-.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1286
1288
  );
1287
1289
  const ProtectedListViewPage = lazy(
1288
- () => import("./ListViewPage-JSyNAAYu.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1290
+ () => import("./ListViewPage-C4IvrMgY.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1289
1291
  );
1290
1292
  const ProtectedListConfiguration = lazy(
1291
- () => import("./ListConfigurationPage-Bm5HACXf.mjs").then((mod) => ({
1293
+ () => import("./ListConfigurationPage-DScmJVkW.mjs").then((mod) => ({
1292
1294
  default: mod.ProtectedListConfiguration
1293
1295
  }))
1294
1296
  );
1295
1297
  const ProtectedEditConfigurationPage = lazy(
1296
- () => import("./EditConfigurationPage-Cp6HAEzN.mjs").then((mod) => ({
1298
+ () => import("./EditConfigurationPage-DmoXawIh.mjs").then((mod) => ({
1297
1299
  default: mod.ProtectedEditConfigurationPage
1298
1300
  }))
1299
1301
  );
1300
1302
  const ProtectedComponentConfigurationPage = lazy(
1301
- () => import("./ComponentConfigurationPage-DHNM3YBz.mjs").then((mod) => ({
1303
+ () => import("./ComponentConfigurationPage-BAgyHiMm.mjs").then((mod) => ({
1302
1304
  default: mod.ProtectedComponentConfigurationPage
1303
1305
  }))
1304
1306
  );
1305
1307
  const NoPermissions = lazy(
1306
- () => import("./NoPermissionsPage-DNmf_pj0.mjs").then((mod) => ({ default: mod.NoPermissions }))
1308
+ () => import("./NoPermissionsPage-DSP7R-hv.mjs").then((mod) => ({ default: mod.NoPermissions }))
1307
1309
  );
1308
1310
  const NoContentType = lazy(
1309
- () => import("./NoContentTypePage-CsrQUpBE.mjs").then((mod) => ({ default: mod.NoContentType }))
1311
+ () => import("./NoContentTypePage-Djg8nPlj.mjs").then((mod) => ({ default: mod.NoContentType }))
1310
1312
  );
1311
1313
  const CollectionTypePages = () => {
1312
1314
  const { collectionType } = useParams();
@@ -1433,7 +1435,7 @@ const DocumentActionButton = (action) => {
1433
1435
  DocumentActionConfirmDialog,
1434
1436
  {
1435
1437
  ...action.dialog,
1436
- variant: action.variant,
1438
+ variant: action.dialog?.variant ?? action.variant,
1437
1439
  isOpen: dialogId === action.id,
1438
1440
  onClose: handleClose
1439
1441
  }
@@ -1639,8 +1641,8 @@ const DocumentActionModal = ({
1639
1641
  };
1640
1642
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1641
1643
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1642
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1643
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1644
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1645
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1644
1646
  ] }) });
1645
1647
  };
1646
1648
  const PublishAction$1 = ({
@@ -1662,6 +1664,12 @@ const PublishAction$1 = ({
1662
1664
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1663
1665
  );
1664
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);
1665
1673
  const [{ query, rawQuery }] = useQueryParams();
1666
1674
  const params = React.useMemo(() => buildValidParams(query), [query]);
1667
1675
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1670,10 +1678,101 @@ const PublishAction$1 = ({
1670
1678
  const validate = useForm("PublishAction", (state) => state.validate);
1671
1679
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1672
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]);
1673
1735
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1674
1736
  if (!schema?.options?.draftAndPublish) {
1675
1737
  return null;
1676
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;
1677
1776
  return {
1678
1777
  /**
1679
1778
  * Disabled when:
@@ -1686,46 +1785,38 @@ const PublishAction$1 = ({
1686
1785
  * - the user doesn't have the permission to create a new document
1687
1786
  * - the user doesn't have the permission to update the document
1688
1787
  */
1689
- 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),
1690
1789
  label: formatMessage({
1691
1790
  id: "app.utils.publish",
1692
1791
  defaultMessage: "Publish"
1693
1792
  }),
1694
1793
  onClick: async () => {
1695
- setSubmitting(true);
1696
- try {
1697
- const { errors } = await validate();
1698
- if (errors) {
1699
- toggleNotification({
1700
- type: "danger",
1701
- message: formatMessage({
1702
- id: "content-manager.validation.error",
1703
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1704
- })
1705
- });
1706
- return;
1707
- }
1708
- const res = await publish(
1709
- {
1710
- collectionType,
1711
- model,
1712
- documentId,
1713
- params
1714
- },
1715
- formValues
1716
- );
1717
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1718
- navigate({
1719
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1720
- search: rawQuery
1721
- });
1722
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1723
- 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
1724
1814
  }
1725
- } finally {
1726
- setSubmitting(false);
1815
+ ),
1816
+ onConfirm: async () => {
1817
+ await performPublish();
1727
1818
  }
1728
- }
1819
+ } : void 0
1729
1820
  };
1730
1821
  };
1731
1822
  PublishAction$1.type = "publish";
@@ -1793,10 +1884,13 @@ const UpdateAction = ({
1793
1884
  document
1794
1885
  );
1795
1886
  if ("data" in res) {
1796
- navigate({
1797
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1798
- search: rawQuery
1799
- });
1887
+ navigate(
1888
+ {
1889
+ pathname: `../${res.data.documentId}`,
1890
+ search: rawQuery
1891
+ },
1892
+ { relative: "path" }
1893
+ );
1800
1894
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1801
1895
  setErrors(formatValidationErrors(res.error));
1802
1896
  }
@@ -1826,10 +1920,10 @@ const UpdateAction = ({
1826
1920
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1827
1921
  navigate(
1828
1922
  {
1829
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1923
+ pathname: `../${res.data.documentId}`,
1830
1924
  search: rawQuery
1831
1925
  },
1832
- { replace: true }
1926
+ { replace: true, relative: "path" }
1833
1927
  );
1834
1928
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1835
1929
  setErrors(formatValidationErrors(res.error));
@@ -2076,23 +2170,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2076
2170
  id: "content-manager.containers.edit.title.new",
2077
2171
  defaultMessage: "Create an entry"
2078
2172
  }) : documentTitle;
2079
- 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: [
2080
2174
  /* @__PURE__ */ jsx(BackButton, {}),
2081
- /* @__PURE__ */ jsxs(
2082
- Flex,
2083
- {
2084
- width: "100%",
2085
- justifyContent: "space-between",
2086
- paddingTop: 1,
2087
- gap: "80px",
2088
- alignItems: "flex-start",
2089
- children: [
2090
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2091
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2092
- ]
2093
- }
2094
- ),
2095
- 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
2096
2180
  ] });
2097
2181
  };
2098
2182
  const HeaderToolbar = () => {
@@ -2783,7 +2867,7 @@ const ConfirmBulkActionDialog = ({
2783
2867
  endAction
2784
2868
  }) => {
2785
2869
  const { formatMessage } = useIntl();
2786
- 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: [
2787
2871
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2788
2872
  id: "app.components.ConfirmDialog.title",
2789
2873
  defaultMessage: "Confirmation"
@@ -3574,8 +3658,7 @@ class ContentManagerPlugin {
3574
3658
  documentActions = [
3575
3659
  ...DEFAULT_ACTIONS,
3576
3660
  ...DEFAULT_TABLE_ROW_ACTIONS,
3577
- ...DEFAULT_HEADER_ACTIONS,
3578
- HistoryAction
3661
+ ...DEFAULT_HEADER_ACTIONS
3579
3662
  ];
3580
3663
  editViewSidePanels = [ActionsPanel];
3581
3664
  headerActions = [];
@@ -3664,6 +3747,52 @@ const getPrintableType = (value) => {
3664
3747
  }
3665
3748
  return nativeType;
3666
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
+ };
3667
3796
  const initialState = {
3668
3797
  collectionTypeLinks: [],
3669
3798
  components: [],
@@ -3719,7 +3848,7 @@ const index = {
3719
3848
  app.router.addRoute({
3720
3849
  path: "content-manager/*",
3721
3850
  lazy: async () => {
3722
- const { Layout } = await import("./layout-Bx7svTbY.mjs");
3851
+ const { Layout } = await import("./layout-oPBiO7RY.mjs");
3723
3852
  return {
3724
3853
  Component: Layout
3725
3854
  };
@@ -3728,10 +3857,15 @@ const index = {
3728
3857
  });
3729
3858
  app.registerPlugin(cm.config);
3730
3859
  },
3860
+ bootstrap(app) {
3861
+ if (typeof historyAdmin.bootstrap === "function") {
3862
+ historyAdmin.bootstrap(app);
3863
+ }
3864
+ },
3731
3865
  async registerTrads({ locales }) {
3732
3866
  const importedTrads = await Promise.all(
3733
3867
  locales.map((locale) => {
3734
- 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 }) => {
3735
3869
  return {
3736
3870
  data: prefixPluginTranslations(data, PLUGIN_ID),
3737
3871
  locale
@@ -3790,4 +3924,4 @@ export {
3790
3924
  useUpdateContentTypeConfigurationMutation as y,
3791
3925
  extractContentTypeComponents as z
3792
3926
  };
3793
- //# sourceMappingURL=index-CaE6NG4a.mjs.map
3927
+ //# sourceMappingURL=index-c_5DdJi-.mjs.map