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

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 (175) 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-DjWJdz6Y.js → ComponentConfigurationPage-BNxtMIfV.js} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-BNxtMIfV.js.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-BWOQWCv2.mjs} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-BWOQWCv2.mjs.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-Dmv83RlS.js → EditConfigurationPage-D340bYlT.js} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-D340bYlT.js.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-GTp-Ucnw.mjs} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-GTp-Ucnw.mjs.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-BVMS5hT-.mjs} +47 -47
  19. package/dist/_chunks/EditViewPage-BVMS5hT-.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-CXkmnAvI.js} +46 -48
  21. package/dist/_chunks/EditViewPage-CXkmnAvI.js.map +1 -0
  22. package/dist/_chunks/{Field-DmVKIAOo.js → Field-Ibi32diw.js} +953 -782
  23. package/dist/_chunks/Field-Ibi32diw.js.map +1 -0
  24. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-nNgv5bpd.mjs} +901 -729
  25. package/dist/_chunks/Field-nNgv5bpd.mjs.map +1 -0
  26. package/dist/_chunks/{Form-CPZC9vWa.js → Form-Dhnh34ym.js} +39 -38
  27. package/dist/_chunks/Form-Dhnh34ym.js.map +1 -0
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-DodJsI2A.mjs} +39 -37
  29. package/dist/_chunks/Form-DodJsI2A.mjs.map +1 -0
  30. package/dist/_chunks/{History-DeAPlvtv.js → History-C9auUkDi.js} +149 -56
  31. package/dist/_chunks/History-C9auUkDi.js.map +1 -0
  32. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-CKCSQXz_.mjs} +148 -54
  33. package/dist/_chunks/History-CKCSQXz_.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-Bg4rWUjX.js} +58 -59
  35. package/dist/_chunks/ListConfigurationPage-Bg4rWUjX.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-CKEC4ttG.mjs} +54 -54
  37. package/dist/_chunks/ListConfigurationPage-CKEC4ttG.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-B7_WJUjG.mjs} +93 -104
  39. package/dist/_chunks/ListViewPage-B7_WJUjG.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-C2gIeYHG.js} +98 -109
  41. package/dist/_chunks/ListViewPage-C2gIeYHG.js.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Ckem6Ll6.mjs} +3 -3
  43. package/dist/_chunks/NoContentTypePage-Ckem6Ll6.mjs.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-DqgdUfyn.js} +3 -3
  45. package/dist/_chunks/NoContentTypePage-DqgdUfyn.js.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-BO-GEjA4.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-BO-GEjA4.mjs.map} +1 -1
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-CF29Q-sW.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-CF29Q-sW.js.map} +1 -1
  50. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-C0uC9J4f.js} +70 -61
  51. package/dist/_chunks/Relations-C0uC9J4f.js.map +1 -0
  52. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-DItV5eow.mjs} +66 -56
  53. package/dist/_chunks/Relations-DItV5eow.mjs.map +1 -0
  54. package/dist/_chunks/{en-MBPul9Su.mjs → en-BrCTWlZv.mjs} +11 -4
  55. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  56. package/dist/_chunks/{en-C-V1_90f.js → en-uOUIxfcQ.js} +11 -4
  57. package/dist/_chunks/{en-C-V1_90f.js.map → en-uOUIxfcQ.js.map} +1 -1
  58. package/dist/_chunks/{index-C6AH2hEl.js → index-Dd0nXyJF.js} +1649 -905
  59. package/dist/_chunks/index-Dd0nXyJF.js.map +1 -0
  60. package/dist/_chunks/{index-CwRRo1V9.mjs → index-DrNe6ctw.mjs} +1671 -926
  61. package/dist/_chunks/index-DrNe6ctw.mjs.map +1 -0
  62. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-B3ez7kvr.mjs} +43 -26
  63. package/dist/_chunks/layout-B3ez7kvr.mjs.map +1 -0
  64. package/dist/_chunks/{layout-B_SXLhqf.js → layout-CLLtt_5O.js} +43 -28
  65. package/dist/_chunks/layout-CLLtt_5O.js.map +1 -0
  66. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-B0hlsUU_.mjs} +2 -2
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-B0hlsUU_.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-iBMa_OFG.js → relations-bRxcNv1q.js} +2 -2
  69. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-bRxcNv1q.js.map} +1 -1
  70. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  71. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  72. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  73. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  75. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +5 -4
  79. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  80. package/dist/admin/src/content-manager.d.ts +3 -3
  81. package/dist/admin/src/exports.d.ts +1 -0
  82. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  83. package/dist/admin/src/history/index.d.ts +3 -0
  84. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  86. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  87. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  88. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  89. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  90. package/dist/admin/src/index.d.ts +1 -0
  91. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
  92. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  93. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  96. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  98. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
  102. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  103. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  104. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  105. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  106. package/dist/admin/src/services/api.d.ts +2 -3
  107. package/dist/admin/src/services/components.d.ts +2 -2
  108. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  109. package/dist/admin/src/services/documents.d.ts +29 -17
  110. package/dist/admin/src/services/init.d.ts +2 -2
  111. package/dist/admin/src/services/relations.d.ts +3 -3
  112. package/dist/admin/src/services/uid.d.ts +3 -3
  113. package/dist/admin/src/utils/api.d.ts +4 -18
  114. package/dist/admin/src/utils/validation.d.ts +1 -6
  115. package/dist/server/index.js +392 -261
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/index.mjs +400 -269
  118. package/dist/server/index.mjs.map +1 -1
  119. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  120. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  121. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  122. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  123. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  124. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  125. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  126. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  127. package/dist/server/src/history/services/history.d.ts.map +1 -1
  128. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  129. package/dist/server/src/history/services/utils.d.ts +1 -1
  130. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  131. package/dist/server/src/index.d.ts +18 -39
  132. package/dist/server/src/index.d.ts.map +1 -1
  133. package/dist/server/src/services/document-manager.d.ts +13 -12
  134. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  135. package/dist/server/src/services/document-metadata.d.ts +8 -29
  136. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  137. package/dist/server/src/services/index.d.ts +18 -39
  138. package/dist/server/src/services/index.d.ts.map +1 -1
  139. package/dist/server/src/services/utils/populate.d.ts +8 -1
  140. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  141. package/dist/shared/contracts/collection-types.d.ts +14 -6
  142. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  143. package/dist/shared/contracts/relations.d.ts +2 -2
  144. package/dist/shared/contracts/relations.d.ts.map +1 -1
  145. package/package.json +13 -14
  146. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  147. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  148. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  149. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  150. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  151. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  152. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  153. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  154. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  155. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  156. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  157. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  158. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  159. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  160. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  161. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  162. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  163. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  164. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  165. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  166. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  167. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  168. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  169. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  170. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  171. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  172. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  173. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  174. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  175. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -1,19 +1,17 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, Cog, Pencil, Trash, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, getFetchClient, translatedErrors, useNotification, useAPIErrorHandler, useTracking, useForm, BackButton, DescriptionComponentRenderer } from "@strapi/admin/strapi-admin";
4
- import { stringify } from "qs";
5
- import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, NavLink } from "react-router-dom";
3
+ import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
7
4
  import * as React from "react";
8
5
  import { lazy } from "react";
9
- import { Menu, VisuallyHidden, Flex, Typography, Dialog, DialogBody, DialogFooter, Button, ModalLayout, ModalHeader, ModalBody, Box, Radio, Status, SingleSelect, SingleSelectOption, LinkButton } from "@strapi/design-system";
10
- import styled from "styled-components";
6
+ import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
7
+ import { useIntl } from "react-intl";
8
+ import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
9
+ import { styled } from "styled-components";
11
10
  import * as yup from "yup";
12
11
  import { ValidationError } from "yup";
13
- import { createApi } from "@reduxjs/toolkit/query/react";
14
- import { isAxiosError } from "axios";
15
12
  import pipe from "lodash/fp/pipe";
16
13
  import { intervalToDuration, isPast } from "date-fns";
14
+ import { stringify } from "qs";
17
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
18
16
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
19
17
  const v = glob[path];
@@ -51,42 +49,6 @@ const useInjectionZone = (area) => {
51
49
  const [page, position] = area.split(".");
52
50
  return contentManagerPlugin.getInjectedComponents(page, position);
53
51
  };
54
- const HistoryAction = ({ model, document }) => {
55
- const { formatMessage } = useIntl();
56
- const [{ query }] = useQueryParams();
57
- const navigate = useNavigate();
58
- const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
59
- if (!window.strapi.features.isEnabled("cms-content-history")) {
60
- return null;
61
- }
62
- return {
63
- icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
64
- label: formatMessage({
65
- id: "content-manager.history.document-action",
66
- defaultMessage: "Content History"
67
- }),
68
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
69
- disabled: (
70
- /**
71
- * The user is creating a new document.
72
- * It hasn't been saved yet, so there's no history to go to
73
- */
74
- !document || /**
75
- * The document has been created but the current dimension has never been saved.
76
- * For example, the user is creating a new locale in an existing document,
77
- * so there's no history for the document in that locale
78
- */
79
- !document.id || /**
80
- * History is only available for content types created by the user.
81
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
82
- * which start with `admin::` or `plugin::`
83
- */
84
- !model.startsWith("api::")
85
- ),
86
- position: "header"
87
- };
88
- };
89
- HistoryAction.type = "history";
90
52
  const ID = "id";
91
53
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
92
54
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -157,9 +119,8 @@ const DocumentRBAC = ({ children, permissions }) => {
157
119
  const name = removeNumericalStrings(fieldName.split("."));
158
120
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
159
121
  if (fieldType === "component") {
160
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
161
- return componentOrDynamicZoneFields.some((field) => {
162
- return field.includes(fieldName);
122
+ return componentFieldNames.some((field) => {
123
+ return field.includes(name.join("."));
163
124
  });
164
125
  }
165
126
  if (name.length > 1) {
@@ -189,78 +150,8 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
189
150
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
190
151
  );
191
152
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
192
- const buildValidParams = (query) => {
193
- if (!query)
194
- return query;
195
- const { plugins: _, ...validQueryParams } = {
196
- ...query,
197
- ...Object.values(query?.plugins ?? {}).reduce(
198
- (acc, current) => Object.assign(acc, current),
199
- {}
200
- )
201
- };
202
- if ("_q" in validQueryParams) {
203
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
204
- }
205
- return validQueryParams;
206
- };
207
- const axiosBaseQuery = () => async (query, { signal }) => {
208
- try {
209
- const { get, post, del, put } = getFetchClient();
210
- if (typeof query === "string") {
211
- const result = await get(query, { signal });
212
- return { data: result.data };
213
- } else {
214
- const { url, method = "GET", data, config } = query;
215
- if (method === "POST") {
216
- const result2 = await post(url, data, { ...config, signal });
217
- return { data: result2.data };
218
- }
219
- if (method === "DELETE") {
220
- const result2 = await del(url, { ...config, signal });
221
- return { data: result2.data };
222
- }
223
- if (method === "PUT") {
224
- const result2 = await put(url, data, { ...config, signal });
225
- return { data: result2.data };
226
- }
227
- const result = await get(url, { ...config, signal });
228
- return { data: result.data };
229
- }
230
- } catch (err) {
231
- if (isAxiosError(err)) {
232
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
233
- return { data: void 0, error: err.response?.data.error };
234
- } else {
235
- return {
236
- data: void 0,
237
- error: {
238
- name: "UnknownError",
239
- message: "There was an unknown error response from the API",
240
- details: err.response?.data,
241
- status: err.response?.status
242
- }
243
- };
244
- }
245
- }
246
- const error = err;
247
- return {
248
- data: void 0,
249
- error: {
250
- name: error.name,
251
- message: error.message,
252
- stack: error.stack
253
- }
254
- };
255
- }
256
- };
257
- const isBaseQueryError = (error) => {
258
- return error.name !== void 0;
259
- };
260
- const contentManagerApi = createApi({
261
- reducerPath: "contentManagerApi",
262
- baseQuery: axiosBaseQuery(),
263
- tagTypes: [
153
+ const contentManagerApi = adminApi.enhanceEndpoints({
154
+ addTagTypes: [
264
155
  "ComponentConfiguration",
265
156
  "ContentTypesConfiguration",
266
157
  "ContentTypeSettings",
@@ -268,10 +159,10 @@ const contentManagerApi = createApi({
268
159
  "InitialData",
269
160
  "HistoryVersion",
270
161
  "Relations"
271
- ],
272
- endpoints: () => ({})
162
+ ]
273
163
  });
274
164
  const documentApi = contentManagerApi.injectEndpoints({
165
+ overrideExisting: true,
275
166
  endpoints: (builder) => ({
276
167
  autoCloneDocument: builder.mutation({
277
168
  query: ({ model, sourceId, query }) => ({
@@ -281,7 +172,12 @@ const documentApi = contentManagerApi.injectEndpoints({
281
172
  params: query
282
173
  }
283
174
  }),
284
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
175
+ invalidatesTags: (_result, error, { model }) => {
176
+ if (error) {
177
+ return [];
178
+ }
179
+ return [{ type: "Document", id: `${model}_LIST` }];
180
+ }
285
181
  }),
286
182
  cloneDocument: builder.mutation({
287
183
  query: ({ model, sourceId, data, params }) => ({
@@ -325,12 +221,15 @@ const documentApi = contentManagerApi.injectEndpoints({
325
221
  ]
326
222
  }),
327
223
  deleteManyDocuments: builder.mutation({
328
- query: ({ model, ...body }) => ({
224
+ query: ({ model, params, ...body }) => ({
329
225
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
330
226
  method: "POST",
331
- data: body
227
+ data: body,
228
+ config: {
229
+ params
230
+ }
332
231
  }),
333
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
232
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
334
233
  }),
335
234
  discardDocument: builder.mutation({
336
235
  query: ({ collectionType, model, documentId, params }) => ({
@@ -365,6 +264,7 @@ const documentApi = contentManagerApi.injectEndpoints({
365
264
  }),
366
265
  providesTags: (result, _error, arg) => {
367
266
  return [
267
+ { type: "Document", id: `ALL_LIST` },
368
268
  { type: "Document", id: `${arg.model}_LIST` },
369
269
  ...result?.results.map(({ documentId }) => ({
370
270
  type: "Document",
@@ -441,10 +341,13 @@ const documentApi = contentManagerApi.injectEndpoints({
441
341
  }
442
342
  }),
443
343
  publishManyDocuments: builder.mutation({
444
- query: ({ model, ...body }) => ({
344
+ query: ({ model, params, ...body }) => ({
445
345
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
446
346
  method: "POST",
447
- data: body
347
+ data: body,
348
+ config: {
349
+ params
350
+ }
448
351
  }),
449
352
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
450
353
  }),
@@ -465,6 +368,18 @@ const documentApi = contentManagerApi.injectEndpoints({
465
368
  },
466
369
  "Relations"
467
370
  ];
371
+ },
372
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
373
+ const patchResult = dispatch(
374
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
375
+ Object.assign(draft.data, data);
376
+ })
377
+ );
378
+ try {
379
+ await queryFulfilled;
380
+ } catch {
381
+ patchResult.undo();
382
+ }
468
383
  }
469
384
  }),
470
385
  unpublishDocument: builder.mutation({
@@ -486,10 +401,13 @@ const documentApi = contentManagerApi.injectEndpoints({
486
401
  }
487
402
  }),
488
403
  unpublishManyDocuments: builder.mutation({
489
- query: ({ model, ...body }) => ({
404
+ query: ({ model, params, ...body }) => ({
490
405
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
491
406
  method: "POST",
492
- data: body
407
+ data: body,
408
+ config: {
409
+ params
410
+ }
493
411
  }),
494
412
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
495
413
  })
@@ -513,6 +431,24 @@ const {
513
431
  useUnpublishDocumentMutation,
514
432
  useUnpublishManyDocumentsMutation
515
433
  } = documentApi;
434
+ const buildValidParams = (query) => {
435
+ if (!query)
436
+ return query;
437
+ const { plugins: _, ...validQueryParams } = {
438
+ ...query,
439
+ ...Object.values(query?.plugins ?? {}).reduce(
440
+ (acc, current) => Object.assign(acc, current),
441
+ {}
442
+ )
443
+ };
444
+ if ("_q" in validQueryParams) {
445
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
446
+ }
447
+ return validQueryParams;
448
+ };
449
+ const isBaseQueryError = (error) => {
450
+ return error.name !== void 0;
451
+ };
516
452
  const createYupSchema = (attributes = {}, components = {}) => {
517
453
  const createModelSchema = (attributes2) => yup.object().shape(
518
454
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -552,10 +488,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
552
488
  yup.array().of(
553
489
  yup.lazy(
554
490
  (data) => {
555
- const { attributes: attributes3 } = components[data.__component];
556
- return yup.object().shape({
491
+ const attributes3 = components?.[data?.__component]?.attributes;
492
+ const validation = yup.object().shape({
557
493
  __component: yup.string().required().oneOf(Object.keys(components))
558
- }).nullable(false).concat(createModelSchema(attributes3));
494
+ }).nullable(false);
495
+ if (!attributes3) {
496
+ return validation;
497
+ }
498
+ return validation.concat(createModelSchema(attributes3));
559
499
  }
560
500
  )
561
501
  )
@@ -565,11 +505,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
505
  return {
566
506
  ...acc,
567
507
  [name]: transformSchema(
568
- yup.array().of(
569
- yup.object().shape({
570
- id: yup.string().required()
571
- })
572
- )
508
+ yup.lazy((value) => {
509
+ if (!value) {
510
+ return yup.mixed().nullable(true);
511
+ } else if (Array.isArray(value)) {
512
+ return yup.array().of(
513
+ yup.object().shape({
514
+ id: yup.string().required()
515
+ })
516
+ );
517
+ } else if (typeof value === "object") {
518
+ return yup.object();
519
+ } else {
520
+ return yup.mixed().test(
521
+ "type-error",
522
+ "Relation values must be either null, an array of objects with {id} or an object.",
523
+ () => false
524
+ );
525
+ }
526
+ })
573
527
  )
574
528
  };
575
529
  default:
@@ -628,13 +582,18 @@ const createAttributeSchema = (attribute) => {
628
582
  }
629
583
  };
630
584
  const addRequiredValidation = (attribute) => (schema) => {
631
- if (attribute.required) {
632
- return schema.required({
633
- id: translatedErrors.required.id,
634
- defaultMessage: "This field is required."
635
- });
585
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
586
+ return schema.min(1, translatedErrors.required);
636
587
  }
637
- return schema.nullable();
588
+ if (attribute.required && attribute.type !== "relation") {
589
+ return schema.required(translatedErrors.required);
590
+ }
591
+ return schema?.nullable ? schema.nullable() : (
592
+ // In some cases '.nullable' will not be available on the schema.
593
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
594
+ // In these cases we should just return the schema as it is.
595
+ schema
596
+ );
638
597
  };
639
598
  const addMinLengthValidation = (attribute) => (schema) => {
640
599
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -661,6 +620,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
661
620
  const addMinValidation = (attribute) => (schema) => {
662
621
  if ("min" in attribute) {
663
622
  const min = toInteger(attribute.min);
623
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
624
+ if (!attribute.required && "test" in schema && min) {
625
+ return schema.test(
626
+ "custom-min",
627
+ {
628
+ ...translatedErrors.min,
629
+ values: {
630
+ min: attribute.min
631
+ }
632
+ },
633
+ (value) => {
634
+ if (!value) {
635
+ return true;
636
+ }
637
+ if (Array.isArray(value) && value.length === 0) {
638
+ return true;
639
+ }
640
+ return value.length >= min;
641
+ }
642
+ );
643
+ }
644
+ }
664
645
  if ("min" in schema && min) {
665
646
  return schema.min(min, {
666
647
  ...translatedErrors.min,
@@ -706,24 +687,6 @@ const addRegexValidation = (attribute) => (schema) => {
706
687
  }
707
688
  return schema;
708
689
  };
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
690
  const initApi = contentManagerApi.injectEndpoints({
728
691
  endpoints: (builder) => ({
729
692
  getInitialData: builder.query({
@@ -737,27 +700,20 @@ const { useGetInitialDataQuery } = initApi;
737
700
  const useContentTypeSchema = (model) => {
738
701
  const { toggleNotification } = useNotification();
739
702
  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
- });
703
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
704
+ const { components, contentType, contentTypes } = React.useMemo(() => {
705
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
706
+ const componentsByKey = data?.components.reduce((acc, component) => {
707
+ acc[component.uid] = component;
708
+ return acc;
709
+ }, {});
710
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
711
+ return {
712
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
713
+ contentType: contentType2,
714
+ contentTypes: data?.contentTypes ?? []
715
+ };
716
+ }, [model, data]);
761
717
  React.useEffect(() => {
762
718
  if (error) {
763
719
  toggleNotification({
@@ -812,7 +768,10 @@ const useDocument = (args, opts) => {
812
768
  isLoading: isLoadingDocument,
813
769
  isFetching: isFetchingDocument,
814
770
  error
815
- } = useGetDocumentQuery(args, opts);
771
+ } = useGetDocumentQuery(args, {
772
+ ...opts,
773
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
774
+ });
816
775
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
817
776
  React.useEffect(() => {
818
777
  if (error) {
@@ -840,7 +799,7 @@ const useDocument = (args, opts) => {
840
799
  return null;
841
800
  } catch (error2) {
842
801
  if (error2 instanceof ValidationError) {
843
- return getInnerErrors(error2);
802
+ return getYupValidationErrors(error2);
844
803
  }
845
804
  throw error2;
846
805
  }
@@ -936,14 +895,53 @@ const useDocumentActions = () => {
936
895
  },
937
896
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
938
897
  );
898
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
899
+ const deleteMany = React.useCallback(
900
+ async ({ model, documentIds, params }) => {
901
+ try {
902
+ trackUsage("willBulkDeleteEntries");
903
+ const res = await deleteManyDocuments({
904
+ model,
905
+ documentIds,
906
+ params
907
+ });
908
+ if ("error" in res) {
909
+ toggleNotification({
910
+ type: "danger",
911
+ message: formatAPIError(res.error)
912
+ });
913
+ return { error: res.error };
914
+ }
915
+ toggleNotification({
916
+ type: "success",
917
+ title: formatMessage({
918
+ id: getTranslation("success.records.delete"),
919
+ defaultMessage: "Successfully deleted."
920
+ }),
921
+ message: ""
922
+ });
923
+ trackUsage("didBulkDeleteEntries");
924
+ return res.data;
925
+ } catch (err) {
926
+ toggleNotification({
927
+ type: "danger",
928
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
929
+ });
930
+ trackUsage("didNotBulkDeleteEntries");
931
+ throw err;
932
+ }
933
+ },
934
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
935
+ );
939
936
  const [discardDocument] = useDiscardDocumentMutation();
940
937
  const discard = React.useCallback(
941
- async ({ collectionType, model, documentId }) => {
938
+ async ({ collectionType, model, documentId, params }) => {
942
939
  try {
943
940
  const res = await discardDocument({
944
941
  collectionType,
945
942
  model,
946
- documentId
943
+ documentId,
944
+ params
947
945
  });
948
946
  if ("error" in res) {
949
947
  toggleNotification({
@@ -1005,6 +1003,43 @@ const useDocumentActions = () => {
1005
1003
  },
1006
1004
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1007
1005
  );
1006
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1007
+ const publishMany = React.useCallback(
1008
+ async ({ model, documentIds, params }) => {
1009
+ try {
1010
+ const res = await publishManyDocuments({
1011
+ model,
1012
+ documentIds,
1013
+ params
1014
+ });
1015
+ if ("error" in res) {
1016
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1017
+ return { error: res.error };
1018
+ }
1019
+ toggleNotification({
1020
+ type: "success",
1021
+ message: formatMessage({
1022
+ id: getTranslation("success.record.publish"),
1023
+ defaultMessage: "Published document"
1024
+ })
1025
+ });
1026
+ return res.data;
1027
+ } catch (err) {
1028
+ toggleNotification({
1029
+ type: "danger",
1030
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1031
+ });
1032
+ throw err;
1033
+ }
1034
+ },
1035
+ [
1036
+ // trackUsage,
1037
+ publishManyDocuments,
1038
+ toggleNotification,
1039
+ formatMessage,
1040
+ formatAPIError
1041
+ ]
1042
+ );
1008
1043
  const [updateDocument] = useUpdateDocumentMutation();
1009
1044
  const update = React.useCallback(
1010
1045
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1079,6 +1114,41 @@ const useDocumentActions = () => {
1079
1114
  },
1080
1115
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1081
1116
  );
1117
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1118
+ const unpublishMany = React.useCallback(
1119
+ async ({ model, documentIds, params }) => {
1120
+ try {
1121
+ trackUsage("willBulkUnpublishEntries");
1122
+ const res = await unpublishManyDocuments({
1123
+ model,
1124
+ documentIds,
1125
+ params
1126
+ });
1127
+ if ("error" in res) {
1128
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1129
+ return { error: res.error };
1130
+ }
1131
+ trackUsage("didBulkUnpublishEntries");
1132
+ toggleNotification({
1133
+ type: "success",
1134
+ title: formatMessage({
1135
+ id: getTranslation("success.records.unpublish"),
1136
+ defaultMessage: "Successfully unpublished."
1137
+ }),
1138
+ message: ""
1139
+ });
1140
+ return res.data;
1141
+ } catch (err) {
1142
+ toggleNotification({
1143
+ type: "danger",
1144
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1145
+ });
1146
+ trackUsage("didNotBulkUnpublishEntries");
1147
+ throw err;
1148
+ }
1149
+ },
1150
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1151
+ );
1082
1152
  const [createDocument] = useCreateDocumentMutation();
1083
1153
  const create = React.useCallback(
1084
1154
  async ({ model, params }, data, trackerProperty) => {
@@ -1122,7 +1192,6 @@ const useDocumentActions = () => {
1122
1192
  sourceId
1123
1193
  });
1124
1194
  if ("error" in res) {
1125
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1126
1195
  return { error: res.error };
1127
1196
  }
1128
1197
  toggleNotification({
@@ -1192,15 +1261,18 @@ const useDocumentActions = () => {
1192
1261
  clone,
1193
1262
  create,
1194
1263
  delete: _delete,
1264
+ deleteMany,
1195
1265
  discard,
1196
1266
  getDocument,
1197
1267
  publish,
1268
+ publishMany,
1198
1269
  unpublish,
1270
+ unpublishMany,
1199
1271
  update
1200
1272
  };
1201
1273
  };
1202
1274
  const ProtectedHistoryPage = lazy(
1203
- () => import("./History-Dmr9fmUA.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1275
+ () => import("./History-CKCSQXz_.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1204
1276
  );
1205
1277
  const routes$1 = [
1206
1278
  {
@@ -1213,31 +1285,31 @@ const routes$1 = [
1213
1285
  }
1214
1286
  ];
1215
1287
  const ProtectedEditViewPage = lazy(
1216
- () => import("./EditViewPage-DDS6H9HO.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1288
+ () => import("./EditViewPage-BVMS5hT-.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1217
1289
  );
1218
1290
  const ProtectedListViewPage = lazy(
1219
- () => import("./ListViewPage-BtAwuYLE.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1291
+ () => import("./ListViewPage-B7_WJUjG.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1220
1292
  );
1221
1293
  const ProtectedListConfiguration = lazy(
1222
- () => import("./ListConfigurationPage-DhwvYcNv.mjs").then((mod) => ({
1294
+ () => import("./ListConfigurationPage-CKEC4ttG.mjs").then((mod) => ({
1223
1295
  default: mod.ProtectedListConfiguration
1224
1296
  }))
1225
1297
  );
1226
1298
  const ProtectedEditConfigurationPage = lazy(
1227
- () => import("./EditConfigurationPage-DacbqQ_f.mjs").then((mod) => ({
1299
+ () => import("./EditConfigurationPage-GTp-Ucnw.mjs").then((mod) => ({
1228
1300
  default: mod.ProtectedEditConfigurationPage
1229
1301
  }))
1230
1302
  );
1231
1303
  const ProtectedComponentConfigurationPage = lazy(
1232
- () => import("./ComponentConfigurationPage-BPvzFjM7.mjs").then((mod) => ({
1304
+ () => import("./ComponentConfigurationPage-BWOQWCv2.mjs").then((mod) => ({
1233
1305
  default: mod.ProtectedComponentConfigurationPage
1234
1306
  }))
1235
1307
  );
1236
1308
  const NoPermissions = lazy(
1237
- () => import("./NoPermissionsPage-UWDC-1Tw.mjs").then((mod) => ({ default: mod.NoPermissions }))
1309
+ () => import("./NoPermissionsPage-BO-GEjA4.mjs").then((mod) => ({ default: mod.NoPermissions }))
1238
1310
  );
1239
1311
  const NoContentType = lazy(
1240
- () => import("./NoContentTypePage-DSPxnxxp.mjs").then((mod) => ({ default: mod.NoContentType }))
1312
+ () => import("./NoContentTypePage-Ckem6Ll6.mjs").then((mod) => ({ default: mod.NoContentType }))
1241
1313
  );
1242
1314
  const CollectionTypePages = () => {
1243
1315
  const { collectionType } = useParams();
@@ -1364,7 +1436,7 @@ const DocumentActionButton = (action) => {
1364
1436
  DocumentActionConfirmDialog,
1365
1437
  {
1366
1438
  ...action.dialog,
1367
- variant: action.variant,
1439
+ variant: action.dialog?.variant ?? action.variant,
1368
1440
  isOpen: dialogId === action.id,
1369
1441
  onClose: handleClose
1370
1442
  }
@@ -1421,13 +1493,13 @@ const DocumentActionsMenu = ({
1421
1493
  disabled: isDisabled,
1422
1494
  size: "S",
1423
1495
  endIcon: null,
1424
- paddingTop: "7px",
1425
- paddingLeft: "9px",
1426
- paddingRight: "9px",
1496
+ paddingTop: "4px",
1497
+ paddingLeft: "7px",
1498
+ paddingRight: "7px",
1427
1499
  variant,
1428
1500
  children: [
1429
1501
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
1430
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: label || formatMessage({
1502
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
1431
1503
  id: "content-manager.containers.edit.panels.default.more-actions",
1432
1504
  defaultMessage: "More document actions"
1433
1505
  }) })
@@ -1443,10 +1515,18 @@ const DocumentActionsMenu = ({
1443
1515
  onSelect: handleClick(action),
1444
1516
  display: "block",
1445
1517
  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
- ] }),
1518
+ /* @__PURE__ */ jsxs(
1519
+ Flex,
1520
+ {
1521
+ color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
1522
+ gap: 2,
1523
+ tag: "span",
1524
+ children: [
1525
+ /* @__PURE__ */ jsx("span", { children: action.icon }),
1526
+ action.label
1527
+ ]
1528
+ }
1529
+ ),
1450
1530
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
1451
1531
  Flex,
1452
1532
  {
@@ -1527,61 +1607,42 @@ const DocumentActionConfirmDialog = ({
1527
1607
  }
1528
1608
  onClose();
1529
1609
  };
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
- ] });
1610
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1611
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1612
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1613
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1614
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1615
+ id: "app.components.Button.cancel",
1616
+ defaultMessage: "Cancel"
1617
+ }) }) }),
1618
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1619
+ id: "app.components.Button.confirm",
1620
+ defaultMessage: "Confirm"
1621
+ }) })
1622
+ ] })
1623
+ ] }) });
1546
1624
  };
1547
1625
  const DocumentActionModal = ({
1548
1626
  isOpen,
1549
1627
  title,
1550
1628
  onClose,
1551
1629
  footer: Footer,
1552
- content,
1630
+ content: Content,
1553
1631
  onModalClose
1554
1632
  }) => {
1555
- const id = React.useId();
1556
- if (!isOpen) {
1557
- return null;
1558
- }
1559
1633
  const handleClose = () => {
1560
1634
  if (onClose) {
1561
1635
  onClose();
1562
1636
  }
1563
1637
  onModalClose();
1564
1638
  };
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
- ] });
1639
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1640
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1641
+ typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
1642
+ typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1643
+ ] }) });
1583
1644
  };
1584
- const PublishAction = ({
1645
+ const PublishAction$1 = ({
1585
1646
  activeTab,
1586
1647
  documentId,
1587
1648
  model,
@@ -1600,6 +1661,12 @@ const PublishAction = ({
1600
1661
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1601
1662
  );
1602
1663
  const { publish } = useDocumentActions();
1664
+ const [
1665
+ countDraftRelations,
1666
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1667
+ ] = useLazyGetDraftRelationCountQuery();
1668
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1669
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1603
1670
  const [{ query, rawQuery }] = useQueryParams();
1604
1671
  const params = React.useMemo(() => buildValidParams(query), [query]);
1605
1672
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1608,65 +1675,146 @@ const PublishAction = ({
1608
1675
  const validate = useForm("PublishAction", (state) => state.validate);
1609
1676
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1610
1677
  const formValues = useForm("PublishAction", ({ values }) => values);
1611
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1612
- if (!schema?.options?.draftAndPublish) {
1613
- return null;
1614
- }
1615
- return {
1616
- /**
1617
- * Disabled when:
1618
- * - currently if you're cloning a document we don't support publish & clone at the same time.
1619
- * - the form is submitting
1620
- * - the active tab is the published tab
1621
- * - the document is already published & not modified
1622
- * - the document is being created & not modified
1623
- * - 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
- */
1627
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1628
- label: formatMessage({
1678
+ React.useEffect(() => {
1679
+ if (isErrorDraftRelations) {
1680
+ toggleNotification({
1681
+ type: "danger",
1682
+ message: formatMessage({
1683
+ id: getTranslation("error.records.fetch-draft-relatons"),
1684
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1685
+ })
1686
+ });
1687
+ }
1688
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1689
+ React.useEffect(() => {
1690
+ const localDraftRelations = /* @__PURE__ */ new Set();
1691
+ const extractDraftRelations = (data) => {
1692
+ const relations = data.connect || [];
1693
+ relations.forEach((relation) => {
1694
+ if (relation.status === "draft") {
1695
+ localDraftRelations.add(relation.id);
1696
+ }
1697
+ });
1698
+ };
1699
+ const traverseAndExtract = (data) => {
1700
+ Object.entries(data).forEach(([key, value]) => {
1701
+ if (key === "connect" && Array.isArray(value)) {
1702
+ extractDraftRelations({ connect: value });
1703
+ } else if (typeof value === "object" && value !== null) {
1704
+ traverseAndExtract(value);
1705
+ }
1706
+ });
1707
+ };
1708
+ if (!documentId || modified) {
1709
+ traverseAndExtract(formValues);
1710
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1711
+ }
1712
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1713
+ React.useEffect(() => {
1714
+ if (documentId) {
1715
+ const fetchDraftRelationsCount = async () => {
1716
+ const { data, error } = await countDraftRelations({
1717
+ collectionType,
1718
+ model,
1719
+ documentId,
1720
+ params
1721
+ });
1722
+ if (error) {
1723
+ throw error;
1724
+ }
1725
+ if (data) {
1726
+ setServerCountOfDraftRelations(data.data);
1727
+ }
1728
+ };
1729
+ fetchDraftRelationsCount();
1730
+ }
1731
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1732
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1733
+ if (!schema?.options?.draftAndPublish) {
1734
+ return null;
1735
+ }
1736
+ const performPublish = async () => {
1737
+ setSubmitting(true);
1738
+ try {
1739
+ const { errors } = await validate();
1740
+ if (errors) {
1741
+ toggleNotification({
1742
+ type: "danger",
1743
+ message: formatMessage({
1744
+ id: "content-manager.validation.error",
1745
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1746
+ })
1747
+ });
1748
+ return;
1749
+ }
1750
+ const res = await publish(
1751
+ {
1752
+ collectionType,
1753
+ model,
1754
+ documentId,
1755
+ params
1756
+ },
1757
+ formValues
1758
+ );
1759
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1760
+ navigate({
1761
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1762
+ search: rawQuery
1763
+ });
1764
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1765
+ setErrors(formatValidationErrors(res.error));
1766
+ }
1767
+ } finally {
1768
+ setSubmitting(false);
1769
+ }
1770
+ };
1771
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1772
+ const hasDraftRelations = totalDraftRelations > 0;
1773
+ return {
1774
+ /**
1775
+ * Disabled when:
1776
+ * - currently if you're cloning a document we don't support publish & clone at the same time.
1777
+ * - the form is submitting
1778
+ * - the active tab is the published tab
1779
+ * - the document is already published & not modified
1780
+ * - the document is being created & not modified
1781
+ * - the user doesn't have the permission to publish
1782
+ */
1783
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
1784
+ label: formatMessage({
1629
1785
  id: "app.utils.publish",
1630
1786
  defaultMessage: "Publish"
1631
1787
  }),
1632
1788
  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));
1789
+ if (hasDraftRelations) {
1790
+ return;
1791
+ }
1792
+ await performPublish();
1793
+ },
1794
+ dialog: hasDraftRelations ? {
1795
+ type: "dialog",
1796
+ variant: "danger",
1797
+ footer: null,
1798
+ title: formatMessage({
1799
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1800
+ defaultMessage: "Confirmation"
1801
+ }),
1802
+ content: formatMessage(
1803
+ {
1804
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1805
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1806
+ },
1807
+ {
1808
+ count: totalDraftRelations
1662
1809
  }
1663
- } finally {
1664
- setSubmitting(false);
1810
+ ),
1811
+ onConfirm: async () => {
1812
+ await performPublish();
1665
1813
  }
1666
- }
1814
+ } : void 0
1667
1815
  };
1668
1816
  };
1669
- PublishAction.type = "publish";
1817
+ PublishAction$1.type = "publish";
1670
1818
  const UpdateAction = ({
1671
1819
  activeTab,
1672
1820
  documentId,
@@ -1679,7 +1827,7 @@ const UpdateAction = ({
1679
1827
  const cloneMatch = useMatch(CLONE_PATH);
1680
1828
  const isCloning = cloneMatch !== null;
1681
1829
  const { formatMessage } = useIntl();
1682
- const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1830
+ useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
1683
1831
  canCreate: canCreate2,
1684
1832
  canUpdate: canUpdate2
1685
1833
  }));
@@ -1699,10 +1847,8 @@ const UpdateAction = ({
1699
1847
  * - the form is submitting
1700
1848
  * - the document is not modified & we're not cloning (you can save a clone entity straight away)
1701
1849
  * - 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
1850
  */
1705
- disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
1851
+ disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
1706
1852
  label: formatMessage({
1707
1853
  id: "content-manager.containers.Edit.save",
1708
1854
  defaultMessage: "Save"
@@ -1731,10 +1877,13 @@ const UpdateAction = ({
1731
1877
  document
1732
1878
  );
1733
1879
  if ("data" in res) {
1734
- navigate({
1735
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1736
- search: rawQuery
1737
- });
1880
+ navigate(
1881
+ {
1882
+ pathname: `../${res.data.documentId}`,
1883
+ search: rawQuery
1884
+ },
1885
+ { relative: "path" }
1886
+ );
1738
1887
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1739
1888
  setErrors(formatValidationErrors(res.error));
1740
1889
  }
@@ -1762,10 +1911,13 @@ const UpdateAction = ({
1762
1911
  document
1763
1912
  );
1764
1913
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1765
- navigate({
1766
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1767
- search: rawQuery
1768
- });
1914
+ navigate(
1915
+ {
1916
+ pathname: `../${res.data.documentId}`,
1917
+ search: rawQuery
1918
+ },
1919
+ { replace: true, relative: "path" }
1920
+ );
1769
1921
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1770
1922
  setErrors(formatValidationErrors(res.error));
1771
1923
  }
@@ -1781,7 +1933,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1781
1933
  KEEP: "keep",
1782
1934
  DISCARD: "discard"
1783
1935
  };
1784
- const UnpublishAction = ({
1936
+ const UnpublishAction$1 = ({
1785
1937
  activeTab,
1786
1938
  documentId,
1787
1939
  model,
@@ -1797,10 +1949,8 @@ const UnpublishAction = ({
1797
1949
  const { toggleNotification } = useNotification();
1798
1950
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1799
1951
  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
- }
1952
+ const handleChange = (value) => {
1953
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1804
1954
  };
1805
1955
  if (!schema?.options?.draftAndPublish) {
1806
1956
  return null;
@@ -1844,45 +1994,30 @@ const UnpublishAction = ({
1844
1994
  content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1845
1995
  /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
1846
1996
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1847
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
1997
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1848
1998
  id: "content-manager.actions.unpublish.dialog.body",
1849
1999
  defaultMessage: "Are you sure?"
1850
2000
  }) })
1851
2001
  ] }),
1852
2002
  /* @__PURE__ */ jsxs(
1853
- Flex,
2003
+ Radio.Group,
1854
2004
  {
1855
- onChange: handleChange,
1856
- direction: "column",
1857
- alignItems: "flex-start",
1858
- as: "fieldset",
1859
- gap: 3,
2005
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2006
+ name: "discard-options",
2007
+ "aria-label": formatMessage({
2008
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2009
+ defaultMessage: "Choose an option to unpublish the document."
2010
+ }),
2011
+ onValueChange: handleChange,
1860
2012
  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
- )
2013
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2014
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2015
+ defaultMessage: "Keep draft"
2016
+ }) }),
2017
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2018
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2019
+ defaultMessage: "Replace draft"
2020
+ }) })
1886
2021
  ]
1887
2022
  }
1888
2023
  )
@@ -1915,7 +2050,7 @@ const UnpublishAction = ({
1915
2050
  position: ["panel", "table-row"]
1916
2051
  };
1917
2052
  };
1918
- UnpublishAction.type = "unpublish";
2053
+ UnpublishAction$1.type = "unpublish";
1919
2054
  const DiscardAction = ({
1920
2055
  activeTab,
1921
2056
  documentId,
@@ -1949,7 +2084,7 @@ const DiscardAction = ({
1949
2084
  }),
1950
2085
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
1951
2086
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1952
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2087
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1953
2088
  id: "content-manager.actions.discard.dialog.body",
1954
2089
  defaultMessage: "Are you sure?"
1955
2090
  }) })
@@ -1971,7 +2106,7 @@ const StyledCrossCircle = styled(CrossCircle)`
1971
2106
  fill: currentColor;
1972
2107
  }
1973
2108
  `;
1974
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2109
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1975
2110
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1976
2111
  const RelativeTime = React.forwardRef(
1977
2112
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2019,7 +2154,7 @@ const getDisplayName = ({
2019
2154
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2020
2155
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2021
2156
  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) }) });
2157
+ 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
2158
  };
2024
2159
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2025
2160
  const { formatMessage } = useIntl();
@@ -2028,23 +2163,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2028
2163
  id: "content-manager.containers.edit.title.new",
2029
2164
  defaultMessage: "Create an entry"
2030
2165
  }) : documentTitle;
2031
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2166
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2032
2167
  /* @__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
2168
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2169
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2170
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2171
+ ] }),
2172
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2048
2173
  ] });
2049
2174
  };
2050
2175
  const HeaderToolbar = () => {
@@ -2196,7 +2321,7 @@ const Information = ({ activeTab }) => {
2196
2321
  borderColor: "neutral150",
2197
2322
  direction: "column",
2198
2323
  marginTop: 2,
2199
- as: "dl",
2324
+ tag: "dl",
2200
2325
  padding: 5,
2201
2326
  gap: 3,
2202
2327
  alignItems: "flex-start",
@@ -2204,8 +2329,8 @@ const Information = ({ activeTab }) => {
2204
2329
  marginRight: "-0.4rem",
2205
2330
  width: "calc(100% + 8px)",
2206
2331
  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 })
2332
+ /* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2333
+ /* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2209
2334
  ] }, info.label))
2210
2335
  }
2211
2336
  );
@@ -2238,7 +2363,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2238
2363
  id: "app.links.configure-view",
2239
2364
  defaultMessage: "Configure the view"
2240
2365
  }),
2241
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2366
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2242
2367
  onClick: () => {
2243
2368
  navigate(`../${collectionType}/${model}/configurations/edit`);
2244
2369
  },
@@ -2246,11 +2371,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2246
2371
  };
2247
2372
  };
2248
2373
  ConfigureTheViewAction.type = "configure-the-view";
2249
- const StyledCog = styled(Cog)`
2250
- path {
2251
- fill: currentColor;
2252
- }
2253
- `;
2254
2374
  const EditTheModelAction = ({ model }) => {
2255
2375
  const navigate = useNavigate();
2256
2376
  const { formatMessage } = useIntl();
@@ -2259,7 +2379,7 @@ const EditTheModelAction = ({ model }) => {
2259
2379
  id: "content-manager.link-to-ctb",
2260
2380
  defaultMessage: "Edit the model"
2261
2381
  }),
2262
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2382
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2263
2383
  onClick: () => {
2264
2384
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2265
2385
  },
@@ -2267,12 +2387,7 @@ const EditTheModelAction = ({ model }) => {
2267
2387
  };
2268
2388
  };
2269
2389
  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 }) => {
2390
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2276
2391
  const navigate = useNavigate();
2277
2392
  const { formatMessage } = useIntl();
2278
2393
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2286,7 +2401,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2286
2401
  id: "content-manager.actions.delete.label",
2287
2402
  defaultMessage: "Delete document"
2288
2403
  }),
2289
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2404
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2290
2405
  dialog: {
2291
2406
  type: "dialog",
2292
2407
  title: formatMessage({
@@ -2295,7 +2410,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2295
2410
  }),
2296
2411
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2297
2412
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2298
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2413
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2299
2414
  id: "content-manager.actions.delete.dialog.body",
2300
2415
  defaultMessage: "Are you sure?"
2301
2416
  }) })
@@ -2340,13 +2455,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2340
2455
  position: ["header", "table-row"]
2341
2456
  };
2342
2457
  };
2343
- DeleteAction.type = "delete";
2344
- const StyledTrash = styled(Trash)`
2345
- path {
2346
- fill: currentColor;
2347
- }
2348
- `;
2349
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2458
+ DeleteAction$1.type = "delete";
2459
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2350
2460
  const Panels = () => {
2351
2461
  const isCloning = useMatch(CLONE_PATH) !== null;
2352
2462
  const [
@@ -2420,7 +2530,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2420
2530
  Flex,
2421
2531
  {
2422
2532
  ref,
2423
- as: "aside",
2533
+ tag: "aside",
2424
2534
  "aria-labelledby": "additional-information",
2425
2535
  background: "neutral0",
2426
2536
  borderColor: "neutral150",
@@ -2435,116 +2545,995 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2435
2545
  justifyContent: "stretch",
2436
2546
  alignItems: "flex-start",
2437
2547
  children: [
2438
- /* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2548
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2439
2549
  children
2440
2550
  ]
2441
2551
  }
2442
2552
  );
2443
2553
  });
2444
- const DEFAULT_BULK_ACTIONS = [];
2445
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2446
- const { formatMessage } = useIntl();
2447
- const getDefaultErrorMessage = (reason) => {
2448
- switch (reason) {
2449
- case "relation":
2450
- return "Duplicating the relation could remove it from the original entry.";
2451
- case "unique":
2452
- return "Identical values in a unique field are not allowed";
2453
- default:
2454
- return reason;
2455
- }
2456
- };
2457
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2458
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
2459
- id: getTranslation("containers.list.autoCloneModal.title"),
2460
- defaultMessage: "This entry can't be duplicated directly."
2461
- }) }),
2462
- /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
2463
- id: getTranslation("containers.list.autoCloneModal.description"),
2464
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2465
- }) }) }),
2466
- /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
2467
- Flex,
2468
- {
2469
- direction: "column",
2470
- gap: 2,
2471
- alignItems: "flex-start",
2472
- borderColor: "neutral200",
2473
- hasRadius: true,
2474
- padding: 6,
2475
- children: [
2476
- /* @__PURE__ */ jsx(Flex, { direction: "row", as: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", as: "li", children: [
2477
- pathSegment,
2478
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
2479
- ChevronRight,
2480
- {
2481
- fill: "neutral500",
2482
- height: "0.8rem",
2483
- width: "0.8rem",
2484
- style: { margin: "0 0.8rem" }
2485
- }
2486
- )
2487
- ] }, index2)) }),
2488
- /* @__PURE__ */ jsx(Typography, { as: "p", textColor: "neutral600", children: formatMessage({
2489
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2490
- defaultMessage: getDefaultErrorMessage(reason)
2491
- }) })
2492
- ]
2493
- },
2494
- fieldPath.join()
2495
- )) })
2496
- ] });
2497
- };
2498
- const TableActions = ({ document }) => {
2499
- const { formatMessage } = useIntl();
2500
- const { model, collectionType } = useDoc();
2501
- const plugins = useStrapiApp("TableActions", (state) => state.plugins);
2502
- const props = {
2503
- activeTab: null,
2504
- model,
2505
- documentId: document.documentId,
2506
- collectionType,
2507
- document
2508
- };
2509
- return /* @__PURE__ */ jsx(
2510
- DescriptionComponentRenderer,
2511
- {
2512
- props,
2513
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2514
- children: (actions2) => {
2515
- const tableRowActions = actions2.filter((action) => {
2516
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2517
- return positions.includes("table-row");
2518
- });
2519
- return /* @__PURE__ */ jsx(
2520
- DocumentActionsMenu,
2521
- {
2522
- actions: tableRowActions,
2523
- label: formatMessage({
2524
- id: "content-manager.containers.list.table.row-actions",
2525
- defaultMessage: "Row action"
2526
- }),
2527
- variant: "ghost"
2528
- }
2529
- );
2530
- }
2531
- }
2532
- );
2554
+ const HOOKS = {
2555
+ /**
2556
+ * Hook that allows to mutate the displayed headers of the list view table
2557
+ * @constant
2558
+ * @type {string}
2559
+ */
2560
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2561
+ /**
2562
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2563
+ * @constant
2564
+ * @type {string}
2565
+ */
2566
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2567
+ /**
2568
+ * Hook that allows to mutate the CM's edit view layout
2569
+ * @constant
2570
+ * @type {string}
2571
+ */
2572
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2573
+ /**
2574
+ * Hook that allows to mutate the CM's single types links pre-set filters
2575
+ * @constant
2576
+ * @type {string}
2577
+ */
2578
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2533
2579
  };
2534
- const EditAction = ({ documentId }) => {
2535
- const navigate = useNavigate();
2536
- const { formatMessage } = useIntl();
2537
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2538
- const { toggleNotification } = useNotification();
2539
- const [{ query }] = useQueryParams();
2540
- return {
2541
- disabled: !canRead,
2542
- icon: /* @__PURE__ */ jsx(StyledPencil, {}),
2543
- label: formatMessage({
2544
- id: "content-manager.actions.edit.label",
2545
- defaultMessage: "Edit"
2546
- }),
2547
- position: "table-row",
2580
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2581
+ endpoints: (builder) => ({
2582
+ getContentTypeConfiguration: builder.query({
2583
+ query: (uid) => ({
2584
+ url: `/content-manager/content-types/${uid}/configuration`,
2585
+ method: "GET"
2586
+ }),
2587
+ transformResponse: (response) => response.data,
2588
+ providesTags: (_result, _error, uid) => [
2589
+ { type: "ContentTypesConfiguration", id: uid },
2590
+ { type: "ContentTypeSettings", id: "LIST" }
2591
+ ]
2592
+ }),
2593
+ getAllContentTypeSettings: builder.query({
2594
+ query: () => "/content-manager/content-types-settings",
2595
+ transformResponse: (response) => response.data,
2596
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2597
+ }),
2598
+ updateContentTypeConfiguration: builder.mutation({
2599
+ query: ({ uid, ...body }) => ({
2600
+ url: `/content-manager/content-types/${uid}/configuration`,
2601
+ method: "PUT",
2602
+ data: body
2603
+ }),
2604
+ transformResponse: (response) => response.data,
2605
+ invalidatesTags: (_result, _error, { uid }) => [
2606
+ { type: "ContentTypesConfiguration", id: uid },
2607
+ { type: "ContentTypeSettings", id: "LIST" },
2608
+ // Is this necessary?
2609
+ { type: "InitialData" }
2610
+ ]
2611
+ })
2612
+ })
2613
+ });
2614
+ const {
2615
+ useGetContentTypeConfigurationQuery,
2616
+ useGetAllContentTypeSettingsQuery,
2617
+ useUpdateContentTypeConfigurationMutation
2618
+ } = contentTypesApi;
2619
+ const checkIfAttributeIsDisplayable = (attribute) => {
2620
+ const { type } = attribute;
2621
+ if (type === "relation") {
2622
+ return !attribute.relation.toLowerCase().includes("morph");
2623
+ }
2624
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2625
+ };
2626
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2627
+ if (!mainFieldName) {
2628
+ return void 0;
2629
+ }
2630
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2631
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2632
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2633
+ );
2634
+ return {
2635
+ name: mainFieldName,
2636
+ type: mainFieldType ?? "string"
2637
+ };
2638
+ };
2639
+ const DEFAULT_SETTINGS = {
2640
+ bulkable: false,
2641
+ filterable: false,
2642
+ searchable: false,
2643
+ pagination: false,
2644
+ defaultSortBy: "",
2645
+ defaultSortOrder: "asc",
2646
+ mainField: "id",
2647
+ pageSize: 10
2648
+ };
2649
+ const useDocumentLayout = (model) => {
2650
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2651
+ const [{ query }] = useQueryParams();
2652
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2653
+ const { toggleNotification } = useNotification();
2654
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2655
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2656
+ const {
2657
+ data,
2658
+ isLoading: isLoadingConfigs,
2659
+ error,
2660
+ isFetching: isFetchingConfigs
2661
+ } = useGetContentTypeConfigurationQuery(model);
2662
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2663
+ React.useEffect(() => {
2664
+ if (error) {
2665
+ toggleNotification({
2666
+ type: "danger",
2667
+ message: formatAPIError(error)
2668
+ });
2669
+ }
2670
+ }, [error, formatAPIError, toggleNotification]);
2671
+ const editLayout = React.useMemo(
2672
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2673
+ layout: [],
2674
+ components: {},
2675
+ metadatas: {},
2676
+ options: {},
2677
+ settings: DEFAULT_SETTINGS
2678
+ },
2679
+ [data, isLoading, schemas, schema, components]
2680
+ );
2681
+ const listLayout = React.useMemo(() => {
2682
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2683
+ layout: [],
2684
+ metadatas: {},
2685
+ options: {},
2686
+ settings: DEFAULT_SETTINGS
2687
+ };
2688
+ }, [data, isLoading, schemas, schema, components]);
2689
+ const { layout: edit } = React.useMemo(
2690
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2691
+ layout: editLayout,
2692
+ query
2693
+ }),
2694
+ [editLayout, query, runHookWaterfall]
2695
+ );
2696
+ return {
2697
+ error,
2698
+ isLoading,
2699
+ edit,
2700
+ list: listLayout
2701
+ };
2702
+ };
2703
+ const useDocLayout = () => {
2704
+ const { model } = useDoc();
2705
+ return useDocumentLayout(model);
2706
+ };
2707
+ const formatEditLayout = (data, {
2708
+ schemas,
2709
+ schema,
2710
+ components
2711
+ }) => {
2712
+ let currentPanelIndex = 0;
2713
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2714
+ data.contentType.layouts.edit,
2715
+ schema?.attributes,
2716
+ data.contentType.metadatas,
2717
+ { configurations: data.components, schemas: components },
2718
+ schemas
2719
+ ).reduce((panels, row) => {
2720
+ if (row.some((field) => field.type === "dynamiczone")) {
2721
+ panels.push([row]);
2722
+ currentPanelIndex += 2;
2723
+ } else {
2724
+ if (!panels[currentPanelIndex]) {
2725
+ panels.push([]);
2726
+ }
2727
+ panels[currentPanelIndex].push(row);
2728
+ }
2729
+ return panels;
2730
+ }, []);
2731
+ const componentEditAttributes = Object.entries(data.components).reduce(
2732
+ (acc, [uid, configuration]) => {
2733
+ acc[uid] = {
2734
+ layout: convertEditLayoutToFieldLayouts(
2735
+ configuration.layouts.edit,
2736
+ components[uid].attributes,
2737
+ configuration.metadatas
2738
+ ),
2739
+ settings: {
2740
+ ...configuration.settings,
2741
+ icon: components[uid].info.icon,
2742
+ displayName: components[uid].info.displayName
2743
+ }
2744
+ };
2745
+ return acc;
2746
+ },
2747
+ {}
2748
+ );
2749
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2750
+ (acc, [attribute, metadata]) => {
2751
+ return {
2752
+ ...acc,
2753
+ [attribute]: metadata.edit
2754
+ };
2755
+ },
2756
+ {}
2757
+ );
2758
+ return {
2759
+ layout: panelledEditAttributes,
2760
+ components: componentEditAttributes,
2761
+ metadatas: editMetadatas,
2762
+ settings: {
2763
+ ...data.contentType.settings,
2764
+ displayName: schema?.info.displayName
2765
+ },
2766
+ options: {
2767
+ ...schema?.options,
2768
+ ...schema?.pluginOptions,
2769
+ ...data.contentType.options
2770
+ }
2771
+ };
2772
+ };
2773
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2774
+ return rows.map(
2775
+ (row) => row.map((field) => {
2776
+ const attribute = attributes[field.name];
2777
+ if (!attribute) {
2778
+ return null;
2779
+ }
2780
+ const { edit: metadata } = metadatas[field.name];
2781
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2782
+ return {
2783
+ attribute,
2784
+ disabled: !metadata.editable,
2785
+ hint: metadata.description,
2786
+ label: metadata.label ?? "",
2787
+ name: field.name,
2788
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2789
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2790
+ schemas,
2791
+ components: components?.schemas ?? {}
2792
+ }),
2793
+ placeholder: metadata.placeholder ?? "",
2794
+ required: attribute.required ?? false,
2795
+ size: field.size,
2796
+ unique: "unique" in attribute ? attribute.unique : false,
2797
+ visible: metadata.visible ?? true,
2798
+ type: attribute.type
2799
+ };
2800
+ }).filter((field) => field !== null)
2801
+ );
2802
+ };
2803
+ const formatListLayout = (data, {
2804
+ schemas,
2805
+ schema,
2806
+ components
2807
+ }) => {
2808
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2809
+ (acc, [attribute, metadata]) => {
2810
+ return {
2811
+ ...acc,
2812
+ [attribute]: metadata.list
2813
+ };
2814
+ },
2815
+ {}
2816
+ );
2817
+ const listAttributes = convertListLayoutToFieldLayouts(
2818
+ data.contentType.layouts.list,
2819
+ schema?.attributes,
2820
+ listMetadatas,
2821
+ { configurations: data.components, schemas: components },
2822
+ schemas
2823
+ );
2824
+ return {
2825
+ layout: listAttributes,
2826
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2827
+ metadatas: listMetadatas,
2828
+ options: {
2829
+ ...schema?.options,
2830
+ ...schema?.pluginOptions,
2831
+ ...data.contentType.options
2832
+ }
2833
+ };
2834
+ };
2835
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2836
+ return columns.map((name) => {
2837
+ const attribute = attributes[name];
2838
+ if (!attribute) {
2839
+ return null;
2840
+ }
2841
+ const metadata = metadatas[name];
2842
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2843
+ return {
2844
+ attribute,
2845
+ label: metadata.label ?? "",
2846
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2847
+ schemas,
2848
+ components: components?.schemas ?? {}
2849
+ }),
2850
+ name,
2851
+ searchable: metadata.searchable ?? true,
2852
+ sortable: metadata.sortable ?? true
2853
+ };
2854
+ }).filter((field) => field !== null);
2855
+ };
2856
+ const ConfirmBulkActionDialog = ({
2857
+ onToggleDialog,
2858
+ isOpen = false,
2859
+ dialogBody,
2860
+ endAction
2861
+ }) => {
2862
+ const { formatMessage } = useIntl();
2863
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2864
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2865
+ id: "app.components.ConfirmDialog.title",
2866
+ defaultMessage: "Confirmation"
2867
+ }) }),
2868
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2869
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2870
+ dialogBody
2871
+ ] }) }),
2872
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2873
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2874
+ id: "app.components.Button.cancel",
2875
+ defaultMessage: "Cancel"
2876
+ }) }) }),
2877
+ endAction
2878
+ ] })
2879
+ ] }) });
2880
+ };
2881
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2882
+ const ConfirmDialogPublishAll = ({
2883
+ isOpen,
2884
+ onToggleDialog,
2885
+ isConfirmButtonLoading = false,
2886
+ onConfirm
2887
+ }) => {
2888
+ const { formatMessage } = useIntl();
2889
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2890
+ const { toggleNotification } = useNotification();
2891
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2892
+ const { model, schema } = useDoc();
2893
+ const [{ query }] = useQueryParams();
2894
+ const {
2895
+ data: countDraftRelations = 0,
2896
+ isLoading,
2897
+ error
2898
+ } = useGetManyDraftRelationCountQuery(
2899
+ {
2900
+ model,
2901
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2902
+ locale: query?.plugins?.i18n?.locale
2903
+ },
2904
+ {
2905
+ skip: selectedEntries.length === 0
2906
+ }
2907
+ );
2908
+ React.useEffect(() => {
2909
+ if (error) {
2910
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2911
+ }
2912
+ }, [error, formatAPIError, toggleNotification]);
2913
+ if (error) {
2914
+ return null;
2915
+ }
2916
+ return /* @__PURE__ */ jsx(
2917
+ ConfirmBulkActionDialog,
2918
+ {
2919
+ isOpen: isOpen && !isLoading,
2920
+ onToggleDialog,
2921
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2922
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2923
+ countDraftRelations > 0 && formatMessage(
2924
+ {
2925
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2926
+ 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. "
2927
+ },
2928
+ {
2929
+ b: BoldChunk$1,
2930
+ count: countDraftRelations,
2931
+ entities: selectedEntries.length
2932
+ }
2933
+ ),
2934
+ formatMessage({
2935
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2936
+ defaultMessage: "Are you sure you want to publish these entries?"
2937
+ })
2938
+ ] }),
2939
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2940
+ {
2941
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2942
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2943
+ },
2944
+ {
2945
+ em: Emphasis
2946
+ }
2947
+ ) })
2948
+ ] }),
2949
+ endAction: /* @__PURE__ */ jsx(
2950
+ Button,
2951
+ {
2952
+ onClick: onConfirm,
2953
+ variant: "secondary",
2954
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2955
+ loading: isConfirmButtonLoading,
2956
+ children: formatMessage({
2957
+ id: "app.utils.publish",
2958
+ defaultMessage: "Publish"
2959
+ })
2960
+ }
2961
+ )
2962
+ }
2963
+ );
2964
+ };
2965
+ const TypographyMaxWidth = styled(Typography)`
2966
+ max-width: 300px;
2967
+ `;
2968
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2969
+ const messages = [];
2970
+ Object.entries(errors).forEach(([key, value]) => {
2971
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
2972
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2973
+ if ("id" in value && "defaultMessage" in value) {
2974
+ messages.push(
2975
+ formatMessage(
2976
+ {
2977
+ id: `${value.id}.withField`,
2978
+ defaultMessage: value.defaultMessage
2979
+ },
2980
+ { field: currentKey }
2981
+ )
2982
+ );
2983
+ } else {
2984
+ messages.push(
2985
+ ...formatErrorMessages(
2986
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
2987
+ value,
2988
+ currentKey,
2989
+ formatMessage
2990
+ )
2991
+ );
2992
+ }
2993
+ } else {
2994
+ messages.push(
2995
+ formatMessage(
2996
+ {
2997
+ id: `${value}.withField`,
2998
+ defaultMessage: value
2999
+ },
3000
+ { field: currentKey }
3001
+ )
3002
+ );
3003
+ }
3004
+ });
3005
+ return messages;
3006
+ };
3007
+ const EntryValidationText = ({ validationErrors, status }) => {
3008
+ const { formatMessage } = useIntl();
3009
+ if (validationErrors) {
3010
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3011
+ " "
3012
+ );
3013
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3014
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3015
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3016
+ ] });
3017
+ }
3018
+ if (status === "published") {
3019
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3020
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3021
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3022
+ id: "content-manager.bulk-publish.already-published",
3023
+ defaultMessage: "Already Published"
3024
+ }) })
3025
+ ] });
3026
+ }
3027
+ if (status === "modified") {
3028
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3029
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3030
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3031
+ id: "content-manager.bulk-publish.modified",
3032
+ defaultMessage: "Ready to publish changes"
3033
+ }) })
3034
+ ] });
3035
+ }
3036
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3037
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3038
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3039
+ id: "app.utils.ready-to-publish",
3040
+ defaultMessage: "Ready to publish"
3041
+ }) })
3042
+ ] });
3043
+ };
3044
+ const TABLE_HEADERS = [
3045
+ { name: "id", label: "id" },
3046
+ { name: "name", label: "name" },
3047
+ { name: "status", label: "status" },
3048
+ { name: "publicationStatus", label: "Publication status" }
3049
+ ];
3050
+ const SelectedEntriesTableContent = ({
3051
+ isPublishing,
3052
+ rowsToDisplay = [],
3053
+ entriesToPublish = [],
3054
+ validationErrors = {}
3055
+ }) => {
3056
+ const { pathname } = useLocation();
3057
+ const { formatMessage } = useIntl();
3058
+ const {
3059
+ list: {
3060
+ settings: { mainField }
3061
+ }
3062
+ } = useDocLayout();
3063
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3064
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3065
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3066
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3067
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3068
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3069
+ )
3070
+ ] }),
3071
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3072
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3073
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3074
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3075
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3076
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3077
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3078
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3079
+ id: "content-manager.success.record.publishing",
3080
+ defaultMessage: "Publishing..."
3081
+ }) }),
3082
+ /* @__PURE__ */ jsx(Loader, { small: true })
3083
+ ] }) : /* @__PURE__ */ jsx(
3084
+ EntryValidationText,
3085
+ {
3086
+ validationErrors: validationErrors[row.documentId],
3087
+ status: row.status
3088
+ }
3089
+ ) }),
3090
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3091
+ IconButton,
3092
+ {
3093
+ tag: Link,
3094
+ to: {
3095
+ pathname: `${pathname}/${row.documentId}`,
3096
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3097
+ },
3098
+ state: { from: pathname },
3099
+ label: formatMessage(
3100
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3101
+ {
3102
+ target: formatMessage(
3103
+ {
3104
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3105
+ defaultMessage: "item line {number}"
3106
+ },
3107
+ { number: index2 + 1 }
3108
+ )
3109
+ }
3110
+ ),
3111
+ target: "_blank",
3112
+ marginLeft: "auto",
3113
+ children: /* @__PURE__ */ jsx(Pencil, {})
3114
+ }
3115
+ ) })
3116
+ ] }, row.id)) })
3117
+ ] });
3118
+ };
3119
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3120
+ const SelectedEntriesModalContent = ({
3121
+ listViewSelectedEntries,
3122
+ toggleModal,
3123
+ setListViewSelectedDocuments,
3124
+ model
3125
+ }) => {
3126
+ const { formatMessage } = useIntl();
3127
+ const { schema, components } = useContentTypeSchema(model);
3128
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3129
+ const [{ query }] = useQueryParams();
3130
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3131
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3132
+ {
3133
+ model,
3134
+ params: {
3135
+ page: "1",
3136
+ pageSize: documentIds.length.toString(),
3137
+ sort: query.sort,
3138
+ filters: {
3139
+ documentId: {
3140
+ $in: documentIds
3141
+ }
3142
+ },
3143
+ locale: query.plugins?.i18n?.locale
3144
+ }
3145
+ },
3146
+ {
3147
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3148
+ }
3149
+ );
3150
+ const { rows, validationErrors } = React.useMemo(() => {
3151
+ if (data.length > 0 && schema) {
3152
+ const validate = createYupSchema(schema.attributes, components);
3153
+ const validationErrors2 = {};
3154
+ const rows2 = data.map((entry) => {
3155
+ try {
3156
+ validate.validateSync(entry, { abortEarly: false });
3157
+ return entry;
3158
+ } catch (e) {
3159
+ if (e instanceof ValidationError) {
3160
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3161
+ }
3162
+ return entry;
3163
+ }
3164
+ });
3165
+ return { rows: rows2, validationErrors: validationErrors2 };
3166
+ }
3167
+ return {
3168
+ rows: [],
3169
+ validationErrors: {}
3170
+ };
3171
+ }, [components, data, schema]);
3172
+ const [publishedCount, setPublishedCount] = React.useState(0);
3173
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3174
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3175
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3176
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3177
+ const selectedEntries = rows.filter(
3178
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3179
+ );
3180
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3181
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3182
+ ({ documentId }) => validationErrors[documentId]
3183
+ ).length;
3184
+ const selectedEntriesPublished = selectedEntries.filter(
3185
+ ({ status }) => status === "published"
3186
+ ).length;
3187
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3188
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3189
+ const handleConfirmBulkPublish = async () => {
3190
+ toggleDialog();
3191
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3192
+ if (!("error" in res)) {
3193
+ setPublishedCount(res.count);
3194
+ const unpublishedEntries = rows.filter((row) => {
3195
+ return !entriesToPublish.includes(row.documentId);
3196
+ });
3197
+ setListViewSelectedDocuments(unpublishedEntries);
3198
+ }
3199
+ };
3200
+ const getFormattedCountMessage = () => {
3201
+ if (publishedCount) {
3202
+ return formatMessage(
3203
+ {
3204
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3205
+ 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."
3206
+ },
3207
+ {
3208
+ publishedCount,
3209
+ withErrorsCount: selectedEntriesWithErrorsCount,
3210
+ b: BoldChunk
3211
+ }
3212
+ );
3213
+ }
3214
+ return formatMessage(
3215
+ {
3216
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3217
+ 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."
3218
+ },
3219
+ {
3220
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3221
+ withErrorsCount: selectedEntriesWithErrorsCount,
3222
+ alreadyPublishedCount: selectedEntriesPublished,
3223
+ b: BoldChunk
3224
+ }
3225
+ );
3226
+ };
3227
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3228
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3229
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3230
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3231
+ SelectedEntriesTableContent,
3232
+ {
3233
+ isPublishing: isSubmittingForm,
3234
+ rowsToDisplay: rows,
3235
+ entriesToPublish,
3236
+ validationErrors
3237
+ }
3238
+ ) })
3239
+ ] }),
3240
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3241
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3242
+ id: "app.components.Button.cancel",
3243
+ defaultMessage: "Cancel"
3244
+ }) }),
3245
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3246
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3247
+ /* @__PURE__ */ jsx(
3248
+ Button,
3249
+ {
3250
+ onClick: toggleDialog,
3251
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3252
+ loading: isSubmittingForm,
3253
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3254
+ }
3255
+ )
3256
+ ] })
3257
+ ] }),
3258
+ /* @__PURE__ */ jsx(
3259
+ ConfirmDialogPublishAll,
3260
+ {
3261
+ isOpen: isDialogOpen,
3262
+ onToggleDialog: toggleDialog,
3263
+ isConfirmButtonLoading: isSubmittingForm,
3264
+ onConfirm: handleConfirmBulkPublish
3265
+ }
3266
+ )
3267
+ ] });
3268
+ };
3269
+ const PublishAction = ({ documents, model }) => {
3270
+ const { formatMessage } = useIntl();
3271
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3272
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3273
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3274
+ const refetchList = () => {
3275
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3276
+ };
3277
+ if (!showPublishButton)
3278
+ return null;
3279
+ return {
3280
+ actionType: "publish",
3281
+ variant: "tertiary",
3282
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3283
+ dialog: {
3284
+ type: "modal",
3285
+ title: formatMessage({
3286
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3287
+ defaultMessage: "Publish entries"
3288
+ }),
3289
+ content: ({ onClose }) => {
3290
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3291
+ SelectedEntriesModalContent,
3292
+ {
3293
+ listViewSelectedEntries: documents,
3294
+ toggleModal: () => {
3295
+ onClose();
3296
+ refetchList();
3297
+ },
3298
+ setListViewSelectedDocuments,
3299
+ model
3300
+ }
3301
+ ) });
3302
+ },
3303
+ onClose: () => {
3304
+ refetchList();
3305
+ }
3306
+ }
3307
+ };
3308
+ };
3309
+ const BulkActionsRenderer = () => {
3310
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3311
+ const { model, collectionType } = useDoc();
3312
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3313
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3314
+ DescriptionComponentRenderer,
3315
+ {
3316
+ props: {
3317
+ model,
3318
+ collectionType,
3319
+ documents: selectedRows
3320
+ },
3321
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3322
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3323
+ }
3324
+ ) });
3325
+ };
3326
+ const DeleteAction = ({ documents, model }) => {
3327
+ const { formatMessage } = useIntl();
3328
+ const { schema: contentType } = useDoc();
3329
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3330
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3331
+ const [{ query }] = useQueryParams();
3332
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3333
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3334
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3335
+ const documentIds = documents.map(({ documentId }) => documentId);
3336
+ const handleConfirmBulkDelete = async () => {
3337
+ const res = await bulkDeleteAction({
3338
+ documentIds,
3339
+ model,
3340
+ params
3341
+ });
3342
+ if (!("error" in res)) {
3343
+ selectRow([]);
3344
+ }
3345
+ };
3346
+ if (!hasDeletePermission)
3347
+ return null;
3348
+ return {
3349
+ variant: "danger-light",
3350
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3351
+ dialog: {
3352
+ type: "dialog",
3353
+ title: formatMessage({
3354
+ id: "app.components.ConfirmDialog.title",
3355
+ defaultMessage: "Confirmation"
3356
+ }),
3357
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3358
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3359
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3360
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3361
+ defaultMessage: "Are you sure you want to delete these entries?"
3362
+ }) }),
3363
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3364
+ {
3365
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3366
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3367
+ },
3368
+ {
3369
+ em: Emphasis
3370
+ }
3371
+ ) }) })
3372
+ ] }),
3373
+ onConfirm: handleConfirmBulkDelete
3374
+ }
3375
+ };
3376
+ };
3377
+ DeleteAction.type = "delete";
3378
+ const UnpublishAction = ({ documents, model }) => {
3379
+ const { formatMessage } = useIntl();
3380
+ const { schema } = useDoc();
3381
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3382
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3383
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3384
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3385
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3386
+ const documentIds = documents.map(({ documentId }) => documentId);
3387
+ const [{ query }] = useQueryParams();
3388
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3389
+ const handleConfirmBulkUnpublish = async () => {
3390
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3391
+ if (!("error" in data)) {
3392
+ selectRow([]);
3393
+ }
3394
+ };
3395
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3396
+ if (!showUnpublishButton)
3397
+ return null;
3398
+ return {
3399
+ variant: "tertiary",
3400
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3401
+ dialog: {
3402
+ type: "dialog",
3403
+ title: formatMessage({
3404
+ id: "app.components.ConfirmDialog.title",
3405
+ defaultMessage: "Confirmation"
3406
+ }),
3407
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3408
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3409
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3410
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3411
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3412
+ }) }),
3413
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3414
+ {
3415
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3416
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3417
+ },
3418
+ {
3419
+ em: Emphasis
3420
+ }
3421
+ ) }) })
3422
+ ] }),
3423
+ confirmButton: formatMessage({
3424
+ id: "app.utils.unpublish",
3425
+ defaultMessage: "Unpublish"
3426
+ }),
3427
+ onConfirm: handleConfirmBulkUnpublish
3428
+ }
3429
+ };
3430
+ };
3431
+ UnpublishAction.type = "unpublish";
3432
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3433
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3434
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3435
+ const { formatMessage } = useIntl();
3436
+ const getDefaultErrorMessage = (reason) => {
3437
+ switch (reason) {
3438
+ case "relation":
3439
+ return "Duplicating the relation could remove it from the original entry.";
3440
+ case "unique":
3441
+ return "Identical values in a unique field are not allowed";
3442
+ default:
3443
+ return reason;
3444
+ }
3445
+ };
3446
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3447
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3448
+ id: getTranslation("containers.list.autoCloneModal.title"),
3449
+ defaultMessage: "This entry can't be duplicated directly."
3450
+ }) }),
3451
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3452
+ id: getTranslation("containers.list.autoCloneModal.description"),
3453
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3454
+ }) }) }),
3455
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3456
+ Flex,
3457
+ {
3458
+ direction: "column",
3459
+ gap: 2,
3460
+ alignItems: "flex-start",
3461
+ borderColor: "neutral200",
3462
+ hasRadius: true,
3463
+ padding: 6,
3464
+ children: [
3465
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3466
+ pathSegment,
3467
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3468
+ ChevronRight,
3469
+ {
3470
+ fill: "neutral500",
3471
+ height: "0.8rem",
3472
+ width: "0.8rem",
3473
+ style: { margin: "0 0.8rem" }
3474
+ }
3475
+ )
3476
+ ] }, index2)) }),
3477
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3478
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3479
+ defaultMessage: getDefaultErrorMessage(reason)
3480
+ }) })
3481
+ ]
3482
+ },
3483
+ fieldPath.join()
3484
+ )) })
3485
+ ] });
3486
+ };
3487
+ const TableActions = ({ document }) => {
3488
+ const { formatMessage } = useIntl();
3489
+ const { model, collectionType } = useDoc();
3490
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3491
+ const props = {
3492
+ activeTab: null,
3493
+ model,
3494
+ documentId: document.documentId,
3495
+ collectionType,
3496
+ document
3497
+ };
3498
+ return /* @__PURE__ */ jsx(
3499
+ DescriptionComponentRenderer,
3500
+ {
3501
+ props,
3502
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3503
+ children: (actions2) => {
3504
+ const tableRowActions = actions2.filter((action) => {
3505
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3506
+ return positions.includes("table-row");
3507
+ });
3508
+ return /* @__PURE__ */ jsx(
3509
+ DocumentActionsMenu,
3510
+ {
3511
+ actions: tableRowActions,
3512
+ label: formatMessage({
3513
+ id: "content-manager.containers.list.table.row-actions",
3514
+ defaultMessage: "Row action"
3515
+ }),
3516
+ variant: "ghost"
3517
+ }
3518
+ );
3519
+ }
3520
+ }
3521
+ );
3522
+ };
3523
+ const EditAction = ({ documentId }) => {
3524
+ const navigate = useNavigate();
3525
+ const { formatMessage } = useIntl();
3526
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3527
+ const { toggleNotification } = useNotification();
3528
+ const [{ query }] = useQueryParams();
3529
+ return {
3530
+ disabled: !canRead,
3531
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3532
+ label: formatMessage({
3533
+ id: "content-manager.actions.edit.label",
3534
+ defaultMessage: "Edit"
3535
+ }),
3536
+ position: "table-row",
2548
3537
  onClick: async () => {
2549
3538
  if (!documentId) {
2550
3539
  console.error(
@@ -2629,7 +3618,7 @@ const CloneAction = ({ model, documentId }) => {
2629
3618
  /* @__PURE__ */ jsx(
2630
3619
  LinkButton,
2631
3620
  {
2632
- as: NavLink,
3621
+ tag: NavLink,
2633
3622
  to: {
2634
3623
  pathname: `clone/${documentId}`
2635
3624
  },
@@ -2662,442 +3651,183 @@ class ContentManagerPlugin {
2662
3651
  documentActions = [
2663
3652
  ...DEFAULT_ACTIONS,
2664
3653
  ...DEFAULT_TABLE_ROW_ACTIONS,
2665
- ...DEFAULT_HEADER_ACTIONS,
2666
- HistoryAction
3654
+ ...DEFAULT_HEADER_ACTIONS
2667
3655
  ];
2668
3656
  editViewSidePanels = [ActionsPanel];
2669
3657
  headerActions = [];
2670
3658
  constructor() {
2671
3659
  }
2672
- addEditViewSidePanel(panels) {
2673
- if (Array.isArray(panels)) {
2674
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2675
- } else if (typeof panels === "function") {
2676
- this.editViewSidePanels = panels(this.editViewSidePanels);
2677
- } else {
2678
- throw new Error(
2679
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2680
- panels
2681
- )}`
2682
- );
2683
- }
2684
- }
2685
- addDocumentAction(actions2) {
2686
- if (Array.isArray(actions2)) {
2687
- this.documentActions = [...this.documentActions, ...actions2];
2688
- } else if (typeof actions2 === "function") {
2689
- this.documentActions = actions2(this.documentActions);
2690
- } else {
2691
- throw new Error(
2692
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2693
- actions2
2694
- )}`
2695
- );
2696
- }
2697
- }
2698
- addDocumentHeaderAction(actions2) {
2699
- if (Array.isArray(actions2)) {
2700
- this.headerActions = [...this.headerActions, ...actions2];
2701
- } else if (typeof actions2 === "function") {
2702
- this.headerActions = actions2(this.headerActions);
3660
+ addEditViewSidePanel(panels) {
3661
+ if (Array.isArray(panels)) {
3662
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3663
+ } else if (typeof panels === "function") {
3664
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2703
3665
  } else {
2704
3666
  throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
3667
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3668
+ panels
2707
3669
  )}`
2708
3670
  );
2709
3671
  }
2710
3672
  }
2711
- addBulkAction(actions2) {
3673
+ addDocumentAction(actions2) {
2712
3674
  if (Array.isArray(actions2)) {
2713
- this.bulkActions = [...this.bulkActions, ...actions2];
3675
+ this.documentActions = [...this.documentActions, ...actions2];
2714
3676
  } else if (typeof actions2 === "function") {
2715
- this.bulkActions = actions2(this.bulkActions);
3677
+ this.documentActions = actions2(this.documentActions);
2716
3678
  } else {
2717
3679
  throw new Error(
2718
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3680
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2719
3681
  actions2
2720
3682
  )}`
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;
3683
+ );
3684
+ }
3685
+ }
3686
+ addDocumentHeaderAction(actions2) {
3687
+ if (Array.isArray(actions2)) {
3688
+ this.headerActions = [...this.headerActions, ...actions2];
3689
+ } else if (typeof actions2 === "function") {
3690
+ this.headerActions = actions2(this.headerActions);
2960
3691
  } else {
2961
- if (!panels[currentPanelIndex]) {
2962
- panels.push([]);
2963
- }
2964
- panels[currentPanelIndex].push(row);
3692
+ throw new Error(
3693
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3694
+ actions2
3695
+ )}`
3696
+ );
2965
3697
  }
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
3698
+ }
3699
+ addBulkAction(actions2) {
3700
+ if (Array.isArray(actions2)) {
3701
+ this.bulkActions = [...this.bulkActions, ...actions2];
3702
+ } else if (typeof actions2 === "function") {
3703
+ this.bulkActions = actions2(this.bulkActions);
3704
+ } else {
3705
+ throw new Error(
3706
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3707
+ actions2
3708
+ )}`
3709
+ );
3007
3710
  }
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;
3711
+ }
3712
+ get config() {
3713
+ return {
3714
+ id: PLUGIN_ID,
3715
+ name: "Content Manager",
3716
+ injectionZones: INJECTION_ZONES,
3717
+ apis: {
3718
+ addBulkAction: this.addBulkAction.bind(this),
3719
+ addDocumentAction: this.addDocumentAction.bind(this),
3720
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3721
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3722
+ getBulkActions: () => this.bulkActions,
3723
+ getDocumentActions: () => this.documentActions,
3724
+ getEditViewSidePanels: () => this.editViewSidePanels,
3725
+ getHeaderActions: () => this.headerActions
3016
3726
  }
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
- );
3727
+ };
3728
+ }
3729
+ }
3730
+ const getPrintableType = (value) => {
3731
+ const nativeType = typeof value;
3732
+ if (nativeType === "object") {
3733
+ if (value === null)
3734
+ return "null";
3735
+ if (Array.isArray(value))
3736
+ return "array";
3737
+ if (value instanceof Object && value.constructor.name !== "Object") {
3738
+ return value.constructor.name;
3739
+ }
3740
+ }
3741
+ return nativeType;
3039
3742
  };
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
- );
3743
+ const HistoryAction = ({ model, document }) => {
3744
+ const { formatMessage } = useIntl();
3745
+ const [{ query }] = useQueryParams();
3746
+ const navigate = useNavigate();
3747
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3748
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3749
+ return null;
3750
+ }
3061
3751
  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
- }
3752
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3753
+ label: formatMessage({
3754
+ id: "content-manager.history.document-action",
3755
+ defaultMessage: "Content History"
3756
+ }),
3757
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3758
+ disabled: (
3759
+ /**
3760
+ * The user is creating a new document.
3761
+ * It hasn't been saved yet, so there's no history to go to
3762
+ */
3763
+ !document || /**
3764
+ * The document has been created but the current dimension has never been saved.
3765
+ * For example, the user is creating a new locale in an existing document,
3766
+ * so there's no history for the document in that locale
3767
+ */
3768
+ !document.id || /**
3769
+ * History is only available for content types created by the user.
3770
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3771
+ * which start with `admin::` or `plugin::`
3772
+ */
3773
+ !model.startsWith("api::")
3774
+ ),
3775
+ position: "header"
3070
3776
  };
3071
3777
  };
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);
3778
+ HistoryAction.type = "history";
3779
+ const historyAdmin = {
3780
+ bootstrap(app) {
3781
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3782
+ addDocumentAction((actions2) => {
3783
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3784
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3785
+ return actions2;
3786
+ });
3787
+ }
3788
+ };
3789
+ const initialState = {
3790
+ collectionTypeLinks: [],
3791
+ components: [],
3792
+ fieldSizes: {},
3793
+ models: [],
3794
+ singleTypeLinks: [],
3795
+ isLoading: true
3092
3796
  };
3797
+ const appSlice = createSlice({
3798
+ name: "app",
3799
+ initialState,
3800
+ reducers: {
3801
+ setInitialData(state, action) {
3802
+ const {
3803
+ authorizedCollectionTypeLinks,
3804
+ authorizedSingleTypeLinks,
3805
+ components,
3806
+ contentTypeSchemas,
3807
+ fieldSizes
3808
+ } = action.payload;
3809
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3810
+ ({ isDisplayed }) => isDisplayed
3811
+ );
3812
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3813
+ state.components = components;
3814
+ state.models = contentTypeSchemas;
3815
+ state.fieldSizes = fieldSizes;
3816
+ state.isLoading = false;
3817
+ }
3818
+ }
3819
+ });
3820
+ const { actions, reducer: reducer$1 } = appSlice;
3821
+ const { setInitialData } = actions;
3822
+ const reducer = combineReducers({
3823
+ app: reducer$1
3824
+ });
3093
3825
  const index = {
3094
3826
  register(app) {
3095
3827
  const cm = new ContentManagerPlugin();
3096
3828
  app.addReducers({
3097
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3098
3829
  [PLUGIN_ID]: reducer
3099
3830
  });
3100
- app.addMiddlewares([() => contentManagerApi.middleware]);
3101
3831
  app.addMenuLink({
3102
3832
  to: PLUGIN_ID,
3103
3833
  icon: Feather,
@@ -3106,14 +3836,29 @@ const index = {
3106
3836
  defaultMessage: "Content Manager"
3107
3837
  },
3108
3838
  permissions: [],
3109
- Component: () => import("./layout-jIDzX0Fp.mjs").then((mod) => ({ default: mod.Layout }))
3839
+ position: 1
3840
+ });
3841
+ app.router.addRoute({
3842
+ path: "content-manager/*",
3843
+ lazy: async () => {
3844
+ const { Layout } = await import("./layout-B3ez7kvr.mjs");
3845
+ return {
3846
+ Component: Layout
3847
+ };
3848
+ },
3849
+ children: routes
3110
3850
  });
3111
3851
  app.registerPlugin(cm.config);
3112
3852
  },
3853
+ bootstrap(app) {
3854
+ if (typeof historyAdmin.bootstrap === "function") {
3855
+ historyAdmin.bootstrap(app);
3856
+ }
3857
+ },
3113
3858
  async registerTrads({ locales }) {
3114
3859
  const importedTrads = await Promise.all(
3115
3860
  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 }) => {
3861
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-BrCTWlZv.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3117
3862
  return {
3118
3863
  data: prefixPluginTranslations(data, PLUGIN_ID),
3119
3864
  locale
@@ -3131,7 +3876,7 @@ const index = {
3131
3876
  };
3132
3877
  export {
3133
3878
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3134
- extractContentTypeComponents as B,
3879
+ BulkActionsRenderer as B,
3135
3880
  COLLECTION_TYPES as C,
3136
3881
  DocumentStatus as D,
3137
3882
  DEFAULT_SETTINGS as E,
@@ -3145,31 +3890,31 @@ export {
3145
3890
  RelativeTime as R,
3146
3891
  SINGLE_TYPES as S,
3147
3892
  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,
3893
+ useGetInitialDataQuery as a,
3894
+ useGetAllContentTypeSettingsQuery as b,
3895
+ useDoc as c,
3896
+ buildValidParams as d,
3897
+ contentManagerApi as e,
3898
+ useDocumentRBAC as f,
3154
3899
  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,
3900
+ useDocumentLayout as h,
3901
+ createYupSchema as i,
3902
+ Header as j,
3903
+ PERMISSIONS as k,
3904
+ DocumentRBAC as l,
3905
+ DOCUMENT_META_FIELDS as m,
3906
+ useDocLayout as n,
3162
3907
  useGetContentTypeConfigurationQuery as o,
3163
3908
  CREATOR_FIELDS as p,
3164
3909
  getMainField as q,
3165
- routes as r,
3910
+ getDisplayName as r,
3166
3911
  setInitialData as s,
3167
- getDisplayName as t,
3168
- useGetInitialDataQuery as u,
3169
- checkIfAttributeIsDisplayable as v,
3170
- useGetAllDocumentsQuery as w,
3171
- convertListLayoutToFieldLayouts as x,
3172
- capitalise as y,
3173
- useUpdateContentTypeConfigurationMutation as z
3174
- };
3175
- //# sourceMappingURL=index-CwRRo1V9.mjs.map
3912
+ checkIfAttributeIsDisplayable as t,
3913
+ useContentTypeSchema as u,
3914
+ useGetAllDocumentsQuery as v,
3915
+ convertListLayoutToFieldLayouts as w,
3916
+ capitalise as x,
3917
+ useUpdateContentTypeConfigurationMutation as y,
3918
+ extractContentTypeComponents as z
3919
+ };
3920
+ //# sourceMappingURL=index-DrNe6ctw.mjs.map