@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.2a7cb5ff33df35e8ccde5ef918f9f9a4a3ee9a08

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 (170) hide show
  1. package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
  2. package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
  3. package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
  4. package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
  5. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-BvHtG7uH.js} +3 -3
  6. package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-BvHtG7uH.js.map} +1 -1
  7. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs → ComponentConfigurationPage-DHNM3YBz.mjs} +3 -3
  8. package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-DHNM3YBz.mjs.map} +1 -1
  9. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  10. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  11. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  12. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  13. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs → EditConfigurationPage-Cp6HAEzN.mjs} +3 -3
  14. package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-Cp6HAEzN.mjs.map} +1 -1
  15. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-DOmfCEMo.js} +3 -3
  16. package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-DOmfCEMo.js.map} +1 -1
  17. package/dist/_chunks/{EditViewPage-KRG56aCq.js → EditViewPage-BqNpC6hO.js} +46 -48
  18. package/dist/_chunks/EditViewPage-BqNpC6hO.js.map +1 -0
  19. package/dist/_chunks/{EditViewPage-aUnqL-63.mjs → EditViewPage-BtkEx339.mjs} +47 -47
  20. package/dist/_chunks/EditViewPage-BtkEx339.mjs.map +1 -0
  21. package/dist/_chunks/{Field-kVFO4ZKB.mjs → Field-R5NbffTB.mjs} +854 -707
  22. package/dist/_chunks/Field-R5NbffTB.mjs.map +1 -0
  23. package/dist/_chunks/{Field-kq1c2TF1.js → Field-lsPFnAmH.js} +906 -760
  24. package/dist/_chunks/Field-lsPFnAmH.js.map +1 -0
  25. package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-BHmXSfyy.mjs} +39 -37
  26. package/dist/_chunks/Form-BHmXSfyy.mjs.map +1 -0
  27. package/dist/_chunks/{Form-CQ67ZifP.js → Form-CcGboku8.js} +39 -38
  28. package/dist/_chunks/Form-CcGboku8.js.map +1 -0
  29. package/dist/_chunks/{History-BLEnudTX.js → History-Bsud8jwh.js} +138 -51
  30. package/dist/_chunks/History-Bsud8jwh.js.map +1 -0
  31. package/dist/_chunks/{History-DKhZAPcK.mjs → History-ByUPL3T3.mjs} +137 -49
  32. package/dist/_chunks/History-ByUPL3T3.mjs.map +1 -0
  33. package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bm5HACXf.mjs} +49 -51
  34. package/dist/_chunks/ListConfigurationPage-Bm5HACXf.mjs.map +1 -0
  35. package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-DiT463qx.js} +53 -56
  36. package/dist/_chunks/ListConfigurationPage-DiT463qx.js.map +1 -0
  37. package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-CsrC9L_d.js} +92 -108
  38. package/dist/_chunks/ListViewPage-CsrC9L_d.js.map +1 -0
  39. package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-JSyNAAYu.mjs} +87 -103
  40. package/dist/_chunks/ListViewPage-JSyNAAYu.mjs.map +1 -0
  41. package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Bsvng4II.js} +3 -3
  42. package/dist/_chunks/NoContentTypePage-Bsvng4II.js.map +1 -0
  43. package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CsrQUpBE.mjs} +3 -3
  44. package/dist/_chunks/NoContentTypePage-CsrQUpBE.mjs.map +1 -0
  45. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CdHNJtEf.js} +2 -2
  46. package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CdHNJtEf.js.map} +1 -1
  47. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-DNmf_pj0.mjs} +2 -2
  48. package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-DNmf_pj0.mjs.map} +1 -1
  49. package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CghaPv2D.js} +70 -61
  50. package/dist/_chunks/Relations-CghaPv2D.js.map +1 -0
  51. package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-u8-37jK0.mjs} +66 -56
  52. package/dist/_chunks/Relations-u8-37jK0.mjs.map +1 -0
  53. package/dist/_chunks/{en-MBPul9Su.mjs → en-Ux26r5pl.mjs} +7 -1
  54. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-Ux26r5pl.mjs.map} +1 -1
  55. package/dist/_chunks/{en-C-V1_90f.js → en-fbKQxLGn.js} +7 -1
  56. package/dist/_chunks/{en-C-V1_90f.js.map → en-fbKQxLGn.js.map} +1 -1
  57. package/dist/_chunks/{index-DNa1J4HE.js → index-BOZx6IMg.js} +1481 -864
  58. package/dist/_chunks/index-BOZx6IMg.js.map +1 -0
  59. package/dist/_chunks/{index-CAc9yTnx.mjs → index-CaE6NG4a.mjs} +1450 -832
  60. package/dist/_chunks/index-CaE6NG4a.mjs.map +1 -0
  61. package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-Bx7svTbY.mjs} +28 -23
  62. package/dist/_chunks/layout-Bx7svTbY.mjs.map +1 -0
  63. package/dist/_chunks/{layout-BqtLA6Lb.js → layout-Ciz224q5.js} +29 -26
  64. package/dist/_chunks/layout-Ciz224q5.js.map +1 -0
  65. package/dist/_chunks/{relations-BHY_KDJ_.js → relations-CP8sB2YZ.js} +2 -2
  66. package/dist/_chunks/{relations-BHY_KDJ_.js.map → relations-CP8sB2YZ.js.map} +1 -1
  67. package/dist/_chunks/{relations-mMFEcZRq.mjs → relations-Cxc1cEv3.mjs} +2 -2
  68. package/dist/_chunks/{relations-mMFEcZRq.mjs.map → relations-Cxc1cEv3.mjs.map} +1 -1
  69. package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
  70. package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
  71. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  72. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  73. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  74. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  75. package/dist/admin/index.js +2 -1
  76. package/dist/admin/index.js.map +1 -1
  77. package/dist/admin/index.mjs +5 -4
  78. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  79. package/dist/admin/src/content-manager.d.ts +3 -3
  80. package/dist/admin/src/exports.d.ts +1 -0
  81. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  82. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  83. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  84. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  85. package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
  86. package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
  87. package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
  88. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +10 -4
  89. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  90. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
  91. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  92. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  93. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  94. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +10 -18
  95. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  96. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
  97. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  98. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +59 -52
  99. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  100. package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
  101. package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
  102. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  103. package/dist/admin/src/services/api.d.ts +2 -3
  104. package/dist/admin/src/services/components.d.ts +2 -2
  105. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  106. package/dist/admin/src/services/documents.d.ts +29 -17
  107. package/dist/admin/src/services/init.d.ts +2 -2
  108. package/dist/admin/src/services/relations.d.ts +3 -3
  109. package/dist/admin/src/services/uid.d.ts +3 -3
  110. package/dist/admin/src/utils/api.d.ts +4 -18
  111. package/dist/admin/src/utils/validation.d.ts +1 -6
  112. package/dist/server/index.js +293 -203
  113. package/dist/server/index.js.map +1 -1
  114. package/dist/server/index.mjs +295 -205
  115. package/dist/server/index.mjs.map +1 -1
  116. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  117. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  118. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  119. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  120. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  121. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  122. package/dist/server/src/controllers/validation/index.d.ts +1 -1
  123. package/dist/server/src/history/services/history.d.ts.map +1 -1
  124. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  125. package/dist/server/src/history/services/utils.d.ts.map +1 -1
  126. package/dist/server/src/index.d.ts +17 -33
  127. package/dist/server/src/index.d.ts.map +1 -1
  128. package/dist/server/src/services/document-manager.d.ts +11 -6
  129. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  130. package/dist/server/src/services/document-metadata.d.ts +8 -29
  131. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  132. package/dist/server/src/services/index.d.ts +17 -33
  133. package/dist/server/src/services/index.d.ts.map +1 -1
  134. package/dist/server/src/services/utils/populate.d.ts +8 -1
  135. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  136. package/dist/shared/contracts/collection-types.d.ts +14 -6
  137. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  138. package/dist/shared/contracts/relations.d.ts +2 -2
  139. package/dist/shared/contracts/relations.d.ts.map +1 -1
  140. package/package.json +13 -14
  141. package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
  142. package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
  143. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  144. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  145. package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
  146. package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
  147. package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
  148. package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
  149. package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
  150. package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
  151. package/dist/_chunks/History-BLEnudTX.js.map +0 -1
  152. package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
  153. package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
  154. package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
  155. package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
  156. package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
  157. package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
  158. package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
  159. package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
  160. package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
  161. package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
  162. package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
  163. package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
  164. package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
  165. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  166. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  167. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  168. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  169. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  170. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -1,17 +1,15 @@
1
- import { ClockCounterClockwise, CrossCircle, More, WarningCircle, Cog, Pencil, Trash, ChevronRight, Duplicate, Feather } from "@strapi/icons";
1
+ import { ClockCounterClockwise, CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, Feather } from "@strapi/icons";
2
2
  import { jsx, Fragment, jsxs } from "react/jsx-runtime";
3
- import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, getFetchClient, translatedErrors, useNotification, useAPIErrorHandler, useTracking, useForm, BackButton, DescriptionComponentRenderer } from "@strapi/admin/strapi-admin";
3
+ import { useStrapiApp, useQueryParams, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
4
4
  import { stringify } from "qs";
5
5
  import { useIntl } from "react-intl";
6
- import { useNavigate, useParams, Navigate, useMatch, NavLink } from "react-router-dom";
6
+ import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
7
7
  import * as React from "react";
8
8
  import { lazy } from "react";
9
- import { Menu, VisuallyHidden, Flex, Typography, Dialog, DialogBody, DialogFooter, Button, ModalLayout, ModalHeader, ModalBody, Box, Radio, Status, SingleSelect, SingleSelectOption, LinkButton } from "@strapi/design-system";
10
- import styled from "styled-components";
9
+ import { Button, Menu, VisuallyHidden, Flex, Box, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
10
+ import { styled } from "styled-components";
11
11
  import * as yup from "yup";
12
12
  import { ValidationError } from "yup";
13
- import { createApi } from "@reduxjs/toolkit/query/react";
14
- import { isAxiosError } from "axios";
15
13
  import pipe from "lodash/fp/pipe";
16
14
  import { intervalToDuration, isPast } from "date-fns";
17
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
@@ -157,9 +155,8 @@ const DocumentRBAC = ({ children, permissions }) => {
157
155
  const name = removeNumericalStrings(fieldName.split("."));
158
156
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
159
157
  if (fieldType === "component") {
160
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
161
- return componentOrDynamicZoneFields.some((field) => {
162
- return field.includes(fieldName);
158
+ return componentFieldNames.some((field) => {
159
+ return field.includes(name.join("."));
163
160
  });
164
161
  }
165
162
  if (name.length > 1) {
@@ -189,78 +186,8 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
189
186
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
190
187
  );
191
188
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
192
- const buildValidParams = (query) => {
193
- if (!query)
194
- return query;
195
- const { plugins: _, ...validQueryParams } = {
196
- ...query,
197
- ...Object.values(query?.plugins ?? {}).reduce(
198
- (acc, current) => Object.assign(acc, current),
199
- {}
200
- )
201
- };
202
- if ("_q" in validQueryParams) {
203
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
204
- }
205
- return validQueryParams;
206
- };
207
- const axiosBaseQuery = () => async (query, { signal }) => {
208
- try {
209
- const { get, post, del, put } = getFetchClient();
210
- if (typeof query === "string") {
211
- const result = await get(query, { signal });
212
- return { data: result.data };
213
- } else {
214
- const { url, method = "GET", data, config } = query;
215
- if (method === "POST") {
216
- const result2 = await post(url, data, { ...config, signal });
217
- return { data: result2.data };
218
- }
219
- if (method === "DELETE") {
220
- const result2 = await del(url, { ...config, signal });
221
- return { data: result2.data };
222
- }
223
- if (method === "PUT") {
224
- const result2 = await put(url, data, { ...config, signal });
225
- return { data: result2.data };
226
- }
227
- const result = await get(url, { ...config, signal });
228
- return { data: result.data };
229
- }
230
- } catch (err) {
231
- if (isAxiosError(err)) {
232
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
233
- return { data: void 0, error: err.response?.data.error };
234
- } else {
235
- return {
236
- data: void 0,
237
- error: {
238
- name: "UnknownError",
239
- message: "There was an unknown error response from the API",
240
- details: err.response?.data,
241
- status: err.response?.status
242
- }
243
- };
244
- }
245
- }
246
- const error = err;
247
- return {
248
- data: void 0,
249
- error: {
250
- name: error.name,
251
- message: error.message,
252
- stack: error.stack
253
- }
254
- };
255
- }
256
- };
257
- const isBaseQueryError = (error) => {
258
- return error.name !== void 0;
259
- };
260
- const contentManagerApi = createApi({
261
- reducerPath: "contentManagerApi",
262
- baseQuery: axiosBaseQuery(),
263
- tagTypes: [
189
+ const contentManagerApi = adminApi.enhanceEndpoints({
190
+ addTagTypes: [
264
191
  "ComponentConfiguration",
265
192
  "ContentTypesConfiguration",
266
193
  "ContentTypeSettings",
@@ -268,10 +195,10 @@ const contentManagerApi = createApi({
268
195
  "InitialData",
269
196
  "HistoryVersion",
270
197
  "Relations"
271
- ],
272
- endpoints: () => ({})
198
+ ]
273
199
  });
274
200
  const documentApi = contentManagerApi.injectEndpoints({
201
+ overrideExisting: true,
275
202
  endpoints: (builder) => ({
276
203
  autoCloneDocument: builder.mutation({
277
204
  query: ({ model, sourceId, query }) => ({
@@ -325,12 +252,15 @@ const documentApi = contentManagerApi.injectEndpoints({
325
252
  ]
326
253
  }),
327
254
  deleteManyDocuments: builder.mutation({
328
- query: ({ model, ...body }) => ({
255
+ query: ({ model, params, ...body }) => ({
329
256
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
330
257
  method: "POST",
331
- data: body
258
+ data: body,
259
+ config: {
260
+ params
261
+ }
332
262
  }),
333
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
263
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
334
264
  }),
335
265
  discardDocument: builder.mutation({
336
266
  query: ({ collectionType, model, documentId, params }) => ({
@@ -441,10 +371,13 @@ const documentApi = contentManagerApi.injectEndpoints({
441
371
  }
442
372
  }),
443
373
  publishManyDocuments: builder.mutation({
444
- query: ({ model, ...body }) => ({
374
+ query: ({ model, params, ...body }) => ({
445
375
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
446
376
  method: "POST",
447
- data: body
377
+ data: body,
378
+ config: {
379
+ params
380
+ }
448
381
  }),
449
382
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
450
383
  }),
@@ -486,10 +419,13 @@ const documentApi = contentManagerApi.injectEndpoints({
486
419
  }
487
420
  }),
488
421
  unpublishManyDocuments: builder.mutation({
489
- query: ({ model, ...body }) => ({
422
+ query: ({ model, params, ...body }) => ({
490
423
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
491
424
  method: "POST",
492
- data: body
425
+ data: body,
426
+ config: {
427
+ params
428
+ }
493
429
  }),
494
430
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
495
431
  })
@@ -513,6 +449,24 @@ const {
513
449
  useUnpublishDocumentMutation,
514
450
  useUnpublishManyDocumentsMutation
515
451
  } = documentApi;
452
+ const buildValidParams = (query) => {
453
+ if (!query)
454
+ return query;
455
+ const { plugins: _, ...validQueryParams } = {
456
+ ...query,
457
+ ...Object.values(query?.plugins ?? {}).reduce(
458
+ (acc, current) => Object.assign(acc, current),
459
+ {}
460
+ )
461
+ };
462
+ if ("_q" in validQueryParams) {
463
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
464
+ }
465
+ return validQueryParams;
466
+ };
467
+ const isBaseQueryError = (error) => {
468
+ return error.name !== void 0;
469
+ };
516
470
  const createYupSchema = (attributes = {}, components = {}) => {
517
471
  const createModelSchema = (attributes2) => yup.object().shape(
518
472
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -552,10 +506,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
552
506
  yup.array().of(
553
507
  yup.lazy(
554
508
  (data) => {
555
- const { attributes: attributes3 } = components[data.__component];
556
- return yup.object().shape({
509
+ const attributes3 = components?.[data?.__component]?.attributes;
510
+ const validation = yup.object().shape({
557
511
  __component: yup.string().required().oneOf(Object.keys(components))
558
- }).nullable(false).concat(createModelSchema(attributes3));
512
+ }).nullable(false);
513
+ if (!attributes3) {
514
+ return validation;
515
+ }
516
+ return validation.concat(createModelSchema(attributes3));
559
517
  }
560
518
  )
561
519
  )
@@ -565,11 +523,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
523
  return {
566
524
  ...acc,
567
525
  [name]: transformSchema(
568
- yup.array().of(
569
- yup.object().shape({
570
- id: yup.string().required()
571
- })
572
- )
526
+ yup.lazy((value) => {
527
+ if (!value) {
528
+ return yup.mixed().nullable(true);
529
+ } else if (Array.isArray(value)) {
530
+ return yup.array().of(
531
+ yup.object().shape({
532
+ id: yup.string().required()
533
+ })
534
+ );
535
+ } else if (typeof value === "object") {
536
+ return yup.object();
537
+ } else {
538
+ return yup.mixed().test(
539
+ "type-error",
540
+ "Relation values must be either null, an array of objects with {id} or an object.",
541
+ () => false
542
+ );
543
+ }
544
+ })
573
545
  )
574
546
  };
575
547
  default:
@@ -628,13 +600,18 @@ const createAttributeSchema = (attribute) => {
628
600
  }
629
601
  };
630
602
  const addRequiredValidation = (attribute) => (schema) => {
631
- if (attribute.required) {
603
+ if (attribute.required && attribute.type !== "relation") {
632
604
  return schema.required({
633
605
  id: translatedErrors.required.id,
634
606
  defaultMessage: "This field is required."
635
607
  });
636
608
  }
637
- return schema.nullable();
609
+ return schema?.nullable ? schema.nullable() : (
610
+ // In some cases '.nullable' will not be available on the schema.
611
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
612
+ // In these cases we should just return the schema as it is.
613
+ schema
614
+ );
638
615
  };
639
616
  const addMinLengthValidation = (attribute) => (schema) => {
640
617
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -706,24 +683,6 @@ const addRegexValidation = (attribute) => (schema) => {
706
683
  }
707
684
  return schema;
708
685
  };
709
- const extractValuesFromYupError = (errorType, errorParams) => {
710
- if (!errorType || !errorParams) {
711
- return {};
712
- }
713
- return {
714
- [errorType]: errorParams[errorType]
715
- };
716
- };
717
- const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
718
- if (currentError.path) {
719
- acc[currentError.path.split("[").join(".").split("]").join("")] = {
720
- id: currentError.message,
721
- defaultMessage: currentError.message,
722
- values: extractValuesFromYupError(currentError?.type, currentError?.params)
723
- };
724
- }
725
- return acc;
726
- }, {});
727
686
  const initApi = contentManagerApi.injectEndpoints({
728
687
  endpoints: (builder) => ({
729
688
  getInitialData: builder.query({
@@ -737,27 +696,20 @@ const { useGetInitialDataQuery } = initApi;
737
696
  const useContentTypeSchema = (model) => {
738
697
  const { toggleNotification } = useNotification();
739
698
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
740
- const { components, contentType, contentTypes, error, isLoading, isFetching } = useGetInitialDataQuery(void 0, {
741
- selectFromResult: (res) => {
742
- const contentType2 = res.data?.contentTypes.find((ct) => ct.uid === model);
743
- const componentsByKey = res.data?.components.reduce(
744
- (acc, component) => {
745
- acc[component.uid] = component;
746
- return acc;
747
- },
748
- {}
749
- );
750
- const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
751
- return {
752
- isLoading: res.isLoading,
753
- isFetching: res.isFetching,
754
- error: res.error,
755
- components: Object.keys(components2).length === 0 ? void 0 : components2,
756
- contentType: contentType2,
757
- contentTypes: res.data?.contentTypes ?? []
758
- };
759
- }
760
- });
699
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
700
+ const { components, contentType, contentTypes } = React.useMemo(() => {
701
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
702
+ const componentsByKey = data?.components.reduce((acc, component) => {
703
+ acc[component.uid] = component;
704
+ return acc;
705
+ }, {});
706
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
707
+ return {
708
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
709
+ contentType: contentType2,
710
+ contentTypes: data?.contentTypes ?? []
711
+ };
712
+ }, [model, data]);
761
713
  React.useEffect(() => {
762
714
  if (error) {
763
715
  toggleNotification({
@@ -812,7 +764,10 @@ const useDocument = (args, opts) => {
812
764
  isLoading: isLoadingDocument,
813
765
  isFetching: isFetchingDocument,
814
766
  error
815
- } = useGetDocumentQuery(args, opts);
767
+ } = useGetDocumentQuery(args, {
768
+ ...opts,
769
+ skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
770
+ });
816
771
  const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
817
772
  React.useEffect(() => {
818
773
  if (error) {
@@ -840,7 +795,7 @@ const useDocument = (args, opts) => {
840
795
  return null;
841
796
  } catch (error2) {
842
797
  if (error2 instanceof ValidationError) {
843
- return getInnerErrors(error2);
798
+ return getYupValidationErrors(error2);
844
799
  }
845
800
  throw error2;
846
801
  }
@@ -936,14 +891,53 @@ const useDocumentActions = () => {
936
891
  },
937
892
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
938
893
  );
894
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
895
+ const deleteMany = React.useCallback(
896
+ async ({ model, documentIds, params }) => {
897
+ try {
898
+ trackUsage("willBulkDeleteEntries");
899
+ const res = await deleteManyDocuments({
900
+ model,
901
+ documentIds,
902
+ params
903
+ });
904
+ if ("error" in res) {
905
+ toggleNotification({
906
+ type: "danger",
907
+ message: formatAPIError(res.error)
908
+ });
909
+ return { error: res.error };
910
+ }
911
+ toggleNotification({
912
+ type: "success",
913
+ title: formatMessage({
914
+ id: getTranslation("success.records.delete"),
915
+ defaultMessage: "Successfully deleted."
916
+ }),
917
+ message: ""
918
+ });
919
+ trackUsage("didBulkDeleteEntries");
920
+ return res.data;
921
+ } catch (err) {
922
+ toggleNotification({
923
+ type: "danger",
924
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
925
+ });
926
+ trackUsage("didNotBulkDeleteEntries");
927
+ throw err;
928
+ }
929
+ },
930
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
931
+ );
939
932
  const [discardDocument] = useDiscardDocumentMutation();
940
933
  const discard = React.useCallback(
941
- async ({ collectionType, model, documentId }) => {
934
+ async ({ collectionType, model, documentId, params }) => {
942
935
  try {
943
936
  const res = await discardDocument({
944
937
  collectionType,
945
938
  model,
946
- documentId
939
+ documentId,
940
+ params
947
941
  });
948
942
  if ("error" in res) {
949
943
  toggleNotification({
@@ -1005,6 +999,43 @@ const useDocumentActions = () => {
1005
999
  },
1006
1000
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1007
1001
  );
1002
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
1003
+ const publishMany = React.useCallback(
1004
+ async ({ model, documentIds, params }) => {
1005
+ try {
1006
+ const res = await publishManyDocuments({
1007
+ model,
1008
+ documentIds,
1009
+ params
1010
+ });
1011
+ if ("error" in res) {
1012
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1013
+ return { error: res.error };
1014
+ }
1015
+ toggleNotification({
1016
+ type: "success",
1017
+ message: formatMessage({
1018
+ id: getTranslation("success.record.publish"),
1019
+ defaultMessage: "Published document"
1020
+ })
1021
+ });
1022
+ return res.data;
1023
+ } catch (err) {
1024
+ toggleNotification({
1025
+ type: "danger",
1026
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1027
+ });
1028
+ throw err;
1029
+ }
1030
+ },
1031
+ [
1032
+ // trackUsage,
1033
+ publishManyDocuments,
1034
+ toggleNotification,
1035
+ formatMessage,
1036
+ formatAPIError
1037
+ ]
1038
+ );
1008
1039
  const [updateDocument] = useUpdateDocumentMutation();
1009
1040
  const update = React.useCallback(
1010
1041
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1079,6 +1110,41 @@ const useDocumentActions = () => {
1079
1110
  },
1080
1111
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1081
1112
  );
1113
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1114
+ const unpublishMany = React.useCallback(
1115
+ async ({ model, documentIds, params }) => {
1116
+ try {
1117
+ trackUsage("willBulkUnpublishEntries");
1118
+ const res = await unpublishManyDocuments({
1119
+ model,
1120
+ documentIds,
1121
+ params
1122
+ });
1123
+ if ("error" in res) {
1124
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1125
+ return { error: res.error };
1126
+ }
1127
+ trackUsage("didBulkUnpublishEntries");
1128
+ toggleNotification({
1129
+ type: "success",
1130
+ title: formatMessage({
1131
+ id: getTranslation("success.records.unpublish"),
1132
+ defaultMessage: "Successfully unpublished."
1133
+ }),
1134
+ message: ""
1135
+ });
1136
+ return res.data;
1137
+ } catch (err) {
1138
+ toggleNotification({
1139
+ type: "danger",
1140
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1141
+ });
1142
+ trackUsage("didNotBulkUnpublishEntries");
1143
+ throw err;
1144
+ }
1145
+ },
1146
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1147
+ );
1082
1148
  const [createDocument] = useCreateDocumentMutation();
1083
1149
  const create = React.useCallback(
1084
1150
  async ({ model, params }, data, trackerProperty) => {
@@ -1192,15 +1258,18 @@ const useDocumentActions = () => {
1192
1258
  clone,
1193
1259
  create,
1194
1260
  delete: _delete,
1261
+ deleteMany,
1195
1262
  discard,
1196
1263
  getDocument,
1197
1264
  publish,
1265
+ publishMany,
1198
1266
  unpublish,
1267
+ unpublishMany,
1199
1268
  update
1200
1269
  };
1201
1270
  };
1202
1271
  const ProtectedHistoryPage = lazy(
1203
- () => import("./History-DKhZAPcK.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1272
+ () => import("./History-ByUPL3T3.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1204
1273
  );
1205
1274
  const routes$1 = [
1206
1275
  {
@@ -1213,31 +1282,31 @@ const routes$1 = [
1213
1282
  }
1214
1283
  ];
1215
1284
  const ProtectedEditViewPage = lazy(
1216
- () => import("./EditViewPage-aUnqL-63.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1285
+ () => import("./EditViewPage-BtkEx339.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1217
1286
  );
1218
1287
  const ProtectedListViewPage = lazy(
1219
- () => import("./ListViewPage-ChhYmA-L.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1288
+ () => import("./ListViewPage-JSyNAAYu.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1220
1289
  );
1221
1290
  const ProtectedListConfiguration = lazy(
1222
- () => import("./ListConfigurationPage-nrXcxNYi.mjs").then((mod) => ({
1291
+ () => import("./ListConfigurationPage-Bm5HACXf.mjs").then((mod) => ({
1223
1292
  default: mod.ProtectedListConfiguration
1224
1293
  }))
1225
1294
  );
1226
1295
  const ProtectedEditConfigurationPage = lazy(
1227
- () => import("./EditConfigurationPage-BoBb-DLH.mjs").then((mod) => ({
1296
+ () => import("./EditConfigurationPage-Cp6HAEzN.mjs").then((mod) => ({
1228
1297
  default: mod.ProtectedEditConfigurationPage
1229
1298
  }))
1230
1299
  );
1231
1300
  const ProtectedComponentConfigurationPage = lazy(
1232
- () => import("./ComponentConfigurationPage-DjQBdcKF.mjs").then((mod) => ({
1301
+ () => import("./ComponentConfigurationPage-DHNM3YBz.mjs").then((mod) => ({
1233
1302
  default: mod.ProtectedComponentConfigurationPage
1234
1303
  }))
1235
1304
  );
1236
1305
  const NoPermissions = lazy(
1237
- () => import("./NoPermissionsPage-B9dqrtTy.mjs").then((mod) => ({ default: mod.NoPermissions }))
1306
+ () => import("./NoPermissionsPage-DNmf_pj0.mjs").then((mod) => ({ default: mod.NoPermissions }))
1238
1307
  );
1239
1308
  const NoContentType = lazy(
1240
- () => import("./NoContentTypePage-BrdFcN33.mjs").then((mod) => ({ default: mod.NoContentType }))
1309
+ () => import("./NoContentTypePage-CsrQUpBE.mjs").then((mod) => ({ default: mod.NoContentType }))
1241
1310
  );
1242
1311
  const CollectionTypePages = () => {
1243
1312
  const { collectionType } = useParams();
@@ -1427,7 +1496,7 @@ const DocumentActionsMenu = ({
1427
1496
  variant,
1428
1497
  children: [
1429
1498
  /* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
1430
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: label || formatMessage({
1499
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
1431
1500
  id: "content-manager.containers.edit.panels.default.more-actions",
1432
1501
  defaultMessage: "More document actions"
1433
1502
  }) })
@@ -1443,8 +1512,8 @@ const DocumentActionsMenu = ({
1443
1512
  onSelect: handleClick(action),
1444
1513
  display: "block",
1445
1514
  children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
1446
- /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, as: "span", children: [
1447
- action.icon,
1515
+ /* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
1516
+ /* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
1448
1517
  action.label
1449
1518
  ] }),
1450
1519
  action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
@@ -1505,6 +1574,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
1505
1574
  return "primary600";
1506
1575
  }
1507
1576
  };
1577
+ const convertActionVariantToIconColor = (variant = "secondary") => {
1578
+ switch (variant) {
1579
+ case "danger":
1580
+ return "danger600";
1581
+ case "secondary":
1582
+ return "neutral500";
1583
+ case "success":
1584
+ return "success600";
1585
+ default:
1586
+ return "primary600";
1587
+ }
1588
+ };
1508
1589
  const DocumentActionConfirmDialog = ({
1509
1590
  onClose,
1510
1591
  onCancel,
@@ -1527,61 +1608,42 @@ const DocumentActionConfirmDialog = ({
1527
1608
  }
1528
1609
  onClose();
1529
1610
  };
1530
- return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
1531
- /* @__PURE__ */ jsx(DialogBody, { children: content }),
1532
- /* @__PURE__ */ jsx(
1533
- DialogFooter,
1534
- {
1535
- startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
1536
- id: "app.components.Button.cancel",
1537
- defaultMessage: "Cancel"
1538
- }) }),
1539
- endAction: /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1540
- id: "app.components.Button.confirm",
1541
- defaultMessage: "Confirm"
1542
- }) })
1543
- }
1544
- )
1545
- ] });
1611
+ return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
1612
+ /* @__PURE__ */ jsx(Dialog.Header, { children: title }),
1613
+ /* @__PURE__ */ jsx(Dialog.Body, { children: content }),
1614
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
1615
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
1616
+ id: "app.components.Button.cancel",
1617
+ defaultMessage: "Cancel"
1618
+ }) }) }),
1619
+ /* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
1620
+ id: "app.components.Button.confirm",
1621
+ defaultMessage: "Confirm"
1622
+ }) })
1623
+ ] })
1624
+ ] }) });
1546
1625
  };
1547
1626
  const DocumentActionModal = ({
1548
1627
  isOpen,
1549
1628
  title,
1550
1629
  onClose,
1551
1630
  footer: Footer,
1552
- content,
1631
+ content: Content,
1553
1632
  onModalClose
1554
1633
  }) => {
1555
- const id = React.useId();
1556
- if (!isOpen) {
1557
- return null;
1558
- }
1559
1634
  const handleClose = () => {
1560
1635
  if (onClose) {
1561
1636
  onClose();
1562
1637
  }
1563
1638
  onModalClose();
1564
1639
  };
1565
- return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1566
- /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", as: "h2", id, children: title }) }),
1567
- /* @__PURE__ */ jsx(ModalBody, { children: content }),
1568
- /* @__PURE__ */ jsx(
1569
- Box,
1570
- {
1571
- paddingTop: 4,
1572
- paddingBottom: 4,
1573
- paddingLeft: 5,
1574
- paddingRight: 5,
1575
- borderWidth: "1px 0 0 0",
1576
- borderStyle: "solid",
1577
- borderColor: "neutral150",
1578
- background: "neutral100",
1579
- children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
1580
- }
1581
- )
1582
- ] });
1640
+ return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
1641
+ /* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
1642
+ /* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1643
+ /* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
1644
+ ] }) });
1583
1645
  };
1584
- const PublishAction = ({
1646
+ const PublishAction$1 = ({
1585
1647
  activeTab,
1586
1648
  documentId,
1587
1649
  model,
@@ -1666,7 +1728,7 @@ const PublishAction = ({
1666
1728
  }
1667
1729
  };
1668
1730
  };
1669
- PublishAction.type = "publish";
1731
+ PublishAction$1.type = "publish";
1670
1732
  const UpdateAction = ({
1671
1733
  activeTab,
1672
1734
  documentId,
@@ -1762,10 +1824,13 @@ const UpdateAction = ({
1762
1824
  document
1763
1825
  );
1764
1826
  if ("data" in res && collectionType !== SINGLE_TYPES) {
1765
- navigate({
1766
- pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1767
- search: rawQuery
1768
- });
1827
+ navigate(
1828
+ {
1829
+ pathname: `../${collectionType}/${model}/${res.data.documentId}`,
1830
+ search: rawQuery
1831
+ },
1832
+ { replace: true }
1833
+ );
1769
1834
  } else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
1770
1835
  setErrors(formatValidationErrors(res.error));
1771
1836
  }
@@ -1781,7 +1846,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1781
1846
  KEEP: "keep",
1782
1847
  DISCARD: "discard"
1783
1848
  };
1784
- const UnpublishAction = ({
1849
+ const UnpublishAction$1 = ({
1785
1850
  activeTab,
1786
1851
  documentId,
1787
1852
  model,
@@ -1797,10 +1862,8 @@ const UnpublishAction = ({
1797
1862
  const { toggleNotification } = useNotification();
1798
1863
  const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
1799
1864
  const isDocumentModified = document?.status === "modified";
1800
- const handleChange = (e) => {
1801
- if ("value" in e.target) {
1802
- setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1803
- }
1865
+ const handleChange = (value) => {
1866
+ setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
1804
1867
  };
1805
1868
  if (!schema?.options?.draftAndPublish) {
1806
1869
  return null;
@@ -1844,45 +1907,30 @@ const UnpublishAction = ({
1844
1907
  content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
1845
1908
  /* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
1846
1909
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1847
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
1910
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1848
1911
  id: "content-manager.actions.unpublish.dialog.body",
1849
1912
  defaultMessage: "Are you sure?"
1850
1913
  }) })
1851
1914
  ] }),
1852
1915
  /* @__PURE__ */ jsxs(
1853
- Flex,
1916
+ Radio.Group,
1854
1917
  {
1855
- onChange: handleChange,
1856
- direction: "column",
1857
- alignItems: "flex-start",
1858
- as: "fieldset",
1859
- gap: 3,
1918
+ defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1919
+ name: "discard-options",
1920
+ "aria-label": formatMessage({
1921
+ id: "content-manager.actions.unpublish.dialog.radio-label",
1922
+ defaultMessage: "Choose an option to unpublish the document."
1923
+ }),
1924
+ onValueChange: handleChange,
1860
1925
  children: [
1861
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "legend" }),
1862
- /* @__PURE__ */ jsx(
1863
- Radio,
1864
- {
1865
- checked: shouldKeepDraft,
1866
- value: UNPUBLISH_DRAFT_OPTIONS.KEEP,
1867
- name: "discard-options",
1868
- children: formatMessage({
1869
- id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1870
- defaultMessage: "Keep draft"
1871
- })
1872
- }
1873
- ),
1874
- /* @__PURE__ */ jsx(
1875
- Radio,
1876
- {
1877
- checked: !shouldKeepDraft,
1878
- value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
1879
- name: "discard-options",
1880
- children: formatMessage({
1881
- id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1882
- defaultMessage: "Replace draft"
1883
- })
1884
- }
1885
- )
1926
+ /* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
1927
+ id: "content-manager.actions.unpublish.dialog.option.keep-draft",
1928
+ defaultMessage: "Keep draft"
1929
+ }) }),
1930
+ /* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
1931
+ id: "content-manager.actions.unpublish.dialog.option.replace-draft",
1932
+ defaultMessage: "Replace draft"
1933
+ }) })
1886
1934
  ]
1887
1935
  }
1888
1936
  )
@@ -1915,7 +1963,7 @@ const UnpublishAction = ({
1915
1963
  position: ["panel", "table-row"]
1916
1964
  };
1917
1965
  };
1918
- UnpublishAction.type = "unpublish";
1966
+ UnpublishAction$1.type = "unpublish";
1919
1967
  const DiscardAction = ({
1920
1968
  activeTab,
1921
1969
  documentId,
@@ -1949,7 +1997,7 @@ const DiscardAction = ({
1949
1997
  }),
1950
1998
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
1951
1999
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
1952
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2000
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
1953
2001
  id: "content-manager.actions.discard.dialog.body",
1954
2002
  defaultMessage: "Are you sure?"
1955
2003
  }) })
@@ -1971,7 +2019,7 @@ const StyledCrossCircle = styled(CrossCircle)`
1971
2019
  fill: currentColor;
1972
2020
  }
1973
2021
  `;
1974
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2022
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1975
2023
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1976
2024
  const RelativeTime = React.forwardRef(
1977
2025
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2019,7 +2067,7 @@ const getDisplayName = ({
2019
2067
  const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
2020
2068
  const DocumentStatus = ({ status = "draft", ...restProps }) => {
2021
2069
  const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
2022
- return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { as: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2070
+ return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
2023
2071
  };
2024
2072
  const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2025
2073
  const { formatMessage } = useIntl();
@@ -2039,7 +2087,7 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
2039
2087
  gap: "80px",
2040
2088
  alignItems: "flex-start",
2041
2089
  children: [
2042
- /* @__PURE__ */ jsx(Typography, { variant: "alpha", as: "h1", children: title }),
2090
+ /* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
2043
2091
  /* @__PURE__ */ jsx(HeaderToolbar, {})
2044
2092
  ]
2045
2093
  }
@@ -2196,7 +2244,7 @@ const Information = ({ activeTab }) => {
2196
2244
  borderColor: "neutral150",
2197
2245
  direction: "column",
2198
2246
  marginTop: 2,
2199
- as: "dl",
2247
+ tag: "dl",
2200
2248
  padding: 5,
2201
2249
  gap: 3,
2202
2250
  alignItems: "flex-start",
@@ -2204,8 +2252,8 @@ const Information = ({ activeTab }) => {
2204
2252
  marginRight: "-0.4rem",
2205
2253
  width: "calc(100% + 8px)",
2206
2254
  children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
2207
- /* @__PURE__ */ jsx(Typography, { as: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2208
- /* @__PURE__ */ jsx(Typography, { as: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2255
+ /* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
2256
+ /* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
2209
2257
  ] }, info.label))
2210
2258
  }
2211
2259
  );
@@ -2238,7 +2286,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2238
2286
  id: "app.links.configure-view",
2239
2287
  defaultMessage: "Configure the view"
2240
2288
  }),
2241
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2289
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2242
2290
  onClick: () => {
2243
2291
  navigate(`../${collectionType}/${model}/configurations/edit`);
2244
2292
  },
@@ -2246,11 +2294,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2246
2294
  };
2247
2295
  };
2248
2296
  ConfigureTheViewAction.type = "configure-the-view";
2249
- const StyledCog = styled(Cog)`
2250
- path {
2251
- fill: currentColor;
2252
- }
2253
- `;
2254
2297
  const EditTheModelAction = ({ model }) => {
2255
2298
  const navigate = useNavigate();
2256
2299
  const { formatMessage } = useIntl();
@@ -2259,7 +2302,7 @@ const EditTheModelAction = ({ model }) => {
2259
2302
  id: "content-manager.link-to-ctb",
2260
2303
  defaultMessage: "Edit the model"
2261
2304
  }),
2262
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2305
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2263
2306
  onClick: () => {
2264
2307
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2265
2308
  },
@@ -2267,12 +2310,7 @@ const EditTheModelAction = ({ model }) => {
2267
2310
  };
2268
2311
  };
2269
2312
  EditTheModelAction.type = "edit-the-model";
2270
- const StyledPencil$1 = styled(Pencil)`
2271
- path {
2272
- fill: currentColor;
2273
- }
2274
- `;
2275
- const DeleteAction = ({ documentId, model, collectionType, document }) => {
2313
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2276
2314
  const navigate = useNavigate();
2277
2315
  const { formatMessage } = useIntl();
2278
2316
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2286,7 +2324,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2286
2324
  id: "content-manager.actions.delete.label",
2287
2325
  defaultMessage: "Delete document"
2288
2326
  }),
2289
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2327
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2290
2328
  dialog: {
2291
2329
  type: "dialog",
2292
2330
  title: formatMessage({
@@ -2295,7 +2333,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2295
2333
  }),
2296
2334
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
2297
2335
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
2298
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
2336
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
2299
2337
  id: "content-manager.actions.delete.dialog.body",
2300
2338
  defaultMessage: "Are you sure?"
2301
2339
  }) })
@@ -2340,13 +2378,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2340
2378
  position: ["header", "table-row"]
2341
2379
  };
2342
2380
  };
2343
- DeleteAction.type = "delete";
2344
- const StyledTrash = styled(Trash)`
2345
- path {
2346
- fill: currentColor;
2347
- }
2348
- `;
2349
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2381
+ DeleteAction$1.type = "delete";
2382
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2350
2383
  const Panels = () => {
2351
2384
  const isCloning = useMatch(CLONE_PATH) !== null;
2352
2385
  const [
@@ -2420,7 +2453,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2420
2453
  Flex,
2421
2454
  {
2422
2455
  ref,
2423
- as: "aside",
2456
+ tag: "aside",
2424
2457
  "aria-labelledby": "additional-information",
2425
2458
  background: "neutral0",
2426
2459
  borderColor: "neutral150",
@@ -2435,359 +2468,12 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2435
2468
  justifyContent: "stretch",
2436
2469
  alignItems: "flex-start",
2437
2470
  children: [
2438
- /* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2471
+ /* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
2439
2472
  children
2440
2473
  ]
2441
2474
  }
2442
2475
  );
2443
2476
  });
2444
- const DEFAULT_BULK_ACTIONS = [];
2445
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2446
- const { formatMessage } = useIntl();
2447
- const getDefaultErrorMessage = (reason) => {
2448
- switch (reason) {
2449
- case "relation":
2450
- return "Duplicating the relation could remove it from the original entry.";
2451
- case "unique":
2452
- return "Identical values in a unique field are not allowed";
2453
- default:
2454
- return reason;
2455
- }
2456
- };
2457
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2458
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
2459
- id: getTranslation("containers.list.autoCloneModal.title"),
2460
- defaultMessage: "This entry can't be duplicated directly."
2461
- }) }),
2462
- /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
2463
- id: getTranslation("containers.list.autoCloneModal.description"),
2464
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2465
- }) }) }),
2466
- /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
2467
- Flex,
2468
- {
2469
- direction: "column",
2470
- gap: 2,
2471
- alignItems: "flex-start",
2472
- borderColor: "neutral200",
2473
- hasRadius: true,
2474
- padding: 6,
2475
- children: [
2476
- /* @__PURE__ */ jsx(Flex, { direction: "row", as: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", as: "li", children: [
2477
- pathSegment,
2478
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
2479
- ChevronRight,
2480
- {
2481
- fill: "neutral500",
2482
- height: "0.8rem",
2483
- width: "0.8rem",
2484
- style: { margin: "0 0.8rem" }
2485
- }
2486
- )
2487
- ] }, index2)) }),
2488
- /* @__PURE__ */ jsx(Typography, { as: "p", textColor: "neutral600", children: formatMessage({
2489
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2490
- defaultMessage: getDefaultErrorMessage(reason)
2491
- }) })
2492
- ]
2493
- },
2494
- fieldPath.join()
2495
- )) })
2496
- ] });
2497
- };
2498
- const TableActions = ({ document }) => {
2499
- const { formatMessage } = useIntl();
2500
- const { model, collectionType } = useDoc();
2501
- const plugins = useStrapiApp("TableActions", (state) => state.plugins);
2502
- const props = {
2503
- activeTab: null,
2504
- model,
2505
- documentId: document.documentId,
2506
- collectionType,
2507
- document
2508
- };
2509
- return /* @__PURE__ */ jsx(
2510
- DescriptionComponentRenderer,
2511
- {
2512
- props,
2513
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2514
- children: (actions2) => {
2515
- const tableRowActions = actions2.filter((action) => {
2516
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2517
- return positions.includes("table-row");
2518
- });
2519
- return /* @__PURE__ */ jsx(
2520
- DocumentActionsMenu,
2521
- {
2522
- actions: tableRowActions,
2523
- label: formatMessage({
2524
- id: "content-manager.containers.list.table.row-actions",
2525
- defaultMessage: "Row action"
2526
- }),
2527
- variant: "ghost"
2528
- }
2529
- );
2530
- }
2531
- }
2532
- );
2533
- };
2534
- const EditAction = ({ documentId }) => {
2535
- const navigate = useNavigate();
2536
- const { formatMessage } = useIntl();
2537
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2538
- const { toggleNotification } = useNotification();
2539
- const [{ query }] = useQueryParams();
2540
- return {
2541
- disabled: !canRead,
2542
- icon: /* @__PURE__ */ jsx(StyledPencil, {}),
2543
- label: formatMessage({
2544
- id: "content-manager.actions.edit.label",
2545
- defaultMessage: "Edit"
2546
- }),
2547
- position: "table-row",
2548
- onClick: async () => {
2549
- if (!documentId) {
2550
- console.error(
2551
- "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
2552
- );
2553
- toggleNotification({
2554
- message: formatMessage({
2555
- id: "content-manager.actions.edit.error",
2556
- defaultMessage: "An error occurred while trying to edit the document."
2557
- }),
2558
- type: "danger"
2559
- });
2560
- return;
2561
- }
2562
- navigate({
2563
- pathname: documentId,
2564
- search: stringify({
2565
- plugins: query.plugins
2566
- })
2567
- });
2568
- }
2569
- };
2570
- };
2571
- EditAction.type = "edit";
2572
- const StyledPencil = styled(Pencil)`
2573
- path {
2574
- fill: currentColor;
2575
- }
2576
- `;
2577
- const CloneAction = ({ model, documentId }) => {
2578
- const navigate = useNavigate();
2579
- const { formatMessage } = useIntl();
2580
- const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
2581
- const { toggleNotification } = useNotification();
2582
- const { autoClone } = useDocumentActions();
2583
- const [prohibitedFields, setProhibitedFields] = React.useState([]);
2584
- return {
2585
- disabled: !canCreate,
2586
- icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
2587
- label: formatMessage({
2588
- id: "content-manager.actions.clone.label",
2589
- defaultMessage: "Duplicate"
2590
- }),
2591
- position: "table-row",
2592
- onClick: async () => {
2593
- if (!documentId) {
2594
- console.error(
2595
- "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
2596
- );
2597
- toggleNotification({
2598
- message: formatMessage({
2599
- id: "content-manager.actions.clone.error",
2600
- defaultMessage: "An error occurred while trying to clone the document."
2601
- }),
2602
- type: "danger"
2603
- });
2604
- return;
2605
- }
2606
- const res = await autoClone({ model, sourceId: documentId });
2607
- if ("data" in res) {
2608
- navigate(res.data.documentId);
2609
- return true;
2610
- }
2611
- if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
2612
- const prohibitedFields2 = res.error.details.prohibitedFields;
2613
- setProhibitedFields(prohibitedFields2);
2614
- }
2615
- },
2616
- dialog: {
2617
- type: "modal",
2618
- title: formatMessage({
2619
- id: "content-manager.containers.list.autoCloneModal.header",
2620
- defaultMessage: "Duplicate"
2621
- }),
2622
- content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2623
- footer: ({ onClose }) => {
2624
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
2625
- /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2626
- id: "cancel",
2627
- defaultMessage: "Cancel"
2628
- }) }),
2629
- /* @__PURE__ */ jsx(
2630
- LinkButton,
2631
- {
2632
- as: NavLink,
2633
- to: {
2634
- pathname: `clone/${documentId}`
2635
- },
2636
- children: formatMessage({
2637
- id: "content-manager.containers.list.autoCloneModal.create",
2638
- defaultMessage: "Create"
2639
- })
2640
- }
2641
- )
2642
- ] });
2643
- }
2644
- }
2645
- };
2646
- };
2647
- CloneAction.type = "clone";
2648
- const StyledDuplicate = styled(Duplicate)`
2649
- path {
2650
- fill: currentColor;
2651
- }
2652
- `;
2653
- const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
2654
- class ContentManagerPlugin {
2655
- /**
2656
- * The following properties are the stored ones provided by any plugins registering with
2657
- * the content-manager. The function calls however, need to be called at runtime in the
2658
- * application, so instead we collate them and run them later with the complete list incl.
2659
- * ones already registered & the context of the view.
2660
- */
2661
- bulkActions = [...DEFAULT_BULK_ACTIONS];
2662
- documentActions = [
2663
- ...DEFAULT_ACTIONS,
2664
- ...DEFAULT_TABLE_ROW_ACTIONS,
2665
- ...DEFAULT_HEADER_ACTIONS,
2666
- HistoryAction
2667
- ];
2668
- editViewSidePanels = [ActionsPanel];
2669
- headerActions = [];
2670
- constructor() {
2671
- }
2672
- addEditViewSidePanel(panels) {
2673
- if (Array.isArray(panels)) {
2674
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2675
- } else if (typeof panels === "function") {
2676
- this.editViewSidePanels = panels(this.editViewSidePanels);
2677
- } else {
2678
- throw new Error(
2679
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2680
- panels
2681
- )}`
2682
- );
2683
- }
2684
- }
2685
- addDocumentAction(actions2) {
2686
- if (Array.isArray(actions2)) {
2687
- this.documentActions = [...this.documentActions, ...actions2];
2688
- } else if (typeof actions2 === "function") {
2689
- this.documentActions = actions2(this.documentActions);
2690
- } else {
2691
- throw new Error(
2692
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2693
- actions2
2694
- )}`
2695
- );
2696
- }
2697
- }
2698
- addDocumentHeaderAction(actions2) {
2699
- if (Array.isArray(actions2)) {
2700
- this.headerActions = [...this.headerActions, ...actions2];
2701
- } else if (typeof actions2 === "function") {
2702
- this.headerActions = actions2(this.headerActions);
2703
- } else {
2704
- throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
2707
- )}`
2708
- );
2709
- }
2710
- }
2711
- addBulkAction(actions2) {
2712
- if (Array.isArray(actions2)) {
2713
- this.bulkActions = [...this.bulkActions, ...actions2];
2714
- } else if (typeof actions2 === "function") {
2715
- this.bulkActions = actions2(this.bulkActions);
2716
- } else {
2717
- throw new Error(
2718
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
2719
- actions2
2720
- )}`
2721
- );
2722
- }
2723
- }
2724
- get config() {
2725
- return {
2726
- id: PLUGIN_ID,
2727
- name: "Content Manager",
2728
- injectionZones: INJECTION_ZONES,
2729
- apis: {
2730
- addBulkAction: this.addBulkAction.bind(this),
2731
- addDocumentAction: this.addDocumentAction.bind(this),
2732
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
2733
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
2734
- getBulkActions: () => this.bulkActions,
2735
- getDocumentActions: () => this.documentActions,
2736
- getEditViewSidePanels: () => this.editViewSidePanels,
2737
- getHeaderActions: () => this.headerActions
2738
- }
2739
- };
2740
- }
2741
- }
2742
- const getPrintableType = (value) => {
2743
- const nativeType = typeof value;
2744
- if (nativeType === "object") {
2745
- if (value === null)
2746
- return "null";
2747
- if (Array.isArray(value))
2748
- return "array";
2749
- if (value instanceof Object && value.constructor.name !== "Object") {
2750
- return value.constructor.name;
2751
- }
2752
- }
2753
- return nativeType;
2754
- };
2755
- const initialState = {
2756
- collectionTypeLinks: [],
2757
- components: [],
2758
- fieldSizes: {},
2759
- models: [],
2760
- singleTypeLinks: [],
2761
- isLoading: true
2762
- };
2763
- const appSlice = createSlice({
2764
- name: "app",
2765
- initialState,
2766
- reducers: {
2767
- setInitialData(state, action) {
2768
- const {
2769
- authorizedCollectionTypeLinks,
2770
- authorizedSingleTypeLinks,
2771
- components,
2772
- contentTypeSchemas,
2773
- fieldSizes
2774
- } = action.payload;
2775
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
2776
- ({ isDisplayed }) => isDisplayed
2777
- );
2778
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
2779
- state.components = components;
2780
- state.models = contentTypeSchemas;
2781
- state.fieldSizes = fieldSizes;
2782
- state.isLoading = false;
2783
- }
2784
- }
2785
- });
2786
- const { actions, reducer: reducer$1 } = appSlice;
2787
- const { setInitialData } = actions;
2788
- const reducer = combineReducers({
2789
- app: reducer$1
2790
- });
2791
2477
  const HOOKS = {
2792
2478
  /**
2793
2479
  * Hook that allows to mutate the displayed headers of the list view table
@@ -2869,235 +2555,1157 @@ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2869
2555
  schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2870
2556
  );
2871
2557
  return {
2872
- name: mainFieldName,
2873
- type: mainFieldType ?? "string"
2558
+ name: mainFieldName,
2559
+ type: mainFieldType ?? "string"
2560
+ };
2561
+ };
2562
+ const DEFAULT_SETTINGS = {
2563
+ bulkable: false,
2564
+ filterable: false,
2565
+ searchable: false,
2566
+ pagination: false,
2567
+ defaultSortBy: "",
2568
+ defaultSortOrder: "asc",
2569
+ mainField: "id",
2570
+ pageSize: 10
2571
+ };
2572
+ const useDocumentLayout = (model) => {
2573
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2574
+ const [{ query }] = useQueryParams();
2575
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2576
+ const { toggleNotification } = useNotification();
2577
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2578
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2579
+ const {
2580
+ data,
2581
+ isLoading: isLoadingConfigs,
2582
+ error,
2583
+ isFetching: isFetchingConfigs
2584
+ } = useGetContentTypeConfigurationQuery(model);
2585
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2586
+ React.useEffect(() => {
2587
+ if (error) {
2588
+ toggleNotification({
2589
+ type: "danger",
2590
+ message: formatAPIError(error)
2591
+ });
2592
+ }
2593
+ }, [error, formatAPIError, toggleNotification]);
2594
+ const editLayout = React.useMemo(
2595
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2596
+ layout: [],
2597
+ components: {},
2598
+ metadatas: {},
2599
+ options: {},
2600
+ settings: DEFAULT_SETTINGS
2601
+ },
2602
+ [data, isLoading, schemas, schema, components]
2603
+ );
2604
+ const listLayout = React.useMemo(() => {
2605
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2606
+ layout: [],
2607
+ metadatas: {},
2608
+ options: {},
2609
+ settings: DEFAULT_SETTINGS
2610
+ };
2611
+ }, [data, isLoading, schemas, schema, components]);
2612
+ const { layout: edit } = React.useMemo(
2613
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2614
+ layout: editLayout,
2615
+ query
2616
+ }),
2617
+ [editLayout, query, runHookWaterfall]
2618
+ );
2619
+ return {
2620
+ error,
2621
+ isLoading,
2622
+ edit,
2623
+ list: listLayout
2624
+ };
2625
+ };
2626
+ const useDocLayout = () => {
2627
+ const { model } = useDoc();
2628
+ return useDocumentLayout(model);
2629
+ };
2630
+ const formatEditLayout = (data, {
2631
+ schemas,
2632
+ schema,
2633
+ components
2634
+ }) => {
2635
+ let currentPanelIndex = 0;
2636
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2637
+ data.contentType.layouts.edit,
2638
+ schema?.attributes,
2639
+ data.contentType.metadatas,
2640
+ { configurations: data.components, schemas: components },
2641
+ schemas
2642
+ ).reduce((panels, row) => {
2643
+ if (row.some((field) => field.type === "dynamiczone")) {
2644
+ panels.push([row]);
2645
+ currentPanelIndex += 2;
2646
+ } else {
2647
+ if (!panels[currentPanelIndex]) {
2648
+ panels.push([]);
2649
+ }
2650
+ panels[currentPanelIndex].push(row);
2651
+ }
2652
+ return panels;
2653
+ }, []);
2654
+ const componentEditAttributes = Object.entries(data.components).reduce(
2655
+ (acc, [uid, configuration]) => {
2656
+ acc[uid] = {
2657
+ layout: convertEditLayoutToFieldLayouts(
2658
+ configuration.layouts.edit,
2659
+ components[uid].attributes,
2660
+ configuration.metadatas
2661
+ ),
2662
+ settings: {
2663
+ ...configuration.settings,
2664
+ icon: components[uid].info.icon,
2665
+ displayName: components[uid].info.displayName
2666
+ }
2667
+ };
2668
+ return acc;
2669
+ },
2670
+ {}
2671
+ );
2672
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2673
+ (acc, [attribute, metadata]) => {
2674
+ return {
2675
+ ...acc,
2676
+ [attribute]: metadata.edit
2677
+ };
2678
+ },
2679
+ {}
2680
+ );
2681
+ return {
2682
+ layout: panelledEditAttributes,
2683
+ components: componentEditAttributes,
2684
+ metadatas: editMetadatas,
2685
+ settings: {
2686
+ ...data.contentType.settings,
2687
+ displayName: schema?.info.displayName
2688
+ },
2689
+ options: {
2690
+ ...schema?.options,
2691
+ ...schema?.pluginOptions,
2692
+ ...data.contentType.options
2693
+ }
2694
+ };
2695
+ };
2696
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2697
+ return rows.map(
2698
+ (row) => row.map((field) => {
2699
+ const attribute = attributes[field.name];
2700
+ if (!attribute) {
2701
+ return null;
2702
+ }
2703
+ const { edit: metadata } = metadatas[field.name];
2704
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2705
+ return {
2706
+ attribute,
2707
+ disabled: !metadata.editable,
2708
+ hint: metadata.description,
2709
+ label: metadata.label ?? "",
2710
+ name: field.name,
2711
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2712
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2713
+ schemas,
2714
+ components: components?.schemas ?? {}
2715
+ }),
2716
+ placeholder: metadata.placeholder ?? "",
2717
+ required: attribute.required ?? false,
2718
+ size: field.size,
2719
+ unique: "unique" in attribute ? attribute.unique : false,
2720
+ visible: metadata.visible ?? true,
2721
+ type: attribute.type
2722
+ };
2723
+ }).filter((field) => field !== null)
2724
+ );
2725
+ };
2726
+ const formatListLayout = (data, {
2727
+ schemas,
2728
+ schema,
2729
+ components
2730
+ }) => {
2731
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2732
+ (acc, [attribute, metadata]) => {
2733
+ return {
2734
+ ...acc,
2735
+ [attribute]: metadata.list
2736
+ };
2737
+ },
2738
+ {}
2739
+ );
2740
+ const listAttributes = convertListLayoutToFieldLayouts(
2741
+ data.contentType.layouts.list,
2742
+ schema?.attributes,
2743
+ listMetadatas,
2744
+ { configurations: data.components, schemas: components },
2745
+ schemas
2746
+ );
2747
+ return {
2748
+ layout: listAttributes,
2749
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2750
+ metadatas: listMetadatas,
2751
+ options: {
2752
+ ...schema?.options,
2753
+ ...schema?.pluginOptions,
2754
+ ...data.contentType.options
2755
+ }
2874
2756
  };
2875
2757
  };
2876
- const DEFAULT_SETTINGS = {
2877
- bulkable: false,
2878
- filterable: false,
2879
- searchable: false,
2880
- pagination: false,
2881
- defaultSortBy: "",
2882
- defaultSortOrder: "asc",
2883
- mainField: "id",
2884
- pageSize: 10
2758
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2759
+ return columns.map((name) => {
2760
+ const attribute = attributes[name];
2761
+ if (!attribute) {
2762
+ return null;
2763
+ }
2764
+ const metadata = metadatas[name];
2765
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2766
+ return {
2767
+ attribute,
2768
+ label: metadata.label ?? "",
2769
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2770
+ schemas,
2771
+ components: components?.schemas ?? {}
2772
+ }),
2773
+ name,
2774
+ searchable: metadata.searchable ?? true,
2775
+ sortable: metadata.sortable ?? true
2776
+ };
2777
+ }).filter((field) => field !== null);
2885
2778
  };
2886
- const useDocumentLayout = (model) => {
2887
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2888
- const [{ query }] = useQueryParams();
2889
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2779
+ const ConfirmBulkActionDialog = ({
2780
+ onToggleDialog,
2781
+ isOpen = false,
2782
+ dialogBody,
2783
+ endAction
2784
+ }) => {
2785
+ const { formatMessage } = useIntl();
2786
+ return /* @__PURE__ */ jsx(Dialog.Root, { onOpenChange: onToggleDialog, open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
2787
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
2788
+ id: "app.components.ConfirmDialog.title",
2789
+ defaultMessage: "Confirmation"
2790
+ }) }),
2791
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
2792
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
2793
+ dialogBody
2794
+ ] }) }),
2795
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
2796
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2797
+ id: "app.components.Button.cancel",
2798
+ defaultMessage: "Cancel"
2799
+ }) }) }),
2800
+ endAction
2801
+ ] })
2802
+ ] }) });
2803
+ };
2804
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2805
+ const ConfirmDialogPublishAll = ({
2806
+ isOpen,
2807
+ onToggleDialog,
2808
+ isConfirmButtonLoading = false,
2809
+ onConfirm
2810
+ }) => {
2811
+ const { formatMessage } = useIntl();
2812
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2890
2813
  const { toggleNotification } = useNotification();
2891
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2892
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2814
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2815
+ const { model, schema } = useDoc();
2816
+ const [{ query }] = useQueryParams();
2893
2817
  const {
2894
- data,
2895
- isLoading: isLoadingConfigs,
2896
- error,
2897
- isFetching: isFetchingConfigs
2898
- } = useGetContentTypeConfigurationQuery(model);
2899
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2818
+ data: countDraftRelations = 0,
2819
+ isLoading,
2820
+ error
2821
+ } = useGetManyDraftRelationCountQuery(
2822
+ {
2823
+ model,
2824
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2825
+ locale: query?.plugins?.i18n?.locale
2826
+ },
2827
+ {
2828
+ skip: selectedEntries.length === 0
2829
+ }
2830
+ );
2900
2831
  React.useEffect(() => {
2901
2832
  if (error) {
2902
- toggleNotification({
2903
- type: "danger",
2904
- message: formatAPIError(error)
2905
- });
2833
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2906
2834
  }
2907
2835
  }, [error, formatAPIError, toggleNotification]);
2908
- const editLayout = React.useMemo(
2909
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2910
- layout: [],
2911
- components: {},
2912
- metadatas: {},
2913
- options: {},
2914
- settings: DEFAULT_SETTINGS
2836
+ if (error) {
2837
+ return null;
2838
+ }
2839
+ return /* @__PURE__ */ jsx(
2840
+ ConfirmBulkActionDialog,
2841
+ {
2842
+ isOpen: isOpen && !isLoading,
2843
+ onToggleDialog,
2844
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2845
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2846
+ countDraftRelations > 0 && formatMessage(
2847
+ {
2848
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2849
+ 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. "
2850
+ },
2851
+ {
2852
+ b: BoldChunk$1,
2853
+ count: countDraftRelations,
2854
+ entities: selectedEntries.length
2855
+ }
2856
+ ),
2857
+ formatMessage({
2858
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2859
+ defaultMessage: "Are you sure you want to publish these entries?"
2860
+ })
2861
+ ] }),
2862
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2863
+ {
2864
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2865
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2866
+ },
2867
+ {
2868
+ em: Emphasis
2869
+ }
2870
+ ) })
2871
+ ] }),
2872
+ endAction: /* @__PURE__ */ jsx(
2873
+ Button,
2874
+ {
2875
+ onClick: onConfirm,
2876
+ variant: "secondary",
2877
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2878
+ loading: isConfirmButtonLoading,
2879
+ children: formatMessage({
2880
+ id: "app.utils.publish",
2881
+ defaultMessage: "Publish"
2882
+ })
2883
+ }
2884
+ )
2885
+ }
2886
+ );
2887
+ };
2888
+ const TypographyMaxWidth = styled(Typography)`
2889
+ max-width: 300px;
2890
+ `;
2891
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2892
+ const messages = [];
2893
+ Object.entries(errors).forEach(([key, value]) => {
2894
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
2895
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2896
+ if ("id" in value && "defaultMessage" in value) {
2897
+ messages.push(
2898
+ formatMessage(
2899
+ {
2900
+ id: `${value.id}.withField`,
2901
+ defaultMessage: value.defaultMessage
2902
+ },
2903
+ { field: currentKey }
2904
+ )
2905
+ );
2906
+ } else {
2907
+ messages.push(
2908
+ ...formatErrorMessages(
2909
+ // @ts-expect-error TODO: check why value is not compatible with FormErrors
2910
+ value,
2911
+ currentKey,
2912
+ formatMessage
2913
+ )
2914
+ );
2915
+ }
2916
+ } else {
2917
+ messages.push(
2918
+ formatMessage(
2919
+ {
2920
+ id: `${value}.withField`,
2921
+ defaultMessage: value
2922
+ },
2923
+ { field: currentKey }
2924
+ )
2925
+ );
2926
+ }
2927
+ });
2928
+ return messages;
2929
+ };
2930
+ const EntryValidationText = ({ validationErrors, status }) => {
2931
+ const { formatMessage } = useIntl();
2932
+ if (validationErrors) {
2933
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
2934
+ " "
2935
+ );
2936
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2937
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
2938
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
2939
+ ] });
2940
+ }
2941
+ if (status === "published") {
2942
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2943
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
2944
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
2945
+ id: "content-manager.bulk-publish.already-published",
2946
+ defaultMessage: "Already Published"
2947
+ }) })
2948
+ ] });
2949
+ }
2950
+ if (status === "modified") {
2951
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2952
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
2953
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
2954
+ id: "content-manager.bulk-publish.modified",
2955
+ defaultMessage: "Ready to publish changes"
2956
+ }) })
2957
+ ] });
2958
+ }
2959
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2960
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
2961
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
2962
+ id: "app.utils.ready-to-publish",
2963
+ defaultMessage: "Ready to publish"
2964
+ }) })
2965
+ ] });
2966
+ };
2967
+ const TABLE_HEADERS = [
2968
+ { name: "id", label: "id" },
2969
+ { name: "name", label: "name" },
2970
+ { name: "status", label: "status" },
2971
+ { name: "publicationStatus", label: "Publication status" }
2972
+ ];
2973
+ const SelectedEntriesTableContent = ({
2974
+ isPublishing,
2975
+ rowsToDisplay = [],
2976
+ entriesToPublish = [],
2977
+ validationErrors = {}
2978
+ }) => {
2979
+ const { pathname } = useLocation();
2980
+ const { formatMessage } = useIntl();
2981
+ const {
2982
+ list: {
2983
+ settings: { mainField }
2984
+ }
2985
+ } = useDocLayout();
2986
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
2987
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
2988
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
2989
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
2990
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
2991
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
2992
+ )
2993
+ ] }),
2994
+ /* @__PURE__ */ jsx(Table.Loading, {}),
2995
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
2996
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
2997
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
2998
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
2999
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3000
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3001
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3002
+ id: "content-manager.success.record.publishing",
3003
+ defaultMessage: "Publishing..."
3004
+ }) }),
3005
+ /* @__PURE__ */ jsx(Loader, { small: true })
3006
+ ] }) : /* @__PURE__ */ jsx(
3007
+ EntryValidationText,
3008
+ {
3009
+ validationErrors: validationErrors[row.documentId],
3010
+ status: row.status
3011
+ }
3012
+ ) }),
3013
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3014
+ IconButton,
3015
+ {
3016
+ tag: Link,
3017
+ to: {
3018
+ pathname: `${pathname}/${row.documentId}`,
3019
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3020
+ },
3021
+ state: { from: pathname },
3022
+ label: formatMessage(
3023
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3024
+ {
3025
+ target: formatMessage(
3026
+ {
3027
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3028
+ defaultMessage: "item line {number}"
3029
+ },
3030
+ { number: index2 + 1 }
3031
+ )
3032
+ }
3033
+ ),
3034
+ target: "_blank",
3035
+ marginLeft: "auto",
3036
+ children: /* @__PURE__ */ jsx(Pencil, {})
3037
+ }
3038
+ ) })
3039
+ ] }, row.id)) })
3040
+ ] });
3041
+ };
3042
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3043
+ const SelectedEntriesModalContent = ({
3044
+ listViewSelectedEntries,
3045
+ toggleModal,
3046
+ setListViewSelectedDocuments,
3047
+ model
3048
+ }) => {
3049
+ const { formatMessage } = useIntl();
3050
+ const { schema, components } = useContentTypeSchema(model);
3051
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3052
+ const [{ query }] = useQueryParams();
3053
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3054
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3055
+ {
3056
+ model,
3057
+ params: {
3058
+ page: "1",
3059
+ pageSize: documentIds.length.toString(),
3060
+ sort: query.sort,
3061
+ filters: {
3062
+ documentId: {
3063
+ $in: documentIds
3064
+ }
3065
+ },
3066
+ locale: query.plugins?.i18n?.locale
3067
+ }
2915
3068
  },
2916
- [data, isLoading, schemas, schema, components]
3069
+ {
3070
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3071
+ }
2917
3072
  );
2918
- const listLayout = React.useMemo(() => {
2919
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2920
- layout: [],
2921
- metadatas: {},
2922
- options: {},
2923
- settings: DEFAULT_SETTINGS
3073
+ const { rows, validationErrors } = React.useMemo(() => {
3074
+ if (data.length > 0 && schema) {
3075
+ const validate = createYupSchema(schema.attributes, components);
3076
+ const validationErrors2 = {};
3077
+ const rows2 = data.map((entry) => {
3078
+ try {
3079
+ validate.validateSync(entry, { abortEarly: false });
3080
+ return entry;
3081
+ } catch (e) {
3082
+ if (e instanceof ValidationError) {
3083
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3084
+ }
3085
+ return entry;
3086
+ }
3087
+ });
3088
+ return { rows: rows2, validationErrors: validationErrors2 };
3089
+ }
3090
+ return {
3091
+ rows: [],
3092
+ validationErrors: {}
2924
3093
  };
2925
- }, [data, isLoading, schemas, schema, components]);
2926
- const { layout: edit } = React.useMemo(
2927
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2928
- layout: editLayout,
2929
- query
2930
- }),
2931
- [editLayout, query, runHookWaterfall]
3094
+ }, [components, data, schema]);
3095
+ const [publishedCount, setPublishedCount] = React.useState(0);
3096
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3097
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3098
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3099
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3100
+ const selectedEntries = rows.filter(
3101
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
2932
3102
  );
3103
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3104
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3105
+ ({ documentId }) => validationErrors[documentId]
3106
+ ).length;
3107
+ const selectedEntriesPublished = selectedEntries.filter(
3108
+ ({ status }) => status === "published"
3109
+ ).length;
3110
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3111
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3112
+ const handleConfirmBulkPublish = async () => {
3113
+ toggleDialog();
3114
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3115
+ if (!("error" in res)) {
3116
+ setPublishedCount(res.count);
3117
+ const unpublishedEntries = rows.filter((row) => {
3118
+ return !entriesToPublish.includes(row.documentId);
3119
+ });
3120
+ setListViewSelectedDocuments(unpublishedEntries);
3121
+ }
3122
+ };
3123
+ const getFormattedCountMessage = () => {
3124
+ if (publishedCount) {
3125
+ return formatMessage(
3126
+ {
3127
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3128
+ 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."
3129
+ },
3130
+ {
3131
+ publishedCount,
3132
+ withErrorsCount: selectedEntriesWithErrorsCount,
3133
+ b: BoldChunk
3134
+ }
3135
+ );
3136
+ }
3137
+ return formatMessage(
3138
+ {
3139
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3140
+ 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."
3141
+ },
3142
+ {
3143
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3144
+ withErrorsCount: selectedEntriesWithErrorsCount,
3145
+ alreadyPublishedCount: selectedEntriesPublished,
3146
+ b: BoldChunk
3147
+ }
3148
+ );
3149
+ };
3150
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3151
+ /* @__PURE__ */ jsxs(Modal.Body, { children: [
3152
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3153
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3154
+ SelectedEntriesTableContent,
3155
+ {
3156
+ isPublishing: isSubmittingForm,
3157
+ rowsToDisplay: rows,
3158
+ entriesToPublish,
3159
+ validationErrors
3160
+ }
3161
+ ) })
3162
+ ] }),
3163
+ /* @__PURE__ */ jsxs(Modal.Footer, { children: [
3164
+ /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3165
+ id: "app.components.Button.cancel",
3166
+ defaultMessage: "Cancel"
3167
+ }) }),
3168
+ /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3169
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3170
+ /* @__PURE__ */ jsx(
3171
+ Button,
3172
+ {
3173
+ onClick: toggleDialog,
3174
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3175
+ loading: isSubmittingForm,
3176
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3177
+ }
3178
+ )
3179
+ ] })
3180
+ ] }),
3181
+ /* @__PURE__ */ jsx(
3182
+ ConfirmDialogPublishAll,
3183
+ {
3184
+ isOpen: isDialogOpen,
3185
+ onToggleDialog: toggleDialog,
3186
+ isConfirmButtonLoading: isSubmittingForm,
3187
+ onConfirm: handleConfirmBulkPublish
3188
+ }
3189
+ )
3190
+ ] });
3191
+ };
3192
+ const PublishAction = ({ documents, model }) => {
3193
+ const { formatMessage } = useIntl();
3194
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3195
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3196
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3197
+ const refetchList = () => {
3198
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3199
+ };
3200
+ if (!showPublishButton)
3201
+ return null;
3202
+ return {
3203
+ actionType: "publish",
3204
+ variant: "tertiary",
3205
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
3206
+ dialog: {
3207
+ type: "modal",
3208
+ title: formatMessage({
3209
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3210
+ defaultMessage: "Publish entries"
3211
+ }),
3212
+ content: ({ onClose }) => {
3213
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3214
+ SelectedEntriesModalContent,
3215
+ {
3216
+ listViewSelectedEntries: documents,
3217
+ toggleModal: () => {
3218
+ onClose();
3219
+ refetchList();
3220
+ },
3221
+ setListViewSelectedDocuments,
3222
+ model
3223
+ }
3224
+ ) });
3225
+ },
3226
+ onClose: () => {
3227
+ refetchList();
3228
+ }
3229
+ }
3230
+ };
3231
+ };
3232
+ const BulkActionsRenderer = () => {
3233
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3234
+ const { model, collectionType } = useDoc();
3235
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3236
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3237
+ DescriptionComponentRenderer,
3238
+ {
3239
+ props: {
3240
+ model,
3241
+ collectionType,
3242
+ documents: selectedRows
3243
+ },
3244
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3245
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
3246
+ }
3247
+ ) });
3248
+ };
3249
+ const DeleteAction = ({ documents, model }) => {
3250
+ const { formatMessage } = useIntl();
3251
+ const { schema: contentType } = useDoc();
3252
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3253
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3254
+ const [{ query }] = useQueryParams();
3255
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3256
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3257
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3258
+ const documentIds = documents.map(({ documentId }) => documentId);
3259
+ const handleConfirmBulkDelete = async () => {
3260
+ const res = await bulkDeleteAction({
3261
+ documentIds,
3262
+ model,
3263
+ params
3264
+ });
3265
+ if (!("error" in res)) {
3266
+ selectRow([]);
3267
+ }
3268
+ };
3269
+ if (!hasDeletePermission)
3270
+ return null;
2933
3271
  return {
2934
- error,
2935
- isLoading,
2936
- edit,
2937
- list: listLayout
3272
+ variant: "danger-light",
3273
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3274
+ dialog: {
3275
+ type: "dialog",
3276
+ title: formatMessage({
3277
+ id: "app.components.ConfirmDialog.title",
3278
+ defaultMessage: "Confirmation"
3279
+ }),
3280
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3281
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3282
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3283
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3284
+ defaultMessage: "Are you sure you want to delete these entries?"
3285
+ }) }),
3286
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3287
+ {
3288
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3289
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3290
+ },
3291
+ {
3292
+ em: Emphasis
3293
+ }
3294
+ ) }) })
3295
+ ] }),
3296
+ onConfirm: handleConfirmBulkDelete
3297
+ }
2938
3298
  };
2939
3299
  };
2940
- const useDocLayout = () => {
2941
- const { model } = useDoc();
2942
- return useDocumentLayout(model);
3300
+ DeleteAction.type = "delete";
3301
+ const UnpublishAction = ({ documents, model }) => {
3302
+ const { formatMessage } = useIntl();
3303
+ const { schema } = useDoc();
3304
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3305
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3306
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3307
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3308
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3309
+ const documentIds = documents.map(({ documentId }) => documentId);
3310
+ const [{ query }] = useQueryParams();
3311
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3312
+ const handleConfirmBulkUnpublish = async () => {
3313
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3314
+ if (!("error" in data)) {
3315
+ selectRow([]);
3316
+ }
3317
+ };
3318
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3319
+ if (!showUnpublishButton)
3320
+ return null;
3321
+ return {
3322
+ variant: "tertiary",
3323
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3324
+ dialog: {
3325
+ type: "dialog",
3326
+ title: formatMessage({
3327
+ id: "app.components.ConfirmDialog.title",
3328
+ defaultMessage: "Confirmation"
3329
+ }),
3330
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3331
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
3332
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3333
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3334
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3335
+ }) }),
3336
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3337
+ {
3338
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3339
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3340
+ },
3341
+ {
3342
+ em: Emphasis
3343
+ }
3344
+ ) }) })
3345
+ ] }),
3346
+ confirmButton: formatMessage({
3347
+ id: "app.utils.unpublish",
3348
+ defaultMessage: "Unpublish"
3349
+ }),
3350
+ onConfirm: handleConfirmBulkUnpublish
3351
+ }
3352
+ };
2943
3353
  };
2944
- const formatEditLayout = (data, {
2945
- schemas,
2946
- schema,
2947
- components
2948
- }) => {
2949
- let currentPanelIndex = 0;
2950
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2951
- data.contentType.layouts.edit,
2952
- schema?.attributes,
2953
- data.contentType.metadatas,
2954
- { configurations: data.components, schemas: components },
2955
- schemas
2956
- ).reduce((panels, row) => {
2957
- if (row.some((field) => field.type === "dynamiczone")) {
2958
- panels.push([row]);
2959
- currentPanelIndex += 2;
2960
- } else {
2961
- if (!panels[currentPanelIndex]) {
2962
- panels.push([]);
3354
+ UnpublishAction.type = "unpublish";
3355
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3356
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3357
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3358
+ const { formatMessage } = useIntl();
3359
+ const getDefaultErrorMessage = (reason) => {
3360
+ switch (reason) {
3361
+ case "relation":
3362
+ return "Duplicating the relation could remove it from the original entry.";
3363
+ case "unique":
3364
+ return "Identical values in a unique field are not allowed";
3365
+ default:
3366
+ return reason;
3367
+ }
3368
+ };
3369
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3370
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3371
+ id: getTranslation("containers.list.autoCloneModal.title"),
3372
+ defaultMessage: "This entry can't be duplicated directly."
3373
+ }) }),
3374
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3375
+ id: getTranslation("containers.list.autoCloneModal.description"),
3376
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3377
+ }) }) }),
3378
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3379
+ Flex,
3380
+ {
3381
+ direction: "column",
3382
+ gap: 2,
3383
+ alignItems: "flex-start",
3384
+ borderColor: "neutral200",
3385
+ hasRadius: true,
3386
+ padding: 6,
3387
+ children: [
3388
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3389
+ pathSegment,
3390
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3391
+ ChevronRight,
3392
+ {
3393
+ fill: "neutral500",
3394
+ height: "0.8rem",
3395
+ width: "0.8rem",
3396
+ style: { margin: "0 0.8rem" }
3397
+ }
3398
+ )
3399
+ ] }, index2)) }),
3400
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3401
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3402
+ defaultMessage: getDefaultErrorMessage(reason)
3403
+ }) })
3404
+ ]
3405
+ },
3406
+ fieldPath.join()
3407
+ )) })
3408
+ ] });
3409
+ };
3410
+ const TableActions = ({ document }) => {
3411
+ const { formatMessage } = useIntl();
3412
+ const { model, collectionType } = useDoc();
3413
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3414
+ const props = {
3415
+ activeTab: null,
3416
+ model,
3417
+ documentId: document.documentId,
3418
+ collectionType,
3419
+ document
3420
+ };
3421
+ return /* @__PURE__ */ jsx(
3422
+ DescriptionComponentRenderer,
3423
+ {
3424
+ props,
3425
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3426
+ children: (actions2) => {
3427
+ const tableRowActions = actions2.filter((action) => {
3428
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3429
+ return positions.includes("table-row");
3430
+ });
3431
+ return /* @__PURE__ */ jsx(
3432
+ DocumentActionsMenu,
3433
+ {
3434
+ actions: tableRowActions,
3435
+ label: formatMessage({
3436
+ id: "content-manager.containers.list.table.row-actions",
3437
+ defaultMessage: "Row action"
3438
+ }),
3439
+ variant: "ghost"
3440
+ }
3441
+ );
2963
3442
  }
2964
- panels[currentPanelIndex].push(row);
2965
3443
  }
2966
- return panels;
2967
- }, []);
2968
- const componentEditAttributes = Object.entries(data.components).reduce(
2969
- (acc, [uid, configuration]) => {
2970
- acc[uid] = {
2971
- layout: convertEditLayoutToFieldLayouts(
2972
- configuration.layouts.edit,
2973
- components[uid].attributes,
2974
- configuration.metadatas
2975
- ),
2976
- settings: {
2977
- ...configuration.settings,
2978
- icon: components[uid].info.icon,
2979
- displayName: components[uid].info.displayName
2980
- }
2981
- };
2982
- return acc;
2983
- },
2984
- {}
2985
- );
2986
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2987
- (acc, [attribute, metadata]) => {
2988
- return {
2989
- ...acc,
2990
- [attribute]: metadata.edit
2991
- };
2992
- },
2993
- {}
2994
3444
  );
3445
+ };
3446
+ const EditAction = ({ documentId }) => {
3447
+ const navigate = useNavigate();
3448
+ const { formatMessage } = useIntl();
3449
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3450
+ const { toggleNotification } = useNotification();
3451
+ const [{ query }] = useQueryParams();
2995
3452
  return {
2996
- layout: panelledEditAttributes,
2997
- components: componentEditAttributes,
2998
- metadatas: editMetadatas,
2999
- settings: {
3000
- ...data.contentType.settings,
3001
- displayName: schema?.info.displayName
3002
- },
3003
- options: {
3004
- ...schema?.options,
3005
- ...schema?.pluginOptions,
3006
- ...data.contentType.options
3453
+ disabled: !canRead,
3454
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3455
+ label: formatMessage({
3456
+ id: "content-manager.actions.edit.label",
3457
+ defaultMessage: "Edit"
3458
+ }),
3459
+ position: "table-row",
3460
+ onClick: async () => {
3461
+ if (!documentId) {
3462
+ console.error(
3463
+ "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
3464
+ );
3465
+ toggleNotification({
3466
+ message: formatMessage({
3467
+ id: "content-manager.actions.edit.error",
3468
+ defaultMessage: "An error occurred while trying to edit the document."
3469
+ }),
3470
+ type: "danger"
3471
+ });
3472
+ return;
3473
+ }
3474
+ navigate({
3475
+ pathname: documentId,
3476
+ search: stringify({
3477
+ plugins: query.plugins
3478
+ })
3479
+ });
3007
3480
  }
3008
3481
  };
3009
3482
  };
3010
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3011
- return rows.map(
3012
- (row) => row.map((field) => {
3013
- const attribute = attributes[field.name];
3014
- if (!attribute) {
3015
- return null;
3483
+ EditAction.type = "edit";
3484
+ const StyledPencil = styled(Pencil)`
3485
+ path {
3486
+ fill: currentColor;
3487
+ }
3488
+ `;
3489
+ const CloneAction = ({ model, documentId }) => {
3490
+ const navigate = useNavigate();
3491
+ const { formatMessage } = useIntl();
3492
+ const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
3493
+ const { toggleNotification } = useNotification();
3494
+ const { autoClone } = useDocumentActions();
3495
+ const [prohibitedFields, setProhibitedFields] = React.useState([]);
3496
+ return {
3497
+ disabled: !canCreate,
3498
+ icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
3499
+ label: formatMessage({
3500
+ id: "content-manager.actions.clone.label",
3501
+ defaultMessage: "Duplicate"
3502
+ }),
3503
+ position: "table-row",
3504
+ onClick: async () => {
3505
+ if (!documentId) {
3506
+ console.error(
3507
+ "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
3508
+ );
3509
+ toggleNotification({
3510
+ message: formatMessage({
3511
+ id: "content-manager.actions.clone.error",
3512
+ defaultMessage: "An error occurred while trying to clone the document."
3513
+ }),
3514
+ type: "danger"
3515
+ });
3516
+ return;
3517
+ }
3518
+ const res = await autoClone({ model, sourceId: documentId });
3519
+ if ("data" in res) {
3520
+ navigate(res.data.documentId);
3521
+ return true;
3522
+ }
3523
+ if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
3524
+ const prohibitedFields2 = res.error.details.prohibitedFields;
3525
+ setProhibitedFields(prohibitedFields2);
3016
3526
  }
3017
- const { edit: metadata } = metadatas[field.name];
3018
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3019
- return {
3020
- attribute,
3021
- disabled: !metadata.editable,
3022
- hint: metadata.description,
3023
- label: metadata.label ?? "",
3024
- name: field.name,
3025
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3026
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3027
- schemas,
3028
- components: components?.schemas ?? {}
3029
- }),
3030
- placeholder: metadata.placeholder ?? "",
3031
- required: attribute.required ?? false,
3032
- size: field.size,
3033
- unique: "unique" in attribute ? attribute.unique : false,
3034
- visible: metadata.visible ?? true,
3035
- type: attribute.type
3036
- };
3037
- }).filter((field) => field !== null)
3038
- );
3039
- };
3040
- const formatListLayout = (data, {
3041
- schemas,
3042
- schema,
3043
- components
3044
- }) => {
3045
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3046
- (acc, [attribute, metadata]) => {
3047
- return {
3048
- ...acc,
3049
- [attribute]: metadata.list
3050
- };
3051
3527
  },
3052
- {}
3053
- );
3054
- const listAttributes = convertListLayoutToFieldLayouts(
3055
- data.contentType.layouts.list,
3056
- schema?.attributes,
3057
- listMetadatas,
3058
- { configurations: data.components, schemas: components },
3059
- schemas
3060
- );
3061
- return {
3062
- layout: listAttributes,
3063
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3064
- metadatas: listMetadatas,
3065
- options: {
3066
- ...schema?.options,
3067
- ...schema?.pluginOptions,
3068
- ...data.contentType.options
3528
+ dialog: {
3529
+ type: "modal",
3530
+ title: formatMessage({
3531
+ id: "content-manager.containers.list.autoCloneModal.header",
3532
+ defaultMessage: "Duplicate"
3533
+ }),
3534
+ content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3535
+ footer: ({ onClose }) => {
3536
+ return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3537
+ /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3538
+ id: "cancel",
3539
+ defaultMessage: "Cancel"
3540
+ }) }),
3541
+ /* @__PURE__ */ jsx(
3542
+ LinkButton,
3543
+ {
3544
+ tag: NavLink,
3545
+ to: {
3546
+ pathname: `clone/${documentId}`
3547
+ },
3548
+ children: formatMessage({
3549
+ id: "content-manager.containers.list.autoCloneModal.create",
3550
+ defaultMessage: "Create"
3551
+ })
3552
+ }
3553
+ )
3554
+ ] });
3555
+ }
3069
3556
  }
3070
3557
  };
3071
3558
  };
3072
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3073
- return columns.map((name) => {
3074
- const attribute = attributes[name];
3075
- if (!attribute) {
3076
- return null;
3559
+ CloneAction.type = "clone";
3560
+ const StyledDuplicate = styled(Duplicate)`
3561
+ path {
3562
+ fill: currentColor;
3563
+ }
3564
+ `;
3565
+ const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
3566
+ class ContentManagerPlugin {
3567
+ /**
3568
+ * The following properties are the stored ones provided by any plugins registering with
3569
+ * the content-manager. The function calls however, need to be called at runtime in the
3570
+ * application, so instead we collate them and run them later with the complete list incl.
3571
+ * ones already registered & the context of the view.
3572
+ */
3573
+ bulkActions = [...DEFAULT_BULK_ACTIONS];
3574
+ documentActions = [
3575
+ ...DEFAULT_ACTIONS,
3576
+ ...DEFAULT_TABLE_ROW_ACTIONS,
3577
+ ...DEFAULT_HEADER_ACTIONS,
3578
+ HistoryAction
3579
+ ];
3580
+ editViewSidePanels = [ActionsPanel];
3581
+ headerActions = [];
3582
+ constructor() {
3583
+ }
3584
+ addEditViewSidePanel(panels) {
3585
+ if (Array.isArray(panels)) {
3586
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3587
+ } else if (typeof panels === "function") {
3588
+ this.editViewSidePanels = panels(this.editViewSidePanels);
3589
+ } else {
3590
+ throw new Error(
3591
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3592
+ panels
3593
+ )}`
3594
+ );
3077
3595
  }
3078
- const metadata = metadatas[name];
3079
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3596
+ }
3597
+ addDocumentAction(actions2) {
3598
+ if (Array.isArray(actions2)) {
3599
+ this.documentActions = [...this.documentActions, ...actions2];
3600
+ } else if (typeof actions2 === "function") {
3601
+ this.documentActions = actions2(this.documentActions);
3602
+ } else {
3603
+ throw new Error(
3604
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
3605
+ actions2
3606
+ )}`
3607
+ );
3608
+ }
3609
+ }
3610
+ addDocumentHeaderAction(actions2) {
3611
+ if (Array.isArray(actions2)) {
3612
+ this.headerActions = [...this.headerActions, ...actions2];
3613
+ } else if (typeof actions2 === "function") {
3614
+ this.headerActions = actions2(this.headerActions);
3615
+ } else {
3616
+ throw new Error(
3617
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3618
+ actions2
3619
+ )}`
3620
+ );
3621
+ }
3622
+ }
3623
+ addBulkAction(actions2) {
3624
+ if (Array.isArray(actions2)) {
3625
+ this.bulkActions = [...this.bulkActions, ...actions2];
3626
+ } else if (typeof actions2 === "function") {
3627
+ this.bulkActions = actions2(this.bulkActions);
3628
+ } else {
3629
+ throw new Error(
3630
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3631
+ actions2
3632
+ )}`
3633
+ );
3634
+ }
3635
+ }
3636
+ get config() {
3080
3637
  return {
3081
- attribute,
3082
- label: metadata.label ?? "",
3083
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3084
- schemas,
3085
- components: components?.schemas ?? {}
3086
- }),
3087
- name,
3088
- searchable: metadata.searchable ?? true,
3089
- sortable: metadata.sortable ?? true
3638
+ id: PLUGIN_ID,
3639
+ name: "Content Manager",
3640
+ injectionZones: INJECTION_ZONES,
3641
+ apis: {
3642
+ addBulkAction: this.addBulkAction.bind(this),
3643
+ addDocumentAction: this.addDocumentAction.bind(this),
3644
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3645
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3646
+ getBulkActions: () => this.bulkActions,
3647
+ getDocumentActions: () => this.documentActions,
3648
+ getEditViewSidePanels: () => this.editViewSidePanels,
3649
+ getHeaderActions: () => this.headerActions
3650
+ }
3090
3651
  };
3091
- }).filter((field) => field !== null);
3652
+ }
3653
+ }
3654
+ const getPrintableType = (value) => {
3655
+ const nativeType = typeof value;
3656
+ if (nativeType === "object") {
3657
+ if (value === null)
3658
+ return "null";
3659
+ if (Array.isArray(value))
3660
+ return "array";
3661
+ if (value instanceof Object && value.constructor.name !== "Object") {
3662
+ return value.constructor.name;
3663
+ }
3664
+ }
3665
+ return nativeType;
3666
+ };
3667
+ const initialState = {
3668
+ collectionTypeLinks: [],
3669
+ components: [],
3670
+ fieldSizes: {},
3671
+ models: [],
3672
+ singleTypeLinks: [],
3673
+ isLoading: true
3092
3674
  };
3675
+ const appSlice = createSlice({
3676
+ name: "app",
3677
+ initialState,
3678
+ reducers: {
3679
+ setInitialData(state, action) {
3680
+ const {
3681
+ authorizedCollectionTypeLinks,
3682
+ authorizedSingleTypeLinks,
3683
+ components,
3684
+ contentTypeSchemas,
3685
+ fieldSizes
3686
+ } = action.payload;
3687
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3688
+ ({ isDisplayed }) => isDisplayed
3689
+ );
3690
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3691
+ state.components = components;
3692
+ state.models = contentTypeSchemas;
3693
+ state.fieldSizes = fieldSizes;
3694
+ state.isLoading = false;
3695
+ }
3696
+ }
3697
+ });
3698
+ const { actions, reducer: reducer$1 } = appSlice;
3699
+ const { setInitialData } = actions;
3700
+ const reducer = combineReducers({
3701
+ app: reducer$1
3702
+ });
3093
3703
  const index = {
3094
3704
  register(app) {
3095
3705
  const cm = new ContentManagerPlugin();
3096
3706
  app.addReducers({
3097
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3098
3707
  [PLUGIN_ID]: reducer
3099
3708
  });
3100
- app.addMiddlewares([() => contentManagerApi.middleware]);
3101
3709
  app.addMenuLink({
3102
3710
  to: PLUGIN_ID,
3103
3711
  icon: Feather,
@@ -3106,14 +3714,24 @@ const index = {
3106
3714
  defaultMessage: "Content Manager"
3107
3715
  },
3108
3716
  permissions: [],
3109
- Component: () => import("./layout-CXsHbc3E.mjs").then((mod) => ({ default: mod.Layout }))
3717
+ position: 1
3718
+ });
3719
+ app.router.addRoute({
3720
+ path: "content-manager/*",
3721
+ lazy: async () => {
3722
+ const { Layout } = await import("./layout-Bx7svTbY.mjs");
3723
+ return {
3724
+ Component: Layout
3725
+ };
3726
+ },
3727
+ children: routes
3110
3728
  });
3111
3729
  app.registerPlugin(cm.config);
3112
3730
  },
3113
3731
  async registerTrads({ locales }) {
3114
3732
  const importedTrads = await Promise.all(
3115
3733
  locales.map((locale) => {
3116
- return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-MBPul9Su.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3734
+ return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-Ux26r5pl.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
3117
3735
  return {
3118
3736
  data: prefixPluginTranslations(data, PLUGIN_ID),
3119
3737
  locale
@@ -3131,7 +3749,7 @@ const index = {
3131
3749
  };
3132
3750
  export {
3133
3751
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3134
- extractContentTypeComponents as B,
3752
+ BulkActionsRenderer as B,
3135
3753
  COLLECTION_TYPES as C,
3136
3754
  DocumentStatus as D,
3137
3755
  DEFAULT_SETTINGS as E,
@@ -3145,31 +3763,31 @@ export {
3145
3763
  RelativeTime as R,
3146
3764
  SINGLE_TYPES as S,
3147
3765
  TableActions as T,
3148
- useGetAllContentTypeSettingsQuery as a,
3149
- useDoc as b,
3150
- buildValidParams as c,
3151
- contentManagerApi as d,
3152
- useDocumentRBAC as e,
3153
- useDocumentLayout as f,
3766
+ useGetInitialDataQuery as a,
3767
+ useGetAllContentTypeSettingsQuery as b,
3768
+ useDoc as c,
3769
+ buildValidParams as d,
3770
+ contentManagerApi as e,
3771
+ useDocumentRBAC as f,
3154
3772
  getTranslation as g,
3155
- createYupSchema as h,
3156
- Header as i,
3157
- PERMISSIONS as j,
3158
- DocumentRBAC as k,
3159
- DOCUMENT_META_FIELDS as l,
3160
- useDocLayout as m,
3161
- useContentTypeSchema as n,
3773
+ useDocumentLayout as h,
3774
+ createYupSchema as i,
3775
+ Header as j,
3776
+ PERMISSIONS as k,
3777
+ DocumentRBAC as l,
3778
+ DOCUMENT_META_FIELDS as m,
3779
+ useDocLayout as n,
3162
3780
  useGetContentTypeConfigurationQuery as o,
3163
3781
  CREATOR_FIELDS as p,
3164
3782
  getMainField as q,
3165
- routes as r,
3783
+ getDisplayName as r,
3166
3784
  setInitialData as s,
3167
- getDisplayName as t,
3168
- useGetInitialDataQuery as u,
3169
- checkIfAttributeIsDisplayable as v,
3170
- useGetAllDocumentsQuery as w,
3171
- convertListLayoutToFieldLayouts as x,
3172
- capitalise as y,
3173
- useUpdateContentTypeConfigurationMutation as z
3174
- };
3175
- //# sourceMappingURL=index-CAc9yTnx.mjs.map
3785
+ checkIfAttributeIsDisplayable as t,
3786
+ useContentTypeSchema as u,
3787
+ useGetAllDocumentsQuery as v,
3788
+ convertListLayoutToFieldLayouts as w,
3789
+ capitalise as x,
3790
+ useUpdateContentTypeConfigurationMutation as y,
3791
+ extractContentTypeComponents as z
3792
+ };
3793
+ //# sourceMappingURL=index-CaE6NG4a.mjs.map