@strapi/content-manager 0.0.0-experimental.9612538209f3c68285c5dea8fe26f96e7e470afd → 0.0.0-experimental.9c5778c9200404fcee94d5a0fc88da5e4376b82c

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 (126) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js.map → ComponentConfigurationPage-_zF8p6CY.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-BtkEx339.mjs → EditViewPage-DeTn7rAF.mjs} +19 -8
  11. package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-BqNpC6hO.js → EditViewPage-G9uNzwYL.js} +19 -8
  13. package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
  14. package/dist/_chunks/{Field-R5NbffTB.mjs → Field-CnCKhI1R.mjs} +194 -141
  15. package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
  16. package/dist/_chunks/{Field-lsPFnAmH.js → Field-DDHUWEfV.js} +196 -143
  17. package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
  18. package/dist/_chunks/{Form-CcGboku8.js → Form-DYETaKUX.js} +35 -16
  19. package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
  20. package/dist/_chunks/{Form-BHmXSfyy.mjs → Form-IvVVwqRL.mjs} +35 -16
  21. package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
  22. package/dist/_chunks/{History-ByUPL3T3.mjs → History-BMunT-do.mjs} +28 -18
  23. package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
  24. package/dist/_chunks/{History-Bsud8jwh.js → History-CnZDctSO.js} +28 -18
  25. package/dist/_chunks/History-CnZDctSO.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-DiT463qx.js → ListConfigurationPage-BynalOp8.js} +20 -8
  27. package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-Bm5HACXf.mjs → ListConfigurationPage-CDqkCxgV.mjs} +20 -8
  29. package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-CsrC9L_d.js → ListViewPage-I88Ouzoq.js} +44 -39
  31. package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-JSyNAAYu.mjs → ListViewPage-_5gS-DOF.mjs} +42 -37
  33. package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-Bsvng4II.js → NoContentTypePage-BaWQ7HsA.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-Bsvng4II.js.map → NoContentTypePage-BaWQ7HsA.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs → NoContentTypePage-Dht-55hr.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs.map → NoContentTypePage-Dht-55hr.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js → NoPermissionsPage-DCVUh5at.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
  42. package/dist/_chunks/{Relations-CghaPv2D.js → Relations-BPgFQeGj.js} +4 -4
  43. package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
  44. package/dist/_chunks/{Relations-u8-37jK0.mjs → Relations-Chdt5qWc.mjs} +4 -4
  45. package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
  46. package/dist/_chunks/{en-fbKQxLGn.js → en-BVzUkPxZ.js} +10 -8
  47. package/dist/_chunks/{en-fbKQxLGn.js.map → en-BVzUkPxZ.js.map} +1 -1
  48. package/dist/_chunks/{en-Ux26r5pl.mjs → en-CPTj6CjC.mjs} +10 -8
  49. package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
  50. package/dist/_chunks/{index-BOZx6IMg.js → index-BhbLFX4l.js} +417 -185
  51. package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
  52. package/dist/_chunks/{index-CaE6NG4a.mjs → index-D4UGPFZC.mjs} +436 -204
  53. package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
  54. package/dist/_chunks/{layout-Ciz224q5.js → layout-CYA7s0qO.js} +22 -9
  55. package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
  56. package/dist/_chunks/{layout-Bx7svTbY.mjs → layout-D4HI4_PS.mjs} +23 -10
  57. package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
  58. package/dist/_chunks/{relations-Cxc1cEv3.mjs → relations-1pXaYpBK.mjs} +2 -2
  59. package/dist/_chunks/{relations-Cxc1cEv3.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-CP8sB2YZ.js → relations-DDZ9OxNo.js} +2 -2
  61. package/dist/_chunks/{relations-CP8sB2YZ.js.map → relations-DDZ9OxNo.js.map} +1 -1
  62. package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
  63. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  64. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  65. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  66. package/dist/admin/index.js +1 -1
  67. package/dist/admin/index.mjs +4 -4
  68. package/dist/admin/src/history/index.d.ts +3 -0
  69. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  70. package/dist/admin/src/index.d.ts +1 -0
  71. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
  72. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  73. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  74. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  75. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
  76. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  77. package/dist/admin/src/services/api.d.ts +1 -1
  78. package/dist/admin/src/services/components.d.ts +2 -2
  79. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  80. package/dist/admin/src/services/documents.d.ts +19 -17
  81. package/dist/admin/src/services/init.d.ts +1 -1
  82. package/dist/admin/src/services/relations.d.ts +2 -2
  83. package/dist/admin/src/services/uid.d.ts +3 -3
  84. package/dist/admin/src/utils/validation.d.ts +4 -1
  85. package/dist/server/index.js +174 -105
  86. package/dist/server/index.js.map +1 -1
  87. package/dist/server/index.mjs +175 -106
  88. package/dist/server/index.mjs.map +1 -1
  89. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  90. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  91. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  92. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  93. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  94. package/dist/server/src/history/services/history.d.ts.map +1 -1
  95. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  96. package/dist/server/src/history/services/utils.d.ts +2 -1
  97. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  98. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  99. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  100. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  101. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  102. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  103. package/dist/shared/contracts/collection-types.d.ts +3 -1
  104. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  105. package/package.json +9 -9
  106. package/dist/_chunks/EditViewPage-BqNpC6hO.js.map +0 -1
  107. package/dist/_chunks/EditViewPage-BtkEx339.mjs.map +0 -1
  108. package/dist/_chunks/Field-R5NbffTB.mjs.map +0 -1
  109. package/dist/_chunks/Field-lsPFnAmH.js.map +0 -1
  110. package/dist/_chunks/Form-BHmXSfyy.mjs.map +0 -1
  111. package/dist/_chunks/Form-CcGboku8.js.map +0 -1
  112. package/dist/_chunks/History-Bsud8jwh.js.map +0 -1
  113. package/dist/_chunks/History-ByUPL3T3.mjs.map +0 -1
  114. package/dist/_chunks/ListConfigurationPage-Bm5HACXf.mjs.map +0 -1
  115. package/dist/_chunks/ListConfigurationPage-DiT463qx.js.map +0 -1
  116. package/dist/_chunks/ListViewPage-CsrC9L_d.js.map +0 -1
  117. package/dist/_chunks/ListViewPage-JSyNAAYu.mjs.map +0 -1
  118. package/dist/_chunks/Relations-CghaPv2D.js.map +0 -1
  119. package/dist/_chunks/Relations-u8-37jK0.mjs.map +0 -1
  120. package/dist/_chunks/index-BOZx6IMg.js.map +0 -1
  121. package/dist/_chunks/index-CaE6NG4a.mjs.map +0 -1
  122. package/dist/_chunks/layout-Bx7svTbY.mjs.map +0 -1
  123. package/dist/_chunks/layout-Ciz224q5.js.map +0 -1
  124. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  125. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  126. package/dist/_chunks/usePrev-DH6iah0A.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 { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, 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";
10
- import { styled } from "styled-components";
6
+ import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, 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";
11
9
  import * as yup from "yup";
12
10
  import { ValidationError } from "yup";
13
11
  import pipe from "lodash/fp/pipe";
14
12
  import { intervalToDuration, isPast } from "date-fns";
13
+ import { styled } from "styled-components";
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";
@@ -194,7 +158,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
194
158
  "Document",
195
159
  "InitialData",
196
160
  "HistoryVersion",
197
- "Relations"
161
+ "Relations",
162
+ "UidAvailability"
198
163
  ]
199
164
  });
200
165
  const documentApi = contentManagerApi.injectEndpoints({
@@ -208,7 +173,12 @@ const documentApi = contentManagerApi.injectEndpoints({
208
173
  params: query
209
174
  }
210
175
  }),
211
- 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
+ }
212
182
  }),
213
183
  cloneDocument: builder.mutation({
214
184
  query: ({ model, sourceId, data, params }) => ({
@@ -219,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
219
189
  params
220
190
  }
221
191
  }),
222
- 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
+ ]
223
196
  }),
224
197
  /**
225
198
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -236,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
236
209
  }),
237
210
  invalidatesTags: (result, _error, { model }) => [
238
211
  { type: "Document", id: `${model}_LIST` },
239
- "Relations"
212
+ "Relations",
213
+ { type: "UidAvailability", id: model }
240
214
  ]
241
215
  }),
242
216
  deleteDocument: builder.mutation({
@@ -277,7 +251,8 @@ const documentApi = contentManagerApi.injectEndpoints({
277
251
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
278
252
  },
279
253
  { type: "Document", id: `${model}_LIST` },
280
- "Relations"
254
+ "Relations",
255
+ { type: "UidAvailability", id: model }
281
256
  ];
282
257
  }
283
258
  }),
@@ -295,6 +270,7 @@ const documentApi = contentManagerApi.injectEndpoints({
295
270
  }),
296
271
  providesTags: (result, _error, arg) => {
297
272
  return [
273
+ { type: "Document", id: `ALL_LIST` },
298
274
  { type: "Document", id: `${arg.model}_LIST` },
299
275
  ...result?.results.map(({ documentId }) => ({
300
276
  type: "Document",
@@ -333,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
333
309
  {
334
310
  type: "Document",
335
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`
336
317
  }
337
318
  ];
338
319
  }
@@ -396,8 +377,21 @@ const documentApi = contentManagerApi.injectEndpoints({
396
377
  type: "Document",
397
378
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
398
379
  },
399
- "Relations"
380
+ "Relations",
381
+ { type: "UidAvailability", id: model }
400
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
+ }
401
395
  }
402
396
  }),
403
397
  unpublishDocument: builder.mutation({
@@ -467,7 +461,7 @@ const buildValidParams = (query) => {
467
461
  const isBaseQueryError = (error) => {
468
462
  return error.name !== void 0;
469
463
  };
470
- const createYupSchema = (attributes = {}, components = {}) => {
464
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
471
465
  const createModelSchema = (attributes2) => yup.object().shape(
472
466
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
473
467
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -480,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
480
474
  addMinValidation,
481
475
  addMaxValidation,
482
476
  addRegexValidation
483
- ].map((fn) => fn(attribute));
477
+ ].map((fn) => fn(attribute, options));
484
478
  const transformSchema = pipe(...validations);
485
479
  switch (attribute.type) {
486
480
  case "component": {
@@ -581,6 +575,14 @@ const createAttributeSchema = (attribute) => {
581
575
  if (!value || typeof value === "string" && value.length === 0) {
582
576
  return true;
583
577
  }
578
+ if (typeof value === "object") {
579
+ try {
580
+ JSON.stringify(value);
581
+ return true;
582
+ } catch (err) {
583
+ return false;
584
+ }
585
+ }
584
586
  try {
585
587
  JSON.parse(value);
586
588
  return true;
@@ -599,13 +601,7 @@ const createAttributeSchema = (attribute) => {
599
601
  return yup.mixed();
600
602
  }
601
603
  };
602
- const addRequiredValidation = (attribute) => (schema) => {
603
- if (attribute.required && attribute.type !== "relation") {
604
- return schema.required({
605
- id: translatedErrors.required.id,
606
- defaultMessage: "This field is required."
607
- });
608
- }
604
+ const nullableSchema = (schema) => {
609
605
  return schema?.nullable ? schema.nullable() : (
610
606
  // In some cases '.nullable' will not be available on the schema.
611
607
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -613,7 +609,22 @@ const addRequiredValidation = (attribute) => (schema) => {
613
609
  schema
614
610
  );
615
611
  };
616
- 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
+ }
617
628
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
618
629
  return schema.min(attribute.minLength, {
619
630
  ...translatedErrors.minLength,
@@ -635,9 +646,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
635
646
  }
636
647
  return schema;
637
648
  };
638
- const addMinValidation = (attribute) => (schema) => {
649
+ const addMinValidation = (attribute, options) => (schema) => {
639
650
  if ("min" in attribute) {
640
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
+ }
641
674
  if ("min" in schema && min) {
642
675
  return schema.min(min, {
643
676
  ...translatedErrors.min,
@@ -853,6 +886,7 @@ const useDocumentActions = () => {
853
886
  const { formatMessage } = useIntl();
854
887
  const { trackUsage } = useTracking();
855
888
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
+ const navigate = useNavigate();
856
890
  const [deleteDocument] = useDeleteDocumentMutation();
857
891
  const _delete = React.useCallback(
858
892
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1188,7 +1222,6 @@ const useDocumentActions = () => {
1188
1222
  sourceId
1189
1223
  });
1190
1224
  if ("error" in res) {
1191
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1192
1225
  return { error: res.error };
1193
1226
  }
1194
1227
  toggleNotification({
@@ -1207,7 +1240,7 @@ const useDocumentActions = () => {
1207
1240
  throw err;
1208
1241
  }
1209
1242
  },
1210
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1243
+ [autoCloneDocument, formatMessage, toggleNotification]
1211
1244
  );
1212
1245
  const [cloneDocument] = useCloneDocumentMutation();
1213
1246
  const clone = React.useCallback(
@@ -1233,6 +1266,7 @@ const useDocumentActions = () => {
1233
1266
  defaultMessage: "Cloned document"
1234
1267
  })
1235
1268
  });
1269
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1236
1270
  return res.data;
1237
1271
  } catch (err) {
1238
1272
  toggleNotification({
@@ -1243,7 +1277,7 @@ const useDocumentActions = () => {
1243
1277
  throw err;
1244
1278
  }
1245
1279
  },
1246
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1280
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1247
1281
  );
1248
1282
  const [getDoc] = useLazyGetDocumentQuery();
1249
1283
  const getDocument = React.useCallback(
@@ -1269,7 +1303,7 @@ const useDocumentActions = () => {
1269
1303
  };
1270
1304
  };
1271
1305
  const ProtectedHistoryPage = lazy(
1272
- () => import("./History-ByUPL3T3.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1306
+ () => import("./History-BMunT-do.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1273
1307
  );
1274
1308
  const routes$1 = [
1275
1309
  {
@@ -1282,31 +1316,31 @@ const routes$1 = [
1282
1316
  }
1283
1317
  ];
1284
1318
  const ProtectedEditViewPage = lazy(
1285
- () => import("./EditViewPage-BtkEx339.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1319
+ () => import("./EditViewPage-DeTn7rAF.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1286
1320
  );
1287
1321
  const ProtectedListViewPage = lazy(
1288
- () => import("./ListViewPage-JSyNAAYu.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1322
+ () => import("./ListViewPage-_5gS-DOF.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1289
1323
  );
1290
1324
  const ProtectedListConfiguration = lazy(
1291
- () => import("./ListConfigurationPage-Bm5HACXf.mjs").then((mod) => ({
1325
+ () => import("./ListConfigurationPage-CDqkCxgV.mjs").then((mod) => ({
1292
1326
  default: mod.ProtectedListConfiguration
1293
1327
  }))
1294
1328
  );
1295
1329
  const ProtectedEditConfigurationPage = lazy(
1296
- () => import("./EditConfigurationPage-Cp6HAEzN.mjs").then((mod) => ({
1330
+ () => import("./EditConfigurationPage-CE_yavTi.mjs").then((mod) => ({
1297
1331
  default: mod.ProtectedEditConfigurationPage
1298
1332
  }))
1299
1333
  );
1300
1334
  const ProtectedComponentConfigurationPage = lazy(
1301
- () => import("./ComponentConfigurationPage-DHNM3YBz.mjs").then((mod) => ({
1335
+ () => import("./ComponentConfigurationPage-CpBFh6_r.mjs").then((mod) => ({
1302
1336
  default: mod.ProtectedComponentConfigurationPage
1303
1337
  }))
1304
1338
  );
1305
1339
  const NoPermissions = lazy(
1306
- () => import("./NoPermissionsPage-DNmf_pj0.mjs").then((mod) => ({ default: mod.NoPermissions }))
1340
+ () => import("./NoPermissionsPage-Bs8D5W_v.mjs").then((mod) => ({ default: mod.NoPermissions }))
1307
1341
  );
1308
1342
  const NoContentType = lazy(
1309
- () => import("./NoContentTypePage-CsrQUpBE.mjs").then((mod) => ({ default: mod.NoContentType }))
1343
+ () => import("./NoContentTypePage-Dht-55hr.mjs").then((mod) => ({ default: mod.NoContentType }))
1310
1344
  );
1311
1345
  const CollectionTypePages = () => {
1312
1346
  const { collectionType } = useParams();
@@ -1420,12 +1454,14 @@ const DocumentActionButton = (action) => {
1420
1454
  /* @__PURE__ */ jsx(
1421
1455
  Button,
1422
1456
  {
1423
- flex: 1,
1457
+ flex: "auto",
1424
1458
  startIcon: action.icon,
1425
1459
  disabled: action.disabled,
1426
1460
  onClick: handleClick(action),
1427
1461
  justifyContent: "center",
1428
1462
  variant: action.variant || "default",
1463
+ paddingTop: "7px",
1464
+ paddingBottom: "7px",
1429
1465
  children: action.label
1430
1466
  }
1431
1467
  ),
@@ -1433,7 +1469,7 @@ const DocumentActionButton = (action) => {
1433
1469
  DocumentActionConfirmDialog,
1434
1470
  {
1435
1471
  ...action.dialog,
1436
- variant: action.variant,
1472
+ variant: action.dialog?.variant ?? action.variant,
1437
1473
  isOpen: dialogId === action.id,
1438
1474
  onClose: handleClose
1439
1475
  }
@@ -1490,9 +1526,9 @@ const DocumentActionsMenu = ({
1490
1526
  disabled: isDisabled,
1491
1527
  size: "S",
1492
1528
  endIcon: null,
1493
- paddingTop: "7px",
1494
- paddingLeft: "9px",
1495
- paddingRight: "9px",
1529
+ paddingTop: "4px",
1530
+ paddingLeft: "7px",
1531
+ paddingRight: "7px",
1496
1532
  variant,
1497
1533
  children: [
1498
1534
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1512,10 +1548,25 @@ const DocumentActionsMenu = ({
1512
1548
  onSelect: handleClick(action),
1513
1549
  display: "block",
1514
1550
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1515
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1516
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1517
- action.label
1518
- ] }),
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
+ ),
1519
1570
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1520
1571
  Flex,
1521
1572
  {
@@ -1612,11 +1663,11 @@ const DocumentActionConfirmDialog = ({
1612
1663
  /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1613
1664
  /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1614
1665
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1615
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1666
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1616
1667
  id: "app.components.Button.cancel",
1617
1668
  defaultMessage: "Cancel"
1618
1669
  }) }) }),
1619
- /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1670
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1620
1671
  id: "app.components.Button.confirm",
1621
1672
  defaultMessage: "Confirm"
1622
1673
  }) })
@@ -1639,8 +1690,8 @@ const DocumentActionModal = ({
1639
1690
  };
1640
1691
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1641
1692
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1642
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1643
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1693
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1694
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1644
1695
  ] }) });
1645
1696
  };
1646
1697
  const PublishAction$1 = ({
@@ -1655,13 +1706,17 @@ const PublishAction$1 = ({
1655
1706
  const navigate = useNavigate();
1656
1707
  const { toggleNotification } = useNotification();
1657
1708
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1709
+ const isListView = useMatch(LIST_PATH) !== null;
1658
1710
  const isCloning = useMatch(CLONE_PATH) !== null;
1659
1711
  const { formatMessage } = useIntl();
1660
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1661
- "PublishAction",
1662
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1663
- );
1712
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1664
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);
1665
1720
  const [{ query, rawQuery }] = useQueryParams();
1666
1721
  const params = React.useMemo(() => buildValidParams(query), [query]);
1667
1722
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1670,10 +1725,103 @@ const PublishAction$1 = ({
1670
1725
  const validate = useForm("PublishAction", (state) => state.validate);
1671
1726
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1672
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 (!document || !document.documentId || isListView) {
1765
+ return;
1766
+ }
1767
+ const fetchDraftRelationsCount = async () => {
1768
+ const { data, error } = await countDraftRelations({
1769
+ collectionType,
1770
+ model,
1771
+ documentId,
1772
+ params
1773
+ });
1774
+ if (error) {
1775
+ throw error;
1776
+ }
1777
+ if (data) {
1778
+ setServerCountOfDraftRelations(data.data);
1779
+ }
1780
+ };
1781
+ fetchDraftRelationsCount();
1782
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1673
1783
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1674
1784
  if (!schema?.options?.draftAndPublish) {
1675
1785
  return null;
1676
1786
  }
1787
+ const performPublish = async () => {
1788
+ setSubmitting(true);
1789
+ try {
1790
+ const { errors } = await validate();
1791
+ if (errors) {
1792
+ toggleNotification({
1793
+ type: "danger",
1794
+ message: formatMessage({
1795
+ id: "content-manager.validation.error",
1796
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1797
+ })
1798
+ });
1799
+ return;
1800
+ }
1801
+ const res = await publish(
1802
+ {
1803
+ collectionType,
1804
+ model,
1805
+ documentId,
1806
+ params
1807
+ },
1808
+ formValues
1809
+ );
1810
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1811
+ navigate({
1812
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1813
+ search: rawQuery
1814
+ });
1815
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1816
+ setErrors(formatValidationErrors(res.error));
1817
+ }
1818
+ } finally {
1819
+ setSubmitting(false);
1820
+ }
1821
+ };
1822
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1823
+ const enableDraftRelationsCount = false;
1824
+ const hasDraftRelations = enableDraftRelationsCount;
1677
1825
  return {
1678
1826
  /**
1679
1827
  * Disabled when:
@@ -1683,49 +1831,36 @@ const PublishAction$1 = ({
1683
1831
  * - the document is already published & not modified
1684
1832
  * - the document is being created & not modified
1685
1833
  * - the user doesn't have the permission to publish
1686
- * - the user doesn't have the permission to create a new document
1687
- * - the user doesn't have the permission to update the document
1688
1834
  */
1689
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1835
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1690
1836
  label: formatMessage({
1691
1837
  id: "app.utils.publish",
1692
1838
  defaultMessage: "Publish"
1693
1839
  }),
1694
1840
  onClick: async () => {
1695
- setSubmitting(true);
1696
- try {
1697
- const { errors } = await validate();
1698
- if (errors) {
1699
- toggleNotification({
1700
- type: "danger",
1701
- message: formatMessage({
1702
- id: "content-manager.validation.error",
1703
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1704
- })
1705
- });
1706
- return;
1707
- }
1708
- const res = await publish(
1709
- {
1710
- collectionType,
1711
- model,
1712
- documentId,
1713
- params
1714
- },
1715
- formValues
1716
- );
1717
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1718
- navigate({
1719
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1720
- search: rawQuery
1721
- });
1722
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1723
- setErrors(formatValidationErrors(res.error));
1841
+ await performPublish();
1842
+ },
1843
+ dialog: hasDraftRelations ? {
1844
+ type: "dialog",
1845
+ variant: "danger",
1846
+ footer: null,
1847
+ title: formatMessage({
1848
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1849
+ defaultMessage: "Confirmation"
1850
+ }),
1851
+ content: formatMessage(
1852
+ {
1853
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1854
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1855
+ },
1856
+ {
1857
+ count: totalDraftRelations
1724
1858
  }
1725
- } finally {
1726
- setSubmitting(false);
1859
+ ),
1860
+ onConfirm: async () => {
1861
+ await performPublish();
1727
1862
  }
1728
- }
1863
+ } : void 0
1729
1864
  };
1730
1865
  };
1731
1866
  PublishAction$1.type = "publish";
@@ -1741,10 +1876,6 @@ const UpdateAction = ({
1741
1876
  const cloneMatch = useMatch(CLONE_PATH);
1742
1877
  const isCloning = cloneMatch !== null;
1743
1878
  const { formatMessage } = useIntl();
1744
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1745
- canCreate: canCreate2,
1746
- canUpdate: canUpdate2
1747
- }));
1748
1879
  const { create, update, clone } = useDocumentActions();
1749
1880
  const [{ query, rawQuery }] = useQueryParams();
1750
1881
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1761,10 +1892,8 @@ const UpdateAction = ({
1761
1892
  * - the form is submitting
1762
1893
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1763
1894
  * - the active tab is the published tab
1764
- * - the user doesn't have the permission to create a new document
1765
- * - the user doesn't have the permission to update the document
1766
1895
  */
1767
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1896
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1768
1897
  label: formatMessage({
1769
1898
  id: "content-manager.containers.Edit.save",
1770
1899
  defaultMessage: "Save"
@@ -1772,16 +1901,18 @@ const UpdateAction = ({
1772
1901
  onClick: async () => {
1773
1902
  setSubmitting(true);
1774
1903
  try {
1775
- const { errors } = await validate();
1776
- if (errors) {
1777
- toggleNotification({
1778
- type: "danger",
1779
- message: formatMessage({
1780
- id: "content-manager.validation.error",
1781
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1782
- })
1783
- });
1784
- return;
1904
+ if (activeTab !== "draft") {
1905
+ const { errors } = await validate();
1906
+ if (errors) {
1907
+ toggleNotification({
1908
+ type: "danger",
1909
+ message: formatMessage({
1910
+ id: "content-manager.validation.error",
1911
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1912
+ })
1913
+ });
1914
+ return;
1915
+ }
1785
1916
  }
1786
1917
  if (isCloning) {
1787
1918
  const res = await clone(
@@ -1793,10 +1924,13 @@ const UpdateAction = ({
1793
1924
  document
1794
1925
  );
1795
1926
  if ("data" in res) {
1796
- navigate({
1797
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1798
- search: rawQuery
1799
- });
1927
+ navigate(
1928
+ {
1929
+ pathname: `../${res.data.documentId}`,
1930
+ search: rawQuery
1931
+ },
1932
+ { relative: "path" }
1933
+ );
1800
1934
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1801
1935
  setErrors(formatValidationErrors(res.error));
1802
1936
  }
@@ -1826,10 +1960,10 @@ const UpdateAction = ({
1826
1960
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1827
1961
  navigate(
1828
1962
  {
1829
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1963
+ pathname: `../${res.data.documentId}`,
1830
1964
  search: rawQuery
1831
1965
  },
1832
- { replace: true }
1966
+ { replace: true, relative: "path" }
1833
1967
  );
1834
1968
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1835
1969
  setErrors(formatValidationErrors(res.error));
@@ -1874,7 +2008,7 @@ const UnpublishAction$1 = ({
1874
2008
  id: "app.utils.unpublish",
1875
2009
  defaultMessage: "Unpublish"
1876
2010
  }),
1877
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2011
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1878
2012
  onClick: async () => {
1879
2013
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1880
2014
  if (!documentId) {
@@ -1986,7 +2120,7 @@ const DiscardAction = ({
1986
2120
  id: "content-manager.actions.discard.label",
1987
2121
  defaultMessage: "Discard changes"
1988
2122
  }),
1989
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2123
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1990
2124
  position: ["panel", "table-row"],
1991
2125
  variant: "danger",
1992
2126
  dialog: {
@@ -2014,11 +2148,6 @@ const DiscardAction = ({
2014
2148
  };
2015
2149
  };
2016
2150
  DiscardAction.type = "discard";
2017
- const StyledCrossCircle = styled(CrossCircle)`
2018
- path {
2019
- fill: currentColor;
2020
- }
2021
- `;
2022
2151
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2023
2152
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2024
2153
  const RelativeTime = React.forwardRef(
@@ -2066,7 +2195,7 @@ const getDisplayName = ({
2066
2195
  };
2067
2196
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2068
2197
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2069
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2198
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2070
2199
  return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2071
2200
  };
2072
2201
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2076,23 +2205,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2076
2205
  id: "content-manager.containers.edit.title.new",
2077
2206
  defaultMessage: "Create an entry"
2078
2207
  }) : documentTitle;
2079
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2208
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2080
2209
  /* @__PURE__ */ jsx(BackButton, {}),
2081
- /* @__PURE__ */ jsxs(
2082
- Flex,
2083
- {
2084
- width: "100%",
2085
- justifyContent: "space-between",
2086
- paddingTop: 1,
2087
- gap: "80px",
2088
- alignItems: "flex-start",
2089
- children: [
2090
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2091
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2092
- ]
2093
- }
2094
- ),
2095
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2210
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2211
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2212
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2213
+ ] }),
2214
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2096
2215
  ] });
2097
2216
  };
2098
2217
  const HeaderToolbar = () => {
@@ -2259,8 +2378,22 @@ const Information = ({ activeTab }) => {
2259
2378
  );
2260
2379
  };
2261
2380
  const HeaderActions = ({ actions: actions2 }) => {
2262
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2263
- if ("options" in action) {
2381
+ const [dialogId, setDialogId] = React.useState(null);
2382
+ const handleClick = (action) => async (e) => {
2383
+ if (!("options" in action)) {
2384
+ const { onClick = () => false, dialog, id } = action;
2385
+ const muteDialog = await onClick(e);
2386
+ if (dialog && !muteDialog) {
2387
+ e.preventDefault();
2388
+ setDialogId(id);
2389
+ }
2390
+ }
2391
+ };
2392
+ const handleClose = () => {
2393
+ setDialogId(null);
2394
+ };
2395
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2396
+ if (action.options) {
2264
2397
  return /* @__PURE__ */ jsx(
2265
2398
  SingleSelect,
2266
2399
  {
@@ -2274,10 +2407,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2274
2407
  action.id
2275
2408
  );
2276
2409
  } else {
2277
- return null;
2410
+ if (action.type === "icon") {
2411
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2412
+ /* @__PURE__ */ jsx(
2413
+ IconButton,
2414
+ {
2415
+ disabled: action.disabled,
2416
+ label: action.label,
2417
+ size: "S",
2418
+ onClick: handleClick(action),
2419
+ children: action.icon
2420
+ }
2421
+ ),
2422
+ action.dialog ? /* @__PURE__ */ jsx(
2423
+ HeaderActionDialog,
2424
+ {
2425
+ ...action.dialog,
2426
+ isOpen: dialogId === action.id,
2427
+ onClose: handleClose
2428
+ }
2429
+ ) : null
2430
+ ] }, action.id);
2431
+ }
2278
2432
  }
2279
2433
  }) });
2280
2434
  };
2435
+ const HeaderActionDialog = ({
2436
+ onClose,
2437
+ onCancel,
2438
+ title,
2439
+ content: Content,
2440
+ isOpen
2441
+ }) => {
2442
+ const handleClose = async () => {
2443
+ if (onCancel) {
2444
+ await onCancel();
2445
+ }
2446
+ onClose();
2447
+ };
2448
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2449
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2450
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2451
+ ] }) });
2452
+ };
2281
2453
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2282
2454
  const navigate = useNavigate();
2283
2455
  const { formatMessage } = useIntl();
@@ -2413,7 +2585,7 @@ const ActionsPanel = () => {
2413
2585
  return {
2414
2586
  title: formatMessage({
2415
2587
  id: "content-manager.containers.edit.panels.default.title",
2416
- defaultMessage: "Document"
2588
+ defaultMessage: "Entry"
2417
2589
  }),
2418
2590
  content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2419
2591
  };
@@ -2657,7 +2829,8 @@ const formatEditLayout = (data, {
2657
2829
  layout: convertEditLayoutToFieldLayouts(
2658
2830
  configuration.layouts.edit,
2659
2831
  components[uid].attributes,
2660
- configuration.metadatas
2832
+ configuration.metadatas,
2833
+ { configurations: data.components, schemas: components }
2661
2834
  ),
2662
2835
  settings: {
2663
2836
  ...configuration.settings,
@@ -2783,7 +2956,7 @@ const ConfirmBulkActionDialog = ({
2783
2956
  endAction
2784
2957
  }) => {
2785
2958
  const { formatMessage } = useIntl();
2786
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2959
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2787
2960
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2788
2961
  id: "app.components.ConfirmDialog.title",
2789
2962
  defaultMessage: "Confirmation"
@@ -2814,6 +2987,7 @@ const ConfirmDialogPublishAll = ({
2814
2987
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2815
2988
  const { model, schema } = useDoc();
2816
2989
  const [{ query }] = useQueryParams();
2990
+ const enableDraftRelationsCount = false;
2817
2991
  const {
2818
2992
  data: countDraftRelations = 0,
2819
2993
  isLoading,
@@ -2825,7 +2999,7 @@ const ConfirmDialogPublishAll = ({
2825
2999
  locale: query?.plugins?.i18n?.locale
2826
3000
  },
2827
3001
  {
2828
- skip: selectedEntries.length === 0
3002
+ skip: !enableDraftRelationsCount
2829
3003
  }
2830
3004
  );
2831
3005
  React.useEffect(() => {
@@ -3010,7 +3184,7 @@ const SelectedEntriesTableContent = ({
3010
3184
  status: row.status
3011
3185
  }
3012
3186
  ) }),
3013
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3187
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3014
3188
  IconButton,
3015
3189
  {
3016
3190
  tag: Link,
@@ -3033,9 +3207,10 @@ const SelectedEntriesTableContent = ({
3033
3207
  ),
3034
3208
  target: "_blank",
3035
3209
  marginLeft: "auto",
3036
- children: /* @__PURE__ */ jsx(Pencil, {})
3210
+ variant: "ghost",
3211
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3037
3212
  }
3038
- ) })
3213
+ ) }) })
3039
3214
  ] }, row.id)) })
3040
3215
  ] });
3041
3216
  };
@@ -3072,7 +3247,13 @@ const SelectedEntriesModalContent = ({
3072
3247
  );
3073
3248
  const { rows, validationErrors } = React.useMemo(() => {
3074
3249
  if (data.length > 0 && schema) {
3075
- const validate = createYupSchema(schema.attributes, components);
3250
+ const validate = createYupSchema(
3251
+ schema.attributes,
3252
+ components,
3253
+ // Since this is the "Publish" action, the validation
3254
+ // schema must enforce the rules for published entities
3255
+ { status: "published" }
3256
+ );
3076
3257
  const validationErrors2 = {};
3077
3258
  const rows2 = data.map((entry) => {
3078
3259
  try {
@@ -3422,7 +3603,7 @@ const TableActions = ({ document }) => {
3422
3603
  DescriptionComponentRenderer,
3423
3604
  {
3424
3605
  props,
3425
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3606
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3426
3607
  children: (actions2) => {
3427
3608
  const tableRowActions = actions2.filter((action) => {
3428
3609
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3533,7 +3714,7 @@ const CloneAction = ({ model, documentId }) => {
3533
3714
  }),
3534
3715
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3535
3716
  footer: ({ onClose }) => {
3536
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3717
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3537
3718
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3538
3719
  id: "cancel",
3539
3720
  defaultMessage: "Cancel"
@@ -3574,8 +3755,7 @@ class ContentManagerPlugin {
3574
3755
  documentActions = [
3575
3756
  ...DEFAULT_ACTIONS,
3576
3757
  ...DEFAULT_TABLE_ROW_ACTIONS,
3577
- ...DEFAULT_HEADER_ACTIONS,
3578
- HistoryAction
3758
+ ...DEFAULT_HEADER_ACTIONS
3579
3759
  ];
3580
3760
  editViewSidePanels = [ActionsPanel];
3581
3761
  headerActions = [];
@@ -3664,6 +3844,52 @@ const getPrintableType = (value) => {
3664
3844
  }
3665
3845
  return nativeType;
3666
3846
  };
3847
+ const HistoryAction = ({ model, document }) => {
3848
+ const { formatMessage } = useIntl();
3849
+ const [{ query }] = useQueryParams();
3850
+ const navigate = useNavigate();
3851
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3852
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3853
+ return null;
3854
+ }
3855
+ return {
3856
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3857
+ label: formatMessage({
3858
+ id: "content-manager.history.document-action",
3859
+ defaultMessage: "Content History"
3860
+ }),
3861
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3862
+ disabled: (
3863
+ /**
3864
+ * The user is creating a new document.
3865
+ * It hasn't been saved yet, so there's no history to go to
3866
+ */
3867
+ !document || /**
3868
+ * The document has been created but the current dimension has never been saved.
3869
+ * For example, the user is creating a new locale in an existing document,
3870
+ * so there's no history for the document in that locale
3871
+ */
3872
+ !document.id || /**
3873
+ * History is only available for content types created by the user.
3874
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3875
+ * which start with `admin::` or `plugin::`
3876
+ */
3877
+ !model.startsWith("api::")
3878
+ ),
3879
+ position: "header"
3880
+ };
3881
+ };
3882
+ HistoryAction.type = "history";
3883
+ const historyAdmin = {
3884
+ bootstrap(app) {
3885
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3886
+ addDocumentAction((actions2) => {
3887
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3888
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3889
+ return actions2;
3890
+ });
3891
+ }
3892
+ };
3667
3893
  const initialState = {
3668
3894
  collectionTypeLinks: [],
3669
3895
  components: [],
@@ -3719,7 +3945,7 @@ const index = {
3719
3945
  app.router.addRoute({
3720
3946
  path: "content-manager/*",
3721
3947
  lazy: async () => {
3722
- const { Layout } = await import("./layout-Bx7svTbY.mjs");
3948
+ const { Layout } = await import("./layout-D4HI4_PS.mjs");
3723
3949
  return {
3724
3950
  Component: Layout
3725
3951
  };
@@ -3728,10 +3954,15 @@ const index = {
3728
3954
  });
3729
3955
  app.registerPlugin(cm.config);
3730
3956
  },
3957
+ bootstrap(app) {
3958
+ if (typeof historyAdmin.bootstrap === "function") {
3959
+ historyAdmin.bootstrap(app);
3960
+ }
3961
+ },
3731
3962
  async registerTrads({ locales }) {
3732
3963
  const importedTrads = await Promise.all(
3733
3964
  locales.map((locale) => {
3734
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Ux26r5pl.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3965
+ 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-CPTj6CjC.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3735
3966
  return {
3736
3967
  data: prefixPluginTranslations(data, PLUGIN_ID),
3737
3968
  locale
@@ -3752,13 +3983,14 @@ export {
3752
3983
  BulkActionsRenderer as B,
3753
3984
  COLLECTION_TYPES as C,
3754
3985
  DocumentStatus as D,
3755
- DEFAULT_SETTINGS as E,
3756
- convertEditLayoutToFieldLayouts as F,
3757
- useDocument as G,
3986
+ extractContentTypeComponents as E,
3987
+ DEFAULT_SETTINGS as F,
3988
+ convertEditLayoutToFieldLayouts as G,
3758
3989
  HOOKS as H,
3759
3990
  InjectionZone as I,
3760
- index as J,
3761
- useDocumentActions as K,
3991
+ useDocument as J,
3992
+ index as K,
3993
+ useDocumentActions as L,
3762
3994
  Panels as P,
3763
3995
  RelativeTime as R,
3764
3996
  SINGLE_TYPES as S,
@@ -3776,18 +4008,18 @@ export {
3776
4008
  PERMISSIONS as k,
3777
4009
  DocumentRBAC as l,
3778
4010
  DOCUMENT_META_FIELDS as m,
3779
- useDocLayout as n,
3780
- useGetContentTypeConfigurationQuery as o,
3781
- CREATOR_FIELDS as p,
3782
- getMainField as q,
3783
- getDisplayName as r,
4011
+ CLONE_PATH as n,
4012
+ useDocLayout as o,
4013
+ useGetContentTypeConfigurationQuery as p,
4014
+ CREATOR_FIELDS as q,
4015
+ getMainField as r,
3784
4016
  setInitialData as s,
3785
- checkIfAttributeIsDisplayable as t,
4017
+ getDisplayName as t,
3786
4018
  useContentTypeSchema as u,
3787
- useGetAllDocumentsQuery as v,
3788
- convertListLayoutToFieldLayouts as w,
3789
- capitalise as x,
3790
- useUpdateContentTypeConfigurationMutation as y,
3791
- extractContentTypeComponents as z
4019
+ checkIfAttributeIsDisplayable as v,
4020
+ useGetAllDocumentsQuery as w,
4021
+ convertListLayoutToFieldLayouts as x,
4022
+ capitalise as y,
4023
+ useUpdateContentTypeConfigurationMutation as z
3792
4024
  };
3793
- //# sourceMappingURL=index-CaE6NG4a.mjs.map
4025
+ //# sourceMappingURL=index-D4UGPFZC.mjs.map