@strapi/content-manager 0.0.0-experimental.da85533897155e719d784f0271223c866d2f69ab → 0.0.0-experimental.e02b4637b3906c6d31048d00600d09a23a0edc3d
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{ComponentConfigurationPage-9lRmRdIr.mjs → ComponentConfigurationPage-DfFSZQxe.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-9lRmRdIr.mjs.map → ComponentConfigurationPage-DfFSZQxe.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DyDkPajU.js → ComponentConfigurationPage-FqfsxQ1j.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DyDkPajU.js.map → ComponentConfigurationPage-FqfsxQ1j.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DValmA0m.js → EditConfigurationPage-Cn0e8t3I.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DValmA0m.js.map → EditConfigurationPage-Cn0e8t3I.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Bk893vVY.mjs → EditConfigurationPage-DdPNAbl3.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-Bk893vVY.mjs.map → EditConfigurationPage-DdPNAbl3.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DiNFdFqP.mjs → EditViewPage-B82x_x1b.mjs} +15 -5
- package/dist/_chunks/EditViewPage-B82x_x1b.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-Dk7Eaft4.js → EditViewPage-DlxEHhUt.js} +15 -5
- package/dist/_chunks/EditViewPage-DlxEHhUt.js.map +1 -0
- package/dist/_chunks/{Field-DH2OaqUP.js → Field-COL25JiC.js} +76 -42
- package/dist/_chunks/Field-COL25JiC.js.map +1 -0
- package/dist/_chunks/{Field-Dv_HTFTa.mjs → Field-DufHXW17.mjs} +72 -38
- package/dist/_chunks/Field-DufHXW17.mjs.map +1 -0
- package/dist/_chunks/{Form-B_dUDizM.js → Form-BssUwrTO.js} +16 -8
- package/dist/_chunks/Form-BssUwrTO.js.map +1 -0
- package/dist/_chunks/{Form-Dy6P4HgH.mjs → Form-u_kAOhwB.mjs} +16 -8
- package/dist/_chunks/Form-u_kAOhwB.mjs.map +1 -0
- package/dist/_chunks/{History-BT4w83Oa.js → History-C9t9UqpO.js} +23 -10
- package/dist/_chunks/History-C9t9UqpO.js.map +1 -0
- package/dist/_chunks/{History-DrwsD1Vc.mjs → History-DRwA3oMM.mjs} +24 -11
- package/dist/_chunks/History-DRwA3oMM.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CuYrMcW3.js → ListConfigurationPage-BXYPohh-.js} +2 -2
- package/dist/_chunks/{ListConfigurationPage-CuYrMcW3.js.map → ListConfigurationPage-BXYPohh-.js.map} +1 -1
- package/dist/_chunks/{ListConfigurationPage-BxIP0jRy.mjs → ListConfigurationPage-BxfQJzPk.mjs} +2 -2
- package/dist/_chunks/{ListConfigurationPage-BxIP0jRy.mjs.map → ListConfigurationPage-BxfQJzPk.mjs.map} +1 -1
- package/dist/_chunks/{ListViewPage-5a1vw-OK.mjs → ListViewPage-CELx2ysp.mjs} +24 -12
- package/dist/_chunks/ListViewPage-CELx2ysp.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BvpwNur7.js → ListViewPage-D2VD8Szg.js} +28 -16
- package/dist/_chunks/ListViewPage-D2VD8Szg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-UqEiWKkM.js → NoContentTypePage-BV9IjJSM.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-UqEiWKkM.js.map → NoContentTypePage-BV9IjJSM.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-Bm6tRcd3.mjs → NoContentTypePage-DtJ9jcfk.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-Bm6tRcd3.mjs.map → NoContentTypePage-DtJ9jcfk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BHPqn_tQ.mjs → NoPermissionsPage-DWleVYK7.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BHPqn_tQ.mjs.map → NoPermissionsPage-DWleVYK7.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-C_vGRo8Q.js → NoPermissionsPage-Dp8NpF9I.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-C_vGRo8Q.js.map → NoPermissionsPage-Dp8NpF9I.js.map} +1 -1
- package/dist/_chunks/{Relations-C7fPyh5P.mjs → Relations-BTcf5xaw.mjs} +32 -23
- package/dist/_chunks/Relations-BTcf5xaw.mjs.map +1 -0
- package/dist/_chunks/{Relations-CznVF6LS.js → Relations-DR7EUgyC.js} +32 -23
- package/dist/_chunks/Relations-DR7EUgyC.js.map +1 -0
- package/dist/_chunks/{en-otD_UBJi.js → en-Bm0D0IWz.js} +12 -11
- package/dist/_chunks/{en-otD_UBJi.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-CbaIuYoB.mjs → en-DKV44jRb.mjs} +12 -11
- package/dist/_chunks/{en-CbaIuYoB.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-D9UmmBcM.js → index-BdMf2lfT.js} +1990 -1875
- package/dist/_chunks/index-BdMf2lfT.js.map +1 -0
- package/dist/_chunks/{index-BJ6uTqLL.mjs → index-wnqzm4Q8.mjs} +1994 -1879
- package/dist/_chunks/index-wnqzm4Q8.mjs.map +1 -0
- package/dist/_chunks/{layout-uomiIGbG.mjs → layout-2CfjL0T9.mjs} +5 -4
- package/dist/_chunks/{layout-uomiIGbG.mjs.map → layout-2CfjL0T9.mjs.map} +1 -1
- package/dist/_chunks/{layout-kfu5Wtix.js → layout-B2MyZU-_.js} +5 -4
- package/dist/_chunks/{layout-kfu5Wtix.js.map → layout-B2MyZU-_.js.map} +1 -1
- package/dist/_chunks/{relations-DKENrxko.js → relations-BH7JJGGe.js} +2 -2
- package/dist/_chunks/{relations-DKENrxko.js.map → relations-BH7JJGGe.js.map} +1 -1
- package/dist/_chunks/{relations-DiDufGSA.mjs → relations-C0w0GcXi.mjs} +2 -2
- package/dist/_chunks/{relations-DiDufGSA.mjs.map → relations-C0w0GcXi.mjs.map} +1 -1
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +3 -2
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +32 -1
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/services/documents.d.ts +3 -1
- package/dist/server/index.js +34 -18
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +34 -18
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/history/services/history.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/package.json +12 -12
- package/dist/_chunks/EditViewPage-DiNFdFqP.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-Dk7Eaft4.js.map +0 -1
- package/dist/_chunks/Field-DH2OaqUP.js.map +0 -1
- package/dist/_chunks/Field-Dv_HTFTa.mjs.map +0 -1
- package/dist/_chunks/Form-B_dUDizM.js.map +0 -1
- package/dist/_chunks/Form-Dy6P4HgH.mjs.map +0 -1
- package/dist/_chunks/History-BT4w83Oa.js.map +0 -1
- package/dist/_chunks/History-DrwsD1Vc.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-5a1vw-OK.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BvpwNur7.js.map +0 -1
- package/dist/_chunks/Relations-C7fPyh5P.mjs.map +0 -1
- package/dist/_chunks/Relations-CznVF6LS.js.map +0 -1
- package/dist/_chunks/index-BJ6uTqLL.mjs.map +0 -1
- package/dist/_chunks/index-D9UmmBcM.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,16 +1,16 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors,
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
4
4
|
import * as React from "react";
|
5
5
|
import { lazy } from "react";
|
6
|
-
import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption,
|
6
|
+
import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
7
|
import { useIntl } from "react-intl";
|
8
8
|
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
9
|
-
import { styled } from "styled-components";
|
10
9
|
import * as yup from "yup";
|
11
10
|
import { ValidationError } from "yup";
|
12
11
|
import pipe from "lodash/fp/pipe";
|
13
12
|
import { intervalToDuration, isPast } from "date-fns";
|
13
|
+
import { styled } from "styled-components";
|
14
14
|
import { stringify } from "qs";
|
15
15
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
16
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
@@ -100,6 +100,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
100
100
|
if (!slug) {
|
101
101
|
throw new Error("Cannot find the slug param in the URL");
|
102
102
|
}
|
103
|
+
const [{ rawQuery }] = useQueryParams();
|
103
104
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
104
105
|
const contentTypePermissions = React.useMemo(() => {
|
105
106
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -110,7 +111,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
110
111
|
return { ...acc, [action]: [permission] };
|
111
112
|
}, {});
|
112
113
|
}, [slug, userPermissions]);
|
113
|
-
const { isLoading, allowedActions } = useRBAC(
|
114
|
+
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
contentTypePermissions,
|
116
|
+
permissions ?? void 0,
|
117
|
+
// TODO: useRBAC context should be typed and built differently
|
118
|
+
// We are passing raw query as context to the hook so that it can
|
119
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
120
|
+
rawQuery
|
121
|
+
);
|
114
122
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
115
123
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
116
124
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -461,6 +469,24 @@ const buildValidParams = (query) => {
|
|
461
469
|
const isBaseQueryError = (error) => {
|
462
470
|
return error.name !== void 0;
|
463
471
|
};
|
472
|
+
const arrayValidator = (attribute, options) => ({
|
473
|
+
message: translatedErrors.required,
|
474
|
+
test(value) {
|
475
|
+
if (options.status === "draft") {
|
476
|
+
return true;
|
477
|
+
}
|
478
|
+
if (!attribute.required) {
|
479
|
+
return true;
|
480
|
+
}
|
481
|
+
if (!value) {
|
482
|
+
return false;
|
483
|
+
}
|
484
|
+
if (Array.isArray(value) && value.length === 0) {
|
485
|
+
return false;
|
486
|
+
}
|
487
|
+
return true;
|
488
|
+
}
|
489
|
+
});
|
464
490
|
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
465
491
|
const createModelSchema = (attributes2) => yup.object().shape(
|
466
492
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
@@ -468,6 +494,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
|
|
468
494
|
return acc;
|
469
495
|
}
|
470
496
|
const validations = [
|
497
|
+
addNullableValidation,
|
471
498
|
addRequiredValidation,
|
472
499
|
addMinLengthValidation,
|
473
500
|
addMaxLengthValidation,
|
@@ -484,12 +511,12 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
|
|
484
511
|
...acc,
|
485
512
|
[name]: transformSchema(
|
486
513
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
487
|
-
)
|
514
|
+
).test(arrayValidator(attribute, options))
|
488
515
|
};
|
489
516
|
} else {
|
490
517
|
return {
|
491
518
|
...acc,
|
492
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
519
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
493
520
|
};
|
494
521
|
}
|
495
522
|
}
|
@@ -511,7 +538,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
|
|
511
538
|
}
|
512
539
|
)
|
513
540
|
)
|
514
|
-
)
|
541
|
+
).test(arrayValidator(attribute, options))
|
515
542
|
};
|
516
543
|
case "relation":
|
517
544
|
return {
|
@@ -523,7 +550,7 @@ const createYupSchema = (attributes = {}, components = {}, options = { status: n
|
|
523
550
|
} else if (Array.isArray(value)) {
|
524
551
|
return yup.array().of(
|
525
552
|
yup.object().shape({
|
526
|
-
id: yup.
|
553
|
+
id: yup.number().required()
|
527
554
|
})
|
528
555
|
);
|
529
556
|
} else if (typeof value === "object") {
|
@@ -609,17 +636,17 @@ const nullableSchema = (schema) => {
|
|
609
636
|
schema
|
610
637
|
);
|
611
638
|
};
|
639
|
+
const addNullableValidation = () => (schema) => {
|
640
|
+
return nullableSchema(schema);
|
641
|
+
};
|
612
642
|
const addRequiredValidation = (attribute, options) => (schema) => {
|
613
|
-
if (options.status === "draft") {
|
614
|
-
return
|
615
|
-
}
|
616
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
617
|
-
return schema.min(1, translatedErrors.required);
|
643
|
+
if (options.status === "draft" || !attribute.required) {
|
644
|
+
return schema;
|
618
645
|
}
|
619
|
-
if (attribute.required &&
|
646
|
+
if (attribute.required && "required" in schema) {
|
620
647
|
return schema.required(translatedErrors.required);
|
621
648
|
}
|
622
|
-
return
|
649
|
+
return schema;
|
623
650
|
};
|
624
651
|
const addMinLengthValidation = (attribute, options) => (schema) => {
|
625
652
|
if (options.status === "draft") {
|
@@ -647,31 +674,12 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
647
674
|
return schema;
|
648
675
|
};
|
649
676
|
const addMinValidation = (attribute, options) => (schema) => {
|
650
|
-
if ("
|
677
|
+
if (options.status === "draft") {
|
678
|
+
return schema;
|
679
|
+
}
|
680
|
+
if ("min" in attribute && "min" in schema) {
|
651
681
|
const min = toInteger(attribute.min);
|
652
|
-
if (
|
653
|
-
if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
|
654
|
-
return schema.test(
|
655
|
-
"custom-min",
|
656
|
-
{
|
657
|
-
...translatedErrors.min,
|
658
|
-
values: {
|
659
|
-
min: attribute.min
|
660
|
-
}
|
661
|
-
},
|
662
|
-
(value) => {
|
663
|
-
if (!value) {
|
664
|
-
return true;
|
665
|
-
}
|
666
|
-
if (Array.isArray(value) && value.length === 0) {
|
667
|
-
return true;
|
668
|
-
}
|
669
|
-
return value.length >= min;
|
670
|
-
}
|
671
|
-
);
|
672
|
-
}
|
673
|
-
}
|
674
|
-
if ("min" in schema && min) {
|
682
|
+
if (min) {
|
675
683
|
return schema.min(min, {
|
676
684
|
...translatedErrors.min,
|
677
685
|
values: {
|
@@ -789,19 +797,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
789
797
|
}, {});
|
790
798
|
return componentsByKey;
|
791
799
|
};
|
792
|
-
const
|
800
|
+
const HOOKS = {
|
801
|
+
/**
|
802
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
803
|
+
* @constant
|
804
|
+
* @type {string}
|
805
|
+
*/
|
806
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
807
|
+
/**
|
808
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
809
|
+
* @constant
|
810
|
+
* @type {string}
|
811
|
+
*/
|
812
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
813
|
+
/**
|
814
|
+
* Hook that allows to mutate the CM's edit view layout
|
815
|
+
* @constant
|
816
|
+
* @type {string}
|
817
|
+
*/
|
818
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
819
|
+
/**
|
820
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
821
|
+
* @constant
|
822
|
+
* @type {string}
|
823
|
+
*/
|
824
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
825
|
+
};
|
826
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
827
|
+
endpoints: (builder) => ({
|
828
|
+
getContentTypeConfiguration: builder.query({
|
829
|
+
query: (uid) => ({
|
830
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
831
|
+
method: "GET"
|
832
|
+
}),
|
833
|
+
transformResponse: (response) => response.data,
|
834
|
+
providesTags: (_result, _error, uid) => [
|
835
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
836
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
837
|
+
]
|
838
|
+
}),
|
839
|
+
getAllContentTypeSettings: builder.query({
|
840
|
+
query: () => "/content-manager/content-types-settings",
|
841
|
+
transformResponse: (response) => response.data,
|
842
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
843
|
+
}),
|
844
|
+
updateContentTypeConfiguration: builder.mutation({
|
845
|
+
query: ({ uid, ...body }) => ({
|
846
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
847
|
+
method: "PUT",
|
848
|
+
data: body
|
849
|
+
}),
|
850
|
+
transformResponse: (response) => response.data,
|
851
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
852
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
853
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
854
|
+
// Is this necessary?
|
855
|
+
{ type: "InitialData" }
|
856
|
+
]
|
857
|
+
})
|
858
|
+
})
|
859
|
+
});
|
860
|
+
const {
|
861
|
+
useGetContentTypeConfigurationQuery,
|
862
|
+
useGetAllContentTypeSettingsQuery,
|
863
|
+
useUpdateContentTypeConfigurationMutation
|
864
|
+
} = contentTypesApi;
|
865
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
866
|
+
const { type } = attribute;
|
867
|
+
if (type === "relation") {
|
868
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
869
|
+
}
|
870
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
871
|
+
};
|
872
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
873
|
+
if (!mainFieldName) {
|
874
|
+
return void 0;
|
875
|
+
}
|
876
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
877
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
878
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
879
|
+
);
|
880
|
+
return {
|
881
|
+
name: mainFieldName,
|
882
|
+
type: mainFieldType ?? "string"
|
883
|
+
};
|
884
|
+
};
|
885
|
+
const DEFAULT_SETTINGS = {
|
886
|
+
bulkable: false,
|
887
|
+
filterable: false,
|
888
|
+
searchable: false,
|
889
|
+
pagination: false,
|
890
|
+
defaultSortBy: "",
|
891
|
+
defaultSortOrder: "asc",
|
892
|
+
mainField: "id",
|
893
|
+
pageSize: 10
|
894
|
+
};
|
895
|
+
const useDocumentLayout = (model) => {
|
896
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
897
|
+
const [{ query }] = useQueryParams();
|
898
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
793
899
|
const { toggleNotification } = useNotification();
|
794
900
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
901
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
795
902
|
const {
|
796
|
-
|
797
|
-
isLoading:
|
798
|
-
|
799
|
-
|
800
|
-
} =
|
801
|
-
|
802
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
803
|
-
});
|
804
|
-
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
903
|
+
data,
|
904
|
+
isLoading: isLoadingConfigs,
|
905
|
+
error,
|
906
|
+
isFetching: isFetchingConfigs
|
907
|
+
} = useGetContentTypeConfigurationQuery(model);
|
908
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
805
909
|
React.useEffect(() => {
|
806
910
|
if (error) {
|
807
911
|
toggleNotification({
|
@@ -809,396 +913,439 @@ const useDocument = (args, opts) => {
|
|
809
913
|
message: formatAPIError(error)
|
810
914
|
});
|
811
915
|
}
|
812
|
-
}, [
|
813
|
-
const
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
(document) => {
|
821
|
-
if (!validationSchema) {
|
822
|
-
throw new Error(
|
823
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
824
|
-
);
|
825
|
-
}
|
826
|
-
try {
|
827
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
828
|
-
return null;
|
829
|
-
} catch (error2) {
|
830
|
-
if (error2 instanceof ValidationError) {
|
831
|
-
return getYupValidationErrors(error2);
|
832
|
-
}
|
833
|
-
throw error2;
|
834
|
-
}
|
916
|
+
}, [error, formatAPIError, toggleNotification]);
|
917
|
+
const editLayout = React.useMemo(
|
918
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
919
|
+
layout: [],
|
920
|
+
components: {},
|
921
|
+
metadatas: {},
|
922
|
+
options: {},
|
923
|
+
settings: DEFAULT_SETTINGS
|
835
924
|
},
|
836
|
-
[
|
925
|
+
[data, isLoading, schemas, schema, components]
|
926
|
+
);
|
927
|
+
const listLayout = React.useMemo(() => {
|
928
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
929
|
+
layout: [],
|
930
|
+
metadatas: {},
|
931
|
+
options: {},
|
932
|
+
settings: DEFAULT_SETTINGS
|
933
|
+
};
|
934
|
+
}, [data, isLoading, schemas, schema, components]);
|
935
|
+
const { layout: edit } = React.useMemo(
|
936
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
937
|
+
layout: editLayout,
|
938
|
+
query
|
939
|
+
}),
|
940
|
+
[editLayout, query, runHookWaterfall]
|
837
941
|
);
|
838
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
839
942
|
return {
|
840
|
-
|
841
|
-
document: data?.data,
|
842
|
-
meta: data?.meta,
|
943
|
+
error,
|
843
944
|
isLoading,
|
844
|
-
|
845
|
-
|
846
|
-
};
|
847
|
-
};
|
848
|
-
const useDoc = () => {
|
849
|
-
const { id, slug, collectionType, origin } = useParams();
|
850
|
-
const [{ query }] = useQueryParams();
|
851
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
852
|
-
if (!collectionType) {
|
853
|
-
throw new Error("Could not find collectionType in url params");
|
854
|
-
}
|
855
|
-
if (!slug) {
|
856
|
-
throw new Error("Could not find model in url params");
|
857
|
-
}
|
858
|
-
return {
|
859
|
-
collectionType,
|
860
|
-
model: slug,
|
861
|
-
id: origin || id === "create" ? void 0 : id,
|
862
|
-
...useDocument(
|
863
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
864
|
-
{
|
865
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
866
|
-
}
|
867
|
-
)
|
945
|
+
edit,
|
946
|
+
list: listLayout
|
868
947
|
};
|
869
948
|
};
|
870
|
-
const
|
871
|
-
|
872
|
-
|
873
|
-
}
|
874
|
-
return Object.keys(trad).reduce((acc, current) => {
|
875
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
876
|
-
return acc;
|
877
|
-
}, {});
|
878
|
-
};
|
879
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
880
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
881
|
-
id: "notification.error",
|
882
|
-
defaultMessage: "An error occurred, please try again"
|
949
|
+
const useDocLayout = () => {
|
950
|
+
const { model } = useDoc();
|
951
|
+
return useDocumentLayout(model);
|
883
952
|
};
|
884
|
-
const
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
const
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
type: "danger",
|
904
|
-
message: formatAPIError(res.error)
|
905
|
-
});
|
906
|
-
return { error: res.error };
|
907
|
-
}
|
908
|
-
toggleNotification({
|
909
|
-
type: "success",
|
910
|
-
message: formatMessage({
|
911
|
-
id: getTranslation("success.record.delete"),
|
912
|
-
defaultMessage: "Deleted document"
|
913
|
-
})
|
914
|
-
});
|
915
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
916
|
-
return res.data;
|
917
|
-
} catch (err) {
|
918
|
-
toggleNotification({
|
919
|
-
type: "danger",
|
920
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
921
|
-
});
|
922
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
923
|
-
throw err;
|
953
|
+
const formatEditLayout = (data, {
|
954
|
+
schemas,
|
955
|
+
schema,
|
956
|
+
components
|
957
|
+
}) => {
|
958
|
+
let currentPanelIndex = 0;
|
959
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
960
|
+
data.contentType.layouts.edit,
|
961
|
+
schema?.attributes,
|
962
|
+
data.contentType.metadatas,
|
963
|
+
{ configurations: data.components, schemas: components },
|
964
|
+
schemas
|
965
|
+
).reduce((panels, row) => {
|
966
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
967
|
+
panels.push([row]);
|
968
|
+
currentPanelIndex += 2;
|
969
|
+
} else {
|
970
|
+
if (!panels[currentPanelIndex]) {
|
971
|
+
panels.push([]);
|
924
972
|
}
|
925
|
-
|
926
|
-
|
927
|
-
|
928
|
-
|
929
|
-
const
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
});
|
943
|
-
return { error: res.error };
|
973
|
+
panels[currentPanelIndex].push(row);
|
974
|
+
}
|
975
|
+
return panels;
|
976
|
+
}, []);
|
977
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
978
|
+
(acc, [uid, configuration]) => {
|
979
|
+
acc[uid] = {
|
980
|
+
layout: convertEditLayoutToFieldLayouts(
|
981
|
+
configuration.layouts.edit,
|
982
|
+
components[uid].attributes,
|
983
|
+
configuration.metadatas,
|
984
|
+
{ configurations: data.components, schemas: components }
|
985
|
+
),
|
986
|
+
settings: {
|
987
|
+
...configuration.settings,
|
988
|
+
icon: components[uid].info.icon,
|
989
|
+
displayName: components[uid].info.displayName
|
944
990
|
}
|
945
|
-
|
946
|
-
|
947
|
-
title: formatMessage({
|
948
|
-
id: getTranslation("success.records.delete"),
|
949
|
-
defaultMessage: "Successfully deleted."
|
950
|
-
}),
|
951
|
-
message: ""
|
952
|
-
});
|
953
|
-
trackUsage("didBulkDeleteEntries");
|
954
|
-
return res.data;
|
955
|
-
} catch (err) {
|
956
|
-
toggleNotification({
|
957
|
-
type: "danger",
|
958
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
959
|
-
});
|
960
|
-
trackUsage("didNotBulkDeleteEntries");
|
961
|
-
throw err;
|
962
|
-
}
|
991
|
+
};
|
992
|
+
return acc;
|
963
993
|
},
|
964
|
-
|
994
|
+
{}
|
965
995
|
);
|
966
|
-
const
|
967
|
-
|
968
|
-
|
969
|
-
|
970
|
-
|
971
|
-
|
972
|
-
model,
|
973
|
-
documentId,
|
974
|
-
params
|
975
|
-
});
|
976
|
-
if ("error" in res) {
|
977
|
-
toggleNotification({
|
978
|
-
type: "danger",
|
979
|
-
message: formatAPIError(res.error)
|
980
|
-
});
|
981
|
-
return { error: res.error };
|
982
|
-
}
|
983
|
-
toggleNotification({
|
984
|
-
type: "success",
|
985
|
-
message: formatMessage({
|
986
|
-
id: "content-manager.success.record.discard",
|
987
|
-
defaultMessage: "Changes discarded"
|
988
|
-
})
|
989
|
-
});
|
990
|
-
return res.data;
|
991
|
-
} catch (err) {
|
992
|
-
toggleNotification({
|
993
|
-
type: "danger",
|
994
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
995
|
-
});
|
996
|
-
throw err;
|
997
|
-
}
|
996
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
997
|
+
(acc, [attribute, metadata]) => {
|
998
|
+
return {
|
999
|
+
...acc,
|
1000
|
+
[attribute]: metadata.edit
|
1001
|
+
};
|
998
1002
|
},
|
999
|
-
|
1003
|
+
{}
|
1000
1004
|
);
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
model,
|
1009
|
-
documentId,
|
1010
|
-
data,
|
1011
|
-
params
|
1012
|
-
});
|
1013
|
-
if ("error" in res) {
|
1014
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1015
|
-
return { error: res.error };
|
1016
|
-
}
|
1017
|
-
trackUsage("didPublishEntry");
|
1018
|
-
toggleNotification({
|
1019
|
-
type: "success",
|
1020
|
-
message: formatMessage({
|
1021
|
-
id: getTranslation("success.record.publish"),
|
1022
|
-
defaultMessage: "Published document"
|
1023
|
-
})
|
1024
|
-
});
|
1025
|
-
return res.data;
|
1026
|
-
} catch (err) {
|
1027
|
-
toggleNotification({
|
1028
|
-
type: "danger",
|
1029
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1030
|
-
});
|
1031
|
-
throw err;
|
1032
|
-
}
|
1005
|
+
return {
|
1006
|
+
layout: panelledEditAttributes,
|
1007
|
+
components: componentEditAttributes,
|
1008
|
+
metadatas: editMetadatas,
|
1009
|
+
settings: {
|
1010
|
+
...data.contentType.settings,
|
1011
|
+
displayName: schema?.info.displayName
|
1033
1012
|
},
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
return { error: res.error };
|
1048
|
-
}
|
1049
|
-
toggleNotification({
|
1050
|
-
type: "success",
|
1051
|
-
message: formatMessage({
|
1052
|
-
id: getTranslation("success.record.publish"),
|
1053
|
-
defaultMessage: "Published document"
|
1054
|
-
})
|
1055
|
-
});
|
1056
|
-
return res.data;
|
1057
|
-
} catch (err) {
|
1058
|
-
toggleNotification({
|
1059
|
-
type: "danger",
|
1060
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1061
|
-
});
|
1062
|
-
throw err;
|
1013
|
+
options: {
|
1014
|
+
...schema?.options,
|
1015
|
+
...schema?.pluginOptions,
|
1016
|
+
...data.contentType.options
|
1017
|
+
}
|
1018
|
+
};
|
1019
|
+
};
|
1020
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1021
|
+
return rows.map(
|
1022
|
+
(row) => row.map((field) => {
|
1023
|
+
const attribute = attributes[field.name];
|
1024
|
+
if (!attribute) {
|
1025
|
+
return null;
|
1063
1026
|
}
|
1064
|
-
|
1065
|
-
|
1066
|
-
|
1067
|
-
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1027
|
+
const { edit: metadata } = metadatas[field.name];
|
1028
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1029
|
+
return {
|
1030
|
+
attribute,
|
1031
|
+
disabled: !metadata.editable,
|
1032
|
+
hint: metadata.description,
|
1033
|
+
label: metadata.label ?? "",
|
1034
|
+
name: field.name,
|
1035
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1036
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1037
|
+
schemas,
|
1038
|
+
components: components?.schemas ?? {}
|
1039
|
+
}),
|
1040
|
+
placeholder: metadata.placeholder ?? "",
|
1041
|
+
required: attribute.required ?? false,
|
1042
|
+
size: field.size,
|
1043
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1044
|
+
visible: metadata.visible ?? true,
|
1045
|
+
type: attribute.type
|
1046
|
+
};
|
1047
|
+
}).filter((field) => field !== null)
|
1072
1048
|
);
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1083
|
-
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1049
|
+
};
|
1050
|
+
const formatListLayout = (data, {
|
1051
|
+
schemas,
|
1052
|
+
schema,
|
1053
|
+
components
|
1054
|
+
}) => {
|
1055
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1056
|
+
(acc, [attribute, metadata]) => {
|
1057
|
+
return {
|
1058
|
+
...acc,
|
1059
|
+
[attribute]: metadata.list
|
1060
|
+
};
|
1061
|
+
},
|
1062
|
+
{}
|
1063
|
+
);
|
1064
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1065
|
+
data.contentType.layouts.list,
|
1066
|
+
schema?.attributes,
|
1067
|
+
listMetadatas,
|
1068
|
+
{ configurations: data.components, schemas: components },
|
1069
|
+
schemas
|
1070
|
+
);
|
1071
|
+
return {
|
1072
|
+
layout: listAttributes,
|
1073
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1074
|
+
metadatas: listMetadatas,
|
1075
|
+
options: {
|
1076
|
+
...schema?.options,
|
1077
|
+
...schema?.pluginOptions,
|
1078
|
+
...data.contentType.options
|
1079
|
+
}
|
1080
|
+
};
|
1081
|
+
};
|
1082
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1083
|
+
return columns.map((name) => {
|
1084
|
+
const attribute = attributes[name];
|
1085
|
+
if (!attribute) {
|
1086
|
+
return null;
|
1087
|
+
}
|
1088
|
+
const metadata = metadatas[name];
|
1089
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1090
|
+
return {
|
1091
|
+
attribute,
|
1092
|
+
label: metadata.label ?? "",
|
1093
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1094
|
+
schemas,
|
1095
|
+
components: components?.schemas ?? {}
|
1096
|
+
}),
|
1097
|
+
name,
|
1098
|
+
searchable: metadata.searchable ?? true,
|
1099
|
+
sortable: metadata.sortable ?? true
|
1100
|
+
};
|
1101
|
+
}).filter((field) => field !== null);
|
1102
|
+
};
|
1103
|
+
const useDocument = (args, opts) => {
|
1104
|
+
const { toggleNotification } = useNotification();
|
1105
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1106
|
+
const {
|
1107
|
+
currentData: data,
|
1108
|
+
isLoading: isLoadingDocument,
|
1109
|
+
isFetching: isFetchingDocument,
|
1110
|
+
error
|
1111
|
+
} = useGetDocumentQuery(args, {
|
1112
|
+
...opts,
|
1113
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1114
|
+
});
|
1115
|
+
const {
|
1116
|
+
components,
|
1117
|
+
schema,
|
1118
|
+
schemas,
|
1119
|
+
isLoading: isLoadingSchema
|
1120
|
+
} = useContentTypeSchema(args.model);
|
1121
|
+
React.useEffect(() => {
|
1122
|
+
if (error) {
|
1123
|
+
toggleNotification({
|
1124
|
+
type: "danger",
|
1125
|
+
message: formatAPIError(error)
|
1126
|
+
});
|
1127
|
+
}
|
1128
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1129
|
+
const validationSchema = React.useMemo(() => {
|
1130
|
+
if (!schema) {
|
1131
|
+
return null;
|
1132
|
+
}
|
1133
|
+
return createYupSchema(schema.attributes, components);
|
1134
|
+
}, [schema, components]);
|
1135
|
+
const validate = React.useCallback(
|
1136
|
+
(document) => {
|
1137
|
+
if (!validationSchema) {
|
1138
|
+
throw new Error(
|
1139
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1140
|
+
);
|
1141
|
+
}
|
1142
|
+
try {
|
1143
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1144
|
+
return null;
|
1145
|
+
} catch (error2) {
|
1146
|
+
if (error2 instanceof ValidationError) {
|
1147
|
+
return getYupValidationErrors(error2);
|
1089
1148
|
}
|
1090
|
-
|
1091
|
-
toggleNotification({
|
1092
|
-
type: "success",
|
1093
|
-
message: formatMessage({
|
1094
|
-
id: getTranslation("success.record.save"),
|
1095
|
-
defaultMessage: "Saved document"
|
1096
|
-
})
|
1097
|
-
});
|
1098
|
-
return res.data;
|
1099
|
-
} catch (err) {
|
1100
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1101
|
-
toggleNotification({
|
1102
|
-
type: "danger",
|
1103
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1104
|
-
});
|
1105
|
-
throw err;
|
1149
|
+
throw error2;
|
1106
1150
|
}
|
1107
1151
|
},
|
1108
|
-
[
|
1152
|
+
[validationSchema]
|
1109
1153
|
);
|
1110
|
-
const
|
1111
|
-
const
|
1112
|
-
|
1154
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1155
|
+
const hasError = !!error;
|
1156
|
+
return {
|
1157
|
+
components,
|
1158
|
+
document: data?.data,
|
1159
|
+
meta: data?.meta,
|
1160
|
+
isLoading,
|
1161
|
+
hasError,
|
1162
|
+
schema,
|
1163
|
+
schemas,
|
1164
|
+
validate
|
1165
|
+
};
|
1166
|
+
};
|
1167
|
+
const useDoc = () => {
|
1168
|
+
const { id, slug, collectionType, origin } = useParams();
|
1169
|
+
const [{ query }] = useQueryParams();
|
1170
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1171
|
+
if (!collectionType) {
|
1172
|
+
throw new Error("Could not find collectionType in url params");
|
1173
|
+
}
|
1174
|
+
if (!slug) {
|
1175
|
+
throw new Error("Could not find model in url params");
|
1176
|
+
}
|
1177
|
+
const document = useDocument(
|
1178
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1179
|
+
{
|
1180
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1181
|
+
}
|
1182
|
+
);
|
1183
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
1184
|
+
return {
|
1185
|
+
collectionType,
|
1186
|
+
model: slug,
|
1187
|
+
id: returnId,
|
1188
|
+
...document
|
1189
|
+
};
|
1190
|
+
};
|
1191
|
+
const useContentManagerContext = () => {
|
1192
|
+
const {
|
1193
|
+
collectionType,
|
1194
|
+
model,
|
1195
|
+
id,
|
1196
|
+
components,
|
1197
|
+
isLoading: isLoadingDoc,
|
1198
|
+
schema,
|
1199
|
+
schemas
|
1200
|
+
} = useDoc();
|
1201
|
+
const layout = useDocumentLayout(model);
|
1202
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1203
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1204
|
+
const slug = model;
|
1205
|
+
const isCreatingEntry = id === "create";
|
1206
|
+
useContentTypeSchema();
|
1207
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1208
|
+
const error = layout.error;
|
1209
|
+
return {
|
1210
|
+
error,
|
1211
|
+
isLoading,
|
1212
|
+
// Base metadata
|
1213
|
+
model,
|
1214
|
+
collectionType,
|
1215
|
+
id,
|
1216
|
+
slug,
|
1217
|
+
isCreatingEntry,
|
1218
|
+
isSingleType,
|
1219
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1220
|
+
// All schema infos
|
1221
|
+
components,
|
1222
|
+
contentType: schema,
|
1223
|
+
contentTypes: schemas,
|
1224
|
+
// Form state
|
1225
|
+
form,
|
1226
|
+
// layout infos
|
1227
|
+
layout
|
1228
|
+
};
|
1229
|
+
};
|
1230
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
1231
|
+
if (!pluginId) {
|
1232
|
+
throw new TypeError("pluginId can't be empty");
|
1233
|
+
}
|
1234
|
+
return Object.keys(trad).reduce((acc, current) => {
|
1235
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1236
|
+
return acc;
|
1237
|
+
}, {});
|
1238
|
+
};
|
1239
|
+
const getTranslation = (id) => `content-manager.${id}`;
|
1240
|
+
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
1241
|
+
id: "notification.error",
|
1242
|
+
defaultMessage: "An error occurred, please try again"
|
1243
|
+
};
|
1244
|
+
const useDocumentActions = () => {
|
1245
|
+
const { toggleNotification } = useNotification();
|
1246
|
+
const { formatMessage } = useIntl();
|
1247
|
+
const { trackUsage } = useTracking();
|
1248
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1249
|
+
const navigate = useNavigate();
|
1250
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
1251
|
+
const [deleteDocument] = useDeleteDocumentMutation();
|
1252
|
+
const _delete = React.useCallback(
|
1253
|
+
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
1113
1254
|
try {
|
1114
|
-
trackUsage("
|
1115
|
-
const res = await
|
1255
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1256
|
+
const res = await deleteDocument({
|
1116
1257
|
collectionType,
|
1117
1258
|
model,
|
1118
1259
|
documentId,
|
1119
|
-
params
|
1120
|
-
data: {
|
1121
|
-
discardDraft
|
1122
|
-
}
|
1260
|
+
params
|
1123
1261
|
});
|
1124
1262
|
if ("error" in res) {
|
1125
|
-
toggleNotification({
|
1263
|
+
toggleNotification({
|
1264
|
+
type: "danger",
|
1265
|
+
message: formatAPIError(res.error)
|
1266
|
+
});
|
1126
1267
|
return { error: res.error };
|
1127
1268
|
}
|
1128
|
-
trackUsage("didUnpublishEntry");
|
1129
1269
|
toggleNotification({
|
1130
1270
|
type: "success",
|
1131
1271
|
message: formatMessage({
|
1132
|
-
id: getTranslation("success.record.
|
1133
|
-
defaultMessage: "
|
1272
|
+
id: getTranslation("success.record.delete"),
|
1273
|
+
defaultMessage: "Deleted document"
|
1134
1274
|
})
|
1135
1275
|
});
|
1276
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1136
1277
|
return res.data;
|
1137
1278
|
} catch (err) {
|
1138
1279
|
toggleNotification({
|
1139
1280
|
type: "danger",
|
1140
1281
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1141
1282
|
});
|
1283
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1142
1284
|
throw err;
|
1143
1285
|
}
|
1144
1286
|
},
|
1145
|
-
[trackUsage,
|
1287
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1146
1288
|
);
|
1147
|
-
const [
|
1148
|
-
const
|
1289
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1290
|
+
const deleteMany = React.useCallback(
|
1149
1291
|
async ({ model, documentIds, params }) => {
|
1150
1292
|
try {
|
1151
|
-
trackUsage("
|
1152
|
-
const res = await
|
1293
|
+
trackUsage("willBulkDeleteEntries");
|
1294
|
+
const res = await deleteManyDocuments({
|
1153
1295
|
model,
|
1154
1296
|
documentIds,
|
1155
1297
|
params
|
1156
1298
|
});
|
1157
1299
|
if ("error" in res) {
|
1158
|
-
toggleNotification({
|
1300
|
+
toggleNotification({
|
1301
|
+
type: "danger",
|
1302
|
+
message: formatAPIError(res.error)
|
1303
|
+
});
|
1159
1304
|
return { error: res.error };
|
1160
1305
|
}
|
1161
|
-
trackUsage("didBulkUnpublishEntries");
|
1162
1306
|
toggleNotification({
|
1163
1307
|
type: "success",
|
1164
1308
|
title: formatMessage({
|
1165
|
-
id: getTranslation("success.records.
|
1166
|
-
defaultMessage: "Successfully
|
1309
|
+
id: getTranslation("success.records.delete"),
|
1310
|
+
defaultMessage: "Successfully deleted."
|
1167
1311
|
}),
|
1168
1312
|
message: ""
|
1169
1313
|
});
|
1314
|
+
trackUsage("didBulkDeleteEntries");
|
1170
1315
|
return res.data;
|
1171
1316
|
} catch (err) {
|
1172
1317
|
toggleNotification({
|
1173
1318
|
type: "danger",
|
1174
1319
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1175
1320
|
});
|
1176
|
-
trackUsage("
|
1321
|
+
trackUsage("didNotBulkDeleteEntries");
|
1177
1322
|
throw err;
|
1178
1323
|
}
|
1179
1324
|
},
|
1180
|
-
[trackUsage,
|
1325
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1181
1326
|
);
|
1182
|
-
const [
|
1183
|
-
const
|
1184
|
-
async ({ model, params }
|
1327
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1328
|
+
const discard = React.useCallback(
|
1329
|
+
async ({ collectionType, model, documentId, params }) => {
|
1185
1330
|
try {
|
1186
|
-
const res = await
|
1331
|
+
const res = await discardDocument({
|
1332
|
+
collectionType,
|
1187
1333
|
model,
|
1188
|
-
|
1334
|
+
documentId,
|
1189
1335
|
params
|
1190
1336
|
});
|
1191
1337
|
if ("error" in res) {
|
1192
|
-
toggleNotification({
|
1193
|
-
|
1338
|
+
toggleNotification({
|
1339
|
+
type: "danger",
|
1340
|
+
message: formatAPIError(res.error)
|
1341
|
+
});
|
1194
1342
|
return { error: res.error };
|
1195
1343
|
}
|
1196
|
-
trackUsage("didCreateEntry", trackerProperty);
|
1197
1344
|
toggleNotification({
|
1198
1345
|
type: "success",
|
1199
1346
|
message: formatMessage({
|
1200
|
-
id:
|
1201
|
-
defaultMessage: "
|
1347
|
+
id: "content-manager.success.record.discard",
|
1348
|
+
defaultMessage: "Changes discarded"
|
1202
1349
|
})
|
1203
1350
|
});
|
1204
1351
|
return res.data;
|
@@ -1207,28 +1354,33 @@ const useDocumentActions = () => {
|
|
1207
1354
|
type: "danger",
|
1208
1355
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1209
1356
|
});
|
1210
|
-
trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
|
1211
1357
|
throw err;
|
1212
1358
|
}
|
1213
1359
|
},
|
1214
|
-
[
|
1360
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1215
1361
|
);
|
1216
|
-
const [
|
1217
|
-
const
|
1218
|
-
async ({ model,
|
1362
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1363
|
+
const publish = React.useCallback(
|
1364
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1219
1365
|
try {
|
1220
|
-
|
1366
|
+
trackUsage("willPublishEntry");
|
1367
|
+
const res = await publishDocument({
|
1368
|
+
collectionType,
|
1221
1369
|
model,
|
1222
|
-
|
1370
|
+
documentId,
|
1371
|
+
data,
|
1372
|
+
params
|
1223
1373
|
});
|
1224
1374
|
if ("error" in res) {
|
1375
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1225
1376
|
return { error: res.error };
|
1226
1377
|
}
|
1378
|
+
trackUsage("didPublishEntry");
|
1227
1379
|
toggleNotification({
|
1228
1380
|
type: "success",
|
1229
1381
|
message: formatMessage({
|
1230
|
-
id: getTranslation("success.record.
|
1231
|
-
defaultMessage: "
|
1382
|
+
id: getTranslation("success.record.publish"),
|
1383
|
+
defaultMessage: "Published document"
|
1232
1384
|
})
|
1233
1385
|
});
|
1234
1386
|
return res.data;
|
@@ -1240,1214 +1392,1101 @@ const useDocumentActions = () => {
|
|
1240
1392
|
throw err;
|
1241
1393
|
}
|
1242
1394
|
},
|
1243
|
-
[
|
1395
|
+
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1244
1396
|
);
|
1245
|
-
const [
|
1246
|
-
const
|
1247
|
-
async ({ model,
|
1397
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1398
|
+
const publishMany = React.useCallback(
|
1399
|
+
async ({ model, documentIds, params }) => {
|
1248
1400
|
try {
|
1249
|
-
const
|
1250
|
-
const res = await cloneDocument({
|
1401
|
+
const res = await publishManyDocuments({
|
1251
1402
|
model,
|
1252
|
-
|
1253
|
-
data: restBody,
|
1403
|
+
documentIds,
|
1254
1404
|
params
|
1255
1405
|
});
|
1256
1406
|
if ("error" in res) {
|
1257
1407
|
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1258
|
-
trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
|
1259
1408
|
return { error: res.error };
|
1260
1409
|
}
|
1261
|
-
trackUsage("didCreateEntry", trackerProperty);
|
1262
1410
|
toggleNotification({
|
1263
1411
|
type: "success",
|
1264
1412
|
message: formatMessage({
|
1265
|
-
id: getTranslation("success.record.
|
1266
|
-
defaultMessage: "
|
1413
|
+
id: getTranslation("success.record.publish"),
|
1414
|
+
defaultMessage: "Published document"
|
1267
1415
|
})
|
1268
1416
|
});
|
1269
|
-
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1270
1417
|
return res.data;
|
1271
1418
|
} catch (err) {
|
1272
1419
|
toggleNotification({
|
1273
1420
|
type: "danger",
|
1274
1421
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1275
1422
|
});
|
1276
|
-
trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
|
1277
1423
|
throw err;
|
1278
1424
|
}
|
1279
1425
|
},
|
1280
|
-
[
|
1281
|
-
|
1282
|
-
|
1283
|
-
|
1284
|
-
|
1285
|
-
|
1286
|
-
|
1287
|
-
},
|
1288
|
-
[getDoc]
|
1426
|
+
[
|
1427
|
+
// trackUsage,
|
1428
|
+
publishManyDocuments,
|
1429
|
+
toggleNotification,
|
1430
|
+
formatMessage,
|
1431
|
+
formatAPIError
|
1432
|
+
]
|
1289
1433
|
);
|
1290
|
-
|
1291
|
-
|
1292
|
-
|
1293
|
-
|
1294
|
-
|
1295
|
-
|
1296
|
-
|
1297
|
-
|
1298
|
-
|
1299
|
-
|
1300
|
-
|
1301
|
-
|
1302
|
-
|
1303
|
-
|
1304
|
-
};
|
1305
|
-
|
1306
|
-
() => import("./History-DrwsD1Vc.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1307
|
-
);
|
1308
|
-
const routes$1 = [
|
1309
|
-
{
|
1310
|
-
path: ":collectionType/:slug/:id/history",
|
1311
|
-
Component: ProtectedHistoryPage
|
1312
|
-
},
|
1313
|
-
{
|
1314
|
-
path: ":collectionType/:slug/history",
|
1315
|
-
Component: ProtectedHistoryPage
|
1316
|
-
}
|
1317
|
-
];
|
1318
|
-
const ProtectedEditViewPage = lazy(
|
1319
|
-
() => import("./EditViewPage-DiNFdFqP.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1320
|
-
);
|
1321
|
-
const ProtectedListViewPage = lazy(
|
1322
|
-
() => import("./ListViewPage-5a1vw-OK.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1323
|
-
);
|
1324
|
-
const ProtectedListConfiguration = lazy(
|
1325
|
-
() => import("./ListConfigurationPage-BxIP0jRy.mjs").then((mod) => ({
|
1326
|
-
default: mod.ProtectedListConfiguration
|
1327
|
-
}))
|
1328
|
-
);
|
1329
|
-
const ProtectedEditConfigurationPage = lazy(
|
1330
|
-
() => import("./EditConfigurationPage-Bk893vVY.mjs").then((mod) => ({
|
1331
|
-
default: mod.ProtectedEditConfigurationPage
|
1332
|
-
}))
|
1333
|
-
);
|
1334
|
-
const ProtectedComponentConfigurationPage = lazy(
|
1335
|
-
() => import("./ComponentConfigurationPage-9lRmRdIr.mjs").then((mod) => ({
|
1336
|
-
default: mod.ProtectedComponentConfigurationPage
|
1337
|
-
}))
|
1338
|
-
);
|
1339
|
-
const NoPermissions = lazy(
|
1340
|
-
() => import("./NoPermissionsPage-BHPqn_tQ.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1341
|
-
);
|
1342
|
-
const NoContentType = lazy(
|
1343
|
-
() => import("./NoContentTypePage-Bm6tRcd3.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1344
|
-
);
|
1345
|
-
const CollectionTypePages = () => {
|
1346
|
-
const { collectionType } = useParams();
|
1347
|
-
if (collectionType !== COLLECTION_TYPES && collectionType !== SINGLE_TYPES) {
|
1348
|
-
return /* @__PURE__ */ jsx(Navigate, { to: "/404" });
|
1349
|
-
}
|
1350
|
-
return collectionType === COLLECTION_TYPES ? /* @__PURE__ */ jsx(ProtectedListViewPage, {}) : /* @__PURE__ */ jsx(ProtectedEditViewPage, {});
|
1351
|
-
};
|
1352
|
-
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1353
|
-
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1354
|
-
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1355
|
-
const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
|
1356
|
-
const routes = [
|
1357
|
-
{
|
1358
|
-
path: LIST_RELATIVE_PATH,
|
1359
|
-
element: /* @__PURE__ */ jsx(CollectionTypePages, {})
|
1360
|
-
},
|
1361
|
-
{
|
1362
|
-
path: ":collectionType/:slug/:id",
|
1363
|
-
Component: ProtectedEditViewPage
|
1364
|
-
},
|
1365
|
-
{
|
1366
|
-
path: CLONE_RELATIVE_PATH,
|
1367
|
-
Component: ProtectedEditViewPage
|
1368
|
-
},
|
1369
|
-
{
|
1370
|
-
path: ":collectionType/:slug/configurations/list",
|
1371
|
-
Component: ProtectedListConfiguration
|
1372
|
-
},
|
1373
|
-
{
|
1374
|
-
path: "components/:slug/configurations/edit",
|
1375
|
-
Component: ProtectedComponentConfigurationPage
|
1376
|
-
},
|
1377
|
-
{
|
1378
|
-
path: ":collectionType/:slug/configurations/edit",
|
1379
|
-
Component: ProtectedEditConfigurationPage
|
1380
|
-
},
|
1381
|
-
{
|
1382
|
-
path: "403",
|
1383
|
-
Component: NoPermissions
|
1384
|
-
},
|
1385
|
-
{
|
1386
|
-
path: "no-content-types",
|
1387
|
-
Component: NoContentType
|
1388
|
-
},
|
1389
|
-
...routes$1
|
1390
|
-
];
|
1391
|
-
const DocumentActions = ({ actions: actions2 }) => {
|
1392
|
-
const { formatMessage } = useIntl();
|
1393
|
-
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1394
|
-
if (action.position === void 0) {
|
1395
|
-
return true;
|
1396
|
-
}
|
1397
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1398
|
-
return positions.includes("panel");
|
1399
|
-
});
|
1400
|
-
if (!primaryAction) {
|
1401
|
-
return null;
|
1402
|
-
}
|
1403
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1404
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1405
|
-
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1406
|
-
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1407
|
-
DocumentActionsMenu,
|
1408
|
-
{
|
1409
|
-
actions: restActions,
|
1410
|
-
label: formatMessage({
|
1411
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1412
|
-
defaultMessage: "More document actions"
|
1413
|
-
})
|
1434
|
+
const [updateDocument] = useUpdateDocumentMutation();
|
1435
|
+
const update = React.useCallback(
|
1436
|
+
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
1437
|
+
try {
|
1438
|
+
trackUsage("willEditEntry", trackerProperty);
|
1439
|
+
const res = await updateDocument({
|
1440
|
+
collectionType,
|
1441
|
+
model,
|
1442
|
+
documentId,
|
1443
|
+
data,
|
1444
|
+
params
|
1445
|
+
});
|
1446
|
+
if ("error" in res) {
|
1447
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1448
|
+
trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
|
1449
|
+
return { error: res.error };
|
1414
1450
|
}
|
1415
|
-
|
1416
|
-
|
1417
|
-
|
1418
|
-
|
1419
|
-
|
1420
|
-
|
1421
|
-
|
1422
|
-
|
1423
|
-
|
1424
|
-
|
1425
|
-
};
|
1426
|
-
|
1427
|
-
|
1428
|
-
|
1429
|
-
|
1430
|
-
|
1431
|
-
const muteDialog = await onClick(e);
|
1432
|
-
if (dialog && !muteDialog) {
|
1433
|
-
switch (dialog.type) {
|
1434
|
-
case "notification":
|
1435
|
-
toggleNotification({
|
1436
|
-
title: dialog.title,
|
1437
|
-
message: dialog.content,
|
1438
|
-
type: dialog.status,
|
1439
|
-
timeout: dialog.timeout,
|
1440
|
-
onClose: dialog.onClose
|
1441
|
-
});
|
1442
|
-
break;
|
1443
|
-
case "dialog":
|
1444
|
-
case "modal":
|
1445
|
-
e.preventDefault();
|
1446
|
-
setDialogId(id);
|
1451
|
+
trackUsage("didEditEntry", trackerProperty);
|
1452
|
+
toggleNotification({
|
1453
|
+
type: "success",
|
1454
|
+
message: formatMessage({
|
1455
|
+
id: getTranslation("success.record.save"),
|
1456
|
+
defaultMessage: "Saved document"
|
1457
|
+
})
|
1458
|
+
});
|
1459
|
+
return res.data;
|
1460
|
+
} catch (err) {
|
1461
|
+
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1462
|
+
toggleNotification({
|
1463
|
+
type: "danger",
|
1464
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1465
|
+
});
|
1466
|
+
throw err;
|
1447
1467
|
}
|
1448
|
-
}
|
1449
|
-
|
1450
|
-
|
1451
|
-
|
1452
|
-
|
1453
|
-
|
1454
|
-
|
1455
|
-
|
1456
|
-
|
1457
|
-
flex: "auto",
|
1458
|
-
startIcon: action.icon,
|
1459
|
-
disabled: action.disabled,
|
1460
|
-
onClick: handleClick(action),
|
1461
|
-
justifyContent: "center",
|
1462
|
-
variant: action.variant || "default",
|
1463
|
-
paddingTop: "7px",
|
1464
|
-
paddingBottom: "7px",
|
1465
|
-
children: action.label
|
1466
|
-
}
|
1467
|
-
),
|
1468
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1469
|
-
DocumentActionConfirmDialog,
|
1470
|
-
{
|
1471
|
-
...action.dialog,
|
1472
|
-
variant: action.dialog?.variant ?? action.variant,
|
1473
|
-
isOpen: dialogId === action.id,
|
1474
|
-
onClose: handleClose
|
1475
|
-
}
|
1476
|
-
) : null,
|
1477
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1478
|
-
DocumentActionModal,
|
1479
|
-
{
|
1480
|
-
...action.dialog,
|
1481
|
-
onModalClose: handleClose,
|
1482
|
-
isOpen: dialogId === action.id
|
1483
|
-
}
|
1484
|
-
) : null
|
1485
|
-
] });
|
1486
|
-
};
|
1487
|
-
const DocumentActionsMenu = ({
|
1488
|
-
actions: actions2,
|
1489
|
-
children,
|
1490
|
-
label,
|
1491
|
-
variant = "tertiary"
|
1492
|
-
}) => {
|
1493
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
1494
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1495
|
-
const { formatMessage } = useIntl();
|
1496
|
-
const { toggleNotification } = useNotification();
|
1497
|
-
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1498
|
-
const handleClick = (action) => async (e) => {
|
1499
|
-
const { onClick = () => false, dialog, id } = action;
|
1500
|
-
const muteDialog = await onClick(e);
|
1501
|
-
if (dialog && !muteDialog) {
|
1502
|
-
switch (dialog.type) {
|
1503
|
-
case "notification":
|
1504
|
-
toggleNotification({
|
1505
|
-
title: dialog.title,
|
1506
|
-
message: dialog.content,
|
1507
|
-
type: dialog.status,
|
1508
|
-
timeout: dialog.timeout,
|
1509
|
-
onClose: dialog.onClose
|
1510
|
-
});
|
1511
|
-
break;
|
1512
|
-
case "dialog":
|
1513
|
-
case "modal":
|
1514
|
-
setDialogId(id);
|
1515
|
-
}
|
1516
|
-
}
|
1517
|
-
};
|
1518
|
-
const handleClose = () => {
|
1519
|
-
setDialogId(null);
|
1520
|
-
setIsOpen(false);
|
1521
|
-
};
|
1522
|
-
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1523
|
-
/* @__PURE__ */ jsxs(
|
1524
|
-
Menu.Trigger,
|
1525
|
-
{
|
1526
|
-
disabled: isDisabled,
|
1527
|
-
size: "S",
|
1528
|
-
endIcon: null,
|
1529
|
-
paddingTop: "4px",
|
1530
|
-
paddingLeft: "7px",
|
1531
|
-
paddingRight: "7px",
|
1532
|
-
variant,
|
1533
|
-
children: [
|
1534
|
-
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1535
|
-
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1536
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1537
|
-
defaultMessage: "More document actions"
|
1538
|
-
}) })
|
1539
|
-
]
|
1540
|
-
}
|
1541
|
-
),
|
1542
|
-
/* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1543
|
-
actions2.map((action) => {
|
1544
|
-
return /* @__PURE__ */ jsx(
|
1545
|
-
Menu.Item,
|
1546
|
-
{
|
1547
|
-
disabled: action.disabled,
|
1548
|
-
onSelect: handleClick(action),
|
1549
|
-
display: "block",
|
1550
|
-
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1551
|
-
/* @__PURE__ */ jsxs(
|
1552
|
-
Flex,
|
1553
|
-
{
|
1554
|
-
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1555
|
-
gap: 2,
|
1556
|
-
tag: "span",
|
1557
|
-
children: [
|
1558
|
-
/* @__PURE__ */ jsx(
|
1559
|
-
Flex,
|
1560
|
-
{
|
1561
|
-
tag: "span",
|
1562
|
-
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1563
|
-
children: action.icon
|
1564
|
-
}
|
1565
|
-
),
|
1566
|
-
action.label
|
1567
|
-
]
|
1568
|
-
}
|
1569
|
-
),
|
1570
|
-
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1571
|
-
Flex,
|
1572
|
-
{
|
1573
|
-
alignItems: "center",
|
1574
|
-
background: "alternative100",
|
1575
|
-
borderStyle: "solid",
|
1576
|
-
borderColor: "alternative200",
|
1577
|
-
borderWidth: "1px",
|
1578
|
-
height: 5,
|
1579
|
-
paddingLeft: 2,
|
1580
|
-
paddingRight: 2,
|
1581
|
-
hasRadius: true,
|
1582
|
-
color: "alternative600",
|
1583
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1584
|
-
}
|
1585
|
-
)
|
1586
|
-
] })
|
1587
|
-
},
|
1588
|
-
action.id
|
1589
|
-
);
|
1590
|
-
}),
|
1591
|
-
children
|
1592
|
-
] }),
|
1593
|
-
actions2.map((action) => {
|
1594
|
-
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1595
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1596
|
-
DocumentActionConfirmDialog,
|
1597
|
-
{
|
1598
|
-
...action.dialog,
|
1599
|
-
variant: action.variant,
|
1600
|
-
isOpen: dialogId === action.id,
|
1601
|
-
onClose: handleClose
|
1602
|
-
}
|
1603
|
-
) : null,
|
1604
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1605
|
-
DocumentActionModal,
|
1606
|
-
{
|
1607
|
-
...action.dialog,
|
1608
|
-
onModalClose: handleClose,
|
1609
|
-
isOpen: dialogId === action.id
|
1610
|
-
}
|
1611
|
-
) : null
|
1612
|
-
] }, action.id);
|
1613
|
-
})
|
1614
|
-
] });
|
1615
|
-
};
|
1616
|
-
const convertActionVariantToColor = (variant = "secondary") => {
|
1617
|
-
switch (variant) {
|
1618
|
-
case "danger":
|
1619
|
-
return "danger600";
|
1620
|
-
case "secondary":
|
1621
|
-
return void 0;
|
1622
|
-
case "success":
|
1623
|
-
return "success600";
|
1624
|
-
default:
|
1625
|
-
return "primary600";
|
1626
|
-
}
|
1627
|
-
};
|
1628
|
-
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1629
|
-
switch (variant) {
|
1630
|
-
case "danger":
|
1631
|
-
return "danger600";
|
1632
|
-
case "secondary":
|
1633
|
-
return "neutral500";
|
1634
|
-
case "success":
|
1635
|
-
return "success600";
|
1636
|
-
default:
|
1637
|
-
return "primary600";
|
1638
|
-
}
|
1639
|
-
};
|
1640
|
-
const DocumentActionConfirmDialog = ({
|
1641
|
-
onClose,
|
1642
|
-
onCancel,
|
1643
|
-
onConfirm,
|
1644
|
-
title,
|
1645
|
-
content,
|
1646
|
-
isOpen,
|
1647
|
-
variant = "secondary"
|
1648
|
-
}) => {
|
1649
|
-
const { formatMessage } = useIntl();
|
1650
|
-
const handleClose = async () => {
|
1651
|
-
if (onCancel) {
|
1652
|
-
await onCancel();
|
1653
|
-
}
|
1654
|
-
onClose();
|
1655
|
-
};
|
1656
|
-
const handleConfirm = async () => {
|
1657
|
-
if (onConfirm) {
|
1658
|
-
await onConfirm();
|
1659
|
-
}
|
1660
|
-
onClose();
|
1661
|
-
};
|
1662
|
-
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
1663
|
-
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1664
|
-
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1665
|
-
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1666
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
1667
|
-
id: "app.components.Button.cancel",
|
1668
|
-
defaultMessage: "Cancel"
|
1669
|
-
}) }) }),
|
1670
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1671
|
-
id: "app.components.Button.confirm",
|
1672
|
-
defaultMessage: "Confirm"
|
1673
|
-
}) })
|
1674
|
-
] })
|
1675
|
-
] }) });
|
1676
|
-
};
|
1677
|
-
const DocumentActionModal = ({
|
1678
|
-
isOpen,
|
1679
|
-
title,
|
1680
|
-
onClose,
|
1681
|
-
footer: Footer,
|
1682
|
-
content: Content,
|
1683
|
-
onModalClose
|
1684
|
-
}) => {
|
1685
|
-
const handleClose = () => {
|
1686
|
-
if (onClose) {
|
1687
|
-
onClose();
|
1688
|
-
}
|
1689
|
-
onModalClose();
|
1690
|
-
};
|
1691
|
-
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1692
|
-
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1693
|
-
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
1694
|
-
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1695
|
-
] }) });
|
1696
|
-
};
|
1697
|
-
const PublishAction$1 = ({
|
1698
|
-
activeTab,
|
1699
|
-
documentId,
|
1700
|
-
model,
|
1701
|
-
collectionType,
|
1702
|
-
meta,
|
1703
|
-
document
|
1704
|
-
}) => {
|
1705
|
-
const { schema } = useDoc();
|
1706
|
-
const navigate = useNavigate();
|
1707
|
-
const { toggleNotification } = useNotification();
|
1708
|
-
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
1709
|
-
const isListView = useMatch(LIST_PATH) !== null;
|
1710
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
1711
|
-
const { formatMessage } = useIntl();
|
1712
|
-
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1713
|
-
const { publish } = useDocumentActions();
|
1714
|
-
const [
|
1715
|
-
countDraftRelations,
|
1716
|
-
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1717
|
-
] = useLazyGetDraftRelationCountQuery();
|
1718
|
-
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
1719
|
-
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1720
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1721
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1722
|
-
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
1723
|
-
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1724
|
-
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1725
|
-
const validate = useForm("PublishAction", (state) => state.validate);
|
1726
|
-
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1727
|
-
const formValues = useForm("PublishAction", ({ values }) => values);
|
1728
|
-
React.useEffect(() => {
|
1729
|
-
if (isErrorDraftRelations) {
|
1730
|
-
toggleNotification({
|
1731
|
-
type: "danger",
|
1732
|
-
message: formatMessage({
|
1733
|
-
id: getTranslation("error.records.fetch-draft-relatons"),
|
1734
|
-
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1735
|
-
})
|
1736
|
-
});
|
1737
|
-
}
|
1738
|
-
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1739
|
-
React.useEffect(() => {
|
1740
|
-
const localDraftRelations = /* @__PURE__ */ new Set();
|
1741
|
-
const extractDraftRelations = (data) => {
|
1742
|
-
const relations = data.connect || [];
|
1743
|
-
relations.forEach((relation) => {
|
1744
|
-
if (relation.status === "draft") {
|
1745
|
-
localDraftRelations.add(relation.id);
|
1746
|
-
}
|
1747
|
-
});
|
1748
|
-
};
|
1749
|
-
const traverseAndExtract = (data) => {
|
1750
|
-
Object.entries(data).forEach(([key, value]) => {
|
1751
|
-
if (key === "connect" && Array.isArray(value)) {
|
1752
|
-
extractDraftRelations({ connect: value });
|
1753
|
-
} else if (typeof value === "object" && value !== null) {
|
1754
|
-
traverseAndExtract(value);
|
1755
|
-
}
|
1756
|
-
});
|
1757
|
-
};
|
1758
|
-
if (!documentId || modified) {
|
1759
|
-
traverseAndExtract(formValues);
|
1760
|
-
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1761
|
-
}
|
1762
|
-
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1763
|
-
React.useEffect(() => {
|
1764
|
-
if (documentId && !isListView) {
|
1765
|
-
const fetchDraftRelationsCount = async () => {
|
1766
|
-
const { data, error } = await countDraftRelations({
|
1468
|
+
},
|
1469
|
+
[trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
|
1470
|
+
);
|
1471
|
+
const [unpublishDocument] = useUnpublishDocumentMutation();
|
1472
|
+
const unpublish = React.useCallback(
|
1473
|
+
async ({ collectionType, model, documentId, params }, discardDraft = false) => {
|
1474
|
+
try {
|
1475
|
+
trackUsage("willUnpublishEntry");
|
1476
|
+
const res = await unpublishDocument({
|
1767
1477
|
collectionType,
|
1768
1478
|
model,
|
1769
|
-
documentId,
|
1479
|
+
documentId,
|
1480
|
+
params,
|
1481
|
+
data: {
|
1482
|
+
discardDraft
|
1483
|
+
}
|
1484
|
+
});
|
1485
|
+
if ("error" in res) {
|
1486
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1487
|
+
return { error: res.error };
|
1488
|
+
}
|
1489
|
+
trackUsage("didUnpublishEntry");
|
1490
|
+
toggleNotification({
|
1491
|
+
type: "success",
|
1492
|
+
message: formatMessage({
|
1493
|
+
id: getTranslation("success.record.unpublish"),
|
1494
|
+
defaultMessage: "Unpublished document"
|
1495
|
+
})
|
1496
|
+
});
|
1497
|
+
return res.data;
|
1498
|
+
} catch (err) {
|
1499
|
+
toggleNotification({
|
1500
|
+
type: "danger",
|
1501
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1502
|
+
});
|
1503
|
+
throw err;
|
1504
|
+
}
|
1505
|
+
},
|
1506
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1507
|
+
);
|
1508
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1509
|
+
const unpublishMany = React.useCallback(
|
1510
|
+
async ({ model, documentIds, params }) => {
|
1511
|
+
try {
|
1512
|
+
trackUsage("willBulkUnpublishEntries");
|
1513
|
+
const res = await unpublishManyDocuments({
|
1514
|
+
model,
|
1515
|
+
documentIds,
|
1770
1516
|
params
|
1771
1517
|
});
|
1772
|
-
if (error) {
|
1773
|
-
|
1518
|
+
if ("error" in res) {
|
1519
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1520
|
+
return { error: res.error };
|
1774
1521
|
}
|
1775
|
-
|
1776
|
-
|
1522
|
+
trackUsage("didBulkUnpublishEntries");
|
1523
|
+
toggleNotification({
|
1524
|
+
type: "success",
|
1525
|
+
title: formatMessage({
|
1526
|
+
id: getTranslation("success.records.unpublish"),
|
1527
|
+
defaultMessage: "Successfully unpublished."
|
1528
|
+
}),
|
1529
|
+
message: ""
|
1530
|
+
});
|
1531
|
+
return res.data;
|
1532
|
+
} catch (err) {
|
1533
|
+
toggleNotification({
|
1534
|
+
type: "danger",
|
1535
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1536
|
+
});
|
1537
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1538
|
+
throw err;
|
1539
|
+
}
|
1540
|
+
},
|
1541
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1542
|
+
);
|
1543
|
+
const [createDocument] = useCreateDocumentMutation();
|
1544
|
+
const create = React.useCallback(
|
1545
|
+
async ({ model, params }, data, trackerProperty) => {
|
1546
|
+
try {
|
1547
|
+
const res = await createDocument({
|
1548
|
+
model,
|
1549
|
+
data,
|
1550
|
+
params
|
1551
|
+
});
|
1552
|
+
if ("error" in res) {
|
1553
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1554
|
+
trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
|
1555
|
+
return { error: res.error };
|
1777
1556
|
}
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
1787
|
-
|
1788
|
-
|
1789
|
-
const { errors } = await validate();
|
1790
|
-
if (errors) {
|
1557
|
+
trackUsage("didCreateEntry", trackerProperty);
|
1558
|
+
toggleNotification({
|
1559
|
+
type: "success",
|
1560
|
+
message: formatMessage({
|
1561
|
+
id: getTranslation("success.record.save"),
|
1562
|
+
defaultMessage: "Saved document"
|
1563
|
+
})
|
1564
|
+
});
|
1565
|
+
setCurrentStep("contentManager.success");
|
1566
|
+
return res.data;
|
1567
|
+
} catch (err) {
|
1791
1568
|
toggleNotification({
|
1792
1569
|
type: "danger",
|
1570
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1571
|
+
});
|
1572
|
+
trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
|
1573
|
+
throw err;
|
1574
|
+
}
|
1575
|
+
},
|
1576
|
+
[createDocument, formatAPIError, formatMessage, toggleNotification, trackUsage]
|
1577
|
+
);
|
1578
|
+
const [autoCloneDocument] = useAutoCloneDocumentMutation();
|
1579
|
+
const autoClone = React.useCallback(
|
1580
|
+
async ({ model, sourceId }) => {
|
1581
|
+
try {
|
1582
|
+
const res = await autoCloneDocument({
|
1583
|
+
model,
|
1584
|
+
sourceId
|
1585
|
+
});
|
1586
|
+
if ("error" in res) {
|
1587
|
+
return { error: res.error };
|
1588
|
+
}
|
1589
|
+
toggleNotification({
|
1590
|
+
type: "success",
|
1793
1591
|
message: formatMessage({
|
1794
|
-
id: "
|
1795
|
-
defaultMessage: "
|
1592
|
+
id: getTranslation("success.record.clone"),
|
1593
|
+
defaultMessage: "Cloned document"
|
1796
1594
|
})
|
1797
1595
|
});
|
1798
|
-
return;
|
1596
|
+
return res.data;
|
1597
|
+
} catch (err) {
|
1598
|
+
toggleNotification({
|
1599
|
+
type: "danger",
|
1600
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1601
|
+
});
|
1602
|
+
throw err;
|
1799
1603
|
}
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
1604
|
+
},
|
1605
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1606
|
+
);
|
1607
|
+
const [cloneDocument] = useCloneDocumentMutation();
|
1608
|
+
const clone = React.useCallback(
|
1609
|
+
async ({ model, documentId, params }, body, trackerProperty) => {
|
1610
|
+
try {
|
1611
|
+
const { id: _id, ...restBody } = body;
|
1612
|
+
const res = await cloneDocument({
|
1803
1613
|
model,
|
1804
|
-
documentId,
|
1614
|
+
sourceId: documentId,
|
1615
|
+
data: restBody,
|
1805
1616
|
params
|
1806
|
-
},
|
1807
|
-
formValues
|
1808
|
-
);
|
1809
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1810
|
-
navigate({
|
1811
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1812
|
-
search: rawQuery
|
1813
1617
|
});
|
1814
|
-
|
1815
|
-
|
1618
|
+
if ("error" in res) {
|
1619
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1620
|
+
trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
|
1621
|
+
return { error: res.error };
|
1622
|
+
}
|
1623
|
+
trackUsage("didCreateEntry", trackerProperty);
|
1624
|
+
toggleNotification({
|
1625
|
+
type: "success",
|
1626
|
+
message: formatMessage({
|
1627
|
+
id: getTranslation("success.record.clone"),
|
1628
|
+
defaultMessage: "Cloned document"
|
1629
|
+
})
|
1630
|
+
});
|
1631
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1632
|
+
return res.data;
|
1633
|
+
} catch (err) {
|
1634
|
+
toggleNotification({
|
1635
|
+
type: "danger",
|
1636
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1637
|
+
});
|
1638
|
+
trackUsage("didNotCreateEntry", { error: err, ...trackerProperty });
|
1639
|
+
throw err;
|
1816
1640
|
}
|
1817
|
-
}
|
1818
|
-
|
1641
|
+
},
|
1642
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1643
|
+
);
|
1644
|
+
const [getDoc] = useLazyGetDocumentQuery();
|
1645
|
+
const getDocument = React.useCallback(
|
1646
|
+
async (args) => {
|
1647
|
+
const { data } = await getDoc(args);
|
1648
|
+
return data;
|
1649
|
+
},
|
1650
|
+
[getDoc]
|
1651
|
+
);
|
1652
|
+
return {
|
1653
|
+
autoClone,
|
1654
|
+
clone,
|
1655
|
+
create,
|
1656
|
+
delete: _delete,
|
1657
|
+
deleteMany,
|
1658
|
+
discard,
|
1659
|
+
getDocument,
|
1660
|
+
publish,
|
1661
|
+
publishMany,
|
1662
|
+
unpublish,
|
1663
|
+
unpublishMany,
|
1664
|
+
update
|
1665
|
+
};
|
1666
|
+
};
|
1667
|
+
const ProtectedHistoryPage = lazy(
|
1668
|
+
() => import("./History-DRwA3oMM.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1669
|
+
);
|
1670
|
+
const routes$1 = [
|
1671
|
+
{
|
1672
|
+
path: ":collectionType/:slug/:id/history",
|
1673
|
+
Component: ProtectedHistoryPage
|
1674
|
+
},
|
1675
|
+
{
|
1676
|
+
path: ":collectionType/:slug/history",
|
1677
|
+
Component: ProtectedHistoryPage
|
1678
|
+
}
|
1679
|
+
];
|
1680
|
+
const ProtectedEditViewPage = lazy(
|
1681
|
+
() => import("./EditViewPage-B82x_x1b.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1682
|
+
);
|
1683
|
+
const ProtectedListViewPage = lazy(
|
1684
|
+
() => import("./ListViewPage-CELx2ysp.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1685
|
+
);
|
1686
|
+
const ProtectedListConfiguration = lazy(
|
1687
|
+
() => import("./ListConfigurationPage-BxfQJzPk.mjs").then((mod) => ({
|
1688
|
+
default: mod.ProtectedListConfiguration
|
1689
|
+
}))
|
1690
|
+
);
|
1691
|
+
const ProtectedEditConfigurationPage = lazy(
|
1692
|
+
() => import("./EditConfigurationPage-DdPNAbl3.mjs").then((mod) => ({
|
1693
|
+
default: mod.ProtectedEditConfigurationPage
|
1694
|
+
}))
|
1695
|
+
);
|
1696
|
+
const ProtectedComponentConfigurationPage = lazy(
|
1697
|
+
() => import("./ComponentConfigurationPage-DfFSZQxe.mjs").then((mod) => ({
|
1698
|
+
default: mod.ProtectedComponentConfigurationPage
|
1699
|
+
}))
|
1700
|
+
);
|
1701
|
+
const NoPermissions = lazy(
|
1702
|
+
() => import("./NoPermissionsPage-DWleVYK7.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1703
|
+
);
|
1704
|
+
const NoContentType = lazy(
|
1705
|
+
() => import("./NoContentTypePage-DtJ9jcfk.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1706
|
+
);
|
1707
|
+
const CollectionTypePages = () => {
|
1708
|
+
const { collectionType } = useParams();
|
1709
|
+
if (collectionType !== COLLECTION_TYPES && collectionType !== SINGLE_TYPES) {
|
1710
|
+
return /* @__PURE__ */ jsx(Navigate, { to: "/404" });
|
1711
|
+
}
|
1712
|
+
return collectionType === COLLECTION_TYPES ? /* @__PURE__ */ jsx(ProtectedListViewPage, {}) : /* @__PURE__ */ jsx(ProtectedEditViewPage, {});
|
1713
|
+
};
|
1714
|
+
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1715
|
+
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1716
|
+
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1717
|
+
const LIST_PATH = `/content-manager/${LIST_RELATIVE_PATH}`;
|
1718
|
+
const routes = [
|
1719
|
+
{
|
1720
|
+
path: LIST_RELATIVE_PATH,
|
1721
|
+
element: /* @__PURE__ */ jsx(CollectionTypePages, {})
|
1722
|
+
},
|
1723
|
+
{
|
1724
|
+
path: ":collectionType/:slug/:id",
|
1725
|
+
Component: ProtectedEditViewPage
|
1726
|
+
},
|
1727
|
+
{
|
1728
|
+
path: CLONE_RELATIVE_PATH,
|
1729
|
+
Component: ProtectedEditViewPage
|
1730
|
+
},
|
1731
|
+
{
|
1732
|
+
path: ":collectionType/:slug/configurations/list",
|
1733
|
+
Component: ProtectedListConfiguration
|
1734
|
+
},
|
1735
|
+
{
|
1736
|
+
path: "components/:slug/configurations/edit",
|
1737
|
+
Component: ProtectedComponentConfigurationPage
|
1738
|
+
},
|
1739
|
+
{
|
1740
|
+
path: ":collectionType/:slug/configurations/edit",
|
1741
|
+
Component: ProtectedEditConfigurationPage
|
1742
|
+
},
|
1743
|
+
{
|
1744
|
+
path: "403",
|
1745
|
+
Component: NoPermissions
|
1746
|
+
},
|
1747
|
+
{
|
1748
|
+
path: "no-content-types",
|
1749
|
+
Component: NoContentType
|
1750
|
+
},
|
1751
|
+
...routes$1
|
1752
|
+
];
|
1753
|
+
const DocumentActions = ({ actions: actions2 }) => {
|
1754
|
+
const { formatMessage } = useIntl();
|
1755
|
+
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1756
|
+
if (action.position === void 0) {
|
1757
|
+
return true;
|
1819
1758
|
}
|
1820
|
-
|
1821
|
-
|
1822
|
-
|
1823
|
-
|
1824
|
-
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
* - the document is being created & not modified
|
1832
|
-
* - the user doesn't have the permission to publish
|
1833
|
-
*/
|
1834
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1835
|
-
label: formatMessage({
|
1836
|
-
id: "app.utils.publish",
|
1837
|
-
defaultMessage: "Publish"
|
1838
|
-
}),
|
1839
|
-
onClick: async () => {
|
1840
|
-
await performPublish();
|
1841
|
-
},
|
1842
|
-
dialog: hasDraftRelations ? {
|
1843
|
-
type: "dialog",
|
1844
|
-
variant: "danger",
|
1845
|
-
footer: null,
|
1846
|
-
title: formatMessage({
|
1847
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1848
|
-
defaultMessage: "Confirmation"
|
1849
|
-
}),
|
1850
|
-
content: formatMessage(
|
1851
|
-
{
|
1852
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1853
|
-
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1854
|
-
},
|
1759
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1760
|
+
return positions.includes("panel");
|
1761
|
+
});
|
1762
|
+
if (!primaryAction) {
|
1763
|
+
return null;
|
1764
|
+
}
|
1765
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1766
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1767
|
+
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1768
|
+
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1769
|
+
DocumentActionsMenu,
|
1855
1770
|
{
|
1856
|
-
|
1771
|
+
actions: restActions,
|
1772
|
+
label: formatMessage({
|
1773
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1774
|
+
defaultMessage: "More document actions"
|
1775
|
+
})
|
1857
1776
|
}
|
1858
|
-
)
|
1859
|
-
|
1860
|
-
|
1777
|
+
) : null
|
1778
|
+
] }),
|
1779
|
+
secondaryAction ? /* @__PURE__ */ jsx(
|
1780
|
+
DocumentActionButton,
|
1781
|
+
{
|
1782
|
+
...secondaryAction,
|
1783
|
+
variant: secondaryAction.variant || "secondary"
|
1861
1784
|
}
|
1862
|
-
|
1863
|
-
};
|
1785
|
+
) : null
|
1786
|
+
] });
|
1864
1787
|
};
|
1865
|
-
|
1866
|
-
const
|
1867
|
-
activeTab,
|
1868
|
-
documentId,
|
1869
|
-
model,
|
1870
|
-
collectionType
|
1871
|
-
}) => {
|
1872
|
-
const navigate = useNavigate();
|
1788
|
+
const DocumentActionButton = (action) => {
|
1789
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1873
1790
|
const { toggleNotification } = useNotification();
|
1874
|
-
const
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1893
|
-
* - the active tab is the published tab
|
1894
|
-
*/
|
1895
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1896
|
-
label: formatMessage({
|
1897
|
-
id: "content-manager.containers.Edit.save",
|
1898
|
-
defaultMessage: "Save"
|
1899
|
-
}),
|
1900
|
-
onClick: async () => {
|
1901
|
-
setSubmitting(true);
|
1902
|
-
try {
|
1903
|
-
if (activeTab !== "draft") {
|
1904
|
-
const { errors } = await validate();
|
1905
|
-
if (errors) {
|
1906
|
-
toggleNotification({
|
1907
|
-
type: "danger",
|
1908
|
-
message: formatMessage({
|
1909
|
-
id: "content-manager.validation.error",
|
1910
|
-
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1911
|
-
})
|
1912
|
-
});
|
1913
|
-
return;
|
1914
|
-
}
|
1915
|
-
}
|
1916
|
-
if (isCloning) {
|
1917
|
-
const res = await clone(
|
1918
|
-
{
|
1919
|
-
model,
|
1920
|
-
documentId: cloneMatch.params.origin,
|
1921
|
-
params
|
1922
|
-
},
|
1923
|
-
document
|
1924
|
-
);
|
1925
|
-
if ("data" in res) {
|
1926
|
-
navigate(
|
1927
|
-
{
|
1928
|
-
pathname: `../${res.data.documentId}`,
|
1929
|
-
search: rawQuery
|
1930
|
-
},
|
1931
|
-
{ relative: "path" }
|
1932
|
-
);
|
1933
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1934
|
-
setErrors(formatValidationErrors(res.error));
|
1935
|
-
}
|
1936
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1937
|
-
const res = await update(
|
1938
|
-
{
|
1939
|
-
collectionType,
|
1940
|
-
model,
|
1941
|
-
documentId,
|
1942
|
-
params
|
1943
|
-
},
|
1944
|
-
document
|
1945
|
-
);
|
1946
|
-
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1947
|
-
setErrors(formatValidationErrors(res.error));
|
1948
|
-
} else {
|
1949
|
-
resetForm();
|
1950
|
-
}
|
1951
|
-
} else {
|
1952
|
-
const res = await create(
|
1953
|
-
{
|
1954
|
-
model,
|
1955
|
-
params
|
1956
|
-
},
|
1957
|
-
document
|
1958
|
-
);
|
1959
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1960
|
-
navigate(
|
1961
|
-
{
|
1962
|
-
pathname: `../${res.data.documentId}`,
|
1963
|
-
search: rawQuery
|
1964
|
-
},
|
1965
|
-
{ replace: true, relative: "path" }
|
1966
|
-
);
|
1967
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1968
|
-
setErrors(formatValidationErrors(res.error));
|
1969
|
-
}
|
1970
|
-
}
|
1971
|
-
} finally {
|
1972
|
-
setSubmitting(false);
|
1791
|
+
const handleClick = (action2) => async (e) => {
|
1792
|
+
const { onClick = () => false, dialog, id } = action2;
|
1793
|
+
const muteDialog = await onClick(e);
|
1794
|
+
if (dialog && !muteDialog) {
|
1795
|
+
switch (dialog.type) {
|
1796
|
+
case "notification":
|
1797
|
+
toggleNotification({
|
1798
|
+
title: dialog.title,
|
1799
|
+
message: dialog.content,
|
1800
|
+
type: dialog.status,
|
1801
|
+
timeout: dialog.timeout,
|
1802
|
+
onClose: dialog.onClose
|
1803
|
+
});
|
1804
|
+
break;
|
1805
|
+
case "dialog":
|
1806
|
+
case "modal":
|
1807
|
+
e.preventDefault();
|
1808
|
+
setDialogId(id);
|
1973
1809
|
}
|
1974
1810
|
}
|
1975
1811
|
};
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1812
|
+
const handleClose = () => {
|
1813
|
+
setDialogId(null);
|
1814
|
+
};
|
1815
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1816
|
+
/* @__PURE__ */ jsx(
|
1817
|
+
Button,
|
1818
|
+
{
|
1819
|
+
flex: "auto",
|
1820
|
+
startIcon: action.icon,
|
1821
|
+
disabled: action.disabled,
|
1822
|
+
onClick: handleClick(action),
|
1823
|
+
justifyContent: "center",
|
1824
|
+
variant: action.variant || "default",
|
1825
|
+
paddingTop: "7px",
|
1826
|
+
paddingBottom: "7px",
|
1827
|
+
children: action.label
|
1828
|
+
}
|
1829
|
+
),
|
1830
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1831
|
+
DocumentActionConfirmDialog,
|
1832
|
+
{
|
1833
|
+
...action.dialog,
|
1834
|
+
variant: action.dialog?.variant ?? action.variant,
|
1835
|
+
isOpen: dialogId === action.id,
|
1836
|
+
onClose: handleClose
|
1837
|
+
}
|
1838
|
+
) : null,
|
1839
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1840
|
+
DocumentActionModal,
|
1841
|
+
{
|
1842
|
+
...action.dialog,
|
1843
|
+
onModalClose: handleClose,
|
1844
|
+
isOpen: dialogId === action.id
|
1845
|
+
}
|
1846
|
+
) : null
|
1847
|
+
] });
|
1848
|
+
};
|
1849
|
+
const DocumentActionsMenu = ({
|
1850
|
+
actions: actions2,
|
1851
|
+
children,
|
1852
|
+
label,
|
1853
|
+
variant = "tertiary"
|
1988
1854
|
}) => {
|
1855
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
1856
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1989
1857
|
const { formatMessage } = useIntl();
|
1990
|
-
const { schema } = useDoc();
|
1991
|
-
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1992
|
-
const { unpublish } = useDocumentActions();
|
1993
|
-
const [{ query }] = useQueryParams();
|
1994
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1995
1858
|
const { toggleNotification } = useNotification();
|
1996
|
-
const
|
1997
|
-
const
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
}
|
2004
|
-
return {
|
2005
|
-
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2006
|
-
label: formatMessage({
|
2007
|
-
id: "app.utils.unpublish",
|
2008
|
-
defaultMessage: "Unpublish"
|
2009
|
-
}),
|
2010
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
2011
|
-
onClick: async () => {
|
2012
|
-
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2013
|
-
if (!documentId) {
|
2014
|
-
console.error(
|
2015
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2016
|
-
);
|
1859
|
+
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1860
|
+
const handleClick = (action) => async (e) => {
|
1861
|
+
const { onClick = () => false, dialog, id } = action;
|
1862
|
+
const muteDialog = await onClick(e);
|
1863
|
+
if (dialog && !muteDialog) {
|
1864
|
+
switch (dialog.type) {
|
1865
|
+
case "notification":
|
2017
1866
|
toggleNotification({
|
2018
|
-
|
2019
|
-
|
2020
|
-
|
2021
|
-
|
2022
|
-
|
1867
|
+
title: dialog.title,
|
1868
|
+
message: dialog.content,
|
1869
|
+
type: dialog.status,
|
1870
|
+
timeout: dialog.timeout,
|
1871
|
+
onClose: dialog.onClose
|
2023
1872
|
});
|
2024
|
-
|
2025
|
-
|
1873
|
+
break;
|
1874
|
+
case "dialog":
|
1875
|
+
case "modal":
|
1876
|
+
setDialogId(id);
|
2026
1877
|
}
|
2027
|
-
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
2039
|
-
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
1878
|
+
}
|
1879
|
+
};
|
1880
|
+
const handleClose = () => {
|
1881
|
+
setDialogId(null);
|
1882
|
+
setIsOpen(false);
|
1883
|
+
};
|
1884
|
+
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1885
|
+
/* @__PURE__ */ jsxs(
|
1886
|
+
Menu.Trigger,
|
1887
|
+
{
|
1888
|
+
disabled: isDisabled,
|
1889
|
+
size: "S",
|
1890
|
+
endIcon: null,
|
1891
|
+
paddingTop: "4px",
|
1892
|
+
paddingLeft: "7px",
|
1893
|
+
paddingRight: "7px",
|
1894
|
+
variant,
|
1895
|
+
children: [
|
1896
|
+
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1897
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1898
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1899
|
+
defaultMessage: "More document actions"
|
2046
1900
|
}) })
|
2047
|
-
]
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2055
|
-
defaultMessage: "Choose an option to unpublish the document."
|
2056
|
-
}),
|
2057
|
-
onValueChange: handleChange,
|
2058
|
-
children: [
|
2059
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2060
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2061
|
-
defaultMessage: "Keep draft"
|
2062
|
-
}) }),
|
2063
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2064
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2065
|
-
defaultMessage: "Replace draft"
|
2066
|
-
}) })
|
2067
|
-
]
|
2068
|
-
}
|
2069
|
-
)
|
2070
|
-
] }),
|
2071
|
-
onConfirm: async () => {
|
2072
|
-
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2073
|
-
console.error(
|
2074
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2075
|
-
);
|
2076
|
-
toggleNotification({
|
2077
|
-
message: formatMessage({
|
2078
|
-
id: "content-manager.actions.unpublish.error",
|
2079
|
-
defaultMessage: "An error occurred while trying to unpublish the document."
|
2080
|
-
}),
|
2081
|
-
type: "danger"
|
2082
|
-
});
|
2083
|
-
}
|
2084
|
-
await unpublish(
|
1901
|
+
]
|
1902
|
+
}
|
1903
|
+
),
|
1904
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1905
|
+
actions2.map((action) => {
|
1906
|
+
return /* @__PURE__ */ jsx(
|
1907
|
+
Menu.Item,
|
2085
1908
|
{
|
2086
|
-
|
2087
|
-
|
2088
|
-
|
2089
|
-
|
1909
|
+
disabled: action.disabled,
|
1910
|
+
onSelect: handleClick(action),
|
1911
|
+
display: "block",
|
1912
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1913
|
+
/* @__PURE__ */ jsxs(
|
1914
|
+
Flex,
|
1915
|
+
{
|
1916
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1917
|
+
gap: 2,
|
1918
|
+
tag: "span",
|
1919
|
+
children: [
|
1920
|
+
/* @__PURE__ */ jsx(
|
1921
|
+
Flex,
|
1922
|
+
{
|
1923
|
+
tag: "span",
|
1924
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1925
|
+
children: action.icon
|
1926
|
+
}
|
1927
|
+
),
|
1928
|
+
action.label
|
1929
|
+
]
|
1930
|
+
}
|
1931
|
+
),
|
1932
|
+
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1933
|
+
Flex,
|
1934
|
+
{
|
1935
|
+
alignItems: "center",
|
1936
|
+
background: "alternative100",
|
1937
|
+
borderStyle: "solid",
|
1938
|
+
borderColor: "alternative200",
|
1939
|
+
borderWidth: "1px",
|
1940
|
+
height: 5,
|
1941
|
+
paddingLeft: 2,
|
1942
|
+
paddingRight: 2,
|
1943
|
+
hasRadius: true,
|
1944
|
+
color: "alternative600",
|
1945
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1946
|
+
}
|
1947
|
+
)
|
1948
|
+
] })
|
2090
1949
|
},
|
2091
|
-
|
1950
|
+
action.id
|
2092
1951
|
);
|
2093
|
-
}
|
2094
|
-
|
2095
|
-
|
2096
|
-
|
1952
|
+
}),
|
1953
|
+
children
|
1954
|
+
] }),
|
1955
|
+
actions2.map((action) => {
|
1956
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1957
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1958
|
+
DocumentActionConfirmDialog,
|
1959
|
+
{
|
1960
|
+
...action.dialog,
|
1961
|
+
variant: action.variant,
|
1962
|
+
isOpen: dialogId === action.id,
|
1963
|
+
onClose: handleClose
|
1964
|
+
}
|
1965
|
+
) : null,
|
1966
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1967
|
+
DocumentActionModal,
|
1968
|
+
{
|
1969
|
+
...action.dialog,
|
1970
|
+
onModalClose: handleClose,
|
1971
|
+
isOpen: dialogId === action.id
|
1972
|
+
}
|
1973
|
+
) : null
|
1974
|
+
] }, action.id);
|
1975
|
+
})
|
1976
|
+
] });
|
1977
|
+
};
|
1978
|
+
const convertActionVariantToColor = (variant = "secondary") => {
|
1979
|
+
switch (variant) {
|
1980
|
+
case "danger":
|
1981
|
+
return "danger600";
|
1982
|
+
case "secondary":
|
1983
|
+
return void 0;
|
1984
|
+
case "success":
|
1985
|
+
return "success600";
|
1986
|
+
default:
|
1987
|
+
return "primary600";
|
1988
|
+
}
|
1989
|
+
};
|
1990
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1991
|
+
switch (variant) {
|
1992
|
+
case "danger":
|
1993
|
+
return "danger600";
|
1994
|
+
case "secondary":
|
1995
|
+
return "neutral500";
|
1996
|
+
case "success":
|
1997
|
+
return "success600";
|
1998
|
+
default:
|
1999
|
+
return "primary600";
|
2000
|
+
}
|
2001
|
+
};
|
2002
|
+
const DocumentActionConfirmDialog = ({
|
2003
|
+
onClose,
|
2004
|
+
onCancel,
|
2005
|
+
onConfirm,
|
2006
|
+
title,
|
2007
|
+
content,
|
2008
|
+
isOpen,
|
2009
|
+
variant = "secondary"
|
2010
|
+
}) => {
|
2011
|
+
const { formatMessage } = useIntl();
|
2012
|
+
const handleClose = async () => {
|
2013
|
+
if (onCancel) {
|
2014
|
+
await onCancel();
|
2015
|
+
}
|
2016
|
+
onClose();
|
2097
2017
|
};
|
2018
|
+
const handleConfirm = async () => {
|
2019
|
+
if (onConfirm) {
|
2020
|
+
await onConfirm();
|
2021
|
+
}
|
2022
|
+
onClose();
|
2023
|
+
};
|
2024
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2025
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2026
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2027
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2028
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2029
|
+
id: "app.components.Button.cancel",
|
2030
|
+
defaultMessage: "Cancel"
|
2031
|
+
}) }) }),
|
2032
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2033
|
+
id: "app.components.Button.confirm",
|
2034
|
+
defaultMessage: "Confirm"
|
2035
|
+
}) })
|
2036
|
+
] })
|
2037
|
+
] }) });
|
2098
2038
|
};
|
2099
|
-
|
2100
|
-
|
2039
|
+
const DocumentActionModal = ({
|
2040
|
+
isOpen,
|
2041
|
+
title,
|
2042
|
+
onClose,
|
2043
|
+
footer: Footer,
|
2044
|
+
content: Content,
|
2045
|
+
onModalClose
|
2046
|
+
}) => {
|
2047
|
+
const handleClose = () => {
|
2048
|
+
if (onClose) {
|
2049
|
+
onClose();
|
2050
|
+
}
|
2051
|
+
onModalClose();
|
2052
|
+
};
|
2053
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2054
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2055
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2056
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2057
|
+
] }) });
|
2058
|
+
};
|
2059
|
+
const PublishAction$1 = ({
|
2101
2060
|
activeTab,
|
2102
2061
|
documentId,
|
2103
2062
|
model,
|
2104
2063
|
collectionType,
|
2064
|
+
meta,
|
2105
2065
|
document
|
2106
2066
|
}) => {
|
2107
|
-
const { formatMessage } = useIntl();
|
2108
2067
|
const { schema } = useDoc();
|
2109
|
-
const
|
2110
|
-
const {
|
2111
|
-
const
|
2112
|
-
const
|
2113
|
-
if (!schema?.options?.draftAndPublish) {
|
2114
|
-
return null;
|
2115
|
-
}
|
2116
|
-
return {
|
2117
|
-
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2118
|
-
label: formatMessage({
|
2119
|
-
id: "content-manager.actions.discard.label",
|
2120
|
-
defaultMessage: "Discard changes"
|
2121
|
-
}),
|
2122
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
2123
|
-
position: ["panel", "table-row"],
|
2124
|
-
variant: "danger",
|
2125
|
-
dialog: {
|
2126
|
-
type: "dialog",
|
2127
|
-
title: formatMessage({
|
2128
|
-
id: "app.components.ConfirmDialog.title",
|
2129
|
-
defaultMessage: "Confirmation"
|
2130
|
-
}),
|
2131
|
-
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2132
|
-
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2133
|
-
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2134
|
-
id: "content-manager.actions.discard.dialog.body",
|
2135
|
-
defaultMessage: "Are you sure?"
|
2136
|
-
}) })
|
2137
|
-
] }),
|
2138
|
-
onConfirm: async () => {
|
2139
|
-
await discard({
|
2140
|
-
collectionType,
|
2141
|
-
model,
|
2142
|
-
documentId,
|
2143
|
-
params
|
2144
|
-
});
|
2145
|
-
}
|
2146
|
-
}
|
2147
|
-
};
|
2148
|
-
};
|
2149
|
-
DiscardAction.type = "discard";
|
2150
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2151
|
-
path {
|
2152
|
-
fill: currentColor;
|
2153
|
-
}
|
2154
|
-
`;
|
2155
|
-
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2156
|
-
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2157
|
-
const RelativeTime = React.forwardRef(
|
2158
|
-
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2159
|
-
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2160
|
-
const interval = intervalToDuration({
|
2161
|
-
start: timestamp,
|
2162
|
-
end: Date.now()
|
2163
|
-
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2164
|
-
});
|
2165
|
-
const unit = intervals.find((intervalUnit) => {
|
2166
|
-
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2167
|
-
});
|
2168
|
-
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2169
|
-
const customInterval = customIntervals.find(
|
2170
|
-
(custom) => interval[custom.unit] < custom.threshold
|
2171
|
-
);
|
2172
|
-
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2173
|
-
return /* @__PURE__ */ jsx(
|
2174
|
-
"time",
|
2175
|
-
{
|
2176
|
-
ref: forwardedRef,
|
2177
|
-
dateTime: timestamp.toISOString(),
|
2178
|
-
role: "time",
|
2179
|
-
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2180
|
-
...restProps,
|
2181
|
-
children: displayText
|
2182
|
-
}
|
2183
|
-
);
|
2184
|
-
}
|
2185
|
-
);
|
2186
|
-
const getDisplayName = ({
|
2187
|
-
firstname,
|
2188
|
-
lastname,
|
2189
|
-
username,
|
2190
|
-
email
|
2191
|
-
} = {}) => {
|
2192
|
-
if (username) {
|
2193
|
-
return username;
|
2194
|
-
}
|
2195
|
-
if (firstname) {
|
2196
|
-
return `${firstname} ${lastname ?? ""}`.trim();
|
2197
|
-
}
|
2198
|
-
return email ?? "";
|
2199
|
-
};
|
2200
|
-
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2201
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2202
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
2203
|
-
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2204
|
-
};
|
2205
|
-
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2206
|
-
const { formatMessage } = useIntl();
|
2068
|
+
const navigate = useNavigate();
|
2069
|
+
const { toggleNotification } = useNotification();
|
2070
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2071
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
2207
2072
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2208
|
-
const title = isCreating ? formatMessage({
|
2209
|
-
id: "content-manager.containers.edit.title.new",
|
2210
|
-
defaultMessage: "Create an entry"
|
2211
|
-
}) : documentTitle;
|
2212
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2213
|
-
/* @__PURE__ */ jsx(BackButton, {}),
|
2214
|
-
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2215
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2216
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2217
|
-
] }),
|
2218
|
-
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2219
|
-
] });
|
2220
|
-
};
|
2221
|
-
const HeaderToolbar = () => {
|
2222
2073
|
const { formatMessage } = useIntl();
|
2223
|
-
const
|
2074
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2075
|
+
const { publish } = useDocumentActions();
|
2224
2076
|
const [
|
2225
|
-
|
2226
|
-
|
2077
|
+
countDraftRelations,
|
2078
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2079
|
+
] = useLazyGetDraftRelationCountQuery();
|
2080
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2081
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
2082
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2083
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2084
|
+
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
2085
|
+
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2086
|
+
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2087
|
+
const validate = useForm("PublishAction", (state) => state.validate);
|
2088
|
+
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
2089
|
+
const formValues = useForm("PublishAction", ({ values }) => values);
|
2090
|
+
React.useEffect(() => {
|
2091
|
+
if (isErrorDraftRelations) {
|
2092
|
+
toggleNotification({
|
2093
|
+
type: "danger",
|
2094
|
+
message: formatMessage({
|
2095
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2096
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2097
|
+
})
|
2098
|
+
});
|
2227
2099
|
}
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2232
|
-
|
2233
|
-
|
2234
|
-
|
2235
|
-
|
2236
|
-
activeTab: status,
|
2237
|
-
model,
|
2238
|
-
documentId: id,
|
2239
|
-
document: isCloning ? void 0 : document,
|
2240
|
-
meta: isCloning ? void 0 : meta,
|
2241
|
-
collectionType
|
2242
|
-
},
|
2243
|
-
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2244
|
-
children: (actions2) => {
|
2245
|
-
if (actions2.length > 0) {
|
2246
|
-
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2247
|
-
} else {
|
2248
|
-
return null;
|
2249
|
-
}
|
2100
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2101
|
+
React.useEffect(() => {
|
2102
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2103
|
+
const extractDraftRelations = (data) => {
|
2104
|
+
const relations = data.connect || [];
|
2105
|
+
relations.forEach((relation) => {
|
2106
|
+
if (relation.status === "draft") {
|
2107
|
+
localDraftRelations.add(relation.id);
|
2250
2108
|
}
|
2251
|
-
}
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
documentId: id,
|
2260
|
-
document: isCloning ? void 0 : document,
|
2261
|
-
meta: isCloning ? void 0 : meta,
|
2262
|
-
collectionType
|
2263
|
-
},
|
2264
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2265
|
-
children: (actions2) => {
|
2266
|
-
const headerActions = actions2.filter((action) => {
|
2267
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2268
|
-
return positions.includes("header");
|
2269
|
-
});
|
2270
|
-
return /* @__PURE__ */ jsx(
|
2271
|
-
DocumentActionsMenu,
|
2272
|
-
{
|
2273
|
-
actions: headerActions,
|
2274
|
-
label: formatMessage({
|
2275
|
-
id: "content-manager.containers.edit.header.more-actions",
|
2276
|
-
defaultMessage: "More actions"
|
2277
|
-
}),
|
2278
|
-
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2279
|
-
}
|
2280
|
-
);
|
2109
|
+
});
|
2110
|
+
};
|
2111
|
+
const traverseAndExtract = (data) => {
|
2112
|
+
Object.entries(data).forEach(([key, value]) => {
|
2113
|
+
if (key === "connect" && Array.isArray(value)) {
|
2114
|
+
extractDraftRelations({ connect: value });
|
2115
|
+
} else if (typeof value === "object" && value !== null) {
|
2116
|
+
traverseAndExtract(value);
|
2281
2117
|
}
|
2118
|
+
});
|
2119
|
+
};
|
2120
|
+
if (!documentId || modified) {
|
2121
|
+
traverseAndExtract(formValues);
|
2122
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2123
|
+
}
|
2124
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2125
|
+
React.useEffect(() => {
|
2126
|
+
if (!document || !document.documentId || isListView) {
|
2127
|
+
return;
|
2128
|
+
}
|
2129
|
+
const fetchDraftRelationsCount = async () => {
|
2130
|
+
const { data, error } = await countDraftRelations({
|
2131
|
+
collectionType,
|
2132
|
+
model,
|
2133
|
+
documentId,
|
2134
|
+
params
|
2135
|
+
});
|
2136
|
+
if (error) {
|
2137
|
+
throw error;
|
2282
2138
|
}
|
2283
|
-
|
2284
|
-
|
2285
|
-
}
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2139
|
+
if (data) {
|
2140
|
+
setServerCountOfDraftRelations(data.data);
|
2141
|
+
}
|
2142
|
+
};
|
2143
|
+
fetchDraftRelationsCount();
|
2144
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2145
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2146
|
+
if (!schema?.options?.draftAndPublish) {
|
2290
2147
|
return null;
|
2291
2148
|
}
|
2292
|
-
const
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2149
|
+
const performPublish = async () => {
|
2150
|
+
setSubmitting(true);
|
2151
|
+
try {
|
2152
|
+
const { errors } = await validate(true, {
|
2153
|
+
status: "published"
|
2154
|
+
});
|
2155
|
+
if (errors) {
|
2156
|
+
toggleNotification({
|
2157
|
+
type: "danger",
|
2158
|
+
message: formatMessage({
|
2159
|
+
id: "content-manager.validation.error",
|
2160
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2161
|
+
})
|
2162
|
+
});
|
2163
|
+
return;
|
2164
|
+
}
|
2165
|
+
const res = await publish(
|
2304
2166
|
{
|
2305
|
-
|
2306
|
-
|
2167
|
+
collectionType,
|
2168
|
+
model,
|
2169
|
+
documentId,
|
2170
|
+
params
|
2307
2171
|
},
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2172
|
+
formValues
|
2173
|
+
);
|
2174
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2175
|
+
navigate({
|
2176
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2177
|
+
search: rawQuery
|
2178
|
+
});
|
2179
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2180
|
+
setErrors(formatValidationErrors(res.error));
|
2181
|
+
}
|
2182
|
+
} finally {
|
2183
|
+
setSubmitting(false);
|
2184
|
+
}
|
2185
|
+
};
|
2186
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2187
|
+
const enableDraftRelationsCount = false;
|
2188
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2189
|
+
return {
|
2190
|
+
/**
|
2191
|
+
* Disabled when:
|
2192
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2193
|
+
* - the form is submitting
|
2194
|
+
* - the active tab is the published tab
|
2195
|
+
* - the document is already published & not modified
|
2196
|
+
* - the document is being created & not modified
|
2197
|
+
* - the user doesn't have the permission to publish
|
2198
|
+
*/
|
2199
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
2200
|
+
label: formatMessage({
|
2201
|
+
id: "app.utils.publish",
|
2202
|
+
defaultMessage: "Publish"
|
2203
|
+
}),
|
2204
|
+
onClick: async () => {
|
2205
|
+
await performPublish();
|
2314
2206
|
},
|
2315
|
-
{
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2207
|
+
dialog: hasDraftRelations ? {
|
2208
|
+
type: "dialog",
|
2209
|
+
variant: "danger",
|
2210
|
+
footer: null,
|
2211
|
+
title: formatMessage({
|
2212
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2213
|
+
defaultMessage: "Confirmation"
|
2320
2214
|
}),
|
2321
|
-
|
2215
|
+
content: formatMessage(
|
2322
2216
|
{
|
2323
|
-
id:
|
2324
|
-
defaultMessage:
|
2217
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2218
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2325
2219
|
},
|
2326
2220
|
{
|
2327
|
-
|
2328
|
-
RelativeTime,
|
2329
|
-
{
|
2330
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2331
|
-
}
|
2332
|
-
),
|
2333
|
-
isAnonymous: !updator,
|
2334
|
-
author: updator
|
2221
|
+
count: totalDraftRelations
|
2335
2222
|
}
|
2336
|
-
)
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2223
|
+
),
|
2224
|
+
onConfirm: async () => {
|
2225
|
+
await performPublish();
|
2226
|
+
}
|
2227
|
+
} : void 0
|
2228
|
+
};
|
2229
|
+
};
|
2230
|
+
PublishAction$1.type = "publish";
|
2231
|
+
const UpdateAction = ({
|
2232
|
+
activeTab,
|
2233
|
+
documentId,
|
2234
|
+
model,
|
2235
|
+
collectionType
|
2236
|
+
}) => {
|
2237
|
+
const navigate = useNavigate();
|
2238
|
+
const { toggleNotification } = useNotification();
|
2239
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2240
|
+
const cloneMatch = useMatch(CLONE_PATH);
|
2241
|
+
const isCloning = cloneMatch !== null;
|
2242
|
+
const { formatMessage } = useIntl();
|
2243
|
+
const { create, update, clone } = useDocumentActions();
|
2244
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2245
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2246
|
+
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2247
|
+
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
2248
|
+
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2249
|
+
const document = useForm("UpdateAction", ({ values }) => values);
|
2250
|
+
const validate = useForm("UpdateAction", (state) => state.validate);
|
2251
|
+
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
2252
|
+
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
2253
|
+
return {
|
2254
|
+
/**
|
2255
|
+
* Disabled when:
|
2256
|
+
* - the form is submitting
|
2257
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2258
|
+
* - the active tab is the published tab
|
2259
|
+
*/
|
2260
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2261
|
+
label: formatMessage({
|
2262
|
+
id: "content-manager.containers.Edit.save",
|
2263
|
+
defaultMessage: "Save"
|
2264
|
+
}),
|
2265
|
+
onClick: async () => {
|
2266
|
+
setSubmitting(true);
|
2267
|
+
try {
|
2268
|
+
const { errors } = await validate(true, {
|
2269
|
+
status: "draft"
|
2270
|
+
});
|
2271
|
+
if (errors) {
|
2272
|
+
toggleNotification({
|
2273
|
+
type: "danger",
|
2274
|
+
message: formatMessage({
|
2275
|
+
id: "content-manager.validation.error",
|
2276
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2277
|
+
})
|
2278
|
+
});
|
2279
|
+
return;
|
2358
2280
|
}
|
2359
|
-
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
|
2373
|
-
|
2374
|
-
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2281
|
+
if (isCloning) {
|
2282
|
+
const res = await clone(
|
2283
|
+
{
|
2284
|
+
model,
|
2285
|
+
documentId: cloneMatch.params.origin,
|
2286
|
+
params
|
2287
|
+
},
|
2288
|
+
document
|
2289
|
+
);
|
2290
|
+
if ("data" in res) {
|
2291
|
+
navigate(
|
2292
|
+
{
|
2293
|
+
pathname: `../${res.data.documentId}`,
|
2294
|
+
search: rawQuery
|
2295
|
+
},
|
2296
|
+
{ relative: "path" }
|
2297
|
+
);
|
2298
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2299
|
+
setErrors(formatValidationErrors(res.error));
|
2300
|
+
}
|
2301
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2302
|
+
const res = await update(
|
2303
|
+
{
|
2304
|
+
collectionType,
|
2305
|
+
model,
|
2306
|
+
documentId,
|
2307
|
+
params
|
2308
|
+
},
|
2309
|
+
document
|
2310
|
+
);
|
2311
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2312
|
+
setErrors(formatValidationErrors(res.error));
|
2313
|
+
} else {
|
2314
|
+
resetForm();
|
2315
|
+
}
|
2316
|
+
} else {
|
2317
|
+
const res = await create(
|
2318
|
+
{
|
2319
|
+
model,
|
2320
|
+
params
|
2321
|
+
},
|
2322
|
+
document
|
2323
|
+
);
|
2324
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2325
|
+
navigate(
|
2326
|
+
{
|
2327
|
+
pathname: `../${res.data.documentId}`,
|
2328
|
+
search: rawQuery
|
2329
|
+
},
|
2330
|
+
{ replace: true, relative: "path" }
|
2331
|
+
);
|
2332
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2333
|
+
setErrors(formatValidationErrors(res.error));
|
2334
|
+
}
|
2335
|
+
}
|
2336
|
+
} finally {
|
2337
|
+
setSubmitting(false);
|
2338
|
+
}
|
2381
2339
|
}
|
2382
|
-
|
2340
|
+
};
|
2383
2341
|
};
|
2384
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
SingleSelect,
|
2389
|
-
{
|
2390
|
-
size: "S",
|
2391
|
-
disabled: action.disabled,
|
2392
|
-
"aria-label": action.label,
|
2393
|
-
onChange: action.onSelect,
|
2394
|
-
value: action.value,
|
2395
|
-
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2396
|
-
},
|
2397
|
-
action.id
|
2398
|
-
);
|
2399
|
-
} else {
|
2400
|
-
return null;
|
2401
|
-
}
|
2402
|
-
}) });
|
2342
|
+
UpdateAction.type = "update";
|
2343
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2344
|
+
KEEP: "keep",
|
2345
|
+
DISCARD: "discard"
|
2403
2346
|
};
|
2404
|
-
const
|
2405
|
-
|
2347
|
+
const UnpublishAction$1 = ({
|
2348
|
+
activeTab,
|
2349
|
+
documentId,
|
2350
|
+
model,
|
2351
|
+
collectionType,
|
2352
|
+
document
|
2353
|
+
}) => {
|
2406
2354
|
const { formatMessage } = useIntl();
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2355
|
+
const { schema } = useDoc();
|
2356
|
+
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2357
|
+
const { unpublish } = useDocumentActions();
|
2358
|
+
const [{ query }] = useQueryParams();
|
2359
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2360
|
+
const { toggleNotification } = useNotification();
|
2361
|
+
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
2362
|
+
const isDocumentModified = document?.status === "modified";
|
2363
|
+
const handleChange = (value) => {
|
2364
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
2417
2365
|
};
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
const navigate = useNavigate();
|
2422
|
-
const { formatMessage } = useIntl();
|
2366
|
+
if (!schema?.options?.draftAndPublish) {
|
2367
|
+
return null;
|
2368
|
+
}
|
2423
2369
|
return {
|
2370
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2424
2371
|
label: formatMessage({
|
2425
|
-
id: "
|
2426
|
-
defaultMessage: "
|
2372
|
+
id: "app.utils.unpublish",
|
2373
|
+
defaultMessage: "Unpublish"
|
2427
2374
|
}),
|
2428
|
-
icon: /* @__PURE__ */ jsx(
|
2429
|
-
onClick: () => {
|
2430
|
-
|
2375
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2376
|
+
onClick: async () => {
|
2377
|
+
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2378
|
+
if (!documentId) {
|
2379
|
+
console.error(
|
2380
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2381
|
+
);
|
2382
|
+
toggleNotification({
|
2383
|
+
message: formatMessage({
|
2384
|
+
id: "content-manager.actions.unpublish.error",
|
2385
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2386
|
+
}),
|
2387
|
+
type: "danger"
|
2388
|
+
});
|
2389
|
+
}
|
2390
|
+
return;
|
2391
|
+
}
|
2392
|
+
await unpublish({
|
2393
|
+
collectionType,
|
2394
|
+
model,
|
2395
|
+
documentId,
|
2396
|
+
params
|
2397
|
+
});
|
2431
2398
|
},
|
2432
|
-
|
2399
|
+
dialog: isDocumentModified ? {
|
2400
|
+
type: "dialog",
|
2401
|
+
title: formatMessage({
|
2402
|
+
id: "app.components.ConfirmDialog.title",
|
2403
|
+
defaultMessage: "Confirmation"
|
2404
|
+
}),
|
2405
|
+
content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
2406
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
|
2407
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2408
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2409
|
+
id: "content-manager.actions.unpublish.dialog.body",
|
2410
|
+
defaultMessage: "Are you sure?"
|
2411
|
+
}) })
|
2412
|
+
] }),
|
2413
|
+
/* @__PURE__ */ jsxs(
|
2414
|
+
Radio.Group,
|
2415
|
+
{
|
2416
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2417
|
+
name: "discard-options",
|
2418
|
+
"aria-label": formatMessage({
|
2419
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2420
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2421
|
+
}),
|
2422
|
+
onValueChange: handleChange,
|
2423
|
+
children: [
|
2424
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2425
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2426
|
+
defaultMessage: "Keep draft"
|
2427
|
+
}) }),
|
2428
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2429
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2430
|
+
defaultMessage: "Replace draft"
|
2431
|
+
}) })
|
2432
|
+
]
|
2433
|
+
}
|
2434
|
+
)
|
2435
|
+
] }),
|
2436
|
+
onConfirm: async () => {
|
2437
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2438
|
+
console.error(
|
2439
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2440
|
+
);
|
2441
|
+
toggleNotification({
|
2442
|
+
message: formatMessage({
|
2443
|
+
id: "content-manager.actions.unpublish.error",
|
2444
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2445
|
+
}),
|
2446
|
+
type: "danger"
|
2447
|
+
});
|
2448
|
+
}
|
2449
|
+
await unpublish(
|
2450
|
+
{
|
2451
|
+
collectionType,
|
2452
|
+
model,
|
2453
|
+
documentId,
|
2454
|
+
params
|
2455
|
+
},
|
2456
|
+
!shouldKeepDraft
|
2457
|
+
);
|
2458
|
+
}
|
2459
|
+
} : void 0,
|
2460
|
+
variant: "danger",
|
2461
|
+
position: ["panel", "table-row"]
|
2433
2462
|
};
|
2434
2463
|
};
|
2435
|
-
|
2436
|
-
const
|
2437
|
-
|
2464
|
+
UnpublishAction$1.type = "unpublish";
|
2465
|
+
const DiscardAction = ({
|
2466
|
+
activeTab,
|
2467
|
+
documentId,
|
2468
|
+
model,
|
2469
|
+
collectionType,
|
2470
|
+
document
|
2471
|
+
}) => {
|
2438
2472
|
const { formatMessage } = useIntl();
|
2439
|
-
const
|
2440
|
-
const
|
2441
|
-
const {
|
2442
|
-
const {
|
2443
|
-
const
|
2473
|
+
const { schema } = useDoc();
|
2474
|
+
const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
|
2475
|
+
const { discard } = useDocumentActions();
|
2476
|
+
const [{ query }] = useQueryParams();
|
2477
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2478
|
+
if (!schema?.options?.draftAndPublish) {
|
2479
|
+
return null;
|
2480
|
+
}
|
2444
2481
|
return {
|
2445
|
-
disabled: !
|
2482
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2446
2483
|
label: formatMessage({
|
2447
|
-
id: "content-manager.actions.
|
2448
|
-
defaultMessage: "
|
2484
|
+
id: "content-manager.actions.discard.label",
|
2485
|
+
defaultMessage: "Discard changes"
|
2449
2486
|
}),
|
2450
|
-
icon: /* @__PURE__ */ jsx(
|
2487
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2488
|
+
position: ["panel", "table-row"],
|
2489
|
+
variant: "danger",
|
2451
2490
|
dialog: {
|
2452
2491
|
type: "dialog",
|
2453
2492
|
title: formatMessage({
|
@@ -2457,92 +2496,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2457
2496
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2458
2497
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2459
2498
|
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2460
|
-
id: "content-manager.actions.
|
2499
|
+
id: "content-manager.actions.discard.dialog.body",
|
2461
2500
|
defaultMessage: "Are you sure?"
|
2462
2501
|
}) })
|
2463
2502
|
] }),
|
2464
2503
|
onConfirm: async () => {
|
2465
|
-
|
2466
|
-
|
2467
|
-
|
2468
|
-
|
2469
|
-
|
2470
|
-
|
2471
|
-
|
2472
|
-
|
2473
|
-
|
2474
|
-
|
2475
|
-
|
2476
|
-
|
2477
|
-
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
2486
|
-
|
2487
|
-
|
2488
|
-
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2504
|
+
await discard({
|
2505
|
+
collectionType,
|
2506
|
+
model,
|
2507
|
+
documentId,
|
2508
|
+
params
|
2509
|
+
});
|
2510
|
+
}
|
2511
|
+
}
|
2512
|
+
};
|
2513
|
+
};
|
2514
|
+
DiscardAction.type = "discard";
|
2515
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2516
|
+
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2517
|
+
const RelativeTime = React.forwardRef(
|
2518
|
+
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2519
|
+
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2520
|
+
const interval = intervalToDuration({
|
2521
|
+
start: timestamp,
|
2522
|
+
end: Date.now()
|
2523
|
+
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2524
|
+
});
|
2525
|
+
const unit = intervals.find((intervalUnit) => {
|
2526
|
+
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2527
|
+
});
|
2528
|
+
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2529
|
+
const customInterval = customIntervals.find(
|
2530
|
+
(custom) => interval[custom.unit] < custom.threshold
|
2531
|
+
);
|
2532
|
+
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2533
|
+
return /* @__PURE__ */ jsx(
|
2534
|
+
"time",
|
2535
|
+
{
|
2536
|
+
ref: forwardedRef,
|
2537
|
+
dateTime: timestamp.toISOString(),
|
2538
|
+
role: "time",
|
2539
|
+
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2540
|
+
...restProps,
|
2541
|
+
children: displayText
|
2498
2542
|
}
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2543
|
+
);
|
2544
|
+
}
|
2545
|
+
);
|
2546
|
+
const getDisplayName = ({
|
2547
|
+
firstname,
|
2548
|
+
lastname,
|
2549
|
+
username,
|
2550
|
+
email
|
2551
|
+
} = {}) => {
|
2552
|
+
if (username) {
|
2553
|
+
return username;
|
2554
|
+
}
|
2555
|
+
if (firstname) {
|
2556
|
+
return `${firstname} ${lastname ?? ""}`.trim();
|
2557
|
+
}
|
2558
|
+
return email ?? "";
|
2503
2559
|
};
|
2504
|
-
|
2505
|
-
const
|
2506
|
-
const
|
2507
|
-
|
2508
|
-
const [
|
2509
|
-
{
|
2510
|
-
query: { status }
|
2511
|
-
}
|
2512
|
-
] = useQueryParams({
|
2513
|
-
status: "draft"
|
2514
|
-
});
|
2515
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2516
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2517
|
-
const props = {
|
2518
|
-
activeTab: status,
|
2519
|
-
model,
|
2520
|
-
documentId: id,
|
2521
|
-
document: isCloning ? void 0 : document,
|
2522
|
-
meta: isCloning ? void 0 : meta,
|
2523
|
-
collectionType
|
2524
|
-
};
|
2525
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2526
|
-
DescriptionComponentRenderer,
|
2527
|
-
{
|
2528
|
-
props,
|
2529
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2530
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2531
|
-
}
|
2532
|
-
) });
|
2560
|
+
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2561
|
+
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2562
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2563
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2533
2564
|
};
|
2534
|
-
const
|
2565
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2535
2566
|
const { formatMessage } = useIntl();
|
2536
|
-
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2567
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2568
|
+
const title = isCreating ? formatMessage({
|
2569
|
+
id: "content-manager.containers.edit.title.new",
|
2570
|
+
defaultMessage: "Create an entry"
|
2571
|
+
}) : documentTitle;
|
2572
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2573
|
+
/* @__PURE__ */ jsx(BackButton, {}),
|
2574
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2575
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2576
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2577
|
+
] }),
|
2578
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2579
|
+
] });
|
2543
2580
|
};
|
2544
|
-
|
2545
|
-
const
|
2581
|
+
const HeaderToolbar = () => {
|
2582
|
+
const { formatMessage } = useIntl();
|
2546
2583
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2547
2584
|
const [
|
2548
2585
|
{
|
@@ -2550,355 +2587,432 @@ const ActionsPanelContent = () => {
|
|
2550
2587
|
}
|
2551
2588
|
] = useQueryParams();
|
2552
2589
|
const { model, id, document, meta, collectionType } = useDoc();
|
2553
|
-
const plugins = useStrapiApp("
|
2554
|
-
|
2555
|
-
activeTab: status,
|
2556
|
-
model,
|
2557
|
-
documentId: id,
|
2558
|
-
document: isCloning ? void 0 : document,
|
2559
|
-
meta: isCloning ? void 0 : meta,
|
2560
|
-
collectionType
|
2561
|
-
};
|
2562
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2590
|
+
const plugins = useStrapiApp("HeaderToolbar", (state) => state.plugins);
|
2591
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
2563
2592
|
/* @__PURE__ */ jsx(
|
2564
2593
|
DescriptionComponentRenderer,
|
2565
2594
|
{
|
2566
|
-
props
|
2567
|
-
|
2568
|
-
|
2595
|
+
props: {
|
2596
|
+
activeTab: status,
|
2597
|
+
model,
|
2598
|
+
documentId: id,
|
2599
|
+
document: isCloning ? void 0 : document,
|
2600
|
+
meta: isCloning ? void 0 : meta,
|
2601
|
+
collectionType
|
2602
|
+
},
|
2603
|
+
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2604
|
+
children: (actions2) => {
|
2605
|
+
if (actions2.length > 0) {
|
2606
|
+
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2607
|
+
} else {
|
2608
|
+
return null;
|
2609
|
+
}
|
2610
|
+
}
|
2569
2611
|
}
|
2570
2612
|
),
|
2571
|
-
/* @__PURE__ */ jsx(
|
2613
|
+
/* @__PURE__ */ jsx(
|
2614
|
+
DescriptionComponentRenderer,
|
2615
|
+
{
|
2616
|
+
props: {
|
2617
|
+
activeTab: status,
|
2618
|
+
model,
|
2619
|
+
documentId: id,
|
2620
|
+
document: isCloning ? void 0 : document,
|
2621
|
+
meta: isCloning ? void 0 : meta,
|
2622
|
+
collectionType
|
2623
|
+
},
|
2624
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2625
|
+
children: (actions2) => {
|
2626
|
+
const headerActions = actions2.filter((action) => {
|
2627
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2628
|
+
return positions.includes("header");
|
2629
|
+
});
|
2630
|
+
return /* @__PURE__ */ jsx(
|
2631
|
+
DocumentActionsMenu,
|
2632
|
+
{
|
2633
|
+
actions: headerActions,
|
2634
|
+
label: formatMessage({
|
2635
|
+
id: "content-manager.containers.edit.header.more-actions",
|
2636
|
+
defaultMessage: "More actions"
|
2637
|
+
}),
|
2638
|
+
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2639
|
+
}
|
2640
|
+
);
|
2641
|
+
}
|
2642
|
+
}
|
2643
|
+
)
|
2572
2644
|
] });
|
2573
2645
|
};
|
2574
|
-
const
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
tag: "aside",
|
2580
|
-
"aria-labelledby": "additional-information",
|
2581
|
-
background: "neutral0",
|
2582
|
-
borderColor: "neutral150",
|
2583
|
-
hasRadius: true,
|
2584
|
-
paddingBottom: 4,
|
2585
|
-
paddingLeft: 4,
|
2586
|
-
paddingRight: 4,
|
2587
|
-
paddingTop: 4,
|
2588
|
-
shadow: "tableShadow",
|
2589
|
-
gap: 3,
|
2590
|
-
direction: "column",
|
2591
|
-
justifyContent: "stretch",
|
2592
|
-
alignItems: "flex-start",
|
2593
|
-
children: [
|
2594
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2595
|
-
children
|
2596
|
-
]
|
2597
|
-
}
|
2598
|
-
);
|
2599
|
-
});
|
2600
|
-
const HOOKS = {
|
2601
|
-
/**
|
2602
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2603
|
-
* @constant
|
2604
|
-
* @type {string}
|
2605
|
-
*/
|
2606
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2607
|
-
/**
|
2608
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2609
|
-
* @constant
|
2610
|
-
* @type {string}
|
2611
|
-
*/
|
2612
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2613
|
-
/**
|
2614
|
-
* Hook that allows to mutate the CM's edit view layout
|
2615
|
-
* @constant
|
2616
|
-
* @type {string}
|
2617
|
-
*/
|
2618
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2619
|
-
/**
|
2620
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2621
|
-
* @constant
|
2622
|
-
* @type {string}
|
2623
|
-
*/
|
2624
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2625
|
-
};
|
2626
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2627
|
-
endpoints: (builder) => ({
|
2628
|
-
getContentTypeConfiguration: builder.query({
|
2629
|
-
query: (uid) => ({
|
2630
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2631
|
-
method: "GET"
|
2632
|
-
}),
|
2633
|
-
transformResponse: (response) => response.data,
|
2634
|
-
providesTags: (_result, _error, uid) => [
|
2635
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2636
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2637
|
-
]
|
2638
|
-
}),
|
2639
|
-
getAllContentTypeSettings: builder.query({
|
2640
|
-
query: () => "/content-manager/content-types-settings",
|
2641
|
-
transformResponse: (response) => response.data,
|
2642
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2643
|
-
}),
|
2644
|
-
updateContentTypeConfiguration: builder.mutation({
|
2645
|
-
query: ({ uid, ...body }) => ({
|
2646
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2647
|
-
method: "PUT",
|
2648
|
-
data: body
|
2649
|
-
}),
|
2650
|
-
transformResponse: (response) => response.data,
|
2651
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2652
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2653
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2654
|
-
// Is this necessary?
|
2655
|
-
{ type: "InitialData" }
|
2656
|
-
]
|
2657
|
-
})
|
2658
|
-
})
|
2659
|
-
});
|
2660
|
-
const {
|
2661
|
-
useGetContentTypeConfigurationQuery,
|
2662
|
-
useGetAllContentTypeSettingsQuery,
|
2663
|
-
useUpdateContentTypeConfigurationMutation
|
2664
|
-
} = contentTypesApi;
|
2665
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2666
|
-
const { type } = attribute;
|
2667
|
-
if (type === "relation") {
|
2668
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2669
|
-
}
|
2670
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2671
|
-
};
|
2672
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2673
|
-
if (!mainFieldName) {
|
2674
|
-
return void 0;
|
2646
|
+
const Information = ({ activeTab }) => {
|
2647
|
+
const { formatMessage } = useIntl();
|
2648
|
+
const { document, meta } = useDoc();
|
2649
|
+
if (!document || !document.id) {
|
2650
|
+
return null;
|
2675
2651
|
}
|
2676
|
-
const
|
2677
|
-
|
2678
|
-
|
2652
|
+
const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
|
2653
|
+
const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
|
2654
|
+
const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
|
2655
|
+
const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
|
2656
|
+
const information = [
|
2657
|
+
{
|
2658
|
+
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2659
|
+
label: formatMessage({
|
2660
|
+
id: "content-manager.containers.edit.information.last-published.label",
|
2661
|
+
defaultMessage: "Published"
|
2662
|
+
}),
|
2663
|
+
value: formatMessage(
|
2664
|
+
{
|
2665
|
+
id: "content-manager.containers.edit.information.last-published.value",
|
2666
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2667
|
+
},
|
2668
|
+
{
|
2669
|
+
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
2670
|
+
isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
|
2671
|
+
author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
|
2672
|
+
}
|
2673
|
+
)
|
2674
|
+
},
|
2675
|
+
{
|
2676
|
+
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2677
|
+
label: formatMessage({
|
2678
|
+
id: "content-manager.containers.edit.information.last-draft.label",
|
2679
|
+
defaultMessage: "Updated"
|
2680
|
+
}),
|
2681
|
+
value: formatMessage(
|
2682
|
+
{
|
2683
|
+
id: "content-manager.containers.edit.information.last-draft.value",
|
2684
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2685
|
+
},
|
2686
|
+
{
|
2687
|
+
time: /* @__PURE__ */ jsx(
|
2688
|
+
RelativeTime,
|
2689
|
+
{
|
2690
|
+
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2691
|
+
}
|
2692
|
+
),
|
2693
|
+
isAnonymous: !updator,
|
2694
|
+
author: updator
|
2695
|
+
}
|
2696
|
+
)
|
2697
|
+
},
|
2698
|
+
{
|
2699
|
+
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2700
|
+
label: formatMessage({
|
2701
|
+
id: "content-manager.containers.edit.information.document.label",
|
2702
|
+
defaultMessage: "Created"
|
2703
|
+
}),
|
2704
|
+
value: formatMessage(
|
2705
|
+
{
|
2706
|
+
id: "content-manager.containers.edit.information.document.value",
|
2707
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2708
|
+
},
|
2709
|
+
{
|
2710
|
+
time: /* @__PURE__ */ jsx(
|
2711
|
+
RelativeTime,
|
2712
|
+
{
|
2713
|
+
timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
|
2714
|
+
}
|
2715
|
+
),
|
2716
|
+
isAnonymous: !creator,
|
2717
|
+
author: creator
|
2718
|
+
}
|
2719
|
+
)
|
2720
|
+
}
|
2721
|
+
].filter((info) => info.isDisplayed);
|
2722
|
+
return /* @__PURE__ */ jsx(
|
2723
|
+
Flex,
|
2724
|
+
{
|
2725
|
+
borderWidth: "1px 0 0 0",
|
2726
|
+
borderStyle: "solid",
|
2727
|
+
borderColor: "neutral150",
|
2728
|
+
direction: "column",
|
2729
|
+
marginTop: 2,
|
2730
|
+
tag: "dl",
|
2731
|
+
padding: 5,
|
2732
|
+
gap: 3,
|
2733
|
+
alignItems: "flex-start",
|
2734
|
+
marginLeft: "-0.4rem",
|
2735
|
+
marginRight: "-0.4rem",
|
2736
|
+
width: "calc(100% + 8px)",
|
2737
|
+
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2738
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2739
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2740
|
+
] }, info.label))
|
2741
|
+
}
|
2679
2742
|
);
|
2680
|
-
return {
|
2681
|
-
name: mainFieldName,
|
2682
|
-
type: mainFieldType ?? "string"
|
2683
|
-
};
|
2684
|
-
};
|
2685
|
-
const DEFAULT_SETTINGS = {
|
2686
|
-
bulkable: false,
|
2687
|
-
filterable: false,
|
2688
|
-
searchable: false,
|
2689
|
-
pagination: false,
|
2690
|
-
defaultSortBy: "",
|
2691
|
-
defaultSortOrder: "asc",
|
2692
|
-
mainField: "id",
|
2693
|
-
pageSize: 10
|
2694
2743
|
};
|
2695
|
-
const
|
2696
|
-
const
|
2697
|
-
const
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
error,
|
2706
|
-
isFetching: isFetchingConfigs
|
2707
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2708
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2709
|
-
React.useEffect(() => {
|
2710
|
-
if (error) {
|
2711
|
-
toggleNotification({
|
2712
|
-
type: "danger",
|
2713
|
-
message: formatAPIError(error)
|
2714
|
-
});
|
2744
|
+
const HeaderActions = ({ actions: actions2 }) => {
|
2745
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2746
|
+
const handleClick = (action) => async (e) => {
|
2747
|
+
if (!("options" in action)) {
|
2748
|
+
const { onClick = () => false, dialog, id } = action;
|
2749
|
+
const muteDialog = await onClick(e);
|
2750
|
+
if (dialog && !muteDialog) {
|
2751
|
+
e.preventDefault();
|
2752
|
+
setDialogId(id);
|
2753
|
+
}
|
2715
2754
|
}
|
2716
|
-
}, [error, formatAPIError, toggleNotification]);
|
2717
|
-
const editLayout = React.useMemo(
|
2718
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2719
|
-
layout: [],
|
2720
|
-
components: {},
|
2721
|
-
metadatas: {},
|
2722
|
-
options: {},
|
2723
|
-
settings: DEFAULT_SETTINGS
|
2724
|
-
},
|
2725
|
-
[data, isLoading, schemas, schema, components]
|
2726
|
-
);
|
2727
|
-
const listLayout = React.useMemo(() => {
|
2728
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2729
|
-
layout: [],
|
2730
|
-
metadatas: {},
|
2731
|
-
options: {},
|
2732
|
-
settings: DEFAULT_SETTINGS
|
2733
|
-
};
|
2734
|
-
}, [data, isLoading, schemas, schema, components]);
|
2735
|
-
const { layout: edit } = React.useMemo(
|
2736
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2737
|
-
layout: editLayout,
|
2738
|
-
query
|
2739
|
-
}),
|
2740
|
-
[editLayout, query, runHookWaterfall]
|
2741
|
-
);
|
2742
|
-
return {
|
2743
|
-
error,
|
2744
|
-
isLoading,
|
2745
|
-
edit,
|
2746
|
-
list: listLayout
|
2747
2755
|
};
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
return
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
schemas
|
2765
|
-
).reduce((panels, row) => {
|
2766
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2767
|
-
panels.push([row]);
|
2768
|
-
currentPanelIndex += 2;
|
2756
|
+
const handleClose = () => {
|
2757
|
+
setDialogId(null);
|
2758
|
+
};
|
2759
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2760
|
+
if (action.options) {
|
2761
|
+
return /* @__PURE__ */ jsx(
|
2762
|
+
SingleSelect,
|
2763
|
+
{
|
2764
|
+
size: "S",
|
2765
|
+
onChange: action.onSelect,
|
2766
|
+
"aria-label": action.label,
|
2767
|
+
...action,
|
2768
|
+
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2769
|
+
},
|
2770
|
+
action.id
|
2771
|
+
);
|
2769
2772
|
} else {
|
2770
|
-
if (
|
2771
|
-
|
2773
|
+
if (action.type === "icon") {
|
2774
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2775
|
+
/* @__PURE__ */ jsx(
|
2776
|
+
IconButton,
|
2777
|
+
{
|
2778
|
+
disabled: action.disabled,
|
2779
|
+
label: action.label,
|
2780
|
+
size: "S",
|
2781
|
+
onClick: handleClick(action),
|
2782
|
+
children: action.icon
|
2783
|
+
}
|
2784
|
+
),
|
2785
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2786
|
+
HeaderActionDialog,
|
2787
|
+
{
|
2788
|
+
...action.dialog,
|
2789
|
+
isOpen: dialogId === action.id,
|
2790
|
+
onClose: handleClose
|
2791
|
+
}
|
2792
|
+
) : null
|
2793
|
+
] }, action.id);
|
2772
2794
|
}
|
2773
|
-
panels[currentPanelIndex].push(row);
|
2774
2795
|
}
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
}
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
|
2796
|
+
}) });
|
2797
|
+
};
|
2798
|
+
const HeaderActionDialog = ({
|
2799
|
+
onClose,
|
2800
|
+
onCancel,
|
2801
|
+
title,
|
2802
|
+
content: Content,
|
2803
|
+
isOpen
|
2804
|
+
}) => {
|
2805
|
+
const handleClose = async () => {
|
2806
|
+
if (onCancel) {
|
2807
|
+
await onCancel();
|
2808
|
+
}
|
2809
|
+
onClose();
|
2810
|
+
};
|
2811
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2812
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2813
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2814
|
+
] }) });
|
2815
|
+
};
|
2816
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2817
|
+
const navigate = useNavigate();
|
2818
|
+
const { formatMessage } = useIntl();
|
2819
|
+
return {
|
2820
|
+
label: formatMessage({
|
2821
|
+
id: "app.links.configure-view",
|
2822
|
+
defaultMessage: "Configure the view"
|
2823
|
+
}),
|
2824
|
+
icon: /* @__PURE__ */ jsx(ListPlus, {}),
|
2825
|
+
onClick: () => {
|
2826
|
+
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2801
2827
|
},
|
2802
|
-
|
2803
|
-
|
2828
|
+
position: "header"
|
2829
|
+
};
|
2830
|
+
};
|
2831
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2832
|
+
const EditTheModelAction = ({ model }) => {
|
2833
|
+
const navigate = useNavigate();
|
2834
|
+
const { formatMessage } = useIntl();
|
2804
2835
|
return {
|
2805
|
-
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2836
|
+
label: formatMessage({
|
2837
|
+
id: "content-manager.link-to-ctb",
|
2838
|
+
defaultMessage: "Edit the model"
|
2839
|
+
}),
|
2840
|
+
icon: /* @__PURE__ */ jsx(Pencil, {}),
|
2841
|
+
onClick: () => {
|
2842
|
+
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2811
2843
|
},
|
2812
|
-
|
2813
|
-
...schema?.options,
|
2814
|
-
...schema?.pluginOptions,
|
2815
|
-
...data.contentType.options
|
2816
|
-
}
|
2844
|
+
position: "header"
|
2817
2845
|
};
|
2818
2846
|
};
|
2819
|
-
|
2820
|
-
|
2821
|
-
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2847
|
+
EditTheModelAction.type = "edit-the-model";
|
2848
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2849
|
+
const navigate = useNavigate();
|
2850
|
+
const { formatMessage } = useIntl();
|
2851
|
+
const listViewPathMatch = useMatch(LIST_PATH);
|
2852
|
+
const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
|
2853
|
+
const { delete: deleteAction } = useDocumentActions();
|
2854
|
+
const { toggleNotification } = useNotification();
|
2855
|
+
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2856
|
+
const isLocalized = document?.locale != null;
|
2857
|
+
return {
|
2858
|
+
disabled: !canDelete || !document,
|
2859
|
+
label: formatMessage(
|
2860
|
+
{
|
2861
|
+
id: "content-manager.actions.delete.label",
|
2862
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2863
|
+
},
|
2864
|
+
{ isLocalized }
|
2865
|
+
),
|
2866
|
+
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2867
|
+
dialog: {
|
2868
|
+
type: "dialog",
|
2869
|
+
title: formatMessage({
|
2870
|
+
id: "app.components.ConfirmDialog.title",
|
2871
|
+
defaultMessage: "Confirmation"
|
2872
|
+
}),
|
2873
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2874
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2875
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2876
|
+
id: "content-manager.actions.delete.dialog.body",
|
2877
|
+
defaultMessage: "Are you sure?"
|
2878
|
+
}) })
|
2879
|
+
] }),
|
2880
|
+
onConfirm: async () => {
|
2881
|
+
if (!listViewPathMatch) {
|
2882
|
+
setSubmitting(true);
|
2883
|
+
}
|
2884
|
+
try {
|
2885
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2886
|
+
console.error(
|
2887
|
+
"You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2888
|
+
);
|
2889
|
+
toggleNotification({
|
2890
|
+
message: formatMessage({
|
2891
|
+
id: "content-manager.actions.delete.error",
|
2892
|
+
defaultMessage: "An error occurred while trying to delete the document."
|
2893
|
+
}),
|
2894
|
+
type: "danger"
|
2895
|
+
});
|
2896
|
+
return;
|
2897
|
+
}
|
2898
|
+
const res = await deleteAction({
|
2899
|
+
documentId,
|
2900
|
+
model,
|
2901
|
+
collectionType,
|
2902
|
+
params: {
|
2903
|
+
locale: "*"
|
2904
|
+
}
|
2905
|
+
});
|
2906
|
+
if (!("error" in res)) {
|
2907
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2908
|
+
}
|
2909
|
+
} finally {
|
2910
|
+
if (!listViewPathMatch) {
|
2911
|
+
setSubmitting(false);
|
2912
|
+
}
|
2913
|
+
}
|
2825
2914
|
}
|
2826
|
-
const { edit: metadata } = metadatas[field.name];
|
2827
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2828
|
-
return {
|
2829
|
-
attribute,
|
2830
|
-
disabled: !metadata.editable,
|
2831
|
-
hint: metadata.description,
|
2832
|
-
label: metadata.label ?? "",
|
2833
|
-
name: field.name,
|
2834
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2835
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2836
|
-
schemas,
|
2837
|
-
components: components?.schemas ?? {}
|
2838
|
-
}),
|
2839
|
-
placeholder: metadata.placeholder ?? "",
|
2840
|
-
required: attribute.required ?? false,
|
2841
|
-
size: field.size,
|
2842
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2843
|
-
visible: metadata.visible ?? true,
|
2844
|
-
type: attribute.type
|
2845
|
-
};
|
2846
|
-
}).filter((field) => field !== null)
|
2847
|
-
);
|
2848
|
-
};
|
2849
|
-
const formatListLayout = (data, {
|
2850
|
-
schemas,
|
2851
|
-
schema,
|
2852
|
-
components
|
2853
|
-
}) => {
|
2854
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2855
|
-
(acc, [attribute, metadata]) => {
|
2856
|
-
return {
|
2857
|
-
...acc,
|
2858
|
-
[attribute]: metadata.list
|
2859
|
-
};
|
2860
2915
|
},
|
2861
|
-
|
2862
|
-
|
2863
|
-
|
2864
|
-
|
2865
|
-
|
2866
|
-
|
2867
|
-
|
2868
|
-
|
2869
|
-
|
2870
|
-
|
2871
|
-
|
2872
|
-
|
2873
|
-
|
2874
|
-
|
2875
|
-
|
2876
|
-
|
2877
|
-
|
2916
|
+
variant: "danger",
|
2917
|
+
position: ["header", "table-row"]
|
2918
|
+
};
|
2919
|
+
};
|
2920
|
+
DeleteAction$1.type = "delete";
|
2921
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2922
|
+
const Panels = () => {
|
2923
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2924
|
+
const [
|
2925
|
+
{
|
2926
|
+
query: { status }
|
2927
|
+
}
|
2928
|
+
] = useQueryParams({
|
2929
|
+
status: "draft"
|
2930
|
+
});
|
2931
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2932
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2933
|
+
const props = {
|
2934
|
+
activeTab: status,
|
2935
|
+
model,
|
2936
|
+
documentId: id,
|
2937
|
+
document: isCloning ? void 0 : document,
|
2938
|
+
meta: isCloning ? void 0 : meta,
|
2939
|
+
collectionType
|
2940
|
+
};
|
2941
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2942
|
+
DescriptionComponentRenderer,
|
2943
|
+
{
|
2944
|
+
props,
|
2945
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2946
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2878
2947
|
}
|
2948
|
+
) });
|
2949
|
+
};
|
2950
|
+
const ActionsPanel = () => {
|
2951
|
+
const { formatMessage } = useIntl();
|
2952
|
+
return {
|
2953
|
+
title: formatMessage({
|
2954
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2955
|
+
defaultMessage: "Entry"
|
2956
|
+
}),
|
2957
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2879
2958
|
};
|
2880
2959
|
};
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
2885
|
-
|
2960
|
+
ActionsPanel.type = "actions";
|
2961
|
+
const ActionsPanelContent = () => {
|
2962
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2963
|
+
const [
|
2964
|
+
{
|
2965
|
+
query: { status = "draft" }
|
2886
2966
|
}
|
2887
|
-
|
2888
|
-
|
2889
|
-
|
2890
|
-
|
2891
|
-
|
2892
|
-
|
2893
|
-
|
2894
|
-
|
2895
|
-
|
2896
|
-
|
2897
|
-
|
2898
|
-
|
2899
|
-
|
2900
|
-
|
2967
|
+
] = useQueryParams();
|
2968
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2969
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2970
|
+
const props = {
|
2971
|
+
activeTab: status,
|
2972
|
+
model,
|
2973
|
+
documentId: id,
|
2974
|
+
document: isCloning ? void 0 : document,
|
2975
|
+
meta: isCloning ? void 0 : meta,
|
2976
|
+
collectionType
|
2977
|
+
};
|
2978
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2979
|
+
/* @__PURE__ */ jsx(
|
2980
|
+
DescriptionComponentRenderer,
|
2981
|
+
{
|
2982
|
+
props,
|
2983
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2984
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2985
|
+
}
|
2986
|
+
),
|
2987
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2988
|
+
] });
|
2901
2989
|
};
|
2990
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2991
|
+
return /* @__PURE__ */ jsxs(
|
2992
|
+
Flex,
|
2993
|
+
{
|
2994
|
+
ref,
|
2995
|
+
tag: "aside",
|
2996
|
+
"aria-labelledby": "additional-information",
|
2997
|
+
background: "neutral0",
|
2998
|
+
borderColor: "neutral150",
|
2999
|
+
hasRadius: true,
|
3000
|
+
paddingBottom: 4,
|
3001
|
+
paddingLeft: 4,
|
3002
|
+
paddingRight: 4,
|
3003
|
+
paddingTop: 4,
|
3004
|
+
shadow: "tableShadow",
|
3005
|
+
gap: 3,
|
3006
|
+
direction: "column",
|
3007
|
+
justifyContent: "stretch",
|
3008
|
+
alignItems: "flex-start",
|
3009
|
+
children: [
|
3010
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3011
|
+
children
|
3012
|
+
]
|
3013
|
+
}
|
3014
|
+
);
|
3015
|
+
});
|
2902
3016
|
const ConfirmBulkActionDialog = ({
|
2903
3017
|
onToggleDialog,
|
2904
3018
|
isOpen = false,
|
@@ -3895,7 +4009,7 @@ const index = {
|
|
3895
4009
|
app.router.addRoute({
|
3896
4010
|
path: "content-manager/*",
|
3897
4011
|
lazy: async () => {
|
3898
|
-
const { Layout } = await import("./layout-
|
4012
|
+
const { Layout } = await import("./layout-2CfjL0T9.mjs");
|
3899
4013
|
return {
|
3900
4014
|
Component: Layout
|
3901
4015
|
};
|
@@ -3912,7 +4026,7 @@ const index = {
|
|
3912
4026
|
async registerTrads({ locales }) {
|
3913
4027
|
const importedTrads = await Promise.all(
|
3914
4028
|
locales.map((locale) => {
|
3915
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-
|
4029
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-DKV44jRb.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
|
3916
4030
|
return {
|
3917
4031
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3918
4032
|
locale
|
@@ -3940,7 +4054,8 @@ export {
|
|
3940
4054
|
InjectionZone as I,
|
3941
4055
|
useDocument as J,
|
3942
4056
|
index as K,
|
3943
|
-
|
4057
|
+
useContentManagerContext as L,
|
4058
|
+
useDocumentActions as M,
|
3944
4059
|
Panels as P,
|
3945
4060
|
RelativeTime as R,
|
3946
4061
|
SINGLE_TYPES as S,
|
@@ -3972,4 +4087,4 @@ export {
|
|
3972
4087
|
capitalise as y,
|
3973
4088
|
useUpdateContentTypeConfigurationMutation as z
|
3974
4089
|
};
|
3975
|
-
//# sourceMappingURL=index-
|
4090
|
+
//# sourceMappingURL=index-wnqzm4Q8.mjs.map
|