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

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 (182) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs → ComponentConfigurationPage-B1bIXVuX.mjs} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-B1bIXVuX.mjs.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-Bqgx7Mes.js} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-Bqgx7Mes.js.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  11. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-BFEwvdMW.js} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-BFEwvdMW.js.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-ZO0vOO8q.mjs} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-ZO0vOO8q.mjs.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-DA95Ha6J.js} +46 -48
  19. package/dist/_chunks/EditViewPage-DA95Ha6J.js.map +1 -0
  20. package/dist/_chunks/{EditViewPage-Bm8lgcm6.mjs → EditViewPage-DlLEyUL6.mjs} +47 -47
  21. package/dist/_chunks/EditViewPage-DlLEyUL6.mjs.map +1 -0
  22. package/dist/_chunks/{Field-Caef4JjM.js → Field-CnK8dO8N.js} +948 -777
  23. package/dist/_chunks/Field-CnK8dO8N.js.map +1 -0
  24. package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-Dq7bDnuh.mjs} +896 -724
  25. package/dist/_chunks/Field-Dq7bDnuh.mjs.map +1 -0
  26. package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-B_JE0dbz.mjs} +43 -41
  27. package/dist/_chunks/Form-B_JE0dbz.mjs.map +1 -0
  28. package/dist/_chunks/{Form-BzuAjtRq.js → Form-BpiR4piS.js} +42 -41
  29. package/dist/_chunks/Form-BpiR4piS.js.map +1 -0
  30. package/dist/_chunks/{History-D6sbCJvo.mjs → History-CBNGU7a-.mjs} +149 -65
  31. package/dist/_chunks/History-CBNGU7a-.mjs.map +1 -0
  32. package/dist/_chunks/{History-C17LiyRg.js → History-DdIstl8b.js} +149 -66
  33. package/dist/_chunks/History-DdIstl8b.js.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-5dr4qpue.mjs} +58 -58
  35. package/dist/_chunks/ListConfigurationPage-5dr4qpue.mjs.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-DkKRparB.js} +61 -62
  37. package/dist/_chunks/ListConfigurationPage-DkKRparB.js.map +1 -0
  38. package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-DecLrYV6.mjs} +90 -106
  39. package/dist/_chunks/ListViewPage-DecLrYV6.mjs.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-wE0lXqoD.js} +95 -111
  41. package/dist/_chunks/ListViewPage-wE0lXqoD.js.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-CiIcfYsd.mjs} +7 -7
  43. package/dist/_chunks/NoContentTypePage-CiIcfYsd.mjs.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-DEKR6tf9.js} +5 -5
  45. package/dist/_chunks/NoContentTypePage-DEKR6tf9.js.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-CM5UD8ee.mjs} +5 -6
  47. package/dist/_chunks/NoPermissionsPage-CM5UD8ee.mjs.map +1 -0
  48. package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-DmNfF2Bb.js} +4 -5
  49. package/dist/_chunks/NoPermissionsPage-DmNfF2Bb.js.map +1 -0
  50. package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-Dqz0C1fz.mjs} +66 -56
  51. package/dist/_chunks/Relations-Dqz0C1fz.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-L0xYRoSQ.js} +70 -61
  53. package/dist/_chunks/Relations-L0xYRoSQ.js.map +1 -0
  54. package/dist/_chunks/{en-MBPul9Su.mjs → en-BrCTWlZv.mjs} +11 -4
  55. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
  56. package/dist/_chunks/{en-C-V1_90f.js → en-uOUIxfcQ.js} +11 -4
  57. package/dist/_chunks/{en-C-V1_90f.js.map → en-uOUIxfcQ.js.map} +1 -1
  58. package/dist/_chunks/{index-DNVx8ssZ.mjs → index-BSn97i8U.mjs} +1644 -911
  59. package/dist/_chunks/index-BSn97i8U.mjs.map +1 -0
  60. package/dist/_chunks/{index-X_2tafck.js → index-DyvUPg1a.js} +1622 -890
  61. package/dist/_chunks/index-DyvUPg1a.js.map +1 -0
  62. package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-DPaHUusj.mjs} +32 -27
  63. package/dist/_chunks/layout-DPaHUusj.mjs.map +1 -0
  64. package/dist/_chunks/{layout-dBc7wN7L.js → layout-TPqF2oJ5.js} +32 -29
  65. package/dist/_chunks/layout-TPqF2oJ5.js.map +1 -0
  66. package/dist/_chunks/{relations-4pHtBrHJ.js → relations-BWYS9gkn.js} +2 -2
  67. package/dist/_chunks/{relations-4pHtBrHJ.js.map → relations-BWYS9gkn.js.map} +1 -1
  68. package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-Ck7-ecDT.mjs} +2 -2
  69. package/dist/_chunks/{relations-Dx7tMKJN.mjs.map → relations-Ck7-ecDT.mjs.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 +547 -416
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/index.mjs +555 -424
  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/utils/metadata.d.ts +8 -0
  122. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  123. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  124. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  125. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  126. package/dist/server/src/history/services/history.d.ts +2 -4
  127. package/dist/server/src/history/services/history.d.ts.map +1 -1
  128. package/dist/server/src/history/services/index.d.ts +6 -2
  129. package/dist/server/src/history/services/index.d.ts.map +1 -1
  130. package/dist/server/src/history/services/lifecycles.d.ts +9 -0
  131. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
  132. package/dist/server/src/history/services/utils.d.ts +41 -9
  133. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  134. package/dist/server/src/history/utils.d.ts +6 -2
  135. package/dist/server/src/history/utils.d.ts.map +1 -1
  136. package/dist/server/src/index.d.ts +18 -39
  137. package/dist/server/src/index.d.ts.map +1 -1
  138. package/dist/server/src/services/document-manager.d.ts +13 -12
  139. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  140. package/dist/server/src/services/document-metadata.d.ts +8 -29
  141. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  142. package/dist/server/src/services/index.d.ts +18 -39
  143. package/dist/server/src/services/index.d.ts.map +1 -1
  144. package/dist/server/src/services/utils/populate.d.ts +8 -1
  145. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  146. package/dist/shared/contracts/collection-types.d.ts +14 -6
  147. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  148. package/dist/shared/contracts/relations.d.ts +2 -2
  149. package/dist/shared/contracts/relations.d.ts.map +1 -1
  150. package/package.json +13 -14
  151. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  152. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  153. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  154. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  155. package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs.map +0 -1
  156. package/dist/_chunks/EditViewPage-CzOT5Kpj.js.map +0 -1
  157. package/dist/_chunks/Field-Caef4JjM.js.map +0 -1
  158. package/dist/_chunks/Field-Dlh0uGnL.mjs.map +0 -1
  159. package/dist/_chunks/Form-BzuAjtRq.js.map +0 -1
  160. package/dist/_chunks/Form-EnaQL_6L.mjs.map +0 -1
  161. package/dist/_chunks/History-C17LiyRg.js.map +0 -1
  162. package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
  163. package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
  164. package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
  165. package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
  166. package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
  167. package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
  168. package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
  169. package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
  170. package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
  171. package/dist/_chunks/Relations-CY7AtkDA.mjs.map +0 -1
  172. package/dist/_chunks/Relations-Czs-uZ-s.js.map +0 -1
  173. package/dist/_chunks/index-DNVx8ssZ.mjs.map +0 -1
  174. package/dist/_chunks/index-X_2tafck.js.map +0 -1
  175. package/dist/_chunks/layout-Dnh0PNp9.mjs.map +0 -1
  176. package/dist/_chunks/layout-dBc7wN7L.js.map +0 -1
  177. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  178. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  179. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  180. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  181. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  182. 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, Box, Typography, Dialog, Modal, Radio, Status, 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 }) => ({
@@ -325,12 +216,15 @@ const documentApi = contentManagerApi.injectEndpoints({
325
216
  ]
326
217
  }),
327
218
  deleteManyDocuments: builder.mutation({
328
- query: ({ model, ...body }) => ({
219
+ query: ({ model, params, ...body }) => ({
329
220
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
330
221
  method: "POST",
331
- data: body
222
+ data: body,
223
+ config: {
224
+ params
225
+ }
332
226
  }),
333
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
227
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
334
228
  }),
335
229
  discardDocument: builder.mutation({
336
230
  query: ({ collectionType, model, documentId, params }) => ({
@@ -441,10 +335,13 @@ const documentApi = contentManagerApi.injectEndpoints({
441
335
  }
442
336
  }),
443
337
  publishManyDocuments: builder.mutation({
444
- query: ({ model, ...body }) => ({
338
+ query: ({ model, params, ...body }) => ({
445
339
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
446
340
  method: "POST",
447
- data: body
341
+ data: body,
342
+ config: {
343
+ params
344
+ }
448
345
  }),
449
346
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
450
347
  }),
@@ -486,10 +383,13 @@ const documentApi = contentManagerApi.injectEndpoints({
486
383
  }
487
384
  }),
488
385
  unpublishManyDocuments: builder.mutation({
489
- query: ({ model, ...body }) => ({
386
+ query: ({ model, params, ...body }) => ({
490
387
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
491
388
  method: "POST",
492
- data: body
389
+ data: body,
390
+ config: {
391
+ params
392
+ }
493
393
  }),
494
394
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
495
395
  })
@@ -513,6 +413,24 @@ const {
513
413
  useUnpublishDocumentMutation,
514
414
  useUnpublishManyDocumentsMutation
515
415
  } = documentApi;
416
+ const buildValidParams = (query) => {
417
+ if (!query)
418
+ return query;
419
+ const { plugins: _, ...validQueryParams } = {
420
+ ...query,
421
+ ...Object.values(query?.plugins ?? {}).reduce(
422
+ (acc, current) => Object.assign(acc, current),
423
+ {}
424
+ )
425
+ };
426
+ if ("_q" in validQueryParams) {
427
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
428
+ }
429
+ return validQueryParams;
430
+ };
431
+ const isBaseQueryError = (error) => {
432
+ return error.name !== void 0;
433
+ };
516
434
  const createYupSchema = (attributes = {}, components = {}) => {
517
435
  const createModelSchema = (attributes2) => yup.object().shape(
518
436
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -552,10 +470,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
552
470
  yup.array().of(
553
471
  yup.lazy(
554
472
  (data) => {
555
- const { attributes: attributes3 } = components[data.__component];
556
- return yup.object().shape({
473
+ const attributes3 = components?.[data?.__component]?.attributes;
474
+ const validation = yup.object().shape({
557
475
  __component: yup.string().required().oneOf(Object.keys(components))
558
- }).nullable(false).concat(createModelSchema(attributes3));
476
+ }).nullable(false);
477
+ if (!attributes3) {
478
+ return validation;
479
+ }
480
+ return validation.concat(createModelSchema(attributes3));
559
481
  }
560
482
  )
561
483
  )
@@ -565,11 +487,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
487
  return {
566
488
  ...acc,
567
489
  [name]: transformSchema(
568
- yup.array().of(
569
- yup.object().shape({
570
- id: yup.string().required()
571
- })
572
- )
490
+ yup.lazy((value) => {
491
+ if (!value) {
492
+ return yup.mixed().nullable(true);
493
+ } else if (Array.isArray(value)) {
494
+ return yup.array().of(
495
+ yup.object().shape({
496
+ id: yup.string().required()
497
+ })
498
+ );
499
+ } else if (typeof value === "object") {
500
+ return yup.object();
501
+ } else {
502
+ return yup.mixed().test(
503
+ "type-error",
504
+ "Relation values must be either null, an array of objects with {id} or an object.",
505
+ () => false
506
+ );
507
+ }
508
+ })
573
509
  )
574
510
  };
575
511
  default:
@@ -628,13 +564,18 @@ const createAttributeSchema = (attribute) => {
628
564
  }
629
565
  };
630
566
  const addRequiredValidation = (attribute) => (schema) => {
631
- if (attribute.required) {
632
- return schema.required({
633
- id: translatedErrors.required.id,
634
- defaultMessage: "This field is required."
635
- });
567
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
568
+ return schema.min(1, translatedErrors.required);
636
569
  }
637
- return schema.nullable();
570
+ if (attribute.required && attribute.type !== "relation") {
571
+ return schema.required(translatedErrors.required);
572
+ }
573
+ return schema?.nullable ? schema.nullable() : (
574
+ // In some cases '.nullable' will not be available on the schema.
575
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
576
+ // In these cases we should just return the schema as it is.
577
+ schema
578
+ );
638
579
  };
639
580
  const addMinLengthValidation = (attribute) => (schema) => {
640
581
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -661,6 +602,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
661
602
  const addMinValidation = (attribute) => (schema) => {
662
603
  if ("min" in attribute) {
663
604
  const min = toInteger(attribute.min);
605
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
606
+ if (!attribute.required && "test" in schema && min) {
607
+ return schema.test(
608
+ "custom-min",
609
+ {
610
+ ...translatedErrors.min,
611
+ values: {
612
+ min: attribute.min
613
+ }
614
+ },
615
+ (value) => {
616
+ if (!value) {
617
+ return true;
618
+ }
619
+ if (Array.isArray(value) && value.length === 0) {
620
+ return true;
621
+ }
622
+ return value.length >= min;
623
+ }
624
+ );
625
+ }
626
+ }
664
627
  if ("min" in schema && min) {
665
628
  return schema.min(min, {
666
629
  ...translatedErrors.min,
@@ -706,24 +669,6 @@ const addRegexValidation = (attribute) => (schema) => {
706
669
  }
707
670
  return schema;
708
671
  };
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
672
  const initApi = contentManagerApi.injectEndpoints({
728
673
  endpoints: (builder) => ({
729
674
  getInitialData: builder.query({
@@ -737,27 +682,20 @@ const { useGetInitialDataQuery } = initApi;
737
682
  const useContentTypeSchema = (model) => {
738
683
  const { toggleNotification } = useNotification();
739
684
  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
- });
685
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
686
+ const { components, contentType, contentTypes } = React.useMemo(() => {
687
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
688
+ const componentsByKey = data?.components.reduce((acc, component) => {
689
+ acc[component.uid] = component;
690
+ return acc;
691
+ }, {});
692
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
693
+ return {
694
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
695
+ contentType: contentType2,
696
+ contentTypes: data?.contentTypes ?? []
697
+ };
698
+ }, [model, data]);
761
699
  React.useEffect(() => {
762
700
  if (error) {
763
701
  toggleNotification({
@@ -812,7 +750,10 @@ const useDocument = (args, opts) => {
812
750
  isLoading: isLoadingDocument,
813
751
  isFetching: isFetchingDocument,
814
752
  error
815
- } = useGetDocumentQuery(args, opts);
753
+ } = useGetDocumentQuery(args, {
754
+ ...opts,
755
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
756
+ });
816
757
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
817
758
  React.useEffect(() => {
818
759
  if (error) {
@@ -840,7 +781,7 @@ const useDocument = (args, opts) => {
840
781
  return null;
841
782
  } catch (error2) {
842
783
  if (error2 instanceof ValidationError) {
843
- return getInnerErrors(error2);
784
+ return getYupValidationErrors(error2);
844
785
  }
845
786
  throw error2;
846
787
  }
@@ -936,14 +877,53 @@ const useDocumentActions = () => {
936
877
  },
937
878
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
938
879
  );
880
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
881
+ const deleteMany = React.useCallback(
882
+ async ({ model, documentIds, params }) => {
883
+ try {
884
+ trackUsage("willBulkDeleteEntries");
885
+ const res = await deleteManyDocuments({
886
+ model,
887
+ documentIds,
888
+ params
889
+ });
890
+ if ("error" in res) {
891
+ toggleNotification({
892
+ type: "danger",
893
+ message: formatAPIError(res.error)
894
+ });
895
+ return { error: res.error };
896
+ }
897
+ toggleNotification({
898
+ type: "success",
899
+ title: formatMessage({
900
+ id: getTranslation("success.records.delete"),
901
+ defaultMessage: "Successfully deleted."
902
+ }),
903
+ message: ""
904
+ });
905
+ trackUsage("didBulkDeleteEntries");
906
+ return res.data;
907
+ } catch (err) {
908
+ toggleNotification({
909
+ type: "danger",
910
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
911
+ });
912
+ trackUsage("didNotBulkDeleteEntries");
913
+ throw err;
914
+ }
915
+ },
916
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
917
+ );
939
918
  const [discardDocument] = useDiscardDocumentMutation();
940
919
  const discard = React.useCallback(
941
- async ({ collectionType, model, documentId }) => {
920
+ async ({ collectionType, model, documentId, params }) => {
942
921
  try {
943
922
  const res = await discardDocument({
944
923
  collectionType,
945
924
  model,
946
- documentId
925
+ documentId,
926
+ params
947
927
  });
948
928
  if ("error" in res) {
949
929
  toggleNotification({
@@ -1005,6 +985,43 @@ const useDocumentActions = () => {
1005
985
  },
1006
986
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1007
987
  );
988
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
989
+ const publishMany = React.useCallback(
990
+ async ({ model, documentIds, params }) => {
991
+ try {
992
+ const res = await publishManyDocuments({
993
+ model,
994
+ documentIds,
995
+ params
996
+ });
997
+ if ("error" in res) {
998
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
999
+ return { error: res.error };
1000
+ }
1001
+ toggleNotification({
1002
+ type: "success",
1003
+ message: formatMessage({
1004
+ id: getTranslation("success.record.publish"),
1005
+ defaultMessage: "Published document"
1006
+ })
1007
+ });
1008
+ return res.data;
1009
+ } catch (err) {
1010
+ toggleNotification({
1011
+ type: "danger",
1012
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1013
+ });
1014
+ throw err;
1015
+ }
1016
+ },
1017
+ [
1018
+ // trackUsage,
1019
+ publishManyDocuments,
1020
+ toggleNotification,
1021
+ formatMessage,
1022
+ formatAPIError
1023
+ ]
1024
+ );
1008
1025
  const [updateDocument] = useUpdateDocumentMutation();
1009
1026
  const update = React.useCallback(
1010
1027
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1079,6 +1096,41 @@ const useDocumentActions = () => {
1079
1096
  },
1080
1097
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1081
1098
  );
1099
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1100
+ const unpublishMany = React.useCallback(
1101
+ async ({ model, documentIds, params }) => {
1102
+ try {
1103
+ trackUsage("willBulkUnpublishEntries");
1104
+ const res = await unpublishManyDocuments({
1105
+ model,
1106
+ documentIds,
1107
+ params
1108
+ });
1109
+ if ("error" in res) {
1110
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1111
+ return { error: res.error };
1112
+ }
1113
+ trackUsage("didBulkUnpublishEntries");
1114
+ toggleNotification({
1115
+ type: "success",
1116
+ title: formatMessage({
1117
+ id: getTranslation("success.records.unpublish"),
1118
+ defaultMessage: "Successfully unpublished."
1119
+ }),
1120
+ message: ""
1121
+ });
1122
+ return res.data;
1123
+ } catch (err) {
1124
+ toggleNotification({
1125
+ type: "danger",
1126
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1127
+ });
1128
+ trackUsage("didNotBulkUnpublishEntries");
1129
+ throw err;
1130
+ }
1131
+ },
1132
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1133
+ );
1082
1134
  const [createDocument] = useCreateDocumentMutation();
1083
1135
  const create = React.useCallback(
1084
1136
  async ({ model, params }, data, trackerProperty) => {
@@ -1192,15 +1244,18 @@ const useDocumentActions = () => {
1192
1244
  clone,
1193
1245
  create,
1194
1246
  delete: _delete,
1247
+ deleteMany,
1195
1248
  discard,
1196
1249
  getDocument,
1197
1250
  publish,
1251
+ publishMany,
1198
1252
  unpublish,
1253
+ unpublishMany,
1199
1254
  update
1200
1255
  };
1201
1256
  };
1202
1257
  const ProtectedHistoryPage = lazy(
1203
- () => import("./History-D6sbCJvo.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1258
+ () => import("./History-CBNGU7a-.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1204
1259
  );
1205
1260
  const routes$1 = [
1206
1261
  {
@@ -1213,31 +1268,31 @@ const routes$1 = [
1213
1268
  }
1214
1269
  ];
1215
1270
  const ProtectedEditViewPage = lazy(
1216
- () => import("./EditViewPage-Bm8lgcm6.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1271
+ () => import("./EditViewPage-DlLEyUL6.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1217
1272
  );
1218
1273
  const ProtectedListViewPage = lazy(
1219
- () => import("./ListViewPage-Be7S5aKL.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1274
+ () => import("./ListViewPage-DecLrYV6.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1220
1275
  );
1221
1276
  const ProtectedListConfiguration = lazy(
1222
- () => import("./ListConfigurationPage-Ce4qs7qE.mjs").then((mod) => ({
1277
+ () => import("./ListConfigurationPage-5dr4qpue.mjs").then((mod) => ({
1223
1278
  default: mod.ProtectedListConfiguration
1224
1279
  }))
1225
1280
  );
1226
1281
  const ProtectedEditConfigurationPage = lazy(
1227
- () => import("./EditConfigurationPage-CUcGHHvQ.mjs").then((mod) => ({
1282
+ () => import("./EditConfigurationPage-ZO0vOO8q.mjs").then((mod) => ({
1228
1283
  default: mod.ProtectedEditConfigurationPage
1229
1284
  }))
1230
1285
  );
1231
1286
  const ProtectedComponentConfigurationPage = lazy(
1232
- () => import("./ComponentConfigurationPage--2aLCv-G.mjs").then((mod) => ({
1287
+ () => import("./ComponentConfigurationPage-B1bIXVuX.mjs").then((mod) => ({
1233
1288
  default: mod.ProtectedComponentConfigurationPage
1234
1289
  }))
1235
1290
  );
1236
1291
  const NoPermissions = lazy(
1237
- () => import("./NoPermissionsPage-DhJ7LYrr.mjs").then((mod) => ({ default: mod.NoPermissions }))
1292
+ () => import("./NoPermissionsPage-CM5UD8ee.mjs").then((mod) => ({ default: mod.NoPermissions }))
1238
1293
  );
1239
1294
  const NoContentType = lazy(
1240
- () => import("./NoContentTypePage-CIPmYQMm.mjs").then((mod) => ({ default: mod.NoContentType }))
1295
+ () => import("./NoContentTypePage-CiIcfYsd.mjs").then((mod) => ({ default: mod.NoContentType }))
1241
1296
  );
1242
1297
  const CollectionTypePages = () => {
1243
1298
  const { collectionType } = useParams();
@@ -1364,7 +1419,7 @@ const DocumentActionButton = (action) => {
1364
1419
  DocumentActionConfirmDialog,
1365
1420
  {
1366
1421
  ...action.dialog,
1367
- variant: action.variant,
1422
+ variant: action.dialog?.variant ?? action.variant,
1368
1423
  isOpen: dialogId === action.id,
1369
1424
  onClose: handleClose
1370
1425
  }
@@ -1427,7 +1482,7 @@ const DocumentActionsMenu = ({
1427
1482
  variant,
1428
1483
  children: [
1429
1484
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
1430
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: label || formatMessage({
1485
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
1431
1486
  id: "content-manager.containers.edit.panels.default.more-actions",
1432
1487
  defaultMessage: "More document actions"
1433
1488
  }) })
@@ -1443,8 +1498,8 @@ const DocumentActionsMenu = ({
1443
1498
  onSelect: handleClick(action),
1444
1499
  display: "block",
1445
1500
  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,
1501
+ /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1502
+ /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1448
1503
  action.label
1449
1504
  ] }),
1450
1505
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
@@ -1505,6 +1560,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1505
1560
  return "primary600";
1506
1561
  }
1507
1562
  };
1563
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1564
+ switch (variant) {
1565
+ case "danger":
1566
+ return "danger600";
1567
+ case "secondary":
1568
+ return "neutral500";
1569
+ case "success":
1570
+ return "success600";
1571
+ default:
1572
+ return "primary600";
1573
+ }
1574
+ };
1508
1575
  const DocumentActionConfirmDialog = ({
1509
1576
  onClose,
1510
1577
  onCancel,
@@ -1527,61 +1594,42 @@ const DocumentActionConfirmDialog = ({
1527
1594
  }
1528
1595
  onClose();
1529
1596
  };
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
- ] });
1597
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1598
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1599
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1600
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1601
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1602
+ id: "app.components.Button.cancel",
1603
+ defaultMessage: "Cancel"
1604
+ }) }) }),
1605
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1606
+ id: "app.components.Button.confirm",
1607
+ defaultMessage: "Confirm"
1608
+ }) })
1609
+ ] })
1610
+ ] }) });
1546
1611
  };
1547
1612
  const DocumentActionModal = ({
1548
1613
  isOpen,
1549
1614
  title,
1550
1615
  onClose,
1551
1616
  footer: Footer,
1552
- content,
1617
+ content: Content,
1553
1618
  onModalClose
1554
1619
  }) => {
1555
- const id = React.useId();
1556
- if (!isOpen) {
1557
- return null;
1558
- }
1559
1620
  const handleClose = () => {
1560
1621
  if (onClose) {
1561
1622
  onClose();
1562
1623
  }
1563
1624
  onModalClose();
1564
1625
  };
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
- ] });
1626
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1627
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1628
+ /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1629
+ /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1630
+ ] }) });
1583
1631
  };
1584
- const PublishAction = ({
1632
+ const PublishAction$1 = ({
1585
1633
  activeTab,
1586
1634
  documentId,
1587
1635
  model,
@@ -1600,6 +1648,12 @@ const PublishAction = ({
1600
1648
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1601
1649
  );
1602
1650
  const { publish } = useDocumentActions();
1651
+ const [
1652
+ countDraftRelations,
1653
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1654
+ ] = useLazyGetDraftRelationCountQuery();
1655
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
1656
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
1603
1657
  const [{ query, rawQuery }] = useQueryParams();
1604
1658
  const params = React.useMemo(() => buildValidParams(query), [query]);
1605
1659
  const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1608,65 +1662,148 @@ const PublishAction = ({
1608
1662
  const validate = useForm("PublishAction", (state) => state.validate);
1609
1663
  const setErrors = useForm("PublishAction", (state) => state.setErrors);
1610
1664
  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({
1629
- id: "app.utils.publish",
1665
+ React.useEffect(() => {
1666
+ if (isErrorDraftRelations) {
1667
+ toggleNotification({
1668
+ type: "danger",
1669
+ message: formatMessage({
1670
+ id: getTranslation("error.records.fetch-draft-relatons"),
1671
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1672
+ })
1673
+ });
1674
+ }
1675
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1676
+ React.useEffect(() => {
1677
+ const localDraftRelations = /* @__PURE__ */ new Set();
1678
+ const extractDraftRelations = (data) => {
1679
+ const relations = data.connect || [];
1680
+ relations.forEach((relation) => {
1681
+ if (relation.status === "draft") {
1682
+ localDraftRelations.add(relation.id);
1683
+ }
1684
+ });
1685
+ };
1686
+ const traverseAndExtract = (data) => {
1687
+ Object.entries(data).forEach(([key, value]) => {
1688
+ if (key === "connect" && Array.isArray(value)) {
1689
+ extractDraftRelations({ connect: value });
1690
+ } else if (typeof value === "object" && value !== null) {
1691
+ traverseAndExtract(value);
1692
+ }
1693
+ });
1694
+ };
1695
+ if (!documentId || modified) {
1696
+ traverseAndExtract(formValues);
1697
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1698
+ }
1699
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1700
+ React.useEffect(() => {
1701
+ if (documentId) {
1702
+ const fetchDraftRelationsCount = async () => {
1703
+ const { data, error } = await countDraftRelations({
1704
+ collectionType,
1705
+ model,
1706
+ documentId,
1707
+ params
1708
+ });
1709
+ if (error) {
1710
+ throw error;
1711
+ }
1712
+ if (data) {
1713
+ setServerCountOfDraftRelations(data.data);
1714
+ }
1715
+ };
1716
+ fetchDraftRelationsCount();
1717
+ }
1718
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1719
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1720
+ if (!schema?.options?.draftAndPublish) {
1721
+ return null;
1722
+ }
1723
+ const performPublish = async () => {
1724
+ setSubmitting(true);
1725
+ try {
1726
+ const { errors } = await validate();
1727
+ if (errors) {
1728
+ toggleNotification({
1729
+ type: "danger",
1730
+ message: formatMessage({
1731
+ id: "content-manager.validation.error",
1732
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1733
+ })
1734
+ });
1735
+ return;
1736
+ }
1737
+ const res = await publish(
1738
+ {
1739
+ collectionType,
1740
+ model,
1741
+ documentId,
1742
+ params
1743
+ },
1744
+ formValues
1745
+ );
1746
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1747
+ navigate({
1748
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1749
+ search: rawQuery
1750
+ });
1751
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1752
+ setErrors(formatValidationErrors(res.error));
1753
+ }
1754
+ } finally {
1755
+ setSubmitting(false);
1756
+ }
1757
+ };
1758
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1759
+ const hasDraftRelations = totalDraftRelations > 0;
1760
+ return {
1761
+ /**
1762
+ * Disabled when:
1763
+ * - currently if you're cloning a document we don't support publish & clone at the same time.
1764
+ * - the form is submitting
1765
+ * - the active tab is the published tab
1766
+ * - the document is already published & not modified
1767
+ * - the document is being created & not modified
1768
+ * - the user doesn't have the permission to publish
1769
+ * - the user doesn't have the permission to create a new document
1770
+ * - the user doesn't have the permission to update the document
1771
+ */
1772
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1773
+ label: formatMessage({
1774
+ id: "app.utils.publish",
1630
1775
  defaultMessage: "Publish"
1631
1776
  }),
1632
1777
  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));
1778
+ if (hasDraftRelations) {
1779
+ return;
1780
+ }
1781
+ await performPublish();
1782
+ },
1783
+ dialog: hasDraftRelations ? {
1784
+ type: "dialog",
1785
+ variant: "danger",
1786
+ footer: null,
1787
+ title: formatMessage({
1788
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1789
+ defaultMessage: "Confirmation"
1790
+ }),
1791
+ content: formatMessage(
1792
+ {
1793
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1794
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1795
+ },
1796
+ {
1797
+ count: totalDraftRelations
1662
1798
  }
1663
- } finally {
1664
- setSubmitting(false);
1799
+ ),
1800
+ onConfirm: async () => {
1801
+ await performPublish();
1665
1802
  }
1666
- }
1803
+ } : void 0
1667
1804
  };
1668
1805
  };
1669
- PublishAction.type = "publish";
1806
+ PublishAction$1.type = "publish";
1670
1807
  const UpdateAction = ({
1671
1808
  activeTab,
1672
1809
  documentId,
@@ -1762,10 +1899,13 @@ const UpdateAction = ({
1762
1899
  document
1763
1900
  );
1764
1901
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1765
- navigate({
1766
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1767
- search: rawQuery
1768
- });
1902
+ navigate(
1903
+ {
1904
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1905
+ search: rawQuery
1906
+ },
1907
+ { replace: true }
1908
+ );
1769
1909
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1770
1910
  setErrors(formatValidationErrors(res.error));
1771
1911
  }
@@ -1781,7 +1921,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1781
1921
  KEEP: "keep",
1782
1922
  DISCARD: "discard"
1783
1923
  };
1784
- const UnpublishAction = ({
1924
+ const UnpublishAction$1 = ({
1785
1925
  activeTab,
1786
1926
  documentId,
1787
1927
  model,
@@ -1797,10 +1937,8 @@ const UnpublishAction = ({
1797
1937
  const { toggleNotification } = useNotification();
1798
1938
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1799
1939
  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
- }
1940
+ const handleChange = (value) => {
1941
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1804
1942
  };
1805
1943
  if (!schema?.options?.draftAndPublish) {
1806
1944
  return null;
@@ -1844,45 +1982,30 @@ const UnpublishAction = ({
1844
1982
  content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1845
1983
  /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
1846
1984
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1847
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
1985
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1848
1986
  id: "content-manager.actions.unpublish.dialog.body",
1849
1987
  defaultMessage: "Are you sure?"
1850
1988
  }) })
1851
1989
  ] }),
1852
1990
  /* @__PURE__ */ jsxs(
1853
- Flex,
1991
+ Radio.Group,
1854
1992
  {
1855
- onChange: handleChange,
1856
- direction: "column",
1857
- alignItems: "flex-start",
1858
- as: "fieldset",
1859
- gap: 3,
1993
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1994
+ name: "discard-options",
1995
+ "aria-label": formatMessage({
1996
+ id: "content-manager.actions.unpublish.dialog.radio-label",
1997
+ defaultMessage: "Choose an option to unpublish the document."
1998
+ }),
1999
+ onValueChange: handleChange,
1860
2000
  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
- )
2001
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2002
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2003
+ defaultMessage: "Keep draft"
2004
+ }) }),
2005
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2006
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2007
+ defaultMessage: "Replace draft"
2008
+ }) })
1886
2009
  ]
1887
2010
  }
1888
2011
  )
@@ -1915,7 +2038,7 @@ const UnpublishAction = ({
1915
2038
  position: ["panel", "table-row"]
1916
2039
  };
1917
2040
  };
1918
- UnpublishAction.type = "unpublish";
2041
+ UnpublishAction$1.type = "unpublish";
1919
2042
  const DiscardAction = ({
1920
2043
  activeTab,
1921
2044
  documentId,
@@ -1949,7 +2072,7 @@ const DiscardAction = ({
1949
2072
  }),
1950
2073
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
1951
2074
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1952
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2075
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1953
2076
  id: "content-manager.actions.discard.dialog.body",
1954
2077
  defaultMessage: "Are you sure?"
1955
2078
  }) })
@@ -1971,7 +2094,7 @@ const StyledCrossCircle = styled(CrossCircle)`
1971
2094
  fill: currentColor;
1972
2095
  }
1973
2096
  `;
1974
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2097
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1975
2098
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1976
2099
  const RelativeTime = React.forwardRef(
1977
2100
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2019,7 +2142,7 @@ const getDisplayName = ({
2019
2142
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2020
2143
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2021
2144
  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) }) });
2145
+ 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
2146
  };
2024
2147
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2025
2148
  const { formatMessage } = useIntl();
@@ -2028,23 +2151,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2028
2151
  id: "content-manager.containers.edit.title.new",
2029
2152
  defaultMessage: "Create an entry"
2030
2153
  }) : documentTitle;
2031
- return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2154
+ return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2032
2155
  /* @__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
2156
+ /* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2157
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2158
+ /* @__PURE__ */ jsx(HeaderToolbar, {})
2159
+ ] }),
2160
+ status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2048
2161
  ] });
2049
2162
  };
2050
2163
  const HeaderToolbar = () => {
@@ -2196,7 +2309,7 @@ const Information = ({ activeTab }) => {
2196
2309
  borderColor: "neutral150",
2197
2310
  direction: "column",
2198
2311
  marginTop: 2,
2199
- as: "dl",
2312
+ tag: "dl",
2200
2313
  padding: 5,
2201
2314
  gap: 3,
2202
2315
  alignItems: "flex-start",
@@ -2204,8 +2317,8 @@ const Information = ({ activeTab }) => {
2204
2317
  marginRight: "-0.4rem",
2205
2318
  width: "calc(100% + 8px)",
2206
2319
  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 })
2320
+ /* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2321
+ /* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2209
2322
  ] }, info.label))
2210
2323
  }
2211
2324
  );
@@ -2238,7 +2351,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2238
2351
  id: "app.links.configure-view",
2239
2352
  defaultMessage: "Configure the view"
2240
2353
  }),
2241
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2354
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2242
2355
  onClick: () => {
2243
2356
  navigate(`../${collectionType}/${model}/configurations/edit`);
2244
2357
  },
@@ -2246,11 +2359,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2246
2359
  };
2247
2360
  };
2248
2361
  ConfigureTheViewAction.type = "configure-the-view";
2249
- const StyledCog = styled(Cog)`
2250
- path {
2251
- fill: currentColor;
2252
- }
2253
- `;
2254
2362
  const EditTheModelAction = ({ model }) => {
2255
2363
  const navigate = useNavigate();
2256
2364
  const { formatMessage } = useIntl();
@@ -2259,7 +2367,7 @@ const EditTheModelAction = ({ model }) => {
2259
2367
  id: "content-manager.link-to-ctb",
2260
2368
  defaultMessage: "Edit the model"
2261
2369
  }),
2262
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2370
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2263
2371
  onClick: () => {
2264
2372
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2265
2373
  },
@@ -2267,12 +2375,7 @@ const EditTheModelAction = ({ model }) => {
2267
2375
  };
2268
2376
  };
2269
2377
  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 }) => {
2378
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2276
2379
  const navigate = useNavigate();
2277
2380
  const { formatMessage } = useIntl();
2278
2381
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2286,7 +2389,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2286
2389
  id: "content-manager.actions.delete.label",
2287
2390
  defaultMessage: "Delete document"
2288
2391
  }),
2289
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2392
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2290
2393
  dialog: {
2291
2394
  type: "dialog",
2292
2395
  title: formatMessage({
@@ -2295,7 +2398,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2295
2398
  }),
2296
2399
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2297
2400
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2298
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2401
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2299
2402
  id: "content-manager.actions.delete.dialog.body",
2300
2403
  defaultMessage: "Are you sure?"
2301
2404
  }) })
@@ -2340,13 +2443,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2340
2443
  position: ["header", "table-row"]
2341
2444
  };
2342
2445
  };
2343
- DeleteAction.type = "delete";
2344
- const StyledTrash = styled(Trash)`
2345
- path {
2346
- fill: currentColor;
2347
- }
2348
- `;
2349
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2446
+ DeleteAction$1.type = "delete";
2447
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2350
2448
  const Panels = () => {
2351
2449
  const isCloning = useMatch(CLONE_PATH) !== null;
2352
2450
  const [
@@ -2420,7 +2518,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2420
2518
  Flex,
2421
2519
  {
2422
2520
  ref,
2423
- as: "aside",
2521
+ tag: "aside",
2424
2522
  "aria-labelledby": "additional-information",
2425
2523
  background: "neutral0",
2426
2524
  borderColor: "neutral150",
@@ -2435,115 +2533,994 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2435
2533
  justifyContent: "stretch",
2436
2534
  alignItems: "flex-start",
2437
2535
  children: [
2438
- /* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2536
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2439
2537
  children
2440
2538
  ]
2441
2539
  }
2442
2540
  );
2443
2541
  });
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
- );
2542
+ const HOOKS = {
2543
+ /**
2544
+ * Hook that allows to mutate the displayed headers of the list view table
2545
+ * @constant
2546
+ * @type {string}
2547
+ */
2548
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2549
+ /**
2550
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2551
+ * @constant
2552
+ * @type {string}
2553
+ */
2554
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2555
+ /**
2556
+ * Hook that allows to mutate the CM's edit view layout
2557
+ * @constant
2558
+ * @type {string}
2559
+ */
2560
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2561
+ /**
2562
+ * Hook that allows to mutate the CM's single types links pre-set filters
2563
+ * @constant
2564
+ * @type {string}
2565
+ */
2566
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2533
2567
  };
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
- }),
2568
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2569
+ endpoints: (builder) => ({
2570
+ getContentTypeConfiguration: builder.query({
2571
+ query: (uid) => ({
2572
+ url: `/content-manager/content-types/${uid}/configuration`,
2573
+ method: "GET"
2574
+ }),
2575
+ transformResponse: (response) => response.data,
2576
+ providesTags: (_result, _error, uid) => [
2577
+ { type: "ContentTypesConfiguration", id: uid },
2578
+ { type: "ContentTypeSettings", id: "LIST" }
2579
+ ]
2580
+ }),
2581
+ getAllContentTypeSettings: builder.query({
2582
+ query: () => "/content-manager/content-types-settings",
2583
+ transformResponse: (response) => response.data,
2584
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2585
+ }),
2586
+ updateContentTypeConfiguration: builder.mutation({
2587
+ query: ({ uid, ...body }) => ({
2588
+ url: `/content-manager/content-types/${uid}/configuration`,
2589
+ method: "PUT",
2590
+ data: body
2591
+ }),
2592
+ transformResponse: (response) => response.data,
2593
+ invalidatesTags: (_result, _error, { uid }) => [
2594
+ { type: "ContentTypesConfiguration", id: uid },
2595
+ { type: "ContentTypeSettings", id: "LIST" },
2596
+ // Is this necessary?
2597
+ { type: "InitialData" }
2598
+ ]
2599
+ })
2600
+ })
2601
+ });
2602
+ const {
2603
+ useGetContentTypeConfigurationQuery,
2604
+ useGetAllContentTypeSettingsQuery,
2605
+ useUpdateContentTypeConfigurationMutation
2606
+ } = contentTypesApi;
2607
+ const checkIfAttributeIsDisplayable = (attribute) => {
2608
+ const { type } = attribute;
2609
+ if (type === "relation") {
2610
+ return !attribute.relation.toLowerCase().includes("morph");
2611
+ }
2612
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2613
+ };
2614
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2615
+ if (!mainFieldName) {
2616
+ return void 0;
2617
+ }
2618
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2619
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2620
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2621
+ );
2622
+ return {
2623
+ name: mainFieldName,
2624
+ type: mainFieldType ?? "string"
2625
+ };
2626
+ };
2627
+ const DEFAULT_SETTINGS = {
2628
+ bulkable: false,
2629
+ filterable: false,
2630
+ searchable: false,
2631
+ pagination: false,
2632
+ defaultSortBy: "",
2633
+ defaultSortOrder: "asc",
2634
+ mainField: "id",
2635
+ pageSize: 10
2636
+ };
2637
+ const useDocumentLayout = (model) => {
2638
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2639
+ const [{ query }] = useQueryParams();
2640
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2641
+ const { toggleNotification } = useNotification();
2642
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2643
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2644
+ const {
2645
+ data,
2646
+ isLoading: isLoadingConfigs,
2647
+ error,
2648
+ isFetching: isFetchingConfigs
2649
+ } = useGetContentTypeConfigurationQuery(model);
2650
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2651
+ React.useEffect(() => {
2652
+ if (error) {
2653
+ toggleNotification({
2654
+ type: "danger",
2655
+ message: formatAPIError(error)
2656
+ });
2657
+ }
2658
+ }, [error, formatAPIError, toggleNotification]);
2659
+ const editLayout = React.useMemo(
2660
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2661
+ layout: [],
2662
+ components: {},
2663
+ metadatas: {},
2664
+ options: {},
2665
+ settings: DEFAULT_SETTINGS
2666
+ },
2667
+ [data, isLoading, schemas, schema, components]
2668
+ );
2669
+ const listLayout = React.useMemo(() => {
2670
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2671
+ layout: [],
2672
+ metadatas: {},
2673
+ options: {},
2674
+ settings: DEFAULT_SETTINGS
2675
+ };
2676
+ }, [data, isLoading, schemas, schema, components]);
2677
+ const { layout: edit } = React.useMemo(
2678
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2679
+ layout: editLayout,
2680
+ query
2681
+ }),
2682
+ [editLayout, query, runHookWaterfall]
2683
+ );
2684
+ return {
2685
+ error,
2686
+ isLoading,
2687
+ edit,
2688
+ list: listLayout
2689
+ };
2690
+ };
2691
+ const useDocLayout = () => {
2692
+ const { model } = useDoc();
2693
+ return useDocumentLayout(model);
2694
+ };
2695
+ const formatEditLayout = (data, {
2696
+ schemas,
2697
+ schema,
2698
+ components
2699
+ }) => {
2700
+ let currentPanelIndex = 0;
2701
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2702
+ data.contentType.layouts.edit,
2703
+ schema?.attributes,
2704
+ data.contentType.metadatas,
2705
+ { configurations: data.components, schemas: components },
2706
+ schemas
2707
+ ).reduce((panels, row) => {
2708
+ if (row.some((field) => field.type === "dynamiczone")) {
2709
+ panels.push([row]);
2710
+ currentPanelIndex += 2;
2711
+ } else {
2712
+ if (!panels[currentPanelIndex]) {
2713
+ panels.push([]);
2714
+ }
2715
+ panels[currentPanelIndex].push(row);
2716
+ }
2717
+ return panels;
2718
+ }, []);
2719
+ const componentEditAttributes = Object.entries(data.components).reduce(
2720
+ (acc, [uid, configuration]) => {
2721
+ acc[uid] = {
2722
+ layout: convertEditLayoutToFieldLayouts(
2723
+ configuration.layouts.edit,
2724
+ components[uid].attributes,
2725
+ configuration.metadatas
2726
+ ),
2727
+ settings: {
2728
+ ...configuration.settings,
2729
+ icon: components[uid].info.icon,
2730
+ displayName: components[uid].info.displayName
2731
+ }
2732
+ };
2733
+ return acc;
2734
+ },
2735
+ {}
2736
+ );
2737
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2738
+ (acc, [attribute, metadata]) => {
2739
+ return {
2740
+ ...acc,
2741
+ [attribute]: metadata.edit
2742
+ };
2743
+ },
2744
+ {}
2745
+ );
2746
+ return {
2747
+ layout: panelledEditAttributes,
2748
+ components: componentEditAttributes,
2749
+ metadatas: editMetadatas,
2750
+ settings: {
2751
+ ...data.contentType.settings,
2752
+ displayName: schema?.info.displayName
2753
+ },
2754
+ options: {
2755
+ ...schema?.options,
2756
+ ...schema?.pluginOptions,
2757
+ ...data.contentType.options
2758
+ }
2759
+ };
2760
+ };
2761
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2762
+ return rows.map(
2763
+ (row) => row.map((field) => {
2764
+ const attribute = attributes[field.name];
2765
+ if (!attribute) {
2766
+ return null;
2767
+ }
2768
+ const { edit: metadata } = metadatas[field.name];
2769
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2770
+ return {
2771
+ attribute,
2772
+ disabled: !metadata.editable,
2773
+ hint: metadata.description,
2774
+ label: metadata.label ?? "",
2775
+ name: field.name,
2776
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2777
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2778
+ schemas,
2779
+ components: components?.schemas ?? {}
2780
+ }),
2781
+ placeholder: metadata.placeholder ?? "",
2782
+ required: attribute.required ?? false,
2783
+ size: field.size,
2784
+ unique: "unique" in attribute ? attribute.unique : false,
2785
+ visible: metadata.visible ?? true,
2786
+ type: attribute.type
2787
+ };
2788
+ }).filter((field) => field !== null)
2789
+ );
2790
+ };
2791
+ const formatListLayout = (data, {
2792
+ schemas,
2793
+ schema,
2794
+ components
2795
+ }) => {
2796
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2797
+ (acc, [attribute, metadata]) => {
2798
+ return {
2799
+ ...acc,
2800
+ [attribute]: metadata.list
2801
+ };
2802
+ },
2803
+ {}
2804
+ );
2805
+ const listAttributes = convertListLayoutToFieldLayouts(
2806
+ data.contentType.layouts.list,
2807
+ schema?.attributes,
2808
+ listMetadatas,
2809
+ { configurations: data.components, schemas: components },
2810
+ schemas
2811
+ );
2812
+ return {
2813
+ layout: listAttributes,
2814
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2815
+ metadatas: listMetadatas,
2816
+ options: {
2817
+ ...schema?.options,
2818
+ ...schema?.pluginOptions,
2819
+ ...data.contentType.options
2820
+ }
2821
+ };
2822
+ };
2823
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2824
+ return columns.map((name) => {
2825
+ const attribute = attributes[name];
2826
+ if (!attribute) {
2827
+ return null;
2828
+ }
2829
+ const metadata = metadatas[name];
2830
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2831
+ return {
2832
+ attribute,
2833
+ label: metadata.label ?? "",
2834
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2835
+ schemas,
2836
+ components: components?.schemas ?? {}
2837
+ }),
2838
+ name,
2839
+ searchable: metadata.searchable ?? true,
2840
+ sortable: metadata.sortable ?? true
2841
+ };
2842
+ }).filter((field) => field !== null);
2843
+ };
2844
+ const ConfirmBulkActionDialog = ({
2845
+ onToggleDialog,
2846
+ isOpen = false,
2847
+ dialogBody,
2848
+ endAction
2849
+ }) => {
2850
+ const { formatMessage } = useIntl();
2851
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2852
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2853
+ id: "app.components.ConfirmDialog.title",
2854
+ defaultMessage: "Confirmation"
2855
+ }) }),
2856
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2857
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2858
+ dialogBody
2859
+ ] }) }),
2860
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2861
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2862
+ id: "app.components.Button.cancel",
2863
+ defaultMessage: "Cancel"
2864
+ }) }) }),
2865
+ endAction
2866
+ ] })
2867
+ ] }) });
2868
+ };
2869
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2870
+ const ConfirmDialogPublishAll = ({
2871
+ isOpen,
2872
+ onToggleDialog,
2873
+ isConfirmButtonLoading = false,
2874
+ onConfirm
2875
+ }) => {
2876
+ const { formatMessage } = useIntl();
2877
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2878
+ const { toggleNotification } = useNotification();
2879
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2880
+ const { model, schema } = useDoc();
2881
+ const [{ query }] = useQueryParams();
2882
+ const {
2883
+ data: countDraftRelations = 0,
2884
+ isLoading,
2885
+ error
2886
+ } = useGetManyDraftRelationCountQuery(
2887
+ {
2888
+ model,
2889
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2890
+ locale: query?.plugins?.i18n?.locale
2891
+ },
2892
+ {
2893
+ skip: selectedEntries.length === 0
2894
+ }
2895
+ );
2896
+ React.useEffect(() => {
2897
+ if (error) {
2898
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2899
+ }
2900
+ }, [error, formatAPIError, toggleNotification]);
2901
+ if (error) {
2902
+ return null;
2903
+ }
2904
+ return /* @__PURE__ */ jsx(
2905
+ ConfirmBulkActionDialog,
2906
+ {
2907
+ isOpen: isOpen && !isLoading,
2908
+ onToggleDialog,
2909
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2910
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2911
+ countDraftRelations > 0 && formatMessage(
2912
+ {
2913
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2914
+ 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. "
2915
+ },
2916
+ {
2917
+ b: BoldChunk$1,
2918
+ count: countDraftRelations,
2919
+ entities: selectedEntries.length
2920
+ }
2921
+ ),
2922
+ formatMessage({
2923
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2924
+ defaultMessage: "Are you sure you want to publish these entries?"
2925
+ })
2926
+ ] }),
2927
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2928
+ {
2929
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2930
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2931
+ },
2932
+ {
2933
+ em: Emphasis
2934
+ }
2935
+ ) })
2936
+ ] }),
2937
+ endAction: /* @__PURE__ */ jsx(
2938
+ Button,
2939
+ {
2940
+ onClick: onConfirm,
2941
+ variant: "secondary",
2942
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2943
+ loading: isConfirmButtonLoading,
2944
+ children: formatMessage({
2945
+ id: "app.utils.publish",
2946
+ defaultMessage: "Publish"
2947
+ })
2948
+ }
2949
+ )
2950
+ }
2951
+ );
2952
+ };
2953
+ const TypographyMaxWidth = styled(Typography)`
2954
+ max-width: 300px;
2955
+ `;
2956
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2957
+ const messages = [];
2958
+ Object.entries(errors).forEach(([key, value]) => {
2959
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
2960
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2961
+ if ("id" in value && "defaultMessage" in value) {
2962
+ messages.push(
2963
+ formatMessage(
2964
+ {
2965
+ id: `${value.id}.withField`,
2966
+ defaultMessage: value.defaultMessage
2967
+ },
2968
+ { field: currentKey }
2969
+ )
2970
+ );
2971
+ } else {
2972
+ messages.push(
2973
+ ...formatErrorMessages(
2974
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
2975
+ value,
2976
+ currentKey,
2977
+ formatMessage
2978
+ )
2979
+ );
2980
+ }
2981
+ } else {
2982
+ messages.push(
2983
+ formatMessage(
2984
+ {
2985
+ id: `${value}.withField`,
2986
+ defaultMessage: value
2987
+ },
2988
+ { field: currentKey }
2989
+ )
2990
+ );
2991
+ }
2992
+ });
2993
+ return messages;
2994
+ };
2995
+ const EntryValidationText = ({ validationErrors, status }) => {
2996
+ const { formatMessage } = useIntl();
2997
+ if (validationErrors) {
2998
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
2999
+ " "
3000
+ );
3001
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3002
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
3003
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3004
+ ] });
3005
+ }
3006
+ if (status === "published") {
3007
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3008
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3009
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3010
+ id: "content-manager.bulk-publish.already-published",
3011
+ defaultMessage: "Already Published"
3012
+ }) })
3013
+ ] });
3014
+ }
3015
+ if (status === "modified") {
3016
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3017
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
3018
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3019
+ id: "content-manager.bulk-publish.modified",
3020
+ defaultMessage: "Ready to publish changes"
3021
+ }) })
3022
+ ] });
3023
+ }
3024
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3025
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
3026
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3027
+ id: "app.utils.ready-to-publish",
3028
+ defaultMessage: "Ready to publish"
3029
+ }) })
3030
+ ] });
3031
+ };
3032
+ const TABLE_HEADERS = [
3033
+ { name: "id", label: "id" },
3034
+ { name: "name", label: "name" },
3035
+ { name: "status", label: "status" },
3036
+ { name: "publicationStatus", label: "Publication status" }
3037
+ ];
3038
+ const SelectedEntriesTableContent = ({
3039
+ isPublishing,
3040
+ rowsToDisplay = [],
3041
+ entriesToPublish = [],
3042
+ validationErrors = {}
3043
+ }) => {
3044
+ const { pathname } = useLocation();
3045
+ const { formatMessage } = useIntl();
3046
+ const {
3047
+ list: {
3048
+ settings: { mainField }
3049
+ }
3050
+ } = useDocLayout();
3051
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3052
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3053
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3054
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3055
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3056
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3057
+ )
3058
+ ] }),
3059
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3060
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3061
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3062
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3063
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3064
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3065
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3066
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3067
+ id: "content-manager.success.record.publishing",
3068
+ defaultMessage: "Publishing..."
3069
+ }) }),
3070
+ /* @__PURE__ */ jsx(Loader, { small: true })
3071
+ ] }) : /* @__PURE__ */ jsx(
3072
+ EntryValidationText,
3073
+ {
3074
+ validationErrors: validationErrors[row.documentId],
3075
+ status: row.status
3076
+ }
3077
+ ) }),
3078
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3079
+ IconButton,
3080
+ {
3081
+ tag: Link,
3082
+ to: {
3083
+ pathname: `${pathname}/${row.documentId}`,
3084
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3085
+ },
3086
+ state: { from: pathname },
3087
+ label: formatMessage(
3088
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3089
+ {
3090
+ target: formatMessage(
3091
+ {
3092
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3093
+ defaultMessage: "item line {number}"
3094
+ },
3095
+ { number: index2 + 1 }
3096
+ )
3097
+ }
3098
+ ),
3099
+ target: "_blank",
3100
+ marginLeft: "auto",
3101
+ children: /* @__PURE__ */ jsx(Pencil, {})
3102
+ }
3103
+ ) })
3104
+ ] }, row.id)) })
3105
+ ] });
3106
+ };
3107
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3108
+ const SelectedEntriesModalContent = ({
3109
+ listViewSelectedEntries,
3110
+ toggleModal,
3111
+ setListViewSelectedDocuments,
3112
+ model
3113
+ }) => {
3114
+ const { formatMessage } = useIntl();
3115
+ const { schema, components } = useContentTypeSchema(model);
3116
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3117
+ const [{ query }] = useQueryParams();
3118
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3119
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3120
+ {
3121
+ model,
3122
+ params: {
3123
+ page: "1",
3124
+ pageSize: documentIds.length.toString(),
3125
+ sort: query.sort,
3126
+ filters: {
3127
+ documentId: {
3128
+ $in: documentIds
3129
+ }
3130
+ },
3131
+ locale: query.plugins?.i18n?.locale
3132
+ }
3133
+ },
3134
+ {
3135
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3136
+ }
3137
+ );
3138
+ const { rows, validationErrors } = React.useMemo(() => {
3139
+ if (data.length > 0 && schema) {
3140
+ const validate = createYupSchema(schema.attributes, components);
3141
+ const validationErrors2 = {};
3142
+ const rows2 = data.map((entry) => {
3143
+ try {
3144
+ validate.validateSync(entry, { abortEarly: false });
3145
+ return entry;
3146
+ } catch (e) {
3147
+ if (e instanceof ValidationError) {
3148
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3149
+ }
3150
+ return entry;
3151
+ }
3152
+ });
3153
+ return { rows: rows2, validationErrors: validationErrors2 };
3154
+ }
3155
+ return {
3156
+ rows: [],
3157
+ validationErrors: {}
3158
+ };
3159
+ }, [components, data, schema]);
3160
+ const [publishedCount, setPublishedCount] = React.useState(0);
3161
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3162
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3163
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3164
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3165
+ const selectedEntries = rows.filter(
3166
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3167
+ );
3168
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3169
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3170
+ ({ documentId }) => validationErrors[documentId]
3171
+ ).length;
3172
+ const selectedEntriesPublished = selectedEntries.filter(
3173
+ ({ status }) => status === "published"
3174
+ ).length;
3175
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3176
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3177
+ const handleConfirmBulkPublish = async () => {
3178
+ toggleDialog();
3179
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3180
+ if (!("error" in res)) {
3181
+ setPublishedCount(res.count);
3182
+ const unpublishedEntries = rows.filter((row) => {
3183
+ return !entriesToPublish.includes(row.documentId);
3184
+ });
3185
+ setListViewSelectedDocuments(unpublishedEntries);
3186
+ }
3187
+ };
3188
+ const getFormattedCountMessage = () => {
3189
+ if (publishedCount) {
3190
+ return formatMessage(
3191
+ {
3192
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3193
+ 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."
3194
+ },
3195
+ {
3196
+ publishedCount,
3197
+ withErrorsCount: selectedEntriesWithErrorsCount,
3198
+ b: BoldChunk
3199
+ }
3200
+ );
3201
+ }
3202
+ return formatMessage(
3203
+ {
3204
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3205
+ 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."
3206
+ },
3207
+ {
3208
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3209
+ withErrorsCount: selectedEntriesWithErrorsCount,
3210
+ alreadyPublishedCount: selectedEntriesPublished,
3211
+ b: BoldChunk
3212
+ }
3213
+ );
3214
+ };
3215
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3216
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3217
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3218
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3219
+ SelectedEntriesTableContent,
3220
+ {
3221
+ isPublishing: isSubmittingForm,
3222
+ rowsToDisplay: rows,
3223
+ entriesToPublish,
3224
+ validationErrors
3225
+ }
3226
+ ) })
3227
+ ] }),
3228
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3229
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3230
+ id: "app.components.Button.cancel",
3231
+ defaultMessage: "Cancel"
3232
+ }) }),
3233
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3234
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3235
+ /* @__PURE__ */ jsx(
3236
+ Button,
3237
+ {
3238
+ onClick: toggleDialog,
3239
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3240
+ loading: isSubmittingForm,
3241
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3242
+ }
3243
+ )
3244
+ ] })
3245
+ ] }),
3246
+ /* @__PURE__ */ jsx(
3247
+ ConfirmDialogPublishAll,
3248
+ {
3249
+ isOpen: isDialogOpen,
3250
+ onToggleDialog: toggleDialog,
3251
+ isConfirmButtonLoading: isSubmittingForm,
3252
+ onConfirm: handleConfirmBulkPublish
3253
+ }
3254
+ )
3255
+ ] });
3256
+ };
3257
+ const PublishAction = ({ documents, model }) => {
3258
+ const { formatMessage } = useIntl();
3259
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3260
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3261
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3262
+ const refetchList = () => {
3263
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3264
+ };
3265
+ if (!showPublishButton)
3266
+ return null;
3267
+ return {
3268
+ actionType: "publish",
3269
+ variant: "tertiary",
3270
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3271
+ dialog: {
3272
+ type: "modal",
3273
+ title: formatMessage({
3274
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3275
+ defaultMessage: "Publish entries"
3276
+ }),
3277
+ content: ({ onClose }) => {
3278
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3279
+ SelectedEntriesModalContent,
3280
+ {
3281
+ listViewSelectedEntries: documents,
3282
+ toggleModal: () => {
3283
+ onClose();
3284
+ refetchList();
3285
+ },
3286
+ setListViewSelectedDocuments,
3287
+ model
3288
+ }
3289
+ ) });
3290
+ },
3291
+ onClose: () => {
3292
+ refetchList();
3293
+ }
3294
+ }
3295
+ };
3296
+ };
3297
+ const BulkActionsRenderer = () => {
3298
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3299
+ const { model, collectionType } = useDoc();
3300
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3301
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3302
+ DescriptionComponentRenderer,
3303
+ {
3304
+ props: {
3305
+ model,
3306
+ collectionType,
3307
+ documents: selectedRows
3308
+ },
3309
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3310
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3311
+ }
3312
+ ) });
3313
+ };
3314
+ const DeleteAction = ({ documents, model }) => {
3315
+ const { formatMessage } = useIntl();
3316
+ const { schema: contentType } = useDoc();
3317
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3318
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3319
+ const [{ query }] = useQueryParams();
3320
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3321
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3322
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3323
+ const documentIds = documents.map(({ documentId }) => documentId);
3324
+ const handleConfirmBulkDelete = async () => {
3325
+ const res = await bulkDeleteAction({
3326
+ documentIds,
3327
+ model,
3328
+ params
3329
+ });
3330
+ if (!("error" in res)) {
3331
+ selectRow([]);
3332
+ }
3333
+ };
3334
+ if (!hasDeletePermission)
3335
+ return null;
3336
+ return {
3337
+ variant: "danger-light",
3338
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3339
+ dialog: {
3340
+ type: "dialog",
3341
+ title: formatMessage({
3342
+ id: "app.components.ConfirmDialog.title",
3343
+ defaultMessage: "Confirmation"
3344
+ }),
3345
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3346
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3347
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3348
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3349
+ defaultMessage: "Are you sure you want to delete these entries?"
3350
+ }) }),
3351
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3352
+ {
3353
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3354
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3355
+ },
3356
+ {
3357
+ em: Emphasis
3358
+ }
3359
+ ) }) })
3360
+ ] }),
3361
+ onConfirm: handleConfirmBulkDelete
3362
+ }
3363
+ };
3364
+ };
3365
+ DeleteAction.type = "delete";
3366
+ const UnpublishAction = ({ documents, model }) => {
3367
+ const { formatMessage } = useIntl();
3368
+ const { schema } = useDoc();
3369
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3370
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3371
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3372
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3373
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3374
+ const documentIds = documents.map(({ documentId }) => documentId);
3375
+ const [{ query }] = useQueryParams();
3376
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3377
+ const handleConfirmBulkUnpublish = async () => {
3378
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3379
+ if (!("error" in data)) {
3380
+ selectRow([]);
3381
+ }
3382
+ };
3383
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3384
+ if (!showUnpublishButton)
3385
+ return null;
3386
+ return {
3387
+ variant: "tertiary",
3388
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3389
+ dialog: {
3390
+ type: "dialog",
3391
+ title: formatMessage({
3392
+ id: "app.components.ConfirmDialog.title",
3393
+ defaultMessage: "Confirmation"
3394
+ }),
3395
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3396
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3397
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3398
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3399
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3400
+ }) }),
3401
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3402
+ {
3403
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3404
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3405
+ },
3406
+ {
3407
+ em: Emphasis
3408
+ }
3409
+ ) }) })
3410
+ ] }),
3411
+ confirmButton: formatMessage({
3412
+ id: "app.utils.unpublish",
3413
+ defaultMessage: "Unpublish"
3414
+ }),
3415
+ onConfirm: handleConfirmBulkUnpublish
3416
+ }
3417
+ };
3418
+ };
3419
+ UnpublishAction.type = "unpublish";
3420
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3421
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3422
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3423
+ const { formatMessage } = useIntl();
3424
+ const getDefaultErrorMessage = (reason) => {
3425
+ switch (reason) {
3426
+ case "relation":
3427
+ return "Duplicating the relation could remove it from the original entry.";
3428
+ case "unique":
3429
+ return "Identical values in a unique field are not allowed";
3430
+ default:
3431
+ return reason;
3432
+ }
3433
+ };
3434
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3435
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3436
+ id: getTranslation("containers.list.autoCloneModal.title"),
3437
+ defaultMessage: "This entry can't be duplicated directly."
3438
+ }) }),
3439
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3440
+ id: getTranslation("containers.list.autoCloneModal.description"),
3441
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3442
+ }) }) }),
3443
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3444
+ Flex,
3445
+ {
3446
+ direction: "column",
3447
+ gap: 2,
3448
+ alignItems: "flex-start",
3449
+ borderColor: "neutral200",
3450
+ hasRadius: true,
3451
+ padding: 6,
3452
+ children: [
3453
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3454
+ pathSegment,
3455
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3456
+ ChevronRight,
3457
+ {
3458
+ fill: "neutral500",
3459
+ height: "0.8rem",
3460
+ width: "0.8rem",
3461
+ style: { margin: "0 0.8rem" }
3462
+ }
3463
+ )
3464
+ ] }, index2)) }),
3465
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3466
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3467
+ defaultMessage: getDefaultErrorMessage(reason)
3468
+ }) })
3469
+ ]
3470
+ },
3471
+ fieldPath.join()
3472
+ )) })
3473
+ ] });
3474
+ };
3475
+ const TableActions = ({ document }) => {
3476
+ const { formatMessage } = useIntl();
3477
+ const { model, collectionType } = useDoc();
3478
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3479
+ const props = {
3480
+ activeTab: null,
3481
+ model,
3482
+ documentId: document.documentId,
3483
+ collectionType,
3484
+ document
3485
+ };
3486
+ return /* @__PURE__ */ jsx(
3487
+ DescriptionComponentRenderer,
3488
+ {
3489
+ props,
3490
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3491
+ children: (actions2) => {
3492
+ const tableRowActions = actions2.filter((action) => {
3493
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3494
+ return positions.includes("table-row");
3495
+ });
3496
+ return /* @__PURE__ */ jsx(
3497
+ DocumentActionsMenu,
3498
+ {
3499
+ actions: tableRowActions,
3500
+ label: formatMessage({
3501
+ id: "content-manager.containers.list.table.row-actions",
3502
+ defaultMessage: "Row action"
3503
+ }),
3504
+ variant: "ghost"
3505
+ }
3506
+ );
3507
+ }
3508
+ }
3509
+ );
3510
+ };
3511
+ const EditAction = ({ documentId }) => {
3512
+ const navigate = useNavigate();
3513
+ const { formatMessage } = useIntl();
3514
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3515
+ const { toggleNotification } = useNotification();
3516
+ const [{ query }] = useQueryParams();
3517
+ return {
3518
+ disabled: !canRead,
3519
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3520
+ label: formatMessage({
3521
+ id: "content-manager.actions.edit.label",
3522
+ defaultMessage: "Edit"
3523
+ }),
2547
3524
  position: "table-row",
2548
3525
  onClick: async () => {
2549
3526
  if (!documentId) {
@@ -2629,7 +3606,7 @@ const CloneAction = ({ model, documentId }) => {
2629
3606
  /* @__PURE__ */ jsx(
2630
3607
  LinkButton,
2631
3608
  {
2632
- as: NavLink,
3609
+ tag: NavLink,
2633
3610
  to: {
2634
3611
  pathname: `clone/${documentId}`
2635
3612
  },
@@ -2662,442 +3639,183 @@ class ContentManagerPlugin {
2662
3639
  documentActions = [
2663
3640
  ...DEFAULT_ACTIONS,
2664
3641
  ...DEFAULT_TABLE_ROW_ACTIONS,
2665
- ...DEFAULT_HEADER_ACTIONS,
2666
- HistoryAction
3642
+ ...DEFAULT_HEADER_ACTIONS
2667
3643
  ];
2668
3644
  editViewSidePanels = [ActionsPanel];
2669
3645
  headerActions = [];
2670
3646
  constructor() {
2671
3647
  }
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);
3648
+ addEditViewSidePanel(panels) {
3649
+ if (Array.isArray(panels)) {
3650
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3651
+ } else if (typeof panels === "function") {
3652
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2703
3653
  } else {
2704
3654
  throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
3655
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3656
+ panels
2707
3657
  )}`
2708
3658
  );
2709
3659
  }
2710
3660
  }
2711
- addBulkAction(actions2) {
3661
+ addDocumentAction(actions2) {
2712
3662
  if (Array.isArray(actions2)) {
2713
- this.bulkActions = [...this.bulkActions, ...actions2];
3663
+ this.documentActions = [...this.documentActions, ...actions2];
2714
3664
  } else if (typeof actions2 === "function") {
2715
- this.bulkActions = actions2(this.bulkActions);
3665
+ this.documentActions = actions2(this.documentActions);
2716
3666
  } else {
2717
3667
  throw new Error(
2718
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3668
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2719
3669
  actions2
2720
3670
  )}`
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;
3671
+ );
3672
+ }
3673
+ }
3674
+ addDocumentHeaderAction(actions2) {
3675
+ if (Array.isArray(actions2)) {
3676
+ this.headerActions = [...this.headerActions, ...actions2];
3677
+ } else if (typeof actions2 === "function") {
3678
+ this.headerActions = actions2(this.headerActions);
2960
3679
  } else {
2961
- if (!panels[currentPanelIndex]) {
2962
- panels.push([]);
2963
- }
2964
- panels[currentPanelIndex].push(row);
3680
+ throw new Error(
3681
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3682
+ actions2
3683
+ )}`
3684
+ );
2965
3685
  }
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
3686
+ }
3687
+ addBulkAction(actions2) {
3688
+ if (Array.isArray(actions2)) {
3689
+ this.bulkActions = [...this.bulkActions, ...actions2];
3690
+ } else if (typeof actions2 === "function") {
3691
+ this.bulkActions = actions2(this.bulkActions);
3692
+ } else {
3693
+ throw new Error(
3694
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3695
+ actions2
3696
+ )}`
3697
+ );
3007
3698
  }
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;
3699
+ }
3700
+ get config() {
3701
+ return {
3702
+ id: PLUGIN_ID,
3703
+ name: "Content Manager",
3704
+ injectionZones: INJECTION_ZONES,
3705
+ apis: {
3706
+ addBulkAction: this.addBulkAction.bind(this),
3707
+ addDocumentAction: this.addDocumentAction.bind(this),
3708
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3709
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3710
+ getBulkActions: () => this.bulkActions,
3711
+ getDocumentActions: () => this.documentActions,
3712
+ getEditViewSidePanels: () => this.editViewSidePanels,
3713
+ getHeaderActions: () => this.headerActions
3016
3714
  }
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
- );
3715
+ };
3716
+ }
3717
+ }
3718
+ const getPrintableType = (value) => {
3719
+ const nativeType = typeof value;
3720
+ if (nativeType === "object") {
3721
+ if (value === null)
3722
+ return "null";
3723
+ if (Array.isArray(value))
3724
+ return "array";
3725
+ if (value instanceof Object && value.constructor.name !== "Object") {
3726
+ return value.constructor.name;
3727
+ }
3728
+ }
3729
+ return nativeType;
3039
3730
  };
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
- );
3731
+ const HistoryAction = ({ model, document }) => {
3732
+ const { formatMessage } = useIntl();
3733
+ const [{ query }] = useQueryParams();
3734
+ const navigate = useNavigate();
3735
+ const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
3736
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3737
+ return null;
3738
+ }
3061
3739
  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
- }
3740
+ icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
3741
+ label: formatMessage({
3742
+ id: "content-manager.history.document-action",
3743
+ defaultMessage: "Content History"
3744
+ }),
3745
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3746
+ disabled: (
3747
+ /**
3748
+ * The user is creating a new document.
3749
+ * It hasn't been saved yet, so there's no history to go to
3750
+ */
3751
+ !document || /**
3752
+ * The document has been created but the current dimension has never been saved.
3753
+ * For example, the user is creating a new locale in an existing document,
3754
+ * so there's no history for the document in that locale
3755
+ */
3756
+ !document.id || /**
3757
+ * History is only available for content types created by the user.
3758
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3759
+ * which start with `admin::` or `plugin::`
3760
+ */
3761
+ !model.startsWith("api::")
3762
+ ),
3763
+ position: "header"
3070
3764
  };
3071
3765
  };
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);
3766
+ HistoryAction.type = "history";
3767
+ const historyAdmin = {
3768
+ bootstrap(app) {
3769
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3770
+ addDocumentAction((actions2) => {
3771
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3772
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3773
+ return actions2;
3774
+ });
3775
+ }
3776
+ };
3777
+ const initialState = {
3778
+ collectionTypeLinks: [],
3779
+ components: [],
3780
+ fieldSizes: {},
3781
+ models: [],
3782
+ singleTypeLinks: [],
3783
+ isLoading: true
3092
3784
  };
3785
+ const appSlice = createSlice({
3786
+ name: "app",
3787
+ initialState,
3788
+ reducers: {
3789
+ setInitialData(state, action) {
3790
+ const {
3791
+ authorizedCollectionTypeLinks,
3792
+ authorizedSingleTypeLinks,
3793
+ components,
3794
+ contentTypeSchemas,
3795
+ fieldSizes
3796
+ } = action.payload;
3797
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3798
+ ({ isDisplayed }) => isDisplayed
3799
+ );
3800
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3801
+ state.components = components;
3802
+ state.models = contentTypeSchemas;
3803
+ state.fieldSizes = fieldSizes;
3804
+ state.isLoading = false;
3805
+ }
3806
+ }
3807
+ });
3808
+ const { actions, reducer: reducer$1 } = appSlice;
3809
+ const { setInitialData } = actions;
3810
+ const reducer = combineReducers({
3811
+ app: reducer$1
3812
+ });
3093
3813
  const index = {
3094
3814
  register(app) {
3095
3815
  const cm = new ContentManagerPlugin();
3096
3816
  app.addReducers({
3097
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3098
3817
  [PLUGIN_ID]: reducer
3099
3818
  });
3100
- app.addMiddlewares([() => contentManagerApi.middleware]);
3101
3819
  app.addMenuLink({
3102
3820
  to: PLUGIN_ID,
3103
3821
  icon: Feather,
@@ -3106,14 +3824,29 @@ const index = {
3106
3824
  defaultMessage: "Content Manager"
3107
3825
  },
3108
3826
  permissions: [],
3109
- Component: () => import("./layout-Dnh0PNp9.mjs").then((mod) => ({ default: mod.Layout }))
3827
+ position: 1
3828
+ });
3829
+ app.router.addRoute({
3830
+ path: "content-manager/*",
3831
+ lazy: async () => {
3832
+ const { Layout } = await import("./layout-DPaHUusj.mjs");
3833
+ return {
3834
+ Component: Layout
3835
+ };
3836
+ },
3837
+ children: routes
3110
3838
  });
3111
3839
  app.registerPlugin(cm.config);
3112
3840
  },
3841
+ bootstrap(app) {
3842
+ if (typeof historyAdmin.bootstrap === "function") {
3843
+ historyAdmin.bootstrap(app);
3844
+ }
3845
+ },
3113
3846
  async registerTrads({ locales }) {
3114
3847
  const importedTrads = await Promise.all(
3115
3848
  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 }) => {
3849
+ 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
3850
  return {
3118
3851
  data: prefixPluginTranslations(data, PLUGIN_ID),
3119
3852
  locale
@@ -3131,7 +3864,7 @@ const index = {
3131
3864
  };
3132
3865
  export {
3133
3866
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3134
- extractContentTypeComponents as B,
3867
+ BulkActionsRenderer as B,
3135
3868
  COLLECTION_TYPES as C,
3136
3869
  DocumentStatus as D,
3137
3870
  DEFAULT_SETTINGS as E,
@@ -3145,31 +3878,31 @@ export {
3145
3878
  RelativeTime as R,
3146
3879
  SINGLE_TYPES as S,
3147
3880
  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,
3881
+ useGetInitialDataQuery as a,
3882
+ useGetAllContentTypeSettingsQuery as b,
3883
+ useDoc as c,
3884
+ buildValidParams as d,
3885
+ contentManagerApi as e,
3886
+ useDocumentRBAC as f,
3154
3887
  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,
3888
+ useDocumentLayout as h,
3889
+ createYupSchema as i,
3890
+ Header as j,
3891
+ PERMISSIONS as k,
3892
+ DocumentRBAC as l,
3893
+ DOCUMENT_META_FIELDS as m,
3894
+ useDocLayout as n,
3162
3895
  useGetContentTypeConfigurationQuery as o,
3163
3896
  CREATOR_FIELDS as p,
3164
3897
  getMainField as q,
3165
- routes as r,
3898
+ getDisplayName as r,
3166
3899
  setInitialData as s,
3167
- getDisplayName as t,
3168
- useGetInitialDataQuery as u,
3169
- checkIfAttributeIsDisplayable as v,
3170
- useGetAllDocumentsQuery as w,
3171
- convertListLayoutToFieldLayouts as x,
3172
- capitalise as y,
3173
- useUpdateContentTypeConfigurationMutation as z
3174
- };
3175
- //# sourceMappingURL=index-DNVx8ssZ.mjs.map
3900
+ checkIfAttributeIsDisplayable as t,
3901
+ useContentTypeSchema as u,
3902
+ useGetAllDocumentsQuery as v,
3903
+ convertListLayoutToFieldLayouts as w,
3904
+ capitalise as x,
3905
+ useUpdateContentTypeConfigurationMutation as y,
3906
+ extractContentTypeComponents as z
3907
+ };
3908
+ //# sourceMappingURL=index-BSn97i8U.mjs.map