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