@strapi/content-manager 5.0.0-beta.7 → 5.0.0-beta.9

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 (146) hide show
  1. package/dist/_chunks/{ComponentConfigurationPage-uTMkLI60.mjs → ComponentConfigurationPage-BMajAl1u.mjs} +3 -3
  2. package/dist/_chunks/{ComponentConfigurationPage-uTMkLI60.mjs.map → ComponentConfigurationPage-BMajAl1u.mjs.map} +1 -1
  3. package/dist/_chunks/{ComponentConfigurationPage-DMq0wvcL.js → ComponentConfigurationPage-y_7iLdmB.js} +3 -3
  4. package/dist/_chunks/{ComponentConfigurationPage-DMq0wvcL.js.map → ComponentConfigurationPage-y_7iLdmB.js.map} +1 -1
  5. package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
  6. package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
  7. package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
  8. package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
  9. package/dist/_chunks/{EditConfigurationPage-BFpQwwbc.js → EditConfigurationPage-CPVB8Uqc.js} +3 -3
  10. package/dist/_chunks/{EditConfigurationPage-BFpQwwbc.js.map → EditConfigurationPage-CPVB8Uqc.js.map} +1 -1
  11. package/dist/_chunks/{EditConfigurationPage-B2HhCh-b.mjs → EditConfigurationPage-CcOoD26O.mjs} +3 -3
  12. package/dist/_chunks/{EditConfigurationPage-B2HhCh-b.mjs.map → EditConfigurationPage-CcOoD26O.mjs.map} +1 -1
  13. package/dist/_chunks/{EditViewPage-CXXue16T.js → EditViewPage-CTTDHKkQ.js} +5 -5
  14. package/dist/_chunks/{EditViewPage-CXXue16T.js.map → EditViewPage-CTTDHKkQ.js.map} +1 -1
  15. package/dist/_chunks/{EditViewPage-BVIrgjyG.mjs → EditViewPage-DWb0DE7R.mjs} +5 -5
  16. package/dist/_chunks/{EditViewPage-BVIrgjyG.mjs.map → EditViewPage-DWb0DE7R.mjs.map} +1 -1
  17. package/dist/_chunks/{Field-ZgzKlgxR.js → Field-C5Z1Ivdv.js} +240 -357
  18. package/dist/_chunks/Field-C5Z1Ivdv.js.map +1 -0
  19. package/dist/_chunks/{Field-0_2h1vuK.mjs → Field-DnStdvQw.mjs} +240 -357
  20. package/dist/_chunks/Field-DnStdvQw.mjs.map +1 -0
  21. package/dist/_chunks/{Form-DgTc2qkx.js → Form-B81OtW-k.js} +9 -6
  22. package/dist/_chunks/Form-B81OtW-k.js.map +1 -0
  23. package/dist/_chunks/{Form-B7TUnQDd.mjs → Form-DqGgE55Q.mjs} +9 -6
  24. package/dist/_chunks/Form-DqGgE55Q.mjs.map +1 -0
  25. package/dist/_chunks/{History-DtHjQuqM.js → History-4NbOq2dX.js} +97 -15
  26. package/dist/_chunks/History-4NbOq2dX.js.map +1 -0
  27. package/dist/_chunks/{History-Dug_4HIA.mjs → History-DS6-HCYX.mjs} +97 -15
  28. package/dist/_chunks/History-DS6-HCYX.mjs.map +1 -0
  29. package/dist/_chunks/{ListConfigurationPage-BuSdTjfa.js → ListConfigurationPage-CpfstlYY.js} +2 -2
  30. package/dist/_chunks/{ListConfigurationPage-BuSdTjfa.js.map → ListConfigurationPage-CpfstlYY.js.map} +1 -1
  31. package/dist/_chunks/{ListConfigurationPage-CmEeNg6T.mjs → ListConfigurationPage-DQJJltko.mjs} +2 -2
  32. package/dist/_chunks/{ListConfigurationPage-CmEeNg6T.mjs.map → ListConfigurationPage-DQJJltko.mjs.map} +1 -1
  33. package/dist/_chunks/{ListViewPage-CExWwa4S.js → ListViewPage-CA3I75m5.js} +23 -18
  34. package/dist/_chunks/ListViewPage-CA3I75m5.js.map +1 -0
  35. package/dist/_chunks/{ListViewPage-Dsoa3wEA.mjs → ListViewPage-nQrOQuVo.mjs} +21 -17
  36. package/dist/_chunks/ListViewPage-nQrOQuVo.mjs.map +1 -0
  37. package/dist/_chunks/{NoContentTypePage-Dh38hBXB.mjs → NoContentTypePage-DbnHE22g.mjs} +2 -2
  38. package/dist/_chunks/{NoContentTypePage-Dh38hBXB.mjs.map → NoContentTypePage-DbnHE22g.mjs.map} +1 -1
  39. package/dist/_chunks/{NoContentTypePage-DCUL8gVi.js → NoContentTypePage-Dldu-_Mx.js} +2 -2
  40. package/dist/_chunks/{NoContentTypePage-DCUL8gVi.js.map → NoContentTypePage-Dldu-_Mx.js.map} +1 -1
  41. package/dist/_chunks/{NoPermissionsPage-BK-XCpIy.js → NoPermissionsPage-CO2MK200.js} +2 -2
  42. package/dist/_chunks/{NoPermissionsPage-BK-XCpIy.js.map → NoPermissionsPage-CO2MK200.js.map} +1 -1
  43. package/dist/_chunks/{NoPermissionsPage-Dt2O40ey.mjs → NoPermissionsPage-fOIkQM0v.mjs} +2 -2
  44. package/dist/_chunks/{NoPermissionsPage-Dt2O40ey.mjs.map → NoPermissionsPage-fOIkQM0v.mjs.map} +1 -1
  45. package/dist/_chunks/{Relations-DZyjWZHl.mjs → Relations-BDRl99Ux.mjs} +8 -6
  46. package/dist/_chunks/{Relations-DZyjWZHl.mjs.map → Relations-BDRl99Ux.mjs.map} +1 -1
  47. package/dist/_chunks/{Relations-CNypkp-g.js → Relations-DG2jnOcr.js} +8 -6
  48. package/dist/_chunks/{Relations-CNypkp-g.js.map → Relations-DG2jnOcr.js.map} +1 -1
  49. package/dist/_chunks/{en-MBPul9Su.mjs → en-Ux26r5pl.mjs} +7 -1
  50. package/dist/_chunks/{en-MBPul9Su.mjs.map → en-Ux26r5pl.mjs.map} +1 -1
  51. package/dist/_chunks/{en-C-V1_90f.js → en-fbKQxLGn.js} +7 -1
  52. package/dist/_chunks/{en-C-V1_90f.js.map → en-fbKQxLGn.js.map} +1 -1
  53. package/dist/_chunks/{index-DFK7LwDW.js → index-BZoNZMXL.js} +1528 -779
  54. package/dist/_chunks/index-BZoNZMXL.js.map +1 -0
  55. package/dist/_chunks/{index-B3c-4it4.mjs → index-Drt2DN7v.mjs} +1552 -803
  56. package/dist/_chunks/index-Drt2DN7v.mjs.map +1 -0
  57. package/dist/_chunks/{layout-B5cm7cZj.mjs → layout-BzAbmoO6.mjs} +20 -15
  58. package/dist/_chunks/layout-BzAbmoO6.mjs.map +1 -0
  59. package/dist/_chunks/{layout-DLih5-_W.js → layout-DEYBqgF1.js} +20 -15
  60. package/dist/_chunks/layout-DEYBqgF1.js.map +1 -0
  61. package/dist/_chunks/{relations-CTvkuINQ.js → relations-D0eZ4VWw.js} +2 -2
  62. package/dist/_chunks/{relations-CTvkuINQ.js.map → relations-D0eZ4VWw.js.map} +1 -1
  63. package/dist/_chunks/{relations-BZkrMa2z.mjs → relations-D26zVRdi.mjs} +2 -2
  64. package/dist/_chunks/{relations-BZkrMa2z.mjs.map → relations-D26zVRdi.mjs.map} +1 -1
  65. package/dist/_chunks/usePrev-B9w_-eYc.js +15 -0
  66. package/dist/_chunks/usePrev-B9w_-eYc.js.map +1 -0
  67. package/dist/_chunks/usePrev-DH6iah0A.mjs +16 -0
  68. package/dist/_chunks/usePrev-DH6iah0A.mjs.map +1 -0
  69. package/dist/admin/index.js +2 -1
  70. package/dist/admin/index.js.map +1 -1
  71. package/dist/admin/index.mjs +8 -7
  72. package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
  73. package/dist/admin/src/content-manager.d.ts +3 -3
  74. package/dist/admin/src/exports.d.ts +1 -0
  75. package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
  76. package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
  77. package/dist/admin/src/hooks/useDocument.d.ts +5 -8
  78. package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
  79. package/dist/admin/src/hooks/useDocumentLayout.d.ts +1 -1
  80. package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +3 -1
  81. package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
  82. package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
  83. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
  84. package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
  85. package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +2 -15
  86. package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
  87. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
  88. package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +56 -35
  89. package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
  90. package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
  91. package/dist/admin/src/services/api.d.ts +2 -3
  92. package/dist/admin/src/services/components.d.ts +2 -2
  93. package/dist/admin/src/services/contentTypes.d.ts +5 -5
  94. package/dist/admin/src/services/documents.d.ts +29 -17
  95. package/dist/admin/src/services/init.d.ts +2 -2
  96. package/dist/admin/src/services/relations.d.ts +3 -3
  97. package/dist/admin/src/services/uid.d.ts +3 -3
  98. package/dist/admin/src/utils/api.d.ts +4 -17
  99. package/dist/admin/src/utils/validation.d.ts +1 -6
  100. package/dist/server/index.js +247 -127
  101. package/dist/server/index.js.map +1 -1
  102. package/dist/server/index.mjs +249 -129
  103. package/dist/server/index.mjs.map +1 -1
  104. package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
  105. package/dist/server/src/controllers/single-types.d.ts.map +1 -1
  106. package/dist/server/src/controllers/utils/metadata.d.ts +8 -0
  107. package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
  108. package/dist/server/src/controllers/validation/dimensions.d.ts +9 -0
  109. package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
  110. package/dist/server/src/history/services/history.d.ts.map +1 -1
  111. package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
  112. package/dist/server/src/index.d.ts +12 -33
  113. package/dist/server/src/index.d.ts.map +1 -1
  114. package/dist/server/src/services/document-manager.d.ts +6 -6
  115. package/dist/server/src/services/document-manager.d.ts.map +1 -1
  116. package/dist/server/src/services/document-metadata.d.ts +8 -29
  117. package/dist/server/src/services/document-metadata.d.ts.map +1 -1
  118. package/dist/server/src/services/index.d.ts +12 -33
  119. package/dist/server/src/services/index.d.ts.map +1 -1
  120. package/dist/server/src/services/utils/populate.d.ts +8 -1
  121. package/dist/server/src/services/utils/populate.d.ts.map +1 -1
  122. package/dist/shared/contracts/collection-types.d.ts +11 -5
  123. package/dist/shared/contracts/collection-types.d.ts.map +1 -1
  124. package/dist/shared/contracts/relations.d.ts +2 -2
  125. package/dist/shared/contracts/relations.d.ts.map +1 -1
  126. package/package.json +11 -11
  127. package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
  128. package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
  129. package/dist/_chunks/Field-0_2h1vuK.mjs.map +0 -1
  130. package/dist/_chunks/Field-ZgzKlgxR.js.map +0 -1
  131. package/dist/_chunks/Form-B7TUnQDd.mjs.map +0 -1
  132. package/dist/_chunks/Form-DgTc2qkx.js.map +0 -1
  133. package/dist/_chunks/History-DtHjQuqM.js.map +0 -1
  134. package/dist/_chunks/History-Dug_4HIA.mjs.map +0 -1
  135. package/dist/_chunks/ListViewPage-CExWwa4S.js.map +0 -1
  136. package/dist/_chunks/ListViewPage-Dsoa3wEA.mjs.map +0 -1
  137. package/dist/_chunks/index-B3c-4it4.mjs.map +0 -1
  138. package/dist/_chunks/index-DFK7LwDW.js.map +0 -1
  139. package/dist/_chunks/layout-B5cm7cZj.mjs.map +0 -1
  140. package/dist/_chunks/layout-DLih5-_W.js.map +0 -1
  141. package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
  142. package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
  143. package/dist/_chunks/urls-DzZya_gm.js +0 -6
  144. package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
  145. package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
  146. package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
@@ -1,16 +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, isFetchError, 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";
9
+ import { Menu, VisuallyHidden, Flex, Typography, Dialog, DialogBody, DialogFooter, Button, ModalLayout, ModalHeader, ModalBody, Box, Radio, Status, SingleSelect, SingleSelectOption, ModalFooter, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
10
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
13
  import pipe from "lodash/fp/pipe";
15
14
  import { intervalToDuration, isPast } from "date-fns";
16
15
  import { createSlice, combineReducers } from "@reduxjs/toolkit";
@@ -156,9 +155,8 @@ const DocumentRBAC = ({ children, permissions }) => {
156
155
  const name = removeNumericalStrings(fieldName.split("."));
157
156
  const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
158
157
  if (fieldType === "component") {
159
- const componentOrDynamicZoneFields = componentFieldNames.map((field) => field.split("."));
160
- return componentOrDynamicZoneFields.some((field) => {
161
- return field.includes(fieldName);
158
+ return componentFieldNames.some((field) => {
159
+ return field.includes(name.join("."));
162
160
  });
163
161
  }
164
162
  if (name.length > 1) {
@@ -188,92 +186,8 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
188
186
  (field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
189
187
  );
190
188
  const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
191
- const buildValidParams = (query) => {
192
- if (!query)
193
- return query;
194
- const { plugins: _, ...validQueryParams } = {
195
- ...query,
196
- ...Object.values(query?.plugins ?? {}).reduce(
197
- (acc, current) => Object.assign(acc, current),
198
- {}
199
- )
200
- };
201
- if ("_q" in validQueryParams) {
202
- validQueryParams._q = encodeURIComponent(validQueryParams._q);
203
- }
204
- return validQueryParams;
205
- };
206
- const fetchBaseQuery = () => async (query, { signal }) => {
207
- try {
208
- const { get, post, del, put } = getFetchClient();
209
- if (typeof query === "string") {
210
- const result = await get(query, {
211
- signal
212
- });
213
- return { data: result.data };
214
- } else {
215
- const { url, method = "GET", data, config } = query;
216
- if (method === "POST") {
217
- const result2 = await post(url, data, {
218
- ...config,
219
- signal
220
- });
221
- return { data: result2.data };
222
- }
223
- if (method === "DELETE") {
224
- const result2 = await del(url, {
225
- ...config,
226
- signal
227
- });
228
- return { data: result2.data };
229
- }
230
- if (method === "PUT") {
231
- const result2 = await put(url, data, {
232
- ...config,
233
- signal
234
- });
235
- return { data: result2.data };
236
- }
237
- const result = await get(url, {
238
- ...config,
239
- signal
240
- });
241
- return { data: result.data };
242
- }
243
- } catch (err) {
244
- if (isFetchError(err)) {
245
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
246
- return { data: void 0, error: err.response?.data.error };
247
- } else {
248
- return {
249
- data: void 0,
250
- error: {
251
- name: "UnknownError",
252
- message: "There was an unknown error response from the API",
253
- details: err.response,
254
- status: err.status
255
- }
256
- };
257
- }
258
- }
259
- const error = err;
260
- return {
261
- data: void 0,
262
- error: {
263
- name: error.name,
264
- message: error.message,
265
- stack: error.stack
266
- }
267
- };
268
- }
269
- };
270
- const isBaseQueryError = (error) => {
271
- return error.name !== void 0;
272
- };
273
- const contentManagerApi = createApi({
274
- reducerPath: "contentManagerApi",
275
- baseQuery: fetchBaseQuery(),
276
- tagTypes: [
189
+ const contentManagerApi = adminApi.enhanceEndpoints({
190
+ addTagTypes: [
277
191
  "ComponentConfiguration",
278
192
  "ContentTypesConfiguration",
279
193
  "ContentTypeSettings",
@@ -281,8 +195,7 @@ const contentManagerApi = createApi({
281
195
  "InitialData",
282
196
  "HistoryVersion",
283
197
  "Relations"
284
- ],
285
- endpoints: () => ({})
198
+ ]
286
199
  });
287
200
  const documentApi = contentManagerApi.injectEndpoints({
288
201
  endpoints: (builder) => ({
@@ -338,12 +251,15 @@ const documentApi = contentManagerApi.injectEndpoints({
338
251
  ]
339
252
  }),
340
253
  deleteManyDocuments: builder.mutation({
341
- query: ({ model, ...body }) => ({
254
+ query: ({ model, params, ...body }) => ({
342
255
  url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
343
256
  method: "POST",
344
- data: body
257
+ data: body,
258
+ config: {
259
+ params
260
+ }
345
261
  }),
346
- invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
262
+ invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
347
263
  }),
348
264
  discardDocument: builder.mutation({
349
265
  query: ({ collectionType, model, documentId, params }) => ({
@@ -454,10 +370,13 @@ const documentApi = contentManagerApi.injectEndpoints({
454
370
  }
455
371
  }),
456
372
  publishManyDocuments: builder.mutation({
457
- query: ({ model, ...body }) => ({
373
+ query: ({ model, params, ...body }) => ({
458
374
  url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
459
375
  method: "POST",
460
- data: body
376
+ data: body,
377
+ config: {
378
+ params
379
+ }
461
380
  }),
462
381
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
463
382
  }),
@@ -499,10 +418,13 @@ const documentApi = contentManagerApi.injectEndpoints({
499
418
  }
500
419
  }),
501
420
  unpublishManyDocuments: builder.mutation({
502
- query: ({ model, ...body }) => ({
421
+ query: ({ model, params, ...body }) => ({
503
422
  url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
504
423
  method: "POST",
505
- data: body
424
+ data: body,
425
+ config: {
426
+ params
427
+ }
506
428
  }),
507
429
  invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
508
430
  })
@@ -526,6 +448,24 @@ const {
526
448
  useUnpublishDocumentMutation,
527
449
  useUnpublishManyDocumentsMutation
528
450
  } = documentApi;
451
+ const buildValidParams = (query) => {
452
+ if (!query)
453
+ return query;
454
+ const { plugins: _, ...validQueryParams } = {
455
+ ...query,
456
+ ...Object.values(query?.plugins ?? {}).reduce(
457
+ (acc, current) => Object.assign(acc, current),
458
+ {}
459
+ )
460
+ };
461
+ if ("_q" in validQueryParams) {
462
+ validQueryParams._q = encodeURIComponent(validQueryParams._q);
463
+ }
464
+ return validQueryParams;
465
+ };
466
+ const isBaseQueryError = (error) => {
467
+ return error.name !== void 0;
468
+ };
529
469
  const createYupSchema = (attributes = {}, components = {}) => {
530
470
  const createModelSchema = (attributes2) => yup.object().shape(
531
471
  Object.entries(attributes2).reduce((acc, [name, attribute]) => {
@@ -565,10 +505,14 @@ const createYupSchema = (attributes = {}, components = {}) => {
565
505
  yup.array().of(
566
506
  yup.lazy(
567
507
  (data) => {
568
- const { attributes: attributes3 } = components[data.__component];
569
- return yup.object().shape({
508
+ const attributes3 = components?.[data?.__component]?.attributes;
509
+ const validation = yup.object().shape({
570
510
  __component: yup.string().required().oneOf(Object.keys(components))
571
- }).nullable(false).concat(createModelSchema(attributes3));
511
+ }).nullable(false);
512
+ if (!attributes3) {
513
+ return validation;
514
+ }
515
+ return validation.concat(createModelSchema(attributes3));
572
516
  }
573
517
  )
574
518
  )
@@ -578,11 +522,25 @@ const createYupSchema = (attributes = {}, components = {}) => {
578
522
  return {
579
523
  ...acc,
580
524
  [name]: transformSchema(
581
- yup.array().of(
582
- yup.object().shape({
583
- id: yup.string().required()
584
- })
585
- )
525
+ yup.lazy((value) => {
526
+ if (!value) {
527
+ return yup.mixed().nullable(true);
528
+ } else if (Array.isArray(value)) {
529
+ return yup.array().of(
530
+ yup.object().shape({
531
+ id: yup.string().required()
532
+ })
533
+ );
534
+ } else if (typeof value === "object") {
535
+ return yup.object();
536
+ } else {
537
+ return yup.mixed().test(
538
+ "type-error",
539
+ "Relation values must be either null, an array of objects with {id} or an object.",
540
+ () => false
541
+ );
542
+ }
543
+ })
586
544
  )
587
545
  };
588
546
  default:
@@ -647,7 +605,12 @@ const addRequiredValidation = (attribute) => (schema) => {
647
605
  defaultMessage: "This field is required."
648
606
  });
649
607
  }
650
- return schema.nullable();
608
+ return schema?.nullable ? schema.nullable() : (
609
+ // In some cases '.nullable' will not be available on the schema.
610
+ // e.g. when the schema has been built using yup.lazy (e.g. for relations).
611
+ // In these cases we should just return the schema as it is.
612
+ schema
613
+ );
651
614
  };
652
615
  const addMinLengthValidation = (attribute) => (schema) => {
653
616
  if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
@@ -719,24 +682,6 @@ const addRegexValidation = (attribute) => (schema) => {
719
682
  }
720
683
  return schema;
721
684
  };
722
- const extractValuesFromYupError = (errorType, errorParams) => {
723
- if (!errorType || !errorParams) {
724
- return {};
725
- }
726
- return {
727
- [errorType]: errorParams[errorType]
728
- };
729
- };
730
- const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
731
- if (currentError.path) {
732
- acc[currentError.path.split("[").join(".").split("]").join("")] = {
733
- id: currentError.message,
734
- defaultMessage: currentError.message,
735
- values: extractValuesFromYupError(currentError?.type, currentError?.params)
736
- };
737
- }
738
- return acc;
739
- }, {});
740
685
  const initApi = contentManagerApi.injectEndpoints({
741
686
  endpoints: (builder) => ({
742
687
  getInitialData: builder.query({
@@ -750,27 +695,20 @@ const { useGetInitialDataQuery } = initApi;
750
695
  const useContentTypeSchema = (model) => {
751
696
  const { toggleNotification } = useNotification();
752
697
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
753
- const { components, contentType, contentTypes, error, isLoading, isFetching } = useGetInitialDataQuery(void 0, {
754
- selectFromResult: (res) => {
755
- const contentType2 = res.data?.contentTypes.find((ct) => ct.uid === model);
756
- const componentsByKey = res.data?.components.reduce(
757
- (acc, component) => {
758
- acc[component.uid] = component;
759
- return acc;
760
- },
761
- {}
762
- );
763
- const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
764
- return {
765
- isLoading: res.isLoading,
766
- isFetching: res.isFetching,
767
- error: res.error,
768
- components: Object.keys(components2).length === 0 ? void 0 : components2,
769
- contentType: contentType2,
770
- contentTypes: res.data?.contentTypes ?? []
771
- };
772
- }
773
- });
698
+ const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
699
+ const { components, contentType, contentTypes } = React.useMemo(() => {
700
+ const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
701
+ const componentsByKey = data?.components.reduce((acc, component) => {
702
+ acc[component.uid] = component;
703
+ return acc;
704
+ }, {});
705
+ const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
706
+ return {
707
+ components: Object.keys(components2).length === 0 ? void 0 : components2,
708
+ contentType: contentType2,
709
+ contentTypes: data?.contentTypes ?? []
710
+ };
711
+ }, [model, data]);
774
712
  React.useEffect(() => {
775
713
  if (error) {
776
714
  toggleNotification({
@@ -853,7 +791,7 @@ const useDocument = (args, opts) => {
853
791
  return null;
854
792
  } catch (error2) {
855
793
  if (error2 instanceof ValidationError) {
856
- return getInnerErrors(error2);
794
+ return getYupValidationErrors(error2);
857
795
  }
858
796
  throw error2;
859
797
  }
@@ -949,14 +887,53 @@ const useDocumentActions = () => {
949
887
  },
950
888
  [trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
951
889
  );
890
+ const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
891
+ const deleteMany = React.useCallback(
892
+ async ({ model, documentIds, params }) => {
893
+ try {
894
+ trackUsage("willBulkDeleteEntries");
895
+ const res = await deleteManyDocuments({
896
+ model,
897
+ documentIds,
898
+ params
899
+ });
900
+ if ("error" in res) {
901
+ toggleNotification({
902
+ type: "danger",
903
+ message: formatAPIError(res.error)
904
+ });
905
+ return { error: res.error };
906
+ }
907
+ toggleNotification({
908
+ type: "success",
909
+ title: formatMessage({
910
+ id: getTranslation("success.records.delete"),
911
+ defaultMessage: "Successfully deleted."
912
+ }),
913
+ message: ""
914
+ });
915
+ trackUsage("didBulkDeleteEntries");
916
+ return res.data;
917
+ } catch (err) {
918
+ toggleNotification({
919
+ type: "danger",
920
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
921
+ });
922
+ trackUsage("didNotBulkDeleteEntries");
923
+ throw err;
924
+ }
925
+ },
926
+ [trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
927
+ );
952
928
  const [discardDocument] = useDiscardDocumentMutation();
953
929
  const discard = React.useCallback(
954
- async ({ collectionType, model, documentId }) => {
930
+ async ({ collectionType, model, documentId, params }) => {
955
931
  try {
956
932
  const res = await discardDocument({
957
933
  collectionType,
958
934
  model,
959
- documentId
935
+ documentId,
936
+ params
960
937
  });
961
938
  if ("error" in res) {
962
939
  toggleNotification({
@@ -1018,6 +995,43 @@ const useDocumentActions = () => {
1018
995
  },
1019
996
  [trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
1020
997
  );
998
+ const [publishManyDocuments] = usePublishManyDocumentsMutation();
999
+ const publishMany = React.useCallback(
1000
+ async ({ model, documentIds, params }) => {
1001
+ try {
1002
+ const res = await publishManyDocuments({
1003
+ model,
1004
+ documentIds,
1005
+ params
1006
+ });
1007
+ if ("error" in res) {
1008
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1009
+ return { error: res.error };
1010
+ }
1011
+ toggleNotification({
1012
+ type: "success",
1013
+ message: formatMessage({
1014
+ id: getTranslation("success.record.publish"),
1015
+ defaultMessage: "Published document"
1016
+ })
1017
+ });
1018
+ return res.data;
1019
+ } catch (err) {
1020
+ toggleNotification({
1021
+ type: "danger",
1022
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1023
+ });
1024
+ throw err;
1025
+ }
1026
+ },
1027
+ [
1028
+ // trackUsage,
1029
+ publishManyDocuments,
1030
+ toggleNotification,
1031
+ formatMessage,
1032
+ formatAPIError
1033
+ ]
1034
+ );
1021
1035
  const [updateDocument] = useUpdateDocumentMutation();
1022
1036
  const update = React.useCallback(
1023
1037
  async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
@@ -1092,6 +1106,41 @@ const useDocumentActions = () => {
1092
1106
  },
1093
1107
  [trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
1094
1108
  );
1109
+ const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
1110
+ const unpublishMany = React.useCallback(
1111
+ async ({ model, documentIds, params }) => {
1112
+ try {
1113
+ trackUsage("willBulkUnpublishEntries");
1114
+ const res = await unpublishManyDocuments({
1115
+ model,
1116
+ documentIds,
1117
+ params
1118
+ });
1119
+ if ("error" in res) {
1120
+ toggleNotification({ type: "danger", message: formatAPIError(res.error) });
1121
+ return { error: res.error };
1122
+ }
1123
+ trackUsage("didBulkUnpublishEntries");
1124
+ toggleNotification({
1125
+ type: "success",
1126
+ title: formatMessage({
1127
+ id: getTranslation("success.records.unpublish"),
1128
+ defaultMessage: "Successfully unpublished."
1129
+ }),
1130
+ message: ""
1131
+ });
1132
+ return res.data;
1133
+ } catch (err) {
1134
+ toggleNotification({
1135
+ type: "danger",
1136
+ message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
1137
+ });
1138
+ trackUsage("didNotBulkUnpublishEntries");
1139
+ throw err;
1140
+ }
1141
+ },
1142
+ [trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
1143
+ );
1095
1144
  const [createDocument] = useCreateDocumentMutation();
1096
1145
  const create = React.useCallback(
1097
1146
  async ({ model, params }, data, trackerProperty) => {
@@ -1205,15 +1254,18 @@ const useDocumentActions = () => {
1205
1254
  clone,
1206
1255
  create,
1207
1256
  delete: _delete,
1257
+ deleteMany,
1208
1258
  discard,
1209
1259
  getDocument,
1210
1260
  publish,
1261
+ publishMany,
1211
1262
  unpublish,
1263
+ unpublishMany,
1212
1264
  update
1213
1265
  };
1214
1266
  };
1215
1267
  const ProtectedHistoryPage = lazy(
1216
- () => import("./History-Dug_4HIA.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1268
+ () => import("./History-DS6-HCYX.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
1217
1269
  );
1218
1270
  const routes$1 = [
1219
1271
  {
@@ -1226,31 +1278,31 @@ const routes$1 = [
1226
1278
  }
1227
1279
  ];
1228
1280
  const ProtectedEditViewPage = lazy(
1229
- () => import("./EditViewPage-BVIrgjyG.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1281
+ () => import("./EditViewPage-DWb0DE7R.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
1230
1282
  );
1231
1283
  const ProtectedListViewPage = lazy(
1232
- () => import("./ListViewPage-Dsoa3wEA.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1284
+ () => import("./ListViewPage-nQrOQuVo.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
1233
1285
  );
1234
1286
  const ProtectedListConfiguration = lazy(
1235
- () => import("./ListConfigurationPage-CmEeNg6T.mjs").then((mod) => ({
1287
+ () => import("./ListConfigurationPage-DQJJltko.mjs").then((mod) => ({
1236
1288
  default: mod.ProtectedListConfiguration
1237
1289
  }))
1238
1290
  );
1239
1291
  const ProtectedEditConfigurationPage = lazy(
1240
- () => import("./EditConfigurationPage-B2HhCh-b.mjs").then((mod) => ({
1292
+ () => import("./EditConfigurationPage-CcOoD26O.mjs").then((mod) => ({
1241
1293
  default: mod.ProtectedEditConfigurationPage
1242
1294
  }))
1243
1295
  );
1244
1296
  const ProtectedComponentConfigurationPage = lazy(
1245
- () => import("./ComponentConfigurationPage-uTMkLI60.mjs").then((mod) => ({
1297
+ () => import("./ComponentConfigurationPage-BMajAl1u.mjs").then((mod) => ({
1246
1298
  default: mod.ProtectedComponentConfigurationPage
1247
1299
  }))
1248
1300
  );
1249
1301
  const NoPermissions = lazy(
1250
- () => import("./NoPermissionsPage-Dt2O40ey.mjs").then((mod) => ({ default: mod.NoPermissions }))
1302
+ () => import("./NoPermissionsPage-fOIkQM0v.mjs").then((mod) => ({ default: mod.NoPermissions }))
1251
1303
  );
1252
1304
  const NoContentType = lazy(
1253
- () => import("./NoContentTypePage-Dh38hBXB.mjs").then((mod) => ({ default: mod.NoContentType }))
1305
+ () => import("./NoContentTypePage-DbnHE22g.mjs").then((mod) => ({ default: mod.NoContentType }))
1254
1306
  );
1255
1307
  const CollectionTypePages = () => {
1256
1308
  const { collectionType } = useParams();
@@ -1562,7 +1614,7 @@ const DocumentActionModal = ({
1562
1614
  title,
1563
1615
  onClose,
1564
1616
  footer: Footer,
1565
- content,
1617
+ content: Content,
1566
1618
  onModalClose
1567
1619
  }) => {
1568
1620
  const id = React.useId();
@@ -1577,7 +1629,7 @@ const DocumentActionModal = ({
1577
1629
  };
1578
1630
  return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
1579
1631
  /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
1580
- /* @__PURE__ */ jsx(ModalBody, { children: content }),
1632
+ /* @__PURE__ */ jsx(ModalBody, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
1581
1633
  /* @__PURE__ */ jsx(
1582
1634
  Box,
1583
1635
  {
@@ -1594,7 +1646,7 @@ const DocumentActionModal = ({
1594
1646
  )
1595
1647
  ] });
1596
1648
  };
1597
- const PublishAction = ({
1649
+ const PublishAction$1 = ({
1598
1650
  activeTab,
1599
1651
  documentId,
1600
1652
  model,
@@ -1679,7 +1731,7 @@ const PublishAction = ({
1679
1731
  }
1680
1732
  };
1681
1733
  };
1682
- PublishAction.type = "publish";
1734
+ PublishAction$1.type = "publish";
1683
1735
  const UpdateAction = ({
1684
1736
  activeTab,
1685
1737
  documentId,
@@ -1794,7 +1846,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
1794
1846
  KEEP: "keep",
1795
1847
  DISCARD: "discard"
1796
1848
  };
1797
- const UnpublishAction = ({
1849
+ const UnpublishAction$1 = ({
1798
1850
  activeTab,
1799
1851
  documentId,
1800
1852
  model,
@@ -1869,6 +1921,7 @@ const UnpublishAction = ({
1869
1921
  direction: "column",
1870
1922
  alignItems: "flex-start",
1871
1923
  tag: "fieldset",
1924
+ borderWidth: 0,
1872
1925
  gap: 3,
1873
1926
  children: [
1874
1927
  /* @__PURE__ */ jsx(VisuallyHidden, { tag: "legend" }),
@@ -1928,7 +1981,7 @@ const UnpublishAction = ({
1928
1981
  position: ["panel", "table-row"]
1929
1982
  };
1930
1983
  };
1931
- UnpublishAction.type = "unpublish";
1984
+ UnpublishAction$1.type = "unpublish";
1932
1985
  const DiscardAction = ({
1933
1986
  activeTab,
1934
1987
  documentId,
@@ -1984,7 +2037,7 @@ const StyledCrossCircle = styled(CrossCircle)`
1984
2037
  fill: currentColor;
1985
2038
  }
1986
2039
  `;
1987
- const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
2040
+ const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
1988
2041
  const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
1989
2042
  const RelativeTime = React.forwardRef(
1990
2043
  ({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
@@ -2251,7 +2304,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2251
2304
  id: "app.links.configure-view",
2252
2305
  defaultMessage: "Configure the view"
2253
2306
  }),
2254
- icon: /* @__PURE__ */ jsx(StyledCog, {}),
2307
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
2255
2308
  onClick: () => {
2256
2309
  navigate(`../${collectionType}/${model}/configurations/edit`);
2257
2310
  },
@@ -2259,11 +2312,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
2259
2312
  };
2260
2313
  };
2261
2314
  ConfigureTheViewAction.type = "configure-the-view";
2262
- const StyledCog = styled(Cog)`
2263
- path {
2264
- fill: currentColor;
2265
- }
2266
- `;
2267
2315
  const EditTheModelAction = ({ model }) => {
2268
2316
  const navigate = useNavigate();
2269
2317
  const { formatMessage } = useIntl();
@@ -2272,7 +2320,7 @@ const EditTheModelAction = ({ model }) => {
2272
2320
  id: "content-manager.link-to-ctb",
2273
2321
  defaultMessage: "Edit the model"
2274
2322
  }),
2275
- icon: /* @__PURE__ */ jsx(StyledPencil$1, {}),
2323
+ icon: /* @__PURE__ */ jsx(Pencil, {}),
2276
2324
  onClick: () => {
2277
2325
  navigate(`/plugins/content-type-builder/content-types/${model}`);
2278
2326
  },
@@ -2280,12 +2328,7 @@ const EditTheModelAction = ({ model }) => {
2280
2328
  };
2281
2329
  };
2282
2330
  EditTheModelAction.type = "edit-the-model";
2283
- const StyledPencil$1 = styled(Pencil)`
2284
- path {
2285
- fill: currentColor;
2286
- }
2287
- `;
2288
- const DeleteAction = ({ documentId, model, collectionType, document }) => {
2331
+ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
2289
2332
  const navigate = useNavigate();
2290
2333
  const { formatMessage } = useIntl();
2291
2334
  const listViewPathMatch = useMatch(LIST_PATH);
@@ -2299,7 +2342,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2299
2342
  id: "content-manager.actions.delete.label",
2300
2343
  defaultMessage: "Delete document"
2301
2344
  }),
2302
- icon: /* @__PURE__ */ jsx(StyledTrash, {}),
2345
+ icon: /* @__PURE__ */ jsx(Trash, {}),
2303
2346
  dialog: {
2304
2347
  type: "dialog",
2305
2348
  title: formatMessage({
@@ -2353,13 +2396,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
2353
2396
  position: ["header", "table-row"]
2354
2397
  };
2355
2398
  };
2356
- DeleteAction.type = "delete";
2357
- const StyledTrash = styled(Trash)`
2358
- path {
2359
- fill: currentColor;
2360
- }
2361
- `;
2362
- const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
2399
+ DeleteAction$1.type = "delete";
2400
+ const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
2363
2401
  const Panels = () => {
2364
2402
  const isCloning = useMatch(CLONE_PATH) !== null;
2365
2403
  const [
@@ -2454,663 +2492,1372 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
2454
2492
  }
2455
2493
  );
2456
2494
  });
2457
- const DEFAULT_BULK_ACTIONS = [];
2458
- const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
2459
- const { formatMessage } = useIntl();
2460
- const getDefaultErrorMessage = (reason) => {
2461
- switch (reason) {
2462
- case "relation":
2463
- return "Duplicating the relation could remove it from the original entry.";
2464
- case "unique":
2465
- return "Identical values in a unique field are not allowed";
2466
- default:
2467
- return reason;
2468
- }
2469
- };
2470
- return /* @__PURE__ */ jsxs(Fragment, { children: [
2471
- /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
2472
- id: getTranslation("containers.list.autoCloneModal.title"),
2473
- defaultMessage: "This entry can't be duplicated directly."
2474
- }) }),
2475
- /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
2476
- id: getTranslation("containers.list.autoCloneModal.description"),
2477
- defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
2478
- }) }) }),
2479
- /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
2480
- Flex,
2481
- {
2482
- direction: "column",
2483
- gap: 2,
2484
- alignItems: "flex-start",
2485
- borderColor: "neutral200",
2486
- hasRadius: true,
2487
- padding: 6,
2488
- children: [
2489
- /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
2490
- pathSegment,
2491
- index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
2492
- ChevronRight,
2493
- {
2494
- fill: "neutral500",
2495
- height: "0.8rem",
2496
- width: "0.8rem",
2497
- style: { margin: "0 0.8rem" }
2498
- }
2499
- )
2500
- ] }, index2)) }),
2501
- /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
2502
- id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
2503
- defaultMessage: getDefaultErrorMessage(reason)
2504
- }) })
2505
- ]
2506
- },
2507
- fieldPath.join()
2508
- )) })
2509
- ] });
2495
+ const HOOKS = {
2496
+ /**
2497
+ * Hook that allows to mutate the displayed headers of the list view table
2498
+ * @constant
2499
+ * @type {string}
2500
+ */
2501
+ INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2502
+ /**
2503
+ * Hook that allows to mutate the CM's collection types links pre-set filters
2504
+ * @constant
2505
+ * @type {string}
2506
+ */
2507
+ MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2508
+ /**
2509
+ * Hook that allows to mutate the CM's edit view layout
2510
+ * @constant
2511
+ * @type {string}
2512
+ */
2513
+ MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2514
+ /**
2515
+ * Hook that allows to mutate the CM's single types links pre-set filters
2516
+ * @constant
2517
+ * @type {string}
2518
+ */
2519
+ MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2510
2520
  };
2511
- const TableActions = ({ document }) => {
2512
- const { formatMessage } = useIntl();
2513
- const { model, collectionType } = useDoc();
2514
- const plugins = useStrapiApp("TableActions", (state) => state.plugins);
2515
- const props = {
2516
- activeTab: null,
2517
- model,
2518
- documentId: document.documentId,
2519
- collectionType,
2520
- document
2521
+ const contentTypesApi = contentManagerApi.injectEndpoints({
2522
+ endpoints: (builder) => ({
2523
+ getContentTypeConfiguration: builder.query({
2524
+ query: (uid) => ({
2525
+ url: `/content-manager/content-types/${uid}/configuration`,
2526
+ method: "GET"
2527
+ }),
2528
+ transformResponse: (response) => response.data,
2529
+ providesTags: (_result, _error, uid) => [
2530
+ { type: "ContentTypesConfiguration", id: uid },
2531
+ { type: "ContentTypeSettings", id: "LIST" }
2532
+ ]
2533
+ }),
2534
+ getAllContentTypeSettings: builder.query({
2535
+ query: () => "/content-manager/content-types-settings",
2536
+ transformResponse: (response) => response.data,
2537
+ providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2538
+ }),
2539
+ updateContentTypeConfiguration: builder.mutation({
2540
+ query: ({ uid, ...body }) => ({
2541
+ url: `/content-manager/content-types/${uid}/configuration`,
2542
+ method: "PUT",
2543
+ data: body
2544
+ }),
2545
+ transformResponse: (response) => response.data,
2546
+ invalidatesTags: (_result, _error, { uid }) => [
2547
+ { type: "ContentTypesConfiguration", id: uid },
2548
+ { type: "ContentTypeSettings", id: "LIST" },
2549
+ // Is this necessary?
2550
+ { type: "InitialData" }
2551
+ ]
2552
+ })
2553
+ })
2554
+ });
2555
+ const {
2556
+ useGetContentTypeConfigurationQuery,
2557
+ useGetAllContentTypeSettingsQuery,
2558
+ useUpdateContentTypeConfigurationMutation
2559
+ } = contentTypesApi;
2560
+ const checkIfAttributeIsDisplayable = (attribute) => {
2561
+ const { type } = attribute;
2562
+ if (type === "relation") {
2563
+ return !attribute.relation.toLowerCase().includes("morph");
2564
+ }
2565
+ return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2566
+ };
2567
+ const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2568
+ if (!mainFieldName) {
2569
+ return void 0;
2570
+ }
2571
+ const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2572
+ // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2573
+ schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2574
+ );
2575
+ return {
2576
+ name: mainFieldName,
2577
+ type: mainFieldType ?? "string"
2521
2578
  };
2522
- return /* @__PURE__ */ jsx(
2523
- DescriptionComponentRenderer,
2579
+ };
2580
+ const DEFAULT_SETTINGS = {
2581
+ bulkable: false,
2582
+ filterable: false,
2583
+ searchable: false,
2584
+ pagination: false,
2585
+ defaultSortBy: "",
2586
+ defaultSortOrder: "asc",
2587
+ mainField: "id",
2588
+ pageSize: 10
2589
+ };
2590
+ const useDocumentLayout = (model) => {
2591
+ const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
2592
+ const [{ query }] = useQueryParams();
2593
+ const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2594
+ const { toggleNotification } = useNotification();
2595
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2596
+ const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2597
+ const {
2598
+ data,
2599
+ isLoading: isLoadingConfigs,
2600
+ error,
2601
+ isFetching: isFetchingConfigs
2602
+ } = useGetContentTypeConfigurationQuery(model);
2603
+ const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2604
+ React.useEffect(() => {
2605
+ if (error) {
2606
+ toggleNotification({
2607
+ type: "danger",
2608
+ message: formatAPIError(error)
2609
+ });
2610
+ }
2611
+ }, [error, formatAPIError, toggleNotification]);
2612
+ const editLayout = React.useMemo(
2613
+ () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2614
+ layout: [],
2615
+ components: {},
2616
+ metadatas: {},
2617
+ options: {},
2618
+ settings: DEFAULT_SETTINGS
2619
+ },
2620
+ [data, isLoading, schemas, schema, components]
2621
+ );
2622
+ const listLayout = React.useMemo(() => {
2623
+ return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2624
+ layout: [],
2625
+ metadatas: {},
2626
+ options: {},
2627
+ settings: DEFAULT_SETTINGS
2628
+ };
2629
+ }, [data, isLoading, schemas, schema, components]);
2630
+ const { layout: edit } = React.useMemo(
2631
+ () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2632
+ layout: editLayout,
2633
+ query
2634
+ }),
2635
+ [editLayout, query, runHookWaterfall]
2636
+ );
2637
+ return {
2638
+ error,
2639
+ isLoading,
2640
+ edit,
2641
+ list: listLayout
2642
+ };
2643
+ };
2644
+ const useDocLayout = () => {
2645
+ const { model } = useDoc();
2646
+ return useDocumentLayout(model);
2647
+ };
2648
+ const formatEditLayout = (data, {
2649
+ schemas,
2650
+ schema,
2651
+ components
2652
+ }) => {
2653
+ let currentPanelIndex = 0;
2654
+ const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2655
+ data.contentType.layouts.edit,
2656
+ schema?.attributes,
2657
+ data.contentType.metadatas,
2658
+ { configurations: data.components, schemas: components },
2659
+ schemas
2660
+ ).reduce((panels, row) => {
2661
+ if (row.some((field) => field.type === "dynamiczone")) {
2662
+ panels.push([row]);
2663
+ currentPanelIndex += 2;
2664
+ } else {
2665
+ if (!panels[currentPanelIndex]) {
2666
+ panels.push([]);
2667
+ }
2668
+ panels[currentPanelIndex].push(row);
2669
+ }
2670
+ return panels;
2671
+ }, []);
2672
+ const componentEditAttributes = Object.entries(data.components).reduce(
2673
+ (acc, [uid, configuration]) => {
2674
+ acc[uid] = {
2675
+ layout: convertEditLayoutToFieldLayouts(
2676
+ configuration.layouts.edit,
2677
+ components[uid].attributes,
2678
+ configuration.metadatas
2679
+ ),
2680
+ settings: {
2681
+ ...configuration.settings,
2682
+ icon: components[uid].info.icon,
2683
+ displayName: components[uid].info.displayName
2684
+ }
2685
+ };
2686
+ return acc;
2687
+ },
2688
+ {}
2689
+ );
2690
+ const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
2691
+ (acc, [attribute, metadata]) => {
2692
+ return {
2693
+ ...acc,
2694
+ [attribute]: metadata.edit
2695
+ };
2696
+ },
2697
+ {}
2698
+ );
2699
+ return {
2700
+ layout: panelledEditAttributes,
2701
+ components: componentEditAttributes,
2702
+ metadatas: editMetadatas,
2703
+ settings: {
2704
+ ...data.contentType.settings,
2705
+ displayName: schema?.info.displayName
2706
+ },
2707
+ options: {
2708
+ ...schema?.options,
2709
+ ...schema?.pluginOptions,
2710
+ ...data.contentType.options
2711
+ }
2712
+ };
2713
+ };
2714
+ const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
2715
+ return rows.map(
2716
+ (row) => row.map((field) => {
2717
+ const attribute = attributes[field.name];
2718
+ if (!attribute) {
2719
+ return null;
2720
+ }
2721
+ const { edit: metadata } = metadatas[field.name];
2722
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2723
+ return {
2724
+ attribute,
2725
+ disabled: !metadata.editable,
2726
+ hint: metadata.description,
2727
+ label: metadata.label ?? "",
2728
+ name: field.name,
2729
+ // @ts-expect-error – mainField does exist on the metadata for a relation.
2730
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2731
+ schemas,
2732
+ components: components?.schemas ?? {}
2733
+ }),
2734
+ placeholder: metadata.placeholder ?? "",
2735
+ required: attribute.required ?? false,
2736
+ size: field.size,
2737
+ unique: "unique" in attribute ? attribute.unique : false,
2738
+ visible: metadata.visible ?? true,
2739
+ type: attribute.type
2740
+ };
2741
+ }).filter((field) => field !== null)
2742
+ );
2743
+ };
2744
+ const formatListLayout = (data, {
2745
+ schemas,
2746
+ schema,
2747
+ components
2748
+ }) => {
2749
+ const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
2750
+ (acc, [attribute, metadata]) => {
2751
+ return {
2752
+ ...acc,
2753
+ [attribute]: metadata.list
2754
+ };
2755
+ },
2756
+ {}
2757
+ );
2758
+ const listAttributes = convertListLayoutToFieldLayouts(
2759
+ data.contentType.layouts.list,
2760
+ schema?.attributes,
2761
+ listMetadatas,
2762
+ { configurations: data.components, schemas: components },
2763
+ schemas
2764
+ );
2765
+ return {
2766
+ layout: listAttributes,
2767
+ settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
2768
+ metadatas: listMetadatas,
2769
+ options: {
2770
+ ...schema?.options,
2771
+ ...schema?.pluginOptions,
2772
+ ...data.contentType.options
2773
+ }
2774
+ };
2775
+ };
2776
+ const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
2777
+ return columns.map((name) => {
2778
+ const attribute = attributes[name];
2779
+ if (!attribute) {
2780
+ return null;
2781
+ }
2782
+ const metadata = metadatas[name];
2783
+ const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
2784
+ return {
2785
+ attribute,
2786
+ label: metadata.label ?? "",
2787
+ mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
2788
+ schemas,
2789
+ components: components?.schemas ?? {}
2790
+ }),
2791
+ name,
2792
+ searchable: metadata.searchable ?? true,
2793
+ sortable: metadata.sortable ?? true
2794
+ };
2795
+ }).filter((field) => field !== null);
2796
+ };
2797
+ const ConfirmBulkActionDialog = ({
2798
+ onToggleDialog,
2799
+ isOpen = false,
2800
+ dialogBody,
2801
+ endAction
2802
+ }) => {
2803
+ const { formatMessage } = useIntl();
2804
+ return /* @__PURE__ */ jsxs(
2805
+ Dialog,
2524
2806
  {
2525
- props,
2526
- descriptions: plugins["content-manager"].apis.getDocumentActions(),
2527
- children: (actions2) => {
2528
- const tableRowActions = actions2.filter((action) => {
2529
- const positions = Array.isArray(action.position) ? action.position : [action.position];
2530
- return positions.includes("table-row");
2531
- });
2532
- return /* @__PURE__ */ jsx(
2533
- DocumentActionsMenu,
2807
+ onClose: onToggleDialog,
2808
+ title: formatMessage({
2809
+ id: "app.components.ConfirmDialog.title",
2810
+ defaultMessage: "Confirmation"
2811
+ }),
2812
+ isOpen,
2813
+ children: [
2814
+ /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: dialogBody }) }),
2815
+ /* @__PURE__ */ jsx(
2816
+ DialogFooter,
2534
2817
  {
2535
- actions: tableRowActions,
2536
- label: formatMessage({
2537
- id: "content-manager.containers.list.table.row-actions",
2538
- defaultMessage: "Row action"
2539
- }),
2540
- variant: "ghost"
2818
+ startAction: /* @__PURE__ */ jsx(Button, { onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
2819
+ id: "app.components.Button.cancel",
2820
+ defaultMessage: "Cancel"
2821
+ }) }),
2822
+ endAction
2541
2823
  }
2542
- );
2543
- }
2824
+ )
2825
+ ]
2544
2826
  }
2545
2827
  );
2546
2828
  };
2547
- const EditAction = ({ documentId }) => {
2548
- const navigate = useNavigate();
2829
+ const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
2830
+ const ConfirmDialogPublishAll = ({
2831
+ isOpen,
2832
+ onToggleDialog,
2833
+ isConfirmButtonLoading = false,
2834
+ onConfirm
2835
+ }) => {
2549
2836
  const { formatMessage } = useIntl();
2550
- const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
2837
+ const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
2551
2838
  const { toggleNotification } = useNotification();
2839
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
2840
+ const { model, schema } = useDoc();
2552
2841
  const [{ query }] = useQueryParams();
2553
- return {
2554
- disabled: !canRead,
2555
- icon: /* @__PURE__ */ jsx(StyledPencil, {}),
2556
- label: formatMessage({
2557
- id: "content-manager.actions.edit.label",
2558
- defaultMessage: "Edit"
2559
- }),
2560
- position: "table-row",
2561
- onClick: async () => {
2562
- if (!documentId) {
2563
- console.error(
2564
- "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
2842
+ const {
2843
+ data: countDraftRelations = 0,
2844
+ isLoading,
2845
+ error
2846
+ } = useGetManyDraftRelationCountQuery(
2847
+ {
2848
+ model,
2849
+ documentIds: selectedEntries.map((entry) => entry.documentId),
2850
+ locale: query?.plugins?.i18n?.locale
2851
+ },
2852
+ {
2853
+ skip: selectedEntries.length === 0
2854
+ }
2855
+ );
2856
+ React.useEffect(() => {
2857
+ if (error) {
2858
+ toggleNotification({ type: "danger", message: formatAPIError(error) });
2859
+ }
2860
+ }, [error, formatAPIError, toggleNotification]);
2861
+ if (error) {
2862
+ return null;
2863
+ }
2864
+ return /* @__PURE__ */ jsx(
2865
+ ConfirmBulkActionDialog,
2866
+ {
2867
+ isOpen: isOpen && !isLoading,
2868
+ onToggleDialog,
2869
+ dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
2870
+ /* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
2871
+ countDraftRelations > 0 && formatMessage(
2872
+ {
2873
+ id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
2874
+ 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. "
2875
+ },
2876
+ {
2877
+ b: BoldChunk$1,
2878
+ count: countDraftRelations,
2879
+ entities: selectedEntries.length
2880
+ }
2881
+ ),
2882
+ formatMessage({
2883
+ id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
2884
+ defaultMessage: "Are you sure you want to publish these entries?"
2885
+ })
2886
+ ] }),
2887
+ schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
2888
+ {
2889
+ id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
2890
+ defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
2891
+ },
2892
+ {
2893
+ em: Emphasis
2894
+ }
2895
+ ) })
2896
+ ] }),
2897
+ endAction: /* @__PURE__ */ jsx(
2898
+ Button,
2899
+ {
2900
+ onClick: onConfirm,
2901
+ variant: "secondary",
2902
+ startIcon: /* @__PURE__ */ jsx(Check, {}),
2903
+ loading: isConfirmButtonLoading,
2904
+ children: formatMessage({
2905
+ id: "app.utils.publish",
2906
+ defaultMessage: "Publish"
2907
+ })
2908
+ }
2909
+ )
2910
+ }
2911
+ );
2912
+ };
2913
+ const TypographyMaxWidth = styled(Typography)`
2914
+ max-width: 300px;
2915
+ `;
2916
+ const formatErrorMessages = (errors, parentKey, formatMessage) => {
2917
+ const messages = [];
2918
+ Object.entries(errors).forEach(([key, value]) => {
2919
+ const currentKey = parentKey ? `${parentKey}.${key}` : key;
2920
+ if (typeof value === "object" && value !== null && !Array.isArray(value)) {
2921
+ if ("id" in value && "defaultMessage" in value) {
2922
+ messages.push(
2923
+ formatMessage(
2924
+ {
2925
+ id: `${value.id}.withField`,
2926
+ defaultMessage: value.defaultMessage
2927
+ },
2928
+ { field: currentKey }
2929
+ )
2565
2930
  );
2566
- toggleNotification({
2567
- message: formatMessage({
2568
- id: "content-manager.actions.edit.error",
2569
- defaultMessage: "An error occurred while trying to edit the document."
2570
- }),
2571
- type: "danger"
2572
- });
2573
- return;
2931
+ } else {
2932
+ messages.push(...formatErrorMessages(value, currentKey, formatMessage));
2933
+ }
2934
+ } else {
2935
+ messages.push(
2936
+ formatMessage(
2937
+ {
2938
+ id: `${value}.withField`,
2939
+ defaultMessage: value
2940
+ },
2941
+ { field: currentKey }
2942
+ )
2943
+ );
2944
+ }
2945
+ });
2946
+ return messages;
2947
+ };
2948
+ const EntryValidationText = ({ validationErrors, status }) => {
2949
+ const { formatMessage } = useIntl();
2950
+ if (validationErrors) {
2951
+ const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
2952
+ " "
2953
+ );
2954
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2955
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
2956
+ /* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
2957
+ ] });
2958
+ }
2959
+ if (status === "published") {
2960
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2961
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
2962
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
2963
+ id: "content-manager.bulk-publish.already-published",
2964
+ defaultMessage: "Already Published"
2965
+ }) })
2966
+ ] });
2967
+ }
2968
+ if (status === "modified") {
2969
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2970
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
2971
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
2972
+ id: "content-manager.bulk-publish.modified",
2973
+ defaultMessage: "Ready to publish changes"
2974
+ }) })
2975
+ ] });
2976
+ }
2977
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
2978
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
2979
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
2980
+ id: "app.utils.ready-to-publish",
2981
+ defaultMessage: "Ready to publish"
2982
+ }) })
2983
+ ] });
2984
+ };
2985
+ const TABLE_HEADERS = [
2986
+ { name: "id", label: "id" },
2987
+ { name: "name", label: "name" },
2988
+ { name: "status", label: "status" },
2989
+ { name: "publicationStatus", label: "Publication status" }
2990
+ ];
2991
+ const SelectedEntriesTableContent = ({
2992
+ isPublishing,
2993
+ rowsToDisplay = [],
2994
+ entriesToPublish = [],
2995
+ validationErrors = {}
2996
+ }) => {
2997
+ const { pathname } = useLocation();
2998
+ const { formatMessage } = useIntl();
2999
+ const {
3000
+ list: {
3001
+ settings: { mainField }
3002
+ }
3003
+ } = useDocLayout();
3004
+ const shouldDisplayMainField = mainField != null && mainField !== "id";
3005
+ return /* @__PURE__ */ jsxs(Table.Content, { children: [
3006
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
3007
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
3008
+ TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
3009
+ (head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
3010
+ )
3011
+ ] }),
3012
+ /* @__PURE__ */ jsx(Table.Loading, {}),
3013
+ /* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
3014
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
3015
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
3016
+ shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
3017
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
3018
+ /* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3019
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
3020
+ id: "content-manager.success.record.publishing",
3021
+ defaultMessage: "Publishing..."
3022
+ }) }),
3023
+ /* @__PURE__ */ jsx(Loader, { small: true })
3024
+ ] }) : /* @__PURE__ */ jsx(
3025
+ EntryValidationText,
3026
+ {
3027
+ validationErrors: validationErrors[row.documentId],
3028
+ status: row.status
3029
+ }
3030
+ ) }),
3031
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
3032
+ IconButton,
3033
+ {
3034
+ tag: Link,
3035
+ to: {
3036
+ pathname: `${pathname}/${row.documentId}`,
3037
+ search: row.locale && `?plugins[i18n][locale]=${row.locale}`
3038
+ },
3039
+ state: { from: pathname },
3040
+ label: formatMessage(
3041
+ { id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
3042
+ {
3043
+ target: formatMessage(
3044
+ {
3045
+ id: "content-manager.components.ListViewHelperPluginTable.row-line",
3046
+ defaultMessage: "item line {number}"
3047
+ },
3048
+ { number: index2 + 1 }
3049
+ )
3050
+ }
3051
+ ),
3052
+ target: "_blank",
3053
+ marginLeft: "auto",
3054
+ children: /* @__PURE__ */ jsx(Pencil, {})
3055
+ }
3056
+ ) })
3057
+ ] }, row.id)) })
3058
+ ] });
3059
+ };
3060
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
3061
+ const SelectedEntriesModalContent = ({
3062
+ listViewSelectedEntries,
3063
+ toggleModal,
3064
+ setListViewSelectedDocuments,
3065
+ model
3066
+ }) => {
3067
+ const { formatMessage } = useIntl();
3068
+ const { schema, components } = useContentTypeSchema(model);
3069
+ const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
3070
+ const [{ query }] = useQueryParams();
3071
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3072
+ const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
3073
+ {
3074
+ model,
3075
+ params: {
3076
+ page: "1",
3077
+ pageSize: documentIds.length.toString(),
3078
+ sort: query.sort,
3079
+ filters: {
3080
+ documentId: {
3081
+ $in: documentIds
3082
+ }
3083
+ },
3084
+ locale: query.plugins?.i18n?.locale
2574
3085
  }
2575
- navigate({
2576
- pathname: documentId,
2577
- search: stringify({
2578
- plugins: query.plugins
2579
- })
3086
+ },
3087
+ {
3088
+ selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
3089
+ }
3090
+ );
3091
+ const { rows, validationErrors } = React.useMemo(() => {
3092
+ if (data.length > 0 && schema) {
3093
+ const validate = createYupSchema(schema.attributes, components);
3094
+ const validationErrors2 = {};
3095
+ const rows2 = data.map((entry) => {
3096
+ try {
3097
+ validate.validateSync(entry, { abortEarly: false });
3098
+ return entry;
3099
+ } catch (e) {
3100
+ if (e instanceof ValidationError) {
3101
+ validationErrors2[entry.documentId] = getYupValidationErrors(e);
3102
+ }
3103
+ return entry;
3104
+ }
3105
+ });
3106
+ return { rows: rows2, validationErrors: validationErrors2 };
3107
+ }
3108
+ return {
3109
+ rows: [],
3110
+ validationErrors: {}
3111
+ };
3112
+ }, [components, data, schema]);
3113
+ const [publishedCount, setPublishedCount] = React.useState(0);
3114
+ const [isDialogOpen, setIsDialogOpen] = React.useState(false);
3115
+ const { publishMany: bulkPublishAction } = useDocumentActions();
3116
+ const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
3117
+ const selectedRows = useTable("publishAction", (state) => state.selectedRows);
3118
+ const selectedEntries = rows.filter(
3119
+ (entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
3120
+ );
3121
+ const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
3122
+ const selectedEntriesWithErrorsCount = selectedEntries.filter(
3123
+ ({ documentId }) => validationErrors[documentId]
3124
+ ).length;
3125
+ const selectedEntriesPublished = selectedEntries.filter(
3126
+ ({ status }) => status === "published"
3127
+ ).length;
3128
+ const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
3129
+ const toggleDialog = () => setIsDialogOpen((prev) => !prev);
3130
+ const handleConfirmBulkPublish = async () => {
3131
+ toggleDialog();
3132
+ const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
3133
+ if (!("error" in res)) {
3134
+ setPublishedCount(res.count);
3135
+ const unpublishedEntries = rows.filter((row) => {
3136
+ return !entriesToPublish.includes(row.documentId);
2580
3137
  });
3138
+ setListViewSelectedDocuments(unpublishedEntries);
2581
3139
  }
2582
3140
  };
2583
- };
2584
- EditAction.type = "edit";
2585
- const StyledPencil = styled(Pencil)`
2586
- path {
2587
- fill: currentColor;
2588
- }
2589
- `;
2590
- const CloneAction = ({ model, documentId }) => {
2591
- const navigate = useNavigate();
2592
- const { formatMessage } = useIntl();
2593
- const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
2594
- const { toggleNotification } = useNotification();
2595
- const { autoClone } = useDocumentActions();
2596
- const [prohibitedFields, setProhibitedFields] = React.useState([]);
2597
- return {
2598
- disabled: !canCreate,
2599
- icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
2600
- label: formatMessage({
2601
- id: "content-manager.actions.clone.label",
2602
- defaultMessage: "Duplicate"
2603
- }),
2604
- position: "table-row",
2605
- onClick: async () => {
2606
- if (!documentId) {
2607
- console.error(
2608
- "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
2609
- );
2610
- toggleNotification({
2611
- message: formatMessage({
2612
- id: "content-manager.actions.clone.error",
2613
- defaultMessage: "An error occurred while trying to clone the document."
2614
- }),
2615
- type: "danger"
2616
- });
2617
- return;
3141
+ const getFormattedCountMessage = () => {
3142
+ if (publishedCount) {
3143
+ return formatMessage(
3144
+ {
3145
+ id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
3146
+ 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."
3147
+ },
3148
+ {
3149
+ publishedCount,
3150
+ withErrorsCount: selectedEntriesWithErrorsCount,
3151
+ b: BoldChunk
3152
+ }
3153
+ );
3154
+ }
3155
+ return formatMessage(
3156
+ {
3157
+ id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
3158
+ 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."
3159
+ },
3160
+ {
3161
+ readyToPublishCount: selectedEntriesWithNoErrorsCount,
3162
+ withErrorsCount: selectedEntriesWithErrorsCount,
3163
+ alreadyPublishedCount: selectedEntriesPublished,
3164
+ b: BoldChunk
2618
3165
  }
2619
- const res = await autoClone({ model, sourceId: documentId });
2620
- if ("data" in res) {
2621
- navigate(res.data.documentId);
2622
- return true;
3166
+ );
3167
+ };
3168
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3169
+ /* @__PURE__ */ jsxs(ModalBody, { children: [
3170
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
3171
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
3172
+ SelectedEntriesTableContent,
3173
+ {
3174
+ isPublishing: isSubmittingForm,
3175
+ rowsToDisplay: rows,
3176
+ entriesToPublish,
3177
+ validationErrors
3178
+ }
3179
+ ) })
3180
+ ] }),
3181
+ /* @__PURE__ */ jsx(
3182
+ ModalFooter,
3183
+ {
3184
+ startActions: /* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
3185
+ id: "app.components.Button.cancel",
3186
+ defaultMessage: "Cancel"
3187
+ }) }),
3188
+ endActions: /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
3189
+ /* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
3190
+ /* @__PURE__ */ jsx(
3191
+ Button,
3192
+ {
3193
+ onClick: toggleDialog,
3194
+ disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
3195
+ loading: isSubmittingForm,
3196
+ children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
3197
+ }
3198
+ )
3199
+ ] })
2623
3200
  }
2624
- if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
2625
- const prohibitedFields2 = res.error.details.prohibitedFields;
2626
- setProhibitedFields(prohibitedFields2);
3201
+ ),
3202
+ /* @__PURE__ */ jsx(
3203
+ ConfirmDialogPublishAll,
3204
+ {
3205
+ isOpen: isDialogOpen,
3206
+ onToggleDialog: toggleDialog,
3207
+ isConfirmButtonLoading: isSubmittingForm,
3208
+ onConfirm: handleConfirmBulkPublish
2627
3209
  }
2628
- },
3210
+ )
3211
+ ] });
3212
+ };
3213
+ const PublishAction = ({ documents, model }) => {
3214
+ const { formatMessage } = useIntl();
3215
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3216
+ const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
3217
+ const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
3218
+ const refetchList = () => {
3219
+ contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
3220
+ };
3221
+ if (!showPublishButton)
3222
+ return null;
3223
+ return {
3224
+ actionType: "publish",
3225
+ variant: "tertiary",
3226
+ label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
2629
3227
  dialog: {
2630
3228
  type: "modal",
2631
3229
  title: formatMessage({
2632
- id: "content-manager.containers.list.autoCloneModal.header",
2633
- defaultMessage: "Duplicate"
3230
+ id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
3231
+ defaultMessage: "Publish entries"
2634
3232
  }),
2635
- content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
2636
- footer: ({ onClose }) => {
2637
- return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
2638
- /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
2639
- id: "cancel",
2640
- defaultMessage: "Cancel"
2641
- }) }),
2642
- /* @__PURE__ */ jsx(
2643
- LinkButton,
2644
- {
2645
- tag: NavLink,
2646
- to: {
2647
- pathname: `clone/${documentId}`
2648
- },
2649
- children: formatMessage({
2650
- id: "content-manager.containers.list.autoCloneModal.create",
2651
- defaultMessage: "Create"
2652
- })
2653
- }
2654
- )
2655
- ] });
3233
+ content: ({ onClose }) => {
3234
+ return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
3235
+ SelectedEntriesModalContent,
3236
+ {
3237
+ listViewSelectedEntries: documents,
3238
+ toggleModal: () => {
3239
+ onClose();
3240
+ refetchList();
3241
+ },
3242
+ setListViewSelectedDocuments,
3243
+ model
3244
+ }
3245
+ ) });
3246
+ },
3247
+ onClose: () => {
3248
+ refetchList();
2656
3249
  }
2657
3250
  }
2658
3251
  };
2659
3252
  };
2660
- CloneAction.type = "clone";
2661
- const StyledDuplicate = styled(Duplicate)`
2662
- path {
2663
- fill: currentColor;
2664
- }
2665
- `;
2666
- const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
2667
- class ContentManagerPlugin {
2668
- /**
2669
- * The following properties are the stored ones provided by any plugins registering with
2670
- * the content-manager. The function calls however, need to be called at runtime in the
2671
- * application, so instead we collate them and run them later with the complete list incl.
2672
- * ones already registered & the context of the view.
2673
- */
2674
- bulkActions = [...DEFAULT_BULK_ACTIONS];
2675
- documentActions = [
2676
- ...DEFAULT_ACTIONS,
2677
- ...DEFAULT_TABLE_ROW_ACTIONS,
2678
- ...DEFAULT_HEADER_ACTIONS,
2679
- HistoryAction
2680
- ];
2681
- editViewSidePanels = [ActionsPanel];
2682
- headerActions = [];
2683
- constructor() {
2684
- }
2685
- addEditViewSidePanel(panels) {
2686
- if (Array.isArray(panels)) {
2687
- this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
2688
- } else if (typeof panels === "function") {
2689
- this.editViewSidePanels = panels(this.editViewSidePanels);
2690
- } else {
2691
- throw new Error(
2692
- `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
2693
- panels
2694
- )}`
2695
- );
3253
+ const BulkActionsRenderer = () => {
3254
+ const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
3255
+ const { model, collectionType } = useDoc();
3256
+ const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
3257
+ return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
3258
+ DescriptionComponentRenderer,
3259
+ {
3260
+ props: {
3261
+ model,
3262
+ collectionType,
3263
+ documents: selectedRows
3264
+ },
3265
+ descriptions: plugins["content-manager"].apis.getBulkActions(),
3266
+ children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(BulkActionAction, { ...action }, action.id))
2696
3267
  }
2697
- }
2698
- addDocumentAction(actions2) {
2699
- if (Array.isArray(actions2)) {
2700
- this.documentActions = [...this.documentActions, ...actions2];
2701
- } else if (typeof actions2 === "function") {
2702
- this.documentActions = actions2(this.documentActions);
2703
- } else {
2704
- throw new Error(
2705
- `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
2706
- actions2
2707
- )}`
2708
- );
3268
+ ) });
3269
+ };
3270
+ const BulkActionAction = (action) => {
3271
+ const [dialogId, setDialogId] = React.useState(null);
3272
+ const { toggleNotification } = useNotification();
3273
+ const handleClick = (action2) => (e) => {
3274
+ const { onClick, dialog, id } = action2;
3275
+ if (onClick) {
3276
+ onClick(e);
2709
3277
  }
2710
- }
2711
- addDocumentHeaderAction(actions2) {
2712
- if (Array.isArray(actions2)) {
2713
- this.headerActions = [...this.headerActions, ...actions2];
2714
- } else if (typeof actions2 === "function") {
2715
- this.headerActions = actions2(this.headerActions);
2716
- } else {
2717
- throw new Error(
2718
- `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
2719
- actions2
2720
- )}`
2721
- );
3278
+ if (dialog) {
3279
+ switch (dialog.type) {
3280
+ case "notification":
3281
+ toggleNotification({
3282
+ title: dialog.title,
3283
+ message: dialog.content,
3284
+ type: dialog.status,
3285
+ timeout: dialog.timeout,
3286
+ onClose: dialog.onClose
3287
+ });
3288
+ break;
3289
+ case "dialog":
3290
+ case "modal": {
3291
+ e.preventDefault();
3292
+ setDialogId(id);
3293
+ }
3294
+ }
3295
+ }
3296
+ };
3297
+ const handleClose = () => {
3298
+ setDialogId(null);
3299
+ if (action.dialog?.type === "modal" && action.dialog?.onClose) {
3300
+ action.dialog.onClose();
3301
+ }
3302
+ };
3303
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3304
+ /* @__PURE__ */ jsx(
3305
+ Button,
3306
+ {
3307
+ disabled: action.disabled,
3308
+ startIcon: action.icon,
3309
+ variant: action.variant,
3310
+ onClick: handleClick(action),
3311
+ children: action.label
3312
+ }
3313
+ ),
3314
+ action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
3315
+ BulkActionConfirmDialog,
3316
+ {
3317
+ ...action.dialog,
3318
+ variant: action.variant,
3319
+ isOpen: dialogId === action.id,
3320
+ onClose: handleClose
3321
+ }
3322
+ ) : null,
3323
+ action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
3324
+ BulkActionModal,
3325
+ {
3326
+ ...action.dialog,
3327
+ onModalClose: handleClose,
3328
+ isOpen: dialogId === action.id
3329
+ }
3330
+ ) : null
3331
+ ] });
3332
+ };
3333
+ const BulkActionConfirmDialog = ({
3334
+ onClose,
3335
+ onCancel,
3336
+ onConfirm,
3337
+ title,
3338
+ content,
3339
+ confirmButton,
3340
+ isOpen,
3341
+ variant = "secondary"
3342
+ }) => {
3343
+ const { formatMessage } = useIntl();
3344
+ const handleClose = async () => {
3345
+ if (onCancel) {
3346
+ await onCancel();
2722
3347
  }
2723
- }
2724
- addBulkAction(actions2) {
2725
- if (Array.isArray(actions2)) {
2726
- this.bulkActions = [...this.bulkActions, ...actions2];
2727
- } else if (typeof actions2 === "function") {
2728
- this.bulkActions = actions2(this.bulkActions);
2729
- } else {
2730
- throw new Error(
2731
- `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
2732
- actions2
2733
- )}`
2734
- );
3348
+ onClose();
3349
+ };
3350
+ const handleConfirm = async () => {
3351
+ if (onConfirm) {
3352
+ await onConfirm();
2735
3353
  }
2736
- }
2737
- get config() {
2738
- return {
2739
- id: PLUGIN_ID,
2740
- name: "Content Manager",
2741
- injectionZones: INJECTION_ZONES,
2742
- apis: {
2743
- addBulkAction: this.addBulkAction.bind(this),
2744
- addDocumentAction: this.addDocumentAction.bind(this),
2745
- addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
2746
- addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
2747
- getBulkActions: () => this.bulkActions,
2748
- getDocumentActions: () => this.documentActions,
2749
- getEditViewSidePanels: () => this.editViewSidePanels,
2750
- getHeaderActions: () => this.headerActions
3354
+ onClose();
3355
+ };
3356
+ return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
3357
+ /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
3358
+ /* @__PURE__ */ jsx(
3359
+ DialogFooter,
3360
+ {
3361
+ startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
3362
+ id: "app.components.Button.cancel",
3363
+ defaultMessage: "Cancel"
3364
+ }) }),
3365
+ endAction: /* @__PURE__ */ jsx(
3366
+ Button,
3367
+ {
3368
+ onClick: handleConfirm,
3369
+ variant: variant === "danger-light" ? variant : "secondary",
3370
+ startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
3371
+ children: confirmButton ? confirmButton : formatMessage({
3372
+ id: "app.components.Button.confirm",
3373
+ defaultMessage: "Confirm"
3374
+ })
3375
+ }
3376
+ )
2751
3377
  }
2752
- };
3378
+ )
3379
+ ] });
3380
+ };
3381
+ const BulkActionModal = ({
3382
+ isOpen,
3383
+ title,
3384
+ onClose,
3385
+ content: Content,
3386
+ onModalClose
3387
+ }) => {
3388
+ const id = React.useId();
3389
+ if (!isOpen) {
3390
+ return null;
2753
3391
  }
2754
- }
2755
- const getPrintableType = (value) => {
2756
- const nativeType = typeof value;
2757
- if (nativeType === "object") {
2758
- if (value === null)
2759
- return "null";
2760
- if (Array.isArray(value))
2761
- return "array";
2762
- if (value instanceof Object && value.constructor.name !== "Object") {
2763
- return value.constructor.name;
3392
+ const handleClose = () => {
3393
+ if (onClose) {
3394
+ onClose();
2764
3395
  }
2765
- }
2766
- return nativeType;
2767
- };
2768
- const initialState = {
2769
- collectionTypeLinks: [],
2770
- components: [],
2771
- fieldSizes: {},
2772
- models: [],
2773
- singleTypeLinks: [],
2774
- isLoading: true
3396
+ onModalClose();
3397
+ };
3398
+ return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
3399
+ /* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
3400
+ /* @__PURE__ */ jsx(Content, { onClose: handleClose })
3401
+ ] });
2775
3402
  };
2776
- const appSlice = createSlice({
2777
- name: "app",
2778
- initialState,
2779
- reducers: {
2780
- setInitialData(state, action) {
2781
- const {
2782
- authorizedCollectionTypeLinks,
2783
- authorizedSingleTypeLinks,
2784
- components,
2785
- contentTypeSchemas,
2786
- fieldSizes
2787
- } = action.payload;
2788
- state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
2789
- ({ isDisplayed }) => isDisplayed
2790
- );
2791
- state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
2792
- state.components = components;
2793
- state.models = contentTypeSchemas;
2794
- state.fieldSizes = fieldSizes;
2795
- state.isLoading = false;
3403
+ const DeleteAction = ({ documents, model }) => {
3404
+ const { formatMessage } = useIntl();
3405
+ const { schema: contentType } = useDoc();
3406
+ const selectRow = useTable("DeleteAction", (state) => state.selectRow);
3407
+ const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
3408
+ const [{ query }] = useQueryParams();
3409
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3410
+ const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
3411
+ const { deleteMany: bulkDeleteAction } = useDocumentActions();
3412
+ const documentIds = documents.map(({ documentId }) => documentId);
3413
+ const handleConfirmBulkDelete = async () => {
3414
+ const res = await bulkDeleteAction({
3415
+ documentIds,
3416
+ model,
3417
+ params
3418
+ });
3419
+ if (!("error" in res)) {
3420
+ selectRow([]);
2796
3421
  }
2797
- }
2798
- });
2799
- const { actions, reducer: reducer$1 } = appSlice;
2800
- const { setInitialData } = actions;
2801
- const reducer = combineReducers({
2802
- app: reducer$1
2803
- });
2804
- const HOOKS = {
2805
- /**
2806
- * Hook that allows to mutate the displayed headers of the list view table
2807
- * @constant
2808
- * @type {string}
2809
- */
2810
- INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
2811
- /**
2812
- * Hook that allows to mutate the CM's collection types links pre-set filters
2813
- * @constant
2814
- * @type {string}
2815
- */
2816
- MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
2817
- /**
2818
- * Hook that allows to mutate the CM's edit view layout
2819
- * @constant
2820
- * @type {string}
2821
- */
2822
- MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
2823
- /**
2824
- * Hook that allows to mutate the CM's single types links pre-set filters
2825
- * @constant
2826
- * @type {string}
2827
- */
2828
- MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
2829
- };
2830
- const contentTypesApi = contentManagerApi.injectEndpoints({
2831
- endpoints: (builder) => ({
2832
- getContentTypeConfiguration: builder.query({
2833
- query: (uid) => ({
2834
- url: `/content-manager/content-types/${uid}/configuration`,
2835
- method: "GET"
2836
- }),
2837
- transformResponse: (response) => response.data,
2838
- providesTags: (_result, _error, uid) => [
2839
- { type: "ContentTypesConfiguration", id: uid },
2840
- { type: "ContentTypeSettings", id: "LIST" }
2841
- ]
2842
- }),
2843
- getAllContentTypeSettings: builder.query({
2844
- query: () => "/content-manager/content-types-settings",
2845
- transformResponse: (response) => response.data,
2846
- providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
2847
- }),
2848
- updateContentTypeConfiguration: builder.mutation({
2849
- query: ({ uid, ...body }) => ({
2850
- url: `/content-manager/content-types/${uid}/configuration`,
2851
- method: "PUT",
2852
- data: body
2853
- }),
2854
- transformResponse: (response) => response.data,
2855
- invalidatesTags: (_result, _error, { uid }) => [
2856
- { type: "ContentTypesConfiguration", id: uid },
2857
- { type: "ContentTypeSettings", id: "LIST" },
2858
- // Is this necessary?
2859
- { type: "InitialData" }
2860
- ]
2861
- })
2862
- })
2863
- });
2864
- const {
2865
- useGetContentTypeConfigurationQuery,
2866
- useGetAllContentTypeSettingsQuery,
2867
- useUpdateContentTypeConfigurationMutation
2868
- } = contentTypesApi;
2869
- const checkIfAttributeIsDisplayable = (attribute) => {
2870
- const { type } = attribute;
2871
- if (type === "relation") {
2872
- return !attribute.relation.toLowerCase().includes("morph");
2873
- }
2874
- return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
2875
- };
2876
- const getMainField = (attribute, mainFieldName, { schemas, components }) => {
2877
- if (!mainFieldName) {
2878
- return void 0;
2879
- }
2880
- const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
2881
- // @ts-expect-error – `targetModel` does exist on the attribute for a relation.
2882
- schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
2883
- );
3422
+ };
3423
+ if (!hasDeletePermission)
3424
+ return null;
2884
3425
  return {
2885
- name: mainFieldName,
2886
- type: mainFieldType ?? "string"
3426
+ variant: "danger-light",
3427
+ label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
3428
+ dialog: {
3429
+ type: "dialog",
3430
+ title: formatMessage({
3431
+ id: "app.components.ConfirmDialog.title",
3432
+ defaultMessage: "Confirmation"
3433
+ }),
3434
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3435
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3436
+ id: "popUpWarning.bodyMessage.contentType.delete.all",
3437
+ defaultMessage: "Are you sure you want to delete these entries?"
3438
+ }) }),
3439
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3440
+ {
3441
+ id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
3442
+ defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
3443
+ },
3444
+ {
3445
+ em: Emphasis
3446
+ }
3447
+ ) }) })
3448
+ ] }),
3449
+ onConfirm: handleConfirmBulkDelete
3450
+ }
2887
3451
  };
2888
3452
  };
2889
- const DEFAULT_SETTINGS = {
2890
- bulkable: false,
2891
- filterable: false,
2892
- searchable: false,
2893
- pagination: false,
2894
- defaultSortBy: "",
2895
- defaultSortOrder: "asc",
2896
- mainField: "id",
2897
- pageSize: 10
2898
- };
2899
- const useDocumentLayout = (model) => {
2900
- const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
3453
+ DeleteAction.type = "delete";
3454
+ const UnpublishAction = ({ documents, model }) => {
3455
+ const { formatMessage } = useIntl();
3456
+ const { schema } = useDoc();
3457
+ const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
3458
+ const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
3459
+ const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
3460
+ const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
3461
+ const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
3462
+ const documentIds = documents.map(({ documentId }) => documentId);
2901
3463
  const [{ query }] = useQueryParams();
2902
- const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
2903
- const { toggleNotification } = useNotification();
2904
- const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
2905
- const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
2906
- const {
2907
- data,
2908
- isLoading: isLoadingConfigs,
2909
- error,
2910
- isFetching: isFetchingConfigs
2911
- } = useGetContentTypeConfigurationQuery(model);
2912
- const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
2913
- React.useEffect(() => {
2914
- if (error) {
2915
- toggleNotification({
2916
- type: "danger",
2917
- message: formatAPIError(error)
2918
- });
3464
+ const params = React.useMemo(() => buildValidParams(query), [query]);
3465
+ const handleConfirmBulkUnpublish = async () => {
3466
+ const data = await bulkUnpublishAction({ documentIds, model, params });
3467
+ if (!("error" in data)) {
3468
+ selectRow([]);
2919
3469
  }
2920
- }, [error, formatAPIError, toggleNotification]);
2921
- const editLayout = React.useMemo(
2922
- () => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
2923
- layout: [],
2924
- components: {},
2925
- metadatas: {},
2926
- options: {},
2927
- settings: DEFAULT_SETTINGS
2928
- },
2929
- [data, isLoading, schemas, schema, components]
2930
- );
2931
- const listLayout = React.useMemo(() => {
2932
- return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
2933
- layout: [],
2934
- metadatas: {},
2935
- options: {},
2936
- settings: DEFAULT_SETTINGS
2937
- };
2938
- }, [data, isLoading, schemas, schema, components]);
2939
- const { layout: edit } = React.useMemo(
2940
- () => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
2941
- layout: editLayout,
2942
- query
2943
- }),
2944
- [editLayout, query, runHookWaterfall]
2945
- );
3470
+ };
3471
+ const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
3472
+ if (!showUnpublishButton)
3473
+ return null;
2946
3474
  return {
2947
- error,
2948
- isLoading,
2949
- edit,
2950
- list: listLayout
3475
+ variant: "tertiary",
3476
+ label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
3477
+ dialog: {
3478
+ type: "dialog",
3479
+ title: formatMessage({
3480
+ id: "app.components.ConfirmDialog.title",
3481
+ defaultMessage: "Confirmation"
3482
+ }),
3483
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
3484
+ /* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
3485
+ id: "popUpWarning.bodyMessage.contentType.unpublish.all",
3486
+ defaultMessage: "Are you sure you want to unpublish these entries?"
3487
+ }) }),
3488
+ hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
3489
+ {
3490
+ id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
3491
+ defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
3492
+ },
3493
+ {
3494
+ em: Emphasis
3495
+ }
3496
+ ) }) })
3497
+ ] }),
3498
+ confirmButton: formatMessage({
3499
+ id: "app.utils.unpublish",
3500
+ defaultMessage: "Unpublish"
3501
+ }),
3502
+ onConfirm: handleConfirmBulkUnpublish
3503
+ }
2951
3504
  };
2952
3505
  };
2953
- const useDocLayout = () => {
2954
- const { model } = useDoc();
2955
- return useDocumentLayout(model);
3506
+ UnpublishAction.type = "unpublish";
3507
+ const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
3508
+ const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
3509
+ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
3510
+ const { formatMessage } = useIntl();
3511
+ const getDefaultErrorMessage = (reason) => {
3512
+ switch (reason) {
3513
+ case "relation":
3514
+ return "Duplicating the relation could remove it from the original entry.";
3515
+ case "unique":
3516
+ return "Identical values in a unique field are not allowed";
3517
+ default:
3518
+ return reason;
3519
+ }
3520
+ };
3521
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
3522
+ /* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
3523
+ id: getTranslation("containers.list.autoCloneModal.title"),
3524
+ defaultMessage: "This entry can't be duplicated directly."
3525
+ }) }),
3526
+ /* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
3527
+ id: getTranslation("containers.list.autoCloneModal.description"),
3528
+ defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
3529
+ }) }) }),
3530
+ /* @__PURE__ */ jsx(Flex, { marginTop: 6, gap: 2, direction: "column", alignItems: "stretch", children: prohibitedFields.map(([fieldPath, reason]) => /* @__PURE__ */ jsxs(
3531
+ Flex,
3532
+ {
3533
+ direction: "column",
3534
+ gap: 2,
3535
+ alignItems: "flex-start",
3536
+ borderColor: "neutral200",
3537
+ hasRadius: true,
3538
+ padding: 6,
3539
+ children: [
3540
+ /* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
3541
+ pathSegment,
3542
+ index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
3543
+ ChevronRight,
3544
+ {
3545
+ fill: "neutral500",
3546
+ height: "0.8rem",
3547
+ width: "0.8rem",
3548
+ style: { margin: "0 0.8rem" }
3549
+ }
3550
+ )
3551
+ ] }, index2)) }),
3552
+ /* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
3553
+ id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
3554
+ defaultMessage: getDefaultErrorMessage(reason)
3555
+ }) })
3556
+ ]
3557
+ },
3558
+ fieldPath.join()
3559
+ )) })
3560
+ ] });
2956
3561
  };
2957
- const formatEditLayout = (data, {
2958
- schemas,
2959
- schema,
2960
- components
2961
- }) => {
2962
- let currentPanelIndex = 0;
2963
- const panelledEditAttributes = convertEditLayoutToFieldLayouts(
2964
- data.contentType.layouts.edit,
2965
- schema?.attributes,
2966
- data.contentType.metadatas,
2967
- { configurations: data.components, schemas: components },
2968
- schemas
2969
- ).reduce((panels, row) => {
2970
- if (row.some((field) => field.type === "dynamiczone")) {
2971
- panels.push([row]);
2972
- currentPanelIndex += 2;
2973
- } else {
2974
- if (!panels[currentPanelIndex]) {
2975
- panels.push([]);
3562
+ const TableActions = ({ document }) => {
3563
+ const { formatMessage } = useIntl();
3564
+ const { model, collectionType } = useDoc();
3565
+ const plugins = useStrapiApp("TableActions", (state) => state.plugins);
3566
+ const props = {
3567
+ activeTab: null,
3568
+ model,
3569
+ documentId: document.documentId,
3570
+ collectionType,
3571
+ document
3572
+ };
3573
+ return /* @__PURE__ */ jsx(
3574
+ DescriptionComponentRenderer,
3575
+ {
3576
+ props,
3577
+ descriptions: plugins["content-manager"].apis.getDocumentActions(),
3578
+ children: (actions2) => {
3579
+ const tableRowActions = actions2.filter((action) => {
3580
+ const positions = Array.isArray(action.position) ? action.position : [action.position];
3581
+ return positions.includes("table-row");
3582
+ });
3583
+ return /* @__PURE__ */ jsx(
3584
+ DocumentActionsMenu,
3585
+ {
3586
+ actions: tableRowActions,
3587
+ label: formatMessage({
3588
+ id: "content-manager.containers.list.table.row-actions",
3589
+ defaultMessage: "Row action"
3590
+ }),
3591
+ variant: "ghost"
3592
+ }
3593
+ );
2976
3594
  }
2977
- panels[currentPanelIndex].push(row);
2978
3595
  }
2979
- return panels;
2980
- }, []);
2981
- const componentEditAttributes = Object.entries(data.components).reduce(
2982
- (acc, [uid, configuration]) => {
2983
- acc[uid] = {
2984
- layout: convertEditLayoutToFieldLayouts(
2985
- configuration.layouts.edit,
2986
- components[uid].attributes,
2987
- configuration.metadatas
2988
- ),
2989
- settings: {
2990
- ...configuration.settings,
2991
- icon: components[uid].info.icon,
2992
- displayName: components[uid].info.displayName
2993
- }
2994
- };
2995
- return acc;
2996
- },
2997
- {}
2998
- );
2999
- const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
3000
- (acc, [attribute, metadata]) => {
3001
- return {
3002
- ...acc,
3003
- [attribute]: metadata.edit
3004
- };
3005
- },
3006
- {}
3007
3596
  );
3597
+ };
3598
+ const EditAction = ({ documentId }) => {
3599
+ const navigate = useNavigate();
3600
+ const { formatMessage } = useIntl();
3601
+ const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
3602
+ const { toggleNotification } = useNotification();
3603
+ const [{ query }] = useQueryParams();
3008
3604
  return {
3009
- layout: panelledEditAttributes,
3010
- components: componentEditAttributes,
3011
- metadatas: editMetadatas,
3012
- settings: {
3013
- ...data.contentType.settings,
3014
- displayName: schema?.info.displayName
3015
- },
3016
- options: {
3017
- ...schema?.options,
3018
- ...schema?.pluginOptions,
3019
- ...data.contentType.options
3605
+ disabled: !canRead,
3606
+ icon: /* @__PURE__ */ jsx(StyledPencil, {}),
3607
+ label: formatMessage({
3608
+ id: "content-manager.actions.edit.label",
3609
+ defaultMessage: "Edit"
3610
+ }),
3611
+ position: "table-row",
3612
+ onClick: async () => {
3613
+ if (!documentId) {
3614
+ console.error(
3615
+ "You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
3616
+ );
3617
+ toggleNotification({
3618
+ message: formatMessage({
3619
+ id: "content-manager.actions.edit.error",
3620
+ defaultMessage: "An error occurred while trying to edit the document."
3621
+ }),
3622
+ type: "danger"
3623
+ });
3624
+ return;
3625
+ }
3626
+ navigate({
3627
+ pathname: documentId,
3628
+ search: stringify({
3629
+ plugins: query.plugins
3630
+ })
3631
+ });
3020
3632
  }
3021
3633
  };
3022
3634
  };
3023
- const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
3024
- return rows.map(
3025
- (row) => row.map((field) => {
3026
- const attribute = attributes[field.name];
3027
- if (!attribute) {
3028
- return null;
3635
+ EditAction.type = "edit";
3636
+ const StyledPencil = styled(Pencil)`
3637
+ path {
3638
+ fill: currentColor;
3639
+ }
3640
+ `;
3641
+ const CloneAction = ({ model, documentId }) => {
3642
+ const navigate = useNavigate();
3643
+ const { formatMessage } = useIntl();
3644
+ const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
3645
+ const { toggleNotification } = useNotification();
3646
+ const { autoClone } = useDocumentActions();
3647
+ const [prohibitedFields, setProhibitedFields] = React.useState([]);
3648
+ return {
3649
+ disabled: !canCreate,
3650
+ icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
3651
+ label: formatMessage({
3652
+ id: "content-manager.actions.clone.label",
3653
+ defaultMessage: "Duplicate"
3654
+ }),
3655
+ position: "table-row",
3656
+ onClick: async () => {
3657
+ if (!documentId) {
3658
+ console.error(
3659
+ "You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
3660
+ );
3661
+ toggleNotification({
3662
+ message: formatMessage({
3663
+ id: "content-manager.actions.clone.error",
3664
+ defaultMessage: "An error occurred while trying to clone the document."
3665
+ }),
3666
+ type: "danger"
3667
+ });
3668
+ return;
3669
+ }
3670
+ const res = await autoClone({ model, sourceId: documentId });
3671
+ if ("data" in res) {
3672
+ navigate(res.data.documentId);
3673
+ return true;
3674
+ }
3675
+ if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
3676
+ const prohibitedFields2 = res.error.details.prohibitedFields;
3677
+ setProhibitedFields(prohibitedFields2);
3029
3678
  }
3030
- const { edit: metadata } = metadatas[field.name];
3031
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3032
- return {
3033
- attribute,
3034
- disabled: !metadata.editable,
3035
- hint: metadata.description,
3036
- label: metadata.label ?? "",
3037
- name: field.name,
3038
- // @ts-expect-error – mainField does exist on the metadata for a relation.
3039
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3040
- schemas,
3041
- components: components?.schemas ?? {}
3042
- }),
3043
- placeholder: metadata.placeholder ?? "",
3044
- required: attribute.required ?? false,
3045
- size: field.size,
3046
- unique: "unique" in attribute ? attribute.unique : false,
3047
- visible: metadata.visible ?? true,
3048
- type: attribute.type
3049
- };
3050
- }).filter((field) => field !== null)
3051
- );
3052
- };
3053
- const formatListLayout = (data, {
3054
- schemas,
3055
- schema,
3056
- components
3057
- }) => {
3058
- const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
3059
- (acc, [attribute, metadata]) => {
3060
- return {
3061
- ...acc,
3062
- [attribute]: metadata.list
3063
- };
3064
3679
  },
3065
- {}
3066
- );
3067
- const listAttributes = convertListLayoutToFieldLayouts(
3068
- data.contentType.layouts.list,
3069
- schema?.attributes,
3070
- listMetadatas,
3071
- { configurations: data.components, schemas: components },
3072
- schemas
3073
- );
3074
- return {
3075
- layout: listAttributes,
3076
- settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
3077
- metadatas: listMetadatas,
3078
- options: {
3079
- ...schema?.options,
3080
- ...schema?.pluginOptions,
3081
- ...data.contentType.options
3680
+ dialog: {
3681
+ type: "modal",
3682
+ title: formatMessage({
3683
+ id: "content-manager.containers.list.autoCloneModal.header",
3684
+ defaultMessage: "Duplicate"
3685
+ }),
3686
+ content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
3687
+ footer: ({ onClose }) => {
3688
+ return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
3689
+ /* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
3690
+ id: "cancel",
3691
+ defaultMessage: "Cancel"
3692
+ }) }),
3693
+ /* @__PURE__ */ jsx(
3694
+ LinkButton,
3695
+ {
3696
+ tag: NavLink,
3697
+ to: {
3698
+ pathname: `clone/${documentId}`
3699
+ },
3700
+ children: formatMessage({
3701
+ id: "content-manager.containers.list.autoCloneModal.create",
3702
+ defaultMessage: "Create"
3703
+ })
3704
+ }
3705
+ )
3706
+ ] });
3707
+ }
3082
3708
  }
3083
3709
  };
3084
3710
  };
3085
- const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
3086
- return columns.map((name) => {
3087
- const attribute = attributes[name];
3088
- if (!attribute) {
3089
- return null;
3711
+ CloneAction.type = "clone";
3712
+ const StyledDuplicate = styled(Duplicate)`
3713
+ path {
3714
+ fill: currentColor;
3715
+ }
3716
+ `;
3717
+ const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
3718
+ class ContentManagerPlugin {
3719
+ /**
3720
+ * The following properties are the stored ones provided by any plugins registering with
3721
+ * the content-manager. The function calls however, need to be called at runtime in the
3722
+ * application, so instead we collate them and run them later with the complete list incl.
3723
+ * ones already registered & the context of the view.
3724
+ */
3725
+ bulkActions = [...DEFAULT_BULK_ACTIONS];
3726
+ documentActions = [
3727
+ ...DEFAULT_ACTIONS,
3728
+ ...DEFAULT_TABLE_ROW_ACTIONS,
3729
+ ...DEFAULT_HEADER_ACTIONS,
3730
+ HistoryAction
3731
+ ];
3732
+ editViewSidePanels = [ActionsPanel];
3733
+ headerActions = [];
3734
+ constructor() {
3735
+ }
3736
+ addEditViewSidePanel(panels) {
3737
+ if (Array.isArray(panels)) {
3738
+ this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
3739
+ } else if (typeof panels === "function") {
3740
+ this.editViewSidePanels = panels(this.editViewSidePanels);
3741
+ } else {
3742
+ throw new Error(
3743
+ `Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
3744
+ panels
3745
+ )}`
3746
+ );
3090
3747
  }
3091
- const metadata = metadatas[name];
3092
- const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
3748
+ }
3749
+ addDocumentAction(actions2) {
3750
+ if (Array.isArray(actions2)) {
3751
+ this.documentActions = [...this.documentActions, ...actions2];
3752
+ } else if (typeof actions2 === "function") {
3753
+ this.documentActions = actions2(this.documentActions);
3754
+ } else {
3755
+ throw new Error(
3756
+ `Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
3757
+ actions2
3758
+ )}`
3759
+ );
3760
+ }
3761
+ }
3762
+ addDocumentHeaderAction(actions2) {
3763
+ if (Array.isArray(actions2)) {
3764
+ this.headerActions = [...this.headerActions, ...actions2];
3765
+ } else if (typeof actions2 === "function") {
3766
+ this.headerActions = actions2(this.headerActions);
3767
+ } else {
3768
+ throw new Error(
3769
+ `Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
3770
+ actions2
3771
+ )}`
3772
+ );
3773
+ }
3774
+ }
3775
+ addBulkAction(actions2) {
3776
+ if (Array.isArray(actions2)) {
3777
+ this.bulkActions = [...this.bulkActions, ...actions2];
3778
+ } else if (typeof actions2 === "function") {
3779
+ this.bulkActions = actions2(this.bulkActions);
3780
+ } else {
3781
+ throw new Error(
3782
+ `Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
3783
+ actions2
3784
+ )}`
3785
+ );
3786
+ }
3787
+ }
3788
+ get config() {
3093
3789
  return {
3094
- attribute,
3095
- label: metadata.label ?? "",
3096
- mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
3097
- schemas,
3098
- components: components?.schemas ?? {}
3099
- }),
3100
- name,
3101
- searchable: metadata.searchable ?? true,
3102
- sortable: metadata.sortable ?? true
3790
+ id: PLUGIN_ID,
3791
+ name: "Content Manager",
3792
+ injectionZones: INJECTION_ZONES,
3793
+ apis: {
3794
+ addBulkAction: this.addBulkAction.bind(this),
3795
+ addDocumentAction: this.addDocumentAction.bind(this),
3796
+ addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
3797
+ addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
3798
+ getBulkActions: () => this.bulkActions,
3799
+ getDocumentActions: () => this.documentActions,
3800
+ getEditViewSidePanels: () => this.editViewSidePanels,
3801
+ getHeaderActions: () => this.headerActions
3802
+ }
3103
3803
  };
3104
- }).filter((field) => field !== null);
3804
+ }
3805
+ }
3806
+ const getPrintableType = (value) => {
3807
+ const nativeType = typeof value;
3808
+ if (nativeType === "object") {
3809
+ if (value === null)
3810
+ return "null";
3811
+ if (Array.isArray(value))
3812
+ return "array";
3813
+ if (value instanceof Object && value.constructor.name !== "Object") {
3814
+ return value.constructor.name;
3815
+ }
3816
+ }
3817
+ return nativeType;
3818
+ };
3819
+ const initialState = {
3820
+ collectionTypeLinks: [],
3821
+ components: [],
3822
+ fieldSizes: {},
3823
+ models: [],
3824
+ singleTypeLinks: [],
3825
+ isLoading: true
3105
3826
  };
3827
+ const appSlice = createSlice({
3828
+ name: "app",
3829
+ initialState,
3830
+ reducers: {
3831
+ setInitialData(state, action) {
3832
+ const {
3833
+ authorizedCollectionTypeLinks,
3834
+ authorizedSingleTypeLinks,
3835
+ components,
3836
+ contentTypeSchemas,
3837
+ fieldSizes
3838
+ } = action.payload;
3839
+ state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
3840
+ ({ isDisplayed }) => isDisplayed
3841
+ );
3842
+ state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
3843
+ state.components = components;
3844
+ state.models = contentTypeSchemas;
3845
+ state.fieldSizes = fieldSizes;
3846
+ state.isLoading = false;
3847
+ }
3848
+ }
3849
+ });
3850
+ const { actions, reducer: reducer$1 } = appSlice;
3851
+ const { setInitialData } = actions;
3852
+ const reducer = combineReducers({
3853
+ app: reducer$1
3854
+ });
3106
3855
  const index = {
3107
3856
  register(app) {
3108
3857
  const cm = new ContentManagerPlugin();
3109
3858
  app.addReducers({
3110
- [contentManagerApi.reducerPath]: contentManagerApi.reducer,
3111
3859
  [PLUGIN_ID]: reducer
3112
3860
  });
3113
- app.addMiddlewares([() => contentManagerApi.middleware]);
3114
3861
  app.addMenuLink({
3115
3862
  to: PLUGIN_ID,
3116
3863
  icon: Feather,
@@ -3119,14 +3866,15 @@ const index = {
3119
3866
  defaultMessage: "Content Manager"
3120
3867
  },
3121
3868
  permissions: [],
3122
- Component: () => import("./layout-B5cm7cZj.mjs").then((mod) => ({ default: mod.Layout }))
3869
+ Component: () => import("./layout-BzAbmoO6.mjs").then((mod) => ({ default: mod.Layout })),
3870
+ position: 1
3123
3871
  });
3124
3872
  app.registerPlugin(cm.config);
3125
3873
  },
3126
3874
  async registerTrads({ locales }) {
3127
3875
  const importedTrads = await Promise.all(
3128
3876
  locales.map((locale) => {
3129
- 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 }) => {
3877
+ 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 }) => {
3130
3878
  return {
3131
3879
  data: prefixPluginTranslations(data, PLUGIN_ID),
3132
3880
  locale
@@ -3144,45 +3892,46 @@ const index = {
3144
3892
  };
3145
3893
  export {
3146
3894
  ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
3147
- extractContentTypeComponents as B,
3895
+ BulkActionsRenderer as B,
3148
3896
  COLLECTION_TYPES as C,
3149
3897
  DocumentStatus as D,
3150
- DEFAULT_SETTINGS as E,
3151
- convertEditLayoutToFieldLayouts as F,
3152
- useDocument as G,
3898
+ extractContentTypeComponents as E,
3899
+ DEFAULT_SETTINGS as F,
3900
+ convertEditLayoutToFieldLayouts as G,
3153
3901
  HOOKS as H,
3154
3902
  InjectionZone as I,
3155
- index as J,
3156
- useDocumentActions as K,
3903
+ useDocument as J,
3904
+ index as K,
3905
+ useDocumentActions as L,
3157
3906
  Panels as P,
3158
3907
  RelativeTime as R,
3159
3908
  SINGLE_TYPES as S,
3160
3909
  TableActions as T,
3161
- useGetAllContentTypeSettingsQuery as a,
3162
- useDoc as b,
3163
- buildValidParams as c,
3164
- contentManagerApi as d,
3165
- useDocumentRBAC as e,
3166
- useDocumentLayout as f,
3910
+ useGetInitialDataQuery as a,
3911
+ useGetAllContentTypeSettingsQuery as b,
3912
+ useDoc as c,
3913
+ buildValidParams as d,
3914
+ contentManagerApi as e,
3915
+ useDocumentRBAC as f,
3167
3916
  getTranslation as g,
3168
- createYupSchema as h,
3169
- Header as i,
3170
- PERMISSIONS as j,
3171
- DocumentRBAC as k,
3172
- DOCUMENT_META_FIELDS as l,
3173
- useDocLayout as m,
3174
- useContentTypeSchema as n,
3917
+ useDocumentLayout as h,
3918
+ createYupSchema as i,
3919
+ Header as j,
3920
+ PERMISSIONS as k,
3921
+ DocumentRBAC as l,
3922
+ DOCUMENT_META_FIELDS as m,
3923
+ useDocLayout as n,
3175
3924
  useGetContentTypeConfigurationQuery as o,
3176
3925
  CREATOR_FIELDS as p,
3177
3926
  getMainField as q,
3178
3927
  routes as r,
3179
3928
  setInitialData as s,
3180
3929
  getDisplayName as t,
3181
- useGetInitialDataQuery as u,
3930
+ useContentTypeSchema as u,
3182
3931
  checkIfAttributeIsDisplayable as v,
3183
3932
  useGetAllDocumentsQuery as w,
3184
3933
  convertListLayoutToFieldLayouts as x,
3185
3934
  capitalise as y,
3186
3935
  useUpdateContentTypeConfigurationMutation as z
3187
3936
  };
3188
- //# sourceMappingURL=index-B3c-4it4.mjs.map
3937
+ //# sourceMappingURL=index-Drt2DN7v.mjs.map