@strapi/content-manager 0.0.0-experimental.9df68962083938acba06546a7901c68a63266aec → 0.0.0-experimental.9f812af47f0e9db3d5531382c836c2ac0776afdf
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-BSEZcJVB.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-BSEZcJVB.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-BiASGi7x.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-BiASGi7x.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-DjFJw56M.js → EditConfigurationPage-D2rtvneE.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-D2rtvneE.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-vN4zupij.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-vN4zupij.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-BwisF04Q.js} +63 -13
- package/dist/_chunks/EditViewPage-BwisF04Q.js.map +1 -0
- package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-_A31Cl4g.mjs} +63 -12
- package/dist/_chunks/EditViewPage-_A31Cl4g.mjs.map +1 -0
- package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-CvIunNOj.mjs} +405 -256
- package/dist/_chunks/Field-CvIunNOj.mjs.map +1 -0
- package/dist/_chunks/{Field-Boxf9Ajp.js → Field-Dsu6-FrM.js} +409 -260
- package/dist/_chunks/Field-Dsu6-FrM.js.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-DHrru2AV.mjs → Form-DK0fG0Gj.mjs} +37 -18
- package/dist/_chunks/Form-DK0fG0Gj.mjs.map +1 -0
- package/dist/_chunks/{Form-y5g1SRsh.js → Form-DUwWcCmA.js} +39 -21
- package/dist/_chunks/Form-DUwWcCmA.js.map +1 -0
- package/dist/_chunks/{History-CqN6K7SX.js → History-CeCDhoJG.js} +81 -114
- package/dist/_chunks/History-CeCDhoJG.js.map +1 -0
- package/dist/_chunks/{History-Bru_KoeP.mjs → History-DP8gmXpm.mjs} +82 -114
- package/dist/_chunks/History-DP8gmXpm.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BCkO5iuN.mjs} +25 -12
- package/dist/_chunks/ListConfigurationPage-BCkO5iuN.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-C-bAd44a.js} +25 -13
- package/dist/_chunks/ListConfigurationPage-C-bAd44a.js.map +1 -0
- package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-BKTZFhsM.js} +121 -81
- package/dist/_chunks/ListViewPage-BKTZFhsM.js.map +1 -0
- package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-Cf_DgaFV.mjs} +118 -77
- package/dist/_chunks/ListViewPage-Cf_DgaFV.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-D3Cm3v3q.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-D3Cm3v3q.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-nHIyvJcB.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-nHIyvJcB.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-BALVSJ7x.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-BALVSJ7x.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-CChGWBj5.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-CChGWBj5.js.map} +1 -1
- package/dist/_chunks/Preview-C4NBzKUV.mjs +294 -0
- package/dist/_chunks/Preview-C4NBzKUV.mjs.map +1 -0
- package/dist/_chunks/Preview-CT28Ckpg.js +312 -0
- package/dist/_chunks/Preview-CT28Ckpg.js.map +1 -0
- package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-C8uC89cT.mjs} +76 -42
- package/dist/_chunks/Relations-C8uC89cT.mjs.map +1 -0
- package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-CvkPCng_.js} +76 -43
- package/dist/_chunks/Relations-CvkPCng_.js.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-BK8Xyl5I.js} +32 -18
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-BK8Xyl5I.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-Dtk_ot79.mjs} +32 -18
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-Dtk_ot79.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-DVPWZkbS.js → index-CnX_j5h-.js} +1235 -746
- package/dist/_chunks/index-CnX_j5h-.js.map +1 -0
- package/dist/_chunks/{index-DJXJw9V5.mjs → index-Dh2aGTGJ.mjs} +1252 -763
- package/dist/_chunks/index-Dh2aGTGJ.mjs.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-Bau7ZfLV.mjs → layout-B5qsPihj.mjs} +26 -13
- package/dist/_chunks/layout-B5qsPihj.mjs.map +1 -0
- package/dist/_chunks/{layout-Dm6fbiQj.js → layout-B_qdWGny.js} +26 -14
- package/dist/_chunks/layout-B_qdWGny.js.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CKnpRgrN.js → relations-ChcieiF5.js} +6 -7
- package/dist/_chunks/relations-ChcieiF5.js.map +1 -0
- package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-DMXpNY-e.mjs} +6 -7
- package/dist/_chunks/relations-DMXpNY-e.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 +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- package/dist/admin/src/content-manager.d.ts +3 -2
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +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 +2 -2
- 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 +686 -360
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +687 -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-CPj61RMh.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
- package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
- package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
- package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
- package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
- package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
- package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
- package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
- package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
- package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
- package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
- package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
- package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
- package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
- package/dist/_chunks/relations-BH_kBSJ0.mjs.map +0 -1
- package/dist/_chunks/relations-CKnpRgrN.js.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,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
194
174
|
"Document",
|
195
175
|
"InitialData",
|
196
176
|
"HistoryVersion",
|
197
|
-
"Relations"
|
177
|
+
"Relations",
|
178
|
+
"UidAvailability"
|
198
179
|
]
|
199
180
|
});
|
200
181
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -208,7 +189,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
208
189
|
params: query
|
209
190
|
}
|
210
191
|
}),
|
211
|
-
invalidatesTags: (_result,
|
192
|
+
invalidatesTags: (_result, error, { model }) => {
|
193
|
+
if (error) {
|
194
|
+
return [];
|
195
|
+
}
|
196
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
197
|
+
}
|
212
198
|
}),
|
213
199
|
cloneDocument: builder.mutation({
|
214
200
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -219,7 +205,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
219
205
|
params
|
220
206
|
}
|
221
207
|
}),
|
222
|
-
invalidatesTags: (_result, _error, { model }) => [
|
208
|
+
invalidatesTags: (_result, _error, { model }) => [
|
209
|
+
{ type: "Document", id: `${model}_LIST` },
|
210
|
+
{ type: "UidAvailability", id: model }
|
211
|
+
]
|
223
212
|
}),
|
224
213
|
/**
|
225
214
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -236,8 +225,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
236
225
|
}),
|
237
226
|
invalidatesTags: (result, _error, { model }) => [
|
238
227
|
{ type: "Document", id: `${model}_LIST` },
|
239
|
-
"Relations"
|
240
|
-
|
228
|
+
"Relations",
|
229
|
+
{ type: "UidAvailability", id: model }
|
230
|
+
],
|
231
|
+
transformResponse: (response, meta, arg) => {
|
232
|
+
if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
|
233
|
+
return {
|
234
|
+
data: response,
|
235
|
+
meta: {
|
236
|
+
availableStatus: [],
|
237
|
+
availableLocales: []
|
238
|
+
}
|
239
|
+
};
|
240
|
+
}
|
241
|
+
return response;
|
242
|
+
}
|
241
243
|
}),
|
242
244
|
deleteDocument: builder.mutation({
|
243
245
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -277,7 +279,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
277
279
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
278
280
|
},
|
279
281
|
{ type: "Document", id: `${model}_LIST` },
|
280
|
-
"Relations"
|
282
|
+
"Relations",
|
283
|
+
{ type: "UidAvailability", id: model }
|
281
284
|
];
|
282
285
|
}
|
283
286
|
}),
|
@@ -290,11 +293,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
290
293
|
url: `/content-manager/collection-types/${model}`,
|
291
294
|
method: "GET",
|
292
295
|
config: {
|
293
|
-
params
|
296
|
+
params: stringify(params, { encode: true })
|
294
297
|
}
|
295
298
|
}),
|
296
299
|
providesTags: (result, _error, arg) => {
|
297
300
|
return [
|
301
|
+
{ type: "Document", id: `ALL_LIST` },
|
298
302
|
{ type: "Document", id: `${arg.model}_LIST` },
|
299
303
|
...result?.results.map(({ documentId }) => ({
|
300
304
|
type: "Document",
|
@@ -333,6 +337,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
333
337
|
{
|
334
338
|
type: "Document",
|
335
339
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
340
|
+
},
|
341
|
+
// Make it easy to invalidate all individual documents queries for a model
|
342
|
+
{
|
343
|
+
type: "Document",
|
344
|
+
id: `${model}_ALL_ITEMS`
|
336
345
|
}
|
337
346
|
];
|
338
347
|
}
|
@@ -396,8 +405,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
396
405
|
type: "Document",
|
397
406
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
398
407
|
},
|
399
|
-
"Relations"
|
408
|
+
"Relations",
|
409
|
+
{ type: "UidAvailability", id: model }
|
400
410
|
];
|
411
|
+
},
|
412
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
413
|
+
const patchResult = dispatch(
|
414
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
415
|
+
Object.assign(draft.data, data);
|
416
|
+
})
|
417
|
+
);
|
418
|
+
try {
|
419
|
+
await queryFulfilled;
|
420
|
+
} catch {
|
421
|
+
patchResult.undo();
|
422
|
+
}
|
401
423
|
}
|
402
424
|
}),
|
403
425
|
unpublishDocument: builder.mutation({
|
@@ -450,8 +472,7 @@ const {
|
|
450
472
|
useUnpublishManyDocumentsMutation
|
451
473
|
} = documentApi;
|
452
474
|
const buildValidParams = (query) => {
|
453
|
-
if (!query)
|
454
|
-
return query;
|
475
|
+
if (!query) return query;
|
455
476
|
const { plugins: _, ...validQueryParams } = {
|
456
477
|
...query,
|
457
478
|
...Object.values(query?.plugins ?? {}).reduce(
|
@@ -459,28 +480,44 @@ const buildValidParams = (query) => {
|
|
459
480
|
{}
|
460
481
|
)
|
461
482
|
};
|
462
|
-
if ("_q" in validQueryParams) {
|
463
|
-
validQueryParams._q = encodeURIComponent(validQueryParams._q);
|
464
|
-
}
|
465
483
|
return validQueryParams;
|
466
484
|
};
|
467
485
|
const isBaseQueryError = (error) => {
|
468
486
|
return error.name !== void 0;
|
469
487
|
};
|
470
|
-
const
|
488
|
+
const arrayValidator = (attribute, options) => ({
|
489
|
+
message: translatedErrors.required,
|
490
|
+
test(value) {
|
491
|
+
if (options.status === "draft") {
|
492
|
+
return true;
|
493
|
+
}
|
494
|
+
if (!attribute.required) {
|
495
|
+
return true;
|
496
|
+
}
|
497
|
+
if (!value) {
|
498
|
+
return false;
|
499
|
+
}
|
500
|
+
if (Array.isArray(value) && value.length === 0) {
|
501
|
+
return false;
|
502
|
+
}
|
503
|
+
return true;
|
504
|
+
}
|
505
|
+
});
|
506
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
471
507
|
const createModelSchema = (attributes2) => yup.object().shape(
|
472
508
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
473
509
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
474
510
|
return acc;
|
475
511
|
}
|
476
512
|
const validations = [
|
513
|
+
addNullableValidation,
|
477
514
|
addRequiredValidation,
|
478
515
|
addMinLengthValidation,
|
479
516
|
addMaxLengthValidation,
|
480
517
|
addMinValidation,
|
481
518
|
addMaxValidation,
|
482
519
|
addRegexValidation
|
483
|
-
].map((fn) => fn(attribute));
|
520
|
+
].map((fn) => fn(attribute, options));
|
484
521
|
const transformSchema = pipe(...validations);
|
485
522
|
switch (attribute.type) {
|
486
523
|
case "component": {
|
@@ -490,12 +527,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
490
527
|
...acc,
|
491
528
|
[name]: transformSchema(
|
492
529
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
493
|
-
)
|
530
|
+
).test(arrayValidator(attribute, options))
|
494
531
|
};
|
495
532
|
} else {
|
496
533
|
return {
|
497
534
|
...acc,
|
498
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
535
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
499
536
|
};
|
500
537
|
}
|
501
538
|
}
|
@@ -517,7 +554,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
517
554
|
}
|
518
555
|
)
|
519
556
|
)
|
520
|
-
)
|
557
|
+
).test(arrayValidator(attribute, options))
|
521
558
|
};
|
522
559
|
case "relation":
|
523
560
|
return {
|
@@ -529,7 +566,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
529
566
|
} else if (Array.isArray(value)) {
|
530
567
|
return yup.array().of(
|
531
568
|
yup.object().shape({
|
532
|
-
id: yup.
|
569
|
+
id: yup.number().required()
|
533
570
|
})
|
534
571
|
);
|
535
572
|
} else if (typeof value === "object") {
|
@@ -581,6 +618,14 @@ const createAttributeSchema = (attribute) => {
|
|
581
618
|
if (!value || typeof value === "string" && value.length === 0) {
|
582
619
|
return true;
|
583
620
|
}
|
621
|
+
if (typeof value === "object") {
|
622
|
+
try {
|
623
|
+
JSON.stringify(value);
|
624
|
+
return true;
|
625
|
+
} catch (err) {
|
626
|
+
return false;
|
627
|
+
}
|
628
|
+
}
|
584
629
|
try {
|
585
630
|
JSON.parse(value);
|
586
631
|
return true;
|
@@ -599,13 +644,7 @@ const createAttributeSchema = (attribute) => {
|
|
599
644
|
return yup.mixed();
|
600
645
|
}
|
601
646
|
};
|
602
|
-
const
|
603
|
-
if (attribute.required) {
|
604
|
-
return schema.required({
|
605
|
-
id: translatedErrors.required.id,
|
606
|
-
defaultMessage: "This field is required."
|
607
|
-
});
|
608
|
-
}
|
647
|
+
const nullableSchema = (schema) => {
|
609
648
|
return schema?.nullable ? schema.nullable() : (
|
610
649
|
// In some cases '.nullable' will not be available on the schema.
|
611
650
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -613,7 +652,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
613
652
|
schema
|
614
653
|
);
|
615
654
|
};
|
616
|
-
const
|
655
|
+
const addNullableValidation = () => (schema) => {
|
656
|
+
return nullableSchema(schema);
|
657
|
+
};
|
658
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
659
|
+
if (options.status === "draft" || !attribute.required) {
|
660
|
+
return schema;
|
661
|
+
}
|
662
|
+
if (attribute.required && "required" in schema) {
|
663
|
+
return schema.required(translatedErrors.required);
|
664
|
+
}
|
665
|
+
return schema;
|
666
|
+
};
|
667
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
668
|
+
if (options.status === "draft") {
|
669
|
+
return schema;
|
670
|
+
}
|
617
671
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
618
672
|
return schema.min(attribute.minLength, {
|
619
673
|
...translatedErrors.minLength,
|
@@ -635,10 +689,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
635
689
|
}
|
636
690
|
return schema;
|
637
691
|
};
|
638
|
-
const addMinValidation = (attribute) => (schema) => {
|
639
|
-
if ("
|
692
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
693
|
+
if (options.status === "draft") {
|
694
|
+
return schema;
|
695
|
+
}
|
696
|
+
if ("min" in attribute && "min" in schema) {
|
640
697
|
const min = toInteger(attribute.min);
|
641
|
-
if (
|
698
|
+
if (min) {
|
642
699
|
return schema.min(min, {
|
643
700
|
...translatedErrors.min,
|
644
701
|
values: {
|
@@ -756,16 +813,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
756
813
|
}, {});
|
757
814
|
return componentsByKey;
|
758
815
|
};
|
759
|
-
const
|
816
|
+
const HOOKS = {
|
817
|
+
/**
|
818
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
819
|
+
* @constant
|
820
|
+
* @type {string}
|
821
|
+
*/
|
822
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
823
|
+
/**
|
824
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
825
|
+
* @constant
|
826
|
+
* @type {string}
|
827
|
+
*/
|
828
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
829
|
+
/**
|
830
|
+
* Hook that allows to mutate the CM's edit view layout
|
831
|
+
* @constant
|
832
|
+
* @type {string}
|
833
|
+
*/
|
834
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
835
|
+
/**
|
836
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
837
|
+
* @constant
|
838
|
+
* @type {string}
|
839
|
+
*/
|
840
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
841
|
+
};
|
842
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
843
|
+
endpoints: (builder) => ({
|
844
|
+
getContentTypeConfiguration: builder.query({
|
845
|
+
query: (uid) => ({
|
846
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
847
|
+
method: "GET"
|
848
|
+
}),
|
849
|
+
transformResponse: (response) => response.data,
|
850
|
+
providesTags: (_result, _error, uid) => [
|
851
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
852
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
853
|
+
]
|
854
|
+
}),
|
855
|
+
getAllContentTypeSettings: builder.query({
|
856
|
+
query: () => "/content-manager/content-types-settings",
|
857
|
+
transformResponse: (response) => response.data,
|
858
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
859
|
+
}),
|
860
|
+
updateContentTypeConfiguration: builder.mutation({
|
861
|
+
query: ({ uid, ...body }) => ({
|
862
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
863
|
+
method: "PUT",
|
864
|
+
data: body
|
865
|
+
}),
|
866
|
+
transformResponse: (response) => response.data,
|
867
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
868
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
869
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
870
|
+
// Is this necessary?
|
871
|
+
{ type: "InitialData" }
|
872
|
+
]
|
873
|
+
})
|
874
|
+
})
|
875
|
+
});
|
876
|
+
const {
|
877
|
+
useGetContentTypeConfigurationQuery,
|
878
|
+
useGetAllContentTypeSettingsQuery,
|
879
|
+
useUpdateContentTypeConfigurationMutation
|
880
|
+
} = contentTypesApi;
|
881
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
882
|
+
const { type } = attribute;
|
883
|
+
if (type === "relation") {
|
884
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
885
|
+
}
|
886
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
887
|
+
};
|
888
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
889
|
+
if (!mainFieldName) {
|
890
|
+
return void 0;
|
891
|
+
}
|
892
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
893
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
894
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
895
|
+
);
|
896
|
+
return {
|
897
|
+
name: mainFieldName,
|
898
|
+
type: mainFieldType ?? "string"
|
899
|
+
};
|
900
|
+
};
|
901
|
+
const DEFAULT_SETTINGS = {
|
902
|
+
bulkable: false,
|
903
|
+
filterable: false,
|
904
|
+
searchable: false,
|
905
|
+
pagination: false,
|
906
|
+
defaultSortBy: "",
|
907
|
+
defaultSortOrder: "asc",
|
908
|
+
mainField: "id",
|
909
|
+
pageSize: 10
|
910
|
+
};
|
911
|
+
const useDocumentLayout = (model) => {
|
912
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
913
|
+
const [{ query }] = useQueryParams();
|
914
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
760
915
|
const { toggleNotification } = useNotification();
|
761
916
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
917
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
762
918
|
const {
|
763
|
-
|
764
|
-
isLoading:
|
765
|
-
|
766
|
-
|
767
|
-
} =
|
768
|
-
const
|
919
|
+
data,
|
920
|
+
isLoading: isLoadingConfigs,
|
921
|
+
error,
|
922
|
+
isFetching: isFetchingConfigs
|
923
|
+
} = useGetContentTypeConfigurationQuery(model);
|
924
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
769
925
|
React.useEffect(() => {
|
770
926
|
if (error) {
|
771
927
|
toggleNotification({
|
@@ -773,44 +929,260 @@ const useDocument = (args, opts) => {
|
|
773
929
|
message: formatAPIError(error)
|
774
930
|
});
|
775
931
|
}
|
776
|
-
}, [
|
777
|
-
const
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
(document) => {
|
785
|
-
if (!validationSchema) {
|
786
|
-
throw new Error(
|
787
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
788
|
-
);
|
789
|
-
}
|
790
|
-
try {
|
791
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
792
|
-
return null;
|
793
|
-
} catch (error2) {
|
794
|
-
if (error2 instanceof ValidationError) {
|
795
|
-
return getYupValidationErrors(error2);
|
796
|
-
}
|
797
|
-
throw error2;
|
798
|
-
}
|
932
|
+
}, [error, formatAPIError, toggleNotification]);
|
933
|
+
const editLayout = React.useMemo(
|
934
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
935
|
+
layout: [],
|
936
|
+
components: {},
|
937
|
+
metadatas: {},
|
938
|
+
options: {},
|
939
|
+
settings: DEFAULT_SETTINGS
|
799
940
|
},
|
800
|
-
[
|
941
|
+
[data, isLoading, schemas, schema, components]
|
942
|
+
);
|
943
|
+
const listLayout = React.useMemo(() => {
|
944
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
945
|
+
layout: [],
|
946
|
+
metadatas: {},
|
947
|
+
options: {},
|
948
|
+
settings: DEFAULT_SETTINGS
|
949
|
+
};
|
950
|
+
}, [data, isLoading, schemas, schema, components]);
|
951
|
+
const { layout: edit } = React.useMemo(
|
952
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
953
|
+
layout: editLayout,
|
954
|
+
query
|
955
|
+
}),
|
956
|
+
[editLayout, query, runHookWaterfall]
|
801
957
|
);
|
802
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
803
958
|
return {
|
804
|
-
|
805
|
-
document: data?.data,
|
806
|
-
meta: data?.meta,
|
959
|
+
error,
|
807
960
|
isLoading,
|
808
|
-
|
809
|
-
|
961
|
+
edit,
|
962
|
+
list: listLayout
|
810
963
|
};
|
811
964
|
};
|
812
|
-
const
|
813
|
-
const {
|
965
|
+
const useDocLayout = () => {
|
966
|
+
const { model } = useDoc();
|
967
|
+
return useDocumentLayout(model);
|
968
|
+
};
|
969
|
+
const formatEditLayout = (data, {
|
970
|
+
schemas,
|
971
|
+
schema,
|
972
|
+
components
|
973
|
+
}) => {
|
974
|
+
let currentPanelIndex = 0;
|
975
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
976
|
+
data.contentType.layouts.edit,
|
977
|
+
schema?.attributes,
|
978
|
+
data.contentType.metadatas,
|
979
|
+
{ configurations: data.components, schemas: components },
|
980
|
+
schemas
|
981
|
+
).reduce((panels, row) => {
|
982
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
983
|
+
panels.push([row]);
|
984
|
+
currentPanelIndex += 2;
|
985
|
+
} else {
|
986
|
+
if (!panels[currentPanelIndex]) {
|
987
|
+
panels.push([row]);
|
988
|
+
} else {
|
989
|
+
panels[currentPanelIndex].push(row);
|
990
|
+
}
|
991
|
+
}
|
992
|
+
return panels;
|
993
|
+
}, []);
|
994
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
995
|
+
(acc, [uid, configuration]) => {
|
996
|
+
acc[uid] = {
|
997
|
+
layout: convertEditLayoutToFieldLayouts(
|
998
|
+
configuration.layouts.edit,
|
999
|
+
components[uid].attributes,
|
1000
|
+
configuration.metadatas,
|
1001
|
+
{ configurations: data.components, schemas: components }
|
1002
|
+
),
|
1003
|
+
settings: {
|
1004
|
+
...configuration.settings,
|
1005
|
+
icon: components[uid].info.icon,
|
1006
|
+
displayName: components[uid].info.displayName
|
1007
|
+
}
|
1008
|
+
};
|
1009
|
+
return acc;
|
1010
|
+
},
|
1011
|
+
{}
|
1012
|
+
);
|
1013
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1014
|
+
(acc, [attribute, metadata]) => {
|
1015
|
+
return {
|
1016
|
+
...acc,
|
1017
|
+
[attribute]: metadata.edit
|
1018
|
+
};
|
1019
|
+
},
|
1020
|
+
{}
|
1021
|
+
);
|
1022
|
+
return {
|
1023
|
+
layout: panelledEditAttributes,
|
1024
|
+
components: componentEditAttributes,
|
1025
|
+
metadatas: editMetadatas,
|
1026
|
+
settings: {
|
1027
|
+
...data.contentType.settings,
|
1028
|
+
displayName: schema?.info.displayName
|
1029
|
+
},
|
1030
|
+
options: {
|
1031
|
+
...schema?.options,
|
1032
|
+
...schema?.pluginOptions,
|
1033
|
+
...data.contentType.options
|
1034
|
+
}
|
1035
|
+
};
|
1036
|
+
};
|
1037
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1038
|
+
return rows.map(
|
1039
|
+
(row) => row.map((field) => {
|
1040
|
+
const attribute = attributes[field.name];
|
1041
|
+
if (!attribute) {
|
1042
|
+
return null;
|
1043
|
+
}
|
1044
|
+
const { edit: metadata } = metadatas[field.name];
|
1045
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1046
|
+
return {
|
1047
|
+
attribute,
|
1048
|
+
disabled: !metadata.editable,
|
1049
|
+
hint: metadata.description,
|
1050
|
+
label: metadata.label ?? "",
|
1051
|
+
name: field.name,
|
1052
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1053
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1054
|
+
schemas,
|
1055
|
+
components: components?.schemas ?? {}
|
1056
|
+
}),
|
1057
|
+
placeholder: metadata.placeholder ?? "",
|
1058
|
+
required: attribute.required ?? false,
|
1059
|
+
size: field.size,
|
1060
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1061
|
+
visible: metadata.visible ?? true,
|
1062
|
+
type: attribute.type
|
1063
|
+
};
|
1064
|
+
}).filter((field) => field !== null)
|
1065
|
+
);
|
1066
|
+
};
|
1067
|
+
const formatListLayout = (data, {
|
1068
|
+
schemas,
|
1069
|
+
schema,
|
1070
|
+
components
|
1071
|
+
}) => {
|
1072
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1073
|
+
(acc, [attribute, metadata]) => {
|
1074
|
+
return {
|
1075
|
+
...acc,
|
1076
|
+
[attribute]: metadata.list
|
1077
|
+
};
|
1078
|
+
},
|
1079
|
+
{}
|
1080
|
+
);
|
1081
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1082
|
+
data.contentType.layouts.list,
|
1083
|
+
schema?.attributes,
|
1084
|
+
listMetadatas,
|
1085
|
+
{ configurations: data.components, schemas: components },
|
1086
|
+
schemas
|
1087
|
+
);
|
1088
|
+
return {
|
1089
|
+
layout: listAttributes,
|
1090
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1091
|
+
metadatas: listMetadatas,
|
1092
|
+
options: {
|
1093
|
+
...schema?.options,
|
1094
|
+
...schema?.pluginOptions,
|
1095
|
+
...data.contentType.options
|
1096
|
+
}
|
1097
|
+
};
|
1098
|
+
};
|
1099
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1100
|
+
return columns.map((name) => {
|
1101
|
+
const attribute = attributes[name];
|
1102
|
+
if (!attribute) {
|
1103
|
+
return null;
|
1104
|
+
}
|
1105
|
+
const metadata = metadatas[name];
|
1106
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1107
|
+
return {
|
1108
|
+
attribute,
|
1109
|
+
label: metadata.label ?? "",
|
1110
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1111
|
+
schemas,
|
1112
|
+
components: components?.schemas ?? {}
|
1113
|
+
}),
|
1114
|
+
name,
|
1115
|
+
searchable: metadata.searchable ?? true,
|
1116
|
+
sortable: metadata.sortable ?? true
|
1117
|
+
};
|
1118
|
+
}).filter((field) => field !== null);
|
1119
|
+
};
|
1120
|
+
const useDocument = (args, opts) => {
|
1121
|
+
const { toggleNotification } = useNotification();
|
1122
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1123
|
+
const {
|
1124
|
+
currentData: data,
|
1125
|
+
isLoading: isLoadingDocument,
|
1126
|
+
isFetching: isFetchingDocument,
|
1127
|
+
error
|
1128
|
+
} = useGetDocumentQuery(args, {
|
1129
|
+
...opts,
|
1130
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1131
|
+
});
|
1132
|
+
const {
|
1133
|
+
components,
|
1134
|
+
schema,
|
1135
|
+
schemas,
|
1136
|
+
isLoading: isLoadingSchema
|
1137
|
+
} = useContentTypeSchema(args.model);
|
1138
|
+
React.useEffect(() => {
|
1139
|
+
if (error) {
|
1140
|
+
toggleNotification({
|
1141
|
+
type: "danger",
|
1142
|
+
message: formatAPIError(error)
|
1143
|
+
});
|
1144
|
+
}
|
1145
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1146
|
+
const validationSchema = React.useMemo(() => {
|
1147
|
+
if (!schema) {
|
1148
|
+
return null;
|
1149
|
+
}
|
1150
|
+
return createYupSchema(schema.attributes, components);
|
1151
|
+
}, [schema, components]);
|
1152
|
+
const validate = React.useCallback(
|
1153
|
+
(document) => {
|
1154
|
+
if (!validationSchema) {
|
1155
|
+
throw new Error(
|
1156
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1157
|
+
);
|
1158
|
+
}
|
1159
|
+
try {
|
1160
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1161
|
+
return null;
|
1162
|
+
} catch (error2) {
|
1163
|
+
if (error2 instanceof ValidationError) {
|
1164
|
+
return getYupValidationErrors(error2);
|
1165
|
+
}
|
1166
|
+
throw error2;
|
1167
|
+
}
|
1168
|
+
},
|
1169
|
+
[validationSchema]
|
1170
|
+
);
|
1171
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1172
|
+
const hasError = !!error;
|
1173
|
+
return {
|
1174
|
+
components,
|
1175
|
+
document: data?.data,
|
1176
|
+
meta: data?.meta,
|
1177
|
+
isLoading,
|
1178
|
+
hasError,
|
1179
|
+
schema,
|
1180
|
+
schemas,
|
1181
|
+
validate
|
1182
|
+
};
|
1183
|
+
};
|
1184
|
+
const useDoc = () => {
|
1185
|
+
const { id, slug, collectionType, origin } = useParams();
|
814
1186
|
const [{ query }] = useQueryParams();
|
815
1187
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
816
1188
|
if (!collectionType) {
|
@@ -819,22 +1191,60 @@ const useDoc = () => {
|
|
819
1191
|
if (!slug) {
|
820
1192
|
throw new Error("Could not find model in url params");
|
821
1193
|
}
|
1194
|
+
const document = useDocument(
|
1195
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1196
|
+
{
|
1197
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1198
|
+
}
|
1199
|
+
);
|
1200
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
822
1201
|
return {
|
823
1202
|
collectionType,
|
824
1203
|
model: slug,
|
825
|
-
id:
|
826
|
-
...
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
1204
|
+
id: returnId,
|
1205
|
+
...document
|
1206
|
+
};
|
1207
|
+
};
|
1208
|
+
const useContentManagerContext = () => {
|
1209
|
+
const {
|
1210
|
+
collectionType,
|
1211
|
+
model,
|
1212
|
+
id,
|
1213
|
+
components,
|
1214
|
+
isLoading: isLoadingDoc,
|
1215
|
+
schema,
|
1216
|
+
schemas
|
1217
|
+
} = useDoc();
|
1218
|
+
const layout = useDocumentLayout(model);
|
1219
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1220
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1221
|
+
const slug = model;
|
1222
|
+
const isCreatingEntry = id === "create";
|
1223
|
+
useContentTypeSchema();
|
1224
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1225
|
+
const error = layout.error;
|
1226
|
+
return {
|
1227
|
+
error,
|
1228
|
+
isLoading,
|
1229
|
+
// Base metadata
|
1230
|
+
model,
|
1231
|
+
collectionType,
|
1232
|
+
id,
|
1233
|
+
slug,
|
1234
|
+
isCreatingEntry,
|
1235
|
+
isSingleType,
|
1236
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1237
|
+
// All schema infos
|
1238
|
+
components,
|
1239
|
+
contentType: schema,
|
1240
|
+
contentTypes: schemas,
|
1241
|
+
// Form state
|
1242
|
+
form,
|
1243
|
+
// layout infos
|
1244
|
+
layout
|
832
1245
|
};
|
833
1246
|
};
|
834
1247
|
const prefixPluginTranslations = (trad, pluginId) => {
|
835
|
-
if (!pluginId) {
|
836
|
-
throw new TypeError("pluginId can't be empty");
|
837
|
-
}
|
838
1248
|
return Object.keys(trad).reduce((acc, current) => {
|
839
1249
|
acc[`${pluginId}.${current}`] = trad[current];
|
840
1250
|
return acc;
|
@@ -850,6 +1260,8 @@ const useDocumentActions = () => {
|
|
850
1260
|
const { formatMessage } = useIntl();
|
851
1261
|
const { trackUsage } = useTracking();
|
852
1262
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1263
|
+
const navigate = useNavigate();
|
1264
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
853
1265
|
const [deleteDocument] = useDeleteDocumentMutation();
|
854
1266
|
const _delete = React.useCallback(
|
855
1267
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1164,6 +1576,7 @@ const useDocumentActions = () => {
|
|
1164
1576
|
defaultMessage: "Saved document"
|
1165
1577
|
})
|
1166
1578
|
});
|
1579
|
+
setCurrentStep("contentManager.success");
|
1167
1580
|
return res.data;
|
1168
1581
|
} catch (err) {
|
1169
1582
|
toggleNotification({
|
@@ -1185,7 +1598,6 @@ const useDocumentActions = () => {
|
|
1185
1598
|
sourceId
|
1186
1599
|
});
|
1187
1600
|
if ("error" in res) {
|
1188
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1189
1601
|
return { error: res.error };
|
1190
1602
|
}
|
1191
1603
|
toggleNotification({
|
@@ -1204,7 +1616,7 @@ const useDocumentActions = () => {
|
|
1204
1616
|
throw err;
|
1205
1617
|
}
|
1206
1618
|
},
|
1207
|
-
[autoCloneDocument,
|
1619
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1208
1620
|
);
|
1209
1621
|
const [cloneDocument] = useCloneDocumentMutation();
|
1210
1622
|
const clone = React.useCallback(
|
@@ -1230,6 +1642,7 @@ const useDocumentActions = () => {
|
|
1230
1642
|
defaultMessage: "Cloned document"
|
1231
1643
|
})
|
1232
1644
|
});
|
1645
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1233
1646
|
return res.data;
|
1234
1647
|
} catch (err) {
|
1235
1648
|
toggleNotification({
|
@@ -1240,7 +1653,7 @@ const useDocumentActions = () => {
|
|
1240
1653
|
throw err;
|
1241
1654
|
}
|
1242
1655
|
},
|
1243
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1656
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1244
1657
|
);
|
1245
1658
|
const [getDoc] = useLazyGetDocumentQuery();
|
1246
1659
|
const getDocument = React.useCallback(
|
@@ -1265,10 +1678,10 @@ const useDocumentActions = () => {
|
|
1265
1678
|
update
|
1266
1679
|
};
|
1267
1680
|
};
|
1268
|
-
const ProtectedHistoryPage = lazy(
|
1269
|
-
() => import("./History-
|
1681
|
+
const ProtectedHistoryPage = React.lazy(
|
1682
|
+
() => import("./History-DP8gmXpm.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1270
1683
|
);
|
1271
|
-
const routes$
|
1684
|
+
const routes$2 = [
|
1272
1685
|
{
|
1273
1686
|
path: ":collectionType/:slug/:id/history",
|
1274
1687
|
Component: ProtectedHistoryPage
|
@@ -1278,32 +1691,45 @@ const routes$1 = [
|
|
1278
1691
|
Component: ProtectedHistoryPage
|
1279
1692
|
}
|
1280
1693
|
];
|
1694
|
+
const ProtectedPreviewPage = React.lazy(
|
1695
|
+
() => import("./Preview-C4NBzKUV.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1696
|
+
);
|
1697
|
+
const routes$1 = [
|
1698
|
+
{
|
1699
|
+
path: ":collectionType/:slug/:id/preview",
|
1700
|
+
Component: ProtectedPreviewPage
|
1701
|
+
},
|
1702
|
+
{
|
1703
|
+
path: ":collectionType/:slug/preview",
|
1704
|
+
Component: ProtectedPreviewPage
|
1705
|
+
}
|
1706
|
+
];
|
1281
1707
|
const ProtectedEditViewPage = lazy(
|
1282
|
-
() => import("./EditViewPage-
|
1708
|
+
() => import("./EditViewPage-_A31Cl4g.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1283
1709
|
);
|
1284
1710
|
const ProtectedListViewPage = lazy(
|
1285
|
-
() => import("./ListViewPage-
|
1711
|
+
() => import("./ListViewPage-Cf_DgaFV.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1286
1712
|
);
|
1287
1713
|
const ProtectedListConfiguration = lazy(
|
1288
|
-
() => import("./ListConfigurationPage-
|
1714
|
+
() => import("./ListConfigurationPage-BCkO5iuN.mjs").then((mod) => ({
|
1289
1715
|
default: mod.ProtectedListConfiguration
|
1290
1716
|
}))
|
1291
1717
|
);
|
1292
1718
|
const ProtectedEditConfigurationPage = lazy(
|
1293
|
-
() => import("./EditConfigurationPage-
|
1719
|
+
() => import("./EditConfigurationPage-vN4zupij.mjs").then((mod) => ({
|
1294
1720
|
default: mod.ProtectedEditConfigurationPage
|
1295
1721
|
}))
|
1296
1722
|
);
|
1297
1723
|
const ProtectedComponentConfigurationPage = lazy(
|
1298
|
-
() => import("./ComponentConfigurationPage-
|
1724
|
+
() => import("./ComponentConfigurationPage-BiASGi7x.mjs").then((mod) => ({
|
1299
1725
|
default: mod.ProtectedComponentConfigurationPage
|
1300
1726
|
}))
|
1301
1727
|
);
|
1302
1728
|
const NoPermissions = lazy(
|
1303
|
-
() => import("./NoPermissionsPage-
|
1729
|
+
() => import("./NoPermissionsPage-BALVSJ7x.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1304
1730
|
);
|
1305
1731
|
const NoContentType = lazy(
|
1306
|
-
() => import("./NoContentTypePage-
|
1732
|
+
() => import("./NoContentTypePage-nHIyvJcB.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1307
1733
|
);
|
1308
1734
|
const CollectionTypePages = () => {
|
1309
1735
|
const { collectionType } = useParams();
|
@@ -1315,7 +1741,7 @@ const CollectionTypePages = () => {
|
|
1315
1741
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1316
1742
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1317
1743
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1318
|
-
const LIST_PATH = `/content-manager
|
1744
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1319
1745
|
const routes = [
|
1320
1746
|
{
|
1321
1747
|
path: LIST_RELATIVE_PATH,
|
@@ -1349,6 +1775,7 @@ const routes = [
|
|
1349
1775
|
path: "no-content-types",
|
1350
1776
|
Component: NoContentType
|
1351
1777
|
},
|
1778
|
+
...routes$2,
|
1352
1779
|
...routes$1
|
1353
1780
|
];
|
1354
1781
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1417,12 +1844,14 @@ const DocumentActionButton = (action) => {
|
|
1417
1844
|
/* @__PURE__ */ jsx(
|
1418
1845
|
Button,
|
1419
1846
|
{
|
1420
|
-
flex:
|
1847
|
+
flex: "auto",
|
1421
1848
|
startIcon: action.icon,
|
1422
1849
|
disabled: action.disabled,
|
1423
1850
|
onClick: handleClick(action),
|
1424
1851
|
justifyContent: "center",
|
1425
1852
|
variant: action.variant || "default",
|
1853
|
+
paddingTop: "7px",
|
1854
|
+
paddingBottom: "7px",
|
1426
1855
|
children: action.label
|
1427
1856
|
}
|
1428
1857
|
),
|
@@ -1430,7 +1859,7 @@ const DocumentActionButton = (action) => {
|
|
1430
1859
|
DocumentActionConfirmDialog,
|
1431
1860
|
{
|
1432
1861
|
...action.dialog,
|
1433
|
-
variant: action.variant,
|
1862
|
+
variant: action.dialog?.variant ?? action.variant,
|
1434
1863
|
isOpen: dialogId === action.id,
|
1435
1864
|
onClose: handleClose
|
1436
1865
|
}
|
@@ -1445,6 +1874,11 @@ const DocumentActionButton = (action) => {
|
|
1445
1874
|
) : null
|
1446
1875
|
] });
|
1447
1876
|
};
|
1877
|
+
const MenuItem = styled(Menu.Item)`
|
1878
|
+
&:hover {
|
1879
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
1880
|
+
}
|
1881
|
+
`;
|
1448
1882
|
const DocumentActionsMenu = ({
|
1449
1883
|
actions: actions2,
|
1450
1884
|
children,
|
@@ -1487,9 +1921,9 @@ const DocumentActionsMenu = ({
|
|
1487
1921
|
disabled: isDisabled,
|
1488
1922
|
size: "S",
|
1489
1923
|
endIcon: null,
|
1490
|
-
paddingTop: "
|
1491
|
-
paddingLeft: "
|
1492
|
-
paddingRight: "
|
1924
|
+
paddingTop: "4px",
|
1925
|
+
paddingLeft: "7px",
|
1926
|
+
paddingRight: "7px",
|
1493
1927
|
variant,
|
1494
1928
|
children: [
|
1495
1929
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1500,36 +1934,35 @@ const DocumentActionsMenu = ({
|
|
1500
1934
|
]
|
1501
1935
|
}
|
1502
1936
|
),
|
1503
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1937
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1504
1938
|
actions2.map((action) => {
|
1505
1939
|
return /* @__PURE__ */ jsx(
|
1506
|
-
|
1940
|
+
MenuItem,
|
1507
1941
|
{
|
1508
1942
|
disabled: action.disabled,
|
1509
1943
|
onSelect: handleClick(action),
|
1510
1944
|
display: "block",
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
] })
|
1945
|
+
isVariantDanger: action.variant === "danger",
|
1946
|
+
isDisabled: action.disabled,
|
1947
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
|
1948
|
+
Flex,
|
1949
|
+
{
|
1950
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1951
|
+
gap: 2,
|
1952
|
+
tag: "span",
|
1953
|
+
children: [
|
1954
|
+
/* @__PURE__ */ jsx(
|
1955
|
+
Flex,
|
1956
|
+
{
|
1957
|
+
tag: "span",
|
1958
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1959
|
+
children: action.icon
|
1960
|
+
}
|
1961
|
+
),
|
1962
|
+
action.label
|
1963
|
+
]
|
1964
|
+
}
|
1965
|
+
) })
|
1533
1966
|
},
|
1534
1967
|
action.id
|
1535
1968
|
);
|
@@ -1609,11 +2042,11 @@ const DocumentActionConfirmDialog = ({
|
|
1609
2042
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1610
2043
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1611
2044
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1612
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2045
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1613
2046
|
id: "app.components.Button.cancel",
|
1614
2047
|
defaultMessage: "Cancel"
|
1615
2048
|
}) }) }),
|
1616
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2049
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1617
2050
|
id: "app.components.Button.confirm",
|
1618
2051
|
defaultMessage: "Confirm"
|
1619
2052
|
}) })
|
@@ -1640,6 +2073,18 @@ const DocumentActionModal = ({
|
|
1640
2073
|
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1641
2074
|
] }) });
|
1642
2075
|
};
|
2076
|
+
const transformData = (data) => {
|
2077
|
+
if (Array.isArray(data)) {
|
2078
|
+
return data.map(transformData);
|
2079
|
+
}
|
2080
|
+
if (typeof data === "object" && data !== null) {
|
2081
|
+
if ("apiData" in data) {
|
2082
|
+
return data.apiData;
|
2083
|
+
}
|
2084
|
+
return mapValues(transformData)(data);
|
2085
|
+
}
|
2086
|
+
return data;
|
2087
|
+
};
|
1643
2088
|
const PublishAction$1 = ({
|
1644
2089
|
activeTab,
|
1645
2090
|
documentId,
|
@@ -1652,13 +2097,18 @@ const PublishAction$1 = ({
|
|
1652
2097
|
const navigate = useNavigate();
|
1653
2098
|
const { toggleNotification } = useNotification();
|
1654
2099
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2100
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1655
2101
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2102
|
+
const { id } = useParams();
|
1656
2103
|
const { formatMessage } = useIntl();
|
1657
|
-
const { canPublish
|
1658
|
-
"PublishAction",
|
1659
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1660
|
-
);
|
2104
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1661
2105
|
const { publish } = useDocumentActions();
|
2106
|
+
const [
|
2107
|
+
countDraftRelations,
|
2108
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2109
|
+
] = useLazyGetDraftRelationCountQuery();
|
2110
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2111
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1662
2112
|
const [{ query, rawQuery }] = useQueryParams();
|
1663
2113
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1664
2114
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1667,10 +2117,107 @@ const PublishAction$1 = ({
|
|
1667
2117
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1668
2118
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1669
2119
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1670
|
-
|
1671
|
-
|
2120
|
+
React.useEffect(() => {
|
2121
|
+
if (isErrorDraftRelations) {
|
2122
|
+
toggleNotification({
|
2123
|
+
type: "danger",
|
2124
|
+
message: formatMessage({
|
2125
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2126
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2127
|
+
})
|
2128
|
+
});
|
2129
|
+
}
|
2130
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2131
|
+
React.useEffect(() => {
|
2132
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2133
|
+
const extractDraftRelations = (data) => {
|
2134
|
+
const relations = data.connect || [];
|
2135
|
+
relations.forEach((relation) => {
|
2136
|
+
if (relation.status === "draft") {
|
2137
|
+
localDraftRelations.add(relation.id);
|
2138
|
+
}
|
2139
|
+
});
|
2140
|
+
};
|
2141
|
+
const traverseAndExtract = (data) => {
|
2142
|
+
Object.entries(data).forEach(([key, value]) => {
|
2143
|
+
if (key === "connect" && Array.isArray(value)) {
|
2144
|
+
extractDraftRelations({ connect: value });
|
2145
|
+
} else if (typeof value === "object" && value !== null) {
|
2146
|
+
traverseAndExtract(value);
|
2147
|
+
}
|
2148
|
+
});
|
2149
|
+
};
|
2150
|
+
if (!documentId || modified) {
|
2151
|
+
traverseAndExtract(formValues);
|
2152
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2153
|
+
}
|
2154
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2155
|
+
React.useEffect(() => {
|
2156
|
+
if (!document || !document.documentId || isListView) {
|
2157
|
+
return;
|
2158
|
+
}
|
2159
|
+
const fetchDraftRelationsCount = async () => {
|
2160
|
+
const { data, error } = await countDraftRelations({
|
2161
|
+
collectionType,
|
2162
|
+
model,
|
2163
|
+
documentId,
|
2164
|
+
params
|
2165
|
+
});
|
2166
|
+
if (error) {
|
2167
|
+
throw error;
|
2168
|
+
}
|
2169
|
+
if (data) {
|
2170
|
+
setServerCountOfDraftRelations(data.data);
|
2171
|
+
}
|
2172
|
+
};
|
2173
|
+
fetchDraftRelationsCount();
|
2174
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2175
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2176
|
+
if (!schema?.options?.draftAndPublish) {
|
1672
2177
|
return null;
|
1673
2178
|
}
|
2179
|
+
const performPublish = async () => {
|
2180
|
+
setSubmitting(true);
|
2181
|
+
try {
|
2182
|
+
const { errors } = await validate(true, {
|
2183
|
+
status: "published"
|
2184
|
+
});
|
2185
|
+
if (errors) {
|
2186
|
+
toggleNotification({
|
2187
|
+
type: "danger",
|
2188
|
+
message: formatMessage({
|
2189
|
+
id: "content-manager.validation.error",
|
2190
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2191
|
+
})
|
2192
|
+
});
|
2193
|
+
return;
|
2194
|
+
}
|
2195
|
+
const res = await publish(
|
2196
|
+
{
|
2197
|
+
collectionType,
|
2198
|
+
model,
|
2199
|
+
documentId,
|
2200
|
+
params
|
2201
|
+
},
|
2202
|
+
transformData(formValues)
|
2203
|
+
);
|
2204
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2205
|
+
if (id === "create") {
|
2206
|
+
navigate({
|
2207
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2208
|
+
search: rawQuery
|
2209
|
+
});
|
2210
|
+
}
|
2211
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2212
|
+
setErrors(formatValidationErrors(res.error));
|
2213
|
+
}
|
2214
|
+
} finally {
|
2215
|
+
setSubmitting(false);
|
2216
|
+
}
|
2217
|
+
};
|
2218
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2219
|
+
const enableDraftRelationsCount = false;
|
2220
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1674
2221
|
return {
|
1675
2222
|
/**
|
1676
2223
|
* Disabled when:
|
@@ -1680,52 +2227,40 @@ const PublishAction$1 = ({
|
|
1680
2227
|
* - the document is already published & not modified
|
1681
2228
|
* - the document is being created & not modified
|
1682
2229
|
* - the user doesn't have the permission to publish
|
1683
|
-
* - the user doesn't have the permission to create a new document
|
1684
|
-
* - the user doesn't have the permission to update the document
|
1685
2230
|
*/
|
1686
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2231
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1687
2232
|
label: formatMessage({
|
1688
2233
|
id: "app.utils.publish",
|
1689
2234
|
defaultMessage: "Publish"
|
1690
2235
|
}),
|
1691
2236
|
onClick: async () => {
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
documentId,
|
1710
|
-
params
|
1711
|
-
},
|
1712
|
-
formValues
|
1713
|
-
);
|
1714
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1715
|
-
navigate({
|
1716
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1717
|
-
search: rawQuery
|
1718
|
-
});
|
1719
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1720
|
-
setErrors(formatValidationErrors(res.error));
|
2237
|
+
await performPublish();
|
2238
|
+
},
|
2239
|
+
dialog: hasDraftRelations ? {
|
2240
|
+
type: "dialog",
|
2241
|
+
variant: "danger",
|
2242
|
+
footer: null,
|
2243
|
+
title: formatMessage({
|
2244
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2245
|
+
defaultMessage: "Confirmation"
|
2246
|
+
}),
|
2247
|
+
content: formatMessage(
|
2248
|
+
{
|
2249
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2250
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2251
|
+
},
|
2252
|
+
{
|
2253
|
+
count: totalDraftRelations
|
1721
2254
|
}
|
1722
|
-
|
1723
|
-
|
2255
|
+
),
|
2256
|
+
onConfirm: async () => {
|
2257
|
+
await performPublish();
|
1724
2258
|
}
|
1725
|
-
}
|
2259
|
+
} : void 0
|
1726
2260
|
};
|
1727
2261
|
};
|
1728
2262
|
PublishAction$1.type = "publish";
|
2263
|
+
PublishAction$1.position = "panel";
|
1729
2264
|
const UpdateAction = ({
|
1730
2265
|
activeTab,
|
1731
2266
|
documentId,
|
@@ -1738,10 +2273,6 @@ const UpdateAction = ({
|
|
1738
2273
|
const cloneMatch = useMatch(CLONE_PATH);
|
1739
2274
|
const isCloning = cloneMatch !== null;
|
1740
2275
|
const { formatMessage } = useIntl();
|
1741
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1742
|
-
canCreate: canCreate2,
|
1743
|
-
canUpdate: canUpdate2
|
1744
|
-
}));
|
1745
2276
|
const { create, update, clone } = useDocumentActions();
|
1746
2277
|
const [{ query, rawQuery }] = useQueryParams();
|
1747
2278
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1752,90 +2283,134 @@ const UpdateAction = ({
|
|
1752
2283
|
const validate = useForm("UpdateAction", (state) => state.validate);
|
1753
2284
|
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1754
2285
|
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1755
|
-
|
1756
|
-
|
1757
|
-
|
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
|
-
if (
|
1784
|
-
|
2286
|
+
const handleUpdate = React.useCallback(async () => {
|
2287
|
+
setSubmitting(true);
|
2288
|
+
try {
|
2289
|
+
if (!modified) {
|
2290
|
+
return;
|
2291
|
+
}
|
2292
|
+
const { errors } = await validate(true, {
|
2293
|
+
status: "draft"
|
2294
|
+
});
|
2295
|
+
if (errors) {
|
2296
|
+
toggleNotification({
|
2297
|
+
type: "danger",
|
2298
|
+
message: formatMessage({
|
2299
|
+
id: "content-manager.validation.error",
|
2300
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2301
|
+
})
|
2302
|
+
});
|
2303
|
+
return;
|
2304
|
+
}
|
2305
|
+
if (isCloning) {
|
2306
|
+
const res = await clone(
|
2307
|
+
{
|
2308
|
+
model,
|
2309
|
+
documentId: cloneMatch.params.origin,
|
2310
|
+
params
|
2311
|
+
},
|
2312
|
+
transformData(document)
|
2313
|
+
);
|
2314
|
+
if ("data" in res) {
|
2315
|
+
navigate(
|
1785
2316
|
{
|
1786
|
-
|
1787
|
-
documentId: cloneMatch.params.origin,
|
1788
|
-
params
|
1789
|
-
},
|
1790
|
-
document
|
1791
|
-
);
|
1792
|
-
if ("data" in res) {
|
1793
|
-
navigate({
|
1794
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2317
|
+
pathname: `../${res.data.documentId}`,
|
1795
2318
|
search: rawQuery
|
1796
|
-
});
|
1797
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1798
|
-
setErrors(formatValidationErrors(res.error));
|
1799
|
-
}
|
1800
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1801
|
-
const res = await update(
|
1802
|
-
{
|
1803
|
-
collectionType,
|
1804
|
-
model,
|
1805
|
-
documentId,
|
1806
|
-
params
|
1807
2319
|
},
|
1808
|
-
|
2320
|
+
{ relative: "path" }
|
1809
2321
|
);
|
1810
|
-
|
1811
|
-
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
2322
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2323
|
+
setErrors(formatValidationErrors(res.error));
|
2324
|
+
}
|
2325
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2326
|
+
const res = await update(
|
2327
|
+
{
|
2328
|
+
collectionType,
|
2329
|
+
model,
|
2330
|
+
documentId,
|
2331
|
+
params
|
2332
|
+
},
|
2333
|
+
transformData(document)
|
2334
|
+
);
|
2335
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2336
|
+
setErrors(formatValidationErrors(res.error));
|
1815
2337
|
} else {
|
1816
|
-
|
2338
|
+
resetForm();
|
2339
|
+
}
|
2340
|
+
} else {
|
2341
|
+
const res = await create(
|
2342
|
+
{
|
2343
|
+
model,
|
2344
|
+
params
|
2345
|
+
},
|
2346
|
+
transformData(document)
|
2347
|
+
);
|
2348
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2349
|
+
navigate(
|
1817
2350
|
{
|
1818
|
-
|
1819
|
-
|
2351
|
+
pathname: `../${res.data.documentId}`,
|
2352
|
+
search: rawQuery
|
1820
2353
|
},
|
1821
|
-
|
2354
|
+
{ replace: true, relative: "path" }
|
1822
2355
|
);
|
1823
|
-
|
1824
|
-
|
1825
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1826
|
-
search: rawQuery
|
1827
|
-
});
|
1828
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1829
|
-
setErrors(formatValidationErrors(res.error));
|
1830
|
-
}
|
2356
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2357
|
+
setErrors(formatValidationErrors(res.error));
|
1831
2358
|
}
|
1832
|
-
} finally {
|
1833
|
-
setSubmitting(false);
|
1834
2359
|
}
|
2360
|
+
} finally {
|
2361
|
+
setSubmitting(false);
|
1835
2362
|
}
|
2363
|
+
}, [
|
2364
|
+
clone,
|
2365
|
+
cloneMatch?.params.origin,
|
2366
|
+
collectionType,
|
2367
|
+
create,
|
2368
|
+
document,
|
2369
|
+
documentId,
|
2370
|
+
formatMessage,
|
2371
|
+
formatValidationErrors,
|
2372
|
+
isCloning,
|
2373
|
+
model,
|
2374
|
+
modified,
|
2375
|
+
navigate,
|
2376
|
+
params,
|
2377
|
+
rawQuery,
|
2378
|
+
resetForm,
|
2379
|
+
setErrors,
|
2380
|
+
setSubmitting,
|
2381
|
+
toggleNotification,
|
2382
|
+
update,
|
2383
|
+
validate
|
2384
|
+
]);
|
2385
|
+
React.useEffect(() => {
|
2386
|
+
const handleKeyDown = (e) => {
|
2387
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
2388
|
+
e.preventDefault();
|
2389
|
+
handleUpdate();
|
2390
|
+
}
|
2391
|
+
};
|
2392
|
+
window.addEventListener("keydown", handleKeyDown);
|
2393
|
+
return () => {
|
2394
|
+
window.removeEventListener("keydown", handleKeyDown);
|
2395
|
+
};
|
2396
|
+
}, [handleUpdate]);
|
2397
|
+
return {
|
2398
|
+
/**
|
2399
|
+
* Disabled when:
|
2400
|
+
* - the form is submitting
|
2401
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2402
|
+
* - the active tab is the published tab
|
2403
|
+
*/
|
2404
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2405
|
+
label: formatMessage({
|
2406
|
+
id: "global.save",
|
2407
|
+
defaultMessage: "Save"
|
2408
|
+
}),
|
2409
|
+
onClick: handleUpdate
|
1836
2410
|
};
|
1837
2411
|
};
|
1838
2412
|
UpdateAction.type = "update";
|
2413
|
+
UpdateAction.position = "panel";
|
1839
2414
|
const UNPUBLISH_DRAFT_OPTIONS = {
|
1840
2415
|
KEEP: "keep",
|
1841
2416
|
DISCARD: "discard"
|
@@ -1868,7 +2443,7 @@ const UnpublishAction$1 = ({
|
|
1868
2443
|
id: "app.utils.unpublish",
|
1869
2444
|
defaultMessage: "Unpublish"
|
1870
2445
|
}),
|
1871
|
-
icon: /* @__PURE__ */ jsx(
|
2446
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1872
2447
|
onClick: async () => {
|
1873
2448
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1874
2449
|
if (!documentId) {
|
@@ -1958,6 +2533,7 @@ const UnpublishAction$1 = ({
|
|
1958
2533
|
};
|
1959
2534
|
};
|
1960
2535
|
UnpublishAction$1.type = "unpublish";
|
2536
|
+
UnpublishAction$1.position = "panel";
|
1961
2537
|
const DiscardAction = ({
|
1962
2538
|
activeTab,
|
1963
2539
|
documentId,
|
@@ -1980,7 +2556,7 @@ const DiscardAction = ({
|
|
1980
2556
|
id: "content-manager.actions.discard.label",
|
1981
2557
|
defaultMessage: "Discard changes"
|
1982
2558
|
}),
|
1983
|
-
icon: /* @__PURE__ */ jsx(
|
2559
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1984
2560
|
position: ["panel", "table-row"],
|
1985
2561
|
variant: "danger",
|
1986
2562
|
dialog: {
|
@@ -2008,11 +2584,7 @@ const DiscardAction = ({
|
|
2008
2584
|
};
|
2009
2585
|
};
|
2010
2586
|
DiscardAction.type = "discard";
|
2011
|
-
|
2012
|
-
path {
|
2013
|
-
fill: currentColor;
|
2014
|
-
}
|
2015
|
-
`;
|
2587
|
+
DiscardAction.position = "panel";
|
2016
2588
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2017
2589
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2018
2590
|
const RelativeTime = React.forwardRef(
|
@@ -2025,7 +2597,7 @@ const RelativeTime = React.forwardRef(
|
|
2025
2597
|
});
|
2026
2598
|
const unit = intervals.find((intervalUnit) => {
|
2027
2599
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2028
|
-
});
|
2600
|
+
}) ?? "seconds";
|
2029
2601
|
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2030
2602
|
const customInterval = customIntervals.find(
|
2031
2603
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2059,34 +2631,34 @@ const getDisplayName = ({
|
|
2059
2631
|
return email ?? "";
|
2060
2632
|
};
|
2061
2633
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2062
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2063
|
-
const statusVariant = status === "draft" ? "
|
2064
|
-
|
2634
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2635
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2636
|
+
const { formatMessage } = useIntl();
|
2637
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2638
|
+
id: `content-manager.containers.List.${status}`,
|
2639
|
+
defaultMessage: capitalise(status)
|
2640
|
+
}) }) });
|
2065
2641
|
};
|
2066
2642
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2067
2643
|
const { formatMessage } = useIntl();
|
2068
2644
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2645
|
+
const params = useParams();
|
2069
2646
|
const title = isCreating ? formatMessage({
|
2070
2647
|
id: "content-manager.containers.edit.title.new",
|
2071
2648
|
defaultMessage: "Create an entry"
|
2072
2649
|
}) : documentTitle;
|
2073
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2074
|
-
/* @__PURE__ */ jsx(
|
2075
|
-
|
2076
|
-
Flex,
|
2650
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2651
|
+
/* @__PURE__ */ jsx(
|
2652
|
+
BackButton,
|
2077
2653
|
{
|
2078
|
-
|
2079
|
-
justifyContent: "space-between",
|
2080
|
-
paddingTop: 1,
|
2081
|
-
gap: "80px",
|
2082
|
-
alignItems: "flex-start",
|
2083
|
-
children: [
|
2084
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2085
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2086
|
-
]
|
2654
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2087
2655
|
}
|
2088
2656
|
),
|
2089
|
-
|
2657
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2658
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2659
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2660
|
+
] }),
|
2661
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2090
2662
|
] });
|
2091
2663
|
};
|
2092
2664
|
const HeaderToolbar = () => {
|
@@ -2132,7 +2704,7 @@ const HeaderToolbar = () => {
|
|
2132
2704
|
meta: isCloning ? void 0 : meta,
|
2133
2705
|
collectionType
|
2134
2706
|
},
|
2135
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2707
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
|
2136
2708
|
children: (actions2) => {
|
2137
2709
|
const headerActions = actions2.filter((action) => {
|
2138
2710
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2169,12 +2741,12 @@ const Information = ({ activeTab }) => {
|
|
2169
2741
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2170
2742
|
label: formatMessage({
|
2171
2743
|
id: "content-manager.containers.edit.information.last-published.label",
|
2172
|
-
defaultMessage: "
|
2744
|
+
defaultMessage: "Published"
|
2173
2745
|
}),
|
2174
2746
|
value: formatMessage(
|
2175
2747
|
{
|
2176
2748
|
id: "content-manager.containers.edit.information.last-published.value",
|
2177
|
-
defaultMessage: `
|
2749
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2178
2750
|
},
|
2179
2751
|
{
|
2180
2752
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2187,12 +2759,12 @@ const Information = ({ activeTab }) => {
|
|
2187
2759
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2188
2760
|
label: formatMessage({
|
2189
2761
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2190
|
-
defaultMessage: "
|
2762
|
+
defaultMessage: "Updated"
|
2191
2763
|
}),
|
2192
2764
|
value: formatMessage(
|
2193
2765
|
{
|
2194
2766
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2195
|
-
defaultMessage: `
|
2767
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2196
2768
|
},
|
2197
2769
|
{
|
2198
2770
|
time: /* @__PURE__ */ jsx(
|
@@ -2210,12 +2782,12 @@ const Information = ({ activeTab }) => {
|
|
2210
2782
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2211
2783
|
label: formatMessage({
|
2212
2784
|
id: "content-manager.containers.edit.information.document.label",
|
2213
|
-
defaultMessage: "
|
2785
|
+
defaultMessage: "Created"
|
2214
2786
|
}),
|
2215
2787
|
value: formatMessage(
|
2216
2788
|
{
|
2217
2789
|
id: "content-manager.containers.edit.information.document.value",
|
2218
|
-
defaultMessage: `
|
2790
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2219
2791
|
},
|
2220
2792
|
{
|
2221
2793
|
time: /* @__PURE__ */ jsx(
|
@@ -2253,25 +2825,77 @@ const Information = ({ activeTab }) => {
|
|
2253
2825
|
);
|
2254
2826
|
};
|
2255
2827
|
const HeaderActions = ({ actions: actions2 }) => {
|
2256
|
-
|
2257
|
-
|
2828
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2829
|
+
const handleClick = (action) => async (e) => {
|
2830
|
+
if (!("options" in action)) {
|
2831
|
+
const { onClick = () => false, dialog, id } = action;
|
2832
|
+
const muteDialog = await onClick(e);
|
2833
|
+
if (dialog && !muteDialog) {
|
2834
|
+
e.preventDefault();
|
2835
|
+
setDialogId(id);
|
2836
|
+
}
|
2837
|
+
}
|
2838
|
+
};
|
2839
|
+
const handleClose = () => {
|
2840
|
+
setDialogId(null);
|
2841
|
+
};
|
2842
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2843
|
+
if (action.options) {
|
2258
2844
|
return /* @__PURE__ */ jsx(
|
2259
2845
|
SingleSelect,
|
2260
2846
|
{
|
2261
2847
|
size: "S",
|
2262
|
-
disabled: action.disabled,
|
2263
|
-
"aria-label": action.label,
|
2264
2848
|
onChange: action.onSelect,
|
2265
|
-
|
2849
|
+
"aria-label": action.label,
|
2850
|
+
...action,
|
2266
2851
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2267
2852
|
},
|
2268
2853
|
action.id
|
2269
2854
|
);
|
2270
2855
|
} else {
|
2271
|
-
|
2856
|
+
if (action.type === "icon") {
|
2857
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2858
|
+
/* @__PURE__ */ jsx(
|
2859
|
+
IconButton,
|
2860
|
+
{
|
2861
|
+
disabled: action.disabled,
|
2862
|
+
label: action.label,
|
2863
|
+
size: "S",
|
2864
|
+
onClick: handleClick(action),
|
2865
|
+
children: action.icon
|
2866
|
+
}
|
2867
|
+
),
|
2868
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2869
|
+
HeaderActionDialog,
|
2870
|
+
{
|
2871
|
+
...action.dialog,
|
2872
|
+
isOpen: dialogId === action.id,
|
2873
|
+
onClose: handleClose
|
2874
|
+
}
|
2875
|
+
) : null
|
2876
|
+
] }, action.id);
|
2877
|
+
}
|
2272
2878
|
}
|
2273
2879
|
}) });
|
2274
2880
|
};
|
2881
|
+
const HeaderActionDialog = ({
|
2882
|
+
onClose,
|
2883
|
+
onCancel,
|
2884
|
+
title,
|
2885
|
+
content: Content,
|
2886
|
+
isOpen
|
2887
|
+
}) => {
|
2888
|
+
const handleClose = async () => {
|
2889
|
+
if (onCancel) {
|
2890
|
+
await onCancel();
|
2891
|
+
}
|
2892
|
+
onClose();
|
2893
|
+
};
|
2894
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2895
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2896
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2897
|
+
] }) });
|
2898
|
+
};
|
2275
2899
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2276
2900
|
const navigate = useNavigate();
|
2277
2901
|
const { formatMessage } = useIntl();
|
@@ -2288,6 +2912,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2288
2912
|
};
|
2289
2913
|
};
|
2290
2914
|
ConfigureTheViewAction.type = "configure-the-view";
|
2915
|
+
ConfigureTheViewAction.position = "header";
|
2291
2916
|
const EditTheModelAction = ({ model }) => {
|
2292
2917
|
const navigate = useNavigate();
|
2293
2918
|
const { formatMessage } = useIntl();
|
@@ -2304,6 +2929,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2304
2929
|
};
|
2305
2930
|
};
|
2306
2931
|
EditTheModelAction.type = "edit-the-model";
|
2932
|
+
EditTheModelAction.position = "header";
|
2307
2933
|
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2308
2934
|
const navigate = useNavigate();
|
2309
2935
|
const { formatMessage } = useIntl();
|
@@ -2312,12 +2938,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2312
2938
|
const { delete: deleteAction } = useDocumentActions();
|
2313
2939
|
const { toggleNotification } = useNotification();
|
2314
2940
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2941
|
+
const isLocalized = document?.locale != null;
|
2315
2942
|
return {
|
2316
2943
|
disabled: !canDelete || !document,
|
2317
|
-
label: formatMessage(
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2944
|
+
label: formatMessage(
|
2945
|
+
{
|
2946
|
+
id: "content-manager.actions.delete.label",
|
2947
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2948
|
+
},
|
2949
|
+
{ isLocalized }
|
2950
|
+
),
|
2321
2951
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2322
2952
|
dialog: {
|
2323
2953
|
type: "dialog",
|
@@ -2373,403 +3003,102 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2373
3003
|
};
|
2374
3004
|
};
|
2375
3005
|
DeleteAction$1.type = "delete";
|
3006
|
+
DeleteAction$1.position = ["header", "table-row"];
|
2376
3007
|
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2377
3008
|
const Panels = () => {
|
2378
3009
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2379
3010
|
const [
|
2380
3011
|
{
|
2381
|
-
query: { status }
|
2382
|
-
}
|
2383
|
-
] = useQueryParams({
|
2384
|
-
status: "draft"
|
2385
|
-
});
|
2386
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2387
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2388
|
-
const props = {
|
2389
|
-
activeTab: status,
|
2390
|
-
model,
|
2391
|
-
documentId: id,
|
2392
|
-
document: isCloning ? void 0 : document,
|
2393
|
-
meta: isCloning ? void 0 : meta,
|
2394
|
-
collectionType
|
2395
|
-
};
|
2396
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2397
|
-
DescriptionComponentRenderer,
|
2398
|
-
{
|
2399
|
-
props,
|
2400
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2401
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2402
|
-
}
|
2403
|
-
) });
|
2404
|
-
};
|
2405
|
-
const ActionsPanel = () => {
|
2406
|
-
const { formatMessage } = useIntl();
|
2407
|
-
return {
|
2408
|
-
title: formatMessage({
|
2409
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2410
|
-
defaultMessage: "Document"
|
2411
|
-
}),
|
2412
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2413
|
-
};
|
2414
|
-
};
|
2415
|
-
ActionsPanel.type = "actions";
|
2416
|
-
const ActionsPanelContent = () => {
|
2417
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2418
|
-
const [
|
2419
|
-
{
|
2420
|
-
query: { status = "draft" }
|
2421
|
-
}
|
2422
|
-
] = useQueryParams();
|
2423
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2424
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2425
|
-
const props = {
|
2426
|
-
activeTab: status,
|
2427
|
-
model,
|
2428
|
-
documentId: id,
|
2429
|
-
document: isCloning ? void 0 : document,
|
2430
|
-
meta: isCloning ? void 0 : meta,
|
2431
|
-
collectionType
|
2432
|
-
};
|
2433
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2434
|
-
/* @__PURE__ */ jsx(
|
2435
|
-
DescriptionComponentRenderer,
|
2436
|
-
{
|
2437
|
-
props,
|
2438
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2439
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2440
|
-
}
|
2441
|
-
),
|
2442
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2443
|
-
] });
|
2444
|
-
};
|
2445
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2446
|
-
return /* @__PURE__ */ jsxs(
|
2447
|
-
Flex,
|
2448
|
-
{
|
2449
|
-
ref,
|
2450
|
-
tag: "aside",
|
2451
|
-
"aria-labelledby": "additional-information",
|
2452
|
-
background: "neutral0",
|
2453
|
-
borderColor: "neutral150",
|
2454
|
-
hasRadius: true,
|
2455
|
-
paddingBottom: 4,
|
2456
|
-
paddingLeft: 4,
|
2457
|
-
paddingRight: 4,
|
2458
|
-
paddingTop: 4,
|
2459
|
-
shadow: "tableShadow",
|
2460
|
-
gap: 3,
|
2461
|
-
direction: "column",
|
2462
|
-
justifyContent: "stretch",
|
2463
|
-
alignItems: "flex-start",
|
2464
|
-
children: [
|
2465
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2466
|
-
children
|
2467
|
-
]
|
2468
|
-
}
|
2469
|
-
);
|
2470
|
-
});
|
2471
|
-
const HOOKS = {
|
2472
|
-
/**
|
2473
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2474
|
-
* @constant
|
2475
|
-
* @type {string}
|
2476
|
-
*/
|
2477
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2478
|
-
/**
|
2479
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2480
|
-
* @constant
|
2481
|
-
* @type {string}
|
2482
|
-
*/
|
2483
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2484
|
-
/**
|
2485
|
-
* Hook that allows to mutate the CM's edit view layout
|
2486
|
-
* @constant
|
2487
|
-
* @type {string}
|
2488
|
-
*/
|
2489
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2490
|
-
/**
|
2491
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2492
|
-
* @constant
|
2493
|
-
* @type {string}
|
2494
|
-
*/
|
2495
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2496
|
-
};
|
2497
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2498
|
-
endpoints: (builder) => ({
|
2499
|
-
getContentTypeConfiguration: builder.query({
|
2500
|
-
query: (uid) => ({
|
2501
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2502
|
-
method: "GET"
|
2503
|
-
}),
|
2504
|
-
transformResponse: (response) => response.data,
|
2505
|
-
providesTags: (_result, _error, uid) => [
|
2506
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2507
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2508
|
-
]
|
2509
|
-
}),
|
2510
|
-
getAllContentTypeSettings: builder.query({
|
2511
|
-
query: () => "/content-manager/content-types-settings",
|
2512
|
-
transformResponse: (response) => response.data,
|
2513
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2514
|
-
}),
|
2515
|
-
updateContentTypeConfiguration: builder.mutation({
|
2516
|
-
query: ({ uid, ...body }) => ({
|
2517
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2518
|
-
method: "PUT",
|
2519
|
-
data: body
|
2520
|
-
}),
|
2521
|
-
transformResponse: (response) => response.data,
|
2522
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2523
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2524
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2525
|
-
// Is this necessary?
|
2526
|
-
{ type: "InitialData" }
|
2527
|
-
]
|
2528
|
-
})
|
2529
|
-
})
|
2530
|
-
});
|
2531
|
-
const {
|
2532
|
-
useGetContentTypeConfigurationQuery,
|
2533
|
-
useGetAllContentTypeSettingsQuery,
|
2534
|
-
useUpdateContentTypeConfigurationMutation
|
2535
|
-
} = contentTypesApi;
|
2536
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2537
|
-
const { type } = attribute;
|
2538
|
-
if (type === "relation") {
|
2539
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2540
|
-
}
|
2541
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2542
|
-
};
|
2543
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2544
|
-
if (!mainFieldName) {
|
2545
|
-
return void 0;
|
2546
|
-
}
|
2547
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2548
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2549
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2550
|
-
);
|
2551
|
-
return {
|
2552
|
-
name: mainFieldName,
|
2553
|
-
type: mainFieldType ?? "string"
|
2554
|
-
};
|
2555
|
-
};
|
2556
|
-
const DEFAULT_SETTINGS = {
|
2557
|
-
bulkable: false,
|
2558
|
-
filterable: false,
|
2559
|
-
searchable: false,
|
2560
|
-
pagination: false,
|
2561
|
-
defaultSortBy: "",
|
2562
|
-
defaultSortOrder: "asc",
|
2563
|
-
mainField: "id",
|
2564
|
-
pageSize: 10
|
2565
|
-
};
|
2566
|
-
const useDocumentLayout = (model) => {
|
2567
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2568
|
-
const [{ query }] = useQueryParams();
|
2569
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2570
|
-
const { toggleNotification } = useNotification();
|
2571
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2572
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2573
|
-
const {
|
2574
|
-
data,
|
2575
|
-
isLoading: isLoadingConfigs,
|
2576
|
-
error,
|
2577
|
-
isFetching: isFetchingConfigs
|
2578
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2579
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2580
|
-
React.useEffect(() => {
|
2581
|
-
if (error) {
|
2582
|
-
toggleNotification({
|
2583
|
-
type: "danger",
|
2584
|
-
message: formatAPIError(error)
|
2585
|
-
});
|
2586
|
-
}
|
2587
|
-
}, [error, formatAPIError, toggleNotification]);
|
2588
|
-
const editLayout = React.useMemo(
|
2589
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2590
|
-
layout: [],
|
2591
|
-
components: {},
|
2592
|
-
metadatas: {},
|
2593
|
-
options: {},
|
2594
|
-
settings: DEFAULT_SETTINGS
|
2595
|
-
},
|
2596
|
-
[data, isLoading, schemas, schema, components]
|
2597
|
-
);
|
2598
|
-
const listLayout = React.useMemo(() => {
|
2599
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2600
|
-
layout: [],
|
2601
|
-
metadatas: {},
|
2602
|
-
options: {},
|
2603
|
-
settings: DEFAULT_SETTINGS
|
2604
|
-
};
|
2605
|
-
}, [data, isLoading, schemas, schema, components]);
|
2606
|
-
const { layout: edit } = React.useMemo(
|
2607
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2608
|
-
layout: editLayout,
|
2609
|
-
query
|
2610
|
-
}),
|
2611
|
-
[editLayout, query, runHookWaterfall]
|
2612
|
-
);
|
2613
|
-
return {
|
2614
|
-
error,
|
2615
|
-
isLoading,
|
2616
|
-
edit,
|
2617
|
-
list: listLayout
|
2618
|
-
};
|
2619
|
-
};
|
2620
|
-
const useDocLayout = () => {
|
2621
|
-
const { model } = useDoc();
|
2622
|
-
return useDocumentLayout(model);
|
2623
|
-
};
|
2624
|
-
const formatEditLayout = (data, {
|
2625
|
-
schemas,
|
2626
|
-
schema,
|
2627
|
-
components
|
2628
|
-
}) => {
|
2629
|
-
let currentPanelIndex = 0;
|
2630
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2631
|
-
data.contentType.layouts.edit,
|
2632
|
-
schema?.attributes,
|
2633
|
-
data.contentType.metadatas,
|
2634
|
-
{ configurations: data.components, schemas: components },
|
2635
|
-
schemas
|
2636
|
-
).reduce((panels, row) => {
|
2637
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2638
|
-
panels.push([row]);
|
2639
|
-
currentPanelIndex += 2;
|
2640
|
-
} else {
|
2641
|
-
if (!panels[currentPanelIndex]) {
|
2642
|
-
panels.push([]);
|
2643
|
-
}
|
2644
|
-
panels[currentPanelIndex].push(row);
|
2645
|
-
}
|
2646
|
-
return panels;
|
2647
|
-
}, []);
|
2648
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2649
|
-
(acc, [uid, configuration]) => {
|
2650
|
-
acc[uid] = {
|
2651
|
-
layout: convertEditLayoutToFieldLayouts(
|
2652
|
-
configuration.layouts.edit,
|
2653
|
-
components[uid].attributes,
|
2654
|
-
configuration.metadatas
|
2655
|
-
),
|
2656
|
-
settings: {
|
2657
|
-
...configuration.settings,
|
2658
|
-
icon: components[uid].info.icon,
|
2659
|
-
displayName: components[uid].info.displayName
|
2660
|
-
}
|
2661
|
-
};
|
2662
|
-
return acc;
|
2663
|
-
},
|
2664
|
-
{}
|
2665
|
-
);
|
2666
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2667
|
-
(acc, [attribute, metadata]) => {
|
2668
|
-
return {
|
2669
|
-
...acc,
|
2670
|
-
[attribute]: metadata.edit
|
2671
|
-
};
|
2672
|
-
},
|
2673
|
-
{}
|
2674
|
-
);
|
2675
|
-
return {
|
2676
|
-
layout: panelledEditAttributes,
|
2677
|
-
components: componentEditAttributes,
|
2678
|
-
metadatas: editMetadatas,
|
2679
|
-
settings: {
|
2680
|
-
...data.contentType.settings,
|
2681
|
-
displayName: schema?.info.displayName
|
2682
|
-
},
|
2683
|
-
options: {
|
2684
|
-
...schema?.options,
|
2685
|
-
...schema?.pluginOptions,
|
2686
|
-
...data.contentType.options
|
3012
|
+
query: { status }
|
2687
3013
|
}
|
3014
|
+
] = useQueryParams({
|
3015
|
+
status: "draft"
|
3016
|
+
});
|
3017
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3018
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
3019
|
+
const props = {
|
3020
|
+
activeTab: status,
|
3021
|
+
model,
|
3022
|
+
documentId: id,
|
3023
|
+
document: isCloning ? void 0 : document,
|
3024
|
+
meta: isCloning ? void 0 : meta,
|
3025
|
+
collectionType
|
2688
3026
|
};
|
3027
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
3028
|
+
DescriptionComponentRenderer,
|
3029
|
+
{
|
3030
|
+
props,
|
3031
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
3032
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
3033
|
+
}
|
3034
|
+
) });
|
2689
3035
|
};
|
2690
|
-
const
|
2691
|
-
|
2692
|
-
(row) => row.map((field) => {
|
2693
|
-
const attribute = attributes[field.name];
|
2694
|
-
if (!attribute) {
|
2695
|
-
return null;
|
2696
|
-
}
|
2697
|
-
const { edit: metadata } = metadatas[field.name];
|
2698
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2699
|
-
return {
|
2700
|
-
attribute,
|
2701
|
-
disabled: !metadata.editable,
|
2702
|
-
hint: metadata.description,
|
2703
|
-
label: metadata.label ?? "",
|
2704
|
-
name: field.name,
|
2705
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2706
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2707
|
-
schemas,
|
2708
|
-
components: components?.schemas ?? {}
|
2709
|
-
}),
|
2710
|
-
placeholder: metadata.placeholder ?? "",
|
2711
|
-
required: attribute.required ?? false,
|
2712
|
-
size: field.size,
|
2713
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2714
|
-
visible: metadata.visible ?? true,
|
2715
|
-
type: attribute.type
|
2716
|
-
};
|
2717
|
-
}).filter((field) => field !== null)
|
2718
|
-
);
|
2719
|
-
};
|
2720
|
-
const formatListLayout = (data, {
|
2721
|
-
schemas,
|
2722
|
-
schema,
|
2723
|
-
components
|
2724
|
-
}) => {
|
2725
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2726
|
-
(acc, [attribute, metadata]) => {
|
2727
|
-
return {
|
2728
|
-
...acc,
|
2729
|
-
[attribute]: metadata.list
|
2730
|
-
};
|
2731
|
-
},
|
2732
|
-
{}
|
2733
|
-
);
|
2734
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2735
|
-
data.contentType.layouts.list,
|
2736
|
-
schema?.attributes,
|
2737
|
-
listMetadatas,
|
2738
|
-
{ configurations: data.components, schemas: components },
|
2739
|
-
schemas
|
2740
|
-
);
|
3036
|
+
const ActionsPanel = () => {
|
3037
|
+
const { formatMessage } = useIntl();
|
2741
3038
|
return {
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
...schema?.pluginOptions,
|
2748
|
-
...data.contentType.options
|
2749
|
-
}
|
3039
|
+
title: formatMessage({
|
3040
|
+
id: "content-manager.containers.edit.panels.default.title",
|
3041
|
+
defaultMessage: "Entry"
|
3042
|
+
}),
|
3043
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2750
3044
|
};
|
2751
3045
|
};
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
3046
|
+
ActionsPanel.type = "actions";
|
3047
|
+
const ActionsPanelContent = () => {
|
3048
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
3049
|
+
const [
|
3050
|
+
{
|
3051
|
+
query: { status = "draft" }
|
2757
3052
|
}
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
3053
|
+
] = useQueryParams();
|
3054
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3055
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
3056
|
+
const props = {
|
3057
|
+
activeTab: status,
|
3058
|
+
model,
|
3059
|
+
documentId: id,
|
3060
|
+
document: isCloning ? void 0 : document,
|
3061
|
+
meta: isCloning ? void 0 : meta,
|
3062
|
+
collectionType
|
3063
|
+
};
|
3064
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3065
|
+
/* @__PURE__ */ jsx(
|
3066
|
+
DescriptionComponentRenderer,
|
3067
|
+
{
|
3068
|
+
props,
|
3069
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
|
3070
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
3071
|
+
}
|
3072
|
+
),
|
3073
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3074
|
+
] });
|
2772
3075
|
};
|
3076
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
3077
|
+
return /* @__PURE__ */ jsxs(
|
3078
|
+
Flex,
|
3079
|
+
{
|
3080
|
+
ref,
|
3081
|
+
tag: "aside",
|
3082
|
+
"aria-labelledby": "additional-information",
|
3083
|
+
background: "neutral0",
|
3084
|
+
borderColor: "neutral150",
|
3085
|
+
hasRadius: true,
|
3086
|
+
paddingBottom: 4,
|
3087
|
+
paddingLeft: 4,
|
3088
|
+
paddingRight: 4,
|
3089
|
+
paddingTop: 4,
|
3090
|
+
shadow: "tableShadow",
|
3091
|
+
gap: 3,
|
3092
|
+
direction: "column",
|
3093
|
+
justifyContent: "stretch",
|
3094
|
+
alignItems: "flex-start",
|
3095
|
+
children: [
|
3096
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
3097
|
+
children
|
3098
|
+
]
|
3099
|
+
}
|
3100
|
+
);
|
3101
|
+
});
|
2773
3102
|
const ConfirmBulkActionDialog = ({
|
2774
3103
|
onToggleDialog,
|
2775
3104
|
isOpen = false,
|
@@ -2777,7 +3106,7 @@ const ConfirmBulkActionDialog = ({
|
|
2777
3106
|
endAction
|
2778
3107
|
}) => {
|
2779
3108
|
const { formatMessage } = useIntl();
|
2780
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3109
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2781
3110
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2782
3111
|
id: "app.components.ConfirmDialog.title",
|
2783
3112
|
defaultMessage: "Confirmation"
|
@@ -2808,6 +3137,7 @@ const ConfirmDialogPublishAll = ({
|
|
2808
3137
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2809
3138
|
const { model, schema } = useDoc();
|
2810
3139
|
const [{ query }] = useQueryParams();
|
3140
|
+
const enableDraftRelationsCount = false;
|
2811
3141
|
const {
|
2812
3142
|
data: countDraftRelations = 0,
|
2813
3143
|
isLoading,
|
@@ -2819,7 +3149,7 @@ const ConfirmDialogPublishAll = ({
|
|
2819
3149
|
locale: query?.plugins?.i18n?.locale
|
2820
3150
|
},
|
2821
3151
|
{
|
2822
|
-
skip:
|
3152
|
+
skip: !enableDraftRelationsCount
|
2823
3153
|
}
|
2824
3154
|
);
|
2825
3155
|
React.useEffect(() => {
|
@@ -2898,7 +3228,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2898
3228
|
)
|
2899
3229
|
);
|
2900
3230
|
} else {
|
2901
|
-
messages.push(
|
3231
|
+
messages.push(
|
3232
|
+
...formatErrorMessages(
|
3233
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3234
|
+
value,
|
3235
|
+
currentKey,
|
3236
|
+
formatMessage
|
3237
|
+
)
|
3238
|
+
);
|
2902
3239
|
}
|
2903
3240
|
} else {
|
2904
3241
|
messages.push(
|
@@ -2997,7 +3334,7 @@ const SelectedEntriesTableContent = ({
|
|
2997
3334
|
status: row.status
|
2998
3335
|
}
|
2999
3336
|
) }),
|
3000
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3337
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3001
3338
|
IconButton,
|
3002
3339
|
{
|
3003
3340
|
tag: Link,
|
@@ -3006,23 +3343,16 @@ const SelectedEntriesTableContent = ({
|
|
3006
3343
|
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3007
3344
|
},
|
3008
3345
|
state: { from: pathname },
|
3009
|
-
label: formatMessage(
|
3010
|
-
|
3011
|
-
|
3012
|
-
|
3013
|
-
{
|
3014
|
-
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3015
|
-
defaultMessage: "item line {number}"
|
3016
|
-
},
|
3017
|
-
{ number: index2 + 1 }
|
3018
|
-
)
|
3019
|
-
}
|
3020
|
-
),
|
3346
|
+
label: formatMessage({
|
3347
|
+
id: "content-manager.bulk-publish.edit",
|
3348
|
+
defaultMessage: "Edit"
|
3349
|
+
}),
|
3021
3350
|
target: "_blank",
|
3022
3351
|
marginLeft: "auto",
|
3023
|
-
|
3352
|
+
variant: "ghost",
|
3353
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3024
3354
|
}
|
3025
|
-
) })
|
3355
|
+
) }) })
|
3026
3356
|
] }, row.id)) })
|
3027
3357
|
] });
|
3028
3358
|
};
|
@@ -3059,7 +3389,13 @@ const SelectedEntriesModalContent = ({
|
|
3059
3389
|
);
|
3060
3390
|
const { rows, validationErrors } = React.useMemo(() => {
|
3061
3391
|
if (data.length > 0 && schema) {
|
3062
|
-
const validate = createYupSchema(
|
3392
|
+
const validate = createYupSchema(
|
3393
|
+
schema.attributes,
|
3394
|
+
components,
|
3395
|
+
// Since this is the "Publish" action, the validation
|
3396
|
+
// schema must enforce the rules for published entities
|
3397
|
+
{ status: "published" }
|
3398
|
+
);
|
3063
3399
|
const validationErrors2 = {};
|
3064
3400
|
const rows2 = data.map((entry) => {
|
3065
3401
|
try {
|
@@ -3184,8 +3520,7 @@ const PublishAction = ({ documents, model }) => {
|
|
3184
3520
|
const refetchList = () => {
|
3185
3521
|
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3186
3522
|
};
|
3187
|
-
if (!showPublishButton)
|
3188
|
-
return null;
|
3523
|
+
if (!showPublishButton) return null;
|
3189
3524
|
return {
|
3190
3525
|
actionType: "publish",
|
3191
3526
|
variant: "tertiary",
|
@@ -3253,8 +3588,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
3253
3588
|
selectRow([]);
|
3254
3589
|
}
|
3255
3590
|
};
|
3256
|
-
if (!hasDeletePermission)
|
3257
|
-
return null;
|
3591
|
+
if (!hasDeletePermission) return null;
|
3258
3592
|
return {
|
3259
3593
|
variant: "danger-light",
|
3260
3594
|
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
@@ -3303,8 +3637,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3303
3637
|
}
|
3304
3638
|
};
|
3305
3639
|
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3306
|
-
if (!showUnpublishButton)
|
3307
|
-
return null;
|
3640
|
+
if (!showUnpublishButton) return null;
|
3308
3641
|
return {
|
3309
3642
|
variant: "tertiary",
|
3310
3643
|
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
@@ -3409,7 +3742,7 @@ const TableActions = ({ document }) => {
|
|
3409
3742
|
DescriptionComponentRenderer,
|
3410
3743
|
{
|
3411
3744
|
props,
|
3412
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3745
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
|
3413
3746
|
children: (actions2) => {
|
3414
3747
|
const tableRowActions = actions2.filter((action) => {
|
3415
3748
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3468,6 +3801,7 @@ const EditAction = ({ documentId }) => {
|
|
3468
3801
|
};
|
3469
3802
|
};
|
3470
3803
|
EditAction.type = "edit";
|
3804
|
+
EditAction.position = "table-row";
|
3471
3805
|
const StyledPencil = styled(Pencil)`
|
3472
3806
|
path {
|
3473
3807
|
fill: currentColor;
|
@@ -3520,7 +3854,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3520
3854
|
}),
|
3521
3855
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3522
3856
|
footer: ({ onClose }) => {
|
3523
|
-
return /* @__PURE__ */ jsxs(
|
3857
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3524
3858
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3525
3859
|
id: "cancel",
|
3526
3860
|
defaultMessage: "Cancel"
|
@@ -3544,6 +3878,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3544
3878
|
};
|
3545
3879
|
};
|
3546
3880
|
CloneAction.type = "clone";
|
3881
|
+
CloneAction.position = "table-row";
|
3547
3882
|
const StyledDuplicate = styled(Duplicate)`
|
3548
3883
|
path {
|
3549
3884
|
fill: currentColor;
|
@@ -3561,8 +3896,7 @@ class ContentManagerPlugin {
|
|
3561
3896
|
documentActions = [
|
3562
3897
|
...DEFAULT_ACTIONS,
|
3563
3898
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3564
|
-
...DEFAULT_HEADER_ACTIONS
|
3565
|
-
HistoryAction
|
3899
|
+
...DEFAULT_HEADER_ACTIONS
|
3566
3900
|
];
|
3567
3901
|
editViewSidePanels = [ActionsPanel];
|
3568
3902
|
headerActions = [];
|
@@ -3631,7 +3965,14 @@ class ContentManagerPlugin {
|
|
3631
3965
|
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
3632
3966
|
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
3633
3967
|
getBulkActions: () => this.bulkActions,
|
3634
|
-
getDocumentActions: () =>
|
3968
|
+
getDocumentActions: (position) => {
|
3969
|
+
if (position) {
|
3970
|
+
return this.documentActions.filter(
|
3971
|
+
(action) => action.position == void 0 || [action.position].flat().includes(position)
|
3972
|
+
);
|
3973
|
+
}
|
3974
|
+
return this.documentActions;
|
3975
|
+
},
|
3635
3976
|
getEditViewSidePanels: () => this.editViewSidePanels,
|
3636
3977
|
getHeaderActions: () => this.headerActions
|
3637
3978
|
}
|
@@ -3641,16 +3982,71 @@ class ContentManagerPlugin {
|
|
3641
3982
|
const getPrintableType = (value) => {
|
3642
3983
|
const nativeType = typeof value;
|
3643
3984
|
if (nativeType === "object") {
|
3644
|
-
if (value === null)
|
3645
|
-
|
3646
|
-
if (Array.isArray(value))
|
3647
|
-
return "array";
|
3985
|
+
if (value === null) return "null";
|
3986
|
+
if (Array.isArray(value)) return "array";
|
3648
3987
|
if (value instanceof Object && value.constructor.name !== "Object") {
|
3649
3988
|
return value.constructor.name;
|
3650
3989
|
}
|
3651
3990
|
}
|
3652
3991
|
return nativeType;
|
3653
3992
|
};
|
3993
|
+
const HistoryAction = ({ model, document }) => {
|
3994
|
+
const { formatMessage } = useIntl();
|
3995
|
+
const [{ query }] = useQueryParams();
|
3996
|
+
const navigate = useNavigate();
|
3997
|
+
const { trackUsage } = useTracking();
|
3998
|
+
const { pathname } = useLocation();
|
3999
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
4000
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
4001
|
+
return null;
|
4002
|
+
}
|
4003
|
+
const handleOnClick = () => {
|
4004
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
4005
|
+
trackUsage("willNavigate", {
|
4006
|
+
from: pathname,
|
4007
|
+
to: `${pathname}/${destination.pathname}`
|
4008
|
+
});
|
4009
|
+
navigate(destination);
|
4010
|
+
};
|
4011
|
+
return {
|
4012
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
4013
|
+
label: formatMessage({
|
4014
|
+
id: "content-manager.history.document-action",
|
4015
|
+
defaultMessage: "Content History"
|
4016
|
+
}),
|
4017
|
+
onClick: handleOnClick,
|
4018
|
+
disabled: (
|
4019
|
+
/**
|
4020
|
+
* The user is creating a new document.
|
4021
|
+
* It hasn't been saved yet, so there's no history to go to
|
4022
|
+
*/
|
4023
|
+
!document || /**
|
4024
|
+
* The document has been created but the current dimension has never been saved.
|
4025
|
+
* For example, the user is creating a new locale in an existing document,
|
4026
|
+
* so there's no history for the document in that locale
|
4027
|
+
*/
|
4028
|
+
!document.id || /**
|
4029
|
+
* History is only available for content types created by the user.
|
4030
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
4031
|
+
* which start with `admin::` or `plugin::`
|
4032
|
+
*/
|
4033
|
+
!model.startsWith("api::")
|
4034
|
+
),
|
4035
|
+
position: "header"
|
4036
|
+
};
|
4037
|
+
};
|
4038
|
+
HistoryAction.type = "history";
|
4039
|
+
HistoryAction.position = "header";
|
4040
|
+
const historyAdmin = {
|
4041
|
+
bootstrap(app) {
|
4042
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
4043
|
+
addDocumentAction((actions2) => {
|
4044
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
4045
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
4046
|
+
return actions2;
|
4047
|
+
});
|
4048
|
+
}
|
4049
|
+
};
|
3654
4050
|
const initialState = {
|
3655
4051
|
collectionTypeLinks: [],
|
3656
4052
|
components: [],
|
@@ -3687,6 +4083,88 @@ const { setInitialData } = actions;
|
|
3687
4083
|
const reducer = combineReducers({
|
3688
4084
|
app: reducer$1
|
3689
4085
|
});
|
4086
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
4087
|
+
endpoints: (builder) => ({
|
4088
|
+
getPreviewUrl: builder.query({
|
4089
|
+
query({ query, params }) {
|
4090
|
+
return {
|
4091
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4092
|
+
method: "GET",
|
4093
|
+
config: {
|
4094
|
+
params: query
|
4095
|
+
}
|
4096
|
+
};
|
4097
|
+
}
|
4098
|
+
})
|
4099
|
+
})
|
4100
|
+
});
|
4101
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4102
|
+
const ConditionalTooltip = ({ isShown, label, children }) => {
|
4103
|
+
if (isShown) {
|
4104
|
+
return /* @__PURE__ */ jsx(Tooltip, { label, children });
|
4105
|
+
}
|
4106
|
+
return children;
|
4107
|
+
};
|
4108
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4109
|
+
const { formatMessage } = useIntl();
|
4110
|
+
const { trackUsage } = useTracking();
|
4111
|
+
const { pathname } = useLocation();
|
4112
|
+
const [{ query }] = useQueryParams();
|
4113
|
+
const isModified = useForm("PreviewSidePanel", (state) => state.modified);
|
4114
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4115
|
+
params: {
|
4116
|
+
contentType: model
|
4117
|
+
},
|
4118
|
+
query: {
|
4119
|
+
documentId,
|
4120
|
+
locale: document?.locale,
|
4121
|
+
status: document?.status
|
4122
|
+
}
|
4123
|
+
});
|
4124
|
+
if (!data?.data?.url || error) {
|
4125
|
+
return null;
|
4126
|
+
}
|
4127
|
+
const trackNavigation = () => {
|
4128
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4129
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
4130
|
+
};
|
4131
|
+
return {
|
4132
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4133
|
+
content: /* @__PURE__ */ jsx(
|
4134
|
+
ConditionalTooltip,
|
4135
|
+
{
|
4136
|
+
label: formatMessage({
|
4137
|
+
id: "content-manager.preview.panel.button-disabled-tooltip",
|
4138
|
+
defaultMessage: "Please save to open the preview"
|
4139
|
+
}),
|
4140
|
+
isShown: isModified,
|
4141
|
+
children: /* @__PURE__ */ jsx(Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsx(
|
4142
|
+
Button,
|
4143
|
+
{
|
4144
|
+
variant: "tertiary",
|
4145
|
+
tag: Link,
|
4146
|
+
to: { pathname: "preview", search: stringify(query, { encode: false }) },
|
4147
|
+
onClick: trackNavigation,
|
4148
|
+
width: "100%",
|
4149
|
+
disabled: isModified,
|
4150
|
+
pointerEvents: isModified ? "none" : void 0,
|
4151
|
+
tabIndex: isModified ? -1 : void 0,
|
4152
|
+
children: formatMessage({
|
4153
|
+
id: "content-manager.preview.panel.button",
|
4154
|
+
defaultMessage: "Open preview"
|
4155
|
+
})
|
4156
|
+
}
|
4157
|
+
) })
|
4158
|
+
}
|
4159
|
+
)
|
4160
|
+
};
|
4161
|
+
};
|
4162
|
+
const previewAdmin = {
|
4163
|
+
bootstrap(app) {
|
4164
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4165
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4166
|
+
}
|
4167
|
+
};
|
3690
4168
|
const index = {
|
3691
4169
|
register(app) {
|
3692
4170
|
const cm = new ContentManagerPlugin();
|
@@ -3706,7 +4184,7 @@ const index = {
|
|
3706
4184
|
app.router.addRoute({
|
3707
4185
|
path: "content-manager/*",
|
3708
4186
|
lazy: async () => {
|
3709
|
-
const { Layout } = await import("./layout-
|
4187
|
+
const { Layout } = await import("./layout-B5qsPihj.mjs");
|
3710
4188
|
return {
|
3711
4189
|
Component: Layout
|
3712
4190
|
};
|
@@ -3715,10 +4193,18 @@ const index = {
|
|
3715
4193
|
});
|
3716
4194
|
app.registerPlugin(cm.config);
|
3717
4195
|
},
|
4196
|
+
bootstrap(app) {
|
4197
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4198
|
+
historyAdmin.bootstrap(app);
|
4199
|
+
}
|
4200
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4201
|
+
previewAdmin.bootstrap(app);
|
4202
|
+
}
|
4203
|
+
},
|
3718
4204
|
async registerTrads({ locales }) {
|
3719
4205
|
const importedTrads = await Promise.all(
|
3720
4206
|
locales.map((locale) => {
|
3721
|
-
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-
|
4207
|
+
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-Dtk_ot79.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 }) => {
|
3722
4208
|
return {
|
3723
4209
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3724
4210
|
locale
|
@@ -3739,13 +4225,16 @@ export {
|
|
3739
4225
|
BulkActionsRenderer as B,
|
3740
4226
|
COLLECTION_TYPES as C,
|
3741
4227
|
DocumentStatus as D,
|
3742
|
-
|
3743
|
-
|
3744
|
-
|
4228
|
+
extractContentTypeComponents as E,
|
4229
|
+
DEFAULT_SETTINGS as F,
|
4230
|
+
convertEditLayoutToFieldLayouts as G,
|
3745
4231
|
HOOKS as H,
|
3746
4232
|
InjectionZone as I,
|
3747
|
-
|
3748
|
-
|
4233
|
+
useDocument as J,
|
4234
|
+
useGetPreviewUrlQuery as K,
|
4235
|
+
index as L,
|
4236
|
+
useContentManagerContext as M,
|
4237
|
+
useDocumentActions as N,
|
3749
4238
|
Panels as P,
|
3750
4239
|
RelativeTime as R,
|
3751
4240
|
SINGLE_TYPES as S,
|
@@ -3763,18 +4252,18 @@ export {
|
|
3763
4252
|
PERMISSIONS as k,
|
3764
4253
|
DocumentRBAC as l,
|
3765
4254
|
DOCUMENT_META_FIELDS as m,
|
3766
|
-
|
3767
|
-
|
3768
|
-
|
3769
|
-
|
3770
|
-
|
4255
|
+
CLONE_PATH as n,
|
4256
|
+
useDocLayout as o,
|
4257
|
+
useGetContentTypeConfigurationQuery as p,
|
4258
|
+
CREATOR_FIELDS as q,
|
4259
|
+
getMainField as r,
|
3771
4260
|
setInitialData as s,
|
3772
|
-
|
4261
|
+
getDisplayName as t,
|
3773
4262
|
useContentTypeSchema as u,
|
3774
|
-
|
3775
|
-
|
3776
|
-
|
3777
|
-
|
3778
|
-
|
4263
|
+
checkIfAttributeIsDisplayable as v,
|
4264
|
+
useGetAllDocumentsQuery as w,
|
4265
|
+
convertListLayoutToFieldLayouts as x,
|
4266
|
+
capitalise as y,
|
4267
|
+
useUpdateContentTypeConfigurationMutation as z
|
3779
4268
|
};
|
3780
|
-
//# sourceMappingURL=index-
|
4269
|
+
//# sourceMappingURL=index-Dh2aGTGJ.mjs.map
|