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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-C7ImeKGM.mjs → ComponentConfigurationPage-D0dyDTwq.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-C7ImeKGM.mjs.map → ComponentConfigurationPage-D0dyDTwq.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BWQv6yRj.js → ComponentConfigurationPage-DL1MHO8i.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-BWQv6yRj.js.map → ComponentConfigurationPage-DL1MHO8i.js.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-MItFGzT9.mjs → EditConfigurationPage-13b7S5Cq.mjs} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-MItFGzT9.mjs.map → EditConfigurationPage-13b7S5Cq.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-CEGwxV-L.js → EditConfigurationPage-CMaOf-A-.js} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-CEGwxV-L.js.map → EditConfigurationPage-CMaOf-A-.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-CmMi2Xsn.js → EditViewPage-BSVmMpRd.js} +3 -3
  10. package/dist/_chunks/{EditViewPage-CmMi2Xsn.js.map → EditViewPage-BSVmMpRd.js.map} +1 -1
  11. package/dist/_chunks/{EditViewPage-DhmAg0NK.mjs → EditViewPage-C3tIZ8F5.mjs} +3 -3
  12. package/dist/_chunks/{EditViewPage-DhmAg0NK.mjs.map → EditViewPage-C3tIZ8F5.mjs.map} +1 -1
  13. package/dist/_chunks/{Field-Cs62u5pl.mjs → Field-BvuT8cGL.mjs} +8 -8
  14. package/dist/_chunks/Field-BvuT8cGL.mjs.map +1 -0
  15. package/dist/_chunks/{Field-1DLtcLAI.js → Field-DUCVth4C.js} +8 -8
  16. package/dist/_chunks/Field-DUCVth4C.js.map +1 -0
  17. package/dist/_chunks/{Form-zYHtzGUX.mjs → Form-BZmDNVr9.mjs} +2 -2
  18. package/dist/_chunks/{Form-zYHtzGUX.mjs.map → Form-BZmDNVr9.mjs.map} +1 -1
  19. package/dist/_chunks/{Form-CqFA7F_V.js → Form-Cpl4W1ak.js} +2 -2
  20. package/dist/_chunks/{Form-CqFA7F_V.js.map → Form-Cpl4W1ak.js.map} +1 -1
  21. package/dist/_chunks/{History-DalgFQ3D.mjs → History-Cq_Hrzuu.mjs} +21 -11
  22. package/dist/_chunks/History-Cq_Hrzuu.mjs.map +1 -0
  23. package/dist/_chunks/{History-BblwXv7-.js → History-D4U2YISB.js} +21 -11
  24. package/dist/_chunks/History-D4U2YISB.js.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-Cpy4QqNd.js → ListConfigurationPage-Bny6CdWe.js} +2 -2
  26. package/dist/_chunks/{ListConfigurationPage-Cpy4QqNd.js.map → ListConfigurationPage-Bny6CdWe.js.map} +1 -1
  27. package/dist/_chunks/{ListConfigurationPage-DWy-vRzs.mjs → ListConfigurationPage-W-KQHmBv.mjs} +2 -2
  28. package/dist/_chunks/{ListConfigurationPage-DWy-vRzs.mjs.map → ListConfigurationPage-W-KQHmBv.mjs.map} +1 -1
  29. package/dist/_chunks/{ListViewPage-BkAwIW9s.mjs → ListViewPage-HBBnJa8K.mjs} +10 -5
  30. package/dist/_chunks/ListViewPage-HBBnJa8K.mjs.map +1 -0
  31. package/dist/_chunks/{ListViewPage-DFjn1DNW.js → ListViewPage-O8F1pBJo.js} +9 -4
  32. package/dist/_chunks/ListViewPage-O8F1pBJo.js.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-B9BCNNdL.mjs → NoContentTypePage-B-gIhHWM.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-B9BCNNdL.mjs.map → NoContentTypePage-B-gIhHWM.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-C-3ykoxs.js → NoContentTypePage-CQWChGPw.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-C-3ykoxs.js.map → NoContentTypePage-CQWChGPw.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DKLmDZnZ.js → NoPermissionsPage-CY46zxnM.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DKLmDZnZ.js.map → NoPermissionsPage-CY46zxnM.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-Bt_HWGat.mjs → NoPermissionsPage-XhOPl8wx.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-Bt_HWGat.mjs.map → NoPermissionsPage-XhOPl8wx.mjs.map} +1 -1
  41. package/dist/_chunks/{Relations-CrxfoH2n.js → Relations-C4gGfZRv.js} +3 -3
  42. package/dist/_chunks/Relations-C4gGfZRv.js.map +1 -0
  43. package/dist/_chunks/{Relations-CJmTbZ8T.mjs → Relations-vFZ6Wasg.mjs} +3 -3
  44. package/dist/_chunks/Relations-vFZ6Wasg.mjs.map +1 -0
  45. package/dist/_chunks/{en-Ux26r5pl.mjs → en-BrCTWlZv.mjs} +5 -4
  46. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  47. package/dist/_chunks/{en-fbKQxLGn.js → en-uOUIxfcQ.js} +5 -4
  48. package/dist/_chunks/{en-fbKQxLGn.js.map → en-uOUIxfcQ.js.map} +1 -1
  49. package/dist/_chunks/{index-Buwn78Rt.js → index-5EMXLEM_.js} +257 -139
  50. package/dist/_chunks/index-5EMXLEM_.js.map +1 -0
  51. package/dist/_chunks/{index-D1344xdw.mjs → index-Dpxg3ctD.mjs} +260 -142
  52. package/dist/_chunks/index-Dpxg3ctD.mjs.map +1 -0
  53. package/dist/_chunks/{layout-ChVuUpa1.mjs → layout-C0INpKap.mjs} +17 -5
  54. package/dist/_chunks/{layout-ChVuUpa1.mjs.map → layout-C0INpKap.mjs.map} +1 -1
  55. package/dist/_chunks/{layout-DRuJUpas.js → layout-P3eKO1Qy.js} +16 -4
  56. package/dist/_chunks/{layout-DRuJUpas.js.map → layout-P3eKO1Qy.js.map} +1 -1
  57. package/dist/_chunks/{relations-DuoUwyJr.js → relations-B1y0K6LE.js} +2 -2
  58. package/dist/_chunks/{relations-DuoUwyJr.js.map → relations-B1y0K6LE.js.map} +1 -1
  59. package/dist/_chunks/{relations-B-deMCy4.mjs → relations-FBRRBWeO.mjs} +2 -2
  60. package/dist/_chunks/{relations-B-deMCy4.mjs.map → relations-FBRRBWeO.mjs.map} +1 -1
  61. package/dist/admin/index.js +1 -1
  62. package/dist/admin/index.mjs +1 -1
  63. package/dist/admin/src/history/index.d.ts +3 -0
  64. package/dist/admin/src/index.d.ts +1 -0
  65. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  66. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  67. package/dist/server/index.js +130 -85
  68. package/dist/server/index.js.map +1 -1
  69. package/dist/server/index.mjs +131 -86
  70. package/dist/server/index.mjs.map +1 -1
  71. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  72. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  73. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  74. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  75. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  76. package/dist/server/src/history/services/utils.d.ts +1 -1
  77. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  78. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  79. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  80. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  81. package/package.json +6 -6
  82. package/dist/_chunks/Field-1DLtcLAI.js.map +0 -1
  83. package/dist/_chunks/Field-Cs62u5pl.mjs.map +0 -1
  84. package/dist/_chunks/History-BblwXv7-.js.map +0 -1
  85. package/dist/_chunks/History-DalgFQ3D.mjs.map +0 -1
  86. package/dist/_chunks/ListViewPage-BkAwIW9s.mjs.map +0 -1
  87. package/dist/_chunks/ListViewPage-DFjn1DNW.js.map +0 -1
  88. package/dist/_chunks/Relations-CJmTbZ8T.mjs.map +0 -1
  89. package/dist/_chunks/Relations-CrxfoH2n.js.map +0 -1
  90. package/dist/_chunks/index-Buwn78Rt.js.map +0 -1
  91. package/dist/_chunks/index-D1344xdw.mjs.map +0 -1
@@ -1,17 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import { useIntl } from "react-intl";
8
+ import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
9
  import { styled } from "styled-components";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
12
  import pipe from "lodash/fp/pipe";
14
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { stringify } from "qs";
15
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
17
  const v = glob[path];
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
49
49
  const [page, position] = area.split(".");
50
50
  return contentManagerPlugin.getInjectedComponents(page, position);
51
51
  };
52
- const HistoryAction = ({ model, document }) => {
53
- const { formatMessage } = useIntl();
54
- const [{ query }] = useQueryParams();
55
- const navigate = useNavigate();
56
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
57
- if (!window.strapi.features.isEnabled("cms-content-history")) {
58
- return null;
59
- }
60
- return {
61
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
62
- label: formatMessage({
63
- id: "content-manager.history.document-action",
64
- defaultMessage: "Content History"
65
- }),
66
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
67
- disabled: (
68
- /**
69
- * The user is creating a new document.
70
- * It hasn't been saved yet, so there's no history to go to
71
- */
72
- !document || /**
73
- * The document has been created but the current dimension has never been saved.
74
- * For example, the user is creating a new locale in an existing document,
75
- * so there's no history for the document in that locale
76
- */
77
- !document.id || /**
78
- * History is only available for content types created by the user.
79
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
80
- * which start with `admin::` or `plugin::`
81
- */
82
- !model.startsWith("api::")
83
- ),
84
- position: "header"
85
- };
86
- };
87
- HistoryAction.type = "history";
88
52
  const ID = "id";
89
53
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
90
54
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -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 }) => ({
@@ -295,6 +264,7 @@ const documentApi = contentManagerApi.injectEndpoints({
295
264
  }),
296
265
  providesTags: (result, _error, arg) => {
297
266
  return [
267
+ { type: "Document", id: `ALL_LIST` },
298
268
  { type: "Document", id: `${arg.model}_LIST` },
299
269
  ...result?.results.map(({ documentId }) => ({
300
270
  type: "Document",
@@ -333,6 +303,11 @@ const documentApi = contentManagerApi.injectEndpoints({
333
303
  {
334
304
  type: "Document",
335
305
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
306
+ },
307
+ // Make it easy to invalidate all individual documents queries for a model
308
+ {
309
+ type: "Document",
310
+ id: `${model}_ALL_ITEMS`
336
311
  }
337
312
  ];
338
313
  }
@@ -398,6 +373,18 @@ const documentApi = contentManagerApi.injectEndpoints({
398
373
  },
399
374
  "Relations"
400
375
  ];
376
+ },
377
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
378
+ const patchResult = dispatch(
379
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
380
+ Object.assign(draft.data, data);
381
+ })
382
+ );
383
+ try {
384
+ await queryFulfilled;
385
+ } catch {
386
+ patchResult.undo();
387
+ }
401
388
  }
402
389
  }),
403
390
  unpublishDocument: builder.mutation({
@@ -581,6 +568,14 @@ const createAttributeSchema = (attribute) => {
581
568
  if (!value || typeof value === "string" && value.length === 0) {
582
569
  return true;
583
570
  }
571
+ if (typeof value === "object") {
572
+ try {
573
+ JSON.stringify(value);
574
+ return true;
575
+ } catch (err) {
576
+ return false;
577
+ }
578
+ }
584
579
  try {
585
580
  JSON.parse(value);
586
581
  return true;
@@ -1210,7 +1205,6 @@ const useDocumentActions = () => {
1210
1205
  sourceId
1211
1206
  });
1212
1207
  if ("error" in res) {
1213
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1214
1208
  return { error: res.error };
1215
1209
  }
1216
1210
  toggleNotification({
@@ -1291,7 +1285,7 @@ const useDocumentActions = () => {
1291
1285
  };
1292
1286
  };
1293
1287
  const ProtectedHistoryPage = lazy(
1294
- () => import("./History-DalgFQ3D.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1288
+ () => import("./History-Cq_Hrzuu.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1295
1289
  );
1296
1290
  const routes$1 = [
1297
1291
  {
@@ -1304,31 +1298,31 @@ const routes$1 = [
1304
1298
  }
1305
1299
  ];
1306
1300
  const ProtectedEditViewPage = lazy(
1307
- () => import("./EditViewPage-DhmAg0NK.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1301
+ () => import("./EditViewPage-C3tIZ8F5.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1308
1302
  );
1309
1303
  const ProtectedListViewPage = lazy(
1310
- () => import("./ListViewPage-BkAwIW9s.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1304
+ () => import("./ListViewPage-HBBnJa8K.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1311
1305
  );
1312
1306
  const ProtectedListConfiguration = lazy(
1313
- () => import("./ListConfigurationPage-DWy-vRzs.mjs").then((mod) => ({
1307
+ () => import("./ListConfigurationPage-W-KQHmBv.mjs").then((mod) => ({
1314
1308
  default: mod.ProtectedListConfiguration
1315
1309
  }))
1316
1310
  );
1317
1311
  const ProtectedEditConfigurationPage = lazy(
1318
- () => import("./EditConfigurationPage-MItFGzT9.mjs").then((mod) => ({
1312
+ () => import("./EditConfigurationPage-13b7S5Cq.mjs").then((mod) => ({
1319
1313
  default: mod.ProtectedEditConfigurationPage
1320
1314
  }))
1321
1315
  );
1322
1316
  const ProtectedComponentConfigurationPage = lazy(
1323
- () => import("./ComponentConfigurationPage-C7ImeKGM.mjs").then((mod) => ({
1317
+ () => import("./ComponentConfigurationPage-D0dyDTwq.mjs").then((mod) => ({
1324
1318
  default: mod.ProtectedComponentConfigurationPage
1325
1319
  }))
1326
1320
  );
1327
1321
  const NoPermissions = lazy(
1328
- () => import("./NoPermissionsPage-Bt_HWGat.mjs").then((mod) => ({ default: mod.NoPermissions }))
1322
+ () => import("./NoPermissionsPage-XhOPl8wx.mjs").then((mod) => ({ default: mod.NoPermissions }))
1329
1323
  );
1330
1324
  const NoContentType = lazy(
1331
- () => import("./NoContentTypePage-B9BCNNdL.mjs").then((mod) => ({ default: mod.NoContentType }))
1325
+ () => import("./NoContentTypePage-B-gIhHWM.mjs").then((mod) => ({ default: mod.NoContentType }))
1332
1326
  );
1333
1327
  const CollectionTypePages = () => {
1334
1328
  const { collectionType } = useParams();
@@ -1442,7 +1436,7 @@ const DocumentActionButton = (action) => {
1442
1436
  /* @__PURE__ */ jsx(
1443
1437
  Button,
1444
1438
  {
1445
- flex: 1,
1439
+ flex: "auto",
1446
1440
  startIcon: action.icon,
1447
1441
  disabled: action.disabled,
1448
1442
  onClick: handleClick(action),
@@ -1455,7 +1449,7 @@ const DocumentActionButton = (action) => {
1455
1449
  DocumentActionConfirmDialog,
1456
1450
  {
1457
1451
  ...action.dialog,
1458
- variant: action.variant,
1452
+ variant: action.dialog?.variant ?? action.variant,
1459
1453
  isOpen: dialogId === action.id,
1460
1454
  onClose: handleClose
1461
1455
  }
@@ -1512,9 +1506,9 @@ const DocumentActionsMenu = ({
1512
1506
  disabled: isDisabled,
1513
1507
  size: "S",
1514
1508
  endIcon: null,
1515
- paddingTop: "7px",
1516
- paddingLeft: "9px",
1517
- paddingRight: "9px",
1509
+ paddingTop: "4px",
1510
+ paddingLeft: "7px",
1511
+ paddingRight: "7px",
1518
1512
  variant,
1519
1513
  children: [
1520
1514
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1534,10 +1528,18 @@ const DocumentActionsMenu = ({
1534
1528
  onSelect: handleClick(action),
1535
1529
  display: "block",
1536
1530
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1537
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1538
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1539
- action.label
1540
- ] }),
1531
+ /* @__PURE__ */ jsxs(
1532
+ Flex,
1533
+ {
1534
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1535
+ gap: 2,
1536
+ tag: "span",
1537
+ children: [
1538
+ /* @__PURE__ */ jsx("span", { children: action.icon }),
1539
+ action.label
1540
+ ]
1541
+ }
1542
+ ),
1541
1543
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1542
1544
  Flex,
1543
1545
  {
@@ -1596,18 +1598,6 @@ const convertActionVariantToColor = (variant = "secondary") => {
1596
1598
  return "primary600";
1597
1599
  }
1598
1600
  };
1599
- const convertActionVariantToIconColor = (variant = "secondary") => {
1600
- switch (variant) {
1601
- case "danger":
1602
- return "danger600";
1603
- case "secondary":
1604
- return "neutral500";
1605
- case "success":
1606
- return "success600";
1607
- default:
1608
- return "primary600";
1609
- }
1610
- };
1611
1601
  const DocumentActionConfirmDialog = ({
1612
1602
  onClose,
1613
1603
  onCancel,
@@ -1661,8 +1651,8 @@ const DocumentActionModal = ({
1661
1651
  };
1662
1652
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1663
1653
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1664
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1665
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1654
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1655
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1666
1656
  ] }) });
1667
1657
  };
1668
1658
  const PublishAction$1 = ({
@@ -1684,6 +1674,12 @@ const PublishAction$1 = ({
1684
1674
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1685
1675
  );
1686
1676
  const { publish } = useDocumentActions();
1677
+ const [
1678
+ countDraftRelations,
1679
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1680
+ ] = useLazyGetDraftRelationCountQuery();
1681
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1682
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1687
1683
  const [{ query, rawQuery }] = useQueryParams();
1688
1684
  const params = React.useMemo(() => buildValidParams(query), [query]);
1689
1685
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1692,10 +1688,101 @@ const PublishAction$1 = ({
1692
1688
  const validate = useForm("PublishAction", (state) => state.validate);
1693
1689
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1694
1690
  const formValues = useForm("PublishAction", ({ values }) => values);
1691
+ React.useEffect(() => {
1692
+ if (isErrorDraftRelations) {
1693
+ toggleNotification({
1694
+ type: "danger",
1695
+ message: formatMessage({
1696
+ id: getTranslation("error.records.fetch-draft-relatons"),
1697
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1698
+ })
1699
+ });
1700
+ }
1701
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1702
+ React.useEffect(() => {
1703
+ const localDraftRelations = /* @__PURE__ */ new Set();
1704
+ const extractDraftRelations = (data) => {
1705
+ const relations = data.connect || [];
1706
+ relations.forEach((relation) => {
1707
+ if (relation.status === "draft") {
1708
+ localDraftRelations.add(relation.id);
1709
+ }
1710
+ });
1711
+ };
1712
+ const traverseAndExtract = (data) => {
1713
+ Object.entries(data).forEach(([key, value]) => {
1714
+ if (key === "connect" && Array.isArray(value)) {
1715
+ extractDraftRelations({ connect: value });
1716
+ } else if (typeof value === "object" && value !== null) {
1717
+ traverseAndExtract(value);
1718
+ }
1719
+ });
1720
+ };
1721
+ if (!documentId || modified) {
1722
+ traverseAndExtract(formValues);
1723
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1724
+ }
1725
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1726
+ React.useEffect(() => {
1727
+ if (documentId) {
1728
+ const fetchDraftRelationsCount = async () => {
1729
+ const { data, error } = await countDraftRelations({
1730
+ collectionType,
1731
+ model,
1732
+ documentId,
1733
+ params
1734
+ });
1735
+ if (error) {
1736
+ throw error;
1737
+ }
1738
+ if (data) {
1739
+ setServerCountOfDraftRelations(data.data);
1740
+ }
1741
+ };
1742
+ fetchDraftRelationsCount();
1743
+ }
1744
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1695
1745
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1696
1746
  if (!schema?.options?.draftAndPublish) {
1697
1747
  return null;
1698
1748
  }
1749
+ const performPublish = async () => {
1750
+ setSubmitting(true);
1751
+ try {
1752
+ const { errors } = await validate();
1753
+ if (errors) {
1754
+ toggleNotification({
1755
+ type: "danger",
1756
+ message: formatMessage({
1757
+ id: "content-manager.validation.error",
1758
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1759
+ })
1760
+ });
1761
+ return;
1762
+ }
1763
+ const res = await publish(
1764
+ {
1765
+ collectionType,
1766
+ model,
1767
+ documentId,
1768
+ params
1769
+ },
1770
+ formValues
1771
+ );
1772
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1773
+ navigate({
1774
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1775
+ search: rawQuery
1776
+ });
1777
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1778
+ setErrors(formatValidationErrors(res.error));
1779
+ }
1780
+ } finally {
1781
+ setSubmitting(false);
1782
+ }
1783
+ };
1784
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1785
+ const hasDraftRelations = totalDraftRelations > 0;
1699
1786
  return {
1700
1787
  /**
1701
1788
  * Disabled when:
@@ -1705,49 +1792,39 @@ const PublishAction$1 = ({
1705
1792
  * - the document is already published & not modified
1706
1793
  * - the document is being created & not modified
1707
1794
  * - the user doesn't have the permission to publish
1708
- * - the user doesn't have the permission to create a new document
1709
- * - the user doesn't have the permission to update the document
1710
1795
  */
1711
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1796
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1712
1797
  label: formatMessage({
1713
1798
  id: "app.utils.publish",
1714
1799
  defaultMessage: "Publish"
1715
1800
  }),
1716
1801
  onClick: async () => {
1717
- setSubmitting(true);
1718
- try {
1719
- const { errors } = await validate();
1720
- if (errors) {
1721
- toggleNotification({
1722
- type: "danger",
1723
- message: formatMessage({
1724
- id: "content-manager.validation.error",
1725
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1726
- })
1727
- });
1728
- return;
1729
- }
1730
- const res = await publish(
1731
- {
1732
- collectionType,
1733
- model,
1734
- documentId,
1735
- params
1736
- },
1737
- formValues
1738
- );
1739
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1740
- navigate({
1741
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1742
- search: rawQuery
1743
- });
1744
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1745
- setErrors(formatValidationErrors(res.error));
1802
+ if (hasDraftRelations) {
1803
+ return;
1804
+ }
1805
+ await performPublish();
1806
+ },
1807
+ dialog: hasDraftRelations ? {
1808
+ type: "dialog",
1809
+ variant: "danger",
1810
+ footer: null,
1811
+ title: formatMessage({
1812
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1813
+ defaultMessage: "Confirmation"
1814
+ }),
1815
+ content: formatMessage(
1816
+ {
1817
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1818
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1819
+ },
1820
+ {
1821
+ count: totalDraftRelations
1746
1822
  }
1747
- } finally {
1748
- setSubmitting(false);
1823
+ ),
1824
+ onConfirm: async () => {
1825
+ await performPublish();
1749
1826
  }
1750
- }
1827
+ } : void 0
1751
1828
  };
1752
1829
  };
1753
1830
  PublishAction$1.type = "publish";
@@ -1763,7 +1840,7 @@ const UpdateAction = ({
1763
1840
  const cloneMatch = useMatch(CLONE_PATH);
1764
1841
  const isCloning = cloneMatch !== null;
1765
1842
  const { formatMessage } = useIntl();
1766
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1843
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1767
1844
  canCreate: canCreate2,
1768
1845
  canUpdate: canUpdate2
1769
1846
  }));
@@ -1783,10 +1860,8 @@ const UpdateAction = ({
1783
1860
  * - the form is submitting
1784
1861
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1785
1862
  * - the active tab is the published tab
1786
- * - the user doesn't have the permission to create a new document
1787
- * - the user doesn't have the permission to update the document
1788
1863
  */
1789
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1864
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1790
1865
  label: formatMessage({
1791
1866
  id: "content-manager.containers.Edit.save",
1792
1867
  defaultMessage: "Save"
@@ -1815,10 +1890,13 @@ const UpdateAction = ({
1815
1890
  document
1816
1891
  );
1817
1892
  if ("data" in res) {
1818
- navigate({
1819
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1820
- search: rawQuery
1821
- });
1893
+ navigate(
1894
+ {
1895
+ pathname: `../${res.data.documentId}`,
1896
+ search: rawQuery
1897
+ },
1898
+ { relative: "path" }
1899
+ );
1822
1900
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1823
1901
  setErrors(formatValidationErrors(res.error));
1824
1902
  }
@@ -1848,10 +1926,10 @@ const UpdateAction = ({
1848
1926
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1849
1927
  navigate(
1850
1928
  {
1851
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1929
+ pathname: `../${res.data.documentId}`,
1852
1930
  search: rawQuery
1853
1931
  },
1854
- { replace: true }
1932
+ { replace: true, relative: "path" }
1855
1933
  );
1856
1934
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1857
1935
  setErrors(formatValidationErrors(res.error));
@@ -2098,23 +2176,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2098
2176
  id: "content-manager.containers.edit.title.new",
2099
2177
  defaultMessage: "Create an entry"
2100
2178
  }) : documentTitle;
2101
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2179
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2102
2180
  /* @__PURE__ */ jsx(BackButton, {}),
2103
- /* @__PURE__ */ jsxs(
2104
- Flex,
2105
- {
2106
- width: "100%",
2107
- justifyContent: "space-between",
2108
- paddingTop: 1,
2109
- gap: "80px",
2110
- alignItems: "flex-start",
2111
- children: [
2112
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2113
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2114
- ]
2115
- }
2116
- ),
2117
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2181
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2182
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2183
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2184
+ ] }),
2185
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2118
2186
  ] });
2119
2187
  };
2120
2188
  const HeaderToolbar = () => {
@@ -2805,7 +2873,7 @@ const ConfirmBulkActionDialog = ({
2805
2873
  endAction
2806
2874
  }) => {
2807
2875
  const { formatMessage } = useIntl();
2808
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2876
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2809
2877
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2810
2878
  id: "app.components.ConfirmDialog.title",
2811
2879
  defaultMessage: "Confirmation"
@@ -3596,8 +3664,7 @@ class ContentManagerPlugin {
3596
3664
  documentActions = [
3597
3665
  ...DEFAULT_ACTIONS,
3598
3666
  ...DEFAULT_TABLE_ROW_ACTIONS,
3599
- ...DEFAULT_HEADER_ACTIONS,
3600
- HistoryAction
3667
+ ...DEFAULT_HEADER_ACTIONS
3601
3668
  ];
3602
3669
  editViewSidePanels = [ActionsPanel];
3603
3670
  headerActions = [];
@@ -3686,6 +3753,52 @@ const getPrintableType = (value) => {
3686
3753
  }
3687
3754
  return nativeType;
3688
3755
  };
3756
+ const HistoryAction = ({ model, document }) => {
3757
+ const { formatMessage } = useIntl();
3758
+ const [{ query }] = useQueryParams();
3759
+ const navigate = useNavigate();
3760
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3761
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3762
+ return null;
3763
+ }
3764
+ return {
3765
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3766
+ label: formatMessage({
3767
+ id: "content-manager.history.document-action",
3768
+ defaultMessage: "Content History"
3769
+ }),
3770
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3771
+ disabled: (
3772
+ /**
3773
+ * The user is creating a new document.
3774
+ * It hasn't been saved yet, so there's no history to go to
3775
+ */
3776
+ !document || /**
3777
+ * The document has been created but the current dimension has never been saved.
3778
+ * For example, the user is creating a new locale in an existing document,
3779
+ * so there's no history for the document in that locale
3780
+ */
3781
+ !document.id || /**
3782
+ * History is only available for content types created by the user.
3783
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3784
+ * which start with `admin::` or `plugin::`
3785
+ */
3786
+ !model.startsWith("api::")
3787
+ ),
3788
+ position: "header"
3789
+ };
3790
+ };
3791
+ HistoryAction.type = "history";
3792
+ const historyAdmin = {
3793
+ bootstrap(app) {
3794
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3795
+ addDocumentAction((actions2) => {
3796
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3797
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3798
+ return actions2;
3799
+ });
3800
+ }
3801
+ };
3689
3802
  const initialState = {
3690
3803
  collectionTypeLinks: [],
3691
3804
  components: [],
@@ -3741,7 +3854,7 @@ const index = {
3741
3854
  app.router.addRoute({
3742
3855
  path: "content-manager/*",
3743
3856
  lazy: async () => {
3744
- const { Layout } = await import("./layout-ChVuUpa1.mjs");
3857
+ const { Layout } = await import("./layout-C0INpKap.mjs");
3745
3858
  return {
3746
3859
  Component: Layout
3747
3860
  };
@@ -3750,10 +3863,15 @@ const index = {
3750
3863
  });
3751
3864
  app.registerPlugin(cm.config);
3752
3865
  },
3866
+ bootstrap(app) {
3867
+ if (typeof historyAdmin.bootstrap === "function") {
3868
+ historyAdmin.bootstrap(app);
3869
+ }
3870
+ },
3753
3871
  async registerTrads({ locales }) {
3754
3872
  const importedTrads = await Promise.all(
3755
3873
  locales.map((locale) => {
3756
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Ux26r5pl.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3874
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-BrCTWlZv.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3757
3875
  return {
3758
3876
  data: prefixPluginTranslations(data, PLUGIN_ID),
3759
3877
  locale
@@ -3812,4 +3930,4 @@ export {
3812
3930
  useUpdateContentTypeConfigurationMutation as y,
3813
3931
  extractContentTypeComponents as z
3814
3932
  };
3815
- //# sourceMappingURL=index-D1344xdw.mjs.map
3933
+ //# sourceMappingURL=index-Dpxg3ctD.mjs.map