@strapi/content-manager 0.0.0-experimental.e60ec1829240dae21c1e1d29076681c322288813 → 0.0.0-experimental.e9122b401c96877b6707775c4f893660eab93ae3

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 (180) 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-BPvzFjM7.mjs → ComponentConfigurationPage-CpBFh6_r.mjs} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-CpBFh6_r.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-_zF8p6CY.js} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-_zF8p6CY.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-DacbqQ_f.mjs → EditConfigurationPage-CE_yavTi.mjs} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-CE_yavTi.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-_aG2DJSU.js} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-_aG2DJSU.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-DeTn7rAF.mjs} +59 -48
  19. package/dist/_chunks/EditViewPage-DeTn7rAF.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-G9uNzwYL.js} +58 -49
  21. package/dist/_chunks/EditViewPage-G9uNzwYL.js.map +1 -0
  22. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-CnCKhI1R.mjs} +995 -795
  23. package/dist/_chunks/Field-CnCKhI1R.mjs.map +1 -0
  24. package/dist/_chunks/{Field-DmVKIAOo.js → Field-DDHUWEfV.js} +1041 -842
  25. package/dist/_chunks/Field-DDHUWEfV.js.map +1 -0
  26. package/dist/_chunks/{Form-CPZC9vWa.js → Form-DYETaKUX.js} +65 -45
  27. package/dist/_chunks/Form-DYETaKUX.js.map +1 -0
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-IvVVwqRL.mjs} +65 -44
  29. package/dist/_chunks/Form-IvVVwqRL.mjs.map +1 -0
  30. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-BMunT-do.mjs} +148 -54
  31. package/dist/_chunks/History-BMunT-do.mjs.map +1 -0
  32. package/dist/_chunks/{History-DeAPlvtv.js → History-CnZDctSO.js} +149 -56
  33. package/dist/_chunks/History-CnZDctSO.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-BynalOp8.js} +67 -58
  35. package/dist/_chunks/ListConfigurationPage-BynalOp8.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-CDqkCxgV.mjs} +63 -53
  37. package/dist/_chunks/ListConfigurationPage-CDqkCxgV.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-I88Ouzoq.js} +126 -137
  39. package/dist/_chunks/ListViewPage-I88Ouzoq.js.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-_5gS-DOF.mjs} +123 -134
  41. package/dist/_chunks/ListViewPage-_5gS-DOF.mjs.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BaWQ7HsA.js} +3 -3
  43. package/dist/_chunks/NoContentTypePage-BaWQ7HsA.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Dht-55hr.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-Dht-55hr.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-Bs8D5W_v.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-Bs8D5W_v.mjs.map} +1 -1
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-DCVUh5at.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-DCVUh5at.js.map} +1 -1
  50. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-BPgFQeGj.js} +71 -62
  51. package/dist/_chunks/Relations-BPgFQeGj.js.map +1 -0
  52. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-Chdt5qWc.mjs} +67 -57
  53. package/dist/_chunks/Relations-Chdt5qWc.mjs.map +1 -0
  54. package/dist/_chunks/{en-C-V1_90f.js → en-BVzUkPxZ.js} +16 -8
  55. package/dist/_chunks/{en-C-V1_90f.js.map → en-BVzUkPxZ.js.map} +1 -1
  56. package/dist/_chunks/{en-MBPul9Su.mjs → en-CPTj6CjC.mjs} +16 -8
  57. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-CPTj6CjC.mjs.map} +1 -1
  58. package/dist/_chunks/{index-C6AH2hEl.js → index-BhbLFX4l.js} +1752 -903
  59. package/dist/_chunks/index-BhbLFX4l.js.map +1 -0
  60. package/dist/_chunks/{index-CwRRo1V9.mjs → index-D4UGPFZC.mjs} +1778 -928
  61. package/dist/_chunks/index-D4UGPFZC.mjs.map +1 -0
  62. package/dist/_chunks/{layout-B_SXLhqf.js → layout-CYA7s0qO.js} +45 -29
  63. package/dist/_chunks/layout-CYA7s0qO.js.map +1 -0
  64. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-D4HI4_PS.mjs} +45 -27
  65. package/dist/_chunks/layout-D4HI4_PS.mjs.map +1 -0
  66. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-1pXaYpBK.mjs} +2 -2
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-1pXaYpBK.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-iBMa_OFG.js → relations-DDZ9OxNo.js} +2 -2
  69. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-DDZ9OxNo.js.map} +1 -1
  70. package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
  71. package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
  72. package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
  73. package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
  74. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  75. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +8 -7
  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 +16 -53
  103. package/dist/admin/src/pages/EditView/components/Header.d.ts +10 -11
  104. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  105. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  106. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  107. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  108. package/dist/admin/src/services/api.d.ts +2 -3
  109. package/dist/admin/src/services/components.d.ts +2 -2
  110. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  111. package/dist/admin/src/services/documents.d.ts +31 -17
  112. package/dist/admin/src/services/init.d.ts +2 -2
  113. package/dist/admin/src/services/relations.d.ts +3 -3
  114. package/dist/admin/src/services/uid.d.ts +3 -3
  115. package/dist/admin/src/utils/api.d.ts +4 -18
  116. package/dist/admin/src/utils/validation.d.ts +5 -7
  117. package/dist/server/index.js +436 -281
  118. package/dist/server/index.js.map +1 -1
  119. package/dist/server/index.mjs +444 -289
  120. package/dist/server/index.mjs.map +1 -1
  121. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  122. package/dist/server/src/controllers/relations.d.ts.map +1 -1
  123. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  124. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  125. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  126. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  127. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  128. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  129. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  130. package/dist/server/src/history/services/history.d.ts.map +1 -1
  131. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  132. package/dist/server/src/history/services/utils.d.ts +2 -1
  133. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  134. package/dist/server/src/index.d.ts +18 -39
  135. package/dist/server/src/index.d.ts.map +1 -1
  136. package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
  137. package/dist/server/src/services/document-manager.d.ts +13 -12
  138. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  139. package/dist/server/src/services/document-metadata.d.ts +8 -29
  140. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  141. package/dist/server/src/services/index.d.ts +18 -39
  142. package/dist/server/src/services/index.d.ts.map +1 -1
  143. package/dist/server/src/services/permission-checker.d.ts.map +1 -1
  144. package/dist/server/src/services/utils/populate.d.ts +8 -1
  145. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  146. package/dist/shared/contracts/collection-types.d.ts +17 -7
  147. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  148. package/dist/shared/contracts/relations.d.ts +2 -2
  149. package/dist/shared/contracts/relations.d.ts.map +1 -1
  150. package/package.json +14 -15
  151. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  152. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  153. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  154. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  155. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  156. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  157. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  158. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  159. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  160. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  161. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  162. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  163. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  164. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  165. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  166. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  167. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  168. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  169. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  170. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  171. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  172. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  173. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  174. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  175. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  176. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  177. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  178. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  179. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  180. 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 { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, 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 { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import { useIntl } from "react-intl";
8
+ import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
11
9
  import * as yup from "yup";
12
10
  import { ValidationError } from "yup";
13
- import { createApi } from "@reduxjs/toolkit/query/react";
14
- import { isAxiosError } from "axios";
15
11
  import pipe from "lodash/fp/pipe";
16
12
  import { intervalToDuration, isPast } from "date-fns";
13
+ import { styled } from "styled-components";
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,89 +150,20 @@ 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",
267
158
  "Document",
268
159
  "InitialData",
269
160
  "HistoryVersion",
270
- "Relations"
271
- ],
272
- endpoints: () => ({})
161
+ "Relations",
162
+ "UidAvailability"
163
+ ]
273
164
  });
274
165
  const documentApi = contentManagerApi.injectEndpoints({
166
+ overrideExisting: true,
275
167
  endpoints: (builder) => ({
276
168
  autoCloneDocument: builder.mutation({
277
169
  query: ({ model, sourceId, query }) => ({
@@ -281,7 +173,12 @@ const documentApi = contentManagerApi.injectEndpoints({
281
173
  params: query
282
174
  }
283
175
  }),
284
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
176
+ invalidatesTags: (_result, error, { model }) => {
177
+ if (error) {
178
+ return [];
179
+ }
180
+ return [{ type: "Document", id: `${model}_LIST` }];
181
+ }
285
182
  }),
286
183
  cloneDocument: builder.mutation({
287
184
  query: ({ model, sourceId, data, params }) => ({
@@ -292,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
292
189
  params
293
190
  }
294
191
  }),
295
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
192
+ invalidatesTags: (_result, _error, { model }) => [
193
+ { type: "Document", id: `${model}_LIST` },
194
+ { type: "UidAvailability", id: model }
195
+ ]
296
196
  }),
297
197
  /**
298
198
  * Creates a new collection-type document. This should ONLY be used for collection-types.
@@ -309,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
309
209
  }),
310
210
  invalidatesTags: (result, _error, { model }) => [
311
211
  { type: "Document", id: `${model}_LIST` },
312
- "Relations"
212
+ "Relations",
213
+ { type: "UidAvailability", id: model }
313
214
  ]
314
215
  }),
315
216
  deleteDocument: builder.mutation({
@@ -325,12 +226,15 @@ const documentApi = contentManagerApi.injectEndpoints({
325
226
  ]
326
227
  }),
327
228
  deleteManyDocuments: builder.mutation({
328
- query: ({ model, ...body }) => ({
229
+ query: ({ model, params, ...body }) => ({
329
230
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
330
231
  method: "POST",
331
- data: body
232
+ data: body,
233
+ config: {
234
+ params
235
+ }
332
236
  }),
333
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
237
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
334
238
  }),
335
239
  discardDocument: builder.mutation({
336
240
  query: ({ collectionType, model, documentId, params }) => ({
@@ -347,7 +251,8 @@ const documentApi = contentManagerApi.injectEndpoints({
347
251
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
348
252
  },
349
253
  { type: "Document", id: `${model}_LIST` },
350
- "Relations"
254
+ "Relations",
255
+ { type: "UidAvailability", id: model }
351
256
  ];
352
257
  }
353
258
  }),
@@ -365,6 +270,7 @@ const documentApi = contentManagerApi.injectEndpoints({
365
270
  }),
366
271
  providesTags: (result, _error, arg) => {
367
272
  return [
273
+ { type: "Document", id: `ALL_LIST` },
368
274
  { type: "Document", id: `${arg.model}_LIST` },
369
275
  ...result?.results.map(({ documentId }) => ({
370
276
  type: "Document",
@@ -403,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
403
309
  {
404
310
  type: "Document",
405
311
  id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
312
+ },
313
+ // Make it easy to invalidate all individual documents queries for a model
314
+ {
315
+ type: "Document",
316
+ id: `${model}_ALL_ITEMS`
406
317
  }
407
318
  ];
408
319
  }
@@ -441,10 +352,13 @@ const documentApi = contentManagerApi.injectEndpoints({
441
352
  }
442
353
  }),
443
354
  publishManyDocuments: builder.mutation({
444
- query: ({ model, ...body }) => ({
355
+ query: ({ model, params, ...body }) => ({
445
356
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
446
357
  method: "POST",
447
- data: body
358
+ data: body,
359
+ config: {
360
+ params
361
+ }
448
362
  }),
449
363
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
450
364
  }),
@@ -463,8 +377,21 @@ const documentApi = contentManagerApi.injectEndpoints({
463
377
  type: "Document",
464
378
  id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
465
379
  },
466
- "Relations"
380
+ "Relations",
381
+ { type: "UidAvailability", id: model }
467
382
  ];
383
+ },
384
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
385
+ const patchResult = dispatch(
386
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
387
+ Object.assign(draft.data, data);
388
+ })
389
+ );
390
+ try {
391
+ await queryFulfilled;
392
+ } catch {
393
+ patchResult.undo();
394
+ }
468
395
  }
469
396
  }),
470
397
  unpublishDocument: builder.mutation({
@@ -486,10 +413,13 @@ const documentApi = contentManagerApi.injectEndpoints({
486
413
  }
487
414
  }),
488
415
  unpublishManyDocuments: builder.mutation({
489
- query: ({ model, ...body }) => ({
416
+ query: ({ model, params, ...body }) => ({
490
417
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
491
418
  method: "POST",
492
- data: body
419
+ data: body,
420
+ config: {
421
+ params
422
+ }
493
423
  }),
494
424
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
495
425
  })
@@ -513,7 +443,25 @@ const {
513
443
  useUnpublishDocumentMutation,
514
444
  useUnpublishManyDocumentsMutation
515
445
  } = documentApi;
516
- const createYupSchema = (attributes = {}, components = {}) => {
446
+ const buildValidParams = (query) => {
447
+ if (!query)
448
+ return query;
449
+ const { plugins: _, ...validQueryParams } = {
450
+ ...query,
451
+ ...Object.values(query?.plugins ?? {}).reduce(
452
+ (acc, current) => Object.assign(acc, current),
453
+ {}
454
+ )
455
+ };
456
+ if ("_q" in validQueryParams) {
457
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
458
+ }
459
+ return validQueryParams;
460
+ };
461
+ const isBaseQueryError = (error) => {
462
+ return error.name !== void 0;
463
+ };
464
+ const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
517
465
  const createModelSchema = (attributes2) => yup.object().shape(
518
466
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
519
467
  if (DOCUMENT_META_FIELDS.includes(name)) {
@@ -526,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
526
474
  addMinValidation,
527
475
  addMaxValidation,
528
476
  addRegexValidation
529
- ].map((fn) => fn(attribute));
477
+ ].map((fn) => fn(attribute, options));
530
478
  const transformSchema = pipe(...validations);
531
479
  switch (attribute.type) {
532
480
  case "component": {
@@ -552,10 +500,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
552
500
  yup.array().of(
553
501
  yup.lazy(
554
502
  (data) => {
555
- const { attributes: attributes3 } = components[data.__component];
556
- return yup.object().shape({
503
+ const attributes3 = components?.[data?.__component]?.attributes;
504
+ const validation = yup.object().shape({
557
505
  __component: yup.string().required().oneOf(Object.keys(components))
558
- }).nullable(false).concat(createModelSchema(attributes3));
506
+ }).nullable(false);
507
+ if (!attributes3) {
508
+ return validation;
509
+ }
510
+ return validation.concat(createModelSchema(attributes3));
559
511
  }
560
512
  )
561
513
  )
@@ -565,11 +517,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
517
  return {
566
518
  ...acc,
567
519
  [name]: transformSchema(
568
- yup.array().of(
569
- yup.object().shape({
570
- id: yup.string().required()
571
- })
572
- )
520
+ yup.lazy((value) => {
521
+ if (!value) {
522
+ return yup.mixed().nullable(true);
523
+ } else if (Array.isArray(value)) {
524
+ return yup.array().of(
525
+ yup.object().shape({
526
+ id: yup.string().required()
527
+ })
528
+ );
529
+ } else if (typeof value === "object") {
530
+ return yup.object();
531
+ } else {
532
+ return yup.mixed().test(
533
+ "type-error",
534
+ "Relation values must be either null, an array of objects with {id} or an object.",
535
+ () => false
536
+ );
537
+ }
538
+ })
573
539
  )
574
540
  };
575
541
  default:
@@ -609,6 +575,14 @@ const createAttributeSchema = (attribute) => {
609
575
  if (!value || typeof value === "string" && value.length === 0) {
610
576
  return true;
611
577
  }
578
+ if (typeof value === "object") {
579
+ try {
580
+ JSON.stringify(value);
581
+ return true;
582
+ } catch (err) {
583
+ return false;
584
+ }
585
+ }
612
586
  try {
613
587
  JSON.parse(value);
614
588
  return true;
@@ -627,16 +601,30 @@ const createAttributeSchema = (attribute) => {
627
601
  return yup.mixed();
628
602
  }
629
603
  };
630
- const addRequiredValidation = (attribute) => (schema) => {
631
- if (attribute.required) {
632
- return schema.required({
633
- id: translatedErrors.required.id,
634
- defaultMessage: "This field is required."
635
- });
604
+ const nullableSchema = (schema) => {
605
+ return schema?.nullable ? schema.nullable() : (
606
+ // In some cases '.nullable' will not be available on the schema.
607
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
608
+ // In these cases we should just return the schema as it is.
609
+ schema
610
+ );
611
+ };
612
+ const addRequiredValidation = (attribute, options) => (schema) => {
613
+ if (options.status === "draft") {
614
+ return nullableSchema(schema);
636
615
  }
637
- return schema.nullable();
616
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
617
+ return schema.min(1, translatedErrors.required);
618
+ }
619
+ if (attribute.required && attribute.type !== "relation") {
620
+ return schema.required(translatedErrors.required);
621
+ }
622
+ return nullableSchema(schema);
638
623
  };
639
- const addMinLengthValidation = (attribute) => (schema) => {
624
+ const addMinLengthValidation = (attribute, options) => (schema) => {
625
+ if (options.status === "draft") {
626
+ return schema;
627
+ }
640
628
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
641
629
  return schema.min(attribute.minLength, {
642
630
  ...translatedErrors.minLength,
@@ -658,9 +646,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
658
646
  }
659
647
  return schema;
660
648
  };
661
- const addMinValidation = (attribute) => (schema) => {
649
+ const addMinValidation = (attribute, options) => (schema) => {
662
650
  if ("min" in attribute) {
663
651
  const min = toInteger(attribute.min);
652
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
653
+ if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
654
+ return schema.test(
655
+ "custom-min",
656
+ {
657
+ ...translatedErrors.min,
658
+ values: {
659
+ min: attribute.min
660
+ }
661
+ },
662
+ (value) => {
663
+ if (!value) {
664
+ return true;
665
+ }
666
+ if (Array.isArray(value) && value.length === 0) {
667
+ return true;
668
+ }
669
+ return value.length >= min;
670
+ }
671
+ );
672
+ }
673
+ }
664
674
  if ("min" in schema && min) {
665
675
  return schema.min(min, {
666
676
  ...translatedErrors.min,
@@ -706,24 +716,6 @@ const addRegexValidation = (attribute) => (schema) => {
706
716
  }
707
717
  return schema;
708
718
  };
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
719
  const initApi = contentManagerApi.injectEndpoints({
728
720
  endpoints: (builder) => ({
729
721
  getInitialData: builder.query({
@@ -737,27 +729,20 @@ const { useGetInitialDataQuery } = initApi;
737
729
  const useContentTypeSchema = (model) => {
738
730
  const { toggleNotification } = useNotification();
739
731
  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
- });
732
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
733
+ const { components, contentType, contentTypes } = React.useMemo(() => {
734
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
735
+ const componentsByKey = data?.components.reduce((acc, component) => {
736
+ acc[component.uid] = component;
737
+ return acc;
738
+ }, {});
739
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
740
+ return {
741
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
742
+ contentType: contentType2,
743
+ contentTypes: data?.contentTypes ?? []
744
+ };
745
+ }, [model, data]);
761
746
  React.useEffect(() => {
762
747
  if (error) {
763
748
  toggleNotification({
@@ -812,7 +797,10 @@ const useDocument = (args, opts) => {
812
797
  isLoading: isLoadingDocument,
813
798
  isFetching: isFetchingDocument,
814
799
  error
815
- } = useGetDocumentQuery(args, opts);
800
+ } = useGetDocumentQuery(args, {
801
+ ...opts,
802
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
803
+ });
816
804
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
817
805
  React.useEffect(() => {
818
806
  if (error) {
@@ -840,7 +828,7 @@ const useDocument = (args, opts) => {
840
828
  return null;
841
829
  } catch (error2) {
842
830
  if (error2 instanceof ValidationError) {
843
- return getInnerErrors(error2);
831
+ return getYupValidationErrors(error2);
844
832
  }
845
833
  throw error2;
846
834
  }
@@ -898,6 +886,7 @@ const useDocumentActions = () => {
898
886
  const { formatMessage } = useIntl();
899
887
  const { trackUsage } = useTracking();
900
888
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
889
+ const navigate = useNavigate();
901
890
  const [deleteDocument] = useDeleteDocumentMutation();
902
891
  const _delete = React.useCallback(
903
892
  async ({ collectionType, model, documentId, params }, trackerProperty) => {
@@ -936,14 +925,53 @@ const useDocumentActions = () => {
936
925
  },
937
926
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
938
927
  );
928
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
929
+ const deleteMany = React.useCallback(
930
+ async ({ model, documentIds, params }) => {
931
+ try {
932
+ trackUsage("willBulkDeleteEntries");
933
+ const res = await deleteManyDocuments({
934
+ model,
935
+ documentIds,
936
+ params
937
+ });
938
+ if ("error" in res) {
939
+ toggleNotification({
940
+ type: "danger",
941
+ message: formatAPIError(res.error)
942
+ });
943
+ return { error: res.error };
944
+ }
945
+ toggleNotification({
946
+ type: "success",
947
+ title: formatMessage({
948
+ id: getTranslation("success.records.delete"),
949
+ defaultMessage: "Successfully deleted."
950
+ }),
951
+ message: ""
952
+ });
953
+ trackUsage("didBulkDeleteEntries");
954
+ return res.data;
955
+ } catch (err) {
956
+ toggleNotification({
957
+ type: "danger",
958
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
959
+ });
960
+ trackUsage("didNotBulkDeleteEntries");
961
+ throw err;
962
+ }
963
+ },
964
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
965
+ );
939
966
  const [discardDocument] = useDiscardDocumentMutation();
940
967
  const discard = React.useCallback(
941
- async ({ collectionType, model, documentId }) => {
968
+ async ({ collectionType, model, documentId, params }) => {
942
969
  try {
943
970
  const res = await discardDocument({
944
971
  collectionType,
945
972
  model,
946
- documentId
973
+ documentId,
974
+ params
947
975
  });
948
976
  if ("error" in res) {
949
977
  toggleNotification({
@@ -1005,6 +1033,43 @@ const useDocumentActions = () => {
1005
1033
  },
1006
1034
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1007
1035
  );
1036
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1037
+ const publishMany = React.useCallback(
1038
+ async ({ model, documentIds, params }) => {
1039
+ try {
1040
+ const res = await publishManyDocuments({
1041
+ model,
1042
+ documentIds,
1043
+ params
1044
+ });
1045
+ if ("error" in res) {
1046
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1047
+ return { error: res.error };
1048
+ }
1049
+ toggleNotification({
1050
+ type: "success",
1051
+ message: formatMessage({
1052
+ id: getTranslation("success.record.publish"),
1053
+ defaultMessage: "Published document"
1054
+ })
1055
+ });
1056
+ return res.data;
1057
+ } catch (err) {
1058
+ toggleNotification({
1059
+ type: "danger",
1060
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1061
+ });
1062
+ throw err;
1063
+ }
1064
+ },
1065
+ [
1066
+ // trackUsage,
1067
+ publishManyDocuments,
1068
+ toggleNotification,
1069
+ formatMessage,
1070
+ formatAPIError
1071
+ ]
1072
+ );
1008
1073
  const [updateDocument] = useUpdateDocumentMutation();
1009
1074
  const update = React.useCallback(
1010
1075
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1079,6 +1144,41 @@ const useDocumentActions = () => {
1079
1144
  },
1080
1145
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1081
1146
  );
1147
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1148
+ const unpublishMany = React.useCallback(
1149
+ async ({ model, documentIds, params }) => {
1150
+ try {
1151
+ trackUsage("willBulkUnpublishEntries");
1152
+ const res = await unpublishManyDocuments({
1153
+ model,
1154
+ documentIds,
1155
+ params
1156
+ });
1157
+ if ("error" in res) {
1158
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1159
+ return { error: res.error };
1160
+ }
1161
+ trackUsage("didBulkUnpublishEntries");
1162
+ toggleNotification({
1163
+ type: "success",
1164
+ title: formatMessage({
1165
+ id: getTranslation("success.records.unpublish"),
1166
+ defaultMessage: "Successfully unpublished."
1167
+ }),
1168
+ message: ""
1169
+ });
1170
+ return res.data;
1171
+ } catch (err) {
1172
+ toggleNotification({
1173
+ type: "danger",
1174
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1175
+ });
1176
+ trackUsage("didNotBulkUnpublishEntries");
1177
+ throw err;
1178
+ }
1179
+ },
1180
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1181
+ );
1082
1182
  const [createDocument] = useCreateDocumentMutation();
1083
1183
  const create = React.useCallback(
1084
1184
  async ({ model, params }, data, trackerProperty) => {
@@ -1122,7 +1222,6 @@ const useDocumentActions = () => {
1122
1222
  sourceId
1123
1223
  });
1124
1224
  if ("error" in res) {
1125
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1126
1225
  return { error: res.error };
1127
1226
  }
1128
1227
  toggleNotification({
@@ -1141,7 +1240,7 @@ const useDocumentActions = () => {
1141
1240
  throw err;
1142
1241
  }
1143
1242
  },
1144
- [autoCloneDocument, formatAPIError, formatMessage, toggleNotification]
1243
+ [autoCloneDocument, formatMessage, toggleNotification]
1145
1244
  );
1146
1245
  const [cloneDocument] = useCloneDocumentMutation();
1147
1246
  const clone = React.useCallback(
@@ -1167,6 +1266,7 @@ const useDocumentActions = () => {
1167
1266
  defaultMessage: "Cloned document"
1168
1267
  })
1169
1268
  });
1269
+ navigate(`../../${res.data.data.documentId}`, { relative: "path" });
1170
1270
  return res.data;
1171
1271
  } catch (err) {
1172
1272
  toggleNotification({
@@ -1177,7 +1277,7 @@ const useDocumentActions = () => {
1177
1277
  throw err;
1178
1278
  }
1179
1279
  },
1180
- [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
1280
+ [cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
1181
1281
  );
1182
1282
  const [getDoc] = useLazyGetDocumentQuery();
1183
1283
  const getDocument = React.useCallback(
@@ -1192,15 +1292,18 @@ const useDocumentActions = () => {
1192
1292
  clone,
1193
1293
  create,
1194
1294
  delete: _delete,
1295
+ deleteMany,
1195
1296
  discard,
1196
1297
  getDocument,
1197
1298
  publish,
1299
+ publishMany,
1198
1300
  unpublish,
1301
+ unpublishMany,
1199
1302
  update
1200
1303
  };
1201
1304
  };
1202
1305
  const ProtectedHistoryPage = lazy(
1203
- () => import("./History-Dmr9fmUA.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1306
+ () => import("./History-BMunT-do.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1204
1307
  );
1205
1308
  const routes$1 = [
1206
1309
  {
@@ -1213,31 +1316,31 @@ const routes$1 = [
1213
1316
  }
1214
1317
  ];
1215
1318
  const ProtectedEditViewPage = lazy(
1216
- () => import("./EditViewPage-DDS6H9HO.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1319
+ () => import("./EditViewPage-DeTn7rAF.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1217
1320
  );
1218
1321
  const ProtectedListViewPage = lazy(
1219
- () => import("./ListViewPage-BtAwuYLE.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1322
+ () => import("./ListViewPage-_5gS-DOF.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1220
1323
  );
1221
1324
  const ProtectedListConfiguration = lazy(
1222
- () => import("./ListConfigurationPage-DhwvYcNv.mjs").then((mod) => ({
1325
+ () => import("./ListConfigurationPage-CDqkCxgV.mjs").then((mod) => ({
1223
1326
  default: mod.ProtectedListConfiguration
1224
1327
  }))
1225
1328
  );
1226
1329
  const ProtectedEditConfigurationPage = lazy(
1227
- () => import("./EditConfigurationPage-DacbqQ_f.mjs").then((mod) => ({
1330
+ () => import("./EditConfigurationPage-CE_yavTi.mjs").then((mod) => ({
1228
1331
  default: mod.ProtectedEditConfigurationPage
1229
1332
  }))
1230
1333
  );
1231
1334
  const ProtectedComponentConfigurationPage = lazy(
1232
- () => import("./ComponentConfigurationPage-BPvzFjM7.mjs").then((mod) => ({
1335
+ () => import("./ComponentConfigurationPage-CpBFh6_r.mjs").then((mod) => ({
1233
1336
  default: mod.ProtectedComponentConfigurationPage
1234
1337
  }))
1235
1338
  );
1236
1339
  const NoPermissions = lazy(
1237
- () => import("./NoPermissionsPage-UWDC-1Tw.mjs").then((mod) => ({ default: mod.NoPermissions }))
1340
+ () => import("./NoPermissionsPage-Bs8D5W_v.mjs").then((mod) => ({ default: mod.NoPermissions }))
1238
1341
  );
1239
1342
  const NoContentType = lazy(
1240
- () => import("./NoContentTypePage-DSPxnxxp.mjs").then((mod) => ({ default: mod.NoContentType }))
1343
+ () => import("./NoContentTypePage-Dht-55hr.mjs").then((mod) => ({ default: mod.NoContentType }))
1241
1344
  );
1242
1345
  const CollectionTypePages = () => {
1243
1346
  const { collectionType } = useParams();
@@ -1351,12 +1454,14 @@ const DocumentActionButton = (action) => {
1351
1454
  /* @__PURE__ */ jsx(
1352
1455
  Button,
1353
1456
  {
1354
- flex: 1,
1457
+ flex: "auto",
1355
1458
  startIcon: action.icon,
1356
1459
  disabled: action.disabled,
1357
1460
  onClick: handleClick(action),
1358
1461
  justifyContent: "center",
1359
1462
  variant: action.variant || "default",
1463
+ paddingTop: "7px",
1464
+ paddingBottom: "7px",
1360
1465
  children: action.label
1361
1466
  }
1362
1467
  ),
@@ -1364,7 +1469,7 @@ const DocumentActionButton = (action) => {
1364
1469
  DocumentActionConfirmDialog,
1365
1470
  {
1366
1471
  ...action.dialog,
1367
- variant: action.variant,
1472
+ variant: action.dialog?.variant ?? action.variant,
1368
1473
  isOpen: dialogId === action.id,
1369
1474
  onClose: handleClose
1370
1475
  }
@@ -1421,13 +1526,13 @@ const DocumentActionsMenu = ({
1421
1526
  disabled: isDisabled,
1422
1527
  size: "S",
1423
1528
  endIcon: null,
1424
- paddingTop: "7px",
1425
- paddingLeft: "9px",
1426
- paddingRight: "9px",
1529
+ paddingTop: "4px",
1530
+ paddingLeft: "7px",
1531
+ paddingRight: "7px",
1427
1532
  variant,
1428
1533
  children: [
1429
1534
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
1430
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: label || formatMessage({
1535
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
1431
1536
  id: "content-manager.containers.edit.panels.default.more-actions",
1432
1537
  defaultMessage: "More document actions"
1433
1538
  }) })
@@ -1443,10 +1548,25 @@ const DocumentActionsMenu = ({
1443
1548
  onSelect: handleClick(action),
1444
1549
  display: "block",
1445
1550
  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
- ] }),
1551
+ /* @__PURE__ */ jsxs(
1552
+ Flex,
1553
+ {
1554
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1555
+ gap: 2,
1556
+ tag: "span",
1557
+ children: [
1558
+ /* @__PURE__ */ jsx(
1559
+ Flex,
1560
+ {
1561
+ tag: "span",
1562
+ color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
1563
+ children: action.icon
1564
+ }
1565
+ ),
1566
+ action.label
1567
+ ]
1568
+ }
1569
+ ),
1450
1570
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1451
1571
  Flex,
1452
1572
  {
@@ -1505,6 +1625,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1505
1625
  return "primary600";
1506
1626
  }
1507
1627
  };
1628
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1629
+ switch (variant) {
1630
+ case "danger":
1631
+ return "danger600";
1632
+ case "secondary":
1633
+ return "neutral500";
1634
+ case "success":
1635
+ return "success600";
1636
+ default:
1637
+ return "primary600";
1638
+ }
1639
+ };
1508
1640
  const DocumentActionConfirmDialog = ({
1509
1641
  onClose,
1510
1642
  onCancel,
@@ -1527,61 +1659,42 @@ const DocumentActionConfirmDialog = ({
1527
1659
  }
1528
1660
  onClose();
1529
1661
  };
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
- ] });
1662
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1663
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1664
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1665
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1666
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
1667
+ id: "app.components.Button.cancel",
1668
+ defaultMessage: "Cancel"
1669
+ }) }) }),
1670
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
1671
+ id: "app.components.Button.confirm",
1672
+ defaultMessage: "Confirm"
1673
+ }) })
1674
+ ] })
1675
+ ] }) });
1546
1676
  };
1547
1677
  const DocumentActionModal = ({
1548
1678
  isOpen,
1549
1679
  title,
1550
1680
  onClose,
1551
1681
  footer: Footer,
1552
- content,
1682
+ content: Content,
1553
1683
  onModalClose
1554
1684
  }) => {
1555
- const id = React.useId();
1556
- if (!isOpen) {
1557
- return null;
1558
- }
1559
1685
  const handleClose = () => {
1560
1686
  if (onClose) {
1561
1687
  onClose();
1562
1688
  }
1563
1689
  onModalClose();
1564
1690
  };
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
- ] });
1691
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1692
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1693
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1694
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1695
+ ] }) });
1583
1696
  };
1584
- const PublishAction = ({
1697
+ const PublishAction$1 = ({
1585
1698
  activeTab,
1586
1699
  documentId,
1587
1700
  model,
@@ -1593,13 +1706,17 @@ const PublishAction = ({
1593
1706
  const navigate = useNavigate();
1594
1707
  const { toggleNotification } = useNotification();
1595
1708
  const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
1709
+ const isListView = useMatch(LIST_PATH) !== null;
1596
1710
  const isCloning = useMatch(CLONE_PATH) !== null;
1597
1711
  const { formatMessage } = useIntl();
1598
- const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
1599
- "PublishAction",
1600
- ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1601
- );
1712
+ const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
1602
1713
  const { publish } = useDocumentActions();
1714
+ const [
1715
+ countDraftRelations,
1716
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1717
+ ] = useLazyGetDraftRelationCountQuery();
1718
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1719
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1603
1720
  const [{ query, rawQuery }] = useQueryParams();
1604
1721
  const params = React.useMemo(() => buildValidParams(query), [query]);
1605
1722
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1608,10 +1725,103 @@ const PublishAction = ({
1608
1725
  const validate = useForm("PublishAction", (state) => state.validate);
1609
1726
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1610
1727
  const formValues = useForm("PublishAction", ({ values }) => values);
1728
+ React.useEffect(() => {
1729
+ if (isErrorDraftRelations) {
1730
+ toggleNotification({
1731
+ type: "danger",
1732
+ message: formatMessage({
1733
+ id: getTranslation("error.records.fetch-draft-relatons"),
1734
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1735
+ })
1736
+ });
1737
+ }
1738
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1739
+ React.useEffect(() => {
1740
+ const localDraftRelations = /* @__PURE__ */ new Set();
1741
+ const extractDraftRelations = (data) => {
1742
+ const relations = data.connect || [];
1743
+ relations.forEach((relation) => {
1744
+ if (relation.status === "draft") {
1745
+ localDraftRelations.add(relation.id);
1746
+ }
1747
+ });
1748
+ };
1749
+ const traverseAndExtract = (data) => {
1750
+ Object.entries(data).forEach(([key, value]) => {
1751
+ if (key === "connect" && Array.isArray(value)) {
1752
+ extractDraftRelations({ connect: value });
1753
+ } else if (typeof value === "object" && value !== null) {
1754
+ traverseAndExtract(value);
1755
+ }
1756
+ });
1757
+ };
1758
+ if (!documentId || modified) {
1759
+ traverseAndExtract(formValues);
1760
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1761
+ }
1762
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1763
+ React.useEffect(() => {
1764
+ if (!document || !document.documentId || isListView) {
1765
+ return;
1766
+ }
1767
+ const fetchDraftRelationsCount = async () => {
1768
+ const { data, error } = await countDraftRelations({
1769
+ collectionType,
1770
+ model,
1771
+ documentId,
1772
+ params
1773
+ });
1774
+ if (error) {
1775
+ throw error;
1776
+ }
1777
+ if (data) {
1778
+ setServerCountOfDraftRelations(data.data);
1779
+ }
1780
+ };
1781
+ fetchDraftRelationsCount();
1782
+ }, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
1611
1783
  const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1612
1784
  if (!schema?.options?.draftAndPublish) {
1613
1785
  return null;
1614
1786
  }
1787
+ const performPublish = async () => {
1788
+ setSubmitting(true);
1789
+ try {
1790
+ const { errors } = await validate();
1791
+ if (errors) {
1792
+ toggleNotification({
1793
+ type: "danger",
1794
+ message: formatMessage({
1795
+ id: "content-manager.validation.error",
1796
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1797
+ })
1798
+ });
1799
+ return;
1800
+ }
1801
+ const res = await publish(
1802
+ {
1803
+ collectionType,
1804
+ model,
1805
+ documentId,
1806
+ params
1807
+ },
1808
+ formValues
1809
+ );
1810
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1811
+ navigate({
1812
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1813
+ search: rawQuery
1814
+ });
1815
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1816
+ setErrors(formatValidationErrors(res.error));
1817
+ }
1818
+ } finally {
1819
+ setSubmitting(false);
1820
+ }
1821
+ };
1822
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1823
+ const enableDraftRelationsCount = false;
1824
+ const hasDraftRelations = enableDraftRelationsCount;
1615
1825
  return {
1616
1826
  /**
1617
1827
  * Disabled when:
@@ -1621,52 +1831,39 @@ const PublishAction = ({
1621
1831
  * - the document is already published & not modified
1622
1832
  * - the document is being created & not modified
1623
1833
  * - 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
1834
  */
1627
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1835
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1628
1836
  label: formatMessage({
1629
1837
  id: "app.utils.publish",
1630
1838
  defaultMessage: "Publish"
1631
1839
  }),
1632
1840
  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));
1841
+ await performPublish();
1842
+ },
1843
+ dialog: hasDraftRelations ? {
1844
+ type: "dialog",
1845
+ variant: "danger",
1846
+ footer: null,
1847
+ title: formatMessage({
1848
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1849
+ defaultMessage: "Confirmation"
1850
+ }),
1851
+ content: formatMessage(
1852
+ {
1853
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1854
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1855
+ },
1856
+ {
1857
+ count: totalDraftRelations
1662
1858
  }
1663
- } finally {
1664
- setSubmitting(false);
1859
+ ),
1860
+ onConfirm: async () => {
1861
+ await performPublish();
1665
1862
  }
1666
- }
1863
+ } : void 0
1667
1864
  };
1668
1865
  };
1669
- PublishAction.type = "publish";
1866
+ PublishAction$1.type = "publish";
1670
1867
  const UpdateAction = ({
1671
1868
  activeTab,
1672
1869
  documentId,
@@ -1679,10 +1876,6 @@ const UpdateAction = ({
1679
1876
  const cloneMatch = useMatch(CLONE_PATH);
1680
1877
  const isCloning = cloneMatch !== null;
1681
1878
  const { formatMessage } = useIntl();
1682
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1683
- canCreate: canCreate2,
1684
- canUpdate: canUpdate2
1685
- }));
1686
1879
  const { create, update, clone } = useDocumentActions();
1687
1880
  const [{ query, rawQuery }] = useQueryParams();
1688
1881
  const params = React.useMemo(() => buildValidParams(query), [query]);
@@ -1699,10 +1892,8 @@ const UpdateAction = ({
1699
1892
  * - the form is submitting
1700
1893
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1701
1894
  * - 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
1895
  */
1705
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1896
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1706
1897
  label: formatMessage({
1707
1898
  id: "content-manager.containers.Edit.save",
1708
1899
  defaultMessage: "Save"
@@ -1710,16 +1901,18 @@ const UpdateAction = ({
1710
1901
  onClick: async () => {
1711
1902
  setSubmitting(true);
1712
1903
  try {
1713
- const { errors } = await validate();
1714
- if (errors) {
1715
- toggleNotification({
1716
- type: "danger",
1717
- message: formatMessage({
1718
- id: "content-manager.validation.error",
1719
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1720
- })
1721
- });
1722
- return;
1904
+ if (activeTab !== "draft") {
1905
+ const { errors } = await validate();
1906
+ if (errors) {
1907
+ toggleNotification({
1908
+ type: "danger",
1909
+ message: formatMessage({
1910
+ id: "content-manager.validation.error",
1911
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1912
+ })
1913
+ });
1914
+ return;
1915
+ }
1723
1916
  }
1724
1917
  if (isCloning) {
1725
1918
  const res = await clone(
@@ -1731,10 +1924,13 @@ const UpdateAction = ({
1731
1924
  document
1732
1925
  );
1733
1926
  if ("data" in res) {
1734
- navigate({
1735
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1736
- search: rawQuery
1737
- });
1927
+ navigate(
1928
+ {
1929
+ pathname: `../${res.data.documentId}`,
1930
+ search: rawQuery
1931
+ },
1932
+ { relative: "path" }
1933
+ );
1738
1934
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1739
1935
  setErrors(formatValidationErrors(res.error));
1740
1936
  }
@@ -1762,10 +1958,13 @@ const UpdateAction = ({
1762
1958
  document
1763
1959
  );
1764
1960
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1765
- navigate({
1766
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1767
- search: rawQuery
1768
- });
1961
+ navigate(
1962
+ {
1963
+ pathname: `../${res.data.documentId}`,
1964
+ search: rawQuery
1965
+ },
1966
+ { replace: true, relative: "path" }
1967
+ );
1769
1968
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1770
1969
  setErrors(formatValidationErrors(res.error));
1771
1970
  }
@@ -1781,7 +1980,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1781
1980
  KEEP: "keep",
1782
1981
  DISCARD: "discard"
1783
1982
  };
1784
- const UnpublishAction = ({
1983
+ const UnpublishAction$1 = ({
1785
1984
  activeTab,
1786
1985
  documentId,
1787
1986
  model,
@@ -1797,10 +1996,8 @@ const UnpublishAction = ({
1797
1996
  const { toggleNotification } = useNotification();
1798
1997
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1799
1998
  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
- }
1999
+ const handleChange = (value) => {
2000
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1804
2001
  };
1805
2002
  if (!schema?.options?.draftAndPublish) {
1806
2003
  return null;
@@ -1811,7 +2008,7 @@ const UnpublishAction = ({
1811
2008
  id: "app.utils.unpublish",
1812
2009
  defaultMessage: "Unpublish"
1813
2010
  }),
1814
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2011
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1815
2012
  onClick: async () => {
1816
2013
  if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
1817
2014
  if (!documentId) {
@@ -1844,45 +2041,30 @@ const UnpublishAction = ({
1844
2041
  content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1845
2042
  /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
1846
2043
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1847
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2044
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1848
2045
  id: "content-manager.actions.unpublish.dialog.body",
1849
2046
  defaultMessage: "Are you sure?"
1850
2047
  }) })
1851
2048
  ] }),
1852
2049
  /* @__PURE__ */ jsxs(
1853
- Flex,
2050
+ Radio.Group,
1854
2051
  {
1855
- onChange: handleChange,
1856
- direction: "column",
1857
- alignItems: "flex-start",
1858
- as: "fieldset",
1859
- gap: 3,
2052
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2053
+ name: "discard-options",
2054
+ "aria-label": formatMessage({
2055
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2056
+ defaultMessage: "Choose an option to unpublish the document."
2057
+ }),
2058
+ onValueChange: handleChange,
1860
2059
  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
- )
2060
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2061
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2062
+ defaultMessage: "Keep draft"
2063
+ }) }),
2064
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2065
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2066
+ defaultMessage: "Replace draft"
2067
+ }) })
1886
2068
  ]
1887
2069
  }
1888
2070
  )
@@ -1915,7 +2097,7 @@ const UnpublishAction = ({
1915
2097
  position: ["panel", "table-row"]
1916
2098
  };
1917
2099
  };
1918
- UnpublishAction.type = "unpublish";
2100
+ UnpublishAction$1.type = "unpublish";
1919
2101
  const DiscardAction = ({
1920
2102
  activeTab,
1921
2103
  documentId,
@@ -1938,7 +2120,7 @@ const DiscardAction = ({
1938
2120
  id: "content-manager.actions.discard.label",
1939
2121
  defaultMessage: "Discard changes"
1940
2122
  }),
1941
- icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
2123
+ icon: /* @__PURE__ */ jsx(Cross, {}),
1942
2124
  position: ["panel", "table-row"],
1943
2125
  variant: "danger",
1944
2126
  dialog: {
@@ -1949,7 +2131,7 @@ const DiscardAction = ({
1949
2131
  }),
1950
2132
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
1951
2133
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1952
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2134
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1953
2135
  id: "content-manager.actions.discard.dialog.body",
1954
2136
  defaultMessage: "Are you sure?"
1955
2137
  }) })
@@ -1966,12 +2148,7 @@ const DiscardAction = ({
1966
2148
  };
1967
2149
  };
1968
2150
  DiscardAction.type = "discard";
1969
- const StyledCrossCircle = styled(CrossCircle)`
1970
- path {
1971
- fill: currentColor;
1972
- }
1973
- `;
1974
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2151
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1975
2152
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1976
2153
  const RelativeTime = React.forwardRef(
1977
2154
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2018,8 +2195,8 @@ const getDisplayName = ({
2018
2195
  };
2019
2196
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2020
2197
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2021
- 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) }) });
2198
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
2199
+ return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2023
2200
  };
2024
2201
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2025
2202
  const { formatMessage } = useIntl();
@@ -2028,23 +2205,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2028
2205
  id: "content-manager.containers.edit.title.new",
2029
2206
  defaultMessage: "Create an entry"
2030
2207
  }) : documentTitle;
2031
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2208
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2032
2209
  /* @__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
2210
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2211
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2212
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2213
+ ] }),
2214
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2048
2215
  ] });
2049
2216
  };
2050
2217
  const HeaderToolbar = () => {
@@ -2196,7 +2363,7 @@ const Information = ({ activeTab }) => {
2196
2363
  borderColor: "neutral150",
2197
2364
  direction: "column",
2198
2365
  marginTop: 2,
2199
- as: "dl",
2366
+ tag: "dl",
2200
2367
  padding: 5,
2201
2368
  gap: 3,
2202
2369
  alignItems: "flex-start",
@@ -2204,15 +2371,29 @@ const Information = ({ activeTab }) => {
2204
2371
  marginRight: "-0.4rem",
2205
2372
  width: "calc(100% + 8px)",
2206
2373
  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 })
2374
+ /* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2375
+ /* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2209
2376
  ] }, info.label))
2210
2377
  }
2211
2378
  );
2212
2379
  };
2213
2380
  const HeaderActions = ({ actions: actions2 }) => {
2214
- return /* @__PURE__ */ jsx(Flex, { children: actions2.map((action) => {
2215
- if ("options" in action) {
2381
+ const [dialogId, setDialogId] = React.useState(null);
2382
+ const handleClick = (action) => async (e) => {
2383
+ if (!("options" in action)) {
2384
+ const { onClick = () => false, dialog, id } = action;
2385
+ const muteDialog = await onClick(e);
2386
+ if (dialog && !muteDialog) {
2387
+ e.preventDefault();
2388
+ setDialogId(id);
2389
+ }
2390
+ }
2391
+ };
2392
+ const handleClose = () => {
2393
+ setDialogId(null);
2394
+ };
2395
+ return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
2396
+ if (action.options) {
2216
2397
  return /* @__PURE__ */ jsx(
2217
2398
  SingleSelect,
2218
2399
  {
@@ -2226,10 +2407,49 @@ const HeaderActions = ({ actions: actions2 }) => {
2226
2407
  action.id
2227
2408
  );
2228
2409
  } else {
2229
- return null;
2410
+ if (action.type === "icon") {
2411
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
2412
+ /* @__PURE__ */ jsx(
2413
+ IconButton,
2414
+ {
2415
+ disabled: action.disabled,
2416
+ label: action.label,
2417
+ size: "S",
2418
+ onClick: handleClick(action),
2419
+ children: action.icon
2420
+ }
2421
+ ),
2422
+ action.dialog ? /* @__PURE__ */ jsx(
2423
+ HeaderActionDialog,
2424
+ {
2425
+ ...action.dialog,
2426
+ isOpen: dialogId === action.id,
2427
+ onClose: handleClose
2428
+ }
2429
+ ) : null
2430
+ ] }, action.id);
2431
+ }
2230
2432
  }
2231
2433
  }) });
2232
2434
  };
2435
+ const HeaderActionDialog = ({
2436
+ onClose,
2437
+ onCancel,
2438
+ title,
2439
+ content: Content,
2440
+ isOpen
2441
+ }) => {
2442
+ const handleClose = async () => {
2443
+ if (onCancel) {
2444
+ await onCancel();
2445
+ }
2446
+ onClose();
2447
+ };
2448
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2449
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
2450
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
2451
+ ] }) });
2452
+ };
2233
2453
  const ConfigureTheViewAction = ({ collectionType, model }) => {
2234
2454
  const navigate = useNavigate();
2235
2455
  const { formatMessage } = useIntl();
@@ -2238,7 +2458,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2238
2458
  id: "app.links.configure-view",
2239
2459
  defaultMessage: "Configure the view"
2240
2460
  }),
2241
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2461
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2242
2462
  onClick: () => {
2243
2463
  navigate(`../${collectionType}/${model}/configurations/edit`);
2244
2464
  },
@@ -2246,11 +2466,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2246
2466
  };
2247
2467
  };
2248
2468
  ConfigureTheViewAction.type = "configure-the-view";
2249
- const StyledCog = styled(Cog)`
2250
- path {
2251
- fill: currentColor;
2252
- }
2253
- `;
2254
2469
  const EditTheModelAction = ({ model }) => {
2255
2470
  const navigate = useNavigate();
2256
2471
  const { formatMessage } = useIntl();
@@ -2259,7 +2474,7 @@ const EditTheModelAction = ({ model }) => {
2259
2474
  id: "content-manager.link-to-ctb",
2260
2475
  defaultMessage: "Edit the model"
2261
2476
  }),
2262
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2477
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2263
2478
  onClick: () => {
2264
2479
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2265
2480
  },
@@ -2267,12 +2482,7 @@ const EditTheModelAction = ({ model }) => {
2267
2482
  };
2268
2483
  };
2269
2484
  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 }) => {
2485
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2276
2486
  const navigate = useNavigate();
2277
2487
  const { formatMessage } = useIntl();
2278
2488
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2286,7 +2496,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2286
2496
  id: "content-manager.actions.delete.label",
2287
2497
  defaultMessage: "Delete document"
2288
2498
  }),
2289
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2499
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2290
2500
  dialog: {
2291
2501
  type: "dialog",
2292
2502
  title: formatMessage({
@@ -2295,7 +2505,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2295
2505
  }),
2296
2506
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2297
2507
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2298
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2508
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2299
2509
  id: "content-manager.actions.delete.dialog.body",
2300
2510
  defaultMessage: "Are you sure?"
2301
2511
  }) })
@@ -2340,13 +2550,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2340
2550
  position: ["header", "table-row"]
2341
2551
  };
2342
2552
  };
2343
- DeleteAction.type = "delete";
2344
- const StyledTrash = styled(Trash)`
2345
- path {
2346
- fill: currentColor;
2347
- }
2348
- `;
2349
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2553
+ DeleteAction$1.type = "delete";
2554
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2350
2555
  const Panels = () => {
2351
2556
  const isCloning = useMatch(CLONE_PATH) !== null;
2352
2557
  const [
@@ -2380,7 +2585,7 @@ const ActionsPanel = () => {
2380
2585
  return {
2381
2586
  title: formatMessage({
2382
2587
  id: "content-manager.containers.edit.panels.default.title",
2383
- defaultMessage: "Document"
2588
+ defaultMessage: "Entry"
2384
2589
  }),
2385
2590
  content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
2386
2591
  };
@@ -2420,7 +2625,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2420
2625
  Flex,
2421
2626
  {
2422
2627
  ref,
2423
- as: "aside",
2628
+ tag: "aside",
2424
2629
  "aria-labelledby": "additional-information",
2425
2630
  background: "neutral0",
2426
2631
  borderColor: "neutral150",
@@ -2435,89 +2640,977 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2435
2640
  justifyContent: "stretch",
2436
2641
  alignItems: "flex-start",
2437
2642
  children: [
2438
- /* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2643
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2439
2644
  children
2440
2645
  ]
2441
2646
  }
2442
2647
  );
2443
2648
  });
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
- ] });
2649
+ const HOOKS = {
2650
+ /**
2651
+ * Hook that allows to mutate the displayed headers of the list view table
2652
+ * @constant
2653
+ * @type {string}
2654
+ */
2655
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2656
+ /**
2657
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2658
+ * @constant
2659
+ * @type {string}
2660
+ */
2661
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2662
+ /**
2663
+ * Hook that allows to mutate the CM's edit view layout
2664
+ * @constant
2665
+ * @type {string}
2666
+ */
2667
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2668
+ /**
2669
+ * Hook that allows to mutate the CM's single types links pre-set filters
2670
+ * @constant
2671
+ * @type {string}
2672
+ */
2673
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2497
2674
  };
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,
2675
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2676
+ endpoints: (builder) => ({
2677
+ getContentTypeConfiguration: builder.query({
2678
+ query: (uid) => ({
2679
+ url: `/content-manager/content-types/${uid}/configuration`,
2680
+ method: "GET"
2681
+ }),
2682
+ transformResponse: (response) => response.data,
2683
+ providesTags: (_result, _error, uid) => [
2684
+ { type: "ContentTypesConfiguration", id: uid },
2685
+ { type: "ContentTypeSettings", id: "LIST" }
2686
+ ]
2687
+ }),
2688
+ getAllContentTypeSettings: builder.query({
2689
+ query: () => "/content-manager/content-types-settings",
2690
+ transformResponse: (response) => response.data,
2691
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2692
+ }),
2693
+ updateContentTypeConfiguration: builder.mutation({
2694
+ query: ({ uid, ...body }) => ({
2695
+ url: `/content-manager/content-types/${uid}/configuration`,
2696
+ method: "PUT",
2697
+ data: body
2698
+ }),
2699
+ transformResponse: (response) => response.data,
2700
+ invalidatesTags: (_result, _error, { uid }) => [
2701
+ { type: "ContentTypesConfiguration", id: uid },
2702
+ { type: "ContentTypeSettings", id: "LIST" },
2703
+ // Is this necessary?
2704
+ { type: "InitialData" }
2705
+ ]
2706
+ })
2707
+ })
2708
+ });
2709
+ const {
2710
+ useGetContentTypeConfigurationQuery,
2711
+ useGetAllContentTypeSettingsQuery,
2712
+ useUpdateContentTypeConfigurationMutation
2713
+ } = contentTypesApi;
2714
+ const checkIfAttributeIsDisplayable = (attribute) => {
2715
+ const { type } = attribute;
2716
+ if (type === "relation") {
2717
+ return !attribute.relation.toLowerCase().includes("morph");
2718
+ }
2719
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2720
+ };
2721
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2722
+ if (!mainFieldName) {
2723
+ return void 0;
2724
+ }
2725
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2726
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2727
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2728
+ );
2729
+ return {
2730
+ name: mainFieldName,
2731
+ type: mainFieldType ?? "string"
2732
+ };
2733
+ };
2734
+ const DEFAULT_SETTINGS = {
2735
+ bulkable: false,
2736
+ filterable: false,
2737
+ searchable: false,
2738
+ pagination: false,
2739
+ defaultSortBy: "",
2740
+ defaultSortOrder: "asc",
2741
+ mainField: "id",
2742
+ pageSize: 10
2743
+ };
2744
+ const useDocumentLayout = (model) => {
2745
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2746
+ const [{ query }] = useQueryParams();
2747
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2748
+ const { toggleNotification } = useNotification();
2749
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2750
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2751
+ const {
2752
+ data,
2753
+ isLoading: isLoadingConfigs,
2754
+ error,
2755
+ isFetching: isFetchingConfigs
2756
+ } = useGetContentTypeConfigurationQuery(model);
2757
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2758
+ React.useEffect(() => {
2759
+ if (error) {
2760
+ toggleNotification({
2761
+ type: "danger",
2762
+ message: formatAPIError(error)
2763
+ });
2764
+ }
2765
+ }, [error, formatAPIError, toggleNotification]);
2766
+ const editLayout = React.useMemo(
2767
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2768
+ layout: [],
2769
+ components: {},
2770
+ metadatas: {},
2771
+ options: {},
2772
+ settings: DEFAULT_SETTINGS
2773
+ },
2774
+ [data, isLoading, schemas, schema, components]
2775
+ );
2776
+ const listLayout = React.useMemo(() => {
2777
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2778
+ layout: [],
2779
+ metadatas: {},
2780
+ options: {},
2781
+ settings: DEFAULT_SETTINGS
2782
+ };
2783
+ }, [data, isLoading, schemas, schema, components]);
2784
+ const { layout: edit } = React.useMemo(
2785
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2786
+ layout: editLayout,
2787
+ query
2788
+ }),
2789
+ [editLayout, query, runHookWaterfall]
2790
+ );
2791
+ return {
2792
+ error,
2793
+ isLoading,
2794
+ edit,
2795
+ list: listLayout
2796
+ };
2797
+ };
2798
+ const useDocLayout = () => {
2799
+ const { model } = useDoc();
2800
+ return useDocumentLayout(model);
2801
+ };
2802
+ const formatEditLayout = (data, {
2803
+ schemas,
2804
+ schema,
2805
+ components
2806
+ }) => {
2807
+ let currentPanelIndex = 0;
2808
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2809
+ data.contentType.layouts.edit,
2810
+ schema?.attributes,
2811
+ data.contentType.metadatas,
2812
+ { configurations: data.components, schemas: components },
2813
+ schemas
2814
+ ).reduce((panels, row) => {
2815
+ if (row.some((field) => field.type === "dynamiczone")) {
2816
+ panels.push([row]);
2817
+ currentPanelIndex += 2;
2818
+ } else {
2819
+ if (!panels[currentPanelIndex]) {
2820
+ panels.push([]);
2821
+ }
2822
+ panels[currentPanelIndex].push(row);
2823
+ }
2824
+ return panels;
2825
+ }, []);
2826
+ const componentEditAttributes = Object.entries(data.components).reduce(
2827
+ (acc, [uid, configuration]) => {
2828
+ acc[uid] = {
2829
+ layout: convertEditLayoutToFieldLayouts(
2830
+ configuration.layouts.edit,
2831
+ components[uid].attributes,
2832
+ configuration.metadatas,
2833
+ { configurations: data.components, schemas: components }
2834
+ ),
2835
+ settings: {
2836
+ ...configuration.settings,
2837
+ icon: components[uid].info.icon,
2838
+ displayName: components[uid].info.displayName
2839
+ }
2840
+ };
2841
+ return acc;
2842
+ },
2843
+ {}
2844
+ );
2845
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2846
+ (acc, [attribute, metadata]) => {
2847
+ return {
2848
+ ...acc,
2849
+ [attribute]: metadata.edit
2850
+ };
2851
+ },
2852
+ {}
2853
+ );
2854
+ return {
2855
+ layout: panelledEditAttributes,
2856
+ components: componentEditAttributes,
2857
+ metadatas: editMetadatas,
2858
+ settings: {
2859
+ ...data.contentType.settings,
2860
+ displayName: schema?.info.displayName
2861
+ },
2862
+ options: {
2863
+ ...schema?.options,
2864
+ ...schema?.pluginOptions,
2865
+ ...data.contentType.options
2866
+ }
2867
+ };
2868
+ };
2869
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2870
+ return rows.map(
2871
+ (row) => row.map((field) => {
2872
+ const attribute = attributes[field.name];
2873
+ if (!attribute) {
2874
+ return null;
2875
+ }
2876
+ const { edit: metadata } = metadatas[field.name];
2877
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2878
+ return {
2879
+ attribute,
2880
+ disabled: !metadata.editable,
2881
+ hint: metadata.description,
2882
+ label: metadata.label ?? "",
2883
+ name: field.name,
2884
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2885
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2886
+ schemas,
2887
+ components: components?.schemas ?? {}
2888
+ }),
2889
+ placeholder: metadata.placeholder ?? "",
2890
+ required: attribute.required ?? false,
2891
+ size: field.size,
2892
+ unique: "unique" in attribute ? attribute.unique : false,
2893
+ visible: metadata.visible ?? true,
2894
+ type: attribute.type
2895
+ };
2896
+ }).filter((field) => field !== null)
2897
+ );
2898
+ };
2899
+ const formatListLayout = (data, {
2900
+ schemas,
2901
+ schema,
2902
+ components
2903
+ }) => {
2904
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2905
+ (acc, [attribute, metadata]) => {
2906
+ return {
2907
+ ...acc,
2908
+ [attribute]: metadata.list
2909
+ };
2910
+ },
2911
+ {}
2912
+ );
2913
+ const listAttributes = convertListLayoutToFieldLayouts(
2914
+ data.contentType.layouts.list,
2915
+ schema?.attributes,
2916
+ listMetadatas,
2917
+ { configurations: data.components, schemas: components },
2918
+ schemas
2919
+ );
2920
+ return {
2921
+ layout: listAttributes,
2922
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2923
+ metadatas: listMetadatas,
2924
+ options: {
2925
+ ...schema?.options,
2926
+ ...schema?.pluginOptions,
2927
+ ...data.contentType.options
2928
+ }
2929
+ };
2930
+ };
2931
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2932
+ return columns.map((name) => {
2933
+ const attribute = attributes[name];
2934
+ if (!attribute) {
2935
+ return null;
2936
+ }
2937
+ const metadata = metadatas[name];
2938
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2939
+ return {
2940
+ attribute,
2941
+ label: metadata.label ?? "",
2942
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2943
+ schemas,
2944
+ components: components?.schemas ?? {}
2945
+ }),
2946
+ name,
2947
+ searchable: metadata.searchable ?? true,
2948
+ sortable: metadata.sortable ?? true
2949
+ };
2950
+ }).filter((field) => field !== null);
2951
+ };
2952
+ const ConfirmBulkActionDialog = ({
2953
+ onToggleDialog,
2954
+ isOpen = false,
2955
+ dialogBody,
2956
+ endAction
2957
+ }) => {
2958
+ const { formatMessage } = useIntl();
2959
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2960
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2961
+ id: "app.components.ConfirmDialog.title",
2962
+ defaultMessage: "Confirmation"
2963
+ }) }),
2964
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2965
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2966
+ dialogBody
2967
+ ] }) }),
2968
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2969
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2970
+ id: "app.components.Button.cancel",
2971
+ defaultMessage: "Cancel"
2972
+ }) }) }),
2973
+ endAction
2974
+ ] })
2975
+ ] }) });
2976
+ };
2977
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2978
+ const ConfirmDialogPublishAll = ({
2979
+ isOpen,
2980
+ onToggleDialog,
2981
+ isConfirmButtonLoading = false,
2982
+ onConfirm
2983
+ }) => {
2984
+ const { formatMessage } = useIntl();
2985
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2986
+ const { toggleNotification } = useNotification();
2987
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2988
+ const { model, schema } = useDoc();
2989
+ const [{ query }] = useQueryParams();
2990
+ const enableDraftRelationsCount = false;
2991
+ const {
2992
+ data: countDraftRelations = 0,
2993
+ isLoading,
2994
+ error
2995
+ } = useGetManyDraftRelationCountQuery(
2996
+ {
2997
+ model,
2998
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2999
+ locale: query?.plugins?.i18n?.locale
3000
+ },
3001
+ {
3002
+ skip: !enableDraftRelationsCount
3003
+ }
3004
+ );
3005
+ React.useEffect(() => {
3006
+ if (error) {
3007
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
3008
+ }
3009
+ }, [error, formatAPIError, toggleNotification]);
3010
+ if (error) {
3011
+ return null;
3012
+ }
3013
+ return /* @__PURE__ */ jsx(
3014
+ ConfirmBulkActionDialog,
3015
+ {
3016
+ isOpen: isOpen && !isLoading,
3017
+ onToggleDialog,
3018
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
3019
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
3020
+ countDraftRelations > 0 && formatMessage(
3021
+ {
3022
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
3023
+ 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. "
3024
+ },
3025
+ {
3026
+ b: BoldChunk$1,
3027
+ count: countDraftRelations,
3028
+ entities: selectedEntries.length
3029
+ }
3030
+ ),
3031
+ formatMessage({
3032
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
3033
+ defaultMessage: "Are you sure you want to publish these entries?"
3034
+ })
3035
+ ] }),
3036
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
3037
+ {
3038
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
3039
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
3040
+ },
3041
+ {
3042
+ em: Emphasis
3043
+ }
3044
+ ) })
3045
+ ] }),
3046
+ endAction: /* @__PURE__ */ jsx(
3047
+ Button,
3048
+ {
3049
+ onClick: onConfirm,
3050
+ variant: "secondary",
3051
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
3052
+ loading: isConfirmButtonLoading,
3053
+ children: formatMessage({
3054
+ id: "app.utils.publish",
3055
+ defaultMessage: "Publish"
3056
+ })
3057
+ }
3058
+ )
3059
+ }
3060
+ );
3061
+ };
3062
+ const TypographyMaxWidth = styled(Typography)`
3063
+ max-width: 300px;
3064
+ `;
3065
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
3066
+ const messages = [];
3067
+ Object.entries(errors).forEach(([key, value]) => {
3068
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3069
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3070
+ if ("id" in value && "defaultMessage" in value) {
3071
+ messages.push(
3072
+ formatMessage(
3073
+ {
3074
+ id: `${value.id}.withField`,
3075
+ defaultMessage: value.defaultMessage
3076
+ },
3077
+ { field: currentKey }
3078
+ )
3079
+ );
3080
+ } else {
3081
+ messages.push(
3082
+ ...formatErrorMessages(
3083
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3084
+ value,
3085
+ currentKey,
3086
+ formatMessage
3087
+ )
3088
+ );
3089
+ }
3090
+ } else {
3091
+ messages.push(
3092
+ formatMessage(
3093
+ {
3094
+ id: `${value}.withField`,
3095
+ defaultMessage: value
3096
+ },
3097
+ { field: currentKey }
3098
+ )
3099
+ );
3100
+ }
3101
+ });
3102
+ return messages;
3103
+ };
3104
+ const EntryValidationText = ({ validationErrors, status }) => {
3105
+ const { formatMessage } = useIntl();
3106
+ if (validationErrors) {
3107
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3108
+ " "
3109
+ );
3110
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3111
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3112
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3113
+ ] });
3114
+ }
3115
+ if (status === "published") {
3116
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3117
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3118
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3119
+ id: "content-manager.bulk-publish.already-published",
3120
+ defaultMessage: "Already Published"
3121
+ }) })
3122
+ ] });
3123
+ }
3124
+ if (status === "modified") {
3125
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3126
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3127
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3128
+ id: "content-manager.bulk-publish.modified",
3129
+ defaultMessage: "Ready to publish changes"
3130
+ }) })
3131
+ ] });
3132
+ }
3133
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3134
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3135
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3136
+ id: "app.utils.ready-to-publish",
3137
+ defaultMessage: "Ready to publish"
3138
+ }) })
3139
+ ] });
3140
+ };
3141
+ const TABLE_HEADERS = [
3142
+ { name: "id", label: "id" },
3143
+ { name: "name", label: "name" },
3144
+ { name: "status", label: "status" },
3145
+ { name: "publicationStatus", label: "Publication status" }
3146
+ ];
3147
+ const SelectedEntriesTableContent = ({
3148
+ isPublishing,
3149
+ rowsToDisplay = [],
3150
+ entriesToPublish = [],
3151
+ validationErrors = {}
3152
+ }) => {
3153
+ const { pathname } = useLocation();
3154
+ const { formatMessage } = useIntl();
3155
+ const {
3156
+ list: {
3157
+ settings: { mainField }
3158
+ }
3159
+ } = useDocLayout();
3160
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3161
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3162
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3163
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3164
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3165
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3166
+ )
3167
+ ] }),
3168
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3169
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3170
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3171
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3172
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3173
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3174
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3175
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3176
+ id: "content-manager.success.record.publishing",
3177
+ defaultMessage: "Publishing..."
3178
+ }) }),
3179
+ /* @__PURE__ */ jsx(Loader, { small: true })
3180
+ ] }) : /* @__PURE__ */ jsx(
3181
+ EntryValidationText,
3182
+ {
3183
+ validationErrors: validationErrors[row.documentId],
3184
+ status: row.status
3185
+ }
3186
+ ) }),
3187
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
3188
+ IconButton,
3189
+ {
3190
+ tag: Link,
3191
+ to: {
3192
+ pathname: `${pathname}/${row.documentId}`,
3193
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3194
+ },
3195
+ state: { from: pathname },
3196
+ label: formatMessage(
3197
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3198
+ {
3199
+ target: formatMessage(
3200
+ {
3201
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3202
+ defaultMessage: "item line {number}"
3203
+ },
3204
+ { number: index2 + 1 }
3205
+ )
3206
+ }
3207
+ ),
3208
+ target: "_blank",
3209
+ marginLeft: "auto",
3210
+ variant: "ghost",
3211
+ children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
3212
+ }
3213
+ ) }) })
3214
+ ] }, row.id)) })
3215
+ ] });
3216
+ };
3217
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3218
+ const SelectedEntriesModalContent = ({
3219
+ listViewSelectedEntries,
3220
+ toggleModal,
3221
+ setListViewSelectedDocuments,
3222
+ model
3223
+ }) => {
3224
+ const { formatMessage } = useIntl();
3225
+ const { schema, components } = useContentTypeSchema(model);
3226
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3227
+ const [{ query }] = useQueryParams();
3228
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3229
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3230
+ {
3231
+ model,
3232
+ params: {
3233
+ page: "1",
3234
+ pageSize: documentIds.length.toString(),
3235
+ sort: query.sort,
3236
+ filters: {
3237
+ documentId: {
3238
+ $in: documentIds
3239
+ }
3240
+ },
3241
+ locale: query.plugins?.i18n?.locale
3242
+ }
3243
+ },
3244
+ {
3245
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3246
+ }
3247
+ );
3248
+ const { rows, validationErrors } = React.useMemo(() => {
3249
+ if (data.length > 0 && schema) {
3250
+ const validate = createYupSchema(
3251
+ schema.attributes,
3252
+ components,
3253
+ // Since this is the "Publish" action, the validation
3254
+ // schema must enforce the rules for published entities
3255
+ { status: "published" }
3256
+ );
3257
+ const validationErrors2 = {};
3258
+ const rows2 = data.map((entry) => {
3259
+ try {
3260
+ validate.validateSync(entry, { abortEarly: false });
3261
+ return entry;
3262
+ } catch (e) {
3263
+ if (e instanceof ValidationError) {
3264
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3265
+ }
3266
+ return entry;
3267
+ }
3268
+ });
3269
+ return { rows: rows2, validationErrors: validationErrors2 };
3270
+ }
3271
+ return {
3272
+ rows: [],
3273
+ validationErrors: {}
3274
+ };
3275
+ }, [components, data, schema]);
3276
+ const [publishedCount, setPublishedCount] = React.useState(0);
3277
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3278
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3279
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3280
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3281
+ const selectedEntries = rows.filter(
3282
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3283
+ );
3284
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3285
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3286
+ ({ documentId }) => validationErrors[documentId]
3287
+ ).length;
3288
+ const selectedEntriesPublished = selectedEntries.filter(
3289
+ ({ status }) => status === "published"
3290
+ ).length;
3291
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3292
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3293
+ const handleConfirmBulkPublish = async () => {
3294
+ toggleDialog();
3295
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3296
+ if (!("error" in res)) {
3297
+ setPublishedCount(res.count);
3298
+ const unpublishedEntries = rows.filter((row) => {
3299
+ return !entriesToPublish.includes(row.documentId);
3300
+ });
3301
+ setListViewSelectedDocuments(unpublishedEntries);
3302
+ }
3303
+ };
3304
+ const getFormattedCountMessage = () => {
3305
+ if (publishedCount) {
3306
+ return formatMessage(
3307
+ {
3308
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3309
+ 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."
3310
+ },
3311
+ {
3312
+ publishedCount,
3313
+ withErrorsCount: selectedEntriesWithErrorsCount,
3314
+ b: BoldChunk
3315
+ }
3316
+ );
3317
+ }
3318
+ return formatMessage(
3319
+ {
3320
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3321
+ 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."
3322
+ },
3323
+ {
3324
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3325
+ withErrorsCount: selectedEntriesWithErrorsCount,
3326
+ alreadyPublishedCount: selectedEntriesPublished,
3327
+ b: BoldChunk
3328
+ }
3329
+ );
3330
+ };
3331
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3332
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3333
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3334
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3335
+ SelectedEntriesTableContent,
3336
+ {
3337
+ isPublishing: isSubmittingForm,
3338
+ rowsToDisplay: rows,
3339
+ entriesToPublish,
3340
+ validationErrors
3341
+ }
3342
+ ) })
3343
+ ] }),
3344
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3345
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3346
+ id: "app.components.Button.cancel",
3347
+ defaultMessage: "Cancel"
3348
+ }) }),
3349
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3350
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3351
+ /* @__PURE__ */ jsx(
3352
+ Button,
3353
+ {
3354
+ onClick: toggleDialog,
3355
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3356
+ loading: isSubmittingForm,
3357
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3358
+ }
3359
+ )
3360
+ ] })
3361
+ ] }),
3362
+ /* @__PURE__ */ jsx(
3363
+ ConfirmDialogPublishAll,
3364
+ {
3365
+ isOpen: isDialogOpen,
3366
+ onToggleDialog: toggleDialog,
3367
+ isConfirmButtonLoading: isSubmittingForm,
3368
+ onConfirm: handleConfirmBulkPublish
3369
+ }
3370
+ )
3371
+ ] });
3372
+ };
3373
+ const PublishAction = ({ documents, model }) => {
3374
+ const { formatMessage } = useIntl();
3375
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3376
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3377
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3378
+ const refetchList = () => {
3379
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3380
+ };
3381
+ if (!showPublishButton)
3382
+ return null;
3383
+ return {
3384
+ actionType: "publish",
3385
+ variant: "tertiary",
3386
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3387
+ dialog: {
3388
+ type: "modal",
3389
+ title: formatMessage({
3390
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3391
+ defaultMessage: "Publish entries"
3392
+ }),
3393
+ content: ({ onClose }) => {
3394
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3395
+ SelectedEntriesModalContent,
3396
+ {
3397
+ listViewSelectedEntries: documents,
3398
+ toggleModal: () => {
3399
+ onClose();
3400
+ refetchList();
3401
+ },
3402
+ setListViewSelectedDocuments,
3403
+ model
3404
+ }
3405
+ ) });
3406
+ },
3407
+ onClose: () => {
3408
+ refetchList();
3409
+ }
3410
+ }
3411
+ };
3412
+ };
3413
+ const BulkActionsRenderer = () => {
3414
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3415
+ const { model, collectionType } = useDoc();
3416
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3417
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3418
+ DescriptionComponentRenderer,
3419
+ {
3420
+ props: {
3421
+ model,
3422
+ collectionType,
3423
+ documents: selectedRows
3424
+ },
3425
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3426
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3427
+ }
3428
+ ) });
3429
+ };
3430
+ const DeleteAction = ({ documents, model }) => {
3431
+ const { formatMessage } = useIntl();
3432
+ const { schema: contentType } = useDoc();
3433
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3434
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3435
+ const [{ query }] = useQueryParams();
3436
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3437
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3438
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3439
+ const documentIds = documents.map(({ documentId }) => documentId);
3440
+ const handleConfirmBulkDelete = async () => {
3441
+ const res = await bulkDeleteAction({
3442
+ documentIds,
3443
+ model,
3444
+ params
3445
+ });
3446
+ if (!("error" in res)) {
3447
+ selectRow([]);
3448
+ }
3449
+ };
3450
+ if (!hasDeletePermission)
3451
+ return null;
3452
+ return {
3453
+ variant: "danger-light",
3454
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3455
+ dialog: {
3456
+ type: "dialog",
3457
+ title: formatMessage({
3458
+ id: "app.components.ConfirmDialog.title",
3459
+ defaultMessage: "Confirmation"
3460
+ }),
3461
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3462
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3463
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3464
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3465
+ defaultMessage: "Are you sure you want to delete these entries?"
3466
+ }) }),
3467
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3468
+ {
3469
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3470
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3471
+ },
3472
+ {
3473
+ em: Emphasis
3474
+ }
3475
+ ) }) })
3476
+ ] }),
3477
+ onConfirm: handleConfirmBulkDelete
3478
+ }
3479
+ };
3480
+ };
3481
+ DeleteAction.type = "delete";
3482
+ const UnpublishAction = ({ documents, model }) => {
3483
+ const { formatMessage } = useIntl();
3484
+ const { schema } = useDoc();
3485
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3486
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3487
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3488
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3489
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3490
+ const documentIds = documents.map(({ documentId }) => documentId);
3491
+ const [{ query }] = useQueryParams();
3492
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3493
+ const handleConfirmBulkUnpublish = async () => {
3494
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3495
+ if (!("error" in data)) {
3496
+ selectRow([]);
3497
+ }
3498
+ };
3499
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3500
+ if (!showUnpublishButton)
3501
+ return null;
3502
+ return {
3503
+ variant: "tertiary",
3504
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3505
+ dialog: {
3506
+ type: "dialog",
3507
+ title: formatMessage({
3508
+ id: "app.components.ConfirmDialog.title",
3509
+ defaultMessage: "Confirmation"
3510
+ }),
3511
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3512
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3513
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3514
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3515
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3516
+ }) }),
3517
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3518
+ {
3519
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3520
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3521
+ },
3522
+ {
3523
+ em: Emphasis
3524
+ }
3525
+ ) }) })
3526
+ ] }),
3527
+ confirmButton: formatMessage({
3528
+ id: "app.utils.unpublish",
3529
+ defaultMessage: "Unpublish"
3530
+ }),
3531
+ onConfirm: handleConfirmBulkUnpublish
3532
+ }
3533
+ };
3534
+ };
3535
+ UnpublishAction.type = "unpublish";
3536
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3537
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3538
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3539
+ const { formatMessage } = useIntl();
3540
+ const getDefaultErrorMessage = (reason) => {
3541
+ switch (reason) {
3542
+ case "relation":
3543
+ return "Duplicating the relation could remove it from the original entry.";
3544
+ case "unique":
3545
+ return "Identical values in a unique field are not allowed";
3546
+ default:
3547
+ return reason;
3548
+ }
3549
+ };
3550
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3551
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3552
+ id: getTranslation("containers.list.autoCloneModal.title"),
3553
+ defaultMessage: "This entry can't be duplicated directly."
3554
+ }) }),
3555
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3556
+ id: getTranslation("containers.list.autoCloneModal.description"),
3557
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3558
+ }) }) }),
3559
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3560
+ Flex,
3561
+ {
3562
+ direction: "column",
3563
+ gap: 2,
3564
+ alignItems: "flex-start",
3565
+ borderColor: "neutral200",
3566
+ hasRadius: true,
3567
+ padding: 6,
3568
+ children: [
3569
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3570
+ pathSegment,
3571
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3572
+ ChevronRight,
3573
+ {
3574
+ fill: "neutral500",
3575
+ height: "0.8rem",
3576
+ width: "0.8rem",
3577
+ style: { margin: "0 0.8rem" }
3578
+ }
3579
+ )
3580
+ ] }, index2)) }),
3581
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3582
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3583
+ defaultMessage: getDefaultErrorMessage(reason)
3584
+ }) })
3585
+ ]
3586
+ },
3587
+ fieldPath.join()
3588
+ )) })
3589
+ ] });
3590
+ };
3591
+ const TableActions = ({ document }) => {
3592
+ const { formatMessage } = useIntl();
3593
+ const { model, collectionType } = useDoc();
3594
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3595
+ const props = {
3596
+ activeTab: null,
3597
+ model,
3598
+ documentId: document.documentId,
3599
+ collectionType,
3600
+ document
3601
+ };
3602
+ return /* @__PURE__ */ jsx(
3603
+ DescriptionComponentRenderer,
3604
+ {
3605
+ props,
3606
+ descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
3607
+ children: (actions2) => {
3608
+ const tableRowActions = actions2.filter((action) => {
3609
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3610
+ return positions.includes("table-row");
3611
+ });
3612
+ return /* @__PURE__ */ jsx(
3613
+ DocumentActionsMenu,
2521
3614
  {
2522
3615
  actions: tableRowActions,
2523
3616
  label: formatMessage({
@@ -2621,7 +3714,7 @@ const CloneAction = ({ model, documentId }) => {
2621
3714
  }),
2622
3715
  content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2623
3716
  footer: ({ onClose }) => {
2624
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3717
+ return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
2625
3718
  /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2626
3719
  id: "cancel",
2627
3720
  defaultMessage: "Cancel"
@@ -2629,7 +3722,7 @@ const CloneAction = ({ model, documentId }) => {
2629
3722
  /* @__PURE__ */ jsx(
2630
3723
  LinkButton,
2631
3724
  {
2632
- as: NavLink,
3725
+ tag: NavLink,
2633
3726
  to: {
2634
3727
  pathname: `clone/${documentId}`
2635
3728
  },
@@ -2662,442 +3755,183 @@ class ContentManagerPlugin {
2662
3755
  documentActions = [
2663
3756
  ...DEFAULT_ACTIONS,
2664
3757
  ...DEFAULT_TABLE_ROW_ACTIONS,
2665
- ...DEFAULT_HEADER_ACTIONS,
2666
- HistoryAction
3758
+ ...DEFAULT_HEADER_ACTIONS
2667
3759
  ];
2668
3760
  editViewSidePanels = [ActionsPanel];
2669
3761
  headerActions = [];
2670
3762
  constructor() {
2671
3763
  }
2672
3764
  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);
3765
+ if (Array.isArray(panels)) {
3766
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3767
+ } else if (typeof panels === "function") {
3768
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2703
3769
  } else {
2704
3770
  throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
3771
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3772
+ panels
2707
3773
  )}`
2708
3774
  );
2709
3775
  }
2710
3776
  }
2711
- addBulkAction(actions2) {
3777
+ addDocumentAction(actions2) {
2712
3778
  if (Array.isArray(actions2)) {
2713
- this.bulkActions = [...this.bulkActions, ...actions2];
3779
+ this.documentActions = [...this.documentActions, ...actions2];
2714
3780
  } else if (typeof actions2 === "function") {
2715
- this.bulkActions = actions2(this.bulkActions);
3781
+ this.documentActions = actions2(this.documentActions);
2716
3782
  } else {
2717
3783
  throw new Error(
2718
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3784
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2719
3785
  actions2
2720
- )}`
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;
3786
+ )}`
3787
+ );
3788
+ }
3789
+ }
3790
+ addDocumentHeaderAction(actions2) {
3791
+ if (Array.isArray(actions2)) {
3792
+ this.headerActions = [...this.headerActions, ...actions2];
3793
+ } else if (typeof actions2 === "function") {
3794
+ this.headerActions = actions2(this.headerActions);
2960
3795
  } else {
2961
- if (!panels[currentPanelIndex]) {
2962
- panels.push([]);
2963
- }
2964
- panels[currentPanelIndex].push(row);
3796
+ throw new Error(
3797
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3798
+ actions2
3799
+ )}`
3800
+ );
2965
3801
  }
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
3802
+ }
3803
+ addBulkAction(actions2) {
3804
+ if (Array.isArray(actions2)) {
3805
+ this.bulkActions = [...this.bulkActions, ...actions2];
3806
+ } else if (typeof actions2 === "function") {
3807
+ this.bulkActions = actions2(this.bulkActions);
3808
+ } else {
3809
+ throw new Error(
3810
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3811
+ actions2
3812
+ )}`
3813
+ );
3007
3814
  }
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;
3815
+ }
3816
+ get config() {
3817
+ return {
3818
+ id: PLUGIN_ID,
3819
+ name: "Content Manager",
3820
+ injectionZones: INJECTION_ZONES,
3821
+ apis: {
3822
+ addBulkAction: this.addBulkAction.bind(this),
3823
+ addDocumentAction: this.addDocumentAction.bind(this),
3824
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3825
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3826
+ getBulkActions: () => this.bulkActions,
3827
+ getDocumentActions: () => this.documentActions,
3828
+ getEditViewSidePanels: () => this.editViewSidePanels,
3829
+ getHeaderActions: () => this.headerActions
3016
3830
  }
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
- );
3831
+ };
3832
+ }
3833
+ }
3834
+ const getPrintableType = (value) => {
3835
+ const nativeType = typeof value;
3836
+ if (nativeType === "object") {
3837
+ if (value === null)
3838
+ return "null";
3839
+ if (Array.isArray(value))
3840
+ return "array";
3841
+ if (value instanceof Object && value.constructor.name !== "Object") {
3842
+ return value.constructor.name;
3843
+ }
3844
+ }
3845
+ return nativeType;
3039
3846
  };
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
- );
3847
+ const HistoryAction = ({ model, document }) => {
3848
+ const { formatMessage } = useIntl();
3849
+ const [{ query }] = useQueryParams();
3850
+ const navigate = useNavigate();
3851
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3852
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3853
+ return null;
3854
+ }
3061
3855
  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
- }
3856
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3857
+ label: formatMessage({
3858
+ id: "content-manager.history.document-action",
3859
+ defaultMessage: "Content History"
3860
+ }),
3861
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3862
+ disabled: (
3863
+ /**
3864
+ * The user is creating a new document.
3865
+ * It hasn't been saved yet, so there's no history to go to
3866
+ */
3867
+ !document || /**
3868
+ * The document has been created but the current dimension has never been saved.
3869
+ * For example, the user is creating a new locale in an existing document,
3870
+ * so there's no history for the document in that locale
3871
+ */
3872
+ !document.id || /**
3873
+ * History is only available for content types created by the user.
3874
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3875
+ * which start with `admin::` or `plugin::`
3876
+ */
3877
+ !model.startsWith("api::")
3878
+ ),
3879
+ position: "header"
3070
3880
  };
3071
3881
  };
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);
3882
+ HistoryAction.type = "history";
3883
+ const historyAdmin = {
3884
+ bootstrap(app) {
3885
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3886
+ addDocumentAction((actions2) => {
3887
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3888
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3889
+ return actions2;
3890
+ });
3891
+ }
3892
+ };
3893
+ const initialState = {
3894
+ collectionTypeLinks: [],
3895
+ components: [],
3896
+ fieldSizes: {},
3897
+ models: [],
3898
+ singleTypeLinks: [],
3899
+ isLoading: true
3092
3900
  };
3901
+ const appSlice = createSlice({
3902
+ name: "app",
3903
+ initialState,
3904
+ reducers: {
3905
+ setInitialData(state, action) {
3906
+ const {
3907
+ authorizedCollectionTypeLinks,
3908
+ authorizedSingleTypeLinks,
3909
+ components,
3910
+ contentTypeSchemas,
3911
+ fieldSizes
3912
+ } = action.payload;
3913
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3914
+ ({ isDisplayed }) => isDisplayed
3915
+ );
3916
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3917
+ state.components = components;
3918
+ state.models = contentTypeSchemas;
3919
+ state.fieldSizes = fieldSizes;
3920
+ state.isLoading = false;
3921
+ }
3922
+ }
3923
+ });
3924
+ const { actions, reducer: reducer$1 } = appSlice;
3925
+ const { setInitialData } = actions;
3926
+ const reducer = combineReducers({
3927
+ app: reducer$1
3928
+ });
3093
3929
  const index = {
3094
3930
  register(app) {
3095
3931
  const cm = new ContentManagerPlugin();
3096
3932
  app.addReducers({
3097
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3098
3933
  [PLUGIN_ID]: reducer
3099
3934
  });
3100
- app.addMiddlewares([() => contentManagerApi.middleware]);
3101
3935
  app.addMenuLink({
3102
3936
  to: PLUGIN_ID,
3103
3937
  icon: Feather,
@@ -3106,14 +3940,29 @@ const index = {
3106
3940
  defaultMessage: "Content Manager"
3107
3941
  },
3108
3942
  permissions: [],
3109
- Component: () => import("./layout-jIDzX0Fp.mjs").then((mod) => ({ default: mod.Layout }))
3943
+ position: 1
3944
+ });
3945
+ app.router.addRoute({
3946
+ path: "content-manager/*",
3947
+ lazy: async () => {
3948
+ const { Layout } = await import("./layout-D4HI4_PS.mjs");
3949
+ return {
3950
+ Component: Layout
3951
+ };
3952
+ },
3953
+ children: routes
3110
3954
  });
3111
3955
  app.registerPlugin(cm.config);
3112
3956
  },
3957
+ bootstrap(app) {
3958
+ if (typeof historyAdmin.bootstrap === "function") {
3959
+ historyAdmin.bootstrap(app);
3960
+ }
3961
+ },
3113
3962
  async registerTrads({ locales }) {
3114
3963
  const importedTrads = await Promise.all(
3115
3964
  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 }) => {
3965
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-CPTj6CjC.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3117
3966
  return {
3118
3967
  data: prefixPluginTranslations(data, PLUGIN_ID),
3119
3968
  locale
@@ -3131,45 +3980,46 @@ const index = {
3131
3980
  };
3132
3981
  export {
3133
3982
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3134
- extractContentTypeComponents as B,
3983
+ BulkActionsRenderer as B,
3135
3984
  COLLECTION_TYPES as C,
3136
3985
  DocumentStatus as D,
3137
- DEFAULT_SETTINGS as E,
3138
- convertEditLayoutToFieldLayouts as F,
3139
- useDocument as G,
3986
+ extractContentTypeComponents as E,
3987
+ DEFAULT_SETTINGS as F,
3988
+ convertEditLayoutToFieldLayouts as G,
3140
3989
  HOOKS as H,
3141
3990
  InjectionZone as I,
3142
- index as J,
3143
- useDocumentActions as K,
3991
+ useDocument as J,
3992
+ index as K,
3993
+ useDocumentActions as L,
3144
3994
  Panels as P,
3145
3995
  RelativeTime as R,
3146
3996
  SINGLE_TYPES as S,
3147
3997
  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,
3998
+ useGetInitialDataQuery as a,
3999
+ useGetAllContentTypeSettingsQuery as b,
4000
+ useDoc as c,
4001
+ buildValidParams as d,
4002
+ contentManagerApi as e,
4003
+ useDocumentRBAC as f,
3154
4004
  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,
3162
- useGetContentTypeConfigurationQuery as o,
3163
- CREATOR_FIELDS as p,
3164
- getMainField as q,
3165
- routes as r,
4005
+ useDocumentLayout as h,
4006
+ createYupSchema as i,
4007
+ Header as j,
4008
+ PERMISSIONS as k,
4009
+ DocumentRBAC as l,
4010
+ DOCUMENT_META_FIELDS as m,
4011
+ CLONE_PATH as n,
4012
+ useDocLayout as o,
4013
+ useGetContentTypeConfigurationQuery as p,
4014
+ CREATOR_FIELDS as q,
4015
+ getMainField as r,
3166
4016
  setInitialData as s,
3167
4017
  getDisplayName as t,
3168
- useGetInitialDataQuery as u,
4018
+ useContentTypeSchema as u,
3169
4019
  checkIfAttributeIsDisplayable as v,
3170
4020
  useGetAllDocumentsQuery as w,
3171
4021
  convertListLayoutToFieldLayouts as x,
3172
4022
  capitalise as y,
3173
4023
  useUpdateContentTypeConfigurationMutation as z
3174
4024
  };
3175
- //# sourceMappingURL=index-CwRRo1V9.mjs.map
4025
+ //# sourceMappingURL=index-D4UGPFZC.mjs.map