@strapi/content-manager 5.0.0-rc.0 → 5.0.0-rc.10

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 (106) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-DVY3LwHo.js → ComponentConfigurationPage-BEJqMzZA.js} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-DVY3LwHo.js.map → ComponentConfigurationPage-BEJqMzZA.js.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-Dy9BQQ2V.mjs → ComponentConfigurationPage-C1B5XNIM.mjs} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-Dy9BQQ2V.mjs.map → ComponentConfigurationPage-C1B5XNIM.mjs.map} +1 -1
  5. package/dist/_chunks/{EditConfigurationPage-DbR8mWH5.mjs → EditConfigurationPage-D2DPoQ3j.mjs} +3 -3
  6. package/dist/_chunks/{EditConfigurationPage-DbR8mWH5.mjs.map → EditConfigurationPage-D2DPoQ3j.mjs.map} +1 -1
  7. package/dist/_chunks/{EditConfigurationPage-b6V7YHfo.js → EditConfigurationPage-DOyPS5Tv.js} +3 -3
  8. package/dist/_chunks/{EditConfigurationPage-b6V7YHfo.js.map → EditConfigurationPage-DOyPS5Tv.js.map} +1 -1
  9. package/dist/_chunks/{EditViewPage-CPrukwtO.mjs → EditViewPage-Ymi21g_V.mjs} +19 -8
  10. package/dist/_chunks/EditViewPage-Ymi21g_V.mjs.map +1 -0
  11. package/dist/_chunks/{EditViewPage-DhttErmY.js → EditViewPage-fuASFJIx.js} +19 -8
  12. package/dist/_chunks/EditViewPage-fuASFJIx.js.map +1 -0
  13. package/dist/_chunks/{Field-DrgIgQPw.mjs → Field-BOo2Rz0Z.mjs} +106 -40
  14. package/dist/_chunks/Field-BOo2Rz0Z.mjs.map +1 -0
  15. package/dist/_chunks/{Field-CBRV4uan.js → Field-Ce4O31Zm.js} +104 -38
  16. package/dist/_chunks/Field-Ce4O31Zm.js.map +1 -0
  17. package/dist/_chunks/{Form-Bk3v7Frl.js → Form-CCGDm2PL.js} +22 -11
  18. package/dist/_chunks/Form-CCGDm2PL.js.map +1 -0
  19. package/dist/_chunks/{Form-Dxk4txLJ.mjs → Form-D2_h3W-h.mjs} +22 -11
  20. package/dist/_chunks/Form-D2_h3W-h.mjs.map +1 -0
  21. package/dist/_chunks/{History-xNH_9UuV.js → History-CARFXr5U.js} +21 -11
  22. package/dist/_chunks/History-CARFXr5U.js.map +1 -0
  23. package/dist/_chunks/{History-DSU-y4Hg.mjs → History-KY23tw1N.mjs} +21 -11
  24. package/dist/_chunks/History-KY23tw1N.mjs.map +1 -0
  25. package/dist/_chunks/{ListConfigurationPage-BWwZ-uMJ.mjs → ListConfigurationPage-BrwfEo-f.mjs} +14 -4
  26. package/dist/_chunks/ListConfigurationPage-BrwfEo-f.mjs.map +1 -0
  27. package/dist/_chunks/{ListConfigurationPage-BCPzXk5W.js → ListConfigurationPage-fZjkRyi9.js} +14 -4
  28. package/dist/_chunks/ListConfigurationPage-fZjkRyi9.js.map +1 -0
  29. package/dist/_chunks/{ListViewPage-ZIvstfvl.js → ListViewPage-CY6a70Y-.js} +9 -4
  30. package/dist/_chunks/ListViewPage-CY6a70Y-.js.map +1 -0
  31. package/dist/_chunks/{ListViewPage-D9UmehuA.mjs → ListViewPage-CjkCjT3z.mjs} +10 -5
  32. package/dist/_chunks/ListViewPage-CjkCjT3z.mjs.map +1 -0
  33. package/dist/_chunks/{NoContentTypePage-CstnyWv2.mjs → NoContentTypePage-C8XPPlCu.mjs} +2 -2
  34. package/dist/_chunks/{NoContentTypePage-CstnyWv2.mjs.map → NoContentTypePage-C8XPPlCu.mjs.map} +1 -1
  35. package/dist/_chunks/{NoContentTypePage-h7FcuMjI.js → NoContentTypePage-DId86YmW.js} +2 -2
  36. package/dist/_chunks/{NoContentTypePage-h7FcuMjI.js.map → NoContentTypePage-DId86YmW.js.map} +1 -1
  37. package/dist/_chunks/{NoPermissionsPage-DofU68cO.js → NoPermissionsPage-CT9LmH-v.js} +2 -2
  38. package/dist/_chunks/{NoPermissionsPage-DofU68cO.js.map → NoPermissionsPage-CT9LmH-v.js.map} +1 -1
  39. package/dist/_chunks/{NoPermissionsPage-aFCCLbsf.mjs → NoPermissionsPage-gwaMeI0N.mjs} +2 -2
  40. package/dist/_chunks/{NoPermissionsPage-aFCCLbsf.mjs.map → NoPermissionsPage-gwaMeI0N.mjs.map} +1 -1
  41. package/dist/_chunks/{Relations-7v66IP7b.mjs → Relations-BHyHGiTJ.mjs} +4 -4
  42. package/dist/_chunks/{Relations-7v66IP7b.mjs.map → Relations-BHyHGiTJ.mjs.map} +1 -1
  43. package/dist/_chunks/{Relations-DAS_DKG5.js → Relations-Zqwo0Moa.js} +4 -4
  44. package/dist/_chunks/{Relations-DAS_DKG5.js.map → Relations-Zqwo0Moa.js.map} +1 -1
  45. package/dist/_chunks/{index-CAlLHIrI.js → index-9nr_f9vB.js} +202 -117
  46. package/dist/_chunks/index-9nr_f9vB.js.map +1 -0
  47. package/dist/_chunks/{index-DIQ7Io-l.mjs → index-CS6TpAQJ.mjs} +221 -136
  48. package/dist/_chunks/index-CS6TpAQJ.mjs.map +1 -0
  49. package/dist/_chunks/{layout-DHe2GdT4.mjs → layout-2aGdWAdb.mjs} +20 -8
  50. package/dist/_chunks/layout-2aGdWAdb.mjs.map +1 -0
  51. package/dist/_chunks/{layout-B1ZS-usI.js → layout-BssHa4-L.js} +19 -7
  52. package/dist/_chunks/layout-BssHa4-L.js.map +1 -0
  53. package/dist/_chunks/{relations-yXHkSG1Z.js → relations-BuxzjpZ_.js} +2 -2
  54. package/dist/_chunks/{relations-yXHkSG1Z.js.map → relations-BuxzjpZ_.js.map} +1 -1
  55. package/dist/_chunks/{relations-BUieBWhT.mjs → relations-DBOO7qaP.mjs} +2 -2
  56. package/dist/_chunks/{relations-BUieBWhT.mjs.map → relations-DBOO7qaP.mjs.map} +1 -1
  57. package/dist/admin/index.js +1 -1
  58. package/dist/admin/index.mjs +4 -4
  59. package/dist/admin/src/history/index.d.ts +3 -0
  60. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  61. package/dist/admin/src/index.d.ts +1 -0
  62. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
  63. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  64. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +10 -22
  65. package/dist/admin/src/services/api.d.ts +1 -1
  66. package/dist/admin/src/services/components.d.ts +2 -2
  67. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  68. package/dist/admin/src/services/documents.d.ts +16 -16
  69. package/dist/admin/src/services/init.d.ts +1 -1
  70. package/dist/admin/src/services/relations.d.ts +2 -2
  71. package/dist/admin/src/services/uid.d.ts +3 -3
  72. package/dist/admin/src/utils/validation.d.ts +4 -1
  73. package/dist/server/index.js +159 -103
  74. package/dist/server/index.js.map +1 -1
  75. package/dist/server/index.mjs +160 -104
  76. package/dist/server/index.mjs.map +1 -1
  77. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  78. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  79. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  80. package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
  81. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
  82. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  83. package/dist/server/src/history/services/utils.d.ts +1 -1
  84. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  85. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  86. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  87. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  88. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  89. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  90. package/package.json +8 -8
  91. package/dist/_chunks/EditViewPage-CPrukwtO.mjs.map +0 -1
  92. package/dist/_chunks/EditViewPage-DhttErmY.js.map +0 -1
  93. package/dist/_chunks/Field-CBRV4uan.js.map +0 -1
  94. package/dist/_chunks/Field-DrgIgQPw.mjs.map +0 -1
  95. package/dist/_chunks/Form-Bk3v7Frl.js.map +0 -1
  96. package/dist/_chunks/Form-Dxk4txLJ.mjs.map +0 -1
  97. package/dist/_chunks/History-DSU-y4Hg.mjs.map +0 -1
  98. package/dist/_chunks/History-xNH_9UuV.js.map +0 -1
  99. package/dist/_chunks/ListConfigurationPage-BCPzXk5W.js.map +0 -1
  100. package/dist/_chunks/ListConfigurationPage-BWwZ-uMJ.mjs.map +0 -1
  101. package/dist/_chunks/ListViewPage-D9UmehuA.mjs.map +0 -1
  102. package/dist/_chunks/ListViewPage-ZIvstfvl.js.map +0 -1
  103. package/dist/_chunks/index-CAlLHIrI.js.map +0 -1
  104. package/dist/_chunks/index-DIQ7Io-l.mjs.map +0 -1
  105. package/dist/_chunks/layout-B1ZS-usI.js.map +0 -1
  106. package/dist/_chunks/layout-DHe2GdT4.mjs.map +0 -1
@@ -1,17 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Menu, Button, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import { useIntl } from "react-intl";
8
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
9
  import { styled } from "styled-components";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
12
  import pipe from "lodash/fp/pipe";
14
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { stringify } from "qs";
15
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
16
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
17
  const v = glob[path];
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
49
49
  const [page, position] = area.split(".");
50
50
  return contentManagerPlugin.getInjectedComponents(page, position);
51
51
  };
52
- const HistoryAction = ({ model, document }) => {
53
- const { formatMessage } = useIntl();
54
- const [{ query }] = useQueryParams();
55
- const navigate = useNavigate();
56
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
57
- if (!window.strapi.features.isEnabled("cms-content-history")) {
58
- return null;
59
- }
60
- return {
61
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
62
- label: formatMessage({
63
- id: "content-manager.history.document-action",
64
- defaultMessage: "Content History"
65
- }),
66
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
67
- disabled: (
68
- /**
69
- * The user is creating a new document.
70
- * It hasn't been saved yet, so there's no history to go to
71
- */
72
- !document || /**
73
- * The document has been created but the current dimension has never been saved.
74
- * For example, the user is creating a new locale in an existing document,
75
- * so there's no history for the document in that locale
76
- */
77
- !document.id || /**
78
- * History is only available for content types created by the user.
79
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
80
- * which start with `admin::` or `plugin::`
81
- */
82
- !model.startsWith("api::")
83
- ),
84
- position: "header"
85
- };
86
- };
87
- HistoryAction.type = "history";
88
52
  const ID = "id";
89
53
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
90
54
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -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.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
604
- return schema.min(1, translatedErrors.required);
605
- }
606
- if (attribute.required && attribute.type !== "relation") {
607
- return schema.required(translatedErrors.required);
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,11 +646,11 @@ 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);
641
652
  if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
642
- if (!attribute.required && "test" in schema && min) {
653
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
643
654
  return schema.test(
644
655
  "custom-min",
645
656
  {
@@ -875,6 +886,7 @@ const useDocumentActions = () => {
875
886
  const { formatMessage } = useIntl();
876
887
  const { trackUsage } = useTracking();
877
888
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
+ const navigate = useNavigate();
878
890
  const [deleteDocument] = useDeleteDocumentMutation();
879
891
  const _delete = React.useCallback(
880
892
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -1210,7 +1222,6 @@ const useDocumentActions = () => {
1210
1222
  sourceId
1211
1223
  });
1212
1224
  if ("error" in res) {
1213
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1214
1225
  return { error: res.error };
1215
1226
  }
1216
1227
  toggleNotification({
@@ -1229,7 +1240,7 @@ const useDocumentActions = () => {
1229
1240
  throw err;
1230
1241
  }
1231
1242
  },
1232
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1243
+ [autoCloneDocument, formatMessage, toggleNotification]
1233
1244
  );
1234
1245
  const [cloneDocument] = useCloneDocumentMutation();
1235
1246
  const clone = React.useCallback(
@@ -1255,6 +1266,7 @@ const useDocumentActions = () => {
1255
1266
  defaultMessage: "Cloned document"
1256
1267
  })
1257
1268
  });
1269
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1258
1270
  return res.data;
1259
1271
  } catch (err) {
1260
1272
  toggleNotification({
@@ -1265,7 +1277,7 @@ const useDocumentActions = () => {
1265
1277
  throw err;
1266
1278
  }
1267
1279
  },
1268
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1280
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1269
1281
  );
1270
1282
  const [getDoc] = useLazyGetDocumentQuery();
1271
1283
  const getDocument = React.useCallback(
@@ -1291,7 +1303,7 @@ const useDocumentActions = () => {
1291
1303
  };
1292
1304
  };
1293
1305
  const ProtectedHistoryPage = lazy(
1294
- () => import("./History-DSU-y4Hg.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1306
+ () => import("./History-KY23tw1N.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1295
1307
  );
1296
1308
  const routes$1 = [
1297
1309
  {
@@ -1304,31 +1316,31 @@ const routes$1 = [
1304
1316
  }
1305
1317
  ];
1306
1318
  const ProtectedEditViewPage = lazy(
1307
- () => import("./EditViewPage-CPrukwtO.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1319
+ () => import("./EditViewPage-Ymi21g_V.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1308
1320
  );
1309
1321
  const ProtectedListViewPage = lazy(
1310
- () => import("./ListViewPage-D9UmehuA.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1322
+ () => import("./ListViewPage-CjkCjT3z.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1311
1323
  );
1312
1324
  const ProtectedListConfiguration = lazy(
1313
- () => import("./ListConfigurationPage-BWwZ-uMJ.mjs").then((mod) => ({
1325
+ () => import("./ListConfigurationPage-BrwfEo-f.mjs").then((mod) => ({
1314
1326
  default: mod.ProtectedListConfiguration
1315
1327
  }))
1316
1328
  );
1317
1329
  const ProtectedEditConfigurationPage = lazy(
1318
- () => import("./EditConfigurationPage-DbR8mWH5.mjs").then((mod) => ({
1330
+ () => import("./EditConfigurationPage-D2DPoQ3j.mjs").then((mod) => ({
1319
1331
  default: mod.ProtectedEditConfigurationPage
1320
1332
  }))
1321
1333
  );
1322
1334
  const ProtectedComponentConfigurationPage = lazy(
1323
- () => import("./ComponentConfigurationPage-Dy9BQQ2V.mjs").then((mod) => ({
1335
+ () => import("./ComponentConfigurationPage-C1B5XNIM.mjs").then((mod) => ({
1324
1336
  default: mod.ProtectedComponentConfigurationPage
1325
1337
  }))
1326
1338
  );
1327
1339
  const NoPermissions = lazy(
1328
- () => import("./NoPermissionsPage-aFCCLbsf.mjs").then((mod) => ({ default: mod.NoPermissions }))
1340
+ () => import("./NoPermissionsPage-gwaMeI0N.mjs").then((mod) => ({ default: mod.NoPermissions }))
1329
1341
  );
1330
1342
  const NoContentType = lazy(
1331
- () => import("./NoContentTypePage-CstnyWv2.mjs").then((mod) => ({ default: mod.NoContentType }))
1343
+ () => import("./NoContentTypePage-C8XPPlCu.mjs").then((mod) => ({ default: mod.NoContentType }))
1332
1344
  );
1333
1345
  const CollectionTypePages = () => {
1334
1346
  const { collectionType } = useParams();
@@ -1442,12 +1454,14 @@ const DocumentActionButton = (action) => {
1442
1454
  /* @__PURE__ */ jsx(
1443
1455
  Button,
1444
1456
  {
1445
- flex: 1,
1457
+ flex: "auto",
1446
1458
  startIcon: action.icon,
1447
1459
  disabled: action.disabled,
1448
1460
  onClick: handleClick(action),
1449
1461
  justifyContent: "center",
1450
1462
  variant: action.variant || "default",
1463
+ paddingTop: "7px",
1464
+ paddingBottom: "7px",
1451
1465
  children: action.label
1452
1466
  }
1453
1467
  ),
@@ -1507,14 +1521,14 @@ const DocumentActionsMenu = ({
1507
1521
  };
1508
1522
  return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1509
1523
  /* @__PURE__ */ jsxs(
1510
- Menu.Trigger,
1524
+ StyledMoreButton,
1511
1525
  {
1512
1526
  disabled: isDisabled,
1513
1527
  size: "S",
1514
1528
  endIcon: null,
1515
- paddingTop: "7px",
1516
- paddingLeft: "9px",
1517
- paddingRight: "9px",
1529
+ paddingTop: "4px",
1530
+ paddingLeft: "7px",
1531
+ paddingRight: "7px",
1518
1532
  variant,
1519
1533
  children: [
1520
1534
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
@@ -1534,10 +1548,25 @@ const DocumentActionsMenu = ({
1534
1548
  onSelect: handleClick(action),
1535
1549
  display: "block",
1536
1550
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1537
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1538
- /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1539
- action.label
1540
- ] }),
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
+ ),
1541
1570
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1542
1571
  Flex,
1543
1572
  {
@@ -1608,6 +1637,11 @@ const convertActionVariantToIconColor = (variant = "secondary") => {
1608
1637
  return "primary600";
1609
1638
  }
1610
1639
  };
1640
+ const StyledMoreButton = styled(Menu.Trigger)`
1641
+ & > span {
1642
+ display: flex;
1643
+ }
1644
+ `;
1611
1645
  const DocumentActionConfirmDialog = ({
1612
1646
  onClose,
1613
1647
  onCancel,
@@ -1661,8 +1695,8 @@ const DocumentActionModal = ({
1661
1695
  };
1662
1696
  return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1663
1697
  /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1664
- /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1665
- /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1698
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1699
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1666
1700
  ] }) });
1667
1701
  };
1668
1702
  const PublishAction$1 = ({
@@ -1679,10 +1713,7 @@ const PublishAction$1 = ({
1679
1713
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1680
1714
  const isCloning = useMatch(CLONE_PATH) !== null;
1681
1715
  const { formatMessage } = useIntl();
1682
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1683
- "PublishAction",
1684
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1685
- );
1716
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1686
1717
  const { publish } = useDocumentActions();
1687
1718
  const [
1688
1719
  countDraftRelations,
@@ -1802,10 +1833,8 @@ const PublishAction$1 = ({
1802
1833
  * - the document is already published & not modified
1803
1834
  * - the document is being created & not modified
1804
1835
  * - the user doesn't have the permission to publish
1805
- * - the user doesn't have the permission to create a new document
1806
- * - the user doesn't have the permission to update the document
1807
1836
  */
1808
- disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1837
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1809
1838
  label: formatMessage({
1810
1839
  id: "app.utils.publish",
1811
1840
  defaultMessage: "Publish"
@@ -1852,10 +1881,6 @@ const UpdateAction = ({
1852
1881
  const cloneMatch = useMatch(CLONE_PATH);
1853
1882
  const isCloning = cloneMatch !== null;
1854
1883
  const { formatMessage } = useIntl();
1855
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1856
- canCreate: canCreate2,
1857
- canUpdate: canUpdate2
1858
- }));
1859
1884
  const { create, update, clone } = useDocumentActions();
1860
1885
  const [{ query, rawQuery }] = useQueryParams();
1861
1886
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1872,10 +1897,8 @@ const UpdateAction = ({
1872
1897
  * - the form is submitting
1873
1898
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1874
1899
  * - the active tab is the published tab
1875
- * - the user doesn't have the permission to create a new document
1876
- * - the user doesn't have the permission to update the document
1877
1900
  */
1878
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1901
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1879
1902
  label: formatMessage({
1880
1903
  id: "content-manager.containers.Edit.save",
1881
1904
  defaultMessage: "Save"
@@ -1883,16 +1906,18 @@ const UpdateAction = ({
1883
1906
  onClick: async () => {
1884
1907
  setSubmitting(true);
1885
1908
  try {
1886
- const { errors } = await validate();
1887
- if (errors) {
1888
- toggleNotification({
1889
- type: "danger",
1890
- message: formatMessage({
1891
- id: "content-manager.validation.error",
1892
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1893
- })
1894
- });
1895
- return;
1909
+ if (activeTab !== "draft") {
1910
+ const { errors } = await validate();
1911
+ if (errors) {
1912
+ toggleNotification({
1913
+ type: "danger",
1914
+ message: formatMessage({
1915
+ id: "content-manager.validation.error",
1916
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1917
+ })
1918
+ });
1919
+ return;
1920
+ }
1896
1921
  }
1897
1922
  if (isCloning) {
1898
1923
  const res = await clone(
@@ -1904,10 +1929,13 @@ const UpdateAction = ({
1904
1929
  document
1905
1930
  );
1906
1931
  if ("data" in res) {
1907
- navigate({
1908
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1909
- search: rawQuery
1910
- });
1932
+ navigate(
1933
+ {
1934
+ pathname: `../${res.data.documentId}`,
1935
+ search: rawQuery
1936
+ },
1937
+ { relative: "path" }
1938
+ );
1911
1939
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1912
1940
  setErrors(formatValidationErrors(res.error));
1913
1941
  }
@@ -1937,10 +1965,10 @@ const UpdateAction = ({
1937
1965
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1938
1966
  navigate(
1939
1967
  {
1940
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1968
+ pathname: `../${res.data.documentId}`,
1941
1969
  search: rawQuery
1942
1970
  },
1943
- { replace: true }
1971
+ { replace: true, relative: "path" }
1944
1972
  );
1945
1973
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1946
1974
  setErrors(formatValidationErrors(res.error));
@@ -2884,7 +2912,7 @@ const ConfirmBulkActionDialog = ({
2884
2912
  endAction
2885
2913
  }) => {
2886
2914
  const { formatMessage } = useIntl();
2887
- return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2915
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2888
2916
  /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2889
2917
  id: "app.components.ConfirmDialog.title",
2890
2918
  defaultMessage: "Confirmation"
@@ -3173,7 +3201,13 @@ const SelectedEntriesModalContent = ({
3173
3201
  );
3174
3202
  const { rows, validationErrors } = React.useMemo(() => {
3175
3203
  if (data.length > 0 && schema) {
3176
- const validate = createYupSchema(schema.attributes, components);
3204
+ const validate = createYupSchema(
3205
+ schema.attributes,
3206
+ components,
3207
+ // Since this is the "Publish" action, the validation
3208
+ // schema must enforce the rules for published entities
3209
+ { status: "published" }
3210
+ );
3177
3211
  const validationErrors2 = {};
3178
3212
  const rows2 = data.map((entry) => {
3179
3213
  try {
@@ -3523,7 +3557,7 @@ const TableActions = ({ document }) => {
3523
3557
  DescriptionComponentRenderer,
3524
3558
  {
3525
3559
  props,
3526
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3560
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3527
3561
  children: (actions2) => {
3528
3562
  const tableRowActions = actions2.filter((action) => {
3529
3563
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3634,7 +3668,7 @@ const CloneAction = ({ model, documentId }) => {
3634
3668
  }),
3635
3669
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3636
3670
  footer: ({ onClose }) => {
3637
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3671
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3638
3672
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3639
3673
  id: "cancel",
3640
3674
  defaultMessage: "Cancel"
@@ -3675,8 +3709,7 @@ class ContentManagerPlugin {
3675
3709
  documentActions = [
3676
3710
  ...DEFAULT_ACTIONS,
3677
3711
  ...DEFAULT_TABLE_ROW_ACTIONS,
3678
- ...DEFAULT_HEADER_ACTIONS,
3679
- HistoryAction
3712
+ ...DEFAULT_HEADER_ACTIONS
3680
3713
  ];
3681
3714
  editViewSidePanels = [ActionsPanel];
3682
3715
  headerActions = [];
@@ -3765,6 +3798,52 @@ const getPrintableType = (value) => {
3765
3798
  }
3766
3799
  return nativeType;
3767
3800
  };
3801
+ const HistoryAction = ({ model, document }) => {
3802
+ const { formatMessage } = useIntl();
3803
+ const [{ query }] = useQueryParams();
3804
+ const navigate = useNavigate();
3805
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3806
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3807
+ return null;
3808
+ }
3809
+ return {
3810
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3811
+ label: formatMessage({
3812
+ id: "content-manager.history.document-action",
3813
+ defaultMessage: "Content History"
3814
+ }),
3815
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3816
+ disabled: (
3817
+ /**
3818
+ * The user is creating a new document.
3819
+ * It hasn't been saved yet, so there's no history to go to
3820
+ */
3821
+ !document || /**
3822
+ * The document has been created but the current dimension has never been saved.
3823
+ * For example, the user is creating a new locale in an existing document,
3824
+ * so there's no history for the document in that locale
3825
+ */
3826
+ !document.id || /**
3827
+ * History is only available for content types created by the user.
3828
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3829
+ * which start with `admin::` or `plugin::`
3830
+ */
3831
+ !model.startsWith("api::")
3832
+ ),
3833
+ position: "header"
3834
+ };
3835
+ };
3836
+ HistoryAction.type = "history";
3837
+ const historyAdmin = {
3838
+ bootstrap(app) {
3839
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3840
+ addDocumentAction((actions2) => {
3841
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3842
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3843
+ return actions2;
3844
+ });
3845
+ }
3846
+ };
3768
3847
  const initialState = {
3769
3848
  collectionTypeLinks: [],
3770
3849
  components: [],
@@ -3820,7 +3899,7 @@ const index = {
3820
3899
  app.router.addRoute({
3821
3900
  path: "content-manager/*",
3822
3901
  lazy: async () => {
3823
- const { Layout } = await import("./layout-DHe2GdT4.mjs");
3902
+ const { Layout } = await import("./layout-2aGdWAdb.mjs");
3824
3903
  return {
3825
3904
  Component: Layout
3826
3905
  };
@@ -3829,6 +3908,11 @@ const index = {
3829
3908
  });
3830
3909
  app.registerPlugin(cm.config);
3831
3910
  },
3911
+ bootstrap(app) {
3912
+ if (typeof historyAdmin.bootstrap === "function") {
3913
+ historyAdmin.bootstrap(app);
3914
+ }
3915
+ },
3832
3916
  async registerTrads({ locales }) {
3833
3917
  const importedTrads = await Promise.all(
3834
3918
  locales.map((locale) => {
@@ -3853,13 +3937,14 @@ export {
3853
3937
  BulkActionsRenderer as B,
3854
3938
  COLLECTION_TYPES as C,
3855
3939
  DocumentStatus as D,
3856
- DEFAULT_SETTINGS as E,
3857
- convertEditLayoutToFieldLayouts as F,
3858
- useDocument as G,
3940
+ extractContentTypeComponents as E,
3941
+ DEFAULT_SETTINGS as F,
3942
+ convertEditLayoutToFieldLayouts as G,
3859
3943
  HOOKS as H,
3860
3944
  InjectionZone as I,
3861
- index as J,
3862
- useDocumentActions as K,
3945
+ useDocument as J,
3946
+ index as K,
3947
+ useDocumentActions as L,
3863
3948
  Panels as P,
3864
3949
  RelativeTime as R,
3865
3950
  SINGLE_TYPES as S,
@@ -3877,18 +3962,18 @@ export {
3877
3962
  PERMISSIONS as k,
3878
3963
  DocumentRBAC as l,
3879
3964
  DOCUMENT_META_FIELDS as m,
3880
- useDocLayout as n,
3881
- useGetContentTypeConfigurationQuery as o,
3882
- CREATOR_FIELDS as p,
3883
- getMainField as q,
3884
- getDisplayName as r,
3965
+ CLONE_PATH as n,
3966
+ useDocLayout as o,
3967
+ useGetContentTypeConfigurationQuery as p,
3968
+ CREATOR_FIELDS as q,
3969
+ getMainField as r,
3885
3970
  setInitialData as s,
3886
- checkIfAttributeIsDisplayable as t,
3971
+ getDisplayName as t,
3887
3972
  useContentTypeSchema as u,
3888
- useGetAllDocumentsQuery as v,
3889
- convertListLayoutToFieldLayouts as w,
3890
- capitalise as x,
3891
- useUpdateContentTypeConfigurationMutation as y,
3892
- extractContentTypeComponents as z
3973
+ checkIfAttributeIsDisplayable as v,
3974
+ useGetAllDocumentsQuery as w,
3975
+ convertListLayoutToFieldLayouts as x,
3976
+ capitalise as y,
3977
+ useUpdateContentTypeConfigurationMutation as z
3893
3978
  };
3894
- //# sourceMappingURL=index-DIQ7Io-l.mjs.map
3979
+ //# sourceMappingURL=index-CS6TpAQJ.mjs.map