@strapi/content-manager 0.0.0-experimental.a65a85fdea97faae8679d3ffc5f9d79af61abd26 → 0.0.0-experimental.a687a6977f91492ccfc6771bf398a5236ece3c94
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.
- package/LICENSE +18 -3
- package/dist/_chunks/{CardDragPreview-DSVYodBX.js → CardDragPreview-C0QyJgRA.js} +10 -14
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -0
- package/dist/_chunks/{CardDragPreview-ikSG4M46.mjs → CardDragPreview-DOxamsuj.mjs} +7 -9
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -0
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js → ComponentConfigurationPage-BebDdCkl.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-43KmCNQE.js.map → ComponentConfigurationPage-BebDdCkl.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs → ComponentConfigurationPage-XdGcgtZh.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage--2aLCv-G.mjs.map → ComponentConfigurationPage-XdGcgtZh.mjs.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-BXdiCGQp.js} +8 -2
- package/dist/_chunks/ComponentIcon-BXdiCGQp.js.map +1 -0
- package/dist/_chunks/{ComponentIcon-BOFnK76n.mjs → ComponentIcon-u4bIXTFY.mjs} +9 -3
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -0
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs → EditConfigurationPage-DaNf9MoK.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-CUcGHHvQ.mjs.map → EditConfigurationPage-DaNf9MoK.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js → EditConfigurationPage-sdGi-bna.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-BfFzJ4Br.js.map → EditConfigurationPage-sdGi-bna.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-CzOT5Kpj.js → EditViewPage-BRA-JSnw.js} +101 -52
- package/dist/_chunks/EditViewPage-BRA-JSnw.js.map +1 -0
- package/dist/_chunks/EditViewPage-DtbTsNeX.mjs +254 -0
- package/dist/_chunks/EditViewPage-DtbTsNeX.mjs.map +1 -0
- package/dist/_chunks/{Field-Dlh0uGnL.mjs → Field-CDmB9zqh.mjs} +1075 -812
- package/dist/_chunks/Field-CDmB9zqh.mjs.map +1 -0
- package/dist/_chunks/{Field-Caef4JjM.js → Field-DoVRA4co.js} +1120 -858
- package/dist/_chunks/Field-DoVRA4co.js.map +1 -0
- package/dist/_chunks/{Form-BzuAjtRq.js → Form-BEh514bg.js} +69 -49
- package/dist/_chunks/Form-BEh514bg.js.map +1 -0
- package/dist/_chunks/{Form-EnaQL_6L.mjs → Form-Cle2X-4n.mjs} +70 -49
- package/dist/_chunks/Form-Cle2X-4n.mjs.map +1 -0
- package/dist/_chunks/{History-C17LiyRg.js → History-BsPXl1XH.js} +182 -146
- package/dist/_chunks/History-BsPXl1XH.js.map +1 -0
- package/dist/_chunks/{History-D6sbCJvo.mjs → History-ktAPcvHJ.mjs} +182 -145
- package/dist/_chunks/History-ktAPcvHJ.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Ce4qs7qE.mjs → ListConfigurationPage-BNAS_v2s.mjs} +71 -60
- package/dist/_chunks/ListConfigurationPage-BNAS_v2s.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Dks5SX6f.js → ListConfigurationPage-CN1-7Pgi.js} +73 -63
- package/dist/_chunks/ListConfigurationPage-CN1-7Pgi.js.map +1 -0
- package/dist/_chunks/{ListViewPage-Be7S5aKL.mjs → ListViewPage-B15c_0Vt.mjs} +143 -139
- package/dist/_chunks/ListViewPage-B15c_0Vt.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BwrZrPsh.js → ListViewPage-BUKFOJuS.js} +146 -142
- package/dist/_chunks/ListViewPage-BUKFOJuS.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CIPmYQMm.mjs → NoContentTypePage-CAgdmhlo.mjs} +7 -7
- package/dist/_chunks/NoContentTypePage-CAgdmhlo.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-Cu5r1-JT.js → NoContentTypePage-Cs7Kk9EW.js} +5 -5
- package/dist/_chunks/NoContentTypePage-Cs7Kk9EW.js.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-C-j6TEUF.js → NoPermissionsPage-DRPnEq9t.js} +4 -5
- package/dist/_chunks/NoPermissionsPage-DRPnEq9t.js.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-DhJ7LYrr.mjs → NoPermissionsPage-JxX4Y4RJ.mjs} +5 -6
- package/dist/_chunks/NoPermissionsPage-JxX4Y4RJ.mjs.map +1 -0
- package/dist/_chunks/Preview-BKuVG1dV.js +286 -0
- package/dist/_chunks/Preview-BKuVG1dV.js.map +1 -0
- package/dist/_chunks/Preview-CQlTtbLc.mjs +267 -0
- package/dist/_chunks/Preview-CQlTtbLc.mjs.map +1 -0
- package/dist/_chunks/{Relations-CY7AtkDA.mjs → Relations-DMQ93R3L.mjs} +135 -89
- package/dist/_chunks/Relations-DMQ93R3L.mjs.map +1 -0
- package/dist/_chunks/{Relations-Czs-uZ-s.js → Relations-DTEGSaM_.js} +138 -93
- package/dist/_chunks/Relations-DTEGSaM_.js.map +1 -0
- package/dist/_chunks/{en-MBPul9Su.mjs → en-CfIXaZf9.mjs} +36 -17
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-CfIXaZf9.mjs.map} +1 -1
- package/dist/_chunks/{en-C-V1_90f.js → en-DTWPCdTS.js} +36 -17
- package/dist/_chunks/{en-C-V1_90f.js.map → en-DTWPCdTS.js.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
- package/dist/_chunks/{index-DNVx8ssZ.mjs → index-BdUq-Dtg.mjs} +1839 -831
- package/dist/_chunks/index-BdUq-Dtg.mjs.map +1 -0
- package/dist/_chunks/{index-X_2tafck.js → index-DjV7tyGu.js} +1826 -818
- package/dist/_chunks/index-DjV7tyGu.js.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout-Dnh0PNp9.mjs → layout-BJ8CpEJu.mjs} +47 -29
- package/dist/_chunks/layout-BJ8CpEJu.mjs.map +1 -0
- package/dist/_chunks/{layout-dBc7wN7L.js → layout-Cx9LHtH5.js} +47 -31
- package/dist/_chunks/layout-Cx9LHtH5.js.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-4pHtBrHJ.js → relations-5bc76OJz.js} +6 -7
- package/dist/_chunks/relations-5bc76OJz.js.map +1 -0
- package/dist/_chunks/{relations-Dx7tMKJN.mjs → relations-BeezTo41.mjs} +6 -7
- package/dist/_chunks/relations-BeezTo41.mjs.map +1 -0
- package/dist/_chunks/useDebounce-CtcjDB3L.js +28 -0
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +1 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.js.map +1 -1
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +9 -7
- package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
- package/dist/admin/src/content-manager.d.ts +3 -3
- package/dist/admin/src/exports.d.ts +2 -1
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +37 -9
- package/dist/admin/src/hooks/useDocumentActions.d.ts +24 -3
- package/dist/admin/src/hooks/useDocumentLayout.d.ts +2 -2
- package/dist/admin/src/hooks/useDragAndDrop.d.ts +4 -4
- package/dist/admin/src/hooks/useKeyboardDragAndDrop.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +11 -4
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/BlocksInput.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Component/Input.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/ComponentCategory.d.ts +3 -5
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +1 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +30 -18
- package/dist/admin/src/pages/EditView/components/FormInputs/UID.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +3 -49
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/Field.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +16 -53
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/EditView/components/InputRenderer.d.ts +2 -10
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +9 -26
- package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
- package/dist/admin/src/preview/constants.d.ts +1 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
- package/dist/admin/src/preview/routes.d.ts +3 -0
- package/dist/admin/src/preview/services/preview.d.ts +3 -0
- package/dist/admin/src/router.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +2 -3
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +5 -5
- package/dist/admin/src/services/documents.d.ts +31 -20
- package/dist/admin/src/services/init.d.ts +2 -2
- package/dist/admin/src/services/relations.d.ts +3 -3
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/api.d.ts +4 -18
- package/dist/admin/src/utils/validation.d.ts +5 -7
- package/dist/server/index.js +1008 -594
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +1014 -600
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +22 -0
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts +11 -0
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -0
- package/dist/server/src/controllers/validation/index.d.ts +1 -1
- package/dist/server/src/history/services/history.d.ts +2 -4
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/index.d.ts +6 -2
- package/dist/server/src/history/services/index.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts +9 -0
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -0
- package/dist/server/src/history/services/utils.d.ts +41 -9
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/history/utils.d.ts +6 -2
- package/dist/server/src/history/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +21 -42
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/preview/constants.d.ts +2 -0
- package/dist/server/src/preview/constants.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +13 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +15 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +30 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +12 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +18 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts +13 -12
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +14 -35
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +21 -42
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts +8 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +17 -7
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/preview.d.ts +27 -0
- package/dist/shared/contracts/preview.d.ts.map +1 -0
- package/dist/shared/contracts/relations.d.ts +2 -2
- package/dist/shared/contracts/relations.d.ts.map +1 -1
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +4 -0
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +19 -20
- package/dist/_chunks/CardDragPreview-DSVYodBX.js.map +0 -1
- package/dist/_chunks/CardDragPreview-ikSG4M46.mjs.map +0 -1
- package/dist/_chunks/ComponentIcon-BBQsYCVn.js.map +0 -1
- package/dist/_chunks/ComponentIcon-BOFnK76n.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs +0 -203
- package/dist/_chunks/EditViewPage-Bm8lgcm6.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-CzOT5Kpj.js.map +0 -1
- package/dist/_chunks/Field-Caef4JjM.js.map +0 -1
- package/dist/_chunks/Field-Dlh0uGnL.mjs.map +0 -1
- package/dist/_chunks/Form-BzuAjtRq.js.map +0 -1
- package/dist/_chunks/Form-EnaQL_6L.mjs.map +0 -1
- package/dist/_chunks/History-C17LiyRg.js.map +0 -1
- package/dist/_chunks/History-D6sbCJvo.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Ce4qs7qE.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Dks5SX6f.js.map +0 -1
- package/dist/_chunks/ListViewPage-Be7S5aKL.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BwrZrPsh.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-CIPmYQMm.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-Cu5r1-JT.js.map +0 -1
- package/dist/_chunks/NoPermissionsPage-C-j6TEUF.js.map +0 -1
- package/dist/_chunks/NoPermissionsPage-DhJ7LYrr.mjs.map +0 -1
- package/dist/_chunks/Relations-CY7AtkDA.mjs.map +0 -1
- package/dist/_chunks/Relations-Czs-uZ-s.js.map +0 -1
- package/dist/_chunks/index-DNVx8ssZ.mjs.map +0 -1
- package/dist/_chunks/index-X_2tafck.js.map +0 -1
- package/dist/_chunks/layout-Dnh0PNp9.mjs.map +0 -1
- package/dist/_chunks/layout-dBc7wN7L.js.map +0 -1
- package/dist/_chunks/relations-4pHtBrHJ.js.map +0 -1
- package/dist/_chunks/relations-Dx7tMKJN.mjs.map +0 -1
- package/dist/_chunks/urls-CbOsUOoW.mjs +0 -7
- package/dist/_chunks/urls-CbOsUOoW.mjs.map +0 -1
- package/dist/_chunks/urls-DzZya_gm.js +0 -6
- package/dist/_chunks/urls-DzZya_gm.js.map +0 -1
- package/dist/server/src/controllers/utils/dimensions.d.ts +0 -5
- package/dist/server/src/controllers/utils/dimensions.d.ts.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,17 +1,16 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
7
4
|
import * as React from "react";
|
8
5
|
import { lazy } from "react";
|
9
|
-
import { Menu, VisuallyHidden, Flex,
|
10
|
-
import
|
6
|
+
import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import mapValues from "lodash/fp/mapValues";
|
8
|
+
import { useIntl } from "react-intl";
|
9
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
10
|
+
import { styled } from "styled-components";
|
11
11
|
import * as yup from "yup";
|
12
12
|
import { ValidationError } from "yup";
|
13
|
-
import {
|
14
|
-
import { isAxiosError } from "axios";
|
13
|
+
import { stringify } from "qs";
|
15
14
|
import pipe from "lodash/fp/pipe";
|
16
15
|
import { intervalToDuration, isPast } from "date-fns";
|
17
16
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
@@ -51,42 +50,6 @@ const useInjectionZone = (area) => {
|
|
51
50
|
const [page, position] = area.split(".");
|
52
51
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
53
52
|
};
|
54
|
-
const HistoryAction = ({ model, document }) => {
|
55
|
-
const { formatMessage } = useIntl();
|
56
|
-
const [{ query }] = useQueryParams();
|
57
|
-
const navigate = useNavigate();
|
58
|
-
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
59
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
60
|
-
return null;
|
61
|
-
}
|
62
|
-
return {
|
63
|
-
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
64
|
-
label: formatMessage({
|
65
|
-
id: "content-manager.history.document-action",
|
66
|
-
defaultMessage: "Content History"
|
67
|
-
}),
|
68
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
69
|
-
disabled: (
|
70
|
-
/**
|
71
|
-
* The user is creating a new document.
|
72
|
-
* It hasn't been saved yet, so there's no history to go to
|
73
|
-
*/
|
74
|
-
!document || /**
|
75
|
-
* The document has been created but the current dimension has never been saved.
|
76
|
-
* For example, the user is creating a new locale in an existing document,
|
77
|
-
* so there's no history for the document in that locale
|
78
|
-
*/
|
79
|
-
!document.id || /**
|
80
|
-
* History is only available for content types created by the user.
|
81
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
82
|
-
* which start with `admin::` or `plugin::`
|
83
|
-
*/
|
84
|
-
!model.startsWith("api::")
|
85
|
-
),
|
86
|
-
position: "header"
|
87
|
-
};
|
88
|
-
};
|
89
|
-
HistoryAction.type = "history";
|
90
53
|
const ID = "id";
|
91
54
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
92
55
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -138,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
138
101
|
if (!slug) {
|
139
102
|
throw new Error("Cannot find the slug param in the URL");
|
140
103
|
}
|
104
|
+
const [{ rawQuery }] = useQueryParams();
|
141
105
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
142
106
|
const contentTypePermissions = React.useMemo(() => {
|
143
107
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -148,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
148
112
|
return { ...acc, [action]: [permission] };
|
149
113
|
}, {});
|
150
114
|
}, [slug, userPermissions]);
|
151
|
-
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
const { isLoading, allowedActions } = useRBAC(
|
116
|
+
contentTypePermissions,
|
117
|
+
permissions ?? void 0,
|
118
|
+
// TODO: useRBAC context should be typed and built differently
|
119
|
+
// We are passing raw query as context to the hook so that it can
|
120
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
121
|
+
rawQuery
|
122
|
+
);
|
152
123
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
153
124
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
154
125
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -157,9 +128,8 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
157
128
|
const name = removeNumericalStrings(fieldName.split("."));
|
158
129
|
const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
|
159
130
|
if (fieldType === "component") {
|
160
|
-
|
161
|
-
|
162
|
-
return field.includes(fieldName);
|
131
|
+
return componentFieldNames.some((field) => {
|
132
|
+
return field.includes(name.join("."));
|
163
133
|
});
|
164
134
|
}
|
165
135
|
if (name.length > 1) {
|
@@ -189,89 +159,20 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
|
|
189
159
|
(field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
|
190
160
|
);
|
191
161
|
const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
|
192
|
-
const
|
193
|
-
|
194
|
-
return query;
|
195
|
-
const { plugins: _, ...validQueryParams } = {
|
196
|
-
...query,
|
197
|
-
...Object.values(query?.plugins ?? {}).reduce(
|
198
|
-
(acc, current) => Object.assign(acc, current),
|
199
|
-
{}
|
200
|
-
)
|
201
|
-
};
|
202
|
-
if ("_q" in validQueryParams) {
|
203
|
-
validQueryParams._q = encodeURIComponent(validQueryParams._q);
|
204
|
-
}
|
205
|
-
return validQueryParams;
|
206
|
-
};
|
207
|
-
const axiosBaseQuery = () => async (query, { signal }) => {
|
208
|
-
try {
|
209
|
-
const { get, post, del, put } = getFetchClient();
|
210
|
-
if (typeof query === "string") {
|
211
|
-
const result = await get(query, { signal });
|
212
|
-
return { data: result.data };
|
213
|
-
} else {
|
214
|
-
const { url, method = "GET", data, config } = query;
|
215
|
-
if (method === "POST") {
|
216
|
-
const result2 = await post(url, data, { ...config, signal });
|
217
|
-
return { data: result2.data };
|
218
|
-
}
|
219
|
-
if (method === "DELETE") {
|
220
|
-
const result2 = await del(url, { ...config, signal });
|
221
|
-
return { data: result2.data };
|
222
|
-
}
|
223
|
-
if (method === "PUT") {
|
224
|
-
const result2 = await put(url, data, { ...config, signal });
|
225
|
-
return { data: result2.data };
|
226
|
-
}
|
227
|
-
const result = await get(url, { ...config, signal });
|
228
|
-
return { data: result.data };
|
229
|
-
}
|
230
|
-
} catch (err) {
|
231
|
-
if (isAxiosError(err)) {
|
232
|
-
if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
|
233
|
-
return { data: void 0, error: err.response?.data.error };
|
234
|
-
} else {
|
235
|
-
return {
|
236
|
-
data: void 0,
|
237
|
-
error: {
|
238
|
-
name: "UnknownError",
|
239
|
-
message: "There was an unknown error response from the API",
|
240
|
-
details: err.response?.data,
|
241
|
-
status: err.response?.status
|
242
|
-
}
|
243
|
-
};
|
244
|
-
}
|
245
|
-
}
|
246
|
-
const error = err;
|
247
|
-
return {
|
248
|
-
data: void 0,
|
249
|
-
error: {
|
250
|
-
name: error.name,
|
251
|
-
message: error.message,
|
252
|
-
stack: error.stack
|
253
|
-
}
|
254
|
-
};
|
255
|
-
}
|
256
|
-
};
|
257
|
-
const isBaseQueryError = (error) => {
|
258
|
-
return error.name !== void 0;
|
259
|
-
};
|
260
|
-
const contentManagerApi = createApi({
|
261
|
-
reducerPath: "contentManagerApi",
|
262
|
-
baseQuery: axiosBaseQuery(),
|
263
|
-
tagTypes: [
|
162
|
+
const contentManagerApi = adminApi.enhanceEndpoints({
|
163
|
+
addTagTypes: [
|
264
164
|
"ComponentConfiguration",
|
265
165
|
"ContentTypesConfiguration",
|
266
166
|
"ContentTypeSettings",
|
267
167
|
"Document",
|
268
168
|
"InitialData",
|
269
169
|
"HistoryVersion",
|
270
|
-
"Relations"
|
271
|
-
|
272
|
-
|
170
|
+
"Relations",
|
171
|
+
"UidAvailability"
|
172
|
+
]
|
273
173
|
});
|
274
174
|
const documentApi = contentManagerApi.injectEndpoints({
|
175
|
+
overrideExisting: true,
|
275
176
|
endpoints: (builder) => ({
|
276
177
|
autoCloneDocument: builder.mutation({
|
277
178
|
query: ({ model, sourceId, query }) => ({
|
@@ -281,7 +182,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
281
182
|
params: query
|
282
183
|
}
|
283
184
|
}),
|
284
|
-
invalidatesTags: (_result,
|
185
|
+
invalidatesTags: (_result, error, { model }) => {
|
186
|
+
if (error) {
|
187
|
+
return [];
|
188
|
+
}
|
189
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
190
|
+
}
|
285
191
|
}),
|
286
192
|
cloneDocument: builder.mutation({
|
287
193
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -292,7 +198,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
292
198
|
params
|
293
199
|
}
|
294
200
|
}),
|
295
|
-
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
invalidatesTags: (_result, _error, { model }) => [
|
202
|
+
{ type: "Document", id: `${model}_LIST` },
|
203
|
+
{ type: "UidAvailability", id: model }
|
204
|
+
]
|
296
205
|
}),
|
297
206
|
/**
|
298
207
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -309,7 +218,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
309
218
|
}),
|
310
219
|
invalidatesTags: (result, _error, { model }) => [
|
311
220
|
{ type: "Document", id: `${model}_LIST` },
|
312
|
-
"Relations"
|
221
|
+
"Relations",
|
222
|
+
{ type: "UidAvailability", id: model }
|
313
223
|
]
|
314
224
|
}),
|
315
225
|
deleteDocument: builder.mutation({
|
@@ -325,12 +235,15 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
325
235
|
]
|
326
236
|
}),
|
327
237
|
deleteManyDocuments: builder.mutation({
|
328
|
-
query: ({ model, ...body }) => ({
|
238
|
+
query: ({ model, params, ...body }) => ({
|
329
239
|
url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
|
330
240
|
method: "POST",
|
331
|
-
data: body
|
241
|
+
data: body,
|
242
|
+
config: {
|
243
|
+
params
|
244
|
+
}
|
332
245
|
}),
|
333
|
-
invalidatesTags: (_res, _error, { model
|
246
|
+
invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
|
334
247
|
}),
|
335
248
|
discardDocument: builder.mutation({
|
336
249
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -347,7 +260,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
347
260
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
348
261
|
},
|
349
262
|
{ type: "Document", id: `${model}_LIST` },
|
350
|
-
"Relations"
|
263
|
+
"Relations",
|
264
|
+
{ type: "UidAvailability", id: model }
|
351
265
|
];
|
352
266
|
}
|
353
267
|
}),
|
@@ -360,11 +274,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
360
274
|
url: `/content-manager/collection-types/${model}`,
|
361
275
|
method: "GET",
|
362
276
|
config: {
|
363
|
-
params
|
277
|
+
params: stringify(params, { encode: true })
|
364
278
|
}
|
365
279
|
}),
|
366
280
|
providesTags: (result, _error, arg) => {
|
367
281
|
return [
|
282
|
+
{ type: "Document", id: `ALL_LIST` },
|
368
283
|
{ type: "Document", id: `${arg.model}_LIST` },
|
369
284
|
...result?.results.map(({ documentId }) => ({
|
370
285
|
type: "Document",
|
@@ -403,6 +318,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
403
318
|
{
|
404
319
|
type: "Document",
|
405
320
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
321
|
+
},
|
322
|
+
// Make it easy to invalidate all individual documents queries for a model
|
323
|
+
{
|
324
|
+
type: "Document",
|
325
|
+
id: `${model}_ALL_ITEMS`
|
406
326
|
}
|
407
327
|
];
|
408
328
|
}
|
@@ -441,10 +361,13 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
441
361
|
}
|
442
362
|
}),
|
443
363
|
publishManyDocuments: builder.mutation({
|
444
|
-
query: ({ model, ...body }) => ({
|
364
|
+
query: ({ model, params, ...body }) => ({
|
445
365
|
url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
|
446
366
|
method: "POST",
|
447
|
-
data: body
|
367
|
+
data: body,
|
368
|
+
config: {
|
369
|
+
params
|
370
|
+
}
|
448
371
|
}),
|
449
372
|
invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
|
450
373
|
}),
|
@@ -463,8 +386,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
463
386
|
type: "Document",
|
464
387
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
465
388
|
},
|
466
|
-
"Relations"
|
389
|
+
"Relations",
|
390
|
+
{ type: "UidAvailability", id: model }
|
467
391
|
];
|
392
|
+
},
|
393
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
394
|
+
const patchResult = dispatch(
|
395
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
396
|
+
Object.assign(draft.data, data);
|
397
|
+
})
|
398
|
+
);
|
399
|
+
try {
|
400
|
+
await queryFulfilled;
|
401
|
+
} catch {
|
402
|
+
patchResult.undo();
|
403
|
+
}
|
468
404
|
}
|
469
405
|
}),
|
470
406
|
unpublishDocument: builder.mutation({
|
@@ -486,10 +422,13 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
486
422
|
}
|
487
423
|
}),
|
488
424
|
unpublishManyDocuments: builder.mutation({
|
489
|
-
query: ({ model, ...body }) => ({
|
425
|
+
query: ({ model, params, ...body }) => ({
|
490
426
|
url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
|
491
427
|
method: "POST",
|
492
|
-
data: body
|
428
|
+
data: body,
|
429
|
+
config: {
|
430
|
+
params
|
431
|
+
}
|
493
432
|
}),
|
494
433
|
invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
|
495
434
|
})
|
@@ -513,20 +452,54 @@ const {
|
|
513
452
|
useUnpublishDocumentMutation,
|
514
453
|
useUnpublishManyDocumentsMutation
|
515
454
|
} = documentApi;
|
516
|
-
const
|
455
|
+
const buildValidParams = (query) => {
|
456
|
+
if (!query)
|
457
|
+
return query;
|
458
|
+
const { plugins: _, ...validQueryParams } = {
|
459
|
+
...query,
|
460
|
+
...Object.values(query?.plugins ?? {}).reduce(
|
461
|
+
(acc, current) => Object.assign(acc, current),
|
462
|
+
{}
|
463
|
+
)
|
464
|
+
};
|
465
|
+
return validQueryParams;
|
466
|
+
};
|
467
|
+
const isBaseQueryError = (error) => {
|
468
|
+
return error.name !== void 0;
|
469
|
+
};
|
470
|
+
const arrayValidator = (attribute, options) => ({
|
471
|
+
message: translatedErrors.required,
|
472
|
+
test(value) {
|
473
|
+
if (options.status === "draft") {
|
474
|
+
return true;
|
475
|
+
}
|
476
|
+
if (!attribute.required) {
|
477
|
+
return true;
|
478
|
+
}
|
479
|
+
if (!value) {
|
480
|
+
return false;
|
481
|
+
}
|
482
|
+
if (Array.isArray(value) && value.length === 0) {
|
483
|
+
return false;
|
484
|
+
}
|
485
|
+
return true;
|
486
|
+
}
|
487
|
+
});
|
488
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
517
489
|
const createModelSchema = (attributes2) => yup.object().shape(
|
518
490
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
519
491
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
520
492
|
return acc;
|
521
493
|
}
|
522
494
|
const validations = [
|
495
|
+
addNullableValidation,
|
523
496
|
addRequiredValidation,
|
524
497
|
addMinLengthValidation,
|
525
498
|
addMaxLengthValidation,
|
526
499
|
addMinValidation,
|
527
500
|
addMaxValidation,
|
528
501
|
addRegexValidation
|
529
|
-
].map((fn) => fn(attribute));
|
502
|
+
].map((fn) => fn(attribute, options));
|
530
503
|
const transformSchema = pipe(...validations);
|
531
504
|
switch (attribute.type) {
|
532
505
|
case "component": {
|
@@ -536,12 +509,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
536
509
|
...acc,
|
537
510
|
[name]: transformSchema(
|
538
511
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
539
|
-
)
|
512
|
+
).test(arrayValidator(attribute, options))
|
540
513
|
};
|
541
514
|
} else {
|
542
515
|
return {
|
543
516
|
...acc,
|
544
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
517
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
545
518
|
};
|
546
519
|
}
|
547
520
|
}
|
@@ -552,24 +525,42 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
552
525
|
yup.array().of(
|
553
526
|
yup.lazy(
|
554
527
|
(data) => {
|
555
|
-
const
|
556
|
-
|
528
|
+
const attributes3 = components?.[data?.__component]?.attributes;
|
529
|
+
const validation = yup.object().shape({
|
557
530
|
__component: yup.string().required().oneOf(Object.keys(components))
|
558
|
-
}).nullable(false)
|
531
|
+
}).nullable(false);
|
532
|
+
if (!attributes3) {
|
533
|
+
return validation;
|
534
|
+
}
|
535
|
+
return validation.concat(createModelSchema(attributes3));
|
559
536
|
}
|
560
537
|
)
|
561
538
|
)
|
562
|
-
)
|
539
|
+
).test(arrayValidator(attribute, options))
|
563
540
|
};
|
564
541
|
case "relation":
|
565
542
|
return {
|
566
543
|
...acc,
|
567
544
|
[name]: transformSchema(
|
568
|
-
yup.
|
569
|
-
|
570
|
-
|
571
|
-
})
|
572
|
-
|
545
|
+
yup.lazy((value) => {
|
546
|
+
if (!value) {
|
547
|
+
return yup.mixed().nullable(true);
|
548
|
+
} else if (Array.isArray(value)) {
|
549
|
+
return yup.array().of(
|
550
|
+
yup.object().shape({
|
551
|
+
id: yup.number().required()
|
552
|
+
})
|
553
|
+
);
|
554
|
+
} else if (typeof value === "object") {
|
555
|
+
return yup.object();
|
556
|
+
} else {
|
557
|
+
return yup.mixed().test(
|
558
|
+
"type-error",
|
559
|
+
"Relation values must be either null, an array of objects with {id} or an object.",
|
560
|
+
() => false
|
561
|
+
);
|
562
|
+
}
|
563
|
+
})
|
573
564
|
)
|
574
565
|
};
|
575
566
|
default:
|
@@ -609,6 +600,14 @@ const createAttributeSchema = (attribute) => {
|
|
609
600
|
if (!value || typeof value === "string" && value.length === 0) {
|
610
601
|
return true;
|
611
602
|
}
|
603
|
+
if (typeof value === "object") {
|
604
|
+
try {
|
605
|
+
JSON.stringify(value);
|
606
|
+
return true;
|
607
|
+
} catch (err) {
|
608
|
+
return false;
|
609
|
+
}
|
610
|
+
}
|
612
611
|
try {
|
613
612
|
JSON.parse(value);
|
614
613
|
return true;
|
@@ -627,16 +626,30 @@ const createAttributeSchema = (attribute) => {
|
|
627
626
|
return yup.mixed();
|
628
627
|
}
|
629
628
|
};
|
630
|
-
const
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
629
|
+
const nullableSchema = (schema) => {
|
630
|
+
return schema?.nullable ? schema.nullable() : (
|
631
|
+
// In some cases '.nullable' will not be available on the schema.
|
632
|
+
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
633
|
+
// In these cases we should just return the schema as it is.
|
634
|
+
schema
|
635
|
+
);
|
636
|
+
};
|
637
|
+
const addNullableValidation = () => (schema) => {
|
638
|
+
return nullableSchema(schema);
|
639
|
+
};
|
640
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
641
|
+
if (options.status === "draft" || !attribute.required) {
|
642
|
+
return schema;
|
643
|
+
}
|
644
|
+
if (attribute.required && "required" in schema) {
|
645
|
+
return schema.required(translatedErrors.required);
|
636
646
|
}
|
637
|
-
return schema
|
647
|
+
return schema;
|
638
648
|
};
|
639
|
-
const addMinLengthValidation = (attribute) => (schema) => {
|
649
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
650
|
+
if (options.status === "draft") {
|
651
|
+
return schema;
|
652
|
+
}
|
640
653
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
641
654
|
return schema.min(attribute.minLength, {
|
642
655
|
...translatedErrors.minLength,
|
@@ -658,10 +671,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
658
671
|
}
|
659
672
|
return schema;
|
660
673
|
};
|
661
|
-
const addMinValidation = (attribute) => (schema) => {
|
662
|
-
if ("
|
674
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
675
|
+
if (options.status === "draft") {
|
676
|
+
return schema;
|
677
|
+
}
|
678
|
+
if ("min" in attribute && "min" in schema) {
|
663
679
|
const min = toInteger(attribute.min);
|
664
|
-
if (
|
680
|
+
if (min) {
|
665
681
|
return schema.min(min, {
|
666
682
|
...translatedErrors.min,
|
667
683
|
values: {
|
@@ -706,24 +722,6 @@ const addRegexValidation = (attribute) => (schema) => {
|
|
706
722
|
}
|
707
723
|
return schema;
|
708
724
|
};
|
709
|
-
const extractValuesFromYupError = (errorType, errorParams) => {
|
710
|
-
if (!errorType || !errorParams) {
|
711
|
-
return {};
|
712
|
-
}
|
713
|
-
return {
|
714
|
-
[errorType]: errorParams[errorType]
|
715
|
-
};
|
716
|
-
};
|
717
|
-
const getInnerErrors = (error) => (error?.inner || []).reduce((acc, currentError) => {
|
718
|
-
if (currentError.path) {
|
719
|
-
acc[currentError.path.split("[").join(".").split("]").join("")] = {
|
720
|
-
id: currentError.message,
|
721
|
-
defaultMessage: currentError.message,
|
722
|
-
values: extractValuesFromYupError(currentError?.type, currentError?.params)
|
723
|
-
};
|
724
|
-
}
|
725
|
-
return acc;
|
726
|
-
}, {});
|
727
725
|
const initApi = contentManagerApi.injectEndpoints({
|
728
726
|
endpoints: (builder) => ({
|
729
727
|
getInitialData: builder.query({
|
@@ -737,27 +735,20 @@ const { useGetInitialDataQuery } = initApi;
|
|
737
735
|
const useContentTypeSchema = (model) => {
|
738
736
|
const { toggleNotification } = useNotification();
|
739
737
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
740
|
-
const {
|
741
|
-
|
742
|
-
|
743
|
-
|
744
|
-
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
)
|
750
|
-
|
751
|
-
|
752
|
-
|
753
|
-
|
754
|
-
error: res.error,
|
755
|
-
components: Object.keys(components2).length === 0 ? void 0 : components2,
|
756
|
-
contentType: contentType2,
|
757
|
-
contentTypes: res.data?.contentTypes ?? []
|
758
|
-
};
|
759
|
-
}
|
760
|
-
});
|
738
|
+
const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
|
739
|
+
const { components, contentType, contentTypes } = React.useMemo(() => {
|
740
|
+
const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
|
741
|
+
const componentsByKey = data?.components.reduce((acc, component) => {
|
742
|
+
acc[component.uid] = component;
|
743
|
+
return acc;
|
744
|
+
}, {});
|
745
|
+
const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
|
746
|
+
return {
|
747
|
+
components: Object.keys(components2).length === 0 ? void 0 : components2,
|
748
|
+
contentType: contentType2,
|
749
|
+
contentTypes: data?.contentTypes ?? []
|
750
|
+
};
|
751
|
+
}, [model, data]);
|
761
752
|
React.useEffect(() => {
|
762
753
|
if (error) {
|
763
754
|
toggleNotification({
|
@@ -804,16 +795,328 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
804
795
|
}, {});
|
805
796
|
return componentsByKey;
|
806
797
|
};
|
807
|
-
const
|
798
|
+
const HOOKS = {
|
799
|
+
/**
|
800
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
801
|
+
* @constant
|
802
|
+
* @type {string}
|
803
|
+
*/
|
804
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
805
|
+
/**
|
806
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
807
|
+
* @constant
|
808
|
+
* @type {string}
|
809
|
+
*/
|
810
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
811
|
+
/**
|
812
|
+
* Hook that allows to mutate the CM's edit view layout
|
813
|
+
* @constant
|
814
|
+
* @type {string}
|
815
|
+
*/
|
816
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
817
|
+
/**
|
818
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
819
|
+
* @constant
|
820
|
+
* @type {string}
|
821
|
+
*/
|
822
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
823
|
+
};
|
824
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
825
|
+
endpoints: (builder) => ({
|
826
|
+
getContentTypeConfiguration: builder.query({
|
827
|
+
query: (uid) => ({
|
828
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
829
|
+
method: "GET"
|
830
|
+
}),
|
831
|
+
transformResponse: (response) => response.data,
|
832
|
+
providesTags: (_result, _error, uid) => [
|
833
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
834
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
835
|
+
]
|
836
|
+
}),
|
837
|
+
getAllContentTypeSettings: builder.query({
|
838
|
+
query: () => "/content-manager/content-types-settings",
|
839
|
+
transformResponse: (response) => response.data,
|
840
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
841
|
+
}),
|
842
|
+
updateContentTypeConfiguration: builder.mutation({
|
843
|
+
query: ({ uid, ...body }) => ({
|
844
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
845
|
+
method: "PUT",
|
846
|
+
data: body
|
847
|
+
}),
|
848
|
+
transformResponse: (response) => response.data,
|
849
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
850
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
851
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
852
|
+
// Is this necessary?
|
853
|
+
{ type: "InitialData" }
|
854
|
+
]
|
855
|
+
})
|
856
|
+
})
|
857
|
+
});
|
858
|
+
const {
|
859
|
+
useGetContentTypeConfigurationQuery,
|
860
|
+
useGetAllContentTypeSettingsQuery,
|
861
|
+
useUpdateContentTypeConfigurationMutation
|
862
|
+
} = contentTypesApi;
|
863
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
864
|
+
const { type } = attribute;
|
865
|
+
if (type === "relation") {
|
866
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
867
|
+
}
|
868
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
869
|
+
};
|
870
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
871
|
+
if (!mainFieldName) {
|
872
|
+
return void 0;
|
873
|
+
}
|
874
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
875
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
876
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
877
|
+
);
|
878
|
+
return {
|
879
|
+
name: mainFieldName,
|
880
|
+
type: mainFieldType ?? "string"
|
881
|
+
};
|
882
|
+
};
|
883
|
+
const DEFAULT_SETTINGS = {
|
884
|
+
bulkable: false,
|
885
|
+
filterable: false,
|
886
|
+
searchable: false,
|
887
|
+
pagination: false,
|
888
|
+
defaultSortBy: "",
|
889
|
+
defaultSortOrder: "asc",
|
890
|
+
mainField: "id",
|
891
|
+
pageSize: 10
|
892
|
+
};
|
893
|
+
const useDocumentLayout = (model) => {
|
894
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
895
|
+
const [{ query }] = useQueryParams();
|
896
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
808
897
|
const { toggleNotification } = useNotification();
|
809
898
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
899
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
810
900
|
const {
|
811
|
-
|
812
|
-
isLoading:
|
813
|
-
|
814
|
-
|
815
|
-
} =
|
816
|
-
const
|
901
|
+
data,
|
902
|
+
isLoading: isLoadingConfigs,
|
903
|
+
error,
|
904
|
+
isFetching: isFetchingConfigs
|
905
|
+
} = useGetContentTypeConfigurationQuery(model);
|
906
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
907
|
+
React.useEffect(() => {
|
908
|
+
if (error) {
|
909
|
+
toggleNotification({
|
910
|
+
type: "danger",
|
911
|
+
message: formatAPIError(error)
|
912
|
+
});
|
913
|
+
}
|
914
|
+
}, [error, formatAPIError, toggleNotification]);
|
915
|
+
const editLayout = React.useMemo(
|
916
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
917
|
+
layout: [],
|
918
|
+
components: {},
|
919
|
+
metadatas: {},
|
920
|
+
options: {},
|
921
|
+
settings: DEFAULT_SETTINGS
|
922
|
+
},
|
923
|
+
[data, isLoading, schemas, schema, components]
|
924
|
+
);
|
925
|
+
const listLayout = React.useMemo(() => {
|
926
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
927
|
+
layout: [],
|
928
|
+
metadatas: {},
|
929
|
+
options: {},
|
930
|
+
settings: DEFAULT_SETTINGS
|
931
|
+
};
|
932
|
+
}, [data, isLoading, schemas, schema, components]);
|
933
|
+
const { layout: edit } = React.useMemo(
|
934
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
935
|
+
layout: editLayout,
|
936
|
+
query
|
937
|
+
}),
|
938
|
+
[editLayout, query, runHookWaterfall]
|
939
|
+
);
|
940
|
+
return {
|
941
|
+
error,
|
942
|
+
isLoading,
|
943
|
+
edit,
|
944
|
+
list: listLayout
|
945
|
+
};
|
946
|
+
};
|
947
|
+
const useDocLayout = () => {
|
948
|
+
const { model } = useDoc();
|
949
|
+
return useDocumentLayout(model);
|
950
|
+
};
|
951
|
+
const formatEditLayout = (data, {
|
952
|
+
schemas,
|
953
|
+
schema,
|
954
|
+
components
|
955
|
+
}) => {
|
956
|
+
let currentPanelIndex = 0;
|
957
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
958
|
+
data.contentType.layouts.edit,
|
959
|
+
schema?.attributes,
|
960
|
+
data.contentType.metadatas,
|
961
|
+
{ configurations: data.components, schemas: components },
|
962
|
+
schemas
|
963
|
+
).reduce((panels, row) => {
|
964
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
965
|
+
panels.push([row]);
|
966
|
+
currentPanelIndex += 2;
|
967
|
+
} else {
|
968
|
+
if (!panels[currentPanelIndex]) {
|
969
|
+
panels.push([row]);
|
970
|
+
} else {
|
971
|
+
panels[currentPanelIndex].push(row);
|
972
|
+
}
|
973
|
+
}
|
974
|
+
return panels;
|
975
|
+
}, []);
|
976
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
977
|
+
(acc, [uid, configuration]) => {
|
978
|
+
acc[uid] = {
|
979
|
+
layout: convertEditLayoutToFieldLayouts(
|
980
|
+
configuration.layouts.edit,
|
981
|
+
components[uid].attributes,
|
982
|
+
configuration.metadatas,
|
983
|
+
{ configurations: data.components, schemas: components }
|
984
|
+
),
|
985
|
+
settings: {
|
986
|
+
...configuration.settings,
|
987
|
+
icon: components[uid].info.icon,
|
988
|
+
displayName: components[uid].info.displayName
|
989
|
+
}
|
990
|
+
};
|
991
|
+
return acc;
|
992
|
+
},
|
993
|
+
{}
|
994
|
+
);
|
995
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
996
|
+
(acc, [attribute, metadata]) => {
|
997
|
+
return {
|
998
|
+
...acc,
|
999
|
+
[attribute]: metadata.edit
|
1000
|
+
};
|
1001
|
+
},
|
1002
|
+
{}
|
1003
|
+
);
|
1004
|
+
return {
|
1005
|
+
layout: panelledEditAttributes,
|
1006
|
+
components: componentEditAttributes,
|
1007
|
+
metadatas: editMetadatas,
|
1008
|
+
settings: {
|
1009
|
+
...data.contentType.settings,
|
1010
|
+
displayName: schema?.info.displayName
|
1011
|
+
},
|
1012
|
+
options: {
|
1013
|
+
...schema?.options,
|
1014
|
+
...schema?.pluginOptions,
|
1015
|
+
...data.contentType.options
|
1016
|
+
}
|
1017
|
+
};
|
1018
|
+
};
|
1019
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1020
|
+
return rows.map(
|
1021
|
+
(row) => row.map((field) => {
|
1022
|
+
const attribute = attributes[field.name];
|
1023
|
+
if (!attribute) {
|
1024
|
+
return null;
|
1025
|
+
}
|
1026
|
+
const { edit: metadata } = metadatas[field.name];
|
1027
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1028
|
+
return {
|
1029
|
+
attribute,
|
1030
|
+
disabled: !metadata.editable,
|
1031
|
+
hint: metadata.description,
|
1032
|
+
label: metadata.label ?? "",
|
1033
|
+
name: field.name,
|
1034
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1035
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1036
|
+
schemas,
|
1037
|
+
components: components?.schemas ?? {}
|
1038
|
+
}),
|
1039
|
+
placeholder: metadata.placeholder ?? "",
|
1040
|
+
required: attribute.required ?? false,
|
1041
|
+
size: field.size,
|
1042
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1043
|
+
visible: metadata.visible ?? true,
|
1044
|
+
type: attribute.type
|
1045
|
+
};
|
1046
|
+
}).filter((field) => field !== null)
|
1047
|
+
);
|
1048
|
+
};
|
1049
|
+
const formatListLayout = (data, {
|
1050
|
+
schemas,
|
1051
|
+
schema,
|
1052
|
+
components
|
1053
|
+
}) => {
|
1054
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1055
|
+
(acc, [attribute, metadata]) => {
|
1056
|
+
return {
|
1057
|
+
...acc,
|
1058
|
+
[attribute]: metadata.list
|
1059
|
+
};
|
1060
|
+
},
|
1061
|
+
{}
|
1062
|
+
);
|
1063
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1064
|
+
data.contentType.layouts.list,
|
1065
|
+
schema?.attributes,
|
1066
|
+
listMetadatas,
|
1067
|
+
{ configurations: data.components, schemas: components },
|
1068
|
+
schemas
|
1069
|
+
);
|
1070
|
+
return {
|
1071
|
+
layout: listAttributes,
|
1072
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1073
|
+
metadatas: listMetadatas,
|
1074
|
+
options: {
|
1075
|
+
...schema?.options,
|
1076
|
+
...schema?.pluginOptions,
|
1077
|
+
...data.contentType.options
|
1078
|
+
}
|
1079
|
+
};
|
1080
|
+
};
|
1081
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1082
|
+
return columns.map((name) => {
|
1083
|
+
const attribute = attributes[name];
|
1084
|
+
if (!attribute) {
|
1085
|
+
return null;
|
1086
|
+
}
|
1087
|
+
const metadata = metadatas[name];
|
1088
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1089
|
+
return {
|
1090
|
+
attribute,
|
1091
|
+
label: metadata.label ?? "",
|
1092
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1093
|
+
schemas,
|
1094
|
+
components: components?.schemas ?? {}
|
1095
|
+
}),
|
1096
|
+
name,
|
1097
|
+
searchable: metadata.searchable ?? true,
|
1098
|
+
sortable: metadata.sortable ?? true
|
1099
|
+
};
|
1100
|
+
}).filter((field) => field !== null);
|
1101
|
+
};
|
1102
|
+
const useDocument = (args, opts) => {
|
1103
|
+
const { toggleNotification } = useNotification();
|
1104
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1105
|
+
const {
|
1106
|
+
currentData: data,
|
1107
|
+
isLoading: isLoadingDocument,
|
1108
|
+
isFetching: isFetchingDocument,
|
1109
|
+
error
|
1110
|
+
} = useGetDocumentQuery(args, {
|
1111
|
+
...opts,
|
1112
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1113
|
+
});
|
1114
|
+
const {
|
1115
|
+
components,
|
1116
|
+
schema,
|
1117
|
+
schemas,
|
1118
|
+
isLoading: isLoadingSchema
|
1119
|
+
} = useContentTypeSchema(args.model);
|
817
1120
|
React.useEffect(() => {
|
818
1121
|
if (error) {
|
819
1122
|
toggleNotification({
|
@@ -840,7 +1143,7 @@ const useDocument = (args, opts) => {
|
|
840
1143
|
return null;
|
841
1144
|
} catch (error2) {
|
842
1145
|
if (error2 instanceof ValidationError) {
|
843
|
-
return
|
1146
|
+
return getYupValidationErrors(error2);
|
844
1147
|
}
|
845
1148
|
throw error2;
|
846
1149
|
}
|
@@ -848,12 +1151,15 @@ const useDocument = (args, opts) => {
|
|
848
1151
|
[validationSchema]
|
849
1152
|
);
|
850
1153
|
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1154
|
+
const hasError = !!error;
|
851
1155
|
return {
|
852
1156
|
components,
|
853
1157
|
document: data?.data,
|
854
1158
|
meta: data?.meta,
|
855
1159
|
isLoading,
|
1160
|
+
hasError,
|
856
1161
|
schema,
|
1162
|
+
schemas,
|
857
1163
|
validate
|
858
1164
|
};
|
859
1165
|
};
|
@@ -867,22 +1173,60 @@ const useDoc = () => {
|
|
867
1173
|
if (!slug) {
|
868
1174
|
throw new Error("Could not find model in url params");
|
869
1175
|
}
|
1176
|
+
const document = useDocument(
|
1177
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1178
|
+
{
|
1179
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1180
|
+
}
|
1181
|
+
);
|
1182
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
870
1183
|
return {
|
871
1184
|
collectionType,
|
872
1185
|
model: slug,
|
873
|
-
id:
|
874
|
-
...
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
1186
|
+
id: returnId,
|
1187
|
+
...document
|
1188
|
+
};
|
1189
|
+
};
|
1190
|
+
const useContentManagerContext = () => {
|
1191
|
+
const {
|
1192
|
+
collectionType,
|
1193
|
+
model,
|
1194
|
+
id,
|
1195
|
+
components,
|
1196
|
+
isLoading: isLoadingDoc,
|
1197
|
+
schema,
|
1198
|
+
schemas
|
1199
|
+
} = useDoc();
|
1200
|
+
const layout = useDocumentLayout(model);
|
1201
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1202
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1203
|
+
const slug = model;
|
1204
|
+
const isCreatingEntry = id === "create";
|
1205
|
+
useContentTypeSchema();
|
1206
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1207
|
+
const error = layout.error;
|
1208
|
+
return {
|
1209
|
+
error,
|
1210
|
+
isLoading,
|
1211
|
+
// Base metadata
|
1212
|
+
model,
|
1213
|
+
collectionType,
|
1214
|
+
id,
|
1215
|
+
slug,
|
1216
|
+
isCreatingEntry,
|
1217
|
+
isSingleType,
|
1218
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1219
|
+
// All schema infos
|
1220
|
+
components,
|
1221
|
+
contentType: schema,
|
1222
|
+
contentTypes: schemas,
|
1223
|
+
// Form state
|
1224
|
+
form,
|
1225
|
+
// layout infos
|
1226
|
+
layout
|
880
1227
|
};
|
881
1228
|
};
|
882
1229
|
const prefixPluginTranslations = (trad, pluginId) => {
|
883
|
-
if (!pluginId) {
|
884
|
-
throw new TypeError("pluginId can't be empty");
|
885
|
-
}
|
886
1230
|
return Object.keys(trad).reduce((acc, current) => {
|
887
1231
|
acc[`${pluginId}.${current}`] = trad[current];
|
888
1232
|
return acc;
|
@@ -898,6 +1242,8 @@ const useDocumentActions = () => {
|
|
898
1242
|
const { formatMessage } = useIntl();
|
899
1243
|
const { trackUsage } = useTracking();
|
900
1244
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1245
|
+
const navigate = useNavigate();
|
1246
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
901
1247
|
const [deleteDocument] = useDeleteDocumentMutation();
|
902
1248
|
const _delete = React.useCallback(
|
903
1249
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -936,14 +1282,15 @@ const useDocumentActions = () => {
|
|
936
1282
|
},
|
937
1283
|
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
938
1284
|
);
|
939
|
-
const [
|
940
|
-
const
|
941
|
-
async ({
|
1285
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1286
|
+
const deleteMany = React.useCallback(
|
1287
|
+
async ({ model, documentIds, params }) => {
|
942
1288
|
try {
|
943
|
-
|
944
|
-
|
1289
|
+
trackUsage("willBulkDeleteEntries");
|
1290
|
+
const res = await deleteManyDocuments({
|
945
1291
|
model,
|
946
|
-
|
1292
|
+
documentIds,
|
1293
|
+
params
|
947
1294
|
});
|
948
1295
|
if ("error" in res) {
|
949
1296
|
toggleNotification({
|
@@ -954,36 +1301,74 @@ const useDocumentActions = () => {
|
|
954
1301
|
}
|
955
1302
|
toggleNotification({
|
956
1303
|
type: "success",
|
957
|
-
|
958
|
-
id: "
|
959
|
-
defaultMessage: "
|
960
|
-
})
|
1304
|
+
title: formatMessage({
|
1305
|
+
id: getTranslation("success.records.delete"),
|
1306
|
+
defaultMessage: "Successfully deleted."
|
1307
|
+
}),
|
1308
|
+
message: ""
|
961
1309
|
});
|
1310
|
+
trackUsage("didBulkDeleteEntries");
|
962
1311
|
return res.data;
|
963
1312
|
} catch (err) {
|
964
1313
|
toggleNotification({
|
965
1314
|
type: "danger",
|
966
1315
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
967
1316
|
});
|
1317
|
+
trackUsage("didNotBulkDeleteEntries");
|
968
1318
|
throw err;
|
969
1319
|
}
|
970
1320
|
},
|
971
|
-
[
|
1321
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
972
1322
|
);
|
973
|
-
const [
|
974
|
-
const
|
975
|
-
async ({ collectionType, model, documentId, params }
|
1323
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1324
|
+
const discard = React.useCallback(
|
1325
|
+
async ({ collectionType, model, documentId, params }) => {
|
976
1326
|
try {
|
977
|
-
|
978
|
-
const res = await publishDocument({
|
1327
|
+
const res = await discardDocument({
|
979
1328
|
collectionType,
|
980
1329
|
model,
|
981
1330
|
documentId,
|
982
|
-
data,
|
983
1331
|
params
|
984
1332
|
});
|
985
1333
|
if ("error" in res) {
|
986
|
-
toggleNotification({
|
1334
|
+
toggleNotification({
|
1335
|
+
type: "danger",
|
1336
|
+
message: formatAPIError(res.error)
|
1337
|
+
});
|
1338
|
+
return { error: res.error };
|
1339
|
+
}
|
1340
|
+
toggleNotification({
|
1341
|
+
type: "success",
|
1342
|
+
message: formatMessage({
|
1343
|
+
id: "content-manager.success.record.discard",
|
1344
|
+
defaultMessage: "Changes discarded"
|
1345
|
+
})
|
1346
|
+
});
|
1347
|
+
return res.data;
|
1348
|
+
} catch (err) {
|
1349
|
+
toggleNotification({
|
1350
|
+
type: "danger",
|
1351
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1352
|
+
});
|
1353
|
+
throw err;
|
1354
|
+
}
|
1355
|
+
},
|
1356
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1357
|
+
);
|
1358
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1359
|
+
const publish = React.useCallback(
|
1360
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1361
|
+
try {
|
1362
|
+
trackUsage("willPublishEntry");
|
1363
|
+
const res = await publishDocument({
|
1364
|
+
collectionType,
|
1365
|
+
model,
|
1366
|
+
documentId,
|
1367
|
+
data,
|
1368
|
+
params
|
1369
|
+
});
|
1370
|
+
if ("error" in res) {
|
1371
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
987
1372
|
return { error: res.error };
|
988
1373
|
}
|
989
1374
|
trackUsage("didPublishEntry");
|
@@ -1005,6 +1390,43 @@ const useDocumentActions = () => {
|
|
1005
1390
|
},
|
1006
1391
|
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1007
1392
|
);
|
1393
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1394
|
+
const publishMany = React.useCallback(
|
1395
|
+
async ({ model, documentIds, params }) => {
|
1396
|
+
try {
|
1397
|
+
const res = await publishManyDocuments({
|
1398
|
+
model,
|
1399
|
+
documentIds,
|
1400
|
+
params
|
1401
|
+
});
|
1402
|
+
if ("error" in res) {
|
1403
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1404
|
+
return { error: res.error };
|
1405
|
+
}
|
1406
|
+
toggleNotification({
|
1407
|
+
type: "success",
|
1408
|
+
message: formatMessage({
|
1409
|
+
id: getTranslation("success.record.publish"),
|
1410
|
+
defaultMessage: "Published document"
|
1411
|
+
})
|
1412
|
+
});
|
1413
|
+
return res.data;
|
1414
|
+
} catch (err) {
|
1415
|
+
toggleNotification({
|
1416
|
+
type: "danger",
|
1417
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1418
|
+
});
|
1419
|
+
throw err;
|
1420
|
+
}
|
1421
|
+
},
|
1422
|
+
[
|
1423
|
+
// trackUsage,
|
1424
|
+
publishManyDocuments,
|
1425
|
+
toggleNotification,
|
1426
|
+
formatMessage,
|
1427
|
+
formatAPIError
|
1428
|
+
]
|
1429
|
+
);
|
1008
1430
|
const [updateDocument] = useUpdateDocumentMutation();
|
1009
1431
|
const update = React.useCallback(
|
1010
1432
|
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
@@ -1079,6 +1501,41 @@ const useDocumentActions = () => {
|
|
1079
1501
|
},
|
1080
1502
|
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1081
1503
|
);
|
1504
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1505
|
+
const unpublishMany = React.useCallback(
|
1506
|
+
async ({ model, documentIds, params }) => {
|
1507
|
+
try {
|
1508
|
+
trackUsage("willBulkUnpublishEntries");
|
1509
|
+
const res = await unpublishManyDocuments({
|
1510
|
+
model,
|
1511
|
+
documentIds,
|
1512
|
+
params
|
1513
|
+
});
|
1514
|
+
if ("error" in res) {
|
1515
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1516
|
+
return { error: res.error };
|
1517
|
+
}
|
1518
|
+
trackUsage("didBulkUnpublishEntries");
|
1519
|
+
toggleNotification({
|
1520
|
+
type: "success",
|
1521
|
+
title: formatMessage({
|
1522
|
+
id: getTranslation("success.records.unpublish"),
|
1523
|
+
defaultMessage: "Successfully unpublished."
|
1524
|
+
}),
|
1525
|
+
message: ""
|
1526
|
+
});
|
1527
|
+
return res.data;
|
1528
|
+
} catch (err) {
|
1529
|
+
toggleNotification({
|
1530
|
+
type: "danger",
|
1531
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1532
|
+
});
|
1533
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1534
|
+
throw err;
|
1535
|
+
}
|
1536
|
+
},
|
1537
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1538
|
+
);
|
1082
1539
|
const [createDocument] = useCreateDocumentMutation();
|
1083
1540
|
const create = React.useCallback(
|
1084
1541
|
async ({ model, params }, data, trackerProperty) => {
|
@@ -1101,6 +1558,7 @@ const useDocumentActions = () => {
|
|
1101
1558
|
defaultMessage: "Saved document"
|
1102
1559
|
})
|
1103
1560
|
});
|
1561
|
+
setCurrentStep("contentManager.success");
|
1104
1562
|
return res.data;
|
1105
1563
|
} catch (err) {
|
1106
1564
|
toggleNotification({
|
@@ -1122,7 +1580,6 @@ const useDocumentActions = () => {
|
|
1122
1580
|
sourceId
|
1123
1581
|
});
|
1124
1582
|
if ("error" in res) {
|
1125
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1126
1583
|
return { error: res.error };
|
1127
1584
|
}
|
1128
1585
|
toggleNotification({
|
@@ -1141,7 +1598,7 @@ const useDocumentActions = () => {
|
|
1141
1598
|
throw err;
|
1142
1599
|
}
|
1143
1600
|
},
|
1144
|
-
[autoCloneDocument,
|
1601
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1145
1602
|
);
|
1146
1603
|
const [cloneDocument] = useCloneDocumentMutation();
|
1147
1604
|
const clone = React.useCallback(
|
@@ -1167,6 +1624,7 @@ const useDocumentActions = () => {
|
|
1167
1624
|
defaultMessage: "Cloned document"
|
1168
1625
|
})
|
1169
1626
|
});
|
1627
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1170
1628
|
return res.data;
|
1171
1629
|
} catch (err) {
|
1172
1630
|
toggleNotification({
|
@@ -1177,7 +1635,7 @@ const useDocumentActions = () => {
|
|
1177
1635
|
throw err;
|
1178
1636
|
}
|
1179
1637
|
},
|
1180
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1638
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1181
1639
|
);
|
1182
1640
|
const [getDoc] = useLazyGetDocumentQuery();
|
1183
1641
|
const getDocument = React.useCallback(
|
@@ -1192,17 +1650,20 @@ const useDocumentActions = () => {
|
|
1192
1650
|
clone,
|
1193
1651
|
create,
|
1194
1652
|
delete: _delete,
|
1653
|
+
deleteMany,
|
1195
1654
|
discard,
|
1196
1655
|
getDocument,
|
1197
1656
|
publish,
|
1657
|
+
publishMany,
|
1198
1658
|
unpublish,
|
1659
|
+
unpublishMany,
|
1199
1660
|
update
|
1200
1661
|
};
|
1201
1662
|
};
|
1202
|
-
const ProtectedHistoryPage = lazy(
|
1203
|
-
() => import("./History-
|
1663
|
+
const ProtectedHistoryPage = React.lazy(
|
1664
|
+
() => import("./History-ktAPcvHJ.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1204
1665
|
);
|
1205
|
-
const routes$
|
1666
|
+
const routes$2 = [
|
1206
1667
|
{
|
1207
1668
|
path: ":collectionType/:slug/:id/history",
|
1208
1669
|
Component: ProtectedHistoryPage
|
@@ -1212,32 +1673,45 @@ const routes$1 = [
|
|
1212
1673
|
Component: ProtectedHistoryPage
|
1213
1674
|
}
|
1214
1675
|
];
|
1676
|
+
const ProtectedPreviewPage = React.lazy(
|
1677
|
+
() => import("./Preview-CQlTtbLc.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1678
|
+
);
|
1679
|
+
const routes$1 = [
|
1680
|
+
{
|
1681
|
+
path: ":collectionType/:slug/:id/preview",
|
1682
|
+
Component: ProtectedPreviewPage
|
1683
|
+
},
|
1684
|
+
{
|
1685
|
+
path: ":collectionType/:slug/preview",
|
1686
|
+
Component: ProtectedPreviewPage
|
1687
|
+
}
|
1688
|
+
];
|
1215
1689
|
const ProtectedEditViewPage = lazy(
|
1216
|
-
() => import("./EditViewPage-
|
1690
|
+
() => import("./EditViewPage-DtbTsNeX.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1217
1691
|
);
|
1218
1692
|
const ProtectedListViewPage = lazy(
|
1219
|
-
() => import("./ListViewPage-
|
1693
|
+
() => import("./ListViewPage-B15c_0Vt.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1220
1694
|
);
|
1221
1695
|
const ProtectedListConfiguration = lazy(
|
1222
|
-
() => import("./ListConfigurationPage-
|
1696
|
+
() => import("./ListConfigurationPage-BNAS_v2s.mjs").then((mod) => ({
|
1223
1697
|
default: mod.ProtectedListConfiguration
|
1224
1698
|
}))
|
1225
1699
|
);
|
1226
1700
|
const ProtectedEditConfigurationPage = lazy(
|
1227
|
-
() => import("./EditConfigurationPage-
|
1701
|
+
() => import("./EditConfigurationPage-DaNf9MoK.mjs").then((mod) => ({
|
1228
1702
|
default: mod.ProtectedEditConfigurationPage
|
1229
1703
|
}))
|
1230
1704
|
);
|
1231
1705
|
const ProtectedComponentConfigurationPage = lazy(
|
1232
|
-
() => import("./ComponentConfigurationPage
|
1706
|
+
() => import("./ComponentConfigurationPage-XdGcgtZh.mjs").then((mod) => ({
|
1233
1707
|
default: mod.ProtectedComponentConfigurationPage
|
1234
1708
|
}))
|
1235
1709
|
);
|
1236
1710
|
const NoPermissions = lazy(
|
1237
|
-
() => import("./NoPermissionsPage-
|
1711
|
+
() => import("./NoPermissionsPage-JxX4Y4RJ.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1238
1712
|
);
|
1239
1713
|
const NoContentType = lazy(
|
1240
|
-
() => import("./NoContentTypePage-
|
1714
|
+
() => import("./NoContentTypePage-CAgdmhlo.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1241
1715
|
);
|
1242
1716
|
const CollectionTypePages = () => {
|
1243
1717
|
const { collectionType } = useParams();
|
@@ -1249,7 +1723,7 @@ const CollectionTypePages = () => {
|
|
1249
1723
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1250
1724
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1251
1725
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1252
|
-
const LIST_PATH = `/content-manager
|
1726
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1253
1727
|
const routes = [
|
1254
1728
|
{
|
1255
1729
|
path: LIST_RELATIVE_PATH,
|
@@ -1283,6 +1757,7 @@ const routes = [
|
|
1283
1757
|
path: "no-content-types",
|
1284
1758
|
Component: NoContentType
|
1285
1759
|
},
|
1760
|
+
...routes$2,
|
1286
1761
|
...routes$1
|
1287
1762
|
];
|
1288
1763
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1351,12 +1826,14 @@ const DocumentActionButton = (action) => {
|
|
1351
1826
|
/* @__PURE__ */ jsx(
|
1352
1827
|
Button,
|
1353
1828
|
{
|
1354
|
-
flex:
|
1829
|
+
flex: "auto",
|
1355
1830
|
startIcon: action.icon,
|
1356
1831
|
disabled: action.disabled,
|
1357
1832
|
onClick: handleClick(action),
|
1358
1833
|
justifyContent: "center",
|
1359
1834
|
variant: action.variant || "default",
|
1835
|
+
paddingTop: "7px",
|
1836
|
+
paddingBottom: "7px",
|
1360
1837
|
children: action.label
|
1361
1838
|
}
|
1362
1839
|
),
|
@@ -1364,7 +1841,7 @@ const DocumentActionButton = (action) => {
|
|
1364
1841
|
DocumentActionConfirmDialog,
|
1365
1842
|
{
|
1366
1843
|
...action.dialog,
|
1367
|
-
variant: action.variant,
|
1844
|
+
variant: action.dialog?.variant ?? action.variant,
|
1368
1845
|
isOpen: dialogId === action.id,
|
1369
1846
|
onClose: handleClose
|
1370
1847
|
}
|
@@ -1379,6 +1856,11 @@ const DocumentActionButton = (action) => {
|
|
1379
1856
|
) : null
|
1380
1857
|
] });
|
1381
1858
|
};
|
1859
|
+
const MenuItem = styled(Menu.Item)`
|
1860
|
+
&:hover {
|
1861
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
1862
|
+
}
|
1863
|
+
`;
|
1382
1864
|
const DocumentActionsMenu = ({
|
1383
1865
|
actions: actions2,
|
1384
1866
|
children,
|
@@ -1421,49 +1903,48 @@ const DocumentActionsMenu = ({
|
|
1421
1903
|
disabled: isDisabled,
|
1422
1904
|
size: "S",
|
1423
1905
|
endIcon: null,
|
1424
|
-
paddingTop: "
|
1425
|
-
paddingLeft: "
|
1426
|
-
paddingRight: "
|
1906
|
+
paddingTop: "4px",
|
1907
|
+
paddingLeft: "7px",
|
1908
|
+
paddingRight: "7px",
|
1427
1909
|
variant,
|
1428
1910
|
children: [
|
1429
1911
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1430
|
-
/* @__PURE__ */ jsx(VisuallyHidden, {
|
1912
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1431
1913
|
id: "content-manager.containers.edit.panels.default.more-actions",
|
1432
1914
|
defaultMessage: "More document actions"
|
1433
1915
|
}) })
|
1434
1916
|
]
|
1435
1917
|
}
|
1436
1918
|
),
|
1437
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1919
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1438
1920
|
actions2.map((action) => {
|
1439
1921
|
return /* @__PURE__ */ jsx(
|
1440
|
-
|
1922
|
+
MenuItem,
|
1441
1923
|
{
|
1442
1924
|
disabled: action.disabled,
|
1443
1925
|
onSelect: handleClick(action),
|
1444
1926
|
display: "block",
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
] })
|
1927
|
+
isVariantDanger: action.variant === "danger",
|
1928
|
+
isDisabled: action.disabled,
|
1929
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
|
1930
|
+
Flex,
|
1931
|
+
{
|
1932
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1933
|
+
gap: 2,
|
1934
|
+
tag: "span",
|
1935
|
+
children: [
|
1936
|
+
/* @__PURE__ */ jsx(
|
1937
|
+
Flex,
|
1938
|
+
{
|
1939
|
+
tag: "span",
|
1940
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1941
|
+
children: action.icon
|
1942
|
+
}
|
1943
|
+
),
|
1944
|
+
action.label
|
1945
|
+
]
|
1946
|
+
}
|
1947
|
+
) })
|
1467
1948
|
},
|
1468
1949
|
action.id
|
1469
1950
|
);
|
@@ -1505,6 +1986,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
|
|
1505
1986
|
return "primary600";
|
1506
1987
|
}
|
1507
1988
|
};
|
1989
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1990
|
+
switch (variant) {
|
1991
|
+
case "danger":
|
1992
|
+
return "danger600";
|
1993
|
+
case "secondary":
|
1994
|
+
return "neutral500";
|
1995
|
+
case "success":
|
1996
|
+
return "success600";
|
1997
|
+
default:
|
1998
|
+
return "primary600";
|
1999
|
+
}
|
2000
|
+
};
|
1508
2001
|
const DocumentActionConfirmDialog = ({
|
1509
2002
|
onClose,
|
1510
2003
|
onCancel,
|
@@ -1527,61 +2020,54 @@ const DocumentActionConfirmDialog = ({
|
|
1527
2020
|
}
|
1528
2021
|
onClose();
|
1529
2022
|
};
|
1530
|
-
return /* @__PURE__ */
|
1531
|
-
/* @__PURE__ */ jsx(
|
1532
|
-
/* @__PURE__ */ jsx(
|
1533
|
-
|
1534
|
-
{
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
)
|
1545
|
-
] });
|
2023
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2024
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2025
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2026
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2027
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2028
|
+
id: "app.components.Button.cancel",
|
2029
|
+
defaultMessage: "Cancel"
|
2030
|
+
}) }) }),
|
2031
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2032
|
+
id: "app.components.Button.confirm",
|
2033
|
+
defaultMessage: "Confirm"
|
2034
|
+
}) })
|
2035
|
+
] })
|
2036
|
+
] }) });
|
1546
2037
|
};
|
1547
2038
|
const DocumentActionModal = ({
|
1548
2039
|
isOpen,
|
1549
2040
|
title,
|
1550
2041
|
onClose,
|
1551
2042
|
footer: Footer,
|
1552
|
-
content,
|
2043
|
+
content: Content,
|
1553
2044
|
onModalClose
|
1554
2045
|
}) => {
|
1555
|
-
const id = React.useId();
|
1556
|
-
if (!isOpen) {
|
1557
|
-
return null;
|
1558
|
-
}
|
1559
2046
|
const handleClose = () => {
|
1560
2047
|
if (onClose) {
|
1561
2048
|
onClose();
|
1562
2049
|
}
|
1563
2050
|
onModalClose();
|
1564
2051
|
};
|
1565
|
-
return /* @__PURE__ */
|
1566
|
-
/* @__PURE__ */ jsx(
|
1567
|
-
/* @__PURE__ */ jsx(
|
1568
|
-
/* @__PURE__ */ jsx(
|
1569
|
-
|
1570
|
-
|
1571
|
-
|
1572
|
-
|
1573
|
-
|
1574
|
-
|
1575
|
-
|
1576
|
-
|
1577
|
-
|
1578
|
-
|
1579
|
-
|
1580
|
-
|
1581
|
-
|
1582
|
-
] });
|
2052
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2053
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2054
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2055
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2056
|
+
] }) });
|
2057
|
+
};
|
2058
|
+
const transformData = (data) => {
|
2059
|
+
if (Array.isArray(data)) {
|
2060
|
+
return data.map(transformData);
|
2061
|
+
}
|
2062
|
+
if (typeof data === "object" && data !== null) {
|
2063
|
+
if ("apiData" in data) {
|
2064
|
+
return data.apiData;
|
2065
|
+
}
|
2066
|
+
return mapValues(transformData)(data);
|
2067
|
+
}
|
2068
|
+
return data;
|
1583
2069
|
};
|
1584
|
-
const PublishAction = ({
|
2070
|
+
const PublishAction$1 = ({
|
1585
2071
|
activeTab,
|
1586
2072
|
documentId,
|
1587
2073
|
model,
|
@@ -1593,13 +2079,17 @@ const PublishAction = ({
|
|
1593
2079
|
const navigate = useNavigate();
|
1594
2080
|
const { toggleNotification } = useNotification();
|
1595
2081
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2082
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1596
2083
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1597
2084
|
const { formatMessage } = useIntl();
|
1598
|
-
const { canPublish
|
1599
|
-
"PublishAction",
|
1600
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1601
|
-
);
|
2085
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1602
2086
|
const { publish } = useDocumentActions();
|
2087
|
+
const [
|
2088
|
+
countDraftRelations,
|
2089
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2090
|
+
] = useLazyGetDraftRelationCountQuery();
|
2091
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2092
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1603
2093
|
const [{ query, rawQuery }] = useQueryParams();
|
1604
2094
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1605
2095
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1608,10 +2098,105 @@ const PublishAction = ({
|
|
1608
2098
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1609
2099
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1610
2100
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
2101
|
+
React.useEffect(() => {
|
2102
|
+
if (isErrorDraftRelations) {
|
2103
|
+
toggleNotification({
|
2104
|
+
type: "danger",
|
2105
|
+
message: formatMessage({
|
2106
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2107
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2108
|
+
})
|
2109
|
+
});
|
2110
|
+
}
|
2111
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2112
|
+
React.useEffect(() => {
|
2113
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2114
|
+
const extractDraftRelations = (data) => {
|
2115
|
+
const relations = data.connect || [];
|
2116
|
+
relations.forEach((relation) => {
|
2117
|
+
if (relation.status === "draft") {
|
2118
|
+
localDraftRelations.add(relation.id);
|
2119
|
+
}
|
2120
|
+
});
|
2121
|
+
};
|
2122
|
+
const traverseAndExtract = (data) => {
|
2123
|
+
Object.entries(data).forEach(([key, value]) => {
|
2124
|
+
if (key === "connect" && Array.isArray(value)) {
|
2125
|
+
extractDraftRelations({ connect: value });
|
2126
|
+
} else if (typeof value === "object" && value !== null) {
|
2127
|
+
traverseAndExtract(value);
|
2128
|
+
}
|
2129
|
+
});
|
2130
|
+
};
|
2131
|
+
if (!documentId || modified) {
|
2132
|
+
traverseAndExtract(formValues);
|
2133
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2134
|
+
}
|
2135
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2136
|
+
React.useEffect(() => {
|
2137
|
+
if (!document || !document.documentId || isListView) {
|
2138
|
+
return;
|
2139
|
+
}
|
2140
|
+
const fetchDraftRelationsCount = async () => {
|
2141
|
+
const { data, error } = await countDraftRelations({
|
2142
|
+
collectionType,
|
2143
|
+
model,
|
2144
|
+
documentId,
|
2145
|
+
params
|
2146
|
+
});
|
2147
|
+
if (error) {
|
2148
|
+
throw error;
|
2149
|
+
}
|
2150
|
+
if (data) {
|
2151
|
+
setServerCountOfDraftRelations(data.data);
|
2152
|
+
}
|
2153
|
+
};
|
2154
|
+
fetchDraftRelationsCount();
|
2155
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1611
2156
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1612
2157
|
if (!schema?.options?.draftAndPublish) {
|
1613
2158
|
return null;
|
1614
2159
|
}
|
2160
|
+
const performPublish = async () => {
|
2161
|
+
setSubmitting(true);
|
2162
|
+
try {
|
2163
|
+
const { errors } = await validate(true, {
|
2164
|
+
status: "published"
|
2165
|
+
});
|
2166
|
+
if (errors) {
|
2167
|
+
toggleNotification({
|
2168
|
+
type: "danger",
|
2169
|
+
message: formatMessage({
|
2170
|
+
id: "content-manager.validation.error",
|
2171
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2172
|
+
})
|
2173
|
+
});
|
2174
|
+
return;
|
2175
|
+
}
|
2176
|
+
const res = await publish(
|
2177
|
+
{
|
2178
|
+
collectionType,
|
2179
|
+
model,
|
2180
|
+
documentId,
|
2181
|
+
params
|
2182
|
+
},
|
2183
|
+
transformData(formValues)
|
2184
|
+
);
|
2185
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2186
|
+
navigate({
|
2187
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2188
|
+
search: rawQuery
|
2189
|
+
});
|
2190
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2191
|
+
setErrors(formatValidationErrors(res.error));
|
2192
|
+
}
|
2193
|
+
} finally {
|
2194
|
+
setSubmitting(false);
|
2195
|
+
}
|
2196
|
+
};
|
2197
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2198
|
+
const enableDraftRelationsCount = false;
|
2199
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1615
2200
|
return {
|
1616
2201
|
/**
|
1617
2202
|
* Disabled when:
|
@@ -1621,52 +2206,39 @@ const PublishAction = ({
|
|
1621
2206
|
* - the document is already published & not modified
|
1622
2207
|
* - the document is being created & not modified
|
1623
2208
|
* - the user doesn't have the permission to publish
|
1624
|
-
* - the user doesn't have the permission to create a new document
|
1625
|
-
* - the user doesn't have the permission to update the document
|
1626
2209
|
*/
|
1627
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2210
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1628
2211
|
label: formatMessage({
|
1629
2212
|
id: "app.utils.publish",
|
1630
2213
|
defaultMessage: "Publish"
|
1631
2214
|
}),
|
1632
2215
|
onClick: async () => {
|
1633
|
-
|
1634
|
-
|
1635
|
-
|
1636
|
-
|
1637
|
-
|
1638
|
-
|
1639
|
-
|
1640
|
-
|
1641
|
-
|
1642
|
-
|
1643
|
-
|
1644
|
-
|
1645
|
-
|
1646
|
-
|
1647
|
-
|
1648
|
-
|
1649
|
-
|
1650
|
-
documentId,
|
1651
|
-
params
|
1652
|
-
},
|
1653
|
-
formValues
|
1654
|
-
);
|
1655
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1656
|
-
navigate({
|
1657
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1658
|
-
search: rawQuery
|
1659
|
-
});
|
1660
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1661
|
-
setErrors(formatValidationErrors(res.error));
|
2216
|
+
await performPublish();
|
2217
|
+
},
|
2218
|
+
dialog: hasDraftRelations ? {
|
2219
|
+
type: "dialog",
|
2220
|
+
variant: "danger",
|
2221
|
+
footer: null,
|
2222
|
+
title: formatMessage({
|
2223
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2224
|
+
defaultMessage: "Confirmation"
|
2225
|
+
}),
|
2226
|
+
content: formatMessage(
|
2227
|
+
{
|
2228
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2229
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2230
|
+
},
|
2231
|
+
{
|
2232
|
+
count: totalDraftRelations
|
1662
2233
|
}
|
1663
|
-
|
1664
|
-
|
2234
|
+
),
|
2235
|
+
onConfirm: async () => {
|
2236
|
+
await performPublish();
|
1665
2237
|
}
|
1666
|
-
}
|
2238
|
+
} : void 0
|
1667
2239
|
};
|
1668
2240
|
};
|
1669
|
-
PublishAction.type = "publish";
|
2241
|
+
PublishAction$1.type = "publish";
|
1670
2242
|
const UpdateAction = ({
|
1671
2243
|
activeTab,
|
1672
2244
|
documentId,
|
@@ -1679,10 +2251,6 @@ const UpdateAction = ({
|
|
1679
2251
|
const cloneMatch = useMatch(CLONE_PATH);
|
1680
2252
|
const isCloning = cloneMatch !== null;
|
1681
2253
|
const { formatMessage } = useIntl();
|
1682
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1683
|
-
canCreate: canCreate2,
|
1684
|
-
canUpdate: canUpdate2
|
1685
|
-
}));
|
1686
2254
|
const { create, update, clone } = useDocumentActions();
|
1687
2255
|
const [{ query, rawQuery }] = useQueryParams();
|
1688
2256
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1699,18 +2267,18 @@ const UpdateAction = ({
|
|
1699
2267
|
* - the form is submitting
|
1700
2268
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1701
2269
|
* - the active tab is the published tab
|
1702
|
-
* - the user doesn't have the permission to create a new document
|
1703
|
-
* - the user doesn't have the permission to update the document
|
1704
2270
|
*/
|
1705
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2271
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1706
2272
|
label: formatMessage({
|
1707
|
-
id: "
|
2273
|
+
id: "global.save",
|
1708
2274
|
defaultMessage: "Save"
|
1709
2275
|
}),
|
1710
2276
|
onClick: async () => {
|
1711
2277
|
setSubmitting(true);
|
1712
2278
|
try {
|
1713
|
-
const { errors } = await validate(
|
2279
|
+
const { errors } = await validate(true, {
|
2280
|
+
status: "draft"
|
2281
|
+
});
|
1714
2282
|
if (errors) {
|
1715
2283
|
toggleNotification({
|
1716
2284
|
type: "danger",
|
@@ -1728,13 +2296,16 @@ const UpdateAction = ({
|
|
1728
2296
|
documentId: cloneMatch.params.origin,
|
1729
2297
|
params
|
1730
2298
|
},
|
1731
|
-
document
|
2299
|
+
transformData(document)
|
1732
2300
|
);
|
1733
2301
|
if ("data" in res) {
|
1734
|
-
navigate(
|
1735
|
-
|
1736
|
-
|
1737
|
-
|
2302
|
+
navigate(
|
2303
|
+
{
|
2304
|
+
pathname: `../${res.data.documentId}`,
|
2305
|
+
search: rawQuery
|
2306
|
+
},
|
2307
|
+
{ relative: "path" }
|
2308
|
+
);
|
1738
2309
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1739
2310
|
setErrors(formatValidationErrors(res.error));
|
1740
2311
|
}
|
@@ -1746,7 +2317,7 @@ const UpdateAction = ({
|
|
1746
2317
|
documentId,
|
1747
2318
|
params
|
1748
2319
|
},
|
1749
|
-
document
|
2320
|
+
transformData(document)
|
1750
2321
|
);
|
1751
2322
|
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1752
2323
|
setErrors(formatValidationErrors(res.error));
|
@@ -1759,13 +2330,16 @@ const UpdateAction = ({
|
|
1759
2330
|
model,
|
1760
2331
|
params
|
1761
2332
|
},
|
1762
|
-
document
|
2333
|
+
transformData(document)
|
1763
2334
|
);
|
1764
2335
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1765
|
-
navigate(
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
2336
|
+
navigate(
|
2337
|
+
{
|
2338
|
+
pathname: `../${res.data.documentId}`,
|
2339
|
+
search: rawQuery
|
2340
|
+
},
|
2341
|
+
{ replace: true, relative: "path" }
|
2342
|
+
);
|
1769
2343
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1770
2344
|
setErrors(formatValidationErrors(res.error));
|
1771
2345
|
}
|
@@ -1781,7 +2355,7 @@ const UNPUBLISH_DRAFT_OPTIONS = {
|
|
1781
2355
|
KEEP: "keep",
|
1782
2356
|
DISCARD: "discard"
|
1783
2357
|
};
|
1784
|
-
const UnpublishAction = ({
|
2358
|
+
const UnpublishAction$1 = ({
|
1785
2359
|
activeTab,
|
1786
2360
|
documentId,
|
1787
2361
|
model,
|
@@ -1797,10 +2371,8 @@ const UnpublishAction = ({
|
|
1797
2371
|
const { toggleNotification } = useNotification();
|
1798
2372
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1799
2373
|
const isDocumentModified = document?.status === "modified";
|
1800
|
-
const handleChange = (
|
1801
|
-
|
1802
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1803
|
-
}
|
2374
|
+
const handleChange = (value) => {
|
2375
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1804
2376
|
};
|
1805
2377
|
if (!schema?.options?.draftAndPublish) {
|
1806
2378
|
return null;
|
@@ -1811,7 +2383,7 @@ const UnpublishAction = ({
|
|
1811
2383
|
id: "app.utils.unpublish",
|
1812
2384
|
defaultMessage: "Unpublish"
|
1813
2385
|
}),
|
1814
|
-
icon: /* @__PURE__ */ jsx(
|
2386
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1815
2387
|
onClick: async () => {
|
1816
2388
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1817
2389
|
if (!documentId) {
|
@@ -1844,45 +2416,30 @@ const UnpublishAction = ({
|
|
1844
2416
|
content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
1845
2417
|
/* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
|
1846
2418
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
1847
|
-
/* @__PURE__ */ jsx(Typography, {
|
2419
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
1848
2420
|
id: "content-manager.actions.unpublish.dialog.body",
|
1849
2421
|
defaultMessage: "Are you sure?"
|
1850
2422
|
}) })
|
1851
2423
|
] }),
|
1852
2424
|
/* @__PURE__ */ jsxs(
|
1853
|
-
|
2425
|
+
Radio.Group,
|
1854
2426
|
{
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
|
1859
|
-
|
2427
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2428
|
+
name: "discard-options",
|
2429
|
+
"aria-label": formatMessage({
|
2430
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2431
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2432
|
+
}),
|
2433
|
+
onValueChange: handleChange,
|
1860
2434
|
children: [
|
1861
|
-
/* @__PURE__ */ jsx(
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
1870
|
-
defaultMessage: "Keep draft"
|
1871
|
-
})
|
1872
|
-
}
|
1873
|
-
),
|
1874
|
-
/* @__PURE__ */ jsx(
|
1875
|
-
Radio,
|
1876
|
-
{
|
1877
|
-
checked: !shouldKeepDraft,
|
1878
|
-
value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
|
1879
|
-
name: "discard-options",
|
1880
|
-
children: formatMessage({
|
1881
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
1882
|
-
defaultMessage: "Replace draft"
|
1883
|
-
})
|
1884
|
-
}
|
1885
|
-
)
|
2435
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2436
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2437
|
+
defaultMessage: "Keep draft"
|
2438
|
+
}) }),
|
2439
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2440
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2441
|
+
defaultMessage: "Replace draft"
|
2442
|
+
}) })
|
1886
2443
|
]
|
1887
2444
|
}
|
1888
2445
|
)
|
@@ -1915,7 +2472,7 @@ const UnpublishAction = ({
|
|
1915
2472
|
position: ["panel", "table-row"]
|
1916
2473
|
};
|
1917
2474
|
};
|
1918
|
-
UnpublishAction.type = "unpublish";
|
2475
|
+
UnpublishAction$1.type = "unpublish";
|
1919
2476
|
const DiscardAction = ({
|
1920
2477
|
activeTab,
|
1921
2478
|
documentId,
|
@@ -1938,7 +2495,7 @@ const DiscardAction = ({
|
|
1938
2495
|
id: "content-manager.actions.discard.label",
|
1939
2496
|
defaultMessage: "Discard changes"
|
1940
2497
|
}),
|
1941
|
-
icon: /* @__PURE__ */ jsx(
|
2498
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1942
2499
|
position: ["panel", "table-row"],
|
1943
2500
|
variant: "danger",
|
1944
2501
|
dialog: {
|
@@ -1949,7 +2506,7 @@ const DiscardAction = ({
|
|
1949
2506
|
}),
|
1950
2507
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
1951
2508
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
1952
|
-
/* @__PURE__ */ jsx(Typography, {
|
2509
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
1953
2510
|
id: "content-manager.actions.discard.dialog.body",
|
1954
2511
|
defaultMessage: "Are you sure?"
|
1955
2512
|
}) })
|
@@ -1966,12 +2523,7 @@ const DiscardAction = ({
|
|
1966
2523
|
};
|
1967
2524
|
};
|
1968
2525
|
DiscardAction.type = "discard";
|
1969
|
-
const
|
1970
|
-
path {
|
1971
|
-
fill: currentColor;
|
1972
|
-
}
|
1973
|
-
`;
|
1974
|
-
const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
|
2526
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
1975
2527
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
1976
2528
|
const RelativeTime = React.forwardRef(
|
1977
2529
|
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
@@ -1983,7 +2535,7 @@ const RelativeTime = React.forwardRef(
|
|
1983
2535
|
});
|
1984
2536
|
const unit = intervals.find((intervalUnit) => {
|
1985
2537
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
1986
|
-
});
|
2538
|
+
}) ?? "seconds";
|
1987
2539
|
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
1988
2540
|
const customInterval = customIntervals.find(
|
1989
2541
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2017,34 +2569,34 @@ const getDisplayName = ({
|
|
2017
2569
|
return email ?? "";
|
2018
2570
|
};
|
2019
2571
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2020
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2021
|
-
const statusVariant = status === "draft" ? "
|
2022
|
-
|
2572
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2573
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2574
|
+
const { formatMessage } = useIntl();
|
2575
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2576
|
+
id: `content-manager.containers.List.${status}`,
|
2577
|
+
defaultMessage: capitalise(status)
|
2578
|
+
}) }) });
|
2023
2579
|
};
|
2024
2580
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2025
2581
|
const { formatMessage } = useIntl();
|
2026
2582
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2583
|
+
const params = useParams();
|
2027
2584
|
const title = isCreating ? formatMessage({
|
2028
2585
|
id: "content-manager.containers.edit.title.new",
|
2029
2586
|
defaultMessage: "Create an entry"
|
2030
2587
|
}) : documentTitle;
|
2031
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2032
|
-
/* @__PURE__ */ jsx(
|
2033
|
-
|
2034
|
-
Flex,
|
2588
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2589
|
+
/* @__PURE__ */ jsx(
|
2590
|
+
BackButton,
|
2035
2591
|
{
|
2036
|
-
|
2037
|
-
justifyContent: "space-between",
|
2038
|
-
paddingTop: 1,
|
2039
|
-
gap: "80px",
|
2040
|
-
alignItems: "flex-start",
|
2041
|
-
children: [
|
2042
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", as: "h1", children: title }),
|
2043
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2044
|
-
]
|
2592
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2045
2593
|
}
|
2046
2594
|
),
|
2047
|
-
|
2595
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2596
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2597
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2598
|
+
] }),
|
2599
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2048
2600
|
] });
|
2049
2601
|
};
|
2050
2602
|
const HeaderToolbar = () => {
|
@@ -2127,12 +2679,12 @@ const Information = ({ activeTab }) => {
|
|
2127
2679
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2128
2680
|
label: formatMessage({
|
2129
2681
|
id: "content-manager.containers.edit.information.last-published.label",
|
2130
|
-
defaultMessage: "
|
2682
|
+
defaultMessage: "Published"
|
2131
2683
|
}),
|
2132
2684
|
value: formatMessage(
|
2133
2685
|
{
|
2134
2686
|
id: "content-manager.containers.edit.information.last-published.value",
|
2135
|
-
defaultMessage: `
|
2687
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2136
2688
|
},
|
2137
2689
|
{
|
2138
2690
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2145,12 +2697,12 @@ const Information = ({ activeTab }) => {
|
|
2145
2697
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2146
2698
|
label: formatMessage({
|
2147
2699
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2148
|
-
defaultMessage: "
|
2700
|
+
defaultMessage: "Updated"
|
2149
2701
|
}),
|
2150
2702
|
value: formatMessage(
|
2151
2703
|
{
|
2152
2704
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2153
|
-
defaultMessage: `
|
2705
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2154
2706
|
},
|
2155
2707
|
{
|
2156
2708
|
time: /* @__PURE__ */ jsx(
|
@@ -2168,12 +2720,12 @@ const Information = ({ activeTab }) => {
|
|
2168
2720
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2169
2721
|
label: formatMessage({
|
2170
2722
|
id: "content-manager.containers.edit.information.document.label",
|
2171
|
-
defaultMessage: "
|
2723
|
+
defaultMessage: "Created"
|
2172
2724
|
}),
|
2173
2725
|
value: formatMessage(
|
2174
2726
|
{
|
2175
2727
|
id: "content-manager.containers.edit.information.document.value",
|
2176
|
-
defaultMessage: `
|
2728
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2177
2729
|
},
|
2178
2730
|
{
|
2179
2731
|
time: /* @__PURE__ */ jsx(
|
@@ -2196,7 +2748,7 @@ const Information = ({ activeTab }) => {
|
|
2196
2748
|
borderColor: "neutral150",
|
2197
2749
|
direction: "column",
|
2198
2750
|
marginTop: 2,
|
2199
|
-
|
2751
|
+
tag: "dl",
|
2200
2752
|
padding: 5,
|
2201
2753
|
gap: 3,
|
2202
2754
|
alignItems: "flex-start",
|
@@ -2204,41 +2756,93 @@ const Information = ({ activeTab }) => {
|
|
2204
2756
|
marginRight: "-0.4rem",
|
2205
2757
|
width: "calc(100% + 8px)",
|
2206
2758
|
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2207
|
-
/* @__PURE__ */ jsx(Typography, {
|
2208
|
-
/* @__PURE__ */ jsx(Typography, {
|
2759
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2760
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2209
2761
|
] }, info.label))
|
2210
2762
|
}
|
2211
2763
|
);
|
2212
2764
|
};
|
2213
2765
|
const HeaderActions = ({ actions: actions2 }) => {
|
2214
|
-
|
2215
|
-
|
2766
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2767
|
+
const handleClick = (action) => async (e) => {
|
2768
|
+
if (!("options" in action)) {
|
2769
|
+
const { onClick = () => false, dialog, id } = action;
|
2770
|
+
const muteDialog = await onClick(e);
|
2771
|
+
if (dialog && !muteDialog) {
|
2772
|
+
e.preventDefault();
|
2773
|
+
setDialogId(id);
|
2774
|
+
}
|
2775
|
+
}
|
2776
|
+
};
|
2777
|
+
const handleClose = () => {
|
2778
|
+
setDialogId(null);
|
2779
|
+
};
|
2780
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2781
|
+
if (action.options) {
|
2216
2782
|
return /* @__PURE__ */ jsx(
|
2217
2783
|
SingleSelect,
|
2218
2784
|
{
|
2219
2785
|
size: "S",
|
2220
|
-
disabled: action.disabled,
|
2221
|
-
"aria-label": action.label,
|
2222
2786
|
onChange: action.onSelect,
|
2223
|
-
|
2787
|
+
"aria-label": action.label,
|
2788
|
+
...action,
|
2224
2789
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2225
2790
|
},
|
2226
2791
|
action.id
|
2227
2792
|
);
|
2228
2793
|
} else {
|
2229
|
-
|
2794
|
+
if (action.type === "icon") {
|
2795
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2796
|
+
/* @__PURE__ */ jsx(
|
2797
|
+
IconButton,
|
2798
|
+
{
|
2799
|
+
disabled: action.disabled,
|
2800
|
+
label: action.label,
|
2801
|
+
size: "S",
|
2802
|
+
onClick: handleClick(action),
|
2803
|
+
children: action.icon
|
2804
|
+
}
|
2805
|
+
),
|
2806
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2807
|
+
HeaderActionDialog,
|
2808
|
+
{
|
2809
|
+
...action.dialog,
|
2810
|
+
isOpen: dialogId === action.id,
|
2811
|
+
onClose: handleClose
|
2812
|
+
}
|
2813
|
+
) : null
|
2814
|
+
] }, action.id);
|
2815
|
+
}
|
2230
2816
|
}
|
2231
2817
|
}) });
|
2232
2818
|
};
|
2233
|
-
const
|
2234
|
-
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2819
|
+
const HeaderActionDialog = ({
|
2820
|
+
onClose,
|
2821
|
+
onCancel,
|
2822
|
+
title,
|
2823
|
+
content: Content,
|
2824
|
+
isOpen
|
2825
|
+
}) => {
|
2826
|
+
const handleClose = async () => {
|
2827
|
+
if (onCancel) {
|
2828
|
+
await onCancel();
|
2829
|
+
}
|
2830
|
+
onClose();
|
2831
|
+
};
|
2832
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2833
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2834
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2835
|
+
] }) });
|
2836
|
+
};
|
2837
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2838
|
+
const navigate = useNavigate();
|
2839
|
+
const { formatMessage } = useIntl();
|
2840
|
+
return {
|
2841
|
+
label: formatMessage({
|
2842
|
+
id: "app.links.configure-view",
|
2239
2843
|
defaultMessage: "Configure the view"
|
2240
2844
|
}),
|
2241
|
-
icon: /* @__PURE__ */ jsx(
|
2845
|
+
icon: /* @__PURE__ */ jsx(ListPlus, {}),
|
2242
2846
|
onClick: () => {
|
2243
2847
|
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2244
2848
|
},
|
@@ -2246,11 +2850,6 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2246
2850
|
};
|
2247
2851
|
};
|
2248
2852
|
ConfigureTheViewAction.type = "configure-the-view";
|
2249
|
-
const StyledCog = styled(Cog)`
|
2250
|
-
path {
|
2251
|
-
fill: currentColor;
|
2252
|
-
}
|
2253
|
-
`;
|
2254
2853
|
const EditTheModelAction = ({ model }) => {
|
2255
2854
|
const navigate = useNavigate();
|
2256
2855
|
const { formatMessage } = useIntl();
|
@@ -2259,7 +2858,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2259
2858
|
id: "content-manager.link-to-ctb",
|
2260
2859
|
defaultMessage: "Edit the model"
|
2261
2860
|
}),
|
2262
|
-
icon: /* @__PURE__ */ jsx(
|
2861
|
+
icon: /* @__PURE__ */ jsx(Pencil, {}),
|
2263
2862
|
onClick: () => {
|
2264
2863
|
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2265
2864
|
},
|
@@ -2267,12 +2866,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2267
2866
|
};
|
2268
2867
|
};
|
2269
2868
|
EditTheModelAction.type = "edit-the-model";
|
2270
|
-
const
|
2271
|
-
path {
|
2272
|
-
fill: currentColor;
|
2273
|
-
}
|
2274
|
-
`;
|
2275
|
-
const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
2869
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2276
2870
|
const navigate = useNavigate();
|
2277
2871
|
const { formatMessage } = useIntl();
|
2278
2872
|
const listViewPathMatch = useMatch(LIST_PATH);
|
@@ -2280,13 +2874,17 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2280
2874
|
const { delete: deleteAction } = useDocumentActions();
|
2281
2875
|
const { toggleNotification } = useNotification();
|
2282
2876
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2877
|
+
const isLocalized = document?.locale != null;
|
2283
2878
|
return {
|
2284
2879
|
disabled: !canDelete || !document,
|
2285
|
-
label: formatMessage(
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2880
|
+
label: formatMessage(
|
2881
|
+
{
|
2882
|
+
id: "content-manager.actions.delete.label",
|
2883
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2884
|
+
},
|
2885
|
+
{ isLocalized }
|
2886
|
+
),
|
2887
|
+
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2290
2888
|
dialog: {
|
2291
2889
|
type: "dialog",
|
2292
2890
|
title: formatMessage({
|
@@ -2295,7 +2893,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2295
2893
|
}),
|
2296
2894
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2297
2895
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2298
|
-
/* @__PURE__ */ jsx(Typography, {
|
2896
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2299
2897
|
id: "content-manager.actions.delete.dialog.body",
|
2300
2898
|
defaultMessage: "Are you sure?"
|
2301
2899
|
}) })
|
@@ -2340,13 +2938,8 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2340
2938
|
position: ["header", "table-row"]
|
2341
2939
|
};
|
2342
2940
|
};
|
2343
|
-
DeleteAction.type = "delete";
|
2344
|
-
const
|
2345
|
-
path {
|
2346
|
-
fill: currentColor;
|
2347
|
-
}
|
2348
|
-
`;
|
2349
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction];
|
2941
|
+
DeleteAction$1.type = "delete";
|
2942
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2350
2943
|
const Panels = () => {
|
2351
2944
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2352
2945
|
const [
|
@@ -2380,7 +2973,7 @@ const ActionsPanel = () => {
|
|
2380
2973
|
return {
|
2381
2974
|
title: formatMessage({
|
2382
2975
|
id: "content-manager.containers.edit.panels.default.title",
|
2383
|
-
defaultMessage: "
|
2976
|
+
defaultMessage: "Entry"
|
2384
2977
|
}),
|
2385
2978
|
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2386
2979
|
};
|
@@ -2420,7 +3013,7 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
|
|
2420
3013
|
Flex,
|
2421
3014
|
{
|
2422
3015
|
ref,
|
2423
|
-
|
3016
|
+
tag: "aside",
|
2424
3017
|
"aria-labelledby": "additional-information",
|
2425
3018
|
background: "neutral0",
|
2426
3019
|
borderColor: "neutral150",
|
@@ -2435,13 +3028,590 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
|
|
2435
3028
|
justifyContent: "stretch",
|
2436
3029
|
alignItems: "flex-start",
|
2437
3030
|
children: [
|
2438
|
-
/* @__PURE__ */ jsx(Typography, {
|
3031
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
2439
3032
|
children
|
2440
3033
|
]
|
2441
3034
|
}
|
2442
3035
|
);
|
2443
3036
|
});
|
2444
|
-
const
|
3037
|
+
const ConfirmBulkActionDialog = ({
|
3038
|
+
onToggleDialog,
|
3039
|
+
isOpen = false,
|
3040
|
+
dialogBody,
|
3041
|
+
endAction
|
3042
|
+
}) => {
|
3043
|
+
const { formatMessage } = useIntl();
|
3044
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3045
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
3046
|
+
id: "app.components.ConfirmDialog.title",
|
3047
|
+
defaultMessage: "Confirmation"
|
3048
|
+
}) }),
|
3049
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3050
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3051
|
+
dialogBody
|
3052
|
+
] }) }),
|
3053
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
3054
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
3055
|
+
id: "app.components.Button.cancel",
|
3056
|
+
defaultMessage: "Cancel"
|
3057
|
+
}) }) }),
|
3058
|
+
endAction
|
3059
|
+
] })
|
3060
|
+
] }) });
|
3061
|
+
};
|
3062
|
+
const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3063
|
+
const ConfirmDialogPublishAll = ({
|
3064
|
+
isOpen,
|
3065
|
+
onToggleDialog,
|
3066
|
+
isConfirmButtonLoading = false,
|
3067
|
+
onConfirm
|
3068
|
+
}) => {
|
3069
|
+
const { formatMessage } = useIntl();
|
3070
|
+
const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
|
3071
|
+
const { toggleNotification } = useNotification();
|
3072
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
3073
|
+
const { model, schema } = useDoc();
|
3074
|
+
const [{ query }] = useQueryParams();
|
3075
|
+
const enableDraftRelationsCount = false;
|
3076
|
+
const {
|
3077
|
+
data: countDraftRelations = 0,
|
3078
|
+
isLoading,
|
3079
|
+
error
|
3080
|
+
} = useGetManyDraftRelationCountQuery(
|
3081
|
+
{
|
3082
|
+
model,
|
3083
|
+
documentIds: selectedEntries.map((entry) => entry.documentId),
|
3084
|
+
locale: query?.plugins?.i18n?.locale
|
3085
|
+
},
|
3086
|
+
{
|
3087
|
+
skip: !enableDraftRelationsCount
|
3088
|
+
}
|
3089
|
+
);
|
3090
|
+
React.useEffect(() => {
|
3091
|
+
if (error) {
|
3092
|
+
toggleNotification({ type: "danger", message: formatAPIError(error) });
|
3093
|
+
}
|
3094
|
+
}, [error, formatAPIError, toggleNotification]);
|
3095
|
+
if (error) {
|
3096
|
+
return null;
|
3097
|
+
}
|
3098
|
+
return /* @__PURE__ */ jsx(
|
3099
|
+
ConfirmBulkActionDialog,
|
3100
|
+
{
|
3101
|
+
isOpen: isOpen && !isLoading,
|
3102
|
+
onToggleDialog,
|
3103
|
+
dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
|
3104
|
+
/* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
|
3105
|
+
countDraftRelations > 0 && formatMessage(
|
3106
|
+
{
|
3107
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
3108
|
+
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. "
|
3109
|
+
},
|
3110
|
+
{
|
3111
|
+
b: BoldChunk$1,
|
3112
|
+
count: countDraftRelations,
|
3113
|
+
entities: selectedEntries.length
|
3114
|
+
}
|
3115
|
+
),
|
3116
|
+
formatMessage({
|
3117
|
+
id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
|
3118
|
+
defaultMessage: "Are you sure you want to publish these entries?"
|
3119
|
+
})
|
3120
|
+
] }),
|
3121
|
+
schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
|
3122
|
+
{
|
3123
|
+
id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
|
3124
|
+
defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
|
3125
|
+
},
|
3126
|
+
{
|
3127
|
+
em: Emphasis
|
3128
|
+
}
|
3129
|
+
) })
|
3130
|
+
] }),
|
3131
|
+
endAction: /* @__PURE__ */ jsx(
|
3132
|
+
Button,
|
3133
|
+
{
|
3134
|
+
onClick: onConfirm,
|
3135
|
+
variant: "secondary",
|
3136
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
3137
|
+
loading: isConfirmButtonLoading,
|
3138
|
+
children: formatMessage({
|
3139
|
+
id: "app.utils.publish",
|
3140
|
+
defaultMessage: "Publish"
|
3141
|
+
})
|
3142
|
+
}
|
3143
|
+
)
|
3144
|
+
}
|
3145
|
+
);
|
3146
|
+
};
|
3147
|
+
const TypographyMaxWidth = styled(Typography)`
|
3148
|
+
max-width: 300px;
|
3149
|
+
`;
|
3150
|
+
const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
3151
|
+
const messages = [];
|
3152
|
+
Object.entries(errors).forEach(([key, value]) => {
|
3153
|
+
const currentKey = parentKey ? `${parentKey}.${key}` : key;
|
3154
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
3155
|
+
if ("id" in value && "defaultMessage" in value) {
|
3156
|
+
messages.push(
|
3157
|
+
formatMessage(
|
3158
|
+
{
|
3159
|
+
id: `${value.id}.withField`,
|
3160
|
+
defaultMessage: value.defaultMessage
|
3161
|
+
},
|
3162
|
+
{ field: currentKey }
|
3163
|
+
)
|
3164
|
+
);
|
3165
|
+
} else {
|
3166
|
+
messages.push(
|
3167
|
+
...formatErrorMessages(
|
3168
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3169
|
+
value,
|
3170
|
+
currentKey,
|
3171
|
+
formatMessage
|
3172
|
+
)
|
3173
|
+
);
|
3174
|
+
}
|
3175
|
+
} else {
|
3176
|
+
messages.push(
|
3177
|
+
formatMessage(
|
3178
|
+
{
|
3179
|
+
id: `${value}.withField`,
|
3180
|
+
defaultMessage: value
|
3181
|
+
},
|
3182
|
+
{ field: currentKey }
|
3183
|
+
)
|
3184
|
+
);
|
3185
|
+
}
|
3186
|
+
});
|
3187
|
+
return messages;
|
3188
|
+
};
|
3189
|
+
const EntryValidationText = ({ validationErrors, status }) => {
|
3190
|
+
const { formatMessage } = useIntl();
|
3191
|
+
if (validationErrors) {
|
3192
|
+
const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
|
3193
|
+
" "
|
3194
|
+
);
|
3195
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3196
|
+
/* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
|
3197
|
+
/* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
|
3198
|
+
] });
|
3199
|
+
}
|
3200
|
+
if (status === "published") {
|
3201
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3202
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3203
|
+
/* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
|
3204
|
+
id: "content-manager.bulk-publish.already-published",
|
3205
|
+
defaultMessage: "Already Published"
|
3206
|
+
}) })
|
3207
|
+
] });
|
3208
|
+
}
|
3209
|
+
if (status === "modified") {
|
3210
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3211
|
+
/* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3212
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3213
|
+
id: "content-manager.bulk-publish.modified",
|
3214
|
+
defaultMessage: "Ready to publish changes"
|
3215
|
+
}) })
|
3216
|
+
] });
|
3217
|
+
}
|
3218
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3219
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3220
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3221
|
+
id: "app.utils.ready-to-publish",
|
3222
|
+
defaultMessage: "Ready to publish"
|
3223
|
+
}) })
|
3224
|
+
] });
|
3225
|
+
};
|
3226
|
+
const TABLE_HEADERS = [
|
3227
|
+
{ name: "id", label: "id" },
|
3228
|
+
{ name: "name", label: "name" },
|
3229
|
+
{ name: "status", label: "status" },
|
3230
|
+
{ name: "publicationStatus", label: "Publication status" }
|
3231
|
+
];
|
3232
|
+
const SelectedEntriesTableContent = ({
|
3233
|
+
isPublishing,
|
3234
|
+
rowsToDisplay = [],
|
3235
|
+
entriesToPublish = [],
|
3236
|
+
validationErrors = {}
|
3237
|
+
}) => {
|
3238
|
+
const { pathname } = useLocation();
|
3239
|
+
const { formatMessage } = useIntl();
|
3240
|
+
const {
|
3241
|
+
list: {
|
3242
|
+
settings: { mainField }
|
3243
|
+
}
|
3244
|
+
} = useDocLayout();
|
3245
|
+
const shouldDisplayMainField = mainField != null && mainField !== "id";
|
3246
|
+
return /* @__PURE__ */ jsxs(Table.Content, { children: [
|
3247
|
+
/* @__PURE__ */ jsxs(Table.Head, { children: [
|
3248
|
+
/* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
|
3249
|
+
TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
|
3250
|
+
(head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
|
3251
|
+
)
|
3252
|
+
] }),
|
3253
|
+
/* @__PURE__ */ jsx(Table.Loading, {}),
|
3254
|
+
/* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
3255
|
+
/* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
|
3256
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
|
3257
|
+
shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
|
3258
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
|
3259
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3260
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3261
|
+
id: "content-manager.success.record.publishing",
|
3262
|
+
defaultMessage: "Publishing..."
|
3263
|
+
}) }),
|
3264
|
+
/* @__PURE__ */ jsx(Loader, { small: true })
|
3265
|
+
] }) : /* @__PURE__ */ jsx(
|
3266
|
+
EntryValidationText,
|
3267
|
+
{
|
3268
|
+
validationErrors: validationErrors[row.documentId],
|
3269
|
+
status: row.status
|
3270
|
+
}
|
3271
|
+
) }),
|
3272
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3273
|
+
IconButton,
|
3274
|
+
{
|
3275
|
+
tag: Link,
|
3276
|
+
to: {
|
3277
|
+
pathname: `${pathname}/${row.documentId}`,
|
3278
|
+
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3279
|
+
},
|
3280
|
+
state: { from: pathname },
|
3281
|
+
label: formatMessage({
|
3282
|
+
id: "content-manager.bulk-publish.edit",
|
3283
|
+
defaultMessage: "Edit"
|
3284
|
+
}),
|
3285
|
+
target: "_blank",
|
3286
|
+
marginLeft: "auto",
|
3287
|
+
variant: "ghost",
|
3288
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3289
|
+
}
|
3290
|
+
) }) })
|
3291
|
+
] }, row.id)) })
|
3292
|
+
] });
|
3293
|
+
};
|
3294
|
+
const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3295
|
+
const SelectedEntriesModalContent = ({
|
3296
|
+
listViewSelectedEntries,
|
3297
|
+
toggleModal,
|
3298
|
+
setListViewSelectedDocuments,
|
3299
|
+
model
|
3300
|
+
}) => {
|
3301
|
+
const { formatMessage } = useIntl();
|
3302
|
+
const { schema, components } = useContentTypeSchema(model);
|
3303
|
+
const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
|
3304
|
+
const [{ query }] = useQueryParams();
|
3305
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3306
|
+
const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
|
3307
|
+
{
|
3308
|
+
model,
|
3309
|
+
params: {
|
3310
|
+
page: "1",
|
3311
|
+
pageSize: documentIds.length.toString(),
|
3312
|
+
sort: query.sort,
|
3313
|
+
filters: {
|
3314
|
+
documentId: {
|
3315
|
+
$in: documentIds
|
3316
|
+
}
|
3317
|
+
},
|
3318
|
+
locale: query.plugins?.i18n?.locale
|
3319
|
+
}
|
3320
|
+
},
|
3321
|
+
{
|
3322
|
+
selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
|
3323
|
+
}
|
3324
|
+
);
|
3325
|
+
const { rows, validationErrors } = React.useMemo(() => {
|
3326
|
+
if (data.length > 0 && schema) {
|
3327
|
+
const validate = createYupSchema(
|
3328
|
+
schema.attributes,
|
3329
|
+
components,
|
3330
|
+
// Since this is the "Publish" action, the validation
|
3331
|
+
// schema must enforce the rules for published entities
|
3332
|
+
{ status: "published" }
|
3333
|
+
);
|
3334
|
+
const validationErrors2 = {};
|
3335
|
+
const rows2 = data.map((entry) => {
|
3336
|
+
try {
|
3337
|
+
validate.validateSync(entry, { abortEarly: false });
|
3338
|
+
return entry;
|
3339
|
+
} catch (e) {
|
3340
|
+
if (e instanceof ValidationError) {
|
3341
|
+
validationErrors2[entry.documentId] = getYupValidationErrors(e);
|
3342
|
+
}
|
3343
|
+
return entry;
|
3344
|
+
}
|
3345
|
+
});
|
3346
|
+
return { rows: rows2, validationErrors: validationErrors2 };
|
3347
|
+
}
|
3348
|
+
return {
|
3349
|
+
rows: [],
|
3350
|
+
validationErrors: {}
|
3351
|
+
};
|
3352
|
+
}, [components, data, schema]);
|
3353
|
+
const [publishedCount, setPublishedCount] = React.useState(0);
|
3354
|
+
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
3355
|
+
const { publishMany: bulkPublishAction } = useDocumentActions();
|
3356
|
+
const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
|
3357
|
+
const selectedRows = useTable("publishAction", (state) => state.selectedRows);
|
3358
|
+
const selectedEntries = rows.filter(
|
3359
|
+
(entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
|
3360
|
+
);
|
3361
|
+
const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
|
3362
|
+
const selectedEntriesWithErrorsCount = selectedEntries.filter(
|
3363
|
+
({ documentId }) => validationErrors[documentId]
|
3364
|
+
).length;
|
3365
|
+
const selectedEntriesPublished = selectedEntries.filter(
|
3366
|
+
({ status }) => status === "published"
|
3367
|
+
).length;
|
3368
|
+
const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
|
3369
|
+
const toggleDialog = () => setIsDialogOpen((prev) => !prev);
|
3370
|
+
const handleConfirmBulkPublish = async () => {
|
3371
|
+
toggleDialog();
|
3372
|
+
const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
|
3373
|
+
if (!("error" in res)) {
|
3374
|
+
setPublishedCount(res.count);
|
3375
|
+
const unpublishedEntries = rows.filter((row) => {
|
3376
|
+
return !entriesToPublish.includes(row.documentId);
|
3377
|
+
});
|
3378
|
+
setListViewSelectedDocuments(unpublishedEntries);
|
3379
|
+
}
|
3380
|
+
};
|
3381
|
+
const getFormattedCountMessage = () => {
|
3382
|
+
if (publishedCount) {
|
3383
|
+
return formatMessage(
|
3384
|
+
{
|
3385
|
+
id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
|
3386
|
+
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."
|
3387
|
+
},
|
3388
|
+
{
|
3389
|
+
publishedCount,
|
3390
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3391
|
+
b: BoldChunk
|
3392
|
+
}
|
3393
|
+
);
|
3394
|
+
}
|
3395
|
+
return formatMessage(
|
3396
|
+
{
|
3397
|
+
id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
|
3398
|
+
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."
|
3399
|
+
},
|
3400
|
+
{
|
3401
|
+
readyToPublishCount: selectedEntriesWithNoErrorsCount,
|
3402
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3403
|
+
alreadyPublishedCount: selectedEntriesPublished,
|
3404
|
+
b: BoldChunk
|
3405
|
+
}
|
3406
|
+
);
|
3407
|
+
};
|
3408
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3409
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3410
|
+
/* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
|
3411
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
|
3412
|
+
SelectedEntriesTableContent,
|
3413
|
+
{
|
3414
|
+
isPublishing: isSubmittingForm,
|
3415
|
+
rowsToDisplay: rows,
|
3416
|
+
entriesToPublish,
|
3417
|
+
validationErrors
|
3418
|
+
}
|
3419
|
+
) })
|
3420
|
+
] }),
|
3421
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3422
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3423
|
+
id: "app.components.Button.cancel",
|
3424
|
+
defaultMessage: "Cancel"
|
3425
|
+
}) }),
|
3426
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3427
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3428
|
+
/* @__PURE__ */ jsx(
|
3429
|
+
Button,
|
3430
|
+
{
|
3431
|
+
onClick: toggleDialog,
|
3432
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
|
3433
|
+
loading: isSubmittingForm,
|
3434
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3435
|
+
}
|
3436
|
+
)
|
3437
|
+
] })
|
3438
|
+
] }),
|
3439
|
+
/* @__PURE__ */ jsx(
|
3440
|
+
ConfirmDialogPublishAll,
|
3441
|
+
{
|
3442
|
+
isOpen: isDialogOpen,
|
3443
|
+
onToggleDialog: toggleDialog,
|
3444
|
+
isConfirmButtonLoading: isSubmittingForm,
|
3445
|
+
onConfirm: handleConfirmBulkPublish
|
3446
|
+
}
|
3447
|
+
)
|
3448
|
+
] });
|
3449
|
+
};
|
3450
|
+
const PublishAction = ({ documents, model }) => {
|
3451
|
+
const { formatMessage } = useIntl();
|
3452
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3453
|
+
const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
|
3454
|
+
const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
|
3455
|
+
const refetchList = () => {
|
3456
|
+
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3457
|
+
};
|
3458
|
+
if (!showPublishButton)
|
3459
|
+
return null;
|
3460
|
+
return {
|
3461
|
+
actionType: "publish",
|
3462
|
+
variant: "tertiary",
|
3463
|
+
label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
|
3464
|
+
dialog: {
|
3465
|
+
type: "modal",
|
3466
|
+
title: formatMessage({
|
3467
|
+
id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
|
3468
|
+
defaultMessage: "Publish entries"
|
3469
|
+
}),
|
3470
|
+
content: ({ onClose }) => {
|
3471
|
+
return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
|
3472
|
+
SelectedEntriesModalContent,
|
3473
|
+
{
|
3474
|
+
listViewSelectedEntries: documents,
|
3475
|
+
toggleModal: () => {
|
3476
|
+
onClose();
|
3477
|
+
refetchList();
|
3478
|
+
},
|
3479
|
+
setListViewSelectedDocuments,
|
3480
|
+
model
|
3481
|
+
}
|
3482
|
+
) });
|
3483
|
+
},
|
3484
|
+
onClose: () => {
|
3485
|
+
refetchList();
|
3486
|
+
}
|
3487
|
+
}
|
3488
|
+
};
|
3489
|
+
};
|
3490
|
+
const BulkActionsRenderer = () => {
|
3491
|
+
const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
|
3492
|
+
const { model, collectionType } = useDoc();
|
3493
|
+
const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
|
3494
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
|
3495
|
+
DescriptionComponentRenderer,
|
3496
|
+
{
|
3497
|
+
props: {
|
3498
|
+
model,
|
3499
|
+
collectionType,
|
3500
|
+
documents: selectedRows
|
3501
|
+
},
|
3502
|
+
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3503
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
3504
|
+
}
|
3505
|
+
) });
|
3506
|
+
};
|
3507
|
+
const DeleteAction = ({ documents, model }) => {
|
3508
|
+
const { formatMessage } = useIntl();
|
3509
|
+
const { schema: contentType } = useDoc();
|
3510
|
+
const selectRow = useTable("DeleteAction", (state) => state.selectRow);
|
3511
|
+
const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
|
3512
|
+
const [{ query }] = useQueryParams();
|
3513
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3514
|
+
const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
|
3515
|
+
const { deleteMany: bulkDeleteAction } = useDocumentActions();
|
3516
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3517
|
+
const handleConfirmBulkDelete = async () => {
|
3518
|
+
const res = await bulkDeleteAction({
|
3519
|
+
documentIds,
|
3520
|
+
model,
|
3521
|
+
params
|
3522
|
+
});
|
3523
|
+
if (!("error" in res)) {
|
3524
|
+
selectRow([]);
|
3525
|
+
}
|
3526
|
+
};
|
3527
|
+
if (!hasDeletePermission)
|
3528
|
+
return null;
|
3529
|
+
return {
|
3530
|
+
variant: "danger-light",
|
3531
|
+
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
3532
|
+
dialog: {
|
3533
|
+
type: "dialog",
|
3534
|
+
title: formatMessage({
|
3535
|
+
id: "app.components.ConfirmDialog.title",
|
3536
|
+
defaultMessage: "Confirmation"
|
3537
|
+
}),
|
3538
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3539
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3540
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3541
|
+
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
3542
|
+
defaultMessage: "Are you sure you want to delete these entries?"
|
3543
|
+
}) }),
|
3544
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3545
|
+
{
|
3546
|
+
id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
|
3547
|
+
defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
|
3548
|
+
},
|
3549
|
+
{
|
3550
|
+
em: Emphasis
|
3551
|
+
}
|
3552
|
+
) }) })
|
3553
|
+
] }),
|
3554
|
+
onConfirm: handleConfirmBulkDelete
|
3555
|
+
}
|
3556
|
+
};
|
3557
|
+
};
|
3558
|
+
DeleteAction.type = "delete";
|
3559
|
+
const UnpublishAction = ({ documents, model }) => {
|
3560
|
+
const { formatMessage } = useIntl();
|
3561
|
+
const { schema } = useDoc();
|
3562
|
+
const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
|
3563
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3564
|
+
const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
|
3565
|
+
const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
|
3566
|
+
const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
|
3567
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3568
|
+
const [{ query }] = useQueryParams();
|
3569
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3570
|
+
const handleConfirmBulkUnpublish = async () => {
|
3571
|
+
const data = await bulkUnpublishAction({ documentIds, model, params });
|
3572
|
+
if (!("error" in data)) {
|
3573
|
+
selectRow([]);
|
3574
|
+
}
|
3575
|
+
};
|
3576
|
+
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3577
|
+
if (!showUnpublishButton)
|
3578
|
+
return null;
|
3579
|
+
return {
|
3580
|
+
variant: "tertiary",
|
3581
|
+
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
3582
|
+
dialog: {
|
3583
|
+
type: "dialog",
|
3584
|
+
title: formatMessage({
|
3585
|
+
id: "app.components.ConfirmDialog.title",
|
3586
|
+
defaultMessage: "Confirmation"
|
3587
|
+
}),
|
3588
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3589
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3590
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3591
|
+
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
3592
|
+
defaultMessage: "Are you sure you want to unpublish these entries?"
|
3593
|
+
}) }),
|
3594
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3595
|
+
{
|
3596
|
+
id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
|
3597
|
+
defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
|
3598
|
+
},
|
3599
|
+
{
|
3600
|
+
em: Emphasis
|
3601
|
+
}
|
3602
|
+
) }) })
|
3603
|
+
] }),
|
3604
|
+
confirmButton: formatMessage({
|
3605
|
+
id: "app.utils.unpublish",
|
3606
|
+
defaultMessage: "Unpublish"
|
3607
|
+
}),
|
3608
|
+
onConfirm: handleConfirmBulkUnpublish
|
3609
|
+
}
|
3610
|
+
};
|
3611
|
+
};
|
3612
|
+
UnpublishAction.type = "unpublish";
|
3613
|
+
const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
|
3614
|
+
const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
|
2445
3615
|
const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
2446
3616
|
const { formatMessage } = useIntl();
|
2447
3617
|
const getDefaultErrorMessage = (reason) => {
|
@@ -2473,7 +3643,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
|
2473
3643
|
hasRadius: true,
|
2474
3644
|
padding: 6,
|
2475
3645
|
children: [
|
2476
|
-
/* @__PURE__ */ jsx(Flex, { direction: "row",
|
3646
|
+
/* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
|
2477
3647
|
pathSegment,
|
2478
3648
|
index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
|
2479
3649
|
ChevronRight,
|
@@ -2485,7 +3655,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
|
2485
3655
|
}
|
2486
3656
|
)
|
2487
3657
|
] }, index2)) }),
|
2488
|
-
/* @__PURE__ */ jsx(Typography, {
|
3658
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
|
2489
3659
|
id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
|
2490
3660
|
defaultMessage: getDefaultErrorMessage(reason)
|
2491
3661
|
}) })
|
@@ -2510,7 +3680,7 @@ const TableActions = ({ document }) => {
|
|
2510
3680
|
DescriptionComponentRenderer,
|
2511
3681
|
{
|
2512
3682
|
props,
|
2513
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3683
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
2514
3684
|
children: (actions2) => {
|
2515
3685
|
const tableRowActions = actions2.filter((action) => {
|
2516
3686
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2621,7 +3791,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2621
3791
|
}),
|
2622
3792
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
2623
3793
|
footer: ({ onClose }) => {
|
2624
|
-
return /* @__PURE__ */ jsxs(
|
3794
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
2625
3795
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
2626
3796
|
id: "cancel",
|
2627
3797
|
defaultMessage: "Cancel"
|
@@ -2629,7 +3799,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2629
3799
|
/* @__PURE__ */ jsx(
|
2630
3800
|
LinkButton,
|
2631
3801
|
{
|
2632
|
-
|
3802
|
+
tag: NavLink,
|
2633
3803
|
to: {
|
2634
3804
|
pathname: `clone/${documentId}`
|
2635
3805
|
},
|
@@ -2662,8 +3832,7 @@ class ContentManagerPlugin {
|
|
2662
3832
|
documentActions = [
|
2663
3833
|
...DEFAULT_ACTIONS,
|
2664
3834
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
2665
|
-
...DEFAULT_HEADER_ACTIONS
|
2666
|
-
HistoryAction
|
3835
|
+
...DEFAULT_HEADER_ACTIONS
|
2667
3836
|
];
|
2668
3837
|
editViewSidePanels = [ActionsPanel];
|
2669
3838
|
headerActions = [];
|
@@ -2752,16 +3921,72 @@ const getPrintableType = (value) => {
|
|
2752
3921
|
}
|
2753
3922
|
return nativeType;
|
2754
3923
|
};
|
2755
|
-
const
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
3924
|
+
const HistoryAction = ({ model, document }) => {
|
3925
|
+
const { formatMessage } = useIntl();
|
3926
|
+
const [{ query }] = useQueryParams();
|
3927
|
+
const navigate = useNavigate();
|
3928
|
+
const { trackUsage } = useTracking();
|
3929
|
+
const { pathname } = useLocation();
|
3930
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3931
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3932
|
+
return null;
|
3933
|
+
}
|
3934
|
+
const handleOnClick = () => {
|
3935
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
3936
|
+
trackUsage("willNavigate", {
|
3937
|
+
from: pathname,
|
3938
|
+
to: `${pathname}/${destination.pathname}`
|
3939
|
+
});
|
3940
|
+
navigate(destination);
|
3941
|
+
};
|
3942
|
+
return {
|
3943
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3944
|
+
label: formatMessage({
|
3945
|
+
id: "content-manager.history.document-action",
|
3946
|
+
defaultMessage: "Content History"
|
3947
|
+
}),
|
3948
|
+
onClick: handleOnClick,
|
3949
|
+
disabled: (
|
3950
|
+
/**
|
3951
|
+
* The user is creating a new document.
|
3952
|
+
* It hasn't been saved yet, so there's no history to go to
|
3953
|
+
*/
|
3954
|
+
!document || /**
|
3955
|
+
* The document has been created but the current dimension has never been saved.
|
3956
|
+
* For example, the user is creating a new locale in an existing document,
|
3957
|
+
* so there's no history for the document in that locale
|
3958
|
+
*/
|
3959
|
+
!document.id || /**
|
3960
|
+
* History is only available for content types created by the user.
|
3961
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3962
|
+
* which start with `admin::` or `plugin::`
|
3963
|
+
*/
|
3964
|
+
!model.startsWith("api::")
|
3965
|
+
),
|
3966
|
+
position: "header"
|
3967
|
+
};
|
3968
|
+
};
|
3969
|
+
HistoryAction.type = "history";
|
3970
|
+
const historyAdmin = {
|
3971
|
+
bootstrap(app) {
|
3972
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3973
|
+
addDocumentAction((actions2) => {
|
3974
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3975
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3976
|
+
return actions2;
|
3977
|
+
});
|
3978
|
+
}
|
3979
|
+
};
|
3980
|
+
const initialState = {
|
3981
|
+
collectionTypeLinks: [],
|
3982
|
+
components: [],
|
3983
|
+
fieldSizes: {},
|
3984
|
+
models: [],
|
3985
|
+
singleTypeLinks: [],
|
3986
|
+
isLoading: true
|
3987
|
+
};
|
3988
|
+
const appSlice = createSlice({
|
3989
|
+
name: "app",
|
2765
3990
|
initialState,
|
2766
3991
|
reducers: {
|
2767
3992
|
setInitialData(state, action) {
|
@@ -2788,316 +4013,78 @@ const { setInitialData } = actions;
|
|
2788
4013
|
const reducer = combineReducers({
|
2789
4014
|
app: reducer$1
|
2790
4015
|
});
|
2791
|
-
const
|
2792
|
-
/**
|
2793
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2794
|
-
* @constant
|
2795
|
-
* @type {string}
|
2796
|
-
*/
|
2797
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2798
|
-
/**
|
2799
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2800
|
-
* @constant
|
2801
|
-
* @type {string}
|
2802
|
-
*/
|
2803
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2804
|
-
/**
|
2805
|
-
* Hook that allows to mutate the CM's edit view layout
|
2806
|
-
* @constant
|
2807
|
-
* @type {string}
|
2808
|
-
*/
|
2809
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2810
|
-
/**
|
2811
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2812
|
-
* @constant
|
2813
|
-
* @type {string}
|
2814
|
-
*/
|
2815
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2816
|
-
};
|
2817
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
4016
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
2818
4017
|
endpoints: (builder) => ({
|
2819
|
-
|
2820
|
-
query
|
2821
|
-
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2828
|
-
|
2829
|
-
}),
|
2830
|
-
getAllContentTypeSettings: builder.query({
|
2831
|
-
query: () => "/content-manager/content-types-settings",
|
2832
|
-
transformResponse: (response) => response.data,
|
2833
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2834
|
-
}),
|
2835
|
-
updateContentTypeConfiguration: builder.mutation({
|
2836
|
-
query: ({ uid, ...body }) => ({
|
2837
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2838
|
-
method: "PUT",
|
2839
|
-
data: body
|
2840
|
-
}),
|
2841
|
-
transformResponse: (response) => response.data,
|
2842
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2843
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2844
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2845
|
-
// Is this necessary?
|
2846
|
-
{ type: "InitialData" }
|
2847
|
-
]
|
4018
|
+
getPreviewUrl: builder.query({
|
4019
|
+
query({ query, params }) {
|
4020
|
+
return {
|
4021
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4022
|
+
method: "GET",
|
4023
|
+
config: {
|
4024
|
+
params: query
|
4025
|
+
}
|
4026
|
+
};
|
4027
|
+
}
|
2848
4028
|
})
|
2849
4029
|
})
|
2850
4030
|
});
|
2851
|
-
const {
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
} =
|
2856
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2857
|
-
const { type } = attribute;
|
2858
|
-
if (type === "relation") {
|
2859
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2860
|
-
}
|
2861
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2862
|
-
};
|
2863
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2864
|
-
if (!mainFieldName) {
|
2865
|
-
return void 0;
|
2866
|
-
}
|
2867
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2868
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2869
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2870
|
-
);
|
2871
|
-
return {
|
2872
|
-
name: mainFieldName,
|
2873
|
-
type: mainFieldType ?? "string"
|
2874
|
-
};
|
2875
|
-
};
|
2876
|
-
const DEFAULT_SETTINGS = {
|
2877
|
-
bulkable: false,
|
2878
|
-
filterable: false,
|
2879
|
-
searchable: false,
|
2880
|
-
pagination: false,
|
2881
|
-
defaultSortBy: "",
|
2882
|
-
defaultSortOrder: "asc",
|
2883
|
-
mainField: "id",
|
2884
|
-
pageSize: 10
|
2885
|
-
};
|
2886
|
-
const useDocumentLayout = (model) => {
|
2887
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
4031
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4032
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4033
|
+
const { formatMessage } = useIntl();
|
4034
|
+
const { trackUsage } = useTracking();
|
4035
|
+
const { pathname } = useLocation();
|
2888
4036
|
const [{ query }] = useQueryParams();
|
2889
|
-
const
|
2890
|
-
|
2891
|
-
|
2892
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2893
|
-
const {
|
2894
|
-
data,
|
2895
|
-
isLoading: isLoadingConfigs,
|
2896
|
-
error,
|
2897
|
-
isFetching: isFetchingConfigs
|
2898
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2899
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2900
|
-
React.useEffect(() => {
|
2901
|
-
if (error) {
|
2902
|
-
toggleNotification({
|
2903
|
-
type: "danger",
|
2904
|
-
message: formatAPIError(error)
|
2905
|
-
});
|
2906
|
-
}
|
2907
|
-
}, [error, formatAPIError, toggleNotification]);
|
2908
|
-
const editLayout = React.useMemo(
|
2909
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2910
|
-
layout: [],
|
2911
|
-
components: {},
|
2912
|
-
metadatas: {},
|
2913
|
-
options: {},
|
2914
|
-
settings: DEFAULT_SETTINGS
|
2915
|
-
},
|
2916
|
-
[data, isLoading, schemas, schema, components]
|
2917
|
-
);
|
2918
|
-
const listLayout = React.useMemo(() => {
|
2919
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2920
|
-
layout: [],
|
2921
|
-
metadatas: {},
|
2922
|
-
options: {},
|
2923
|
-
settings: DEFAULT_SETTINGS
|
2924
|
-
};
|
2925
|
-
}, [data, isLoading, schemas, schema, components]);
|
2926
|
-
const { layout: edit } = React.useMemo(
|
2927
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2928
|
-
layout: editLayout,
|
2929
|
-
query
|
2930
|
-
}),
|
2931
|
-
[editLayout, query, runHookWaterfall]
|
2932
|
-
);
|
2933
|
-
return {
|
2934
|
-
error,
|
2935
|
-
isLoading,
|
2936
|
-
edit,
|
2937
|
-
list: listLayout
|
2938
|
-
};
|
2939
|
-
};
|
2940
|
-
const useDocLayout = () => {
|
2941
|
-
const { model } = useDoc();
|
2942
|
-
return useDocumentLayout(model);
|
2943
|
-
};
|
2944
|
-
const formatEditLayout = (data, {
|
2945
|
-
schemas,
|
2946
|
-
schema,
|
2947
|
-
components
|
2948
|
-
}) => {
|
2949
|
-
let currentPanelIndex = 0;
|
2950
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2951
|
-
data.contentType.layouts.edit,
|
2952
|
-
schema?.attributes,
|
2953
|
-
data.contentType.metadatas,
|
2954
|
-
{ configurations: data.components, schemas: components },
|
2955
|
-
schemas
|
2956
|
-
).reduce((panels, row) => {
|
2957
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2958
|
-
panels.push([row]);
|
2959
|
-
currentPanelIndex += 2;
|
2960
|
-
} else {
|
2961
|
-
if (!panels[currentPanelIndex]) {
|
2962
|
-
panels.push([]);
|
2963
|
-
}
|
2964
|
-
panels[currentPanelIndex].push(row);
|
2965
|
-
}
|
2966
|
-
return panels;
|
2967
|
-
}, []);
|
2968
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2969
|
-
(acc, [uid, configuration]) => {
|
2970
|
-
acc[uid] = {
|
2971
|
-
layout: convertEditLayoutToFieldLayouts(
|
2972
|
-
configuration.layouts.edit,
|
2973
|
-
components[uid].attributes,
|
2974
|
-
configuration.metadatas
|
2975
|
-
),
|
2976
|
-
settings: {
|
2977
|
-
...configuration.settings,
|
2978
|
-
icon: components[uid].info.icon,
|
2979
|
-
displayName: components[uid].info.displayName
|
2980
|
-
}
|
2981
|
-
};
|
2982
|
-
return acc;
|
4037
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4038
|
+
params: {
|
4039
|
+
contentType: model
|
2983
4040
|
},
|
2984
|
-
{
|
2985
|
-
|
2986
|
-
|
2987
|
-
|
2988
|
-
return {
|
2989
|
-
...acc,
|
2990
|
-
[attribute]: metadata.edit
|
2991
|
-
};
|
2992
|
-
},
|
2993
|
-
{}
|
2994
|
-
);
|
2995
|
-
return {
|
2996
|
-
layout: panelledEditAttributes,
|
2997
|
-
components: componentEditAttributes,
|
2998
|
-
metadatas: editMetadatas,
|
2999
|
-
settings: {
|
3000
|
-
...data.contentType.settings,
|
3001
|
-
displayName: schema?.info.displayName
|
3002
|
-
},
|
3003
|
-
options: {
|
3004
|
-
...schema?.options,
|
3005
|
-
...schema?.pluginOptions,
|
3006
|
-
...data.contentType.options
|
4041
|
+
query: {
|
4042
|
+
documentId,
|
4043
|
+
locale: document?.locale,
|
4044
|
+
status: document?.status
|
3007
4045
|
}
|
4046
|
+
});
|
4047
|
+
if (!data?.data?.url || error) {
|
4048
|
+
return null;
|
4049
|
+
}
|
4050
|
+
const trackNavigation = () => {
|
4051
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4052
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
3008
4053
|
};
|
3009
|
-
};
|
3010
|
-
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
3011
|
-
return rows.map(
|
3012
|
-
(row) => row.map((field) => {
|
3013
|
-
const attribute = attributes[field.name];
|
3014
|
-
if (!attribute) {
|
3015
|
-
return null;
|
3016
|
-
}
|
3017
|
-
const { edit: metadata } = metadatas[field.name];
|
3018
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
3019
|
-
return {
|
3020
|
-
attribute,
|
3021
|
-
disabled: !metadata.editable,
|
3022
|
-
hint: metadata.description,
|
3023
|
-
label: metadata.label ?? "",
|
3024
|
-
name: field.name,
|
3025
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
3026
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
3027
|
-
schemas,
|
3028
|
-
components: components?.schemas ?? {}
|
3029
|
-
}),
|
3030
|
-
placeholder: metadata.placeholder ?? "",
|
3031
|
-
required: attribute.required ?? false,
|
3032
|
-
size: field.size,
|
3033
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
3034
|
-
visible: metadata.visible ?? true,
|
3035
|
-
type: attribute.type
|
3036
|
-
};
|
3037
|
-
}).filter((field) => field !== null)
|
3038
|
-
);
|
3039
|
-
};
|
3040
|
-
const formatListLayout = (data, {
|
3041
|
-
schemas,
|
3042
|
-
schema,
|
3043
|
-
components
|
3044
|
-
}) => {
|
3045
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
3046
|
-
(acc, [attribute, metadata]) => {
|
3047
|
-
return {
|
3048
|
-
...acc,
|
3049
|
-
[attribute]: metadata.list
|
3050
|
-
};
|
3051
|
-
},
|
3052
|
-
{}
|
3053
|
-
);
|
3054
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
3055
|
-
data.contentType.layouts.list,
|
3056
|
-
schema?.attributes,
|
3057
|
-
listMetadatas,
|
3058
|
-
{ configurations: data.components, schemas: components },
|
3059
|
-
schemas
|
3060
|
-
);
|
3061
4054
|
return {
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
4055
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4056
|
+
content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
|
4057
|
+
Button,
|
4058
|
+
{
|
4059
|
+
variant: "tertiary",
|
4060
|
+
tag: Link,
|
4061
|
+
to: { pathname: "preview", search: stringify(query, { encode: false }) },
|
4062
|
+
onClick: trackNavigation,
|
4063
|
+
flex: "auto",
|
4064
|
+
children: formatMessage({
|
4065
|
+
id: "content-manager.preview.panel.button",
|
4066
|
+
defaultMessage: "Open preview"
|
4067
|
+
})
|
4068
|
+
}
|
4069
|
+
) })
|
3070
4070
|
};
|
3071
4071
|
};
|
3072
|
-
const
|
3073
|
-
|
3074
|
-
|
3075
|
-
if (!
|
3076
|
-
return
|
4072
|
+
const FEATURE_ID = "preview";
|
4073
|
+
const previewAdmin = {
|
4074
|
+
bootstrap(app) {
|
4075
|
+
if (!window.strapi.future.isEnabled(FEATURE_ID)) {
|
4076
|
+
return;
|
3077
4077
|
}
|
3078
|
-
const
|
3079
|
-
|
3080
|
-
|
3081
|
-
attribute,
|
3082
|
-
label: metadata.label ?? "",
|
3083
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
3084
|
-
schemas,
|
3085
|
-
components: components?.schemas ?? {}
|
3086
|
-
}),
|
3087
|
-
name,
|
3088
|
-
searchable: metadata.searchable ?? true,
|
3089
|
-
sortable: metadata.sortable ?? true
|
3090
|
-
};
|
3091
|
-
}).filter((field) => field !== null);
|
4078
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4079
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4080
|
+
}
|
3092
4081
|
};
|
3093
4082
|
const index = {
|
3094
4083
|
register(app) {
|
3095
4084
|
const cm = new ContentManagerPlugin();
|
3096
4085
|
app.addReducers({
|
3097
|
-
[contentManagerApi.reducerPath]: contentManagerApi.reducer,
|
3098
4086
|
[PLUGIN_ID]: reducer
|
3099
4087
|
});
|
3100
|
-
app.addMiddlewares([() => contentManagerApi.middleware]);
|
3101
4088
|
app.addMenuLink({
|
3102
4089
|
to: PLUGIN_ID,
|
3103
4090
|
icon: Feather,
|
@@ -3106,14 +4093,32 @@ const index = {
|
|
3106
4093
|
defaultMessage: "Content Manager"
|
3107
4094
|
},
|
3108
4095
|
permissions: [],
|
3109
|
-
|
4096
|
+
position: 1
|
4097
|
+
});
|
4098
|
+
app.router.addRoute({
|
4099
|
+
path: "content-manager/*",
|
4100
|
+
lazy: async () => {
|
4101
|
+
const { Layout } = await import("./layout-BJ8CpEJu.mjs");
|
4102
|
+
return {
|
4103
|
+
Component: Layout
|
4104
|
+
};
|
4105
|
+
},
|
4106
|
+
children: routes
|
3110
4107
|
});
|
3111
4108
|
app.registerPlugin(cm.config);
|
3112
4109
|
},
|
4110
|
+
bootstrap(app) {
|
4111
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4112
|
+
historyAdmin.bootstrap(app);
|
4113
|
+
}
|
4114
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4115
|
+
previewAdmin.bootstrap(app);
|
4116
|
+
}
|
4117
|
+
},
|
3113
4118
|
async registerTrads({ locales }) {
|
3114
4119
|
const importedTrads = await Promise.all(
|
3115
4120
|
locales.map((locale) => {
|
3116
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-
|
4121
|
+
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-CfIXaZf9.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.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-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
|
3117
4122
|
return {
|
3118
4123
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3119
4124
|
locale
|
@@ -3131,45 +4136,48 @@ const index = {
|
|
3131
4136
|
};
|
3132
4137
|
export {
|
3133
4138
|
ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as A,
|
3134
|
-
|
4139
|
+
BulkActionsRenderer as B,
|
3135
4140
|
COLLECTION_TYPES as C,
|
3136
4141
|
DocumentStatus as D,
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
4142
|
+
extractContentTypeComponents as E,
|
4143
|
+
DEFAULT_SETTINGS as F,
|
4144
|
+
convertEditLayoutToFieldLayouts as G,
|
3140
4145
|
HOOKS as H,
|
3141
4146
|
InjectionZone as I,
|
3142
|
-
|
3143
|
-
|
4147
|
+
useDocument as J,
|
4148
|
+
useGetPreviewUrlQuery as K,
|
4149
|
+
index as L,
|
4150
|
+
useContentManagerContext as M,
|
4151
|
+
useDocumentActions as N,
|
3144
4152
|
Panels as P,
|
3145
4153
|
RelativeTime as R,
|
3146
4154
|
SINGLE_TYPES as S,
|
3147
4155
|
TableActions as T,
|
3148
|
-
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3153
|
-
|
4156
|
+
useGetInitialDataQuery as a,
|
4157
|
+
useGetAllContentTypeSettingsQuery as b,
|
4158
|
+
useDoc as c,
|
4159
|
+
buildValidParams as d,
|
4160
|
+
contentManagerApi as e,
|
4161
|
+
useDocumentRBAC as f,
|
3154
4162
|
getTranslation as g,
|
3155
|
-
|
3156
|
-
|
3157
|
-
|
3158
|
-
|
3159
|
-
|
3160
|
-
|
3161
|
-
|
3162
|
-
|
3163
|
-
|
3164
|
-
|
3165
|
-
|
4163
|
+
useDocumentLayout as h,
|
4164
|
+
createYupSchema as i,
|
4165
|
+
Header as j,
|
4166
|
+
PERMISSIONS as k,
|
4167
|
+
DocumentRBAC as l,
|
4168
|
+
DOCUMENT_META_FIELDS as m,
|
4169
|
+
CLONE_PATH as n,
|
4170
|
+
useDocLayout as o,
|
4171
|
+
useGetContentTypeConfigurationQuery as p,
|
4172
|
+
CREATOR_FIELDS as q,
|
4173
|
+
getMainField as r,
|
3166
4174
|
setInitialData as s,
|
3167
4175
|
getDisplayName as t,
|
3168
|
-
|
4176
|
+
useContentTypeSchema as u,
|
3169
4177
|
checkIfAttributeIsDisplayable as v,
|
3170
4178
|
useGetAllDocumentsQuery as w,
|
3171
4179
|
convertListLayoutToFieldLayouts as x,
|
3172
4180
|
capitalise as y,
|
3173
4181
|
useUpdateContentTypeConfigurationMutation as z
|
3174
4182
|
};
|
3175
|
-
//# sourceMappingURL=index-
|
4183
|
+
//# sourceMappingURL=index-BdUq-Dtg.mjs.map
|