@strapi/content-manager 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78 → 0.0.0-experimental.fb442e5e12dd3f611303691bf85a249520ba348b
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs → ComponentConfigurationPage-B3yDbeU1.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs.map → ComponentConfigurationPage-B3yDbeU1.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js → ComponentConfigurationPage-KXSuLnQD.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js.map → ComponentConfigurationPage-KXSuLnQD.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js → EditConfigurationPage-BQ17--5R.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js.map → EditConfigurationPage-BQ17--5R.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs → EditConfigurationPage-D7PrLO8j.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs.map → EditConfigurationPage-D7PrLO8j.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-dFPBya9U.mjs → EditViewPage-B7VgwJaG.mjs} +57 -46
- package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-ChgloMyO.js → EditViewPage-BgjdnGz2.js} +56 -45
- package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +1 -0
- package/dist/_chunks/{Field-dLk-vgLL.js → Field-CdK7ZLmv.js} +504 -165
- package/dist/_chunks/Field-CdK7ZLmv.js.map +1 -0
- package/dist/_chunks/{Field-C1nUKcdS.mjs → Field-tHCw4lGA.mjs} +505 -166
- package/dist/_chunks/Field-tHCw4lGA.mjs.map +1 -0
- package/dist/_chunks/{Form-DOlpi7Js.mjs → Form-BJxdTv3Q.mjs} +40 -30
- package/dist/_chunks/Form-BJxdTv3Q.mjs.map +1 -0
- package/dist/_chunks/{Form-CbXtmHC_.js → Form-C_0KTVvV.js} +38 -28
- package/dist/_chunks/Form-C_0KTVvV.js.map +1 -0
- package/dist/_chunks/{History-BFNUAiGc.mjs → History-DR2txJLE.mjs} +142 -37
- package/dist/_chunks/History-DR2txJLE.mjs.map +1 -0
- package/dist/_chunks/{History-BjDfohBr.js → History-nuEzM5qm.js} +141 -36
- package/dist/_chunks/History-nuEzM5qm.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-IQBgWTaa.js → ListConfigurationPage-CnB86Psm.js} +57 -46
- package/dist/_chunks/ListConfigurationPage-CnB86Psm.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DDi0KqFm.mjs → ListConfigurationPage-voFVtXu6.mjs} +58 -48
- package/dist/_chunks/ListConfigurationPage-voFVtXu6.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BPjljUsH.mjs → ListViewPage-B_GaWgRH.mjs} +80 -71
- package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CZYGqlvF.js → ListViewPage-SXIXm-RM.js} +78 -69
- package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js → NoContentTypePage-BzsQ3hLZ.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js.map → NoContentTypePage-BzsQ3hLZ.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs → NoContentTypePage-CYiGpsbj.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs.map → NoContentTypePage-CYiGpsbj.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs → NoPermissionsPage-B5baIHal.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs.map → NoPermissionsPage-B5baIHal.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js → NoPermissionsPage-IGkId4C5.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js.map → NoPermissionsPage-IGkId4C5.js.map} +1 -1
- package/dist/_chunks/{Relations-DTowyge2.mjs → Relations-CIYDdKU-.mjs} +5 -5
- package/dist/_chunks/Relations-CIYDdKU-.mjs.map +1 -0
- package/dist/_chunks/{Relations-DU6B7irU.js → Relations-Dhuurpx2.js} +5 -5
- package/dist/_chunks/Relations-Dhuurpx2.js.map +1 -0
- package/dist/_chunks/{en-GCOTL6jR.mjs → en-BrCTWlZv.mjs} +9 -4
- package/dist/_chunks/{en-GCOTL6jR.mjs.map → en-BrCTWlZv.mjs.map} +1 -1
- package/dist/_chunks/{en-DTULi5-d.js → en-uOUIxfcQ.js} +9 -4
- package/dist/_chunks/{en-DTULi5-d.js.map → en-uOUIxfcQ.js.map} +1 -1
- package/dist/_chunks/{index-BaGHmIir.mjs → index-C9TJPyni.mjs} +1542 -1063
- package/dist/_chunks/index-C9TJPyni.mjs.map +1 -0
- package/dist/_chunks/{index-CCJeB7Rw.js → index-CdT0kHZ8.js} +1510 -1031
- package/dist/_chunks/index-CdT0kHZ8.js.map +1 -0
- package/dist/_chunks/{layout-BinjszSQ.mjs → layout-BNqvLR_b.mjs} +39 -22
- package/dist/_chunks/layout-BNqvLR_b.mjs.map +1 -0
- package/dist/_chunks/{layout-ni_L9kT1.js → layout-C6dxWYT7.js} +37 -20
- package/dist/_chunks/layout-C6dxWYT7.js.map +1 -0
- package/dist/_chunks/{relations-c91ji5eR.mjs → relations-CkKqKw65.mjs} +2 -2
- package/dist/_chunks/{relations-c91ji5eR.mjs.map → relations-CkKqKw65.mjs.map} +1 -1
- package/dist/_chunks/{relations-CeJAJc5I.js → relations-DtFaDnP1.js} +2 -2
- package/dist/_chunks/{relations-CeJAJc5I.js.map → relations-DtFaDnP1.js.map} +1 -1
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +8 -8
- package/dist/admin/src/history/components/VersionInputRenderer.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/hooks/useDocumentActions.d.ts +1 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +12 -32
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- package/dist/admin/src/pages/ListView/components/BulkActions/PublishAction.d.ts +14 -0
- package/dist/server/index.js +147 -93
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +148 -94
- 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/single-types.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +1 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/package.json +8 -8
- package/dist/_chunks/EditViewPage-ChgloMyO.js.map +0 -1
- package/dist/_chunks/EditViewPage-dFPBya9U.mjs.map +0 -1
- package/dist/_chunks/Field-C1nUKcdS.mjs.map +0 -1
- package/dist/_chunks/Field-dLk-vgLL.js.map +0 -1
- package/dist/_chunks/Form-CbXtmHC_.js.map +0 -1
- package/dist/_chunks/Form-DOlpi7Js.mjs.map +0 -1
- package/dist/_chunks/History-BFNUAiGc.mjs.map +0 -1
- package/dist/_chunks/History-BjDfohBr.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DDi0KqFm.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-IQBgWTaa.js.map +0 -1
- package/dist/_chunks/ListViewPage-BPjljUsH.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-CZYGqlvF.js.map +0 -1
- package/dist/_chunks/Relations-DTowyge2.mjs.map +0 -1
- package/dist/_chunks/Relations-DU6B7irU.js.map +0 -1
- package/dist/_chunks/index-BaGHmIir.mjs.map +0 -1
- package/dist/_chunks/index-CCJeB7Rw.js.map +0 -1
- package/dist/_chunks/layout-BinjszSQ.mjs.map +0 -1
- package/dist/_chunks/layout-ni_L9kT1.js.map +0 -1
@@ -1,17 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { CrossCircle, More, WarningCircle, ListPlus, Pencil, Trash, Check, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useQueryParams, useTracking, useForm, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
7
4
|
import * as React from "react";
|
8
5
|
import { lazy } from "react";
|
9
|
-
import { Menu, VisuallyHidden, Flex, Typography, Dialog,
|
6
|
+
import { Menu, Button, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, Loader, IconButton, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import { useIntl } from "react-intl";
|
8
|
+
import { useParams, Navigate, useNavigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
10
9
|
import { styled } from "styled-components";
|
11
10
|
import * as yup from "yup";
|
12
11
|
import { ValidationError } from "yup";
|
13
12
|
import pipe from "lodash/fp/pipe";
|
14
13
|
import { intervalToDuration, isPast } from "date-fns";
|
14
|
+
import { stringify } from "qs";
|
15
15
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
16
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
17
|
const v = glob[path];
|
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
|
|
49
49
|
const [page, position] = area.split(".");
|
50
50
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
51
51
|
};
|
52
|
-
const HistoryAction = ({ model, document }) => {
|
53
|
-
const { formatMessage } = useIntl();
|
54
|
-
const [{ query }] = useQueryParams();
|
55
|
-
const navigate = useNavigate();
|
56
|
-
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
57
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
58
|
-
return null;
|
59
|
-
}
|
60
|
-
return {
|
61
|
-
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
62
|
-
label: formatMessage({
|
63
|
-
id: "content-manager.history.document-action",
|
64
|
-
defaultMessage: "Content History"
|
65
|
-
}),
|
66
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
67
|
-
disabled: (
|
68
|
-
/**
|
69
|
-
* The user is creating a new document.
|
70
|
-
* It hasn't been saved yet, so there's no history to go to
|
71
|
-
*/
|
72
|
-
!document || /**
|
73
|
-
* The document has been created but the current dimension has never been saved.
|
74
|
-
* For example, the user is creating a new locale in an existing document,
|
75
|
-
* so there's no history for the document in that locale
|
76
|
-
*/
|
77
|
-
!document.id || /**
|
78
|
-
* History is only available for content types created by the user.
|
79
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
80
|
-
* which start with `admin::` or `plugin::`
|
81
|
-
*/
|
82
|
-
!model.startsWith("api::")
|
83
|
-
),
|
84
|
-
position: "header"
|
85
|
-
};
|
86
|
-
};
|
87
|
-
HistoryAction.type = "history";
|
88
52
|
const ID = "id";
|
89
53
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
90
54
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -198,6 +162,7 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
198
162
|
]
|
199
163
|
});
|
200
164
|
const documentApi = contentManagerApi.injectEndpoints({
|
165
|
+
overrideExisting: true,
|
201
166
|
endpoints: (builder) => ({
|
202
167
|
autoCloneDocument: builder.mutation({
|
203
168
|
query: ({ model, sourceId, query }) => ({
|
@@ -207,7 +172,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
207
172
|
params: query
|
208
173
|
}
|
209
174
|
}),
|
210
|
-
invalidatesTags: (_result,
|
175
|
+
invalidatesTags: (_result, error, { model }) => {
|
176
|
+
if (error) {
|
177
|
+
return [];
|
178
|
+
}
|
179
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
180
|
+
}
|
211
181
|
}),
|
212
182
|
cloneDocument: builder.mutation({
|
213
183
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -294,6 +264,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
294
264
|
}),
|
295
265
|
providesTags: (result, _error, arg) => {
|
296
266
|
return [
|
267
|
+
{ type: "Document", id: `ALL_LIST` },
|
297
268
|
{ type: "Document", id: `${arg.model}_LIST` },
|
298
269
|
...result?.results.map(({ documentId }) => ({
|
299
270
|
type: "Document",
|
@@ -332,6 +303,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
332
303
|
{
|
333
304
|
type: "Document",
|
334
305
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
306
|
+
},
|
307
|
+
// Make it easy to invalidate all individual documents queries for a model
|
308
|
+
{
|
309
|
+
type: "Document",
|
310
|
+
id: `${model}_ALL_ITEMS`
|
335
311
|
}
|
336
312
|
];
|
337
313
|
}
|
@@ -397,6 +373,18 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
397
373
|
},
|
398
374
|
"Relations"
|
399
375
|
];
|
376
|
+
},
|
377
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
378
|
+
const patchResult = dispatch(
|
379
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
380
|
+
Object.assign(draft.data, data);
|
381
|
+
})
|
382
|
+
);
|
383
|
+
try {
|
384
|
+
await queryFulfilled;
|
385
|
+
} catch {
|
386
|
+
patchResult.undo();
|
387
|
+
}
|
400
388
|
}
|
401
389
|
}),
|
402
390
|
unpublishDocument: builder.mutation({
|
@@ -580,6 +568,14 @@ const createAttributeSchema = (attribute) => {
|
|
580
568
|
if (!value || typeof value === "string" && value.length === 0) {
|
581
569
|
return true;
|
582
570
|
}
|
571
|
+
if (typeof value === "object") {
|
572
|
+
try {
|
573
|
+
JSON.stringify(value);
|
574
|
+
return true;
|
575
|
+
} catch (err) {
|
576
|
+
return false;
|
577
|
+
}
|
578
|
+
}
|
583
579
|
try {
|
584
580
|
JSON.parse(value);
|
585
581
|
return true;
|
@@ -599,11 +595,11 @@ const createAttributeSchema = (attribute) => {
|
|
599
595
|
}
|
600
596
|
};
|
601
597
|
const addRequiredValidation = (attribute) => (schema) => {
|
602
|
-
if (attribute.required) {
|
603
|
-
return schema.required
|
604
|
-
|
605
|
-
|
606
|
-
|
598
|
+
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
599
|
+
return schema.min(1, translatedErrors.required);
|
600
|
+
}
|
601
|
+
if (attribute.required && attribute.type !== "relation") {
|
602
|
+
return schema.required(translatedErrors.required);
|
607
603
|
}
|
608
604
|
return schema?.nullable ? schema.nullable() : (
|
609
605
|
// In some cases '.nullable' will not be available on the schema.
|
@@ -637,6 +633,28 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
637
633
|
const addMinValidation = (attribute) => (schema) => {
|
638
634
|
if ("min" in attribute) {
|
639
635
|
const min = toInteger(attribute.min);
|
636
|
+
if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
|
637
|
+
if (!attribute.required && "test" in schema && min) {
|
638
|
+
return schema.test(
|
639
|
+
"custom-min",
|
640
|
+
{
|
641
|
+
...translatedErrors.min,
|
642
|
+
values: {
|
643
|
+
min: attribute.min
|
644
|
+
}
|
645
|
+
},
|
646
|
+
(value) => {
|
647
|
+
if (!value) {
|
648
|
+
return true;
|
649
|
+
}
|
650
|
+
if (Array.isArray(value) && value.length === 0) {
|
651
|
+
return true;
|
652
|
+
}
|
653
|
+
return value.length >= min;
|
654
|
+
}
|
655
|
+
);
|
656
|
+
}
|
657
|
+
}
|
640
658
|
if ("min" in schema && min) {
|
641
659
|
return schema.min(min, {
|
642
660
|
...translatedErrors.min,
|
@@ -763,7 +781,10 @@ const useDocument = (args, opts) => {
|
|
763
781
|
isLoading: isLoadingDocument,
|
764
782
|
isFetching: isFetchingDocument,
|
765
783
|
error
|
766
|
-
} = useGetDocumentQuery(args,
|
784
|
+
} = useGetDocumentQuery(args, {
|
785
|
+
...opts,
|
786
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
787
|
+
});
|
767
788
|
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
768
789
|
React.useEffect(() => {
|
769
790
|
if (error) {
|
@@ -927,12 +948,13 @@ const useDocumentActions = () => {
|
|
927
948
|
);
|
928
949
|
const [discardDocument] = useDiscardDocumentMutation();
|
929
950
|
const discard = React.useCallback(
|
930
|
-
async ({ collectionType, model, documentId }) => {
|
951
|
+
async ({ collectionType, model, documentId, params }) => {
|
931
952
|
try {
|
932
953
|
const res = await discardDocument({
|
933
954
|
collectionType,
|
934
955
|
model,
|
935
|
-
documentId
|
956
|
+
documentId,
|
957
|
+
params
|
936
958
|
});
|
937
959
|
if ("error" in res) {
|
938
960
|
toggleNotification({
|
@@ -1183,7 +1205,6 @@ const useDocumentActions = () => {
|
|
1183
1205
|
sourceId
|
1184
1206
|
});
|
1185
1207
|
if ("error" in res) {
|
1186
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1187
1208
|
return { error: res.error };
|
1188
1209
|
}
|
1189
1210
|
toggleNotification({
|
@@ -1264,7 +1285,7 @@ const useDocumentActions = () => {
|
|
1264
1285
|
};
|
1265
1286
|
};
|
1266
1287
|
const ProtectedHistoryPage = lazy(
|
1267
|
-
() => import("./History-
|
1288
|
+
() => import("./History-DR2txJLE.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1268
1289
|
);
|
1269
1290
|
const routes$1 = [
|
1270
1291
|
{
|
@@ -1277,31 +1298,31 @@ const routes$1 = [
|
|
1277
1298
|
}
|
1278
1299
|
];
|
1279
1300
|
const ProtectedEditViewPage = lazy(
|
1280
|
-
() => import("./EditViewPage-
|
1301
|
+
() => import("./EditViewPage-B7VgwJaG.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1281
1302
|
);
|
1282
1303
|
const ProtectedListViewPage = lazy(
|
1283
|
-
() => import("./ListViewPage-
|
1304
|
+
() => import("./ListViewPage-B_GaWgRH.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1284
1305
|
);
|
1285
1306
|
const ProtectedListConfiguration = lazy(
|
1286
|
-
() => import("./ListConfigurationPage-
|
1307
|
+
() => import("./ListConfigurationPage-voFVtXu6.mjs").then((mod) => ({
|
1287
1308
|
default: mod.ProtectedListConfiguration
|
1288
1309
|
}))
|
1289
1310
|
);
|
1290
1311
|
const ProtectedEditConfigurationPage = lazy(
|
1291
|
-
() => import("./EditConfigurationPage-
|
1312
|
+
() => import("./EditConfigurationPage-D7PrLO8j.mjs").then((mod) => ({
|
1292
1313
|
default: mod.ProtectedEditConfigurationPage
|
1293
1314
|
}))
|
1294
1315
|
);
|
1295
1316
|
const ProtectedComponentConfigurationPage = lazy(
|
1296
|
-
() => import("./ComponentConfigurationPage-
|
1317
|
+
() => import("./ComponentConfigurationPage-B3yDbeU1.mjs").then((mod) => ({
|
1297
1318
|
default: mod.ProtectedComponentConfigurationPage
|
1298
1319
|
}))
|
1299
1320
|
);
|
1300
1321
|
const NoPermissions = lazy(
|
1301
|
-
() => import("./NoPermissionsPage-
|
1322
|
+
() => import("./NoPermissionsPage-B5baIHal.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1302
1323
|
);
|
1303
1324
|
const NoContentType = lazy(
|
1304
|
-
() => import("./NoContentTypePage-
|
1325
|
+
() => import("./NoContentTypePage-CYiGpsbj.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1305
1326
|
);
|
1306
1327
|
const CollectionTypePages = () => {
|
1307
1328
|
const { collectionType } = useParams();
|
@@ -1415,12 +1436,14 @@ const DocumentActionButton = (action) => {
|
|
1415
1436
|
/* @__PURE__ */ jsx(
|
1416
1437
|
Button,
|
1417
1438
|
{
|
1418
|
-
flex:
|
1439
|
+
flex: "auto",
|
1419
1440
|
startIcon: action.icon,
|
1420
1441
|
disabled: action.disabled,
|
1421
1442
|
onClick: handleClick(action),
|
1422
1443
|
justifyContent: "center",
|
1423
1444
|
variant: action.variant || "default",
|
1445
|
+
paddingTop: "7px",
|
1446
|
+
paddingBottom: "7px",
|
1424
1447
|
children: action.label
|
1425
1448
|
}
|
1426
1449
|
),
|
@@ -1428,7 +1451,7 @@ const DocumentActionButton = (action) => {
|
|
1428
1451
|
DocumentActionConfirmDialog,
|
1429
1452
|
{
|
1430
1453
|
...action.dialog,
|
1431
|
-
variant: action.variant,
|
1454
|
+
variant: action.dialog?.variant ?? action.variant,
|
1432
1455
|
isOpen: dialogId === action.id,
|
1433
1456
|
onClose: handleClose
|
1434
1457
|
}
|
@@ -1480,14 +1503,14 @@ const DocumentActionsMenu = ({
|
|
1480
1503
|
};
|
1481
1504
|
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1482
1505
|
/* @__PURE__ */ jsxs(
|
1483
|
-
|
1506
|
+
StyledMoreButton,
|
1484
1507
|
{
|
1485
1508
|
disabled: isDisabled,
|
1486
1509
|
size: "S",
|
1487
1510
|
endIcon: null,
|
1488
|
-
paddingTop: "
|
1489
|
-
paddingLeft: "
|
1490
|
-
paddingRight: "
|
1511
|
+
paddingTop: "4px",
|
1512
|
+
paddingLeft: "7px",
|
1513
|
+
paddingRight: "7px",
|
1491
1514
|
variant,
|
1492
1515
|
children: [
|
1493
1516
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1507,10 +1530,25 @@ const DocumentActionsMenu = ({
|
|
1507
1530
|
onSelect: handleClick(action),
|
1508
1531
|
display: "block",
|
1509
1532
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1510
|
-
/* @__PURE__ */ jsxs(
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1533
|
+
/* @__PURE__ */ jsxs(
|
1534
|
+
Flex,
|
1535
|
+
{
|
1536
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1537
|
+
gap: 2,
|
1538
|
+
tag: "span",
|
1539
|
+
children: [
|
1540
|
+
/* @__PURE__ */ jsx(
|
1541
|
+
Flex,
|
1542
|
+
{
|
1543
|
+
tag: "span",
|
1544
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1545
|
+
children: action.icon
|
1546
|
+
}
|
1547
|
+
),
|
1548
|
+
action.label
|
1549
|
+
]
|
1550
|
+
}
|
1551
|
+
),
|
1514
1552
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1515
1553
|
Flex,
|
1516
1554
|
{
|
@@ -1569,6 +1607,23 @@ const convertActionVariantToColor = (variant = "secondary") => {
|
|
1569
1607
|
return "primary600";
|
1570
1608
|
}
|
1571
1609
|
};
|
1610
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1611
|
+
switch (variant) {
|
1612
|
+
case "danger":
|
1613
|
+
return "danger600";
|
1614
|
+
case "secondary":
|
1615
|
+
return "neutral500";
|
1616
|
+
case "success":
|
1617
|
+
return "success600";
|
1618
|
+
default:
|
1619
|
+
return "primary600";
|
1620
|
+
}
|
1621
|
+
};
|
1622
|
+
const StyledMoreButton = styled(Menu.Trigger)`
|
1623
|
+
& > span {
|
1624
|
+
display: flex;
|
1625
|
+
}
|
1626
|
+
`;
|
1572
1627
|
const DocumentActionConfirmDialog = ({
|
1573
1628
|
onClose,
|
1574
1629
|
onCancel,
|
@@ -1591,22 +1646,20 @@ const DocumentActionConfirmDialog = ({
|
|
1591
1646
|
}
|
1592
1647
|
onClose();
|
1593
1648
|
};
|
1594
|
-
return /* @__PURE__ */
|
1595
|
-
/* @__PURE__ */ jsx(
|
1596
|
-
/* @__PURE__ */ jsx(
|
1597
|
-
|
1598
|
-
{
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
)
|
1609
|
-
] });
|
1649
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
1650
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1651
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1652
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1653
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
1654
|
+
id: "app.components.Button.cancel",
|
1655
|
+
defaultMessage: "Cancel"
|
1656
|
+
}) }) }),
|
1657
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1658
|
+
id: "app.components.Button.confirm",
|
1659
|
+
defaultMessage: "Confirm"
|
1660
|
+
}) })
|
1661
|
+
] })
|
1662
|
+
] }) });
|
1610
1663
|
};
|
1611
1664
|
const DocumentActionModal = ({
|
1612
1665
|
isOpen,
|
@@ -1616,36 +1669,19 @@ const DocumentActionModal = ({
|
|
1616
1669
|
content: Content,
|
1617
1670
|
onModalClose
|
1618
1671
|
}) => {
|
1619
|
-
const id = React.useId();
|
1620
|
-
if (!isOpen) {
|
1621
|
-
return null;
|
1622
|
-
}
|
1623
1672
|
const handleClose = () => {
|
1624
1673
|
if (onClose) {
|
1625
1674
|
onClose();
|
1626
1675
|
}
|
1627
1676
|
onModalClose();
|
1628
1677
|
};
|
1629
|
-
return /* @__PURE__ */
|
1630
|
-
/* @__PURE__ */ jsx(
|
1631
|
-
|
1632
|
-
/* @__PURE__ */ jsx(
|
1633
|
-
|
1634
|
-
{
|
1635
|
-
paddingTop: 4,
|
1636
|
-
paddingBottom: 4,
|
1637
|
-
paddingLeft: 5,
|
1638
|
-
paddingRight: 5,
|
1639
|
-
borderWidth: "1px 0 0 0",
|
1640
|
-
borderStyle: "solid",
|
1641
|
-
borderColor: "neutral150",
|
1642
|
-
background: "neutral100",
|
1643
|
-
children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1644
|
-
}
|
1645
|
-
)
|
1646
|
-
] });
|
1678
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1679
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1680
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
1681
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1682
|
+
] }) });
|
1647
1683
|
};
|
1648
|
-
const PublishAction = ({
|
1684
|
+
const PublishAction$1 = ({
|
1649
1685
|
activeTab,
|
1650
1686
|
documentId,
|
1651
1687
|
model,
|
@@ -1664,6 +1700,12 @@ const PublishAction = ({
|
|
1664
1700
|
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1665
1701
|
);
|
1666
1702
|
const { publish } = useDocumentActions();
|
1703
|
+
const [
|
1704
|
+
countDraftRelations,
|
1705
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1706
|
+
] = useLazyGetDraftRelationCountQuery();
|
1707
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
1708
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1667
1709
|
const [{ query, rawQuery }] = useQueryParams();
|
1668
1710
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1669
1711
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1672,10 +1714,101 @@ const PublishAction = ({
|
|
1672
1714
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1673
1715
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1674
1716
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1717
|
+
React.useEffect(() => {
|
1718
|
+
if (isErrorDraftRelations) {
|
1719
|
+
toggleNotification({
|
1720
|
+
type: "danger",
|
1721
|
+
message: formatMessage({
|
1722
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
1723
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1724
|
+
})
|
1725
|
+
});
|
1726
|
+
}
|
1727
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1728
|
+
React.useEffect(() => {
|
1729
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
1730
|
+
const extractDraftRelations = (data) => {
|
1731
|
+
const relations = data.connect || [];
|
1732
|
+
relations.forEach((relation) => {
|
1733
|
+
if (relation.status === "draft") {
|
1734
|
+
localDraftRelations.add(relation.id);
|
1735
|
+
}
|
1736
|
+
});
|
1737
|
+
};
|
1738
|
+
const traverseAndExtract = (data) => {
|
1739
|
+
Object.entries(data).forEach(([key, value]) => {
|
1740
|
+
if (key === "connect" && Array.isArray(value)) {
|
1741
|
+
extractDraftRelations({ connect: value });
|
1742
|
+
} else if (typeof value === "object" && value !== null) {
|
1743
|
+
traverseAndExtract(value);
|
1744
|
+
}
|
1745
|
+
});
|
1746
|
+
};
|
1747
|
+
if (!documentId || modified) {
|
1748
|
+
traverseAndExtract(formValues);
|
1749
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1750
|
+
}
|
1751
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1752
|
+
React.useEffect(() => {
|
1753
|
+
if (documentId) {
|
1754
|
+
const fetchDraftRelationsCount = async () => {
|
1755
|
+
const { data, error } = await countDraftRelations({
|
1756
|
+
collectionType,
|
1757
|
+
model,
|
1758
|
+
documentId,
|
1759
|
+
params
|
1760
|
+
});
|
1761
|
+
if (error) {
|
1762
|
+
throw error;
|
1763
|
+
}
|
1764
|
+
if (data) {
|
1765
|
+
setServerCountOfDraftRelations(data.data);
|
1766
|
+
}
|
1767
|
+
};
|
1768
|
+
fetchDraftRelationsCount();
|
1769
|
+
}
|
1770
|
+
}, [documentId, countDraftRelations, collectionType, model, params]);
|
1675
1771
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1676
1772
|
if (!schema?.options?.draftAndPublish) {
|
1677
1773
|
return null;
|
1678
1774
|
}
|
1775
|
+
const performPublish = async () => {
|
1776
|
+
setSubmitting(true);
|
1777
|
+
try {
|
1778
|
+
const { errors } = await validate();
|
1779
|
+
if (errors) {
|
1780
|
+
toggleNotification({
|
1781
|
+
type: "danger",
|
1782
|
+
message: formatMessage({
|
1783
|
+
id: "content-manager.validation.error",
|
1784
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1785
|
+
})
|
1786
|
+
});
|
1787
|
+
return;
|
1788
|
+
}
|
1789
|
+
const res = await publish(
|
1790
|
+
{
|
1791
|
+
collectionType,
|
1792
|
+
model,
|
1793
|
+
documentId,
|
1794
|
+
params
|
1795
|
+
},
|
1796
|
+
formValues
|
1797
|
+
);
|
1798
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1799
|
+
navigate({
|
1800
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1801
|
+
search: rawQuery
|
1802
|
+
});
|
1803
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1804
|
+
setErrors(formatValidationErrors(res.error));
|
1805
|
+
}
|
1806
|
+
} finally {
|
1807
|
+
setSubmitting(false);
|
1808
|
+
}
|
1809
|
+
};
|
1810
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1811
|
+
const hasDraftRelations = totalDraftRelations > 0;
|
1679
1812
|
return {
|
1680
1813
|
/**
|
1681
1814
|
* Disabled when:
|
@@ -1685,52 +1818,42 @@ const PublishAction = ({
|
|
1685
1818
|
* - the document is already published & not modified
|
1686
1819
|
* - the document is being created & not modified
|
1687
1820
|
* - the user doesn't have the permission to publish
|
1688
|
-
* - the user doesn't have the permission to create a new document
|
1689
|
-
* - the user doesn't have the permission to update the document
|
1690
1821
|
*/
|
1691
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
1822
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1692
1823
|
label: formatMessage({
|
1693
1824
|
id: "app.utils.publish",
|
1694
1825
|
defaultMessage: "Publish"
|
1695
1826
|
}),
|
1696
1827
|
onClick: async () => {
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
formValues
|
1718
|
-
);
|
1719
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1720
|
-
navigate({
|
1721
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1722
|
-
search: rawQuery
|
1723
|
-
});
|
1724
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1725
|
-
setErrors(formatValidationErrors(res.error));
|
1828
|
+
if (hasDraftRelations) {
|
1829
|
+
return;
|
1830
|
+
}
|
1831
|
+
await performPublish();
|
1832
|
+
},
|
1833
|
+
dialog: hasDraftRelations ? {
|
1834
|
+
type: "dialog",
|
1835
|
+
variant: "danger",
|
1836
|
+
footer: null,
|
1837
|
+
title: formatMessage({
|
1838
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1839
|
+
defaultMessage: "Confirmation"
|
1840
|
+
}),
|
1841
|
+
content: formatMessage(
|
1842
|
+
{
|
1843
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1844
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1845
|
+
},
|
1846
|
+
{
|
1847
|
+
count: totalDraftRelations
|
1726
1848
|
}
|
1727
|
-
|
1728
|
-
|
1849
|
+
),
|
1850
|
+
onConfirm: async () => {
|
1851
|
+
await performPublish();
|
1729
1852
|
}
|
1730
|
-
}
|
1853
|
+
} : void 0
|
1731
1854
|
};
|
1732
1855
|
};
|
1733
|
-
PublishAction.type = "publish";
|
1856
|
+
PublishAction$1.type = "publish";
|
1734
1857
|
const UpdateAction = ({
|
1735
1858
|
activeTab,
|
1736
1859
|
documentId,
|
@@ -1743,7 +1866,7 @@ const UpdateAction = ({
|
|
1743
1866
|
const cloneMatch = useMatch(CLONE_PATH);
|
1744
1867
|
const isCloning = cloneMatch !== null;
|
1745
1868
|
const { formatMessage } = useIntl();
|
1746
|
-
|
1869
|
+
useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1747
1870
|
canCreate: canCreate2,
|
1748
1871
|
canUpdate: canUpdate2
|
1749
1872
|
}));
|
@@ -1763,10 +1886,8 @@ const UpdateAction = ({
|
|
1763
1886
|
* - the form is submitting
|
1764
1887
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1765
1888
|
* - the active tab is the published tab
|
1766
|
-
* - the user doesn't have the permission to create a new document
|
1767
|
-
* - the user doesn't have the permission to update the document
|
1768
1889
|
*/
|
1769
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
1890
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1770
1891
|
label: formatMessage({
|
1771
1892
|
id: "content-manager.containers.Edit.save",
|
1772
1893
|
defaultMessage: "Save"
|
@@ -1795,10 +1916,13 @@ const UpdateAction = ({
|
|
1795
1916
|
document
|
1796
1917
|
);
|
1797
1918
|
if ("data" in res) {
|
1798
|
-
navigate(
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
1919
|
+
navigate(
|
1920
|
+
{
|
1921
|
+
pathname: `../${res.data.documentId}`,
|
1922
|
+
search: rawQuery
|
1923
|
+
},
|
1924
|
+
{ relative: "path" }
|
1925
|
+
);
|
1802
1926
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1803
1927
|
setErrors(formatValidationErrors(res.error));
|
1804
1928
|
}
|
@@ -1826,10 +1950,13 @@ const UpdateAction = ({
|
|
1826
1950
|
document
|
1827
1951
|
);
|
1828
1952
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1829
|
-
navigate(
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
1953
|
+
navigate(
|
1954
|
+
{
|
1955
|
+
pathname: `../${res.data.documentId}`,
|
1956
|
+
search: rawQuery
|
1957
|
+
},
|
1958
|
+
{ replace: true, relative: "path" }
|
1959
|
+
);
|
1833
1960
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1834
1961
|
setErrors(formatValidationErrors(res.error));
|
1835
1962
|
}
|
@@ -1861,10 +1988,8 @@ const UnpublishAction$1 = ({
|
|
1861
1988
|
const { toggleNotification } = useNotification();
|
1862
1989
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1863
1990
|
const isDocumentModified = document?.status === "modified";
|
1864
|
-
const handleChange = (
|
1865
|
-
|
1866
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1867
|
-
}
|
1991
|
+
const handleChange = (value) => {
|
1992
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1868
1993
|
};
|
1869
1994
|
if (!schema?.options?.draftAndPublish) {
|
1870
1995
|
return null;
|
@@ -1914,40 +2039,24 @@ const UnpublishAction$1 = ({
|
|
1914
2039
|
}) })
|
1915
2040
|
] }),
|
1916
2041
|
/* @__PURE__ */ jsxs(
|
1917
|
-
|
2042
|
+
Radio.Group,
|
1918
2043
|
{
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
2044
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2045
|
+
name: "discard-options",
|
2046
|
+
"aria-label": formatMessage({
|
2047
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2048
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2049
|
+
}),
|
2050
|
+
onValueChange: handleChange,
|
1925
2051
|
children: [
|
1926
|
-
/* @__PURE__ */ jsx(
|
1927
|
-
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
1935
|
-
defaultMessage: "Keep draft"
|
1936
|
-
})
|
1937
|
-
}
|
1938
|
-
),
|
1939
|
-
/* @__PURE__ */ jsx(
|
1940
|
-
Radio,
|
1941
|
-
{
|
1942
|
-
checked: !shouldKeepDraft,
|
1943
|
-
value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
|
1944
|
-
name: "discard-options",
|
1945
|
-
children: formatMessage({
|
1946
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
1947
|
-
defaultMessage: "Replace draft"
|
1948
|
-
})
|
1949
|
-
}
|
1950
|
-
)
|
2052
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2053
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2054
|
+
defaultMessage: "Keep draft"
|
2055
|
+
}) }),
|
2056
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2057
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2058
|
+
defaultMessage: "Replace draft"
|
2059
|
+
}) })
|
1951
2060
|
]
|
1952
2061
|
}
|
1953
2062
|
)
|
@@ -2036,7 +2145,7 @@ const StyledCrossCircle = styled(CrossCircle)`
|
|
2036
2145
|
fill: currentColor;
|
2037
2146
|
}
|
2038
2147
|
`;
|
2039
|
-
const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction$1, DiscardAction];
|
2148
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2040
2149
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2041
2150
|
const RelativeTime = React.forwardRef(
|
2042
2151
|
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
@@ -2093,23 +2202,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2093
2202
|
id: "content-manager.containers.edit.title.new",
|
2094
2203
|
defaultMessage: "Create an entry"
|
2095
2204
|
}) : documentTitle;
|
2096
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2205
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2097
2206
|
/* @__PURE__ */ jsx(BackButton, {}),
|
2098
|
-
/* @__PURE__ */ jsxs(
|
2099
|
-
|
2100
|
-
{
|
2101
|
-
|
2102
|
-
|
2103
|
-
paddingTop: 1,
|
2104
|
-
gap: "80px",
|
2105
|
-
alignItems: "flex-start",
|
2106
|
-
children: [
|
2107
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2108
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2109
|
-
]
|
2110
|
-
}
|
2111
|
-
),
|
2112
|
-
status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
|
2207
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2208
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2209
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2210
|
+
] }),
|
2211
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2113
2212
|
] });
|
2114
2213
|
};
|
2115
2214
|
const HeaderToolbar = () => {
|
@@ -2491,280 +2590,904 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
|
|
2491
2590
|
}
|
2492
2591
|
);
|
2493
2592
|
});
|
2494
|
-
const
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2507
|
-
|
2508
|
-
|
2509
|
-
|
2593
|
+
const HOOKS = {
|
2594
|
+
/**
|
2595
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
2596
|
+
* @constant
|
2597
|
+
* @type {string}
|
2598
|
+
*/
|
2599
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2600
|
+
/**
|
2601
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2602
|
+
* @constant
|
2603
|
+
* @type {string}
|
2604
|
+
*/
|
2605
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2606
|
+
/**
|
2607
|
+
* Hook that allows to mutate the CM's edit view layout
|
2608
|
+
* @constant
|
2609
|
+
* @type {string}
|
2610
|
+
*/
|
2611
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2612
|
+
/**
|
2613
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
2614
|
+
* @constant
|
2615
|
+
* @type {string}
|
2616
|
+
*/
|
2617
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2510
2618
|
};
|
2511
|
-
const
|
2512
|
-
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2530
|
-
|
2531
|
-
|
2532
|
-
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
2536
|
-
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
}
|
2543
|
-
}
|
2544
|
-
|
2545
|
-
|
2546
|
-
|
2547
|
-
|
2548
|
-
|
2549
|
-
|
2550
|
-
|
2551
|
-
|
2552
|
-
|
2553
|
-
|
2554
|
-
|
2555
|
-
|
2556
|
-
BulkActionConfirmDialog,
|
2557
|
-
{
|
2558
|
-
...action.dialog,
|
2559
|
-
variant: action.variant,
|
2560
|
-
isOpen: dialogId === action.id,
|
2561
|
-
onClose: handleClose
|
2562
|
-
}
|
2563
|
-
) : null,
|
2564
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
2565
|
-
BulkActionModal,
|
2566
|
-
{
|
2567
|
-
...action.dialog,
|
2568
|
-
onModalClose: handleClose,
|
2569
|
-
isOpen: dialogId === action.id
|
2570
|
-
}
|
2571
|
-
) : null
|
2572
|
-
] });
|
2573
|
-
};
|
2574
|
-
const BulkActionConfirmDialog = ({
|
2575
|
-
onClose,
|
2576
|
-
onCancel,
|
2577
|
-
onConfirm,
|
2578
|
-
title,
|
2579
|
-
content,
|
2580
|
-
confirmButton,
|
2581
|
-
isOpen,
|
2582
|
-
variant = "secondary"
|
2583
|
-
}) => {
|
2584
|
-
const { formatMessage } = useIntl();
|
2585
|
-
const handleClose = async () => {
|
2586
|
-
if (onCancel) {
|
2587
|
-
await onCancel();
|
2588
|
-
}
|
2589
|
-
onClose();
|
2590
|
-
};
|
2591
|
-
const handleConfirm = async () => {
|
2592
|
-
if (onConfirm) {
|
2593
|
-
await onConfirm();
|
2594
|
-
}
|
2595
|
-
onClose();
|
2596
|
-
};
|
2597
|
-
return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
|
2598
|
-
/* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
|
2599
|
-
/* @__PURE__ */ jsx(
|
2600
|
-
DialogFooter,
|
2601
|
-
{
|
2602
|
-
startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
|
2603
|
-
id: "app.components.Button.cancel",
|
2604
|
-
defaultMessage: "Cancel"
|
2605
|
-
}) }),
|
2606
|
-
endAction: /* @__PURE__ */ jsx(
|
2607
|
-
Button,
|
2608
|
-
{
|
2609
|
-
onClick: handleConfirm,
|
2610
|
-
variant: variant === "danger-light" ? variant : "secondary",
|
2611
|
-
startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
|
2612
|
-
children: confirmButton ? confirmButton : formatMessage({
|
2613
|
-
id: "app.components.Button.confirm",
|
2614
|
-
defaultMessage: "Confirm"
|
2615
|
-
})
|
2616
|
-
}
|
2617
|
-
)
|
2618
|
-
}
|
2619
|
-
)
|
2620
|
-
] });
|
2619
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2620
|
+
endpoints: (builder) => ({
|
2621
|
+
getContentTypeConfiguration: builder.query({
|
2622
|
+
query: (uid) => ({
|
2623
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
2624
|
+
method: "GET"
|
2625
|
+
}),
|
2626
|
+
transformResponse: (response) => response.data,
|
2627
|
+
providesTags: (_result, _error, uid) => [
|
2628
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
2629
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
2630
|
+
]
|
2631
|
+
}),
|
2632
|
+
getAllContentTypeSettings: builder.query({
|
2633
|
+
query: () => "/content-manager/content-types-settings",
|
2634
|
+
transformResponse: (response) => response.data,
|
2635
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2636
|
+
}),
|
2637
|
+
updateContentTypeConfiguration: builder.mutation({
|
2638
|
+
query: ({ uid, ...body }) => ({
|
2639
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
2640
|
+
method: "PUT",
|
2641
|
+
data: body
|
2642
|
+
}),
|
2643
|
+
transformResponse: (response) => response.data,
|
2644
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
2645
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
2646
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
2647
|
+
// Is this necessary?
|
2648
|
+
{ type: "InitialData" }
|
2649
|
+
]
|
2650
|
+
})
|
2651
|
+
})
|
2652
|
+
});
|
2653
|
+
const {
|
2654
|
+
useGetContentTypeConfigurationQuery,
|
2655
|
+
useGetAllContentTypeSettingsQuery,
|
2656
|
+
useUpdateContentTypeConfigurationMutation
|
2657
|
+
} = contentTypesApi;
|
2658
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
2659
|
+
const { type } = attribute;
|
2660
|
+
if (type === "relation") {
|
2661
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
2662
|
+
}
|
2663
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2621
2664
|
};
|
2622
|
-
const
|
2623
|
-
|
2624
|
-
|
2625
|
-
onClose,
|
2626
|
-
content: Content,
|
2627
|
-
onModalClose
|
2628
|
-
}) => {
|
2629
|
-
const id = React.useId();
|
2630
|
-
if (!isOpen) {
|
2631
|
-
return null;
|
2665
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2666
|
+
if (!mainFieldName) {
|
2667
|
+
return void 0;
|
2632
2668
|
}
|
2633
|
-
const
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
2669
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2670
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2671
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2672
|
+
);
|
2673
|
+
return {
|
2674
|
+
name: mainFieldName,
|
2675
|
+
type: mainFieldType ?? "string"
|
2638
2676
|
};
|
2639
|
-
return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
|
2640
|
-
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
|
2641
|
-
/* @__PURE__ */ jsx(Content, { onClose: handleClose })
|
2642
|
-
] });
|
2643
2677
|
};
|
2644
|
-
const
|
2645
|
-
|
2646
|
-
|
2647
|
-
|
2648
|
-
|
2678
|
+
const DEFAULT_SETTINGS = {
|
2679
|
+
bulkable: false,
|
2680
|
+
filterable: false,
|
2681
|
+
searchable: false,
|
2682
|
+
pagination: false,
|
2683
|
+
defaultSortBy: "",
|
2684
|
+
defaultSortOrder: "asc",
|
2685
|
+
mainField: "id",
|
2686
|
+
pageSize: 10
|
2687
|
+
};
|
2688
|
+
const useDocumentLayout = (model) => {
|
2689
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2649
2690
|
const [{ query }] = useQueryParams();
|
2650
|
-
const
|
2651
|
-
const
|
2652
|
-
const {
|
2653
|
-
const
|
2654
|
-
const
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
|
2691
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2692
|
+
const { toggleNotification } = useNotification();
|
2693
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2694
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2695
|
+
const {
|
2696
|
+
data,
|
2697
|
+
isLoading: isLoadingConfigs,
|
2698
|
+
error,
|
2699
|
+
isFetching: isFetchingConfigs
|
2700
|
+
} = useGetContentTypeConfigurationQuery(model);
|
2701
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2702
|
+
React.useEffect(() => {
|
2703
|
+
if (error) {
|
2704
|
+
toggleNotification({
|
2705
|
+
type: "danger",
|
2706
|
+
message: formatAPIError(error)
|
2707
|
+
});
|
2662
2708
|
}
|
2663
|
-
};
|
2664
|
-
|
2665
|
-
|
2709
|
+
}, [error, formatAPIError, toggleNotification]);
|
2710
|
+
const editLayout = React.useMemo(
|
2711
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2712
|
+
layout: [],
|
2713
|
+
components: {},
|
2714
|
+
metadatas: {},
|
2715
|
+
options: {},
|
2716
|
+
settings: DEFAULT_SETTINGS
|
2717
|
+
},
|
2718
|
+
[data, isLoading, schemas, schema, components]
|
2719
|
+
);
|
2720
|
+
const listLayout = React.useMemo(() => {
|
2721
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2722
|
+
layout: [],
|
2723
|
+
metadatas: {},
|
2724
|
+
options: {},
|
2725
|
+
settings: DEFAULT_SETTINGS
|
2726
|
+
};
|
2727
|
+
}, [data, isLoading, schemas, schema, components]);
|
2728
|
+
const { layout: edit } = React.useMemo(
|
2729
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2730
|
+
layout: editLayout,
|
2731
|
+
query
|
2732
|
+
}),
|
2733
|
+
[editLayout, query, runHookWaterfall]
|
2734
|
+
);
|
2666
2735
|
return {
|
2667
|
-
|
2668
|
-
|
2669
|
-
|
2670
|
-
|
2671
|
-
title: formatMessage({
|
2672
|
-
id: "app.components.ConfirmDialog.title",
|
2673
|
-
defaultMessage: "Confirmation"
|
2674
|
-
}),
|
2675
|
-
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
2676
|
-
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
2677
|
-
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
2678
|
-
defaultMessage: "Are you sure you want to delete these entries?"
|
2679
|
-
}) }),
|
2680
|
-
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
2681
|
-
{
|
2682
|
-
id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
|
2683
|
-
defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
|
2684
|
-
},
|
2685
|
-
{
|
2686
|
-
em: Emphasis
|
2687
|
-
}
|
2688
|
-
) }) })
|
2689
|
-
] }),
|
2690
|
-
onConfirm: handleConfirmBulkDelete
|
2691
|
-
}
|
2736
|
+
error,
|
2737
|
+
isLoading,
|
2738
|
+
edit,
|
2739
|
+
list: listLayout
|
2692
2740
|
};
|
2693
2741
|
};
|
2694
|
-
|
2695
|
-
const
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
const
|
2705
|
-
|
2706
|
-
|
2707
|
-
|
2708
|
-
|
2709
|
-
|
2742
|
+
const useDocLayout = () => {
|
2743
|
+
const { model } = useDoc();
|
2744
|
+
return useDocumentLayout(model);
|
2745
|
+
};
|
2746
|
+
const formatEditLayout = (data, {
|
2747
|
+
schemas,
|
2748
|
+
schema,
|
2749
|
+
components
|
2750
|
+
}) => {
|
2751
|
+
let currentPanelIndex = 0;
|
2752
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2753
|
+
data.contentType.layouts.edit,
|
2754
|
+
schema?.attributes,
|
2755
|
+
data.contentType.metadatas,
|
2756
|
+
{ configurations: data.components, schemas: components },
|
2757
|
+
schemas
|
2758
|
+
).reduce((panels, row) => {
|
2759
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
2760
|
+
panels.push([row]);
|
2761
|
+
currentPanelIndex += 2;
|
2762
|
+
} else {
|
2763
|
+
if (!panels[currentPanelIndex]) {
|
2764
|
+
panels.push([]);
|
2765
|
+
}
|
2766
|
+
panels[currentPanelIndex].push(row);
|
2767
|
+
}
|
2768
|
+
return panels;
|
2769
|
+
}, []);
|
2770
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
2771
|
+
(acc, [uid, configuration]) => {
|
2772
|
+
acc[uid] = {
|
2773
|
+
layout: convertEditLayoutToFieldLayouts(
|
2774
|
+
configuration.layouts.edit,
|
2775
|
+
components[uid].attributes,
|
2776
|
+
configuration.metadatas
|
2777
|
+
),
|
2778
|
+
settings: {
|
2779
|
+
...configuration.settings,
|
2780
|
+
icon: components[uid].info.icon,
|
2781
|
+
displayName: components[uid].info.displayName
|
2782
|
+
}
|
2783
|
+
};
|
2784
|
+
return acc;
|
2785
|
+
},
|
2786
|
+
{}
|
2787
|
+
);
|
2788
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2789
|
+
(acc, [attribute, metadata]) => {
|
2790
|
+
return {
|
2791
|
+
...acc,
|
2792
|
+
[attribute]: metadata.edit
|
2793
|
+
};
|
2794
|
+
},
|
2795
|
+
{}
|
2796
|
+
);
|
2797
|
+
return {
|
2798
|
+
layout: panelledEditAttributes,
|
2799
|
+
components: componentEditAttributes,
|
2800
|
+
metadatas: editMetadatas,
|
2801
|
+
settings: {
|
2802
|
+
...data.contentType.settings,
|
2803
|
+
displayName: schema?.info.displayName
|
2804
|
+
},
|
2805
|
+
options: {
|
2806
|
+
...schema?.options,
|
2807
|
+
...schema?.pluginOptions,
|
2808
|
+
...data.contentType.options
|
2710
2809
|
}
|
2711
2810
|
};
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2811
|
+
};
|
2812
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
2813
|
+
return rows.map(
|
2814
|
+
(row) => row.map((field) => {
|
2815
|
+
const attribute = attributes[field.name];
|
2816
|
+
if (!attribute) {
|
2817
|
+
return null;
|
2818
|
+
}
|
2819
|
+
const { edit: metadata } = metadatas[field.name];
|
2820
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2821
|
+
return {
|
2822
|
+
attribute,
|
2823
|
+
disabled: !metadata.editable,
|
2824
|
+
hint: metadata.description,
|
2825
|
+
label: metadata.label ?? "",
|
2826
|
+
name: field.name,
|
2827
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2828
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2829
|
+
schemas,
|
2830
|
+
components: components?.schemas ?? {}
|
2831
|
+
}),
|
2832
|
+
placeholder: metadata.placeholder ?? "",
|
2833
|
+
required: attribute.required ?? false,
|
2834
|
+
size: field.size,
|
2835
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
2836
|
+
visible: metadata.visible ?? true,
|
2837
|
+
type: attribute.type
|
2838
|
+
};
|
2839
|
+
}).filter((field) => field !== null)
|
2840
|
+
);
|
2841
|
+
};
|
2842
|
+
const formatListLayout = (data, {
|
2843
|
+
schemas,
|
2844
|
+
schema,
|
2845
|
+
components
|
2846
|
+
}) => {
|
2847
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2848
|
+
(acc, [attribute, metadata]) => {
|
2849
|
+
return {
|
2850
|
+
...acc,
|
2851
|
+
[attribute]: metadata.list
|
2852
|
+
};
|
2853
|
+
},
|
2854
|
+
{}
|
2855
|
+
);
|
2856
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
2857
|
+
data.contentType.layouts.list,
|
2858
|
+
schema?.attributes,
|
2859
|
+
listMetadatas,
|
2860
|
+
{ configurations: data.components, schemas: components },
|
2861
|
+
schemas
|
2862
|
+
);
|
2715
2863
|
return {
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2864
|
+
layout: listAttributes,
|
2865
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
2866
|
+
metadatas: listMetadatas,
|
2867
|
+
options: {
|
2868
|
+
...schema?.options,
|
2869
|
+
...schema?.pluginOptions,
|
2870
|
+
...data.contentType.options
|
2871
|
+
}
|
2872
|
+
};
|
2873
|
+
};
|
2874
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
2875
|
+
return columns.map((name) => {
|
2876
|
+
const attribute = attributes[name];
|
2877
|
+
if (!attribute) {
|
2878
|
+
return null;
|
2879
|
+
}
|
2880
|
+
const metadata = metadatas[name];
|
2881
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2882
|
+
return {
|
2883
|
+
attribute,
|
2884
|
+
label: metadata.label ?? "",
|
2885
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2886
|
+
schemas,
|
2887
|
+
components: components?.schemas ?? {}
|
2723
2888
|
}),
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2889
|
+
name,
|
2890
|
+
searchable: metadata.searchable ?? true,
|
2891
|
+
sortable: metadata.sortable ?? true
|
2892
|
+
};
|
2893
|
+
}).filter((field) => field !== null);
|
2894
|
+
};
|
2895
|
+
const ConfirmBulkActionDialog = ({
|
2896
|
+
onToggleDialog,
|
2897
|
+
isOpen = false,
|
2898
|
+
dialogBody,
|
2899
|
+
endAction
|
2900
|
+
}) => {
|
2901
|
+
const { formatMessage } = useIntl();
|
2902
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2903
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2904
|
+
id: "app.components.ConfirmDialog.title",
|
2905
|
+
defaultMessage: "Confirmation"
|
2906
|
+
}) }),
|
2907
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
2908
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
2909
|
+
dialogBody
|
2910
|
+
] }) }),
|
2911
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2912
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
2913
|
+
id: "app.components.Button.cancel",
|
2914
|
+
defaultMessage: "Cancel"
|
2915
|
+
}) }) }),
|
2916
|
+
endAction
|
2917
|
+
] })
|
2918
|
+
] }) });
|
2919
|
+
};
|
2920
|
+
const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
2921
|
+
const ConfirmDialogPublishAll = ({
|
2922
|
+
isOpen,
|
2923
|
+
onToggleDialog,
|
2924
|
+
isConfirmButtonLoading = false,
|
2925
|
+
onConfirm
|
2926
|
+
}) => {
|
2927
|
+
const { formatMessage } = useIntl();
|
2928
|
+
const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
|
2929
|
+
const { toggleNotification } = useNotification();
|
2930
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2931
|
+
const { model, schema } = useDoc();
|
2932
|
+
const [{ query }] = useQueryParams();
|
2933
|
+
const {
|
2934
|
+
data: countDraftRelations = 0,
|
2935
|
+
isLoading,
|
2936
|
+
error
|
2937
|
+
} = useGetManyDraftRelationCountQuery(
|
2938
|
+
{
|
2939
|
+
model,
|
2940
|
+
documentIds: selectedEntries.map((entry) => entry.documentId),
|
2941
|
+
locale: query?.plugins?.i18n?.locale
|
2942
|
+
},
|
2943
|
+
{
|
2944
|
+
skip: selectedEntries.length === 0
|
2945
|
+
}
|
2946
|
+
);
|
2947
|
+
React.useEffect(() => {
|
2948
|
+
if (error) {
|
2949
|
+
toggleNotification({ type: "danger", message: formatAPIError(error) });
|
2950
|
+
}
|
2951
|
+
}, [error, formatAPIError, toggleNotification]);
|
2952
|
+
if (error) {
|
2953
|
+
return null;
|
2954
|
+
}
|
2955
|
+
return /* @__PURE__ */ jsx(
|
2956
|
+
ConfirmBulkActionDialog,
|
2957
|
+
{
|
2958
|
+
isOpen: isOpen && !isLoading,
|
2959
|
+
onToggleDialog,
|
2960
|
+
dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
|
2961
|
+
/* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
|
2962
|
+
countDraftRelations > 0 && formatMessage(
|
2963
|
+
{
|
2964
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2965
|
+
defaultMessage: "<b>{count} {count, plural, one { relation } other { relations } } out of {entities} { entities, plural, one { entry } other { entries } } {count, plural, one { is } other { are } }</b> not published yet and might lead to unexpected behavior. "
|
2966
|
+
},
|
2967
|
+
{
|
2968
|
+
b: BoldChunk$1,
|
2969
|
+
count: countDraftRelations,
|
2970
|
+
entities: selectedEntries.length
|
2971
|
+
}
|
2972
|
+
),
|
2973
|
+
formatMessage({
|
2974
|
+
id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
|
2975
|
+
defaultMessage: "Are you sure you want to publish these entries?"
|
2976
|
+
})
|
2977
|
+
] }),
|
2978
|
+
schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
|
2730
2979
|
{
|
2731
|
-
id: getTranslation("Settings.list.actions.
|
2732
|
-
defaultMessage: "This will
|
2980
|
+
id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
|
2981
|
+
defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
|
2733
2982
|
},
|
2734
2983
|
{
|
2735
2984
|
em: Emphasis
|
2736
2985
|
}
|
2737
|
-
) })
|
2986
|
+
) })
|
2738
2987
|
] }),
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2988
|
+
endAction: /* @__PURE__ */ jsx(
|
2989
|
+
Button,
|
2990
|
+
{
|
2991
|
+
onClick: onConfirm,
|
2992
|
+
variant: "secondary",
|
2993
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
2994
|
+
loading: isConfirmButtonLoading,
|
2995
|
+
children: formatMessage({
|
2996
|
+
id: "app.utils.publish",
|
2997
|
+
defaultMessage: "Publish"
|
2998
|
+
})
|
2999
|
+
}
|
3000
|
+
)
|
2744
3001
|
}
|
2745
|
-
|
3002
|
+
);
|
2746
3003
|
};
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
const
|
3004
|
+
const TypographyMaxWidth = styled(Typography)`
|
3005
|
+
max-width: 300px;
|
3006
|
+
`;
|
3007
|
+
const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
3008
|
+
const messages = [];
|
3009
|
+
Object.entries(errors).forEach(([key, value]) => {
|
3010
|
+
const currentKey = parentKey ? `${parentKey}.${key}` : key;
|
3011
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
3012
|
+
if ("id" in value && "defaultMessage" in value) {
|
3013
|
+
messages.push(
|
3014
|
+
formatMessage(
|
3015
|
+
{
|
3016
|
+
id: `${value.id}.withField`,
|
3017
|
+
defaultMessage: value.defaultMessage
|
3018
|
+
},
|
3019
|
+
{ field: currentKey }
|
3020
|
+
)
|
3021
|
+
);
|
3022
|
+
} else {
|
3023
|
+
messages.push(
|
3024
|
+
...formatErrorMessages(
|
3025
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3026
|
+
value,
|
3027
|
+
currentKey,
|
3028
|
+
formatMessage
|
3029
|
+
)
|
3030
|
+
);
|
3031
|
+
}
|
3032
|
+
} else {
|
3033
|
+
messages.push(
|
3034
|
+
formatMessage(
|
3035
|
+
{
|
3036
|
+
id: `${value}.withField`,
|
3037
|
+
defaultMessage: value
|
3038
|
+
},
|
3039
|
+
{ field: currentKey }
|
3040
|
+
)
|
3041
|
+
);
|
3042
|
+
}
|
3043
|
+
});
|
3044
|
+
return messages;
|
3045
|
+
};
|
3046
|
+
const EntryValidationText = ({ validationErrors, status }) => {
|
2751
3047
|
const { formatMessage } = useIntl();
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
3048
|
+
if (validationErrors) {
|
3049
|
+
const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
|
3050
|
+
" "
|
3051
|
+
);
|
3052
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3053
|
+
/* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
|
3054
|
+
/* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
|
3055
|
+
] });
|
3056
|
+
}
|
3057
|
+
if (status === "published") {
|
3058
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3059
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3060
|
+
/* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
|
3061
|
+
id: "content-manager.bulk-publish.already-published",
|
3062
|
+
defaultMessage: "Already Published"
|
3063
|
+
}) })
|
3064
|
+
] });
|
3065
|
+
}
|
3066
|
+
if (status === "modified") {
|
3067
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3068
|
+
/* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3069
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3070
|
+
id: "content-manager.bulk-publish.modified",
|
3071
|
+
defaultMessage: "Ready to publish changes"
|
3072
|
+
}) })
|
3073
|
+
] });
|
3074
|
+
}
|
3075
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3076
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3077
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3078
|
+
id: "app.utils.ready-to-publish",
|
3079
|
+
defaultMessage: "Ready to publish"
|
3080
|
+
}) })
|
3081
|
+
] });
|
3082
|
+
};
|
3083
|
+
const TABLE_HEADERS = [
|
3084
|
+
{ name: "id", label: "id" },
|
3085
|
+
{ name: "name", label: "name" },
|
3086
|
+
{ name: "status", label: "status" },
|
3087
|
+
{ name: "publicationStatus", label: "Publication status" }
|
3088
|
+
];
|
3089
|
+
const SelectedEntriesTableContent = ({
|
3090
|
+
isPublishing,
|
3091
|
+
rowsToDisplay = [],
|
3092
|
+
entriesToPublish = [],
|
3093
|
+
validationErrors = {}
|
3094
|
+
}) => {
|
3095
|
+
const { pathname } = useLocation();
|
3096
|
+
const { formatMessage } = useIntl();
|
3097
|
+
const {
|
3098
|
+
list: {
|
3099
|
+
settings: { mainField }
|
2760
3100
|
}
|
2761
|
-
};
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
3101
|
+
} = useDocLayout();
|
3102
|
+
const shouldDisplayMainField = mainField != null && mainField !== "id";
|
3103
|
+
return /* @__PURE__ */ jsxs(Table.Content, { children: [
|
3104
|
+
/* @__PURE__ */ jsxs(Table.Head, { children: [
|
3105
|
+
/* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
|
3106
|
+
TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
|
3107
|
+
(head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
|
3108
|
+
)
|
3109
|
+
] }),
|
3110
|
+
/* @__PURE__ */ jsx(Table.Loading, {}),
|
3111
|
+
/* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
3112
|
+
/* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
|
3113
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
|
3114
|
+
shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
|
3115
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
|
3116
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3117
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3118
|
+
id: "content-manager.success.record.publishing",
|
3119
|
+
defaultMessage: "Publishing..."
|
3120
|
+
}) }),
|
3121
|
+
/* @__PURE__ */ jsx(Loader, { small: true })
|
3122
|
+
] }) : /* @__PURE__ */ jsx(
|
3123
|
+
EntryValidationText,
|
3124
|
+
{
|
3125
|
+
validationErrors: validationErrors[row.documentId],
|
3126
|
+
status: row.status
|
3127
|
+
}
|
3128
|
+
) }),
|
3129
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3130
|
+
IconButton,
|
3131
|
+
{
|
3132
|
+
tag: Link,
|
3133
|
+
to: {
|
3134
|
+
pathname: `${pathname}/${row.documentId}`,
|
3135
|
+
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3136
|
+
},
|
3137
|
+
state: { from: pathname },
|
3138
|
+
label: formatMessage(
|
3139
|
+
{ id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
|
3140
|
+
{
|
3141
|
+
target: formatMessage(
|
3142
|
+
{
|
3143
|
+
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3144
|
+
defaultMessage: "item line {number}"
|
3145
|
+
},
|
3146
|
+
{ number: index2 + 1 }
|
3147
|
+
)
|
3148
|
+
}
|
3149
|
+
),
|
3150
|
+
target: "_blank",
|
3151
|
+
marginLeft: "auto",
|
3152
|
+
children: /* @__PURE__ */ jsx(Pencil, {})
|
3153
|
+
}
|
3154
|
+
) })
|
3155
|
+
] }, row.id)) })
|
3156
|
+
] });
|
3157
|
+
};
|
3158
|
+
const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3159
|
+
const SelectedEntriesModalContent = ({
|
3160
|
+
listViewSelectedEntries,
|
3161
|
+
toggleModal,
|
3162
|
+
setListViewSelectedDocuments,
|
3163
|
+
model
|
3164
|
+
}) => {
|
3165
|
+
const { formatMessage } = useIntl();
|
3166
|
+
const { schema, components } = useContentTypeSchema(model);
|
3167
|
+
const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
|
3168
|
+
const [{ query }] = useQueryParams();
|
3169
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3170
|
+
const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
|
3171
|
+
{
|
3172
|
+
model,
|
3173
|
+
params: {
|
3174
|
+
page: "1",
|
3175
|
+
pageSize: documentIds.length.toString(),
|
3176
|
+
sort: query.sort,
|
3177
|
+
filters: {
|
3178
|
+
documentId: {
|
3179
|
+
$in: documentIds
|
3180
|
+
}
|
3181
|
+
},
|
3182
|
+
locale: query.plugins?.i18n?.locale
|
3183
|
+
}
|
3184
|
+
},
|
3185
|
+
{
|
3186
|
+
selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
|
3187
|
+
}
|
3188
|
+
);
|
3189
|
+
const { rows, validationErrors } = React.useMemo(() => {
|
3190
|
+
if (data.length > 0 && schema) {
|
3191
|
+
const validate = createYupSchema(schema.attributes, components);
|
3192
|
+
const validationErrors2 = {};
|
3193
|
+
const rows2 = data.map((entry) => {
|
3194
|
+
try {
|
3195
|
+
validate.validateSync(entry, { abortEarly: false });
|
3196
|
+
return entry;
|
3197
|
+
} catch (e) {
|
3198
|
+
if (e instanceof ValidationError) {
|
3199
|
+
validationErrors2[entry.documentId] = getYupValidationErrors(e);
|
3200
|
+
}
|
3201
|
+
return entry;
|
3202
|
+
}
|
3203
|
+
});
|
3204
|
+
return { rows: rows2, validationErrors: validationErrors2 };
|
3205
|
+
}
|
3206
|
+
return {
|
3207
|
+
rows: [],
|
3208
|
+
validationErrors: {}
|
3209
|
+
};
|
3210
|
+
}, [components, data, schema]);
|
3211
|
+
const [publishedCount, setPublishedCount] = React.useState(0);
|
3212
|
+
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
3213
|
+
const { publishMany: bulkPublishAction } = useDocumentActions();
|
3214
|
+
const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
|
3215
|
+
const selectedRows = useTable("publishAction", (state) => state.selectedRows);
|
3216
|
+
const selectedEntries = rows.filter(
|
3217
|
+
(entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
|
3218
|
+
);
|
3219
|
+
const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
|
3220
|
+
const selectedEntriesWithErrorsCount = selectedEntries.filter(
|
3221
|
+
({ documentId }) => validationErrors[documentId]
|
3222
|
+
).length;
|
3223
|
+
const selectedEntriesPublished = selectedEntries.filter(
|
3224
|
+
({ status }) => status === "published"
|
3225
|
+
).length;
|
3226
|
+
const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
|
3227
|
+
const toggleDialog = () => setIsDialogOpen((prev) => !prev);
|
3228
|
+
const handleConfirmBulkPublish = async () => {
|
3229
|
+
toggleDialog();
|
3230
|
+
const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
|
3231
|
+
if (!("error" in res)) {
|
3232
|
+
setPublishedCount(res.count);
|
3233
|
+
const unpublishedEntries = rows.filter((row) => {
|
3234
|
+
return !entriesToPublish.includes(row.documentId);
|
3235
|
+
});
|
3236
|
+
setListViewSelectedDocuments(unpublishedEntries);
|
3237
|
+
}
|
3238
|
+
};
|
3239
|
+
const getFormattedCountMessage = () => {
|
3240
|
+
if (publishedCount) {
|
3241
|
+
return formatMessage(
|
3242
|
+
{
|
3243
|
+
id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
|
3244
|
+
defaultMessage: "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} published. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
|
3245
|
+
},
|
3246
|
+
{
|
3247
|
+
publishedCount,
|
3248
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3249
|
+
b: BoldChunk
|
3250
|
+
}
|
3251
|
+
);
|
3252
|
+
}
|
3253
|
+
return formatMessage(
|
3254
|
+
{
|
3255
|
+
id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
|
3256
|
+
defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
|
3257
|
+
},
|
3258
|
+
{
|
3259
|
+
readyToPublishCount: selectedEntriesWithNoErrorsCount,
|
3260
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3261
|
+
alreadyPublishedCount: selectedEntriesPublished,
|
3262
|
+
b: BoldChunk
|
3263
|
+
}
|
3264
|
+
);
|
3265
|
+
};
|
3266
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3267
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3268
|
+
/* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
|
3269
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
|
3270
|
+
SelectedEntriesTableContent,
|
3271
|
+
{
|
3272
|
+
isPublishing: isSubmittingForm,
|
3273
|
+
rowsToDisplay: rows,
|
3274
|
+
entriesToPublish,
|
3275
|
+
validationErrors
|
3276
|
+
}
|
3277
|
+
) })
|
3278
|
+
] }),
|
3279
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3280
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3281
|
+
id: "app.components.Button.cancel",
|
3282
|
+
defaultMessage: "Cancel"
|
3283
|
+
}) }),
|
3284
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3285
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3286
|
+
/* @__PURE__ */ jsx(
|
3287
|
+
Button,
|
3288
|
+
{
|
3289
|
+
onClick: toggleDialog,
|
3290
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
|
3291
|
+
loading: isSubmittingForm,
|
3292
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3293
|
+
}
|
3294
|
+
)
|
3295
|
+
] })
|
3296
|
+
] }),
|
3297
|
+
/* @__PURE__ */ jsx(
|
3298
|
+
ConfirmDialogPublishAll,
|
3299
|
+
{
|
3300
|
+
isOpen: isDialogOpen,
|
3301
|
+
onToggleDialog: toggleDialog,
|
3302
|
+
isConfirmButtonLoading: isSubmittingForm,
|
3303
|
+
onConfirm: handleConfirmBulkPublish
|
3304
|
+
}
|
3305
|
+
)
|
3306
|
+
] });
|
3307
|
+
};
|
3308
|
+
const PublishAction = ({ documents, model }) => {
|
3309
|
+
const { formatMessage } = useIntl();
|
3310
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3311
|
+
const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
|
3312
|
+
const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
|
3313
|
+
const refetchList = () => {
|
3314
|
+
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3315
|
+
};
|
3316
|
+
if (!showPublishButton)
|
3317
|
+
return null;
|
3318
|
+
return {
|
3319
|
+
actionType: "publish",
|
3320
|
+
variant: "tertiary",
|
3321
|
+
label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
|
3322
|
+
dialog: {
|
3323
|
+
type: "modal",
|
3324
|
+
title: formatMessage({
|
3325
|
+
id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
|
3326
|
+
defaultMessage: "Publish entries"
|
3327
|
+
}),
|
3328
|
+
content: ({ onClose }) => {
|
3329
|
+
return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
|
3330
|
+
SelectedEntriesModalContent,
|
3331
|
+
{
|
3332
|
+
listViewSelectedEntries: documents,
|
3333
|
+
toggleModal: () => {
|
3334
|
+
onClose();
|
3335
|
+
refetchList();
|
3336
|
+
},
|
3337
|
+
setListViewSelectedDocuments,
|
3338
|
+
model
|
3339
|
+
}
|
3340
|
+
) });
|
3341
|
+
},
|
3342
|
+
onClose: () => {
|
3343
|
+
refetchList();
|
3344
|
+
}
|
3345
|
+
}
|
3346
|
+
};
|
3347
|
+
};
|
3348
|
+
const BulkActionsRenderer = () => {
|
3349
|
+
const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
|
3350
|
+
const { model, collectionType } = useDoc();
|
3351
|
+
const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
|
3352
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
|
3353
|
+
DescriptionComponentRenderer,
|
3354
|
+
{
|
3355
|
+
props: {
|
3356
|
+
model,
|
3357
|
+
collectionType,
|
3358
|
+
documents: selectedRows
|
3359
|
+
},
|
3360
|
+
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3361
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
3362
|
+
}
|
3363
|
+
) });
|
3364
|
+
};
|
3365
|
+
const DeleteAction = ({ documents, model }) => {
|
3366
|
+
const { formatMessage } = useIntl();
|
3367
|
+
const { schema: contentType } = useDoc();
|
3368
|
+
const selectRow = useTable("DeleteAction", (state) => state.selectRow);
|
3369
|
+
const hasI18nEnabled = Boolean(contentType?.pluginOptions?.i18n);
|
3370
|
+
const [{ query }] = useQueryParams();
|
3371
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3372
|
+
const hasDeletePermission = useDocumentRBAC("deleteAction", (state) => state.canDelete);
|
3373
|
+
const { deleteMany: bulkDeleteAction } = useDocumentActions();
|
3374
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3375
|
+
const handleConfirmBulkDelete = async () => {
|
3376
|
+
const res = await bulkDeleteAction({
|
3377
|
+
documentIds,
|
3378
|
+
model,
|
3379
|
+
params
|
3380
|
+
});
|
3381
|
+
if (!("error" in res)) {
|
3382
|
+
selectRow([]);
|
3383
|
+
}
|
3384
|
+
};
|
3385
|
+
if (!hasDeletePermission)
|
3386
|
+
return null;
|
3387
|
+
return {
|
3388
|
+
variant: "danger-light",
|
3389
|
+
label: formatMessage({ id: "global.delete", defaultMessage: "Delete" }),
|
3390
|
+
dialog: {
|
3391
|
+
type: "dialog",
|
3392
|
+
title: formatMessage({
|
3393
|
+
id: "app.components.ConfirmDialog.title",
|
3394
|
+
defaultMessage: "Confirmation"
|
3395
|
+
}),
|
3396
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3397
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3398
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3399
|
+
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
3400
|
+
defaultMessage: "Are you sure you want to delete these entries?"
|
3401
|
+
}) }),
|
3402
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3403
|
+
{
|
3404
|
+
id: getTranslation("Settings.list.actions.deleteAdditionalInfos"),
|
3405
|
+
defaultMessage: "This will delete the active locale versions <em>(from Internationalization)</em>"
|
3406
|
+
},
|
3407
|
+
{
|
3408
|
+
em: Emphasis
|
3409
|
+
}
|
3410
|
+
) }) })
|
3411
|
+
] }),
|
3412
|
+
onConfirm: handleConfirmBulkDelete
|
3413
|
+
}
|
3414
|
+
};
|
3415
|
+
};
|
3416
|
+
DeleteAction.type = "delete";
|
3417
|
+
const UnpublishAction = ({ documents, model }) => {
|
3418
|
+
const { formatMessage } = useIntl();
|
3419
|
+
const { schema } = useDoc();
|
3420
|
+
const selectRow = useTable("UnpublishAction", (state) => state.selectRow);
|
3421
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3422
|
+
const hasI18nEnabled = Boolean(schema?.pluginOptions?.i18n);
|
3423
|
+
const hasDraftAndPublishEnabled = Boolean(schema?.options?.draftAndPublish);
|
3424
|
+
const { unpublishMany: bulkUnpublishAction } = useDocumentActions();
|
3425
|
+
const documentIds = documents.map(({ documentId }) => documentId);
|
3426
|
+
const [{ query }] = useQueryParams();
|
3427
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3428
|
+
const handleConfirmBulkUnpublish = async () => {
|
3429
|
+
const data = await bulkUnpublishAction({ documentIds, model, params });
|
3430
|
+
if (!("error" in data)) {
|
3431
|
+
selectRow([]);
|
3432
|
+
}
|
3433
|
+
};
|
3434
|
+
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3435
|
+
if (!showUnpublishButton)
|
3436
|
+
return null;
|
3437
|
+
return {
|
3438
|
+
variant: "tertiary",
|
3439
|
+
label: formatMessage({ id: "app.utils.unpublish", defaultMessage: "Unpublish" }),
|
3440
|
+
dialog: {
|
3441
|
+
type: "dialog",
|
3442
|
+
title: formatMessage({
|
3443
|
+
id: "app.components.ConfirmDialog.title",
|
3444
|
+
defaultMessage: "Confirmation"
|
3445
|
+
}),
|
3446
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3447
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3448
|
+
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3449
|
+
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
3450
|
+
defaultMessage: "Are you sure you want to unpublish these entries?"
|
3451
|
+
}) }),
|
3452
|
+
hasI18nEnabled && /* @__PURE__ */ jsx(Box, { textAlign: "center", padding: 3, children: /* @__PURE__ */ jsx(Typography, { textColor: "danger500", children: formatMessage(
|
3453
|
+
{
|
3454
|
+
id: getTranslation("Settings.list.actions.unpublishAdditionalInfos"),
|
3455
|
+
defaultMessage: "This will unpublish the active locale versions <em>(from Internationalization)</em>"
|
3456
|
+
},
|
3457
|
+
{
|
3458
|
+
em: Emphasis
|
3459
|
+
}
|
3460
|
+
) }) })
|
3461
|
+
] }),
|
3462
|
+
confirmButton: formatMessage({
|
3463
|
+
id: "app.utils.unpublish",
|
3464
|
+
defaultMessage: "Unpublish"
|
3465
|
+
}),
|
3466
|
+
onConfirm: handleConfirmBulkUnpublish
|
3467
|
+
}
|
3468
|
+
};
|
3469
|
+
};
|
3470
|
+
UnpublishAction.type = "unpublish";
|
3471
|
+
const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
|
3472
|
+
const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
|
3473
|
+
const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
3474
|
+
const { formatMessage } = useIntl();
|
3475
|
+
const getDefaultErrorMessage = (reason) => {
|
3476
|
+
switch (reason) {
|
3477
|
+
case "relation":
|
3478
|
+
return "Duplicating the relation could remove it from the original entry.";
|
3479
|
+
case "unique":
|
3480
|
+
return "Identical values in a unique field are not allowed";
|
3481
|
+
default:
|
3482
|
+
return reason;
|
3483
|
+
}
|
3484
|
+
};
|
3485
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3486
|
+
/* @__PURE__ */ jsx(Typography, { variant: "beta", children: formatMessage({
|
3487
|
+
id: getTranslation("containers.list.autoCloneModal.title"),
|
3488
|
+
defaultMessage: "This entry can't be duplicated directly."
|
3489
|
+
}) }),
|
3490
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 2, children: /* @__PURE__ */ jsx(Typography, { textColor: "neutral600", children: formatMessage({
|
2768
3491
|
id: getTranslation("containers.list.autoCloneModal.description"),
|
2769
3492
|
defaultMessage: "A new entry will be created with the same content, but you'll have to change the following fields to save it."
|
2770
3493
|
}) }) }),
|
@@ -2805,596 +3528,339 @@ const TableActions = ({ document }) => {
|
|
2805
3528
|
const { model, collectionType } = useDoc();
|
2806
3529
|
const plugins = useStrapiApp("TableActions", (state) => state.plugins);
|
2807
3530
|
const props = {
|
2808
|
-
activeTab: null,
|
2809
|
-
model,
|
2810
|
-
documentId: document.documentId,
|
2811
|
-
collectionType,
|
2812
|
-
document
|
2813
|
-
};
|
2814
|
-
return /* @__PURE__ */ jsx(
|
2815
|
-
DescriptionComponentRenderer,
|
2816
|
-
{
|
2817
|
-
props,
|
2818
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2819
|
-
children: (actions2) => {
|
2820
|
-
const tableRowActions = actions2.filter((action) => {
|
2821
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2822
|
-
return positions.includes("table-row");
|
2823
|
-
});
|
2824
|
-
return /* @__PURE__ */ jsx(
|
2825
|
-
DocumentActionsMenu,
|
2826
|
-
{
|
2827
|
-
actions: tableRowActions,
|
2828
|
-
label: formatMessage({
|
2829
|
-
id: "content-manager.containers.list.table.row-actions",
|
2830
|
-
defaultMessage: "Row action"
|
2831
|
-
}),
|
2832
|
-
variant: "ghost"
|
2833
|
-
}
|
2834
|
-
);
|
2835
|
-
}
|
2836
|
-
}
|
2837
|
-
);
|
2838
|
-
};
|
2839
|
-
const EditAction = ({ documentId }) => {
|
2840
|
-
const navigate = useNavigate();
|
2841
|
-
const { formatMessage } = useIntl();
|
2842
|
-
const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
|
2843
|
-
const { toggleNotification } = useNotification();
|
2844
|
-
const [{ query }] = useQueryParams();
|
2845
|
-
return {
|
2846
|
-
disabled: !canRead,
|
2847
|
-
icon: /* @__PURE__ */ jsx(StyledPencil, {}),
|
2848
|
-
label: formatMessage({
|
2849
|
-
id: "content-manager.actions.edit.label",
|
2850
|
-
defaultMessage: "Edit"
|
2851
|
-
}),
|
2852
|
-
position: "table-row",
|
2853
|
-
onClick: async () => {
|
2854
|
-
if (!documentId) {
|
2855
|
-
console.error(
|
2856
|
-
"You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2857
|
-
);
|
2858
|
-
toggleNotification({
|
2859
|
-
message: formatMessage({
|
2860
|
-
id: "content-manager.actions.edit.error",
|
2861
|
-
defaultMessage: "An error occurred while trying to edit the document."
|
2862
|
-
}),
|
2863
|
-
type: "danger"
|
2864
|
-
});
|
2865
|
-
return;
|
2866
|
-
}
|
2867
|
-
navigate({
|
2868
|
-
pathname: documentId,
|
2869
|
-
search: stringify({
|
2870
|
-
plugins: query.plugins
|
2871
|
-
})
|
2872
|
-
});
|
2873
|
-
}
|
2874
|
-
};
|
2875
|
-
};
|
2876
|
-
EditAction.type = "edit";
|
2877
|
-
const StyledPencil = styled(Pencil)`
|
2878
|
-
path {
|
2879
|
-
fill: currentColor;
|
2880
|
-
}
|
2881
|
-
`;
|
2882
|
-
const CloneAction = ({ model, documentId }) => {
|
2883
|
-
const navigate = useNavigate();
|
2884
|
-
const { formatMessage } = useIntl();
|
2885
|
-
const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
|
2886
|
-
const { toggleNotification } = useNotification();
|
2887
|
-
const { autoClone } = useDocumentActions();
|
2888
|
-
const [prohibitedFields, setProhibitedFields] = React.useState([]);
|
2889
|
-
return {
|
2890
|
-
disabled: !canCreate,
|
2891
|
-
icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
|
2892
|
-
label: formatMessage({
|
2893
|
-
id: "content-manager.actions.clone.label",
|
2894
|
-
defaultMessage: "Duplicate"
|
2895
|
-
}),
|
2896
|
-
position: "table-row",
|
2897
|
-
onClick: async () => {
|
2898
|
-
if (!documentId) {
|
2899
|
-
console.error(
|
2900
|
-
"You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
|
2901
|
-
);
|
2902
|
-
toggleNotification({
|
2903
|
-
message: formatMessage({
|
2904
|
-
id: "content-manager.actions.clone.error",
|
2905
|
-
defaultMessage: "An error occurred while trying to clone the document."
|
2906
|
-
}),
|
2907
|
-
type: "danger"
|
2908
|
-
});
|
2909
|
-
return;
|
2910
|
-
}
|
2911
|
-
const res = await autoClone({ model, sourceId: documentId });
|
2912
|
-
if ("data" in res) {
|
2913
|
-
navigate(res.data.documentId);
|
2914
|
-
return true;
|
2915
|
-
}
|
2916
|
-
if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
|
2917
|
-
const prohibitedFields2 = res.error.details.prohibitedFields;
|
2918
|
-
setProhibitedFields(prohibitedFields2);
|
2919
|
-
}
|
2920
|
-
},
|
2921
|
-
dialog: {
|
2922
|
-
type: "modal",
|
2923
|
-
title: formatMessage({
|
2924
|
-
id: "content-manager.containers.list.autoCloneModal.header",
|
2925
|
-
defaultMessage: "Duplicate"
|
2926
|
-
}),
|
2927
|
-
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
2928
|
-
footer: ({ onClose }) => {
|
2929
|
-
return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
|
2930
|
-
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
2931
|
-
id: "cancel",
|
2932
|
-
defaultMessage: "Cancel"
|
2933
|
-
}) }),
|
2934
|
-
/* @__PURE__ */ jsx(
|
2935
|
-
LinkButton,
|
2936
|
-
{
|
2937
|
-
tag: NavLink,
|
2938
|
-
to: {
|
2939
|
-
pathname: `clone/${documentId}`
|
2940
|
-
},
|
2941
|
-
children: formatMessage({
|
2942
|
-
id: "content-manager.containers.list.autoCloneModal.create",
|
2943
|
-
defaultMessage: "Create"
|
2944
|
-
})
|
2945
|
-
}
|
2946
|
-
)
|
2947
|
-
] });
|
2948
|
-
}
|
2949
|
-
}
|
2950
|
-
};
|
2951
|
-
};
|
2952
|
-
CloneAction.type = "clone";
|
2953
|
-
const StyledDuplicate = styled(Duplicate)`
|
2954
|
-
path {
|
2955
|
-
fill: currentColor;
|
2956
|
-
}
|
2957
|
-
`;
|
2958
|
-
const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
|
2959
|
-
class ContentManagerPlugin {
|
2960
|
-
/**
|
2961
|
-
* The following properties are the stored ones provided by any plugins registering with
|
2962
|
-
* the content-manager. The function calls however, need to be called at runtime in the
|
2963
|
-
* application, so instead we collate them and run them later with the complete list incl.
|
2964
|
-
* ones already registered & the context of the view.
|
2965
|
-
*/
|
2966
|
-
bulkActions = [...DEFAULT_BULK_ACTIONS];
|
2967
|
-
documentActions = [
|
2968
|
-
...DEFAULT_ACTIONS,
|
2969
|
-
...DEFAULT_TABLE_ROW_ACTIONS,
|
2970
|
-
...DEFAULT_HEADER_ACTIONS,
|
2971
|
-
HistoryAction
|
2972
|
-
];
|
2973
|
-
editViewSidePanels = [ActionsPanel];
|
2974
|
-
headerActions = [];
|
2975
|
-
constructor() {
|
2976
|
-
}
|
2977
|
-
addEditViewSidePanel(panels) {
|
2978
|
-
if (Array.isArray(panels)) {
|
2979
|
-
this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
|
2980
|
-
} else if (typeof panels === "function") {
|
2981
|
-
this.editViewSidePanels = panels(this.editViewSidePanels);
|
2982
|
-
} else {
|
2983
|
-
throw new Error(
|
2984
|
-
`Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
|
2985
|
-
panels
|
2986
|
-
)}`
|
2987
|
-
);
|
2988
|
-
}
|
2989
|
-
}
|
2990
|
-
addDocumentAction(actions2) {
|
2991
|
-
if (Array.isArray(actions2)) {
|
2992
|
-
this.documentActions = [...this.documentActions, ...actions2];
|
2993
|
-
} else if (typeof actions2 === "function") {
|
2994
|
-
this.documentActions = actions2(this.documentActions);
|
2995
|
-
} else {
|
2996
|
-
throw new Error(
|
2997
|
-
`Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
|
2998
|
-
actions2
|
2999
|
-
)}`
|
3000
|
-
);
|
3001
|
-
}
|
3002
|
-
}
|
3003
|
-
addDocumentHeaderAction(actions2) {
|
3004
|
-
if (Array.isArray(actions2)) {
|
3005
|
-
this.headerActions = [...this.headerActions, ...actions2];
|
3006
|
-
} else if (typeof actions2 === "function") {
|
3007
|
-
this.headerActions = actions2(this.headerActions);
|
3008
|
-
} else {
|
3009
|
-
throw new Error(
|
3010
|
-
`Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
|
3011
|
-
actions2
|
3012
|
-
)}`
|
3013
|
-
);
|
3014
|
-
}
|
3015
|
-
}
|
3016
|
-
addBulkAction(actions2) {
|
3017
|
-
if (Array.isArray(actions2)) {
|
3018
|
-
this.bulkActions = [...this.bulkActions, ...actions2];
|
3019
|
-
} else if (typeof actions2 === "function") {
|
3020
|
-
this.bulkActions = actions2(this.bulkActions);
|
3021
|
-
} else {
|
3022
|
-
throw new Error(
|
3023
|
-
`Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
|
3024
|
-
actions2
|
3025
|
-
)}`
|
3026
|
-
);
|
3027
|
-
}
|
3028
|
-
}
|
3029
|
-
get config() {
|
3030
|
-
return {
|
3031
|
-
id: PLUGIN_ID,
|
3032
|
-
name: "Content Manager",
|
3033
|
-
injectionZones: INJECTION_ZONES,
|
3034
|
-
apis: {
|
3035
|
-
addBulkAction: this.addBulkAction.bind(this),
|
3036
|
-
addDocumentAction: this.addDocumentAction.bind(this),
|
3037
|
-
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
3038
|
-
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
3039
|
-
getBulkActions: () => this.bulkActions,
|
3040
|
-
getDocumentActions: () => this.documentActions,
|
3041
|
-
getEditViewSidePanels: () => this.editViewSidePanels,
|
3042
|
-
getHeaderActions: () => this.headerActions
|
3043
|
-
}
|
3044
|
-
};
|
3045
|
-
}
|
3046
|
-
}
|
3047
|
-
const getPrintableType = (value) => {
|
3048
|
-
const nativeType = typeof value;
|
3049
|
-
if (nativeType === "object") {
|
3050
|
-
if (value === null)
|
3051
|
-
return "null";
|
3052
|
-
if (Array.isArray(value))
|
3053
|
-
return "array";
|
3054
|
-
if (value instanceof Object && value.constructor.name !== "Object") {
|
3055
|
-
return value.constructor.name;
|
3056
|
-
}
|
3057
|
-
}
|
3058
|
-
return nativeType;
|
3059
|
-
};
|
3060
|
-
const initialState = {
|
3061
|
-
collectionTypeLinks: [],
|
3062
|
-
components: [],
|
3063
|
-
fieldSizes: {},
|
3064
|
-
models: [],
|
3065
|
-
singleTypeLinks: [],
|
3066
|
-
isLoading: true
|
3067
|
-
};
|
3068
|
-
const appSlice = createSlice({
|
3069
|
-
name: "app",
|
3070
|
-
initialState,
|
3071
|
-
reducers: {
|
3072
|
-
setInitialData(state, action) {
|
3073
|
-
const {
|
3074
|
-
authorizedCollectionTypeLinks,
|
3075
|
-
authorizedSingleTypeLinks,
|
3076
|
-
components,
|
3077
|
-
contentTypeSchemas,
|
3078
|
-
fieldSizes
|
3079
|
-
} = action.payload;
|
3080
|
-
state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
|
3081
|
-
({ isDisplayed }) => isDisplayed
|
3082
|
-
);
|
3083
|
-
state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
|
3084
|
-
state.components = components;
|
3085
|
-
state.models = contentTypeSchemas;
|
3086
|
-
state.fieldSizes = fieldSizes;
|
3087
|
-
state.isLoading = false;
|
3088
|
-
}
|
3089
|
-
}
|
3090
|
-
});
|
3091
|
-
const { actions, reducer: reducer$1 } = appSlice;
|
3092
|
-
const { setInitialData } = actions;
|
3093
|
-
const reducer = combineReducers({
|
3094
|
-
app: reducer$1
|
3095
|
-
});
|
3096
|
-
const HOOKS = {
|
3097
|
-
/**
|
3098
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
3099
|
-
* @constant
|
3100
|
-
* @type {string}
|
3101
|
-
*/
|
3102
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
3103
|
-
/**
|
3104
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
3105
|
-
* @constant
|
3106
|
-
* @type {string}
|
3107
|
-
*/
|
3108
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
3109
|
-
/**
|
3110
|
-
* Hook that allows to mutate the CM's edit view layout
|
3111
|
-
* @constant
|
3112
|
-
* @type {string}
|
3113
|
-
*/
|
3114
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
3115
|
-
/**
|
3116
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
3117
|
-
* @constant
|
3118
|
-
* @type {string}
|
3119
|
-
*/
|
3120
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
3121
|
-
};
|
3122
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
3123
|
-
endpoints: (builder) => ({
|
3124
|
-
getContentTypeConfiguration: builder.query({
|
3125
|
-
query: (uid) => ({
|
3126
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
3127
|
-
method: "GET"
|
3128
|
-
}),
|
3129
|
-
transformResponse: (response) => response.data,
|
3130
|
-
providesTags: (_result, _error, uid) => [
|
3131
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
3132
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
3133
|
-
]
|
3134
|
-
}),
|
3135
|
-
getAllContentTypeSettings: builder.query({
|
3136
|
-
query: () => "/content-manager/content-types-settings",
|
3137
|
-
transformResponse: (response) => response.data,
|
3138
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
3139
|
-
}),
|
3140
|
-
updateContentTypeConfiguration: builder.mutation({
|
3141
|
-
query: ({ uid, ...body }) => ({
|
3142
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
3143
|
-
method: "PUT",
|
3144
|
-
data: body
|
3145
|
-
}),
|
3146
|
-
transformResponse: (response) => response.data,
|
3147
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
3148
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
3149
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
3150
|
-
// Is this necessary?
|
3151
|
-
{ type: "InitialData" }
|
3152
|
-
]
|
3153
|
-
})
|
3154
|
-
})
|
3155
|
-
});
|
3156
|
-
const {
|
3157
|
-
useGetContentTypeConfigurationQuery,
|
3158
|
-
useGetAllContentTypeSettingsQuery,
|
3159
|
-
useUpdateContentTypeConfigurationMutation
|
3160
|
-
} = contentTypesApi;
|
3161
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
3162
|
-
const { type } = attribute;
|
3163
|
-
if (type === "relation") {
|
3164
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
3165
|
-
}
|
3166
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
3167
|
-
};
|
3168
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
3169
|
-
if (!mainFieldName) {
|
3170
|
-
return void 0;
|
3171
|
-
}
|
3172
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
3173
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
3174
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
3175
|
-
);
|
3176
|
-
return {
|
3177
|
-
name: mainFieldName,
|
3178
|
-
type: mainFieldType ?? "string"
|
3531
|
+
activeTab: null,
|
3532
|
+
model,
|
3533
|
+
documentId: document.documentId,
|
3534
|
+
collectionType,
|
3535
|
+
document
|
3179
3536
|
};
|
3537
|
+
return /* @__PURE__ */ jsx(
|
3538
|
+
DescriptionComponentRenderer,
|
3539
|
+
{
|
3540
|
+
props,
|
3541
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3542
|
+
children: (actions2) => {
|
3543
|
+
const tableRowActions = actions2.filter((action) => {
|
3544
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
3545
|
+
return positions.includes("table-row");
|
3546
|
+
});
|
3547
|
+
return /* @__PURE__ */ jsx(
|
3548
|
+
DocumentActionsMenu,
|
3549
|
+
{
|
3550
|
+
actions: tableRowActions,
|
3551
|
+
label: formatMessage({
|
3552
|
+
id: "content-manager.containers.list.table.row-actions",
|
3553
|
+
defaultMessage: "Row action"
|
3554
|
+
}),
|
3555
|
+
variant: "ghost"
|
3556
|
+
}
|
3557
|
+
);
|
3558
|
+
}
|
3559
|
+
}
|
3560
|
+
);
|
3180
3561
|
};
|
3181
|
-
const
|
3182
|
-
|
3183
|
-
|
3184
|
-
|
3185
|
-
pagination: false,
|
3186
|
-
defaultSortBy: "",
|
3187
|
-
defaultSortOrder: "asc",
|
3188
|
-
mainField: "id",
|
3189
|
-
pageSize: 10
|
3190
|
-
};
|
3191
|
-
const useDocumentLayout = (model) => {
|
3192
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
3193
|
-
const [{ query }] = useQueryParams();
|
3194
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
3562
|
+
const EditAction = ({ documentId }) => {
|
3563
|
+
const navigate = useNavigate();
|
3564
|
+
const { formatMessage } = useIntl();
|
3565
|
+
const { canRead } = useDocumentRBAC("EditAction", ({ canRead: canRead2 }) => ({ canRead: canRead2 }));
|
3195
3566
|
const { toggleNotification } = useNotification();
|
3196
|
-
const {
|
3197
|
-
|
3198
|
-
|
3199
|
-
|
3200
|
-
|
3201
|
-
|
3202
|
-
|
3203
|
-
|
3204
|
-
|
3205
|
-
|
3206
|
-
|
3207
|
-
|
3208
|
-
|
3209
|
-
|
3567
|
+
const [{ query }] = useQueryParams();
|
3568
|
+
return {
|
3569
|
+
disabled: !canRead,
|
3570
|
+
icon: /* @__PURE__ */ jsx(StyledPencil, {}),
|
3571
|
+
label: formatMessage({
|
3572
|
+
id: "content-manager.actions.edit.label",
|
3573
|
+
defaultMessage: "Edit"
|
3574
|
+
}),
|
3575
|
+
position: "table-row",
|
3576
|
+
onClick: async () => {
|
3577
|
+
if (!documentId) {
|
3578
|
+
console.error(
|
3579
|
+
"You're trying to edit a document without an id, this is likely a bug with Strapi. Please open an issue."
|
3580
|
+
);
|
3581
|
+
toggleNotification({
|
3582
|
+
message: formatMessage({
|
3583
|
+
id: "content-manager.actions.edit.error",
|
3584
|
+
defaultMessage: "An error occurred while trying to edit the document."
|
3585
|
+
}),
|
3586
|
+
type: "danger"
|
3587
|
+
});
|
3588
|
+
return;
|
3589
|
+
}
|
3590
|
+
navigate({
|
3591
|
+
pathname: documentId,
|
3592
|
+
search: stringify({
|
3593
|
+
plugins: query.plugins
|
3594
|
+
})
|
3210
3595
|
});
|
3211
3596
|
}
|
3212
|
-
}, [error, formatAPIError, toggleNotification]);
|
3213
|
-
const editLayout = React.useMemo(
|
3214
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
3215
|
-
layout: [],
|
3216
|
-
components: {},
|
3217
|
-
metadatas: {},
|
3218
|
-
options: {},
|
3219
|
-
settings: DEFAULT_SETTINGS
|
3220
|
-
},
|
3221
|
-
[data, isLoading, schemas, schema, components]
|
3222
|
-
);
|
3223
|
-
const listLayout = React.useMemo(() => {
|
3224
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
3225
|
-
layout: [],
|
3226
|
-
metadatas: {},
|
3227
|
-
options: {},
|
3228
|
-
settings: DEFAULT_SETTINGS
|
3229
|
-
};
|
3230
|
-
}, [data, isLoading, schemas, schema, components]);
|
3231
|
-
const { layout: edit } = React.useMemo(
|
3232
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
3233
|
-
layout: editLayout,
|
3234
|
-
query
|
3235
|
-
}),
|
3236
|
-
[editLayout, query, runHookWaterfall]
|
3237
|
-
);
|
3238
|
-
return {
|
3239
|
-
error,
|
3240
|
-
isLoading,
|
3241
|
-
edit,
|
3242
|
-
list: listLayout
|
3243
3597
|
};
|
3244
3598
|
};
|
3245
|
-
|
3246
|
-
|
3247
|
-
|
3248
|
-
|
3249
|
-
|
3250
|
-
|
3251
|
-
|
3252
|
-
|
3253
|
-
}
|
3254
|
-
|
3255
|
-
const
|
3256
|
-
|
3257
|
-
|
3258
|
-
data.contentType.metadatas,
|
3259
|
-
{ configurations: data.components, schemas: components },
|
3260
|
-
schemas
|
3261
|
-
).reduce((panels, row) => {
|
3262
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
3263
|
-
panels.push([row]);
|
3264
|
-
currentPanelIndex += 2;
|
3265
|
-
} else {
|
3266
|
-
if (!panels[currentPanelIndex]) {
|
3267
|
-
panels.push([]);
|
3268
|
-
}
|
3269
|
-
panels[currentPanelIndex].push(row);
|
3270
|
-
}
|
3271
|
-
return panels;
|
3272
|
-
}, []);
|
3273
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
3274
|
-
(acc, [uid, configuration]) => {
|
3275
|
-
acc[uid] = {
|
3276
|
-
layout: convertEditLayoutToFieldLayouts(
|
3277
|
-
configuration.layouts.edit,
|
3278
|
-
components[uid].attributes,
|
3279
|
-
configuration.metadatas
|
3280
|
-
),
|
3281
|
-
settings: {
|
3282
|
-
...configuration.settings,
|
3283
|
-
icon: components[uid].info.icon,
|
3284
|
-
displayName: components[uid].info.displayName
|
3285
|
-
}
|
3286
|
-
};
|
3287
|
-
return acc;
|
3288
|
-
},
|
3289
|
-
{}
|
3290
|
-
);
|
3291
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
3292
|
-
(acc, [attribute, metadata]) => {
|
3293
|
-
return {
|
3294
|
-
...acc,
|
3295
|
-
[attribute]: metadata.edit
|
3296
|
-
};
|
3297
|
-
},
|
3298
|
-
{}
|
3299
|
-
);
|
3599
|
+
EditAction.type = "edit";
|
3600
|
+
const StyledPencil = styled(Pencil)`
|
3601
|
+
path {
|
3602
|
+
fill: currentColor;
|
3603
|
+
}
|
3604
|
+
`;
|
3605
|
+
const CloneAction = ({ model, documentId }) => {
|
3606
|
+
const navigate = useNavigate();
|
3607
|
+
const { formatMessage } = useIntl();
|
3608
|
+
const { canCreate } = useDocumentRBAC("CloneAction", ({ canCreate: canCreate2 }) => ({ canCreate: canCreate2 }));
|
3609
|
+
const { toggleNotification } = useNotification();
|
3610
|
+
const { autoClone } = useDocumentActions();
|
3611
|
+
const [prohibitedFields, setProhibitedFields] = React.useState([]);
|
3300
3612
|
return {
|
3301
|
-
|
3302
|
-
|
3303
|
-
|
3304
|
-
|
3305
|
-
|
3306
|
-
|
3613
|
+
disabled: !canCreate,
|
3614
|
+
icon: /* @__PURE__ */ jsx(StyledDuplicate, {}),
|
3615
|
+
label: formatMessage({
|
3616
|
+
id: "content-manager.actions.clone.label",
|
3617
|
+
defaultMessage: "Duplicate"
|
3618
|
+
}),
|
3619
|
+
position: "table-row",
|
3620
|
+
onClick: async () => {
|
3621
|
+
if (!documentId) {
|
3622
|
+
console.error(
|
3623
|
+
"You're trying to clone a document in the table without an id, this is likely a bug with Strapi. Please open an issue."
|
3624
|
+
);
|
3625
|
+
toggleNotification({
|
3626
|
+
message: formatMessage({
|
3627
|
+
id: "content-manager.actions.clone.error",
|
3628
|
+
defaultMessage: "An error occurred while trying to clone the document."
|
3629
|
+
}),
|
3630
|
+
type: "danger"
|
3631
|
+
});
|
3632
|
+
return;
|
3633
|
+
}
|
3634
|
+
const res = await autoClone({ model, sourceId: documentId });
|
3635
|
+
if ("data" in res) {
|
3636
|
+
navigate(res.data.documentId);
|
3637
|
+
return true;
|
3638
|
+
}
|
3639
|
+
if (isBaseQueryError(res.error) && res.error.details && typeof res.error.details === "object" && "prohibitedFields" in res.error.details && Array.isArray(res.error.details.prohibitedFields)) {
|
3640
|
+
const prohibitedFields2 = res.error.details.prohibitedFields;
|
3641
|
+
setProhibitedFields(prohibitedFields2);
|
3642
|
+
}
|
3307
3643
|
},
|
3308
|
-
|
3309
|
-
|
3310
|
-
|
3311
|
-
|
3644
|
+
dialog: {
|
3645
|
+
type: "modal",
|
3646
|
+
title: formatMessage({
|
3647
|
+
id: "content-manager.containers.list.autoCloneModal.header",
|
3648
|
+
defaultMessage: "Duplicate"
|
3649
|
+
}),
|
3650
|
+
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3651
|
+
footer: ({ onClose }) => {
|
3652
|
+
return /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", children: [
|
3653
|
+
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3654
|
+
id: "cancel",
|
3655
|
+
defaultMessage: "Cancel"
|
3656
|
+
}) }),
|
3657
|
+
/* @__PURE__ */ jsx(
|
3658
|
+
LinkButton,
|
3659
|
+
{
|
3660
|
+
tag: NavLink,
|
3661
|
+
to: {
|
3662
|
+
pathname: `clone/${documentId}`
|
3663
|
+
},
|
3664
|
+
children: formatMessage({
|
3665
|
+
id: "content-manager.containers.list.autoCloneModal.create",
|
3666
|
+
defaultMessage: "Create"
|
3667
|
+
})
|
3668
|
+
}
|
3669
|
+
)
|
3670
|
+
] });
|
3671
|
+
}
|
3312
3672
|
}
|
3313
3673
|
};
|
3314
3674
|
};
|
3315
|
-
|
3316
|
-
|
3317
|
-
|
3318
|
-
|
3319
|
-
|
3320
|
-
|
3675
|
+
CloneAction.type = "clone";
|
3676
|
+
const StyledDuplicate = styled(Duplicate)`
|
3677
|
+
path {
|
3678
|
+
fill: currentColor;
|
3679
|
+
}
|
3680
|
+
`;
|
3681
|
+
const DEFAULT_TABLE_ROW_ACTIONS = [EditAction, CloneAction];
|
3682
|
+
class ContentManagerPlugin {
|
3683
|
+
/**
|
3684
|
+
* The following properties are the stored ones provided by any plugins registering with
|
3685
|
+
* the content-manager. The function calls however, need to be called at runtime in the
|
3686
|
+
* application, so instead we collate them and run them later with the complete list incl.
|
3687
|
+
* ones already registered & the context of the view.
|
3688
|
+
*/
|
3689
|
+
bulkActions = [...DEFAULT_BULK_ACTIONS];
|
3690
|
+
documentActions = [
|
3691
|
+
...DEFAULT_ACTIONS,
|
3692
|
+
...DEFAULT_TABLE_ROW_ACTIONS,
|
3693
|
+
...DEFAULT_HEADER_ACTIONS
|
3694
|
+
];
|
3695
|
+
editViewSidePanels = [ActionsPanel];
|
3696
|
+
headerActions = [];
|
3697
|
+
constructor() {
|
3698
|
+
}
|
3699
|
+
addEditViewSidePanel(panels) {
|
3700
|
+
if (Array.isArray(panels)) {
|
3701
|
+
this.editViewSidePanels = [...this.editViewSidePanels, ...panels];
|
3702
|
+
} else if (typeof panels === "function") {
|
3703
|
+
this.editViewSidePanels = panels(this.editViewSidePanels);
|
3704
|
+
} else {
|
3705
|
+
throw new Error(
|
3706
|
+
`Expected the \`panels\` passed to \`addEditViewSidePanel\` to be an array or a function, but received ${getPrintableType(
|
3707
|
+
panels
|
3708
|
+
)}`
|
3709
|
+
);
|
3710
|
+
}
|
3711
|
+
}
|
3712
|
+
addDocumentAction(actions2) {
|
3713
|
+
if (Array.isArray(actions2)) {
|
3714
|
+
this.documentActions = [...this.documentActions, ...actions2];
|
3715
|
+
} else if (typeof actions2 === "function") {
|
3716
|
+
this.documentActions = actions2(this.documentActions);
|
3717
|
+
} else {
|
3718
|
+
throw new Error(
|
3719
|
+
`Expected the \`actions\` passed to \`addDocumentAction\` to be an array or a function, but received ${getPrintableType(
|
3720
|
+
actions2
|
3721
|
+
)}`
|
3722
|
+
);
|
3723
|
+
}
|
3724
|
+
}
|
3725
|
+
addDocumentHeaderAction(actions2) {
|
3726
|
+
if (Array.isArray(actions2)) {
|
3727
|
+
this.headerActions = [...this.headerActions, ...actions2];
|
3728
|
+
} else if (typeof actions2 === "function") {
|
3729
|
+
this.headerActions = actions2(this.headerActions);
|
3730
|
+
} else {
|
3731
|
+
throw new Error(
|
3732
|
+
`Expected the \`actions\` passed to \`addDocumentHeaderAction\` to be an array or a function, but received ${getPrintableType(
|
3733
|
+
actions2
|
3734
|
+
)}`
|
3735
|
+
);
|
3736
|
+
}
|
3737
|
+
}
|
3738
|
+
addBulkAction(actions2) {
|
3739
|
+
if (Array.isArray(actions2)) {
|
3740
|
+
this.bulkActions = [...this.bulkActions, ...actions2];
|
3741
|
+
} else if (typeof actions2 === "function") {
|
3742
|
+
this.bulkActions = actions2(this.bulkActions);
|
3743
|
+
} else {
|
3744
|
+
throw new Error(
|
3745
|
+
`Expected the \`actions\` passed to \`addBulkAction\` to be an array or a function, but received ${getPrintableType(
|
3746
|
+
actions2
|
3747
|
+
)}`
|
3748
|
+
);
|
3749
|
+
}
|
3750
|
+
}
|
3751
|
+
get config() {
|
3752
|
+
return {
|
3753
|
+
id: PLUGIN_ID,
|
3754
|
+
name: "Content Manager",
|
3755
|
+
injectionZones: INJECTION_ZONES,
|
3756
|
+
apis: {
|
3757
|
+
addBulkAction: this.addBulkAction.bind(this),
|
3758
|
+
addDocumentAction: this.addDocumentAction.bind(this),
|
3759
|
+
addDocumentHeaderAction: this.addDocumentHeaderAction.bind(this),
|
3760
|
+
addEditViewSidePanel: this.addEditViewSidePanel.bind(this),
|
3761
|
+
getBulkActions: () => this.bulkActions,
|
3762
|
+
getDocumentActions: () => this.documentActions,
|
3763
|
+
getEditViewSidePanels: () => this.editViewSidePanels,
|
3764
|
+
getHeaderActions: () => this.headerActions
|
3321
3765
|
}
|
3322
|
-
|
3323
|
-
|
3324
|
-
|
3325
|
-
|
3326
|
-
|
3327
|
-
|
3328
|
-
|
3329
|
-
|
3330
|
-
|
3331
|
-
|
3332
|
-
|
3333
|
-
|
3334
|
-
|
3335
|
-
|
3336
|
-
|
3337
|
-
size: field.size,
|
3338
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
3339
|
-
visible: metadata.visible ?? true,
|
3340
|
-
type: attribute.type
|
3341
|
-
};
|
3342
|
-
}).filter((field) => field !== null)
|
3343
|
-
);
|
3766
|
+
};
|
3767
|
+
}
|
3768
|
+
}
|
3769
|
+
const getPrintableType = (value) => {
|
3770
|
+
const nativeType = typeof value;
|
3771
|
+
if (nativeType === "object") {
|
3772
|
+
if (value === null)
|
3773
|
+
return "null";
|
3774
|
+
if (Array.isArray(value))
|
3775
|
+
return "array";
|
3776
|
+
if (value instanceof Object && value.constructor.name !== "Object") {
|
3777
|
+
return value.constructor.name;
|
3778
|
+
}
|
3779
|
+
}
|
3780
|
+
return nativeType;
|
3344
3781
|
};
|
3345
|
-
const
|
3346
|
-
|
3347
|
-
|
3348
|
-
|
3349
|
-
}
|
3350
|
-
|
3351
|
-
|
3352
|
-
|
3353
|
-
...acc,
|
3354
|
-
[attribute]: metadata.list
|
3355
|
-
};
|
3356
|
-
},
|
3357
|
-
{}
|
3358
|
-
);
|
3359
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
3360
|
-
data.contentType.layouts.list,
|
3361
|
-
schema?.attributes,
|
3362
|
-
listMetadatas,
|
3363
|
-
{ configurations: data.components, schemas: components },
|
3364
|
-
schemas
|
3365
|
-
);
|
3782
|
+
const HistoryAction = ({ model, document }) => {
|
3783
|
+
const { formatMessage } = useIntl();
|
3784
|
+
const [{ query }] = useQueryParams();
|
3785
|
+
const navigate = useNavigate();
|
3786
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3787
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3788
|
+
return null;
|
3789
|
+
}
|
3366
3790
|
return {
|
3367
|
-
|
3368
|
-
|
3369
|
-
|
3370
|
-
|
3371
|
-
|
3372
|
-
|
3373
|
-
|
3374
|
-
|
3791
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3792
|
+
label: formatMessage({
|
3793
|
+
id: "content-manager.history.document-action",
|
3794
|
+
defaultMessage: "Content History"
|
3795
|
+
}),
|
3796
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3797
|
+
disabled: (
|
3798
|
+
/**
|
3799
|
+
* The user is creating a new document.
|
3800
|
+
* It hasn't been saved yet, so there's no history to go to
|
3801
|
+
*/
|
3802
|
+
!document || /**
|
3803
|
+
* The document has been created but the current dimension has never been saved.
|
3804
|
+
* For example, the user is creating a new locale in an existing document,
|
3805
|
+
* so there's no history for the document in that locale
|
3806
|
+
*/
|
3807
|
+
!document.id || /**
|
3808
|
+
* History is only available for content types created by the user.
|
3809
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3810
|
+
* which start with `admin::` or `plugin::`
|
3811
|
+
*/
|
3812
|
+
!model.startsWith("api::")
|
3813
|
+
),
|
3814
|
+
position: "header"
|
3375
3815
|
};
|
3376
3816
|
};
|
3377
|
-
|
3378
|
-
|
3379
|
-
|
3380
|
-
|
3381
|
-
|
3382
|
-
|
3383
|
-
|
3384
|
-
|
3385
|
-
|
3386
|
-
|
3387
|
-
|
3388
|
-
|
3389
|
-
|
3390
|
-
|
3391
|
-
|
3392
|
-
|
3393
|
-
|
3394
|
-
|
3395
|
-
};
|
3396
|
-
}).filter((field) => field !== null);
|
3817
|
+
HistoryAction.type = "history";
|
3818
|
+
const historyAdmin = {
|
3819
|
+
bootstrap(app) {
|
3820
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3821
|
+
addDocumentAction((actions2) => {
|
3822
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3823
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3824
|
+
return actions2;
|
3825
|
+
});
|
3826
|
+
}
|
3827
|
+
};
|
3828
|
+
const initialState = {
|
3829
|
+
collectionTypeLinks: [],
|
3830
|
+
components: [],
|
3831
|
+
fieldSizes: {},
|
3832
|
+
models: [],
|
3833
|
+
singleTypeLinks: [],
|
3834
|
+
isLoading: true
|
3397
3835
|
};
|
3836
|
+
const appSlice = createSlice({
|
3837
|
+
name: "app",
|
3838
|
+
initialState,
|
3839
|
+
reducers: {
|
3840
|
+
setInitialData(state, action) {
|
3841
|
+
const {
|
3842
|
+
authorizedCollectionTypeLinks,
|
3843
|
+
authorizedSingleTypeLinks,
|
3844
|
+
components,
|
3845
|
+
contentTypeSchemas,
|
3846
|
+
fieldSizes
|
3847
|
+
} = action.payload;
|
3848
|
+
state.collectionTypeLinks = authorizedCollectionTypeLinks.filter(
|
3849
|
+
({ isDisplayed }) => isDisplayed
|
3850
|
+
);
|
3851
|
+
state.singleTypeLinks = authorizedSingleTypeLinks.filter(({ isDisplayed }) => isDisplayed);
|
3852
|
+
state.components = components;
|
3853
|
+
state.models = contentTypeSchemas;
|
3854
|
+
state.fieldSizes = fieldSizes;
|
3855
|
+
state.isLoading = false;
|
3856
|
+
}
|
3857
|
+
}
|
3858
|
+
});
|
3859
|
+
const { actions, reducer: reducer$1 } = appSlice;
|
3860
|
+
const { setInitialData } = actions;
|
3861
|
+
const reducer = combineReducers({
|
3862
|
+
app: reducer$1
|
3863
|
+
});
|
3398
3864
|
const index = {
|
3399
3865
|
register(app) {
|
3400
3866
|
const cm = new ContentManagerPlugin();
|
@@ -3409,15 +3875,29 @@ const index = {
|
|
3409
3875
|
defaultMessage: "Content Manager"
|
3410
3876
|
},
|
3411
3877
|
permissions: [],
|
3412
|
-
Component: () => import("./layout-BinjszSQ.mjs").then((mod) => ({ default: mod.Layout })),
|
3413
3878
|
position: 1
|
3414
3879
|
});
|
3880
|
+
app.router.addRoute({
|
3881
|
+
path: "content-manager/*",
|
3882
|
+
lazy: async () => {
|
3883
|
+
const { Layout } = await import("./layout-BNqvLR_b.mjs");
|
3884
|
+
return {
|
3885
|
+
Component: Layout
|
3886
|
+
};
|
3887
|
+
},
|
3888
|
+
children: routes
|
3889
|
+
});
|
3415
3890
|
app.registerPlugin(cm.config);
|
3416
3891
|
},
|
3892
|
+
bootstrap(app) {
|
3893
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
3894
|
+
historyAdmin.bootstrap(app);
|
3895
|
+
}
|
3896
|
+
},
|
3417
3897
|
async registerTrads({ locales }) {
|
3418
3898
|
const importedTrads = await Promise.all(
|
3419
3899
|
locales.map((locale) => {
|
3420
|
-
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-
|
3900
|
+
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-BrCTWlZv.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 }) => {
|
3421
3901
|
return {
|
3422
3902
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3423
3903
|
locale
|
@@ -3438,43 +3918,42 @@ export {
|
|
3438
3918
|
BulkActionsRenderer as B,
|
3439
3919
|
COLLECTION_TYPES as C,
|
3440
3920
|
DocumentStatus as D,
|
3441
|
-
|
3442
|
-
|
3443
|
-
|
3921
|
+
DEFAULT_SETTINGS as E,
|
3922
|
+
convertEditLayoutToFieldLayouts as F,
|
3923
|
+
useDocument as G,
|
3444
3924
|
HOOKS as H,
|
3445
3925
|
InjectionZone as I,
|
3446
|
-
|
3447
|
-
|
3448
|
-
useDocumentActions as L,
|
3926
|
+
index as J,
|
3927
|
+
useDocumentActions as K,
|
3449
3928
|
Panels as P,
|
3450
3929
|
RelativeTime as R,
|
3451
3930
|
SINGLE_TYPES as S,
|
3452
3931
|
TableActions as T,
|
3453
|
-
|
3454
|
-
|
3455
|
-
|
3456
|
-
|
3457
|
-
|
3458
|
-
|
3932
|
+
useGetInitialDataQuery as a,
|
3933
|
+
useGetAllContentTypeSettingsQuery as b,
|
3934
|
+
useDoc as c,
|
3935
|
+
buildValidParams as d,
|
3936
|
+
contentManagerApi as e,
|
3937
|
+
useDocumentRBAC as f,
|
3459
3938
|
getTranslation as g,
|
3460
|
-
|
3461
|
-
|
3462
|
-
|
3463
|
-
|
3464
|
-
|
3465
|
-
|
3466
|
-
|
3939
|
+
useDocumentLayout as h,
|
3940
|
+
createYupSchema as i,
|
3941
|
+
Header as j,
|
3942
|
+
PERMISSIONS as k,
|
3943
|
+
DocumentRBAC as l,
|
3944
|
+
DOCUMENT_META_FIELDS as m,
|
3945
|
+
useDocLayout as n,
|
3467
3946
|
useGetContentTypeConfigurationQuery as o,
|
3468
3947
|
CREATOR_FIELDS as p,
|
3469
3948
|
getMainField as q,
|
3470
|
-
|
3949
|
+
getDisplayName as r,
|
3471
3950
|
setInitialData as s,
|
3472
|
-
|
3473
|
-
|
3474
|
-
|
3475
|
-
|
3476
|
-
|
3477
|
-
|
3478
|
-
|
3479
|
-
};
|
3480
|
-
//# sourceMappingURL=index-
|
3951
|
+
checkIfAttributeIsDisplayable as t,
|
3952
|
+
useContentTypeSchema as u,
|
3953
|
+
useGetAllDocumentsQuery as v,
|
3954
|
+
convertListLayoutToFieldLayouts as w,
|
3955
|
+
capitalise as x,
|
3956
|
+
useUpdateContentTypeConfigurationMutation as y,
|
3957
|
+
extractContentTypeComponents as z
|
3958
|
+
};
|
3959
|
+
//# sourceMappingURL=index-C9TJPyni.mjs.map
|