@strapi/content-manager 0.0.0-next.bec3f8cddf61be32ee5516609a1d4d6032933972 → 0.0.0-next.bffd3c1819cd08304e7d270e88b4973e9fcbc183

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 (168) hide show
  1. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
  2. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-BUOQFZ08.mjs → ComponentConfigurationPage-9_4yUE9L.mjs} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-BUOQFZ08.mjs.map → ComponentConfigurationPage-9_4yUE9L.mjs.map} +1 -1
  5. package/dist/_chunks/{ComponentConfigurationPage-WtZ2yaRP.js → ComponentConfigurationPage-DBSh-kET.js} +4 -5
  6. package/dist/_chunks/{ComponentConfigurationPage-WtZ2yaRP.js.map → ComponentConfigurationPage-DBSh-kET.js.map} +1 -1
  7. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
  8. package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
  9. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
  10. package/dist/_chunks/{EditConfigurationPage-BVrCP5lF.js → EditConfigurationPage-Bl_U2JgH.js} +4 -5
  11. package/dist/_chunks/{EditConfigurationPage-BVrCP5lF.js.map → EditConfigurationPage-Bl_U2JgH.js.map} +1 -1
  12. package/dist/_chunks/{EditConfigurationPage-D7HkxcAN.mjs → EditConfigurationPage-COe6hjPC.mjs} +3 -3
  13. package/dist/_chunks/{EditConfigurationPage-D7HkxcAN.mjs.map → EditConfigurationPage-COe6hjPC.mjs.map} +1 -1
  14. package/dist/_chunks/{EditViewPage-BKQ83NAk.js → EditViewPage-D4yFJET6.js} +23 -57
  15. package/dist/_chunks/EditViewPage-D4yFJET6.js.map +1 -0
  16. package/dist/_chunks/{EditViewPage-zKmMBER4.mjs → EditViewPage-DrmVmYN0.mjs} +21 -54
  17. package/dist/_chunks/EditViewPage-DrmVmYN0.mjs.map +1 -0
  18. package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
  19. package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
  20. package/dist/_chunks/{Form-CkbrtNZd.js → Form-C4rSaGsz.js} +5 -6
  21. package/dist/_chunks/{Form-CkbrtNZd.js.map → Form-C4rSaGsz.js.map} +1 -1
  22. package/dist/_chunks/{Form-B-E8l73g.mjs → Form-DamaxNpG.mjs} +3 -3
  23. package/dist/_chunks/{Form-B-E8l73g.mjs.map → Form-DamaxNpG.mjs.map} +1 -1
  24. package/dist/_chunks/{History-C72HQ0-i.mjs → History-D1PreDSY.mjs} +37 -67
  25. package/dist/_chunks/History-D1PreDSY.mjs.map +1 -0
  26. package/dist/_chunks/{History-B2Dg9q7H.js → History-DTm8UCCQ.js} +48 -79
  27. package/dist/_chunks/History-DTm8UCCQ.js.map +1 -0
  28. package/dist/_chunks/{Field-BhN0lyyZ.js → Input-B7sapvBG.js} +1293 -1271
  29. package/dist/_chunks/Input-B7sapvBG.js.map +1 -0
  30. package/dist/_chunks/{Field-BbrX_tUG.mjs → Input-CZ1YvjHR.mjs} +1332 -1310
  31. package/dist/_chunks/Input-CZ1YvjHR.mjs.map +1 -0
  32. package/dist/_chunks/{ListConfigurationPage-BalSo5dp.mjs → ListConfigurationPage-Bbi32isk.mjs} +6 -5
  33. package/dist/_chunks/ListConfigurationPage-Bbi32isk.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-BQCc3BnJ.js → ListConfigurationPage-ysFMjKI3.js} +6 -6
  35. package/dist/_chunks/ListConfigurationPage-ysFMjKI3.js.map +1 -0
  36. package/dist/_chunks/{ListViewPage-Dfue5wQ2.mjs → ListViewPage-Bud_jBDQ.mjs} +68 -53
  37. package/dist/_chunks/ListViewPage-Bud_jBDQ.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-Cu5dZKZe.js → ListViewPage-DTuuxU3n.js} +74 -60
  39. package/dist/_chunks/ListViewPage-DTuuxU3n.js.map +1 -0
  40. package/dist/_chunks/{NoContentTypePage-MGzn4JPu.js → NoContentTypePage-CL7VVeYs.js} +2 -2
  41. package/dist/_chunks/{NoContentTypePage-MGzn4JPu.js.map → NoContentTypePage-CL7VVeYs.js.map} +1 -1
  42. package/dist/_chunks/{NoContentTypePage-BLC8M9U0.mjs → NoContentTypePage-DVhkugsf.mjs} +2 -2
  43. package/dist/_chunks/{NoContentTypePage-BLC8M9U0.mjs.map → NoContentTypePage-DVhkugsf.mjs.map} +1 -1
  44. package/dist/_chunks/{NoPermissionsPage-BpAoEQy_.mjs → NoPermissionsPage-CMdM-dCo.mjs} +2 -2
  45. package/dist/_chunks/{NoPermissionsPage-BpAoEQy_.mjs.map → NoPermissionsPage-CMdM-dCo.mjs.map} +1 -1
  46. package/dist/_chunks/{NoPermissionsPage-DJPwEpOD.js → NoPermissionsPage-v7I599vC.js} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-DJPwEpOD.js.map → NoPermissionsPage-v7I599vC.js.map} +1 -1
  48. package/dist/_chunks/Preview-BNuU0SuQ.mjs +287 -0
  49. package/dist/_chunks/Preview-BNuU0SuQ.mjs.map +1 -0
  50. package/dist/_chunks/Preview-Cxq-uI6D.js +305 -0
  51. package/dist/_chunks/Preview-Cxq-uI6D.js.map +1 -0
  52. package/dist/_chunks/{Relations-BULOkyWN.mjs → Relations-C2Ahkrdg.mjs} +6 -8
  53. package/dist/_chunks/{Relations-BULOkyWN.mjs.map → Relations-C2Ahkrdg.mjs.map} +1 -1
  54. package/dist/_chunks/{Relations-DTiqnyGx.js → Relations-CWS79QQn.js} +7 -10
  55. package/dist/_chunks/{Relations-DTiqnyGx.js.map → Relations-CWS79QQn.js.map} +1 -1
  56. package/dist/_chunks/{en-C-J4DGEe.js → en-BR48D_RH.js} +20 -3
  57. package/dist/_chunks/{en-C-J4DGEe.js.map → en-BR48D_RH.js.map} +1 -1
  58. package/dist/_chunks/{en-DPfZ6tPQ.mjs → en-D65uIF6Y.mjs} +20 -3
  59. package/dist/_chunks/{en-DPfZ6tPQ.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
  60. package/dist/_chunks/{fr-B2Kyv8Z9.js → fr-C43IbhA_.js} +4 -1
  61. package/dist/_chunks/{fr-B2Kyv8Z9.js.map → fr-C43IbhA_.js.map} +1 -1
  62. package/dist/_chunks/{fr--pg5jUbt.mjs → fr-DBseuRuB.mjs} +4 -1
  63. package/dist/_chunks/{fr--pg5jUbt.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
  64. package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
  65. package/dist/_chunks/{index-76eawJUd.js → index-DQsvBb_N.js} +568 -243
  66. package/dist/_chunks/index-DQsvBb_N.js.map +1 -0
  67. package/dist/_chunks/{index-DW7xp_LG.mjs → index-ZKrsjv-2.mjs} +585 -259
  68. package/dist/_chunks/index-ZKrsjv-2.mjs.map +1 -0
  69. package/dist/_chunks/{layout-CVz8WiDC.js → layout-Cl0NhlQB.js} +5 -6
  70. package/dist/_chunks/{layout-CVz8WiDC.js.map → layout-Cl0NhlQB.js.map} +1 -1
  71. package/dist/_chunks/{layout-DNfLIjbP.mjs → layout-fQk1rMk9.mjs} +4 -4
  72. package/dist/_chunks/{layout-DNfLIjbP.mjs.map → layout-fQk1rMk9.mjs.map} +1 -1
  73. package/dist/_chunks/objects-BcXOv6_9.js.map +1 -1
  74. package/dist/_chunks/objects-D6yBsdmx.mjs.map +1 -1
  75. package/dist/_chunks/{relations-B6K4WRjW.js → relations-BRfBxVbX.js} +6 -3
  76. package/dist/_chunks/relations-BRfBxVbX.js.map +1 -0
  77. package/dist/_chunks/{relations-ByHSIjSe.mjs → relations-BakOFl_1.mjs} +6 -3
  78. package/dist/_chunks/relations-BakOFl_1.mjs.map +1 -0
  79. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
  80. package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
  81. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
  82. package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
  83. package/dist/_chunks/{useDebounce-DmuSJIF3.mjs → usePrev-CZGy2Vjf.mjs} +11 -11
  84. package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
  85. package/dist/_chunks/{useDebounce-CtcjDB3L.js → usePrev-D5J_2fEu.js} +8 -8
  86. package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
  87. package/dist/admin/index.js +2 -1
  88. package/dist/admin/index.js.map +1 -1
  89. package/dist/admin/index.mjs +6 -5
  90. package/dist/admin/src/content-manager.d.ts +3 -2
  91. package/dist/admin/src/exports.d.ts +1 -0
  92. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  93. package/dist/admin/src/hooks/useDocument.d.ts +19 -2
  94. package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
  95. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -1
  96. package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
  97. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
  98. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
  99. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
  100. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
  101. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
  102. package/dist/admin/src/pages/EditView/components/FormLayout.d.ts +27 -0
  103. package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
  104. package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
  105. package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
  106. package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
  107. package/dist/admin/src/preview/routes.d.ts +3 -0
  108. package/dist/admin/src/preview/services/preview.d.ts +1 -1
  109. package/dist/admin/src/router.d.ts +1 -1
  110. package/dist/admin/src/services/api.d.ts +1 -1
  111. package/dist/admin/src/services/components.d.ts +2 -2
  112. package/dist/admin/src/services/contentTypes.d.ts +3 -3
  113. package/dist/admin/src/services/documents.d.ts +16 -19
  114. package/dist/admin/src/services/init.d.ts +1 -1
  115. package/dist/admin/src/services/relations.d.ts +2 -2
  116. package/dist/admin/src/services/uid.d.ts +3 -3
  117. package/dist/server/index.js +230 -187
  118. package/dist/server/index.js.map +1 -1
  119. package/dist/server/index.mjs +231 -187
  120. package/dist/server/index.mjs.map +1 -1
  121. package/dist/server/src/controllers/utils/metadata.d.ts +1 -0
  122. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
  123. package/dist/server/src/history/controllers/history-version.d.ts +1 -1
  124. package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
  125. package/dist/server/src/history/services/history.d.ts +3 -3
  126. package/dist/server/src/history/services/history.d.ts.map +1 -1
  127. package/dist/server/src/history/services/utils.d.ts +6 -10
  128. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  129. package/dist/server/src/index.d.ts +3 -2
  130. package/dist/server/src/index.d.ts.map +1 -1
  131. package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -1
  132. package/dist/server/src/preview/index.d.ts.map +1 -1
  133. package/dist/server/src/preview/services/index.d.ts +1 -0
  134. package/dist/server/src/preview/services/index.d.ts.map +1 -1
  135. package/dist/server/src/preview/services/preview-config.d.ts +2 -0
  136. package/dist/server/src/preview/services/preview-config.d.ts.map +1 -1
  137. package/dist/server/src/preview/utils.d.ts +1 -0
  138. package/dist/server/src/preview/utils.d.ts.map +1 -1
  139. package/dist/server/src/register.d.ts.map +1 -1
  140. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  141. package/dist/server/src/services/document-metadata.d.ts +4 -2
  142. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  143. package/dist/server/src/services/index.d.ts +3 -2
  144. package/dist/server/src/services/index.d.ts.map +1 -1
  145. package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
  146. package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
  147. package/dist/server/src/services/utils/populate.d.ts +2 -2
  148. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  149. package/package.json +12 -11
  150. package/dist/_chunks/EditViewPage-BKQ83NAk.js.map +0 -1
  151. package/dist/_chunks/EditViewPage-zKmMBER4.mjs.map +0 -1
  152. package/dist/_chunks/Field-BbrX_tUG.mjs.map +0 -1
  153. package/dist/_chunks/Field-BhN0lyyZ.js.map +0 -1
  154. package/dist/_chunks/History-B2Dg9q7H.js.map +0 -1
  155. package/dist/_chunks/History-C72HQ0-i.mjs.map +0 -1
  156. package/dist/_chunks/ListConfigurationPage-BQCc3BnJ.js.map +0 -1
  157. package/dist/_chunks/ListConfigurationPage-BalSo5dp.mjs.map +0 -1
  158. package/dist/_chunks/ListViewPage-Cu5dZKZe.js.map +0 -1
  159. package/dist/_chunks/ListViewPage-Dfue5wQ2.mjs.map +0 -1
  160. package/dist/_chunks/index-76eawJUd.js.map +0 -1
  161. package/dist/_chunks/index-DW7xp_LG.mjs.map +0 -1
  162. package/dist/_chunks/relations-B6K4WRjW.js.map +0 -1
  163. package/dist/_chunks/relations-ByHSIjSe.mjs.map +0 -1
  164. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +0 -1
  165. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +0 -1
  166. package/dist/admin/src/preview/constants.d.ts +0 -1
  167. package/dist/server/src/preview/constants.d.ts +0 -2
  168. package/dist/server/src/preview/constants.d.ts.map +0 -1
@@ -1,26 +1,34 @@
1
- import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
1
+ import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, CrossCircle, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
3
  import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import * as React from "react";
5
5
  import { lazy } from "react";
6
- import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
6
+ import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, RawTable, Loader, Tbody, Tr, Td, Tooltip, LinkButton } from "@strapi/design-system";
7
7
  import mapValues from "lodash/fp/mapValues";
8
8
  import { useIntl } from "react-intl";
9
9
  import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
10
+ import { styled } from "styled-components";
10
11
  import * as yup from "yup";
11
12
  import { ValidationError } from "yup";
13
+ import { generateNKeysBetween } from "fractional-indexing";
12
14
  import pipe from "lodash/fp/pipe";
13
- import { intervalToDuration, isPast } from "date-fns";
14
- import { styled } from "styled-components";
15
15
  import { stringify } from "qs";
16
+ import { intervalToDuration, isPast } from "date-fns";
16
17
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
17
- const __variableDynamicImportRuntimeHelper = (glob, path) => {
18
+ const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
18
19
  const v = glob[path];
19
20
  if (v) {
20
21
  return typeof v === "function" ? v() : Promise.resolve(v);
21
22
  }
22
23
  return new Promise((_, reject) => {
23
- (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(reject.bind(null, new Error("Unknown variable dynamic import: " + path)));
24
+ (typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
25
+ reject.bind(
26
+ null,
27
+ new Error(
28
+ "Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
29
+ )
30
+ )
31
+ );
24
32
  });
25
33
  };
26
34
  const PLUGIN_ID = "content-manager";
@@ -159,6 +167,113 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
159
167
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
160
168
  );
161
169
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
170
+ const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
171
+ const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
172
+ const traverse = (datum, attributes) => {
173
+ return Object.entries(datum).reduce((acc, [key, value]) => {
174
+ const attribute = attributes[key];
175
+ if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
176
+ acc[key] = value;
177
+ return acc;
178
+ }
179
+ if (attribute.type === "component") {
180
+ if (attribute.repeatable) {
181
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
182
+ acc[key] = componentValue.map(
183
+ (componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
184
+ );
185
+ } else {
186
+ const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
187
+ acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
188
+ }
189
+ } else if (attribute.type === "dynamiczone") {
190
+ const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
191
+ acc[key] = dynamicZoneValue.map(
192
+ (componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
193
+ );
194
+ } else if (predicate(attribute, value)) {
195
+ acc[key] = transform(value, attribute);
196
+ } else {
197
+ acc[key] = value;
198
+ }
199
+ return acc;
200
+ }, {});
201
+ };
202
+ return traverse(data, schema.attributes);
203
+ };
204
+ const removeProhibitedFields = (prohibitedFields) => traverseData(
205
+ (attribute) => prohibitedFields.includes(attribute.type),
206
+ () => ""
207
+ );
208
+ const prepareRelations = traverseData(
209
+ (attribute) => attribute.type === "relation",
210
+ () => ({
211
+ connect: [],
212
+ disconnect: []
213
+ })
214
+ );
215
+ const prepareTempKeys = traverseData(
216
+ (attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
217
+ (data) => {
218
+ if (Array.isArray(data) && data.length > 0) {
219
+ const keys = generateNKeysBetween(void 0, void 0, data.length);
220
+ return data.map((datum, index2) => ({
221
+ ...datum,
222
+ __temp_key__: keys[index2]
223
+ }));
224
+ }
225
+ return data;
226
+ }
227
+ );
228
+ const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
229
+ const schemaKeys = Object.keys(schema.attributes);
230
+ const dataKeys = Object.keys(data);
231
+ const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
232
+ const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
233
+ delete acc[key];
234
+ return acc;
235
+ }, structuredClone(data));
236
+ return revisedData;
237
+ };
238
+ const removeNullValues = (data) => {
239
+ return Object.entries(data).reduce((acc, [key, value]) => {
240
+ if (value === null) {
241
+ return acc;
242
+ }
243
+ acc[key] = value;
244
+ return acc;
245
+ }, {});
246
+ };
247
+ const transformDocument = (schema, components = {}) => (document) => {
248
+ const transformations = pipe(
249
+ removeFieldsThatDontExistOnSchema(schema),
250
+ removeProhibitedFields(["password"])(schema, components),
251
+ removeNullValues,
252
+ prepareRelations(schema, components),
253
+ prepareTempKeys(schema, components)
254
+ );
255
+ return transformations(document);
256
+ };
257
+ const createDefaultForm = (contentType, components = {}) => {
258
+ const traverseSchema = (attributes) => {
259
+ return Object.entries(attributes).reduce((acc, [key, attribute]) => {
260
+ if ("default" in attribute) {
261
+ acc[key] = attribute.default;
262
+ } else if (attribute.type === "component" && attribute.required) {
263
+ const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
264
+ if (attribute.repeatable) {
265
+ acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
266
+ } else {
267
+ acc[key] = defaultComponentForm;
268
+ }
269
+ } else if (attribute.type === "dynamiczone" && attribute.required) {
270
+ acc[key] = [];
271
+ }
272
+ return acc;
273
+ }, {});
274
+ };
275
+ return traverseSchema(contentType.attributes);
276
+ };
162
277
  const contentManagerApi = adminApi.enhanceEndpoints({
163
278
  addTagTypes: [
164
279
  "ComponentConfiguration",
@@ -168,7 +283,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
168
283
  "InitialData",
169
284
  "HistoryVersion",
170
285
  "Relations",
171
- "UidAvailability"
286
+ "UidAvailability",
287
+ "RecentDocumentList"
172
288
  ]
173
289
  });
174
290
  const documentApi = contentManagerApi.injectEndpoints({
@@ -186,7 +302,7 @@ const documentApi = contentManagerApi.injectEndpoints({
186
302
  if (error) {
187
303
  return [];
188
304
  }
189
- return [{ type: "Document", id: `${model}_LIST` }];
305
+ return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
190
306
  }
191
307
  }),
192
308
  cloneDocument: builder.mutation({
@@ -200,7 +316,8 @@ const documentApi = contentManagerApi.injectEndpoints({
200
316
  }),
201
317
  invalidatesTags: (_result, _error, { model }) => [
202
318
  { type: "Document", id: `${model}_LIST` },
203
- { type: "UidAvailability", id: model }
319
+ { type: "UidAvailability", id: model },
320
+ "RecentDocumentList"
204
321
  ]
205
322
  }),
206
323
  /**
@@ -219,8 +336,21 @@ const documentApi = contentManagerApi.injectEndpoints({
219
336
  invalidatesTags: (result, _error, { model }) => [
220
337
  { type: "Document", id: `${model}_LIST` },
221
338
  "Relations",
222
- { type: "UidAvailability", id: model }
223
- ]
339
+ { type: "UidAvailability", id: model },
340
+ "RecentDocumentList"
341
+ ],
342
+ transformResponse: (response, meta, arg) => {
343
+ if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
344
+ return {
345
+ data: response,
346
+ meta: {
347
+ availableStatus: [],
348
+ availableLocales: []
349
+ }
350
+ };
351
+ }
352
+ return response;
353
+ }
224
354
  }),
225
355
  deleteDocument: builder.mutation({
226
356
  query: ({ collectionType, model, documentId, params }) => ({
@@ -231,7 +361,8 @@ const documentApi = contentManagerApi.injectEndpoints({
231
361
  }
232
362
  }),
233
363
  invalidatesTags: (_result, _error, { collectionType, model }) => [
234
- { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
364
+ { type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
365
+ "RecentDocumentList"
235
366
  ]
236
367
  }),
237
368
  deleteManyDocuments: builder.mutation({
@@ -243,7 +374,10 @@ const documentApi = contentManagerApi.injectEndpoints({
243
374
  params
244
375
  }
245
376
  }),
246
- invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
377
+ invalidatesTags: (_res, _error, { model }) => [
378
+ { type: "Document", id: `${model}_LIST` },
379
+ "RecentDocumentList"
380
+ ]
247
381
  }),
248
382
  discardDocument: builder.mutation({
249
383
  query: ({ collectionType, model, documentId, params }) => ({
@@ -261,7 +395,8 @@ const documentApi = contentManagerApi.injectEndpoints({
261
395
  },
262
396
  { type: "Document", id: `${model}_LIST` },
263
397
  "Relations",
264
- { type: "UidAvailability", id: model }
398
+ { type: "UidAvailability", id: model },
399
+ "RecentDocumentList"
265
400
  ];
266
401
  }
267
402
  }),
@@ -271,10 +406,10 @@ const documentApi = contentManagerApi.injectEndpoints({
271
406
  */
272
407
  getAllDocuments: builder.query({
273
408
  query: ({ model, params }) => ({
274
- url: `/content-manager/collection-types/${model}${params ? `?${params}` : ""}`,
409
+ url: `/content-manager/collection-types/${model}`,
275
410
  method: "GET",
276
411
  config: {
277
- params
412
+ params: stringify(params, { encode: true })
278
413
  }
279
414
  }),
280
415
  providesTags: (result, _error, arg) => {
@@ -356,7 +491,8 @@ const documentApi = contentManagerApi.injectEndpoints({
356
491
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
357
492
  },
358
493
  { type: "Document", id: `${model}_LIST` },
359
- "Relations"
494
+ "Relations",
495
+ "RecentDocumentList"
360
496
  ];
361
497
  }
362
498
  }),
@@ -387,7 +523,9 @@ const documentApi = contentManagerApi.injectEndpoints({
387
523
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
388
524
  },
389
525
  "Relations",
390
- { type: "UidAvailability", id: model }
526
+ { type: "UidAvailability", id: model },
527
+ "RecentDocumentList",
528
+ "RecentDocumentList"
391
529
  ];
392
530
  },
393
531
  async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
@@ -417,7 +555,8 @@ const documentApi = contentManagerApi.injectEndpoints({
417
555
  {
418
556
  type: "Document",
419
557
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
420
- }
558
+ },
559
+ "RecentDocumentList"
421
560
  ];
422
561
  }
423
562
  }),
@@ -430,7 +569,10 @@ const documentApi = contentManagerApi.injectEndpoints({
430
569
  params
431
570
  }
432
571
  }),
433
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
572
+ invalidatesTags: (_res, _error, { model, documentIds }) => [
573
+ ...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
574
+ "RecentDocumentList"
575
+ ]
434
576
  })
435
577
  })
436
578
  });
@@ -453,8 +595,7 @@ const {
453
595
  useUnpublishManyDocumentsMutation
454
596
  } = documentApi;
455
597
  const buildValidParams = (query) => {
456
- if (!query)
457
- return query;
598
+ if (!query) return query;
458
599
  const { plugins: _, ...validQueryParams } = {
459
600
  ...query,
460
601
  ...Object.values(query?.plugins ?? {}).reduce(
@@ -462,9 +603,6 @@ const buildValidParams = (query) => {
462
603
  {}
463
604
  )
464
605
  };
465
- if ("_q" in validQueryParams) {
466
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
467
- }
468
606
  return validQueryParams;
469
607
  };
470
608
  const isBaseQueryError = (error) => {
@@ -1105,6 +1243,7 @@ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, co
1105
1243
  const useDocument = (args, opts) => {
1106
1244
  const { toggleNotification } = useNotification();
1107
1245
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
1246
+ const { formatMessage } = useIntl();
1108
1247
  const {
1109
1248
  currentData: data,
1110
1249
  isLoading: isLoadingDocument,
@@ -1114,12 +1253,27 @@ const useDocument = (args, opts) => {
1114
1253
  ...opts,
1115
1254
  skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
1116
1255
  });
1256
+ const document = data?.data;
1257
+ const meta = data?.meta;
1117
1258
  const {
1118
1259
  components,
1119
1260
  schema,
1120
1261
  schemas,
1121
1262
  isLoading: isLoadingSchema
1122
1263
  } = useContentTypeSchema(args.model);
1264
+ const isSingleType = schema?.kind === "singleType";
1265
+ const getTitle = (mainField) => {
1266
+ if (mainField !== "id" && document?.[mainField]) {
1267
+ return document[mainField];
1268
+ }
1269
+ if (isSingleType && schema?.info.displayName) {
1270
+ return schema.info.displayName;
1271
+ }
1272
+ return formatMessage({
1273
+ id: "content-manager.containers.untitled",
1274
+ defaultMessage: "Untitled"
1275
+ });
1276
+ };
1123
1277
  React.useEffect(() => {
1124
1278
  if (error) {
1125
1279
  toggleNotification({
@@ -1135,14 +1289,14 @@ const useDocument = (args, opts) => {
1135
1289
  return createYupSchema(schema.attributes, components);
1136
1290
  }, [schema, components]);
1137
1291
  const validate = React.useCallback(
1138
- (document) => {
1292
+ (document2) => {
1139
1293
  if (!validationSchema) {
1140
1294
  throw new Error(
1141
1295
  "There is no validation schema generated, this is likely due to the schema not being loaded yet."
1142
1296
  );
1143
1297
  }
1144
1298
  try {
1145
- validationSchema.validateSync(document, { abortEarly: false, strict: true });
1299
+ validationSchema.validateSync(document2, { abortEarly: false, strict: true });
1146
1300
  return null;
1147
1301
  } catch (error2) {
1148
1302
  if (error2 instanceof ValidationError) {
@@ -1153,17 +1307,29 @@ const useDocument = (args, opts) => {
1153
1307
  },
1154
1308
  [validationSchema]
1155
1309
  );
1310
+ const getInitialFormValues = React.useCallback(
1311
+ (isCreatingDocument = false) => {
1312
+ if (!document && !isCreatingDocument && !isSingleType || !schema) {
1313
+ return void 0;
1314
+ }
1315
+ const form = document?.id ? document : createDefaultForm(schema, components);
1316
+ return transformDocument(schema, components)(form);
1317
+ },
1318
+ [document, isSingleType, schema, components]
1319
+ );
1156
1320
  const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
1157
1321
  const hasError = !!error;
1158
1322
  return {
1159
1323
  components,
1160
- document: data?.data,
1161
- meta: data?.meta,
1324
+ document,
1325
+ meta,
1162
1326
  isLoading,
1163
1327
  hasError,
1164
1328
  schema,
1165
1329
  schemas,
1166
- validate
1330
+ validate,
1331
+ getTitle,
1332
+ getInitialFormValues
1167
1333
  };
1168
1334
  };
1169
1335
  const useDoc = () => {
@@ -1663,10 +1829,10 @@ const useDocumentActions = () => {
1663
1829
  update
1664
1830
  };
1665
1831
  };
1666
- const ProtectedHistoryPage = lazy(
1667
- () => import("./History-C72HQ0-i.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1832
+ const ProtectedHistoryPage = React.lazy(
1833
+ () => import("./History-D1PreDSY.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1668
1834
  );
1669
- const routes$1 = [
1835
+ const routes$2 = [
1670
1836
  {
1671
1837
  path: ":collectionType/:slug/:id/history",
1672
1838
  Component: ProtectedHistoryPage
@@ -1676,32 +1842,45 @@ const routes$1 = [
1676
1842
  Component: ProtectedHistoryPage
1677
1843
  }
1678
1844
  ];
1845
+ const ProtectedPreviewPage = React.lazy(
1846
+ () => import("./Preview-BNuU0SuQ.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
1847
+ );
1848
+ const routes$1 = [
1849
+ {
1850
+ path: ":collectionType/:slug/:id/preview",
1851
+ Component: ProtectedPreviewPage
1852
+ },
1853
+ {
1854
+ path: ":collectionType/:slug/preview",
1855
+ Component: ProtectedPreviewPage
1856
+ }
1857
+ ];
1679
1858
  const ProtectedEditViewPage = lazy(
1680
- () => import("./EditViewPage-zKmMBER4.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1859
+ () => import("./EditViewPage-DrmVmYN0.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1681
1860
  );
1682
1861
  const ProtectedListViewPage = lazy(
1683
- () => import("./ListViewPage-Dfue5wQ2.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1862
+ () => import("./ListViewPage-Bud_jBDQ.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1684
1863
  );
1685
1864
  const ProtectedListConfiguration = lazy(
1686
- () => import("./ListConfigurationPage-BalSo5dp.mjs").then((mod) => ({
1865
+ () => import("./ListConfigurationPage-Bbi32isk.mjs").then((mod) => ({
1687
1866
  default: mod.ProtectedListConfiguration
1688
1867
  }))
1689
1868
  );
1690
1869
  const ProtectedEditConfigurationPage = lazy(
1691
- () => import("./EditConfigurationPage-D7HkxcAN.mjs").then((mod) => ({
1870
+ () => import("./EditConfigurationPage-COe6hjPC.mjs").then((mod) => ({
1692
1871
  default: mod.ProtectedEditConfigurationPage
1693
1872
  }))
1694
1873
  );
1695
1874
  const ProtectedComponentConfigurationPage = lazy(
1696
- () => import("./ComponentConfigurationPage-BUOQFZ08.mjs").then((mod) => ({
1875
+ () => import("./ComponentConfigurationPage-9_4yUE9L.mjs").then((mod) => ({
1697
1876
  default: mod.ProtectedComponentConfigurationPage
1698
1877
  }))
1699
1878
  );
1700
1879
  const NoPermissions = lazy(
1701
- () => import("./NoPermissionsPage-BpAoEQy_.mjs").then((mod) => ({ default: mod.NoPermissions }))
1880
+ () => import("./NoPermissionsPage-CMdM-dCo.mjs").then((mod) => ({ default: mod.NoPermissions }))
1702
1881
  );
1703
1882
  const NoContentType = lazy(
1704
- () => import("./NoContentTypePage-BLC8M9U0.mjs").then((mod) => ({ default: mod.NoContentType }))
1883
+ () => import("./NoContentTypePage-DVhkugsf.mjs").then((mod) => ({ default: mod.NoContentType }))
1705
1884
  );
1706
1885
  const CollectionTypePages = () => {
1707
1886
  const { collectionType } = useParams();
@@ -1713,7 +1892,7 @@ const CollectionTypePages = () => {
1713
1892
  const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
1714
1893
  const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
1715
1894
  const LIST_RELATIVE_PATH = ":collectionType/:slug";
1716
- const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
1895
+ const LIST_PATH = `/content-manager/collection-types/:slug`;
1717
1896
  const routes = [
1718
1897
  {
1719
1898
  path: LIST_RELATIVE_PATH,
@@ -1747,6 +1926,7 @@ const routes = [
1747
1926
  path: "no-content-types",
1748
1927
  Component: NoContentType
1749
1928
  },
1929
+ ...routes$2,
1750
1930
  ...routes$1
1751
1931
  ];
1752
1932
  const DocumentActions = ({ actions: actions2 }) => {
@@ -1845,6 +2025,11 @@ const DocumentActionButton = (action) => {
1845
2025
  ) : null
1846
2026
  ] });
1847
2027
  };
2028
+ const MenuItem = styled(Menu.Item)`
2029
+ &:hover {
2030
+ background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
2031
+ }
2032
+ `;
1848
2033
  const DocumentActionsMenu = ({
1849
2034
  actions: actions2,
1850
2035
  children,
@@ -1903,48 +2088,32 @@ const DocumentActionsMenu = ({
1903
2088
  /* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
1904
2089
  actions2.map((action) => {
1905
2090
  return /* @__PURE__ */ jsx(
1906
- Menu.Item,
2091
+ MenuItem,
1907
2092
  {
1908
2093
  disabled: action.disabled,
1909
2094
  onSelect: handleClick(action),
1910
2095
  display: "block",
1911
- children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1912
- /* @__PURE__ */ jsxs(
1913
- Flex,
1914
- {
1915
- color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1916
- gap: 2,
1917
- tag: "span",
1918
- children: [
1919
- /* @__PURE__ */ jsx(
1920
- Flex,
1921
- {
1922
- tag: "span",
1923
- color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1924
- children: action.icon
1925
- }
1926
- ),
1927
- action.label
1928
- ]
1929
- }
1930
- ),
1931
- action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1932
- Flex,
1933
- {
1934
- alignItems: "center",
1935
- background: "alternative100",
1936
- borderStyle: "solid",
1937
- borderColor: "alternative200",
1938
- borderWidth: "1px",
1939
- height: 5,
1940
- paddingLeft: 2,
1941
- paddingRight: 2,
1942
- hasRadius: true,
1943
- color: "alternative600",
1944
- children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
1945
- }
1946
- )
1947
- ] })
2096
+ isVariantDanger: action.variant === "danger",
2097
+ isDisabled: action.disabled,
2098
+ children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
2099
+ Flex,
2100
+ {
2101
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
2102
+ gap: 2,
2103
+ tag: "span",
2104
+ children: [
2105
+ /* @__PURE__ */ jsx(
2106
+ Flex,
2107
+ {
2108
+ tag: "span",
2109
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
2110
+ children: action.icon
2111
+ }
2112
+ ),
2113
+ action.label
2114
+ ]
2115
+ }
2116
+ ) })
1948
2117
  },
1949
2118
  action.id
1950
2119
  );
@@ -2081,6 +2250,7 @@ const PublishAction$1 = ({
2081
2250
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
2082
2251
  const isListView = useMatch(LIST_PATH) !== null;
2083
2252
  const isCloning = useMatch(CLONE_PATH) !== null;
2253
+ const { id } = useParams();
2084
2254
  const { formatMessage } = useIntl();
2085
2255
  const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
2086
2256
  const { publish } = useDocumentActions();
@@ -2183,10 +2353,12 @@ const PublishAction$1 = ({
2183
2353
  transformData(formValues)
2184
2354
  );
2185
2355
  if ("data" in res && collectionType !== SINGLE_TYPES) {
2186
- navigate({
2187
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2188
- search: rawQuery
2189
- });
2356
+ if (id === "create") {
2357
+ navigate({
2358
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
2359
+ search: rawQuery
2360
+ });
2361
+ }
2190
2362
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2191
2363
  setErrors(formatValidationErrors(res.error));
2192
2364
  }
@@ -2239,6 +2411,7 @@ const PublishAction$1 = ({
2239
2411
  };
2240
2412
  };
2241
2413
  PublishAction$1.type = "publish";
2414
+ PublishAction$1.position = "panel";
2242
2415
  const UpdateAction = ({
2243
2416
  activeTab,
2244
2417
  documentId,
@@ -2261,96 +2434,134 @@ const UpdateAction = ({
2261
2434
  const validate = useForm("UpdateAction", (state) => state.validate);
2262
2435
  const setErrors = useForm("UpdateAction", (state) => state.setErrors);
2263
2436
  const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
2264
- return {
2265
- /**
2266
- * Disabled when:
2267
- * - the form is submitting
2268
- * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2269
- * - the active tab is the published tab
2270
- */
2271
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2272
- label: formatMessage({
2273
- id: "content-manager.containers.Edit.save",
2274
- defaultMessage: "Save"
2275
- }),
2276
- onClick: async () => {
2277
- setSubmitting(true);
2278
- try {
2279
- const { errors } = await validate(true, {
2280
- status: "draft"
2437
+ const handleUpdate = React.useCallback(async () => {
2438
+ setSubmitting(true);
2439
+ try {
2440
+ if (!modified) {
2441
+ return;
2442
+ }
2443
+ const { errors } = await validate(true, {
2444
+ status: "draft"
2445
+ });
2446
+ if (errors) {
2447
+ toggleNotification({
2448
+ type: "danger",
2449
+ message: formatMessage({
2450
+ id: "content-manager.validation.error",
2451
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
2452
+ })
2281
2453
  });
2282
- if (errors) {
2283
- toggleNotification({
2284
- type: "danger",
2285
- message: formatMessage({
2286
- id: "content-manager.validation.error",
2287
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
2288
- })
2289
- });
2290
- return;
2291
- }
2292
- if (isCloning) {
2293
- const res = await clone(
2294
- {
2295
- model,
2296
- documentId: cloneMatch.params.origin,
2297
- params
2298
- },
2299
- transformData(document)
2300
- );
2301
- if ("data" in res) {
2302
- navigate(
2303
- {
2304
- pathname: `../${res.data.documentId}`,
2305
- search: rawQuery
2306
- },
2307
- { relative: "path" }
2308
- );
2309
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2310
- setErrors(formatValidationErrors(res.error));
2311
- }
2312
- } else if (documentId || collectionType === SINGLE_TYPES) {
2313
- const res = await update(
2454
+ return;
2455
+ }
2456
+ if (isCloning) {
2457
+ const res = await clone(
2458
+ {
2459
+ model,
2460
+ documentId: cloneMatch.params.origin,
2461
+ params
2462
+ },
2463
+ transformData(document)
2464
+ );
2465
+ if ("data" in res) {
2466
+ navigate(
2314
2467
  {
2315
- collectionType,
2316
- model,
2317
- documentId,
2318
- params
2468
+ pathname: `../${res.data.documentId}`,
2469
+ search: rawQuery
2319
2470
  },
2320
- transformData(document)
2471
+ { relative: "path" }
2321
2472
  );
2322
- if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2323
- setErrors(formatValidationErrors(res.error));
2324
- } else {
2325
- resetForm();
2326
- }
2473
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2474
+ setErrors(formatValidationErrors(res.error));
2475
+ }
2476
+ } else if (documentId || collectionType === SINGLE_TYPES) {
2477
+ const res = await update(
2478
+ {
2479
+ collectionType,
2480
+ model,
2481
+ documentId,
2482
+ params
2483
+ },
2484
+ transformData(document)
2485
+ );
2486
+ if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2487
+ setErrors(formatValidationErrors(res.error));
2327
2488
  } else {
2328
- const res = await create(
2489
+ resetForm();
2490
+ }
2491
+ } else {
2492
+ const res = await create(
2493
+ {
2494
+ model,
2495
+ params
2496
+ },
2497
+ transformData(document)
2498
+ );
2499
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
2500
+ navigate(
2329
2501
  {
2330
- model,
2331
- params
2502
+ pathname: `../${res.data.documentId}`,
2503
+ search: rawQuery
2332
2504
  },
2333
- transformData(document)
2505
+ { replace: true, relative: "path" }
2334
2506
  );
2335
- if ("data" in res && collectionType !== SINGLE_TYPES) {
2336
- navigate(
2337
- {
2338
- pathname: `../${res.data.documentId}`,
2339
- search: rawQuery
2340
- },
2341
- { replace: true, relative: "path" }
2342
- );
2343
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2344
- setErrors(formatValidationErrors(res.error));
2345
- }
2507
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
2508
+ setErrors(formatValidationErrors(res.error));
2346
2509
  }
2347
- } finally {
2348
- setSubmitting(false);
2349
2510
  }
2511
+ } finally {
2512
+ setSubmitting(false);
2350
2513
  }
2514
+ }, [
2515
+ clone,
2516
+ cloneMatch?.params.origin,
2517
+ collectionType,
2518
+ create,
2519
+ document,
2520
+ documentId,
2521
+ formatMessage,
2522
+ formatValidationErrors,
2523
+ isCloning,
2524
+ model,
2525
+ modified,
2526
+ navigate,
2527
+ params,
2528
+ rawQuery,
2529
+ resetForm,
2530
+ setErrors,
2531
+ setSubmitting,
2532
+ toggleNotification,
2533
+ update,
2534
+ validate
2535
+ ]);
2536
+ React.useEffect(() => {
2537
+ const handleKeyDown = (e) => {
2538
+ if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
2539
+ e.preventDefault();
2540
+ handleUpdate();
2541
+ }
2542
+ };
2543
+ window.addEventListener("keydown", handleKeyDown);
2544
+ return () => {
2545
+ window.removeEventListener("keydown", handleKeyDown);
2546
+ };
2547
+ }, [handleUpdate]);
2548
+ return {
2549
+ /**
2550
+ * Disabled when:
2551
+ * - the form is submitting
2552
+ * - the document is not modified & we're not cloning (you can save a clone entity straight away)
2553
+ * - the active tab is the published tab
2554
+ */
2555
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
2556
+ label: formatMessage({
2557
+ id: "global.save",
2558
+ defaultMessage: "Save"
2559
+ }),
2560
+ onClick: handleUpdate
2351
2561
  };
2352
2562
  };
2353
2563
  UpdateAction.type = "update";
2564
+ UpdateAction.position = "panel";
2354
2565
  const UNPUBLISH_DRAFT_OPTIONS = {
2355
2566
  KEEP: "keep",
2356
2567
  DISCARD: "discard"
@@ -2473,6 +2684,7 @@ const UnpublishAction$1 = ({
2473
2684
  };
2474
2685
  };
2475
2686
  UnpublishAction$1.type = "unpublish";
2687
+ UnpublishAction$1.position = "panel";
2476
2688
  const DiscardAction = ({
2477
2689
  activeTab,
2478
2690
  documentId,
@@ -2523,6 +2735,7 @@ const DiscardAction = ({
2523
2735
  };
2524
2736
  };
2525
2737
  DiscardAction.type = "discard";
2738
+ DiscardAction.position = "panel";
2526
2739
  const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
2527
2740
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
2528
2741
  const RelativeTime = React.forwardRef(
@@ -2535,7 +2748,7 @@ const RelativeTime = React.forwardRef(
2535
2748
  });
2536
2749
  const unit = intervals.find((intervalUnit) => {
2537
2750
  return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
2538
- });
2751
+ }) ?? "seconds";
2539
2752
  const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
2540
2753
  const customInterval = customIntervals.find(
2541
2754
  (custom) => interval[custom.unit] < custom.threshold
@@ -2569,19 +2782,29 @@ const getDisplayName = ({
2569
2782
  return email ?? "";
2570
2783
  };
2571
2784
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2572
- const DocumentStatus = ({ status = "draft", ...restProps }) => {
2785
+ const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
2573
2786
  const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2574
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2787
+ const { formatMessage } = useIntl();
2788
+ return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
2789
+ id: `content-manager.containers.List.${status}`,
2790
+ defaultMessage: capitalise(status)
2791
+ }) }) });
2575
2792
  };
2576
2793
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2577
2794
  const { formatMessage } = useIntl();
2578
2795
  const isCloning = useMatch(CLONE_PATH) !== null;
2796
+ const params = useParams();
2579
2797
  const title = isCreating ? formatMessage({
2580
2798
  id: "content-manager.containers.edit.title.new",
2581
2799
  defaultMessage: "Create an entry"
2582
2800
  }) : documentTitle;
2583
2801
  return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2584
- /* @__PURE__ */ jsx(BackButton, {}),
2802
+ /* @__PURE__ */ jsx(
2803
+ BackButton,
2804
+ {
2805
+ fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
2806
+ }
2807
+ ),
2585
2808
  /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2586
2809
  /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2587
2810
  /* @__PURE__ */ jsx(HeaderToolbar, {})
@@ -2632,7 +2855,7 @@ const HeaderToolbar = () => {
2632
2855
  meta: isCloning ? void 0 : meta,
2633
2856
  collectionType
2634
2857
  },
2635
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2858
+ descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
2636
2859
  children: (actions2) => {
2637
2860
  const headerActions = actions2.filter((action) => {
2638
2861
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -2840,6 +3063,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2840
3063
  };
2841
3064
  };
2842
3065
  ConfigureTheViewAction.type = "configure-the-view";
3066
+ ConfigureTheViewAction.position = "header";
2843
3067
  const EditTheModelAction = ({ model }) => {
2844
3068
  const navigate = useNavigate();
2845
3069
  const { formatMessage } = useIntl();
@@ -2856,6 +3080,7 @@ const EditTheModelAction = ({ model }) => {
2856
3080
  };
2857
3081
  };
2858
3082
  EditTheModelAction.type = "edit-the-model";
3083
+ EditTheModelAction.position = "header";
2859
3084
  const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2860
3085
  const navigate = useNavigate();
2861
3086
  const { formatMessage } = useIntl();
@@ -2929,6 +3154,7 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2929
3154
  };
2930
3155
  };
2931
3156
  DeleteAction$1.type = "delete";
3157
+ DeleteAction$1.position = ["header", "table-row"];
2932
3158
  const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2933
3159
  const Panels = () => {
2934
3160
  const isCloning = useMatch(CLONE_PATH) !== null;
@@ -2991,7 +3217,7 @@ const ActionsPanelContent = () => {
2991
3217
  DescriptionComponentRenderer,
2992
3218
  {
2993
3219
  props,
2994
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
3220
+ descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
2995
3221
  children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
2996
3222
  }
2997
3223
  ),
@@ -3049,7 +3275,7 @@ const ConfirmBulkActionDialog = ({
3049
3275
  ] })
3050
3276
  ] }) });
3051
3277
  };
3052
- const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3278
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3053
3279
  const ConfirmDialogPublishAll = ({
3054
3280
  isOpen,
3055
3281
  onToggleDialog,
@@ -3098,7 +3324,7 @@ const ConfirmDialogPublishAll = ({
3098
3324
  defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
3099
3325
  },
3100
3326
  {
3101
- b: BoldChunk$1,
3327
+ b: BoldChunk,
3102
3328
  count: countDraftRelations,
3103
3329
  entities: selectedEntries.length
3104
3330
  }
@@ -3137,6 +3363,16 @@ const ConfirmDialogPublishAll = ({
3137
3363
  const TypographyMaxWidth = styled(Typography)`
3138
3364
  max-width: 300px;
3139
3365
  `;
3366
+ const TableComponent = styled(RawTable)`
3367
+ width: 100%;
3368
+ table-layout: fixed;
3369
+ td:first-child {
3370
+ border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
3371
+ }
3372
+ td:first-of-type {
3373
+ padding: ${({ theme }) => theme.spaces[4]};
3374
+ }
3375
+ `;
3140
3376
  const formatErrorMessages = (errors, parentKey, formatMessage) => {
3141
3377
  const messages = [];
3142
3378
  Object.entries(errors).forEach(([key, value]) => {
@@ -3241,7 +3477,7 @@ const SelectedEntriesTableContent = ({
3241
3477
  )
3242
3478
  ] }),
3243
3479
  /* @__PURE__ */ jsx(Table.Loading, {}),
3244
- /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3480
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3245
3481
  /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3246
3482
  /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3247
3483
  shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
@@ -3268,18 +3504,10 @@ const SelectedEntriesTableContent = ({
3268
3504
  search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3269
3505
  },
3270
3506
  state: { from: pathname },
3271
- label: formatMessage(
3272
- { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3273
- {
3274
- target: formatMessage(
3275
- {
3276
- id: "content-manager.components.ListViewHelperPluginTable.row-line",
3277
- defaultMessage: "item line {number}"
3278
- },
3279
- { number: index2 + 1 }
3280
- )
3281
- }
3282
- ),
3507
+ label: formatMessage({
3508
+ id: "content-manager.bulk-publish.edit",
3509
+ defaultMessage: "Edit"
3510
+ }),
3283
3511
  target: "_blank",
3284
3512
  marginLeft: "auto",
3285
3513
  variant: "ghost",
@@ -3289,7 +3517,73 @@ const SelectedEntriesTableContent = ({
3289
3517
  ] }, row.id)) })
3290
3518
  ] });
3291
3519
  };
3292
- const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3520
+ const PublicationStatusSummary = ({ count, icon, message }) => {
3521
+ return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", flex: 1, gap: 3, children: [
3522
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3523
+ icon,
3524
+ /* @__PURE__ */ jsx(Typography, { children: message })
3525
+ ] }),
3526
+ /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: count })
3527
+ ] });
3528
+ };
3529
+ const PublicationStatusGrid = ({
3530
+ entriesReadyToPublishCount,
3531
+ entriesPublishedCount,
3532
+ entriesModifiedCount,
3533
+ entriesWithErrorsCount
3534
+ }) => {
3535
+ const { formatMessage } = useIntl();
3536
+ return /* @__PURE__ */ jsx(Box, { hasRadius: true, borderColor: "neutral150", children: /* @__PURE__ */ jsx(TableComponent, { colCount: 2, rowCount: 2, children: /* @__PURE__ */ jsxs(Tbody, { children: [
3537
+ /* @__PURE__ */ jsxs(Tr, { children: [
3538
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
3539
+ PublicationStatusSummary,
3540
+ {
3541
+ count: entriesReadyToPublishCount,
3542
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3543
+ message: formatMessage({
3544
+ id: "app.utils.ready-to-publish",
3545
+ defaultMessage: "Ready to publish"
3546
+ })
3547
+ }
3548
+ ) }),
3549
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
3550
+ PublicationStatusSummary,
3551
+ {
3552
+ count: entriesPublishedCount,
3553
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3554
+ message: formatMessage({
3555
+ id: "app.utils.already-published",
3556
+ defaultMessage: "Already published"
3557
+ })
3558
+ }
3559
+ ) })
3560
+ ] }),
3561
+ /* @__PURE__ */ jsxs(Tr, { children: [
3562
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
3563
+ PublicationStatusSummary,
3564
+ {
3565
+ count: entriesModifiedCount,
3566
+ icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3567
+ message: formatMessage({
3568
+ id: "content-manager.bulk-publish.modified",
3569
+ defaultMessage: "Ready to publish changes"
3570
+ })
3571
+ }
3572
+ ) }),
3573
+ /* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
3574
+ PublicationStatusSummary,
3575
+ {
3576
+ count: entriesWithErrorsCount,
3577
+ icon: /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3578
+ message: formatMessage({
3579
+ id: "content-manager.bulk-publish.waiting-for-action",
3580
+ defaultMessage: "Waiting for action"
3581
+ })
3582
+ }
3583
+ ) })
3584
+ ] })
3585
+ ] }) }) });
3586
+ };
3293
3587
  const SelectedEntriesModalContent = ({
3294
3588
  listViewSelectedEntries,
3295
3589
  toggleModal,
@@ -3348,7 +3642,6 @@ const SelectedEntriesModalContent = ({
3348
3642
  validationErrors: {}
3349
3643
  };
3350
3644
  }, [components, data, schema]);
3351
- const [publishedCount, setPublishedCount] = React.useState(0);
3352
3645
  const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3353
3646
  const { publishMany: bulkPublishAction } = useDocumentActions();
3354
3647
  const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
@@ -3360,53 +3653,36 @@ const SelectedEntriesModalContent = ({
3360
3653
  const selectedEntriesWithErrorsCount = selectedEntries.filter(
3361
3654
  ({ documentId }) => validationErrors[documentId]
3362
3655
  ).length;
3363
- const selectedEntriesPublished = selectedEntries.filter(
3656
+ const selectedEntriesPublishedCount = selectedEntries.filter(
3364
3657
  ({ status }) => status === "published"
3365
3658
  ).length;
3366
- const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3659
+ const selectedEntriesModifiedCount = selectedEntries.filter(
3660
+ ({ status, documentId }) => status === "modified" && !validationErrors[documentId]
3661
+ ).length;
3662
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublishedCount;
3367
3663
  const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3368
3664
  const handleConfirmBulkPublish = async () => {
3369
3665
  toggleDialog();
3370
3666
  const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3371
3667
  if (!("error" in res)) {
3372
- setPublishedCount(res.count);
3373
3668
  const unpublishedEntries = rows.filter((row) => {
3374
3669
  return !entriesToPublish.includes(row.documentId);
3375
3670
  });
3376
3671
  setListViewSelectedDocuments(unpublishedEntries);
3377
3672
  }
3378
3673
  };
3379
- const getFormattedCountMessage = () => {
3380
- if (publishedCount) {
3381
- return formatMessage(
3382
- {
3383
- id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3384
- defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3385
- },
3386
- {
3387
- publishedCount,
3388
- withErrorsCount: selectedEntriesWithErrorsCount,
3389
- b: BoldChunk
3390
- }
3391
- );
3392
- }
3393
- return formatMessage(
3394
- {
3395
- id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3396
- defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
3397
- },
3398
- {
3399
- readyToPublishCount: selectedEntriesWithNoErrorsCount,
3400
- withErrorsCount: selectedEntriesWithErrorsCount,
3401
- alreadyPublishedCount: selectedEntriesPublished,
3402
- b: BoldChunk
3403
- }
3404
- );
3405
- };
3406
3674
  return /* @__PURE__ */ jsxs(Fragment, { children: [
3407
3675
  /* @__PURE__ */ jsxs(Modal.Body, { children: [
3408
- /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3409
- /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3676
+ /* @__PURE__ */ jsx(
3677
+ PublicationStatusGrid,
3678
+ {
3679
+ entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
3680
+ entriesPublishedCount: selectedEntriesPublishedCount,
3681
+ entriesModifiedCount: selectedEntriesModifiedCount,
3682
+ entriesWithErrorsCount: selectedEntriesWithErrorsCount
3683
+ }
3684
+ ),
3685
+ /* @__PURE__ */ jsx(Box, { marginTop: 7, children: /* @__PURE__ */ jsx(
3410
3686
  SelectedEntriesTableContent,
3411
3687
  {
3412
3688
  isPublishing: isSubmittingForm,
@@ -3427,7 +3703,7 @@ const SelectedEntriesModalContent = ({
3427
3703
  Button,
3428
3704
  {
3429
3705
  onClick: toggleDialog,
3430
- disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3706
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
3431
3707
  loading: isSubmittingForm,
3432
3708
  children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3433
3709
  }
@@ -3453,8 +3729,7 @@ const PublishAction = ({ documents, model }) => {
3453
3729
  const refetchList = () => {
3454
3730
  contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3455
3731
  };
3456
- if (!showPublishButton)
3457
- return null;
3732
+ if (!showPublishButton) return null;
3458
3733
  return {
3459
3734
  actionType: "publish",
3460
3735
  variant: "tertiary",
@@ -3522,8 +3797,7 @@ const DeleteAction = ({ documents, model }) => {
3522
3797
  selectRow([]);
3523
3798
  }
3524
3799
  };
3525
- if (!hasDeletePermission)
3526
- return null;
3800
+ if (!hasDeletePermission) return null;
3527
3801
  return {
3528
3802
  variant: "danger-light",
3529
3803
  label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
@@ -3572,8 +3846,7 @@ const UnpublishAction = ({ documents, model }) => {
3572
3846
  }
3573
3847
  };
3574
3848
  const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3575
- if (!showUnpublishButton)
3576
- return null;
3849
+ if (!showUnpublishButton) return null;
3577
3850
  return {
3578
3851
  variant: "tertiary",
3579
3852
  label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
@@ -3678,7 +3951,7 @@ const TableActions = ({ document }) => {
3678
3951
  DescriptionComponentRenderer,
3679
3952
  {
3680
3953
  props,
3681
- descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3954
+ descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
3682
3955
  children: (actions2) => {
3683
3956
  const tableRowActions = actions2.filter((action) => {
3684
3957
  const positions = Array.isArray(action.position) ? action.position : [action.position];
@@ -3737,6 +4010,7 @@ const EditAction = ({ documentId }) => {
3737
4010
  };
3738
4011
  };
3739
4012
  EditAction.type = "edit";
4013
+ EditAction.position = "table-row";
3740
4014
  const StyledPencil = styled(Pencil)`
3741
4015
  path {
3742
4016
  fill: currentColor;
@@ -3813,6 +4087,7 @@ const CloneAction = ({ model, documentId }) => {
3813
4087
  };
3814
4088
  };
3815
4089
  CloneAction.type = "clone";
4090
+ CloneAction.position = "table-row";
3816
4091
  const StyledDuplicate = styled(Duplicate)`
3817
4092
  path {
3818
4093
  fill: currentColor;
@@ -3899,7 +4174,14 @@ class ContentManagerPlugin {
3899
4174
  addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3900
4175
  addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3901
4176
  getBulkActions: () => this.bulkActions,
3902
- getDocumentActions: () => this.documentActions,
4177
+ getDocumentActions: (position) => {
4178
+ if (position) {
4179
+ return this.documentActions.filter(
4180
+ (action) => action.position == void 0 || [action.position].flat().includes(position)
4181
+ );
4182
+ }
4183
+ return this.documentActions;
4184
+ },
3903
4185
  getEditViewSidePanels: () => this.editViewSidePanels,
3904
4186
  getHeaderActions: () => this.headerActions
3905
4187
  }
@@ -3909,10 +4191,8 @@ class ContentManagerPlugin {
3909
4191
  const getPrintableType = (value) => {
3910
4192
  const nativeType = typeof value;
3911
4193
  if (nativeType === "object") {
3912
- if (value === null)
3913
- return "null";
3914
- if (Array.isArray(value))
3915
- return "array";
4194
+ if (value === null) return "null";
4195
+ if (Array.isArray(value)) return "array";
3916
4196
  if (value instanceof Object && value.constructor.name !== "Object") {
3917
4197
  return value.constructor.name;
3918
4198
  }
@@ -3923,17 +4203,27 @@ const HistoryAction = ({ model, document }) => {
3923
4203
  const { formatMessage } = useIntl();
3924
4204
  const [{ query }] = useQueryParams();
3925
4205
  const navigate = useNavigate();
4206
+ const { trackUsage } = useTracking();
4207
+ const { pathname } = useLocation();
3926
4208
  const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3927
4209
  if (!window.strapi.features.isEnabled("cms-content-history")) {
3928
4210
  return null;
3929
4211
  }
4212
+ const handleOnClick = () => {
4213
+ const destination = { pathname: "history", search: pluginsQueryParams };
4214
+ trackUsage("willNavigate", {
4215
+ from: pathname,
4216
+ to: `${pathname}/${destination.pathname}`
4217
+ });
4218
+ navigate(destination);
4219
+ };
3930
4220
  return {
3931
4221
  icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3932
4222
  label: formatMessage({
3933
4223
  id: "content-manager.history.document-action",
3934
4224
  defaultMessage: "Content History"
3935
4225
  }),
3936
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
4226
+ onClick: handleOnClick,
3937
4227
  disabled: (
3938
4228
  /**
3939
4229
  * The user is creating a new document.
@@ -3955,6 +4245,7 @@ const HistoryAction = ({ model, document }) => {
3955
4245
  };
3956
4246
  };
3957
4247
  HistoryAction.type = "history";
4248
+ HistoryAction.position = "header";
3958
4249
  const historyAdmin = {
3959
4250
  bootstrap(app) {
3960
4251
  const { addDocumentAction } = app.getPlugin("content-manager").apis;
@@ -4017,8 +4308,18 @@ const previewApi = contentManagerApi.injectEndpoints({
4017
4308
  })
4018
4309
  });
4019
4310
  const { useGetPreviewUrlQuery } = previewApi;
4311
+ const ConditionalTooltip = ({ isShown, label, children }) => {
4312
+ if (isShown) {
4313
+ return /* @__PURE__ */ jsx(Tooltip, { label, children });
4314
+ }
4315
+ return children;
4316
+ };
4020
4317
  const PreviewSidePanel = ({ model, documentId, document }) => {
4021
4318
  const { formatMessage } = useIntl();
4319
+ const { trackUsage } = useTracking();
4320
+ const { pathname } = useLocation();
4321
+ const [{ query }] = useQueryParams();
4322
+ const isModified = useForm("PreviewSidePanel", (state) => state.modified);
4022
4323
  const { data, error } = useGetPreviewUrlQuery({
4023
4324
  params: {
4024
4325
  contentType: model
@@ -4032,24 +4333,45 @@ const PreviewSidePanel = ({ model, documentId, document }) => {
4032
4333
  if (!data?.data?.url || error) {
4033
4334
  return null;
4034
4335
  }
4336
+ const trackNavigation = () => {
4337
+ const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
4338
+ trackUsage("willNavigate", { from: pathname, to: destinationPathname });
4339
+ };
4035
4340
  return {
4036
4341
  title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
4037
- content: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, tag: Link, to: data.data.url, target: "_blank", children: formatMessage({
4038
- id: "content-manager.preview.panel.button",
4039
- defaultMessage: "Open preview"
4040
- }) })
4342
+ content: /* @__PURE__ */ jsx(
4343
+ ConditionalTooltip,
4344
+ {
4345
+ label: formatMessage({
4346
+ id: "content-manager.preview.panel.button-disabled-tooltip",
4347
+ defaultMessage: "Please save to open the preview"
4348
+ }),
4349
+ isShown: isModified,
4350
+ children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
4351
+ Button,
4352
+ {
4353
+ variant: "tertiary",
4354
+ tag: Link,
4355
+ to: { pathname: "preview", search: stringify(query, { encode: false }) },
4356
+ onClick: trackNavigation,
4357
+ width: "100%",
4358
+ disabled: isModified,
4359
+ pointerEvents: isModified ? "none" : void 0,
4360
+ tabIndex: isModified ? -1 : void 0,
4361
+ children: formatMessage({
4362
+ id: "content-manager.preview.panel.button",
4363
+ defaultMessage: "Open preview"
4364
+ })
4365
+ }
4366
+ ) })
4367
+ }
4368
+ )
4041
4369
  };
4042
4370
  };
4043
- const FEATURE_ID = "preview";
4044
4371
  const previewAdmin = {
4045
4372
  bootstrap(app) {
4046
- if (!window.strapi.future.isEnabled(FEATURE_ID)) {
4047
- return;
4048
- }
4049
4373
  const contentManagerPluginApis = app.getPlugin("content-manager").apis;
4050
- if ("addEditViewSidePanel" in contentManagerPluginApis && typeof contentManagerPluginApis.addEditViewSidePanel === "function") {
4051
- contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4052
- }
4374
+ contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
4053
4375
  }
4054
4376
  };
4055
4377
  const index = {
@@ -4071,7 +4393,7 @@ const index = {
4071
4393
  app.router.addRoute({
4072
4394
  path: "content-manager/*",
4073
4395
  lazy: async () => {
4074
- const { Layout } = await import("./layout-DNfLIjbP.mjs");
4396
+ const { Layout } = await import("./layout-fQk1rMk9.mjs");
4075
4397
  return {
4076
4398
  Component: Layout
4077
4399
  };
@@ -4091,7 +4413,7 @@ const index = {
4091
4413
  async registerTrads({ locales }) {
4092
4414
  const importedTrads = await Promise.all(
4093
4415
  locales.map((locale) => {
4094
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-DPfZ6tPQ.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
4416
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-D65uIF6Y.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-DBseuRuB.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
4095
4417
  return {
4096
4418
  data: prefixPluginTranslations(data, PLUGIN_ID),
4097
4419
  locale
@@ -4108,23 +4430,27 @@ const index = {
4108
4430
  }
4109
4431
  };
4110
4432
  export {
4111
- ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
4433
+ useUpdateContentTypeConfigurationMutation as A,
4112
4434
  BulkActionsRenderer as B,
4113
4435
  COLLECTION_TYPES as C,
4114
4436
  DocumentStatus as D,
4115
- extractContentTypeComponents as E,
4116
- DEFAULT_SETTINGS as F,
4117
- convertEditLayoutToFieldLayouts as G,
4437
+ ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as E,
4438
+ extractContentTypeComponents as F,
4439
+ DEFAULT_SETTINGS as G,
4118
4440
  HOOKS as H,
4119
4441
  InjectionZone as I,
4120
- useDocument as J,
4121
- index as K,
4122
- useContentManagerContext as L,
4123
- useDocumentActions as M,
4442
+ convertEditLayoutToFieldLayouts as J,
4443
+ removeFieldsThatDontExistOnSchema as K,
4444
+ prepareTempKeys as L,
4445
+ useDocument as M,
4446
+ useGetPreviewUrlQuery as N,
4447
+ index as O,
4124
4448
  Panels as P,
4449
+ useContentManagerContext as Q,
4125
4450
  RelativeTime as R,
4126
4451
  SINGLE_TYPES as S,
4127
4452
  TableActions as T,
4453
+ useDocumentActions as U,
4128
4454
  useGetInitialDataQuery as a,
4129
4455
  useGetAllContentTypeSettingsQuery as b,
4130
4456
  useDoc as c,
@@ -4137,19 +4463,19 @@ export {
4137
4463
  Header as j,
4138
4464
  PERMISSIONS as k,
4139
4465
  DocumentRBAC as l,
4140
- DOCUMENT_META_FIELDS as m,
4141
- CLONE_PATH as n,
4142
- useDocLayout as o,
4466
+ useDocLayout as m,
4467
+ createDefaultForm as n,
4468
+ CLONE_PATH as o,
4143
4469
  useGetContentTypeConfigurationQuery as p,
4144
4470
  CREATOR_FIELDS as q,
4145
4471
  getMainField as r,
4146
4472
  setInitialData as s,
4147
- getDisplayName as t,
4473
+ transformDocument as t,
4148
4474
  useContentTypeSchema as u,
4149
- checkIfAttributeIsDisplayable as v,
4150
- useGetAllDocumentsQuery as w,
4151
- convertListLayoutToFieldLayouts as x,
4152
- capitalise as y,
4153
- useUpdateContentTypeConfigurationMutation as z
4475
+ getDisplayName as v,
4476
+ checkIfAttributeIsDisplayable as w,
4477
+ useGetAllDocumentsQuery as x,
4478
+ convertListLayoutToFieldLayouts as y,
4479
+ capitalise as z
4154
4480
  };
4155
- //# sourceMappingURL=index-DW7xp_LG.mjs.map
4481
+ //# sourceMappingURL=index-ZKrsjv-2.mjs.map