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