@strapi/content-manager 0.0.0-experimental.16eaafeff6bd4cd49d56f3c31d002cad71a1134a → 0.0.0-experimental.1bca8e0e074de8b0775bcddc7656fbc9e9f1393b

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 (93) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-Tqd-Ji_E.js → ComponentConfigurationPage-5ukroXAh.js} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-Tqd-Ji_E.js.map → ComponentConfigurationPage-5ukroXAh.js.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-B5mDY7I0.mjs → ComponentConfigurationPage-BAgyHiMm.mjs} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-B5mDY7I0.mjs.map → ComponentConfigurationPage-BAgyHiMm.mjs.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-B8UqkdtD.mjs → EditConfigurationPage-DmoXawIh.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-B8UqkdtD.mjs.map → EditConfigurationPage-DmoXawIh.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-C28IfcPs.js → EditConfigurationPage-Xp7lun0f.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-C28IfcPs.js.map → EditConfigurationPage-Xp7lun0f.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-DQUCbpW-.mjs → EditViewPage-BLsjc5F-.mjs} +3 -3
  11. package/dist/_chunks/{EditViewPage-DQUCbpW-.mjs.map → EditViewPage-BLsjc5F-.mjs.map} +1 -1
  12. package/dist/_chunks/{EditViewPage-BDL9cM0Q.js → EditViewPage-C-ukDOB7.js} +3 -3
  13. package/dist/_chunks/{EditViewPage-BDL9cM0Q.js.map → EditViewPage-C-ukDOB7.js.map} +1 -1
  14. package/dist/_chunks/{Field-D8I8rXr9.js → Field-Bfph5SOd.js} +79 -54
  15. package/dist/_chunks/Field-Bfph5SOd.js.map +1 -0
  16. package/dist/_chunks/{Field-DSGnyyoh.mjs → Field-Cs7duwWd.mjs} +79 -54
  17. package/dist/_chunks/Field-Cs7duwWd.mjs.map +1 -0
  18. package/dist/_chunks/{Form-DVvv6Hst.js → Form-CPYqIWDG.js} +2 -2
  19. package/dist/_chunks/{Form-DVvv6Hst.js.map → Form-CPYqIWDG.js.map} +1 -1
  20. package/dist/_chunks/{Form-DZGlZ79l.mjs → Form-Dg_GS5TQ.mjs} +2 -2
  21. package/dist/_chunks/{Form-DZGlZ79l.mjs.map → Form-Dg_GS5TQ.mjs.map} +1 -1
  22. package/dist/_chunks/{History-CQl54kNG.js → History-DNQkXANT.js} +44 -19
  23. package/dist/_chunks/History-DNQkXANT.js.map +1 -0
  24. package/dist/_chunks/{History-DOWk7MB4.mjs → History-wrnHqf09.mjs} +44 -19
  25. package/dist/_chunks/History-wrnHqf09.mjs.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-G_22rTAp.js → ListConfigurationPage-CUQxfpjT.js} +8 -6
  27. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-lN3NMkhK.mjs → ListConfigurationPage-DScmJVkW.mjs} +8 -6
  29. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-BIEXJtcz.js → ListViewPage-BsLiH2-2.js} +15 -6
  31. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-D_MY3zjg.mjs → ListViewPage-C4IvrMgY.mjs} +15 -6
  33. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-P-gvTfgg.js → NoContentTypePage-BZ-PnGAf.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-P-gvTfgg.js.map → NoContentTypePage-BZ-PnGAf.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CUrrV_mP.mjs → NoContentTypePage-Djg8nPlj.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CUrrV_mP.mjs.map → NoContentTypePage-Djg8nPlj.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-B-DP9Ht4.mjs → NoPermissionsPage-DSP7R-hv.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-B-DP9Ht4.mjs.map → NoPermissionsPage-DSP7R-hv.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-CIFc7iTR.js → NoPermissionsPage-_lUqjGW3.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-CIFc7iTR.js.map → NoPermissionsPage-_lUqjGW3.js.map} +1 -1
  42. package/dist/_chunks/{Relations-CSzJbIBP.mjs → Relations-BZr8tL0R.mjs} +3 -3
  43. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-BqSXkgPb.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-iXGIUU_l.js → index-OerGjbAN.js} +259 -119
  51. package/dist/_chunks/index-OerGjbAN.js.map +1 -0
  52. package/dist/_chunks/{index-BYpa_5O9.mjs → index-c_5DdJi-.mjs} +261 -121
  53. package/dist/_chunks/index-c_5DdJi-.mjs.map +1 -0
  54. package/dist/_chunks/{layout-BLa_DTtQ.js → layout-Ci7qHlFb.js} +6 -6
  55. package/dist/_chunks/layout-Ci7qHlFb.js.map +1 -0
  56. package/dist/_chunks/{layout-DT9g7_U1.mjs → layout-oPBiO7RY.mjs} +6 -6
  57. package/dist/_chunks/layout-oPBiO7RY.mjs.map +1 -0
  58. package/dist/_chunks/{relations-CHM_mYAI.mjs → relations-BIdWFjdq.mjs} +2 -2
  59. package/dist/_chunks/{relations-CHM_mYAI.mjs.map → relations-BIdWFjdq.mjs.map} +1 -1
  60. package/dist/_chunks/{relations--l5ixWIN.js → relations-COBpStiF.js} +2 -2
  61. package/dist/_chunks/{relations--l5ixWIN.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 +37 -28
  69. package/dist/server/index.js.map +1 -1
  70. package/dist/server/index.mjs +37 -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/history/services/utils.d.ts.map +1 -1
  77. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  78. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  79. package/package.json +6 -6
  80. package/dist/_chunks/Field-D8I8rXr9.js.map +0 -1
  81. package/dist/_chunks/Field-DSGnyyoh.mjs.map +0 -1
  82. package/dist/_chunks/History-CQl54kNG.js.map +0 -1
  83. package/dist/_chunks/History-DOWk7MB4.mjs.map +0 -1
  84. package/dist/_chunks/ListConfigurationPage-G_22rTAp.js.map +0 -1
  85. package/dist/_chunks/ListConfigurationPage-lN3NMkhK.mjs.map +0 -1
  86. package/dist/_chunks/ListViewPage-BIEXJtcz.js.map +0 -1
  87. package/dist/_chunks/ListViewPage-D_MY3zjg.mjs.map +0 -1
  88. package/dist/_chunks/Relations-BqSXkgPb.js.map +0 -1
  89. package/dist/_chunks/Relations-CSzJbIBP.mjs.map +0 -1
  90. package/dist/_chunks/index-BYpa_5O9.mjs.map +0 -1
  91. package/dist/_chunks/index-iXGIUU_l.js.map +0 -1
  92. package/dist/_chunks/layout-BLa_DTtQ.js.map +0 -1
  93. package/dist/_chunks/layout-DT9g7_U1.mjs.map +0 -1
@@ -2,15 +2,15 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
10
9
  const styledComponents = require("styled-components");
11
10
  const yup = require("yup");
12
11
  const pipe = require("lodash/fp/pipe");
13
12
  const dateFns = require("date-fns");
13
+ const qs = require("qs");
14
14
  const toolkit = require("@reduxjs/toolkit");
15
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
16
  function _interopNamespace(e) {
@@ -70,42 +70,6 @@ const useInjectionZone = (area) => {
70
70
  const [page, position] = area.split(".");
71
71
  return contentManagerPlugin.getInjectedComponents(page, position);
72
72
  };
73
- const HistoryAction = ({ model, document }) => {
74
- const { formatMessage } = reactIntl.useIntl();
75
- const [{ query }] = strapiAdmin.useQueryParams();
76
- const navigate = reactRouterDom.useNavigate();
77
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
78
- if (!window.strapi.features.isEnabled("cms-content-history")) {
79
- return null;
80
- }
81
- return {
82
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
83
- label: formatMessage({
84
- id: "content-manager.history.document-action",
85
- defaultMessage: "Content History"
86
- }),
87
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
88
- disabled: (
89
- /**
90
- * The user is creating a new document.
91
- * It hasn't been saved yet, so there's no history to go to
92
- */
93
- !document || /**
94
- * The document has been created but the current dimension has never been saved.
95
- * For example, the user is creating a new locale in an existing document,
96
- * so there's no history for the document in that locale
97
- */
98
- !document.id || /**
99
- * History is only available for content types created by the user.
100
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
101
- * which start with `admin::` or `plugin::`
102
- */
103
- !model.startsWith("api::")
104
- ),
105
- position: "header"
106
- };
107
- };
108
- HistoryAction.type = "history";
109
73
  const ID = "id";
110
74
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
111
75
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -229,7 +193,12 @@ const documentApi = contentManagerApi.injectEndpoints({
229
193
  params: query
230
194
  }
231
195
  }),
232
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
196
+ invalidatesTags: (_result, error, { model }) => {
197
+ if (error) {
198
+ return [];
199
+ }
200
+ return [{ type: "Document", id: `${model}_LIST` }];
201
+ }
233
202
  }),
234
203
  cloneDocument: builder.mutation({
235
204
  query: ({ model, sourceId, data, params }) => ({
@@ -419,6 +388,18 @@ const documentApi = contentManagerApi.injectEndpoints({
419
388
  },
420
389
  "Relations"
421
390
  ];
391
+ },
392
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
393
+ const patchResult = dispatch(
394
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
395
+ Object.assign(draft.data, data);
396
+ })
397
+ );
398
+ try {
399
+ await queryFulfilled;
400
+ } catch {
401
+ patchResult.undo();
402
+ }
422
403
  }
423
404
  }),
424
405
  unpublishDocument: builder.mutation({
@@ -621,11 +602,11 @@ const createAttributeSchema = (attribute) => {
621
602
  }
622
603
  };
623
604
  const addRequiredValidation = (attribute) => (schema) => {
624
- if (attribute.required) {
625
- return schema.required({
626
- id: strapiAdmin.translatedErrors.required.id,
627
- defaultMessage: "This field is required."
628
- });
605
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
606
+ return schema.min(1, strapiAdmin.translatedErrors.required);
607
+ }
608
+ if (attribute.required && attribute.type !== "relation") {
609
+ return schema.required(strapiAdmin.translatedErrors.required);
629
610
  }
630
611
  return schema?.nullable ? schema.nullable() : (
631
612
  // In some cases '.nullable' will not be available on the schema.
@@ -659,6 +640,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
659
640
  const addMinValidation = (attribute) => (schema) => {
660
641
  if ("min" in attribute) {
661
642
  const min = toInteger(attribute.min);
643
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
644
+ if (!attribute.required && "test" in schema && min) {
645
+ return schema.test(
646
+ "custom-min",
647
+ {
648
+ ...strapiAdmin.translatedErrors.min,
649
+ values: {
650
+ min: attribute.min
651
+ }
652
+ },
653
+ (value) => {
654
+ if (!value) {
655
+ return true;
656
+ }
657
+ if (Array.isArray(value) && value.length === 0) {
658
+ return true;
659
+ }
660
+ return value.length >= min;
661
+ }
662
+ );
663
+ }
664
+ }
662
665
  if ("min" in schema && min) {
663
666
  return schema.min(min, {
664
667
  ...strapiAdmin.translatedErrors.min,
@@ -785,7 +788,10 @@ const useDocument = (args, opts) => {
785
788
  isLoading: isLoadingDocument,
786
789
  isFetching: isFetchingDocument,
787
790
  error
788
- } = useGetDocumentQuery(args, opts);
791
+ } = useGetDocumentQuery(args, {
792
+ ...opts,
793
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
794
+ });
789
795
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
790
796
  React__namespace.useEffect(() => {
791
797
  if (error) {
@@ -1206,7 +1212,6 @@ const useDocumentActions = () => {
1206
1212
  sourceId
1207
1213
  });
1208
1214
  if ("error" in res) {
1209
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1210
1215
  return { error: res.error };
1211
1216
  }
1212
1217
  toggleNotification({
@@ -1287,7 +1292,7 @@ const useDocumentActions = () => {
1287
1292
  };
1288
1293
  };
1289
1294
  const ProtectedHistoryPage = React.lazy(
1290
- () => Promise.resolve().then(() => require("./History-CQl54kNG.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1295
+ () => Promise.resolve().then(() => require("./History-DNQkXANT.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1291
1296
  );
1292
1297
  const routes$1 = [
1293
1298
  {
@@ -1300,31 +1305,31 @@ const routes$1 = [
1300
1305
  }
1301
1306
  ];
1302
1307
  const ProtectedEditViewPage = React.lazy(
1303
- () => Promise.resolve().then(() => require("./EditViewPage-BDL9cM0Q.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1308
+ () => Promise.resolve().then(() => require("./EditViewPage-C-ukDOB7.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1304
1309
  );
1305
1310
  const ProtectedListViewPage = React.lazy(
1306
- () => Promise.resolve().then(() => require("./ListViewPage-BIEXJtcz.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1311
+ () => Promise.resolve().then(() => require("./ListViewPage-BsLiH2-2.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1307
1312
  );
1308
1313
  const ProtectedListConfiguration = React.lazy(
1309
- () => Promise.resolve().then(() => require("./ListConfigurationPage-G_22rTAp.js")).then((mod) => ({
1314
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-CUQxfpjT.js")).then((mod) => ({
1310
1315
  default: mod.ProtectedListConfiguration
1311
1316
  }))
1312
1317
  );
1313
1318
  const ProtectedEditConfigurationPage = React.lazy(
1314
- () => Promise.resolve().then(() => require("./EditConfigurationPage-C28IfcPs.js")).then((mod) => ({
1319
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-Xp7lun0f.js")).then((mod) => ({
1315
1320
  default: mod.ProtectedEditConfigurationPage
1316
1321
  }))
1317
1322
  );
1318
1323
  const ProtectedComponentConfigurationPage = React.lazy(
1319
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-Tqd-Ji_E.js")).then((mod) => ({
1324
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-5ukroXAh.js")).then((mod) => ({
1320
1325
  default: mod.ProtectedComponentConfigurationPage
1321
1326
  }))
1322
1327
  );
1323
1328
  const NoPermissions = React.lazy(
1324
- () => Promise.resolve().then(() => require("./NoPermissionsPage-CIFc7iTR.js")).then((mod) => ({ default: mod.NoPermissions }))
1329
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-_lUqjGW3.js")).then((mod) => ({ default: mod.NoPermissions }))
1325
1330
  );
1326
1331
  const NoContentType = React.lazy(
1327
- () => Promise.resolve().then(() => require("./NoContentTypePage-P-gvTfgg.js")).then((mod) => ({ default: mod.NoContentType }))
1332
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BZ-PnGAf.js")).then((mod) => ({ default: mod.NoContentType }))
1328
1333
  );
1329
1334
  const CollectionTypePages = () => {
1330
1335
  const { collectionType } = reactRouterDom.useParams();
@@ -1451,7 +1456,7 @@ const DocumentActionButton = (action) => {
1451
1456
  DocumentActionConfirmDialog,
1452
1457
  {
1453
1458
  ...action.dialog,
1454
- variant: action.variant,
1459
+ variant: action.dialog?.variant ?? action.variant,
1455
1460
  isOpen: dialogId === action.id,
1456
1461
  onClose: handleClose
1457
1462
  }
@@ -1680,6 +1685,12 @@ const PublishAction$1 = ({
1680
1685
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1681
1686
  );
1682
1687
  const { publish } = useDocumentActions();
1688
+ const [
1689
+ countDraftRelations,
1690
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1691
+ ] = useLazyGetDraftRelationCountQuery();
1692
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1693
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1683
1694
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1684
1695
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1685
1696
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1688,10 +1699,101 @@ const PublishAction$1 = ({
1688
1699
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1689
1700
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1690
1701
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1702
+ React__namespace.useEffect(() => {
1703
+ if (isErrorDraftRelations) {
1704
+ toggleNotification({
1705
+ type: "danger",
1706
+ message: formatMessage({
1707
+ id: getTranslation("error.records.fetch-draft-relatons"),
1708
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1709
+ })
1710
+ });
1711
+ }
1712
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1713
+ React__namespace.useEffect(() => {
1714
+ const localDraftRelations = /* @__PURE__ */ new Set();
1715
+ const extractDraftRelations = (data) => {
1716
+ const relations = data.connect || [];
1717
+ relations.forEach((relation) => {
1718
+ if (relation.status === "draft") {
1719
+ localDraftRelations.add(relation.id);
1720
+ }
1721
+ });
1722
+ };
1723
+ const traverseAndExtract = (data) => {
1724
+ Object.entries(data).forEach(([key, value]) => {
1725
+ if (key === "connect" && Array.isArray(value)) {
1726
+ extractDraftRelations({ connect: value });
1727
+ } else if (typeof value === "object" && value !== null) {
1728
+ traverseAndExtract(value);
1729
+ }
1730
+ });
1731
+ };
1732
+ if (!documentId || modified) {
1733
+ traverseAndExtract(formValues);
1734
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1735
+ }
1736
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1737
+ React__namespace.useEffect(() => {
1738
+ if (documentId) {
1739
+ const fetchDraftRelationsCount = async () => {
1740
+ const { data, error } = await countDraftRelations({
1741
+ collectionType,
1742
+ model,
1743
+ documentId,
1744
+ params
1745
+ });
1746
+ if (error) {
1747
+ throw error;
1748
+ }
1749
+ if (data) {
1750
+ setServerCountOfDraftRelations(data.data);
1751
+ }
1752
+ };
1753
+ fetchDraftRelationsCount();
1754
+ }
1755
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1691
1756
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1692
1757
  if (!schema?.options?.draftAndPublish) {
1693
1758
  return null;
1694
1759
  }
1760
+ const performPublish = async () => {
1761
+ setSubmitting(true);
1762
+ try {
1763
+ const { errors } = await validate();
1764
+ if (errors) {
1765
+ toggleNotification({
1766
+ type: "danger",
1767
+ message: formatMessage({
1768
+ id: "content-manager.validation.error",
1769
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1770
+ })
1771
+ });
1772
+ return;
1773
+ }
1774
+ const res = await publish(
1775
+ {
1776
+ collectionType,
1777
+ model,
1778
+ documentId,
1779
+ params
1780
+ },
1781
+ formValues
1782
+ );
1783
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1784
+ navigate({
1785
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1786
+ search: rawQuery
1787
+ });
1788
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1789
+ setErrors(formatValidationErrors(res.error));
1790
+ }
1791
+ } finally {
1792
+ setSubmitting(false);
1793
+ }
1794
+ };
1795
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1796
+ const hasDraftRelations = totalDraftRelations > 0;
1695
1797
  return {
1696
1798
  /**
1697
1799
  * Disabled when:
@@ -1704,46 +1806,38 @@ const PublishAction$1 = ({
1704
1806
  * - the user doesn't have the permission to create a new document
1705
1807
  * - the user doesn't have the permission to update the document
1706
1808
  */
1707
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1809
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1708
1810
  label: formatMessage({
1709
1811
  id: "app.utils.publish",
1710
1812
  defaultMessage: "Publish"
1711
1813
  }),
1712
1814
  onClick: async () => {
1713
- setSubmitting(true);
1714
- try {
1715
- const { errors } = await validate();
1716
- if (errors) {
1717
- toggleNotification({
1718
- type: "danger",
1719
- message: formatMessage({
1720
- id: "content-manager.validation.error",
1721
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1722
- })
1723
- });
1724
- return;
1725
- }
1726
- const res = await publish(
1727
- {
1728
- collectionType,
1729
- model,
1730
- documentId,
1731
- params
1732
- },
1733
- formValues
1734
- );
1735
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1736
- navigate({
1737
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1738
- search: rawQuery
1739
- });
1740
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1741
- setErrors(formatValidationErrors(res.error));
1815
+ if (hasDraftRelations) {
1816
+ return;
1817
+ }
1818
+ await performPublish();
1819
+ },
1820
+ dialog: hasDraftRelations ? {
1821
+ type: "dialog",
1822
+ variant: "danger",
1823
+ footer: null,
1824
+ title: formatMessage({
1825
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1826
+ defaultMessage: "Confirmation"
1827
+ }),
1828
+ content: formatMessage(
1829
+ {
1830
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1831
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1832
+ },
1833
+ {
1834
+ count: totalDraftRelations
1742
1835
  }
1743
- } finally {
1744
- setSubmitting(false);
1836
+ ),
1837
+ onConfirm: async () => {
1838
+ await performPublish();
1745
1839
  }
1746
- }
1840
+ } : void 0
1747
1841
  };
1748
1842
  };
1749
1843
  PublishAction$1.type = "publish";
@@ -1811,10 +1905,13 @@ const UpdateAction = ({
1811
1905
  document
1812
1906
  );
1813
1907
  if ("data" in res) {
1814
- navigate({
1815
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1816
- search: rawQuery
1817
- });
1908
+ navigate(
1909
+ {
1910
+ pathname: `../${res.data.documentId}`,
1911
+ search: rawQuery
1912
+ },
1913
+ { relative: "path" }
1914
+ );
1818
1915
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1819
1916
  setErrors(formatValidationErrors(res.error));
1820
1917
  }
@@ -1842,10 +1939,13 @@ const UpdateAction = ({
1842
1939
  document
1843
1940
  );
1844
1941
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1845
- navigate({
1846
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1847
- search: rawQuery
1848
- });
1942
+ navigate(
1943
+ {
1944
+ pathname: `../${res.data.documentId}`,
1945
+ search: rawQuery
1946
+ },
1947
+ { replace: true, relative: "path" }
1948
+ );
1849
1949
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1850
1950
  setErrors(formatValidationErrors(res.error));
1851
1951
  }
@@ -2091,23 +2191,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2091
2191
  id: "content-manager.containers.edit.title.new",
2092
2192
  defaultMessage: "Create an entry"
2093
2193
  }) : documentTitle;
2094
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2194
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2095
2195
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2096
- /* @__PURE__ */ jsxRuntime.jsxs(
2097
- designSystem.Flex,
2098
- {
2099
- width: "100%",
2100
- justifyContent: "space-between",
2101
- paddingTop: 1,
2102
- gap: "80px",
2103
- alignItems: "flex-start",
2104
- children: [
2105
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2106
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2107
- ]
2108
- }
2109
- ),
2110
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2196
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2197
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2198
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2199
+ ] }),
2200
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2111
2201
  ] });
2112
2202
  };
2113
2203
  const HeaderToolbar = () => {
@@ -2798,7 +2888,7 @@ const ConfirmBulkActionDialog = ({
2798
2888
  endAction
2799
2889
  }) => {
2800
2890
  const { formatMessage } = reactIntl.useIntl();
2801
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2891
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2802
2892
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2803
2893
  id: "app.components.ConfirmDialog.title",
2804
2894
  defaultMessage: "Confirmation"
@@ -3589,8 +3679,7 @@ class ContentManagerPlugin {
3589
3679
  documentActions = [
3590
3680
  ...DEFAULT_ACTIONS,
3591
3681
  ...DEFAULT_TABLE_ROW_ACTIONS,
3592
- ...DEFAULT_HEADER_ACTIONS,
3593
- HistoryAction
3682
+ ...DEFAULT_HEADER_ACTIONS
3594
3683
  ];
3595
3684
  editViewSidePanels = [ActionsPanel];
3596
3685
  headerActions = [];
@@ -3679,6 +3768,52 @@ const getPrintableType = (value) => {
3679
3768
  }
3680
3769
  return nativeType;
3681
3770
  };
3771
+ const HistoryAction = ({ model, document }) => {
3772
+ const { formatMessage } = reactIntl.useIntl();
3773
+ const [{ query }] = strapiAdmin.useQueryParams();
3774
+ const navigate = reactRouterDom.useNavigate();
3775
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3776
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3777
+ return null;
3778
+ }
3779
+ return {
3780
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3781
+ label: formatMessage({
3782
+ id: "content-manager.history.document-action",
3783
+ defaultMessage: "Content History"
3784
+ }),
3785
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3786
+ disabled: (
3787
+ /**
3788
+ * The user is creating a new document.
3789
+ * It hasn't been saved yet, so there's no history to go to
3790
+ */
3791
+ !document || /**
3792
+ * The document has been created but the current dimension has never been saved.
3793
+ * For example, the user is creating a new locale in an existing document,
3794
+ * so there's no history for the document in that locale
3795
+ */
3796
+ !document.id || /**
3797
+ * History is only available for content types created by the user.
3798
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3799
+ * which start with `admin::` or `plugin::`
3800
+ */
3801
+ !model.startsWith("api::")
3802
+ ),
3803
+ position: "header"
3804
+ };
3805
+ };
3806
+ HistoryAction.type = "history";
3807
+ const historyAdmin = {
3808
+ bootstrap(app) {
3809
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3810
+ addDocumentAction((actions2) => {
3811
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3812
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3813
+ return actions2;
3814
+ });
3815
+ }
3816
+ };
3682
3817
  const initialState = {
3683
3818
  collectionTypeLinks: [],
3684
3819
  components: [],
@@ -3734,7 +3869,7 @@ const index = {
3734
3869
  app.router.addRoute({
3735
3870
  path: "content-manager/*",
3736
3871
  lazy: async () => {
3737
- const { Layout } = await Promise.resolve().then(() => require("./layout-BLa_DTtQ.js"));
3872
+ const { Layout } = await Promise.resolve().then(() => require("./layout-Ci7qHlFb.js"));
3738
3873
  return {
3739
3874
  Component: Layout
3740
3875
  };
@@ -3743,10 +3878,15 @@ const index = {
3743
3878
  });
3744
3879
  app.registerPlugin(cm.config);
3745
3880
  },
3881
+ bootstrap(app) {
3882
+ if (typeof historyAdmin.bootstrap === "function") {
3883
+ historyAdmin.bootstrap(app);
3884
+ }
3885
+ },
3746
3886
  async registerTrads({ locales }) {
3747
3887
  const importedTrads = await Promise.all(
3748
3888
  locales.map((locale) => {
3749
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-fbKQxLGn.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3889
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-uOUIxfcQ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3750
3890
  return {
3751
3891
  data: prefixPluginTranslations(data, PLUGIN_ID),
3752
3892
  locale
@@ -3803,4 +3943,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3803
3943
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3804
3944
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3805
3945
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3806
- //# sourceMappingURL=index-iXGIUU_l.js.map
3946
+ //# sourceMappingURL=index-OerGjbAN.js.map