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

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 (174) hide show
  1. package/LICENSE +18 -3
  2. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  3. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  4. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  5. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  6. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js → ComponentConfigurationPage-5ukroXAh.js} +3 -3
  7. package/dist/_chunks/{ComponentConfigurationPage-DjWJdz6Y.js.map → ComponentConfigurationPage-5ukroXAh.js.map} +1 -1
  8. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs → ComponentConfigurationPage-BAgyHiMm.mjs} +3 -3
  9. package/dist/_chunks/{ComponentConfigurationPage-BPvzFjM7.mjs.map → ComponentConfigurationPage-BAgyHiMm.mjs.map} +1 -1
  10. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  11. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  12. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  13. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  14. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs → EditConfigurationPage-DmoXawIh.mjs} +3 -3
  15. package/dist/_chunks/{EditConfigurationPage-DacbqQ_f.mjs.map → EditConfigurationPage-DmoXawIh.mjs.map} +1 -1
  16. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js → EditConfigurationPage-Xp7lun0f.js} +3 -3
  17. package/dist/_chunks/{EditConfigurationPage-Dmv83RlS.js.map → EditConfigurationPage-Xp7lun0f.js.map} +1 -1
  18. package/dist/_chunks/{EditViewPage-DDS6H9HO.mjs → EditViewPage-BLsjc5F-.mjs} +47 -47
  19. package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +1 -0
  20. package/dist/_chunks/{EditViewPage-DvNpQkam.js → EditViewPage-C-ukDOB7.js} +46 -48
  21. package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +1 -0
  22. package/dist/_chunks/{Field-DmVKIAOo.js → Field-Bfph5SOd.js} +953 -782
  23. package/dist/_chunks/Field-Bfph5SOd.js.map +1 -0
  24. package/dist/_chunks/{Field-6gvGdPBV.mjs → Field-Cs7duwWd.mjs} +901 -729
  25. package/dist/_chunks/Field-Cs7duwWd.mjs.map +1 -0
  26. package/dist/_chunks/{Form-CPZC9vWa.js → Form-CPYqIWDG.js} +39 -38
  27. package/dist/_chunks/Form-CPYqIWDG.js.map +1 -0
  28. package/dist/_chunks/{Form-DW6K1IH-.mjs → Form-Dg_GS5TQ.mjs} +39 -37
  29. package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +1 -0
  30. package/dist/_chunks/{History-DeAPlvtv.js → History-DNQkXANT.js} +149 -56
  31. package/dist/_chunks/History-DNQkXANT.js.map +1 -0
  32. package/dist/_chunks/{History-Dmr9fmUA.mjs → History-wrnHqf09.mjs} +148 -54
  33. package/dist/_chunks/History-wrnHqf09.mjs.map +1 -0
  34. package/dist/_chunks/{ListConfigurationPage-DPCwW5Vr.js → ListConfigurationPage-CUQxfpjT.js} +58 -59
  35. package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +1 -0
  36. package/dist/_chunks/{ListConfigurationPage-DhwvYcNv.mjs → ListConfigurationPage-DScmJVkW.mjs} +54 -54
  37. package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +1 -0
  38. package/dist/_chunks/{ListViewPage-5ySZ-VUs.js → ListViewPage-BsLiH2-2.js} +92 -108
  39. package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +1 -0
  40. package/dist/_chunks/{ListViewPage-BtAwuYLE.mjs → ListViewPage-C4IvrMgY.mjs} +87 -103
  41. package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +1 -0
  42. package/dist/_chunks/{NoContentTypePage-DOC_yWOf.js → NoContentTypePage-BZ-PnGAf.js} +3 -3
  43. package/dist/_chunks/NoContentTypePage-BZ-PnGAf.js.map +1 -0
  44. package/dist/_chunks/{NoContentTypePage-DSPxnxxp.mjs → NoContentTypePage-Djg8nPlj.mjs} +3 -3
  45. package/dist/_chunks/NoContentTypePage-Djg8nPlj.mjs.map +1 -0
  46. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs → NoPermissionsPage-DSP7R-hv.mjs} +2 -2
  47. package/dist/_chunks/{NoPermissionsPage-UWDC-1Tw.mjs.map → NoPermissionsPage-DSP7R-hv.mjs.map} +1 -1
  48. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js → NoPermissionsPage-_lUqjGW3.js} +2 -2
  49. package/dist/_chunks/{NoPermissionsPage-Dwu8rRJu.js.map → NoPermissionsPage-_lUqjGW3.js.map} +1 -1
  50. package/dist/_chunks/{Relations-J8cscLlR.mjs → Relations-BZr8tL0R.mjs} +66 -56
  51. package/dist/_chunks/Relations-BZr8tL0R.mjs.map +1 -0
  52. package/dist/_chunks/{Relations-CgWtgnPe.js → Relations-CtELXYIK.js} +70 -61
  53. package/dist/_chunks/Relations-CtELXYIK.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-C6AH2hEl.js → index-OerGjbAN.js} +1588 -837
  59. package/dist/_chunks/index-OerGjbAN.js.map +1 -0
  60. package/dist/_chunks/{index-CwRRo1V9.mjs → index-c_5DdJi-.mjs} +1610 -858
  61. package/dist/_chunks/index-c_5DdJi-.mjs.map +1 -0
  62. package/dist/_chunks/{layout-B_SXLhqf.js → layout-Ci7qHlFb.js} +30 -27
  63. package/dist/_chunks/layout-Ci7qHlFb.js.map +1 -0
  64. package/dist/_chunks/{layout-jIDzX0Fp.mjs → layout-oPBiO7RY.mjs} +29 -24
  65. package/dist/_chunks/layout-oPBiO7RY.mjs.map +1 -0
  66. package/dist/_chunks/{relations-CuvIgCqI.mjs → relations-BIdWFjdq.mjs} +2 -2
  67. package/dist/_chunks/{relations-CuvIgCqI.mjs.map → relations-BIdWFjdq.mjs.map} +1 -1
  68. package/dist/_chunks/{relations-iBMa_OFG.js → relations-COBpStiF.js} +2 -2
  69. package/dist/_chunks/{relations-iBMa_OFG.js.map → relations-COBpStiF.js.map} +1 -1
  70. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  71. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  72. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  73. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  75. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  76. package/dist/admin/index.js +2 -1
  77. package/dist/admin/index.js.map +1 -1
  78. package/dist/admin/index.mjs +5 -4
  79. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  80. package/dist/admin/src/content-manager.d.ts +3 -3
  81. package/dist/admin/src/exports.d.ts +1 -0
  82. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  83. package/dist/admin/src/history/index.d.ts +3 -0
  84. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  85. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  86. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  87. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  88. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  89. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  90. package/dist/admin/src/index.d.ts +1 -0
  91. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
  92. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  93. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  95. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  96. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
  98. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  99. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  100. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  101. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
  102. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  103. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  104. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  105. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  106. package/dist/admin/src/services/api.d.ts +2 -3
  107. package/dist/admin/src/services/components.d.ts +2 -2
  108. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  109. package/dist/admin/src/services/documents.d.ts +29 -17
  110. package/dist/admin/src/services/init.d.ts +2 -2
  111. package/dist/admin/src/services/relations.d.ts +3 -3
  112. package/dist/admin/src/services/uid.d.ts +3 -3
  113. package/dist/admin/src/utils/api.d.ts +4 -18
  114. package/dist/admin/src/utils/validation.d.ts +1 -6
  115. package/dist/server/index.js +309 -218
  116. package/dist/server/index.js.map +1 -1
  117. package/dist/server/index.mjs +317 -226
  118. package/dist/server/index.mjs.map +1 -1
  119. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  120. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  121. package/dist/server/src/controllers/uid.d.ts.map +1 -1
  122. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  123. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  124. package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
  125. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  126. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  127. package/dist/server/src/history/services/history.d.ts.map +1 -1
  128. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  129. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  130. package/dist/server/src/index.d.ts +18 -39
  131. package/dist/server/src/index.d.ts.map +1 -1
  132. package/dist/server/src/services/document-manager.d.ts +13 -12
  133. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  134. package/dist/server/src/services/document-metadata.d.ts +8 -29
  135. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  136. package/dist/server/src/services/index.d.ts +18 -39
  137. package/dist/server/src/services/index.d.ts.map +1 -1
  138. package/dist/server/src/services/utils/populate.d.ts +8 -1
  139. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  140. package/dist/shared/contracts/collection-types.d.ts +14 -6
  141. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  142. package/dist/shared/contracts/relations.d.ts +2 -2
  143. package/dist/shared/contracts/relations.d.ts.map +1 -1
  144. package/package.json +13 -14
  145. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  146. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  147. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  148. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  149. package/dist/_chunks/EditViewPage-DDS6H9HO.mjs.map +0 -1
  150. package/dist/_chunks/EditViewPage-DvNpQkam.js.map +0 -1
  151. package/dist/_chunks/Field-6gvGdPBV.mjs.map +0 -1
  152. package/dist/_chunks/Field-DmVKIAOo.js.map +0 -1
  153. package/dist/_chunks/Form-CPZC9vWa.js.map +0 -1
  154. package/dist/_chunks/Form-DW6K1IH-.mjs.map +0 -1
  155. package/dist/_chunks/History-DeAPlvtv.js.map +0 -1
  156. package/dist/_chunks/History-Dmr9fmUA.mjs.map +0 -1
  157. package/dist/_chunks/ListConfigurationPage-DPCwW5Vr.js.map +0 -1
  158. package/dist/_chunks/ListConfigurationPage-DhwvYcNv.mjs.map +0 -1
  159. package/dist/_chunks/ListViewPage-5ySZ-VUs.js.map +0 -1
  160. package/dist/_chunks/ListViewPage-BtAwuYLE.mjs.map +0 -1
  161. package/dist/_chunks/NoContentTypePage-DOC_yWOf.js.map +0 -1
  162. package/dist/_chunks/NoContentTypePage-DSPxnxxp.mjs.map +0 -1
  163. package/dist/_chunks/Relations-CgWtgnPe.js.map +0 -1
  164. package/dist/_chunks/Relations-J8cscLlR.mjs.map +0 -1
  165. package/dist/_chunks/index-C6AH2hEl.js.map +0 -1
  166. package/dist/_chunks/index-CwRRo1V9.mjs.map +0 -1
  167. package/dist/_chunks/layout-B_SXLhqf.js.map +0 -1
  168. package/dist/_chunks/layout-jIDzX0Fp.mjs.map +0 -1
  169. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  170. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  171. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  172. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  173. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  174. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -2,17 +2,15 @@
2
2
  const Icons = require("@strapi/icons");
3
3
  const jsxRuntime = require("react/jsx-runtime");
4
4
  const strapiAdmin = require("@strapi/admin/strapi-admin");
5
- const qs = require("qs");
6
- const reactIntl = require("react-intl");
7
- const reactRouterDom = require("react-router-dom");
8
5
  const React = require("react");
9
6
  const designSystem = require("@strapi/design-system");
10
- const styled = require("styled-components");
7
+ const reactIntl = require("react-intl");
8
+ const reactRouterDom = require("react-router-dom");
9
+ const styledComponents = require("styled-components");
11
10
  const yup = require("yup");
12
- const react = require("@reduxjs/toolkit/query/react");
13
- const axios = require("axios");
14
11
  const pipe = require("lodash/fp/pipe");
15
12
  const dateFns = require("date-fns");
13
+ const qs = require("qs");
16
14
  const toolkit = require("@reduxjs/toolkit");
17
15
  const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
18
16
  function _interopNamespace(e) {
@@ -34,7 +32,6 @@ function _interopNamespace(e) {
34
32
  return Object.freeze(n);
35
33
  }
36
34
  const React__namespace = /* @__PURE__ */ _interopNamespace(React);
37
- const styled__default = /* @__PURE__ */ _interopDefault(styled);
38
35
  const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
39
36
  const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
40
37
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
@@ -73,42 +70,6 @@ const useInjectionZone = (area) => {
73
70
  const [page, position] = area.split(".");
74
71
  return contentManagerPlugin.getInjectedComponents(page, position);
75
72
  };
76
- const HistoryAction = ({ model, document }) => {
77
- const { formatMessage } = reactIntl.useIntl();
78
- const [{ query }] = strapiAdmin.useQueryParams();
79
- const navigate = reactRouterDom.useNavigate();
80
- const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
81
- if (!window.strapi.features.isEnabled("cms-content-history")) {
82
- return null;
83
- }
84
- return {
85
- icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
86
- label: formatMessage({
87
- id: "content-manager.history.document-action",
88
- defaultMessage: "Content History"
89
- }),
90
- onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
91
- disabled: (
92
- /**
93
- * The user is creating a new document.
94
- * It hasn't been saved yet, so there's no history to go to
95
- */
96
- !document || /**
97
- * The document has been created but the current dimension has never been saved.
98
- * For example, the user is creating a new locale in an existing document,
99
- * so there's no history for the document in that locale
100
- */
101
- !document.id || /**
102
- * History is only available for content types created by the user.
103
- * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
104
- * which start with `admin::` or `plugin::`
105
- */
106
- !model.startsWith("api::")
107
- ),
108
- position: "header"
109
- };
110
- };
111
- HistoryAction.type = "history";
112
73
  const ID = "id";
113
74
  const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
114
75
  const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
@@ -179,9 +140,8 @@ const DocumentRBAC = ({ children, permissions }) => {
179
140
  const name = removeNumericalStrings(fieldName.split("."));
180
141
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
181
142
  if (fieldType === "component") {
182
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
183
- return componentOrDynamicZoneFields.some((field) => {
184
- return field.includes(fieldName);
143
+ return componentFieldNames.some((field) => {
144
+ return field.includes(name.join("."));
185
145
  });
186
146
  }
187
147
  if (name.length > 1) {
@@ -211,78 +171,8 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
211
171
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
212
172
  );
213
173
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
214
- const buildValidParams = (query) => {
215
- if (!query)
216
- return query;
217
- const { plugins: _, ...validQueryParams } = {
218
- ...query,
219
- ...Object.values(query?.plugins ?? {}).reduce(
220
- (acc, current) => Object.assign(acc, current),
221
- {}
222
- )
223
- };
224
- if ("_q" in validQueryParams) {
225
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
226
- }
227
- return validQueryParams;
228
- };
229
- const axiosBaseQuery = () => async (query, { signal }) => {
230
- try {
231
- const { get, post, del, put } = strapiAdmin.getFetchClient();
232
- if (typeof query === "string") {
233
- const result = await get(query, { signal });
234
- return { data: result.data };
235
- } else {
236
- const { url, method = "GET", data, config } = query;
237
- if (method === "POST") {
238
- const result2 = await post(url, data, { ...config, signal });
239
- return { data: result2.data };
240
- }
241
- if (method === "DELETE") {
242
- const result2 = await del(url, { ...config, signal });
243
- return { data: result2.data };
244
- }
245
- if (method === "PUT") {
246
- const result2 = await put(url, data, { ...config, signal });
247
- return { data: result2.data };
248
- }
249
- const result = await get(url, { ...config, signal });
250
- return { data: result.data };
251
- }
252
- } catch (err) {
253
- if (axios.isAxiosError(err)) {
254
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
255
- return { data: void 0, error: err.response?.data.error };
256
- } else {
257
- return {
258
- data: void 0,
259
- error: {
260
- name: "UnknownError",
261
- message: "There was an unknown error response from the API",
262
- details: err.response?.data,
263
- status: err.response?.status
264
- }
265
- };
266
- }
267
- }
268
- const error = err;
269
- return {
270
- data: void 0,
271
- error: {
272
- name: error.name,
273
- message: error.message,
274
- stack: error.stack
275
- }
276
- };
277
- }
278
- };
279
- const isBaseQueryError = (error) => {
280
- return error.name !== void 0;
281
- };
282
- const contentManagerApi = react.createApi({
283
- reducerPath: "contentManagerApi",
284
- baseQuery: axiosBaseQuery(),
285
- tagTypes: [
174
+ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
175
+ addTagTypes: [
286
176
  "ComponentConfiguration",
287
177
  "ContentTypesConfiguration",
288
178
  "ContentTypeSettings",
@@ -290,10 +180,10 @@ const contentManagerApi = react.createApi({
290
180
  "InitialData",
291
181
  "HistoryVersion",
292
182
  "Relations"
293
- ],
294
- endpoints: () => ({})
183
+ ]
295
184
  });
296
185
  const documentApi = contentManagerApi.injectEndpoints({
186
+ overrideExisting: true,
297
187
  endpoints: (builder) => ({
298
188
  autoCloneDocument: builder.mutation({
299
189
  query: ({ model, sourceId, query }) => ({
@@ -303,7 +193,12 @@ const documentApi = contentManagerApi.injectEndpoints({
303
193
  params: query
304
194
  }
305
195
  }),
306
- invalidatesTags: (_result, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
196
+ invalidatesTags: (_result, error, { model }) => {
197
+ if (error) {
198
+ return [];
199
+ }
200
+ return [{ type: "Document", id: `${model}_LIST` }];
201
+ }
307
202
  }),
308
203
  cloneDocument: builder.mutation({
309
204
  query: ({ model, sourceId, data, params }) => ({
@@ -347,12 +242,15 @@ const documentApi = contentManagerApi.injectEndpoints({
347
242
  ]
348
243
  }),
349
244
  deleteManyDocuments: builder.mutation({
350
- query: ({ model, ...body }) => ({
245
+ query: ({ model, params, ...body }) => ({
351
246
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
352
247
  method: "POST",
353
- data: body
248
+ data: body,
249
+ config: {
250
+ params
251
+ }
354
252
  }),
355
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
253
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
356
254
  }),
357
255
  discardDocument: builder.mutation({
358
256
  query: ({ collectionType, model, documentId, params }) => ({
@@ -463,10 +361,13 @@ const documentApi = contentManagerApi.injectEndpoints({
463
361
  }
464
362
  }),
465
363
  publishManyDocuments: builder.mutation({
466
- query: ({ model, ...body }) => ({
364
+ query: ({ model, params, ...body }) => ({
467
365
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
468
366
  method: "POST",
469
- data: body
367
+ data: body,
368
+ config: {
369
+ params
370
+ }
470
371
  }),
471
372
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
472
373
  }),
@@ -487,6 +388,18 @@ const documentApi = contentManagerApi.injectEndpoints({
487
388
  },
488
389
  "Relations"
489
390
  ];
391
+ },
392
+ async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
393
+ const patchResult = dispatch(
394
+ documentApi.util.updateQueryData("getDocument", patch, (draft) => {
395
+ Object.assign(draft.data, data);
396
+ })
397
+ );
398
+ try {
399
+ await queryFulfilled;
400
+ } catch {
401
+ patchResult.undo();
402
+ }
490
403
  }
491
404
  }),
492
405
  unpublishDocument: builder.mutation({
@@ -508,10 +421,13 @@ const documentApi = contentManagerApi.injectEndpoints({
508
421
  }
509
422
  }),
510
423
  unpublishManyDocuments: builder.mutation({
511
- query: ({ model, ...body }) => ({
424
+ query: ({ model, params, ...body }) => ({
512
425
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
513
426
  method: "POST",
514
- data: body
427
+ data: body,
428
+ config: {
429
+ params
430
+ }
515
431
  }),
516
432
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
517
433
  })
@@ -535,6 +451,24 @@ const {
535
451
  useUnpublishDocumentMutation,
536
452
  useUnpublishManyDocumentsMutation
537
453
  } = documentApi;
454
+ const buildValidParams = (query) => {
455
+ if (!query)
456
+ return query;
457
+ const { plugins: _, ...validQueryParams } = {
458
+ ...query,
459
+ ...Object.values(query?.plugins ?? {}).reduce(
460
+ (acc, current) => Object.assign(acc, current),
461
+ {}
462
+ )
463
+ };
464
+ if ("_q" in validQueryParams) {
465
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
466
+ }
467
+ return validQueryParams;
468
+ };
469
+ const isBaseQueryError = (error) => {
470
+ return error.name !== void 0;
471
+ };
538
472
  const createYupSchema = (attributes = {}, components = {}) => {
539
473
  const createModelSchema = (attributes2) => yup__namespace.object().shape(
540
474
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -574,10 +508,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
574
508
  yup__namespace.array().of(
575
509
  yup__namespace.lazy(
576
510
  (data) => {
577
- const { attributes: attributes3 } = components[data.__component];
578
- return yup__namespace.object().shape({
511
+ const attributes3 = components?.[data?.__component]?.attributes;
512
+ const validation = yup__namespace.object().shape({
579
513
  __component: yup__namespace.string().required().oneOf(Object.keys(components))
580
- }).nullable(false).concat(createModelSchema(attributes3));
514
+ }).nullable(false);
515
+ if (!attributes3) {
516
+ return validation;
517
+ }
518
+ return validation.concat(createModelSchema(attributes3));
581
519
  }
582
520
  )
583
521
  )
@@ -587,11 +525,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
587
525
  return {
588
526
  ...acc,
589
527
  [name]: transformSchema(
590
- yup__namespace.array().of(
591
- yup__namespace.object().shape({
592
- id: yup__namespace.string().required()
593
- })
594
- )
528
+ yup__namespace.lazy((value) => {
529
+ if (!value) {
530
+ return yup__namespace.mixed().nullable(true);
531
+ } else if (Array.isArray(value)) {
532
+ return yup__namespace.array().of(
533
+ yup__namespace.object().shape({
534
+ id: yup__namespace.string().required()
535
+ })
536
+ );
537
+ } else if (typeof value === "object") {
538
+ return yup__namespace.object();
539
+ } else {
540
+ return yup__namespace.mixed().test(
541
+ "type-error",
542
+ "Relation values must be either null, an array of objects with {id} or an object.",
543
+ () => false
544
+ );
545
+ }
546
+ })
595
547
  )
596
548
  };
597
549
  default:
@@ -650,13 +602,18 @@ const createAttributeSchema = (attribute) => {
650
602
  }
651
603
  };
652
604
  const addRequiredValidation = (attribute) => (schema) => {
653
- if (attribute.required) {
654
- return schema.required({
655
- id: strapiAdmin.translatedErrors.required.id,
656
- defaultMessage: "This field is required."
657
- });
605
+ if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
606
+ return schema.min(1, strapiAdmin.translatedErrors.required);
658
607
  }
659
- return schema.nullable();
608
+ if (attribute.required && attribute.type !== "relation") {
609
+ return schema.required(strapiAdmin.translatedErrors.required);
610
+ }
611
+ return schema?.nullable ? schema.nullable() : (
612
+ // In some cases '.nullable' will not be available on the schema.
613
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
614
+ // In these cases we should just return the schema as it is.
615
+ schema
616
+ );
660
617
  };
661
618
  const addMinLengthValidation = (attribute) => (schema) => {
662
619
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -683,6 +640,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
683
640
  const addMinValidation = (attribute) => (schema) => {
684
641
  if ("min" in attribute) {
685
642
  const min = toInteger(attribute.min);
643
+ if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
644
+ if (!attribute.required && "test" in schema && min) {
645
+ return schema.test(
646
+ "custom-min",
647
+ {
648
+ ...strapiAdmin.translatedErrors.min,
649
+ values: {
650
+ min: attribute.min
651
+ }
652
+ },
653
+ (value) => {
654
+ if (!value) {
655
+ return true;
656
+ }
657
+ if (Array.isArray(value) && value.length === 0) {
658
+ return true;
659
+ }
660
+ return value.length >= min;
661
+ }
662
+ );
663
+ }
664
+ }
686
665
  if ("min" in schema && min) {
687
666
  return schema.min(min, {
688
667
  ...strapiAdmin.translatedErrors.min,
@@ -728,24 +707,6 @@ const addRegexValidation = (attribute) => (schema) => {
728
707
  }
729
708
  return schema;
730
709
  };
731
- const extractValuesFromYupError = (errorType, errorParams) => {
732
- if (!errorType || !errorParams) {
733
- return {};
734
- }
735
- return {
736
- [errorType]: errorParams[errorType]
737
- };
738
- };
739
- const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
740
- if (currentError.path) {
741
- acc[currentError.path.split("[").join(".").split("]").join("")] = {
742
- id: currentError.message,
743
- defaultMessage: currentError.message,
744
- values: extractValuesFromYupError(currentError?.type, currentError?.params)
745
- };
746
- }
747
- return acc;
748
- }, {});
749
710
  const initApi = contentManagerApi.injectEndpoints({
750
711
  endpoints: (builder) => ({
751
712
  getInitialData: builder.query({
@@ -759,27 +720,20 @@ const { useGetInitialDataQuery } = initApi;
759
720
  const useContentTypeSchema = (model) => {
760
721
  const { toggleNotification } = strapiAdmin.useNotification();
761
722
  const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
762
- const { components, contentType, contentTypes, error, isLoading, isFetching } = useGetInitialDataQuery(void 0, {
763
- selectFromResult: (res) => {
764
- const contentType2 = res.data?.contentTypes.find((ct) => ct.uid === model);
765
- const componentsByKey = res.data?.components.reduce(
766
- (acc, component) => {
767
- acc[component.uid] = component;
768
- return acc;
769
- },
770
- {}
771
- );
772
- const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
773
- return {
774
- isLoading: res.isLoading,
775
- isFetching: res.isFetching,
776
- error: res.error,
777
- components: Object.keys(components2).length === 0 ? void 0 : components2,
778
- contentType: contentType2,
779
- contentTypes: res.data?.contentTypes ?? []
780
- };
781
- }
782
- });
723
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
724
+ const { components, contentType, contentTypes } = React__namespace.useMemo(() => {
725
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
726
+ const componentsByKey = data?.components.reduce((acc, component) => {
727
+ acc[component.uid] = component;
728
+ return acc;
729
+ }, {});
730
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
731
+ return {
732
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
733
+ contentType: contentType2,
734
+ contentTypes: data?.contentTypes ?? []
735
+ };
736
+ }, [model, data]);
783
737
  React__namespace.useEffect(() => {
784
738
  if (error) {
785
739
  toggleNotification({
@@ -834,7 +788,10 @@ const useDocument = (args, opts) => {
834
788
  isLoading: isLoadingDocument,
835
789
  isFetching: isFetchingDocument,
836
790
  error
837
- } = useGetDocumentQuery(args, opts);
791
+ } = useGetDocumentQuery(args, {
792
+ ...opts,
793
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
794
+ });
838
795
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
839
796
  React__namespace.useEffect(() => {
840
797
  if (error) {
@@ -862,7 +819,7 @@ const useDocument = (args, opts) => {
862
819
  return null;
863
820
  } catch (error2) {
864
821
  if (error2 instanceof yup.ValidationError) {
865
- return getInnerErrors(error2);
822
+ return strapiAdmin.getYupValidationErrors(error2);
866
823
  }
867
824
  throw error2;
868
825
  }
@@ -958,14 +915,53 @@ const useDocumentActions = () => {
958
915
  },
959
916
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
960
917
  );
918
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
919
+ const deleteMany = React__namespace.useCallback(
920
+ async ({ model, documentIds, params }) => {
921
+ try {
922
+ trackUsage("willBulkDeleteEntries");
923
+ const res = await deleteManyDocuments({
924
+ model,
925
+ documentIds,
926
+ params
927
+ });
928
+ if ("error" in res) {
929
+ toggleNotification({
930
+ type: "danger",
931
+ message: formatAPIError(res.error)
932
+ });
933
+ return { error: res.error };
934
+ }
935
+ toggleNotification({
936
+ type: "success",
937
+ title: formatMessage({
938
+ id: getTranslation("success.records.delete"),
939
+ defaultMessage: "Successfully deleted."
940
+ }),
941
+ message: ""
942
+ });
943
+ trackUsage("didBulkDeleteEntries");
944
+ return res.data;
945
+ } catch (err) {
946
+ toggleNotification({
947
+ type: "danger",
948
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
949
+ });
950
+ trackUsage("didNotBulkDeleteEntries");
951
+ throw err;
952
+ }
953
+ },
954
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
955
+ );
961
956
  const [discardDocument] = useDiscardDocumentMutation();
962
957
  const discard = React__namespace.useCallback(
963
- async ({ collectionType, model, documentId }) => {
958
+ async ({ collectionType, model, documentId, params }) => {
964
959
  try {
965
960
  const res = await discardDocument({
966
961
  collectionType,
967
962
  model,
968
- documentId
963
+ documentId,
964
+ params
969
965
  });
970
966
  if ("error" in res) {
971
967
  toggleNotification({
@@ -1027,6 +1023,43 @@ const useDocumentActions = () => {
1027
1023
  },
1028
1024
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1029
1025
  );
1026
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1027
+ const publishMany = React__namespace.useCallback(
1028
+ async ({ model, documentIds, params }) => {
1029
+ try {
1030
+ const res = await publishManyDocuments({
1031
+ model,
1032
+ documentIds,
1033
+ params
1034
+ });
1035
+ if ("error" in res) {
1036
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1037
+ return { error: res.error };
1038
+ }
1039
+ toggleNotification({
1040
+ type: "success",
1041
+ message: formatMessage({
1042
+ id: getTranslation("success.record.publish"),
1043
+ defaultMessage: "Published document"
1044
+ })
1045
+ });
1046
+ return res.data;
1047
+ } catch (err) {
1048
+ toggleNotification({
1049
+ type: "danger",
1050
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1051
+ });
1052
+ throw err;
1053
+ }
1054
+ },
1055
+ [
1056
+ // trackUsage,
1057
+ publishManyDocuments,
1058
+ toggleNotification,
1059
+ formatMessage,
1060
+ formatAPIError
1061
+ ]
1062
+ );
1030
1063
  const [updateDocument] = useUpdateDocumentMutation();
1031
1064
  const update = React__namespace.useCallback(
1032
1065
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1101,6 +1134,41 @@ const useDocumentActions = () => {
1101
1134
  },
1102
1135
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1103
1136
  );
1137
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1138
+ const unpublishMany = React__namespace.useCallback(
1139
+ async ({ model, documentIds, params }) => {
1140
+ try {
1141
+ trackUsage("willBulkUnpublishEntries");
1142
+ const res = await unpublishManyDocuments({
1143
+ model,
1144
+ documentIds,
1145
+ params
1146
+ });
1147
+ if ("error" in res) {
1148
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1149
+ return { error: res.error };
1150
+ }
1151
+ trackUsage("didBulkUnpublishEntries");
1152
+ toggleNotification({
1153
+ type: "success",
1154
+ title: formatMessage({
1155
+ id: getTranslation("success.records.unpublish"),
1156
+ defaultMessage: "Successfully unpublished."
1157
+ }),
1158
+ message: ""
1159
+ });
1160
+ return res.data;
1161
+ } catch (err) {
1162
+ toggleNotification({
1163
+ type: "danger",
1164
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1165
+ });
1166
+ trackUsage("didNotBulkUnpublishEntries");
1167
+ throw err;
1168
+ }
1169
+ },
1170
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1171
+ );
1104
1172
  const [createDocument] = useCreateDocumentMutation();
1105
1173
  const create = React__namespace.useCallback(
1106
1174
  async ({ model, params }, data, trackerProperty) => {
@@ -1144,7 +1212,6 @@ const useDocumentActions = () => {
1144
1212
  sourceId
1145
1213
  });
1146
1214
  if ("error" in res) {
1147
- toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1148
1215
  return { error: res.error };
1149
1216
  }
1150
1217
  toggleNotification({
@@ -1214,15 +1281,18 @@ const useDocumentActions = () => {
1214
1281
  clone,
1215
1282
  create,
1216
1283
  delete: _delete,
1284
+ deleteMany,
1217
1285
  discard,
1218
1286
  getDocument,
1219
1287
  publish,
1288
+ publishMany,
1220
1289
  unpublish,
1290
+ unpublishMany,
1221
1291
  update
1222
1292
  };
1223
1293
  };
1224
1294
  const ProtectedHistoryPage = React.lazy(
1225
- () => Promise.resolve().then(() => require("./History-DeAPlvtv.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1295
+ () => Promise.resolve().then(() => require("./History-DNQkXANT.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
1226
1296
  );
1227
1297
  const routes$1 = [
1228
1298
  {
@@ -1235,31 +1305,31 @@ const routes$1 = [
1235
1305
  }
1236
1306
  ];
1237
1307
  const ProtectedEditViewPage = React.lazy(
1238
- () => Promise.resolve().then(() => require("./EditViewPage-DvNpQkam.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1308
+ () => Promise.resolve().then(() => require("./EditViewPage-C-ukDOB7.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
1239
1309
  );
1240
1310
  const ProtectedListViewPage = React.lazy(
1241
- () => Promise.resolve().then(() => require("./ListViewPage-5ySZ-VUs.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1311
+ () => Promise.resolve().then(() => require("./ListViewPage-BsLiH2-2.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
1242
1312
  );
1243
1313
  const ProtectedListConfiguration = React.lazy(
1244
- () => Promise.resolve().then(() => require("./ListConfigurationPage-DPCwW5Vr.js")).then((mod) => ({
1314
+ () => Promise.resolve().then(() => require("./ListConfigurationPage-CUQxfpjT.js")).then((mod) => ({
1245
1315
  default: mod.ProtectedListConfiguration
1246
1316
  }))
1247
1317
  );
1248
1318
  const ProtectedEditConfigurationPage = React.lazy(
1249
- () => Promise.resolve().then(() => require("./EditConfigurationPage-Dmv83RlS.js")).then((mod) => ({
1319
+ () => Promise.resolve().then(() => require("./EditConfigurationPage-Xp7lun0f.js")).then((mod) => ({
1250
1320
  default: mod.ProtectedEditConfigurationPage
1251
1321
  }))
1252
1322
  );
1253
1323
  const ProtectedComponentConfigurationPage = React.lazy(
1254
- () => Promise.resolve().then(() => require("./ComponentConfigurationPage-DjWJdz6Y.js")).then((mod) => ({
1324
+ () => Promise.resolve().then(() => require("./ComponentConfigurationPage-5ukroXAh.js")).then((mod) => ({
1255
1325
  default: mod.ProtectedComponentConfigurationPage
1256
1326
  }))
1257
1327
  );
1258
1328
  const NoPermissions = React.lazy(
1259
- () => Promise.resolve().then(() => require("./NoPermissionsPage-Dwu8rRJu.js")).then((mod) => ({ default: mod.NoPermissions }))
1329
+ () => Promise.resolve().then(() => require("./NoPermissionsPage-_lUqjGW3.js")).then((mod) => ({ default: mod.NoPermissions }))
1260
1330
  );
1261
1331
  const NoContentType = React.lazy(
1262
- () => Promise.resolve().then(() => require("./NoContentTypePage-DOC_yWOf.js")).then((mod) => ({ default: mod.NoContentType }))
1332
+ () => Promise.resolve().then(() => require("./NoContentTypePage-BZ-PnGAf.js")).then((mod) => ({ default: mod.NoContentType }))
1263
1333
  );
1264
1334
  const CollectionTypePages = () => {
1265
1335
  const { collectionType } = reactRouterDom.useParams();
@@ -1386,7 +1456,7 @@ const DocumentActionButton = (action) => {
1386
1456
  DocumentActionConfirmDialog,
1387
1457
  {
1388
1458
  ...action.dialog,
1389
- variant: action.variant,
1459
+ variant: action.dialog?.variant ?? action.variant,
1390
1460
  isOpen: dialogId === action.id,
1391
1461
  onClose: handleClose
1392
1462
  }
@@ -1449,7 +1519,7 @@ const DocumentActionsMenu = ({
1449
1519
  variant,
1450
1520
  children: [
1451
1521
  /* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
1452
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "span", children: label || formatMessage({
1522
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
1453
1523
  id: "content-manager.containers.edit.panels.default.more-actions",
1454
1524
  defaultMessage: "More document actions"
1455
1525
  }) })
@@ -1465,8 +1535,8 @@ const DocumentActionsMenu = ({
1465
1535
  onSelect: handleClick(action),
1466
1536
  display: "block",
1467
1537
  children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
1468
- /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, as: "span", children: [
1469
- action.icon,
1538
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1539
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1470
1540
  action.label
1471
1541
  ] }),
1472
1542
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
@@ -1527,6 +1597,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1527
1597
  return "primary600";
1528
1598
  }
1529
1599
  };
1600
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1601
+ switch (variant) {
1602
+ case "danger":
1603
+ return "danger600";
1604
+ case "secondary":
1605
+ return "neutral500";
1606
+ case "success":
1607
+ return "success600";
1608
+ default:
1609
+ return "primary600";
1610
+ }
1611
+ };
1530
1612
  const DocumentActionConfirmDialog = ({
1531
1613
  onClose,
1532
1614
  onCancel,
@@ -1549,61 +1631,42 @@ const DocumentActionConfirmDialog = ({
1549
1631
  }
1550
1632
  onClose();
1551
1633
  };
1552
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog, { isOpen, title, onClose: handleClose, children: [
1553
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.DialogBody, { children: content }),
1554
- /* @__PURE__ */ jsxRuntime.jsx(
1555
- designSystem.DialogFooter,
1556
- {
1557
- startAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1558
- id: "app.components.Button.cancel",
1559
- defaultMessage: "Cancel"
1560
- }) }),
1561
- endAction: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1562
- id: "app.components.Button.confirm",
1563
- defaultMessage: "Confirm"
1564
- }) })
1565
- }
1566
- )
1567
- ] });
1634
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
1635
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
1636
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
1637
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
1638
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
1639
+ id: "app.components.Button.cancel",
1640
+ defaultMessage: "Cancel"
1641
+ }) }) }),
1642
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
1643
+ id: "app.components.Button.confirm",
1644
+ defaultMessage: "Confirm"
1645
+ }) })
1646
+ ] })
1647
+ ] }) });
1568
1648
  };
1569
1649
  const DocumentActionModal = ({
1570
1650
  isOpen,
1571
1651
  title,
1572
1652
  onClose,
1573
1653
  footer: Footer,
1574
- content,
1654
+ content: Content,
1575
1655
  onModalClose
1576
1656
  }) => {
1577
- const id = React__namespace.useId();
1578
- if (!isOpen) {
1579
- return null;
1580
- }
1581
1657
  const handleClose = () => {
1582
1658
  if (onClose) {
1583
1659
  onClose();
1584
1660
  }
1585
1661
  onModalClose();
1586
1662
  };
1587
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1588
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalHeader, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", textColor: "neutral800", as: "h2", id, children: title }) }),
1589
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.ModalBody, { children: content }),
1590
- /* @__PURE__ */ jsxRuntime.jsx(
1591
- designSystem.Box,
1592
- {
1593
- paddingTop: 4,
1594
- paddingBottom: 4,
1595
- paddingLeft: 5,
1596
- paddingRight: 5,
1597
- borderWidth: "1px 0 0 0",
1598
- borderStyle: "solid",
1599
- borderColor: "neutral150",
1600
- background: "neutral100",
1601
- children: typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1602
- }
1603
- )
1604
- ] });
1663
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
1664
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
1665
+ typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
1666
+ typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
1667
+ ] }) });
1605
1668
  };
1606
- const PublishAction = ({
1669
+ const PublishAction$1 = ({
1607
1670
  activeTab,
1608
1671
  documentId,
1609
1672
  model,
@@ -1622,6 +1685,12 @@ const PublishAction = ({
1622
1685
  ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
1623
1686
  );
1624
1687
  const { publish } = useDocumentActions();
1688
+ const [
1689
+ countDraftRelations,
1690
+ { isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
1691
+ ] = useLazyGetDraftRelationCountQuery();
1692
+ const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
1693
+ const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
1625
1694
  const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
1626
1695
  const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
1627
1696
  const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
@@ -1630,13 +1699,104 @@ const PublishAction = ({
1630
1699
  const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
1631
1700
  const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
1632
1701
  const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
1633
- const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1634
- if (!schema?.options?.draftAndPublish) {
1635
- return null;
1636
- }
1637
- return {
1638
- /**
1639
- * Disabled when:
1702
+ React__namespace.useEffect(() => {
1703
+ if (isErrorDraftRelations) {
1704
+ toggleNotification({
1705
+ type: "danger",
1706
+ message: formatMessage({
1707
+ id: getTranslation("error.records.fetch-draft-relatons"),
1708
+ defaultMessage: "An error occurred while fetching draft relations on this document."
1709
+ })
1710
+ });
1711
+ }
1712
+ }, [isErrorDraftRelations, toggleNotification, formatMessage]);
1713
+ React__namespace.useEffect(() => {
1714
+ const localDraftRelations = /* @__PURE__ */ new Set();
1715
+ const extractDraftRelations = (data) => {
1716
+ const relations = data.connect || [];
1717
+ relations.forEach((relation) => {
1718
+ if (relation.status === "draft") {
1719
+ localDraftRelations.add(relation.id);
1720
+ }
1721
+ });
1722
+ };
1723
+ const traverseAndExtract = (data) => {
1724
+ Object.entries(data).forEach(([key, value]) => {
1725
+ if (key === "connect" && Array.isArray(value)) {
1726
+ extractDraftRelations({ connect: value });
1727
+ } else if (typeof value === "object" && value !== null) {
1728
+ traverseAndExtract(value);
1729
+ }
1730
+ });
1731
+ };
1732
+ if (!documentId || modified) {
1733
+ traverseAndExtract(formValues);
1734
+ setLocalCountOfDraftRelations(localDraftRelations.size);
1735
+ }
1736
+ }, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
1737
+ React__namespace.useEffect(() => {
1738
+ if (documentId) {
1739
+ const fetchDraftRelationsCount = async () => {
1740
+ const { data, error } = await countDraftRelations({
1741
+ collectionType,
1742
+ model,
1743
+ documentId,
1744
+ params
1745
+ });
1746
+ if (error) {
1747
+ throw error;
1748
+ }
1749
+ if (data) {
1750
+ setServerCountOfDraftRelations(data.data);
1751
+ }
1752
+ };
1753
+ fetchDraftRelationsCount();
1754
+ }
1755
+ }, [documentId, countDraftRelations, collectionType, model, params]);
1756
+ const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
1757
+ if (!schema?.options?.draftAndPublish) {
1758
+ return null;
1759
+ }
1760
+ const performPublish = async () => {
1761
+ setSubmitting(true);
1762
+ try {
1763
+ const { errors } = await validate();
1764
+ if (errors) {
1765
+ toggleNotification({
1766
+ type: "danger",
1767
+ message: formatMessage({
1768
+ id: "content-manager.validation.error",
1769
+ defaultMessage: "There are validation errors in your document. Please fix them before saving."
1770
+ })
1771
+ });
1772
+ return;
1773
+ }
1774
+ const res = await publish(
1775
+ {
1776
+ collectionType,
1777
+ model,
1778
+ documentId,
1779
+ params
1780
+ },
1781
+ formValues
1782
+ );
1783
+ if ("data" in res && collectionType !== SINGLE_TYPES) {
1784
+ navigate({
1785
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1786
+ search: rawQuery
1787
+ });
1788
+ } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1789
+ setErrors(formatValidationErrors(res.error));
1790
+ }
1791
+ } finally {
1792
+ setSubmitting(false);
1793
+ }
1794
+ };
1795
+ const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
1796
+ const hasDraftRelations = totalDraftRelations > 0;
1797
+ return {
1798
+ /**
1799
+ * Disabled when:
1640
1800
  * - currently if you're cloning a document we don't support publish & clone at the same time.
1641
1801
  * - the form is submitting
1642
1802
  * - the active tab is the published tab
@@ -1646,49 +1806,41 @@ const PublishAction = ({
1646
1806
  * - the user doesn't have the permission to create a new document
1647
1807
  * - the user doesn't have the permission to update the document
1648
1808
  */
1649
- disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1809
+ disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
1650
1810
  label: formatMessage({
1651
1811
  id: "app.utils.publish",
1652
1812
  defaultMessage: "Publish"
1653
1813
  }),
1654
1814
  onClick: async () => {
1655
- setSubmitting(true);
1656
- try {
1657
- const { errors } = await validate();
1658
- if (errors) {
1659
- toggleNotification({
1660
- type: "danger",
1661
- message: formatMessage({
1662
- id: "content-manager.validation.error",
1663
- defaultMessage: "There are validation errors in your document. Please fix them before saving."
1664
- })
1665
- });
1666
- return;
1667
- }
1668
- const res = await publish(
1669
- {
1670
- collectionType,
1671
- model,
1672
- documentId,
1673
- params
1674
- },
1675
- formValues
1676
- );
1677
- if ("data" in res && collectionType !== SINGLE_TYPES) {
1678
- navigate({
1679
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1680
- search: rawQuery
1681
- });
1682
- } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1683
- setErrors(formatValidationErrors(res.error));
1815
+ if (hasDraftRelations) {
1816
+ return;
1817
+ }
1818
+ await performPublish();
1819
+ },
1820
+ dialog: hasDraftRelations ? {
1821
+ type: "dialog",
1822
+ variant: "danger",
1823
+ footer: null,
1824
+ title: formatMessage({
1825
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
1826
+ defaultMessage: "Confirmation"
1827
+ }),
1828
+ content: formatMessage(
1829
+ {
1830
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
1831
+ defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
1832
+ },
1833
+ {
1834
+ count: totalDraftRelations
1684
1835
  }
1685
- } finally {
1686
- setSubmitting(false);
1836
+ ),
1837
+ onConfirm: async () => {
1838
+ await performPublish();
1687
1839
  }
1688
- }
1840
+ } : void 0
1689
1841
  };
1690
1842
  };
1691
- PublishAction.type = "publish";
1843
+ PublishAction$1.type = "publish";
1692
1844
  const UpdateAction = ({
1693
1845
  activeTab,
1694
1846
  documentId,
@@ -1753,10 +1905,13 @@ const UpdateAction = ({
1753
1905
  document
1754
1906
  );
1755
1907
  if ("data" in res) {
1756
- navigate({
1757
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1758
- search: rawQuery
1759
- });
1908
+ navigate(
1909
+ {
1910
+ pathname: `../${res.data.documentId}`,
1911
+ search: rawQuery
1912
+ },
1913
+ { relative: "path" }
1914
+ );
1760
1915
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1761
1916
  setErrors(formatValidationErrors(res.error));
1762
1917
  }
@@ -1784,10 +1939,13 @@ const UpdateAction = ({
1784
1939
  document
1785
1940
  );
1786
1941
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1787
- navigate({
1788
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1789
- search: rawQuery
1790
- });
1942
+ navigate(
1943
+ {
1944
+ pathname: `../${res.data.documentId}`,
1945
+ search: rawQuery
1946
+ },
1947
+ { replace: true, relative: "path" }
1948
+ );
1791
1949
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1792
1950
  setErrors(formatValidationErrors(res.error));
1793
1951
  }
@@ -1803,7 +1961,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1803
1961
  KEEP: "keep",
1804
1962
  DISCARD: "discard"
1805
1963
  };
1806
- const UnpublishAction = ({
1964
+ const UnpublishAction$1 = ({
1807
1965
  activeTab,
1808
1966
  documentId,
1809
1967
  model,
@@ -1819,10 +1977,8 @@ const UnpublishAction = ({
1819
1977
  const { toggleNotification } = strapiAdmin.useNotification();
1820
1978
  const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
1821
1979
  const isDocumentModified = document?.status === "modified";
1822
- const handleChange = (e) => {
1823
- if ("value" in e.target) {
1824
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1825
- }
1980
+ const handleChange = (value) => {
1981
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1826
1982
  };
1827
1983
  if (!schema?.options?.draftAndPublish) {
1828
1984
  return null;
@@ -1866,45 +2022,30 @@ const UnpublishAction = ({
1866
2022
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1867
2023
  /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
1868
2024
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1869
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2025
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1870
2026
  id: "content-manager.actions.unpublish.dialog.body",
1871
2027
  defaultMessage: "Are you sure?"
1872
2028
  }) })
1873
2029
  ] }),
1874
2030
  /* @__PURE__ */ jsxRuntime.jsxs(
1875
- designSystem.Flex,
2031
+ designSystem.Radio.Group,
1876
2032
  {
1877
- onChange: handleChange,
1878
- direction: "column",
1879
- alignItems: "flex-start",
1880
- as: "fieldset",
1881
- gap: 3,
2033
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
2034
+ name: "discard-options",
2035
+ "aria-label": formatMessage({
2036
+ id: "content-manager.actions.unpublish.dialog.radio-label",
2037
+ defaultMessage: "Choose an option to unpublish the document."
2038
+ }),
2039
+ onValueChange: handleChange,
1882
2040
  children: [
1883
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { as: "legend" }),
1884
- /* @__PURE__ */ jsxRuntime.jsx(
1885
- designSystem.Radio,
1886
- {
1887
- checked: shouldKeepDraft,
1888
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1889
- name: "discard-options",
1890
- children: formatMessage({
1891
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1892
- defaultMessage: "Keep draft"
1893
- })
1894
- }
1895
- ),
1896
- /* @__PURE__ */ jsxRuntime.jsx(
1897
- designSystem.Radio,
1898
- {
1899
- checked: !shouldKeepDraft,
1900
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1901
- name: "discard-options",
1902
- children: formatMessage({
1903
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1904
- defaultMessage: "Replace draft"
1905
- })
1906
- }
1907
- )
2041
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
2042
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
2043
+ defaultMessage: "Keep draft"
2044
+ }) }),
2045
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
2046
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
2047
+ defaultMessage: "Replace draft"
2048
+ }) })
1908
2049
  ]
1909
2050
  }
1910
2051
  )
@@ -1937,7 +2078,7 @@ const UnpublishAction = ({
1937
2078
  position: ["panel", "table-row"]
1938
2079
  };
1939
2080
  };
1940
- UnpublishAction.type = "unpublish";
2081
+ UnpublishAction$1.type = "unpublish";
1941
2082
  const DiscardAction = ({
1942
2083
  activeTab,
1943
2084
  documentId,
@@ -1971,7 +2112,7 @@ const DiscardAction = ({
1971
2112
  }),
1972
2113
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
1973
2114
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1974
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2115
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1975
2116
  id: "content-manager.actions.discard.dialog.body",
1976
2117
  defaultMessage: "Are you sure?"
1977
2118
  }) })
@@ -1988,12 +2129,12 @@ const DiscardAction = ({
1988
2129
  };
1989
2130
  };
1990
2131
  DiscardAction.type = "discard";
1991
- const StyledCrossCircle = styled__default.default(Icons.CrossCircle)`
2132
+ const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
1992
2133
  path {
1993
2134
  fill: currentColor;
1994
2135
  }
1995
2136
  `;
1996
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2137
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1997
2138
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1998
2139
  const RelativeTime = React__namespace.forwardRef(
1999
2140
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2041,7 +2182,7 @@ const getDisplayName = ({
2041
2182
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2042
2183
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2043
2184
  const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2044
- return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2185
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2045
2186
  };
2046
2187
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2047
2188
  const { formatMessage } = reactIntl.useIntl();
@@ -2050,23 +2191,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2050
2191
  id: "content-manager.containers.edit.title.new",
2051
2192
  defaultMessage: "Create an entry"
2052
2193
  }) : documentTitle;
2053
- return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 8, paddingBottom: 4, gap: 3, children: [
2194
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
2054
2195
  /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
2055
- /* @__PURE__ */ jsxRuntime.jsxs(
2056
- designSystem.Flex,
2057
- {
2058
- width: "100%",
2059
- justifyContent: "space-between",
2060
- paddingTop: 1,
2061
- gap: "80px",
2062
- alignItems: "flex-start",
2063
- children: [
2064
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", as: "h1", children: title }),
2065
- /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2066
- ]
2067
- }
2068
- ),
2069
- status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
2196
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
2197
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
2198
+ /* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
2199
+ ] }),
2200
+ status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
2070
2201
  ] });
2071
2202
  };
2072
2203
  const HeaderToolbar = () => {
@@ -2218,7 +2349,7 @@ const Information = ({ activeTab }) => {
2218
2349
  borderColor: "neutral150",
2219
2350
  direction: "column",
2220
2351
  marginTop: 2,
2221
- as: "dl",
2352
+ tag: "dl",
2222
2353
  padding: 5,
2223
2354
  gap: 3,
2224
2355
  alignItems: "flex-start",
@@ -2226,8 +2357,8 @@ const Information = ({ activeTab }) => {
2226
2357
  marginRight: "-0.4rem",
2227
2358
  width: "calc(100% + 8px)",
2228
2359
  children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2229
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2230
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2360
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2361
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2231
2362
  ] }, info.label))
2232
2363
  }
2233
2364
  );
@@ -2260,7 +2391,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2260
2391
  id: "app.links.configure-view",
2261
2392
  defaultMessage: "Configure the view"
2262
2393
  }),
2263
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCog, {}),
2394
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
2264
2395
  onClick: () => {
2265
2396
  navigate(`../${collectionType}/${model}/configurations/edit`);
2266
2397
  },
@@ -2268,11 +2399,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2268
2399
  };
2269
2400
  };
2270
2401
  ConfigureTheViewAction.type = "configure-the-view";
2271
- const StyledCog = styled__default.default(Icons.Cog)`
2272
- path {
2273
- fill: currentColor;
2274
- }
2275
- `;
2276
2402
  const EditTheModelAction = ({ model }) => {
2277
2403
  const navigate = reactRouterDom.useNavigate();
2278
2404
  const { formatMessage } = reactIntl.useIntl();
@@ -2281,7 +2407,7 @@ const EditTheModelAction = ({ model }) => {
2281
2407
  id: "content-manager.link-to-ctb",
2282
2408
  defaultMessage: "Edit the model"
2283
2409
  }),
2284
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledPencil$1, {}),
2410
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
2285
2411
  onClick: () => {
2286
2412
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2287
2413
  },
@@ -2289,12 +2415,7 @@ const EditTheModelAction = ({ model }) => {
2289
2415
  };
2290
2416
  };
2291
2417
  EditTheModelAction.type = "edit-the-model";
2292
- const StyledPencil$1 = styled__default.default(Icons.Pencil)`
2293
- path {
2294
- fill: currentColor;
2295
- }
2296
- `;
2297
- const DeleteAction = ({ documentId, model, collectionType, document }) => {
2418
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2298
2419
  const navigate = reactRouterDom.useNavigate();
2299
2420
  const { formatMessage } = reactIntl.useIntl();
2300
2421
  const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
@@ -2308,7 +2429,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2308
2429
  id: "content-manager.actions.delete.label",
2309
2430
  defaultMessage: "Delete document"
2310
2431
  }),
2311
- icon: /* @__PURE__ */ jsxRuntime.jsx(StyledTrash, {}),
2432
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
2312
2433
  dialog: {
2313
2434
  type: "dialog",
2314
2435
  title: formatMessage({
@@ -2317,7 +2438,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2317
2438
  }),
2318
2439
  content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
2319
2440
  /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2320
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2441
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2321
2442
  id: "content-manager.actions.delete.dialog.body",
2322
2443
  defaultMessage: "Are you sure?"
2323
2444
  }) })
@@ -2362,13 +2483,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2362
2483
  position: ["header", "table-row"]
2363
2484
  };
2364
2485
  };
2365
- DeleteAction.type = "delete";
2366
- const StyledTrash = styled__default.default(Icons.Trash)`
2367
- path {
2368
- fill: currentColor;
2369
- }
2370
- `;
2371
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2486
+ DeleteAction$1.type = "delete";
2487
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2372
2488
  const Panels = () => {
2373
2489
  const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
2374
2490
  const [
@@ -2442,7 +2558,7 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2442
2558
  designSystem.Flex,
2443
2559
  {
2444
2560
  ref,
2445
- as: "aside",
2561
+ tag: "aside",
2446
2562
  "aria-labelledby": "additional-information",
2447
2563
  background: "neutral0",
2448
2564
  borderColor: "neutral150",
@@ -2457,68 +2573,947 @@ const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
2457
2573
  justifyContent: "stretch",
2458
2574
  alignItems: "flex-start",
2459
2575
  children: [
2460
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2576
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2461
2577
  children
2462
2578
  ]
2463
2579
  }
2464
2580
  );
2465
2581
  });
2466
- const DEFAULT_BULK_ACTIONS = [];
2467
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2468
- const { formatMessage } = reactIntl.useIntl();
2469
- const getDefaultErrorMessage = (reason) => {
2470
- switch (reason) {
2471
- case "relation":
2472
- return "Duplicating the relation could remove it from the original entry.";
2473
- case "unique":
2474
- return "Identical values in a unique field are not allowed";
2475
- default:
2476
- return reason;
2477
- }
2582
+ const HOOKS = {
2583
+ /**
2584
+ * Hook that allows to mutate the displayed headers of the list view table
2585
+ * @constant
2586
+ * @type {string}
2587
+ */
2588
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2589
+ /**
2590
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2591
+ * @constant
2592
+ * @type {string}
2593
+ */
2594
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2595
+ /**
2596
+ * Hook that allows to mutate the CM's edit view layout
2597
+ * @constant
2598
+ * @type {string}
2599
+ */
2600
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2601
+ /**
2602
+ * Hook that allows to mutate the CM's single types links pre-set filters
2603
+ * @constant
2604
+ * @type {string}
2605
+ */
2606
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2607
+ };
2608
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2609
+ endpoints: (builder) => ({
2610
+ getContentTypeConfiguration: builder.query({
2611
+ query: (uid) => ({
2612
+ url: `/content-manager/content-types/${uid}/configuration`,
2613
+ method: "GET"
2614
+ }),
2615
+ transformResponse: (response) => response.data,
2616
+ providesTags: (_result, _error, uid) => [
2617
+ { type: "ContentTypesConfiguration", id: uid },
2618
+ { type: "ContentTypeSettings", id: "LIST" }
2619
+ ]
2620
+ }),
2621
+ getAllContentTypeSettings: builder.query({
2622
+ query: () => "/content-manager/content-types-settings",
2623
+ transformResponse: (response) => response.data,
2624
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2625
+ }),
2626
+ updateContentTypeConfiguration: builder.mutation({
2627
+ query: ({ uid, ...body }) => ({
2628
+ url: `/content-manager/content-types/${uid}/configuration`,
2629
+ method: "PUT",
2630
+ data: body
2631
+ }),
2632
+ transformResponse: (response) => response.data,
2633
+ invalidatesTags: (_result, _error, { uid }) => [
2634
+ { type: "ContentTypesConfiguration", id: uid },
2635
+ { type: "ContentTypeSettings", id: "LIST" },
2636
+ // Is this necessary?
2637
+ { type: "InitialData" }
2638
+ ]
2639
+ })
2640
+ })
2641
+ });
2642
+ const {
2643
+ useGetContentTypeConfigurationQuery,
2644
+ useGetAllContentTypeSettingsQuery,
2645
+ useUpdateContentTypeConfigurationMutation
2646
+ } = contentTypesApi;
2647
+ const checkIfAttributeIsDisplayable = (attribute) => {
2648
+ const { type } = attribute;
2649
+ if (type === "relation") {
2650
+ return !attribute.relation.toLowerCase().includes("morph");
2651
+ }
2652
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2653
+ };
2654
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2655
+ if (!mainFieldName) {
2656
+ return void 0;
2657
+ }
2658
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2659
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2660
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2661
+ );
2662
+ return {
2663
+ name: mainFieldName,
2664
+ type: mainFieldType ?? "string"
2478
2665
  };
2479
- return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2480
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
2481
- id: getTranslation("containers.list.autoCloneModal.title"),
2482
- defaultMessage: "This entry can't be duplicated directly."
2483
- }) }),
2484
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
2485
- id: getTranslation("containers.list.autoCloneModal.description"),
2486
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2487
- }) }) }),
2488
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxRuntime.jsxs(
2489
- designSystem.Flex,
2490
- {
2491
- direction: "column",
2492
- gap: 2,
2493
- alignItems: "flex-start",
2494
- borderColor: "neutral200",
2495
- hasRadius: true,
2496
- padding: 6,
2497
- children: [
2498
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "row", as: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { fontWeight: "semiBold", as: "li", children: [
2499
- pathSegment,
2500
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
2501
- Icons.ChevronRight,
2502
- {
2503
- fill: "neutral500",
2504
- height: "0.8rem",
2505
- width: "0.8rem",
2506
- style: { margin: "0 0.8rem" }
2507
- }
2508
- )
2509
- ] }, index2)) }),
2510
- /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { as: "p", textColor: "neutral600", children: formatMessage({
2511
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2512
- defaultMessage: getDefaultErrorMessage(reason)
2513
- }) })
2514
- ]
2515
- },
2516
- fieldPath.join()
2517
- )) })
2518
- ] });
2519
2666
  };
2520
- const TableActions = ({ document }) => {
2521
- const { formatMessage } = reactIntl.useIntl();
2667
+ const DEFAULT_SETTINGS = {
2668
+ bulkable: false,
2669
+ filterable: false,
2670
+ searchable: false,
2671
+ pagination: false,
2672
+ defaultSortBy: "",
2673
+ defaultSortOrder: "asc",
2674
+ mainField: "id",
2675
+ pageSize: 10
2676
+ };
2677
+ const useDocumentLayout = (model) => {
2678
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2679
+ const [{ query }] = strapiAdmin.useQueryParams();
2680
+ const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2681
+ const { toggleNotification } = strapiAdmin.useNotification();
2682
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2683
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2684
+ const {
2685
+ data,
2686
+ isLoading: isLoadingConfigs,
2687
+ error,
2688
+ isFetching: isFetchingConfigs
2689
+ } = useGetContentTypeConfigurationQuery(model);
2690
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2691
+ React__namespace.useEffect(() => {
2692
+ if (error) {
2693
+ toggleNotification({
2694
+ type: "danger",
2695
+ message: formatAPIError(error)
2696
+ });
2697
+ }
2698
+ }, [error, formatAPIError, toggleNotification]);
2699
+ const editLayout = React__namespace.useMemo(
2700
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2701
+ layout: [],
2702
+ components: {},
2703
+ metadatas: {},
2704
+ options: {},
2705
+ settings: DEFAULT_SETTINGS
2706
+ },
2707
+ [data, isLoading, schemas, schema, components]
2708
+ );
2709
+ const listLayout = React__namespace.useMemo(() => {
2710
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2711
+ layout: [],
2712
+ metadatas: {},
2713
+ options: {},
2714
+ settings: DEFAULT_SETTINGS
2715
+ };
2716
+ }, [data, isLoading, schemas, schema, components]);
2717
+ const { layout: edit } = React__namespace.useMemo(
2718
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2719
+ layout: editLayout,
2720
+ query
2721
+ }),
2722
+ [editLayout, query, runHookWaterfall]
2723
+ );
2724
+ return {
2725
+ error,
2726
+ isLoading,
2727
+ edit,
2728
+ list: listLayout
2729
+ };
2730
+ };
2731
+ const useDocLayout = () => {
2732
+ const { model } = useDoc();
2733
+ return useDocumentLayout(model);
2734
+ };
2735
+ const formatEditLayout = (data, {
2736
+ schemas,
2737
+ schema,
2738
+ components
2739
+ }) => {
2740
+ let currentPanelIndex = 0;
2741
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2742
+ data.contentType.layouts.edit,
2743
+ schema?.attributes,
2744
+ data.contentType.metadatas,
2745
+ { configurations: data.components, schemas: components },
2746
+ schemas
2747
+ ).reduce((panels, row) => {
2748
+ if (row.some((field) => field.type === "dynamiczone")) {
2749
+ panels.push([row]);
2750
+ currentPanelIndex += 2;
2751
+ } else {
2752
+ if (!panels[currentPanelIndex]) {
2753
+ panels.push([]);
2754
+ }
2755
+ panels[currentPanelIndex].push(row);
2756
+ }
2757
+ return panels;
2758
+ }, []);
2759
+ const componentEditAttributes = Object.entries(data.components).reduce(
2760
+ (acc, [uid, configuration]) => {
2761
+ acc[uid] = {
2762
+ layout: convertEditLayoutToFieldLayouts(
2763
+ configuration.layouts.edit,
2764
+ components[uid].attributes,
2765
+ configuration.metadatas
2766
+ ),
2767
+ settings: {
2768
+ ...configuration.settings,
2769
+ icon: components[uid].info.icon,
2770
+ displayName: components[uid].info.displayName
2771
+ }
2772
+ };
2773
+ return acc;
2774
+ },
2775
+ {}
2776
+ );
2777
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2778
+ (acc, [attribute, metadata]) => {
2779
+ return {
2780
+ ...acc,
2781
+ [attribute]: metadata.edit
2782
+ };
2783
+ },
2784
+ {}
2785
+ );
2786
+ return {
2787
+ layout: panelledEditAttributes,
2788
+ components: componentEditAttributes,
2789
+ metadatas: editMetadatas,
2790
+ settings: {
2791
+ ...data.contentType.settings,
2792
+ displayName: schema?.info.displayName
2793
+ },
2794
+ options: {
2795
+ ...schema?.options,
2796
+ ...schema?.pluginOptions,
2797
+ ...data.contentType.options
2798
+ }
2799
+ };
2800
+ };
2801
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2802
+ return rows.map(
2803
+ (row) => row.map((field) => {
2804
+ const attribute = attributes[field.name];
2805
+ if (!attribute) {
2806
+ return null;
2807
+ }
2808
+ const { edit: metadata } = metadatas[field.name];
2809
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2810
+ return {
2811
+ attribute,
2812
+ disabled: !metadata.editable,
2813
+ hint: metadata.description,
2814
+ label: metadata.label ?? "",
2815
+ name: field.name,
2816
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2817
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2818
+ schemas,
2819
+ components: components?.schemas ?? {}
2820
+ }),
2821
+ placeholder: metadata.placeholder ?? "",
2822
+ required: attribute.required ?? false,
2823
+ size: field.size,
2824
+ unique: "unique" in attribute ? attribute.unique : false,
2825
+ visible: metadata.visible ?? true,
2826
+ type: attribute.type
2827
+ };
2828
+ }).filter((field) => field !== null)
2829
+ );
2830
+ };
2831
+ const formatListLayout = (data, {
2832
+ schemas,
2833
+ schema,
2834
+ components
2835
+ }) => {
2836
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2837
+ (acc, [attribute, metadata]) => {
2838
+ return {
2839
+ ...acc,
2840
+ [attribute]: metadata.list
2841
+ };
2842
+ },
2843
+ {}
2844
+ );
2845
+ const listAttributes = convertListLayoutToFieldLayouts(
2846
+ data.contentType.layouts.list,
2847
+ schema?.attributes,
2848
+ listMetadatas,
2849
+ { configurations: data.components, schemas: components },
2850
+ schemas
2851
+ );
2852
+ return {
2853
+ layout: listAttributes,
2854
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2855
+ metadatas: listMetadatas,
2856
+ options: {
2857
+ ...schema?.options,
2858
+ ...schema?.pluginOptions,
2859
+ ...data.contentType.options
2860
+ }
2861
+ };
2862
+ };
2863
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2864
+ return columns.map((name) => {
2865
+ const attribute = attributes[name];
2866
+ if (!attribute) {
2867
+ return null;
2868
+ }
2869
+ const metadata = metadatas[name];
2870
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2871
+ return {
2872
+ attribute,
2873
+ label: metadata.label ?? "",
2874
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2875
+ schemas,
2876
+ components: components?.schemas ?? {}
2877
+ }),
2878
+ name,
2879
+ searchable: metadata.searchable ?? true,
2880
+ sortable: metadata.sortable ?? true
2881
+ };
2882
+ }).filter((field) => field !== null);
2883
+ };
2884
+ const ConfirmBulkActionDialog = ({
2885
+ onToggleDialog,
2886
+ isOpen = false,
2887
+ dialogBody,
2888
+ endAction
2889
+ }) => {
2890
+ const { formatMessage } = reactIntl.useIntl();
2891
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
2892
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
2893
+ id: "app.components.ConfirmDialog.title",
2894
+ defaultMessage: "Confirmation"
2895
+ }) }),
2896
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2897
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2898
+ dialogBody
2899
+ ] }) }),
2900
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
2901
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2902
+ id: "app.components.Button.cancel",
2903
+ defaultMessage: "Cancel"
2904
+ }) }) }),
2905
+ endAction
2906
+ ] })
2907
+ ] }) });
2908
+ };
2909
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
2910
+ const ConfirmDialogPublishAll = ({
2911
+ isOpen,
2912
+ onToggleDialog,
2913
+ isConfirmButtonLoading = false,
2914
+ onConfirm
2915
+ }) => {
2916
+ const { formatMessage } = reactIntl.useIntl();
2917
+ const selectedEntries = strapiAdmin.useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2918
+ const { toggleNotification } = strapiAdmin.useNotification();
2919
+ const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
2920
+ const { model, schema } = useDoc();
2921
+ const [{ query }] = strapiAdmin.useQueryParams();
2922
+ const {
2923
+ data: countDraftRelations = 0,
2924
+ isLoading,
2925
+ error
2926
+ } = useGetManyDraftRelationCountQuery(
2927
+ {
2928
+ model,
2929
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2930
+ locale: query?.plugins?.i18n?.locale
2931
+ },
2932
+ {
2933
+ skip: selectedEntries.length === 0
2934
+ }
2935
+ );
2936
+ React__namespace.useEffect(() => {
2937
+ if (error) {
2938
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2939
+ }
2940
+ }, [error, formatAPIError, toggleNotification]);
2941
+ if (error) {
2942
+ return null;
2943
+ }
2944
+ return /* @__PURE__ */ jsxRuntime.jsx(
2945
+ ConfirmBulkActionDialog,
2946
+ {
2947
+ isOpen: isOpen && !isLoading,
2948
+ onToggleDialog,
2949
+ dialogBody: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
2950
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: [
2951
+ countDraftRelations > 0 && formatMessage(
2952
+ {
2953
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2954
+ 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. "
2955
+ },
2956
+ {
2957
+ b: BoldChunk$1,
2958
+ count: countDraftRelations,
2959
+ entities: selectedEntries.length
2960
+ }
2961
+ ),
2962
+ formatMessage({
2963
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2964
+ defaultMessage: "Are you sure you want to publish these entries?"
2965
+ })
2966
+ ] }),
2967
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2968
+ {
2969
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2970
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2971
+ },
2972
+ {
2973
+ em: Emphasis
2974
+ }
2975
+ ) })
2976
+ ] }),
2977
+ endAction: /* @__PURE__ */ jsxRuntime.jsx(
2978
+ designSystem.Button,
2979
+ {
2980
+ onClick: onConfirm,
2981
+ variant: "secondary",
2982
+ startIcon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Check, {}),
2983
+ loading: isConfirmButtonLoading,
2984
+ children: formatMessage({
2985
+ id: "app.utils.publish",
2986
+ defaultMessage: "Publish"
2987
+ })
2988
+ }
2989
+ )
2990
+ }
2991
+ );
2992
+ };
2993
+ const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
2994
+ max-width: 300px;
2995
+ `;
2996
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2997
+ const messages = [];
2998
+ Object.entries(errors).forEach(([key, value]) => {
2999
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
3000
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
3001
+ if ("id" in value && "defaultMessage" in value) {
3002
+ messages.push(
3003
+ formatMessage(
3004
+ {
3005
+ id: `${value.id}.withField`,
3006
+ defaultMessage: value.defaultMessage
3007
+ },
3008
+ { field: currentKey }
3009
+ )
3010
+ );
3011
+ } else {
3012
+ messages.push(
3013
+ ...formatErrorMessages(
3014
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
3015
+ value,
3016
+ currentKey,
3017
+ formatMessage
3018
+ )
3019
+ );
3020
+ }
3021
+ } else {
3022
+ messages.push(
3023
+ formatMessage(
3024
+ {
3025
+ id: `${value}.withField`,
3026
+ defaultMessage: value
3027
+ },
3028
+ { field: currentKey }
3029
+ )
3030
+ );
3031
+ }
3032
+ });
3033
+ return messages;
3034
+ };
3035
+ const EntryValidationText = ({ validationErrors, status }) => {
3036
+ const { formatMessage } = reactIntl.useIntl();
3037
+ if (validationErrors) {
3038
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
3039
+ " "
3040
+ );
3041
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3042
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
3043
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsxRuntime.jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
3044
+ ] });
3045
+ }
3046
+ if (status === "published") {
3047
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3048
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3049
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
3050
+ id: "content-manager.bulk-publish.already-published",
3051
+ defaultMessage: "Already Published"
3052
+ }) })
3053
+ ] });
3054
+ }
3055
+ if (status === "modified") {
3056
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3057
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
3058
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3059
+ id: "content-manager.bulk-publish.modified",
3060
+ defaultMessage: "Ready to publish changes"
3061
+ }) })
3062
+ ] });
3063
+ }
3064
+ return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3065
+ /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
3066
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3067
+ id: "app.utils.ready-to-publish",
3068
+ defaultMessage: "Ready to publish"
3069
+ }) })
3070
+ ] });
3071
+ };
3072
+ const TABLE_HEADERS = [
3073
+ { name: "id", label: "id" },
3074
+ { name: "name", label: "name" },
3075
+ { name: "status", label: "status" },
3076
+ { name: "publicationStatus", label: "Publication status" }
3077
+ ];
3078
+ const SelectedEntriesTableContent = ({
3079
+ isPublishing,
3080
+ rowsToDisplay = [],
3081
+ entriesToPublish = [],
3082
+ validationErrors = {}
3083
+ }) => {
3084
+ const { pathname } = reactRouterDom.useLocation();
3085
+ const { formatMessage } = reactIntl.useIntl();
3086
+ const {
3087
+ list: {
3088
+ settings: { mainField }
3089
+ }
3090
+ } = useDocLayout();
3091
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3092
+ return /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Content, { children: [
3093
+ /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Head, { children: [
3094
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCheckboxCell, {}),
3095
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3096
+ (head) => /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.HeaderCell, { ...head }, head.name)
3097
+ )
3098
+ ] }),
3099
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
3100
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
3101
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
3102
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
3103
+ shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
3104
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3105
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3106
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: formatMessage({
3107
+ id: "content-manager.success.record.publishing",
3108
+ defaultMessage: "Publishing..."
3109
+ }) }),
3110
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Loader, { small: true })
3111
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx(
3112
+ EntryValidationText,
3113
+ {
3114
+ validationErrors: validationErrors[row.documentId],
3115
+ status: row.status
3116
+ }
3117
+ ) }),
3118
+ /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
3119
+ designSystem.IconButton,
3120
+ {
3121
+ tag: reactRouterDom.Link,
3122
+ to: {
3123
+ pathname: `${pathname}/${row.documentId}`,
3124
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3125
+ },
3126
+ state: { from: pathname },
3127
+ label: formatMessage(
3128
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3129
+ {
3130
+ target: formatMessage(
3131
+ {
3132
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3133
+ defaultMessage: "item line {number}"
3134
+ },
3135
+ { number: index2 + 1 }
3136
+ )
3137
+ }
3138
+ ),
3139
+ target: "_blank",
3140
+ marginLeft: "auto",
3141
+ children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {})
3142
+ }
3143
+ ) })
3144
+ ] }, row.id)) })
3145
+ ] });
3146
+ };
3147
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
3148
+ const SelectedEntriesModalContent = ({
3149
+ listViewSelectedEntries,
3150
+ toggleModal,
3151
+ setListViewSelectedDocuments,
3152
+ model
3153
+ }) => {
3154
+ const { formatMessage } = reactIntl.useIntl();
3155
+ const { schema, components } = useContentTypeSchema(model);
3156
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3157
+ const [{ query }] = strapiAdmin.useQueryParams();
3158
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3159
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3160
+ {
3161
+ model,
3162
+ params: {
3163
+ page: "1",
3164
+ pageSize: documentIds.length.toString(),
3165
+ sort: query.sort,
3166
+ filters: {
3167
+ documentId: {
3168
+ $in: documentIds
3169
+ }
3170
+ },
3171
+ locale: query.plugins?.i18n?.locale
3172
+ }
3173
+ },
3174
+ {
3175
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3176
+ }
3177
+ );
3178
+ const { rows, validationErrors } = React__namespace.useMemo(() => {
3179
+ if (data.length > 0 && schema) {
3180
+ const validate = createYupSchema(schema.attributes, components);
3181
+ const validationErrors2 = {};
3182
+ const rows2 = data.map((entry) => {
3183
+ try {
3184
+ validate.validateSync(entry, { abortEarly: false });
3185
+ return entry;
3186
+ } catch (e) {
3187
+ if (e instanceof yup.ValidationError) {
3188
+ validationErrors2[entry.documentId] = strapiAdmin.getYupValidationErrors(e);
3189
+ }
3190
+ return entry;
3191
+ }
3192
+ });
3193
+ return { rows: rows2, validationErrors: validationErrors2 };
3194
+ }
3195
+ return {
3196
+ rows: [],
3197
+ validationErrors: {}
3198
+ };
3199
+ }, [components, data, schema]);
3200
+ const [publishedCount, setPublishedCount] = React__namespace.useState(0);
3201
+ const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
3202
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3203
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3204
+ const selectedRows = strapiAdmin.useTable("publishAction", (state) => state.selectedRows);
3205
+ const selectedEntries = rows.filter(
3206
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3207
+ );
3208
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3209
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3210
+ ({ documentId }) => validationErrors[documentId]
3211
+ ).length;
3212
+ const selectedEntriesPublished = selectedEntries.filter(
3213
+ ({ status }) => status === "published"
3214
+ ).length;
3215
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3216
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3217
+ const handleConfirmBulkPublish = async () => {
3218
+ toggleDialog();
3219
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3220
+ if (!("error" in res)) {
3221
+ setPublishedCount(res.count);
3222
+ const unpublishedEntries = rows.filter((row) => {
3223
+ return !entriesToPublish.includes(row.documentId);
3224
+ });
3225
+ setListViewSelectedDocuments(unpublishedEntries);
3226
+ }
3227
+ };
3228
+ const getFormattedCountMessage = () => {
3229
+ if (publishedCount) {
3230
+ return formatMessage(
3231
+ {
3232
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3233
+ 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."
3234
+ },
3235
+ {
3236
+ publishedCount,
3237
+ withErrorsCount: selectedEntriesWithErrorsCount,
3238
+ b: BoldChunk
3239
+ }
3240
+ );
3241
+ }
3242
+ return formatMessage(
3243
+ {
3244
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3245
+ 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."
3246
+ },
3247
+ {
3248
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3249
+ withErrorsCount: selectedEntriesWithErrorsCount,
3250
+ alreadyPublishedCount: selectedEntriesPublished,
3251
+ b: BoldChunk
3252
+ }
3253
+ );
3254
+ };
3255
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3256
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
3257
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: getFormattedCountMessage() }),
3258
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 5, children: /* @__PURE__ */ jsxRuntime.jsx(
3259
+ SelectedEntriesTableContent,
3260
+ {
3261
+ isPublishing: isSubmittingForm,
3262
+ rowsToDisplay: rows,
3263
+ entriesToPublish,
3264
+ validationErrors
3265
+ }
3266
+ ) })
3267
+ ] }),
3268
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
3269
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3270
+ id: "app.components.Button.cancel",
3271
+ defaultMessage: "Cancel"
3272
+ }) }),
3273
+ /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
3274
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3275
+ /* @__PURE__ */ jsxRuntime.jsx(
3276
+ designSystem.Button,
3277
+ {
3278
+ onClick: toggleDialog,
3279
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3280
+ loading: isSubmittingForm,
3281
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3282
+ }
3283
+ )
3284
+ ] })
3285
+ ] }),
3286
+ /* @__PURE__ */ jsxRuntime.jsx(
3287
+ ConfirmDialogPublishAll,
3288
+ {
3289
+ isOpen: isDialogOpen,
3290
+ onToggleDialog: toggleDialog,
3291
+ isConfirmButtonLoading: isSubmittingForm,
3292
+ onConfirm: handleConfirmBulkPublish
3293
+ }
3294
+ )
3295
+ ] });
3296
+ };
3297
+ const PublishAction = ({ documents, model }) => {
3298
+ const { formatMessage } = reactIntl.useIntl();
3299
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3300
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3301
+ const setListViewSelectedDocuments = strapiAdmin.useTable("publishAction", (state) => state.selectRow);
3302
+ const refetchList = () => {
3303
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3304
+ };
3305
+ if (!showPublishButton)
3306
+ return null;
3307
+ return {
3308
+ actionType: "publish",
3309
+ variant: "tertiary",
3310
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3311
+ dialog: {
3312
+ type: "modal",
3313
+ title: formatMessage({
3314
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3315
+ defaultMessage: "Publish entries"
3316
+ }),
3317
+ content: ({ onClose }) => {
3318
+ return /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsxRuntime.jsx(
3319
+ SelectedEntriesModalContent,
3320
+ {
3321
+ listViewSelectedEntries: documents,
3322
+ toggleModal: () => {
3323
+ onClose();
3324
+ refetchList();
3325
+ },
3326
+ setListViewSelectedDocuments,
3327
+ model
3328
+ }
3329
+ ) });
3330
+ },
3331
+ onClose: () => {
3332
+ refetchList();
3333
+ }
3334
+ }
3335
+ };
3336
+ };
3337
+ const BulkActionsRenderer = () => {
3338
+ const plugins = strapiAdmin.useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3339
+ const { model, collectionType } = useDoc();
3340
+ const { selectedRows } = strapiAdmin.useTable("BulkActionsRenderer", (state) => state);
3341
+ return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
3342
+ strapiAdmin.DescriptionComponentRenderer,
3343
+ {
3344
+ props: {
3345
+ model,
3346
+ collectionType,
3347
+ documents: selectedRows
3348
+ },
3349
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3350
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...action }, action.id))
3351
+ }
3352
+ ) });
3353
+ };
3354
+ const DeleteAction = ({ documents, model }) => {
3355
+ const { formatMessage } = reactIntl.useIntl();
3356
+ const { schema: contentType } = useDoc();
3357
+ const selectRow = strapiAdmin.useTable("DeleteAction", (state) => state.selectRow);
3358
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3359
+ const [{ query }] = strapiAdmin.useQueryParams();
3360
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3361
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3362
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3363
+ const documentIds = documents.map(({ documentId }) => documentId);
3364
+ const handleConfirmBulkDelete = async () => {
3365
+ const res = await bulkDeleteAction({
3366
+ documentIds,
3367
+ model,
3368
+ params
3369
+ });
3370
+ if (!("error" in res)) {
3371
+ selectRow([]);
3372
+ }
3373
+ };
3374
+ if (!hasDeletePermission)
3375
+ return null;
3376
+ return {
3377
+ variant: "danger-light",
3378
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3379
+ dialog: {
3380
+ type: "dialog",
3381
+ title: formatMessage({
3382
+ id: "app.components.ConfirmDialog.title",
3383
+ defaultMessage: "Confirmation"
3384
+ }),
3385
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3386
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3387
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3388
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3389
+ defaultMessage: "Are you sure you want to delete these entries?"
3390
+ }) }),
3391
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3392
+ {
3393
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3394
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3395
+ },
3396
+ {
3397
+ em: Emphasis
3398
+ }
3399
+ ) }) })
3400
+ ] }),
3401
+ onConfirm: handleConfirmBulkDelete
3402
+ }
3403
+ };
3404
+ };
3405
+ DeleteAction.type = "delete";
3406
+ const UnpublishAction = ({ documents, model }) => {
3407
+ const { formatMessage } = reactIntl.useIntl();
3408
+ const { schema } = useDoc();
3409
+ const selectRow = strapiAdmin.useTable("UnpublishAction", (state) => state.selectRow);
3410
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3411
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3412
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3413
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3414
+ const documentIds = documents.map(({ documentId }) => documentId);
3415
+ const [{ query }] = strapiAdmin.useQueryParams();
3416
+ const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
3417
+ const handleConfirmBulkUnpublish = async () => {
3418
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3419
+ if (!("error" in data)) {
3420
+ selectRow([]);
3421
+ }
3422
+ };
3423
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3424
+ if (!showUnpublishButton)
3425
+ return null;
3426
+ return {
3427
+ variant: "tertiary",
3428
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3429
+ dialog: {
3430
+ type: "dialog",
3431
+ title: formatMessage({
3432
+ id: "app.components.ConfirmDialog.title",
3433
+ defaultMessage: "Confirmation"
3434
+ }),
3435
+ content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3436
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "center", children: /* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3437
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3438
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3439
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3440
+ }) }),
3441
+ hasI18nEnabled && /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "danger500", children: formatMessage(
3442
+ {
3443
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3444
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3445
+ },
3446
+ {
3447
+ em: Emphasis
3448
+ }
3449
+ ) }) })
3450
+ ] }),
3451
+ confirmButton: formatMessage({
3452
+ id: "app.utils.unpublish",
3453
+ defaultMessage: "Unpublish"
3454
+ }),
3455
+ onConfirm: handleConfirmBulkUnpublish
3456
+ }
3457
+ };
3458
+ };
3459
+ UnpublishAction.type = "unpublish";
3460
+ const Emphasis = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3461
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3462
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3463
+ const { formatMessage } = reactIntl.useIntl();
3464
+ const getDefaultErrorMessage = (reason) => {
3465
+ switch (reason) {
3466
+ case "relation":
3467
+ return "Duplicating the relation could remove it from the original entry.";
3468
+ case "unique":
3469
+ return "Identical values in a unique field are not allowed";
3470
+ default:
3471
+ return reason;
3472
+ }
3473
+ };
3474
+ return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
3475
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "beta", children: formatMessage({
3476
+ id: getTranslation("containers.list.autoCloneModal.title"),
3477
+ defaultMessage: "This entry can't be duplicated directly."
3478
+ }) }),
3479
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 2, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { textColor: "neutral600", children: formatMessage({
3480
+ id: getTranslation("containers.list.autoCloneModal.description"),
3481
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3482
+ }) }) }),
3483
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxRuntime.jsxs(
3484
+ designSystem.Flex,
3485
+ {
3486
+ direction: "column",
3487
+ gap: 2,
3488
+ alignItems: "flex-start",
3489
+ borderColor: "neutral200",
3490
+ hasRadius: true,
3491
+ padding: 6,
3492
+ children: [
3493
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Typography, { fontWeight: "semiBold", tag: "li", children: [
3494
+ pathSegment,
3495
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsxRuntime.jsx(
3496
+ Icons.ChevronRight,
3497
+ {
3498
+ fill: "neutral500",
3499
+ height: "0.8rem",
3500
+ width: "0.8rem",
3501
+ style: { margin: "0 0.8rem" }
3502
+ }
3503
+ )
3504
+ ] }, index2)) }),
3505
+ /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3506
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3507
+ defaultMessage: getDefaultErrorMessage(reason)
3508
+ }) })
3509
+ ]
3510
+ },
3511
+ fieldPath.join()
3512
+ )) })
3513
+ ] });
3514
+ };
3515
+ const TableActions = ({ document }) => {
3516
+ const { formatMessage } = reactIntl.useIntl();
2522
3517
  const { model, collectionType } = useDoc();
2523
3518
  const plugins = strapiAdmin.useStrapiApp("TableActions", (state) => state.plugins);
2524
3519
  const props = {
@@ -2591,7 +3586,7 @@ const EditAction = ({ documentId }) => {
2591
3586
  };
2592
3587
  };
2593
3588
  EditAction.type = "edit";
2594
- const StyledPencil = styled__default.default(Icons.Pencil)`
3589
+ const StyledPencil = styledComponents.styled(Icons.Pencil)`
2595
3590
  path {
2596
3591
  fill: currentColor;
2597
3592
  }
@@ -2651,7 +3646,7 @@ const CloneAction = ({ model, documentId }) => {
2651
3646
  /* @__PURE__ */ jsxRuntime.jsx(
2652
3647
  designSystem.LinkButton,
2653
3648
  {
2654
- as: reactRouterDom.NavLink,
3649
+ tag: reactRouterDom.NavLink,
2655
3650
  to: {
2656
3651
  pathname: `clone/${documentId}`
2657
3652
  },
@@ -2667,7 +3662,7 @@ const CloneAction = ({ model, documentId }) => {
2667
3662
  };
2668
3663
  };
2669
3664
  CloneAction.type = "clone";
2670
- const StyledDuplicate = styled__default.default(Icons.Duplicate)`
3665
+ const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
2671
3666
  path {
2672
3667
  fill: currentColor;
2673
3668
  }
@@ -2684,442 +3679,183 @@ class ContentManagerPlugin {
2684
3679
  documentActions = [
2685
3680
  ...DEFAULT_ACTIONS,
2686
3681
  ...DEFAULT_TABLE_ROW_ACTIONS,
2687
- ...DEFAULT_HEADER_ACTIONS,
2688
- HistoryAction
3682
+ ...DEFAULT_HEADER_ACTIONS
2689
3683
  ];
2690
3684
  editViewSidePanels = [ActionsPanel];
2691
3685
  headerActions = [];
2692
3686
  constructor() {
2693
3687
  }
2694
- addEditViewSidePanel(panels) {
2695
- if (Array.isArray(panels)) {
2696
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2697
- } else if (typeof panels === "function") {
2698
- this.editViewSidePanels = panels(this.editViewSidePanels);
2699
- } else {
2700
- throw new Error(
2701
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2702
- panels
2703
- )}`
2704
- );
2705
- }
2706
- }
2707
- addDocumentAction(actions2) {
2708
- if (Array.isArray(actions2)) {
2709
- this.documentActions = [...this.documentActions, ...actions2];
2710
- } else if (typeof actions2 === "function") {
2711
- this.documentActions = actions2(this.documentActions);
2712
- } else {
2713
- throw new Error(
2714
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2715
- actions2
2716
- )}`
2717
- );
2718
- }
2719
- }
2720
- addDocumentHeaderAction(actions2) {
2721
- if (Array.isArray(actions2)) {
2722
- this.headerActions = [...this.headerActions, ...actions2];
2723
- } else if (typeof actions2 === "function") {
2724
- this.headerActions = actions2(this.headerActions);
3688
+ addEditViewSidePanel(panels) {
3689
+ if (Array.isArray(panels)) {
3690
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3691
+ } else if (typeof panels === "function") {
3692
+ this.editViewSidePanels = panels(this.editViewSidePanels);
2725
3693
  } else {
2726
3694
  throw new Error(
2727
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2728
- actions2
3695
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3696
+ panels
2729
3697
  )}`
2730
3698
  );
2731
3699
  }
2732
3700
  }
2733
- addBulkAction(actions2) {
3701
+ addDocumentAction(actions2) {
2734
3702
  if (Array.isArray(actions2)) {
2735
- this.bulkActions = [...this.bulkActions, ...actions2];
3703
+ this.documentActions = [...this.documentActions, ...actions2];
2736
3704
  } else if (typeof actions2 === "function") {
2737
- this.bulkActions = actions2(this.bulkActions);
3705
+ this.documentActions = actions2(this.documentActions);
2738
3706
  } else {
2739
3707
  throw new Error(
2740
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3708
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2741
3709
  actions2
2742
3710
  )}`
2743
- );
2744
- }
2745
- }
2746
- get config() {
2747
- return {
2748
- id: PLUGIN_ID,
2749
- name: "Content Manager",
2750
- injectionZones: INJECTION_ZONES,
2751
- apis: {
2752
- addBulkAction: this.addBulkAction.bind(this),
2753
- addDocumentAction: this.addDocumentAction.bind(this),
2754
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
2755
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
2756
- getBulkActions: () => this.bulkActions,
2757
- getDocumentActions: () => this.documentActions,
2758
- getEditViewSidePanels: () => this.editViewSidePanels,
2759
- getHeaderActions: () => this.headerActions
2760
- }
2761
- };
2762
- }
2763
- }
2764
- const getPrintableType = (value) => {
2765
- const nativeType = typeof value;
2766
- if (nativeType === "object") {
2767
- if (value === null)
2768
- return "null";
2769
- if (Array.isArray(value))
2770
- return "array";
2771
- if (value instanceof Object && value.constructor.name !== "Object") {
2772
- return value.constructor.name;
2773
- }
2774
- }
2775
- return nativeType;
2776
- };
2777
- const initialState = {
2778
- collectionTypeLinks: [],
2779
- components: [],
2780
- fieldSizes: {},
2781
- models: [],
2782
- singleTypeLinks: [],
2783
- isLoading: true
2784
- };
2785
- const appSlice = toolkit.createSlice({
2786
- name: "app",
2787
- initialState,
2788
- reducers: {
2789
- setInitialData(state, action) {
2790
- const {
2791
- authorizedCollectionTypeLinks,
2792
- authorizedSingleTypeLinks,
2793
- components,
2794
- contentTypeSchemas,
2795
- fieldSizes
2796
- } = action.payload;
2797
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
2798
- ({ isDisplayed }) => isDisplayed
2799
- );
2800
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
2801
- state.components = components;
2802
- state.models = contentTypeSchemas;
2803
- state.fieldSizes = fieldSizes;
2804
- state.isLoading = false;
2805
- }
2806
- }
2807
- });
2808
- const { actions, reducer: reducer$1 } = appSlice;
2809
- const { setInitialData } = actions;
2810
- const reducer = toolkit.combineReducers({
2811
- app: reducer$1
2812
- });
2813
- const HOOKS = {
2814
- /**
2815
- * Hook that allows to mutate the displayed headers of the list view table
2816
- * @constant
2817
- * @type {string}
2818
- */
2819
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2820
- /**
2821
- * Hook that allows to mutate the CM's collection types links pre-set filters
2822
- * @constant
2823
- * @type {string}
2824
- */
2825
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2826
- /**
2827
- * Hook that allows to mutate the CM's edit view layout
2828
- * @constant
2829
- * @type {string}
2830
- */
2831
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2832
- /**
2833
- * Hook that allows to mutate the CM's single types links pre-set filters
2834
- * @constant
2835
- * @type {string}
2836
- */
2837
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2838
- };
2839
- const contentTypesApi = contentManagerApi.injectEndpoints({
2840
- endpoints: (builder) => ({
2841
- getContentTypeConfiguration: builder.query({
2842
- query: (uid) => ({
2843
- url: `/content-manager/content-types/${uid}/configuration`,
2844
- method: "GET"
2845
- }),
2846
- transformResponse: (response) => response.data,
2847
- providesTags: (_result, _error, uid) => [
2848
- { type: "ContentTypesConfiguration", id: uid },
2849
- { type: "ContentTypeSettings", id: "LIST" }
2850
- ]
2851
- }),
2852
- getAllContentTypeSettings: builder.query({
2853
- query: () => "/content-manager/content-types-settings",
2854
- transformResponse: (response) => response.data,
2855
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2856
- }),
2857
- updateContentTypeConfiguration: builder.mutation({
2858
- query: ({ uid, ...body }) => ({
2859
- url: `/content-manager/content-types/${uid}/configuration`,
2860
- method: "PUT",
2861
- data: body
2862
- }),
2863
- transformResponse: (response) => response.data,
2864
- invalidatesTags: (_result, _error, { uid }) => [
2865
- { type: "ContentTypesConfiguration", id: uid },
2866
- { type: "ContentTypeSettings", id: "LIST" },
2867
- // Is this necessary?
2868
- { type: "InitialData" }
2869
- ]
2870
- })
2871
- })
2872
- });
2873
- const {
2874
- useGetContentTypeConfigurationQuery,
2875
- useGetAllContentTypeSettingsQuery,
2876
- useUpdateContentTypeConfigurationMutation
2877
- } = contentTypesApi;
2878
- const checkIfAttributeIsDisplayable = (attribute) => {
2879
- const { type } = attribute;
2880
- if (type === "relation") {
2881
- return !attribute.relation.toLowerCase().includes("morph");
2882
- }
2883
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2884
- };
2885
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2886
- if (!mainFieldName) {
2887
- return void 0;
2888
- }
2889
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2890
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2891
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2892
- );
2893
- return {
2894
- name: mainFieldName,
2895
- type: mainFieldType ?? "string"
2896
- };
2897
- };
2898
- const DEFAULT_SETTINGS = {
2899
- bulkable: false,
2900
- filterable: false,
2901
- searchable: false,
2902
- pagination: false,
2903
- defaultSortBy: "",
2904
- defaultSortOrder: "asc",
2905
- mainField: "id",
2906
- pageSize: 10
2907
- };
2908
- const useDocumentLayout = (model) => {
2909
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2910
- const [{ query }] = strapiAdmin.useQueryParams();
2911
- const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2912
- const { toggleNotification } = strapiAdmin.useNotification();
2913
- const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
2914
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2915
- const {
2916
- data,
2917
- isLoading: isLoadingConfigs,
2918
- error,
2919
- isFetching: isFetchingConfigs
2920
- } = useGetContentTypeConfigurationQuery(model);
2921
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2922
- React__namespace.useEffect(() => {
2923
- if (error) {
2924
- toggleNotification({
2925
- type: "danger",
2926
- message: formatAPIError(error)
2927
- });
2928
- }
2929
- }, [error, formatAPIError, toggleNotification]);
2930
- const editLayout = React__namespace.useMemo(
2931
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2932
- layout: [],
2933
- components: {},
2934
- metadatas: {},
2935
- options: {},
2936
- settings: DEFAULT_SETTINGS
2937
- },
2938
- [data, isLoading, schemas, schema, components]
2939
- );
2940
- const listLayout = React__namespace.useMemo(() => {
2941
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2942
- layout: [],
2943
- metadatas: {},
2944
- options: {},
2945
- settings: DEFAULT_SETTINGS
2946
- };
2947
- }, [data, isLoading, schemas, schema, components]);
2948
- const { layout: edit } = React__namespace.useMemo(
2949
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2950
- layout: editLayout,
2951
- query
2952
- }),
2953
- [editLayout, query, runHookWaterfall]
2954
- );
2955
- return {
2956
- error,
2957
- isLoading,
2958
- edit,
2959
- list: listLayout
2960
- };
2961
- };
2962
- const useDocLayout = () => {
2963
- const { model } = useDoc();
2964
- return useDocumentLayout(model);
2965
- };
2966
- const formatEditLayout = (data, {
2967
- schemas,
2968
- schema,
2969
- components
2970
- }) => {
2971
- let currentPanelIndex = 0;
2972
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2973
- data.contentType.layouts.edit,
2974
- schema?.attributes,
2975
- data.contentType.metadatas,
2976
- { configurations: data.components, schemas: components },
2977
- schemas
2978
- ).reduce((panels, row) => {
2979
- if (row.some((field) => field.type === "dynamiczone")) {
2980
- panels.push([row]);
2981
- currentPanelIndex += 2;
3711
+ );
3712
+ }
3713
+ }
3714
+ addDocumentHeaderAction(actions2) {
3715
+ if (Array.isArray(actions2)) {
3716
+ this.headerActions = [...this.headerActions, ...actions2];
3717
+ } else if (typeof actions2 === "function") {
3718
+ this.headerActions = actions2(this.headerActions);
2982
3719
  } else {
2983
- if (!panels[currentPanelIndex]) {
2984
- panels.push([]);
2985
- }
2986
- panels[currentPanelIndex].push(row);
3720
+ throw new Error(
3721
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3722
+ actions2
3723
+ )}`
3724
+ );
2987
3725
  }
2988
- return panels;
2989
- }, []);
2990
- const componentEditAttributes = Object.entries(data.components).reduce(
2991
- (acc, [uid, configuration]) => {
2992
- acc[uid] = {
2993
- layout: convertEditLayoutToFieldLayouts(
2994
- configuration.layouts.edit,
2995
- components[uid].attributes,
2996
- configuration.metadatas
2997
- ),
2998
- settings: {
2999
- ...configuration.settings,
3000
- icon: components[uid].info.icon,
3001
- displayName: components[uid].info.displayName
3002
- }
3003
- };
3004
- return acc;
3005
- },
3006
- {}
3007
- );
3008
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
3009
- (acc, [attribute, metadata]) => {
3010
- return {
3011
- ...acc,
3012
- [attribute]: metadata.edit
3013
- };
3014
- },
3015
- {}
3016
- );
3017
- return {
3018
- layout: panelledEditAttributes,
3019
- components: componentEditAttributes,
3020
- metadatas: editMetadatas,
3021
- settings: {
3022
- ...data.contentType.settings,
3023
- displayName: schema?.info.displayName
3024
- },
3025
- options: {
3026
- ...schema?.options,
3027
- ...schema?.pluginOptions,
3028
- ...data.contentType.options
3726
+ }
3727
+ addBulkAction(actions2) {
3728
+ if (Array.isArray(actions2)) {
3729
+ this.bulkActions = [...this.bulkActions, ...actions2];
3730
+ } else if (typeof actions2 === "function") {
3731
+ this.bulkActions = actions2(this.bulkActions);
3732
+ } else {
3733
+ throw new Error(
3734
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3735
+ actions2
3736
+ )}`
3737
+ );
3029
3738
  }
3030
- };
3031
- };
3032
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3033
- return rows.map(
3034
- (row) => row.map((field) => {
3035
- const attribute = attributes[field.name];
3036
- if (!attribute) {
3037
- return null;
3739
+ }
3740
+ get config() {
3741
+ return {
3742
+ id: PLUGIN_ID,
3743
+ name: "Content Manager",
3744
+ injectionZones: INJECTION_ZONES,
3745
+ apis: {
3746
+ addBulkAction: this.addBulkAction.bind(this),
3747
+ addDocumentAction: this.addDocumentAction.bind(this),
3748
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3749
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3750
+ getBulkActions: () => this.bulkActions,
3751
+ getDocumentActions: () => this.documentActions,
3752
+ getEditViewSidePanels: () => this.editViewSidePanels,
3753
+ getHeaderActions: () => this.headerActions
3038
3754
  }
3039
- const { edit: metadata } = metadatas[field.name];
3040
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3041
- return {
3042
- attribute,
3043
- disabled: !metadata.editable,
3044
- hint: metadata.description,
3045
- label: metadata.label ?? "",
3046
- name: field.name,
3047
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3048
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3049
- schemas,
3050
- components: components?.schemas ?? {}
3051
- }),
3052
- placeholder: metadata.placeholder ?? "",
3053
- required: attribute.required ?? false,
3054
- size: field.size,
3055
- unique: "unique" in attribute ? attribute.unique : false,
3056
- visible: metadata.visible ?? true,
3057
- type: attribute.type
3058
- };
3059
- }).filter((field) => field !== null)
3060
- );
3755
+ };
3756
+ }
3757
+ }
3758
+ const getPrintableType = (value) => {
3759
+ const nativeType = typeof value;
3760
+ if (nativeType === "object") {
3761
+ if (value === null)
3762
+ return "null";
3763
+ if (Array.isArray(value))
3764
+ return "array";
3765
+ if (value instanceof Object && value.constructor.name !== "Object") {
3766
+ return value.constructor.name;
3767
+ }
3768
+ }
3769
+ return nativeType;
3061
3770
  };
3062
- const formatListLayout = (data, {
3063
- schemas,
3064
- schema,
3065
- components
3066
- }) => {
3067
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3068
- (acc, [attribute, metadata]) => {
3069
- return {
3070
- ...acc,
3071
- [attribute]: metadata.list
3072
- };
3073
- },
3074
- {}
3075
- );
3076
- const listAttributes = convertListLayoutToFieldLayouts(
3077
- data.contentType.layouts.list,
3078
- schema?.attributes,
3079
- listMetadatas,
3080
- { configurations: data.components, schemas: components },
3081
- schemas
3082
- );
3771
+ const HistoryAction = ({ model, document }) => {
3772
+ const { formatMessage } = reactIntl.useIntl();
3773
+ const [{ query }] = strapiAdmin.useQueryParams();
3774
+ const navigate = reactRouterDom.useNavigate();
3775
+ const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
3776
+ if (!window.strapi.features.isEnabled("cms-content-history")) {
3777
+ return null;
3778
+ }
3083
3779
  return {
3084
- layout: listAttributes,
3085
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3086
- metadatas: listMetadatas,
3087
- options: {
3088
- ...schema?.options,
3089
- ...schema?.pluginOptions,
3090
- ...data.contentType.options
3091
- }
3780
+ icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
3781
+ label: formatMessage({
3782
+ id: "content-manager.history.document-action",
3783
+ defaultMessage: "Content History"
3784
+ }),
3785
+ onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
3786
+ disabled: (
3787
+ /**
3788
+ * The user is creating a new document.
3789
+ * It hasn't been saved yet, so there's no history to go to
3790
+ */
3791
+ !document || /**
3792
+ * The document has been created but the current dimension has never been saved.
3793
+ * For example, the user is creating a new locale in an existing document,
3794
+ * so there's no history for the document in that locale
3795
+ */
3796
+ !document.id || /**
3797
+ * History is only available for content types created by the user.
3798
+ * These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
3799
+ * which start with `admin::` or `plugin::`
3800
+ */
3801
+ !model.startsWith("api::")
3802
+ ),
3803
+ position: "header"
3092
3804
  };
3093
3805
  };
3094
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3095
- return columns.map((name) => {
3096
- const attribute = attributes[name];
3097
- if (!attribute) {
3098
- return null;
3099
- }
3100
- const metadata = metadatas[name];
3101
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3102
- return {
3103
- attribute,
3104
- label: metadata.label ?? "",
3105
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3106
- schemas,
3107
- components: components?.schemas ?? {}
3108
- }),
3109
- name,
3110
- searchable: metadata.searchable ?? true,
3111
- sortable: metadata.sortable ?? true
3112
- };
3113
- }).filter((field) => field !== null);
3806
+ HistoryAction.type = "history";
3807
+ const historyAdmin = {
3808
+ bootstrap(app) {
3809
+ const { addDocumentAction } = app.getPlugin("content-manager").apis;
3810
+ addDocumentAction((actions2) => {
3811
+ const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
3812
+ actions2.splice(indexOfDeleteAction, 0, HistoryAction);
3813
+ return actions2;
3814
+ });
3815
+ }
3816
+ };
3817
+ const initialState = {
3818
+ collectionTypeLinks: [],
3819
+ components: [],
3820
+ fieldSizes: {},
3821
+ models: [],
3822
+ singleTypeLinks: [],
3823
+ isLoading: true
3114
3824
  };
3825
+ const appSlice = toolkit.createSlice({
3826
+ name: "app",
3827
+ initialState,
3828
+ reducers: {
3829
+ setInitialData(state, action) {
3830
+ const {
3831
+ authorizedCollectionTypeLinks,
3832
+ authorizedSingleTypeLinks,
3833
+ components,
3834
+ contentTypeSchemas,
3835
+ fieldSizes
3836
+ } = action.payload;
3837
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3838
+ ({ isDisplayed }) => isDisplayed
3839
+ );
3840
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3841
+ state.components = components;
3842
+ state.models = contentTypeSchemas;
3843
+ state.fieldSizes = fieldSizes;
3844
+ state.isLoading = false;
3845
+ }
3846
+ }
3847
+ });
3848
+ const { actions, reducer: reducer$1 } = appSlice;
3849
+ const { setInitialData } = actions;
3850
+ const reducer = toolkit.combineReducers({
3851
+ app: reducer$1
3852
+ });
3115
3853
  const index = {
3116
3854
  register(app) {
3117
3855
  const cm = new ContentManagerPlugin();
3118
3856
  app.addReducers({
3119
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3120
3857
  [PLUGIN_ID]: reducer
3121
3858
  });
3122
- app.addMiddlewares([() => contentManagerApi.middleware]);
3123
3859
  app.addMenuLink({
3124
3860
  to: PLUGIN_ID,
3125
3861
  icon: Icons.Feather,
@@ -3128,14 +3864,29 @@ const index = {
3128
3864
  defaultMessage: "Content Manager"
3129
3865
  },
3130
3866
  permissions: [],
3131
- Component: () => Promise.resolve().then(() => require("./layout-B_SXLhqf.js")).then((mod) => ({ default: mod.Layout }))
3867
+ position: 1
3868
+ });
3869
+ app.router.addRoute({
3870
+ path: "content-manager/*",
3871
+ lazy: async () => {
3872
+ const { Layout } = await Promise.resolve().then(() => require("./layout-Ci7qHlFb.js"));
3873
+ return {
3874
+ Component: Layout
3875
+ };
3876
+ },
3877
+ children: routes
3132
3878
  });
3133
3879
  app.registerPlugin(cm.config);
3134
3880
  },
3881
+ bootstrap(app) {
3882
+ if (typeof historyAdmin.bootstrap === "function") {
3883
+ historyAdmin.bootstrap(app);
3884
+ }
3885
+ },
3135
3886
  async registerTrads({ locales }) {
3136
3887
  const importedTrads = await Promise.all(
3137
3888
  locales.map((locale) => {
3138
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-C-V1_90f.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3889
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-uOUIxfcQ.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
3139
3890
  return {
3140
3891
  data: prefixPluginTranslations(data, PLUGIN_ID),
3141
3892
  locale
@@ -3152,6 +3903,7 @@ const index = {
3152
3903
  }
3153
3904
  };
3154
3905
  exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
3906
+ exports.BulkActionsRenderer = BulkActionsRenderer;
3155
3907
  exports.COLLECTION_TYPES = COLLECTION_TYPES;
3156
3908
  exports.CREATOR_FIELDS = CREATOR_FIELDS;
3157
3909
  exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
@@ -3178,7 +3930,6 @@ exports.getDisplayName = getDisplayName;
3178
3930
  exports.getMainField = getMainField;
3179
3931
  exports.getTranslation = getTranslation;
3180
3932
  exports.index = index;
3181
- exports.routes = routes;
3182
3933
  exports.setInitialData = setInitialData;
3183
3934
  exports.useContentTypeSchema = useContentTypeSchema;
3184
3935
  exports.useDoc = useDoc;
@@ -3192,4 +3943,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
3192
3943
  exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
3193
3944
  exports.useGetInitialDataQuery = useGetInitialDataQuery;
3194
3945
  exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
3195
- //# sourceMappingURL=index-C6AH2hEl.js.map
3946
+ //# sourceMappingURL=index-OerGjbAN.js.map