@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.abc

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 (184) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs → ComponentConfigurationPage-B3yDbeU1.mjs} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-B3yDbeU1.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-KXSuLnQD.js} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-KXSuLnQD.js.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  11. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-BQ17--5R.js} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-BQ17--5R.js.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-D7PrLO8j.mjs} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-D7PrLO8j.mjs.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-B7VgwJaG.mjs} +58 -47
  19. package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-BgjdnGz2.js} +57 -48
  21. package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +1 -0
  22. package/dist/_chunks/{Field-Caef4JjM.js → Field-CdK7ZLmv.js} +1030 -800
  23. package/dist/_chunks/Field-CdK7ZLmv.js.map +1 -0
  24. package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-tHCw4lGA.mjs} +981 -750
  25. package/dist/_chunks/Field-tHCw4lGA.mjs.map +1 -0
  26. package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-BJxdTv3Q.mjs} +56 -43
  27. package/dist/_chunks/Form-BJxdTv3Q.mjs.map +1 -0
  28. package/dist/_chunks/{Form-BzuAjtRq.js → Form-C_0KTVvV.js} +55 -43
  29. package/dist/_chunks/Form-C_0KTVvV.js.map +1 -0
  30. package/dist/_chunks/{History-D6sbCJvo.mjs → History-DR2txJLE.mjs} +151 -57
  31. package/dist/_chunks/History-DR2txJLE.mjs.map +1 -0
  32. package/dist/_chunks/{History-C17LiyRg.js → History-nuEzM5qm.js} +151 -58
  33. package/dist/_chunks/History-nuEzM5qm.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-CnB86Psm.js} +70 -61
  35. package/dist/_chunks/ListConfigurationPage-CnB86Psm.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-voFVtXu6.mjs} +67 -57
  37. package/dist/_chunks/ListConfigurationPage-voFVtXu6.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-B_GaWgRH.mjs} +95 -106
  39. package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-SXIXm-RM.js} +100 -111
  41. package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-BzsQ3hLZ.js} +5 -5
  43. package/dist/_chunks/NoContentTypePage-BzsQ3hLZ.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-CYiGpsbj.mjs} +7 -7
  45. package/dist/_chunks/NoContentTypePage-CYiGpsbj.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-B5baIHal.mjs} +5 -6
  47. package/dist/_chunks/NoPermissionsPage-B5baIHal.mjs.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-IGkId4C5.js} +4 -5
  49. package/dist/_chunks/NoPermissionsPage-IGkId4C5.js.map +1 -0
  50. package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-CIYDdKU-.mjs} +67 -57
  51. package/dist/_chunks/Relations-CIYDdKU-.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-Dhuurpx2.js} +71 -62
  53. package/dist/_chunks/Relations-Dhuurpx2.js.map +1 -0
  54. package/dist/_chunks/{en-MBPul9Su.mjs → en-BrCTWlZv.mjs} +11 -4
  55. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  56. package/dist/_chunks/{en-C-V1_90f.js → en-uOUIxfcQ.js} +11 -4
  57. package/dist/_chunks/{en-C-V1_90f.js.map → en-uOUIxfcQ.js.map} +1 -1
  58. package/dist/_chunks/{index-DNVx8ssZ.mjs → index-C9TJPyni.mjs} +1696 -912
  59. package/dist/_chunks/index-C9TJPyni.mjs.map +1 -0
  60. package/dist/_chunks/{index-X_2tafck.js → index-CdT0kHZ8.js} +1626 -843
  61. package/dist/_chunks/index-CdT0kHZ8.js.map +1 -0
  62. package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-BNqvLR_b.mjs} +45 -28
  63. package/dist/_chunks/layout-BNqvLR_b.mjs.map +1 -0
  64. package/dist/_chunks/{layout-dBc7wN7L.js → layout-C6dxWYT7.js} +45 -30
  65. package/dist/_chunks/layout-C6dxWYT7.js.map +1 -0
  66. package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-CkKqKw65.mjs} +2 -2
  67. package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-CkKqKw65.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-4pHtBrHJ.js → relations-DtFaDnP1.js} +2 -2
  69. package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-DtFaDnP1.js.map} +1 -1
  70. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  71. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  72. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  73. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  75. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +5 -4
  79. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  80. package/dist/admin/src/content-manager.d.ts +3 -3
  81. package/dist/admin/src/exports.d.ts +1 -0
  82. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  83. package/dist/admin/src/history/index.d.ts +3 -0
  84. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  86. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  87. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  88. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  89. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  90. package/dist/admin/src/index.d.ts +1 -0
  91. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
  92. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  93. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  96. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  98. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
  102. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +48 -53
  103. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  104. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  105. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  106. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  107. package/dist/admin/src/services/api.d.ts +2 -3
  108. package/dist/admin/src/services/components.d.ts +2 -2
  109. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  110. package/dist/admin/src/services/documents.d.ts +29 -17
  111. package/dist/admin/src/services/init.d.ts +2 -2
  112. package/dist/admin/src/services/relations.d.ts +3 -3
  113. package/dist/admin/src/services/uid.d.ts +3 -3
  114. package/dist/admin/src/utils/api.d.ts +4 -18
  115. package/dist/admin/src/utils/validation.d.ts +1 -6
  116. package/dist/server/index.js +602 -426
  117. package/dist/server/index.js.map +1 -1
  118. package/dist/server/index.mjs +610 -434
  119. package/dist/server/index.mjs.map +1 -1
  120. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  121. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  122. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  123. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  124. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  125. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  126. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  127. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  128. package/dist/server/src/history/services/history.d.ts +2 -4
  129. package/dist/server/src/history/services/history.d.ts.map +1 -1
  130. package/dist/server/src/history/services/index.d.ts +6 -2
  131. package/dist/server/src/history/services/index.d.ts.map +1 -1
  132. package/dist/server/src/history/services/lifecycles.d.ts +9 -0
  133. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
  134. package/dist/server/src/history/services/utils.d.ts +41 -9
  135. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  136. package/dist/server/src/history/utils.d.ts +6 -2
  137. package/dist/server/src/history/utils.d.ts.map +1 -1
  138. package/dist/server/src/index.d.ts +18 -39
  139. package/dist/server/src/index.d.ts.map +1 -1
  140. package/dist/server/src/services/document-manager.d.ts +13 -12
  141. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  142. package/dist/server/src/services/document-metadata.d.ts +8 -29
  143. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  144. package/dist/server/src/services/index.d.ts +18 -39
  145. package/dist/server/src/services/index.d.ts.map +1 -1
  146. package/dist/server/src/services/utils/populate.d.ts +8 -1
  147. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  148. package/dist/shared/contracts/collection-types.d.ts +14 -6
  149. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  150. package/dist/shared/contracts/relations.d.ts +2 -2
  151. package/dist/shared/contracts/relations.d.ts.map +1 -1
  152. package/package.json +13 -14
  153. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  154. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  155. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  156. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  157. package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs.map +0 -1
  158. package/dist/_chunks/EditViewPage-CzOT5Kpj.js.map +0 -1
  159. package/dist/_chunks/Field-Caef4JjM.js.map +0 -1
  160. package/dist/_chunks/Field-Dlh0uGnL.mjs.map +0 -1
  161. package/dist/_chunks/Form-BzuAjtRq.js.map +0 -1
  162. package/dist/_chunks/Form-EnaQL_6L.mjs.map +0 -1
  163. package/dist/_chunks/History-C17LiyRg.js.map +0 -1
  164. package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
  165. package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
  166. package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
  167. package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
  168. package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
  169. package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
  170. package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
  171. package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
  172. package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
  173. package/dist/_chunks/Relations-CY7AtkDA.mjs.map +0 -1
  174. package/dist/_chunks/Relations-Czs-uZ-s.js.map +0 -1
  175. package/dist/_chunks/index-DNVx8ssZ.mjs.map +0 -1
  176. package/dist/_chunks/index-X_2tafck.js.map +0 -1
  177. package/dist/_chunks/layout-Dnh0PNp9.mjs.map +0 -1
  178. package/dist/_chunks/layout-dBc7wN7L.js.map +0 -1
  179. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  180. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  181. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  182. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  183. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  184. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -1,19 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, Cog, Pencil, Trash, 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, getFetchClient, translatedErrors, useNotification, useAPIErrorHandler, useTracking, useForm, BackButton, DescriptionComponentRenderer } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, 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 { Menu, VisuallyHidden, Flex, Typography, Dialog, DialogBody, DialogFooter, Button, ModalLayout, ModalHeader, ModalBody, Box, Radio, Status, SingleSelect, SingleSelectOption, LinkButton } from "@strapi/design-system";
10
- import styled from "styled-components";
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, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
+ import { styled } from "styled-components";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
- import { createApi } from "@reduxjs/toolkit/query/react";
14
- import { isAxiosError } from "axios";
15
12
  import pipe from "lodash/fp/pipe";
16
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { stringify } from "qs";
17
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
18
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
19
17
  const v = glob[path];
@@ -51,42 +49,6 @@ const useInjectionZone = (area) => {
51
49
  const [page, position] = area.split(".");
52
50
  return contentManagerPlugin.getInjectedComponents(page, position);
53
51
  };
54
- const HistoryAction = ({ model, document }) => {
55
- const { formatMessage } = useIntl();
56
- const [{ query }] = useQueryParams();
57
- const navigate = useNavigate();
58
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
59
- if (!window.strapi.features.isEnabled("cms-content-history")) {
60
- return null;
61
- }
62
- return {
63
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
64
- label: formatMessage({
65
- id: "content-manager.history.document-action",
66
- defaultMessage: "Content History"
67
- }),
68
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
69
- disabled: (
70
- /**
71
- * The user is creating a new document.
72
- * It hasn't been saved yet, so there's no history to go to
73
- */
74
- !document || /**
75
- * The document has been created but the current dimension has never been saved.
76
- * For example, the user is creating a new locale in an existing document,
77
- * so there's no history for the document in that locale
78
- */
79
- !document.id || /**
80
- * History is only available for content types created by the user.
81
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
82
- * which start with `admin::` or `plugin::`
83
- */
84
- !model.startsWith("api::")
85
- ),
86
- position: "header"
87
- };
88
- };
89
- HistoryAction.type = "history";
90
52
  const ID = "id";
91
53
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
92
54
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -157,9 +119,8 @@ const DocumentRBAC = ({ children, permissions }) => {
157
119
  const name = removeNumericalStrings(fieldName.split("."));
158
120
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
159
121
  if (fieldType === "component") {
160
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
161
- return componentOrDynamicZoneFields.some((field) => {
162
- return field.includes(fieldName);
122
+ return componentFieldNames.some((field) => {
123
+ return field.includes(name.join("."));
163
124
  });
164
125
  }
165
126
  if (name.length > 1) {
@@ -189,78 +150,8 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
189
150
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
190
151
  );
191
152
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
192
- const buildValidParams = (query) => {
193
- if (!query)
194
- return query;
195
- const { plugins: _, ...validQueryParams } = {
196
- ...query,
197
- ...Object.values(query?.plugins ?? {}).reduce(
198
- (acc, current) => Object.assign(acc, current),
199
- {}
200
- )
201
- };
202
- if ("_q" in validQueryParams) {
203
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
204
- }
205
- return validQueryParams;
206
- };
207
- const axiosBaseQuery = () => async (query, { signal }) => {
208
- try {
209
- const { get, post, del, put } = getFetchClient();
210
- if (typeof query === "string") {
211
- const result = await get(query, { signal });
212
- return { data: result.data };
213
- } else {
214
- const { url, method = "GET", data, config } = query;
215
- if (method === "POST") {
216
- const result2 = await post(url, data, { ...config, signal });
217
- return { data: result2.data };
218
- }
219
- if (method === "DELETE") {
220
- const result2 = await del(url, { ...config, signal });
221
- return { data: result2.data };
222
- }
223
- if (method === "PUT") {
224
- const result2 = await put(url, data, { ...config, signal });
225
- return { data: result2.data };
226
- }
227
- const result = await get(url, { ...config, signal });
228
- return { data: result.data };
229
- }
230
- } catch (err) {
231
- if (isAxiosError(err)) {
232
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
233
- return { data: void 0, error: err.response?.data.error };
234
- } else {
235
- return {
236
- data: void 0,
237
- error: {
238
- name: "UnknownError",
239
- message: "There was an unknown error response from the API",
240
- details: err.response?.data,
241
- status: err.response?.status
242
- }
243
- };
244
- }
245
- }
246
- const error = err;
247
- return {
248
- data: void 0,
249
- error: {
250
- name: error.name,
251
- message: error.message,
252
- stack: error.stack
253
- }
254
- };
255
- }
256
- };
257
- const isBaseQueryError = (error) => {
258
- return error.name !== void 0;
259
- };
260
- const contentManagerApi = createApi({
261
- reducerPath: "contentManagerApi",
262
- baseQuery: axiosBaseQuery(),
263
- tagTypes: [
153
+ const contentManagerApi = adminApi.enhanceEndpoints({
154
+ addTagTypes: [
264
155
  "ComponentConfiguration",
265
156
  "ContentTypesConfiguration",
266
157
  "ContentTypeSettings",
@@ -268,10 +159,10 @@ const contentManagerApi = createApi({
268
159
  "InitialData",
269
160
  "HistoryVersion",
270
161
  "Relations"
271
- ],
272
- endpoints: () => ({})
162
+ ]
273
163
  });
274
164
  const documentApi = contentManagerApi.injectEndpoints({
165
+ overrideExisting: true,
275
166
  endpoints: (builder) => ({
276
167
  autoCloneDocument: builder.mutation({
277
168
  query: ({ model, sourceId, query }) => ({
@@ -281,7 +172,12 @@ const documentApi = contentManagerApi.injectEndpoints({
281
172
  params: query
282
173
  }
283
174
  }),
284
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
175
+ invalidatesTags: (_result, error, { model }) => {
176
+ if (error) {
177
+ return [];
178
+ }
179
+ return [{ type: "Document", id: `${model}_LIST` }];
180
+ }
285
181
  }),
286
182
  cloneDocument: builder.mutation({
287
183
  query: ({ model, sourceId, data, params }) => ({
@@ -325,12 +221,15 @@ const documentApi = contentManagerApi.injectEndpoints({
325
221
  ]
326
222
  }),
327
223
  deleteManyDocuments: builder.mutation({
328
- query: ({ model, ...body }) => ({
224
+ query: ({ model, params, ...body }) => ({
329
225
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
330
226
  method: "POST",
331
- data: body
227
+ data: body,
228
+ config: {
229
+ params
230
+ }
332
231
  }),
333
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
232
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
334
233
  }),
335
234
  discardDocument: builder.mutation({
336
235
  query: ({ collectionType, model, documentId, params }) => ({
@@ -365,6 +264,7 @@ const documentApi = contentManagerApi.injectEndpoints({
365
264
  }),
366
265
  providesTags: (result, _error, arg) => {
367
266
  return [
267
+ { type: "Document", id: `ALL_LIST` },
368
268
  { type: "Document", id: `${arg.model}_LIST` },
369
269
  ...result?.results.map(({ documentId }) => ({
370
270
  type: "Document",
@@ -403,6 +303,11 @@ const documentApi = contentManagerApi.injectEndpoints({
403
303
  {
404
304
  type: "Document",
405
305
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
306
+ },
307
+ // Make it easy to invalidate all individual documents queries for a model
308
+ {
309
+ type: "Document",
310
+ id: `${model}_ALL_ITEMS`
406
311
  }
407
312
  ];
408
313
  }
@@ -441,10 +346,13 @@ const documentApi = contentManagerApi.injectEndpoints({
441
346
  }
442
347
  }),
443
348
  publishManyDocuments: builder.mutation({
444
- query: ({ model, ...body }) => ({
349
+ query: ({ model, params, ...body }) => ({
445
350
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
446
351
  method: "POST",
447
- data: body
352
+ data: body,
353
+ config: {
354
+ params
355
+ }
448
356
  }),
449
357
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
450
358
  }),
@@ -465,6 +373,18 @@ const documentApi = contentManagerApi.injectEndpoints({
465
373
  },
466
374
  "Relations"
467
375
  ];
376
+ },
377
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
378
+ const patchResult = dispatch(
379
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
380
+ Object.assign(draft.data, data);
381
+ })
382
+ );
383
+ try {
384
+ await queryFulfilled;
385
+ } catch {
386
+ patchResult.undo();
387
+ }
468
388
  }
469
389
  }),
470
390
  unpublishDocument: builder.mutation({
@@ -486,10 +406,13 @@ const documentApi = contentManagerApi.injectEndpoints({
486
406
  }
487
407
  }),
488
408
  unpublishManyDocuments: builder.mutation({
489
- query: ({ model, ...body }) => ({
409
+ query: ({ model, params, ...body }) => ({
490
410
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
491
411
  method: "POST",
492
- data: body
412
+ data: body,
413
+ config: {
414
+ params
415
+ }
493
416
  }),
494
417
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
495
418
  })
@@ -513,6 +436,24 @@ const {
513
436
  useUnpublishDocumentMutation,
514
437
  useUnpublishManyDocumentsMutation
515
438
  } = documentApi;
439
+ const buildValidParams = (query) => {
440
+ if (!query)
441
+ return query;
442
+ const { plugins: _, ...validQueryParams } = {
443
+ ...query,
444
+ ...Object.values(query?.plugins ?? {}).reduce(
445
+ (acc, current) => Object.assign(acc, current),
446
+ {}
447
+ )
448
+ };
449
+ if ("_q" in validQueryParams) {
450
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
451
+ }
452
+ return validQueryParams;
453
+ };
454
+ const isBaseQueryError = (error) => {
455
+ return error.name !== void 0;
456
+ };
516
457
  const createYupSchema = (attributes = {}, components = {}) => {
517
458
  const createModelSchema = (attributes2) => yup.object().shape(
518
459
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -552,10 +493,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
552
493
  yup.array().of(
553
494
  yup.lazy(
554
495
  (data) => {
555
- const { attributes: attributes3 } = components[data.__component];
556
- return yup.object().shape({
496
+ const attributes3 = components?.[data?.__component]?.attributes;
497
+ const validation = yup.object().shape({
557
498
  __component: yup.string().required().oneOf(Object.keys(components))
558
- }).nullable(false).concat(createModelSchema(attributes3));
499
+ }).nullable(false);
500
+ if (!attributes3) {
501
+ return validation;
502
+ }
503
+ return validation.concat(createModelSchema(attributes3));
559
504
  }
560
505
  )
561
506
  )
@@ -565,11 +510,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
510
  return {
566
511
  ...acc,
567
512
  [name]: transformSchema(
568
- yup.array().of(
569
- yup.object().shape({
570
- id: yup.string().required()
571
- })
572
- )
513
+ yup.lazy((value) => {
514
+ if (!value) {
515
+ return yup.mixed().nullable(true);
516
+ } else if (Array.isArray(value)) {
517
+ return yup.array().of(
518
+ yup.object().shape({
519
+ id: yup.string().required()
520
+ })
521
+ );
522
+ } else if (typeof value === "object") {
523
+ return yup.object();
524
+ } else {
525
+ return yup.mixed().test(
526
+ "type-error",
527
+ "Relation values must be either null, an array of objects with {id} or an object.",
528
+ () => false
529
+ );
530
+ }
531
+ })
573
532
  )
574
533
  };
575
534
  default:
@@ -609,6 +568,14 @@ const createAttributeSchema = (attribute) => {
609
568
  if (!value || typeof value === "string" && value.length === 0) {
610
569
  return true;
611
570
  }
571
+ if (typeof value === "object") {
572
+ try {
573
+ JSON.stringify(value);
574
+ return true;
575
+ } catch (err) {
576
+ return false;
577
+ }
578
+ }
612
579
  try {
613
580
  JSON.parse(value);
614
581
  return true;
@@ -628,13 +595,18 @@ const createAttributeSchema = (attribute) => {
628
595
  }
629
596
  };
630
597
  const addRequiredValidation = (attribute) => (schema) => {
631
- if (attribute.required) {
632
- return schema.required({
633
- id: translatedErrors.required.id,
634
- defaultMessage: "This field is required."
635
- });
598
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
599
+ return schema.min(1, translatedErrors.required);
600
+ }
601
+ if (attribute.required && attribute.type !== "relation") {
602
+ return schema.required(translatedErrors.required);
636
603
  }
637
- return schema.nullable();
604
+ return schema?.nullable ? schema.nullable() : (
605
+ // In some cases '.nullable' will not be available on the schema.
606
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
607
+ // In these cases we should just return the schema as it is.
608
+ schema
609
+ );
638
610
  };
639
611
  const addMinLengthValidation = (attribute) => (schema) => {
640
612
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -661,6 +633,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
661
633
  const addMinValidation = (attribute) => (schema) => {
662
634
  if ("min" in attribute) {
663
635
  const min = toInteger(attribute.min);
636
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
637
+ if (!attribute.required && "test" in schema && min) {
638
+ return schema.test(
639
+ "custom-min",
640
+ {
641
+ ...translatedErrors.min,
642
+ values: {
643
+ min: attribute.min
644
+ }
645
+ },
646
+ (value) => {
647
+ if (!value) {
648
+ return true;
649
+ }
650
+ if (Array.isArray(value) && value.length === 0) {
651
+ return true;
652
+ }
653
+ return value.length >= min;
654
+ }
655
+ );
656
+ }
657
+ }
664
658
  if ("min" in schema && min) {
665
659
  return schema.min(min, {
666
660
  ...translatedErrors.min,
@@ -706,24 +700,6 @@ const addRegexValidation = (attribute) => (schema) => {
706
700
  }
707
701
  return schema;
708
702
  };
709
- const extractValuesFromYupError = (errorType, errorParams) => {
710
- if (!errorType || !errorParams) {
711
- return {};
712
- }
713
- return {
714
- [errorType]: errorParams[errorType]
715
- };
716
- };
717
- const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
718
- if (currentError.path) {
719
- acc[currentError.path.split("[").join(".").split("]").join("")] = {
720
- id: currentError.message,
721
- defaultMessage: currentError.message,
722
- values: extractValuesFromYupError(currentError?.type, currentError?.params)
723
- };
724
- }
725
- return acc;
726
- }, {});
727
703
  const initApi = contentManagerApi.injectEndpoints({
728
704
  endpoints: (builder) => ({
729
705
  getInitialData: builder.query({
@@ -737,27 +713,20 @@ const { useGetInitialDataQuery } = initApi;
737
713
  const useContentTypeSchema = (model) => {
738
714
  const { toggleNotification } = useNotification();
739
715
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
740
- const { components, contentType, contentTypes, error, isLoading, isFetching } = useGetInitialDataQuery(void 0, {
741
- selectFromResult: (res) => {
742
- const contentType2 = res.data?.contentTypes.find((ct) => ct.uid === model);
743
- const componentsByKey = res.data?.components.reduce(
744
- (acc, component) => {
745
- acc[component.uid] = component;
746
- return acc;
747
- },
748
- {}
749
- );
750
- const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
751
- return {
752
- isLoading: res.isLoading,
753
- isFetching: res.isFetching,
754
- error: res.error,
755
- components: Object.keys(components2).length === 0 ? void 0 : components2,
756
- contentType: contentType2,
757
- contentTypes: res.data?.contentTypes ?? []
758
- };
759
- }
760
- });
716
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
717
+ const { components, contentType, contentTypes } = React.useMemo(() => {
718
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
719
+ const componentsByKey = data?.components.reduce((acc, component) => {
720
+ acc[component.uid] = component;
721
+ return acc;
722
+ }, {});
723
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
724
+ return {
725
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
726
+ contentType: contentType2,
727
+ contentTypes: data?.contentTypes ?? []
728
+ };
729
+ }, [model, data]);
761
730
  React.useEffect(() => {
762
731
  if (error) {
763
732
  toggleNotification({
@@ -812,7 +781,10 @@ const useDocument = (args, opts) => {
812
781
  isLoading: isLoadingDocument,
813
782
  isFetching: isFetchingDocument,
814
783
  error
815
- } = useGetDocumentQuery(args, opts);
784
+ } = useGetDocumentQuery(args, {
785
+ ...opts,
786
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
787
+ });
816
788
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
817
789
  React.useEffect(() => {
818
790
  if (error) {
@@ -840,7 +812,7 @@ const useDocument = (args, opts) => {
840
812
  return null;
841
813
  } catch (error2) {
842
814
  if (error2 instanceof ValidationError) {
843
- return getInnerErrors(error2);
815
+ return getYupValidationErrors(error2);
844
816
  }
845
817
  throw error2;
846
818
  }
@@ -936,14 +908,53 @@ const useDocumentActions = () => {
936
908
  },
937
909
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
938
910
  );
911
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
912
+ const deleteMany = React.useCallback(
913
+ async ({ model, documentIds, params }) => {
914
+ try {
915
+ trackUsage("willBulkDeleteEntries");
916
+ const res = await deleteManyDocuments({
917
+ model,
918
+ documentIds,
919
+ params
920
+ });
921
+ if ("error" in res) {
922
+ toggleNotification({
923
+ type: "danger",
924
+ message: formatAPIError(res.error)
925
+ });
926
+ return { error: res.error };
927
+ }
928
+ toggleNotification({
929
+ type: "success",
930
+ title: formatMessage({
931
+ id: getTranslation("success.records.delete"),
932
+ defaultMessage: "Successfully deleted."
933
+ }),
934
+ message: ""
935
+ });
936
+ trackUsage("didBulkDeleteEntries");
937
+ return res.data;
938
+ } catch (err) {
939
+ toggleNotification({
940
+ type: "danger",
941
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
942
+ });
943
+ trackUsage("didNotBulkDeleteEntries");
944
+ throw err;
945
+ }
946
+ },
947
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
948
+ );
939
949
  const [discardDocument] = useDiscardDocumentMutation();
940
950
  const discard = React.useCallback(
941
- async ({ collectionType, model, documentId }) => {
951
+ async ({ collectionType, model, documentId, params }) => {
942
952
  try {
943
953
  const res = await discardDocument({
944
954
  collectionType,
945
955
  model,
946
- documentId
956
+ documentId,
957
+ params
947
958
  });
948
959
  if ("error" in res) {
949
960
  toggleNotification({
@@ -1005,6 +1016,43 @@ const useDocumentActions = () => {
1005
1016
  },
1006
1017
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1007
1018
  );
1019
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1020
+ const publishMany = React.useCallback(
1021
+ async ({ model, documentIds, params }) => {
1022
+ try {
1023
+ const res = await publishManyDocuments({
1024
+ model,
1025
+ documentIds,
1026
+ params
1027
+ });
1028
+ if ("error" in res) {
1029
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1030
+ return { error: res.error };
1031
+ }
1032
+ toggleNotification({
1033
+ type: "success",
1034
+ message: formatMessage({
1035
+ id: getTranslation("success.record.publish"),
1036
+ defaultMessage: "Published document"
1037
+ })
1038
+ });
1039
+ return res.data;
1040
+ } catch (err) {
1041
+ toggleNotification({
1042
+ type: "danger",
1043
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1044
+ });
1045
+ throw err;
1046
+ }
1047
+ },
1048
+ [
1049
+ // trackUsage,
1050
+ publishManyDocuments,
1051
+ toggleNotification,
1052
+ formatMessage,
1053
+ formatAPIError
1054
+ ]
1055
+ );
1008
1056
  const [updateDocument] = useUpdateDocumentMutation();
1009
1057
  const update = React.useCallback(
1010
1058
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1079,6 +1127,41 @@ const useDocumentActions = () => {
1079
1127
  },
1080
1128
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1081
1129
  );
1130
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1131
+ const unpublishMany = React.useCallback(
1132
+ async ({ model, documentIds, params }) => {
1133
+ try {
1134
+ trackUsage("willBulkUnpublishEntries");
1135
+ const res = await unpublishManyDocuments({
1136
+ model,
1137
+ documentIds,
1138
+ params
1139
+ });
1140
+ if ("error" in res) {
1141
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1142
+ return { error: res.error };
1143
+ }
1144
+ trackUsage("didBulkUnpublishEntries");
1145
+ toggleNotification({
1146
+ type: "success",
1147
+ title: formatMessage({
1148
+ id: getTranslation("success.records.unpublish"),
1149
+ defaultMessage: "Successfully unpublished."
1150
+ }),
1151
+ message: ""
1152
+ });
1153
+ return res.data;
1154
+ } catch (err) {
1155
+ toggleNotification({
1156
+ type: "danger",
1157
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1158
+ });
1159
+ trackUsage("didNotBulkUnpublishEntries");
1160
+ throw err;
1161
+ }
1162
+ },
1163
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1164
+ );
1082
1165
  const [createDocument] = useCreateDocumentMutation();
1083
1166
  const create = React.useCallback(
1084
1167
  async ({ model, params }, data, trackerProperty) => {
@@ -1122,7 +1205,6 @@ const useDocumentActions = () => {
1122
1205
  sourceId
1123
1206
  });
1124
1207
  if ("error" in res) {
1125
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1126
1208
  return { error: res.error };
1127
1209
  }
1128
1210
  toggleNotification({
@@ -1192,15 +1274,18 @@ const useDocumentActions = () => {
1192
1274
  clone,
1193
1275
  create,
1194
1276
  delete: _delete,
1277
+ deleteMany,
1195
1278
  discard,
1196
1279
  getDocument,
1197
1280
  publish,
1281
+ publishMany,
1198
1282
  unpublish,
1283
+ unpublishMany,
1199
1284
  update
1200
1285
  };
1201
1286
  };
1202
1287
  const ProtectedHistoryPage = lazy(
1203
- () => import("./History-D6sbCJvo.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1288
+ () => import("./History-DR2txJLE.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1204
1289
  );
1205
1290
  const routes$1 = [
1206
1291
  {
@@ -1213,31 +1298,31 @@ const routes$1 = [
1213
1298
  }
1214
1299
  ];
1215
1300
  const ProtectedEditViewPage = lazy(
1216
- () => import("./EditViewPage-Bm8lgcm6.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1301
+ () => import("./EditViewPage-B7VgwJaG.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1217
1302
  );
1218
1303
  const ProtectedListViewPage = lazy(
1219
- () => import("./ListViewPage-Be7S5aKL.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1304
+ () => import("./ListViewPage-B_GaWgRH.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1220
1305
  );
1221
1306
  const ProtectedListConfiguration = lazy(
1222
- () => import("./ListConfigurationPage-Ce4qs7qE.mjs").then((mod) => ({
1307
+ () => import("./ListConfigurationPage-voFVtXu6.mjs").then((mod) => ({
1223
1308
  default: mod.ProtectedListConfiguration
1224
1309
  }))
1225
1310
  );
1226
1311
  const ProtectedEditConfigurationPage = lazy(
1227
- () => import("./EditConfigurationPage-CUcGHHvQ.mjs").then((mod) => ({
1312
+ () => import("./EditConfigurationPage-D7PrLO8j.mjs").then((mod) => ({
1228
1313
  default: mod.ProtectedEditConfigurationPage
1229
1314
  }))
1230
1315
  );
1231
1316
  const ProtectedComponentConfigurationPage = lazy(
1232
- () => import("./ComponentConfigurationPage--2aLCv-G.mjs").then((mod) => ({
1317
+ () => import("./ComponentConfigurationPage-B3yDbeU1.mjs").then((mod) => ({
1233
1318
  default: mod.ProtectedComponentConfigurationPage
1234
1319
  }))
1235
1320
  );
1236
1321
  const NoPermissions = lazy(
1237
- () => import("./NoPermissionsPage-DhJ7LYrr.mjs").then((mod) => ({ default: mod.NoPermissions }))
1322
+ () => import("./NoPermissionsPage-B5baIHal.mjs").then((mod) => ({ default: mod.NoPermissions }))
1238
1323
  );
1239
1324
  const NoContentType = lazy(
1240
- () => import("./NoContentTypePage-CIPmYQMm.mjs").then((mod) => ({ default: mod.NoContentType }))
1325
+ () => import("./NoContentTypePage-CYiGpsbj.mjs").then((mod) => ({ default: mod.NoContentType }))
1241
1326
  );
1242
1327
  const CollectionTypePages = () => {
1243
1328
  const { collectionType } = useParams();
@@ -1351,12 +1436,14 @@ const DocumentActionButton = (action) => {
1351
1436
  /* @__PURE__ */ jsx(
1352
1437
  Button,
1353
1438
  {
1354
- flex: 1,
1439
+ flex: "auto",
1355
1440
  startIcon: action.icon,
1356
1441
  disabled: action.disabled,
1357
1442
  onClick: handleClick(action),
1358
1443
  justifyContent: "center",
1359
1444
  variant: action.variant || "default",
1445
+ paddingTop: "7px",
1446
+ paddingBottom: "7px",
1360
1447
  children: action.label
1361
1448
  }
1362
1449
  ),
@@ -1364,7 +1451,7 @@ const DocumentActionButton = (action) => {
1364
1451
  DocumentActionConfirmDialog,
1365
1452
  {
1366
1453
  ...action.dialog,
1367
- variant: action.variant,
1454
+ variant: action.dialog?.variant ?? action.variant,
1368
1455
  isOpen: dialogId === action.id,
1369
1456
  onClose: handleClose
1370
1457
  }
@@ -1416,18 +1503,18 @@ const DocumentActionsMenu = ({
1416
1503
  };
1417
1504
  return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
1418
1505
  /* @__PURE__ */ jsxs(
1419
- Menu.Trigger,
1506
+ StyledMoreButton,
1420
1507
  {
1421
1508
  disabled: isDisabled,
1422
1509
  size: "S",
1423
1510
  endIcon: null,
1424
- paddingTop: "7px",
1425
- paddingLeft: "9px",
1426
- paddingRight: "9px",
1511
+ paddingTop: "4px",
1512
+ paddingLeft: "7px",
1513
+ paddingRight: "7px",
1427
1514
  variant,
1428
1515
  children: [
1429
1516
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
1430
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: label || formatMessage({
1517
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
1431
1518
  id: "content-manager.containers.edit.panels.default.more-actions",
1432
1519
  defaultMessage: "More document actions"
1433
1520
  }) })
@@ -1443,10 +1530,25 @@ const DocumentActionsMenu = ({
1443
1530
  onSelect: handleClick(action),
1444
1531
  display: "block",
1445
1532
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1446
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, as: "span", children: [
1447
- action.icon,
1448
- action.label
1449
- ] }),
1533
+ /* @__PURE__ */ jsxs(
1534
+ Flex,
1535
+ {
1536
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1537
+ gap: 2,
1538
+ tag: "span",
1539
+ children: [
1540
+ /* @__PURE__ */ jsx(
1541
+ Flex,
1542
+ {
1543
+ tag: "span",
1544
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1545
+ children: action.icon
1546
+ }
1547
+ ),
1548
+ action.label
1549
+ ]
1550
+ }
1551
+ ),
1450
1552
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1451
1553
  Flex,
1452
1554
  {
@@ -1505,6 +1607,23 @@ const convertActionVariantToColor = (variant = "secondary") => {
1505
1607
  return "primary600";
1506
1608
  }
1507
1609
  };
1610
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1611
+ switch (variant) {
1612
+ case "danger":
1613
+ return "danger600";
1614
+ case "secondary":
1615
+ return "neutral500";
1616
+ case "success":
1617
+ return "success600";
1618
+ default:
1619
+ return "primary600";
1620
+ }
1621
+ };
1622
+ const StyledMoreButton = styled(Menu.Trigger)`
1623
+ & > span {
1624
+ display: flex;
1625
+ }
1626
+ `;
1508
1627
  const DocumentActionConfirmDialog = ({
1509
1628
  onClose,
1510
1629
  onCancel,
@@ -1527,61 +1646,42 @@ const DocumentActionConfirmDialog = ({
1527
1646
  }
1528
1647
  onClose();
1529
1648
  };
1530
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
1531
- /* @__PURE__ */ jsx(DialogBody, { children: content }),
1532
- /* @__PURE__ */ jsx(
1533
- DialogFooter,
1534
- {
1535
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1536
- id: "app.components.Button.cancel",
1537
- defaultMessage: "Cancel"
1538
- }) }),
1539
- endAction: /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1540
- id: "app.components.Button.confirm",
1541
- defaultMessage: "Confirm"
1542
- }) })
1543
- }
1544
- )
1545
- ] });
1649
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1650
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1651
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1652
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1653
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1654
+ id: "app.components.Button.cancel",
1655
+ defaultMessage: "Cancel"
1656
+ }) }) }),
1657
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1658
+ id: "app.components.Button.confirm",
1659
+ defaultMessage: "Confirm"
1660
+ }) })
1661
+ ] })
1662
+ ] }) });
1546
1663
  };
1547
1664
  const DocumentActionModal = ({
1548
1665
  isOpen,
1549
1666
  title,
1550
1667
  onClose,
1551
1668
  footer: Footer,
1552
- content,
1669
+ content: Content,
1553
1670
  onModalClose
1554
1671
  }) => {
1555
- const id = React.useId();
1556
- if (!isOpen) {
1557
- return null;
1558
- }
1559
1672
  const handleClose = () => {
1560
1673
  if (onClose) {
1561
1674
  onClose();
1562
1675
  }
1563
1676
  onModalClose();
1564
1677
  };
1565
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1566
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", as: "h2", id, children: title }) }),
1567
- /* @__PURE__ */ jsx(ModalBody, { children: content }),
1568
- /* @__PURE__ */ jsx(
1569
- Box,
1570
- {
1571
- paddingTop: 4,
1572
- paddingBottom: 4,
1573
- paddingLeft: 5,
1574
- paddingRight: 5,
1575
- borderWidth: "1px 0 0 0",
1576
- borderStyle: "solid",
1577
- borderColor: "neutral150",
1578
- background: "neutral100",
1579
- children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1580
- }
1581
- )
1582
- ] });
1678
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1679
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1680
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1681
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1682
+ ] }) });
1583
1683
  };
1584
- const PublishAction = ({
1684
+ const PublishAction$1 = ({
1585
1685
  activeTab,
1586
1686
  documentId,
1587
1687
  model,
@@ -1600,6 +1700,12 @@ const PublishAction = ({
1600
1700
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1601
1701
  );
1602
1702
  const { publish } = useDocumentActions();
1703
+ const [
1704
+ countDraftRelations,
1705
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1706
+ ] = useLazyGetDraftRelationCountQuery();
1707
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1708
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1603
1709
  const [{ query, rawQuery }] = useQueryParams();
1604
1710
  const params = React.useMemo(() => buildValidParams(query), [query]);
1605
1711
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1608,10 +1714,101 @@ const PublishAction = ({
1608
1714
  const validate = useForm("PublishAction", (state) => state.validate);
1609
1715
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1610
1716
  const formValues = useForm("PublishAction", ({ values }) => values);
1717
+ React.useEffect(() => {
1718
+ if (isErrorDraftRelations) {
1719
+ toggleNotification({
1720
+ type: "danger",
1721
+ message: formatMessage({
1722
+ id: getTranslation("error.records.fetch-draft-relatons"),
1723
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1724
+ })
1725
+ });
1726
+ }
1727
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1728
+ React.useEffect(() => {
1729
+ const localDraftRelations = /* @__PURE__ */ new Set();
1730
+ const extractDraftRelations = (data) => {
1731
+ const relations = data.connect || [];
1732
+ relations.forEach((relation) => {
1733
+ if (relation.status === "draft") {
1734
+ localDraftRelations.add(relation.id);
1735
+ }
1736
+ });
1737
+ };
1738
+ const traverseAndExtract = (data) => {
1739
+ Object.entries(data).forEach(([key, value]) => {
1740
+ if (key === "connect" && Array.isArray(value)) {
1741
+ extractDraftRelations({ connect: value });
1742
+ } else if (typeof value === "object" && value !== null) {
1743
+ traverseAndExtract(value);
1744
+ }
1745
+ });
1746
+ };
1747
+ if (!documentId || modified) {
1748
+ traverseAndExtract(formValues);
1749
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1750
+ }
1751
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1752
+ React.useEffect(() => {
1753
+ if (documentId) {
1754
+ const fetchDraftRelationsCount = async () => {
1755
+ const { data, error } = await countDraftRelations({
1756
+ collectionType,
1757
+ model,
1758
+ documentId,
1759
+ params
1760
+ });
1761
+ if (error) {
1762
+ throw error;
1763
+ }
1764
+ if (data) {
1765
+ setServerCountOfDraftRelations(data.data);
1766
+ }
1767
+ };
1768
+ fetchDraftRelationsCount();
1769
+ }
1770
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1611
1771
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1612
1772
  if (!schema?.options?.draftAndPublish) {
1613
1773
  return null;
1614
1774
  }
1775
+ const performPublish = async () => {
1776
+ setSubmitting(true);
1777
+ try {
1778
+ const { errors } = await validate();
1779
+ if (errors) {
1780
+ toggleNotification({
1781
+ type: "danger",
1782
+ message: formatMessage({
1783
+ id: "content-manager.validation.error",
1784
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1785
+ })
1786
+ });
1787
+ return;
1788
+ }
1789
+ const res = await publish(
1790
+ {
1791
+ collectionType,
1792
+ model,
1793
+ documentId,
1794
+ params
1795
+ },
1796
+ formValues
1797
+ );
1798
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1799
+ navigate({
1800
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1801
+ search: rawQuery
1802
+ });
1803
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1804
+ setErrors(formatValidationErrors(res.error));
1805
+ }
1806
+ } finally {
1807
+ setSubmitting(false);
1808
+ }
1809
+ };
1810
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1811
+ const hasDraftRelations = totalDraftRelations > 0;
1615
1812
  return {
1616
1813
  /**
1617
1814
  * Disabled when:
@@ -1621,52 +1818,42 @@ const PublishAction = ({
1621
1818
  * - the document is already published & not modified
1622
1819
  * - the document is being created & not modified
1623
1820
  * - the user doesn't have the permission to publish
1624
- * - the user doesn't have the permission to create a new document
1625
- * - the user doesn't have the permission to update the document
1626
1821
  */
1627
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1822
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1628
1823
  label: formatMessage({
1629
1824
  id: "app.utils.publish",
1630
1825
  defaultMessage: "Publish"
1631
1826
  }),
1632
1827
  onClick: async () => {
1633
- setSubmitting(true);
1634
- try {
1635
- const { errors } = await validate();
1636
- if (errors) {
1637
- toggleNotification({
1638
- type: "danger",
1639
- message: formatMessage({
1640
- id: "content-manager.validation.error",
1641
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1642
- })
1643
- });
1644
- return;
1645
- }
1646
- const res = await publish(
1647
- {
1648
- collectionType,
1649
- model,
1650
- documentId,
1651
- params
1652
- },
1653
- formValues
1654
- );
1655
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1656
- navigate({
1657
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1658
- search: rawQuery
1659
- });
1660
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1661
- setErrors(formatValidationErrors(res.error));
1828
+ if (hasDraftRelations) {
1829
+ return;
1830
+ }
1831
+ await performPublish();
1832
+ },
1833
+ dialog: hasDraftRelations ? {
1834
+ type: "dialog",
1835
+ variant: "danger",
1836
+ footer: null,
1837
+ title: formatMessage({
1838
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1839
+ defaultMessage: "Confirmation"
1840
+ }),
1841
+ content: formatMessage(
1842
+ {
1843
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1844
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1845
+ },
1846
+ {
1847
+ count: totalDraftRelations
1662
1848
  }
1663
- } finally {
1664
- setSubmitting(false);
1849
+ ),
1850
+ onConfirm: async () => {
1851
+ await performPublish();
1665
1852
  }
1666
- }
1853
+ } : void 0
1667
1854
  };
1668
1855
  };
1669
- PublishAction.type = "publish";
1856
+ PublishAction$1.type = "publish";
1670
1857
  const UpdateAction = ({
1671
1858
  activeTab,
1672
1859
  documentId,
@@ -1679,7 +1866,7 @@ const UpdateAction = ({
1679
1866
  const cloneMatch = useMatch(CLONE_PATH);
1680
1867
  const isCloning = cloneMatch !== null;
1681
1868
  const { formatMessage } = useIntl();
1682
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1869
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1683
1870
  canCreate: canCreate2,
1684
1871
  canUpdate: canUpdate2
1685
1872
  }));
@@ -1699,10 +1886,8 @@ const UpdateAction = ({
1699
1886
  * - the form is submitting
1700
1887
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1701
1888
  * - the active tab is the published tab
1702
- * - the user doesn't have the permission to create a new document
1703
- * - the user doesn't have the permission to update the document
1704
1889
  */
1705
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1890
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1706
1891
  label: formatMessage({
1707
1892
  id: "content-manager.containers.Edit.save",
1708
1893
  defaultMessage: "Save"
@@ -1731,10 +1916,13 @@ const UpdateAction = ({
1731
1916
  document
1732
1917
  );
1733
1918
  if ("data" in res) {
1734
- navigate({
1735
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1736
- search: rawQuery
1737
- });
1919
+ navigate(
1920
+ {
1921
+ pathname: `../${res.data.documentId}`,
1922
+ search: rawQuery
1923
+ },
1924
+ { relative: "path" }
1925
+ );
1738
1926
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1739
1927
  setErrors(formatValidationErrors(res.error));
1740
1928
  }
@@ -1762,10 +1950,13 @@ const UpdateAction = ({
1762
1950
  document
1763
1951
  );
1764
1952
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1765
- navigate({
1766
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1767
- search: rawQuery
1768
- });
1953
+ navigate(
1954
+ {
1955
+ pathname: `../${res.data.documentId}`,
1956
+ search: rawQuery
1957
+ },
1958
+ { replace: true, relative: "path" }
1959
+ );
1769
1960
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1770
1961
  setErrors(formatValidationErrors(res.error));
1771
1962
  }
@@ -1781,7 +1972,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1781
1972
  KEEP: "keep",
1782
1973
  DISCARD: "discard"
1783
1974
  };
1784
- const UnpublishAction = ({
1975
+ const UnpublishAction$1 = ({
1785
1976
  activeTab,
1786
1977
  documentId,
1787
1978
  model,
@@ -1797,10 +1988,8 @@ const UnpublishAction = ({
1797
1988
  const { toggleNotification } = useNotification();
1798
1989
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1799
1990
  const isDocumentModified = document?.status === "modified";
1800
- const handleChange = (e) => {
1801
- if ("value" in e.target) {
1802
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1803
- }
1991
+ const handleChange = (value) => {
1992
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1804
1993
  };
1805
1994
  if (!schema?.options?.draftAndPublish) {
1806
1995
  return null;
@@ -1844,45 +2033,30 @@ const UnpublishAction = ({
1844
2033
  content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1845
2034
  /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
1846
2035
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1847
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2036
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1848
2037
  id: "content-manager.actions.unpublish.dialog.body",
1849
2038
  defaultMessage: "Are you sure?"
1850
2039
  }) })
1851
2040
  ] }),
1852
2041
  /* @__PURE__ */ jsxs(
1853
- Flex,
2042
+ Radio.Group,
1854
2043
  {
1855
- onChange: handleChange,
1856
- direction: "column",
1857
- alignItems: "flex-start",
1858
- as: "fieldset",
1859
- gap: 3,
2044
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2045
+ name: "discard-options",
2046
+ "aria-label": formatMessage({
2047
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2048
+ defaultMessage: "Choose an option to unpublish the document."
2049
+ }),
2050
+ onValueChange: handleChange,
1860
2051
  children: [
1861
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "legend" }),
1862
- /* @__PURE__ */ jsx(
1863
- Radio,
1864
- {
1865
- checked: shouldKeepDraft,
1866
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1867
- name: "discard-options",
1868
- children: formatMessage({
1869
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1870
- defaultMessage: "Keep draft"
1871
- })
1872
- }
1873
- ),
1874
- /* @__PURE__ */ jsx(
1875
- Radio,
1876
- {
1877
- checked: !shouldKeepDraft,
1878
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1879
- name: "discard-options",
1880
- children: formatMessage({
1881
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1882
- defaultMessage: "Replace draft"
1883
- })
1884
- }
1885
- )
2052
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2053
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2054
+ defaultMessage: "Keep draft"
2055
+ }) }),
2056
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2057
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2058
+ defaultMessage: "Replace draft"
2059
+ }) })
1886
2060
  ]
1887
2061
  }
1888
2062
  )
@@ -1915,7 +2089,7 @@ const UnpublishAction = ({
1915
2089
  position: ["panel", "table-row"]
1916
2090
  };
1917
2091
  };
1918
- UnpublishAction.type = "unpublish";
2092
+ UnpublishAction$1.type = "unpublish";
1919
2093
  const DiscardAction = ({
1920
2094
  activeTab,
1921
2095
  documentId,
@@ -1949,7 +2123,7 @@ const DiscardAction = ({
1949
2123
  }),
1950
2124
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
1951
2125
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1952
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2126
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1953
2127
  id: "content-manager.actions.discard.dialog.body",
1954
2128
  defaultMessage: "Are you sure?"
1955
2129
  }) })
@@ -1971,7 +2145,7 @@ const StyledCrossCircle = styled(CrossCircle)`
1971
2145
  fill: currentColor;
1972
2146
  }
1973
2147
  `;
1974
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2148
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1975
2149
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1976
2150
  const RelativeTime = React.forwardRef(
1977
2151
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2019,7 +2193,7 @@ const getDisplayName = ({
2019
2193
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2020
2194
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2021
2195
  const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2022
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { as: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2196
+ return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2023
2197
  };
2024
2198
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2025
2199
  const { formatMessage } = useIntl();
@@ -2028,23 +2202,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2028
2202
  id: "content-manager.containers.edit.title.new",
2029
2203
  defaultMessage: "Create an entry"
2030
2204
  }) : documentTitle;
2031
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2205
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2032
2206
  /* @__PURE__ */ jsx(BackButton, {}),
2033
- /* @__PURE__ */ jsxs(
2034
- Flex,
2035
- {
2036
- width: "100%",
2037
- justifyContent: "space-between",
2038
- paddingTop: 1,
2039
- gap: "80px",
2040
- alignItems: "flex-start",
2041
- children: [
2042
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", as: "h1", children: title }),
2043
- /* @__PURE__ */ jsx(HeaderToolbar, {})
2044
- ]
2045
- }
2046
- ),
2047
- status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2207
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2208
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2209
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2210
+ ] }),
2211
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2048
2212
  ] });
2049
2213
  };
2050
2214
  const HeaderToolbar = () => {
@@ -2196,7 +2360,7 @@ const Information = ({ activeTab }) => {
2196
2360
  borderColor: "neutral150",
2197
2361
  direction: "column",
2198
2362
  marginTop: 2,
2199
- as: "dl",
2363
+ tag: "dl",
2200
2364
  padding: 5,
2201
2365
  gap: 3,
2202
2366
  alignItems: "flex-start",
@@ -2204,8 +2368,8 @@ const Information = ({ activeTab }) => {
2204
2368
  marginRight: "-0.4rem",
2205
2369
  width: "calc(100% + 8px)",
2206
2370
  children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2207
- /* @__PURE__ */ jsx(Typography, { as: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2208
- /* @__PURE__ */ jsx(Typography, { as: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2371
+ /* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2372
+ /* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2209
2373
  ] }, info.label))
2210
2374
  }
2211
2375
  );
@@ -2238,7 +2402,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2238
2402
  id: "app.links.configure-view",
2239
2403
  defaultMessage: "Configure the view"
2240
2404
  }),
2241
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2405
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2242
2406
  onClick: () => {
2243
2407
  navigate(`../${collectionType}/${model}/configurations/edit`);
2244
2408
  },
@@ -2246,11 +2410,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2246
2410
  };
2247
2411
  };
2248
2412
  ConfigureTheViewAction.type = "configure-the-view";
2249
- const StyledCog = styled(Cog)`
2250
- path {
2251
- fill: currentColor;
2252
- }
2253
- `;
2254
2413
  const EditTheModelAction = ({ model }) => {
2255
2414
  const navigate = useNavigate();
2256
2415
  const { formatMessage } = useIntl();
@@ -2259,7 +2418,7 @@ const EditTheModelAction = ({ model }) => {
2259
2418
  id: "content-manager.link-to-ctb",
2260
2419
  defaultMessage: "Edit the model"
2261
2420
  }),
2262
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2421
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2263
2422
  onClick: () => {
2264
2423
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2265
2424
  },
@@ -2267,12 +2426,7 @@ const EditTheModelAction = ({ model }) => {
2267
2426
  };
2268
2427
  };
2269
2428
  EditTheModelAction.type = "edit-the-model";
2270
- const StyledPencil$1 = styled(Pencil)`
2271
- path {
2272
- fill: currentColor;
2273
- }
2274
- `;
2275
- const DeleteAction = ({ documentId, model, collectionType, document }) => {
2429
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2276
2430
  const navigate = useNavigate();
2277
2431
  const { formatMessage } = useIntl();
2278
2432
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2286,7 +2440,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2286
2440
  id: "content-manager.actions.delete.label",
2287
2441
  defaultMessage: "Delete document"
2288
2442
  }),
2289
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2443
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2290
2444
  dialog: {
2291
2445
  type: "dialog",
2292
2446
  title: formatMessage({
@@ -2295,7 +2449,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2295
2449
  }),
2296
2450
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2297
2451
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2298
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2452
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2299
2453
  id: "content-manager.actions.delete.dialog.body",
2300
2454
  defaultMessage: "Are you sure?"
2301
2455
  }) })
@@ -2340,13 +2494,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2340
2494
  position: ["header", "table-row"]
2341
2495
  };
2342
2496
  };
2343
- DeleteAction.type = "delete";
2344
- const StyledTrash = styled(Trash)`
2345
- path {
2346
- fill: currentColor;
2347
- }
2348
- `;
2349
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2497
+ DeleteAction$1.type = "delete";
2498
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2350
2499
  const Panels = () => {
2351
2500
  const isCloning = useMatch(CLONE_PATH) !== null;
2352
2501
  const [
@@ -2420,7 +2569,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2420
2569
  Flex,
2421
2570
  {
2422
2571
  ref,
2423
- as: "aside",
2572
+ tag: "aside",
2424
2573
  "aria-labelledby": "additional-information",
2425
2574
  background: "neutral0",
2426
2575
  borderColor: "neutral150",
@@ -2435,116 +2584,995 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2435
2584
  justifyContent: "stretch",
2436
2585
  alignItems: "flex-start",
2437
2586
  children: [
2438
- /* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2587
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2439
2588
  children
2440
2589
  ]
2441
2590
  }
2442
2591
  );
2443
2592
  });
2444
- const DEFAULT_BULK_ACTIONS = [];
2445
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2446
- const { formatMessage } = useIntl();
2447
- const getDefaultErrorMessage = (reason) => {
2448
- switch (reason) {
2449
- case "relation":
2450
- return "Duplicating the relation could remove it from the original entry.";
2451
- case "unique":
2452
- return "Identical values in a unique field are not allowed";
2453
- default:
2454
- return reason;
2455
- }
2456
- };
2457
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2458
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
2459
- id: getTranslation("containers.list.autoCloneModal.title"),
2460
- defaultMessage: "This entry can't be duplicated directly."
2461
- }) }),
2462
- /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
2463
- id: getTranslation("containers.list.autoCloneModal.description"),
2464
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2465
- }) }) }),
2466
- /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
2467
- Flex,
2468
- {
2469
- direction: "column",
2470
- gap: 2,
2471
- alignItems: "flex-start",
2472
- borderColor: "neutral200",
2473
- hasRadius: true,
2474
- padding: 6,
2475
- children: [
2476
- /* @__PURE__ */ jsx(Flex, { direction: "row", as: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", as: "li", children: [
2477
- pathSegment,
2478
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
2479
- ChevronRight,
2480
- {
2481
- fill: "neutral500",
2482
- height: "0.8rem",
2483
- width: "0.8rem",
2484
- style: { margin: "0 0.8rem" }
2485
- }
2486
- )
2487
- ] }, index2)) }),
2488
- /* @__PURE__ */ jsx(Typography, { as: "p", textColor: "neutral600", children: formatMessage({
2489
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2490
- defaultMessage: getDefaultErrorMessage(reason)
2491
- }) })
2492
- ]
2493
- },
2494
- fieldPath.join()
2495
- )) })
2496
- ] });
2497
- };
2498
- const TableActions = ({ document }) => {
2499
- const { formatMessage } = useIntl();
2500
- const { model, collectionType } = useDoc();
2501
- const plugins = useStrapiApp("TableActions", (state) => state.plugins);
2502
- const props = {
2503
- activeTab: null,
2504
- model,
2505
- documentId: document.documentId,
2506
- collectionType,
2507
- document
2508
- };
2509
- return /* @__PURE__ */ jsx(
2510
- DescriptionComponentRenderer,
2511
- {
2512
- props,
2513
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2514
- children: (actions2) => {
2515
- const tableRowActions = actions2.filter((action) => {
2516
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2517
- return positions.includes("table-row");
2518
- });
2519
- return /* @__PURE__ */ jsx(
2520
- DocumentActionsMenu,
2521
- {
2522
- actions: tableRowActions,
2523
- label: formatMessage({
2524
- id: "content-manager.containers.list.table.row-actions",
2525
- defaultMessage: "Row action"
2526
- }),
2527
- variant: "ghost"
2528
- }
2529
- );
2530
- }
2531
- }
2532
- );
2593
+ const HOOKS = {
2594
+ /**
2595
+ * Hook that allows to mutate the displayed headers of the list view table
2596
+ * @constant
2597
+ * @type {string}
2598
+ */
2599
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2600
+ /**
2601
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2602
+ * @constant
2603
+ * @type {string}
2604
+ */
2605
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2606
+ /**
2607
+ * Hook that allows to mutate the CM's edit view layout
2608
+ * @constant
2609
+ * @type {string}
2610
+ */
2611
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2612
+ /**
2613
+ * Hook that allows to mutate the CM's single types links pre-set filters
2614
+ * @constant
2615
+ * @type {string}
2616
+ */
2617
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2533
2618
  };
2534
- const EditAction = ({ documentId }) => {
2535
- const navigate = useNavigate();
2536
- const { formatMessage } = useIntl();
2537
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2538
- const { toggleNotification } = useNotification();
2539
- const [{ query }] = useQueryParams();
2540
- return {
2541
- disabled: !canRead,
2542
- icon: /* @__PURE__ */ jsx(StyledPencil, {}),
2543
- label: formatMessage({
2544
- id: "content-manager.actions.edit.label",
2545
- defaultMessage: "Edit"
2619
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2620
+ endpoints: (builder) => ({
2621
+ getContentTypeConfiguration: builder.query({
2622
+ query: (uid) => ({
2623
+ url: `/content-manager/content-types/${uid}/configuration`,
2624
+ method: "GET"
2625
+ }),
2626
+ transformResponse: (response) => response.data,
2627
+ providesTags: (_result, _error, uid) => [
2628
+ { type: "ContentTypesConfiguration", id: uid },
2629
+ { type: "ContentTypeSettings", id: "LIST" }
2630
+ ]
2546
2631
  }),
2547
- position: "table-row",
2632
+ getAllContentTypeSettings: builder.query({
2633
+ query: () => "/content-manager/content-types-settings",
2634
+ transformResponse: (response) => response.data,
2635
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2636
+ }),
2637
+ updateContentTypeConfiguration: builder.mutation({
2638
+ query: ({ uid, ...body }) => ({
2639
+ url: `/content-manager/content-types/${uid}/configuration`,
2640
+ method: "PUT",
2641
+ data: body
2642
+ }),
2643
+ transformResponse: (response) => response.data,
2644
+ invalidatesTags: (_result, _error, { uid }) => [
2645
+ { type: "ContentTypesConfiguration", id: uid },
2646
+ { type: "ContentTypeSettings", id: "LIST" },
2647
+ // Is this necessary?
2648
+ { type: "InitialData" }
2649
+ ]
2650
+ })
2651
+ })
2652
+ });
2653
+ const {
2654
+ useGetContentTypeConfigurationQuery,
2655
+ useGetAllContentTypeSettingsQuery,
2656
+ useUpdateContentTypeConfigurationMutation
2657
+ } = contentTypesApi;
2658
+ const checkIfAttributeIsDisplayable = (attribute) => {
2659
+ const { type } = attribute;
2660
+ if (type === "relation") {
2661
+ return !attribute.relation.toLowerCase().includes("morph");
2662
+ }
2663
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2664
+ };
2665
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2666
+ if (!mainFieldName) {
2667
+ return void 0;
2668
+ }
2669
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2670
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2671
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2672
+ );
2673
+ return {
2674
+ name: mainFieldName,
2675
+ type: mainFieldType ?? "string"
2676
+ };
2677
+ };
2678
+ const DEFAULT_SETTINGS = {
2679
+ bulkable: false,
2680
+ filterable: false,
2681
+ searchable: false,
2682
+ pagination: false,
2683
+ defaultSortBy: "",
2684
+ defaultSortOrder: "asc",
2685
+ mainField: "id",
2686
+ pageSize: 10
2687
+ };
2688
+ const useDocumentLayout = (model) => {
2689
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2690
+ const [{ query }] = useQueryParams();
2691
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2692
+ const { toggleNotification } = useNotification();
2693
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2694
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2695
+ const {
2696
+ data,
2697
+ isLoading: isLoadingConfigs,
2698
+ error,
2699
+ isFetching: isFetchingConfigs
2700
+ } = useGetContentTypeConfigurationQuery(model);
2701
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2702
+ React.useEffect(() => {
2703
+ if (error) {
2704
+ toggleNotification({
2705
+ type: "danger",
2706
+ message: formatAPIError(error)
2707
+ });
2708
+ }
2709
+ }, [error, formatAPIError, toggleNotification]);
2710
+ const editLayout = React.useMemo(
2711
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2712
+ layout: [],
2713
+ components: {},
2714
+ metadatas: {},
2715
+ options: {},
2716
+ settings: DEFAULT_SETTINGS
2717
+ },
2718
+ [data, isLoading, schemas, schema, components]
2719
+ );
2720
+ const listLayout = React.useMemo(() => {
2721
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2722
+ layout: [],
2723
+ metadatas: {},
2724
+ options: {},
2725
+ settings: DEFAULT_SETTINGS
2726
+ };
2727
+ }, [data, isLoading, schemas, schema, components]);
2728
+ const { layout: edit } = React.useMemo(
2729
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2730
+ layout: editLayout,
2731
+ query
2732
+ }),
2733
+ [editLayout, query, runHookWaterfall]
2734
+ );
2735
+ return {
2736
+ error,
2737
+ isLoading,
2738
+ edit,
2739
+ list: listLayout
2740
+ };
2741
+ };
2742
+ const useDocLayout = () => {
2743
+ const { model } = useDoc();
2744
+ return useDocumentLayout(model);
2745
+ };
2746
+ const formatEditLayout = (data, {
2747
+ schemas,
2748
+ schema,
2749
+ components
2750
+ }) => {
2751
+ let currentPanelIndex = 0;
2752
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2753
+ data.contentType.layouts.edit,
2754
+ schema?.attributes,
2755
+ data.contentType.metadatas,
2756
+ { configurations: data.components, schemas: components },
2757
+ schemas
2758
+ ).reduce((panels, row) => {
2759
+ if (row.some((field) => field.type === "dynamiczone")) {
2760
+ panels.push([row]);
2761
+ currentPanelIndex += 2;
2762
+ } else {
2763
+ if (!panels[currentPanelIndex]) {
2764
+ panels.push([]);
2765
+ }
2766
+ panels[currentPanelIndex].push(row);
2767
+ }
2768
+ return panels;
2769
+ }, []);
2770
+ const componentEditAttributes = Object.entries(data.components).reduce(
2771
+ (acc, [uid, configuration]) => {
2772
+ acc[uid] = {
2773
+ layout: convertEditLayoutToFieldLayouts(
2774
+ configuration.layouts.edit,
2775
+ components[uid].attributes,
2776
+ configuration.metadatas
2777
+ ),
2778
+ settings: {
2779
+ ...configuration.settings,
2780
+ icon: components[uid].info.icon,
2781
+ displayName: components[uid].info.displayName
2782
+ }
2783
+ };
2784
+ return acc;
2785
+ },
2786
+ {}
2787
+ );
2788
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2789
+ (acc, [attribute, metadata]) => {
2790
+ return {
2791
+ ...acc,
2792
+ [attribute]: metadata.edit
2793
+ };
2794
+ },
2795
+ {}
2796
+ );
2797
+ return {
2798
+ layout: panelledEditAttributes,
2799
+ components: componentEditAttributes,
2800
+ metadatas: editMetadatas,
2801
+ settings: {
2802
+ ...data.contentType.settings,
2803
+ displayName: schema?.info.displayName
2804
+ },
2805
+ options: {
2806
+ ...schema?.options,
2807
+ ...schema?.pluginOptions,
2808
+ ...data.contentType.options
2809
+ }
2810
+ };
2811
+ };
2812
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2813
+ return rows.map(
2814
+ (row) => row.map((field) => {
2815
+ const attribute = attributes[field.name];
2816
+ if (!attribute) {
2817
+ return null;
2818
+ }
2819
+ const { edit: metadata } = metadatas[field.name];
2820
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2821
+ return {
2822
+ attribute,
2823
+ disabled: !metadata.editable,
2824
+ hint: metadata.description,
2825
+ label: metadata.label ?? "",
2826
+ name: field.name,
2827
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2828
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2829
+ schemas,
2830
+ components: components?.schemas ?? {}
2831
+ }),
2832
+ placeholder: metadata.placeholder ?? "",
2833
+ required: attribute.required ?? false,
2834
+ size: field.size,
2835
+ unique: "unique" in attribute ? attribute.unique : false,
2836
+ visible: metadata.visible ?? true,
2837
+ type: attribute.type
2838
+ };
2839
+ }).filter((field) => field !== null)
2840
+ );
2841
+ };
2842
+ const formatListLayout = (data, {
2843
+ schemas,
2844
+ schema,
2845
+ components
2846
+ }) => {
2847
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2848
+ (acc, [attribute, metadata]) => {
2849
+ return {
2850
+ ...acc,
2851
+ [attribute]: metadata.list
2852
+ };
2853
+ },
2854
+ {}
2855
+ );
2856
+ const listAttributes = convertListLayoutToFieldLayouts(
2857
+ data.contentType.layouts.list,
2858
+ schema?.attributes,
2859
+ listMetadatas,
2860
+ { configurations: data.components, schemas: components },
2861
+ schemas
2862
+ );
2863
+ return {
2864
+ layout: listAttributes,
2865
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2866
+ metadatas: listMetadatas,
2867
+ options: {
2868
+ ...schema?.options,
2869
+ ...schema?.pluginOptions,
2870
+ ...data.contentType.options
2871
+ }
2872
+ };
2873
+ };
2874
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2875
+ return columns.map((name) => {
2876
+ const attribute = attributes[name];
2877
+ if (!attribute) {
2878
+ return null;
2879
+ }
2880
+ const metadata = metadatas[name];
2881
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2882
+ return {
2883
+ attribute,
2884
+ label: metadata.label ?? "",
2885
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2886
+ schemas,
2887
+ components: components?.schemas ?? {}
2888
+ }),
2889
+ name,
2890
+ searchable: metadata.searchable ?? true,
2891
+ sortable: metadata.sortable ?? true
2892
+ };
2893
+ }).filter((field) => field !== null);
2894
+ };
2895
+ const ConfirmBulkActionDialog = ({
2896
+ onToggleDialog,
2897
+ isOpen = false,
2898
+ dialogBody,
2899
+ endAction
2900
+ }) => {
2901
+ const { formatMessage } = useIntl();
2902
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2903
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2904
+ id: "app.components.ConfirmDialog.title",
2905
+ defaultMessage: "Confirmation"
2906
+ }) }),
2907
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2908
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2909
+ dialogBody
2910
+ ] }) }),
2911
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2912
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2913
+ id: "app.components.Button.cancel",
2914
+ defaultMessage: "Cancel"
2915
+ }) }) }),
2916
+ endAction
2917
+ ] })
2918
+ ] }) });
2919
+ };
2920
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2921
+ const ConfirmDialogPublishAll = ({
2922
+ isOpen,
2923
+ onToggleDialog,
2924
+ isConfirmButtonLoading = false,
2925
+ onConfirm
2926
+ }) => {
2927
+ const { formatMessage } = useIntl();
2928
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2929
+ const { toggleNotification } = useNotification();
2930
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2931
+ const { model, schema } = useDoc();
2932
+ const [{ query }] = useQueryParams();
2933
+ const {
2934
+ data: countDraftRelations = 0,
2935
+ isLoading,
2936
+ error
2937
+ } = useGetManyDraftRelationCountQuery(
2938
+ {
2939
+ model,
2940
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2941
+ locale: query?.plugins?.i18n?.locale
2942
+ },
2943
+ {
2944
+ skip: selectedEntries.length === 0
2945
+ }
2946
+ );
2947
+ React.useEffect(() => {
2948
+ if (error) {
2949
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2950
+ }
2951
+ }, [error, formatAPIError, toggleNotification]);
2952
+ if (error) {
2953
+ return null;
2954
+ }
2955
+ return /* @__PURE__ */ jsx(
2956
+ ConfirmBulkActionDialog,
2957
+ {
2958
+ isOpen: isOpen && !isLoading,
2959
+ onToggleDialog,
2960
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2961
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2962
+ countDraftRelations > 0 && formatMessage(
2963
+ {
2964
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2965
+ 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. "
2966
+ },
2967
+ {
2968
+ b: BoldChunk$1,
2969
+ count: countDraftRelations,
2970
+ entities: selectedEntries.length
2971
+ }
2972
+ ),
2973
+ formatMessage({
2974
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2975
+ defaultMessage: "Are you sure you want to publish these entries?"
2976
+ })
2977
+ ] }),
2978
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2979
+ {
2980
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2981
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2982
+ },
2983
+ {
2984
+ em: Emphasis
2985
+ }
2986
+ ) })
2987
+ ] }),
2988
+ endAction: /* @__PURE__ */ jsx(
2989
+ Button,
2990
+ {
2991
+ onClick: onConfirm,
2992
+ variant: "secondary",
2993
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2994
+ loading: isConfirmButtonLoading,
2995
+ children: formatMessage({
2996
+ id: "app.utils.publish",
2997
+ defaultMessage: "Publish"
2998
+ })
2999
+ }
3000
+ )
3001
+ }
3002
+ );
3003
+ };
3004
+ const TypographyMaxWidth = styled(Typography)`
3005
+ max-width: 300px;
3006
+ `;
3007
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3008
+ const messages = [];
3009
+ Object.entries(errors).forEach(([key, value]) => {
3010
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3011
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3012
+ if ("id" in value && "defaultMessage" in value) {
3013
+ messages.push(
3014
+ formatMessage(
3015
+ {
3016
+ id: `${value.id}.withField`,
3017
+ defaultMessage: value.defaultMessage
3018
+ },
3019
+ { field: currentKey }
3020
+ )
3021
+ );
3022
+ } else {
3023
+ messages.push(
3024
+ ...formatErrorMessages(
3025
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3026
+ value,
3027
+ currentKey,
3028
+ formatMessage
3029
+ )
3030
+ );
3031
+ }
3032
+ } else {
3033
+ messages.push(
3034
+ formatMessage(
3035
+ {
3036
+ id: `${value}.withField`,
3037
+ defaultMessage: value
3038
+ },
3039
+ { field: currentKey }
3040
+ )
3041
+ );
3042
+ }
3043
+ });
3044
+ return messages;
3045
+ };
3046
+ const EntryValidationText = ({ validationErrors, status }) => {
3047
+ const { formatMessage } = useIntl();
3048
+ if (validationErrors) {
3049
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3050
+ " "
3051
+ );
3052
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3053
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3054
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3055
+ ] });
3056
+ }
3057
+ if (status === "published") {
3058
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3059
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3060
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3061
+ id: "content-manager.bulk-publish.already-published",
3062
+ defaultMessage: "Already Published"
3063
+ }) })
3064
+ ] });
3065
+ }
3066
+ if (status === "modified") {
3067
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3068
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3069
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3070
+ id: "content-manager.bulk-publish.modified",
3071
+ defaultMessage: "Ready to publish changes"
3072
+ }) })
3073
+ ] });
3074
+ }
3075
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3076
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3077
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3078
+ id: "app.utils.ready-to-publish",
3079
+ defaultMessage: "Ready to publish"
3080
+ }) })
3081
+ ] });
3082
+ };
3083
+ const TABLE_HEADERS = [
3084
+ { name: "id", label: "id" },
3085
+ { name: "name", label: "name" },
3086
+ { name: "status", label: "status" },
3087
+ { name: "publicationStatus", label: "Publication status" }
3088
+ ];
3089
+ const SelectedEntriesTableContent = ({
3090
+ isPublishing,
3091
+ rowsToDisplay = [],
3092
+ entriesToPublish = [],
3093
+ validationErrors = {}
3094
+ }) => {
3095
+ const { pathname } = useLocation();
3096
+ const { formatMessage } = useIntl();
3097
+ const {
3098
+ list: {
3099
+ settings: { mainField }
3100
+ }
3101
+ } = useDocLayout();
3102
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3103
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3104
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3105
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3106
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3107
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3108
+ )
3109
+ ] }),
3110
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3111
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3112
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3113
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3114
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3115
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3116
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3117
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3118
+ id: "content-manager.success.record.publishing",
3119
+ defaultMessage: "Publishing..."
3120
+ }) }),
3121
+ /* @__PURE__ */ jsx(Loader, { small: true })
3122
+ ] }) : /* @__PURE__ */ jsx(
3123
+ EntryValidationText,
3124
+ {
3125
+ validationErrors: validationErrors[row.documentId],
3126
+ status: row.status
3127
+ }
3128
+ ) }),
3129
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3130
+ IconButton,
3131
+ {
3132
+ tag: Link,
3133
+ to: {
3134
+ pathname: `${pathname}/${row.documentId}`,
3135
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3136
+ },
3137
+ state: { from: pathname },
3138
+ label: formatMessage(
3139
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3140
+ {
3141
+ target: formatMessage(
3142
+ {
3143
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3144
+ defaultMessage: "item line {number}"
3145
+ },
3146
+ { number: index2 + 1 }
3147
+ )
3148
+ }
3149
+ ),
3150
+ target: "_blank",
3151
+ marginLeft: "auto",
3152
+ children: /* @__PURE__ */ jsx(Pencil, {})
3153
+ }
3154
+ ) })
3155
+ ] }, row.id)) })
3156
+ ] });
3157
+ };
3158
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3159
+ const SelectedEntriesModalContent = ({
3160
+ listViewSelectedEntries,
3161
+ toggleModal,
3162
+ setListViewSelectedDocuments,
3163
+ model
3164
+ }) => {
3165
+ const { formatMessage } = useIntl();
3166
+ const { schema, components } = useContentTypeSchema(model);
3167
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3168
+ const [{ query }] = useQueryParams();
3169
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3170
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3171
+ {
3172
+ model,
3173
+ params: {
3174
+ page: "1",
3175
+ pageSize: documentIds.length.toString(),
3176
+ sort: query.sort,
3177
+ filters: {
3178
+ documentId: {
3179
+ $in: documentIds
3180
+ }
3181
+ },
3182
+ locale: query.plugins?.i18n?.locale
3183
+ }
3184
+ },
3185
+ {
3186
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3187
+ }
3188
+ );
3189
+ const { rows, validationErrors } = React.useMemo(() => {
3190
+ if (data.length > 0 && schema) {
3191
+ const validate = createYupSchema(schema.attributes, components);
3192
+ const validationErrors2 = {};
3193
+ const rows2 = data.map((entry) => {
3194
+ try {
3195
+ validate.validateSync(entry, { abortEarly: false });
3196
+ return entry;
3197
+ } catch (e) {
3198
+ if (e instanceof ValidationError) {
3199
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3200
+ }
3201
+ return entry;
3202
+ }
3203
+ });
3204
+ return { rows: rows2, validationErrors: validationErrors2 };
3205
+ }
3206
+ return {
3207
+ rows: [],
3208
+ validationErrors: {}
3209
+ };
3210
+ }, [components, data, schema]);
3211
+ const [publishedCount, setPublishedCount] = React.useState(0);
3212
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3213
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3214
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3215
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3216
+ const selectedEntries = rows.filter(
3217
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3218
+ );
3219
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3220
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3221
+ ({ documentId }) => validationErrors[documentId]
3222
+ ).length;
3223
+ const selectedEntriesPublished = selectedEntries.filter(
3224
+ ({ status }) => status === "published"
3225
+ ).length;
3226
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3227
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3228
+ const handleConfirmBulkPublish = async () => {
3229
+ toggleDialog();
3230
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3231
+ if (!("error" in res)) {
3232
+ setPublishedCount(res.count);
3233
+ const unpublishedEntries = rows.filter((row) => {
3234
+ return !entriesToPublish.includes(row.documentId);
3235
+ });
3236
+ setListViewSelectedDocuments(unpublishedEntries);
3237
+ }
3238
+ };
3239
+ const getFormattedCountMessage = () => {
3240
+ if (publishedCount) {
3241
+ return formatMessage(
3242
+ {
3243
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3244
+ 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."
3245
+ },
3246
+ {
3247
+ publishedCount,
3248
+ withErrorsCount: selectedEntriesWithErrorsCount,
3249
+ b: BoldChunk
3250
+ }
3251
+ );
3252
+ }
3253
+ return formatMessage(
3254
+ {
3255
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3256
+ 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."
3257
+ },
3258
+ {
3259
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3260
+ withErrorsCount: selectedEntriesWithErrorsCount,
3261
+ alreadyPublishedCount: selectedEntriesPublished,
3262
+ b: BoldChunk
3263
+ }
3264
+ );
3265
+ };
3266
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3267
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3268
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3269
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3270
+ SelectedEntriesTableContent,
3271
+ {
3272
+ isPublishing: isSubmittingForm,
3273
+ rowsToDisplay: rows,
3274
+ entriesToPublish,
3275
+ validationErrors
3276
+ }
3277
+ ) })
3278
+ ] }),
3279
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3280
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3281
+ id: "app.components.Button.cancel",
3282
+ defaultMessage: "Cancel"
3283
+ }) }),
3284
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3285
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3286
+ /* @__PURE__ */ jsx(
3287
+ Button,
3288
+ {
3289
+ onClick: toggleDialog,
3290
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3291
+ loading: isSubmittingForm,
3292
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3293
+ }
3294
+ )
3295
+ ] })
3296
+ ] }),
3297
+ /* @__PURE__ */ jsx(
3298
+ ConfirmDialogPublishAll,
3299
+ {
3300
+ isOpen: isDialogOpen,
3301
+ onToggleDialog: toggleDialog,
3302
+ isConfirmButtonLoading: isSubmittingForm,
3303
+ onConfirm: handleConfirmBulkPublish
3304
+ }
3305
+ )
3306
+ ] });
3307
+ };
3308
+ const PublishAction = ({ documents, model }) => {
3309
+ const { formatMessage } = useIntl();
3310
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3311
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3312
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3313
+ const refetchList = () => {
3314
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3315
+ };
3316
+ if (!showPublishButton)
3317
+ return null;
3318
+ return {
3319
+ actionType: "publish",
3320
+ variant: "tertiary",
3321
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3322
+ dialog: {
3323
+ type: "modal",
3324
+ title: formatMessage({
3325
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3326
+ defaultMessage: "Publish entries"
3327
+ }),
3328
+ content: ({ onClose }) => {
3329
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3330
+ SelectedEntriesModalContent,
3331
+ {
3332
+ listViewSelectedEntries: documents,
3333
+ toggleModal: () => {
3334
+ onClose();
3335
+ refetchList();
3336
+ },
3337
+ setListViewSelectedDocuments,
3338
+ model
3339
+ }
3340
+ ) });
3341
+ },
3342
+ onClose: () => {
3343
+ refetchList();
3344
+ }
3345
+ }
3346
+ };
3347
+ };
3348
+ const BulkActionsRenderer = () => {
3349
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3350
+ const { model, collectionType } = useDoc();
3351
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3352
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3353
+ DescriptionComponentRenderer,
3354
+ {
3355
+ props: {
3356
+ model,
3357
+ collectionType,
3358
+ documents: selectedRows
3359
+ },
3360
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3361
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3362
+ }
3363
+ ) });
3364
+ };
3365
+ const DeleteAction = ({ documents, model }) => {
3366
+ const { formatMessage } = useIntl();
3367
+ const { schema: contentType } = useDoc();
3368
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3369
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3370
+ const [{ query }] = useQueryParams();
3371
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3372
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3373
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3374
+ const documentIds = documents.map(({ documentId }) => documentId);
3375
+ const handleConfirmBulkDelete = async () => {
3376
+ const res = await bulkDeleteAction({
3377
+ documentIds,
3378
+ model,
3379
+ params
3380
+ });
3381
+ if (!("error" in res)) {
3382
+ selectRow([]);
3383
+ }
3384
+ };
3385
+ if (!hasDeletePermission)
3386
+ return null;
3387
+ return {
3388
+ variant: "danger-light",
3389
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3390
+ dialog: {
3391
+ type: "dialog",
3392
+ title: formatMessage({
3393
+ id: "app.components.ConfirmDialog.title",
3394
+ defaultMessage: "Confirmation"
3395
+ }),
3396
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3397
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3398
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3399
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3400
+ defaultMessage: "Are you sure you want to delete these entries?"
3401
+ }) }),
3402
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3403
+ {
3404
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3405
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3406
+ },
3407
+ {
3408
+ em: Emphasis
3409
+ }
3410
+ ) }) })
3411
+ ] }),
3412
+ onConfirm: handleConfirmBulkDelete
3413
+ }
3414
+ };
3415
+ };
3416
+ DeleteAction.type = "delete";
3417
+ const UnpublishAction = ({ documents, model }) => {
3418
+ const { formatMessage } = useIntl();
3419
+ const { schema } = useDoc();
3420
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3421
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3422
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3423
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3424
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3425
+ const documentIds = documents.map(({ documentId }) => documentId);
3426
+ const [{ query }] = useQueryParams();
3427
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3428
+ const handleConfirmBulkUnpublish = async () => {
3429
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3430
+ if (!("error" in data)) {
3431
+ selectRow([]);
3432
+ }
3433
+ };
3434
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3435
+ if (!showUnpublishButton)
3436
+ return null;
3437
+ return {
3438
+ variant: "tertiary",
3439
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3440
+ dialog: {
3441
+ type: "dialog",
3442
+ title: formatMessage({
3443
+ id: "app.components.ConfirmDialog.title",
3444
+ defaultMessage: "Confirmation"
3445
+ }),
3446
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3447
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3448
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3449
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3450
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3451
+ }) }),
3452
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3453
+ {
3454
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3455
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3456
+ },
3457
+ {
3458
+ em: Emphasis
3459
+ }
3460
+ ) }) })
3461
+ ] }),
3462
+ confirmButton: formatMessage({
3463
+ id: "app.utils.unpublish",
3464
+ defaultMessage: "Unpublish"
3465
+ }),
3466
+ onConfirm: handleConfirmBulkUnpublish
3467
+ }
3468
+ };
3469
+ };
3470
+ UnpublishAction.type = "unpublish";
3471
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3472
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3473
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3474
+ const { formatMessage } = useIntl();
3475
+ const getDefaultErrorMessage = (reason) => {
3476
+ switch (reason) {
3477
+ case "relation":
3478
+ return "Duplicating the relation could remove it from the original entry.";
3479
+ case "unique":
3480
+ return "Identical values in a unique field are not allowed";
3481
+ default:
3482
+ return reason;
3483
+ }
3484
+ };
3485
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3486
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3487
+ id: getTranslation("containers.list.autoCloneModal.title"),
3488
+ defaultMessage: "This entry can't be duplicated directly."
3489
+ }) }),
3490
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3491
+ id: getTranslation("containers.list.autoCloneModal.description"),
3492
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3493
+ }) }) }),
3494
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3495
+ Flex,
3496
+ {
3497
+ direction: "column",
3498
+ gap: 2,
3499
+ alignItems: "flex-start",
3500
+ borderColor: "neutral200",
3501
+ hasRadius: true,
3502
+ padding: 6,
3503
+ children: [
3504
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3505
+ pathSegment,
3506
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3507
+ ChevronRight,
3508
+ {
3509
+ fill: "neutral500",
3510
+ height: "0.8rem",
3511
+ width: "0.8rem",
3512
+ style: { margin: "0 0.8rem" }
3513
+ }
3514
+ )
3515
+ ] }, index2)) }),
3516
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3517
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3518
+ defaultMessage: getDefaultErrorMessage(reason)
3519
+ }) })
3520
+ ]
3521
+ },
3522
+ fieldPath.join()
3523
+ )) })
3524
+ ] });
3525
+ };
3526
+ const TableActions = ({ document }) => {
3527
+ const { formatMessage } = useIntl();
3528
+ const { model, collectionType } = useDoc();
3529
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3530
+ const props = {
3531
+ activeTab: null,
3532
+ model,
3533
+ documentId: document.documentId,
3534
+ collectionType,
3535
+ document
3536
+ };
3537
+ return /* @__PURE__ */ jsx(
3538
+ DescriptionComponentRenderer,
3539
+ {
3540
+ props,
3541
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3542
+ children: (actions2) => {
3543
+ const tableRowActions = actions2.filter((action) => {
3544
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3545
+ return positions.includes("table-row");
3546
+ });
3547
+ return /* @__PURE__ */ jsx(
3548
+ DocumentActionsMenu,
3549
+ {
3550
+ actions: tableRowActions,
3551
+ label: formatMessage({
3552
+ id: "content-manager.containers.list.table.row-actions",
3553
+ defaultMessage: "Row action"
3554
+ }),
3555
+ variant: "ghost"
3556
+ }
3557
+ );
3558
+ }
3559
+ }
3560
+ );
3561
+ };
3562
+ const EditAction = ({ documentId }) => {
3563
+ const navigate = useNavigate();
3564
+ const { formatMessage } = useIntl();
3565
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3566
+ const { toggleNotification } = useNotification();
3567
+ const [{ query }] = useQueryParams();
3568
+ return {
3569
+ disabled: !canRead,
3570
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3571
+ label: formatMessage({
3572
+ id: "content-manager.actions.edit.label",
3573
+ defaultMessage: "Edit"
3574
+ }),
3575
+ position: "table-row",
2548
3576
  onClick: async () => {
2549
3577
  if (!documentId) {
2550
3578
  console.error(
@@ -2629,7 +3657,7 @@ const CloneAction = ({ model, documentId }) => {
2629
3657
  /* @__PURE__ */ jsx(
2630
3658
  LinkButton,
2631
3659
  {
2632
- as: NavLink,
3660
+ tag: NavLink,
2633
3661
  to: {
2634
3662
  pathname: `clone/${documentId}`
2635
3663
  },
@@ -2662,442 +3690,183 @@ class ContentManagerPlugin {
2662
3690
  documentActions = [
2663
3691
  ...DEFAULT_ACTIONS,
2664
3692
  ...DEFAULT_TABLE_ROW_ACTIONS,
2665
- ...DEFAULT_HEADER_ACTIONS,
2666
- HistoryAction
3693
+ ...DEFAULT_HEADER_ACTIONS
2667
3694
  ];
2668
3695
  editViewSidePanels = [ActionsPanel];
2669
3696
  headerActions = [];
2670
3697
  constructor() {
2671
3698
  }
2672
- addEditViewSidePanel(panels) {
2673
- if (Array.isArray(panels)) {
2674
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2675
- } else if (typeof panels === "function") {
2676
- this.editViewSidePanels = panels(this.editViewSidePanels);
2677
- } else {
2678
- throw new Error(
2679
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2680
- panels
2681
- )}`
2682
- );
2683
- }
2684
- }
2685
- addDocumentAction(actions2) {
2686
- if (Array.isArray(actions2)) {
2687
- this.documentActions = [...this.documentActions, ...actions2];
2688
- } else if (typeof actions2 === "function") {
2689
- this.documentActions = actions2(this.documentActions);
2690
- } else {
2691
- throw new Error(
2692
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2693
- actions2
2694
- )}`
2695
- );
2696
- }
2697
- }
2698
- addDocumentHeaderAction(actions2) {
2699
- if (Array.isArray(actions2)) {
2700
- this.headerActions = [...this.headerActions, ...actions2];
2701
- } else if (typeof actions2 === "function") {
2702
- this.headerActions = actions2(this.headerActions);
3699
+ addEditViewSidePanel(panels) {
3700
+ if (Array.isArray(panels)) {
3701
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3702
+ } else if (typeof panels === "function") {
3703
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2703
3704
  } else {
2704
3705
  throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
3706
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3707
+ panels
2707
3708
  )}`
2708
3709
  );
2709
3710
  }
2710
3711
  }
2711
- addBulkAction(actions2) {
3712
+ addDocumentAction(actions2) {
2712
3713
  if (Array.isArray(actions2)) {
2713
- this.bulkActions = [...this.bulkActions, ...actions2];
3714
+ this.documentActions = [...this.documentActions, ...actions2];
2714
3715
  } else if (typeof actions2 === "function") {
2715
- this.bulkActions = actions2(this.bulkActions);
3716
+ this.documentActions = actions2(this.documentActions);
2716
3717
  } else {
2717
3718
  throw new Error(
2718
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3719
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2719
3720
  actions2
2720
3721
  )}`
2721
- );
2722
- }
2723
- }
2724
- get config() {
2725
- return {
2726
- id: PLUGIN_ID,
2727
- name: "Content Manager",
2728
- injectionZones: INJECTION_ZONES,
2729
- apis: {
2730
- addBulkAction: this.addBulkAction.bind(this),
2731
- addDocumentAction: this.addDocumentAction.bind(this),
2732
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
2733
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
2734
- getBulkActions: () => this.bulkActions,
2735
- getDocumentActions: () => this.documentActions,
2736
- getEditViewSidePanels: () => this.editViewSidePanels,
2737
- getHeaderActions: () => this.headerActions
2738
- }
2739
- };
2740
- }
2741
- }
2742
- const getPrintableType = (value) => {
2743
- const nativeType = typeof value;
2744
- if (nativeType === "object") {
2745
- if (value === null)
2746
- return "null";
2747
- if (Array.isArray(value))
2748
- return "array";
2749
- if (value instanceof Object && value.constructor.name !== "Object") {
2750
- return value.constructor.name;
2751
- }
2752
- }
2753
- return nativeType;
2754
- };
2755
- const initialState = {
2756
- collectionTypeLinks: [],
2757
- components: [],
2758
- fieldSizes: {},
2759
- models: [],
2760
- singleTypeLinks: [],
2761
- isLoading: true
2762
- };
2763
- const appSlice = createSlice({
2764
- name: "app",
2765
- initialState,
2766
- reducers: {
2767
- setInitialData(state, action) {
2768
- const {
2769
- authorizedCollectionTypeLinks,
2770
- authorizedSingleTypeLinks,
2771
- components,
2772
- contentTypeSchemas,
2773
- fieldSizes
2774
- } = action.payload;
2775
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
2776
- ({ isDisplayed }) => isDisplayed
2777
- );
2778
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
2779
- state.components = components;
2780
- state.models = contentTypeSchemas;
2781
- state.fieldSizes = fieldSizes;
2782
- state.isLoading = false;
2783
- }
2784
- }
2785
- });
2786
- const { actions, reducer: reducer$1 } = appSlice;
2787
- const { setInitialData } = actions;
2788
- const reducer = combineReducers({
2789
- app: reducer$1
2790
- });
2791
- const HOOKS = {
2792
- /**
2793
- * Hook that allows to mutate the displayed headers of the list view table
2794
- * @constant
2795
- * @type {string}
2796
- */
2797
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2798
- /**
2799
- * Hook that allows to mutate the CM's collection types links pre-set filters
2800
- * @constant
2801
- * @type {string}
2802
- */
2803
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2804
- /**
2805
- * Hook that allows to mutate the CM's edit view layout
2806
- * @constant
2807
- * @type {string}
2808
- */
2809
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2810
- /**
2811
- * Hook that allows to mutate the CM's single types links pre-set filters
2812
- * @constant
2813
- * @type {string}
2814
- */
2815
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2816
- };
2817
- const contentTypesApi = contentManagerApi.injectEndpoints({
2818
- endpoints: (builder) => ({
2819
- getContentTypeConfiguration: builder.query({
2820
- query: (uid) => ({
2821
- url: `/content-manager/content-types/${uid}/configuration`,
2822
- method: "GET"
2823
- }),
2824
- transformResponse: (response) => response.data,
2825
- providesTags: (_result, _error, uid) => [
2826
- { type: "ContentTypesConfiguration", id: uid },
2827
- { type: "ContentTypeSettings", id: "LIST" }
2828
- ]
2829
- }),
2830
- getAllContentTypeSettings: builder.query({
2831
- query: () => "/content-manager/content-types-settings",
2832
- transformResponse: (response) => response.data,
2833
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2834
- }),
2835
- updateContentTypeConfiguration: builder.mutation({
2836
- query: ({ uid, ...body }) => ({
2837
- url: `/content-manager/content-types/${uid}/configuration`,
2838
- method: "PUT",
2839
- data: body
2840
- }),
2841
- transformResponse: (response) => response.data,
2842
- invalidatesTags: (_result, _error, { uid }) => [
2843
- { type: "ContentTypesConfiguration", id: uid },
2844
- { type: "ContentTypeSettings", id: "LIST" },
2845
- // Is this necessary?
2846
- { type: "InitialData" }
2847
- ]
2848
- })
2849
- })
2850
- });
2851
- const {
2852
- useGetContentTypeConfigurationQuery,
2853
- useGetAllContentTypeSettingsQuery,
2854
- useUpdateContentTypeConfigurationMutation
2855
- } = contentTypesApi;
2856
- const checkIfAttributeIsDisplayable = (attribute) => {
2857
- const { type } = attribute;
2858
- if (type === "relation") {
2859
- return !attribute.relation.toLowerCase().includes("morph");
2860
- }
2861
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2862
- };
2863
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2864
- if (!mainFieldName) {
2865
- return void 0;
2866
- }
2867
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2868
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2869
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2870
- );
2871
- return {
2872
- name: mainFieldName,
2873
- type: mainFieldType ?? "string"
2874
- };
2875
- };
2876
- const DEFAULT_SETTINGS = {
2877
- bulkable: false,
2878
- filterable: false,
2879
- searchable: false,
2880
- pagination: false,
2881
- defaultSortBy: "",
2882
- defaultSortOrder: "asc",
2883
- mainField: "id",
2884
- pageSize: 10
2885
- };
2886
- const useDocumentLayout = (model) => {
2887
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2888
- const [{ query }] = useQueryParams();
2889
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2890
- const { toggleNotification } = useNotification();
2891
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2892
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2893
- const {
2894
- data,
2895
- isLoading: isLoadingConfigs,
2896
- error,
2897
- isFetching: isFetchingConfigs
2898
- } = useGetContentTypeConfigurationQuery(model);
2899
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2900
- React.useEffect(() => {
2901
- if (error) {
2902
- toggleNotification({
2903
- type: "danger",
2904
- message: formatAPIError(error)
2905
- });
2906
- }
2907
- }, [error, formatAPIError, toggleNotification]);
2908
- const editLayout = React.useMemo(
2909
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2910
- layout: [],
2911
- components: {},
2912
- metadatas: {},
2913
- options: {},
2914
- settings: DEFAULT_SETTINGS
2915
- },
2916
- [data, isLoading, schemas, schema, components]
2917
- );
2918
- const listLayout = React.useMemo(() => {
2919
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2920
- layout: [],
2921
- metadatas: {},
2922
- options: {},
2923
- settings: DEFAULT_SETTINGS
2924
- };
2925
- }, [data, isLoading, schemas, schema, components]);
2926
- const { layout: edit } = React.useMemo(
2927
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2928
- layout: editLayout,
2929
- query
2930
- }),
2931
- [editLayout, query, runHookWaterfall]
2932
- );
2933
- return {
2934
- error,
2935
- isLoading,
2936
- edit,
2937
- list: listLayout
2938
- };
2939
- };
2940
- const useDocLayout = () => {
2941
- const { model } = useDoc();
2942
- return useDocumentLayout(model);
2943
- };
2944
- const formatEditLayout = (data, {
2945
- schemas,
2946
- schema,
2947
- components
2948
- }) => {
2949
- let currentPanelIndex = 0;
2950
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2951
- data.contentType.layouts.edit,
2952
- schema?.attributes,
2953
- data.contentType.metadatas,
2954
- { configurations: data.components, schemas: components },
2955
- schemas
2956
- ).reduce((panels, row) => {
2957
- if (row.some((field) => field.type === "dynamiczone")) {
2958
- panels.push([row]);
2959
- currentPanelIndex += 2;
3722
+ );
3723
+ }
3724
+ }
3725
+ addDocumentHeaderAction(actions2) {
3726
+ if (Array.isArray(actions2)) {
3727
+ this.headerActions = [...this.headerActions, ...actions2];
3728
+ } else if (typeof actions2 === "function") {
3729
+ this.headerActions = actions2(this.headerActions);
2960
3730
  } else {
2961
- if (!panels[currentPanelIndex]) {
2962
- panels.push([]);
2963
- }
2964
- panels[currentPanelIndex].push(row);
3731
+ throw new Error(
3732
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3733
+ actions2
3734
+ )}`
3735
+ );
2965
3736
  }
2966
- return panels;
2967
- }, []);
2968
- const componentEditAttributes = Object.entries(data.components).reduce(
2969
- (acc, [uid, configuration]) => {
2970
- acc[uid] = {
2971
- layout: convertEditLayoutToFieldLayouts(
2972
- configuration.layouts.edit,
2973
- components[uid].attributes,
2974
- configuration.metadatas
2975
- ),
2976
- settings: {
2977
- ...configuration.settings,
2978
- icon: components[uid].info.icon,
2979
- displayName: components[uid].info.displayName
2980
- }
2981
- };
2982
- return acc;
2983
- },
2984
- {}
2985
- );
2986
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2987
- (acc, [attribute, metadata]) => {
2988
- return {
2989
- ...acc,
2990
- [attribute]: metadata.edit
2991
- };
2992
- },
2993
- {}
2994
- );
2995
- return {
2996
- layout: panelledEditAttributes,
2997
- components: componentEditAttributes,
2998
- metadatas: editMetadatas,
2999
- settings: {
3000
- ...data.contentType.settings,
3001
- displayName: schema?.info.displayName
3002
- },
3003
- options: {
3004
- ...schema?.options,
3005
- ...schema?.pluginOptions,
3006
- ...data.contentType.options
3737
+ }
3738
+ addBulkAction(actions2) {
3739
+ if (Array.isArray(actions2)) {
3740
+ this.bulkActions = [...this.bulkActions, ...actions2];
3741
+ } else if (typeof actions2 === "function") {
3742
+ this.bulkActions = actions2(this.bulkActions);
3743
+ } else {
3744
+ throw new Error(
3745
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3746
+ actions2
3747
+ )}`
3748
+ );
3007
3749
  }
3008
- };
3009
- };
3010
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3011
- return rows.map(
3012
- (row) => row.map((field) => {
3013
- const attribute = attributes[field.name];
3014
- if (!attribute) {
3015
- return null;
3750
+ }
3751
+ get config() {
3752
+ return {
3753
+ id: PLUGIN_ID,
3754
+ name: "Content Manager",
3755
+ injectionZones: INJECTION_ZONES,
3756
+ apis: {
3757
+ addBulkAction: this.addBulkAction.bind(this),
3758
+ addDocumentAction: this.addDocumentAction.bind(this),
3759
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3760
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3761
+ getBulkActions: () => this.bulkActions,
3762
+ getDocumentActions: () => this.documentActions,
3763
+ getEditViewSidePanels: () => this.editViewSidePanels,
3764
+ getHeaderActions: () => this.headerActions
3016
3765
  }
3017
- const { edit: metadata } = metadatas[field.name];
3018
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3019
- return {
3020
- attribute,
3021
- disabled: !metadata.editable,
3022
- hint: metadata.description,
3023
- label: metadata.label ?? "",
3024
- name: field.name,
3025
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3026
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3027
- schemas,
3028
- components: components?.schemas ?? {}
3029
- }),
3030
- placeholder: metadata.placeholder ?? "",
3031
- required: attribute.required ?? false,
3032
- size: field.size,
3033
- unique: "unique" in attribute ? attribute.unique : false,
3034
- visible: metadata.visible ?? true,
3035
- type: attribute.type
3036
- };
3037
- }).filter((field) => field !== null)
3038
- );
3766
+ };
3767
+ }
3768
+ }
3769
+ const getPrintableType = (value) => {
3770
+ const nativeType = typeof value;
3771
+ if (nativeType === "object") {
3772
+ if (value === null)
3773
+ return "null";
3774
+ if (Array.isArray(value))
3775
+ return "array";
3776
+ if (value instanceof Object && value.constructor.name !== "Object") {
3777
+ return value.constructor.name;
3778
+ }
3779
+ }
3780
+ return nativeType;
3039
3781
  };
3040
- const formatListLayout = (data, {
3041
- schemas,
3042
- schema,
3043
- components
3044
- }) => {
3045
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3046
- (acc, [attribute, metadata]) => {
3047
- return {
3048
- ...acc,
3049
- [attribute]: metadata.list
3050
- };
3051
- },
3052
- {}
3053
- );
3054
- const listAttributes = convertListLayoutToFieldLayouts(
3055
- data.contentType.layouts.list,
3056
- schema?.attributes,
3057
- listMetadatas,
3058
- { configurations: data.components, schemas: components },
3059
- schemas
3060
- );
3782
+ const HistoryAction = ({ model, document }) => {
3783
+ const { formatMessage } = useIntl();
3784
+ const [{ query }] = useQueryParams();
3785
+ const navigate = useNavigate();
3786
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3787
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3788
+ return null;
3789
+ }
3061
3790
  return {
3062
- layout: listAttributes,
3063
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3064
- metadatas: listMetadatas,
3065
- options: {
3066
- ...schema?.options,
3067
- ...schema?.pluginOptions,
3068
- ...data.contentType.options
3069
- }
3791
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3792
+ label: formatMessage({
3793
+ id: "content-manager.history.document-action",
3794
+ defaultMessage: "Content History"
3795
+ }),
3796
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3797
+ disabled: (
3798
+ /**
3799
+ * The user is creating a new document.
3800
+ * It hasn't been saved yet, so there's no history to go to
3801
+ */
3802
+ !document || /**
3803
+ * The document has been created but the current dimension has never been saved.
3804
+ * For example, the user is creating a new locale in an existing document,
3805
+ * so there's no history for the document in that locale
3806
+ */
3807
+ !document.id || /**
3808
+ * History is only available for content types created by the user.
3809
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3810
+ * which start with `admin::` or `plugin::`
3811
+ */
3812
+ !model.startsWith("api::")
3813
+ ),
3814
+ position: "header"
3070
3815
  };
3071
3816
  };
3072
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3073
- return columns.map((name) => {
3074
- const attribute = attributes[name];
3075
- if (!attribute) {
3076
- return null;
3077
- }
3078
- const metadata = metadatas[name];
3079
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3080
- return {
3081
- attribute,
3082
- label: metadata.label ?? "",
3083
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3084
- schemas,
3085
- components: components?.schemas ?? {}
3086
- }),
3087
- name,
3088
- searchable: metadata.searchable ?? true,
3089
- sortable: metadata.sortable ?? true
3090
- };
3091
- }).filter((field) => field !== null);
3817
+ HistoryAction.type = "history";
3818
+ const historyAdmin = {
3819
+ bootstrap(app) {
3820
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3821
+ addDocumentAction((actions2) => {
3822
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3823
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3824
+ return actions2;
3825
+ });
3826
+ }
3827
+ };
3828
+ const initialState = {
3829
+ collectionTypeLinks: [],
3830
+ components: [],
3831
+ fieldSizes: {},
3832
+ models: [],
3833
+ singleTypeLinks: [],
3834
+ isLoading: true
3092
3835
  };
3836
+ const appSlice = createSlice({
3837
+ name: "app",
3838
+ initialState,
3839
+ reducers: {
3840
+ setInitialData(state, action) {
3841
+ const {
3842
+ authorizedCollectionTypeLinks,
3843
+ authorizedSingleTypeLinks,
3844
+ components,
3845
+ contentTypeSchemas,
3846
+ fieldSizes
3847
+ } = action.payload;
3848
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3849
+ ({ isDisplayed }) => isDisplayed
3850
+ );
3851
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3852
+ state.components = components;
3853
+ state.models = contentTypeSchemas;
3854
+ state.fieldSizes = fieldSizes;
3855
+ state.isLoading = false;
3856
+ }
3857
+ }
3858
+ });
3859
+ const { actions, reducer: reducer$1 } = appSlice;
3860
+ const { setInitialData } = actions;
3861
+ const reducer = combineReducers({
3862
+ app: reducer$1
3863
+ });
3093
3864
  const index = {
3094
3865
  register(app) {
3095
3866
  const cm = new ContentManagerPlugin();
3096
3867
  app.addReducers({
3097
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3098
3868
  [PLUGIN_ID]: reducer
3099
3869
  });
3100
- app.addMiddlewares([() => contentManagerApi.middleware]);
3101
3870
  app.addMenuLink({
3102
3871
  to: PLUGIN_ID,
3103
3872
  icon: Feather,
@@ -3106,14 +3875,29 @@ const index = {
3106
3875
  defaultMessage: "Content Manager"
3107
3876
  },
3108
3877
  permissions: [],
3109
- Component: () => import("./layout-Dnh0PNp9.mjs").then((mod) => ({ default: mod.Layout }))
3878
+ position: 1
3879
+ });
3880
+ app.router.addRoute({
3881
+ path: "content-manager/*",
3882
+ lazy: async () => {
3883
+ const { Layout } = await import("./layout-BNqvLR_b.mjs");
3884
+ return {
3885
+ Component: Layout
3886
+ };
3887
+ },
3888
+ children: routes
3110
3889
  });
3111
3890
  app.registerPlugin(cm.config);
3112
3891
  },
3892
+ bootstrap(app) {
3893
+ if (typeof historyAdmin.bootstrap === "function") {
3894
+ historyAdmin.bootstrap(app);
3895
+ }
3896
+ },
3113
3897
  async registerTrads({ locales }) {
3114
3898
  const importedTrads = await Promise.all(
3115
3899
  locales.map((locale) => {
3116
- 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-MBPul9Su.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3900
+ 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-BrCTWlZv.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3117
3901
  return {
3118
3902
  data: prefixPluginTranslations(data, PLUGIN_ID),
3119
3903
  locale
@@ -3131,7 +3915,7 @@ const index = {
3131
3915
  };
3132
3916
  export {
3133
3917
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3134
- extractContentTypeComponents as B,
3918
+ BulkActionsRenderer as B,
3135
3919
  COLLECTION_TYPES as C,
3136
3920
  DocumentStatus as D,
3137
3921
  DEFAULT_SETTINGS as E,
@@ -3145,31 +3929,31 @@ export {
3145
3929
  RelativeTime as R,
3146
3930
  SINGLE_TYPES as S,
3147
3931
  TableActions as T,
3148
- useGetAllContentTypeSettingsQuery as a,
3149
- useDoc as b,
3150
- buildValidParams as c,
3151
- contentManagerApi as d,
3152
- useDocumentRBAC as e,
3153
- useDocumentLayout as f,
3932
+ useGetInitialDataQuery as a,
3933
+ useGetAllContentTypeSettingsQuery as b,
3934
+ useDoc as c,
3935
+ buildValidParams as d,
3936
+ contentManagerApi as e,
3937
+ useDocumentRBAC as f,
3154
3938
  getTranslation as g,
3155
- createYupSchema as h,
3156
- Header as i,
3157
- PERMISSIONS as j,
3158
- DocumentRBAC as k,
3159
- DOCUMENT_META_FIELDS as l,
3160
- useDocLayout as m,
3161
- useContentTypeSchema as n,
3939
+ useDocumentLayout as h,
3940
+ createYupSchema as i,
3941
+ Header as j,
3942
+ PERMISSIONS as k,
3943
+ DocumentRBAC as l,
3944
+ DOCUMENT_META_FIELDS as m,
3945
+ useDocLayout as n,
3162
3946
  useGetContentTypeConfigurationQuery as o,
3163
3947
  CREATOR_FIELDS as p,
3164
3948
  getMainField as q,
3165
- routes as r,
3949
+ getDisplayName as r,
3166
3950
  setInitialData as s,
3167
- getDisplayName as t,
3168
- useGetInitialDataQuery as u,
3169
- checkIfAttributeIsDisplayable as v,
3170
- useGetAllDocumentsQuery as w,
3171
- convertListLayoutToFieldLayouts as x,
3172
- capitalise as y,
3173
- useUpdateContentTypeConfigurationMutation as z
3174
- };
3175
- //# sourceMappingURL=index-DNVx8ssZ.mjs.map
3951
+ checkIfAttributeIsDisplayable as t,
3952
+ useContentTypeSchema as u,
3953
+ useGetAllDocumentsQuery as v,
3954
+ convertListLayoutToFieldLayouts as w,
3955
+ capitalise as x,
3956
+ useUpdateContentTypeConfigurationMutation as y,
3957
+ extractContentTypeComponents as z
3958
+ };
3959
+ //# sourceMappingURL=index-C9TJPyni.mjs.map