@strapi/content-manager 0.0.0-experimental.62ce06180fe9a772eaeb3d43d238b26644f39f7c → 0.0.0-experimental.6d27139261823fc4b18da9f3c10b271d5010dbf0

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 (117) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs → ComponentConfigurationPage-9lRmRdIr.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs.map → ComponentConfigurationPage-9lRmRdIr.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js → ComponentConfigurationPage-DyDkPajU.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js.map → ComponentConfigurationPage-DyDkPajU.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs → EditConfigurationPage-Bk893vVY.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs.map → EditConfigurationPage-Bk893vVY.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js → EditConfigurationPage-DValmA0m.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js.map → EditConfigurationPage-DValmA0m.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-ClIueJnM.mjs → EditViewPage-DiNFdFqP.mjs} +19 -8
  11. package/dist/_chunks/EditViewPage-DiNFdFqP.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-DxyAOItK.js → EditViewPage-Dk7Eaft4.js} +19 -8
  13. package/dist/_chunks/EditViewPage-Dk7Eaft4.js.map +1 -0
  14. package/dist/_chunks/{Field-C0Y_SR9e.js → Field-DH2OaqUP.js} +458 -128
  15. package/dist/_chunks/Field-DH2OaqUP.js.map +1 -0
  16. package/dist/_chunks/{Field-BZBYmvaf.mjs → Field-Dv_HTFTa.mjs} +460 -130
  17. package/dist/_chunks/Field-Dv_HTFTa.mjs.map +1 -0
  18. package/dist/_chunks/{Form-DwvGnISS.js → Form-B_dUDizM.js} +22 -11
  19. package/dist/_chunks/Form-B_dUDizM.js.map +1 -0
  20. package/dist/_chunks/{Form-jwRSC2kV.mjs → Form-Dy6P4HgH.mjs} +22 -11
  21. package/dist/_chunks/Form-Dy6P4HgH.mjs.map +1 -0
  22. package/dist/_chunks/{History-Cda0Yjzz.js → History-BT4w83Oa.js} +44 -19
  23. package/dist/_chunks/History-BT4w83Oa.js.map +1 -0
  24. package/dist/_chunks/{History-BgzAIj0G.mjs → History-DrwsD1Vc.mjs} +44 -19
  25. package/dist/_chunks/History-DrwsD1Vc.mjs.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-GH55qfoT.mjs → ListConfigurationPage-BxIP0jRy.mjs} +20 -8
  27. package/dist/_chunks/ListConfigurationPage-BxIP0jRy.mjs.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-C29EF97r.js → ListConfigurationPage-CuYrMcW3.js} +20 -8
  29. package/dist/_chunks/ListConfigurationPage-CuYrMcW3.js.map +1 -0
  30. package/dist/_chunks/{ListViewPage-QU03PFj1.mjs → ListViewPage-5a1vw-OK.mjs} +40 -34
  31. package/dist/_chunks/ListViewPage-5a1vw-OK.mjs.map +1 -0
  32. package/dist/_chunks/{ListViewPage-CnRt0UT7.js → ListViewPage-BvpwNur7.js} +38 -32
  33. package/dist/_chunks/ListViewPage-BvpwNur7.js.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs → NoContentTypePage-Bm6tRcd3.mjs} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs.map → NoContentTypePage-Bm6tRcd3.mjs.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DFDjxByI.js → NoContentTypePage-UqEiWKkM.js} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DFDjxByI.js.map → NoContentTypePage-UqEiWKkM.js.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs → NoPermissionsPage-BHPqn_tQ.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs.map → NoPermissionsPage-BHPqn_tQ.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js → NoPermissionsPage-C_vGRo8Q.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js.map → NoPermissionsPage-C_vGRo8Q.js.map} +1 -1
  42. package/dist/_chunks/{Relations-KMf5qEN0.mjs → Relations-C7fPyh5P.mjs} +4 -4
  43. package/dist/_chunks/Relations-C7fPyh5P.mjs.map +1 -0
  44. package/dist/_chunks/{Relations-BjpPPCKp.js → Relations-CznVF6LS.js} +4 -4
  45. package/dist/_chunks/Relations-CznVF6LS.js.map +1 -0
  46. package/dist/_chunks/{en-Ux26r5pl.mjs → en-CbaIuYoB.mjs} +6 -5
  47. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-CbaIuYoB.mjs.map} +1 -1
  48. package/dist/_chunks/{en-fbKQxLGn.js → en-otD_UBJi.js} +6 -5
  49. package/dist/_chunks/{en-fbKQxLGn.js.map → en-otD_UBJi.js.map} +1 -1
  50. package/dist/_chunks/{index-6kKXK7y8.mjs → index-BJ6uTqLL.mjs} +381 -190
  51. package/dist/_chunks/index-BJ6uTqLL.mjs.map +1 -0
  52. package/dist/_chunks/{index-D9ZwczCV.js → index-D9UmmBcM.js} +374 -183
  53. package/dist/_chunks/index-D9UmmBcM.js.map +1 -0
  54. package/dist/_chunks/{layout-BJfBoBiF.js → layout-kfu5Wtix.js} +23 -11
  55. package/dist/_chunks/layout-kfu5Wtix.js.map +1 -0
  56. package/dist/_chunks/{layout-B1Z-9koY.mjs → layout-uomiIGbG.mjs} +25 -13
  57. package/dist/_chunks/layout-uomiIGbG.mjs.map +1 -0
  58. package/dist/_chunks/{relations-CMvjzyU3.js → relations-DKENrxko.js} +2 -2
  59. package/dist/_chunks/{relations-CMvjzyU3.js.map → relations-DKENrxko.js.map} +1 -1
  60. package/dist/_chunks/{relations-CgZg7Pyx.mjs → relations-DiDufGSA.mjs} +2 -2
  61. package/dist/_chunks/{relations-CgZg7Pyx.mjs.map → relations-DiDufGSA.mjs.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/history/services/historyVersion.d.ts +1 -1
  66. package/dist/admin/src/index.d.ts +1 -0
  67. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  68. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  69. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  70. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  71. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  73. package/dist/admin/src/services/api.d.ts +1 -1
  74. package/dist/admin/src/services/components.d.ts +2 -2
  75. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  76. package/dist/admin/src/services/documents.d.ts +16 -16
  77. package/dist/admin/src/services/init.d.ts +1 -1
  78. package/dist/admin/src/services/relations.d.ts +2 -2
  79. package/dist/admin/src/services/uid.d.ts +3 -3
  80. package/dist/admin/src/utils/validation.d.ts +4 -1
  81. package/dist/server/index.js +175 -104
  82. package/dist/server/index.js.map +1 -1
  83. package/dist/server/index.mjs +176 -105
  84. package/dist/server/index.mjs.map +1 -1
  85. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  86. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  87. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  88. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  89. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  90. package/dist/server/src/history/services/history.d.ts.map +1 -1
  91. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  92. package/dist/server/src/history/services/utils.d.ts +2 -1
  93. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  94. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  95. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  96. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  97. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  98. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  99. package/package.json +8 -8
  100. package/dist/_chunks/EditViewPage-ClIueJnM.mjs.map +0 -1
  101. package/dist/_chunks/EditViewPage-DxyAOItK.js.map +0 -1
  102. package/dist/_chunks/Field-BZBYmvaf.mjs.map +0 -1
  103. package/dist/_chunks/Field-C0Y_SR9e.js.map +0 -1
  104. package/dist/_chunks/Form-DwvGnISS.js.map +0 -1
  105. package/dist/_chunks/Form-jwRSC2kV.mjs.map +0 -1
  106. package/dist/_chunks/History-BgzAIj0G.mjs.map +0 -1
  107. package/dist/_chunks/History-Cda0Yjzz.js.map +0 -1
  108. package/dist/_chunks/ListConfigurationPage-C29EF97r.js.map +0 -1
  109. package/dist/_chunks/ListConfigurationPage-GH55qfoT.mjs.map +0 -1
  110. package/dist/_chunks/ListViewPage-CnRt0UT7.js.map +0 -1
  111. package/dist/_chunks/ListViewPage-QU03PFj1.mjs.map +0 -1
  112. package/dist/_chunks/Relations-BjpPPCKp.js.map +0 -1
  113. package/dist/_chunks/Relations-KMf5qEN0.mjs.map +0 -1
  114. package/dist/_chunks/index-6kKXK7y8.mjs.map +0 -1
  115. package/dist/_chunks/index-D9ZwczCV.js.map +0 -1
  116. package/dist/_chunks/layout-B1Z-9koY.mjs.map +0 -1
  117. package/dist/_chunks/layout-BJfBoBiF.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- 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, useNavigate, Navigate, 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";
@@ -195,8 +159,7 @@ const contentManagerApi = adminApi.enhanceEndpoints({
195
159
  "InitialData",
196
160
  "HistoryVersion",
197
161
  "Relations",
198
- "Release",
199
- "ReleaseAction"
162
+ "UidAvailability"
200
163
  ]
201
164
  });
202
165
  const documentApi = contentManagerApi.injectEndpoints({
@@ -210,7 +173,12 @@ const documentApi = contentManagerApi.injectEndpoints({
210
173
  params: query
211
174
  }
212
175
  }),
213
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
176
+ invalidatesTags: (_result, error, { model }) => {
177
+ if (error) {
178
+ return [];
179
+ }
180
+ return [{ type: "Document", id: `${model}_LIST` }];
181
+ }
214
182
  }),
215
183
  cloneDocument: builder.mutation({
216
184
  query: ({ model, sourceId, data, params }) => ({
@@ -221,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
221
189
  params
222
190
  }
223
191
  }),
224
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
192
+ invalidatesTags: (_result, _error, { model }) => [
193
+ { type: "Document", id: `${model}_LIST` },
194
+ { type: "UidAvailability", id: model }
195
+ ]
225
196
  }),
226
197
  /**
227
198
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -238,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
238
209
  }),
239
210
  invalidatesTags: (result, _error, { model }) => [
240
211
  { type: "Document", id: `${model}_LIST` },
241
- "Relations"
212
+ "Relations",
213
+ { type: "UidAvailability", id: model }
242
214
  ]
243
215
  }),
244
216
  deleteDocument: builder.mutation({
@@ -250,9 +222,7 @@ const documentApi = contentManagerApi.injectEndpoints({
250
222
  }
251
223
  }),
252
224
  invalidatesTags: (_result, _error, { collectionType, model }) => [
253
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
254
- { type: "Release", id: "LIST" },
255
- { type: "ReleaseAction", id: "LIST" }
225
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
256
226
  ]
257
227
  }),
258
228
  deleteManyDocuments: builder.mutation({
@@ -264,11 +234,7 @@ const documentApi = contentManagerApi.injectEndpoints({
264
234
  params
265
235
  }
266
236
  }),
267
- invalidatesTags: (_res, _error, { model }) => [
268
- { type: "Document", id: `${model}_LIST` },
269
- { type: "Release", id: "LIST" },
270
- { type: "ReleaseAction", id: "LIST" }
271
- ]
237
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
272
238
  }),
273
239
  discardDocument: builder.mutation({
274
240
  query: ({ collectionType, model, documentId, params }) => ({
@@ -286,8 +252,7 @@ const documentApi = contentManagerApi.injectEndpoints({
286
252
  },
287
253
  { type: "Document", id: `${model}_LIST` },
288
254
  "Relations",
289
- { type: "Release", id: "LIST" },
290
- { type: "ReleaseAction", id: "LIST" }
255
+ { type: "UidAvailability", id: model }
291
256
  ];
292
257
  }
293
258
  }),
@@ -305,6 +270,7 @@ const documentApi = contentManagerApi.injectEndpoints({
305
270
  }),
306
271
  providesTags: (result, _error, arg) => {
307
272
  return [
273
+ { type: "Document", id: `ALL_LIST` },
308
274
  { type: "Document", id: `${arg.model}_LIST` },
309
275
  ...result?.results.map(({ documentId }) => ({
310
276
  type: "Document",
@@ -343,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
343
309
  {
344
310
  type: "Document",
345
311
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
312
+ },
313
+ // Make it easy to invalidate all individual documents queries for a model
314
+ {
315
+ type: "Document",
316
+ id: `${model}_ALL_ITEMS`
346
317
  }
347
318
  ];
348
319
  }
@@ -407,9 +378,20 @@ const documentApi = contentManagerApi.injectEndpoints({
407
378
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
408
379
  },
409
380
  "Relations",
410
- { type: "Release", id: "LIST" },
411
- { type: "ReleaseAction", id: "LIST" }
381
+ { type: "UidAvailability", id: model }
412
382
  ];
383
+ },
384
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
385
+ const patchResult = dispatch(
386
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
387
+ Object.assign(draft.data, data);
388
+ })
389
+ );
390
+ try {
391
+ await queryFulfilled;
392
+ } catch {
393
+ patchResult.undo();
394
+ }
413
395
  }
414
396
  }),
415
397
  unpublishDocument: builder.mutation({
@@ -479,7 +461,7 @@ const buildValidParams = (query) => {
479
461
  const isBaseQueryError = (error) => {
480
462
  return error.name !== void 0;
481
463
  };
482
- const createYupSchema = (attributes = {}, components = {}) => {
464
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
483
465
  const createModelSchema = (attributes2) => yup.object().shape(
484
466
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
485
467
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -492,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
492
474
  addMinValidation,
493
475
  addMaxValidation,
494
476
  addRegexValidation
495
- ].map((fn) => fn(attribute));
477
+ ].map((fn) => fn(attribute, options));
496
478
  const transformSchema = pipe(...validations);
497
479
  switch (attribute.type) {
498
480
  case "component": {
@@ -593,6 +575,14 @@ const createAttributeSchema = (attribute) => {
593
575
  if (!value || typeof value === "string" && value.length === 0) {
594
576
  return true;
595
577
  }
578
+ if (typeof value === "object") {
579
+ try {
580
+ JSON.stringify(value);
581
+ return true;
582
+ } catch (err) {
583
+ return false;
584
+ }
585
+ }
596
586
  try {
597
587
  JSON.parse(value);
598
588
  return true;
@@ -611,13 +601,7 @@ const createAttributeSchema = (attribute) => {
611
601
  return yup.mixed();
612
602
  }
613
603
  };
614
- const addRequiredValidation = (attribute) => (schema) => {
615
- if (attribute.required) {
616
- return schema.required({
617
- id: translatedErrors.required.id,
618
- defaultMessage: "This field is required."
619
- });
620
- }
604
+ const nullableSchema = (schema) => {
621
605
  return schema?.nullable ? schema.nullable() : (
622
606
  // In some cases '.nullable' will not be available on the schema.
623
607
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -625,7 +609,22 @@ const addRequiredValidation = (attribute) => (schema) => {
625
609
  schema
626
610
  );
627
611
  };
628
- const addMinLengthValidation = (attribute) => (schema) => {
612
+ const addRequiredValidation = (attribute, options) => (schema) => {
613
+ if (options.status === "draft") {
614
+ return nullableSchema(schema);
615
+ }
616
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
617
+ return schema.min(1, translatedErrors.required);
618
+ }
619
+ if (attribute.required && attribute.type !== "relation") {
620
+ return schema.required(translatedErrors.required);
621
+ }
622
+ return nullableSchema(schema);
623
+ };
624
+ const addMinLengthValidation = (attribute, options) => (schema) => {
625
+ if (options.status === "draft") {
626
+ return schema;
627
+ }
629
628
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
630
629
  return schema.min(attribute.minLength, {
631
630
  ...translatedErrors.minLength,
@@ -647,9 +646,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
647
646
  }
648
647
  return schema;
649
648
  };
650
- const addMinValidation = (attribute) => (schema) => {
649
+ const addMinValidation = (attribute, options) => (schema) => {
651
650
  if ("min" in attribute) {
652
651
  const min = toInteger(attribute.min);
652
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
653
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
654
+ return schema.test(
655
+ "custom-min",
656
+ {
657
+ ...translatedErrors.min,
658
+ values: {
659
+ min: attribute.min
660
+ }
661
+ },
662
+ (value) => {
663
+ if (!value) {
664
+ return true;
665
+ }
666
+ if (Array.isArray(value) && value.length === 0) {
667
+ return true;
668
+ }
669
+ return value.length >= min;
670
+ }
671
+ );
672
+ }
673
+ }
653
674
  if ("min" in schema && min) {
654
675
  return schema.min(min, {
655
676
  ...translatedErrors.min,
@@ -776,7 +797,10 @@ const useDocument = (args, opts) => {
776
797
  isLoading: isLoadingDocument,
777
798
  isFetching: isFetchingDocument,
778
799
  error
779
- } = useGetDocumentQuery(args, opts);
800
+ } = useGetDocumentQuery(args, {
801
+ ...opts,
802
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
803
+ });
780
804
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
781
805
  React.useEffect(() => {
782
806
  if (error) {
@@ -862,6 +886,7 @@ const useDocumentActions = () => {
862
886
  const { formatMessage } = useIntl();
863
887
  const { trackUsage } = useTracking();
864
888
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
+ const navigate = useNavigate();
865
890
  const [deleteDocument] = useDeleteDocumentMutation();
866
891
  const _delete = React.useCallback(
867
892
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1197,7 +1222,6 @@ const useDocumentActions = () => {
1197
1222
  sourceId
1198
1223
  });
1199
1224
  if ("error" in res) {
1200
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1201
1225
  return { error: res.error };
1202
1226
  }
1203
1227
  toggleNotification({
@@ -1216,7 +1240,7 @@ const useDocumentActions = () => {
1216
1240
  throw err;
1217
1241
  }
1218
1242
  },
1219
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1243
+ [autoCloneDocument, formatMessage, toggleNotification]
1220
1244
  );
1221
1245
  const [cloneDocument] = useCloneDocumentMutation();
1222
1246
  const clone = React.useCallback(
@@ -1242,6 +1266,7 @@ const useDocumentActions = () => {
1242
1266
  defaultMessage: "Cloned document"
1243
1267
  })
1244
1268
  });
1269
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1245
1270
  return res.data;
1246
1271
  } catch (err) {
1247
1272
  toggleNotification({
@@ -1252,7 +1277,7 @@ const useDocumentActions = () => {
1252
1277
  throw err;
1253
1278
  }
1254
1279
  },
1255
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1280
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1256
1281
  );
1257
1282
  const [getDoc] = useLazyGetDocumentQuery();
1258
1283
  const getDocument = React.useCallback(
@@ -1278,7 +1303,7 @@ const useDocumentActions = () => {
1278
1303
  };
1279
1304
  };
1280
1305
  const ProtectedHistoryPage = lazy(
1281
- () => import("./History-BgzAIj0G.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1306
+ () => import("./History-DrwsD1Vc.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1282
1307
  );
1283
1308
  const routes$1 = [
1284
1309
  {
@@ -1291,31 +1316,31 @@ const routes$1 = [
1291
1316
  }
1292
1317
  ];
1293
1318
  const ProtectedEditViewPage = lazy(
1294
- () => import("./EditViewPage-ClIueJnM.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1319
+ () => import("./EditViewPage-DiNFdFqP.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1295
1320
  );
1296
1321
  const ProtectedListViewPage = lazy(
1297
- () => import("./ListViewPage-QU03PFj1.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1322
+ () => import("./ListViewPage-5a1vw-OK.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1298
1323
  );
1299
1324
  const ProtectedListConfiguration = lazy(
1300
- () => import("./ListConfigurationPage-GH55qfoT.mjs").then((mod) => ({
1325
+ () => import("./ListConfigurationPage-BxIP0jRy.mjs").then((mod) => ({
1301
1326
  default: mod.ProtectedListConfiguration
1302
1327
  }))
1303
1328
  );
1304
1329
  const ProtectedEditConfigurationPage = lazy(
1305
- () => import("./EditConfigurationPage-CBosWqQ7.mjs").then((mod) => ({
1330
+ () => import("./EditConfigurationPage-Bk893vVY.mjs").then((mod) => ({
1306
1331
  default: mod.ProtectedEditConfigurationPage
1307
1332
  }))
1308
1333
  );
1309
1334
  const ProtectedComponentConfigurationPage = lazy(
1310
- () => import("./ComponentConfigurationPage-DErJQEVW.mjs").then((mod) => ({
1335
+ () => import("./ComponentConfigurationPage-9lRmRdIr.mjs").then((mod) => ({
1311
1336
  default: mod.ProtectedComponentConfigurationPage
1312
1337
  }))
1313
1338
  );
1314
1339
  const NoPermissions = lazy(
1315
- () => import("./NoPermissionsPage-ct58lcY0.mjs").then((mod) => ({ default: mod.NoPermissions }))
1340
+ () => import("./NoPermissionsPage-BHPqn_tQ.mjs").then((mod) => ({ default: mod.NoPermissions }))
1316
1341
  );
1317
1342
  const NoContentType = lazy(
1318
- () => import("./NoContentTypePage-CPs2CnzH.mjs").then((mod) => ({ default: mod.NoContentType }))
1343
+ () => import("./NoContentTypePage-Bm6tRcd3.mjs").then((mod) => ({ default: mod.NoContentType }))
1319
1344
  );
1320
1345
  const CollectionTypePages = () => {
1321
1346
  const { collectionType } = useParams();
@@ -1429,12 +1454,14 @@ const DocumentActionButton = (action) => {
1429
1454
  /* @__PURE__ */ jsx(
1430
1455
  Button,
1431
1456
  {
1432
- flex: 1,
1457
+ flex: "auto",
1433
1458
  startIcon: action.icon,
1434
1459
  disabled: action.disabled,
1435
1460
  onClick: handleClick(action),
1436
1461
  justifyContent: "center",
1437
1462
  variant: action.variant || "default",
1463
+ paddingTop: "7px",
1464
+ paddingBottom: "7px",
1438
1465
  children: action.label
1439
1466
  }
1440
1467
  ),
@@ -1442,7 +1469,7 @@ const DocumentActionButton = (action) => {
1442
1469
  DocumentActionConfirmDialog,
1443
1470
  {
1444
1471
  ...action.dialog,
1445
- variant: action.variant,
1472
+ variant: action.dialog?.variant ?? action.variant,
1446
1473
  isOpen: dialogId === action.id,
1447
1474
  onClose: handleClose
1448
1475
  }
@@ -1499,9 +1526,9 @@ const DocumentActionsMenu = ({
1499
1526
  disabled: isDisabled,
1500
1527
  size: "S",
1501
1528
  endIcon: null,
1502
- paddingTop: "7px",
1503
- paddingLeft: "9px",
1504
- paddingRight: "9px",
1529
+ paddingTop: "4px",
1530
+ paddingLeft: "7px",
1531
+ paddingRight: "7px",
1505
1532
  variant,
1506
1533
  children: [
1507
1534
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1521,10 +1548,25 @@ const DocumentActionsMenu = ({
1521
1548
  onSelect: handleClick(action),
1522
1549
  display: "block",
1523
1550
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1524
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1525
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1526
- action.label
1527
- ] }),
1551
+ /* @__PURE__ */ jsxs(
1552
+ Flex,
1553
+ {
1554
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1555
+ gap: 2,
1556
+ tag: "span",
1557
+ children: [
1558
+ /* @__PURE__ */ jsx(
1559
+ Flex,
1560
+ {
1561
+ tag: "span",
1562
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1563
+ children: action.icon
1564
+ }
1565
+ ),
1566
+ action.label
1567
+ ]
1568
+ }
1569
+ ),
1528
1570
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1529
1571
  Flex,
1530
1572
  {
@@ -1664,13 +1706,17 @@ const PublishAction$1 = ({
1664
1706
  const navigate = useNavigate();
1665
1707
  const { toggleNotification } = useNotification();
1666
1708
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1709
+ const isListView = useMatch(LIST_PATH) !== null;
1667
1710
  const isCloning = useMatch(CLONE_PATH) !== null;
1668
1711
  const { formatMessage } = useIntl();
1669
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1670
- "PublishAction",
1671
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1672
- );
1712
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1673
1713
  const { publish } = useDocumentActions();
1714
+ const [
1715
+ countDraftRelations,
1716
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1717
+ ] = useLazyGetDraftRelationCountQuery();
1718
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1719
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1674
1720
  const [{ query, rawQuery }] = useQueryParams();
1675
1721
  const params = React.useMemo(() => buildValidParams(query), [query]);
1676
1722
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1679,10 +1725,102 @@ const PublishAction$1 = ({
1679
1725
  const validate = useForm("PublishAction", (state) => state.validate);
1680
1726
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1681
1727
  const formValues = useForm("PublishAction", ({ values }) => values);
1728
+ React.useEffect(() => {
1729
+ if (isErrorDraftRelations) {
1730
+ toggleNotification({
1731
+ type: "danger",
1732
+ message: formatMessage({
1733
+ id: getTranslation("error.records.fetch-draft-relatons"),
1734
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1735
+ })
1736
+ });
1737
+ }
1738
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1739
+ React.useEffect(() => {
1740
+ const localDraftRelations = /* @__PURE__ */ new Set();
1741
+ const extractDraftRelations = (data) => {
1742
+ const relations = data.connect || [];
1743
+ relations.forEach((relation) => {
1744
+ if (relation.status === "draft") {
1745
+ localDraftRelations.add(relation.id);
1746
+ }
1747
+ });
1748
+ };
1749
+ const traverseAndExtract = (data) => {
1750
+ Object.entries(data).forEach(([key, value]) => {
1751
+ if (key === "connect" && Array.isArray(value)) {
1752
+ extractDraftRelations({ connect: value });
1753
+ } else if (typeof value === "object" && value !== null) {
1754
+ traverseAndExtract(value);
1755
+ }
1756
+ });
1757
+ };
1758
+ if (!documentId || modified) {
1759
+ traverseAndExtract(formValues);
1760
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1761
+ }
1762
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1763
+ React.useEffect(() => {
1764
+ if (documentId && !isListView) {
1765
+ const fetchDraftRelationsCount = async () => {
1766
+ const { data, error } = await countDraftRelations({
1767
+ collectionType,
1768
+ model,
1769
+ documentId,
1770
+ params
1771
+ });
1772
+ if (error) {
1773
+ throw error;
1774
+ }
1775
+ if (data) {
1776
+ setServerCountOfDraftRelations(data.data);
1777
+ }
1778
+ };
1779
+ fetchDraftRelationsCount();
1780
+ }
1781
+ }, [isListView, documentId, countDraftRelations, collectionType, model, params]);
1682
1782
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1683
1783
  if (!schema?.options?.draftAndPublish) {
1684
1784
  return null;
1685
1785
  }
1786
+ const performPublish = async () => {
1787
+ setSubmitting(true);
1788
+ try {
1789
+ const { errors } = await validate();
1790
+ if (errors) {
1791
+ toggleNotification({
1792
+ type: "danger",
1793
+ message: formatMessage({
1794
+ id: "content-manager.validation.error",
1795
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1796
+ })
1797
+ });
1798
+ return;
1799
+ }
1800
+ const res = await publish(
1801
+ {
1802
+ collectionType,
1803
+ model,
1804
+ documentId,
1805
+ params
1806
+ },
1807
+ formValues
1808
+ );
1809
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1810
+ navigate({
1811
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1812
+ search: rawQuery
1813
+ });
1814
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1815
+ setErrors(formatValidationErrors(res.error));
1816
+ }
1817
+ } finally {
1818
+ setSubmitting(false);
1819
+ }
1820
+ };
1821
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1822
+ const enableDraftRelationsCount = false;
1823
+ const hasDraftRelations = enableDraftRelationsCount;
1686
1824
  return {
1687
1825
  /**
1688
1826
  * Disabled when:
@@ -1692,49 +1830,36 @@ const PublishAction$1 = ({
1692
1830
  * - the document is already published & not modified
1693
1831
  * - the document is being created & not modified
1694
1832
  * - the user doesn't have the permission to publish
1695
- * - the user doesn't have the permission to create a new document
1696
- * - the user doesn't have the permission to update the document
1697
1833
  */
1698
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1834
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1699
1835
  label: formatMessage({
1700
1836
  id: "app.utils.publish",
1701
1837
  defaultMessage: "Publish"
1702
1838
  }),
1703
1839
  onClick: async () => {
1704
- setSubmitting(true);
1705
- try {
1706
- const { errors } = await validate();
1707
- if (errors) {
1708
- toggleNotification({
1709
- type: "danger",
1710
- message: formatMessage({
1711
- id: "content-manager.validation.error",
1712
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1713
- })
1714
- });
1715
- return;
1716
- }
1717
- const res = await publish(
1718
- {
1719
- collectionType,
1720
- model,
1721
- documentId,
1722
- params
1723
- },
1724
- formValues
1725
- );
1726
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1727
- navigate({
1728
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1729
- search: rawQuery
1730
- });
1731
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1732
- setErrors(formatValidationErrors(res.error));
1840
+ await performPublish();
1841
+ },
1842
+ dialog: hasDraftRelations ? {
1843
+ type: "dialog",
1844
+ variant: "danger",
1845
+ footer: null,
1846
+ title: formatMessage({
1847
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1848
+ defaultMessage: "Confirmation"
1849
+ }),
1850
+ content: formatMessage(
1851
+ {
1852
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1853
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1854
+ },
1855
+ {
1856
+ count: totalDraftRelations
1733
1857
  }
1734
- } finally {
1735
- setSubmitting(false);
1858
+ ),
1859
+ onConfirm: async () => {
1860
+ await performPublish();
1736
1861
  }
1737
- }
1862
+ } : void 0
1738
1863
  };
1739
1864
  };
1740
1865
  PublishAction$1.type = "publish";
@@ -1750,10 +1875,6 @@ const UpdateAction = ({
1750
1875
  const cloneMatch = useMatch(CLONE_PATH);
1751
1876
  const isCloning = cloneMatch !== null;
1752
1877
  const { formatMessage } = useIntl();
1753
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1754
- canCreate: canCreate2,
1755
- canUpdate: canUpdate2
1756
- }));
1757
1878
  const { create, update, clone } = useDocumentActions();
1758
1879
  const [{ query, rawQuery }] = useQueryParams();
1759
1880
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1770,10 +1891,8 @@ const UpdateAction = ({
1770
1891
  * - the form is submitting
1771
1892
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1772
1893
  * - the active tab is the published tab
1773
- * - the user doesn't have the permission to create a new document
1774
- * - the user doesn't have the permission to update the document
1775
1894
  */
1776
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1895
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1777
1896
  label: formatMessage({
1778
1897
  id: "content-manager.containers.Edit.save",
1779
1898
  defaultMessage: "Save"
@@ -1781,16 +1900,18 @@ const UpdateAction = ({
1781
1900
  onClick: async () => {
1782
1901
  setSubmitting(true);
1783
1902
  try {
1784
- const { errors } = await validate();
1785
- if (errors) {
1786
- toggleNotification({
1787
- type: "danger",
1788
- message: formatMessage({
1789
- id: "content-manager.validation.error",
1790
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1791
- })
1792
- });
1793
- return;
1903
+ if (activeTab !== "draft") {
1904
+ const { errors } = await validate();
1905
+ if (errors) {
1906
+ toggleNotification({
1907
+ type: "danger",
1908
+ message: formatMessage({
1909
+ id: "content-manager.validation.error",
1910
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1911
+ })
1912
+ });
1913
+ return;
1914
+ }
1794
1915
  }
1795
1916
  if (isCloning) {
1796
1917
  const res = await clone(
@@ -1802,10 +1923,13 @@ const UpdateAction = ({
1802
1923
  document
1803
1924
  );
1804
1925
  if ("data" in res) {
1805
- navigate({
1806
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1807
- search: rawQuery
1808
- });
1926
+ navigate(
1927
+ {
1928
+ pathname: `../${res.data.documentId}`,
1929
+ search: rawQuery
1930
+ },
1931
+ { relative: "path" }
1932
+ );
1809
1933
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1810
1934
  setErrors(formatValidationErrors(res.error));
1811
1935
  }
@@ -1833,10 +1957,13 @@ const UpdateAction = ({
1833
1957
  document
1834
1958
  );
1835
1959
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1836
- navigate({
1837
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1838
- search: rawQuery
1839
- });
1960
+ navigate(
1961
+ {
1962
+ pathname: `../${res.data.documentId}`,
1963
+ search: rawQuery
1964
+ },
1965
+ { replace: true, relative: "path" }
1966
+ );
1840
1967
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1841
1968
  setErrors(formatValidationErrors(res.error));
1842
1969
  }
@@ -2082,23 +2209,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2082
2209
  id: "content-manager.containers.edit.title.new",
2083
2210
  defaultMessage: "Create an entry"
2084
2211
  }) : documentTitle;
2085
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2212
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2086
2213
  /* @__PURE__ */ jsx(BackButton, {}),
2087
- /* @__PURE__ */ jsxs(
2088
- Flex,
2089
- {
2090
- width: "100%",
2091
- justifyContent: "space-between",
2092
- paddingTop: 1,
2093
- gap: "80px",
2094
- alignItems: "flex-start",
2095
- children: [
2096
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2097
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2098
- ]
2099
- }
2100
- ),
2101
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2214
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2215
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2216
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2217
+ ] }),
2218
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2102
2219
  ] });
2103
2220
  };
2104
2221
  const HeaderToolbar = () => {
@@ -2789,7 +2906,7 @@ const ConfirmBulkActionDialog = ({
2789
2906
  endAction
2790
2907
  }) => {
2791
2908
  const { formatMessage } = useIntl();
2792
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2909
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2793
2910
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2794
2911
  id: "app.components.ConfirmDialog.title",
2795
2912
  defaultMessage: "Confirmation"
@@ -2820,6 +2937,7 @@ const ConfirmDialogPublishAll = ({
2820
2937
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2821
2938
  const { model, schema } = useDoc();
2822
2939
  const [{ query }] = useQueryParams();
2940
+ const enableDraftRelationsCount = false;
2823
2941
  const {
2824
2942
  data: countDraftRelations = 0,
2825
2943
  isLoading,
@@ -2831,7 +2949,7 @@ const ConfirmDialogPublishAll = ({
2831
2949
  locale: query?.plugins?.i18n?.locale
2832
2950
  },
2833
2951
  {
2834
- skip: selectedEntries.length === 0
2952
+ skip: !enableDraftRelationsCount
2835
2953
  }
2836
2954
  );
2837
2955
  React.useEffect(() => {
@@ -2910,7 +3028,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2910
3028
  )
2911
3029
  );
2912
3030
  } else {
2913
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3031
+ messages.push(
3032
+ ...formatErrorMessages(
3033
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3034
+ value,
3035
+ currentKey,
3036
+ formatMessage
3037
+ )
3038
+ );
2914
3039
  }
2915
3040
  } else {
2916
3041
  messages.push(
@@ -3009,7 +3134,7 @@ const SelectedEntriesTableContent = ({
3009
3134
  status: row.status
3010
3135
  }
3011
3136
  ) }),
3012
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3137
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3013
3138
  IconButton,
3014
3139
  {
3015
3140
  tag: Link,
@@ -3032,9 +3157,10 @@ const SelectedEntriesTableContent = ({
3032
3157
  ),
3033
3158
  target: "_blank",
3034
3159
  marginLeft: "auto",
3035
- children: /* @__PURE__ */ jsx(Pencil, {})
3160
+ variant: "ghost",
3161
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3036
3162
  }
3037
- ) })
3163
+ ) }) })
3038
3164
  ] }, row.id)) })
3039
3165
  ] });
3040
3166
  };
@@ -3071,7 +3197,13 @@ const SelectedEntriesModalContent = ({
3071
3197
  );
3072
3198
  const { rows, validationErrors } = React.useMemo(() => {
3073
3199
  if (data.length > 0 && schema) {
3074
- const validate = createYupSchema(schema.attributes, components);
3200
+ const validate = createYupSchema(
3201
+ schema.attributes,
3202
+ components,
3203
+ // Since this is the "Publish" action, the validation
3204
+ // schema must enforce the rules for published entities
3205
+ { status: "published" }
3206
+ );
3075
3207
  const validationErrors2 = {};
3076
3208
  const rows2 = data.map((entry) => {
3077
3209
  try {
@@ -3421,7 +3553,7 @@ const TableActions = ({ document }) => {
3421
3553
  DescriptionComponentRenderer,
3422
3554
  {
3423
3555
  props,
3424
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3556
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3425
3557
  children: (actions2) => {
3426
3558
  const tableRowActions = actions2.filter((action) => {
3427
3559
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3532,7 +3664,7 @@ const CloneAction = ({ model, documentId }) => {
3532
3664
  }),
3533
3665
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3534
3666
  footer: ({ onClose }) => {
3535
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3667
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3536
3668
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3537
3669
  id: "cancel",
3538
3670
  defaultMessage: "Cancel"
@@ -3573,8 +3705,7 @@ class ContentManagerPlugin {
3573
3705
  documentActions = [
3574
3706
  ...DEFAULT_ACTIONS,
3575
3707
  ...DEFAULT_TABLE_ROW_ACTIONS,
3576
- ...DEFAULT_HEADER_ACTIONS,
3577
- HistoryAction
3708
+ ...DEFAULT_HEADER_ACTIONS
3578
3709
  ];
3579
3710
  editViewSidePanels = [ActionsPanel];
3580
3711
  headerActions = [];
@@ -3663,6 +3794,52 @@ const getPrintableType = (value) => {
3663
3794
  }
3664
3795
  return nativeType;
3665
3796
  };
3797
+ const HistoryAction = ({ model, document }) => {
3798
+ const { formatMessage } = useIntl();
3799
+ const [{ query }] = useQueryParams();
3800
+ const navigate = useNavigate();
3801
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3802
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3803
+ return null;
3804
+ }
3805
+ return {
3806
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3807
+ label: formatMessage({
3808
+ id: "content-manager.history.document-action",
3809
+ defaultMessage: "Content History"
3810
+ }),
3811
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3812
+ disabled: (
3813
+ /**
3814
+ * The user is creating a new document.
3815
+ * It hasn't been saved yet, so there's no history to go to
3816
+ */
3817
+ !document || /**
3818
+ * The document has been created but the current dimension has never been saved.
3819
+ * For example, the user is creating a new locale in an existing document,
3820
+ * so there's no history for the document in that locale
3821
+ */
3822
+ !document.id || /**
3823
+ * History is only available for content types created by the user.
3824
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3825
+ * which start with `admin::` or `plugin::`
3826
+ */
3827
+ !model.startsWith("api::")
3828
+ ),
3829
+ position: "header"
3830
+ };
3831
+ };
3832
+ HistoryAction.type = "history";
3833
+ const historyAdmin = {
3834
+ bootstrap(app) {
3835
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3836
+ addDocumentAction((actions2) => {
3837
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3838
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3839
+ return actions2;
3840
+ });
3841
+ }
3842
+ };
3666
3843
  const initialState = {
3667
3844
  collectionTypeLinks: [],
3668
3845
  components: [],
@@ -3713,15 +3890,29 @@ const index = {
3713
3890
  defaultMessage: "Content Manager"
3714
3891
  },
3715
3892
  permissions: [],
3716
- Component: () => import("./layout-B1Z-9koY.mjs").then((mod) => ({ default: mod.Layout })),
3717
3893
  position: 1
3718
3894
  });
3895
+ app.router.addRoute({
3896
+ path: "content-manager/*",
3897
+ lazy: async () => {
3898
+ const { Layout } = await import("./layout-uomiIGbG.mjs");
3899
+ return {
3900
+ Component: Layout
3901
+ };
3902
+ },
3903
+ children: routes
3904
+ });
3719
3905
  app.registerPlugin(cm.config);
3720
3906
  },
3907
+ bootstrap(app) {
3908
+ if (typeof historyAdmin.bootstrap === "function") {
3909
+ historyAdmin.bootstrap(app);
3910
+ }
3911
+ },
3721
3912
  async registerTrads({ locales }) {
3722
3913
  const importedTrads = await Promise.all(
3723
3914
  locales.map((locale) => {
3724
- 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 }) => {
3915
+ 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-CbaIuYoB.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 }) => {
3725
3916
  return {
3726
3917
  data: prefixPluginTranslations(data, PLUGIN_ID),
3727
3918
  locale
@@ -3767,11 +3958,11 @@ export {
3767
3958
  PERMISSIONS as k,
3768
3959
  DocumentRBAC as l,
3769
3960
  DOCUMENT_META_FIELDS as m,
3770
- useDocLayout as n,
3771
- useGetContentTypeConfigurationQuery as o,
3772
- CREATOR_FIELDS as p,
3773
- getMainField as q,
3774
- routes as r,
3961
+ CLONE_PATH as n,
3962
+ useDocLayout as o,
3963
+ useGetContentTypeConfigurationQuery as p,
3964
+ CREATOR_FIELDS as q,
3965
+ getMainField as r,
3775
3966
  setInitialData as s,
3776
3967
  getDisplayName as t,
3777
3968
  useContentTypeSchema as u,
@@ -3781,4 +3972,4 @@ export {
3781
3972
  capitalise as y,
3782
3973
  useUpdateContentTypeConfigurationMutation as z
3783
3974
  };
3784
- //# sourceMappingURL=index-6kKXK7y8.mjs.map
3975
+ //# sourceMappingURL=index-BJ6uTqLL.mjs.map