@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
@@ -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) => {
603
- if (attribute.required) {
604
- return schema.required({
605
- id: translatedErrors.required.id,
606
- defaultMessage: "This field is required."
607
- });
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);
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,
@@ -764,7 +767,10 @@ const useDocument = (args, opts) => {
764
767
  isLoading: isLoadingDocument,
765
768
  isFetching: isFetchingDocument,
766
769
  error
767
- } = useGetDocumentQuery(args, opts);
770
+ } = useGetDocumentQuery(args, {
771
+ ...opts,
772
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
773
+ });
768
774
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
769
775
  React.useEffect(() => {
770
776
  if (error) {
@@ -1185,7 +1191,6 @@ const useDocumentActions = () => {
1185
1191
  sourceId
1186
1192
  });
1187
1193
  if ("error" in res) {
1188
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1189
1194
  return { error: res.error };
1190
1195
  }
1191
1196
  toggleNotification({
@@ -1266,7 +1271,7 @@ const useDocumentActions = () => {
1266
1271
  };
1267
1272
  };
1268
1273
  const ProtectedHistoryPage = lazy(
1269
- () => import("./History-DOWk7MB4.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1274
+ () => import("./History-wrnHqf09.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1270
1275
  );
1271
1276
  const routes$1 = [
1272
1277
  {
@@ -1279,31 +1284,31 @@ const routes$1 = [
1279
1284
  }
1280
1285
  ];
1281
1286
  const ProtectedEditViewPage = lazy(
1282
- () => import("./EditViewPage-DQUCbpW-.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1287
+ () => import("./EditViewPage-BLsjc5F-.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1283
1288
  );
1284
1289
  const ProtectedListViewPage = lazy(
1285
- () => import("./ListViewPage-D_MY3zjg.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1290
+ () => import("./ListViewPage-C4IvrMgY.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1286
1291
  );
1287
1292
  const ProtectedListConfiguration = lazy(
1288
- () => import("./ListConfigurationPage-lN3NMkhK.mjs").then((mod) => ({
1293
+ () => import("./ListConfigurationPage-DScmJVkW.mjs").then((mod) => ({
1289
1294
  default: mod.ProtectedListConfiguration
1290
1295
  }))
1291
1296
  );
1292
1297
  const ProtectedEditConfigurationPage = lazy(
1293
- () => import("./EditConfigurationPage-B8UqkdtD.mjs").then((mod) => ({
1298
+ () => import("./EditConfigurationPage-DmoXawIh.mjs").then((mod) => ({
1294
1299
  default: mod.ProtectedEditConfigurationPage
1295
1300
  }))
1296
1301
  );
1297
1302
  const ProtectedComponentConfigurationPage = lazy(
1298
- () => import("./ComponentConfigurationPage-B5mDY7I0.mjs").then((mod) => ({
1303
+ () => import("./ComponentConfigurationPage-BAgyHiMm.mjs").then((mod) => ({
1299
1304
  default: mod.ProtectedComponentConfigurationPage
1300
1305
  }))
1301
1306
  );
1302
1307
  const NoPermissions = lazy(
1303
- () => import("./NoPermissionsPage-B-DP9Ht4.mjs").then((mod) => ({ default: mod.NoPermissions }))
1308
+ () => import("./NoPermissionsPage-DSP7R-hv.mjs").then((mod) => ({ default: mod.NoPermissions }))
1304
1309
  );
1305
1310
  const NoContentType = lazy(
1306
- () => import("./NoContentTypePage-CUrrV_mP.mjs").then((mod) => ({ default: mod.NoContentType }))
1311
+ () => import("./NoContentTypePage-Djg8nPlj.mjs").then((mod) => ({ default: mod.NoContentType }))
1307
1312
  );
1308
1313
  const CollectionTypePages = () => {
1309
1314
  const { collectionType } = useParams();
@@ -1430,7 +1435,7 @@ const DocumentActionButton = (action) => {
1430
1435
  DocumentActionConfirmDialog,
1431
1436
  {
1432
1437
  ...action.dialog,
1433
- variant: action.variant,
1438
+ variant: action.dialog?.variant ?? action.variant,
1434
1439
  isOpen: dialogId === action.id,
1435
1440
  onClose: handleClose
1436
1441
  }
@@ -1659,6 +1664,12 @@ const PublishAction$1 = ({
1659
1664
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1660
1665
  );
1661
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);
1662
1673
  const [{ query, rawQuery }] = useQueryParams();
1663
1674
  const params = React.useMemo(() => buildValidParams(query), [query]);
1664
1675
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1667,10 +1678,101 @@ const PublishAction$1 = ({
1667
1678
  const validate = useForm("PublishAction", (state) => state.validate);
1668
1679
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1669
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]);
1670
1735
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1671
1736
  if (!schema?.options?.draftAndPublish) {
1672
1737
  return null;
1673
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;
1674
1776
  return {
1675
1777
  /**
1676
1778
  * Disabled when:
@@ -1683,46 +1785,38 @@ const PublishAction$1 = ({
1683
1785
  * - the user doesn't have the permission to create a new document
1684
1786
  * - the user doesn't have the permission to update the document
1685
1787
  */
1686
- 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),
1687
1789
  label: formatMessage({
1688
1790
  id: "app.utils.publish",
1689
1791
  defaultMessage: "Publish"
1690
1792
  }),
1691
1793
  onClick: async () => {
1692
- setSubmitting(true);
1693
- try {
1694
- const { errors } = await validate();
1695
- if (errors) {
1696
- toggleNotification({
1697
- type: "danger",
1698
- message: formatMessage({
1699
- id: "content-manager.validation.error",
1700
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1701
- })
1702
- });
1703
- return;
1704
- }
1705
- const res = await publish(
1706
- {
1707
- collectionType,
1708
- model,
1709
- documentId,
1710
- params
1711
- },
1712
- formValues
1713
- );
1714
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1715
- navigate({
1716
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1717
- search: rawQuery
1718
- });
1719
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1720
- 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
1721
1814
  }
1722
- } finally {
1723
- setSubmitting(false);
1815
+ ),
1816
+ onConfirm: async () => {
1817
+ await performPublish();
1724
1818
  }
1725
- }
1819
+ } : void 0
1726
1820
  };
1727
1821
  };
1728
1822
  PublishAction$1.type = "publish";
@@ -1790,10 +1884,13 @@ const UpdateAction = ({
1790
1884
  document
1791
1885
  );
1792
1886
  if ("data" in res) {
1793
- navigate({
1794
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1795
- search: rawQuery
1796
- });
1887
+ navigate(
1888
+ {
1889
+ pathname: `../${res.data.documentId}`,
1890
+ search: rawQuery
1891
+ },
1892
+ { relative: "path" }
1893
+ );
1797
1894
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1798
1895
  setErrors(formatValidationErrors(res.error));
1799
1896
  }
@@ -1821,10 +1918,13 @@ const UpdateAction = ({
1821
1918
  document
1822
1919
  );
1823
1920
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1824
- navigate({
1825
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1826
- search: rawQuery
1827
- });
1921
+ navigate(
1922
+ {
1923
+ pathname: `../${res.data.documentId}`,
1924
+ search: rawQuery
1925
+ },
1926
+ { replace: true, relative: "path" }
1927
+ );
1828
1928
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1829
1929
  setErrors(formatValidationErrors(res.error));
1830
1930
  }
@@ -2070,23 +2170,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2070
2170
  id: "content-manager.containers.edit.title.new",
2071
2171
  defaultMessage: "Create an entry"
2072
2172
  }) : documentTitle;
2073
- 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: [
2074
2174
  /* @__PURE__ */ jsx(BackButton, {}),
2075
- /* @__PURE__ */ jsxs(
2076
- Flex,
2077
- {
2078
- width: "100%",
2079
- justifyContent: "space-between",
2080
- paddingTop: 1,
2081
- gap: "80px",
2082
- alignItems: "flex-start",
2083
- children: [
2084
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2085
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2086
- ]
2087
- }
2088
- ),
2089
- 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
2090
2180
  ] });
2091
2181
  };
2092
2182
  const HeaderToolbar = () => {
@@ -2777,7 +2867,7 @@ const ConfirmBulkActionDialog = ({
2777
2867
  endAction
2778
2868
  }) => {
2779
2869
  const { formatMessage } = useIntl();
2780
- 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: [
2781
2871
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2782
2872
  id: "app.components.ConfirmDialog.title",
2783
2873
  defaultMessage: "Confirmation"
@@ -3568,8 +3658,7 @@ class ContentManagerPlugin {
3568
3658
  documentActions = [
3569
3659
  ...DEFAULT_ACTIONS,
3570
3660
  ...DEFAULT_TABLE_ROW_ACTIONS,
3571
- ...DEFAULT_HEADER_ACTIONS,
3572
- HistoryAction
3661
+ ...DEFAULT_HEADER_ACTIONS
3573
3662
  ];
3574
3663
  editViewSidePanels = [ActionsPanel];
3575
3664
  headerActions = [];
@@ -3658,6 +3747,52 @@ const getPrintableType = (value) => {
3658
3747
  }
3659
3748
  return nativeType;
3660
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
+ };
3661
3796
  const initialState = {
3662
3797
  collectionTypeLinks: [],
3663
3798
  components: [],
@@ -3713,7 +3848,7 @@ const index = {
3713
3848
  app.router.addRoute({
3714
3849
  path: "content-manager/*",
3715
3850
  lazy: async () => {
3716
- const { Layout } = await import("./layout-DT9g7_U1.mjs");
3851
+ const { Layout } = await import("./layout-oPBiO7RY.mjs");
3717
3852
  return {
3718
3853
  Component: Layout
3719
3854
  };
@@ -3722,10 +3857,15 @@ const index = {
3722
3857
  });
3723
3858
  app.registerPlugin(cm.config);
3724
3859
  },
3860
+ bootstrap(app) {
3861
+ if (typeof historyAdmin.bootstrap === "function") {
3862
+ historyAdmin.bootstrap(app);
3863
+ }
3864
+ },
3725
3865
  async registerTrads({ locales }) {
3726
3866
  const importedTrads = await Promise.all(
3727
3867
  locales.map((locale) => {
3728
- 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 }) => {
3729
3869
  return {
3730
3870
  data: prefixPluginTranslations(data, PLUGIN_ID),
3731
3871
  locale
@@ -3784,4 +3924,4 @@ export {
3784
3924
  useUpdateContentTypeConfigurationMutation as y,
3785
3925
  extractContentTypeComponents as z
3786
3926
  };
3787
- //# sourceMappingURL=index-BYpa_5O9.mjs.map
3927
+ //# sourceMappingURL=index-c_5DdJi-.mjs.map