@strapi/content-manager 0.0.0-experimental.745741d19e90275ca6f7c928ca19f9bb0fd9d933 → 0.0.0-experimental.76d3543c13df7ef0095963ae2c20b792f179eef0
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/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js → ComponentConfigurationPage-CJPoOvy3.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-BvHtG7uH.js.map → ComponentConfigurationPage-CJPoOvy3.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs → ComponentConfigurationPage-CcRDqD0e.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DHNM3YBz.mjs.map → ComponentConfigurationPage-CcRDqD0e.mjs.map} +1 -1
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js → ComponentIcon-CRbtQEUV.js} +2 -3
- package/dist/_chunks/{ComponentIcon-BXdiCGQp.js.map → ComponentIcon-CRbtQEUV.js.map} +1 -1
- package/dist/_chunks/ComponentIcon-u4bIXTFY.mjs.map +1 -1
- package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs → EditConfigurationPage-C1ddZ_zf.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-Cp6HAEzN.mjs.map → EditConfigurationPage-C1ddZ_zf.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js → EditConfigurationPage-CF3lxOy2.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-DOmfCEMo.js.map → EditConfigurationPage-CF3lxOy2.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-BtkEx339.mjs → EditViewPage-BPFcUbqi.mjs} +63 -12
- package/dist/_chunks/EditViewPage-BPFcUbqi.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-BqNpC6hO.js → EditViewPage-CDyTC6aU.js} +63 -13
- package/dist/_chunks/EditViewPage-CDyTC6aU.js.map +1 -0
- package/dist/_chunks/{Field-lsPFnAmH.js → Field-DuxAW9q2.js} +409 -260
- package/dist/_chunks/Field-DuxAW9q2.js.map +1 -0
- package/dist/_chunks/{Field-R5NbffTB.mjs → Field-fBnTwgU4.mjs} +405 -256
- package/dist/_chunks/Field-fBnTwgU4.mjs.map +1 -0
- package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
- package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
- package/dist/_chunks/{Form-BHmXSfyy.mjs → Form-BGl7PhlZ.mjs} +37 -18
- package/dist/_chunks/Form-BGl7PhlZ.mjs.map +1 -0
- package/dist/_chunks/{Form-CcGboku8.js → Form-DSGh_zkz.js} +39 -21
- package/dist/_chunks/Form-DSGh_zkz.js.map +1 -0
- package/dist/_chunks/{History-ByUPL3T3.mjs → History-DTYB9CSB.mjs} +66 -113
- package/dist/_chunks/History-DTYB9CSB.mjs.map +1 -0
- package/dist/_chunks/{History-Bsud8jwh.js → History-DrDJv698.js} +65 -113
- package/dist/_chunks/History-DrDJv698.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Bm5HACXf.mjs → ListConfigurationPage-qWx8r4D_.mjs} +25 -12
- package/dist/_chunks/ListConfigurationPage-qWx8r4D_.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DiT463qx.js → ListConfigurationPage-zurIlUZ7.js} +25 -13
- package/dist/_chunks/ListConfigurationPage-zurIlUZ7.js.map +1 -0
- package/dist/_chunks/{ListViewPage-CsrC9L_d.js → ListViewPage-DTM2uO_S.js} +109 -78
- package/dist/_chunks/ListViewPage-DTM2uO_S.js.map +1 -0
- package/dist/_chunks/{ListViewPage-JSyNAAYu.mjs → ListViewPage-GKpL5p8A.mjs} +106 -74
- package/dist/_chunks/ListViewPage-GKpL5p8A.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs → NoContentTypePage-B5Vc5Cal.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CsrQUpBE.mjs.map → NoContentTypePage-B5Vc5Cal.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-Bsvng4II.js → NoContentTypePage-BuZlNroO.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-Bsvng4II.js.map → NoContentTypePage-BuZlNroO.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs → NoPermissionsPage-BAZlWgJ4.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DNmf_pj0.mjs.map → NoPermissionsPage-BAZlWgJ4.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js → NoPermissionsPage-DLzkS4Hy.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CdHNJtEf.js.map → NoPermissionsPage-DLzkS4Hy.js.map} +1 -1
- package/dist/_chunks/Preview-VOJ8RuQp.js +312 -0
- package/dist/_chunks/Preview-VOJ8RuQp.js.map +1 -0
- package/dist/_chunks/Preview-Zzjg2_K_.mjs +294 -0
- package/dist/_chunks/Preview-Zzjg2_K_.mjs.map +1 -0
- package/dist/_chunks/{Relations-u8-37jK0.mjs → Relations-BVdRfDkW.mjs} +76 -42
- package/dist/_chunks/Relations-BVdRfDkW.mjs.map +1 -0
- package/dist/_chunks/{Relations-CghaPv2D.js → Relations-Dsj0boFJ.js} +76 -43
- package/dist/_chunks/Relations-Dsj0boFJ.js.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-BzQmavmK.js} +37 -18
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-BzQmavmK.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-CSxLmrh1.mjs} +37 -18
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-CSxLmrh1.mjs.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-CaE6NG4a.mjs → index-Bu_-B7ZA.mjs} +1263 -772
- package/dist/_chunks/index-Bu_-B7ZA.mjs.map +1 -0
- package/dist/_chunks/{index-BOZx6IMg.js → index-Ct-GZ0iV.js} +1246 -755
- package/dist/_chunks/index-Ct-GZ0iV.js.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout-Ciz224q5.js → layout-CDBEgRsM.js} +24 -12
- package/dist/_chunks/layout-CDBEgRsM.js.map +1 -0
- package/dist/_chunks/{layout-Bx7svTbY.mjs → layout-COzAvgJh.mjs} +24 -11
- package/dist/_chunks/layout-COzAvgJh.mjs.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CP8sB2YZ.js → relations-BjiF1Aad.js} +6 -7
- package/dist/_chunks/relations-BjiF1Aad.js.map +1 -0
- package/dist/_chunks/{relations-Cxc1cEv3.mjs → relations-BtmMFBpM.mjs} +6 -7
- package/dist/_chunks/relations-BtmMFBpM.mjs.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- 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-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js.map → useDragAndDrop-BMtgCYzL.js.map} +1 -1
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs → useDragAndDrop-DJ6jqvZN.mjs} +4 -7
- package/dist/_chunks/{useDragAndDrop-DdHgKsqq.mjs.map → useDragAndDrop-DJ6jqvZN.mjs.map} +1 -1
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +6 -4
- package/dist/admin/src/content-manager.d.ts +3 -2
- package/dist/admin/src/exports.d.ts +2 -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 +32 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.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 +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
- package/dist/admin/src/preview/routes.d.ts +3 -0
- package/dist/admin/src/preview/services/preview.d.ts +3 -0
- package/dist/admin/src/router.d.ts +1 -1
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -20
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +682 -360
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +683 -360
- 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/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +16 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +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 +4 -4
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +7 -6
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +13 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +16 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +32 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +12 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +19 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +12 -10
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +7 -6
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts +2 -2
- 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 +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/preview.d.ts +27 -0
- package/dist/shared/contracts/preview.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +4 -0
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +17 -15
- package/dist/_chunks/EditViewPage-BqNpC6hO.js.map +0 -1
- package/dist/_chunks/EditViewPage-BtkEx339.mjs.map +0 -1
- package/dist/_chunks/Field-R5NbffTB.mjs.map +0 -1
- package/dist/_chunks/Field-lsPFnAmH.js.map +0 -1
- package/dist/_chunks/Form-BHmXSfyy.mjs.map +0 -1
- package/dist/_chunks/Form-CcGboku8.js.map +0 -1
- package/dist/_chunks/History-Bsud8jwh.js.map +0 -1
- package/dist/_chunks/History-ByUPL3T3.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Bm5HACXf.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DiT463qx.js.map +0 -1
- package/dist/_chunks/ListViewPage-CsrC9L_d.js.map +0 -1
- package/dist/_chunks/ListViewPage-JSyNAAYu.mjs.map +0 -1
- package/dist/_chunks/Relations-CghaPv2D.js.map +0 -1
- package/dist/_chunks/Relations-u8-37jK0.mjs.map +0 -1
- package/dist/_chunks/index-BOZx6IMg.js.map +0 -1
- package/dist/_chunks/index-CaE6NG4a.mjs.map +0 -1
- package/dist/_chunks/layout-Bx7svTbY.mjs.map +0 -1
- package/dist/_chunks/layout-Ciz224q5.js.map +0 -1
- package/dist/_chunks/relations-CP8sB2YZ.js.map +0 -1
- package/dist/_chunks/relations-Cxc1cEv3.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,25 +1,33 @@
|
|
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, useLocation, Link, 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 {
|
6
|
+
import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import mapValues from "lodash/fp/mapValues";
|
8
|
+
import { useIntl } from "react-intl";
|
9
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
10
10
|
import { styled } from "styled-components";
|
11
11
|
import * as yup from "yup";
|
12
12
|
import { ValidationError } from "yup";
|
13
|
+
import { stringify } from "qs";
|
13
14
|
import pipe from "lodash/fp/pipe";
|
14
15
|
import { intervalToDuration, isPast } from "date-fns";
|
15
16
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
|
-
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
17
18
|
const v = glob[path];
|
18
19
|
if (v) {
|
19
20
|
return typeof v === "function" ? v() : Promise.resolve(v);
|
20
21
|
}
|
21
22
|
return new Promise((_, reject) => {
|
22
|
-
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
23
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
24
|
+
reject.bind(
|
25
|
+
null,
|
26
|
+
new Error(
|
27
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
28
|
+
)
|
29
|
+
)
|
30
|
+
);
|
23
31
|
});
|
24
32
|
};
|
25
33
|
const PLUGIN_ID = "content-manager";
|
@@ -49,42 +57,6 @@ const useInjectionZone = (area) => {
|
|
49
57
|
const [page, position] = area.split(".");
|
50
58
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
51
59
|
};
|
52
|
-
const HistoryAction = ({ model, document }) => {
|
53
|
-
const { formatMessage } = useIntl();
|
54
|
-
const [{ query }] = useQueryParams();
|
55
|
-
const navigate = useNavigate();
|
56
|
-
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
57
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
58
|
-
return null;
|
59
|
-
}
|
60
|
-
return {
|
61
|
-
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
62
|
-
label: formatMessage({
|
63
|
-
id: "content-manager.history.document-action",
|
64
|
-
defaultMessage: "Content History"
|
65
|
-
}),
|
66
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
67
|
-
disabled: (
|
68
|
-
/**
|
69
|
-
* The user is creating a new document.
|
70
|
-
* It hasn't been saved yet, so there's no history to go to
|
71
|
-
*/
|
72
|
-
!document || /**
|
73
|
-
* The document has been created but the current dimension has never been saved.
|
74
|
-
* For example, the user is creating a new locale in an existing document,
|
75
|
-
* so there's no history for the document in that locale
|
76
|
-
*/
|
77
|
-
!document.id || /**
|
78
|
-
* History is only available for content types created by the user.
|
79
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
80
|
-
* which start with `admin::` or `plugin::`
|
81
|
-
*/
|
82
|
-
!model.startsWith("api::")
|
83
|
-
),
|
84
|
-
position: "header"
|
85
|
-
};
|
86
|
-
};
|
87
|
-
HistoryAction.type = "history";
|
88
60
|
const ID = "id";
|
89
61
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
90
62
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -136,6 +108,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
136
108
|
if (!slug) {
|
137
109
|
throw new Error("Cannot find the slug param in the URL");
|
138
110
|
}
|
111
|
+
const [{ rawQuery }] = useQueryParams();
|
139
112
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
140
113
|
const contentTypePermissions = React.useMemo(() => {
|
141
114
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -146,7 +119,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
146
119
|
return { ...acc, [action]: [permission] };
|
147
120
|
}, {});
|
148
121
|
}, [slug, userPermissions]);
|
149
|
-
const { isLoading, allowedActions } = useRBAC(
|
122
|
+
const { isLoading, allowedActions } = useRBAC(
|
123
|
+
contentTypePermissions,
|
124
|
+
permissions ?? void 0,
|
125
|
+
// TODO: useRBAC context should be typed and built differently
|
126
|
+
// We are passing raw query as context to the hook so that it can
|
127
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
128
|
+
rawQuery
|
129
|
+
);
|
150
130
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
151
131
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
152
132
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -194,7 +174,9 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
194
174
|
"Document",
|
195
175
|
"InitialData",
|
196
176
|
"HistoryVersion",
|
197
|
-
"Relations"
|
177
|
+
"Relations",
|
178
|
+
"UidAvailability",
|
179
|
+
"RecentDocumentList"
|
198
180
|
]
|
199
181
|
});
|
200
182
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -208,7 +190,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
208
190
|
params: query
|
209
191
|
}
|
210
192
|
}),
|
211
|
-
invalidatesTags: (_result,
|
193
|
+
invalidatesTags: (_result, error, { model }) => {
|
194
|
+
if (error) {
|
195
|
+
return [];
|
196
|
+
}
|
197
|
+
return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
|
198
|
+
}
|
212
199
|
}),
|
213
200
|
cloneDocument: builder.mutation({
|
214
201
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -219,7 +206,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
219
206
|
params
|
220
207
|
}
|
221
208
|
}),
|
222
|
-
invalidatesTags: (_result, _error, { model }) => [
|
209
|
+
invalidatesTags: (_result, _error, { model }) => [
|
210
|
+
{ type: "Document", id: `${model}_LIST` },
|
211
|
+
{ type: "UidAvailability", id: model },
|
212
|
+
"RecentDocumentList"
|
213
|
+
]
|
223
214
|
}),
|
224
215
|
/**
|
225
216
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -236,8 +227,22 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
236
227
|
}),
|
237
228
|
invalidatesTags: (result, _error, { model }) => [
|
238
229
|
{ type: "Document", id: `${model}_LIST` },
|
239
|
-
"Relations"
|
240
|
-
|
230
|
+
"Relations",
|
231
|
+
{ type: "UidAvailability", id: model },
|
232
|
+
"RecentDocumentList"
|
233
|
+
],
|
234
|
+
transformResponse: (response, meta, arg) => {
|
235
|
+
if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
|
236
|
+
return {
|
237
|
+
data: response,
|
238
|
+
meta: {
|
239
|
+
availableStatus: [],
|
240
|
+
availableLocales: []
|
241
|
+
}
|
242
|
+
};
|
243
|
+
}
|
244
|
+
return response;
|
245
|
+
}
|
241
246
|
}),
|
242
247
|
deleteDocument: builder.mutation({
|
243
248
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -248,7 +253,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
248
253
|
}
|
249
254
|
}),
|
250
255
|
invalidatesTags: (_result, _error, { collectionType, model }) => [
|
251
|
-
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
256
|
+
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
|
257
|
+
"RecentDocumentList"
|
252
258
|
]
|
253
259
|
}),
|
254
260
|
deleteManyDocuments: builder.mutation({
|
@@ -260,7 +266,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
260
266
|
params
|
261
267
|
}
|
262
268
|
}),
|
263
|
-
invalidatesTags: (_res, _error, { model }) => [
|
269
|
+
invalidatesTags: (_res, _error, { model }) => [
|
270
|
+
{ type: "Document", id: `${model}_LIST` },
|
271
|
+
"RecentDocumentList"
|
272
|
+
]
|
264
273
|
}),
|
265
274
|
discardDocument: builder.mutation({
|
266
275
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -277,7 +286,9 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
277
286
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
278
287
|
},
|
279
288
|
{ type: "Document", id: `${model}_LIST` },
|
280
|
-
"Relations"
|
289
|
+
"Relations",
|
290
|
+
{ type: "UidAvailability", id: model },
|
291
|
+
"RecentDocumentList"
|
281
292
|
];
|
282
293
|
}
|
283
294
|
}),
|
@@ -290,11 +301,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
290
301
|
url: `/content-manager/collection-types/${model}`,
|
291
302
|
method: "GET",
|
292
303
|
config: {
|
293
|
-
params
|
304
|
+
params: stringify(params, { encode: true })
|
294
305
|
}
|
295
306
|
}),
|
296
307
|
providesTags: (result, _error, arg) => {
|
297
308
|
return [
|
309
|
+
{ type: "Document", id: `ALL_LIST` },
|
298
310
|
{ type: "Document", id: `${arg.model}_LIST` },
|
299
311
|
...result?.results.map(({ documentId }) => ({
|
300
312
|
type: "Document",
|
@@ -333,6 +345,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
333
345
|
{
|
334
346
|
type: "Document",
|
335
347
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
348
|
+
},
|
349
|
+
// Make it easy to invalidate all individual documents queries for a model
|
350
|
+
{
|
351
|
+
type: "Document",
|
352
|
+
id: `${model}_ALL_ITEMS`
|
336
353
|
}
|
337
354
|
];
|
338
355
|
}
|
@@ -366,7 +383,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
366
383
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
367
384
|
},
|
368
385
|
{ type: "Document", id: `${model}_LIST` },
|
369
|
-
"Relations"
|
386
|
+
"Relations",
|
387
|
+
"RecentDocumentList"
|
370
388
|
];
|
371
389
|
}
|
372
390
|
}),
|
@@ -396,8 +414,23 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
396
414
|
type: "Document",
|
397
415
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
398
416
|
},
|
399
|
-
"Relations"
|
417
|
+
"Relations",
|
418
|
+
{ type: "UidAvailability", id: model },
|
419
|
+
"RecentDocumentList",
|
420
|
+
"RecentDocumentList"
|
400
421
|
];
|
422
|
+
},
|
423
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
424
|
+
const patchResult = dispatch(
|
425
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
426
|
+
Object.assign(draft.data, data);
|
427
|
+
})
|
428
|
+
);
|
429
|
+
try {
|
430
|
+
await queryFulfilled;
|
431
|
+
} catch {
|
432
|
+
patchResult.undo();
|
433
|
+
}
|
401
434
|
}
|
402
435
|
}),
|
403
436
|
unpublishDocument: builder.mutation({
|
@@ -414,7 +447,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
414
447
|
{
|
415
448
|
type: "Document",
|
416
449
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
417
|
-
}
|
450
|
+
},
|
451
|
+
"RecentDocumentList"
|
418
452
|
];
|
419
453
|
}
|
420
454
|
}),
|
@@ -427,7 +461,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
427
461
|
params
|
428
462
|
}
|
429
463
|
}),
|
430
|
-
invalidatesTags: (_res, _error, { model, documentIds }) =>
|
464
|
+
invalidatesTags: (_res, _error, { model, documentIds }) => [
|
465
|
+
...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
|
466
|
+
"RecentDocumentList"
|
467
|
+
]
|
431
468
|
})
|
432
469
|
})
|
433
470
|
});
|
@@ -450,8 +487,7 @@ const {
|
|
450
487
|
useUnpublishManyDocumentsMutation
|
451
488
|
} = documentApi;
|
452
489
|
const buildValidParams = (query) => {
|
453
|
-
if (!query)
|
454
|
-
return query;
|
490
|
+
if (!query) return query;
|
455
491
|
const { plugins: _, ...validQueryParams } = {
|
456
492
|
...query,
|
457
493
|
...Object.values(query?.plugins ?? {}).reduce(
|
@@ -459,28 +495,44 @@ const buildValidParams = (query) => {
|
|
459
495
|
{}
|
460
496
|
)
|
461
497
|
};
|
462
|
-
if ("_q" in validQueryParams) {
|
463
|
-
validQueryParams._q = encodeURIComponent(validQueryParams._q);
|
464
|
-
}
|
465
498
|
return validQueryParams;
|
466
499
|
};
|
467
500
|
const isBaseQueryError = (error) => {
|
468
501
|
return error.name !== void 0;
|
469
502
|
};
|
470
|
-
const
|
503
|
+
const arrayValidator = (attribute, options) => ({
|
504
|
+
message: translatedErrors.required,
|
505
|
+
test(value) {
|
506
|
+
if (options.status === "draft") {
|
507
|
+
return true;
|
508
|
+
}
|
509
|
+
if (!attribute.required) {
|
510
|
+
return true;
|
511
|
+
}
|
512
|
+
if (!value) {
|
513
|
+
return false;
|
514
|
+
}
|
515
|
+
if (Array.isArray(value) && value.length === 0) {
|
516
|
+
return false;
|
517
|
+
}
|
518
|
+
return true;
|
519
|
+
}
|
520
|
+
});
|
521
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
471
522
|
const createModelSchema = (attributes2) => yup.object().shape(
|
472
523
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
473
524
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
474
525
|
return acc;
|
475
526
|
}
|
476
527
|
const validations = [
|
528
|
+
addNullableValidation,
|
477
529
|
addRequiredValidation,
|
478
530
|
addMinLengthValidation,
|
479
531
|
addMaxLengthValidation,
|
480
532
|
addMinValidation,
|
481
533
|
addMaxValidation,
|
482
534
|
addRegexValidation
|
483
|
-
].map((fn) => fn(attribute));
|
535
|
+
].map((fn) => fn(attribute, options));
|
484
536
|
const transformSchema = pipe(...validations);
|
485
537
|
switch (attribute.type) {
|
486
538
|
case "component": {
|
@@ -490,12 +542,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
490
542
|
...acc,
|
491
543
|
[name]: transformSchema(
|
492
544
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
493
|
-
)
|
545
|
+
).test(arrayValidator(attribute, options))
|
494
546
|
};
|
495
547
|
} else {
|
496
548
|
return {
|
497
549
|
...acc,
|
498
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
550
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
499
551
|
};
|
500
552
|
}
|
501
553
|
}
|
@@ -517,7 +569,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
517
569
|
}
|
518
570
|
)
|
519
571
|
)
|
520
|
-
)
|
572
|
+
).test(arrayValidator(attribute, options))
|
521
573
|
};
|
522
574
|
case "relation":
|
523
575
|
return {
|
@@ -529,7 +581,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
529
581
|
} else if (Array.isArray(value)) {
|
530
582
|
return yup.array().of(
|
531
583
|
yup.object().shape({
|
532
|
-
id: yup.
|
584
|
+
id: yup.number().required()
|
533
585
|
})
|
534
586
|
);
|
535
587
|
} else if (typeof value === "object") {
|
@@ -581,6 +633,14 @@ const createAttributeSchema = (attribute) => {
|
|
581
633
|
if (!value || typeof value === "string" && value.length === 0) {
|
582
634
|
return true;
|
583
635
|
}
|
636
|
+
if (typeof value === "object") {
|
637
|
+
try {
|
638
|
+
JSON.stringify(value);
|
639
|
+
return true;
|
640
|
+
} catch (err) {
|
641
|
+
return false;
|
642
|
+
}
|
643
|
+
}
|
584
644
|
try {
|
585
645
|
JSON.parse(value);
|
586
646
|
return true;
|
@@ -599,13 +659,7 @@ const createAttributeSchema = (attribute) => {
|
|
599
659
|
return yup.mixed();
|
600
660
|
}
|
601
661
|
};
|
602
|
-
const
|
603
|
-
if (attribute.required && attribute.type !== "relation") {
|
604
|
-
return schema.required({
|
605
|
-
id: translatedErrors.required.id,
|
606
|
-
defaultMessage: "This field is required."
|
607
|
-
});
|
608
|
-
}
|
662
|
+
const nullableSchema = (schema) => {
|
609
663
|
return schema?.nullable ? schema.nullable() : (
|
610
664
|
// In some cases '.nullable' will not be available on the schema.
|
611
665
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -613,7 +667,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
613
667
|
schema
|
614
668
|
);
|
615
669
|
};
|
616
|
-
const
|
670
|
+
const addNullableValidation = () => (schema) => {
|
671
|
+
return nullableSchema(schema);
|
672
|
+
};
|
673
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
674
|
+
if (options.status === "draft" || !attribute.required) {
|
675
|
+
return schema;
|
676
|
+
}
|
677
|
+
if (attribute.required && "required" in schema) {
|
678
|
+
return schema.required(translatedErrors.required);
|
679
|
+
}
|
680
|
+
return schema;
|
681
|
+
};
|
682
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
683
|
+
if (options.status === "draft") {
|
684
|
+
return schema;
|
685
|
+
}
|
617
686
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
618
687
|
return schema.min(attribute.minLength, {
|
619
688
|
...translatedErrors.minLength,
|
@@ -635,10 +704,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
635
704
|
}
|
636
705
|
return schema;
|
637
706
|
};
|
638
|
-
const addMinValidation = (attribute) => (schema) => {
|
639
|
-
if ("
|
707
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
708
|
+
if (options.status === "draft") {
|
709
|
+
return schema;
|
710
|
+
}
|
711
|
+
if ("min" in attribute && "min" in schema) {
|
640
712
|
const min = toInteger(attribute.min);
|
641
|
-
if (
|
713
|
+
if (min) {
|
642
714
|
return schema.min(min, {
|
643
715
|
...translatedErrors.min,
|
644
716
|
values: {
|
@@ -756,19 +828,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
756
828
|
}, {});
|
757
829
|
return componentsByKey;
|
758
830
|
};
|
759
|
-
const
|
831
|
+
const HOOKS = {
|
832
|
+
/**
|
833
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
834
|
+
* @constant
|
835
|
+
* @type {string}
|
836
|
+
*/
|
837
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
838
|
+
/**
|
839
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
840
|
+
* @constant
|
841
|
+
* @type {string}
|
842
|
+
*/
|
843
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
844
|
+
/**
|
845
|
+
* Hook that allows to mutate the CM's edit view layout
|
846
|
+
* @constant
|
847
|
+
* @type {string}
|
848
|
+
*/
|
849
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
850
|
+
/**
|
851
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
852
|
+
* @constant
|
853
|
+
* @type {string}
|
854
|
+
*/
|
855
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
856
|
+
};
|
857
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
858
|
+
endpoints: (builder) => ({
|
859
|
+
getContentTypeConfiguration: builder.query({
|
860
|
+
query: (uid) => ({
|
861
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
862
|
+
method: "GET"
|
863
|
+
}),
|
864
|
+
transformResponse: (response) => response.data,
|
865
|
+
providesTags: (_result, _error, uid) => [
|
866
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
867
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
868
|
+
]
|
869
|
+
}),
|
870
|
+
getAllContentTypeSettings: builder.query({
|
871
|
+
query: () => "/content-manager/content-types-settings",
|
872
|
+
transformResponse: (response) => response.data,
|
873
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
874
|
+
}),
|
875
|
+
updateContentTypeConfiguration: builder.mutation({
|
876
|
+
query: ({ uid, ...body }) => ({
|
877
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
878
|
+
method: "PUT",
|
879
|
+
data: body
|
880
|
+
}),
|
881
|
+
transformResponse: (response) => response.data,
|
882
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
883
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
884
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
885
|
+
// Is this necessary?
|
886
|
+
{ type: "InitialData" }
|
887
|
+
]
|
888
|
+
})
|
889
|
+
})
|
890
|
+
});
|
891
|
+
const {
|
892
|
+
useGetContentTypeConfigurationQuery,
|
893
|
+
useGetAllContentTypeSettingsQuery,
|
894
|
+
useUpdateContentTypeConfigurationMutation
|
895
|
+
} = contentTypesApi;
|
896
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
897
|
+
const { type } = attribute;
|
898
|
+
if (type === "relation") {
|
899
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
900
|
+
}
|
901
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
902
|
+
};
|
903
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
904
|
+
if (!mainFieldName) {
|
905
|
+
return void 0;
|
906
|
+
}
|
907
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
908
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
909
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
910
|
+
);
|
911
|
+
return {
|
912
|
+
name: mainFieldName,
|
913
|
+
type: mainFieldType ?? "string"
|
914
|
+
};
|
915
|
+
};
|
916
|
+
const DEFAULT_SETTINGS = {
|
917
|
+
bulkable: false,
|
918
|
+
filterable: false,
|
919
|
+
searchable: false,
|
920
|
+
pagination: false,
|
921
|
+
defaultSortBy: "",
|
922
|
+
defaultSortOrder: "asc",
|
923
|
+
mainField: "id",
|
924
|
+
pageSize: 10
|
925
|
+
};
|
926
|
+
const useDocumentLayout = (model) => {
|
927
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
928
|
+
const [{ query }] = useQueryParams();
|
929
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
760
930
|
const { toggleNotification } = useNotification();
|
761
931
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
932
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
762
933
|
const {
|
763
|
-
|
764
|
-
isLoading:
|
765
|
-
|
766
|
-
|
767
|
-
} =
|
768
|
-
|
769
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
770
|
-
});
|
771
|
-
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
934
|
+
data,
|
935
|
+
isLoading: isLoadingConfigs,
|
936
|
+
error,
|
937
|
+
isFetching: isFetchingConfigs
|
938
|
+
} = useGetContentTypeConfigurationQuery(model);
|
939
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
772
940
|
React.useEffect(() => {
|
773
941
|
if (error) {
|
774
942
|
toggleNotification({
|
@@ -776,39 +944,255 @@ const useDocument = (args, opts) => {
|
|
776
944
|
message: formatAPIError(error)
|
777
945
|
});
|
778
946
|
}
|
779
|
-
}, [
|
780
|
-
const
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
(document) => {
|
788
|
-
if (!validationSchema) {
|
789
|
-
throw new Error(
|
790
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
791
|
-
);
|
792
|
-
}
|
793
|
-
try {
|
794
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
795
|
-
return null;
|
796
|
-
} catch (error2) {
|
797
|
-
if (error2 instanceof ValidationError) {
|
798
|
-
return getYupValidationErrors(error2);
|
799
|
-
}
|
800
|
-
throw error2;
|
801
|
-
}
|
947
|
+
}, [error, formatAPIError, toggleNotification]);
|
948
|
+
const editLayout = React.useMemo(
|
949
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
950
|
+
layout: [],
|
951
|
+
components: {},
|
952
|
+
metadatas: {},
|
953
|
+
options: {},
|
954
|
+
settings: DEFAULT_SETTINGS
|
802
955
|
},
|
803
|
-
[
|
956
|
+
[data, isLoading, schemas, schema, components]
|
957
|
+
);
|
958
|
+
const listLayout = React.useMemo(() => {
|
959
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
960
|
+
layout: [],
|
961
|
+
metadatas: {},
|
962
|
+
options: {},
|
963
|
+
settings: DEFAULT_SETTINGS
|
964
|
+
};
|
965
|
+
}, [data, isLoading, schemas, schema, components]);
|
966
|
+
const { layout: edit } = React.useMemo(
|
967
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
968
|
+
layout: editLayout,
|
969
|
+
query
|
970
|
+
}),
|
971
|
+
[editLayout, query, runHookWaterfall]
|
804
972
|
);
|
805
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
806
973
|
return {
|
807
|
-
|
808
|
-
|
974
|
+
error,
|
975
|
+
isLoading,
|
976
|
+
edit,
|
977
|
+
list: listLayout
|
978
|
+
};
|
979
|
+
};
|
980
|
+
const useDocLayout = () => {
|
981
|
+
const { model } = useDoc();
|
982
|
+
return useDocumentLayout(model);
|
983
|
+
};
|
984
|
+
const formatEditLayout = (data, {
|
985
|
+
schemas,
|
986
|
+
schema,
|
987
|
+
components
|
988
|
+
}) => {
|
989
|
+
let currentPanelIndex = 0;
|
990
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
991
|
+
data.contentType.layouts.edit,
|
992
|
+
schema?.attributes,
|
993
|
+
data.contentType.metadatas,
|
994
|
+
{ configurations: data.components, schemas: components },
|
995
|
+
schemas
|
996
|
+
).reduce((panels, row) => {
|
997
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
998
|
+
panels.push([row]);
|
999
|
+
currentPanelIndex += 2;
|
1000
|
+
} else {
|
1001
|
+
if (!panels[currentPanelIndex]) {
|
1002
|
+
panels.push([row]);
|
1003
|
+
} else {
|
1004
|
+
panels[currentPanelIndex].push(row);
|
1005
|
+
}
|
1006
|
+
}
|
1007
|
+
return panels;
|
1008
|
+
}, []);
|
1009
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
1010
|
+
(acc, [uid, configuration]) => {
|
1011
|
+
acc[uid] = {
|
1012
|
+
layout: convertEditLayoutToFieldLayouts(
|
1013
|
+
configuration.layouts.edit,
|
1014
|
+
components[uid].attributes,
|
1015
|
+
configuration.metadatas,
|
1016
|
+
{ configurations: data.components, schemas: components }
|
1017
|
+
),
|
1018
|
+
settings: {
|
1019
|
+
...configuration.settings,
|
1020
|
+
icon: components[uid].info.icon,
|
1021
|
+
displayName: components[uid].info.displayName
|
1022
|
+
}
|
1023
|
+
};
|
1024
|
+
return acc;
|
1025
|
+
},
|
1026
|
+
{}
|
1027
|
+
);
|
1028
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1029
|
+
(acc, [attribute, metadata]) => {
|
1030
|
+
return {
|
1031
|
+
...acc,
|
1032
|
+
[attribute]: metadata.edit
|
1033
|
+
};
|
1034
|
+
},
|
1035
|
+
{}
|
1036
|
+
);
|
1037
|
+
return {
|
1038
|
+
layout: panelledEditAttributes,
|
1039
|
+
components: componentEditAttributes,
|
1040
|
+
metadatas: editMetadatas,
|
1041
|
+
settings: {
|
1042
|
+
...data.contentType.settings,
|
1043
|
+
displayName: schema?.info.displayName
|
1044
|
+
},
|
1045
|
+
options: {
|
1046
|
+
...schema?.options,
|
1047
|
+
...schema?.pluginOptions,
|
1048
|
+
...data.contentType.options
|
1049
|
+
}
|
1050
|
+
};
|
1051
|
+
};
|
1052
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1053
|
+
return rows.map(
|
1054
|
+
(row) => row.map((field) => {
|
1055
|
+
const attribute = attributes[field.name];
|
1056
|
+
if (!attribute) {
|
1057
|
+
return null;
|
1058
|
+
}
|
1059
|
+
const { edit: metadata } = metadatas[field.name];
|
1060
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1061
|
+
return {
|
1062
|
+
attribute,
|
1063
|
+
disabled: !metadata.editable,
|
1064
|
+
hint: metadata.description,
|
1065
|
+
label: metadata.label ?? "",
|
1066
|
+
name: field.name,
|
1067
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1068
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1069
|
+
schemas,
|
1070
|
+
components: components?.schemas ?? {}
|
1071
|
+
}),
|
1072
|
+
placeholder: metadata.placeholder ?? "",
|
1073
|
+
required: attribute.required ?? false,
|
1074
|
+
size: field.size,
|
1075
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1076
|
+
visible: metadata.visible ?? true,
|
1077
|
+
type: attribute.type
|
1078
|
+
};
|
1079
|
+
}).filter((field) => field !== null)
|
1080
|
+
);
|
1081
|
+
};
|
1082
|
+
const formatListLayout = (data, {
|
1083
|
+
schemas,
|
1084
|
+
schema,
|
1085
|
+
components
|
1086
|
+
}) => {
|
1087
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1088
|
+
(acc, [attribute, metadata]) => {
|
1089
|
+
return {
|
1090
|
+
...acc,
|
1091
|
+
[attribute]: metadata.list
|
1092
|
+
};
|
1093
|
+
},
|
1094
|
+
{}
|
1095
|
+
);
|
1096
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1097
|
+
data.contentType.layouts.list,
|
1098
|
+
schema?.attributes,
|
1099
|
+
listMetadatas,
|
1100
|
+
{ configurations: data.components, schemas: components },
|
1101
|
+
schemas
|
1102
|
+
);
|
1103
|
+
return {
|
1104
|
+
layout: listAttributes,
|
1105
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1106
|
+
metadatas: listMetadatas,
|
1107
|
+
options: {
|
1108
|
+
...schema?.options,
|
1109
|
+
...schema?.pluginOptions,
|
1110
|
+
...data.contentType.options
|
1111
|
+
}
|
1112
|
+
};
|
1113
|
+
};
|
1114
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1115
|
+
return columns.map((name) => {
|
1116
|
+
const attribute = attributes[name];
|
1117
|
+
if (!attribute) {
|
1118
|
+
return null;
|
1119
|
+
}
|
1120
|
+
const metadata = metadatas[name];
|
1121
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1122
|
+
return {
|
1123
|
+
attribute,
|
1124
|
+
label: metadata.label ?? "",
|
1125
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1126
|
+
schemas,
|
1127
|
+
components: components?.schemas ?? {}
|
1128
|
+
}),
|
1129
|
+
name,
|
1130
|
+
searchable: metadata.searchable ?? true,
|
1131
|
+
sortable: metadata.sortable ?? true
|
1132
|
+
};
|
1133
|
+
}).filter((field) => field !== null);
|
1134
|
+
};
|
1135
|
+
const useDocument = (args, opts) => {
|
1136
|
+
const { toggleNotification } = useNotification();
|
1137
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1138
|
+
const {
|
1139
|
+
currentData: data,
|
1140
|
+
isLoading: isLoadingDocument,
|
1141
|
+
isFetching: isFetchingDocument,
|
1142
|
+
error
|
1143
|
+
} = useGetDocumentQuery(args, {
|
1144
|
+
...opts,
|
1145
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1146
|
+
});
|
1147
|
+
const {
|
1148
|
+
components,
|
1149
|
+
schema,
|
1150
|
+
schemas,
|
1151
|
+
isLoading: isLoadingSchema
|
1152
|
+
} = useContentTypeSchema(args.model);
|
1153
|
+
React.useEffect(() => {
|
1154
|
+
if (error) {
|
1155
|
+
toggleNotification({
|
1156
|
+
type: "danger",
|
1157
|
+
message: formatAPIError(error)
|
1158
|
+
});
|
1159
|
+
}
|
1160
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1161
|
+
const validationSchema = React.useMemo(() => {
|
1162
|
+
if (!schema) {
|
1163
|
+
return null;
|
1164
|
+
}
|
1165
|
+
return createYupSchema(schema.attributes, components);
|
1166
|
+
}, [schema, components]);
|
1167
|
+
const validate = React.useCallback(
|
1168
|
+
(document) => {
|
1169
|
+
if (!validationSchema) {
|
1170
|
+
throw new Error(
|
1171
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1172
|
+
);
|
1173
|
+
}
|
1174
|
+
try {
|
1175
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1176
|
+
return null;
|
1177
|
+
} catch (error2) {
|
1178
|
+
if (error2 instanceof ValidationError) {
|
1179
|
+
return getYupValidationErrors(error2);
|
1180
|
+
}
|
1181
|
+
throw error2;
|
1182
|
+
}
|
1183
|
+
},
|
1184
|
+
[validationSchema]
|
1185
|
+
);
|
1186
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1187
|
+
const hasError = !!error;
|
1188
|
+
return {
|
1189
|
+
components,
|
1190
|
+
document: data?.data,
|
809
1191
|
meta: data?.meta,
|
810
1192
|
isLoading,
|
1193
|
+
hasError,
|
811
1194
|
schema,
|
1195
|
+
schemas,
|
812
1196
|
validate
|
813
1197
|
};
|
814
1198
|
};
|
@@ -822,22 +1206,60 @@ const useDoc = () => {
|
|
822
1206
|
if (!slug) {
|
823
1207
|
throw new Error("Could not find model in url params");
|
824
1208
|
}
|
1209
|
+
const document = useDocument(
|
1210
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1211
|
+
{
|
1212
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1213
|
+
}
|
1214
|
+
);
|
1215
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
825
1216
|
return {
|
826
1217
|
collectionType,
|
827
1218
|
model: slug,
|
828
|
-
id:
|
829
|
-
...
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
834
|
-
|
1219
|
+
id: returnId,
|
1220
|
+
...document
|
1221
|
+
};
|
1222
|
+
};
|
1223
|
+
const useContentManagerContext = () => {
|
1224
|
+
const {
|
1225
|
+
collectionType,
|
1226
|
+
model,
|
1227
|
+
id,
|
1228
|
+
components,
|
1229
|
+
isLoading: isLoadingDoc,
|
1230
|
+
schema,
|
1231
|
+
schemas
|
1232
|
+
} = useDoc();
|
1233
|
+
const layout = useDocumentLayout(model);
|
1234
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1235
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1236
|
+
const slug = model;
|
1237
|
+
const isCreatingEntry = id === "create";
|
1238
|
+
useContentTypeSchema();
|
1239
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1240
|
+
const error = layout.error;
|
1241
|
+
return {
|
1242
|
+
error,
|
1243
|
+
isLoading,
|
1244
|
+
// Base metadata
|
1245
|
+
model,
|
1246
|
+
collectionType,
|
1247
|
+
id,
|
1248
|
+
slug,
|
1249
|
+
isCreatingEntry,
|
1250
|
+
isSingleType,
|
1251
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1252
|
+
// All schema infos
|
1253
|
+
components,
|
1254
|
+
contentType: schema,
|
1255
|
+
contentTypes: schemas,
|
1256
|
+
// Form state
|
1257
|
+
form,
|
1258
|
+
// layout infos
|
1259
|
+
layout
|
835
1260
|
};
|
836
1261
|
};
|
837
1262
|
const prefixPluginTranslations = (trad, pluginId) => {
|
838
|
-
if (!pluginId) {
|
839
|
-
throw new TypeError("pluginId can't be empty");
|
840
|
-
}
|
841
1263
|
return Object.keys(trad).reduce((acc, current) => {
|
842
1264
|
acc[`${pluginId}.${current}`] = trad[current];
|
843
1265
|
return acc;
|
@@ -853,6 +1275,8 @@ const useDocumentActions = () => {
|
|
853
1275
|
const { formatMessage } = useIntl();
|
854
1276
|
const { trackUsage } = useTracking();
|
855
1277
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1278
|
+
const navigate = useNavigate();
|
1279
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
856
1280
|
const [deleteDocument] = useDeleteDocumentMutation();
|
857
1281
|
const _delete = React.useCallback(
|
858
1282
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1167,6 +1591,7 @@ const useDocumentActions = () => {
|
|
1167
1591
|
defaultMessage: "Saved document"
|
1168
1592
|
})
|
1169
1593
|
});
|
1594
|
+
setCurrentStep("contentManager.success");
|
1170
1595
|
return res.data;
|
1171
1596
|
} catch (err) {
|
1172
1597
|
toggleNotification({
|
@@ -1188,7 +1613,6 @@ const useDocumentActions = () => {
|
|
1188
1613
|
sourceId
|
1189
1614
|
});
|
1190
1615
|
if ("error" in res) {
|
1191
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1192
1616
|
return { error: res.error };
|
1193
1617
|
}
|
1194
1618
|
toggleNotification({
|
@@ -1207,7 +1631,7 @@ const useDocumentActions = () => {
|
|
1207
1631
|
throw err;
|
1208
1632
|
}
|
1209
1633
|
},
|
1210
|
-
[autoCloneDocument,
|
1634
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1211
1635
|
);
|
1212
1636
|
const [cloneDocument] = useCloneDocumentMutation();
|
1213
1637
|
const clone = React.useCallback(
|
@@ -1233,6 +1657,7 @@ const useDocumentActions = () => {
|
|
1233
1657
|
defaultMessage: "Cloned document"
|
1234
1658
|
})
|
1235
1659
|
});
|
1660
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1236
1661
|
return res.data;
|
1237
1662
|
} catch (err) {
|
1238
1663
|
toggleNotification({
|
@@ -1243,7 +1668,7 @@ const useDocumentActions = () => {
|
|
1243
1668
|
throw err;
|
1244
1669
|
}
|
1245
1670
|
},
|
1246
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1671
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1247
1672
|
);
|
1248
1673
|
const [getDoc] = useLazyGetDocumentQuery();
|
1249
1674
|
const getDocument = React.useCallback(
|
@@ -1268,10 +1693,10 @@ const useDocumentActions = () => {
|
|
1268
1693
|
update
|
1269
1694
|
};
|
1270
1695
|
};
|
1271
|
-
const ProtectedHistoryPage = lazy(
|
1272
|
-
() => import("./History-
|
1696
|
+
const ProtectedHistoryPage = React.lazy(
|
1697
|
+
() => import("./History-DTYB9CSB.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1273
1698
|
);
|
1274
|
-
const routes$
|
1699
|
+
const routes$2 = [
|
1275
1700
|
{
|
1276
1701
|
path: ":collectionType/:slug/:id/history",
|
1277
1702
|
Component: ProtectedHistoryPage
|
@@ -1281,32 +1706,45 @@ const routes$1 = [
|
|
1281
1706
|
Component: ProtectedHistoryPage
|
1282
1707
|
}
|
1283
1708
|
];
|
1709
|
+
const ProtectedPreviewPage = React.lazy(
|
1710
|
+
() => import("./Preview-Zzjg2_K_.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1711
|
+
);
|
1712
|
+
const routes$1 = [
|
1713
|
+
{
|
1714
|
+
path: ":collectionType/:slug/:id/preview",
|
1715
|
+
Component: ProtectedPreviewPage
|
1716
|
+
},
|
1717
|
+
{
|
1718
|
+
path: ":collectionType/:slug/preview",
|
1719
|
+
Component: ProtectedPreviewPage
|
1720
|
+
}
|
1721
|
+
];
|
1284
1722
|
const ProtectedEditViewPage = lazy(
|
1285
|
-
() => import("./EditViewPage-
|
1723
|
+
() => import("./EditViewPage-BPFcUbqi.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1286
1724
|
);
|
1287
1725
|
const ProtectedListViewPage = lazy(
|
1288
|
-
() => import("./ListViewPage-
|
1726
|
+
() => import("./ListViewPage-GKpL5p8A.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1289
1727
|
);
|
1290
1728
|
const ProtectedListConfiguration = lazy(
|
1291
|
-
() => import("./ListConfigurationPage-
|
1729
|
+
() => import("./ListConfigurationPage-qWx8r4D_.mjs").then((mod) => ({
|
1292
1730
|
default: mod.ProtectedListConfiguration
|
1293
1731
|
}))
|
1294
1732
|
);
|
1295
1733
|
const ProtectedEditConfigurationPage = lazy(
|
1296
|
-
() => import("./EditConfigurationPage-
|
1734
|
+
() => import("./EditConfigurationPage-C1ddZ_zf.mjs").then((mod) => ({
|
1297
1735
|
default: mod.ProtectedEditConfigurationPage
|
1298
1736
|
}))
|
1299
1737
|
);
|
1300
1738
|
const ProtectedComponentConfigurationPage = lazy(
|
1301
|
-
() => import("./ComponentConfigurationPage-
|
1739
|
+
() => import("./ComponentConfigurationPage-CcRDqD0e.mjs").then((mod) => ({
|
1302
1740
|
default: mod.ProtectedComponentConfigurationPage
|
1303
1741
|
}))
|
1304
1742
|
);
|
1305
1743
|
const NoPermissions = lazy(
|
1306
|
-
() => import("./NoPermissionsPage-
|
1744
|
+
() => import("./NoPermissionsPage-BAZlWgJ4.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1307
1745
|
);
|
1308
1746
|
const NoContentType = lazy(
|
1309
|
-
() => import("./NoContentTypePage-
|
1747
|
+
() => import("./NoContentTypePage-B5Vc5Cal.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1310
1748
|
);
|
1311
1749
|
const CollectionTypePages = () => {
|
1312
1750
|
const { collectionType } = useParams();
|
@@ -1318,7 +1756,7 @@ const CollectionTypePages = () => {
|
|
1318
1756
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1319
1757
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1320
1758
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1321
|
-
const LIST_PATH = `/content-manager
|
1759
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1322
1760
|
const routes = [
|
1323
1761
|
{
|
1324
1762
|
path: LIST_RELATIVE_PATH,
|
@@ -1352,6 +1790,7 @@ const routes = [
|
|
1352
1790
|
path: "no-content-types",
|
1353
1791
|
Component: NoContentType
|
1354
1792
|
},
|
1793
|
+
...routes$2,
|
1355
1794
|
...routes$1
|
1356
1795
|
];
|
1357
1796
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1420,12 +1859,14 @@ const DocumentActionButton = (action) => {
|
|
1420
1859
|
/* @__PURE__ */ jsx(
|
1421
1860
|
Button,
|
1422
1861
|
{
|
1423
|
-
flex:
|
1862
|
+
flex: "auto",
|
1424
1863
|
startIcon: action.icon,
|
1425
1864
|
disabled: action.disabled,
|
1426
1865
|
onClick: handleClick(action),
|
1427
1866
|
justifyContent: "center",
|
1428
1867
|
variant: action.variant || "default",
|
1868
|
+
paddingTop: "7px",
|
1869
|
+
paddingBottom: "7px",
|
1429
1870
|
children: action.label
|
1430
1871
|
}
|
1431
1872
|
),
|
@@ -1433,7 +1874,7 @@ const DocumentActionButton = (action) => {
|
|
1433
1874
|
DocumentActionConfirmDialog,
|
1434
1875
|
{
|
1435
1876
|
...action.dialog,
|
1436
|
-
variant: action.variant,
|
1877
|
+
variant: action.dialog?.variant ?? action.variant,
|
1437
1878
|
isOpen: dialogId === action.id,
|
1438
1879
|
onClose: handleClose
|
1439
1880
|
}
|
@@ -1448,6 +1889,11 @@ const DocumentActionButton = (action) => {
|
|
1448
1889
|
) : null
|
1449
1890
|
] });
|
1450
1891
|
};
|
1892
|
+
const MenuItem = styled(Menu.Item)`
|
1893
|
+
&:hover {
|
1894
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
1895
|
+
}
|
1896
|
+
`;
|
1451
1897
|
const DocumentActionsMenu = ({
|
1452
1898
|
actions: actions2,
|
1453
1899
|
children,
|
@@ -1490,9 +1936,9 @@ const DocumentActionsMenu = ({
|
|
1490
1936
|
disabled: isDisabled,
|
1491
1937
|
size: "S",
|
1492
1938
|
endIcon: null,
|
1493
|
-
paddingTop: "
|
1494
|
-
paddingLeft: "
|
1495
|
-
paddingRight: "
|
1939
|
+
paddingTop: "4px",
|
1940
|
+
paddingLeft: "7px",
|
1941
|
+
paddingRight: "7px",
|
1496
1942
|
variant,
|
1497
1943
|
children: [
|
1498
1944
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1503,36 +1949,35 @@ const DocumentActionsMenu = ({
|
|
1503
1949
|
]
|
1504
1950
|
}
|
1505
1951
|
),
|
1506
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1952
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1507
1953
|
actions2.map((action) => {
|
1508
1954
|
return /* @__PURE__ */ jsx(
|
1509
|
-
|
1955
|
+
MenuItem,
|
1510
1956
|
{
|
1511
1957
|
disabled: action.disabled,
|
1512
1958
|
onSelect: handleClick(action),
|
1513
1959
|
display: "block",
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
] })
|
1960
|
+
isVariantDanger: action.variant === "danger",
|
1961
|
+
isDisabled: action.disabled,
|
1962
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
|
1963
|
+
Flex,
|
1964
|
+
{
|
1965
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1966
|
+
gap: 2,
|
1967
|
+
tag: "span",
|
1968
|
+
children: [
|
1969
|
+
/* @__PURE__ */ jsx(
|
1970
|
+
Flex,
|
1971
|
+
{
|
1972
|
+
tag: "span",
|
1973
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1974
|
+
children: action.icon
|
1975
|
+
}
|
1976
|
+
),
|
1977
|
+
action.label
|
1978
|
+
]
|
1979
|
+
}
|
1980
|
+
) })
|
1536
1981
|
},
|
1537
1982
|
action.id
|
1538
1983
|
);
|
@@ -1612,11 +2057,11 @@ const DocumentActionConfirmDialog = ({
|
|
1612
2057
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1613
2058
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1614
2059
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1615
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2060
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1616
2061
|
id: "app.components.Button.cancel",
|
1617
2062
|
defaultMessage: "Cancel"
|
1618
2063
|
}) }) }),
|
1619
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2064
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1620
2065
|
id: "app.components.Button.confirm",
|
1621
2066
|
defaultMessage: "Confirm"
|
1622
2067
|
}) })
|
@@ -1639,10 +2084,22 @@ const DocumentActionModal = ({
|
|
1639
2084
|
};
|
1640
2085
|
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1641
2086
|
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1642
|
-
|
1643
|
-
|
2087
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2088
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1644
2089
|
] }) });
|
1645
2090
|
};
|
2091
|
+
const transformData = (data) => {
|
2092
|
+
if (Array.isArray(data)) {
|
2093
|
+
return data.map(transformData);
|
2094
|
+
}
|
2095
|
+
if (typeof data === "object" && data !== null) {
|
2096
|
+
if ("apiData" in data) {
|
2097
|
+
return data.apiData;
|
2098
|
+
}
|
2099
|
+
return mapValues(transformData)(data);
|
2100
|
+
}
|
2101
|
+
return data;
|
2102
|
+
};
|
1646
2103
|
const PublishAction$1 = ({
|
1647
2104
|
activeTab,
|
1648
2105
|
documentId,
|
@@ -1655,13 +2112,18 @@ const PublishAction$1 = ({
|
|
1655
2112
|
const navigate = useNavigate();
|
1656
2113
|
const { toggleNotification } = useNotification();
|
1657
2114
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2115
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1658
2116
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2117
|
+
const { id } = useParams();
|
1659
2118
|
const { formatMessage } = useIntl();
|
1660
|
-
const { canPublish
|
1661
|
-
"PublishAction",
|
1662
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1663
|
-
);
|
2119
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1664
2120
|
const { publish } = useDocumentActions();
|
2121
|
+
const [
|
2122
|
+
countDraftRelations,
|
2123
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2124
|
+
] = useLazyGetDraftRelationCountQuery();
|
2125
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2126
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1665
2127
|
const [{ query, rawQuery }] = useQueryParams();
|
1666
2128
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1667
2129
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1670,10 +2132,107 @@ const PublishAction$1 = ({
|
|
1670
2132
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1671
2133
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1672
2134
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1673
|
-
|
2135
|
+
React.useEffect(() => {
|
2136
|
+
if (isErrorDraftRelations) {
|
2137
|
+
toggleNotification({
|
2138
|
+
type: "danger",
|
2139
|
+
message: formatMessage({
|
2140
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2141
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2142
|
+
})
|
2143
|
+
});
|
2144
|
+
}
|
2145
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2146
|
+
React.useEffect(() => {
|
2147
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2148
|
+
const extractDraftRelations = (data) => {
|
2149
|
+
const relations = data.connect || [];
|
2150
|
+
relations.forEach((relation) => {
|
2151
|
+
if (relation.status === "draft") {
|
2152
|
+
localDraftRelations.add(relation.id);
|
2153
|
+
}
|
2154
|
+
});
|
2155
|
+
};
|
2156
|
+
const traverseAndExtract = (data) => {
|
2157
|
+
Object.entries(data).forEach(([key, value]) => {
|
2158
|
+
if (key === "connect" && Array.isArray(value)) {
|
2159
|
+
extractDraftRelations({ connect: value });
|
2160
|
+
} else if (typeof value === "object" && value !== null) {
|
2161
|
+
traverseAndExtract(value);
|
2162
|
+
}
|
2163
|
+
});
|
2164
|
+
};
|
2165
|
+
if (!documentId || modified) {
|
2166
|
+
traverseAndExtract(formValues);
|
2167
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2168
|
+
}
|
2169
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2170
|
+
React.useEffect(() => {
|
2171
|
+
if (!document || !document.documentId || isListView) {
|
2172
|
+
return;
|
2173
|
+
}
|
2174
|
+
const fetchDraftRelationsCount = async () => {
|
2175
|
+
const { data, error } = await countDraftRelations({
|
2176
|
+
collectionType,
|
2177
|
+
model,
|
2178
|
+
documentId,
|
2179
|
+
params
|
2180
|
+
});
|
2181
|
+
if (error) {
|
2182
|
+
throw error;
|
2183
|
+
}
|
2184
|
+
if (data) {
|
2185
|
+
setServerCountOfDraftRelations(data.data);
|
2186
|
+
}
|
2187
|
+
};
|
2188
|
+
fetchDraftRelationsCount();
|
2189
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2190
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1674
2191
|
if (!schema?.options?.draftAndPublish) {
|
1675
2192
|
return null;
|
1676
2193
|
}
|
2194
|
+
const performPublish = async () => {
|
2195
|
+
setSubmitting(true);
|
2196
|
+
try {
|
2197
|
+
const { errors } = await validate(true, {
|
2198
|
+
status: "published"
|
2199
|
+
});
|
2200
|
+
if (errors) {
|
2201
|
+
toggleNotification({
|
2202
|
+
type: "danger",
|
2203
|
+
message: formatMessage({
|
2204
|
+
id: "content-manager.validation.error",
|
2205
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2206
|
+
})
|
2207
|
+
});
|
2208
|
+
return;
|
2209
|
+
}
|
2210
|
+
const res = await publish(
|
2211
|
+
{
|
2212
|
+
collectionType,
|
2213
|
+
model,
|
2214
|
+
documentId,
|
2215
|
+
params
|
2216
|
+
},
|
2217
|
+
transformData(formValues)
|
2218
|
+
);
|
2219
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2220
|
+
if (id === "create") {
|
2221
|
+
navigate({
|
2222
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2223
|
+
search: rawQuery
|
2224
|
+
});
|
2225
|
+
}
|
2226
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2227
|
+
setErrors(formatValidationErrors(res.error));
|
2228
|
+
}
|
2229
|
+
} finally {
|
2230
|
+
setSubmitting(false);
|
2231
|
+
}
|
2232
|
+
};
|
2233
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2234
|
+
const enableDraftRelationsCount = false;
|
2235
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1677
2236
|
return {
|
1678
2237
|
/**
|
1679
2238
|
* Disabled when:
|
@@ -1683,52 +2242,40 @@ const PublishAction$1 = ({
|
|
1683
2242
|
* - the document is already published & not modified
|
1684
2243
|
* - the document is being created & not modified
|
1685
2244
|
* - the user doesn't have the permission to publish
|
1686
|
-
* - the user doesn't have the permission to create a new document
|
1687
|
-
* - the user doesn't have the permission to update the document
|
1688
2245
|
*/
|
1689
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2246
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1690
2247
|
label: formatMessage({
|
1691
2248
|
id: "app.utils.publish",
|
1692
2249
|
defaultMessage: "Publish"
|
1693
2250
|
}),
|
1694
2251
|
onClick: async () => {
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
documentId,
|
1713
|
-
params
|
1714
|
-
},
|
1715
|
-
formValues
|
1716
|
-
);
|
1717
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1718
|
-
navigate({
|
1719
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1720
|
-
search: rawQuery
|
1721
|
-
});
|
1722
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1723
|
-
setErrors(formatValidationErrors(res.error));
|
2252
|
+
await performPublish();
|
2253
|
+
},
|
2254
|
+
dialog: hasDraftRelations ? {
|
2255
|
+
type: "dialog",
|
2256
|
+
variant: "danger",
|
2257
|
+
footer: null,
|
2258
|
+
title: formatMessage({
|
2259
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2260
|
+
defaultMessage: "Confirmation"
|
2261
|
+
}),
|
2262
|
+
content: formatMessage(
|
2263
|
+
{
|
2264
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2265
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2266
|
+
},
|
2267
|
+
{
|
2268
|
+
count: totalDraftRelations
|
1724
2269
|
}
|
1725
|
-
|
1726
|
-
|
2270
|
+
),
|
2271
|
+
onConfirm: async () => {
|
2272
|
+
await performPublish();
|
1727
2273
|
}
|
1728
|
-
}
|
2274
|
+
} : void 0
|
1729
2275
|
};
|
1730
2276
|
};
|
1731
2277
|
PublishAction$1.type = "publish";
|
2278
|
+
PublishAction$1.position = "panel";
|
1732
2279
|
const UpdateAction = ({
|
1733
2280
|
activeTab,
|
1734
2281
|
documentId,
|
@@ -1741,10 +2288,6 @@ const UpdateAction = ({
|
|
1741
2288
|
const cloneMatch = useMatch(CLONE_PATH);
|
1742
2289
|
const isCloning = cloneMatch !== null;
|
1743
2290
|
const { formatMessage } = useIntl();
|
1744
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1745
|
-
canCreate: canCreate2,
|
1746
|
-
canUpdate: canUpdate2
|
1747
|
-
}));
|
1748
2291
|
const { create, update, clone } = useDocumentActions();
|
1749
2292
|
const [{ query, rawQuery }] = useQueryParams();
|
1750
2293
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1755,93 +2298,134 @@ const UpdateAction = ({
|
|
1755
2298
|
const validate = useForm("UpdateAction", (state) => state.validate);
|
1756
2299
|
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1757
2300
|
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1758
|
-
|
1759
|
-
|
1760
|
-
|
1761
|
-
|
1762
|
-
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
1767
|
-
|
1768
|
-
|
1769
|
-
|
1770
|
-
|
1771
|
-
|
1772
|
-
|
1773
|
-
|
1774
|
-
|
1775
|
-
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
}
|
1784
|
-
|
1785
|
-
|
1786
|
-
if (
|
1787
|
-
|
2301
|
+
const handleUpdate = React.useCallback(async () => {
|
2302
|
+
setSubmitting(true);
|
2303
|
+
try {
|
2304
|
+
if (!modified) {
|
2305
|
+
return;
|
2306
|
+
}
|
2307
|
+
const { errors } = await validate(true, {
|
2308
|
+
status: "draft"
|
2309
|
+
});
|
2310
|
+
if (errors) {
|
2311
|
+
toggleNotification({
|
2312
|
+
type: "danger",
|
2313
|
+
message: formatMessage({
|
2314
|
+
id: "content-manager.validation.error",
|
2315
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2316
|
+
})
|
2317
|
+
});
|
2318
|
+
return;
|
2319
|
+
}
|
2320
|
+
if (isCloning) {
|
2321
|
+
const res = await clone(
|
2322
|
+
{
|
2323
|
+
model,
|
2324
|
+
documentId: cloneMatch.params.origin,
|
2325
|
+
params
|
2326
|
+
},
|
2327
|
+
transformData(document)
|
2328
|
+
);
|
2329
|
+
if ("data" in res) {
|
2330
|
+
navigate(
|
1788
2331
|
{
|
1789
|
-
|
1790
|
-
documentId: cloneMatch.params.origin,
|
1791
|
-
params
|
1792
|
-
},
|
1793
|
-
document
|
1794
|
-
);
|
1795
|
-
if ("data" in res) {
|
1796
|
-
navigate({
|
1797
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2332
|
+
pathname: `../${res.data.documentId}`,
|
1798
2333
|
search: rawQuery
|
1799
|
-
});
|
1800
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1801
|
-
setErrors(formatValidationErrors(res.error));
|
1802
|
-
}
|
1803
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1804
|
-
const res = await update(
|
1805
|
-
{
|
1806
|
-
collectionType,
|
1807
|
-
model,
|
1808
|
-
documentId,
|
1809
|
-
params
|
1810
2334
|
},
|
1811
|
-
|
2335
|
+
{ relative: "path" }
|
1812
2336
|
);
|
1813
|
-
|
1814
|
-
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
2337
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2338
|
+
setErrors(formatValidationErrors(res.error));
|
2339
|
+
}
|
2340
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2341
|
+
const res = await update(
|
2342
|
+
{
|
2343
|
+
collectionType,
|
2344
|
+
model,
|
2345
|
+
documentId,
|
2346
|
+
params
|
2347
|
+
},
|
2348
|
+
transformData(document)
|
2349
|
+
);
|
2350
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2351
|
+
setErrors(formatValidationErrors(res.error));
|
1818
2352
|
} else {
|
1819
|
-
|
2353
|
+
resetForm();
|
2354
|
+
}
|
2355
|
+
} else {
|
2356
|
+
const res = await create(
|
2357
|
+
{
|
2358
|
+
model,
|
2359
|
+
params
|
2360
|
+
},
|
2361
|
+
transformData(document)
|
2362
|
+
);
|
2363
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2364
|
+
navigate(
|
1820
2365
|
{
|
1821
|
-
|
1822
|
-
|
2366
|
+
pathname: `../${res.data.documentId}`,
|
2367
|
+
search: rawQuery
|
1823
2368
|
},
|
1824
|
-
|
2369
|
+
{ replace: true, relative: "path" }
|
1825
2370
|
);
|
1826
|
-
|
1827
|
-
|
1828
|
-
{
|
1829
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1830
|
-
search: rawQuery
|
1831
|
-
},
|
1832
|
-
{ replace: true }
|
1833
|
-
);
|
1834
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1835
|
-
setErrors(formatValidationErrors(res.error));
|
1836
|
-
}
|
2371
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2372
|
+
setErrors(formatValidationErrors(res.error));
|
1837
2373
|
}
|
1838
|
-
} finally {
|
1839
|
-
setSubmitting(false);
|
1840
2374
|
}
|
2375
|
+
} finally {
|
2376
|
+
setSubmitting(false);
|
1841
2377
|
}
|
2378
|
+
}, [
|
2379
|
+
clone,
|
2380
|
+
cloneMatch?.params.origin,
|
2381
|
+
collectionType,
|
2382
|
+
create,
|
2383
|
+
document,
|
2384
|
+
documentId,
|
2385
|
+
formatMessage,
|
2386
|
+
formatValidationErrors,
|
2387
|
+
isCloning,
|
2388
|
+
model,
|
2389
|
+
modified,
|
2390
|
+
navigate,
|
2391
|
+
params,
|
2392
|
+
rawQuery,
|
2393
|
+
resetForm,
|
2394
|
+
setErrors,
|
2395
|
+
setSubmitting,
|
2396
|
+
toggleNotification,
|
2397
|
+
update,
|
2398
|
+
validate
|
2399
|
+
]);
|
2400
|
+
React.useEffect(() => {
|
2401
|
+
const handleKeyDown = (e) => {
|
2402
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
2403
|
+
e.preventDefault();
|
2404
|
+
handleUpdate();
|
2405
|
+
}
|
2406
|
+
};
|
2407
|
+
window.addEventListener("keydown", handleKeyDown);
|
2408
|
+
return () => {
|
2409
|
+
window.removeEventListener("keydown", handleKeyDown);
|
2410
|
+
};
|
2411
|
+
}, [handleUpdate]);
|
2412
|
+
return {
|
2413
|
+
/**
|
2414
|
+
* Disabled when:
|
2415
|
+
* - the form is submitting
|
2416
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2417
|
+
* - the active tab is the published tab
|
2418
|
+
*/
|
2419
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2420
|
+
label: formatMessage({
|
2421
|
+
id: "global.save",
|
2422
|
+
defaultMessage: "Save"
|
2423
|
+
}),
|
2424
|
+
onClick: handleUpdate
|
1842
2425
|
};
|
1843
2426
|
};
|
1844
2427
|
UpdateAction.type = "update";
|
2428
|
+
UpdateAction.position = "panel";
|
1845
2429
|
const UNPUBLISH_DRAFT_OPTIONS = {
|
1846
2430
|
KEEP: "keep",
|
1847
2431
|
DISCARD: "discard"
|
@@ -1874,7 +2458,7 @@ const UnpublishAction$1 = ({
|
|
1874
2458
|
id: "app.utils.unpublish",
|
1875
2459
|
defaultMessage: "Unpublish"
|
1876
2460
|
}),
|
1877
|
-
icon: /* @__PURE__ */ jsx(
|
2461
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1878
2462
|
onClick: async () => {
|
1879
2463
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1880
2464
|
if (!documentId) {
|
@@ -1964,6 +2548,7 @@ const UnpublishAction$1 = ({
|
|
1964
2548
|
};
|
1965
2549
|
};
|
1966
2550
|
UnpublishAction$1.type = "unpublish";
|
2551
|
+
UnpublishAction$1.position = "panel";
|
1967
2552
|
const DiscardAction = ({
|
1968
2553
|
activeTab,
|
1969
2554
|
documentId,
|
@@ -1986,7 +2571,7 @@ const DiscardAction = ({
|
|
1986
2571
|
id: "content-manager.actions.discard.label",
|
1987
2572
|
defaultMessage: "Discard changes"
|
1988
2573
|
}),
|
1989
|
-
icon: /* @__PURE__ */ jsx(
|
2574
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1990
2575
|
position: ["panel", "table-row"],
|
1991
2576
|
variant: "danger",
|
1992
2577
|
dialog: {
|
@@ -2014,11 +2599,7 @@ const DiscardAction = ({
|
|
2014
2599
|
};
|
2015
2600
|
};
|
2016
2601
|
DiscardAction.type = "discard";
|
2017
|
-
|
2018
|
-
path {
|
2019
|
-
fill: currentColor;
|
2020
|
-
}
|
2021
|
-
`;
|
2602
|
+
DiscardAction.position = "panel";
|
2022
2603
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2023
2604
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2024
2605
|
const RelativeTime = React.forwardRef(
|
@@ -2031,7 +2612,7 @@ const RelativeTime = React.forwardRef(
|
|
2031
2612
|
});
|
2032
2613
|
const unit = intervals.find((intervalUnit) => {
|
2033
2614
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2034
|
-
});
|
2615
|
+
}) ?? "seconds";
|
2035
2616
|
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2036
2617
|
const customInterval = customIntervals.find(
|
2037
2618
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2065,34 +2646,34 @@ const getDisplayName = ({
|
|
2065
2646
|
return email ?? "";
|
2066
2647
|
};
|
2067
2648
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2068
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2069
|
-
const statusVariant = status === "draft" ? "
|
2070
|
-
|
2649
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2650
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2651
|
+
const { formatMessage } = useIntl();
|
2652
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2653
|
+
id: `content-manager.containers.List.${status}`,
|
2654
|
+
defaultMessage: capitalise(status)
|
2655
|
+
}) }) });
|
2071
2656
|
};
|
2072
2657
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2073
2658
|
const { formatMessage } = useIntl();
|
2074
2659
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2660
|
+
const params = useParams();
|
2075
2661
|
const title = isCreating ? formatMessage({
|
2076
2662
|
id: "content-manager.containers.edit.title.new",
|
2077
2663
|
defaultMessage: "Create an entry"
|
2078
2664
|
}) : documentTitle;
|
2079
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2080
|
-
/* @__PURE__ */ jsx(
|
2081
|
-
|
2082
|
-
Flex,
|
2665
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2666
|
+
/* @__PURE__ */ jsx(
|
2667
|
+
BackButton,
|
2083
2668
|
{
|
2084
|
-
|
2085
|
-
justifyContent: "space-between",
|
2086
|
-
paddingTop: 1,
|
2087
|
-
gap: "80px",
|
2088
|
-
alignItems: "flex-start",
|
2089
|
-
children: [
|
2090
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2091
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2092
|
-
]
|
2669
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2093
2670
|
}
|
2094
2671
|
),
|
2095
|
-
|
2672
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2673
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2674
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2675
|
+
] }),
|
2676
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2096
2677
|
] });
|
2097
2678
|
};
|
2098
2679
|
const HeaderToolbar = () => {
|
@@ -2138,7 +2719,7 @@ const HeaderToolbar = () => {
|
|
2138
2719
|
meta: isCloning ? void 0 : meta,
|
2139
2720
|
collectionType
|
2140
2721
|
},
|
2141
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2722
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
|
2142
2723
|
children: (actions2) => {
|
2143
2724
|
const headerActions = actions2.filter((action) => {
|
2144
2725
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2175,12 +2756,12 @@ const Information = ({ activeTab }) => {
|
|
2175
2756
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2176
2757
|
label: formatMessage({
|
2177
2758
|
id: "content-manager.containers.edit.information.last-published.label",
|
2178
|
-
defaultMessage: "
|
2759
|
+
defaultMessage: "Published"
|
2179
2760
|
}),
|
2180
2761
|
value: formatMessage(
|
2181
2762
|
{
|
2182
2763
|
id: "content-manager.containers.edit.information.last-published.value",
|
2183
|
-
defaultMessage: `
|
2764
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2184
2765
|
},
|
2185
2766
|
{
|
2186
2767
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2193,12 +2774,12 @@ const Information = ({ activeTab }) => {
|
|
2193
2774
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2194
2775
|
label: formatMessage({
|
2195
2776
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2196
|
-
defaultMessage: "
|
2777
|
+
defaultMessage: "Updated"
|
2197
2778
|
}),
|
2198
2779
|
value: formatMessage(
|
2199
2780
|
{
|
2200
2781
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2201
|
-
defaultMessage: `
|
2782
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2202
2783
|
},
|
2203
2784
|
{
|
2204
2785
|
time: /* @__PURE__ */ jsx(
|
@@ -2216,12 +2797,12 @@ const Information = ({ activeTab }) => {
|
|
2216
2797
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2217
2798
|
label: formatMessage({
|
2218
2799
|
id: "content-manager.containers.edit.information.document.label",
|
2219
|
-
defaultMessage: "
|
2800
|
+
defaultMessage: "Created"
|
2220
2801
|
}),
|
2221
2802
|
value: formatMessage(
|
2222
2803
|
{
|
2223
2804
|
id: "content-manager.containers.edit.information.document.value",
|
2224
|
-
defaultMessage: `
|
2805
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2225
2806
|
},
|
2226
2807
|
{
|
2227
2808
|
time: /* @__PURE__ */ jsx(
|
@@ -2259,25 +2840,77 @@ const Information = ({ activeTab }) => {
|
|
2259
2840
|
);
|
2260
2841
|
};
|
2261
2842
|
const HeaderActions = ({ actions: actions2 }) => {
|
2262
|
-
|
2263
|
-
|
2843
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2844
|
+
const handleClick = (action) => async (e) => {
|
2845
|
+
if (!("options" in action)) {
|
2846
|
+
const { onClick = () => false, dialog, id } = action;
|
2847
|
+
const muteDialog = await onClick(e);
|
2848
|
+
if (dialog && !muteDialog) {
|
2849
|
+
e.preventDefault();
|
2850
|
+
setDialogId(id);
|
2851
|
+
}
|
2852
|
+
}
|
2853
|
+
};
|
2854
|
+
const handleClose = () => {
|
2855
|
+
setDialogId(null);
|
2856
|
+
};
|
2857
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2858
|
+
if (action.options) {
|
2264
2859
|
return /* @__PURE__ */ jsx(
|
2265
2860
|
SingleSelect,
|
2266
2861
|
{
|
2267
2862
|
size: "S",
|
2268
|
-
disabled: action.disabled,
|
2269
|
-
"aria-label": action.label,
|
2270
2863
|
onChange: action.onSelect,
|
2271
|
-
|
2864
|
+
"aria-label": action.label,
|
2865
|
+
...action,
|
2272
2866
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2273
2867
|
},
|
2274
2868
|
action.id
|
2275
2869
|
);
|
2276
2870
|
} else {
|
2277
|
-
|
2871
|
+
if (action.type === "icon") {
|
2872
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2873
|
+
/* @__PURE__ */ jsx(
|
2874
|
+
IconButton,
|
2875
|
+
{
|
2876
|
+
disabled: action.disabled,
|
2877
|
+
label: action.label,
|
2878
|
+
size: "S",
|
2879
|
+
onClick: handleClick(action),
|
2880
|
+
children: action.icon
|
2881
|
+
}
|
2882
|
+
),
|
2883
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2884
|
+
HeaderActionDialog,
|
2885
|
+
{
|
2886
|
+
...action.dialog,
|
2887
|
+
isOpen: dialogId === action.id,
|
2888
|
+
onClose: handleClose
|
2889
|
+
}
|
2890
|
+
) : null
|
2891
|
+
] }, action.id);
|
2892
|
+
}
|
2278
2893
|
}
|
2279
2894
|
}) });
|
2280
2895
|
};
|
2896
|
+
const HeaderActionDialog = ({
|
2897
|
+
onClose,
|
2898
|
+
onCancel,
|
2899
|
+
title,
|
2900
|
+
content: Content,
|
2901
|
+
isOpen
|
2902
|
+
}) => {
|
2903
|
+
const handleClose = async () => {
|
2904
|
+
if (onCancel) {
|
2905
|
+
await onCancel();
|
2906
|
+
}
|
2907
|
+
onClose();
|
2908
|
+
};
|
2909
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2910
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2911
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2912
|
+
] }) });
|
2913
|
+
};
|
2281
2914
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2282
2915
|
const navigate = useNavigate();
|
2283
2916
|
const { formatMessage } = useIntl();
|
@@ -2294,6 +2927,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2294
2927
|
};
|
2295
2928
|
};
|
2296
2929
|
ConfigureTheViewAction.type = "configure-the-view";
|
2930
|
+
ConfigureTheViewAction.position = "header";
|
2297
2931
|
const EditTheModelAction = ({ model }) => {
|
2298
2932
|
const navigate = useNavigate();
|
2299
2933
|
const { formatMessage } = useIntl();
|
@@ -2310,6 +2944,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2310
2944
|
};
|
2311
2945
|
};
|
2312
2946
|
EditTheModelAction.type = "edit-the-model";
|
2947
|
+
EditTheModelAction.position = "header";
|
2313
2948
|
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2314
2949
|
const navigate = useNavigate();
|
2315
2950
|
const { formatMessage } = useIntl();
|
@@ -2318,12 +2953,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2318
2953
|
const { delete: deleteAction } = useDocumentActions();
|
2319
2954
|
const { toggleNotification } = useNotification();
|
2320
2955
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2956
|
+
const isLocalized = document?.locale != null;
|
2321
2957
|
return {
|
2322
2958
|
disabled: !canDelete || !document,
|
2323
|
-
label: formatMessage(
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2959
|
+
label: formatMessage(
|
2960
|
+
{
|
2961
|
+
id: "content-manager.actions.delete.label",
|
2962
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2963
|
+
},
|
2964
|
+
{ isLocalized }
|
2965
|
+
),
|
2327
2966
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2328
2967
|
dialog: {
|
2329
2968
|
type: "dialog",
|
@@ -2379,403 +3018,102 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2379
3018
|
};
|
2380
3019
|
};
|
2381
3020
|
DeleteAction$1.type = "delete";
|
3021
|
+
DeleteAction$1.position = ["header", "table-row"];
|
2382
3022
|
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2383
3023
|
const Panels = () => {
|
2384
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2385
|
-
const [
|
2386
|
-
{
|
2387
|
-
query: { status }
|
2388
|
-
}
|
2389
|
-
] = useQueryParams({
|
2390
|
-
status: "draft"
|
2391
|
-
});
|
2392
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2393
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2394
|
-
const props = {
|
2395
|
-
activeTab: status,
|
2396
|
-
model,
|
2397
|
-
documentId: id,
|
2398
|
-
document: isCloning ? void 0 : document,
|
2399
|
-
meta: isCloning ? void 0 : meta,
|
2400
|
-
collectionType
|
2401
|
-
};
|
2402
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2403
|
-
DescriptionComponentRenderer,
|
2404
|
-
{
|
2405
|
-
props,
|
2406
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2407
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2408
|
-
}
|
2409
|
-
) });
|
2410
|
-
};
|
2411
|
-
const ActionsPanel = () => {
|
2412
|
-
const { formatMessage } = useIntl();
|
2413
|
-
return {
|
2414
|
-
title: formatMessage({
|
2415
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2416
|
-
defaultMessage: "Document"
|
2417
|
-
}),
|
2418
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2419
|
-
};
|
2420
|
-
};
|
2421
|
-
ActionsPanel.type = "actions";
|
2422
|
-
const ActionsPanelContent = () => {
|
2423
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2424
|
-
const [
|
2425
|
-
{
|
2426
|
-
query: { status = "draft" }
|
2427
|
-
}
|
2428
|
-
] = useQueryParams();
|
2429
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2430
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2431
|
-
const props = {
|
2432
|
-
activeTab: status,
|
2433
|
-
model,
|
2434
|
-
documentId: id,
|
2435
|
-
document: isCloning ? void 0 : document,
|
2436
|
-
meta: isCloning ? void 0 : meta,
|
2437
|
-
collectionType
|
2438
|
-
};
|
2439
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2440
|
-
/* @__PURE__ */ jsx(
|
2441
|
-
DescriptionComponentRenderer,
|
2442
|
-
{
|
2443
|
-
props,
|
2444
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2445
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2446
|
-
}
|
2447
|
-
),
|
2448
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2449
|
-
] });
|
2450
|
-
};
|
2451
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2452
|
-
return /* @__PURE__ */ jsxs(
|
2453
|
-
Flex,
|
2454
|
-
{
|
2455
|
-
ref,
|
2456
|
-
tag: "aside",
|
2457
|
-
"aria-labelledby": "additional-information",
|
2458
|
-
background: "neutral0",
|
2459
|
-
borderColor: "neutral150",
|
2460
|
-
hasRadius: true,
|
2461
|
-
paddingBottom: 4,
|
2462
|
-
paddingLeft: 4,
|
2463
|
-
paddingRight: 4,
|
2464
|
-
paddingTop: 4,
|
2465
|
-
shadow: "tableShadow",
|
2466
|
-
gap: 3,
|
2467
|
-
direction: "column",
|
2468
|
-
justifyContent: "stretch",
|
2469
|
-
alignItems: "flex-start",
|
2470
|
-
children: [
|
2471
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2472
|
-
children
|
2473
|
-
]
|
2474
|
-
}
|
2475
|
-
);
|
2476
|
-
});
|
2477
|
-
const HOOKS = {
|
2478
|
-
/**
|
2479
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2480
|
-
* @constant
|
2481
|
-
* @type {string}
|
2482
|
-
*/
|
2483
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2484
|
-
/**
|
2485
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2486
|
-
* @constant
|
2487
|
-
* @type {string}
|
2488
|
-
*/
|
2489
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2490
|
-
/**
|
2491
|
-
* Hook that allows to mutate the CM's edit view layout
|
2492
|
-
* @constant
|
2493
|
-
* @type {string}
|
2494
|
-
*/
|
2495
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2496
|
-
/**
|
2497
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2498
|
-
* @constant
|
2499
|
-
* @type {string}
|
2500
|
-
*/
|
2501
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2502
|
-
};
|
2503
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2504
|
-
endpoints: (builder) => ({
|
2505
|
-
getContentTypeConfiguration: builder.query({
|
2506
|
-
query: (uid) => ({
|
2507
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2508
|
-
method: "GET"
|
2509
|
-
}),
|
2510
|
-
transformResponse: (response) => response.data,
|
2511
|
-
providesTags: (_result, _error, uid) => [
|
2512
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2513
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2514
|
-
]
|
2515
|
-
}),
|
2516
|
-
getAllContentTypeSettings: builder.query({
|
2517
|
-
query: () => "/content-manager/content-types-settings",
|
2518
|
-
transformResponse: (response) => response.data,
|
2519
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2520
|
-
}),
|
2521
|
-
updateContentTypeConfiguration: builder.mutation({
|
2522
|
-
query: ({ uid, ...body }) => ({
|
2523
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2524
|
-
method: "PUT",
|
2525
|
-
data: body
|
2526
|
-
}),
|
2527
|
-
transformResponse: (response) => response.data,
|
2528
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2529
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2530
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2531
|
-
// Is this necessary?
|
2532
|
-
{ type: "InitialData" }
|
2533
|
-
]
|
2534
|
-
})
|
2535
|
-
})
|
2536
|
-
});
|
2537
|
-
const {
|
2538
|
-
useGetContentTypeConfigurationQuery,
|
2539
|
-
useGetAllContentTypeSettingsQuery,
|
2540
|
-
useUpdateContentTypeConfigurationMutation
|
2541
|
-
} = contentTypesApi;
|
2542
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2543
|
-
const { type } = attribute;
|
2544
|
-
if (type === "relation") {
|
2545
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2546
|
-
}
|
2547
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2548
|
-
};
|
2549
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2550
|
-
if (!mainFieldName) {
|
2551
|
-
return void 0;
|
2552
|
-
}
|
2553
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2554
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2555
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2556
|
-
);
|
2557
|
-
return {
|
2558
|
-
name: mainFieldName,
|
2559
|
-
type: mainFieldType ?? "string"
|
2560
|
-
};
|
2561
|
-
};
|
2562
|
-
const DEFAULT_SETTINGS = {
|
2563
|
-
bulkable: false,
|
2564
|
-
filterable: false,
|
2565
|
-
searchable: false,
|
2566
|
-
pagination: false,
|
2567
|
-
defaultSortBy: "",
|
2568
|
-
defaultSortOrder: "asc",
|
2569
|
-
mainField: "id",
|
2570
|
-
pageSize: 10
|
2571
|
-
};
|
2572
|
-
const useDocumentLayout = (model) => {
|
2573
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2574
|
-
const [{ query }] = useQueryParams();
|
2575
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2576
|
-
const { toggleNotification } = useNotification();
|
2577
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2578
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2579
|
-
const {
|
2580
|
-
data,
|
2581
|
-
isLoading: isLoadingConfigs,
|
2582
|
-
error,
|
2583
|
-
isFetching: isFetchingConfigs
|
2584
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2585
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2586
|
-
React.useEffect(() => {
|
2587
|
-
if (error) {
|
2588
|
-
toggleNotification({
|
2589
|
-
type: "danger",
|
2590
|
-
message: formatAPIError(error)
|
2591
|
-
});
|
2592
|
-
}
|
2593
|
-
}, [error, formatAPIError, toggleNotification]);
|
2594
|
-
const editLayout = React.useMemo(
|
2595
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2596
|
-
layout: [],
|
2597
|
-
components: {},
|
2598
|
-
metadatas: {},
|
2599
|
-
options: {},
|
2600
|
-
settings: DEFAULT_SETTINGS
|
2601
|
-
},
|
2602
|
-
[data, isLoading, schemas, schema, components]
|
2603
|
-
);
|
2604
|
-
const listLayout = React.useMemo(() => {
|
2605
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2606
|
-
layout: [],
|
2607
|
-
metadatas: {},
|
2608
|
-
options: {},
|
2609
|
-
settings: DEFAULT_SETTINGS
|
2610
|
-
};
|
2611
|
-
}, [data, isLoading, schemas, schema, components]);
|
2612
|
-
const { layout: edit } = React.useMemo(
|
2613
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2614
|
-
layout: editLayout,
|
2615
|
-
query
|
2616
|
-
}),
|
2617
|
-
[editLayout, query, runHookWaterfall]
|
2618
|
-
);
|
2619
|
-
return {
|
2620
|
-
error,
|
2621
|
-
isLoading,
|
2622
|
-
edit,
|
2623
|
-
list: listLayout
|
2624
|
-
};
|
2625
|
-
};
|
2626
|
-
const useDocLayout = () => {
|
2627
|
-
const { model } = useDoc();
|
2628
|
-
return useDocumentLayout(model);
|
2629
|
-
};
|
2630
|
-
const formatEditLayout = (data, {
|
2631
|
-
schemas,
|
2632
|
-
schema,
|
2633
|
-
components
|
2634
|
-
}) => {
|
2635
|
-
let currentPanelIndex = 0;
|
2636
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2637
|
-
data.contentType.layouts.edit,
|
2638
|
-
schema?.attributes,
|
2639
|
-
data.contentType.metadatas,
|
2640
|
-
{ configurations: data.components, schemas: components },
|
2641
|
-
schemas
|
2642
|
-
).reduce((panels, row) => {
|
2643
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2644
|
-
panels.push([row]);
|
2645
|
-
currentPanelIndex += 2;
|
2646
|
-
} else {
|
2647
|
-
if (!panels[currentPanelIndex]) {
|
2648
|
-
panels.push([]);
|
2649
|
-
}
|
2650
|
-
panels[currentPanelIndex].push(row);
|
2651
|
-
}
|
2652
|
-
return panels;
|
2653
|
-
}, []);
|
2654
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2655
|
-
(acc, [uid, configuration]) => {
|
2656
|
-
acc[uid] = {
|
2657
|
-
layout: convertEditLayoutToFieldLayouts(
|
2658
|
-
configuration.layouts.edit,
|
2659
|
-
components[uid].attributes,
|
2660
|
-
configuration.metadatas
|
2661
|
-
),
|
2662
|
-
settings: {
|
2663
|
-
...configuration.settings,
|
2664
|
-
icon: components[uid].info.icon,
|
2665
|
-
displayName: components[uid].info.displayName
|
2666
|
-
}
|
2667
|
-
};
|
2668
|
-
return acc;
|
2669
|
-
},
|
2670
|
-
{}
|
2671
|
-
);
|
2672
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2673
|
-
(acc, [attribute, metadata]) => {
|
2674
|
-
return {
|
2675
|
-
...acc,
|
2676
|
-
[attribute]: metadata.edit
|
2677
|
-
};
|
2678
|
-
},
|
2679
|
-
{}
|
2680
|
-
);
|
2681
|
-
return {
|
2682
|
-
layout: panelledEditAttributes,
|
2683
|
-
components: componentEditAttributes,
|
2684
|
-
metadatas: editMetadatas,
|
2685
|
-
settings: {
|
2686
|
-
...data.contentType.settings,
|
2687
|
-
displayName: schema?.info.displayName
|
2688
|
-
},
|
2689
|
-
options: {
|
2690
|
-
...schema?.options,
|
2691
|
-
...schema?.pluginOptions,
|
2692
|
-
...data.contentType.options
|
3024
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
3025
|
+
const [
|
3026
|
+
{
|
3027
|
+
query: { status }
|
2693
3028
|
}
|
3029
|
+
] = useQueryParams({
|
3030
|
+
status: "draft"
|
3031
|
+
});
|
3032
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3033
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
3034
|
+
const props = {
|
3035
|
+
activeTab: status,
|
3036
|
+
model,
|
3037
|
+
documentId: id,
|
3038
|
+
document: isCloning ? void 0 : document,
|
3039
|
+
meta: isCloning ? void 0 : meta,
|
3040
|
+
collectionType
|
2694
3041
|
};
|
3042
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
3043
|
+
DescriptionComponentRenderer,
|
3044
|
+
{
|
3045
|
+
props,
|
3046
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
3047
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
3048
|
+
}
|
3049
|
+
) });
|
2695
3050
|
};
|
2696
|
-
const
|
2697
|
-
|
2698
|
-
(row) => row.map((field) => {
|
2699
|
-
const attribute = attributes[field.name];
|
2700
|
-
if (!attribute) {
|
2701
|
-
return null;
|
2702
|
-
}
|
2703
|
-
const { edit: metadata } = metadatas[field.name];
|
2704
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2705
|
-
return {
|
2706
|
-
attribute,
|
2707
|
-
disabled: !metadata.editable,
|
2708
|
-
hint: metadata.description,
|
2709
|
-
label: metadata.label ?? "",
|
2710
|
-
name: field.name,
|
2711
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2712
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2713
|
-
schemas,
|
2714
|
-
components: components?.schemas ?? {}
|
2715
|
-
}),
|
2716
|
-
placeholder: metadata.placeholder ?? "",
|
2717
|
-
required: attribute.required ?? false,
|
2718
|
-
size: field.size,
|
2719
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2720
|
-
visible: metadata.visible ?? true,
|
2721
|
-
type: attribute.type
|
2722
|
-
};
|
2723
|
-
}).filter((field) => field !== null)
|
2724
|
-
);
|
2725
|
-
};
|
2726
|
-
const formatListLayout = (data, {
|
2727
|
-
schemas,
|
2728
|
-
schema,
|
2729
|
-
components
|
2730
|
-
}) => {
|
2731
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2732
|
-
(acc, [attribute, metadata]) => {
|
2733
|
-
return {
|
2734
|
-
...acc,
|
2735
|
-
[attribute]: metadata.list
|
2736
|
-
};
|
2737
|
-
},
|
2738
|
-
{}
|
2739
|
-
);
|
2740
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2741
|
-
data.contentType.layouts.list,
|
2742
|
-
schema?.attributes,
|
2743
|
-
listMetadatas,
|
2744
|
-
{ configurations: data.components, schemas: components },
|
2745
|
-
schemas
|
2746
|
-
);
|
3051
|
+
const ActionsPanel = () => {
|
3052
|
+
const { formatMessage } = useIntl();
|
2747
3053
|
return {
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
...schema?.pluginOptions,
|
2754
|
-
...data.contentType.options
|
2755
|
-
}
|
3054
|
+
title: formatMessage({
|
3055
|
+
id: "content-manager.containers.edit.panels.default.title",
|
3056
|
+
defaultMessage: "Entry"
|
3057
|
+
}),
|
3058
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2756
3059
|
};
|
2757
3060
|
};
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
3061
|
+
ActionsPanel.type = "actions";
|
3062
|
+
const ActionsPanelContent = () => {
|
3063
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
3064
|
+
const [
|
3065
|
+
{
|
3066
|
+
query: { status = "draft" }
|
2763
3067
|
}
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
3068
|
+
] = useQueryParams();
|
3069
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3070
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
3071
|
+
const props = {
|
3072
|
+
activeTab: status,
|
3073
|
+
model,
|
3074
|
+
documentId: id,
|
3075
|
+
document: isCloning ? void 0 : document,
|
3076
|
+
meta: isCloning ? void 0 : meta,
|
3077
|
+
collectionType
|
3078
|
+
};
|
3079
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3080
|
+
/* @__PURE__ */ jsx(
|
3081
|
+
DescriptionComponentRenderer,
|
3082
|
+
{
|
3083
|
+
props,
|
3084
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
|
3085
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
3086
|
+
}
|
3087
|
+
),
|
3088
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3089
|
+
] });
|
2778
3090
|
};
|
3091
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
3092
|
+
return /* @__PURE__ */ jsxs(
|
3093
|
+
Flex,
|
3094
|
+
{
|
3095
|
+
ref,
|
3096
|
+
tag: "aside",
|
3097
|
+
"aria-labelledby": "additional-information",
|
3098
|
+
background: "neutral0",
|
3099
|
+
borderColor: "neutral150",
|
3100
|
+
hasRadius: true,
|
3101
|
+
paddingBottom: 4,
|
3102
|
+
paddingLeft: 4,
|
3103
|
+
paddingRight: 4,
|
3104
|
+
paddingTop: 4,
|
3105
|
+
shadow: "tableShadow",
|
3106
|
+
gap: 3,
|
3107
|
+
direction: "column",
|
3108
|
+
justifyContent: "stretch",
|
3109
|
+
alignItems: "flex-start",
|
3110
|
+
children: [
|
3111
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
3112
|
+
children
|
3113
|
+
]
|
3114
|
+
}
|
3115
|
+
);
|
3116
|
+
});
|
2779
3117
|
const ConfirmBulkActionDialog = ({
|
2780
3118
|
onToggleDialog,
|
2781
3119
|
isOpen = false,
|
@@ -2783,7 +3121,7 @@ const ConfirmBulkActionDialog = ({
|
|
2783
3121
|
endAction
|
2784
3122
|
}) => {
|
2785
3123
|
const { formatMessage } = useIntl();
|
2786
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3124
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2787
3125
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2788
3126
|
id: "app.components.ConfirmDialog.title",
|
2789
3127
|
defaultMessage: "Confirmation"
|
@@ -2814,6 +3152,7 @@ const ConfirmDialogPublishAll = ({
|
|
2814
3152
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2815
3153
|
const { model, schema } = useDoc();
|
2816
3154
|
const [{ query }] = useQueryParams();
|
3155
|
+
const enableDraftRelationsCount = false;
|
2817
3156
|
const {
|
2818
3157
|
data: countDraftRelations = 0,
|
2819
3158
|
isLoading,
|
@@ -2825,7 +3164,7 @@ const ConfirmDialogPublishAll = ({
|
|
2825
3164
|
locale: query?.plugins?.i18n?.locale
|
2826
3165
|
},
|
2827
3166
|
{
|
2828
|
-
skip:
|
3167
|
+
skip: !enableDraftRelationsCount
|
2829
3168
|
}
|
2830
3169
|
);
|
2831
3170
|
React.useEffect(() => {
|
@@ -3010,7 +3349,7 @@ const SelectedEntriesTableContent = ({
|
|
3010
3349
|
status: row.status
|
3011
3350
|
}
|
3012
3351
|
) }),
|
3013
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3352
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3014
3353
|
IconButton,
|
3015
3354
|
{
|
3016
3355
|
tag: Link,
|
@@ -3019,23 +3358,16 @@ const SelectedEntriesTableContent = ({
|
|
3019
3358
|
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3020
3359
|
},
|
3021
3360
|
state: { from: pathname },
|
3022
|
-
label: formatMessage(
|
3023
|
-
|
3024
|
-
|
3025
|
-
|
3026
|
-
{
|
3027
|
-
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3028
|
-
defaultMessage: "item line {number}"
|
3029
|
-
},
|
3030
|
-
{ number: index2 + 1 }
|
3031
|
-
)
|
3032
|
-
}
|
3033
|
-
),
|
3361
|
+
label: formatMessage({
|
3362
|
+
id: "content-manager.bulk-publish.edit",
|
3363
|
+
defaultMessage: "Edit"
|
3364
|
+
}),
|
3034
3365
|
target: "_blank",
|
3035
3366
|
marginLeft: "auto",
|
3036
|
-
|
3367
|
+
variant: "ghost",
|
3368
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3037
3369
|
}
|
3038
|
-
) })
|
3370
|
+
) }) })
|
3039
3371
|
] }, row.id)) })
|
3040
3372
|
] });
|
3041
3373
|
};
|
@@ -3072,7 +3404,13 @@ const SelectedEntriesModalContent = ({
|
|
3072
3404
|
);
|
3073
3405
|
const { rows, validationErrors } = React.useMemo(() => {
|
3074
3406
|
if (data.length > 0 && schema) {
|
3075
|
-
const validate = createYupSchema(
|
3407
|
+
const validate = createYupSchema(
|
3408
|
+
schema.attributes,
|
3409
|
+
components,
|
3410
|
+
// Since this is the "Publish" action, the validation
|
3411
|
+
// schema must enforce the rules for published entities
|
3412
|
+
{ status: "published" }
|
3413
|
+
);
|
3076
3414
|
const validationErrors2 = {};
|
3077
3415
|
const rows2 = data.map((entry) => {
|
3078
3416
|
try {
|
@@ -3197,8 +3535,7 @@ const PublishAction = ({ documents, model }) => {
|
|
3197
3535
|
const refetchList = () => {
|
3198
3536
|
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3199
3537
|
};
|
3200
|
-
if (!showPublishButton)
|
3201
|
-
return null;
|
3538
|
+
if (!showPublishButton) return null;
|
3202
3539
|
return {
|
3203
3540
|
actionType: "publish",
|
3204
3541
|
variant: "tertiary",
|
@@ -3266,8 +3603,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
3266
3603
|
selectRow([]);
|
3267
3604
|
}
|
3268
3605
|
};
|
3269
|
-
if (!hasDeletePermission)
|
3270
|
-
return null;
|
3606
|
+
if (!hasDeletePermission) return null;
|
3271
3607
|
return {
|
3272
3608
|
variant: "danger-light",
|
3273
3609
|
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
@@ -3316,8 +3652,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3316
3652
|
}
|
3317
3653
|
};
|
3318
3654
|
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3319
|
-
if (!showUnpublishButton)
|
3320
|
-
return null;
|
3655
|
+
if (!showUnpublishButton) return null;
|
3321
3656
|
return {
|
3322
3657
|
variant: "tertiary",
|
3323
3658
|
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
@@ -3422,7 +3757,7 @@ const TableActions = ({ document }) => {
|
|
3422
3757
|
DescriptionComponentRenderer,
|
3423
3758
|
{
|
3424
3759
|
props,
|
3425
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3760
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
|
3426
3761
|
children: (actions2) => {
|
3427
3762
|
const tableRowActions = actions2.filter((action) => {
|
3428
3763
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3481,6 +3816,7 @@ const EditAction = ({ documentId }) => {
|
|
3481
3816
|
};
|
3482
3817
|
};
|
3483
3818
|
EditAction.type = "edit";
|
3819
|
+
EditAction.position = "table-row";
|
3484
3820
|
const StyledPencil = styled(Pencil)`
|
3485
3821
|
path {
|
3486
3822
|
fill: currentColor;
|
@@ -3533,7 +3869,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3533
3869
|
}),
|
3534
3870
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3535
3871
|
footer: ({ onClose }) => {
|
3536
|
-
return /* @__PURE__ */ jsxs(
|
3872
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3537
3873
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3538
3874
|
id: "cancel",
|
3539
3875
|
defaultMessage: "Cancel"
|
@@ -3557,6 +3893,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3557
3893
|
};
|
3558
3894
|
};
|
3559
3895
|
CloneAction.type = "clone";
|
3896
|
+
CloneAction.position = "table-row";
|
3560
3897
|
const StyledDuplicate = styled(Duplicate)`
|
3561
3898
|
path {
|
3562
3899
|
fill: currentColor;
|
@@ -3574,8 +3911,7 @@ class ContentManagerPlugin {
|
|
3574
3911
|
documentActions = [
|
3575
3912
|
...DEFAULT_ACTIONS,
|
3576
3913
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3577
|
-
...DEFAULT_HEADER_ACTIONS
|
3578
|
-
HistoryAction
|
3914
|
+
...DEFAULT_HEADER_ACTIONS
|
3579
3915
|
];
|
3580
3916
|
editViewSidePanels = [ActionsPanel];
|
3581
3917
|
headerActions = [];
|
@@ -3644,7 +3980,14 @@ class ContentManagerPlugin {
|
|
3644
3980
|
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
3645
3981
|
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
3646
3982
|
getBulkActions: () => this.bulkActions,
|
3647
|
-
getDocumentActions: () =>
|
3983
|
+
getDocumentActions: (position) => {
|
3984
|
+
if (position) {
|
3985
|
+
return this.documentActions.filter(
|
3986
|
+
(action) => action.position == void 0 || [action.position].flat().includes(position)
|
3987
|
+
);
|
3988
|
+
}
|
3989
|
+
return this.documentActions;
|
3990
|
+
},
|
3648
3991
|
getEditViewSidePanels: () => this.editViewSidePanels,
|
3649
3992
|
getHeaderActions: () => this.headerActions
|
3650
3993
|
}
|
@@ -3654,16 +3997,71 @@ class ContentManagerPlugin {
|
|
3654
3997
|
const getPrintableType = (value) => {
|
3655
3998
|
const nativeType = typeof value;
|
3656
3999
|
if (nativeType === "object") {
|
3657
|
-
if (value === null)
|
3658
|
-
|
3659
|
-
if (Array.isArray(value))
|
3660
|
-
return "array";
|
4000
|
+
if (value === null) return "null";
|
4001
|
+
if (Array.isArray(value)) return "array";
|
3661
4002
|
if (value instanceof Object && value.constructor.name !== "Object") {
|
3662
4003
|
return value.constructor.name;
|
3663
4004
|
}
|
3664
4005
|
}
|
3665
4006
|
return nativeType;
|
3666
4007
|
};
|
4008
|
+
const HistoryAction = ({ model, document }) => {
|
4009
|
+
const { formatMessage } = useIntl();
|
4010
|
+
const [{ query }] = useQueryParams();
|
4011
|
+
const navigate = useNavigate();
|
4012
|
+
const { trackUsage } = useTracking();
|
4013
|
+
const { pathname } = useLocation();
|
4014
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
4015
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
4016
|
+
return null;
|
4017
|
+
}
|
4018
|
+
const handleOnClick = () => {
|
4019
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
4020
|
+
trackUsage("willNavigate", {
|
4021
|
+
from: pathname,
|
4022
|
+
to: `${pathname}/${destination.pathname}`
|
4023
|
+
});
|
4024
|
+
navigate(destination);
|
4025
|
+
};
|
4026
|
+
return {
|
4027
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
4028
|
+
label: formatMessage({
|
4029
|
+
id: "content-manager.history.document-action",
|
4030
|
+
defaultMessage: "Content History"
|
4031
|
+
}),
|
4032
|
+
onClick: handleOnClick,
|
4033
|
+
disabled: (
|
4034
|
+
/**
|
4035
|
+
* The user is creating a new document.
|
4036
|
+
* It hasn't been saved yet, so there's no history to go to
|
4037
|
+
*/
|
4038
|
+
!document || /**
|
4039
|
+
* The document has been created but the current dimension has never been saved.
|
4040
|
+
* For example, the user is creating a new locale in an existing document,
|
4041
|
+
* so there's no history for the document in that locale
|
4042
|
+
*/
|
4043
|
+
!document.id || /**
|
4044
|
+
* History is only available for content types created by the user.
|
4045
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
4046
|
+
* which start with `admin::` or `plugin::`
|
4047
|
+
*/
|
4048
|
+
!model.startsWith("api::")
|
4049
|
+
),
|
4050
|
+
position: "header"
|
4051
|
+
};
|
4052
|
+
};
|
4053
|
+
HistoryAction.type = "history";
|
4054
|
+
HistoryAction.position = "header";
|
4055
|
+
const historyAdmin = {
|
4056
|
+
bootstrap(app) {
|
4057
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
4058
|
+
addDocumentAction((actions2) => {
|
4059
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
4060
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
4061
|
+
return actions2;
|
4062
|
+
});
|
4063
|
+
}
|
4064
|
+
};
|
3667
4065
|
const initialState = {
|
3668
4066
|
collectionTypeLinks: [],
|
3669
4067
|
components: [],
|
@@ -3700,6 +4098,88 @@ const { setInitialData } = actions;
|
|
3700
4098
|
const reducer = combineReducers({
|
3701
4099
|
app: reducer$1
|
3702
4100
|
});
|
4101
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
4102
|
+
endpoints: (builder) => ({
|
4103
|
+
getPreviewUrl: builder.query({
|
4104
|
+
query({ query, params }) {
|
4105
|
+
return {
|
4106
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4107
|
+
method: "GET",
|
4108
|
+
config: {
|
4109
|
+
params: query
|
4110
|
+
}
|
4111
|
+
};
|
4112
|
+
}
|
4113
|
+
})
|
4114
|
+
})
|
4115
|
+
});
|
4116
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4117
|
+
const ConditionalTooltip = ({ isShown, label, children }) => {
|
4118
|
+
if (isShown) {
|
4119
|
+
return /* @__PURE__ */ jsx(Tooltip, { label, children });
|
4120
|
+
}
|
4121
|
+
return children;
|
4122
|
+
};
|
4123
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4124
|
+
const { formatMessage } = useIntl();
|
4125
|
+
const { trackUsage } = useTracking();
|
4126
|
+
const { pathname } = useLocation();
|
4127
|
+
const [{ query }] = useQueryParams();
|
4128
|
+
const isModified = useForm("PreviewSidePanel", (state) => state.modified);
|
4129
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4130
|
+
params: {
|
4131
|
+
contentType: model
|
4132
|
+
},
|
4133
|
+
query: {
|
4134
|
+
documentId,
|
4135
|
+
locale: document?.locale,
|
4136
|
+
status: document?.status
|
4137
|
+
}
|
4138
|
+
});
|
4139
|
+
if (!data?.data?.url || error) {
|
4140
|
+
return null;
|
4141
|
+
}
|
4142
|
+
const trackNavigation = () => {
|
4143
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4144
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
4145
|
+
};
|
4146
|
+
return {
|
4147
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4148
|
+
content: /* @__PURE__ */ jsx(
|
4149
|
+
ConditionalTooltip,
|
4150
|
+
{
|
4151
|
+
label: formatMessage({
|
4152
|
+
id: "content-manager.preview.panel.button-disabled-tooltip",
|
4153
|
+
defaultMessage: "Please save to open the preview"
|
4154
|
+
}),
|
4155
|
+
isShown: isModified,
|
4156
|
+
children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
|
4157
|
+
Button,
|
4158
|
+
{
|
4159
|
+
variant: "tertiary",
|
4160
|
+
tag: Link,
|
4161
|
+
to: { pathname: "preview", search: stringify(query, { encode: false }) },
|
4162
|
+
onClick: trackNavigation,
|
4163
|
+
width: "100%",
|
4164
|
+
disabled: isModified,
|
4165
|
+
pointerEvents: isModified ? "none" : void 0,
|
4166
|
+
tabIndex: isModified ? -1 : void 0,
|
4167
|
+
children: formatMessage({
|
4168
|
+
id: "content-manager.preview.panel.button",
|
4169
|
+
defaultMessage: "Open preview"
|
4170
|
+
})
|
4171
|
+
}
|
4172
|
+
) })
|
4173
|
+
}
|
4174
|
+
)
|
4175
|
+
};
|
4176
|
+
};
|
4177
|
+
const previewAdmin = {
|
4178
|
+
bootstrap(app) {
|
4179
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4180
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4181
|
+
}
|
4182
|
+
};
|
3703
4183
|
const index = {
|
3704
4184
|
register(app) {
|
3705
4185
|
const cm = new ContentManagerPlugin();
|
@@ -3719,7 +4199,7 @@ const index = {
|
|
3719
4199
|
app.router.addRoute({
|
3720
4200
|
path: "content-manager/*",
|
3721
4201
|
lazy: async () => {
|
3722
|
-
const { Layout } = await import("./layout-
|
4202
|
+
const { Layout } = await import("./layout-COzAvgJh.mjs");
|
3723
4203
|
return {
|
3724
4204
|
Component: Layout
|
3725
4205
|
};
|
@@ -3728,10 +4208,18 @@ const index = {
|
|
3728
4208
|
});
|
3729
4209
|
app.registerPlugin(cm.config);
|
3730
4210
|
},
|
4211
|
+
bootstrap(app) {
|
4212
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4213
|
+
historyAdmin.bootstrap(app);
|
4214
|
+
}
|
4215
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4216
|
+
previewAdmin.bootstrap(app);
|
4217
|
+
}
|
4218
|
+
},
|
3731
4219
|
async registerTrads({ locales }) {
|
3732
4220
|
const importedTrads = await Promise.all(
|
3733
4221
|
locales.map((locale) => {
|
3734
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-
|
4222
|
+
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-CSxLmrh1.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-BHqhDq4V.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
|
3735
4223
|
return {
|
3736
4224
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3737
4225
|
locale
|
@@ -3752,13 +4240,16 @@ export {
|
|
3752
4240
|
BulkActionsRenderer as B,
|
3753
4241
|
COLLECTION_TYPES as C,
|
3754
4242
|
DocumentStatus as D,
|
3755
|
-
|
3756
|
-
|
3757
|
-
|
4243
|
+
extractContentTypeComponents as E,
|
4244
|
+
DEFAULT_SETTINGS as F,
|
4245
|
+
convertEditLayoutToFieldLayouts as G,
|
3758
4246
|
HOOKS as H,
|
3759
4247
|
InjectionZone as I,
|
3760
|
-
|
3761
|
-
|
4248
|
+
useDocument as J,
|
4249
|
+
useGetPreviewUrlQuery as K,
|
4250
|
+
index as L,
|
4251
|
+
useContentManagerContext as M,
|
4252
|
+
useDocumentActions as N,
|
3762
4253
|
Panels as P,
|
3763
4254
|
RelativeTime as R,
|
3764
4255
|
SINGLE_TYPES as S,
|
@@ -3776,18 +4267,18 @@ export {
|
|
3776
4267
|
PERMISSIONS as k,
|
3777
4268
|
DocumentRBAC as l,
|
3778
4269
|
DOCUMENT_META_FIELDS as m,
|
3779
|
-
|
3780
|
-
|
3781
|
-
|
3782
|
-
|
3783
|
-
|
4270
|
+
CLONE_PATH as n,
|
4271
|
+
useDocLayout as o,
|
4272
|
+
useGetContentTypeConfigurationQuery as p,
|
4273
|
+
CREATOR_FIELDS as q,
|
4274
|
+
getMainField as r,
|
3784
4275
|
setInitialData as s,
|
3785
|
-
|
4276
|
+
getDisplayName as t,
|
3786
4277
|
useContentTypeSchema as u,
|
3787
|
-
|
3788
|
-
|
3789
|
-
|
3790
|
-
|
3791
|
-
|
4278
|
+
checkIfAttributeIsDisplayable as v,
|
4279
|
+
useGetAllDocumentsQuery as w,
|
4280
|
+
convertListLayoutToFieldLayouts as x,
|
4281
|
+
capitalise as y,
|
4282
|
+
useUpdateContentTypeConfigurationMutation as z
|
3792
4283
|
};
|
3793
|
-
//# sourceMappingURL=index-
|
4284
|
+
//# sourceMappingURL=index-Bu_-B7ZA.mjs.map
|