@strapi/content-manager 0.0.0-experimental.3c73a4c6f6073abdf1608121a200c3d4d87b1aa8 → 0.0.0-experimental.3fd705928266d1b836afc8a30fceb35aac0ae2f8

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 (130) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-Cxz51Sve.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
  3. package/dist/_chunks/{ComponentConfigurationPage-Cxz51Sve.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
  4. package/dist/_chunks/{ComponentConfigurationPage-BZIaEffq.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
  5. package/dist/_chunks/{ComponentConfigurationPage-BZIaEffq.js.map → ComponentConfigurationPage-_zF8p6CY.js.map} +1 -1
  6. package/dist/_chunks/{EditConfigurationPage-CZLbgfIp.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
  7. package/dist/_chunks/{EditConfigurationPage-CZLbgfIp.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
  8. package/dist/_chunks/{EditConfigurationPage-CM62NN0L.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
  9. package/dist/_chunks/{EditConfigurationPage-CM62NN0L.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
  10. package/dist/_chunks/{EditViewPage-CzuJgWWp.mjs → EditViewPage-DeTn7rAF.mjs} +58 -47
  11. package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
  12. package/dist/_chunks/{EditViewPage-CU7724gt.js → EditViewPage-G9uNzwYL.js} +57 -46
  13. package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
  14. package/dist/_chunks/{Field-QtUSh5mU.mjs → Field-CnCKhI1R.mjs} +526 -218
  15. package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
  16. package/dist/_chunks/{Field-Dh1yZyqy.js → Field-DDHUWEfV.js} +528 -220
  17. package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
  18. package/dist/_chunks/{Form-BOR8NOe1.js → Form-DYETaKUX.js} +51 -33
  19. package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
  20. package/dist/_chunks/{Form-COLpvlnv.mjs → Form-IvVVwqRL.mjs} +53 -35
  21. package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
  22. package/dist/_chunks/{History-Bu53Yfw-.mjs → History-BMunT-do.mjs} +141 -37
  23. package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
  24. package/dist/_chunks/{History-CW2akQ6h.js → History-CnZDctSO.js} +140 -36
  25. package/dist/_chunks/History-CnZDctSO.js.map +1 -0
  26. package/dist/_chunks/{ListConfigurationPage-jzdhEk_u.js → ListConfigurationPage-BynalOp8.js} +57 -46
  27. package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
  28. package/dist/_chunks/{ListConfigurationPage-TqrmwjPN.mjs → ListConfigurationPage-CDqkCxgV.mjs} +58 -48
  29. package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
  30. package/dist/_chunks/{ListViewPage-B3bMOrMv.js → ListViewPage-I88Ouzoq.js} +100 -103
  31. package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
  32. package/dist/_chunks/{ListViewPage-BO_mOXIl.mjs → ListViewPage-_5gS-DOF.mjs} +98 -101
  33. package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
  34. package/dist/_chunks/{NoContentTypePage-D77xsNHj.js → NoContentTypePage-BaWQ7HsA.js} +2 -2
  35. package/dist/_chunks/{NoContentTypePage-D77xsNHj.js.map → NoContentTypePage-BaWQ7HsA.js.map} +1 -1
  36. package/dist/_chunks/{NoContentTypePage-DqB0QV0k.mjs → NoContentTypePage-Dht-55hr.mjs} +2 -2
  37. package/dist/_chunks/{NoContentTypePage-DqB0QV0k.mjs.map → NoContentTypePage-Dht-55hr.mjs.map} +1 -1
  38. package/dist/_chunks/{NoPermissionsPage-DTXi042N.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
  39. package/dist/_chunks/{NoPermissionsPage-DTXi042N.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
  40. package/dist/_chunks/{NoPermissionsPage-C6qTGogm.js → NoPermissionsPage-DCVUh5at.js} +2 -2
  41. package/dist/_chunks/{NoPermissionsPage-C6qTGogm.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
  42. package/dist/_chunks/{Relations-B6fb2POW.js → Relations-BPgFQeGj.js} +4 -4
  43. package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
  44. package/dist/_chunks/{Relations-CJ4qdkRo.mjs → Relations-Chdt5qWc.mjs} +4 -4
  45. package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
  46. package/dist/_chunks/{en-DZXjRiWA.js → en-BVzUkPxZ.js} +12 -8
  47. package/dist/_chunks/{en-DZXjRiWA.js.map → en-BVzUkPxZ.js.map} +1 -1
  48. package/dist/_chunks/{en-9GwRW_ku.mjs → en-CPTj6CjC.mjs} +12 -8
  49. package/dist/_chunks/{en-9GwRW_ku.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
  50. package/dist/_chunks/{index-DcUu-_72.js → index-BhbLFX4l.js} +527 -439
  51. package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
  52. package/dist/_chunks/{index-Dahjdw4h.mjs → index-D4UGPFZC.mjs} +534 -446
  53. package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
  54. package/dist/_chunks/{layout-jcY4dyUG.js → layout-CYA7s0qO.js} +25 -12
  55. package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
  56. package/dist/_chunks/{layout-omucV6TV.mjs → layout-D4HI4_PS.mjs} +27 -14
  57. package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
  58. package/dist/_chunks/{relations-CN0-aw6p.mjs → relations-1pXaYpBK.mjs} +2 -2
  59. package/dist/_chunks/{relations-CN0-aw6p.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
  60. package/dist/_chunks/{relations-DGzD7ORa.js → relations-DDZ9OxNo.js} +2 -2
  61. package/dist/_chunks/{relations-DGzD7ORa.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 +1 -1
  68. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  69. package/dist/admin/src/history/index.d.ts +3 -0
  70. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  71. package/dist/admin/src/index.d.ts +1 -0
  72. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
  73. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  74. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
  75. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  76. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  77. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +6 -58
  78. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  79. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  80. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  81. package/dist/admin/src/services/api.d.ts +1 -1
  82. package/dist/admin/src/services/components.d.ts +2 -2
  83. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  84. package/dist/admin/src/services/documents.d.ts +19 -17
  85. package/dist/admin/src/services/init.d.ts +1 -1
  86. package/dist/admin/src/services/relations.d.ts +2 -2
  87. package/dist/admin/src/services/uid.d.ts +3 -3
  88. package/dist/admin/src/utils/validation.d.ts +4 -1
  89. package/dist/server/index.js +181 -107
  90. package/dist/server/index.js.map +1 -1
  91. package/dist/server/index.mjs +182 -108
  92. package/dist/server/index.mjs.map +1 -1
  93. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  94. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  95. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  96. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  97. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  98. package/dist/server/src/history/services/history.d.ts.map +1 -1
  99. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  100. package/dist/server/src/history/services/utils.d.ts +2 -1
  101. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  102. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  103. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  104. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  105. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  106. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  107. package/dist/shared/contracts/collection-types.d.ts +3 -1
  108. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  109. package/package.json +9 -9
  110. package/dist/_chunks/EditViewPage-CU7724gt.js.map +0 -1
  111. package/dist/_chunks/EditViewPage-CzuJgWWp.mjs.map +0 -1
  112. package/dist/_chunks/Field-Dh1yZyqy.js.map +0 -1
  113. package/dist/_chunks/Field-QtUSh5mU.mjs.map +0 -1
  114. package/dist/_chunks/Form-BOR8NOe1.js.map +0 -1
  115. package/dist/_chunks/Form-COLpvlnv.mjs.map +0 -1
  116. package/dist/_chunks/History-Bu53Yfw-.mjs.map +0 -1
  117. package/dist/_chunks/History-CW2akQ6h.js.map +0 -1
  118. package/dist/_chunks/ListConfigurationPage-TqrmwjPN.mjs.map +0 -1
  119. package/dist/_chunks/ListConfigurationPage-jzdhEk_u.js.map +0 -1
  120. package/dist/_chunks/ListViewPage-B3bMOrMv.js.map +0 -1
  121. package/dist/_chunks/ListViewPage-BO_mOXIl.mjs.map +0 -1
  122. package/dist/_chunks/Relations-B6fb2POW.js.map +0 -1
  123. package/dist/_chunks/Relations-CJ4qdkRo.mjs.map +0 -1
  124. package/dist/_chunks/index-Dahjdw4h.mjs.map +0 -1
  125. package/dist/_chunks/index-DcUu-_72.js.map +0 -1
  126. package/dist/_chunks/layout-jcY4dyUG.js.map +0 -1
  127. package/dist/_chunks/layout-omucV6TV.mjs.map +0 -1
  128. package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
  129. package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
  130. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
@@ -2,15 +2,15 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
10
- const styledComponents = require("styled-components");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
11
9
  const yup = require("yup");
12
10
  const pipe = require("lodash/fp/pipe");
13
11
  const dateFns = require("date-fns");
12
+ const styledComponents = require("styled-components");
13
+ const qs = require("qs");
14
14
  const toolkit = require("@reduxjs/toolkit");
15
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
16
16
  function _interopNamespace(e) {
@@ -70,42 +70,6 @@ const useInjectionZone = (area) => {
70
70
  const [page, position] = area.split(".");
71
71
  return contentManagerPlugin.getInjectedComponents(page, position);
72
72
  };
73
- const HistoryAction = ({ model, document }) => {
74
- const { formatMessage } = reactIntl.useIntl();
75
- const [{ query }] = strapiAdmin.useQueryParams();
76
- const navigate = reactRouterDom.useNavigate();
77
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
78
- if (!window.strapi.features.isEnabled("cms-content-history")) {
79
- return null;
80
- }
81
- return {
82
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
83
- label: formatMessage({
84
- id: "content-manager.history.document-action",
85
- defaultMessage: "Content History"
86
- }),
87
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
88
- disabled: (
89
- /**
90
- * The user is creating a new document.
91
- * It hasn't been saved yet, so there's no history to go to
92
- */
93
- !document || /**
94
- * The document has been created but the current dimension has never been saved.
95
- * For example, the user is creating a new locale in an existing document,
96
- * so there's no history for the document in that locale
97
- */
98
- !document.id || /**
99
- * History is only available for content types created by the user.
100
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
101
- * which start with `admin::` or `plugin::`
102
- */
103
- !model.startsWith("api::")
104
- ),
105
- position: "header"
106
- };
107
- };
108
- HistoryAction.type = "history";
109
73
  const ID = "id";
110
74
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
111
75
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -215,10 +179,12 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
215
179
  "Document",
216
180
  "InitialData",
217
181
  "HistoryVersion",
218
- "Relations"
182
+ "Relations",
183
+ "UidAvailability"
219
184
  ]
220
185
  });
221
186
  const documentApi = contentManagerApi.injectEndpoints({
187
+ overrideExisting: true,
222
188
  endpoints: (builder) => ({
223
189
  autoCloneDocument: builder.mutation({
224
190
  query: ({ model, sourceId, query }) => ({
@@ -228,7 +194,12 @@ const documentApi = contentManagerApi.injectEndpoints({
228
194
  params: query
229
195
  }
230
196
  }),
231
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
197
+ invalidatesTags: (_result, error, { model }) => {
198
+ if (error) {
199
+ return [];
200
+ }
201
+ return [{ type: "Document", id: `${model}_LIST` }];
202
+ }
232
203
  }),
233
204
  cloneDocument: builder.mutation({
234
205
  query: ({ model, sourceId, data, params }) => ({
@@ -239,7 +210,10 @@ const documentApi = contentManagerApi.injectEndpoints({
239
210
  params
240
211
  }
241
212
  }),
242
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
213
+ invalidatesTags: (_result, _error, { model }) => [
214
+ { type: "Document", id: `${model}_LIST` },
215
+ { type: "UidAvailability", id: model }
216
+ ]
243
217
  }),
244
218
  /**
245
219
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -256,7 +230,8 @@ const documentApi = contentManagerApi.injectEndpoints({
256
230
  }),
257
231
  invalidatesTags: (result, _error, { model }) => [
258
232
  { type: "Document", id: `${model}_LIST` },
259
- "Relations"
233
+ "Relations",
234
+ { type: "UidAvailability", id: model }
260
235
  ]
261
236
  }),
262
237
  deleteDocument: builder.mutation({
@@ -297,7 +272,8 @@ const documentApi = contentManagerApi.injectEndpoints({
297
272
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
298
273
  },
299
274
  { type: "Document", id: `${model}_LIST` },
300
- "Relations"
275
+ "Relations",
276
+ { type: "UidAvailability", id: model }
301
277
  ];
302
278
  }
303
279
  }),
@@ -315,6 +291,7 @@ const documentApi = contentManagerApi.injectEndpoints({
315
291
  }),
316
292
  providesTags: (result, _error, arg) => {
317
293
  return [
294
+ { type: "Document", id: `ALL_LIST` },
318
295
  { type: "Document", id: `${arg.model}_LIST` },
319
296
  ...result?.results.map(({ documentId }) => ({
320
297
  type: "Document",
@@ -353,6 +330,11 @@ const documentApi = contentManagerApi.injectEndpoints({
353
330
  {
354
331
  type: "Document",
355
332
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
333
+ },
334
+ // Make it easy to invalidate all individual documents queries for a model
335
+ {
336
+ type: "Document",
337
+ id: `${model}_ALL_ITEMS`
356
338
  }
357
339
  ];
358
340
  }
@@ -416,8 +398,21 @@ const documentApi = contentManagerApi.injectEndpoints({
416
398
  type: "Document",
417
399
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
418
400
  },
419
- "Relations"
401
+ "Relations",
402
+ { type: "UidAvailability", id: model }
420
403
  ];
404
+ },
405
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
406
+ const patchResult = dispatch(
407
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
408
+ Object.assign(draft.data, data);
409
+ })
410
+ );
411
+ try {
412
+ await queryFulfilled;
413
+ } catch {
414
+ patchResult.undo();
415
+ }
421
416
  }
422
417
  }),
423
418
  unpublishDocument: builder.mutation({
@@ -487,7 +482,7 @@ const buildValidParams = (query) => {
487
482
  const isBaseQueryError = (error) => {
488
483
  return error.name !== void 0;
489
484
  };
490
- const createYupSchema = (attributes = {}, components = {}) => {
485
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
491
486
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
492
487
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
493
488
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -500,7 +495,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
500
495
  addMinValidation,
501
496
  addMaxValidation,
502
497
  addRegexValidation
503
- ].map((fn) => fn(attribute));
498
+ ].map((fn) => fn(attribute, options));
504
499
  const transformSchema = pipe__default.default(...validations);
505
500
  switch (attribute.type) {
506
501
  case "component": {
@@ -601,6 +596,14 @@ const createAttributeSchema = (attribute) => {
601
596
  if (!value || typeof value === "string" && value.length === 0) {
602
597
  return true;
603
598
  }
599
+ if (typeof value === "object") {
600
+ try {
601
+ JSON.stringify(value);
602
+ return true;
603
+ } catch (err) {
604
+ return false;
605
+ }
606
+ }
604
607
  try {
605
608
  JSON.parse(value);
606
609
  return true;
@@ -619,13 +622,7 @@ const createAttributeSchema = (attribute) => {
619
622
  return yup__namespace.mixed();
620
623
  }
621
624
  };
622
- const addRequiredValidation = (attribute) => (schema) => {
623
- if (attribute.required) {
624
- return schema.required({
625
- id: strapiAdmin.translatedErrors.required.id,
626
- defaultMessage: "This field is required."
627
- });
628
- }
625
+ const nullableSchema = (schema) => {
629
626
  return schema?.nullable ? schema.nullable() : (
630
627
  // In some cases '.nullable' will not be available on the schema.
631
628
  // e.g. when the schema has been built using yup.lazy (e.g. for relations).
@@ -633,7 +630,22 @@ const addRequiredValidation = (attribute) => (schema) => {
633
630
  schema
634
631
  );
635
632
  };
636
- const addMinLengthValidation = (attribute) => (schema) => {
633
+ const addRequiredValidation = (attribute, options) => (schema) => {
634
+ if (options.status === "draft") {
635
+ return nullableSchema(schema);
636
+ }
637
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
638
+ return schema.min(1, strapiAdmin.translatedErrors.required);
639
+ }
640
+ if (attribute.required && attribute.type !== "relation") {
641
+ return schema.required(strapiAdmin.translatedErrors.required);
642
+ }
643
+ return nullableSchema(schema);
644
+ };
645
+ const addMinLengthValidation = (attribute, options) => (schema) => {
646
+ if (options.status === "draft") {
647
+ return schema;
648
+ }
637
649
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
638
650
  return schema.min(attribute.minLength, {
639
651
  ...strapiAdmin.translatedErrors.minLength,
@@ -655,9 +667,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
655
667
  }
656
668
  return schema;
657
669
  };
658
- const addMinValidation = (attribute) => (schema) => {
670
+ const addMinValidation = (attribute, options) => (schema) => {
659
671
  if ("min" in attribute) {
660
672
  const min = toInteger(attribute.min);
673
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
674
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
675
+ return schema.test(
676
+ "custom-min",
677
+ {
678
+ ...strapiAdmin.translatedErrors.min,
679
+ values: {
680
+ min: attribute.min
681
+ }
682
+ },
683
+ (value) => {
684
+ if (!value) {
685
+ return true;
686
+ }
687
+ if (Array.isArray(value) && value.length === 0) {
688
+ return true;
689
+ }
690
+ return value.length >= min;
691
+ }
692
+ );
693
+ }
694
+ }
661
695
  if ("min" in schema && min) {
662
696
  return schema.min(min, {
663
697
  ...strapiAdmin.translatedErrors.min,
@@ -784,7 +818,10 @@ const useDocument = (args, opts) => {
784
818
  isLoading: isLoadingDocument,
785
819
  isFetching: isFetchingDocument,
786
820
  error
787
- } = useGetDocumentQuery(args, opts);
821
+ } = useGetDocumentQuery(args, {
822
+ ...opts,
823
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
824
+ });
788
825
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
789
826
  React__namespace.useEffect(() => {
790
827
  if (error) {
@@ -870,6 +907,7 @@ const useDocumentActions = () => {
870
907
  const { formatMessage } = reactIntl.useIntl();
871
908
  const { trackUsage } = strapiAdmin.useTracking();
872
909
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
910
+ const navigate = reactRouterDom.useNavigate();
873
911
  const [deleteDocument] = useDeleteDocumentMutation();
874
912
  const _delete = React__namespace.useCallback(
875
913
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1205,7 +1243,6 @@ const useDocumentActions = () => {
1205
1243
  sourceId
1206
1244
  });
1207
1245
  if ("error" in res) {
1208
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1209
1246
  return { error: res.error };
1210
1247
  }
1211
1248
  toggleNotification({
@@ -1224,7 +1261,7 @@ const useDocumentActions = () => {
1224
1261
  throw err;
1225
1262
  }
1226
1263
  },
1227
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1264
+ [autoCloneDocument, formatMessage, toggleNotification]
1228
1265
  );
1229
1266
  const [cloneDocument] = useCloneDocumentMutation();
1230
1267
  const clone = React__namespace.useCallback(
@@ -1250,6 +1287,7 @@ const useDocumentActions = () => {
1250
1287
  defaultMessage: "Cloned document"
1251
1288
  })
1252
1289
  });
1290
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1253
1291
  return res.data;
1254
1292
  } catch (err) {
1255
1293
  toggleNotification({
@@ -1260,7 +1298,7 @@ const useDocumentActions = () => {
1260
1298
  throw err;
1261
1299
  }
1262
1300
  },
1263
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1301
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1264
1302
  );
1265
1303
  const [getDoc] = useLazyGetDocumentQuery();
1266
1304
  const getDocument = React__namespace.useCallback(
@@ -1286,7 +1324,7 @@ const useDocumentActions = () => {
1286
1324
  };
1287
1325
  };
1288
1326
  const ProtectedHistoryPage = React.lazy(
1289
- () => Promise.resolve().then(() => require("./History-CW2akQ6h.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1327
+ () => Promise.resolve().then(() => require("./History-CnZDctSO.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1290
1328
  );
1291
1329
  const routes$1 = [
1292
1330
  {
@@ -1299,31 +1337,31 @@ const routes$1 = [
1299
1337
  }
1300
1338
  ];
1301
1339
  const ProtectedEditViewPage = React.lazy(
1302
- () => Promise.resolve().then(() => require("./EditViewPage-CU7724gt.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1340
+ () => Promise.resolve().then(() => require("./EditViewPage-G9uNzwYL.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1303
1341
  );
1304
1342
  const ProtectedListViewPage = React.lazy(
1305
- () => Promise.resolve().then(() => require("./ListViewPage-B3bMOrMv.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1343
+ () => Promise.resolve().then(() => require("./ListViewPage-I88Ouzoq.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1306
1344
  );
1307
1345
  const ProtectedListConfiguration = React.lazy(
1308
- () => Promise.resolve().then(() => require("./ListConfigurationPage-jzdhEk_u.js")).then((mod) => ({
1346
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-BynalOp8.js")).then((mod) => ({
1309
1347
  default: mod.ProtectedListConfiguration
1310
1348
  }))
1311
1349
  );
1312
1350
  const ProtectedEditConfigurationPage = React.lazy(
1313
- () => Promise.resolve().then(() => require("./EditConfigurationPage-CM62NN0L.js")).then((mod) => ({
1351
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-_aG2DJSU.js")).then((mod) => ({
1314
1352
  default: mod.ProtectedEditConfigurationPage
1315
1353
  }))
1316
1354
  );
1317
1355
  const ProtectedComponentConfigurationPage = React.lazy(
1318
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-BZIaEffq.js")).then((mod) => ({
1356
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-_zF8p6CY.js")).then((mod) => ({
1319
1357
  default: mod.ProtectedComponentConfigurationPage
1320
1358
  }))
1321
1359
  );
1322
1360
  const NoPermissions = React.lazy(
1323
- () => Promise.resolve().then(() => require("./NoPermissionsPage-C6qTGogm.js")).then((mod) => ({ default: mod.NoPermissions }))
1361
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-DCVUh5at.js")).then((mod) => ({ default: mod.NoPermissions }))
1324
1362
  );
1325
1363
  const NoContentType = React.lazy(
1326
- () => Promise.resolve().then(() => require("./NoContentTypePage-D77xsNHj.js")).then((mod) => ({ default: mod.NoContentType }))
1364
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BaWQ7HsA.js")).then((mod) => ({ default: mod.NoContentType }))
1327
1365
  );
1328
1366
  const CollectionTypePages = () => {
1329
1367
  const { collectionType } = reactRouterDom.useParams();
@@ -1437,12 +1475,14 @@ const DocumentActionButton = (action) => {
1437
1475
  /* @__PURE__ */ jsxRuntime.jsx(
1438
1476
  designSystem.Button,
1439
1477
  {
1440
- flex: 1,
1478
+ flex: "auto",
1441
1479
  startIcon: action.icon,
1442
1480
  disabled: action.disabled,
1443
1481
  onClick: handleClick(action),
1444
1482
  justifyContent: "center",
1445
1483
  variant: action.variant || "default",
1484
+ paddingTop: "7px",
1485
+ paddingBottom: "7px",
1446
1486
  children: action.label
1447
1487
  }
1448
1488
  ),
@@ -1450,7 +1490,7 @@ const DocumentActionButton = (action) => {
1450
1490
  DocumentActionConfirmDialog,
1451
1491
  {
1452
1492
  ...action.dialog,
1453
- variant: action.variant,
1493
+ variant: action.dialog?.variant ?? action.variant,
1454
1494
  isOpen: dialogId === action.id,
1455
1495
  onClose: handleClose
1456
1496
  }
@@ -1507,9 +1547,9 @@ const DocumentActionsMenu = ({
1507
1547
  disabled: isDisabled,
1508
1548
  size: "S",
1509
1549
  endIcon: null,
1510
- paddingTop: "7px",
1511
- paddingLeft: "9px",
1512
- paddingRight: "9px",
1550
+ paddingTop: "4px",
1551
+ paddingLeft: "7px",
1552
+ paddingRight: "7px",
1513
1553
  variant,
1514
1554
  children: [
1515
1555
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
@@ -1529,10 +1569,25 @@ const DocumentActionsMenu = ({
1529
1569
  onSelect: handleClick(action),
1530
1570
  display: "block",
1531
1571
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1532
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1533
- action.icon,
1534
- action.label
1535
- ] }),
1572
+ /* @__PURE__ */ jsxRuntime.jsxs(
1573
+ designSystem.Flex,
1574
+ {
1575
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1576
+ gap: 2,
1577
+ tag: "span",
1578
+ children: [
1579
+ /* @__PURE__ */ jsxRuntime.jsx(
1580
+ designSystem.Flex,
1581
+ {
1582
+ tag: "span",
1583
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1584
+ children: action.icon
1585
+ }
1586
+ ),
1587
+ action.label
1588
+ ]
1589
+ }
1590
+ ),
1536
1591
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
1537
1592
  designSystem.Flex,
1538
1593
  {
@@ -1591,6 +1646,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1591
1646
  return "primary600";
1592
1647
  }
1593
1648
  };
1649
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1650
+ switch (variant) {
1651
+ case "danger":
1652
+ return "danger600";
1653
+ case "secondary":
1654
+ return "neutral500";
1655
+ case "success":
1656
+ return "success600";
1657
+ default:
1658
+ return "primary600";
1659
+ }
1660
+ };
1594
1661
  const DocumentActionConfirmDialog = ({
1595
1662
  onClose,
1596
1663
  onCancel,
@@ -1613,22 +1680,20 @@ const DocumentActionConfirmDialog = ({
1613
1680
  }
1614
1681
  onClose();
1615
1682
  };
1616
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1617
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1618
- /* @__PURE__ */ jsxRuntime.jsx(
1619
- designSystem.DialogFooter,
1620
- {
1621
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1622
- id: "app.components.Button.cancel",
1623
- defaultMessage: "Cancel"
1624
- }) }),
1625
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1626
- id: "app.components.Button.confirm",
1627
- defaultMessage: "Confirm"
1628
- }) })
1629
- }
1630
- )
1631
- ] });
1683
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1684
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1685
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1686
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1687
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1688
+ id: "app.components.Button.cancel",
1689
+ defaultMessage: "Cancel"
1690
+ }) }) }),
1691
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1692
+ id: "app.components.Button.confirm",
1693
+ defaultMessage: "Confirm"
1694
+ }) })
1695
+ ] })
1696
+ ] }) });
1632
1697
  };
1633
1698
  const DocumentActionModal = ({
1634
1699
  isOpen,
@@ -1638,34 +1703,17 @@ const DocumentActionModal = ({
1638
1703
  content: Content,
1639
1704
  onModalClose
1640
1705
  }) => {
1641
- const id = React__namespace.useId();
1642
- if (!isOpen) {
1643
- return null;
1644
- }
1645
1706
  const handleClose = () => {
1646
1707
  if (onClose) {
1647
1708
  onClose();
1648
1709
  }
1649
1710
  onModalClose();
1650
1711
  };
1651
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1652
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1653
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content }),
1654
- /* @__PURE__ */ jsxRuntime.jsx(
1655
- designSystem.Box,
1656
- {
1657
- paddingTop: 4,
1658
- paddingBottom: 4,
1659
- paddingLeft: 5,
1660
- paddingRight: 5,
1661
- borderWidth: "1px 0 0 0",
1662
- borderStyle: "solid",
1663
- borderColor: "neutral150",
1664
- background: "neutral100",
1665
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1666
- }
1667
- )
1668
- ] });
1712
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1713
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1714
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1715
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1716
+ ] }) });
1669
1717
  };
1670
1718
  const PublishAction$1 = ({
1671
1719
  activeTab,
@@ -1679,13 +1727,17 @@ const PublishAction$1 = ({
1679
1727
  const navigate = reactRouterDom.useNavigate();
1680
1728
  const { toggleNotification } = strapiAdmin.useNotification();
1681
1729
  const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
1730
+ const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
1682
1731
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
1683
1732
  const { formatMessage } = reactIntl.useIntl();
1684
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1685
- "PublishAction",
1686
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1687
- );
1733
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1688
1734
  const { publish } = useDocumentActions();
1735
+ const [
1736
+ countDraftRelations,
1737
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1738
+ ] = useLazyGetDraftRelationCountQuery();
1739
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1740
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1689
1741
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1690
1742
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1691
1743
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1694,10 +1746,103 @@ const PublishAction$1 = ({
1694
1746
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1695
1747
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1696
1748
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1749
+ React__namespace.useEffect(() => {
1750
+ if (isErrorDraftRelations) {
1751
+ toggleNotification({
1752
+ type: "danger",
1753
+ message: formatMessage({
1754
+ id: getTranslation("error.records.fetch-draft-relatons"),
1755
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1756
+ })
1757
+ });
1758
+ }
1759
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1760
+ React__namespace.useEffect(() => {
1761
+ const localDraftRelations = /* @__PURE__ */ new Set();
1762
+ const extractDraftRelations = (data) => {
1763
+ const relations = data.connect || [];
1764
+ relations.forEach((relation) => {
1765
+ if (relation.status === "draft") {
1766
+ localDraftRelations.add(relation.id);
1767
+ }
1768
+ });
1769
+ };
1770
+ const traverseAndExtract = (data) => {
1771
+ Object.entries(data).forEach(([key, value]) => {
1772
+ if (key === "connect" && Array.isArray(value)) {
1773
+ extractDraftRelations({ connect: value });
1774
+ } else if (typeof value === "object" && value !== null) {
1775
+ traverseAndExtract(value);
1776
+ }
1777
+ });
1778
+ };
1779
+ if (!documentId || modified) {
1780
+ traverseAndExtract(formValues);
1781
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1782
+ }
1783
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1784
+ React__namespace.useEffect(() => {
1785
+ if (!document || !document.documentId || isListView) {
1786
+ return;
1787
+ }
1788
+ const fetchDraftRelationsCount = async () => {
1789
+ const { data, error } = await countDraftRelations({
1790
+ collectionType,
1791
+ model,
1792
+ documentId,
1793
+ params
1794
+ });
1795
+ if (error) {
1796
+ throw error;
1797
+ }
1798
+ if (data) {
1799
+ setServerCountOfDraftRelations(data.data);
1800
+ }
1801
+ };
1802
+ fetchDraftRelationsCount();
1803
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1697
1804
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1698
1805
  if (!schema?.options?.draftAndPublish) {
1699
1806
  return null;
1700
1807
  }
1808
+ const performPublish = async () => {
1809
+ setSubmitting(true);
1810
+ try {
1811
+ const { errors } = await validate();
1812
+ if (errors) {
1813
+ toggleNotification({
1814
+ type: "danger",
1815
+ message: formatMessage({
1816
+ id: "content-manager.validation.error",
1817
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1818
+ })
1819
+ });
1820
+ return;
1821
+ }
1822
+ const res = await publish(
1823
+ {
1824
+ collectionType,
1825
+ model,
1826
+ documentId,
1827
+ params
1828
+ },
1829
+ formValues
1830
+ );
1831
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1832
+ navigate({
1833
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1834
+ search: rawQuery
1835
+ });
1836
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1837
+ setErrors(formatValidationErrors(res.error));
1838
+ }
1839
+ } finally {
1840
+ setSubmitting(false);
1841
+ }
1842
+ };
1843
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1844
+ const enableDraftRelationsCount = false;
1845
+ const hasDraftRelations = enableDraftRelationsCount;
1701
1846
  return {
1702
1847
  /**
1703
1848
  * Disabled when:
@@ -1707,49 +1852,36 @@ const PublishAction$1 = ({
1707
1852
  * - the document is already published & not modified
1708
1853
  * - the document is being created & not modified
1709
1854
  * - the user doesn't have the permission to publish
1710
- * - the user doesn't have the permission to create a new document
1711
- * - the user doesn't have the permission to update the document
1712
1855
  */
1713
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1856
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1714
1857
  label: formatMessage({
1715
1858
  id: "app.utils.publish",
1716
1859
  defaultMessage: "Publish"
1717
1860
  }),
1718
1861
  onClick: async () => {
1719
- setSubmitting(true);
1720
- try {
1721
- const { errors } = await validate();
1722
- if (errors) {
1723
- toggleNotification({
1724
- type: "danger",
1725
- message: formatMessage({
1726
- id: "content-manager.validation.error",
1727
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1728
- })
1729
- });
1730
- return;
1731
- }
1732
- const res = await publish(
1733
- {
1734
- collectionType,
1735
- model,
1736
- documentId,
1737
- params
1738
- },
1739
- formValues
1740
- );
1741
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1742
- navigate({
1743
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1744
- search: rawQuery
1745
- });
1746
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1747
- setErrors(formatValidationErrors(res.error));
1862
+ await performPublish();
1863
+ },
1864
+ dialog: hasDraftRelations ? {
1865
+ type: "dialog",
1866
+ variant: "danger",
1867
+ footer: null,
1868
+ title: formatMessage({
1869
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1870
+ defaultMessage: "Confirmation"
1871
+ }),
1872
+ content: formatMessage(
1873
+ {
1874
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1875
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1876
+ },
1877
+ {
1878
+ count: totalDraftRelations
1748
1879
  }
1749
- } finally {
1750
- setSubmitting(false);
1880
+ ),
1881
+ onConfirm: async () => {
1882
+ await performPublish();
1751
1883
  }
1752
- }
1884
+ } : void 0
1753
1885
  };
1754
1886
  };
1755
1887
  PublishAction$1.type = "publish";
@@ -1765,10 +1897,6 @@ const UpdateAction = ({
1765
1897
  const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
1766
1898
  const isCloning = cloneMatch !== null;
1767
1899
  const { formatMessage } = reactIntl.useIntl();
1768
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1769
- canCreate: canCreate2,
1770
- canUpdate: canUpdate2
1771
- }));
1772
1900
  const { create, update, clone } = useDocumentActions();
1773
1901
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1774
1902
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
@@ -1785,10 +1913,8 @@ const UpdateAction = ({
1785
1913
  * - the form is submitting
1786
1914
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1787
1915
  * - the active tab is the published tab
1788
- * - the user doesn't have the permission to create a new document
1789
- * - the user doesn't have the permission to update the document
1790
1916
  */
1791
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1917
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1792
1918
  label: formatMessage({
1793
1919
  id: "content-manager.containers.Edit.save",
1794
1920
  defaultMessage: "Save"
@@ -1796,16 +1922,18 @@ const UpdateAction = ({
1796
1922
  onClick: async () => {
1797
1923
  setSubmitting(true);
1798
1924
  try {
1799
- const { errors } = await validate();
1800
- if (errors) {
1801
- toggleNotification({
1802
- type: "danger",
1803
- message: formatMessage({
1804
- id: "content-manager.validation.error",
1805
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1806
- })
1807
- });
1808
- return;
1925
+ if (activeTab !== "draft") {
1926
+ const { errors } = await validate();
1927
+ if (errors) {
1928
+ toggleNotification({
1929
+ type: "danger",
1930
+ message: formatMessage({
1931
+ id: "content-manager.validation.error",
1932
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1933
+ })
1934
+ });
1935
+ return;
1936
+ }
1809
1937
  }
1810
1938
  if (isCloning) {
1811
1939
  const res = await clone(
@@ -1817,10 +1945,13 @@ const UpdateAction = ({
1817
1945
  document
1818
1946
  );
1819
1947
  if ("data" in res) {
1820
- navigate({
1821
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1822
- search: rawQuery
1823
- });
1948
+ navigate(
1949
+ {
1950
+ pathname: `../${res.data.documentId}`,
1951
+ search: rawQuery
1952
+ },
1953
+ { relative: "path" }
1954
+ );
1824
1955
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1825
1956
  setErrors(formatValidationErrors(res.error));
1826
1957
  }
@@ -1848,10 +1979,13 @@ const UpdateAction = ({
1848
1979
  document
1849
1980
  );
1850
1981
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1851
- navigate({
1852
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1853
- search: rawQuery
1854
- });
1982
+ navigate(
1983
+ {
1984
+ pathname: `../${res.data.documentId}`,
1985
+ search: rawQuery
1986
+ },
1987
+ { replace: true, relative: "path" }
1988
+ );
1855
1989
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1856
1990
  setErrors(formatValidationErrors(res.error));
1857
1991
  }
@@ -1883,10 +2017,8 @@ const UnpublishAction$1 = ({
1883
2017
  const { toggleNotification } = strapiAdmin.useNotification();
1884
2018
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1885
2019
  const isDocumentModified = document?.status === "modified";
1886
- const handleChange = (e) => {
1887
- if ("value" in e.target) {
1888
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1889
- }
2020
+ const handleChange = (value) => {
2021
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1890
2022
  };
1891
2023
  if (!schema?.options?.draftAndPublish) {
1892
2024
  return null;
@@ -1897,7 +2029,7 @@ const UnpublishAction$1 = ({
1897
2029
  id: "app.utils.unpublish",
1898
2030
  defaultMessage: "Unpublish"
1899
2031
  }),
1900
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2032
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
1901
2033
  onClick: async () => {
1902
2034
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1903
2035
  if (!documentId) {
@@ -1936,40 +2068,24 @@ const UnpublishAction$1 = ({
1936
2068
  }) })
1937
2069
  ] }),
1938
2070
  /* @__PURE__ */ jsxRuntime.jsxs(
1939
- designSystem.Flex,
2071
+ designSystem.Radio.Group,
1940
2072
  {
1941
- onChange: handleChange,
1942
- direction: "column",
1943
- alignItems: "flex-start",
1944
- tag: "fieldset",
1945
- borderWidth: 0,
1946
- gap: 3,
2073
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2074
+ name: "discard-options",
2075
+ "aria-label": formatMessage({
2076
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2077
+ defaultMessage: "Choose an option to unpublish the document."
2078
+ }),
2079
+ onValueChange: handleChange,
1947
2080
  children: [
1948
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "legend" }),
1949
- /* @__PURE__ */ jsxRuntime.jsx(
1950
- designSystem.Radio,
1951
- {
1952
- checked: shouldKeepDraft,
1953
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1954
- name: "discard-options",
1955
- children: formatMessage({
1956
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1957
- defaultMessage: "Keep draft"
1958
- })
1959
- }
1960
- ),
1961
- /* @__PURE__ */ jsxRuntime.jsx(
1962
- designSystem.Radio,
1963
- {
1964
- checked: !shouldKeepDraft,
1965
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1966
- name: "discard-options",
1967
- children: formatMessage({
1968
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1969
- defaultMessage: "Replace draft"
1970
- })
1971
- }
1972
- )
2081
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2082
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2083
+ defaultMessage: "Keep draft"
2084
+ }) }),
2085
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2086
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2087
+ defaultMessage: "Replace draft"
2088
+ }) })
1973
2089
  ]
1974
2090
  }
1975
2091
  )
@@ -2025,7 +2141,7 @@ const DiscardAction = ({
2025
2141
  id: "content-manager.actions.discard.label",
2026
2142
  defaultMessage: "Discard changes"
2027
2143
  }),
2028
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
2144
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
2029
2145
  position: ["panel", "table-row"],
2030
2146
  variant: "danger",
2031
2147
  dialog: {
@@ -2053,11 +2169,6 @@ const DiscardAction = ({
2053
2169
  };
2054
2170
  };
2055
2171
  DiscardAction.type = "discard";
2056
- const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
2057
- path {
2058
- fill: currentColor;
2059
- }
2060
- `;
2061
2172
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2062
2173
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2063
2174
  const RelativeTime = React__namespace.forwardRef(
@@ -2105,7 +2216,7 @@ const getDisplayName = ({
2105
2216
  };
2106
2217
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2107
2218
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2108
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2219
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2109
2220
  return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2110
2221
  };
2111
2222
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
@@ -2115,23 +2226,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2115
2226
  id: "content-manager.containers.edit.title.new",
2116
2227
  defaultMessage: "Create an entry"
2117
2228
  }) : documentTitle;
2118
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2229
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2119
2230
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2120
- /* @__PURE__ */ jsxRuntime.jsxs(
2121
- designSystem.Flex,
2122
- {
2123
- width: "100%",
2124
- justifyContent: "space-between",
2125
- paddingTop: 1,
2126
- gap: "80px",
2127
- alignItems: "flex-start",
2128
- children: [
2129
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2130
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2131
- ]
2132
- }
2133
- ),
2134
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2231
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2232
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2233
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2234
+ ] }),
2235
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2135
2236
  ] });
2136
2237
  };
2137
2238
  const HeaderToolbar = () => {
@@ -2298,8 +2399,22 @@ const Information = ({ activeTab }) => {
2298
2399
  );
2299
2400
  };
2300
2401
  const HeaderActions = ({ actions: actions2 }) => {
2301
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: actions2.map((action) => {
2302
- if ("options" in action) {
2402
+ const [dialogId, setDialogId] = React__namespace.useState(null);
2403
+ const handleClick = (action) => async (e) => {
2404
+ if (!("options" in action)) {
2405
+ const { onClick = () => false, dialog, id } = action;
2406
+ const muteDialog = await onClick(e);
2407
+ if (dialog && !muteDialog) {
2408
+ e.preventDefault();
2409
+ setDialogId(id);
2410
+ }
2411
+ }
2412
+ };
2413
+ const handleClose = () => {
2414
+ setDialogId(null);
2415
+ };
2416
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
2417
+ if (action.options) {
2303
2418
  return /* @__PURE__ */ jsxRuntime.jsx(
2304
2419
  designSystem.SingleSelect,
2305
2420
  {
@@ -2313,10 +2428,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2313
2428
  action.id
2314
2429
  );
2315
2430
  } else {
2316
- return null;
2431
+ if (action.type === "icon") {
2432
+ return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
2433
+ /* @__PURE__ */ jsxRuntime.jsx(
2434
+ designSystem.IconButton,
2435
+ {
2436
+ disabled: action.disabled,
2437
+ label: action.label,
2438
+ size: "S",
2439
+ onClick: handleClick(action),
2440
+ children: action.icon
2441
+ }
2442
+ ),
2443
+ action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
2444
+ HeaderActionDialog,
2445
+ {
2446
+ ...action.dialog,
2447
+ isOpen: dialogId === action.id,
2448
+ onClose: handleClose
2449
+ }
2450
+ ) : null
2451
+ ] }, action.id);
2452
+ }
2317
2453
  }
2318
2454
  }) });
2319
2455
  };
2456
+ const HeaderActionDialog = ({
2457
+ onClose,
2458
+ onCancel,
2459
+ title,
2460
+ content: Content,
2461
+ isOpen
2462
+ }) => {
2463
+ const handleClose = async () => {
2464
+ if (onCancel) {
2465
+ await onCancel();
2466
+ }
2467
+ onClose();
2468
+ };
2469
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2470
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
2471
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
2472
+ ] }) });
2473
+ };
2320
2474
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2321
2475
  const navigate = reactRouterDom.useNavigate();
2322
2476
  const { formatMessage } = reactIntl.useIntl();
@@ -2452,7 +2606,7 @@ const ActionsPanel = () => {
2452
2606
  return {
2453
2607
  title: formatMessage({
2454
2608
  id: "content-manager.containers.edit.panels.default.title",
2455
- defaultMessage: "Document"
2609
+ defaultMessage: "Entry"
2456
2610
  }),
2457
2611
  content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
2458
2612
  };
@@ -2696,7 +2850,8 @@ const formatEditLayout = (data, {
2696
2850
  layout: convertEditLayoutToFieldLayouts(
2697
2851
  configuration.layouts.edit,
2698
2852
  components[uid].attributes,
2699
- configuration.metadatas
2853
+ configuration.metadatas,
2854
+ { configurations: data.components, schemas: components }
2700
2855
  ),
2701
2856
  settings: {
2702
2857
  ...configuration.settings,
@@ -2822,30 +2977,23 @@ const ConfirmBulkActionDialog = ({
2822
2977
  endAction
2823
2978
  }) => {
2824
2979
  const { formatMessage } = reactIntl.useIntl();
2825
- return /* @__PURE__ */ jsxRuntime.jsxs(
2826
- designSystem.Dialog,
2827
- {
2828
- onClose: onToggleDialog,
2829
- title: formatMessage({
2830
- id: "app.components.ConfirmDialog.title",
2831
- defaultMessage: "Confirmation"
2832
- }),
2833
- isOpen,
2834
- children: [
2835
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2836
- /* @__PURE__ */ jsxRuntime.jsx(
2837
- designSystem.DialogFooter,
2838
- {
2839
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2840
- id: "app.components.Button.cancel",
2841
- defaultMessage: "Cancel"
2842
- }) }),
2843
- endAction
2844
- }
2845
- )
2846
- ]
2847
- }
2848
- );
2980
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2981
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2982
+ id: "app.components.ConfirmDialog.title",
2983
+ defaultMessage: "Confirmation"
2984
+ }) }),
2985
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2986
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2987
+ dialogBody
2988
+ ] }) }),
2989
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2990
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2991
+ id: "app.components.Button.cancel",
2992
+ defaultMessage: "Cancel"
2993
+ }) }) }),
2994
+ endAction
2995
+ ] })
2996
+ ] }) });
2849
2997
  };
2850
2998
  const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2851
2999
  const ConfirmDialogPublishAll = ({
@@ -2860,6 +3008,7 @@ const ConfirmDialogPublishAll = ({
2860
3008
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2861
3009
  const { model, schema } = useDoc();
2862
3010
  const [{ query }] = strapiAdmin.useQueryParams();
3011
+ const enableDraftRelationsCount = false;
2863
3012
  const {
2864
3013
  data: countDraftRelations = 0,
2865
3014
  isLoading,
@@ -2871,7 +3020,7 @@ const ConfirmDialogPublishAll = ({
2871
3020
  locale: query?.plugins?.i18n?.locale
2872
3021
  },
2873
3022
  {
2874
- skip: selectedEntries.length === 0
3023
+ skip: !enableDraftRelationsCount
2875
3024
  }
2876
3025
  );
2877
3026
  React__namespace.useEffect(() => {
@@ -2950,7 +3099,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2950
3099
  )
2951
3100
  );
2952
3101
  } else {
2953
- messages.push(...formatErrorMessages(value, currentKey, formatMessage));
3102
+ messages.push(
3103
+ ...formatErrorMessages(
3104
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3105
+ value,
3106
+ currentKey,
3107
+ formatMessage
3108
+ )
3109
+ );
2954
3110
  }
2955
3111
  } else {
2956
3112
  messages.push(
@@ -3049,7 +3205,7 @@ const SelectedEntriesTableContent = ({
3049
3205
  status: row.status
3050
3206
  }
3051
3207
  ) }),
3052
- /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3208
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
3053
3209
  designSystem.IconButton,
3054
3210
  {
3055
3211
  tag: reactRouterDom.Link,
@@ -3072,9 +3228,10 @@ const SelectedEntriesTableContent = ({
3072
3228
  ),
3073
3229
  target: "_blank",
3074
3230
  marginLeft: "auto",
3075
- children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3231
+ variant: "ghost",
3232
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
3076
3233
  }
3077
- ) })
3234
+ ) }) })
3078
3235
  ] }, row.id)) })
3079
3236
  ] });
3080
3237
  };
@@ -3111,7 +3268,13 @@ const SelectedEntriesModalContent = ({
3111
3268
  );
3112
3269
  const { rows, validationErrors } = React__namespace.useMemo(() => {
3113
3270
  if (data.length > 0 && schema) {
3114
- const validate = createYupSchema(schema.attributes, components);
3271
+ const validate = createYupSchema(
3272
+ schema.attributes,
3273
+ components,
3274
+ // Since this is the "Publish" action, the validation
3275
+ // schema must enforce the rules for published entities
3276
+ { status: "published" }
3277
+ );
3115
3278
  const validationErrors2 = {};
3116
3279
  const rows2 = data.map((entry) => {
3117
3280
  try {
@@ -3187,7 +3350,7 @@ const SelectedEntriesModalContent = ({
3187
3350
  );
3188
3351
  };
3189
3352
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3190
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalBody, { children: [
3353
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3191
3354
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3192
3355
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3193
3356
  SelectedEntriesTableContent,
@@ -3199,27 +3362,24 @@ const SelectedEntriesModalContent = ({
3199
3362
  }
3200
3363
  ) })
3201
3364
  ] }),
3202
- /* @__PURE__ */ jsxRuntime.jsx(
3203
- designSystem.ModalFooter,
3204
- {
3205
- startActions: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3206
- id: "app.components.Button.cancel",
3207
- defaultMessage: "Cancel"
3208
- }) }),
3209
- endActions: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3210
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3211
- /* @__PURE__ */ jsxRuntime.jsx(
3212
- designSystem.Button,
3213
- {
3214
- onClick: toggleDialog,
3215
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3216
- loading: isSubmittingForm,
3217
- children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3218
- }
3219
- )
3220
- ] })
3221
- }
3222
- ),
3365
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3366
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3367
+ id: "app.components.Button.cancel",
3368
+ defaultMessage: "Cancel"
3369
+ }) }),
3370
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3371
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3372
+ /* @__PURE__ */ jsxRuntime.jsx(
3373
+ designSystem.Button,
3374
+ {
3375
+ onClick: toggleDialog,
3376
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3377
+ loading: isSubmittingForm,
3378
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3379
+ }
3380
+ )
3381
+ ] })
3382
+ ] }),
3223
3383
  /* @__PURE__ */ jsxRuntime.jsx(
3224
3384
  ConfirmDialogPublishAll,
3225
3385
  {
@@ -3284,143 +3444,10 @@ const BulkActionsRenderer = () => {
3284
3444
  documents: selectedRows
3285
3445
  },
3286
3446
  descriptions: plugins["content-manager"].apis.getBulkActions(),
3287
- children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(BulkActionAction, { ...action }, action.id))
3447
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3288
3448
  }
3289
3449
  ) });
3290
3450
  };
3291
- const BulkActionAction = (action) => {
3292
- const [dialogId, setDialogId] = React__namespace.useState(null);
3293
- const { toggleNotification } = strapiAdmin.useNotification();
3294
- const handleClick = (action2) => (e) => {
3295
- const { onClick, dialog, id } = action2;
3296
- if (onClick) {
3297
- onClick(e);
3298
- }
3299
- if (dialog) {
3300
- switch (dialog.type) {
3301
- case "notification":
3302
- toggleNotification({
3303
- title: dialog.title,
3304
- message: dialog.content,
3305
- type: dialog.status,
3306
- timeout: dialog.timeout,
3307
- onClose: dialog.onClose
3308
- });
3309
- break;
3310
- case "dialog":
3311
- case "modal": {
3312
- e.preventDefault();
3313
- setDialogId(id);
3314
- }
3315
- }
3316
- }
3317
- };
3318
- const handleClose = () => {
3319
- setDialogId(null);
3320
- if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3321
- action.dialog.onClose();
3322
- }
3323
- };
3324
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3325
- /* @__PURE__ */ jsxRuntime.jsx(
3326
- designSystem.Button,
3327
- {
3328
- disabled: action.disabled,
3329
- startIcon: action.icon,
3330
- variant: action.variant,
3331
- onClick: handleClick(action),
3332
- children: action.label
3333
- }
3334
- ),
3335
- action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
3336
- BulkActionConfirmDialog,
3337
- {
3338
- ...action.dialog,
3339
- variant: action.variant,
3340
- isOpen: dialogId === action.id,
3341
- onClose: handleClose
3342
- }
3343
- ) : null,
3344
- action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
3345
- BulkActionModal,
3346
- {
3347
- ...action.dialog,
3348
- onModalClose: handleClose,
3349
- isOpen: dialogId === action.id
3350
- }
3351
- ) : null
3352
- ] });
3353
- };
3354
- const BulkActionConfirmDialog = ({
3355
- onClose,
3356
- onCancel,
3357
- onConfirm,
3358
- title,
3359
- content,
3360
- confirmButton,
3361
- isOpen,
3362
- variant = "secondary"
3363
- }) => {
3364
- const { formatMessage } = reactIntl.useIntl();
3365
- const handleClose = async () => {
3366
- if (onCancel) {
3367
- await onCancel();
3368
- }
3369
- onClose();
3370
- };
3371
- const handleConfirm = async () => {
3372
- if (onConfirm) {
3373
- await onConfirm();
3374
- }
3375
- onClose();
3376
- };
3377
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
3378
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, {}), children: content }),
3379
- /* @__PURE__ */ jsxRuntime.jsx(
3380
- designSystem.DialogFooter,
3381
- {
3382
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3383
- id: "app.components.Button.cancel",
3384
- defaultMessage: "Cancel"
3385
- }) }),
3386
- endAction: /* @__PURE__ */ jsxRuntime.jsx(
3387
- designSystem.Button,
3388
- {
3389
- onClick: handleConfirm,
3390
- variant: variant === "danger-light" ? variant : "secondary",
3391
- startIcon: variant === "danger-light" ? /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}) : /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
3392
- children: confirmButton ? confirmButton : formatMessage({
3393
- id: "app.components.Button.confirm",
3394
- defaultMessage: "Confirm"
3395
- })
3396
- }
3397
- )
3398
- }
3399
- )
3400
- ] });
3401
- };
3402
- const BulkActionModal = ({
3403
- isOpen,
3404
- title,
3405
- onClose,
3406
- content: Content,
3407
- onModalClose
3408
- }) => {
3409
- const id = React__namespace.useId();
3410
- if (!isOpen) {
3411
- return null;
3412
- }
3413
- const handleClose = () => {
3414
- if (onClose) {
3415
- onClose();
3416
- }
3417
- onModalClose();
3418
- };
3419
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3420
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3421
- /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose })
3422
- ] });
3423
- };
3424
3451
  const DeleteAction = ({ documents, model }) => {
3425
3452
  const { formatMessage } = reactIntl.useIntl();
3426
3453
  const { schema: contentType } = useDoc();
@@ -3453,6 +3480,7 @@ const DeleteAction = ({ documents, model }) => {
3453
3480
  defaultMessage: "Confirmation"
3454
3481
  }),
3455
3482
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3483
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3456
3484
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3457
3485
  id: "popUpWarning.bodyMessage.contentType.delete.all",
3458
3486
  defaultMessage: "Are you sure you want to delete these entries?"
@@ -3502,6 +3530,7 @@ const UnpublishAction = ({ documents, model }) => {
3502
3530
  defaultMessage: "Confirmation"
3503
3531
  }),
3504
3532
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3533
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3505
3534
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3506
3535
  id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3507
3536
  defaultMessage: "Are you sure you want to unpublish these entries?"
@@ -3595,7 +3624,7 @@ const TableActions = ({ document }) => {
3595
3624
  strapiAdmin.DescriptionComponentRenderer,
3596
3625
  {
3597
3626
  props,
3598
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3627
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3599
3628
  children: (actions2) => {
3600
3629
  const tableRowActions = actions2.filter((action) => {
3601
3630
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3706,7 +3735,7 @@ const CloneAction = ({ model, documentId }) => {
3706
3735
  }),
3707
3736
  content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3708
3737
  footer: ({ onClose }) => {
3709
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", children: [
3738
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3710
3739
  /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3711
3740
  id: "cancel",
3712
3741
  defaultMessage: "Cancel"
@@ -3747,8 +3776,7 @@ class ContentManagerPlugin {
3747
3776
  documentActions = [
3748
3777
  ...DEFAULT_ACTIONS,
3749
3778
  ...DEFAULT_TABLE_ROW_ACTIONS,
3750
- ...DEFAULT_HEADER_ACTIONS,
3751
- HistoryAction
3779
+ ...DEFAULT_HEADER_ACTIONS
3752
3780
  ];
3753
3781
  editViewSidePanels = [ActionsPanel];
3754
3782
  headerActions = [];
@@ -3837,6 +3865,52 @@ const getPrintableType = (value) => {
3837
3865
  }
3838
3866
  return nativeType;
3839
3867
  };
3868
+ const HistoryAction = ({ model, document }) => {
3869
+ const { formatMessage } = reactIntl.useIntl();
3870
+ const [{ query }] = strapiAdmin.useQueryParams();
3871
+ const navigate = reactRouterDom.useNavigate();
3872
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3873
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3874
+ return null;
3875
+ }
3876
+ return {
3877
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3878
+ label: formatMessage({
3879
+ id: "content-manager.history.document-action",
3880
+ defaultMessage: "Content History"
3881
+ }),
3882
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3883
+ disabled: (
3884
+ /**
3885
+ * The user is creating a new document.
3886
+ * It hasn't been saved yet, so there's no history to go to
3887
+ */
3888
+ !document || /**
3889
+ * The document has been created but the current dimension has never been saved.
3890
+ * For example, the user is creating a new locale in an existing document,
3891
+ * so there's no history for the document in that locale
3892
+ */
3893
+ !document.id || /**
3894
+ * History is only available for content types created by the user.
3895
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3896
+ * which start with `admin::` or `plugin::`
3897
+ */
3898
+ !model.startsWith("api::")
3899
+ ),
3900
+ position: "header"
3901
+ };
3902
+ };
3903
+ HistoryAction.type = "history";
3904
+ const historyAdmin = {
3905
+ bootstrap(app) {
3906
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3907
+ addDocumentAction((actions2) => {
3908
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3909
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3910
+ return actions2;
3911
+ });
3912
+ }
3913
+ };
3840
3914
  const initialState = {
3841
3915
  collectionTypeLinks: [],
3842
3916
  components: [],
@@ -3887,15 +3961,29 @@ const index = {
3887
3961
  defaultMessage: "Content Manager"
3888
3962
  },
3889
3963
  permissions: [],
3890
- Component: () => Promise.resolve().then(() => require("./layout-jcY4dyUG.js")).then((mod) => ({ default: mod.Layout })),
3891
3964
  position: 1
3892
3965
  });
3966
+ app.router.addRoute({
3967
+ path: "content-manager/*",
3968
+ lazy: async () => {
3969
+ const { Layout } = await Promise.resolve().then(() => require("./layout-CYA7s0qO.js"));
3970
+ return {
3971
+ Component: Layout
3972
+ };
3973
+ },
3974
+ children: routes
3975
+ });
3893
3976
  app.registerPlugin(cm.config);
3894
3977
  },
3978
+ bootstrap(app) {
3979
+ if (typeof historyAdmin.bootstrap === "function") {
3980
+ historyAdmin.bootstrap(app);
3981
+ }
3982
+ },
3895
3983
  async registerTrads({ locales }) {
3896
3984
  const importedTrads = await Promise.all(
3897
3985
  locales.map((locale) => {
3898
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-DZXjRiWA.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3986
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BVzUkPxZ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3899
3987
  return {
3900
3988
  data: prefixPluginTranslations(data, PLUGIN_ID),
3901
3989
  locale
@@ -3913,6 +4001,7 @@ const index = {
3913
4001
  };
3914
4002
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3915
4003
  exports.BulkActionsRenderer = BulkActionsRenderer;
4004
+ exports.CLONE_PATH = CLONE_PATH;
3916
4005
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3917
4006
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3918
4007
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3939,7 +4028,6 @@ exports.getDisplayName = getDisplayName;
3939
4028
  exports.getMainField = getMainField;
3940
4029
  exports.getTranslation = getTranslation;
3941
4030
  exports.index = index;
3942
- exports.routes = routes;
3943
4031
  exports.setInitialData = setInitialData;
3944
4032
  exports.useContentTypeSchema = useContentTypeSchema;
3945
4033
  exports.useDoc = useDoc;
@@ -3953,4 +4041,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3953
4041
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3954
4042
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3955
4043
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3956
- //# sourceMappingURL=index-DcUu-_72.js.map
4044
+ //# sourceMappingURL=index-BhbLFX4l.js.map