@strapi/content-manager 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.19d775295eb622de3e659110caf22fcd2cd5d10d
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-DjQBdcKF.mjs → ComponentConfigurationPage-B_99pmC0.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DjQBdcKF.mjs.map → ComponentConfigurationPage-B_99pmC0.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js → ComponentConfigurationPage-NeMPjY5M.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-2iOVVhqV.js.map → ComponentConfigurationPage-NeMPjY5M.js.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BBQsYCVn.js → ComponentIcon-CRbtQEUV.js} +9 -4
- package/dist/_chunks/ComponentIcon-CRbtQEUV.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-BoBb-DLH.mjs → EditConfigurationPage-B0kNlNoj.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-BoBb-DLH.mjs.map → EditConfigurationPage-B0kNlNoj.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js → EditConfigurationPage-n7_xHayb.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-B7dw5_cS.js.map → EditConfigurationPage-n7_xHayb.js.map} +1 -1
- package/dist/_chunks/EditViewPage-BT7Achc-.js +209 -0
- package/dist/_chunks/EditViewPage-BT7Achc-.js.map +1 -0
- package/dist/_chunks/EditViewPage-DYXZs4_2.mjs +191 -0
- package/dist/_chunks/EditViewPage-DYXZs4_2.mjs.map +1 -0
- package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
- package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
- package/dist/_chunks/{Form-CQ67ZifP.js → Form-BRmk2Dp3.js} +68 -49
- package/dist/_chunks/Form-BRmk2Dp3.js.map +1 -0
- package/dist/_chunks/{Form-Jgh5hGTu.mjs → Form-D3paRF1F.mjs} +67 -46
- package/dist/_chunks/Form-D3paRF1F.mjs.map +1 -0
- package/dist/_chunks/{History-BLEnudTX.js → History-BQpDoOu8.js} +211 -148
- package/dist/_chunks/History-BQpDoOu8.js.map +1 -0
- package/dist/_chunks/{History-DKhZAPcK.mjs → History-CzQbTOwa.mjs} +204 -139
- package/dist/_chunks/History-CzQbTOwa.mjs.map +1 -0
- package/dist/_chunks/{Field-kVFO4ZKB.mjs → Input-ww3KFYZr.mjs} +1996 -1730
- package/dist/_chunks/Input-ww3KFYZr.mjs.map +1 -0
- package/dist/_chunks/{Field-kq1c2TF1.js → Input-yM6HnyQa.js} +2035 -1770
- package/dist/_chunks/Input-yM6HnyQa.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Zso_LUjn.js → ListConfigurationPage-B6NsS-0m.js} +72 -63
- package/dist/_chunks/ListConfigurationPage-B6NsS-0m.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-nrXcxNYi.mjs → ListConfigurationPage-Bbw8w5cS.mjs} +68 -57
- package/dist/_chunks/ListConfigurationPage-Bbw8w5cS.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-ChhYmA-L.mjs → ListViewPage-DnOP55pM.mjs} +179 -160
- package/dist/_chunks/ListViewPage-DnOP55pM.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-DsaOakWQ.js → ListViewPage-Dt8OUTwO.js} +183 -165
- package/dist/_chunks/ListViewPage-Dt8OUTwO.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BrdFcN33.mjs → NoContentTypePage-CXKXHNMa.mjs} +3 -3
- package/dist/_chunks/NoContentTypePage-CXKXHNMa.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DPCuS9Y1.js → NoContentTypePage-Dgm-uj-6.js} +3 -3
- package/dist/_chunks/NoContentTypePage-Dgm-uj-6.js.map +1 -0
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js → NoPermissionsPage-CLbU5SOt.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DdyOfdKb.js.map → NoPermissionsPage-CLbU5SOt.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs → NoPermissionsPage-kaj1rPiW.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B9dqrtTy.mjs.map → NoPermissionsPage-kaj1rPiW.mjs.map} +1 -1
- package/dist/_chunks/Preview-Bieh13Ro.mjs +287 -0
- package/dist/_chunks/Preview-Bieh13Ro.mjs.map +1 -0
- package/dist/_chunks/Preview-CbXHXqBg.js +305 -0
- package/dist/_chunks/Preview-CbXHXqBg.js.map +1 -0
- package/dist/_chunks/{Relations-DjFiYd7-.mjs → Relations-7rWJcZ3_.mjs} +138 -94
- package/dist/_chunks/Relations-7rWJcZ3_.mjs.map +1 -0
- package/dist/_chunks/{Relations-CY8Isqdu.js → Relations-CvifV6Y6.js} +142 -100
- package/dist/_chunks/Relations-CvifV6Y6.js.map +1 -0
- package/dist/_chunks/{en-C-V1_90f.js → en-BR48D_RH.js} +45 -18
- package/dist/_chunks/{en-C-V1_90f.js.map → en-BR48D_RH.js.map} +1 -1
- package/dist/_chunks/{en-MBPul9Su.mjs → en-D65uIF6Y.mjs} +45 -18
- package/dist/_chunks/{en-MBPul9Su.mjs.map → en-D65uIF6Y.mjs.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-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-CAc9yTnx.mjs → index-BH2JnYpF.mjs} +2302 -995
- package/dist/_chunks/index-BH2JnYpF.mjs.map +1 -0
- package/dist/_chunks/{index-DNa1J4HE.js → index-DkJQjlak.js} +2273 -967
- package/dist/_chunks/index-DkJQjlak.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-BqtLA6Lb.js → layout-4BqLFW_b.js} +47 -32
- package/dist/_chunks/layout-4BqLFW_b.js.map +1 -0
- package/dist/_chunks/{layout-CXsHbc3E.mjs → layout-bbOlPwLA.mjs} +46 -28
- package/dist/_chunks/layout-bbOlPwLA.mjs.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-mMFEcZRq.mjs → relations-HsflnFpO.mjs} +6 -7
- package/dist/_chunks/relations-HsflnFpO.mjs.map +1 -0
- package/dist/_chunks/{relations-BHY_KDJ_.js → relations-Yc0Z6A20.js} +6 -7
- package/dist/_chunks/relations-Yc0Z6A20.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/useDragAndDrop-BMtgCYzL.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
- package/dist/_chunks/useDragAndDrop-DJ6jqvZN.mjs.map +1 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
- package/dist/_chunks/usePrev-D5J_2fEu.js +28 -0
- package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
- package/dist/admin/index.js +4 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +10 -7
- package/dist/admin/src/components/ComponentIcon.d.ts +6 -3
- package/dist/admin/src/content-manager.d.ts +7 -5
- package/dist/admin/src/exports.d.ts +3 -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 +54 -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 +12 -5
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
- 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 +5 -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/DynamicComponent.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -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/FormLayout.d.ts +27 -0
- 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/EditView/utils/data.d.ts +1 -0
- 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/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 +959 -543
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +960 -543
- 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 +23 -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/controllers/history-version.d.ts +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts +3 -3
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +8 -12
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +21 -36
- 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/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 +16 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +32 -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 +19 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts +11 -6
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +16 -35
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +21 -36
- 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/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 +22 -22
- 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-KRG56aCq.js +0 -224
- package/dist/_chunks/EditViewPage-KRG56aCq.js.map +0 -1
- package/dist/_chunks/EditViewPage-aUnqL-63.mjs +0 -203
- package/dist/_chunks/EditViewPage-aUnqL-63.mjs.map +0 -1
- package/dist/_chunks/Field-kVFO4ZKB.mjs.map +0 -1
- package/dist/_chunks/Field-kq1c2TF1.js.map +0 -1
- package/dist/_chunks/Form-CQ67ZifP.js.map +0 -1
- package/dist/_chunks/Form-Jgh5hGTu.mjs.map +0 -1
- package/dist/_chunks/History-BLEnudTX.js.map +0 -1
- package/dist/_chunks/History-DKhZAPcK.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Zso_LUjn.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-nrXcxNYi.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-ChhYmA-L.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-DsaOakWQ.js.map +0 -1
- package/dist/_chunks/NoContentTypePage-BrdFcN33.mjs.map +0 -1
- package/dist/_chunks/NoContentTypePage-DPCuS9Y1.js.map +0 -1
- package/dist/_chunks/Relations-CY8Isqdu.js.map +0 -1
- package/dist/_chunks/Relations-DjFiYd7-.mjs.map +0 -1
- package/dist/_chunks/index-CAc9yTnx.mjs.map +0 -1
- package/dist/_chunks/index-DNa1J4HE.js.map +0 -1
- package/dist/_chunks/layout-BqtLA6Lb.js.map +0 -1
- package/dist/_chunks/layout-CXsHbc3E.mjs.map +0 -1
- package/dist/_chunks/relations-BHY_KDJ_.js.map +0 -1
- package/dist/_chunks/relations-mMFEcZRq.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/_chunks/useDragAndDrop-DdHgKsqq.mjs.map +0 -1
- package/dist/_chunks/useDragAndDrop-J0TUUbR6.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,27 +1,34 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, CrossCircle, 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, Typography,
|
10
|
-
import
|
6
|
+
import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, RawTable, Loader, Tbody, Tr, Td, 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 { generateNKeysBetween } from "fractional-indexing";
|
15
14
|
import pipe from "lodash/fp/pipe";
|
15
|
+
import { stringify } from "qs";
|
16
16
|
import { intervalToDuration, isPast } from "date-fns";
|
17
17
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
18
|
-
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
18
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
19
19
|
const v = glob[path];
|
20
20
|
if (v) {
|
21
21
|
return typeof v === "function" ? v() : Promise.resolve(v);
|
22
22
|
}
|
23
23
|
return new Promise((_, reject) => {
|
24
|
-
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
24
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
25
|
+
reject.bind(
|
26
|
+
null,
|
27
|
+
new Error(
|
28
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
29
|
+
)
|
30
|
+
)
|
31
|
+
);
|
25
32
|
});
|
26
33
|
};
|
27
34
|
const PLUGIN_ID = "content-manager";
|
@@ -51,42 +58,6 @@ const useInjectionZone = (area) => {
|
|
51
58
|
const [page, position] = area.split(".");
|
52
59
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
53
60
|
};
|
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
61
|
const ID = "id";
|
91
62
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
92
63
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -138,6 +109,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
138
109
|
if (!slug) {
|
139
110
|
throw new Error("Cannot find the slug param in the URL");
|
140
111
|
}
|
112
|
+
const [{ rawQuery }] = useQueryParams();
|
141
113
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
142
114
|
const contentTypePermissions = React.useMemo(() => {
|
143
115
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -148,7 +120,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
148
120
|
return { ...acc, [action]: [permission] };
|
149
121
|
}, {});
|
150
122
|
}, [slug, userPermissions]);
|
151
|
-
const { isLoading, allowedActions } = useRBAC(
|
123
|
+
const { isLoading, allowedActions } = useRBAC(
|
124
|
+
contentTypePermissions,
|
125
|
+
permissions ?? void 0,
|
126
|
+
// TODO: useRBAC context should be typed and built differently
|
127
|
+
// We are passing raw query as context to the hook so that it can
|
128
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
129
|
+
rawQuery
|
130
|
+
);
|
152
131
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
153
132
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
154
133
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -157,9 +136,8 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
157
136
|
const name = removeNumericalStrings(fieldName.split("."));
|
158
137
|
const componentFieldNames = fieldsUserCanAction.filter((field) => field.split(".").length > 1);
|
159
138
|
if (fieldType === "component") {
|
160
|
-
|
161
|
-
|
162
|
-
return field.includes(fieldName);
|
139
|
+
return componentFieldNames.some((field) => {
|
140
|
+
return field.includes(name.join("."));
|
163
141
|
});
|
164
142
|
}
|
165
143
|
if (name.length > 1) {
|
@@ -189,89 +167,128 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
|
|
189
167
|
(field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
|
190
168
|
);
|
191
169
|
const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
|
192
|
-
const
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
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 };
|
170
|
+
const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
|
171
|
+
const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
|
172
|
+
const traverse = (datum, attributes) => {
|
173
|
+
return Object.entries(datum).reduce((acc, [key, value]) => {
|
174
|
+
const attribute = attributes[key];
|
175
|
+
if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
|
176
|
+
acc[key] = value;
|
177
|
+
return acc;
|
178
|
+
}
|
179
|
+
if (attribute.type === "component") {
|
180
|
+
if (attribute.repeatable) {
|
181
|
+
const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
182
|
+
acc[key] = componentValue.map(
|
183
|
+
(componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
|
184
|
+
);
|
185
|
+
} else {
|
186
|
+
const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
187
|
+
acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
|
188
|
+
}
|
189
|
+
} else if (attribute.type === "dynamiczone") {
|
190
|
+
const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
191
|
+
acc[key] = dynamicZoneValue.map(
|
192
|
+
(componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
|
193
|
+
);
|
194
|
+
} else if (predicate(attribute, value)) {
|
195
|
+
acc[key] = transform(value, attribute);
|
234
196
|
} else {
|
235
|
-
|
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
|
-
};
|
197
|
+
acc[key] = value;
|
244
198
|
}
|
199
|
+
return acc;
|
200
|
+
}, {});
|
201
|
+
};
|
202
|
+
return traverse(data, schema.attributes);
|
203
|
+
};
|
204
|
+
const removeProhibitedFields = (prohibitedFields) => traverseData(
|
205
|
+
(attribute) => prohibitedFields.includes(attribute.type),
|
206
|
+
() => ""
|
207
|
+
);
|
208
|
+
const prepareRelations = traverseData(
|
209
|
+
(attribute) => attribute.type === "relation",
|
210
|
+
() => ({
|
211
|
+
connect: [],
|
212
|
+
disconnect: []
|
213
|
+
})
|
214
|
+
);
|
215
|
+
const prepareTempKeys = traverseData(
|
216
|
+
(attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
|
217
|
+
(data) => {
|
218
|
+
if (Array.isArray(data) && data.length > 0) {
|
219
|
+
const keys = generateNKeysBetween(void 0, void 0, data.length);
|
220
|
+
return data.map((datum, index2) => ({
|
221
|
+
...datum,
|
222
|
+
__temp_key__: keys[index2]
|
223
|
+
}));
|
245
224
|
}
|
246
|
-
|
247
|
-
return {
|
248
|
-
data: void 0,
|
249
|
-
error: {
|
250
|
-
name: error.name,
|
251
|
-
message: error.message,
|
252
|
-
stack: error.stack
|
253
|
-
}
|
254
|
-
};
|
225
|
+
return data;
|
255
226
|
}
|
227
|
+
);
|
228
|
+
const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
|
229
|
+
const schemaKeys = Object.keys(schema.attributes);
|
230
|
+
const dataKeys = Object.keys(data);
|
231
|
+
const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
|
232
|
+
const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
|
233
|
+
delete acc[key];
|
234
|
+
return acc;
|
235
|
+
}, structuredClone(data));
|
236
|
+
return revisedData;
|
256
237
|
};
|
257
|
-
const
|
258
|
-
return
|
238
|
+
const removeNullValues = (data) => {
|
239
|
+
return Object.entries(data).reduce((acc, [key, value]) => {
|
240
|
+
if (value === null) {
|
241
|
+
return acc;
|
242
|
+
}
|
243
|
+
acc[key] = value;
|
244
|
+
return acc;
|
245
|
+
}, {});
|
246
|
+
};
|
247
|
+
const transformDocument = (schema, components = {}) => (document) => {
|
248
|
+
const transformations = pipe(
|
249
|
+
removeFieldsThatDontExistOnSchema(schema),
|
250
|
+
removeProhibitedFields(["password"])(schema, components),
|
251
|
+
removeNullValues,
|
252
|
+
prepareRelations(schema, components),
|
253
|
+
prepareTempKeys(schema, components)
|
254
|
+
);
|
255
|
+
return transformations(document);
|
256
|
+
};
|
257
|
+
const createDefaultForm = (contentType, components = {}) => {
|
258
|
+
const traverseSchema = (attributes) => {
|
259
|
+
return Object.entries(attributes).reduce((acc, [key, attribute]) => {
|
260
|
+
if ("default" in attribute) {
|
261
|
+
acc[key] = attribute.default;
|
262
|
+
} else if (attribute.type === "component" && attribute.required) {
|
263
|
+
const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
|
264
|
+
if (attribute.repeatable) {
|
265
|
+
acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
|
266
|
+
} else {
|
267
|
+
acc[key] = defaultComponentForm;
|
268
|
+
}
|
269
|
+
} else if (attribute.type === "dynamiczone" && attribute.required) {
|
270
|
+
acc[key] = [];
|
271
|
+
}
|
272
|
+
return acc;
|
273
|
+
}, {});
|
274
|
+
};
|
275
|
+
return traverseSchema(contentType.attributes);
|
259
276
|
};
|
260
|
-
const contentManagerApi =
|
261
|
-
|
262
|
-
baseQuery: axiosBaseQuery(),
|
263
|
-
tagTypes: [
|
277
|
+
const contentManagerApi = adminApi.enhanceEndpoints({
|
278
|
+
addTagTypes: [
|
264
279
|
"ComponentConfiguration",
|
265
280
|
"ContentTypesConfiguration",
|
266
281
|
"ContentTypeSettings",
|
267
282
|
"Document",
|
268
283
|
"InitialData",
|
269
284
|
"HistoryVersion",
|
270
|
-
"Relations"
|
271
|
-
|
272
|
-
|
285
|
+
"Relations",
|
286
|
+
"UidAvailability",
|
287
|
+
"RecentDocumentList"
|
288
|
+
]
|
273
289
|
});
|
274
290
|
const documentApi = contentManagerApi.injectEndpoints({
|
291
|
+
overrideExisting: true,
|
275
292
|
endpoints: (builder) => ({
|
276
293
|
autoCloneDocument: builder.mutation({
|
277
294
|
query: ({ model, sourceId, query }) => ({
|
@@ -281,7 +298,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
281
298
|
params: query
|
282
299
|
}
|
283
300
|
}),
|
284
|
-
invalidatesTags: (_result,
|
301
|
+
invalidatesTags: (_result, error, { model }) => {
|
302
|
+
if (error) {
|
303
|
+
return [];
|
304
|
+
}
|
305
|
+
return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
|
306
|
+
}
|
285
307
|
}),
|
286
308
|
cloneDocument: builder.mutation({
|
287
309
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -292,7 +314,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
292
314
|
params
|
293
315
|
}
|
294
316
|
}),
|
295
|
-
invalidatesTags: (_result, _error, { model }) => [
|
317
|
+
invalidatesTags: (_result, _error, { model }) => [
|
318
|
+
{ type: "Document", id: `${model}_LIST` },
|
319
|
+
{ type: "UidAvailability", id: model },
|
320
|
+
"RecentDocumentList"
|
321
|
+
]
|
296
322
|
}),
|
297
323
|
/**
|
298
324
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -309,8 +335,22 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
309
335
|
}),
|
310
336
|
invalidatesTags: (result, _error, { model }) => [
|
311
337
|
{ type: "Document", id: `${model}_LIST` },
|
312
|
-
"Relations"
|
313
|
-
|
338
|
+
"Relations",
|
339
|
+
{ type: "UidAvailability", id: model },
|
340
|
+
"RecentDocumentList"
|
341
|
+
],
|
342
|
+
transformResponse: (response, meta, arg) => {
|
343
|
+
if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
|
344
|
+
return {
|
345
|
+
data: response,
|
346
|
+
meta: {
|
347
|
+
availableStatus: [],
|
348
|
+
availableLocales: []
|
349
|
+
}
|
350
|
+
};
|
351
|
+
}
|
352
|
+
return response;
|
353
|
+
}
|
314
354
|
}),
|
315
355
|
deleteDocument: builder.mutation({
|
316
356
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -321,16 +361,23 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
321
361
|
}
|
322
362
|
}),
|
323
363
|
invalidatesTags: (_result, _error, { collectionType, model }) => [
|
324
|
-
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
364
|
+
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
|
365
|
+
"RecentDocumentList"
|
325
366
|
]
|
326
367
|
}),
|
327
368
|
deleteManyDocuments: builder.mutation({
|
328
|
-
query: ({ model, ...body }) => ({
|
369
|
+
query: ({ model, params, ...body }) => ({
|
329
370
|
url: `/content-manager/collection-types/${model}/actions/bulkDelete`,
|
330
371
|
method: "POST",
|
331
|
-
data: body
|
372
|
+
data: body,
|
373
|
+
config: {
|
374
|
+
params
|
375
|
+
}
|
332
376
|
}),
|
333
|
-
invalidatesTags: (_res, _error, { model
|
377
|
+
invalidatesTags: (_res, _error, { model }) => [
|
378
|
+
{ type: "Document", id: `${model}_LIST` },
|
379
|
+
"RecentDocumentList"
|
380
|
+
]
|
334
381
|
}),
|
335
382
|
discardDocument: builder.mutation({
|
336
383
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -347,7 +394,9 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
347
394
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
348
395
|
},
|
349
396
|
{ type: "Document", id: `${model}_LIST` },
|
350
|
-
"Relations"
|
397
|
+
"Relations",
|
398
|
+
{ type: "UidAvailability", id: model },
|
399
|
+
"RecentDocumentList"
|
351
400
|
];
|
352
401
|
}
|
353
402
|
}),
|
@@ -360,11 +409,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
360
409
|
url: `/content-manager/collection-types/${model}`,
|
361
410
|
method: "GET",
|
362
411
|
config: {
|
363
|
-
params
|
412
|
+
params: stringify(params, { encode: true })
|
364
413
|
}
|
365
414
|
}),
|
366
415
|
providesTags: (result, _error, arg) => {
|
367
416
|
return [
|
417
|
+
{ type: "Document", id: `ALL_LIST` },
|
368
418
|
{ type: "Document", id: `${arg.model}_LIST` },
|
369
419
|
...result?.results.map(({ documentId }) => ({
|
370
420
|
type: "Document",
|
@@ -403,6 +453,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
403
453
|
{
|
404
454
|
type: "Document",
|
405
455
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
456
|
+
},
|
457
|
+
// Make it easy to invalidate all individual documents queries for a model
|
458
|
+
{
|
459
|
+
type: "Document",
|
460
|
+
id: `${model}_ALL_ITEMS`
|
406
461
|
}
|
407
462
|
];
|
408
463
|
}
|
@@ -436,15 +491,19 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
436
491
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
437
492
|
},
|
438
493
|
{ type: "Document", id: `${model}_LIST` },
|
439
|
-
"Relations"
|
494
|
+
"Relations",
|
495
|
+
"RecentDocumentList"
|
440
496
|
];
|
441
497
|
}
|
442
498
|
}),
|
443
499
|
publishManyDocuments: builder.mutation({
|
444
|
-
query: ({ model, ...body }) => ({
|
500
|
+
query: ({ model, params, ...body }) => ({
|
445
501
|
url: `/content-manager/collection-types/${model}/actions/bulkPublish`,
|
446
502
|
method: "POST",
|
447
|
-
data: body
|
503
|
+
data: body,
|
504
|
+
config: {
|
505
|
+
params
|
506
|
+
}
|
448
507
|
}),
|
449
508
|
invalidatesTags: (_res, _error, { model, documentIds }) => documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` }))
|
450
509
|
}),
|
@@ -463,8 +522,23 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
463
522
|
type: "Document",
|
464
523
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
465
524
|
},
|
466
|
-
"Relations"
|
525
|
+
"Relations",
|
526
|
+
{ type: "UidAvailability", id: model },
|
527
|
+
"RecentDocumentList",
|
528
|
+
"RecentDocumentList"
|
467
529
|
];
|
530
|
+
},
|
531
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
532
|
+
const patchResult = dispatch(
|
533
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
534
|
+
Object.assign(draft.data, data);
|
535
|
+
})
|
536
|
+
);
|
537
|
+
try {
|
538
|
+
await queryFulfilled;
|
539
|
+
} catch {
|
540
|
+
patchResult.undo();
|
541
|
+
}
|
468
542
|
}
|
469
543
|
}),
|
470
544
|
unpublishDocument: builder.mutation({
|
@@ -481,17 +555,24 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
481
555
|
{
|
482
556
|
type: "Document",
|
483
557
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
484
|
-
}
|
558
|
+
},
|
559
|
+
"RecentDocumentList"
|
485
560
|
];
|
486
561
|
}
|
487
562
|
}),
|
488
563
|
unpublishManyDocuments: builder.mutation({
|
489
|
-
query: ({ model, ...body }) => ({
|
564
|
+
query: ({ model, params, ...body }) => ({
|
490
565
|
url: `/content-manager/collection-types/${model}/actions/bulkUnpublish`,
|
491
566
|
method: "POST",
|
492
|
-
data: body
|
567
|
+
data: body,
|
568
|
+
config: {
|
569
|
+
params
|
570
|
+
}
|
493
571
|
}),
|
494
|
-
invalidatesTags: (_res, _error, { model, documentIds }) =>
|
572
|
+
invalidatesTags: (_res, _error, { model, documentIds }) => [
|
573
|
+
...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
|
574
|
+
"RecentDocumentList"
|
575
|
+
]
|
495
576
|
})
|
496
577
|
})
|
497
578
|
});
|
@@ -513,20 +594,53 @@ const {
|
|
513
594
|
useUnpublishDocumentMutation,
|
514
595
|
useUnpublishManyDocumentsMutation
|
515
596
|
} = documentApi;
|
516
|
-
const
|
597
|
+
const buildValidParams = (query) => {
|
598
|
+
if (!query) return query;
|
599
|
+
const { plugins: _, ...validQueryParams } = {
|
600
|
+
...query,
|
601
|
+
...Object.values(query?.plugins ?? {}).reduce(
|
602
|
+
(acc, current) => Object.assign(acc, current),
|
603
|
+
{}
|
604
|
+
)
|
605
|
+
};
|
606
|
+
return validQueryParams;
|
607
|
+
};
|
608
|
+
const isBaseQueryError = (error) => {
|
609
|
+
return error.name !== void 0;
|
610
|
+
};
|
611
|
+
const arrayValidator = (attribute, options) => ({
|
612
|
+
message: translatedErrors.required,
|
613
|
+
test(value) {
|
614
|
+
if (options.status === "draft") {
|
615
|
+
return true;
|
616
|
+
}
|
617
|
+
if (!attribute.required) {
|
618
|
+
return true;
|
619
|
+
}
|
620
|
+
if (!value) {
|
621
|
+
return false;
|
622
|
+
}
|
623
|
+
if (Array.isArray(value) && value.length === 0) {
|
624
|
+
return false;
|
625
|
+
}
|
626
|
+
return true;
|
627
|
+
}
|
628
|
+
});
|
629
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
517
630
|
const createModelSchema = (attributes2) => yup.object().shape(
|
518
631
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
519
632
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
520
633
|
return acc;
|
521
634
|
}
|
522
635
|
const validations = [
|
636
|
+
addNullableValidation,
|
523
637
|
addRequiredValidation,
|
524
638
|
addMinLengthValidation,
|
525
639
|
addMaxLengthValidation,
|
526
640
|
addMinValidation,
|
527
641
|
addMaxValidation,
|
528
642
|
addRegexValidation
|
529
|
-
].map((fn) => fn(attribute));
|
643
|
+
].map((fn) => fn(attribute, options));
|
530
644
|
const transformSchema = pipe(...validations);
|
531
645
|
switch (attribute.type) {
|
532
646
|
case "component": {
|
@@ -536,12 +650,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
536
650
|
...acc,
|
537
651
|
[name]: transformSchema(
|
538
652
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
539
|
-
)
|
653
|
+
).test(arrayValidator(attribute, options))
|
540
654
|
};
|
541
655
|
} else {
|
542
656
|
return {
|
543
657
|
...acc,
|
544
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
658
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
545
659
|
};
|
546
660
|
}
|
547
661
|
}
|
@@ -552,24 +666,42 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
552
666
|
yup.array().of(
|
553
667
|
yup.lazy(
|
554
668
|
(data) => {
|
555
|
-
const
|
556
|
-
|
669
|
+
const attributes3 = components?.[data?.__component]?.attributes;
|
670
|
+
const validation = yup.object().shape({
|
557
671
|
__component: yup.string().required().oneOf(Object.keys(components))
|
558
|
-
}).nullable(false)
|
672
|
+
}).nullable(false);
|
673
|
+
if (!attributes3) {
|
674
|
+
return validation;
|
675
|
+
}
|
676
|
+
return validation.concat(createModelSchema(attributes3));
|
559
677
|
}
|
560
678
|
)
|
561
679
|
)
|
562
|
-
)
|
680
|
+
).test(arrayValidator(attribute, options))
|
563
681
|
};
|
564
682
|
case "relation":
|
565
683
|
return {
|
566
684
|
...acc,
|
567
685
|
[name]: transformSchema(
|
568
|
-
yup.
|
569
|
-
|
570
|
-
|
571
|
-
})
|
572
|
-
|
686
|
+
yup.lazy((value) => {
|
687
|
+
if (!value) {
|
688
|
+
return yup.mixed().nullable(true);
|
689
|
+
} else if (Array.isArray(value)) {
|
690
|
+
return yup.array().of(
|
691
|
+
yup.object().shape({
|
692
|
+
id: yup.number().required()
|
693
|
+
})
|
694
|
+
);
|
695
|
+
} else if (typeof value === "object") {
|
696
|
+
return yup.object();
|
697
|
+
} else {
|
698
|
+
return yup.mixed().test(
|
699
|
+
"type-error",
|
700
|
+
"Relation values must be either null, an array of objects with {id} or an object.",
|
701
|
+
() => false
|
702
|
+
);
|
703
|
+
}
|
704
|
+
})
|
573
705
|
)
|
574
706
|
};
|
575
707
|
default:
|
@@ -609,6 +741,14 @@ const createAttributeSchema = (attribute) => {
|
|
609
741
|
if (!value || typeof value === "string" && value.length === 0) {
|
610
742
|
return true;
|
611
743
|
}
|
744
|
+
if (typeof value === "object") {
|
745
|
+
try {
|
746
|
+
JSON.stringify(value);
|
747
|
+
return true;
|
748
|
+
} catch (err) {
|
749
|
+
return false;
|
750
|
+
}
|
751
|
+
}
|
612
752
|
try {
|
613
753
|
JSON.parse(value);
|
614
754
|
return true;
|
@@ -627,16 +767,30 @@ const createAttributeSchema = (attribute) => {
|
|
627
767
|
return yup.mixed();
|
628
768
|
}
|
629
769
|
};
|
630
|
-
const
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
770
|
+
const nullableSchema = (schema) => {
|
771
|
+
return schema?.nullable ? schema.nullable() : (
|
772
|
+
// In some cases '.nullable' will not be available on the schema.
|
773
|
+
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
774
|
+
// In these cases we should just return the schema as it is.
|
775
|
+
schema
|
776
|
+
);
|
777
|
+
};
|
778
|
+
const addNullableValidation = () => (schema) => {
|
779
|
+
return nullableSchema(schema);
|
780
|
+
};
|
781
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
782
|
+
if (options.status === "draft" || !attribute.required) {
|
783
|
+
return schema;
|
636
784
|
}
|
637
|
-
|
785
|
+
if (attribute.required && "required" in schema) {
|
786
|
+
return schema.required(translatedErrors.required);
|
787
|
+
}
|
788
|
+
return schema;
|
638
789
|
};
|
639
|
-
const addMinLengthValidation = (attribute) => (schema) => {
|
790
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
791
|
+
if (options.status === "draft") {
|
792
|
+
return schema;
|
793
|
+
}
|
640
794
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
641
795
|
return schema.min(attribute.minLength, {
|
642
796
|
...translatedErrors.minLength,
|
@@ -658,10 +812,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
658
812
|
}
|
659
813
|
return schema;
|
660
814
|
};
|
661
|
-
const addMinValidation = (attribute) => (schema) => {
|
662
|
-
if ("
|
815
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
816
|
+
if (options.status === "draft") {
|
817
|
+
return schema;
|
818
|
+
}
|
819
|
+
if ("min" in attribute && "min" in schema) {
|
663
820
|
const min = toInteger(attribute.min);
|
664
|
-
if (
|
821
|
+
if (min) {
|
665
822
|
return schema.min(min, {
|
666
823
|
...translatedErrors.min,
|
667
824
|
values: {
|
@@ -706,24 +863,6 @@ const addRegexValidation = (attribute) => (schema) => {
|
|
706
863
|
}
|
707
864
|
return schema;
|
708
865
|
};
|
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
866
|
const initApi = contentManagerApi.injectEndpoints({
|
728
867
|
endpoints: (builder) => ({
|
729
868
|
getInitialData: builder.query({
|
@@ -737,27 +876,20 @@ const { useGetInitialDataQuery } = initApi;
|
|
737
876
|
const useContentTypeSchema = (model) => {
|
738
877
|
const { toggleNotification } = useNotification();
|
739
878
|
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
|
-
});
|
879
|
+
const { data, error, isLoading, isFetching } = useGetInitialDataQuery(void 0);
|
880
|
+
const { components, contentType, contentTypes } = React.useMemo(() => {
|
881
|
+
const contentType2 = data?.contentTypes.find((ct) => ct.uid === model);
|
882
|
+
const componentsByKey = data?.components.reduce((acc, component) => {
|
883
|
+
acc[component.uid] = component;
|
884
|
+
return acc;
|
885
|
+
}, {});
|
886
|
+
const components2 = extractContentTypeComponents(contentType2?.attributes, componentsByKey);
|
887
|
+
return {
|
888
|
+
components: Object.keys(components2).length === 0 ? void 0 : components2,
|
889
|
+
contentType: contentType2,
|
890
|
+
contentTypes: data?.contentTypes ?? []
|
891
|
+
};
|
892
|
+
}, [model, data]);
|
761
893
|
React.useEffect(() => {
|
762
894
|
if (error) {
|
763
895
|
toggleNotification({
|
@@ -804,61 +936,404 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
804
936
|
}, {});
|
805
937
|
return componentsByKey;
|
806
938
|
};
|
807
|
-
const
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
(document) => {
|
833
|
-
if (!validationSchema) {
|
834
|
-
throw new Error(
|
835
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
836
|
-
);
|
837
|
-
}
|
838
|
-
try {
|
839
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
840
|
-
return null;
|
841
|
-
} catch (error2) {
|
842
|
-
if (error2 instanceof ValidationError) {
|
843
|
-
return getInnerErrors(error2);
|
844
|
-
}
|
845
|
-
throw error2;
|
846
|
-
}
|
847
|
-
},
|
848
|
-
[validationSchema]
|
849
|
-
);
|
850
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
851
|
-
return {
|
852
|
-
components,
|
853
|
-
document: data?.data,
|
854
|
-
meta: data?.meta,
|
855
|
-
isLoading,
|
856
|
-
schema,
|
857
|
-
validate
|
858
|
-
};
|
939
|
+
const HOOKS = {
|
940
|
+
/**
|
941
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
942
|
+
* @constant
|
943
|
+
* @type {string}
|
944
|
+
*/
|
945
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
946
|
+
/**
|
947
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
948
|
+
* @constant
|
949
|
+
* @type {string}
|
950
|
+
*/
|
951
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
952
|
+
/**
|
953
|
+
* Hook that allows to mutate the CM's edit view layout
|
954
|
+
* @constant
|
955
|
+
* @type {string}
|
956
|
+
*/
|
957
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
958
|
+
/**
|
959
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
960
|
+
* @constant
|
961
|
+
* @type {string}
|
962
|
+
*/
|
963
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
859
964
|
};
|
860
|
-
const
|
861
|
-
|
965
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
966
|
+
endpoints: (builder) => ({
|
967
|
+
getContentTypeConfiguration: builder.query({
|
968
|
+
query: (uid) => ({
|
969
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
970
|
+
method: "GET"
|
971
|
+
}),
|
972
|
+
transformResponse: (response) => response.data,
|
973
|
+
providesTags: (_result, _error, uid) => [
|
974
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
975
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
976
|
+
]
|
977
|
+
}),
|
978
|
+
getAllContentTypeSettings: builder.query({
|
979
|
+
query: () => "/content-manager/content-types-settings",
|
980
|
+
transformResponse: (response) => response.data,
|
981
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
982
|
+
}),
|
983
|
+
updateContentTypeConfiguration: builder.mutation({
|
984
|
+
query: ({ uid, ...body }) => ({
|
985
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
986
|
+
method: "PUT",
|
987
|
+
data: body
|
988
|
+
}),
|
989
|
+
transformResponse: (response) => response.data,
|
990
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
991
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
992
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
993
|
+
// Is this necessary?
|
994
|
+
{ type: "InitialData" }
|
995
|
+
]
|
996
|
+
})
|
997
|
+
})
|
998
|
+
});
|
999
|
+
const {
|
1000
|
+
useGetContentTypeConfigurationQuery,
|
1001
|
+
useGetAllContentTypeSettingsQuery,
|
1002
|
+
useUpdateContentTypeConfigurationMutation
|
1003
|
+
} = contentTypesApi;
|
1004
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
1005
|
+
const { type } = attribute;
|
1006
|
+
if (type === "relation") {
|
1007
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
1008
|
+
}
|
1009
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
1010
|
+
};
|
1011
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
1012
|
+
if (!mainFieldName) {
|
1013
|
+
return void 0;
|
1014
|
+
}
|
1015
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
1016
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
1017
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
1018
|
+
);
|
1019
|
+
return {
|
1020
|
+
name: mainFieldName,
|
1021
|
+
type: mainFieldType ?? "string"
|
1022
|
+
};
|
1023
|
+
};
|
1024
|
+
const DEFAULT_SETTINGS = {
|
1025
|
+
bulkable: false,
|
1026
|
+
filterable: false,
|
1027
|
+
searchable: false,
|
1028
|
+
pagination: false,
|
1029
|
+
defaultSortBy: "",
|
1030
|
+
defaultSortOrder: "asc",
|
1031
|
+
mainField: "id",
|
1032
|
+
pageSize: 10
|
1033
|
+
};
|
1034
|
+
const useDocumentLayout = (model) => {
|
1035
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
1036
|
+
const [{ query }] = useQueryParams();
|
1037
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
1038
|
+
const { toggleNotification } = useNotification();
|
1039
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1040
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
1041
|
+
const {
|
1042
|
+
data,
|
1043
|
+
isLoading: isLoadingConfigs,
|
1044
|
+
error,
|
1045
|
+
isFetching: isFetchingConfigs
|
1046
|
+
} = useGetContentTypeConfigurationQuery(model);
|
1047
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
1048
|
+
React.useEffect(() => {
|
1049
|
+
if (error) {
|
1050
|
+
toggleNotification({
|
1051
|
+
type: "danger",
|
1052
|
+
message: formatAPIError(error)
|
1053
|
+
});
|
1054
|
+
}
|
1055
|
+
}, [error, formatAPIError, toggleNotification]);
|
1056
|
+
const editLayout = React.useMemo(
|
1057
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
1058
|
+
layout: [],
|
1059
|
+
components: {},
|
1060
|
+
metadatas: {},
|
1061
|
+
options: {},
|
1062
|
+
settings: DEFAULT_SETTINGS
|
1063
|
+
},
|
1064
|
+
[data, isLoading, schemas, schema, components]
|
1065
|
+
);
|
1066
|
+
const listLayout = React.useMemo(() => {
|
1067
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
1068
|
+
layout: [],
|
1069
|
+
metadatas: {},
|
1070
|
+
options: {},
|
1071
|
+
settings: DEFAULT_SETTINGS
|
1072
|
+
};
|
1073
|
+
}, [data, isLoading, schemas, schema, components]);
|
1074
|
+
const { layout: edit } = React.useMemo(
|
1075
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
1076
|
+
layout: editLayout,
|
1077
|
+
query
|
1078
|
+
}),
|
1079
|
+
[editLayout, query, runHookWaterfall]
|
1080
|
+
);
|
1081
|
+
return {
|
1082
|
+
error,
|
1083
|
+
isLoading,
|
1084
|
+
edit,
|
1085
|
+
list: listLayout
|
1086
|
+
};
|
1087
|
+
};
|
1088
|
+
const useDocLayout = () => {
|
1089
|
+
const { model } = useDoc();
|
1090
|
+
return useDocumentLayout(model);
|
1091
|
+
};
|
1092
|
+
const formatEditLayout = (data, {
|
1093
|
+
schemas,
|
1094
|
+
schema,
|
1095
|
+
components
|
1096
|
+
}) => {
|
1097
|
+
let currentPanelIndex = 0;
|
1098
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
1099
|
+
data.contentType.layouts.edit,
|
1100
|
+
schema?.attributes,
|
1101
|
+
data.contentType.metadatas,
|
1102
|
+
{ configurations: data.components, schemas: components },
|
1103
|
+
schemas
|
1104
|
+
).reduce((panels, row) => {
|
1105
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
1106
|
+
panels.push([row]);
|
1107
|
+
currentPanelIndex += 2;
|
1108
|
+
} else {
|
1109
|
+
if (!panels[currentPanelIndex]) {
|
1110
|
+
panels.push([row]);
|
1111
|
+
} else {
|
1112
|
+
panels[currentPanelIndex].push(row);
|
1113
|
+
}
|
1114
|
+
}
|
1115
|
+
return panels;
|
1116
|
+
}, []);
|
1117
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
1118
|
+
(acc, [uid, configuration]) => {
|
1119
|
+
acc[uid] = {
|
1120
|
+
layout: convertEditLayoutToFieldLayouts(
|
1121
|
+
configuration.layouts.edit,
|
1122
|
+
components[uid].attributes,
|
1123
|
+
configuration.metadatas,
|
1124
|
+
{ configurations: data.components, schemas: components }
|
1125
|
+
),
|
1126
|
+
settings: {
|
1127
|
+
...configuration.settings,
|
1128
|
+
icon: components[uid].info.icon,
|
1129
|
+
displayName: components[uid].info.displayName
|
1130
|
+
}
|
1131
|
+
};
|
1132
|
+
return acc;
|
1133
|
+
},
|
1134
|
+
{}
|
1135
|
+
);
|
1136
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1137
|
+
(acc, [attribute, metadata]) => {
|
1138
|
+
return {
|
1139
|
+
...acc,
|
1140
|
+
[attribute]: metadata.edit
|
1141
|
+
};
|
1142
|
+
},
|
1143
|
+
{}
|
1144
|
+
);
|
1145
|
+
return {
|
1146
|
+
layout: panelledEditAttributes,
|
1147
|
+
components: componentEditAttributes,
|
1148
|
+
metadatas: editMetadatas,
|
1149
|
+
settings: {
|
1150
|
+
...data.contentType.settings,
|
1151
|
+
displayName: schema?.info.displayName
|
1152
|
+
},
|
1153
|
+
options: {
|
1154
|
+
...schema?.options,
|
1155
|
+
...schema?.pluginOptions,
|
1156
|
+
...data.contentType.options
|
1157
|
+
}
|
1158
|
+
};
|
1159
|
+
};
|
1160
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1161
|
+
return rows.map(
|
1162
|
+
(row) => row.map((field) => {
|
1163
|
+
const attribute = attributes[field.name];
|
1164
|
+
if (!attribute) {
|
1165
|
+
return null;
|
1166
|
+
}
|
1167
|
+
const { edit: metadata } = metadatas[field.name];
|
1168
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1169
|
+
return {
|
1170
|
+
attribute,
|
1171
|
+
disabled: !metadata.editable,
|
1172
|
+
hint: metadata.description,
|
1173
|
+
label: metadata.label ?? "",
|
1174
|
+
name: field.name,
|
1175
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1176
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1177
|
+
schemas,
|
1178
|
+
components: components?.schemas ?? {}
|
1179
|
+
}),
|
1180
|
+
placeholder: metadata.placeholder ?? "",
|
1181
|
+
required: attribute.required ?? false,
|
1182
|
+
size: field.size,
|
1183
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1184
|
+
visible: metadata.visible ?? true,
|
1185
|
+
type: attribute.type
|
1186
|
+
};
|
1187
|
+
}).filter((field) => field !== null)
|
1188
|
+
);
|
1189
|
+
};
|
1190
|
+
const formatListLayout = (data, {
|
1191
|
+
schemas,
|
1192
|
+
schema,
|
1193
|
+
components
|
1194
|
+
}) => {
|
1195
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1196
|
+
(acc, [attribute, metadata]) => {
|
1197
|
+
return {
|
1198
|
+
...acc,
|
1199
|
+
[attribute]: metadata.list
|
1200
|
+
};
|
1201
|
+
},
|
1202
|
+
{}
|
1203
|
+
);
|
1204
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1205
|
+
data.contentType.layouts.list,
|
1206
|
+
schema?.attributes,
|
1207
|
+
listMetadatas,
|
1208
|
+
{ configurations: data.components, schemas: components },
|
1209
|
+
schemas
|
1210
|
+
);
|
1211
|
+
return {
|
1212
|
+
layout: listAttributes,
|
1213
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1214
|
+
metadatas: listMetadatas,
|
1215
|
+
options: {
|
1216
|
+
...schema?.options,
|
1217
|
+
...schema?.pluginOptions,
|
1218
|
+
...data.contentType.options
|
1219
|
+
}
|
1220
|
+
};
|
1221
|
+
};
|
1222
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1223
|
+
return columns.map((name) => {
|
1224
|
+
const attribute = attributes[name];
|
1225
|
+
if (!attribute) {
|
1226
|
+
return null;
|
1227
|
+
}
|
1228
|
+
const metadata = metadatas[name];
|
1229
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1230
|
+
return {
|
1231
|
+
attribute,
|
1232
|
+
label: metadata.label ?? "",
|
1233
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1234
|
+
schemas,
|
1235
|
+
components: components?.schemas ?? {}
|
1236
|
+
}),
|
1237
|
+
name,
|
1238
|
+
searchable: metadata.searchable ?? true,
|
1239
|
+
sortable: metadata.sortable ?? true
|
1240
|
+
};
|
1241
|
+
}).filter((field) => field !== null);
|
1242
|
+
};
|
1243
|
+
const useDocument = (args, opts) => {
|
1244
|
+
const { toggleNotification } = useNotification();
|
1245
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1246
|
+
const { formatMessage } = useIntl();
|
1247
|
+
const {
|
1248
|
+
currentData: data,
|
1249
|
+
isLoading: isLoadingDocument,
|
1250
|
+
isFetching: isFetchingDocument,
|
1251
|
+
error
|
1252
|
+
} = useGetDocumentQuery(args, {
|
1253
|
+
...opts,
|
1254
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1255
|
+
});
|
1256
|
+
const document = data?.data;
|
1257
|
+
const meta = data?.meta;
|
1258
|
+
const {
|
1259
|
+
components,
|
1260
|
+
schema,
|
1261
|
+
schemas,
|
1262
|
+
isLoading: isLoadingSchema
|
1263
|
+
} = useContentTypeSchema(args.model);
|
1264
|
+
const isSingleType = schema?.kind === "singleType";
|
1265
|
+
const getTitle = (mainField) => {
|
1266
|
+
if (mainField !== "id" && document?.[mainField]) {
|
1267
|
+
return document[mainField];
|
1268
|
+
}
|
1269
|
+
if (isSingleType && schema?.info.displayName) {
|
1270
|
+
return schema.info.displayName;
|
1271
|
+
}
|
1272
|
+
return formatMessage({
|
1273
|
+
id: "content-manager.containers.untitled",
|
1274
|
+
defaultMessage: "Untitled"
|
1275
|
+
});
|
1276
|
+
};
|
1277
|
+
React.useEffect(() => {
|
1278
|
+
if (error) {
|
1279
|
+
toggleNotification({
|
1280
|
+
type: "danger",
|
1281
|
+
message: formatAPIError(error)
|
1282
|
+
});
|
1283
|
+
}
|
1284
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1285
|
+
const validationSchema = React.useMemo(() => {
|
1286
|
+
if (!schema) {
|
1287
|
+
return null;
|
1288
|
+
}
|
1289
|
+
return createYupSchema(schema.attributes, components);
|
1290
|
+
}, [schema, components]);
|
1291
|
+
const validate = React.useCallback(
|
1292
|
+
(document2) => {
|
1293
|
+
if (!validationSchema) {
|
1294
|
+
throw new Error(
|
1295
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1296
|
+
);
|
1297
|
+
}
|
1298
|
+
try {
|
1299
|
+
validationSchema.validateSync(document2, { abortEarly: false, strict: true });
|
1300
|
+
return null;
|
1301
|
+
} catch (error2) {
|
1302
|
+
if (error2 instanceof ValidationError) {
|
1303
|
+
return getYupValidationErrors(error2);
|
1304
|
+
}
|
1305
|
+
throw error2;
|
1306
|
+
}
|
1307
|
+
},
|
1308
|
+
[validationSchema]
|
1309
|
+
);
|
1310
|
+
const getInitialFormValues = React.useCallback(
|
1311
|
+
(isCreatingDocument = false) => {
|
1312
|
+
if (!document && !isCreatingDocument && !isSingleType || !schema) {
|
1313
|
+
return void 0;
|
1314
|
+
}
|
1315
|
+
const form = document?.id ? document : createDefaultForm(schema, components);
|
1316
|
+
return transformDocument(schema, components)(form);
|
1317
|
+
},
|
1318
|
+
[document, isSingleType, schema, components]
|
1319
|
+
);
|
1320
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1321
|
+
const hasError = !!error;
|
1322
|
+
return {
|
1323
|
+
components,
|
1324
|
+
document,
|
1325
|
+
meta,
|
1326
|
+
isLoading,
|
1327
|
+
hasError,
|
1328
|
+
schema,
|
1329
|
+
schemas,
|
1330
|
+
validate,
|
1331
|
+
getTitle,
|
1332
|
+
getInitialFormValues
|
1333
|
+
};
|
1334
|
+
};
|
1335
|
+
const useDoc = () => {
|
1336
|
+
const { id, slug, collectionType, origin } = useParams();
|
862
1337
|
const [{ query }] = useQueryParams();
|
863
1338
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
864
1339
|
if (!collectionType) {
|
@@ -867,22 +1342,60 @@ const useDoc = () => {
|
|
867
1342
|
if (!slug) {
|
868
1343
|
throw new Error("Could not find model in url params");
|
869
1344
|
}
|
1345
|
+
const document = useDocument(
|
1346
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1347
|
+
{
|
1348
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1349
|
+
}
|
1350
|
+
);
|
1351
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
870
1352
|
return {
|
871
1353
|
collectionType,
|
872
1354
|
model: slug,
|
873
|
-
id:
|
874
|
-
...
|
875
|
-
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
1355
|
+
id: returnId,
|
1356
|
+
...document
|
1357
|
+
};
|
1358
|
+
};
|
1359
|
+
const useContentManagerContext = () => {
|
1360
|
+
const {
|
1361
|
+
collectionType,
|
1362
|
+
model,
|
1363
|
+
id,
|
1364
|
+
components,
|
1365
|
+
isLoading: isLoadingDoc,
|
1366
|
+
schema,
|
1367
|
+
schemas
|
1368
|
+
} = useDoc();
|
1369
|
+
const layout = useDocumentLayout(model);
|
1370
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1371
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1372
|
+
const slug = model;
|
1373
|
+
const isCreatingEntry = id === "create";
|
1374
|
+
useContentTypeSchema();
|
1375
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1376
|
+
const error = layout.error;
|
1377
|
+
return {
|
1378
|
+
error,
|
1379
|
+
isLoading,
|
1380
|
+
// Base metadata
|
1381
|
+
model,
|
1382
|
+
collectionType,
|
1383
|
+
id,
|
1384
|
+
slug,
|
1385
|
+
isCreatingEntry,
|
1386
|
+
isSingleType,
|
1387
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1388
|
+
// All schema infos
|
1389
|
+
components,
|
1390
|
+
contentType: schema,
|
1391
|
+
contentTypes: schemas,
|
1392
|
+
// Form state
|
1393
|
+
form,
|
1394
|
+
// layout infos
|
1395
|
+
layout
|
880
1396
|
};
|
881
1397
|
};
|
882
1398
|
const prefixPluginTranslations = (trad, pluginId) => {
|
883
|
-
if (!pluginId) {
|
884
|
-
throw new TypeError("pluginId can't be empty");
|
885
|
-
}
|
886
1399
|
return Object.keys(trad).reduce((acc, current) => {
|
887
1400
|
acc[`${pluginId}.${current}`] = trad[current];
|
888
1401
|
return acc;
|
@@ -898,6 +1411,8 @@ const useDocumentActions = () => {
|
|
898
1411
|
const { formatMessage } = useIntl();
|
899
1412
|
const { trackUsage } = useTracking();
|
900
1413
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1414
|
+
const navigate = useNavigate();
|
1415
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
901
1416
|
const [deleteDocument] = useDeleteDocumentMutation();
|
902
1417
|
const _delete = React.useCallback(
|
903
1418
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -936,14 +1451,53 @@ const useDocumentActions = () => {
|
|
936
1451
|
},
|
937
1452
|
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
938
1453
|
);
|
1454
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1455
|
+
const deleteMany = React.useCallback(
|
1456
|
+
async ({ model, documentIds, params }) => {
|
1457
|
+
try {
|
1458
|
+
trackUsage("willBulkDeleteEntries");
|
1459
|
+
const res = await deleteManyDocuments({
|
1460
|
+
model,
|
1461
|
+
documentIds,
|
1462
|
+
params
|
1463
|
+
});
|
1464
|
+
if ("error" in res) {
|
1465
|
+
toggleNotification({
|
1466
|
+
type: "danger",
|
1467
|
+
message: formatAPIError(res.error)
|
1468
|
+
});
|
1469
|
+
return { error: res.error };
|
1470
|
+
}
|
1471
|
+
toggleNotification({
|
1472
|
+
type: "success",
|
1473
|
+
title: formatMessage({
|
1474
|
+
id: getTranslation("success.records.delete"),
|
1475
|
+
defaultMessage: "Successfully deleted."
|
1476
|
+
}),
|
1477
|
+
message: ""
|
1478
|
+
});
|
1479
|
+
trackUsage("didBulkDeleteEntries");
|
1480
|
+
return res.data;
|
1481
|
+
} catch (err) {
|
1482
|
+
toggleNotification({
|
1483
|
+
type: "danger",
|
1484
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1485
|
+
});
|
1486
|
+
trackUsage("didNotBulkDeleteEntries");
|
1487
|
+
throw err;
|
1488
|
+
}
|
1489
|
+
},
|
1490
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1491
|
+
);
|
939
1492
|
const [discardDocument] = useDiscardDocumentMutation();
|
940
1493
|
const discard = React.useCallback(
|
941
|
-
async ({ collectionType, model, documentId }) => {
|
1494
|
+
async ({ collectionType, model, documentId, params }) => {
|
942
1495
|
try {
|
943
1496
|
const res = await discardDocument({
|
944
1497
|
collectionType,
|
945
1498
|
model,
|
946
|
-
documentId
|
1499
|
+
documentId,
|
1500
|
+
params
|
947
1501
|
});
|
948
1502
|
if ("error" in res) {
|
949
1503
|
toggleNotification({
|
@@ -1005,6 +1559,43 @@ const useDocumentActions = () => {
|
|
1005
1559
|
},
|
1006
1560
|
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1007
1561
|
);
|
1562
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1563
|
+
const publishMany = React.useCallback(
|
1564
|
+
async ({ model, documentIds, params }) => {
|
1565
|
+
try {
|
1566
|
+
const res = await publishManyDocuments({
|
1567
|
+
model,
|
1568
|
+
documentIds,
|
1569
|
+
params
|
1570
|
+
});
|
1571
|
+
if ("error" in res) {
|
1572
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1573
|
+
return { error: res.error };
|
1574
|
+
}
|
1575
|
+
toggleNotification({
|
1576
|
+
type: "success",
|
1577
|
+
message: formatMessage({
|
1578
|
+
id: getTranslation("success.record.publish"),
|
1579
|
+
defaultMessage: "Published document"
|
1580
|
+
})
|
1581
|
+
});
|
1582
|
+
return res.data;
|
1583
|
+
} catch (err) {
|
1584
|
+
toggleNotification({
|
1585
|
+
type: "danger",
|
1586
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1587
|
+
});
|
1588
|
+
throw err;
|
1589
|
+
}
|
1590
|
+
},
|
1591
|
+
[
|
1592
|
+
// trackUsage,
|
1593
|
+
publishManyDocuments,
|
1594
|
+
toggleNotification,
|
1595
|
+
formatMessage,
|
1596
|
+
formatAPIError
|
1597
|
+
]
|
1598
|
+
);
|
1008
1599
|
const [updateDocument] = useUpdateDocumentMutation();
|
1009
1600
|
const update = React.useCallback(
|
1010
1601
|
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
@@ -1077,7 +1668,42 @@ const useDocumentActions = () => {
|
|
1077
1668
|
throw err;
|
1078
1669
|
}
|
1079
1670
|
},
|
1080
|
-
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1671
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1672
|
+
);
|
1673
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1674
|
+
const unpublishMany = React.useCallback(
|
1675
|
+
async ({ model, documentIds, params }) => {
|
1676
|
+
try {
|
1677
|
+
trackUsage("willBulkUnpublishEntries");
|
1678
|
+
const res = await unpublishManyDocuments({
|
1679
|
+
model,
|
1680
|
+
documentIds,
|
1681
|
+
params
|
1682
|
+
});
|
1683
|
+
if ("error" in res) {
|
1684
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1685
|
+
return { error: res.error };
|
1686
|
+
}
|
1687
|
+
trackUsage("didBulkUnpublishEntries");
|
1688
|
+
toggleNotification({
|
1689
|
+
type: "success",
|
1690
|
+
title: formatMessage({
|
1691
|
+
id: getTranslation("success.records.unpublish"),
|
1692
|
+
defaultMessage: "Successfully unpublished."
|
1693
|
+
}),
|
1694
|
+
message: ""
|
1695
|
+
});
|
1696
|
+
return res.data;
|
1697
|
+
} catch (err) {
|
1698
|
+
toggleNotification({
|
1699
|
+
type: "danger",
|
1700
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1701
|
+
});
|
1702
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1703
|
+
throw err;
|
1704
|
+
}
|
1705
|
+
},
|
1706
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1081
1707
|
);
|
1082
1708
|
const [createDocument] = useCreateDocumentMutation();
|
1083
1709
|
const create = React.useCallback(
|
@@ -1101,6 +1727,7 @@ const useDocumentActions = () => {
|
|
1101
1727
|
defaultMessage: "Saved document"
|
1102
1728
|
})
|
1103
1729
|
});
|
1730
|
+
setCurrentStep("contentManager.success");
|
1104
1731
|
return res.data;
|
1105
1732
|
} catch (err) {
|
1106
1733
|
toggleNotification({
|
@@ -1122,7 +1749,6 @@ const useDocumentActions = () => {
|
|
1122
1749
|
sourceId
|
1123
1750
|
});
|
1124
1751
|
if ("error" in res) {
|
1125
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1126
1752
|
return { error: res.error };
|
1127
1753
|
}
|
1128
1754
|
toggleNotification({
|
@@ -1141,7 +1767,7 @@ const useDocumentActions = () => {
|
|
1141
1767
|
throw err;
|
1142
1768
|
}
|
1143
1769
|
},
|
1144
|
-
[autoCloneDocument,
|
1770
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1145
1771
|
);
|
1146
1772
|
const [cloneDocument] = useCloneDocumentMutation();
|
1147
1773
|
const clone = React.useCallback(
|
@@ -1167,6 +1793,7 @@ const useDocumentActions = () => {
|
|
1167
1793
|
defaultMessage: "Cloned document"
|
1168
1794
|
})
|
1169
1795
|
});
|
1796
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1170
1797
|
return res.data;
|
1171
1798
|
} catch (err) {
|
1172
1799
|
toggleNotification({
|
@@ -1177,7 +1804,7 @@ const useDocumentActions = () => {
|
|
1177
1804
|
throw err;
|
1178
1805
|
}
|
1179
1806
|
},
|
1180
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1807
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1181
1808
|
);
|
1182
1809
|
const [getDoc] = useLazyGetDocumentQuery();
|
1183
1810
|
const getDocument = React.useCallback(
|
@@ -1192,17 +1819,20 @@ const useDocumentActions = () => {
|
|
1192
1819
|
clone,
|
1193
1820
|
create,
|
1194
1821
|
delete: _delete,
|
1822
|
+
deleteMany,
|
1195
1823
|
discard,
|
1196
1824
|
getDocument,
|
1197
1825
|
publish,
|
1826
|
+
publishMany,
|
1198
1827
|
unpublish,
|
1828
|
+
unpublishMany,
|
1199
1829
|
update
|
1200
1830
|
};
|
1201
1831
|
};
|
1202
|
-
const ProtectedHistoryPage = lazy(
|
1203
|
-
() => import("./History-
|
1832
|
+
const ProtectedHistoryPage = React.lazy(
|
1833
|
+
() => import("./History-CzQbTOwa.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1204
1834
|
);
|
1205
|
-
const routes$
|
1835
|
+
const routes$2 = [
|
1206
1836
|
{
|
1207
1837
|
path: ":collectionType/:slug/:id/history",
|
1208
1838
|
Component: ProtectedHistoryPage
|
@@ -1212,32 +1842,45 @@ const routes$1 = [
|
|
1212
1842
|
Component: ProtectedHistoryPage
|
1213
1843
|
}
|
1214
1844
|
];
|
1845
|
+
const ProtectedPreviewPage = React.lazy(
|
1846
|
+
() => import("./Preview-Bieh13Ro.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1847
|
+
);
|
1848
|
+
const routes$1 = [
|
1849
|
+
{
|
1850
|
+
path: ":collectionType/:slug/:id/preview",
|
1851
|
+
Component: ProtectedPreviewPage
|
1852
|
+
},
|
1853
|
+
{
|
1854
|
+
path: ":collectionType/:slug/preview",
|
1855
|
+
Component: ProtectedPreviewPage
|
1856
|
+
}
|
1857
|
+
];
|
1215
1858
|
const ProtectedEditViewPage = lazy(
|
1216
|
-
() => import("./EditViewPage-
|
1859
|
+
() => import("./EditViewPage-DYXZs4_2.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1217
1860
|
);
|
1218
1861
|
const ProtectedListViewPage = lazy(
|
1219
|
-
() => import("./ListViewPage-
|
1862
|
+
() => import("./ListViewPage-DnOP55pM.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1220
1863
|
);
|
1221
1864
|
const ProtectedListConfiguration = lazy(
|
1222
|
-
() => import("./ListConfigurationPage-
|
1865
|
+
() => import("./ListConfigurationPage-Bbw8w5cS.mjs").then((mod) => ({
|
1223
1866
|
default: mod.ProtectedListConfiguration
|
1224
1867
|
}))
|
1225
1868
|
);
|
1226
1869
|
const ProtectedEditConfigurationPage = lazy(
|
1227
|
-
() => import("./EditConfigurationPage-
|
1870
|
+
() => import("./EditConfigurationPage-B0kNlNoj.mjs").then((mod) => ({
|
1228
1871
|
default: mod.ProtectedEditConfigurationPage
|
1229
1872
|
}))
|
1230
1873
|
);
|
1231
1874
|
const ProtectedComponentConfigurationPage = lazy(
|
1232
|
-
() => import("./ComponentConfigurationPage-
|
1875
|
+
() => import("./ComponentConfigurationPage-B_99pmC0.mjs").then((mod) => ({
|
1233
1876
|
default: mod.ProtectedComponentConfigurationPage
|
1234
1877
|
}))
|
1235
1878
|
);
|
1236
1879
|
const NoPermissions = lazy(
|
1237
|
-
() => import("./NoPermissionsPage-
|
1880
|
+
() => import("./NoPermissionsPage-kaj1rPiW.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1238
1881
|
);
|
1239
1882
|
const NoContentType = lazy(
|
1240
|
-
() => import("./NoContentTypePage-
|
1883
|
+
() => import("./NoContentTypePage-CXKXHNMa.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1241
1884
|
);
|
1242
1885
|
const CollectionTypePages = () => {
|
1243
1886
|
const { collectionType } = useParams();
|
@@ -1249,7 +1892,7 @@ const CollectionTypePages = () => {
|
|
1249
1892
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1250
1893
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1251
1894
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1252
|
-
const LIST_PATH = `/content-manager
|
1895
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1253
1896
|
const routes = [
|
1254
1897
|
{
|
1255
1898
|
path: LIST_RELATIVE_PATH,
|
@@ -1283,6 +1926,7 @@ const routes = [
|
|
1283
1926
|
path: "no-content-types",
|
1284
1927
|
Component: NoContentType
|
1285
1928
|
},
|
1929
|
+
...routes$2,
|
1286
1930
|
...routes$1
|
1287
1931
|
];
|
1288
1932
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1351,12 +1995,14 @@ const DocumentActionButton = (action) => {
|
|
1351
1995
|
/* @__PURE__ */ jsx(
|
1352
1996
|
Button,
|
1353
1997
|
{
|
1354
|
-
flex:
|
1998
|
+
flex: "auto",
|
1355
1999
|
startIcon: action.icon,
|
1356
2000
|
disabled: action.disabled,
|
1357
2001
|
onClick: handleClick(action),
|
1358
2002
|
justifyContent: "center",
|
1359
2003
|
variant: action.variant || "default",
|
2004
|
+
paddingTop: "7px",
|
2005
|
+
paddingBottom: "7px",
|
1360
2006
|
children: action.label
|
1361
2007
|
}
|
1362
2008
|
),
|
@@ -1364,7 +2010,7 @@ const DocumentActionButton = (action) => {
|
|
1364
2010
|
DocumentActionConfirmDialog,
|
1365
2011
|
{
|
1366
2012
|
...action.dialog,
|
1367
|
-
variant: action.variant,
|
2013
|
+
variant: action.dialog?.variant ?? action.variant,
|
1368
2014
|
isOpen: dialogId === action.id,
|
1369
2015
|
onClose: handleClose
|
1370
2016
|
}
|
@@ -1379,6 +2025,11 @@ const DocumentActionButton = (action) => {
|
|
1379
2025
|
) : null
|
1380
2026
|
] });
|
1381
2027
|
};
|
2028
|
+
const MenuItem = styled(Menu.Item)`
|
2029
|
+
&:hover {
|
2030
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
2031
|
+
}
|
2032
|
+
`;
|
1382
2033
|
const DocumentActionsMenu = ({
|
1383
2034
|
actions: actions2,
|
1384
2035
|
children,
|
@@ -1421,49 +2072,48 @@ const DocumentActionsMenu = ({
|
|
1421
2072
|
disabled: isDisabled,
|
1422
2073
|
size: "S",
|
1423
2074
|
endIcon: null,
|
1424
|
-
paddingTop: "
|
1425
|
-
paddingLeft: "
|
1426
|
-
paddingRight: "
|
2075
|
+
paddingTop: "4px",
|
2076
|
+
paddingLeft: "7px",
|
2077
|
+
paddingRight: "7px",
|
1427
2078
|
variant,
|
1428
2079
|
children: [
|
1429
2080
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1430
|
-
/* @__PURE__ */ jsx(VisuallyHidden, {
|
2081
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1431
2082
|
id: "content-manager.containers.edit.panels.default.more-actions",
|
1432
2083
|
defaultMessage: "More document actions"
|
1433
2084
|
}) })
|
1434
2085
|
]
|
1435
2086
|
}
|
1436
2087
|
),
|
1437
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
2088
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1438
2089
|
actions2.map((action) => {
|
1439
2090
|
return /* @__PURE__ */ jsx(
|
1440
|
-
|
2091
|
+
MenuItem,
|
1441
2092
|
{
|
1442
2093
|
disabled: action.disabled,
|
1443
2094
|
onSelect: handleClick(action),
|
1444
2095
|
display: "block",
|
1445
|
-
|
1446
|
-
|
1447
|
-
|
1448
|
-
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
|
1458
|
-
|
1459
|
-
|
1460
|
-
|
1461
|
-
|
1462
|
-
|
1463
|
-
|
1464
|
-
|
1465
|
-
|
1466
|
-
] })
|
2096
|
+
isVariantDanger: action.variant === "danger",
|
2097
|
+
isDisabled: action.disabled,
|
2098
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
|
2099
|
+
Flex,
|
2100
|
+
{
|
2101
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
2102
|
+
gap: 2,
|
2103
|
+
tag: "span",
|
2104
|
+
children: [
|
2105
|
+
/* @__PURE__ */ jsx(
|
2106
|
+
Flex,
|
2107
|
+
{
|
2108
|
+
tag: "span",
|
2109
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
2110
|
+
children: action.icon
|
2111
|
+
}
|
2112
|
+
),
|
2113
|
+
action.label
|
2114
|
+
]
|
2115
|
+
}
|
2116
|
+
) })
|
1467
2117
|
},
|
1468
2118
|
action.id
|
1469
2119
|
);
|
@@ -1505,6 +2155,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
|
|
1505
2155
|
return "primary600";
|
1506
2156
|
}
|
1507
2157
|
};
|
2158
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
2159
|
+
switch (variant) {
|
2160
|
+
case "danger":
|
2161
|
+
return "danger600";
|
2162
|
+
case "secondary":
|
2163
|
+
return "neutral500";
|
2164
|
+
case "success":
|
2165
|
+
return "success600";
|
2166
|
+
default:
|
2167
|
+
return "primary600";
|
2168
|
+
}
|
2169
|
+
};
|
1508
2170
|
const DocumentActionConfirmDialog = ({
|
1509
2171
|
onClose,
|
1510
2172
|
onCancel,
|
@@ -1527,61 +2189,54 @@ const DocumentActionConfirmDialog = ({
|
|
1527
2189
|
}
|
1528
2190
|
onClose();
|
1529
2191
|
};
|
1530
|
-
return /* @__PURE__ */
|
1531
|
-
/* @__PURE__ */ jsx(
|
1532
|
-
/* @__PURE__ */ jsx(
|
1533
|
-
|
1534
|
-
{
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
)
|
1545
|
-
] });
|
2192
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2193
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2194
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2195
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2196
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2197
|
+
id: "app.components.Button.cancel",
|
2198
|
+
defaultMessage: "Cancel"
|
2199
|
+
}) }) }),
|
2200
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2201
|
+
id: "app.components.Button.confirm",
|
2202
|
+
defaultMessage: "Confirm"
|
2203
|
+
}) })
|
2204
|
+
] })
|
2205
|
+
] }) });
|
1546
2206
|
};
|
1547
2207
|
const DocumentActionModal = ({
|
1548
2208
|
isOpen,
|
1549
2209
|
title,
|
1550
2210
|
onClose,
|
1551
2211
|
footer: Footer,
|
1552
|
-
content,
|
2212
|
+
content: Content,
|
1553
2213
|
onModalClose
|
1554
2214
|
}) => {
|
1555
|
-
const id = React.useId();
|
1556
|
-
if (!isOpen) {
|
1557
|
-
return null;
|
1558
|
-
}
|
1559
2215
|
const handleClose = () => {
|
1560
2216
|
if (onClose) {
|
1561
2217
|
onClose();
|
1562
2218
|
}
|
1563
2219
|
onModalClose();
|
1564
2220
|
};
|
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
|
-
] });
|
2221
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2222
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2223
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2224
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2225
|
+
] }) });
|
2226
|
+
};
|
2227
|
+
const transformData = (data) => {
|
2228
|
+
if (Array.isArray(data)) {
|
2229
|
+
return data.map(transformData);
|
2230
|
+
}
|
2231
|
+
if (typeof data === "object" && data !== null) {
|
2232
|
+
if ("apiData" in data) {
|
2233
|
+
return data.apiData;
|
2234
|
+
}
|
2235
|
+
return mapValues(transformData)(data);
|
2236
|
+
}
|
2237
|
+
return data;
|
1583
2238
|
};
|
1584
|
-
const PublishAction = ({
|
2239
|
+
const PublishAction$1 = ({
|
1585
2240
|
activeTab,
|
1586
2241
|
documentId,
|
1587
2242
|
model,
|
@@ -1593,13 +2248,18 @@ const PublishAction = ({
|
|
1593
2248
|
const navigate = useNavigate();
|
1594
2249
|
const { toggleNotification } = useNotification();
|
1595
2250
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2251
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1596
2252
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2253
|
+
const { id } = useParams();
|
1597
2254
|
const { formatMessage } = useIntl();
|
1598
|
-
const { canPublish
|
1599
|
-
"PublishAction",
|
1600
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1601
|
-
);
|
2255
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1602
2256
|
const { publish } = useDocumentActions();
|
2257
|
+
const [
|
2258
|
+
countDraftRelations,
|
2259
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2260
|
+
] = useLazyGetDraftRelationCountQuery();
|
2261
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2262
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1603
2263
|
const [{ query, rawQuery }] = useQueryParams();
|
1604
2264
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1605
2265
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1608,10 +2268,107 @@ const PublishAction = ({
|
|
1608
2268
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1609
2269
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1610
2270
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
2271
|
+
React.useEffect(() => {
|
2272
|
+
if (isErrorDraftRelations) {
|
2273
|
+
toggleNotification({
|
2274
|
+
type: "danger",
|
2275
|
+
message: formatMessage({
|
2276
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2277
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2278
|
+
})
|
2279
|
+
});
|
2280
|
+
}
|
2281
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2282
|
+
React.useEffect(() => {
|
2283
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2284
|
+
const extractDraftRelations = (data) => {
|
2285
|
+
const relations = data.connect || [];
|
2286
|
+
relations.forEach((relation) => {
|
2287
|
+
if (relation.status === "draft") {
|
2288
|
+
localDraftRelations.add(relation.id);
|
2289
|
+
}
|
2290
|
+
});
|
2291
|
+
};
|
2292
|
+
const traverseAndExtract = (data) => {
|
2293
|
+
Object.entries(data).forEach(([key, value]) => {
|
2294
|
+
if (key === "connect" && Array.isArray(value)) {
|
2295
|
+
extractDraftRelations({ connect: value });
|
2296
|
+
} else if (typeof value === "object" && value !== null) {
|
2297
|
+
traverseAndExtract(value);
|
2298
|
+
}
|
2299
|
+
});
|
2300
|
+
};
|
2301
|
+
if (!documentId || modified) {
|
2302
|
+
traverseAndExtract(formValues);
|
2303
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2304
|
+
}
|
2305
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2306
|
+
React.useEffect(() => {
|
2307
|
+
if (!document || !document.documentId || isListView) {
|
2308
|
+
return;
|
2309
|
+
}
|
2310
|
+
const fetchDraftRelationsCount = async () => {
|
2311
|
+
const { data, error } = await countDraftRelations({
|
2312
|
+
collectionType,
|
2313
|
+
model,
|
2314
|
+
documentId,
|
2315
|
+
params
|
2316
|
+
});
|
2317
|
+
if (error) {
|
2318
|
+
throw error;
|
2319
|
+
}
|
2320
|
+
if (data) {
|
2321
|
+
setServerCountOfDraftRelations(data.data);
|
2322
|
+
}
|
2323
|
+
};
|
2324
|
+
fetchDraftRelationsCount();
|
2325
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1611
2326
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1612
2327
|
if (!schema?.options?.draftAndPublish) {
|
1613
2328
|
return null;
|
1614
2329
|
}
|
2330
|
+
const performPublish = async () => {
|
2331
|
+
setSubmitting(true);
|
2332
|
+
try {
|
2333
|
+
const { errors } = await validate(true, {
|
2334
|
+
status: "published"
|
2335
|
+
});
|
2336
|
+
if (errors) {
|
2337
|
+
toggleNotification({
|
2338
|
+
type: "danger",
|
2339
|
+
message: formatMessage({
|
2340
|
+
id: "content-manager.validation.error",
|
2341
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2342
|
+
})
|
2343
|
+
});
|
2344
|
+
return;
|
2345
|
+
}
|
2346
|
+
const res = await publish(
|
2347
|
+
{
|
2348
|
+
collectionType,
|
2349
|
+
model,
|
2350
|
+
documentId,
|
2351
|
+
params
|
2352
|
+
},
|
2353
|
+
transformData(formValues)
|
2354
|
+
);
|
2355
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2356
|
+
if (id === "create") {
|
2357
|
+
navigate({
|
2358
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2359
|
+
search: rawQuery
|
2360
|
+
});
|
2361
|
+
}
|
2362
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2363
|
+
setErrors(formatValidationErrors(res.error));
|
2364
|
+
}
|
2365
|
+
} finally {
|
2366
|
+
setSubmitting(false);
|
2367
|
+
}
|
2368
|
+
};
|
2369
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2370
|
+
const enableDraftRelationsCount = false;
|
2371
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1615
2372
|
return {
|
1616
2373
|
/**
|
1617
2374
|
* Disabled when:
|
@@ -1621,52 +2378,40 @@ const PublishAction = ({
|
|
1621
2378
|
* - the document is already published & not modified
|
1622
2379
|
* - the document is being created & not modified
|
1623
2380
|
* - 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
2381
|
*/
|
1627
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2382
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1628
2383
|
label: formatMessage({
|
1629
2384
|
id: "app.utils.publish",
|
1630
2385
|
defaultMessage: "Publish"
|
1631
2386
|
}),
|
1632
2387
|
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));
|
2388
|
+
await performPublish();
|
2389
|
+
},
|
2390
|
+
dialog: hasDraftRelations ? {
|
2391
|
+
type: "dialog",
|
2392
|
+
variant: "danger",
|
2393
|
+
footer: null,
|
2394
|
+
title: formatMessage({
|
2395
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2396
|
+
defaultMessage: "Confirmation"
|
2397
|
+
}),
|
2398
|
+
content: formatMessage(
|
2399
|
+
{
|
2400
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2401
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2402
|
+
},
|
2403
|
+
{
|
2404
|
+
count: totalDraftRelations
|
1662
2405
|
}
|
1663
|
-
|
1664
|
-
|
2406
|
+
),
|
2407
|
+
onConfirm: async () => {
|
2408
|
+
await performPublish();
|
1665
2409
|
}
|
1666
|
-
}
|
2410
|
+
} : void 0
|
1667
2411
|
};
|
1668
2412
|
};
|
1669
|
-
PublishAction.type = "publish";
|
2413
|
+
PublishAction$1.type = "publish";
|
2414
|
+
PublishAction$1.position = "panel";
|
1670
2415
|
const UpdateAction = ({
|
1671
2416
|
activeTab,
|
1672
2417
|
documentId,
|
@@ -1679,10 +2424,6 @@ const UpdateAction = ({
|
|
1679
2424
|
const cloneMatch = useMatch(CLONE_PATH);
|
1680
2425
|
const isCloning = cloneMatch !== null;
|
1681
2426
|
const { formatMessage } = useIntl();
|
1682
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1683
|
-
canCreate: canCreate2,
|
1684
|
-
canUpdate: canUpdate2
|
1685
|
-
}));
|
1686
2427
|
const { create, update, clone } = useDocumentActions();
|
1687
2428
|
const [{ query, rawQuery }] = useQueryParams();
|
1688
2429
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1693,95 +2434,139 @@ const UpdateAction = ({
|
|
1693
2434
|
const validate = useForm("UpdateAction", (state) => state.validate);
|
1694
2435
|
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1695
2436
|
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
}
|
1722
|
-
|
1723
|
-
|
1724
|
-
if (
|
1725
|
-
|
2437
|
+
const handleUpdate = React.useCallback(async () => {
|
2438
|
+
setSubmitting(true);
|
2439
|
+
try {
|
2440
|
+
if (!modified) {
|
2441
|
+
return;
|
2442
|
+
}
|
2443
|
+
const { errors } = await validate(true, {
|
2444
|
+
status: "draft"
|
2445
|
+
});
|
2446
|
+
if (errors) {
|
2447
|
+
toggleNotification({
|
2448
|
+
type: "danger",
|
2449
|
+
message: formatMessage({
|
2450
|
+
id: "content-manager.validation.error",
|
2451
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2452
|
+
})
|
2453
|
+
});
|
2454
|
+
return;
|
2455
|
+
}
|
2456
|
+
if (isCloning) {
|
2457
|
+
const res = await clone(
|
2458
|
+
{
|
2459
|
+
model,
|
2460
|
+
documentId: cloneMatch.params.origin,
|
2461
|
+
params
|
2462
|
+
},
|
2463
|
+
transformData(document)
|
2464
|
+
);
|
2465
|
+
if ("data" in res) {
|
2466
|
+
navigate(
|
1726
2467
|
{
|
1727
|
-
|
1728
|
-
documentId: cloneMatch.params.origin,
|
1729
|
-
params
|
1730
|
-
},
|
1731
|
-
document
|
1732
|
-
);
|
1733
|
-
if ("data" in res) {
|
1734
|
-
navigate({
|
1735
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2468
|
+
pathname: `../${res.data.documentId}`,
|
1736
2469
|
search: rawQuery
|
1737
|
-
});
|
1738
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1739
|
-
setErrors(formatValidationErrors(res.error));
|
1740
|
-
}
|
1741
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1742
|
-
const res = await update(
|
1743
|
-
{
|
1744
|
-
collectionType,
|
1745
|
-
model,
|
1746
|
-
documentId,
|
1747
|
-
params
|
1748
2470
|
},
|
1749
|
-
|
2471
|
+
{ relative: "path" }
|
1750
2472
|
);
|
1751
|
-
|
1752
|
-
|
1753
|
-
|
1754
|
-
|
1755
|
-
|
2473
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2474
|
+
setErrors(formatValidationErrors(res.error));
|
2475
|
+
}
|
2476
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2477
|
+
const res = await update(
|
2478
|
+
{
|
2479
|
+
collectionType,
|
2480
|
+
model,
|
2481
|
+
documentId,
|
2482
|
+
params
|
2483
|
+
},
|
2484
|
+
transformData(document)
|
2485
|
+
);
|
2486
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2487
|
+
setErrors(formatValidationErrors(res.error));
|
1756
2488
|
} else {
|
1757
|
-
|
2489
|
+
resetForm();
|
2490
|
+
}
|
2491
|
+
} else {
|
2492
|
+
const res = await create(
|
2493
|
+
{
|
2494
|
+
model,
|
2495
|
+
params
|
2496
|
+
},
|
2497
|
+
transformData(document)
|
2498
|
+
);
|
2499
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2500
|
+
navigate(
|
1758
2501
|
{
|
1759
|
-
|
1760
|
-
|
2502
|
+
pathname: `../${res.data.documentId}`,
|
2503
|
+
search: rawQuery
|
1761
2504
|
},
|
1762
|
-
|
2505
|
+
{ replace: true, relative: "path" }
|
1763
2506
|
);
|
1764
|
-
|
1765
|
-
|
1766
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1767
|
-
search: rawQuery
|
1768
|
-
});
|
1769
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1770
|
-
setErrors(formatValidationErrors(res.error));
|
1771
|
-
}
|
2507
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2508
|
+
setErrors(formatValidationErrors(res.error));
|
1772
2509
|
}
|
1773
|
-
} finally {
|
1774
|
-
setSubmitting(false);
|
1775
2510
|
}
|
2511
|
+
} finally {
|
2512
|
+
setSubmitting(false);
|
1776
2513
|
}
|
2514
|
+
}, [
|
2515
|
+
clone,
|
2516
|
+
cloneMatch?.params.origin,
|
2517
|
+
collectionType,
|
2518
|
+
create,
|
2519
|
+
document,
|
2520
|
+
documentId,
|
2521
|
+
formatMessage,
|
2522
|
+
formatValidationErrors,
|
2523
|
+
isCloning,
|
2524
|
+
model,
|
2525
|
+
modified,
|
2526
|
+
navigate,
|
2527
|
+
params,
|
2528
|
+
rawQuery,
|
2529
|
+
resetForm,
|
2530
|
+
setErrors,
|
2531
|
+
setSubmitting,
|
2532
|
+
toggleNotification,
|
2533
|
+
update,
|
2534
|
+
validate
|
2535
|
+
]);
|
2536
|
+
React.useEffect(() => {
|
2537
|
+
const handleKeyDown = (e) => {
|
2538
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
2539
|
+
e.preventDefault();
|
2540
|
+
handleUpdate();
|
2541
|
+
}
|
2542
|
+
};
|
2543
|
+
window.addEventListener("keydown", handleKeyDown);
|
2544
|
+
return () => {
|
2545
|
+
window.removeEventListener("keydown", handleKeyDown);
|
2546
|
+
};
|
2547
|
+
}, [handleUpdate]);
|
2548
|
+
return {
|
2549
|
+
/**
|
2550
|
+
* Disabled when:
|
2551
|
+
* - the form is submitting
|
2552
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2553
|
+
* - the active tab is the published tab
|
2554
|
+
*/
|
2555
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2556
|
+
label: formatMessage({
|
2557
|
+
id: "global.save",
|
2558
|
+
defaultMessage: "Save"
|
2559
|
+
}),
|
2560
|
+
onClick: handleUpdate
|
1777
2561
|
};
|
1778
2562
|
};
|
1779
2563
|
UpdateAction.type = "update";
|
2564
|
+
UpdateAction.position = "panel";
|
1780
2565
|
const UNPUBLISH_DRAFT_OPTIONS = {
|
1781
2566
|
KEEP: "keep",
|
1782
2567
|
DISCARD: "discard"
|
1783
2568
|
};
|
1784
|
-
const UnpublishAction = ({
|
2569
|
+
const UnpublishAction$1 = ({
|
1785
2570
|
activeTab,
|
1786
2571
|
documentId,
|
1787
2572
|
model,
|
@@ -1797,10 +2582,8 @@ const UnpublishAction = ({
|
|
1797
2582
|
const { toggleNotification } = useNotification();
|
1798
2583
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1799
2584
|
const isDocumentModified = document?.status === "modified";
|
1800
|
-
const handleChange = (
|
1801
|
-
|
1802
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1803
|
-
}
|
2585
|
+
const handleChange = (value) => {
|
2586
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1804
2587
|
};
|
1805
2588
|
if (!schema?.options?.draftAndPublish) {
|
1806
2589
|
return null;
|
@@ -1811,7 +2594,7 @@ const UnpublishAction = ({
|
|
1811
2594
|
id: "app.utils.unpublish",
|
1812
2595
|
defaultMessage: "Unpublish"
|
1813
2596
|
}),
|
1814
|
-
icon: /* @__PURE__ */ jsx(
|
2597
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1815
2598
|
onClick: async () => {
|
1816
2599
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1817
2600
|
if (!documentId) {
|
@@ -1844,45 +2627,30 @@ const UnpublishAction = ({
|
|
1844
2627
|
content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
1845
2628
|
/* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
|
1846
2629
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
1847
|
-
/* @__PURE__ */ jsx(Typography, {
|
2630
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
1848
2631
|
id: "content-manager.actions.unpublish.dialog.body",
|
1849
2632
|
defaultMessage: "Are you sure?"
|
1850
2633
|
}) })
|
1851
2634
|
] }),
|
1852
2635
|
/* @__PURE__ */ jsxs(
|
1853
|
-
|
2636
|
+
Radio.Group,
|
1854
2637
|
{
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1858
|
-
|
1859
|
-
|
2638
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2639
|
+
name: "discard-options",
|
2640
|
+
"aria-label": formatMessage({
|
2641
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2642
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2643
|
+
}),
|
2644
|
+
onValueChange: handleChange,
|
1860
2645
|
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
|
-
)
|
2646
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2647
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2648
|
+
defaultMessage: "Keep draft"
|
2649
|
+
}) }),
|
2650
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2651
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2652
|
+
defaultMessage: "Replace draft"
|
2653
|
+
}) })
|
1886
2654
|
]
|
1887
2655
|
}
|
1888
2656
|
)
|
@@ -1915,7 +2683,8 @@ const UnpublishAction = ({
|
|
1915
2683
|
position: ["panel", "table-row"]
|
1916
2684
|
};
|
1917
2685
|
};
|
1918
|
-
UnpublishAction.type = "unpublish";
|
2686
|
+
UnpublishAction$1.type = "unpublish";
|
2687
|
+
UnpublishAction$1.position = "panel";
|
1919
2688
|
const DiscardAction = ({
|
1920
2689
|
activeTab,
|
1921
2690
|
documentId,
|
@@ -1938,7 +2707,7 @@ const DiscardAction = ({
|
|
1938
2707
|
id: "content-manager.actions.discard.label",
|
1939
2708
|
defaultMessage: "Discard changes"
|
1940
2709
|
}),
|
1941
|
-
icon: /* @__PURE__ */ jsx(
|
2710
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1942
2711
|
position: ["panel", "table-row"],
|
1943
2712
|
variant: "danger",
|
1944
2713
|
dialog: {
|
@@ -1949,7 +2718,7 @@ const DiscardAction = ({
|
|
1949
2718
|
}),
|
1950
2719
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
1951
2720
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
1952
|
-
/* @__PURE__ */ jsx(Typography, {
|
2721
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
1953
2722
|
id: "content-manager.actions.discard.dialog.body",
|
1954
2723
|
defaultMessage: "Are you sure?"
|
1955
2724
|
}) })
|
@@ -1966,12 +2735,8 @@ const DiscardAction = ({
|
|
1966
2735
|
};
|
1967
2736
|
};
|
1968
2737
|
DiscardAction.type = "discard";
|
1969
|
-
|
1970
|
-
|
1971
|
-
fill: currentColor;
|
1972
|
-
}
|
1973
|
-
`;
|
1974
|
-
const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction, DiscardAction];
|
2738
|
+
DiscardAction.position = "panel";
|
2739
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
1975
2740
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
1976
2741
|
const RelativeTime = React.forwardRef(
|
1977
2742
|
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
@@ -1983,7 +2748,7 @@ const RelativeTime = React.forwardRef(
|
|
1983
2748
|
});
|
1984
2749
|
const unit = intervals.find((intervalUnit) => {
|
1985
2750
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
1986
|
-
});
|
2751
|
+
}) ?? "seconds";
|
1987
2752
|
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
1988
2753
|
const customInterval = customIntervals.find(
|
1989
2754
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2017,34 +2782,34 @@ const getDisplayName = ({
|
|
2017
2782
|
return email ?? "";
|
2018
2783
|
};
|
2019
2784
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2020
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2021
|
-
const statusVariant = status === "draft" ? "
|
2022
|
-
|
2785
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2786
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2787
|
+
const { formatMessage } = useIntl();
|
2788
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2789
|
+
id: `content-manager.containers.List.${status}`,
|
2790
|
+
defaultMessage: capitalise(status)
|
2791
|
+
}) }) });
|
2023
2792
|
};
|
2024
2793
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2025
2794
|
const { formatMessage } = useIntl();
|
2026
2795
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2796
|
+
const params = useParams();
|
2027
2797
|
const title = isCreating ? formatMessage({
|
2028
2798
|
id: "content-manager.containers.edit.title.new",
|
2029
2799
|
defaultMessage: "Create an entry"
|
2030
2800
|
}) : documentTitle;
|
2031
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2032
|
-
/* @__PURE__ */ jsx(
|
2033
|
-
|
2034
|
-
Flex,
|
2801
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2802
|
+
/* @__PURE__ */ jsx(
|
2803
|
+
BackButton,
|
2035
2804
|
{
|
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
|
-
]
|
2805
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2045
2806
|
}
|
2046
2807
|
),
|
2047
|
-
|
2808
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2809
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2810
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2811
|
+
] }),
|
2812
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2048
2813
|
] });
|
2049
2814
|
};
|
2050
2815
|
const HeaderToolbar = () => {
|
@@ -2090,7 +2855,7 @@ const HeaderToolbar = () => {
|
|
2090
2855
|
meta: isCloning ? void 0 : meta,
|
2091
2856
|
collectionType
|
2092
2857
|
},
|
2093
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2858
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
|
2094
2859
|
children: (actions2) => {
|
2095
2860
|
const headerActions = actions2.filter((action) => {
|
2096
2861
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2127,12 +2892,12 @@ const Information = ({ activeTab }) => {
|
|
2127
2892
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2128
2893
|
label: formatMessage({
|
2129
2894
|
id: "content-manager.containers.edit.information.last-published.label",
|
2130
|
-
defaultMessage: "
|
2895
|
+
defaultMessage: "Published"
|
2131
2896
|
}),
|
2132
2897
|
value: formatMessage(
|
2133
2898
|
{
|
2134
2899
|
id: "content-manager.containers.edit.information.last-published.value",
|
2135
|
-
defaultMessage: `
|
2900
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2136
2901
|
},
|
2137
2902
|
{
|
2138
2903
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2145,12 +2910,12 @@ const Information = ({ activeTab }) => {
|
|
2145
2910
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2146
2911
|
label: formatMessage({
|
2147
2912
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2148
|
-
defaultMessage: "
|
2913
|
+
defaultMessage: "Updated"
|
2149
2914
|
}),
|
2150
2915
|
value: formatMessage(
|
2151
2916
|
{
|
2152
2917
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2153
|
-
defaultMessage: `
|
2918
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2154
2919
|
},
|
2155
2920
|
{
|
2156
2921
|
time: /* @__PURE__ */ jsx(
|
@@ -2168,12 +2933,12 @@ const Information = ({ activeTab }) => {
|
|
2168
2933
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2169
2934
|
label: formatMessage({
|
2170
2935
|
id: "content-manager.containers.edit.information.document.label",
|
2171
|
-
defaultMessage: "
|
2936
|
+
defaultMessage: "Created"
|
2172
2937
|
}),
|
2173
2938
|
value: formatMessage(
|
2174
2939
|
{
|
2175
2940
|
id: "content-manager.containers.edit.information.document.value",
|
2176
|
-
defaultMessage: `
|
2941
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2177
2942
|
},
|
2178
2943
|
{
|
2179
2944
|
time: /* @__PURE__ */ jsx(
|
@@ -2196,7 +2961,7 @@ const Information = ({ activeTab }) => {
|
|
2196
2961
|
borderColor: "neutral150",
|
2197
2962
|
direction: "column",
|
2198
2963
|
marginTop: 2,
|
2199
|
-
|
2964
|
+
tag: "dl",
|
2200
2965
|
padding: 5,
|
2201
2966
|
gap: 3,
|
2202
2967
|
alignItems: "flex-start",
|
@@ -2204,31 +2969,83 @@ const Information = ({ activeTab }) => {
|
|
2204
2969
|
marginRight: "-0.4rem",
|
2205
2970
|
width: "calc(100% + 8px)",
|
2206
2971
|
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2207
|
-
/* @__PURE__ */ jsx(Typography, {
|
2208
|
-
/* @__PURE__ */ jsx(Typography, {
|
2972
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2973
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2209
2974
|
] }, info.label))
|
2210
2975
|
}
|
2211
2976
|
);
|
2212
2977
|
};
|
2213
2978
|
const HeaderActions = ({ actions: actions2 }) => {
|
2214
|
-
|
2215
|
-
|
2979
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2980
|
+
const handleClick = (action) => async (e) => {
|
2981
|
+
if (!("options" in action)) {
|
2982
|
+
const { onClick = () => false, dialog, id } = action;
|
2983
|
+
const muteDialog = await onClick(e);
|
2984
|
+
if (dialog && !muteDialog) {
|
2985
|
+
e.preventDefault();
|
2986
|
+
setDialogId(id);
|
2987
|
+
}
|
2988
|
+
}
|
2989
|
+
};
|
2990
|
+
const handleClose = () => {
|
2991
|
+
setDialogId(null);
|
2992
|
+
};
|
2993
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2994
|
+
if (action.options) {
|
2216
2995
|
return /* @__PURE__ */ jsx(
|
2217
2996
|
SingleSelect,
|
2218
2997
|
{
|
2219
2998
|
size: "S",
|
2220
|
-
disabled: action.disabled,
|
2221
|
-
"aria-label": action.label,
|
2222
2999
|
onChange: action.onSelect,
|
2223
|
-
|
3000
|
+
"aria-label": action.label,
|
3001
|
+
...action,
|
2224
3002
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2225
3003
|
},
|
2226
3004
|
action.id
|
2227
3005
|
);
|
2228
3006
|
} else {
|
2229
|
-
|
3007
|
+
if (action.type === "icon") {
|
3008
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
3009
|
+
/* @__PURE__ */ jsx(
|
3010
|
+
IconButton,
|
3011
|
+
{
|
3012
|
+
disabled: action.disabled,
|
3013
|
+
label: action.label,
|
3014
|
+
size: "S",
|
3015
|
+
onClick: handleClick(action),
|
3016
|
+
children: action.icon
|
3017
|
+
}
|
3018
|
+
),
|
3019
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
3020
|
+
HeaderActionDialog,
|
3021
|
+
{
|
3022
|
+
...action.dialog,
|
3023
|
+
isOpen: dialogId === action.id,
|
3024
|
+
onClose: handleClose
|
3025
|
+
}
|
3026
|
+
) : null
|
3027
|
+
] }, action.id);
|
3028
|
+
}
|
3029
|
+
}
|
3030
|
+
}) });
|
3031
|
+
};
|
3032
|
+
const HeaderActionDialog = ({
|
3033
|
+
onClose,
|
3034
|
+
onCancel,
|
3035
|
+
title,
|
3036
|
+
content: Content,
|
3037
|
+
isOpen
|
3038
|
+
}) => {
|
3039
|
+
const handleClose = async () => {
|
3040
|
+
if (onCancel) {
|
3041
|
+
await onCancel();
|
2230
3042
|
}
|
2231
|
-
|
3043
|
+
onClose();
|
3044
|
+
};
|
3045
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3046
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
3047
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
3048
|
+
] }) });
|
2232
3049
|
};
|
2233
3050
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2234
3051
|
const navigate = useNavigate();
|
@@ -2238,7 +3055,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2238
3055
|
id: "app.links.configure-view",
|
2239
3056
|
defaultMessage: "Configure the view"
|
2240
3057
|
}),
|
2241
|
-
icon: /* @__PURE__ */ jsx(
|
3058
|
+
icon: /* @__PURE__ */ jsx(ListPlus, {}),
|
2242
3059
|
onClick: () => {
|
2243
3060
|
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2244
3061
|
},
|
@@ -2246,11 +3063,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2246
3063
|
};
|
2247
3064
|
};
|
2248
3065
|
ConfigureTheViewAction.type = "configure-the-view";
|
2249
|
-
|
2250
|
-
path {
|
2251
|
-
fill: currentColor;
|
2252
|
-
}
|
2253
|
-
`;
|
3066
|
+
ConfigureTheViewAction.position = "header";
|
2254
3067
|
const EditTheModelAction = ({ model }) => {
|
2255
3068
|
const navigate = useNavigate();
|
2256
3069
|
const { formatMessage } = useIntl();
|
@@ -2259,7 +3072,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2259
3072
|
id: "content-manager.link-to-ctb",
|
2260
3073
|
defaultMessage: "Edit the model"
|
2261
3074
|
}),
|
2262
|
-
icon: /* @__PURE__ */ jsx(
|
3075
|
+
icon: /* @__PURE__ */ jsx(Pencil, {}),
|
2263
3076
|
onClick: () => {
|
2264
3077
|
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2265
3078
|
},
|
@@ -2267,12 +3080,8 @@ const EditTheModelAction = ({ model }) => {
|
|
2267
3080
|
};
|
2268
3081
|
};
|
2269
3082
|
EditTheModelAction.type = "edit-the-model";
|
2270
|
-
|
2271
|
-
|
2272
|
-
fill: currentColor;
|
2273
|
-
}
|
2274
|
-
`;
|
2275
|
-
const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
3083
|
+
EditTheModelAction.position = "header";
|
3084
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2276
3085
|
const navigate = useNavigate();
|
2277
3086
|
const { formatMessage } = useIntl();
|
2278
3087
|
const listViewPathMatch = useMatch(LIST_PATH);
|
@@ -2280,13 +3089,17 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2280
3089
|
const { delete: deleteAction } = useDocumentActions();
|
2281
3090
|
const { toggleNotification } = useNotification();
|
2282
3091
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
3092
|
+
const isLocalized = document?.locale != null;
|
2283
3093
|
return {
|
2284
3094
|
disabled: !canDelete || !document,
|
2285
|
-
label: formatMessage(
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
3095
|
+
label: formatMessage(
|
3096
|
+
{
|
3097
|
+
id: "content-manager.actions.delete.label",
|
3098
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
3099
|
+
},
|
3100
|
+
{ isLocalized }
|
3101
|
+
),
|
3102
|
+
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2290
3103
|
dialog: {
|
2291
3104
|
type: "dialog",
|
2292
3105
|
title: formatMessage({
|
@@ -2295,7 +3108,7 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2295
3108
|
}),
|
2296
3109
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2297
3110
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2298
|
-
/* @__PURE__ */ jsx(Typography, {
|
3111
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2299
3112
|
id: "content-manager.actions.delete.dialog.body",
|
2300
3113
|
defaultMessage: "Are you sure?"
|
2301
3114
|
}) })
|
@@ -2335,113 +3148,741 @@ const DeleteAction = ({ documentId, model, collectionType, document }) => {
|
|
2335
3148
|
}
|
2336
3149
|
}
|
2337
3150
|
}
|
2338
|
-
},
|
2339
|
-
variant: "danger",
|
2340
|
-
position: ["header", "table-row"]
|
2341
|
-
};
|
3151
|
+
},
|
3152
|
+
variant: "danger",
|
3153
|
+
position: ["header", "table-row"]
|
3154
|
+
};
|
3155
|
+
};
|
3156
|
+
DeleteAction$1.type = "delete";
|
3157
|
+
DeleteAction$1.position = ["header", "table-row"];
|
3158
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
3159
|
+
const Panels = () => {
|
3160
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
3161
|
+
const [
|
3162
|
+
{
|
3163
|
+
query: { status }
|
3164
|
+
}
|
3165
|
+
] = useQueryParams({
|
3166
|
+
status: "draft"
|
3167
|
+
});
|
3168
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3169
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
3170
|
+
const props = {
|
3171
|
+
activeTab: status,
|
3172
|
+
model,
|
3173
|
+
documentId: id,
|
3174
|
+
document: isCloning ? void 0 : document,
|
3175
|
+
meta: isCloning ? void 0 : meta,
|
3176
|
+
collectionType
|
3177
|
+
};
|
3178
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
3179
|
+
DescriptionComponentRenderer,
|
3180
|
+
{
|
3181
|
+
props,
|
3182
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
3183
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
3184
|
+
}
|
3185
|
+
) });
|
3186
|
+
};
|
3187
|
+
const ActionsPanel = () => {
|
3188
|
+
const { formatMessage } = useIntl();
|
3189
|
+
return {
|
3190
|
+
title: formatMessage({
|
3191
|
+
id: "content-manager.containers.edit.panels.default.title",
|
3192
|
+
defaultMessage: "Entry"
|
3193
|
+
}),
|
3194
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
3195
|
+
};
|
3196
|
+
};
|
3197
|
+
ActionsPanel.type = "actions";
|
3198
|
+
const ActionsPanelContent = () => {
|
3199
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
3200
|
+
const [
|
3201
|
+
{
|
3202
|
+
query: { status = "draft" }
|
3203
|
+
}
|
3204
|
+
] = useQueryParams();
|
3205
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3206
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
3207
|
+
const props = {
|
3208
|
+
activeTab: status,
|
3209
|
+
model,
|
3210
|
+
documentId: id,
|
3211
|
+
document: isCloning ? void 0 : document,
|
3212
|
+
meta: isCloning ? void 0 : meta,
|
3213
|
+
collectionType
|
3214
|
+
};
|
3215
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3216
|
+
/* @__PURE__ */ jsx(
|
3217
|
+
DescriptionComponentRenderer,
|
3218
|
+
{
|
3219
|
+
props,
|
3220
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
|
3221
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
3222
|
+
}
|
3223
|
+
),
|
3224
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3225
|
+
] });
|
3226
|
+
};
|
3227
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
3228
|
+
return /* @__PURE__ */ jsxs(
|
3229
|
+
Flex,
|
3230
|
+
{
|
3231
|
+
ref,
|
3232
|
+
tag: "aside",
|
3233
|
+
"aria-labelledby": "additional-information",
|
3234
|
+
background: "neutral0",
|
3235
|
+
borderColor: "neutral150",
|
3236
|
+
hasRadius: true,
|
3237
|
+
paddingBottom: 4,
|
3238
|
+
paddingLeft: 4,
|
3239
|
+
paddingRight: 4,
|
3240
|
+
paddingTop: 4,
|
3241
|
+
shadow: "tableShadow",
|
3242
|
+
gap: 3,
|
3243
|
+
direction: "column",
|
3244
|
+
justifyContent: "stretch",
|
3245
|
+
alignItems: "flex-start",
|
3246
|
+
children: [
|
3247
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
3248
|
+
children
|
3249
|
+
]
|
3250
|
+
}
|
3251
|
+
);
|
3252
|
+
});
|
3253
|
+
const ConfirmBulkActionDialog = ({
|
3254
|
+
onToggleDialog,
|
3255
|
+
isOpen = false,
|
3256
|
+
dialogBody,
|
3257
|
+
endAction
|
3258
|
+
}) => {
|
3259
|
+
const { formatMessage } = useIntl();
|
3260
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3261
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
3262
|
+
id: "app.components.ConfirmDialog.title",
|
3263
|
+
defaultMessage: "Confirmation"
|
3264
|
+
}) }),
|
3265
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3266
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3267
|
+
dialogBody
|
3268
|
+
] }) }),
|
3269
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
3270
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
3271
|
+
id: "app.components.Button.cancel",
|
3272
|
+
defaultMessage: "Cancel"
|
3273
|
+
}) }) }),
|
3274
|
+
endAction
|
3275
|
+
] })
|
3276
|
+
] }) });
|
3277
|
+
};
|
3278
|
+
const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3279
|
+
const ConfirmDialogPublishAll = ({
|
3280
|
+
isOpen,
|
3281
|
+
onToggleDialog,
|
3282
|
+
isConfirmButtonLoading = false,
|
3283
|
+
onConfirm
|
3284
|
+
}) => {
|
3285
|
+
const { formatMessage } = useIntl();
|
3286
|
+
const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
|
3287
|
+
const { toggleNotification } = useNotification();
|
3288
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
3289
|
+
const { model, schema } = useDoc();
|
3290
|
+
const [{ query }] = useQueryParams();
|
3291
|
+
const enableDraftRelationsCount = false;
|
3292
|
+
const {
|
3293
|
+
data: countDraftRelations = 0,
|
3294
|
+
isLoading,
|
3295
|
+
error
|
3296
|
+
} = useGetManyDraftRelationCountQuery(
|
3297
|
+
{
|
3298
|
+
model,
|
3299
|
+
documentIds: selectedEntries.map((entry) => entry.documentId),
|
3300
|
+
locale: query?.plugins?.i18n?.locale
|
3301
|
+
},
|
3302
|
+
{
|
3303
|
+
skip: !enableDraftRelationsCount
|
3304
|
+
}
|
3305
|
+
);
|
3306
|
+
React.useEffect(() => {
|
3307
|
+
if (error) {
|
3308
|
+
toggleNotification({ type: "danger", message: formatAPIError(error) });
|
3309
|
+
}
|
3310
|
+
}, [error, formatAPIError, toggleNotification]);
|
3311
|
+
if (error) {
|
3312
|
+
return null;
|
3313
|
+
}
|
3314
|
+
return /* @__PURE__ */ jsx(
|
3315
|
+
ConfirmBulkActionDialog,
|
3316
|
+
{
|
3317
|
+
isOpen: isOpen && !isLoading,
|
3318
|
+
onToggleDialog,
|
3319
|
+
dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
|
3320
|
+
/* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
|
3321
|
+
countDraftRelations > 0 && formatMessage(
|
3322
|
+
{
|
3323
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
3324
|
+
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. "
|
3325
|
+
},
|
3326
|
+
{
|
3327
|
+
b: BoldChunk,
|
3328
|
+
count: countDraftRelations,
|
3329
|
+
entities: selectedEntries.length
|
3330
|
+
}
|
3331
|
+
),
|
3332
|
+
formatMessage({
|
3333
|
+
id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
|
3334
|
+
defaultMessage: "Are you sure you want to publish these entries?"
|
3335
|
+
})
|
3336
|
+
] }),
|
3337
|
+
schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
|
3338
|
+
{
|
3339
|
+
id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
|
3340
|
+
defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
|
3341
|
+
},
|
3342
|
+
{
|
3343
|
+
em: Emphasis
|
3344
|
+
}
|
3345
|
+
) })
|
3346
|
+
] }),
|
3347
|
+
endAction: /* @__PURE__ */ jsx(
|
3348
|
+
Button,
|
3349
|
+
{
|
3350
|
+
onClick: onConfirm,
|
3351
|
+
variant: "secondary",
|
3352
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
3353
|
+
loading: isConfirmButtonLoading,
|
3354
|
+
children: formatMessage({
|
3355
|
+
id: "app.utils.publish",
|
3356
|
+
defaultMessage: "Publish"
|
3357
|
+
})
|
3358
|
+
}
|
3359
|
+
)
|
3360
|
+
}
|
3361
|
+
);
|
3362
|
+
};
|
3363
|
+
const TypographyMaxWidth = styled(Typography)`
|
3364
|
+
max-width: 300px;
|
3365
|
+
`;
|
3366
|
+
const TableComponent = styled(RawTable)`
|
3367
|
+
width: 100%;
|
3368
|
+
table-layout: fixed;
|
3369
|
+
td:first-child {
|
3370
|
+
border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
|
3371
|
+
}
|
3372
|
+
td:first-of-type {
|
3373
|
+
padding: ${({ theme }) => theme.spaces[4]};
|
3374
|
+
}
|
3375
|
+
`;
|
3376
|
+
const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
3377
|
+
const messages = [];
|
3378
|
+
Object.entries(errors).forEach(([key, value]) => {
|
3379
|
+
const currentKey = parentKey ? `${parentKey}.${key}` : key;
|
3380
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
3381
|
+
if ("id" in value && "defaultMessage" in value) {
|
3382
|
+
messages.push(
|
3383
|
+
formatMessage(
|
3384
|
+
{
|
3385
|
+
id: `${value.id}.withField`,
|
3386
|
+
defaultMessage: value.defaultMessage
|
3387
|
+
},
|
3388
|
+
{ field: currentKey }
|
3389
|
+
)
|
3390
|
+
);
|
3391
|
+
} else {
|
3392
|
+
messages.push(
|
3393
|
+
...formatErrorMessages(
|
3394
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3395
|
+
value,
|
3396
|
+
currentKey,
|
3397
|
+
formatMessage
|
3398
|
+
)
|
3399
|
+
);
|
3400
|
+
}
|
3401
|
+
} else {
|
3402
|
+
messages.push(
|
3403
|
+
formatMessage(
|
3404
|
+
{
|
3405
|
+
id: `${value}.withField`,
|
3406
|
+
defaultMessage: value
|
3407
|
+
},
|
3408
|
+
{ field: currentKey }
|
3409
|
+
)
|
3410
|
+
);
|
3411
|
+
}
|
3412
|
+
});
|
3413
|
+
return messages;
|
3414
|
+
};
|
3415
|
+
const EntryValidationText = ({ validationErrors, status }) => {
|
3416
|
+
const { formatMessage } = useIntl();
|
3417
|
+
if (validationErrors) {
|
3418
|
+
const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
|
3419
|
+
" "
|
3420
|
+
);
|
3421
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3422
|
+
/* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
|
3423
|
+
/* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
|
3424
|
+
] });
|
3425
|
+
}
|
3426
|
+
if (status === "published") {
|
3427
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3428
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3429
|
+
/* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
|
3430
|
+
id: "content-manager.bulk-publish.already-published",
|
3431
|
+
defaultMessage: "Already Published"
|
3432
|
+
}) })
|
3433
|
+
] });
|
3434
|
+
}
|
3435
|
+
if (status === "modified") {
|
3436
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3437
|
+
/* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3438
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3439
|
+
id: "content-manager.bulk-publish.modified",
|
3440
|
+
defaultMessage: "Ready to publish changes"
|
3441
|
+
}) })
|
3442
|
+
] });
|
3443
|
+
}
|
3444
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3445
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3446
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3447
|
+
id: "app.utils.ready-to-publish",
|
3448
|
+
defaultMessage: "Ready to publish"
|
3449
|
+
}) })
|
3450
|
+
] });
|
3451
|
+
};
|
3452
|
+
const TABLE_HEADERS = [
|
3453
|
+
{ name: "id", label: "id" },
|
3454
|
+
{ name: "name", label: "name" },
|
3455
|
+
{ name: "status", label: "status" },
|
3456
|
+
{ name: "publicationStatus", label: "Publication status" }
|
3457
|
+
];
|
3458
|
+
const SelectedEntriesTableContent = ({
|
3459
|
+
isPublishing,
|
3460
|
+
rowsToDisplay = [],
|
3461
|
+
entriesToPublish = [],
|
3462
|
+
validationErrors = {}
|
3463
|
+
}) => {
|
3464
|
+
const { pathname } = useLocation();
|
3465
|
+
const { formatMessage } = useIntl();
|
3466
|
+
const {
|
3467
|
+
list: {
|
3468
|
+
settings: { mainField }
|
3469
|
+
}
|
3470
|
+
} = useDocLayout();
|
3471
|
+
const shouldDisplayMainField = mainField != null && mainField !== "id";
|
3472
|
+
return /* @__PURE__ */ jsxs(Table.Content, { children: [
|
3473
|
+
/* @__PURE__ */ jsxs(Table.Head, { children: [
|
3474
|
+
/* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
|
3475
|
+
TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
|
3476
|
+
(head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
|
3477
|
+
)
|
3478
|
+
] }),
|
3479
|
+
/* @__PURE__ */ jsx(Table.Loading, {}),
|
3480
|
+
/* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
3481
|
+
/* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
|
3482
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
|
3483
|
+
shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
|
3484
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
|
3485
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3486
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3487
|
+
id: "content-manager.success.record.publishing",
|
3488
|
+
defaultMessage: "Publishing..."
|
3489
|
+
}) }),
|
3490
|
+
/* @__PURE__ */ jsx(Loader, { small: true })
|
3491
|
+
] }) : /* @__PURE__ */ jsx(
|
3492
|
+
EntryValidationText,
|
3493
|
+
{
|
3494
|
+
validationErrors: validationErrors[row.documentId],
|
3495
|
+
status: row.status
|
3496
|
+
}
|
3497
|
+
) }),
|
3498
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3499
|
+
IconButton,
|
3500
|
+
{
|
3501
|
+
tag: Link,
|
3502
|
+
to: {
|
3503
|
+
pathname: `${pathname}/${row.documentId}`,
|
3504
|
+
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3505
|
+
},
|
3506
|
+
state: { from: pathname },
|
3507
|
+
label: formatMessage({
|
3508
|
+
id: "content-manager.bulk-publish.edit",
|
3509
|
+
defaultMessage: "Edit"
|
3510
|
+
}),
|
3511
|
+
target: "_blank",
|
3512
|
+
marginLeft: "auto",
|
3513
|
+
variant: "ghost",
|
3514
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3515
|
+
}
|
3516
|
+
) }) })
|
3517
|
+
] }, row.id)) })
|
3518
|
+
] });
|
3519
|
+
};
|
3520
|
+
const PublicationStatusSummary = ({ count, icon, message }) => {
|
3521
|
+
return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", flex: 1, gap: 3, children: [
|
3522
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3523
|
+
icon,
|
3524
|
+
/* @__PURE__ */ jsx(Typography, { children: message })
|
3525
|
+
] }),
|
3526
|
+
/* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: count })
|
3527
|
+
] });
|
3528
|
+
};
|
3529
|
+
const PublicationStatusGrid = ({
|
3530
|
+
entriesReadyToPublishCount,
|
3531
|
+
entriesPublishedCount,
|
3532
|
+
entriesModifiedCount,
|
3533
|
+
entriesWithErrorsCount
|
3534
|
+
}) => {
|
3535
|
+
const { formatMessage } = useIntl();
|
3536
|
+
return /* @__PURE__ */ jsx(Box, { hasRadius: true, borderColor: "neutral150", children: /* @__PURE__ */ jsx(TableComponent, { colCount: 2, rowCount: 2, children: /* @__PURE__ */ jsxs(Tbody, { children: [
|
3537
|
+
/* @__PURE__ */ jsxs(Tr, { children: [
|
3538
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
3539
|
+
PublicationStatusSummary,
|
3540
|
+
{
|
3541
|
+
count: entriesReadyToPublishCount,
|
3542
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3543
|
+
message: formatMessage({
|
3544
|
+
id: "app.utils.ready-to-publish",
|
3545
|
+
defaultMessage: "Ready to publish"
|
3546
|
+
})
|
3547
|
+
}
|
3548
|
+
) }),
|
3549
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
3550
|
+
PublicationStatusSummary,
|
3551
|
+
{
|
3552
|
+
count: entriesPublishedCount,
|
3553
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3554
|
+
message: formatMessage({
|
3555
|
+
id: "app.utils.already-published",
|
3556
|
+
defaultMessage: "Already published"
|
3557
|
+
})
|
3558
|
+
}
|
3559
|
+
) })
|
3560
|
+
] }),
|
3561
|
+
/* @__PURE__ */ jsxs(Tr, { children: [
|
3562
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
3563
|
+
PublicationStatusSummary,
|
3564
|
+
{
|
3565
|
+
count: entriesModifiedCount,
|
3566
|
+
icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3567
|
+
message: formatMessage({
|
3568
|
+
id: "content-manager.bulk-publish.modified",
|
3569
|
+
defaultMessage: "Ready to publish changes"
|
3570
|
+
})
|
3571
|
+
}
|
3572
|
+
) }),
|
3573
|
+
/* @__PURE__ */ jsx(Td, { children: /* @__PURE__ */ jsx(
|
3574
|
+
PublicationStatusSummary,
|
3575
|
+
{
|
3576
|
+
count: entriesWithErrorsCount,
|
3577
|
+
icon: /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
|
3578
|
+
message: formatMessage({
|
3579
|
+
id: "content-manager.bulk-publish.waiting-for-action",
|
3580
|
+
defaultMessage: "Waiting for action"
|
3581
|
+
})
|
3582
|
+
}
|
3583
|
+
) })
|
3584
|
+
] })
|
3585
|
+
] }) }) });
|
3586
|
+
};
|
3587
|
+
const SelectedEntriesModalContent = ({
|
3588
|
+
listViewSelectedEntries,
|
3589
|
+
toggleModal,
|
3590
|
+
setListViewSelectedDocuments,
|
3591
|
+
model
|
3592
|
+
}) => {
|
3593
|
+
const { formatMessage } = useIntl();
|
3594
|
+
const { schema, components } = useContentTypeSchema(model);
|
3595
|
+
const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
|
3596
|
+
const [{ query }] = useQueryParams();
|
3597
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3598
|
+
const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
|
3599
|
+
{
|
3600
|
+
model,
|
3601
|
+
params: {
|
3602
|
+
page: "1",
|
3603
|
+
pageSize: documentIds.length.toString(),
|
3604
|
+
sort: query.sort,
|
3605
|
+
filters: {
|
3606
|
+
documentId: {
|
3607
|
+
$in: documentIds
|
3608
|
+
}
|
3609
|
+
},
|
3610
|
+
locale: query.plugins?.i18n?.locale
|
3611
|
+
}
|
3612
|
+
},
|
3613
|
+
{
|
3614
|
+
selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
|
3615
|
+
}
|
3616
|
+
);
|
3617
|
+
const { rows, validationErrors } = React.useMemo(() => {
|
3618
|
+
if (data.length > 0 && schema) {
|
3619
|
+
const validate = createYupSchema(
|
3620
|
+
schema.attributes,
|
3621
|
+
components,
|
3622
|
+
// Since this is the "Publish" action, the validation
|
3623
|
+
// schema must enforce the rules for published entities
|
3624
|
+
{ status: "published" }
|
3625
|
+
);
|
3626
|
+
const validationErrors2 = {};
|
3627
|
+
const rows2 = data.map((entry) => {
|
3628
|
+
try {
|
3629
|
+
validate.validateSync(entry, { abortEarly: false });
|
3630
|
+
return entry;
|
3631
|
+
} catch (e) {
|
3632
|
+
if (e instanceof ValidationError) {
|
3633
|
+
validationErrors2[entry.documentId] = getYupValidationErrors(e);
|
3634
|
+
}
|
3635
|
+
return entry;
|
3636
|
+
}
|
3637
|
+
});
|
3638
|
+
return { rows: rows2, validationErrors: validationErrors2 };
|
3639
|
+
}
|
3640
|
+
return {
|
3641
|
+
rows: [],
|
3642
|
+
validationErrors: {}
|
3643
|
+
};
|
3644
|
+
}, [components, data, schema]);
|
3645
|
+
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
3646
|
+
const { publishMany: bulkPublishAction } = useDocumentActions();
|
3647
|
+
const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
|
3648
|
+
const selectedRows = useTable("publishAction", (state) => state.selectedRows);
|
3649
|
+
const selectedEntries = rows.filter(
|
3650
|
+
(entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
|
3651
|
+
);
|
3652
|
+
const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
|
3653
|
+
const selectedEntriesWithErrorsCount = selectedEntries.filter(
|
3654
|
+
({ documentId }) => validationErrors[documentId]
|
3655
|
+
).length;
|
3656
|
+
const selectedEntriesPublishedCount = selectedEntries.filter(
|
3657
|
+
({ status }) => status === "published"
|
3658
|
+
).length;
|
3659
|
+
const selectedEntriesModifiedCount = selectedEntries.filter(
|
3660
|
+
({ status, documentId }) => status === "modified" && !validationErrors[documentId]
|
3661
|
+
).length;
|
3662
|
+
const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublishedCount;
|
3663
|
+
const toggleDialog = () => setIsDialogOpen((prev) => !prev);
|
3664
|
+
const handleConfirmBulkPublish = async () => {
|
3665
|
+
toggleDialog();
|
3666
|
+
const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
|
3667
|
+
if (!("error" in res)) {
|
3668
|
+
const unpublishedEntries = rows.filter((row) => {
|
3669
|
+
return !entriesToPublish.includes(row.documentId);
|
3670
|
+
});
|
3671
|
+
setListViewSelectedDocuments(unpublishedEntries);
|
3672
|
+
}
|
3673
|
+
};
|
3674
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3675
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3676
|
+
/* @__PURE__ */ jsx(
|
3677
|
+
PublicationStatusGrid,
|
3678
|
+
{
|
3679
|
+
entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
|
3680
|
+
entriesPublishedCount: selectedEntriesPublishedCount,
|
3681
|
+
entriesModifiedCount: selectedEntriesModifiedCount,
|
3682
|
+
entriesWithErrorsCount: selectedEntriesWithErrorsCount
|
3683
|
+
}
|
3684
|
+
),
|
3685
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 7, children: /* @__PURE__ */ jsx(
|
3686
|
+
SelectedEntriesTableContent,
|
3687
|
+
{
|
3688
|
+
isPublishing: isSubmittingForm,
|
3689
|
+
rowsToDisplay: rows,
|
3690
|
+
entriesToPublish,
|
3691
|
+
validationErrors
|
3692
|
+
}
|
3693
|
+
) })
|
3694
|
+
] }),
|
3695
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3696
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3697
|
+
id: "app.components.Button.cancel",
|
3698
|
+
defaultMessage: "Cancel"
|
3699
|
+
}) }),
|
3700
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3701
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3702
|
+
/* @__PURE__ */ jsx(
|
3703
|
+
Button,
|
3704
|
+
{
|
3705
|
+
onClick: toggleDialog,
|
3706
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
|
3707
|
+
loading: isSubmittingForm,
|
3708
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3709
|
+
}
|
3710
|
+
)
|
3711
|
+
] })
|
3712
|
+
] }),
|
3713
|
+
/* @__PURE__ */ jsx(
|
3714
|
+
ConfirmDialogPublishAll,
|
3715
|
+
{
|
3716
|
+
isOpen: isDialogOpen,
|
3717
|
+
onToggleDialog: toggleDialog,
|
3718
|
+
isConfirmButtonLoading: isSubmittingForm,
|
3719
|
+
onConfirm: handleConfirmBulkPublish
|
3720
|
+
}
|
3721
|
+
)
|
3722
|
+
] });
|
2342
3723
|
};
|
2343
|
-
|
2344
|
-
const
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
3724
|
+
const PublishAction = ({ documents, model }) => {
|
3725
|
+
const { formatMessage } = useIntl();
|
3726
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3727
|
+
const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
|
3728
|
+
const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
|
3729
|
+
const refetchList = () => {
|
3730
|
+
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3731
|
+
};
|
3732
|
+
if (!showPublishButton) return null;
|
3733
|
+
return {
|
3734
|
+
actionType: "publish",
|
3735
|
+
variant: "tertiary",
|
3736
|
+
label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
|
3737
|
+
dialog: {
|
3738
|
+
type: "modal",
|
3739
|
+
title: formatMessage({
|
3740
|
+
id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
|
3741
|
+
defaultMessage: "Publish entries"
|
3742
|
+
}),
|
3743
|
+
content: ({ onClose }) => {
|
3744
|
+
return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
|
3745
|
+
SelectedEntriesModalContent,
|
3746
|
+
{
|
3747
|
+
listViewSelectedEntries: documents,
|
3748
|
+
toggleModal: () => {
|
3749
|
+
onClose();
|
3750
|
+
refetchList();
|
3751
|
+
},
|
3752
|
+
setListViewSelectedDocuments,
|
3753
|
+
model
|
3754
|
+
}
|
3755
|
+
) });
|
3756
|
+
},
|
3757
|
+
onClose: () => {
|
3758
|
+
refetchList();
|
3759
|
+
}
|
2355
3760
|
}
|
2356
|
-
] = useQueryParams({
|
2357
|
-
status: "draft"
|
2358
|
-
});
|
2359
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2360
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2361
|
-
const props = {
|
2362
|
-
activeTab: status,
|
2363
|
-
model,
|
2364
|
-
documentId: id,
|
2365
|
-
document: isCloning ? void 0 : document,
|
2366
|
-
meta: isCloning ? void 0 : meta,
|
2367
|
-
collectionType
|
2368
3761
|
};
|
2369
|
-
|
3762
|
+
};
|
3763
|
+
const BulkActionsRenderer = () => {
|
3764
|
+
const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
|
3765
|
+
const { model, collectionType } = useDoc();
|
3766
|
+
const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
|
3767
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
|
2370
3768
|
DescriptionComponentRenderer,
|
2371
3769
|
{
|
2372
|
-
props
|
2373
|
-
|
2374
|
-
|
3770
|
+
props: {
|
3771
|
+
model,
|
3772
|
+
collectionType,
|
3773
|
+
documents: selectedRows
|
3774
|
+
},
|
3775
|
+
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3776
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
2375
3777
|
}
|
2376
3778
|
) });
|
2377
3779
|
};
|
2378
|
-
const
|
3780
|
+
const DeleteAction = ({ documents, model }) => {
|
2379
3781
|
const { formatMessage } = useIntl();
|
3782
|
+
const { schema: contentType } = useDoc();
|
3783
|
+
const selectRow = useTable("DeleteAction", (state) => state.selectRow);
|
3784
|
+
const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
|
3785
|
+
const [{ query }] = useQueryParams();
|
3786
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3787
|
+
const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
|
3788
|
+
const { deleteMany: bulkDeleteAction } = useDocumentActions();
|
3789
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3790
|
+
const handleConfirmBulkDelete = async () => {
|
3791
|
+
const res = await bulkDeleteAction({
|
3792
|
+
documentIds,
|
3793
|
+
model,
|
3794
|
+
params
|
3795
|
+
});
|
3796
|
+
if (!("error" in res)) {
|
3797
|
+
selectRow([]);
|
3798
|
+
}
|
3799
|
+
};
|
3800
|
+
if (!hasDeletePermission) return null;
|
2380
3801
|
return {
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
3802
|
+
variant: "danger-light",
|
3803
|
+
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
3804
|
+
dialog: {
|
3805
|
+
type: "dialog",
|
3806
|
+
title: formatMessage({
|
3807
|
+
id: "app.components.ConfirmDialog.title",
|
3808
|
+
defaultMessage: "Confirmation"
|
3809
|
+
}),
|
3810
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3811
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3812
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3813
|
+
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
3814
|
+
defaultMessage: "Are you sure you want to delete these entries?"
|
3815
|
+
}) }),
|
3816
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3817
|
+
{
|
3818
|
+
id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
|
3819
|
+
defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
|
3820
|
+
},
|
3821
|
+
{
|
3822
|
+
em: Emphasis
|
3823
|
+
}
|
3824
|
+
) }) })
|
3825
|
+
] }),
|
3826
|
+
onConfirm: handleConfirmBulkDelete
|
3827
|
+
}
|
2386
3828
|
};
|
2387
3829
|
};
|
2388
|
-
|
2389
|
-
const
|
2390
|
-
const
|
2391
|
-
const
|
2392
|
-
|
2393
|
-
|
3830
|
+
DeleteAction.type = "delete";
|
3831
|
+
const UnpublishAction = ({ documents, model }) => {
|
3832
|
+
const { formatMessage } = useIntl();
|
3833
|
+
const { schema } = useDoc();
|
3834
|
+
const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
|
3835
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3836
|
+
const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
|
3837
|
+
const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
|
3838
|
+
const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
|
3839
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3840
|
+
const [{ query }] = useQueryParams();
|
3841
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3842
|
+
const handleConfirmBulkUnpublish = async () => {
|
3843
|
+
const data = await bulkUnpublishAction({ documentIds, model, params });
|
3844
|
+
if (!("error" in data)) {
|
3845
|
+
selectRow([]);
|
2394
3846
|
}
|
2395
|
-
] = useQueryParams();
|
2396
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2397
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2398
|
-
const props = {
|
2399
|
-
activeTab: status,
|
2400
|
-
model,
|
2401
|
-
documentId: id,
|
2402
|
-
document: isCloning ? void 0 : document,
|
2403
|
-
meta: isCloning ? void 0 : meta,
|
2404
|
-
collectionType
|
2405
3847
|
};
|
2406
|
-
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
/* @__PURE__ */ jsx(Typography, { as: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2439
|
-
children
|
2440
|
-
]
|
3848
|
+
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3849
|
+
if (!showUnpublishButton) return null;
|
3850
|
+
return {
|
3851
|
+
variant: "tertiary",
|
3852
|
+
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
3853
|
+
dialog: {
|
3854
|
+
type: "dialog",
|
3855
|
+
title: formatMessage({
|
3856
|
+
id: "app.components.ConfirmDialog.title",
|
3857
|
+
defaultMessage: "Confirmation"
|
3858
|
+
}),
|
3859
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3860
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3861
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3862
|
+
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
3863
|
+
defaultMessage: "Are you sure you want to unpublish these entries?"
|
3864
|
+
}) }),
|
3865
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3866
|
+
{
|
3867
|
+
id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
|
3868
|
+
defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
|
3869
|
+
},
|
3870
|
+
{
|
3871
|
+
em: Emphasis
|
3872
|
+
}
|
3873
|
+
) }) })
|
3874
|
+
] }),
|
3875
|
+
confirmButton: formatMessage({
|
3876
|
+
id: "app.utils.unpublish",
|
3877
|
+
defaultMessage: "Unpublish"
|
3878
|
+
}),
|
3879
|
+
onConfirm: handleConfirmBulkUnpublish
|
2441
3880
|
}
|
2442
|
-
|
2443
|
-
}
|
2444
|
-
|
3881
|
+
};
|
3882
|
+
};
|
3883
|
+
UnpublishAction.type = "unpublish";
|
3884
|
+
const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
|
3885
|
+
const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
|
2445
3886
|
const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
2446
3887
|
const { formatMessage } = useIntl();
|
2447
3888
|
const getDefaultErrorMessage = (reason) => {
|
@@ -2473,7 +3914,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
|
2473
3914
|
hasRadius: true,
|
2474
3915
|
padding: 6,
|
2475
3916
|
children: [
|
2476
|
-
/* @__PURE__ */ jsx(Flex, { direction: "row",
|
3917
|
+
/* @__PURE__ */ jsx(Flex, { direction: "row", tag: "ol", children: fieldPath.map((pathSegment, index2) => /* @__PURE__ */ jsxs(Typography, { fontWeight: "semiBold", tag: "li", children: [
|
2477
3918
|
pathSegment,
|
2478
3919
|
index2 !== fieldPath.length - 1 && /* @__PURE__ */ jsx(
|
2479
3920
|
ChevronRight,
|
@@ -2485,7 +3926,7 @@ const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
|
2485
3926
|
}
|
2486
3927
|
)
|
2487
3928
|
] }, index2)) }),
|
2488
|
-
/* @__PURE__ */ jsx(Typography, {
|
3929
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", textColor: "neutral600", children: formatMessage({
|
2489
3930
|
id: getTranslation(`containers.list.autoCloneModal.error.${reason}`),
|
2490
3931
|
defaultMessage: getDefaultErrorMessage(reason)
|
2491
3932
|
}) })
|
@@ -2510,7 +3951,7 @@ const TableActions = ({ document }) => {
|
|
2510
3951
|
DescriptionComponentRenderer,
|
2511
3952
|
{
|
2512
3953
|
props,
|
2513
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3954
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
|
2514
3955
|
children: (actions2) => {
|
2515
3956
|
const tableRowActions = actions2.filter((action) => {
|
2516
3957
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2569,6 +4010,7 @@ const EditAction = ({ documentId }) => {
|
|
2569
4010
|
};
|
2570
4011
|
};
|
2571
4012
|
EditAction.type = "edit";
|
4013
|
+
EditAction.position = "table-row";
|
2572
4014
|
const StyledPencil = styled(Pencil)`
|
2573
4015
|
path {
|
2574
4016
|
fill: currentColor;
|
@@ -2621,7 +4063,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2621
4063
|
}),
|
2622
4064
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
2623
4065
|
footer: ({ onClose }) => {
|
2624
|
-
return /* @__PURE__ */ jsxs(
|
4066
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
2625
4067
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
2626
4068
|
id: "cancel",
|
2627
4069
|
defaultMessage: "Cancel"
|
@@ -2629,7 +4071,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2629
4071
|
/* @__PURE__ */ jsx(
|
2630
4072
|
LinkButton,
|
2631
4073
|
{
|
2632
|
-
|
4074
|
+
tag: NavLink,
|
2633
4075
|
to: {
|
2634
4076
|
pathname: `clone/${documentId}`
|
2635
4077
|
},
|
@@ -2645,6 +4087,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2645
4087
|
};
|
2646
4088
|
};
|
2647
4089
|
CloneAction.type = "clone";
|
4090
|
+
CloneAction.position = "table-row";
|
2648
4091
|
const StyledDuplicate = styled(Duplicate)`
|
2649
4092
|
path {
|
2650
4093
|
fill: currentColor;
|
@@ -2662,8 +4105,7 @@ class ContentManagerPlugin {
|
|
2662
4105
|
documentActions = [
|
2663
4106
|
...DEFAULT_ACTIONS,
|
2664
4107
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
2665
|
-
...DEFAULT_HEADER_ACTIONS
|
2666
|
-
HistoryAction
|
4108
|
+
...DEFAULT_HEADER_ACTIONS
|
2667
4109
|
];
|
2668
4110
|
editViewSidePanels = [ActionsPanel];
|
2669
4111
|
headerActions = [];
|
@@ -2726,13 +4168,21 @@ class ContentManagerPlugin {
|
|
2726
4168
|
id: PLUGIN_ID,
|
2727
4169
|
name: "Content Manager",
|
2728
4170
|
injectionZones: INJECTION_ZONES,
|
4171
|
+
isReady: false,
|
2729
4172
|
apis: {
|
2730
4173
|
addBulkAction: this.addBulkAction.bind(this),
|
2731
4174
|
addDocumentAction: this.addDocumentAction.bind(this),
|
2732
4175
|
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
2733
4176
|
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
2734
4177
|
getBulkActions: () => this.bulkActions,
|
2735
|
-
getDocumentActions: () =>
|
4178
|
+
getDocumentActions: (position) => {
|
4179
|
+
if (position) {
|
4180
|
+
return this.documentActions.filter(
|
4181
|
+
(action) => action.position == void 0 || [action.position].flat().includes(position)
|
4182
|
+
);
|
4183
|
+
}
|
4184
|
+
return this.documentActions;
|
4185
|
+
},
|
2736
4186
|
getEditViewSidePanels: () => this.editViewSidePanels,
|
2737
4187
|
getHeaderActions: () => this.headerActions
|
2738
4188
|
}
|
@@ -2742,16 +4192,71 @@ class ContentManagerPlugin {
|
|
2742
4192
|
const getPrintableType = (value) => {
|
2743
4193
|
const nativeType = typeof value;
|
2744
4194
|
if (nativeType === "object") {
|
2745
|
-
if (value === null)
|
2746
|
-
|
2747
|
-
if (Array.isArray(value))
|
2748
|
-
return "array";
|
4195
|
+
if (value === null) return "null";
|
4196
|
+
if (Array.isArray(value)) return "array";
|
2749
4197
|
if (value instanceof Object && value.constructor.name !== "Object") {
|
2750
4198
|
return value.constructor.name;
|
2751
4199
|
}
|
2752
4200
|
}
|
2753
4201
|
return nativeType;
|
2754
4202
|
};
|
4203
|
+
const HistoryAction = ({ model, document }) => {
|
4204
|
+
const { formatMessage } = useIntl();
|
4205
|
+
const [{ query }] = useQueryParams();
|
4206
|
+
const navigate = useNavigate();
|
4207
|
+
const { trackUsage } = useTracking();
|
4208
|
+
const { pathname } = useLocation();
|
4209
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
4210
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
4211
|
+
return null;
|
4212
|
+
}
|
4213
|
+
const handleOnClick = () => {
|
4214
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
4215
|
+
trackUsage("willNavigate", {
|
4216
|
+
from: pathname,
|
4217
|
+
to: `${pathname}/${destination.pathname}`
|
4218
|
+
});
|
4219
|
+
navigate(destination);
|
4220
|
+
};
|
4221
|
+
return {
|
4222
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
4223
|
+
label: formatMessage({
|
4224
|
+
id: "content-manager.history.document-action",
|
4225
|
+
defaultMessage: "Content History"
|
4226
|
+
}),
|
4227
|
+
onClick: handleOnClick,
|
4228
|
+
disabled: (
|
4229
|
+
/**
|
4230
|
+
* The user is creating a new document.
|
4231
|
+
* It hasn't been saved yet, so there's no history to go to
|
4232
|
+
*/
|
4233
|
+
!document || /**
|
4234
|
+
* The document has been created but the current dimension has never been saved.
|
4235
|
+
* For example, the user is creating a new locale in an existing document,
|
4236
|
+
* so there's no history for the document in that locale
|
4237
|
+
*/
|
4238
|
+
!document.id || /**
|
4239
|
+
* History is only available for content types created by the user.
|
4240
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
4241
|
+
* which start with `admin::` or `plugin::`
|
4242
|
+
*/
|
4243
|
+
!model.startsWith("api::")
|
4244
|
+
),
|
4245
|
+
position: "header"
|
4246
|
+
};
|
4247
|
+
};
|
4248
|
+
HistoryAction.type = "history";
|
4249
|
+
HistoryAction.position = "header";
|
4250
|
+
const historyAdmin = {
|
4251
|
+
bootstrap(app) {
|
4252
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
4253
|
+
addDocumentAction((actions2) => {
|
4254
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
4255
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
4256
|
+
return actions2;
|
4257
|
+
});
|
4258
|
+
}
|
4259
|
+
};
|
2755
4260
|
const initialState = {
|
2756
4261
|
collectionTypeLinks: [],
|
2757
4262
|
components: [],
|
@@ -2788,316 +4293,94 @@ const { setInitialData } = actions;
|
|
2788
4293
|
const reducer = combineReducers({
|
2789
4294
|
app: reducer$1
|
2790
4295
|
});
|
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({
|
4296
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
2818
4297
|
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
|
-
]
|
4298
|
+
getPreviewUrl: builder.query({
|
4299
|
+
query({ query, params }) {
|
4300
|
+
return {
|
4301
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4302
|
+
method: "GET",
|
4303
|
+
config: {
|
4304
|
+
params: query
|
4305
|
+
}
|
4306
|
+
};
|
4307
|
+
}
|
2848
4308
|
})
|
2849
4309
|
})
|
2850
4310
|
});
|
2851
|
-
const {
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
} = contentTypesApi;
|
2856
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2857
|
-
const { type } = attribute;
|
2858
|
-
if (type === "relation") {
|
2859
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2860
|
-
}
|
2861
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2862
|
-
};
|
2863
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2864
|
-
if (!mainFieldName) {
|
2865
|
-
return void 0;
|
4311
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4312
|
+
const ConditionalTooltip = ({ isShown, label, children }) => {
|
4313
|
+
if (isShown) {
|
4314
|
+
return /* @__PURE__ */ jsx(Tooltip, { label, children });
|
2866
4315
|
}
|
2867
|
-
|
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
|
4316
|
+
return children;
|
2885
4317
|
};
|
2886
|
-
const
|
2887
|
-
const {
|
4318
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4319
|
+
const { formatMessage } = useIntl();
|
4320
|
+
const { trackUsage } = useTracking();
|
4321
|
+
const { pathname } = useLocation();
|
2888
4322
|
const [{ query }] = useQueryParams();
|
2889
|
-
const
|
2890
|
-
const {
|
2891
|
-
|
2892
|
-
|
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;
|
2983
|
-
},
|
2984
|
-
{}
|
2985
|
-
);
|
2986
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2987
|
-
(acc, [attribute, metadata]) => {
|
2988
|
-
return {
|
2989
|
-
...acc,
|
2990
|
-
[attribute]: metadata.edit
|
2991
|
-
};
|
2992
|
-
},
|
2993
|
-
{}
|
2994
|
-
);
|
2995
|
-
return {
|
2996
|
-
layout: panelledEditAttributes,
|
2997
|
-
components: componentEditAttributes,
|
2998
|
-
metadatas: editMetadatas,
|
2999
|
-
settings: {
|
3000
|
-
...data.contentType.settings,
|
3001
|
-
displayName: schema?.info.displayName
|
4323
|
+
const isModified = useForm("PreviewSidePanel", (state) => state.modified);
|
4324
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4325
|
+
params: {
|
4326
|
+
contentType: model
|
3002
4327
|
},
|
3003
|
-
|
3004
|
-
|
3005
|
-
|
3006
|
-
|
4328
|
+
query: {
|
4329
|
+
documentId,
|
4330
|
+
locale: document?.locale,
|
4331
|
+
status: document?.status
|
3007
4332
|
}
|
4333
|
+
});
|
4334
|
+
if (!data?.data?.url || error) {
|
4335
|
+
return null;
|
4336
|
+
}
|
4337
|
+
const trackNavigation = () => {
|
4338
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4339
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
3008
4340
|
};
|
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
4341
|
return {
|
3062
|
-
|
3063
|
-
|
3064
|
-
|
3065
|
-
|
3066
|
-
|
3067
|
-
|
3068
|
-
|
3069
|
-
|
4342
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4343
|
+
content: /* @__PURE__ */ jsx(
|
4344
|
+
ConditionalTooltip,
|
4345
|
+
{
|
4346
|
+
label: formatMessage({
|
4347
|
+
id: "content-manager.preview.panel.button-disabled-tooltip",
|
4348
|
+
defaultMessage: "Please save to open the preview"
|
4349
|
+
}),
|
4350
|
+
isShown: isModified,
|
4351
|
+
children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
|
4352
|
+
Button,
|
4353
|
+
{
|
4354
|
+
variant: "tertiary",
|
4355
|
+
tag: Link,
|
4356
|
+
to: { pathname: "preview", search: stringify(query, { encode: false }) },
|
4357
|
+
onClick: trackNavigation,
|
4358
|
+
width: "100%",
|
4359
|
+
disabled: isModified,
|
4360
|
+
pointerEvents: isModified ? "none" : void 0,
|
4361
|
+
tabIndex: isModified ? -1 : void 0,
|
4362
|
+
children: formatMessage({
|
4363
|
+
id: "content-manager.preview.panel.button",
|
4364
|
+
defaultMessage: "Open preview"
|
4365
|
+
})
|
4366
|
+
}
|
4367
|
+
) })
|
4368
|
+
}
|
4369
|
+
)
|
3070
4370
|
};
|
3071
4371
|
};
|
3072
|
-
const
|
3073
|
-
|
3074
|
-
const
|
3075
|
-
|
3076
|
-
|
3077
|
-
}
|
3078
|
-
const metadata = metadatas[name];
|
3079
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
3080
|
-
return {
|
3081
|
-
attribute,
|
3082
|
-
label: metadata.label ?? "",
|
3083
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
3084
|
-
schemas,
|
3085
|
-
components: components?.schemas ?? {}
|
3086
|
-
}),
|
3087
|
-
name,
|
3088
|
-
searchable: metadata.searchable ?? true,
|
3089
|
-
sortable: metadata.sortable ?? true
|
3090
|
-
};
|
3091
|
-
}).filter((field) => field !== null);
|
4372
|
+
const previewAdmin = {
|
4373
|
+
bootstrap(app) {
|
4374
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4375
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4376
|
+
}
|
3092
4377
|
};
|
3093
4378
|
const index = {
|
3094
4379
|
register(app) {
|
3095
4380
|
const cm = new ContentManagerPlugin();
|
3096
4381
|
app.addReducers({
|
3097
|
-
[contentManagerApi.reducerPath]: contentManagerApi.reducer,
|
3098
4382
|
[PLUGIN_ID]: reducer
|
3099
4383
|
});
|
3100
|
-
app.addMiddlewares([() => contentManagerApi.middleware]);
|
3101
4384
|
app.addMenuLink({
|
3102
4385
|
to: PLUGIN_ID,
|
3103
4386
|
icon: Feather,
|
@@ -3106,14 +4389,32 @@ const index = {
|
|
3106
4389
|
defaultMessage: "Content Manager"
|
3107
4390
|
},
|
3108
4391
|
permissions: [],
|
3109
|
-
|
4392
|
+
position: 1
|
4393
|
+
});
|
4394
|
+
app.router.addRoute({
|
4395
|
+
path: "content-manager/*",
|
4396
|
+
lazy: async () => {
|
4397
|
+
const { Layout } = await import("./layout-bbOlPwLA.mjs");
|
4398
|
+
return {
|
4399
|
+
Component: Layout
|
4400
|
+
};
|
4401
|
+
},
|
4402
|
+
children: routes
|
3110
4403
|
});
|
3111
4404
|
app.registerPlugin(cm.config);
|
3112
4405
|
},
|
4406
|
+
bootstrap(app) {
|
4407
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4408
|
+
historyAdmin.bootstrap(app);
|
4409
|
+
}
|
4410
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4411
|
+
previewAdmin.bootstrap(app);
|
4412
|
+
}
|
4413
|
+
},
|
3113
4414
|
async registerTrads({ locales }) {
|
3114
4415
|
const importedTrads = await Promise.all(
|
3115
4416
|
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-
|
4417
|
+
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-D65uIF6Y.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-DBseuRuB.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`, 3).then(({ default: data }) => {
|
3117
4418
|
return {
|
3118
4419
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3119
4420
|
locale
|
@@ -3130,46 +4431,52 @@ const index = {
|
|
3130
4431
|
}
|
3131
4432
|
};
|
3132
4433
|
export {
|
3133
|
-
|
3134
|
-
|
4434
|
+
useUpdateContentTypeConfigurationMutation as A,
|
4435
|
+
BulkActionsRenderer as B,
|
3135
4436
|
COLLECTION_TYPES as C,
|
3136
4437
|
DocumentStatus as D,
|
3137
|
-
|
3138
|
-
|
3139
|
-
|
4438
|
+
ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD as E,
|
4439
|
+
extractContentTypeComponents as F,
|
4440
|
+
DEFAULT_SETTINGS as G,
|
3140
4441
|
HOOKS as H,
|
3141
4442
|
InjectionZone as I,
|
3142
|
-
|
3143
|
-
|
4443
|
+
convertEditLayoutToFieldLayouts as J,
|
4444
|
+
removeFieldsThatDontExistOnSchema as K,
|
4445
|
+
prepareTempKeys as L,
|
4446
|
+
useDocument as M,
|
4447
|
+
useGetPreviewUrlQuery as N,
|
4448
|
+
index as O,
|
3144
4449
|
Panels as P,
|
4450
|
+
useContentManagerContext as Q,
|
3145
4451
|
RelativeTime as R,
|
3146
4452
|
SINGLE_TYPES as S,
|
3147
4453
|
TableActions as T,
|
3148
|
-
|
3149
|
-
|
3150
|
-
|
3151
|
-
|
3152
|
-
|
3153
|
-
|
4454
|
+
useDocumentActions as U,
|
4455
|
+
useGetInitialDataQuery as a,
|
4456
|
+
useGetAllContentTypeSettingsQuery as b,
|
4457
|
+
useDoc as c,
|
4458
|
+
buildValidParams as d,
|
4459
|
+
contentManagerApi as e,
|
4460
|
+
useDocumentRBAC as f,
|
3154
4461
|
getTranslation as g,
|
3155
|
-
|
3156
|
-
|
3157
|
-
|
3158
|
-
|
3159
|
-
|
4462
|
+
useDocumentLayout as h,
|
4463
|
+
createYupSchema as i,
|
4464
|
+
Header as j,
|
4465
|
+
PERMISSIONS as k,
|
4466
|
+
DocumentRBAC as l,
|
3160
4467
|
useDocLayout as m,
|
3161
|
-
|
3162
|
-
|
3163
|
-
|
3164
|
-
|
3165
|
-
|
4468
|
+
createDefaultForm as n,
|
4469
|
+
CLONE_PATH as o,
|
4470
|
+
useGetContentTypeConfigurationQuery as p,
|
4471
|
+
CREATOR_FIELDS as q,
|
4472
|
+
getMainField as r,
|
3166
4473
|
setInitialData as s,
|
3167
|
-
|
3168
|
-
|
3169
|
-
|
3170
|
-
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
3174
|
-
};
|
3175
|
-
//# sourceMappingURL=index-
|
4474
|
+
transformDocument as t,
|
4475
|
+
useContentTypeSchema as u,
|
4476
|
+
getDisplayName as v,
|
4477
|
+
checkIfAttributeIsDisplayable as w,
|
4478
|
+
useGetAllDocumentsQuery as x,
|
4479
|
+
convertListLayoutToFieldLayouts as y,
|
4480
|
+
capitalise as z
|
4481
|
+
};
|
4482
|
+
//# sourceMappingURL=index-BH2JnYpF.mjs.map
|