@strapi/content-manager 0.0.0-experimental.16eaafeff6bd4cd49d56f3c31d002cad71a1134a → 0.0.0-experimental.19d775295eb622de3e659110caf22fcd2cd5d10d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/CardDragPreview-C0QyJgRA.js.map +1 -1
- package/dist/_chunks/CardDragPreview-DOxamsuj.mjs.map +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-B5mDY7I0.mjs → ComponentConfigurationPage-B_99pmC0.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-B5mDY7I0.mjs.map → ComponentConfigurationPage-B_99pmC0.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-Tqd-Ji_E.js → ComponentConfigurationPage-NeMPjY5M.js} +5 -6
- package/dist/_chunks/{ComponentConfigurationPage-Tqd-Ji_E.js.map → ComponentConfigurationPage-NeMPjY5M.js.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-B8UqkdtD.mjs → EditConfigurationPage-B0kNlNoj.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-B8UqkdtD.mjs.map → EditConfigurationPage-B0kNlNoj.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-C28IfcPs.js → EditConfigurationPage-n7_xHayb.js} +5 -6
- package/dist/_chunks/{EditConfigurationPage-C28IfcPs.js.map → EditConfigurationPage-n7_xHayb.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-BDL9cM0Q.js → EditViewPage-BT7Achc-.js} +36 -49
- package/dist/_chunks/EditViewPage-BT7Achc-.js.map +1 -0
- package/dist/_chunks/{EditViewPage-DQUCbpW-.mjs → EditViewPage-DYXZs4_2.mjs} +34 -46
- package/dist/_chunks/EditViewPage-DYXZs4_2.mjs.map +1 -0
- package/dist/_chunks/FieldTypeIcon-CMlNO8PE.mjs.map +1 -1
- package/dist/_chunks/FieldTypeIcon-Dnwq_IRF.js.map +1 -1
- package/dist/_chunks/{Form-DVvv6Hst.js → Form-BRmk2Dp3.js} +39 -21
- package/dist/_chunks/Form-BRmk2Dp3.js.map +1 -0
- package/dist/_chunks/{Form-DZGlZ79l.mjs → Form-D3paRF1F.mjs} +37 -18
- package/dist/_chunks/Form-D3paRF1F.mjs.map +1 -0
- package/dist/_chunks/{History-CQl54kNG.js → History-BQpDoOu8.js} +118 -127
- package/dist/_chunks/History-BQpDoOu8.js.map +1 -0
- package/dist/_chunks/{History-DOWk7MB4.mjs → History-CzQbTOwa.mjs} +108 -116
- package/dist/_chunks/History-CzQbTOwa.mjs.map +1 -0
- package/dist/_chunks/{Field-DSGnyyoh.mjs → Input-ww3KFYZr.mjs} +1439 -1320
- package/dist/_chunks/Input-ww3KFYZr.mjs.map +1 -0
- package/dist/_chunks/{Field-D8I8rXr9.js → Input-yM6HnyQa.js} +1431 -1312
- package/dist/_chunks/Input-yM6HnyQa.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-G_22rTAp.js → ListConfigurationPage-B6NsS-0m.js} +25 -13
- package/dist/_chunks/ListConfigurationPage-B6NsS-0m.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-lN3NMkhK.mjs → ListConfigurationPage-Bbw8w5cS.mjs} +25 -12
- package/dist/_chunks/ListConfigurationPage-Bbw8w5cS.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-D_MY3zjg.mjs → ListViewPage-DnOP55pM.mjs} +122 -78
- package/dist/_chunks/ListViewPage-DnOP55pM.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BIEXJtcz.js → ListViewPage-Dt8OUTwO.js} +121 -78
- package/dist/_chunks/ListViewPage-Dt8OUTwO.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CUrrV_mP.mjs → NoContentTypePage-CXKXHNMa.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CUrrV_mP.mjs.map → NoContentTypePage-CXKXHNMa.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-P-gvTfgg.js → NoContentTypePage-Dgm-uj-6.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-P-gvTfgg.js.map → NoContentTypePage-Dgm-uj-6.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CIFc7iTR.js → NoPermissionsPage-CLbU5SOt.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CIFc7iTR.js.map → NoPermissionsPage-CLbU5SOt.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B-DP9Ht4.mjs → NoPermissionsPage-kaj1rPiW.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B-DP9Ht4.mjs.map → NoPermissionsPage-kaj1rPiW.mjs.map} +1 -1
- package/dist/_chunks/Preview-Bieh13Ro.mjs +287 -0
- package/dist/_chunks/Preview-Bieh13Ro.mjs.map +1 -0
- package/dist/_chunks/Preview-CbXHXqBg.js +305 -0
- package/dist/_chunks/Preview-CbXHXqBg.js.map +1 -0
- package/dist/_chunks/{Relations-CSzJbIBP.mjs → Relations-7rWJcZ3_.mjs} +76 -42
- package/dist/_chunks/Relations-7rWJcZ3_.mjs.map +1 -0
- package/dist/_chunks/{Relations-BqSXkgPb.js → Relations-CvifV6Y6.js} +76 -43
- package/dist/_chunks/Relations-CvifV6Y6.js.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-BR48D_RH.js} +39 -18
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-BR48D_RH.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-D65uIF6Y.mjs} +39 -18
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-D65uIF6Y.mjs.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-C43IbhA_.js} +16 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-C43IbhA_.js.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr-DBseuRuB.mjs} +16 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr-DBseuRuB.mjs.map} +1 -1
- package/dist/_chunks/hooks-BAaaKPS_.js.map +1 -1
- package/dist/_chunks/{index-BYpa_5O9.mjs → index-BH2JnYpF.mjs} +1477 -782
- package/dist/_chunks/index-BH2JnYpF.mjs.map +1 -0
- package/dist/_chunks/{index-iXGIUU_l.js → index-DkJQjlak.js} +1459 -764
- package/dist/_chunks/index-DkJQjlak.js.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout-BLa_DTtQ.js → layout-4BqLFW_b.js} +26 -14
- package/dist/_chunks/layout-4BqLFW_b.js.map +1 -0
- package/dist/_chunks/{layout-DT9g7_U1.mjs → layout-bbOlPwLA.mjs} +26 -13
- package/dist/_chunks/layout-bbOlPwLA.mjs.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CHM_mYAI.mjs → relations-HsflnFpO.mjs} +6 -7
- package/dist/_chunks/relations-HsflnFpO.mjs.map +1 -0
- package/dist/_chunks/{relations--l5ixWIN.js → relations-Yc0Z6A20.js} +6 -7
- package/dist/_chunks/relations-Yc0Z6A20.js.map +1 -0
- package/dist/_chunks/{useDragAndDrop-J0TUUbR6.js → useDragAndDrop-BMtgCYzL.js} +5 -9
- package/dist/_chunks/{useDragAndDrop-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/_chunks/usePrev-CZGy2Vjf.mjs +29 -0
- package/dist/_chunks/usePrev-CZGy2Vjf.mjs.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → usePrev-D5J_2fEu.js} +14 -1
- package/dist/_chunks/usePrev-D5J_2fEu.js.map +1 -0
- package/dist/admin/index.js +3 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +6 -4
- package/dist/admin/src/content-manager.d.ts +4 -2
- package/dist/admin/src/exports.d.ts +2 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +49 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +2 -1
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +3 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/Code.d.ts +7 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/Blocks/utils/prismLanguages.d.ts +49 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/DynamicComponent.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/DynamicZone/Field.d.ts +4 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +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/FormLayout.d.ts +27 -0
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/EditView/utils/data.d.ts +1 -0
- 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 +762 -432
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +763 -432
- 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/controllers/history-version.d.ts +1 -1
- package/dist/server/src/history/controllers/history-version.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts +3 -3
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +8 -12
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +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 -16
- package/dist/_chunks/EditViewPage-BDL9cM0Q.js.map +0 -1
- package/dist/_chunks/EditViewPage-DQUCbpW-.mjs.map +0 -1
- package/dist/_chunks/Field-D8I8rXr9.js.map +0 -1
- package/dist/_chunks/Field-DSGnyyoh.mjs.map +0 -1
- package/dist/_chunks/Form-DVvv6Hst.js.map +0 -1
- package/dist/_chunks/Form-DZGlZ79l.mjs.map +0 -1
- package/dist/_chunks/History-CQl54kNG.js.map +0 -1
- package/dist/_chunks/History-DOWk7MB4.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-G_22rTAp.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-lN3NMkhK.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BIEXJtcz.js.map +0 -1
- package/dist/_chunks/ListViewPage-D_MY3zjg.mjs.map +0 -1
- package/dist/_chunks/Relations-BqSXkgPb.js.map +0 -1
- package/dist/_chunks/Relations-CSzJbIBP.mjs.map +0 -1
- package/dist/_chunks/index-BYpa_5O9.mjs.map +0 -1
- package/dist/_chunks/index-iXGIUU_l.js.map +0 -1
- package/dist/_chunks/layout-BLa_DTtQ.js.map +0 -1
- package/dist/_chunks/layout-DT9g7_U1.mjs.map +0 -1
- package/dist/_chunks/relations--l5ixWIN.js.map +0 -1
- package/dist/_chunks/relations-CHM_mYAI.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -2,20 +2,21 @@
|
|
2
2
|
const Icons = require("@strapi/icons");
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
4
4
|
const strapiAdmin = require("@strapi/admin/strapi-admin");
|
5
|
-
const qs = require("qs");
|
6
|
-
const reactIntl = require("react-intl");
|
7
|
-
const reactRouterDom = require("react-router-dom");
|
8
5
|
const React = require("react");
|
9
6
|
const designSystem = require("@strapi/design-system");
|
7
|
+
const mapValues = require("lodash/fp/mapValues");
|
8
|
+
const reactIntl = require("react-intl");
|
9
|
+
const reactRouterDom = require("react-router-dom");
|
10
10
|
const styledComponents = require("styled-components");
|
11
11
|
const yup = require("yup");
|
12
|
+
const fractionalIndexing = require("fractional-indexing");
|
12
13
|
const pipe = require("lodash/fp/pipe");
|
14
|
+
const qs = require("qs");
|
13
15
|
const dateFns = require("date-fns");
|
14
16
|
const toolkit = require("@reduxjs/toolkit");
|
15
17
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
16
18
|
function _interopNamespace(e) {
|
17
|
-
if (e && e.__esModule)
|
18
|
-
return e;
|
19
|
+
if (e && e.__esModule) return e;
|
19
20
|
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } });
|
20
21
|
if (e) {
|
21
22
|
for (const k in e) {
|
@@ -32,15 +33,23 @@ function _interopNamespace(e) {
|
|
32
33
|
return Object.freeze(n);
|
33
34
|
}
|
34
35
|
const React__namespace = /* @__PURE__ */ _interopNamespace(React);
|
36
|
+
const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
|
35
37
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
36
38
|
const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
|
37
|
-
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
39
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
38
40
|
const v = glob[path];
|
39
41
|
if (v) {
|
40
42
|
return typeof v === "function" ? v() : Promise.resolve(v);
|
41
43
|
}
|
42
44
|
return new Promise((_, reject) => {
|
43
|
-
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
45
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
46
|
+
reject.bind(
|
47
|
+
null,
|
48
|
+
new Error(
|
49
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
50
|
+
)
|
51
|
+
)
|
52
|
+
);
|
44
53
|
});
|
45
54
|
};
|
46
55
|
const PLUGIN_ID = "content-manager";
|
@@ -70,42 +79,6 @@ const useInjectionZone = (area) => {
|
|
70
79
|
const [page, position] = area.split(".");
|
71
80
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
72
81
|
};
|
73
|
-
const HistoryAction = ({ model, document }) => {
|
74
|
-
const { formatMessage } = reactIntl.useIntl();
|
75
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
76
|
-
const navigate = reactRouterDom.useNavigate();
|
77
|
-
const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
|
78
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
79
|
-
return null;
|
80
|
-
}
|
81
|
-
return {
|
82
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
|
83
|
-
label: formatMessage({
|
84
|
-
id: "content-manager.history.document-action",
|
85
|
-
defaultMessage: "Content History"
|
86
|
-
}),
|
87
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
88
|
-
disabled: (
|
89
|
-
/**
|
90
|
-
* The user is creating a new document.
|
91
|
-
* It hasn't been saved yet, so there's no history to go to
|
92
|
-
*/
|
93
|
-
!document || /**
|
94
|
-
* The document has been created but the current dimension has never been saved.
|
95
|
-
* For example, the user is creating a new locale in an existing document,
|
96
|
-
* so there's no history for the document in that locale
|
97
|
-
*/
|
98
|
-
!document.id || /**
|
99
|
-
* History is only available for content types created by the user.
|
100
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
101
|
-
* which start with `admin::` or `plugin::`
|
102
|
-
*/
|
103
|
-
!model.startsWith("api::")
|
104
|
-
),
|
105
|
-
position: "header"
|
106
|
-
};
|
107
|
-
};
|
108
|
-
HistoryAction.type = "history";
|
109
82
|
const ID = "id";
|
110
83
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
111
84
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -157,6 +130,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
157
130
|
if (!slug) {
|
158
131
|
throw new Error("Cannot find the slug param in the URL");
|
159
132
|
}
|
133
|
+
const [{ rawQuery }] = strapiAdmin.useQueryParams();
|
160
134
|
const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
|
161
135
|
const contentTypePermissions = React__namespace.useMemo(() => {
|
162
136
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -167,7 +141,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
167
141
|
return { ...acc, [action]: [permission] };
|
168
142
|
}, {});
|
169
143
|
}, [slug, userPermissions]);
|
170
|
-
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
144
|
+
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
145
|
+
contentTypePermissions,
|
146
|
+
permissions ?? void 0,
|
147
|
+
// TODO: useRBAC context should be typed and built differently
|
148
|
+
// We are passing raw query as context to the hook so that it can
|
149
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
150
|
+
rawQuery
|
151
|
+
);
|
171
152
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
172
153
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
173
154
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -207,6 +188,113 @@ const extractAndDedupeFields = (permissions = []) => permissions.flatMap((permis
|
|
207
188
|
(field, index2, arr) => arr.indexOf(field) === index2 && typeof field === "string"
|
208
189
|
);
|
209
190
|
const removeNumericalStrings = (arr) => arr.filter((item) => isNaN(Number(item)));
|
191
|
+
const BLOCK_LIST_ATTRIBUTE_KEYS = ["__component", "__temp_key__"];
|
192
|
+
const traverseData = (predicate, transform) => (schema, components = {}) => (data = {}) => {
|
193
|
+
const traverse = (datum, attributes) => {
|
194
|
+
return Object.entries(datum).reduce((acc, [key, value]) => {
|
195
|
+
const attribute = attributes[key];
|
196
|
+
if (BLOCK_LIST_ATTRIBUTE_KEYS.includes(key) || value === null || value === void 0) {
|
197
|
+
acc[key] = value;
|
198
|
+
return acc;
|
199
|
+
}
|
200
|
+
if (attribute.type === "component") {
|
201
|
+
if (attribute.repeatable) {
|
202
|
+
const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
203
|
+
acc[key] = componentValue.map(
|
204
|
+
(componentData) => traverse(componentData, components[attribute.component]?.attributes ?? {})
|
205
|
+
);
|
206
|
+
} else {
|
207
|
+
const componentValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
208
|
+
acc[key] = traverse(componentValue, components[attribute.component]?.attributes ?? {});
|
209
|
+
}
|
210
|
+
} else if (attribute.type === "dynamiczone") {
|
211
|
+
const dynamicZoneValue = predicate(attribute, value) ? transform(value, attribute) : value;
|
212
|
+
acc[key] = dynamicZoneValue.map(
|
213
|
+
(componentData) => traverse(componentData, components[componentData.__component]?.attributes ?? {})
|
214
|
+
);
|
215
|
+
} else if (predicate(attribute, value)) {
|
216
|
+
acc[key] = transform(value, attribute);
|
217
|
+
} else {
|
218
|
+
acc[key] = value;
|
219
|
+
}
|
220
|
+
return acc;
|
221
|
+
}, {});
|
222
|
+
};
|
223
|
+
return traverse(data, schema.attributes);
|
224
|
+
};
|
225
|
+
const removeProhibitedFields = (prohibitedFields) => traverseData(
|
226
|
+
(attribute) => prohibitedFields.includes(attribute.type),
|
227
|
+
() => ""
|
228
|
+
);
|
229
|
+
const prepareRelations = traverseData(
|
230
|
+
(attribute) => attribute.type === "relation",
|
231
|
+
() => ({
|
232
|
+
connect: [],
|
233
|
+
disconnect: []
|
234
|
+
})
|
235
|
+
);
|
236
|
+
const prepareTempKeys = traverseData(
|
237
|
+
(attribute) => attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone",
|
238
|
+
(data) => {
|
239
|
+
if (Array.isArray(data) && data.length > 0) {
|
240
|
+
const keys = fractionalIndexing.generateNKeysBetween(void 0, void 0, data.length);
|
241
|
+
return data.map((datum, index2) => ({
|
242
|
+
...datum,
|
243
|
+
__temp_key__: keys[index2]
|
244
|
+
}));
|
245
|
+
}
|
246
|
+
return data;
|
247
|
+
}
|
248
|
+
);
|
249
|
+
const removeFieldsThatDontExistOnSchema = (schema) => (data) => {
|
250
|
+
const schemaKeys = Object.keys(schema.attributes);
|
251
|
+
const dataKeys = Object.keys(data);
|
252
|
+
const keysToRemove = dataKeys.filter((key) => !schemaKeys.includes(key));
|
253
|
+
const revisedData = [...keysToRemove, ...DOCUMENT_META_FIELDS].reduce((acc, key) => {
|
254
|
+
delete acc[key];
|
255
|
+
return acc;
|
256
|
+
}, structuredClone(data));
|
257
|
+
return revisedData;
|
258
|
+
};
|
259
|
+
const removeNullValues = (data) => {
|
260
|
+
return Object.entries(data).reduce((acc, [key, value]) => {
|
261
|
+
if (value === null) {
|
262
|
+
return acc;
|
263
|
+
}
|
264
|
+
acc[key] = value;
|
265
|
+
return acc;
|
266
|
+
}, {});
|
267
|
+
};
|
268
|
+
const transformDocument = (schema, components = {}) => (document) => {
|
269
|
+
const transformations = pipe__default.default(
|
270
|
+
removeFieldsThatDontExistOnSchema(schema),
|
271
|
+
removeProhibitedFields(["password"])(schema, components),
|
272
|
+
removeNullValues,
|
273
|
+
prepareRelations(schema, components),
|
274
|
+
prepareTempKeys(schema, components)
|
275
|
+
);
|
276
|
+
return transformations(document);
|
277
|
+
};
|
278
|
+
const createDefaultForm = (contentType, components = {}) => {
|
279
|
+
const traverseSchema = (attributes) => {
|
280
|
+
return Object.entries(attributes).reduce((acc, [key, attribute]) => {
|
281
|
+
if ("default" in attribute) {
|
282
|
+
acc[key] = attribute.default;
|
283
|
+
} else if (attribute.type === "component" && attribute.required) {
|
284
|
+
const defaultComponentForm = traverseSchema(components[attribute.component].attributes);
|
285
|
+
if (attribute.repeatable) {
|
286
|
+
acc[key] = attribute.min ? [...Array(attribute.min).fill(defaultComponentForm)] : [];
|
287
|
+
} else {
|
288
|
+
acc[key] = defaultComponentForm;
|
289
|
+
}
|
290
|
+
} else if (attribute.type === "dynamiczone" && attribute.required) {
|
291
|
+
acc[key] = [];
|
292
|
+
}
|
293
|
+
return acc;
|
294
|
+
}, {});
|
295
|
+
};
|
296
|
+
return traverseSchema(contentType.attributes);
|
297
|
+
};
|
210
298
|
const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
|
211
299
|
addTagTypes: [
|
212
300
|
"ComponentConfiguration",
|
@@ -215,7 +303,9 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
215
303
|
"Document",
|
216
304
|
"InitialData",
|
217
305
|
"HistoryVersion",
|
218
|
-
"Relations"
|
306
|
+
"Relations",
|
307
|
+
"UidAvailability",
|
308
|
+
"RecentDocumentList"
|
219
309
|
]
|
220
310
|
});
|
221
311
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -229,7 +319,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
229
319
|
params: query
|
230
320
|
}
|
231
321
|
}),
|
232
|
-
invalidatesTags: (_result,
|
322
|
+
invalidatesTags: (_result, error, { model }) => {
|
323
|
+
if (error) {
|
324
|
+
return [];
|
325
|
+
}
|
326
|
+
return [{ type: "Document", id: `${model}_LIST` }, "RecentDocumentList"];
|
327
|
+
}
|
233
328
|
}),
|
234
329
|
cloneDocument: builder.mutation({
|
235
330
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -240,7 +335,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
240
335
|
params
|
241
336
|
}
|
242
337
|
}),
|
243
|
-
invalidatesTags: (_result, _error, { model }) => [
|
338
|
+
invalidatesTags: (_result, _error, { model }) => [
|
339
|
+
{ type: "Document", id: `${model}_LIST` },
|
340
|
+
{ type: "UidAvailability", id: model },
|
341
|
+
"RecentDocumentList"
|
342
|
+
]
|
244
343
|
}),
|
245
344
|
/**
|
246
345
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -257,8 +356,22 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
257
356
|
}),
|
258
357
|
invalidatesTags: (result, _error, { model }) => [
|
259
358
|
{ type: "Document", id: `${model}_LIST` },
|
260
|
-
"Relations"
|
261
|
-
|
359
|
+
"Relations",
|
360
|
+
{ type: "UidAvailability", id: model },
|
361
|
+
"RecentDocumentList"
|
362
|
+
],
|
363
|
+
transformResponse: (response, meta, arg) => {
|
364
|
+
if (!("data" in response) && arg.model === "plugin::users-permissions.user") {
|
365
|
+
return {
|
366
|
+
data: response,
|
367
|
+
meta: {
|
368
|
+
availableStatus: [],
|
369
|
+
availableLocales: []
|
370
|
+
}
|
371
|
+
};
|
372
|
+
}
|
373
|
+
return response;
|
374
|
+
}
|
262
375
|
}),
|
263
376
|
deleteDocument: builder.mutation({
|
264
377
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -269,7 +382,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
269
382
|
}
|
270
383
|
}),
|
271
384
|
invalidatesTags: (_result, _error, { collectionType, model }) => [
|
272
|
-
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
385
|
+
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model },
|
386
|
+
"RecentDocumentList"
|
273
387
|
]
|
274
388
|
}),
|
275
389
|
deleteManyDocuments: builder.mutation({
|
@@ -281,7 +395,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
281
395
|
params
|
282
396
|
}
|
283
397
|
}),
|
284
|
-
invalidatesTags: (_res, _error, { model }) => [
|
398
|
+
invalidatesTags: (_res, _error, { model }) => [
|
399
|
+
{ type: "Document", id: `${model}_LIST` },
|
400
|
+
"RecentDocumentList"
|
401
|
+
]
|
285
402
|
}),
|
286
403
|
discardDocument: builder.mutation({
|
287
404
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -298,7 +415,9 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
298
415
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
299
416
|
},
|
300
417
|
{ type: "Document", id: `${model}_LIST` },
|
301
|
-
"Relations"
|
418
|
+
"Relations",
|
419
|
+
{ type: "UidAvailability", id: model },
|
420
|
+
"RecentDocumentList"
|
302
421
|
];
|
303
422
|
}
|
304
423
|
}),
|
@@ -311,11 +430,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
311
430
|
url: `/content-manager/collection-types/${model}`,
|
312
431
|
method: "GET",
|
313
432
|
config: {
|
314
|
-
params
|
433
|
+
params: qs.stringify(params, { encode: true })
|
315
434
|
}
|
316
435
|
}),
|
317
436
|
providesTags: (result, _error, arg) => {
|
318
437
|
return [
|
438
|
+
{ type: "Document", id: `ALL_LIST` },
|
319
439
|
{ type: "Document", id: `${arg.model}_LIST` },
|
320
440
|
...result?.results.map(({ documentId }) => ({
|
321
441
|
type: "Document",
|
@@ -354,6 +474,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
354
474
|
{
|
355
475
|
type: "Document",
|
356
476
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
477
|
+
},
|
478
|
+
// Make it easy to invalidate all individual documents queries for a model
|
479
|
+
{
|
480
|
+
type: "Document",
|
481
|
+
id: `${model}_ALL_ITEMS`
|
357
482
|
}
|
358
483
|
];
|
359
484
|
}
|
@@ -387,7 +512,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
387
512
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
388
513
|
},
|
389
514
|
{ type: "Document", id: `${model}_LIST` },
|
390
|
-
"Relations"
|
515
|
+
"Relations",
|
516
|
+
"RecentDocumentList"
|
391
517
|
];
|
392
518
|
}
|
393
519
|
}),
|
@@ -417,8 +543,23 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
417
543
|
type: "Document",
|
418
544
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
419
545
|
},
|
420
|
-
"Relations"
|
546
|
+
"Relations",
|
547
|
+
{ type: "UidAvailability", id: model },
|
548
|
+
"RecentDocumentList",
|
549
|
+
"RecentDocumentList"
|
421
550
|
];
|
551
|
+
},
|
552
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
553
|
+
const patchResult = dispatch(
|
554
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
555
|
+
Object.assign(draft.data, data);
|
556
|
+
})
|
557
|
+
);
|
558
|
+
try {
|
559
|
+
await queryFulfilled;
|
560
|
+
} catch {
|
561
|
+
patchResult.undo();
|
562
|
+
}
|
422
563
|
}
|
423
564
|
}),
|
424
565
|
unpublishDocument: builder.mutation({
|
@@ -435,7 +576,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
435
576
|
{
|
436
577
|
type: "Document",
|
437
578
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
438
|
-
}
|
579
|
+
},
|
580
|
+
"RecentDocumentList"
|
439
581
|
];
|
440
582
|
}
|
441
583
|
}),
|
@@ -448,7 +590,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
448
590
|
params
|
449
591
|
}
|
450
592
|
}),
|
451
|
-
invalidatesTags: (_res, _error, { model, documentIds }) =>
|
593
|
+
invalidatesTags: (_res, _error, { model, documentIds }) => [
|
594
|
+
...documentIds.map((id) => ({ type: "Document", id: `${model}_${id}` })),
|
595
|
+
"RecentDocumentList"
|
596
|
+
]
|
452
597
|
})
|
453
598
|
})
|
454
599
|
});
|
@@ -471,8 +616,7 @@ const {
|
|
471
616
|
useUnpublishManyDocumentsMutation
|
472
617
|
} = documentApi;
|
473
618
|
const buildValidParams = (query) => {
|
474
|
-
if (!query)
|
475
|
-
return query;
|
619
|
+
if (!query) return query;
|
476
620
|
const { plugins: _, ...validQueryParams } = {
|
477
621
|
...query,
|
478
622
|
...Object.values(query?.plugins ?? {}).reduce(
|
@@ -480,28 +624,44 @@ const buildValidParams = (query) => {
|
|
480
624
|
{}
|
481
625
|
)
|
482
626
|
};
|
483
|
-
if ("_q" in validQueryParams) {
|
484
|
-
validQueryParams._q = encodeURIComponent(validQueryParams._q);
|
485
|
-
}
|
486
627
|
return validQueryParams;
|
487
628
|
};
|
488
629
|
const isBaseQueryError = (error) => {
|
489
630
|
return error.name !== void 0;
|
490
631
|
};
|
491
|
-
const
|
632
|
+
const arrayValidator = (attribute, options) => ({
|
633
|
+
message: strapiAdmin.translatedErrors.required,
|
634
|
+
test(value) {
|
635
|
+
if (options.status === "draft") {
|
636
|
+
return true;
|
637
|
+
}
|
638
|
+
if (!attribute.required) {
|
639
|
+
return true;
|
640
|
+
}
|
641
|
+
if (!value) {
|
642
|
+
return false;
|
643
|
+
}
|
644
|
+
if (Array.isArray(value) && value.length === 0) {
|
645
|
+
return false;
|
646
|
+
}
|
647
|
+
return true;
|
648
|
+
}
|
649
|
+
});
|
650
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
492
651
|
const createModelSchema = (attributes2) => yup__namespace.object().shape(
|
493
652
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
494
653
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
495
654
|
return acc;
|
496
655
|
}
|
497
656
|
const validations = [
|
657
|
+
addNullableValidation,
|
498
658
|
addRequiredValidation,
|
499
659
|
addMinLengthValidation,
|
500
660
|
addMaxLengthValidation,
|
501
661
|
addMinValidation,
|
502
662
|
addMaxValidation,
|
503
663
|
addRegexValidation
|
504
|
-
].map((fn) => fn(attribute));
|
664
|
+
].map((fn) => fn(attribute, options));
|
505
665
|
const transformSchema = pipe__default.default(...validations);
|
506
666
|
switch (attribute.type) {
|
507
667
|
case "component": {
|
@@ -511,12 +671,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
511
671
|
...acc,
|
512
672
|
[name]: transformSchema(
|
513
673
|
yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
|
514
|
-
)
|
674
|
+
).test(arrayValidator(attribute, options))
|
515
675
|
};
|
516
676
|
} else {
|
517
677
|
return {
|
518
678
|
...acc,
|
519
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
679
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
520
680
|
};
|
521
681
|
}
|
522
682
|
}
|
@@ -538,7 +698,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
538
698
|
}
|
539
699
|
)
|
540
700
|
)
|
541
|
-
)
|
701
|
+
).test(arrayValidator(attribute, options))
|
542
702
|
};
|
543
703
|
case "relation":
|
544
704
|
return {
|
@@ -550,7 +710,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
550
710
|
} else if (Array.isArray(value)) {
|
551
711
|
return yup__namespace.array().of(
|
552
712
|
yup__namespace.object().shape({
|
553
|
-
id: yup__namespace.
|
713
|
+
id: yup__namespace.number().required()
|
554
714
|
})
|
555
715
|
);
|
556
716
|
} else if (typeof value === "object") {
|
@@ -602,6 +762,14 @@ const createAttributeSchema = (attribute) => {
|
|
602
762
|
if (!value || typeof value === "string" && value.length === 0) {
|
603
763
|
return true;
|
604
764
|
}
|
765
|
+
if (typeof value === "object") {
|
766
|
+
try {
|
767
|
+
JSON.stringify(value);
|
768
|
+
return true;
|
769
|
+
} catch (err) {
|
770
|
+
return false;
|
771
|
+
}
|
772
|
+
}
|
605
773
|
try {
|
606
774
|
JSON.parse(value);
|
607
775
|
return true;
|
@@ -620,13 +788,7 @@ const createAttributeSchema = (attribute) => {
|
|
620
788
|
return yup__namespace.mixed();
|
621
789
|
}
|
622
790
|
};
|
623
|
-
const
|
624
|
-
if (attribute.required) {
|
625
|
-
return schema.required({
|
626
|
-
id: strapiAdmin.translatedErrors.required.id,
|
627
|
-
defaultMessage: "This field is required."
|
628
|
-
});
|
629
|
-
}
|
791
|
+
const nullableSchema = (schema) => {
|
630
792
|
return schema?.nullable ? schema.nullable() : (
|
631
793
|
// In some cases '.nullable' will not be available on the schema.
|
632
794
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -634,7 +796,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
634
796
|
schema
|
635
797
|
);
|
636
798
|
};
|
637
|
-
const
|
799
|
+
const addNullableValidation = () => (schema) => {
|
800
|
+
return nullableSchema(schema);
|
801
|
+
};
|
802
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
803
|
+
if (options.status === "draft" || !attribute.required) {
|
804
|
+
return schema;
|
805
|
+
}
|
806
|
+
if (attribute.required && "required" in schema) {
|
807
|
+
return schema.required(strapiAdmin.translatedErrors.required);
|
808
|
+
}
|
809
|
+
return schema;
|
810
|
+
};
|
811
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
812
|
+
if (options.status === "draft") {
|
813
|
+
return schema;
|
814
|
+
}
|
638
815
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
639
816
|
return schema.min(attribute.minLength, {
|
640
817
|
...strapiAdmin.translatedErrors.minLength,
|
@@ -656,10 +833,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
656
833
|
}
|
657
834
|
return schema;
|
658
835
|
};
|
659
|
-
const addMinValidation = (attribute) => (schema) => {
|
660
|
-
if ("
|
836
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
837
|
+
if (options.status === "draft") {
|
838
|
+
return schema;
|
839
|
+
}
|
840
|
+
if ("min" in attribute && "min" in schema) {
|
661
841
|
const min = toInteger(attribute.min);
|
662
|
-
if (
|
842
|
+
if (min) {
|
663
843
|
return schema.min(min, {
|
664
844
|
...strapiAdmin.translatedErrors.min,
|
665
845
|
values: {
|
@@ -777,16 +957,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
777
957
|
}, {});
|
778
958
|
return componentsByKey;
|
779
959
|
};
|
780
|
-
const
|
960
|
+
const HOOKS = {
|
961
|
+
/**
|
962
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
963
|
+
* @constant
|
964
|
+
* @type {string}
|
965
|
+
*/
|
966
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
967
|
+
/**
|
968
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
969
|
+
* @constant
|
970
|
+
* @type {string}
|
971
|
+
*/
|
972
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
973
|
+
/**
|
974
|
+
* Hook that allows to mutate the CM's edit view layout
|
975
|
+
* @constant
|
976
|
+
* @type {string}
|
977
|
+
*/
|
978
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
979
|
+
/**
|
980
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
981
|
+
* @constant
|
982
|
+
* @type {string}
|
983
|
+
*/
|
984
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
985
|
+
};
|
986
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
987
|
+
endpoints: (builder) => ({
|
988
|
+
getContentTypeConfiguration: builder.query({
|
989
|
+
query: (uid) => ({
|
990
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
991
|
+
method: "GET"
|
992
|
+
}),
|
993
|
+
transformResponse: (response) => response.data,
|
994
|
+
providesTags: (_result, _error, uid) => [
|
995
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
996
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
997
|
+
]
|
998
|
+
}),
|
999
|
+
getAllContentTypeSettings: builder.query({
|
1000
|
+
query: () => "/content-manager/content-types-settings",
|
1001
|
+
transformResponse: (response) => response.data,
|
1002
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
1003
|
+
}),
|
1004
|
+
updateContentTypeConfiguration: builder.mutation({
|
1005
|
+
query: ({ uid, ...body }) => ({
|
1006
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
1007
|
+
method: "PUT",
|
1008
|
+
data: body
|
1009
|
+
}),
|
1010
|
+
transformResponse: (response) => response.data,
|
1011
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
1012
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
1013
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
1014
|
+
// Is this necessary?
|
1015
|
+
{ type: "InitialData" }
|
1016
|
+
]
|
1017
|
+
})
|
1018
|
+
})
|
1019
|
+
});
|
1020
|
+
const {
|
1021
|
+
useGetContentTypeConfigurationQuery,
|
1022
|
+
useGetAllContentTypeSettingsQuery,
|
1023
|
+
useUpdateContentTypeConfigurationMutation
|
1024
|
+
} = contentTypesApi;
|
1025
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
1026
|
+
const { type } = attribute;
|
1027
|
+
if (type === "relation") {
|
1028
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
1029
|
+
}
|
1030
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
1031
|
+
};
|
1032
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
1033
|
+
if (!mainFieldName) {
|
1034
|
+
return void 0;
|
1035
|
+
}
|
1036
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
1037
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
1038
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
1039
|
+
);
|
1040
|
+
return {
|
1041
|
+
name: mainFieldName,
|
1042
|
+
type: mainFieldType ?? "string"
|
1043
|
+
};
|
1044
|
+
};
|
1045
|
+
const DEFAULT_SETTINGS = {
|
1046
|
+
bulkable: false,
|
1047
|
+
filterable: false,
|
1048
|
+
searchable: false,
|
1049
|
+
pagination: false,
|
1050
|
+
defaultSortBy: "",
|
1051
|
+
defaultSortOrder: "asc",
|
1052
|
+
mainField: "id",
|
1053
|
+
pageSize: 10
|
1054
|
+
};
|
1055
|
+
const useDocumentLayout = (model) => {
|
1056
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
1057
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
1058
|
+
const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
781
1059
|
const { toggleNotification } = strapiAdmin.useNotification();
|
782
1060
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1061
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
783
1062
|
const {
|
784
|
-
|
785
|
-
isLoading:
|
786
|
-
|
787
|
-
|
788
|
-
} =
|
789
|
-
const
|
1063
|
+
data,
|
1064
|
+
isLoading: isLoadingConfigs,
|
1065
|
+
error,
|
1066
|
+
isFetching: isFetchingConfigs
|
1067
|
+
} = useGetContentTypeConfigurationQuery(model);
|
1068
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
790
1069
|
React__namespace.useEffect(() => {
|
791
1070
|
if (error) {
|
792
1071
|
toggleNotification({
|
@@ -794,25 +1073,254 @@ const useDocument = (args, opts) => {
|
|
794
1073
|
message: formatAPIError(error)
|
795
1074
|
});
|
796
1075
|
}
|
797
|
-
}, [
|
798
|
-
const
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
|
806
|
-
|
807
|
-
|
808
|
-
|
809
|
-
|
810
|
-
|
811
|
-
|
812
|
-
|
813
|
-
|
814
|
-
|
815
|
-
|
1076
|
+
}, [error, formatAPIError, toggleNotification]);
|
1077
|
+
const editLayout = React__namespace.useMemo(
|
1078
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
1079
|
+
layout: [],
|
1080
|
+
components: {},
|
1081
|
+
metadatas: {},
|
1082
|
+
options: {},
|
1083
|
+
settings: DEFAULT_SETTINGS
|
1084
|
+
},
|
1085
|
+
[data, isLoading, schemas, schema, components]
|
1086
|
+
);
|
1087
|
+
const listLayout = React__namespace.useMemo(() => {
|
1088
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
1089
|
+
layout: [],
|
1090
|
+
metadatas: {},
|
1091
|
+
options: {},
|
1092
|
+
settings: DEFAULT_SETTINGS
|
1093
|
+
};
|
1094
|
+
}, [data, isLoading, schemas, schema, components]);
|
1095
|
+
const { layout: edit } = React__namespace.useMemo(
|
1096
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
1097
|
+
layout: editLayout,
|
1098
|
+
query
|
1099
|
+
}),
|
1100
|
+
[editLayout, query, runHookWaterfall]
|
1101
|
+
);
|
1102
|
+
return {
|
1103
|
+
error,
|
1104
|
+
isLoading,
|
1105
|
+
edit,
|
1106
|
+
list: listLayout
|
1107
|
+
};
|
1108
|
+
};
|
1109
|
+
const useDocLayout = () => {
|
1110
|
+
const { model } = useDoc();
|
1111
|
+
return useDocumentLayout(model);
|
1112
|
+
};
|
1113
|
+
const formatEditLayout = (data, {
|
1114
|
+
schemas,
|
1115
|
+
schema,
|
1116
|
+
components
|
1117
|
+
}) => {
|
1118
|
+
let currentPanelIndex = 0;
|
1119
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
1120
|
+
data.contentType.layouts.edit,
|
1121
|
+
schema?.attributes,
|
1122
|
+
data.contentType.metadatas,
|
1123
|
+
{ configurations: data.components, schemas: components },
|
1124
|
+
schemas
|
1125
|
+
).reduce((panels, row) => {
|
1126
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
1127
|
+
panels.push([row]);
|
1128
|
+
currentPanelIndex += 2;
|
1129
|
+
} else {
|
1130
|
+
if (!panels[currentPanelIndex]) {
|
1131
|
+
panels.push([row]);
|
1132
|
+
} else {
|
1133
|
+
panels[currentPanelIndex].push(row);
|
1134
|
+
}
|
1135
|
+
}
|
1136
|
+
return panels;
|
1137
|
+
}, []);
|
1138
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
1139
|
+
(acc, [uid, configuration]) => {
|
1140
|
+
acc[uid] = {
|
1141
|
+
layout: convertEditLayoutToFieldLayouts(
|
1142
|
+
configuration.layouts.edit,
|
1143
|
+
components[uid].attributes,
|
1144
|
+
configuration.metadatas,
|
1145
|
+
{ configurations: data.components, schemas: components }
|
1146
|
+
),
|
1147
|
+
settings: {
|
1148
|
+
...configuration.settings,
|
1149
|
+
icon: components[uid].info.icon,
|
1150
|
+
displayName: components[uid].info.displayName
|
1151
|
+
}
|
1152
|
+
};
|
1153
|
+
return acc;
|
1154
|
+
},
|
1155
|
+
{}
|
1156
|
+
);
|
1157
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1158
|
+
(acc, [attribute, metadata]) => {
|
1159
|
+
return {
|
1160
|
+
...acc,
|
1161
|
+
[attribute]: metadata.edit
|
1162
|
+
};
|
1163
|
+
},
|
1164
|
+
{}
|
1165
|
+
);
|
1166
|
+
return {
|
1167
|
+
layout: panelledEditAttributes,
|
1168
|
+
components: componentEditAttributes,
|
1169
|
+
metadatas: editMetadatas,
|
1170
|
+
settings: {
|
1171
|
+
...data.contentType.settings,
|
1172
|
+
displayName: schema?.info.displayName
|
1173
|
+
},
|
1174
|
+
options: {
|
1175
|
+
...schema?.options,
|
1176
|
+
...schema?.pluginOptions,
|
1177
|
+
...data.contentType.options
|
1178
|
+
}
|
1179
|
+
};
|
1180
|
+
};
|
1181
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1182
|
+
return rows.map(
|
1183
|
+
(row) => row.map((field) => {
|
1184
|
+
const attribute = attributes[field.name];
|
1185
|
+
if (!attribute) {
|
1186
|
+
return null;
|
1187
|
+
}
|
1188
|
+
const { edit: metadata } = metadatas[field.name];
|
1189
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1190
|
+
return {
|
1191
|
+
attribute,
|
1192
|
+
disabled: !metadata.editable,
|
1193
|
+
hint: metadata.description,
|
1194
|
+
label: metadata.label ?? "",
|
1195
|
+
name: field.name,
|
1196
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1197
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1198
|
+
schemas,
|
1199
|
+
components: components?.schemas ?? {}
|
1200
|
+
}),
|
1201
|
+
placeholder: metadata.placeholder ?? "",
|
1202
|
+
required: attribute.required ?? false,
|
1203
|
+
size: field.size,
|
1204
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1205
|
+
visible: metadata.visible ?? true,
|
1206
|
+
type: attribute.type
|
1207
|
+
};
|
1208
|
+
}).filter((field) => field !== null)
|
1209
|
+
);
|
1210
|
+
};
|
1211
|
+
const formatListLayout = (data, {
|
1212
|
+
schemas,
|
1213
|
+
schema,
|
1214
|
+
components
|
1215
|
+
}) => {
|
1216
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1217
|
+
(acc, [attribute, metadata]) => {
|
1218
|
+
return {
|
1219
|
+
...acc,
|
1220
|
+
[attribute]: metadata.list
|
1221
|
+
};
|
1222
|
+
},
|
1223
|
+
{}
|
1224
|
+
);
|
1225
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1226
|
+
data.contentType.layouts.list,
|
1227
|
+
schema?.attributes,
|
1228
|
+
listMetadatas,
|
1229
|
+
{ configurations: data.components, schemas: components },
|
1230
|
+
schemas
|
1231
|
+
);
|
1232
|
+
return {
|
1233
|
+
layout: listAttributes,
|
1234
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1235
|
+
metadatas: listMetadatas,
|
1236
|
+
options: {
|
1237
|
+
...schema?.options,
|
1238
|
+
...schema?.pluginOptions,
|
1239
|
+
...data.contentType.options
|
1240
|
+
}
|
1241
|
+
};
|
1242
|
+
};
|
1243
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1244
|
+
return columns.map((name) => {
|
1245
|
+
const attribute = attributes[name];
|
1246
|
+
if (!attribute) {
|
1247
|
+
return null;
|
1248
|
+
}
|
1249
|
+
const metadata = metadatas[name];
|
1250
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1251
|
+
return {
|
1252
|
+
attribute,
|
1253
|
+
label: metadata.label ?? "",
|
1254
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1255
|
+
schemas,
|
1256
|
+
components: components?.schemas ?? {}
|
1257
|
+
}),
|
1258
|
+
name,
|
1259
|
+
searchable: metadata.searchable ?? true,
|
1260
|
+
sortable: metadata.sortable ?? true
|
1261
|
+
};
|
1262
|
+
}).filter((field) => field !== null);
|
1263
|
+
};
|
1264
|
+
const useDocument = (args, opts) => {
|
1265
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
1266
|
+
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1267
|
+
const { formatMessage } = reactIntl.useIntl();
|
1268
|
+
const {
|
1269
|
+
currentData: data,
|
1270
|
+
isLoading: isLoadingDocument,
|
1271
|
+
isFetching: isFetchingDocument,
|
1272
|
+
error
|
1273
|
+
} = useGetDocumentQuery(args, {
|
1274
|
+
...opts,
|
1275
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1276
|
+
});
|
1277
|
+
const document = data?.data;
|
1278
|
+
const meta = data?.meta;
|
1279
|
+
const {
|
1280
|
+
components,
|
1281
|
+
schema,
|
1282
|
+
schemas,
|
1283
|
+
isLoading: isLoadingSchema
|
1284
|
+
} = useContentTypeSchema(args.model);
|
1285
|
+
const isSingleType = schema?.kind === "singleType";
|
1286
|
+
const getTitle = (mainField) => {
|
1287
|
+
if (mainField !== "id" && document?.[mainField]) {
|
1288
|
+
return document[mainField];
|
1289
|
+
}
|
1290
|
+
if (isSingleType && schema?.info.displayName) {
|
1291
|
+
return schema.info.displayName;
|
1292
|
+
}
|
1293
|
+
return formatMessage({
|
1294
|
+
id: "content-manager.containers.untitled",
|
1295
|
+
defaultMessage: "Untitled"
|
1296
|
+
});
|
1297
|
+
};
|
1298
|
+
React__namespace.useEffect(() => {
|
1299
|
+
if (error) {
|
1300
|
+
toggleNotification({
|
1301
|
+
type: "danger",
|
1302
|
+
message: formatAPIError(error)
|
1303
|
+
});
|
1304
|
+
}
|
1305
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1306
|
+
const validationSchema = React__namespace.useMemo(() => {
|
1307
|
+
if (!schema) {
|
1308
|
+
return null;
|
1309
|
+
}
|
1310
|
+
return createYupSchema(schema.attributes, components);
|
1311
|
+
}, [schema, components]);
|
1312
|
+
const validate = React__namespace.useCallback(
|
1313
|
+
(document2) => {
|
1314
|
+
if (!validationSchema) {
|
1315
|
+
throw new Error(
|
1316
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1317
|
+
);
|
1318
|
+
}
|
1319
|
+
try {
|
1320
|
+
validationSchema.validateSync(document2, { abortEarly: false, strict: true });
|
1321
|
+
return null;
|
1322
|
+
} catch (error2) {
|
1323
|
+
if (error2 instanceof yup.ValidationError) {
|
816
1324
|
return strapiAdmin.getYupValidationErrors(error2);
|
817
1325
|
}
|
818
1326
|
throw error2;
|
@@ -820,14 +1328,29 @@ const useDocument = (args, opts) => {
|
|
820
1328
|
},
|
821
1329
|
[validationSchema]
|
822
1330
|
);
|
1331
|
+
const getInitialFormValues = React__namespace.useCallback(
|
1332
|
+
(isCreatingDocument = false) => {
|
1333
|
+
if (!document && !isCreatingDocument && !isSingleType || !schema) {
|
1334
|
+
return void 0;
|
1335
|
+
}
|
1336
|
+
const form = document?.id ? document : createDefaultForm(schema, components);
|
1337
|
+
return transformDocument(schema, components)(form);
|
1338
|
+
},
|
1339
|
+
[document, isSingleType, schema, components]
|
1340
|
+
);
|
823
1341
|
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1342
|
+
const hasError = !!error;
|
824
1343
|
return {
|
825
1344
|
components,
|
826
|
-
document
|
827
|
-
meta
|
1345
|
+
document,
|
1346
|
+
meta,
|
828
1347
|
isLoading,
|
1348
|
+
hasError,
|
829
1349
|
schema,
|
830
|
-
|
1350
|
+
schemas,
|
1351
|
+
validate,
|
1352
|
+
getTitle,
|
1353
|
+
getInitialFormValues
|
831
1354
|
};
|
832
1355
|
};
|
833
1356
|
const useDoc = () => {
|
@@ -840,22 +1363,60 @@ const useDoc = () => {
|
|
840
1363
|
if (!slug) {
|
841
1364
|
throw new Error("Could not find model in url params");
|
842
1365
|
}
|
1366
|
+
const document = useDocument(
|
1367
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1368
|
+
{
|
1369
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1370
|
+
}
|
1371
|
+
);
|
1372
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
843
1373
|
return {
|
844
1374
|
collectionType,
|
845
1375
|
model: slug,
|
846
|
-
id:
|
847
|
-
...
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
1376
|
+
id: returnId,
|
1377
|
+
...document
|
1378
|
+
};
|
1379
|
+
};
|
1380
|
+
const useContentManagerContext = () => {
|
1381
|
+
const {
|
1382
|
+
collectionType,
|
1383
|
+
model,
|
1384
|
+
id,
|
1385
|
+
components,
|
1386
|
+
isLoading: isLoadingDoc,
|
1387
|
+
schema,
|
1388
|
+
schemas
|
1389
|
+
} = useDoc();
|
1390
|
+
const layout = useDocumentLayout(model);
|
1391
|
+
const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
|
1392
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1393
|
+
const slug = model;
|
1394
|
+
const isCreatingEntry = id === "create";
|
1395
|
+
useContentTypeSchema();
|
1396
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1397
|
+
const error = layout.error;
|
1398
|
+
return {
|
1399
|
+
error,
|
1400
|
+
isLoading,
|
1401
|
+
// Base metadata
|
1402
|
+
model,
|
1403
|
+
collectionType,
|
1404
|
+
id,
|
1405
|
+
slug,
|
1406
|
+
isCreatingEntry,
|
1407
|
+
isSingleType,
|
1408
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1409
|
+
// All schema infos
|
1410
|
+
components,
|
1411
|
+
contentType: schema,
|
1412
|
+
contentTypes: schemas,
|
1413
|
+
// Form state
|
1414
|
+
form,
|
1415
|
+
// layout infos
|
1416
|
+
layout
|
853
1417
|
};
|
854
1418
|
};
|
855
1419
|
const prefixPluginTranslations = (trad, pluginId) => {
|
856
|
-
if (!pluginId) {
|
857
|
-
throw new TypeError("pluginId can't be empty");
|
858
|
-
}
|
859
1420
|
return Object.keys(trad).reduce((acc, current) => {
|
860
1421
|
acc[`${pluginId}.${current}`] = trad[current];
|
861
1422
|
return acc;
|
@@ -871,6 +1432,8 @@ const useDocumentActions = () => {
|
|
871
1432
|
const { formatMessage } = reactIntl.useIntl();
|
872
1433
|
const { trackUsage } = strapiAdmin.useTracking();
|
873
1434
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1435
|
+
const navigate = reactRouterDom.useNavigate();
|
1436
|
+
const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
874
1437
|
const [deleteDocument] = useDeleteDocumentMutation();
|
875
1438
|
const _delete = React__namespace.useCallback(
|
876
1439
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1185,6 +1748,7 @@ const useDocumentActions = () => {
|
|
1185
1748
|
defaultMessage: "Saved document"
|
1186
1749
|
})
|
1187
1750
|
});
|
1751
|
+
setCurrentStep("contentManager.success");
|
1188
1752
|
return res.data;
|
1189
1753
|
} catch (err) {
|
1190
1754
|
toggleNotification({
|
@@ -1206,7 +1770,6 @@ const useDocumentActions = () => {
|
|
1206
1770
|
sourceId
|
1207
1771
|
});
|
1208
1772
|
if ("error" in res) {
|
1209
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1210
1773
|
return { error: res.error };
|
1211
1774
|
}
|
1212
1775
|
toggleNotification({
|
@@ -1225,7 +1788,7 @@ const useDocumentActions = () => {
|
|
1225
1788
|
throw err;
|
1226
1789
|
}
|
1227
1790
|
},
|
1228
|
-
[autoCloneDocument,
|
1791
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1229
1792
|
);
|
1230
1793
|
const [cloneDocument] = useCloneDocumentMutation();
|
1231
1794
|
const clone = React__namespace.useCallback(
|
@@ -1251,6 +1814,7 @@ const useDocumentActions = () => {
|
|
1251
1814
|
defaultMessage: "Cloned document"
|
1252
1815
|
})
|
1253
1816
|
});
|
1817
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1254
1818
|
return res.data;
|
1255
1819
|
} catch (err) {
|
1256
1820
|
toggleNotification({
|
@@ -1261,7 +1825,7 @@ const useDocumentActions = () => {
|
|
1261
1825
|
throw err;
|
1262
1826
|
}
|
1263
1827
|
},
|
1264
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1828
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1265
1829
|
);
|
1266
1830
|
const [getDoc] = useLazyGetDocumentQuery();
|
1267
1831
|
const getDocument = React__namespace.useCallback(
|
@@ -1286,10 +1850,10 @@ const useDocumentActions = () => {
|
|
1286
1850
|
update
|
1287
1851
|
};
|
1288
1852
|
};
|
1289
|
-
const ProtectedHistoryPage =
|
1290
|
-
() => Promise.resolve().then(() => require("./History-
|
1853
|
+
const ProtectedHistoryPage = React__namespace.lazy(
|
1854
|
+
() => Promise.resolve().then(() => require("./History-BQpDoOu8.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1291
1855
|
);
|
1292
|
-
const routes$
|
1856
|
+
const routes$2 = [
|
1293
1857
|
{
|
1294
1858
|
path: ":collectionType/:slug/:id/history",
|
1295
1859
|
Component: ProtectedHistoryPage
|
@@ -1299,32 +1863,45 @@ const routes$1 = [
|
|
1299
1863
|
Component: ProtectedHistoryPage
|
1300
1864
|
}
|
1301
1865
|
];
|
1302
|
-
const
|
1303
|
-
() => Promise.resolve().then(() => require("./
|
1304
|
-
);
|
1305
|
-
const
|
1306
|
-
|
1866
|
+
const ProtectedPreviewPage = React__namespace.lazy(
|
1867
|
+
() => Promise.resolve().then(() => require("./Preview-CbXHXqBg.js")).then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1868
|
+
);
|
1869
|
+
const routes$1 = [
|
1870
|
+
{
|
1871
|
+
path: ":collectionType/:slug/:id/preview",
|
1872
|
+
Component: ProtectedPreviewPage
|
1873
|
+
},
|
1874
|
+
{
|
1875
|
+
path: ":collectionType/:slug/preview",
|
1876
|
+
Component: ProtectedPreviewPage
|
1877
|
+
}
|
1878
|
+
];
|
1879
|
+
const ProtectedEditViewPage = React.lazy(
|
1880
|
+
() => Promise.resolve().then(() => require("./EditViewPage-BT7Achc-.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1881
|
+
);
|
1882
|
+
const ProtectedListViewPage = React.lazy(
|
1883
|
+
() => Promise.resolve().then(() => require("./ListViewPage-Dt8OUTwO.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1307
1884
|
);
|
1308
1885
|
const ProtectedListConfiguration = React.lazy(
|
1309
|
-
() => Promise.resolve().then(() => require("./ListConfigurationPage-
|
1886
|
+
() => Promise.resolve().then(() => require("./ListConfigurationPage-B6NsS-0m.js")).then((mod) => ({
|
1310
1887
|
default: mod.ProtectedListConfiguration
|
1311
1888
|
}))
|
1312
1889
|
);
|
1313
1890
|
const ProtectedEditConfigurationPage = React.lazy(
|
1314
|
-
() => Promise.resolve().then(() => require("./EditConfigurationPage-
|
1891
|
+
() => Promise.resolve().then(() => require("./EditConfigurationPage-n7_xHayb.js")).then((mod) => ({
|
1315
1892
|
default: mod.ProtectedEditConfigurationPage
|
1316
1893
|
}))
|
1317
1894
|
);
|
1318
1895
|
const ProtectedComponentConfigurationPage = React.lazy(
|
1319
|
-
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-
|
1896
|
+
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-NeMPjY5M.js")).then((mod) => ({
|
1320
1897
|
default: mod.ProtectedComponentConfigurationPage
|
1321
1898
|
}))
|
1322
1899
|
);
|
1323
1900
|
const NoPermissions = React.lazy(
|
1324
|
-
() => Promise.resolve().then(() => require("./NoPermissionsPage-
|
1901
|
+
() => Promise.resolve().then(() => require("./NoPermissionsPage-CLbU5SOt.js")).then((mod) => ({ default: mod.NoPermissions }))
|
1325
1902
|
);
|
1326
1903
|
const NoContentType = React.lazy(
|
1327
|
-
() => Promise.resolve().then(() => require("./NoContentTypePage-
|
1904
|
+
() => Promise.resolve().then(() => require("./NoContentTypePage-Dgm-uj-6.js")).then((mod) => ({ default: mod.NoContentType }))
|
1328
1905
|
);
|
1329
1906
|
const CollectionTypePages = () => {
|
1330
1907
|
const { collectionType } = reactRouterDom.useParams();
|
@@ -1336,7 +1913,7 @@ const CollectionTypePages = () => {
|
|
1336
1913
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1337
1914
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1338
1915
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1339
|
-
const LIST_PATH = `/content-manager
|
1916
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1340
1917
|
const routes = [
|
1341
1918
|
{
|
1342
1919
|
path: LIST_RELATIVE_PATH,
|
@@ -1370,6 +1947,7 @@ const routes = [
|
|
1370
1947
|
path: "no-content-types",
|
1371
1948
|
Component: NoContentType
|
1372
1949
|
},
|
1950
|
+
...routes$2,
|
1373
1951
|
...routes$1
|
1374
1952
|
];
|
1375
1953
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1438,12 +2016,14 @@ const DocumentActionButton = (action) => {
|
|
1438
2016
|
/* @__PURE__ */ jsxRuntime.jsx(
|
1439
2017
|
designSystem.Button,
|
1440
2018
|
{
|
1441
|
-
flex:
|
2019
|
+
flex: "auto",
|
1442
2020
|
startIcon: action.icon,
|
1443
2021
|
disabled: action.disabled,
|
1444
2022
|
onClick: handleClick(action),
|
1445
2023
|
justifyContent: "center",
|
1446
2024
|
variant: action.variant || "default",
|
2025
|
+
paddingTop: "7px",
|
2026
|
+
paddingBottom: "7px",
|
1447
2027
|
children: action.label
|
1448
2028
|
}
|
1449
2029
|
),
|
@@ -1451,7 +2031,7 @@ const DocumentActionButton = (action) => {
|
|
1451
2031
|
DocumentActionConfirmDialog,
|
1452
2032
|
{
|
1453
2033
|
...action.dialog,
|
1454
|
-
variant: action.variant,
|
2034
|
+
variant: action.dialog?.variant ?? action.variant,
|
1455
2035
|
isOpen: dialogId === action.id,
|
1456
2036
|
onClose: handleClose
|
1457
2037
|
}
|
@@ -1466,6 +2046,11 @@ const DocumentActionButton = (action) => {
|
|
1466
2046
|
) : null
|
1467
2047
|
] });
|
1468
2048
|
};
|
2049
|
+
const MenuItem = styledComponents.styled(designSystem.Menu.Item)`
|
2050
|
+
&:hover {
|
2051
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
2052
|
+
}
|
2053
|
+
`;
|
1469
2054
|
const DocumentActionsMenu = ({
|
1470
2055
|
actions: actions2,
|
1471
2056
|
children,
|
@@ -1508,9 +2093,9 @@ const DocumentActionsMenu = ({
|
|
1508
2093
|
disabled: isDisabled,
|
1509
2094
|
size: "S",
|
1510
2095
|
endIcon: null,
|
1511
|
-
paddingTop: "
|
1512
|
-
paddingLeft: "
|
1513
|
-
paddingRight: "
|
2096
|
+
paddingTop: "4px",
|
2097
|
+
paddingLeft: "7px",
|
2098
|
+
paddingRight: "7px",
|
1514
2099
|
variant,
|
1515
2100
|
children: [
|
1516
2101
|
/* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
|
@@ -1521,36 +2106,35 @@ const DocumentActionsMenu = ({
|
|
1521
2106
|
]
|
1522
2107
|
}
|
1523
2108
|
),
|
1524
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, {
|
2109
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1525
2110
|
actions2.map((action) => {
|
1526
2111
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
1527
|
-
|
2112
|
+
MenuItem,
|
1528
2113
|
{
|
1529
2114
|
disabled: action.disabled,
|
1530
2115
|
onSelect: handleClick(action),
|
1531
2116
|
display: "block",
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
|
1538
|
-
|
1539
|
-
|
1540
|
-
|
1541
|
-
|
1542
|
-
|
1543
|
-
|
1544
|
-
|
1545
|
-
|
1546
|
-
|
1547
|
-
|
1548
|
-
|
1549
|
-
|
1550
|
-
|
1551
|
-
|
1552
|
-
|
1553
|
-
] })
|
2117
|
+
isVariantDanger: action.variant === "danger",
|
2118
|
+
isDisabled: action.disabled,
|
2119
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
2120
|
+
designSystem.Flex,
|
2121
|
+
{
|
2122
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
2123
|
+
gap: 2,
|
2124
|
+
tag: "span",
|
2125
|
+
children: [
|
2126
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2127
|
+
designSystem.Flex,
|
2128
|
+
{
|
2129
|
+
tag: "span",
|
2130
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
2131
|
+
children: action.icon
|
2132
|
+
}
|
2133
|
+
),
|
2134
|
+
action.label
|
2135
|
+
]
|
2136
|
+
}
|
2137
|
+
) })
|
1554
2138
|
},
|
1555
2139
|
action.id
|
1556
2140
|
);
|
@@ -1630,11 +2214,11 @@ const DocumentActionConfirmDialog = ({
|
|
1630
2214
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
1631
2215
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
|
1632
2216
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
|
1633
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
|
2217
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1634
2218
|
id: "app.components.Button.cancel",
|
1635
2219
|
defaultMessage: "Cancel"
|
1636
2220
|
}) }) }),
|
1637
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2221
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1638
2222
|
id: "app.components.Button.confirm",
|
1639
2223
|
defaultMessage: "Confirm"
|
1640
2224
|
}) })
|
@@ -1661,6 +2245,18 @@ const DocumentActionModal = ({
|
|
1661
2245
|
typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
|
1662
2246
|
] }) });
|
1663
2247
|
};
|
2248
|
+
const transformData = (data) => {
|
2249
|
+
if (Array.isArray(data)) {
|
2250
|
+
return data.map(transformData);
|
2251
|
+
}
|
2252
|
+
if (typeof data === "object" && data !== null) {
|
2253
|
+
if ("apiData" in data) {
|
2254
|
+
return data.apiData;
|
2255
|
+
}
|
2256
|
+
return mapValues__default.default(transformData)(data);
|
2257
|
+
}
|
2258
|
+
return data;
|
2259
|
+
};
|
1664
2260
|
const PublishAction$1 = ({
|
1665
2261
|
activeTab,
|
1666
2262
|
documentId,
|
@@ -1673,13 +2269,18 @@ const PublishAction$1 = ({
|
|
1673
2269
|
const navigate = reactRouterDom.useNavigate();
|
1674
2270
|
const { toggleNotification } = strapiAdmin.useNotification();
|
1675
2271
|
const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
|
2272
|
+
const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
|
1676
2273
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2274
|
+
const { id } = reactRouterDom.useParams();
|
1677
2275
|
const { formatMessage } = reactIntl.useIntl();
|
1678
|
-
const { canPublish
|
1679
|
-
"PublishAction",
|
1680
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1681
|
-
);
|
2276
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1682
2277
|
const { publish } = useDocumentActions();
|
2278
|
+
const [
|
2279
|
+
countDraftRelations,
|
2280
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2281
|
+
] = useLazyGetDraftRelationCountQuery();
|
2282
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
|
2283
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
|
1683
2284
|
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1684
2285
|
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1685
2286
|
const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1688,10 +2289,107 @@ const PublishAction$1 = ({
|
|
1688
2289
|
const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
|
1689
2290
|
const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
|
1690
2291
|
const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
|
2292
|
+
React__namespace.useEffect(() => {
|
2293
|
+
if (isErrorDraftRelations) {
|
2294
|
+
toggleNotification({
|
2295
|
+
type: "danger",
|
2296
|
+
message: formatMessage({
|
2297
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2298
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2299
|
+
})
|
2300
|
+
});
|
2301
|
+
}
|
2302
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2303
|
+
React__namespace.useEffect(() => {
|
2304
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2305
|
+
const extractDraftRelations = (data) => {
|
2306
|
+
const relations = data.connect || [];
|
2307
|
+
relations.forEach((relation) => {
|
2308
|
+
if (relation.status === "draft") {
|
2309
|
+
localDraftRelations.add(relation.id);
|
2310
|
+
}
|
2311
|
+
});
|
2312
|
+
};
|
2313
|
+
const traverseAndExtract = (data) => {
|
2314
|
+
Object.entries(data).forEach(([key, value]) => {
|
2315
|
+
if (key === "connect" && Array.isArray(value)) {
|
2316
|
+
extractDraftRelations({ connect: value });
|
2317
|
+
} else if (typeof value === "object" && value !== null) {
|
2318
|
+
traverseAndExtract(value);
|
2319
|
+
}
|
2320
|
+
});
|
2321
|
+
};
|
2322
|
+
if (!documentId || modified) {
|
2323
|
+
traverseAndExtract(formValues);
|
2324
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2325
|
+
}
|
2326
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2327
|
+
React__namespace.useEffect(() => {
|
2328
|
+
if (!document || !document.documentId || isListView) {
|
2329
|
+
return;
|
2330
|
+
}
|
2331
|
+
const fetchDraftRelationsCount = async () => {
|
2332
|
+
const { data, error } = await countDraftRelations({
|
2333
|
+
collectionType,
|
2334
|
+
model,
|
2335
|
+
documentId,
|
2336
|
+
params
|
2337
|
+
});
|
2338
|
+
if (error) {
|
2339
|
+
throw error;
|
2340
|
+
}
|
2341
|
+
if (data) {
|
2342
|
+
setServerCountOfDraftRelations(data.data);
|
2343
|
+
}
|
2344
|
+
};
|
2345
|
+
fetchDraftRelationsCount();
|
2346
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1691
2347
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1692
2348
|
if (!schema?.options?.draftAndPublish) {
|
1693
2349
|
return null;
|
1694
2350
|
}
|
2351
|
+
const performPublish = async () => {
|
2352
|
+
setSubmitting(true);
|
2353
|
+
try {
|
2354
|
+
const { errors } = await validate(true, {
|
2355
|
+
status: "published"
|
2356
|
+
});
|
2357
|
+
if (errors) {
|
2358
|
+
toggleNotification({
|
2359
|
+
type: "danger",
|
2360
|
+
message: formatMessage({
|
2361
|
+
id: "content-manager.validation.error",
|
2362
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2363
|
+
})
|
2364
|
+
});
|
2365
|
+
return;
|
2366
|
+
}
|
2367
|
+
const res = await publish(
|
2368
|
+
{
|
2369
|
+
collectionType,
|
2370
|
+
model,
|
2371
|
+
documentId,
|
2372
|
+
params
|
2373
|
+
},
|
2374
|
+
transformData(formValues)
|
2375
|
+
);
|
2376
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2377
|
+
if (id === "create") {
|
2378
|
+
navigate({
|
2379
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2380
|
+
search: rawQuery
|
2381
|
+
});
|
2382
|
+
}
|
2383
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2384
|
+
setErrors(formatValidationErrors(res.error));
|
2385
|
+
}
|
2386
|
+
} finally {
|
2387
|
+
setSubmitting(false);
|
2388
|
+
}
|
2389
|
+
};
|
2390
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2391
|
+
const enableDraftRelationsCount = false;
|
2392
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1695
2393
|
return {
|
1696
2394
|
/**
|
1697
2395
|
* Disabled when:
|
@@ -1701,52 +2399,40 @@ const PublishAction$1 = ({
|
|
1701
2399
|
* - the document is already published & not modified
|
1702
2400
|
* - the document is being created & not modified
|
1703
2401
|
* - the user doesn't have the permission to publish
|
1704
|
-
* - the user doesn't have the permission to create a new document
|
1705
|
-
* - the user doesn't have the permission to update the document
|
1706
2402
|
*/
|
1707
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2403
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1708
2404
|
label: formatMessage({
|
1709
2405
|
id: "app.utils.publish",
|
1710
2406
|
defaultMessage: "Publish"
|
1711
2407
|
}),
|
1712
2408
|
onClick: async () => {
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
documentId,
|
1731
|
-
params
|
1732
|
-
},
|
1733
|
-
formValues
|
1734
|
-
);
|
1735
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1736
|
-
navigate({
|
1737
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1738
|
-
search: rawQuery
|
1739
|
-
});
|
1740
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1741
|
-
setErrors(formatValidationErrors(res.error));
|
2409
|
+
await performPublish();
|
2410
|
+
},
|
2411
|
+
dialog: hasDraftRelations ? {
|
2412
|
+
type: "dialog",
|
2413
|
+
variant: "danger",
|
2414
|
+
footer: null,
|
2415
|
+
title: formatMessage({
|
2416
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2417
|
+
defaultMessage: "Confirmation"
|
2418
|
+
}),
|
2419
|
+
content: formatMessage(
|
2420
|
+
{
|
2421
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2422
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2423
|
+
},
|
2424
|
+
{
|
2425
|
+
count: totalDraftRelations
|
1742
2426
|
}
|
1743
|
-
|
1744
|
-
|
2427
|
+
),
|
2428
|
+
onConfirm: async () => {
|
2429
|
+
await performPublish();
|
1745
2430
|
}
|
1746
|
-
}
|
2431
|
+
} : void 0
|
1747
2432
|
};
|
1748
2433
|
};
|
1749
2434
|
PublishAction$1.type = "publish";
|
2435
|
+
PublishAction$1.position = "panel";
|
1750
2436
|
const UpdateAction = ({
|
1751
2437
|
activeTab,
|
1752
2438
|
documentId,
|
@@ -1759,10 +2445,6 @@ const UpdateAction = ({
|
|
1759
2445
|
const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
|
1760
2446
|
const isCloning = cloneMatch !== null;
|
1761
2447
|
const { formatMessage } = reactIntl.useIntl();
|
1762
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1763
|
-
canCreate: canCreate2,
|
1764
|
-
canUpdate: canUpdate2
|
1765
|
-
}));
|
1766
2448
|
const { create, update, clone } = useDocumentActions();
|
1767
2449
|
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1768
2450
|
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
@@ -1773,90 +2455,134 @@ const UpdateAction = ({
|
|
1773
2455
|
const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
|
1774
2456
|
const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
|
1775
2457
|
const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1776
|
-
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
|
1790
|
-
|
1791
|
-
|
1792
|
-
|
1793
|
-
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
1797
|
-
|
1798
|
-
|
1799
|
-
|
1800
|
-
|
1801
|
-
}
|
1802
|
-
|
1803
|
-
|
1804
|
-
if (
|
1805
|
-
|
2458
|
+
const handleUpdate = React__namespace.useCallback(async () => {
|
2459
|
+
setSubmitting(true);
|
2460
|
+
try {
|
2461
|
+
if (!modified) {
|
2462
|
+
return;
|
2463
|
+
}
|
2464
|
+
const { errors } = await validate(true, {
|
2465
|
+
status: "draft"
|
2466
|
+
});
|
2467
|
+
if (errors) {
|
2468
|
+
toggleNotification({
|
2469
|
+
type: "danger",
|
2470
|
+
message: formatMessage({
|
2471
|
+
id: "content-manager.validation.error",
|
2472
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2473
|
+
})
|
2474
|
+
});
|
2475
|
+
return;
|
2476
|
+
}
|
2477
|
+
if (isCloning) {
|
2478
|
+
const res = await clone(
|
2479
|
+
{
|
2480
|
+
model,
|
2481
|
+
documentId: cloneMatch.params.origin,
|
2482
|
+
params
|
2483
|
+
},
|
2484
|
+
transformData(document)
|
2485
|
+
);
|
2486
|
+
if ("data" in res) {
|
2487
|
+
navigate(
|
1806
2488
|
{
|
1807
|
-
|
1808
|
-
documentId: cloneMatch.params.origin,
|
1809
|
-
params
|
1810
|
-
},
|
1811
|
-
document
|
1812
|
-
);
|
1813
|
-
if ("data" in res) {
|
1814
|
-
navigate({
|
1815
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2489
|
+
pathname: `../${res.data.documentId}`,
|
1816
2490
|
search: rawQuery
|
1817
|
-
});
|
1818
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1819
|
-
setErrors(formatValidationErrors(res.error));
|
1820
|
-
}
|
1821
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1822
|
-
const res = await update(
|
1823
|
-
{
|
1824
|
-
collectionType,
|
1825
|
-
model,
|
1826
|
-
documentId,
|
1827
|
-
params
|
1828
2491
|
},
|
1829
|
-
|
2492
|
+
{ relative: "path" }
|
1830
2493
|
);
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
2494
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2495
|
+
setErrors(formatValidationErrors(res.error));
|
2496
|
+
}
|
2497
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2498
|
+
const res = await update(
|
2499
|
+
{
|
2500
|
+
collectionType,
|
2501
|
+
model,
|
2502
|
+
documentId,
|
2503
|
+
params
|
2504
|
+
},
|
2505
|
+
transformData(document)
|
2506
|
+
);
|
2507
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2508
|
+
setErrors(formatValidationErrors(res.error));
|
1836
2509
|
} else {
|
1837
|
-
|
2510
|
+
resetForm();
|
2511
|
+
}
|
2512
|
+
} else {
|
2513
|
+
const res = await create(
|
2514
|
+
{
|
2515
|
+
model,
|
2516
|
+
params
|
2517
|
+
},
|
2518
|
+
transformData(document)
|
2519
|
+
);
|
2520
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2521
|
+
navigate(
|
1838
2522
|
{
|
1839
|
-
|
1840
|
-
|
2523
|
+
pathname: `../${res.data.documentId}`,
|
2524
|
+
search: rawQuery
|
1841
2525
|
},
|
1842
|
-
|
2526
|
+
{ replace: true, relative: "path" }
|
1843
2527
|
);
|
1844
|
-
|
1845
|
-
|
1846
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1847
|
-
search: rawQuery
|
1848
|
-
});
|
1849
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1850
|
-
setErrors(formatValidationErrors(res.error));
|
1851
|
-
}
|
2528
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2529
|
+
setErrors(formatValidationErrors(res.error));
|
1852
2530
|
}
|
1853
|
-
} finally {
|
1854
|
-
setSubmitting(false);
|
1855
2531
|
}
|
2532
|
+
} finally {
|
2533
|
+
setSubmitting(false);
|
1856
2534
|
}
|
2535
|
+
}, [
|
2536
|
+
clone,
|
2537
|
+
cloneMatch?.params.origin,
|
2538
|
+
collectionType,
|
2539
|
+
create,
|
2540
|
+
document,
|
2541
|
+
documentId,
|
2542
|
+
formatMessage,
|
2543
|
+
formatValidationErrors,
|
2544
|
+
isCloning,
|
2545
|
+
model,
|
2546
|
+
modified,
|
2547
|
+
navigate,
|
2548
|
+
params,
|
2549
|
+
rawQuery,
|
2550
|
+
resetForm,
|
2551
|
+
setErrors,
|
2552
|
+
setSubmitting,
|
2553
|
+
toggleNotification,
|
2554
|
+
update,
|
2555
|
+
validate
|
2556
|
+
]);
|
2557
|
+
React__namespace.useEffect(() => {
|
2558
|
+
const handleKeyDown = (e) => {
|
2559
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
2560
|
+
e.preventDefault();
|
2561
|
+
handleUpdate();
|
2562
|
+
}
|
2563
|
+
};
|
2564
|
+
window.addEventListener("keydown", handleKeyDown);
|
2565
|
+
return () => {
|
2566
|
+
window.removeEventListener("keydown", handleKeyDown);
|
2567
|
+
};
|
2568
|
+
}, [handleUpdate]);
|
2569
|
+
return {
|
2570
|
+
/**
|
2571
|
+
* Disabled when:
|
2572
|
+
* - the form is submitting
|
2573
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2574
|
+
* - the active tab is the published tab
|
2575
|
+
*/
|
2576
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2577
|
+
label: formatMessage({
|
2578
|
+
id: "global.save",
|
2579
|
+
defaultMessage: "Save"
|
2580
|
+
}),
|
2581
|
+
onClick: handleUpdate
|
1857
2582
|
};
|
1858
2583
|
};
|
1859
2584
|
UpdateAction.type = "update";
|
2585
|
+
UpdateAction.position = "panel";
|
1860
2586
|
const UNPUBLISH_DRAFT_OPTIONS = {
|
1861
2587
|
KEEP: "keep",
|
1862
2588
|
DISCARD: "discard"
|
@@ -1889,7 +2615,7 @@ const UnpublishAction$1 = ({
|
|
1889
2615
|
id: "app.utils.unpublish",
|
1890
2616
|
defaultMessage: "Unpublish"
|
1891
2617
|
}),
|
1892
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
2618
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
1893
2619
|
onClick: async () => {
|
1894
2620
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1895
2621
|
if (!documentId) {
|
@@ -1979,6 +2705,7 @@ const UnpublishAction$1 = ({
|
|
1979
2705
|
};
|
1980
2706
|
};
|
1981
2707
|
UnpublishAction$1.type = "unpublish";
|
2708
|
+
UnpublishAction$1.position = "panel";
|
1982
2709
|
const DiscardAction = ({
|
1983
2710
|
activeTab,
|
1984
2711
|
documentId,
|
@@ -2001,7 +2728,7 @@ const DiscardAction = ({
|
|
2001
2728
|
id: "content-manager.actions.discard.label",
|
2002
2729
|
defaultMessage: "Discard changes"
|
2003
2730
|
}),
|
2004
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
2731
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
2005
2732
|
position: ["panel", "table-row"],
|
2006
2733
|
variant: "danger",
|
2007
2734
|
dialog: {
|
@@ -2029,11 +2756,7 @@ const DiscardAction = ({
|
|
2029
2756
|
};
|
2030
2757
|
};
|
2031
2758
|
DiscardAction.type = "discard";
|
2032
|
-
|
2033
|
-
path {
|
2034
|
-
fill: currentColor;
|
2035
|
-
}
|
2036
|
-
`;
|
2759
|
+
DiscardAction.position = "panel";
|
2037
2760
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2038
2761
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2039
2762
|
const RelativeTime = React__namespace.forwardRef(
|
@@ -2046,7 +2769,7 @@ const RelativeTime = React__namespace.forwardRef(
|
|
2046
2769
|
});
|
2047
2770
|
const unit = intervals.find((intervalUnit) => {
|
2048
2771
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2049
|
-
});
|
2772
|
+
}) ?? "seconds";
|
2050
2773
|
const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
|
2051
2774
|
const customInterval = customIntervals.find(
|
2052
2775
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2080,34 +2803,34 @@ const getDisplayName = ({
|
|
2080
2803
|
return email ?? "";
|
2081
2804
|
};
|
2082
2805
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2083
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2084
|
-
const statusVariant = status === "draft" ? "
|
2085
|
-
|
2806
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2807
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2808
|
+
const { formatMessage } = reactIntl.useIntl();
|
2809
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2810
|
+
id: `content-manager.containers.List.${status}`,
|
2811
|
+
defaultMessage: capitalise(status)
|
2812
|
+
}) }) });
|
2086
2813
|
};
|
2087
2814
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2088
2815
|
const { formatMessage } = reactIntl.useIntl();
|
2089
2816
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2817
|
+
const params = reactRouterDom.useParams();
|
2090
2818
|
const title = isCreating ? formatMessage({
|
2091
2819
|
id: "content-manager.containers.edit.title.new",
|
2092
2820
|
defaultMessage: "Create an entry"
|
2093
2821
|
}) : documentTitle;
|
2094
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2095
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
2096
|
-
|
2097
|
-
designSystem.Flex,
|
2822
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2823
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2824
|
+
strapiAdmin.BackButton,
|
2098
2825
|
{
|
2099
|
-
|
2100
|
-
justifyContent: "space-between",
|
2101
|
-
paddingTop: 1,
|
2102
|
-
gap: "80px",
|
2103
|
-
alignItems: "flex-start",
|
2104
|
-
children: [
|
2105
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2106
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2107
|
-
]
|
2826
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2108
2827
|
}
|
2109
2828
|
),
|
2110
|
-
|
2829
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2830
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2831
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2832
|
+
] }),
|
2833
|
+
status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2111
2834
|
] });
|
2112
2835
|
};
|
2113
2836
|
const HeaderToolbar = () => {
|
@@ -2153,7 +2876,7 @@ const HeaderToolbar = () => {
|
|
2153
2876
|
meta: isCloning ? void 0 : meta,
|
2154
2877
|
collectionType
|
2155
2878
|
},
|
2156
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2879
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("header"),
|
2157
2880
|
children: (actions2) => {
|
2158
2881
|
const headerActions = actions2.filter((action) => {
|
2159
2882
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2190,12 +2913,12 @@ const Information = ({ activeTab }) => {
|
|
2190
2913
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2191
2914
|
label: formatMessage({
|
2192
2915
|
id: "content-manager.containers.edit.information.last-published.label",
|
2193
|
-
defaultMessage: "
|
2916
|
+
defaultMessage: "Published"
|
2194
2917
|
}),
|
2195
2918
|
value: formatMessage(
|
2196
2919
|
{
|
2197
2920
|
id: "content-manager.containers.edit.information.last-published.value",
|
2198
|
-
defaultMessage: `
|
2921
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2199
2922
|
},
|
2200
2923
|
{
|
2201
2924
|
time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2208,12 +2931,12 @@ const Information = ({ activeTab }) => {
|
|
2208
2931
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2209
2932
|
label: formatMessage({
|
2210
2933
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2211
|
-
defaultMessage: "
|
2934
|
+
defaultMessage: "Updated"
|
2212
2935
|
}),
|
2213
2936
|
value: formatMessage(
|
2214
2937
|
{
|
2215
2938
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2216
|
-
defaultMessage: `
|
2939
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2217
2940
|
},
|
2218
2941
|
{
|
2219
2942
|
time: /* @__PURE__ */ jsxRuntime.jsx(
|
@@ -2231,12 +2954,12 @@ const Information = ({ activeTab }) => {
|
|
2231
2954
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2232
2955
|
label: formatMessage({
|
2233
2956
|
id: "content-manager.containers.edit.information.document.label",
|
2234
|
-
defaultMessage: "
|
2957
|
+
defaultMessage: "Created"
|
2235
2958
|
}),
|
2236
2959
|
value: formatMessage(
|
2237
2960
|
{
|
2238
2961
|
id: "content-manager.containers.edit.information.document.value",
|
2239
|
-
defaultMessage: `
|
2962
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2240
2963
|
},
|
2241
2964
|
{
|
2242
2965
|
time: /* @__PURE__ */ jsxRuntime.jsx(
|
@@ -2274,25 +2997,77 @@ const Information = ({ activeTab }) => {
|
|
2274
2997
|
);
|
2275
2998
|
};
|
2276
2999
|
const HeaderActions = ({ actions: actions2 }) => {
|
2277
|
-
|
2278
|
-
|
3000
|
+
const [dialogId, setDialogId] = React__namespace.useState(null);
|
3001
|
+
const handleClick = (action) => async (e) => {
|
3002
|
+
if (!("options" in action)) {
|
3003
|
+
const { onClick = () => false, dialog, id } = action;
|
3004
|
+
const muteDialog = await onClick(e);
|
3005
|
+
if (dialog && !muteDialog) {
|
3006
|
+
e.preventDefault();
|
3007
|
+
setDialogId(id);
|
3008
|
+
}
|
3009
|
+
}
|
3010
|
+
};
|
3011
|
+
const handleClose = () => {
|
3012
|
+
setDialogId(null);
|
3013
|
+
};
|
3014
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
|
3015
|
+
if (action.options) {
|
2279
3016
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
2280
3017
|
designSystem.SingleSelect,
|
2281
3018
|
{
|
2282
3019
|
size: "S",
|
2283
|
-
disabled: action.disabled,
|
2284
|
-
"aria-label": action.label,
|
2285
3020
|
onChange: action.onSelect,
|
2286
|
-
|
3021
|
+
"aria-label": action.label,
|
3022
|
+
...action,
|
2287
3023
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
|
2288
3024
|
},
|
2289
3025
|
action.id
|
2290
3026
|
);
|
2291
3027
|
} else {
|
2292
|
-
|
3028
|
+
if (action.type === "icon") {
|
3029
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
3030
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
3031
|
+
designSystem.IconButton,
|
3032
|
+
{
|
3033
|
+
disabled: action.disabled,
|
3034
|
+
label: action.label,
|
3035
|
+
size: "S",
|
3036
|
+
onClick: handleClick(action),
|
3037
|
+
children: action.icon
|
3038
|
+
}
|
3039
|
+
),
|
3040
|
+
action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
|
3041
|
+
HeaderActionDialog,
|
3042
|
+
{
|
3043
|
+
...action.dialog,
|
3044
|
+
isOpen: dialogId === action.id,
|
3045
|
+
onClose: handleClose
|
3046
|
+
}
|
3047
|
+
) : null
|
3048
|
+
] }, action.id);
|
3049
|
+
}
|
2293
3050
|
}
|
2294
3051
|
}) });
|
2295
3052
|
};
|
3053
|
+
const HeaderActionDialog = ({
|
3054
|
+
onClose,
|
3055
|
+
onCancel,
|
3056
|
+
title,
|
3057
|
+
content: Content,
|
3058
|
+
isOpen
|
3059
|
+
}) => {
|
3060
|
+
const handleClose = async () => {
|
3061
|
+
if (onCancel) {
|
3062
|
+
await onCancel();
|
3063
|
+
}
|
3064
|
+
onClose();
|
3065
|
+
};
|
3066
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
3067
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
3068
|
+
typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
|
3069
|
+
] }) });
|
3070
|
+
};
|
2296
3071
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2297
3072
|
const navigate = reactRouterDom.useNavigate();
|
2298
3073
|
const { formatMessage } = reactIntl.useIntl();
|
@@ -2309,6 +3084,7 @@ const ConfigureTheViewAction = ({ collectionType, model }) => {
|
|
2309
3084
|
};
|
2310
3085
|
};
|
2311
3086
|
ConfigureTheViewAction.type = "configure-the-view";
|
3087
|
+
ConfigureTheViewAction.position = "header";
|
2312
3088
|
const EditTheModelAction = ({ model }) => {
|
2313
3089
|
const navigate = reactRouterDom.useNavigate();
|
2314
3090
|
const { formatMessage } = reactIntl.useIntl();
|
@@ -2325,6 +3101,7 @@ const EditTheModelAction = ({ model }) => {
|
|
2325
3101
|
};
|
2326
3102
|
};
|
2327
3103
|
EditTheModelAction.type = "edit-the-model";
|
3104
|
+
EditTheModelAction.position = "header";
|
2328
3105
|
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2329
3106
|
const navigate = reactRouterDom.useNavigate();
|
2330
3107
|
const { formatMessage } = reactIntl.useIntl();
|
@@ -2333,12 +3110,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2333
3110
|
const { delete: deleteAction } = useDocumentActions();
|
2334
3111
|
const { toggleNotification } = strapiAdmin.useNotification();
|
2335
3112
|
const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
|
3113
|
+
const isLocalized = document?.locale != null;
|
2336
3114
|
return {
|
2337
3115
|
disabled: !canDelete || !document,
|
2338
|
-
label: formatMessage(
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
3116
|
+
label: formatMessage(
|
3117
|
+
{
|
3118
|
+
id: "content-manager.actions.delete.label",
|
3119
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
3120
|
+
},
|
3121
|
+
{ isLocalized }
|
3122
|
+
),
|
2342
3123
|
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
|
2343
3124
|
dialog: {
|
2344
3125
|
type: "dialog",
|
@@ -2394,6 +3175,7 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2394
3175
|
};
|
2395
3176
|
};
|
2396
3177
|
DeleteAction$1.type = "delete";
|
3178
|
+
DeleteAction$1.position = ["header", "table-row"];
|
2397
3179
|
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2398
3180
|
const Panels = () => {
|
2399
3181
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
@@ -2417,380 +3199,78 @@ const Panels = () => {
|
|
2417
3199
|
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
2418
3200
|
strapiAdmin.DescriptionComponentRenderer,
|
2419
3201
|
{
|
2420
|
-
props,
|
2421
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2422
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
2423
|
-
}
|
2424
|
-
) });
|
2425
|
-
};
|
2426
|
-
const ActionsPanel = () => {
|
2427
|
-
const { formatMessage } = reactIntl.useIntl();
|
2428
|
-
return {
|
2429
|
-
title: formatMessage({
|
2430
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2431
|
-
defaultMessage: "Document"
|
2432
|
-
}),
|
2433
|
-
content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
|
2434
|
-
};
|
2435
|
-
};
|
2436
|
-
ActionsPanel.type = "actions";
|
2437
|
-
const ActionsPanelContent = () => {
|
2438
|
-
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2439
|
-
const [
|
2440
|
-
{
|
2441
|
-
query: { status = "draft" }
|
2442
|
-
}
|
2443
|
-
] = strapiAdmin.useQueryParams();
|
2444
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2445
|
-
const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2446
|
-
const props = {
|
2447
|
-
activeTab: status,
|
2448
|
-
model,
|
2449
|
-
documentId: id,
|
2450
|
-
document: isCloning ? void 0 : document,
|
2451
|
-
meta: isCloning ? void 0 : meta,
|
2452
|
-
collectionType
|
2453
|
-
};
|
2454
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2455
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
2456
|
-
strapiAdmin.DescriptionComponentRenderer,
|
2457
|
-
{
|
2458
|
-
props,
|
2459
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2460
|
-
children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
|
2461
|
-
}
|
2462
|
-
),
|
2463
|
-
/* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2464
|
-
] });
|
2465
|
-
};
|
2466
|
-
const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
|
2467
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
2468
|
-
designSystem.Flex,
|
2469
|
-
{
|
2470
|
-
ref,
|
2471
|
-
tag: "aside",
|
2472
|
-
"aria-labelledby": "additional-information",
|
2473
|
-
background: "neutral0",
|
2474
|
-
borderColor: "neutral150",
|
2475
|
-
hasRadius: true,
|
2476
|
-
paddingBottom: 4,
|
2477
|
-
paddingLeft: 4,
|
2478
|
-
paddingRight: 4,
|
2479
|
-
paddingTop: 4,
|
2480
|
-
shadow: "tableShadow",
|
2481
|
-
gap: 3,
|
2482
|
-
direction: "column",
|
2483
|
-
justifyContent: "stretch",
|
2484
|
-
alignItems: "flex-start",
|
2485
|
-
children: [
|
2486
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2487
|
-
children
|
2488
|
-
]
|
2489
|
-
}
|
2490
|
-
);
|
2491
|
-
});
|
2492
|
-
const HOOKS = {
|
2493
|
-
/**
|
2494
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2495
|
-
* @constant
|
2496
|
-
* @type {string}
|
2497
|
-
*/
|
2498
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2499
|
-
/**
|
2500
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2501
|
-
* @constant
|
2502
|
-
* @type {string}
|
2503
|
-
*/
|
2504
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2505
|
-
/**
|
2506
|
-
* Hook that allows to mutate the CM's edit view layout
|
2507
|
-
* @constant
|
2508
|
-
* @type {string}
|
2509
|
-
*/
|
2510
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2511
|
-
/**
|
2512
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2513
|
-
* @constant
|
2514
|
-
* @type {string}
|
2515
|
-
*/
|
2516
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2517
|
-
};
|
2518
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2519
|
-
endpoints: (builder) => ({
|
2520
|
-
getContentTypeConfiguration: builder.query({
|
2521
|
-
query: (uid) => ({
|
2522
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2523
|
-
method: "GET"
|
2524
|
-
}),
|
2525
|
-
transformResponse: (response) => response.data,
|
2526
|
-
providesTags: (_result, _error, uid) => [
|
2527
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2528
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2529
|
-
]
|
2530
|
-
}),
|
2531
|
-
getAllContentTypeSettings: builder.query({
|
2532
|
-
query: () => "/content-manager/content-types-settings",
|
2533
|
-
transformResponse: (response) => response.data,
|
2534
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2535
|
-
}),
|
2536
|
-
updateContentTypeConfiguration: builder.mutation({
|
2537
|
-
query: ({ uid, ...body }) => ({
|
2538
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2539
|
-
method: "PUT",
|
2540
|
-
data: body
|
2541
|
-
}),
|
2542
|
-
transformResponse: (response) => response.data,
|
2543
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2544
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2545
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2546
|
-
// Is this necessary?
|
2547
|
-
{ type: "InitialData" }
|
2548
|
-
]
|
2549
|
-
})
|
2550
|
-
})
|
2551
|
-
});
|
2552
|
-
const {
|
2553
|
-
useGetContentTypeConfigurationQuery,
|
2554
|
-
useGetAllContentTypeSettingsQuery,
|
2555
|
-
useUpdateContentTypeConfigurationMutation
|
2556
|
-
} = contentTypesApi;
|
2557
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2558
|
-
const { type } = attribute;
|
2559
|
-
if (type === "relation") {
|
2560
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2561
|
-
}
|
2562
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2563
|
-
};
|
2564
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2565
|
-
if (!mainFieldName) {
|
2566
|
-
return void 0;
|
2567
|
-
}
|
2568
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2569
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2570
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2571
|
-
);
|
2572
|
-
return {
|
2573
|
-
name: mainFieldName,
|
2574
|
-
type: mainFieldType ?? "string"
|
2575
|
-
};
|
2576
|
-
};
|
2577
|
-
const DEFAULT_SETTINGS = {
|
2578
|
-
bulkable: false,
|
2579
|
-
filterable: false,
|
2580
|
-
searchable: false,
|
2581
|
-
pagination: false,
|
2582
|
-
defaultSortBy: "",
|
2583
|
-
defaultSortOrder: "asc",
|
2584
|
-
mainField: "id",
|
2585
|
-
pageSize: 10
|
2586
|
-
};
|
2587
|
-
const useDocumentLayout = (model) => {
|
2588
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2589
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
2590
|
-
const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2591
|
-
const { toggleNotification } = strapiAdmin.useNotification();
|
2592
|
-
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
2593
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2594
|
-
const {
|
2595
|
-
data,
|
2596
|
-
isLoading: isLoadingConfigs,
|
2597
|
-
error,
|
2598
|
-
isFetching: isFetchingConfigs
|
2599
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2600
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2601
|
-
React__namespace.useEffect(() => {
|
2602
|
-
if (error) {
|
2603
|
-
toggleNotification({
|
2604
|
-
type: "danger",
|
2605
|
-
message: formatAPIError(error)
|
2606
|
-
});
|
2607
|
-
}
|
2608
|
-
}, [error, formatAPIError, toggleNotification]);
|
2609
|
-
const editLayout = React__namespace.useMemo(
|
2610
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2611
|
-
layout: [],
|
2612
|
-
components: {},
|
2613
|
-
metadatas: {},
|
2614
|
-
options: {},
|
2615
|
-
settings: DEFAULT_SETTINGS
|
2616
|
-
},
|
2617
|
-
[data, isLoading, schemas, schema, components]
|
2618
|
-
);
|
2619
|
-
const listLayout = React__namespace.useMemo(() => {
|
2620
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2621
|
-
layout: [],
|
2622
|
-
metadatas: {},
|
2623
|
-
options: {},
|
2624
|
-
settings: DEFAULT_SETTINGS
|
2625
|
-
};
|
2626
|
-
}, [data, isLoading, schemas, schema, components]);
|
2627
|
-
const { layout: edit } = React__namespace.useMemo(
|
2628
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2629
|
-
layout: editLayout,
|
2630
|
-
query
|
2631
|
-
}),
|
2632
|
-
[editLayout, query, runHookWaterfall]
|
2633
|
-
);
|
2634
|
-
return {
|
2635
|
-
error,
|
2636
|
-
isLoading,
|
2637
|
-
edit,
|
2638
|
-
list: listLayout
|
2639
|
-
};
|
2640
|
-
};
|
2641
|
-
const useDocLayout = () => {
|
2642
|
-
const { model } = useDoc();
|
2643
|
-
return useDocumentLayout(model);
|
2644
|
-
};
|
2645
|
-
const formatEditLayout = (data, {
|
2646
|
-
schemas,
|
2647
|
-
schema,
|
2648
|
-
components
|
2649
|
-
}) => {
|
2650
|
-
let currentPanelIndex = 0;
|
2651
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2652
|
-
data.contentType.layouts.edit,
|
2653
|
-
schema?.attributes,
|
2654
|
-
data.contentType.metadatas,
|
2655
|
-
{ configurations: data.components, schemas: components },
|
2656
|
-
schemas
|
2657
|
-
).reduce((panels, row) => {
|
2658
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2659
|
-
panels.push([row]);
|
2660
|
-
currentPanelIndex += 2;
|
2661
|
-
} else {
|
2662
|
-
if (!panels[currentPanelIndex]) {
|
2663
|
-
panels.push([]);
|
2664
|
-
}
|
2665
|
-
panels[currentPanelIndex].push(row);
|
2666
|
-
}
|
2667
|
-
return panels;
|
2668
|
-
}, []);
|
2669
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2670
|
-
(acc, [uid, configuration]) => {
|
2671
|
-
acc[uid] = {
|
2672
|
-
layout: convertEditLayoutToFieldLayouts(
|
2673
|
-
configuration.layouts.edit,
|
2674
|
-
components[uid].attributes,
|
2675
|
-
configuration.metadatas
|
2676
|
-
),
|
2677
|
-
settings: {
|
2678
|
-
...configuration.settings,
|
2679
|
-
icon: components[uid].info.icon,
|
2680
|
-
displayName: components[uid].info.displayName
|
2681
|
-
}
|
2682
|
-
};
|
2683
|
-
return acc;
|
2684
|
-
},
|
2685
|
-
{}
|
2686
|
-
);
|
2687
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2688
|
-
(acc, [attribute, metadata]) => {
|
2689
|
-
return {
|
2690
|
-
...acc,
|
2691
|
-
[attribute]: metadata.edit
|
2692
|
-
};
|
2693
|
-
},
|
2694
|
-
{}
|
2695
|
-
);
|
2696
|
-
return {
|
2697
|
-
layout: panelledEditAttributes,
|
2698
|
-
components: componentEditAttributes,
|
2699
|
-
metadatas: editMetadatas,
|
2700
|
-
settings: {
|
2701
|
-
...data.contentType.settings,
|
2702
|
-
displayName: schema?.info.displayName
|
2703
|
-
},
|
2704
|
-
options: {
|
2705
|
-
...schema?.options,
|
2706
|
-
...schema?.pluginOptions,
|
2707
|
-
...data.contentType.options
|
2708
|
-
}
|
2709
|
-
};
|
2710
|
-
};
|
2711
|
-
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
2712
|
-
return rows.map(
|
2713
|
-
(row) => row.map((field) => {
|
2714
|
-
const attribute = attributes[field.name];
|
2715
|
-
if (!attribute) {
|
2716
|
-
return null;
|
2717
|
-
}
|
2718
|
-
const { edit: metadata } = metadatas[field.name];
|
2719
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2720
|
-
return {
|
2721
|
-
attribute,
|
2722
|
-
disabled: !metadata.editable,
|
2723
|
-
hint: metadata.description,
|
2724
|
-
label: metadata.label ?? "",
|
2725
|
-
name: field.name,
|
2726
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2727
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2728
|
-
schemas,
|
2729
|
-
components: components?.schemas ?? {}
|
2730
|
-
}),
|
2731
|
-
placeholder: metadata.placeholder ?? "",
|
2732
|
-
required: attribute.required ?? false,
|
2733
|
-
size: field.size,
|
2734
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2735
|
-
visible: metadata.visible ?? true,
|
2736
|
-
type: attribute.type
|
2737
|
-
};
|
2738
|
-
}).filter((field) => field !== null)
|
2739
|
-
);
|
3202
|
+
props,
|
3203
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
3204
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
3205
|
+
}
|
3206
|
+
) });
|
2740
3207
|
};
|
2741
|
-
const
|
2742
|
-
|
2743
|
-
schema,
|
2744
|
-
components
|
2745
|
-
}) => {
|
2746
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2747
|
-
(acc, [attribute, metadata]) => {
|
2748
|
-
return {
|
2749
|
-
...acc,
|
2750
|
-
[attribute]: metadata.list
|
2751
|
-
};
|
2752
|
-
},
|
2753
|
-
{}
|
2754
|
-
);
|
2755
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2756
|
-
data.contentType.layouts.list,
|
2757
|
-
schema?.attributes,
|
2758
|
-
listMetadatas,
|
2759
|
-
{ configurations: data.components, schemas: components },
|
2760
|
-
schemas
|
2761
|
-
);
|
3208
|
+
const ActionsPanel = () => {
|
3209
|
+
const { formatMessage } = reactIntl.useIntl();
|
2762
3210
|
return {
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
...schema?.pluginOptions,
|
2769
|
-
...data.contentType.options
|
2770
|
-
}
|
3211
|
+
title: formatMessage({
|
3212
|
+
id: "content-manager.containers.edit.panels.default.title",
|
3213
|
+
defaultMessage: "Entry"
|
3214
|
+
}),
|
3215
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
|
2771
3216
|
};
|
2772
3217
|
};
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
3218
|
+
ActionsPanel.type = "actions";
|
3219
|
+
const ActionsPanelContent = () => {
|
3220
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
3221
|
+
const [
|
3222
|
+
{
|
3223
|
+
query: { status = "draft" }
|
2778
3224
|
}
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
3225
|
+
] = strapiAdmin.useQueryParams();
|
3226
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3227
|
+
const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
|
3228
|
+
const props = {
|
3229
|
+
activeTab: status,
|
3230
|
+
model,
|
3231
|
+
documentId: id,
|
3232
|
+
document: isCloning ? void 0 : document,
|
3233
|
+
meta: isCloning ? void 0 : meta,
|
3234
|
+
collectionType
|
3235
|
+
};
|
3236
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3237
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
3238
|
+
strapiAdmin.DescriptionComponentRenderer,
|
3239
|
+
{
|
3240
|
+
props,
|
3241
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("panel"),
|
3242
|
+
children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
|
3243
|
+
}
|
3244
|
+
),
|
3245
|
+
/* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3246
|
+
] });
|
2793
3247
|
};
|
3248
|
+
const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
|
3249
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
3250
|
+
designSystem.Flex,
|
3251
|
+
{
|
3252
|
+
ref,
|
3253
|
+
tag: "aside",
|
3254
|
+
"aria-labelledby": "additional-information",
|
3255
|
+
background: "neutral0",
|
3256
|
+
borderColor: "neutral150",
|
3257
|
+
hasRadius: true,
|
3258
|
+
paddingBottom: 4,
|
3259
|
+
paddingLeft: 4,
|
3260
|
+
paddingRight: 4,
|
3261
|
+
paddingTop: 4,
|
3262
|
+
shadow: "tableShadow",
|
3263
|
+
gap: 3,
|
3264
|
+
direction: "column",
|
3265
|
+
justifyContent: "stretch",
|
3266
|
+
alignItems: "flex-start",
|
3267
|
+
children: [
|
3268
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
3269
|
+
children
|
3270
|
+
]
|
3271
|
+
}
|
3272
|
+
);
|
3273
|
+
});
|
2794
3274
|
const ConfirmBulkActionDialog = ({
|
2795
3275
|
onToggleDialog,
|
2796
3276
|
isOpen = false,
|
@@ -2798,7 +3278,7 @@ const ConfirmBulkActionDialog = ({
|
|
2798
3278
|
endAction
|
2799
3279
|
}) => {
|
2800
3280
|
const { formatMessage } = reactIntl.useIntl();
|
2801
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, {
|
3281
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
2802
3282
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
|
2803
3283
|
id: "app.components.ConfirmDialog.title",
|
2804
3284
|
defaultMessage: "Confirmation"
|
@@ -2816,7 +3296,7 @@ const ConfirmBulkActionDialog = ({
|
|
2816
3296
|
] })
|
2817
3297
|
] }) });
|
2818
3298
|
};
|
2819
|
-
const BoldChunk
|
3299
|
+
const BoldChunk = (chunks) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: chunks });
|
2820
3300
|
const ConfirmDialogPublishAll = ({
|
2821
3301
|
isOpen,
|
2822
3302
|
onToggleDialog,
|
@@ -2829,6 +3309,7 @@ const ConfirmDialogPublishAll = ({
|
|
2829
3309
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
|
2830
3310
|
const { model, schema } = useDoc();
|
2831
3311
|
const [{ query }] = strapiAdmin.useQueryParams();
|
3312
|
+
const enableDraftRelationsCount = false;
|
2832
3313
|
const {
|
2833
3314
|
data: countDraftRelations = 0,
|
2834
3315
|
isLoading,
|
@@ -2840,7 +3321,7 @@ const ConfirmDialogPublishAll = ({
|
|
2840
3321
|
locale: query?.plugins?.i18n?.locale
|
2841
3322
|
},
|
2842
3323
|
{
|
2843
|
-
skip:
|
3324
|
+
skip: !enableDraftRelationsCount
|
2844
3325
|
}
|
2845
3326
|
);
|
2846
3327
|
React__namespace.useEffect(() => {
|
@@ -2864,7 +3345,7 @@ const ConfirmDialogPublishAll = ({
|
|
2864
3345
|
defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
|
2865
3346
|
},
|
2866
3347
|
{
|
2867
|
-
b: BoldChunk
|
3348
|
+
b: BoldChunk,
|
2868
3349
|
count: countDraftRelations,
|
2869
3350
|
entities: selectedEntries.length
|
2870
3351
|
}
|
@@ -2903,6 +3384,16 @@ const ConfirmDialogPublishAll = ({
|
|
2903
3384
|
const TypographyMaxWidth = styledComponents.styled(designSystem.Typography)`
|
2904
3385
|
max-width: 300px;
|
2905
3386
|
`;
|
3387
|
+
const TableComponent = styledComponents.styled(designSystem.RawTable)`
|
3388
|
+
width: 100%;
|
3389
|
+
table-layout: fixed;
|
3390
|
+
td:first-child {
|
3391
|
+
border-right: 1px solid ${({ theme }) => theme.colors.neutral150};
|
3392
|
+
}
|
3393
|
+
td:first-of-type {
|
3394
|
+
padding: ${({ theme }) => theme.spaces[4]};
|
3395
|
+
}
|
3396
|
+
`;
|
2906
3397
|
const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
2907
3398
|
const messages = [];
|
2908
3399
|
Object.entries(errors).forEach(([key, value]) => {
|
@@ -3007,7 +3498,7 @@ const SelectedEntriesTableContent = ({
|
|
3007
3498
|
)
|
3008
3499
|
] }),
|
3009
3500
|
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Loading, {}),
|
3010
|
-
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row
|
3501
|
+
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Body, { children: rowsToDisplay.map((row) => /* @__PURE__ */ jsxRuntime.jsxs(strapiAdmin.Table.Row, { children: [
|
3011
3502
|
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.CheckboxCell, { id: row.id }),
|
3012
3503
|
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row.id }) }),
|
3013
3504
|
shouldDisplayMainField && /* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: row[mainField] }) }),
|
@@ -3025,7 +3516,7 @@ const SelectedEntriesTableContent = ({
|
|
3025
3516
|
status: row.status
|
3026
3517
|
}
|
3027
3518
|
) }),
|
3028
|
-
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3519
|
+
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3029
3520
|
designSystem.IconButton,
|
3030
3521
|
{
|
3031
3522
|
tag: reactRouterDom.Link,
|
@@ -3034,27 +3525,86 @@ const SelectedEntriesTableContent = ({
|
|
3034
3525
|
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3035
3526
|
},
|
3036
3527
|
state: { from: pathname },
|
3037
|
-
label: formatMessage(
|
3038
|
-
|
3039
|
-
|
3040
|
-
|
3041
|
-
{
|
3042
|
-
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3043
|
-
defaultMessage: "item line {number}"
|
3044
|
-
},
|
3045
|
-
{ number: index2 + 1 }
|
3046
|
-
)
|
3047
|
-
}
|
3048
|
-
),
|
3528
|
+
label: formatMessage({
|
3529
|
+
id: "content-manager.bulk-publish.edit",
|
3530
|
+
defaultMessage: "Edit"
|
3531
|
+
}),
|
3049
3532
|
target: "_blank",
|
3050
3533
|
marginLeft: "auto",
|
3051
|
-
|
3534
|
+
variant: "ghost",
|
3535
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
|
3052
3536
|
}
|
3053
|
-
) })
|
3537
|
+
) }) })
|
3054
3538
|
] }, row.id)) })
|
3055
3539
|
] });
|
3056
3540
|
};
|
3057
|
-
const
|
3541
|
+
const PublicationStatusSummary = ({ count, icon, message }) => {
|
3542
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", flex: 1, gap: 3, children: [
|
3543
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
3544
|
+
icon,
|
3545
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { children: message })
|
3546
|
+
] }),
|
3547
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { fontWeight: "bold", children: count })
|
3548
|
+
] });
|
3549
|
+
};
|
3550
|
+
const PublicationStatusGrid = ({
|
3551
|
+
entriesReadyToPublishCount,
|
3552
|
+
entriesPublishedCount,
|
3553
|
+
entriesModifiedCount,
|
3554
|
+
entriesWithErrorsCount
|
3555
|
+
}) => {
|
3556
|
+
const { formatMessage } = reactIntl.useIntl();
|
3557
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { hasRadius: true, borderColor: "neutral150", children: /* @__PURE__ */ jsxRuntime.jsx(TableComponent, { colCount: 2, rowCount: 2, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tbody, { children: [
|
3558
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
3559
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3560
|
+
PublicationStatusSummary,
|
3561
|
+
{
|
3562
|
+
count: entriesReadyToPublishCount,
|
3563
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
|
3564
|
+
message: formatMessage({
|
3565
|
+
id: "app.utils.ready-to-publish",
|
3566
|
+
defaultMessage: "Ready to publish"
|
3567
|
+
})
|
3568
|
+
}
|
3569
|
+
) }),
|
3570
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3571
|
+
PublicationStatusSummary,
|
3572
|
+
{
|
3573
|
+
count: entriesPublishedCount,
|
3574
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CheckCircle, { fill: "success600" }),
|
3575
|
+
message: formatMessage({
|
3576
|
+
id: "app.utils.already-published",
|
3577
|
+
defaultMessage: "Already published"
|
3578
|
+
})
|
3579
|
+
}
|
3580
|
+
) })
|
3581
|
+
] }),
|
3582
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Tr, { children: [
|
3583
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3584
|
+
PublicationStatusSummary,
|
3585
|
+
{
|
3586
|
+
count: entriesModifiedCount,
|
3587
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ArrowsCounterClockwise, { fill: "alternative600" }),
|
3588
|
+
message: formatMessage({
|
3589
|
+
id: "content-manager.bulk-publish.modified",
|
3590
|
+
defaultMessage: "Ready to publish changes"
|
3591
|
+
})
|
3592
|
+
}
|
3593
|
+
) }),
|
3594
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Td, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3595
|
+
PublicationStatusSummary,
|
3596
|
+
{
|
3597
|
+
count: entriesWithErrorsCount,
|
3598
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.CrossCircle, { fill: "danger600" }),
|
3599
|
+
message: formatMessage({
|
3600
|
+
id: "content-manager.bulk-publish.waiting-for-action",
|
3601
|
+
defaultMessage: "Waiting for action"
|
3602
|
+
})
|
3603
|
+
}
|
3604
|
+
) })
|
3605
|
+
] })
|
3606
|
+
] }) }) });
|
3607
|
+
};
|
3058
3608
|
const SelectedEntriesModalContent = ({
|
3059
3609
|
listViewSelectedEntries,
|
3060
3610
|
toggleModal,
|
@@ -3087,7 +3637,13 @@ const SelectedEntriesModalContent = ({
|
|
3087
3637
|
);
|
3088
3638
|
const { rows, validationErrors } = React__namespace.useMemo(() => {
|
3089
3639
|
if (data.length > 0 && schema) {
|
3090
|
-
const validate = createYupSchema(
|
3640
|
+
const validate = createYupSchema(
|
3641
|
+
schema.attributes,
|
3642
|
+
components,
|
3643
|
+
// Since this is the "Publish" action, the validation
|
3644
|
+
// schema must enforce the rules for published entities
|
3645
|
+
{ status: "published" }
|
3646
|
+
);
|
3091
3647
|
const validationErrors2 = {};
|
3092
3648
|
const rows2 = data.map((entry) => {
|
3093
3649
|
try {
|
@@ -3107,7 +3663,6 @@ const SelectedEntriesModalContent = ({
|
|
3107
3663
|
validationErrors: {}
|
3108
3664
|
};
|
3109
3665
|
}, [components, data, schema]);
|
3110
|
-
const [publishedCount, setPublishedCount] = React__namespace.useState(0);
|
3111
3666
|
const [isDialogOpen, setIsDialogOpen] = React__namespace.useState(false);
|
3112
3667
|
const { publishMany: bulkPublishAction } = useDocumentActions();
|
3113
3668
|
const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
|
@@ -3119,53 +3674,36 @@ const SelectedEntriesModalContent = ({
|
|
3119
3674
|
const selectedEntriesWithErrorsCount = selectedEntries.filter(
|
3120
3675
|
({ documentId }) => validationErrors[documentId]
|
3121
3676
|
).length;
|
3122
|
-
const
|
3677
|
+
const selectedEntriesPublishedCount = selectedEntries.filter(
|
3123
3678
|
({ status }) => status === "published"
|
3124
3679
|
).length;
|
3125
|
-
const
|
3680
|
+
const selectedEntriesModifiedCount = selectedEntries.filter(
|
3681
|
+
({ status, documentId }) => status === "modified" && !validationErrors[documentId]
|
3682
|
+
).length;
|
3683
|
+
const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublishedCount;
|
3126
3684
|
const toggleDialog = () => setIsDialogOpen((prev) => !prev);
|
3127
3685
|
const handleConfirmBulkPublish = async () => {
|
3128
3686
|
toggleDialog();
|
3129
3687
|
const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
|
3130
3688
|
if (!("error" in res)) {
|
3131
|
-
setPublishedCount(res.count);
|
3132
3689
|
const unpublishedEntries = rows.filter((row) => {
|
3133
3690
|
return !entriesToPublish.includes(row.documentId);
|
3134
3691
|
});
|
3135
3692
|
setListViewSelectedDocuments(unpublishedEntries);
|
3136
3693
|
}
|
3137
3694
|
};
|
3138
|
-
const getFormattedCountMessage = () => {
|
3139
|
-
if (publishedCount) {
|
3140
|
-
return formatMessage(
|
3141
|
-
{
|
3142
|
-
id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
|
3143
|
-
defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
|
3144
|
-
},
|
3145
|
-
{
|
3146
|
-
publishedCount,
|
3147
|
-
withErrorsCount: selectedEntriesWithErrorsCount,
|
3148
|
-
b: BoldChunk
|
3149
|
-
}
|
3150
|
-
);
|
3151
|
-
}
|
3152
|
-
return formatMessage(
|
3153
|
-
{
|
3154
|
-
id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
|
3155
|
-
defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
|
3156
|
-
},
|
3157
|
-
{
|
3158
|
-
readyToPublishCount: selectedEntriesWithNoErrorsCount,
|
3159
|
-
withErrorsCount: selectedEntriesWithErrorsCount,
|
3160
|
-
alreadyPublishedCount: selectedEntriesPublished,
|
3161
|
-
b: BoldChunk
|
3162
|
-
}
|
3163
|
-
);
|
3164
|
-
};
|
3165
3695
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
3166
3696
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Body, { children: [
|
3167
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
3168
|
-
|
3697
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
3698
|
+
PublicationStatusGrid,
|
3699
|
+
{
|
3700
|
+
entriesReadyToPublishCount: selectedEntriesWithNoErrorsCount - selectedEntriesModifiedCount,
|
3701
|
+
entriesPublishedCount: selectedEntriesPublishedCount,
|
3702
|
+
entriesModifiedCount: selectedEntriesModifiedCount,
|
3703
|
+
entriesWithErrorsCount: selectedEntriesWithErrorsCount
|
3704
|
+
}
|
3705
|
+
),
|
3706
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 7, children: /* @__PURE__ */ jsxRuntime.jsx(
|
3169
3707
|
SelectedEntriesTableContent,
|
3170
3708
|
{
|
3171
3709
|
isPublishing: isSubmittingForm,
|
@@ -3186,7 +3724,7 @@ const SelectedEntriesModalContent = ({
|
|
3186
3724
|
designSystem.Button,
|
3187
3725
|
{
|
3188
3726
|
onClick: toggleDialog,
|
3189
|
-
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount ||
|
3727
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublishedCount === selectedEntries.length || isLoading,
|
3190
3728
|
loading: isSubmittingForm,
|
3191
3729
|
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3192
3730
|
}
|
@@ -3212,8 +3750,7 @@ const PublishAction = ({ documents, model }) => {
|
|
3212
3750
|
const refetchList = () => {
|
3213
3751
|
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3214
3752
|
};
|
3215
|
-
if (!showPublishButton)
|
3216
|
-
return null;
|
3753
|
+
if (!showPublishButton) return null;
|
3217
3754
|
return {
|
3218
3755
|
actionType: "publish",
|
3219
3756
|
variant: "tertiary",
|
@@ -3281,8 +3818,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
3281
3818
|
selectRow([]);
|
3282
3819
|
}
|
3283
3820
|
};
|
3284
|
-
if (!hasDeletePermission)
|
3285
|
-
return null;
|
3821
|
+
if (!hasDeletePermission) return null;
|
3286
3822
|
return {
|
3287
3823
|
variant: "danger-light",
|
3288
3824
|
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
@@ -3331,8 +3867,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3331
3867
|
}
|
3332
3868
|
};
|
3333
3869
|
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3334
|
-
if (!showUnpublishButton)
|
3335
|
-
return null;
|
3870
|
+
if (!showUnpublishButton) return null;
|
3336
3871
|
return {
|
3337
3872
|
variant: "tertiary",
|
3338
3873
|
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
@@ -3437,7 +3972,7 @@ const TableActions = ({ document }) => {
|
|
3437
3972
|
strapiAdmin.DescriptionComponentRenderer,
|
3438
3973
|
{
|
3439
3974
|
props,
|
3440
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3975
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions("table-row").filter((action) => action.name !== "PublishAction"),
|
3441
3976
|
children: (actions2) => {
|
3442
3977
|
const tableRowActions = actions2.filter((action) => {
|
3443
3978
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3496,6 +4031,7 @@ const EditAction = ({ documentId }) => {
|
|
3496
4031
|
};
|
3497
4032
|
};
|
3498
4033
|
EditAction.type = "edit";
|
4034
|
+
EditAction.position = "table-row";
|
3499
4035
|
const StyledPencil = styledComponents.styled(Icons.Pencil)`
|
3500
4036
|
path {
|
3501
4037
|
fill: currentColor;
|
@@ -3548,7 +4084,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3548
4084
|
}),
|
3549
4085
|
content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3550
4086
|
footer: ({ onClose }) => {
|
3551
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.
|
4087
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
|
3552
4088
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3553
4089
|
id: "cancel",
|
3554
4090
|
defaultMessage: "Cancel"
|
@@ -3572,6 +4108,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3572
4108
|
};
|
3573
4109
|
};
|
3574
4110
|
CloneAction.type = "clone";
|
4111
|
+
CloneAction.position = "table-row";
|
3575
4112
|
const StyledDuplicate = styledComponents.styled(Icons.Duplicate)`
|
3576
4113
|
path {
|
3577
4114
|
fill: currentColor;
|
@@ -3589,8 +4126,7 @@ class ContentManagerPlugin {
|
|
3589
4126
|
documentActions = [
|
3590
4127
|
...DEFAULT_ACTIONS,
|
3591
4128
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3592
|
-
...DEFAULT_HEADER_ACTIONS
|
3593
|
-
HistoryAction
|
4129
|
+
...DEFAULT_HEADER_ACTIONS
|
3594
4130
|
];
|
3595
4131
|
editViewSidePanels = [ActionsPanel];
|
3596
4132
|
headerActions = [];
|
@@ -3653,13 +4189,21 @@ class ContentManagerPlugin {
|
|
3653
4189
|
id: PLUGIN_ID,
|
3654
4190
|
name: "Content Manager",
|
3655
4191
|
injectionZones: INJECTION_ZONES,
|
4192
|
+
isReady: false,
|
3656
4193
|
apis: {
|
3657
4194
|
addBulkAction: this.addBulkAction.bind(this),
|
3658
4195
|
addDocumentAction: this.addDocumentAction.bind(this),
|
3659
4196
|
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
3660
4197
|
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
3661
4198
|
getBulkActions: () => this.bulkActions,
|
3662
|
-
getDocumentActions: () =>
|
4199
|
+
getDocumentActions: (position) => {
|
4200
|
+
if (position) {
|
4201
|
+
return this.documentActions.filter(
|
4202
|
+
(action) => action.position == void 0 || [action.position].flat().includes(position)
|
4203
|
+
);
|
4204
|
+
}
|
4205
|
+
return this.documentActions;
|
4206
|
+
},
|
3663
4207
|
getEditViewSidePanels: () => this.editViewSidePanels,
|
3664
4208
|
getHeaderActions: () => this.headerActions
|
3665
4209
|
}
|
@@ -3669,16 +4213,71 @@ class ContentManagerPlugin {
|
|
3669
4213
|
const getPrintableType = (value) => {
|
3670
4214
|
const nativeType = typeof value;
|
3671
4215
|
if (nativeType === "object") {
|
3672
|
-
if (value === null)
|
3673
|
-
|
3674
|
-
if (Array.isArray(value))
|
3675
|
-
return "array";
|
4216
|
+
if (value === null) return "null";
|
4217
|
+
if (Array.isArray(value)) return "array";
|
3676
4218
|
if (value instanceof Object && value.constructor.name !== "Object") {
|
3677
4219
|
return value.constructor.name;
|
3678
4220
|
}
|
3679
4221
|
}
|
3680
4222
|
return nativeType;
|
3681
4223
|
};
|
4224
|
+
const HistoryAction = ({ model, document }) => {
|
4225
|
+
const { formatMessage } = reactIntl.useIntl();
|
4226
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
4227
|
+
const navigate = reactRouterDom.useNavigate();
|
4228
|
+
const { trackUsage } = strapiAdmin.useTracking();
|
4229
|
+
const { pathname } = reactRouterDom.useLocation();
|
4230
|
+
const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
|
4231
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
4232
|
+
return null;
|
4233
|
+
}
|
4234
|
+
const handleOnClick = () => {
|
4235
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
4236
|
+
trackUsage("willNavigate", {
|
4237
|
+
from: pathname,
|
4238
|
+
to: `${pathname}/${destination.pathname}`
|
4239
|
+
});
|
4240
|
+
navigate(destination);
|
4241
|
+
};
|
4242
|
+
return {
|
4243
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
|
4244
|
+
label: formatMessage({
|
4245
|
+
id: "content-manager.history.document-action",
|
4246
|
+
defaultMessage: "Content History"
|
4247
|
+
}),
|
4248
|
+
onClick: handleOnClick,
|
4249
|
+
disabled: (
|
4250
|
+
/**
|
4251
|
+
* The user is creating a new document.
|
4252
|
+
* It hasn't been saved yet, so there's no history to go to
|
4253
|
+
*/
|
4254
|
+
!document || /**
|
4255
|
+
* The document has been created but the current dimension has never been saved.
|
4256
|
+
* For example, the user is creating a new locale in an existing document,
|
4257
|
+
* so there's no history for the document in that locale
|
4258
|
+
*/
|
4259
|
+
!document.id || /**
|
4260
|
+
* History is only available for content types created by the user.
|
4261
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
4262
|
+
* which start with `admin::` or `plugin::`
|
4263
|
+
*/
|
4264
|
+
!model.startsWith("api::")
|
4265
|
+
),
|
4266
|
+
position: "header"
|
4267
|
+
};
|
4268
|
+
};
|
4269
|
+
HistoryAction.type = "history";
|
4270
|
+
HistoryAction.position = "header";
|
4271
|
+
const historyAdmin = {
|
4272
|
+
bootstrap(app) {
|
4273
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
4274
|
+
addDocumentAction((actions2) => {
|
4275
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
4276
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
4277
|
+
return actions2;
|
4278
|
+
});
|
4279
|
+
}
|
4280
|
+
};
|
3682
4281
|
const initialState = {
|
3683
4282
|
collectionTypeLinks: [],
|
3684
4283
|
components: [],
|
@@ -3715,6 +4314,88 @@ const { setInitialData } = actions;
|
|
3715
4314
|
const reducer = toolkit.combineReducers({
|
3716
4315
|
app: reducer$1
|
3717
4316
|
});
|
4317
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
4318
|
+
endpoints: (builder) => ({
|
4319
|
+
getPreviewUrl: builder.query({
|
4320
|
+
query({ query, params }) {
|
4321
|
+
return {
|
4322
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4323
|
+
method: "GET",
|
4324
|
+
config: {
|
4325
|
+
params: query
|
4326
|
+
}
|
4327
|
+
};
|
4328
|
+
}
|
4329
|
+
})
|
4330
|
+
})
|
4331
|
+
});
|
4332
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4333
|
+
const ConditionalTooltip = ({ isShown, label, children }) => {
|
4334
|
+
if (isShown) {
|
4335
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Tooltip, { label, children });
|
4336
|
+
}
|
4337
|
+
return children;
|
4338
|
+
};
|
4339
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4340
|
+
const { formatMessage } = reactIntl.useIntl();
|
4341
|
+
const { trackUsage } = strapiAdmin.useTracking();
|
4342
|
+
const { pathname } = reactRouterDom.useLocation();
|
4343
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
4344
|
+
const isModified = strapiAdmin.useForm("PreviewSidePanel", (state) => state.modified);
|
4345
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4346
|
+
params: {
|
4347
|
+
contentType: model
|
4348
|
+
},
|
4349
|
+
query: {
|
4350
|
+
documentId,
|
4351
|
+
locale: document?.locale,
|
4352
|
+
status: document?.status
|
4353
|
+
}
|
4354
|
+
});
|
4355
|
+
if (!data?.data?.url || error) {
|
4356
|
+
return null;
|
4357
|
+
}
|
4358
|
+
const trackNavigation = () => {
|
4359
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4360
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
4361
|
+
};
|
4362
|
+
return {
|
4363
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4364
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(
|
4365
|
+
ConditionalTooltip,
|
4366
|
+
{
|
4367
|
+
label: formatMessage({
|
4368
|
+
id: "content-manager.preview.panel.button-disabled-tooltip",
|
4369
|
+
defaultMessage: "Please save to open the preview"
|
4370
|
+
}),
|
4371
|
+
isShown: isModified,
|
4372
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { cursor: "not-allowed", width: "100%", children: /* @__PURE__ */ jsxRuntime.jsx(
|
4373
|
+
designSystem.Button,
|
4374
|
+
{
|
4375
|
+
variant: "tertiary",
|
4376
|
+
tag: reactRouterDom.Link,
|
4377
|
+
to: { pathname: "preview", search: qs.stringify(query, { encode: false }) },
|
4378
|
+
onClick: trackNavigation,
|
4379
|
+
width: "100%",
|
4380
|
+
disabled: isModified,
|
4381
|
+
pointerEvents: isModified ? "none" : void 0,
|
4382
|
+
tabIndex: isModified ? -1 : void 0,
|
4383
|
+
children: formatMessage({
|
4384
|
+
id: "content-manager.preview.panel.button",
|
4385
|
+
defaultMessage: "Open preview"
|
4386
|
+
})
|
4387
|
+
}
|
4388
|
+
) })
|
4389
|
+
}
|
4390
|
+
)
|
4391
|
+
};
|
4392
|
+
};
|
4393
|
+
const previewAdmin = {
|
4394
|
+
bootstrap(app) {
|
4395
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4396
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4397
|
+
}
|
4398
|
+
};
|
3718
4399
|
const index = {
|
3719
4400
|
register(app) {
|
3720
4401
|
const cm = new ContentManagerPlugin();
|
@@ -3734,7 +4415,7 @@ const index = {
|
|
3734
4415
|
app.router.addRoute({
|
3735
4416
|
path: "content-manager/*",
|
3736
4417
|
lazy: async () => {
|
3737
|
-
const { Layout } = await Promise.resolve().then(() => require("./layout-
|
4418
|
+
const { Layout } = await Promise.resolve().then(() => require("./layout-4BqLFW_b.js"));
|
3738
4419
|
return {
|
3739
4420
|
Component: Layout
|
3740
4421
|
};
|
@@ -3743,10 +4424,18 @@ const index = {
|
|
3743
4424
|
});
|
3744
4425
|
app.registerPlugin(cm.config);
|
3745
4426
|
},
|
4427
|
+
bootstrap(app) {
|
4428
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4429
|
+
historyAdmin.bootstrap(app);
|
4430
|
+
}
|
4431
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4432
|
+
previewAdmin.bootstrap(app);
|
4433
|
+
}
|
4434
|
+
},
|
3746
4435
|
async registerTrads({ locales }) {
|
3747
4436
|
const importedTrads = await Promise.all(
|
3748
4437
|
locales.map((locale) => {
|
3749
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-
|
4438
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-BR48D_RH.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-9K52xZIr.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-C43IbhA_.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-7sfIbjxE.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
|
3750
4439
|
return {
|
3751
4440
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3752
4441
|
locale
|
@@ -3764,10 +4453,10 @@ const index = {
|
|
3764
4453
|
};
|
3765
4454
|
exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
|
3766
4455
|
exports.BulkActionsRenderer = BulkActionsRenderer;
|
4456
|
+
exports.CLONE_PATH = CLONE_PATH;
|
3767
4457
|
exports.COLLECTION_TYPES = COLLECTION_TYPES;
|
3768
4458
|
exports.CREATOR_FIELDS = CREATOR_FIELDS;
|
3769
4459
|
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
3770
|
-
exports.DOCUMENT_META_FIELDS = DOCUMENT_META_FIELDS;
|
3771
4460
|
exports.DocumentRBAC = DocumentRBAC;
|
3772
4461
|
exports.DocumentStatus = DocumentStatus;
|
3773
4462
|
exports.HOOKS = HOOKS;
|
@@ -3784,13 +4473,18 @@ exports.checkIfAttributeIsDisplayable = checkIfAttributeIsDisplayable;
|
|
3784
4473
|
exports.contentManagerApi = contentManagerApi;
|
3785
4474
|
exports.convertEditLayoutToFieldLayouts = convertEditLayoutToFieldLayouts;
|
3786
4475
|
exports.convertListLayoutToFieldLayouts = convertListLayoutToFieldLayouts;
|
4476
|
+
exports.createDefaultForm = createDefaultForm;
|
3787
4477
|
exports.createYupSchema = createYupSchema;
|
3788
4478
|
exports.extractContentTypeComponents = extractContentTypeComponents;
|
3789
4479
|
exports.getDisplayName = getDisplayName;
|
3790
4480
|
exports.getMainField = getMainField;
|
3791
4481
|
exports.getTranslation = getTranslation;
|
3792
4482
|
exports.index = index;
|
4483
|
+
exports.prepareTempKeys = prepareTempKeys;
|
4484
|
+
exports.removeFieldsThatDontExistOnSchema = removeFieldsThatDontExistOnSchema;
|
3793
4485
|
exports.setInitialData = setInitialData;
|
4486
|
+
exports.transformDocument = transformDocument;
|
4487
|
+
exports.useContentManagerContext = useContentManagerContext;
|
3794
4488
|
exports.useContentTypeSchema = useContentTypeSchema;
|
3795
4489
|
exports.useDoc = useDoc;
|
3796
4490
|
exports.useDocLayout = useDocLayout;
|
@@ -3802,5 +4496,6 @@ exports.useGetAllContentTypeSettingsQuery = useGetAllContentTypeSettingsQuery;
|
|
3802
4496
|
exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
|
3803
4497
|
exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
|
3804
4498
|
exports.useGetInitialDataQuery = useGetInitialDataQuery;
|
4499
|
+
exports.useGetPreviewUrlQuery = useGetPreviewUrlQuery;
|
3805
4500
|
exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
|
3806
|
-
//# sourceMappingURL=index-
|
4501
|
+
//# sourceMappingURL=index-DkJQjlak.js.map
|