@strapi/content-manager 5.0.0-rc.3 → 5.0.0-rc.30
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-BAgyHiMm.mjs → ComponentConfigurationPage-DfFSZQxe.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-DfFSZQxe.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-FqfsxQ1j.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-FqfsxQ1j.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-Cn0e8t3I.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-Cn0e8t3I.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-DdPNAbl3.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-DdPNAbl3.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-B82x_x1b.mjs} +30 -9
- package/dist/_chunks/EditViewPage-B82x_x1b.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-DlxEHhUt.js} +30 -9
- package/dist/_chunks/EditViewPage-DlxEHhUt.js.map +1 -0
- package/dist/_chunks/{Field-Bfph5SOd.js → Field-COL25JiC.js} +174 -102
- package/dist/_chunks/Field-COL25JiC.js.map +1 -0
- package/dist/_chunks/{Field-Cs7duwWd.mjs → Field-DufHXW17.mjs} +172 -100
- package/dist/_chunks/Field-DufHXW17.mjs.map +1 -0
- package/dist/_chunks/{Form-CPYqIWDG.js → Form-BssUwrTO.js} +36 -17
- package/dist/_chunks/Form-BssUwrTO.js.map +1 -0
- package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-u_kAOhwB.mjs} +36 -17
- package/dist/_chunks/Form-u_kAOhwB.mjs.map +1 -0
- package/dist/_chunks/{History-DNQkXANT.js → History-C9t9UqpO.js} +23 -10
- package/dist/_chunks/History-C9t9UqpO.js.map +1 -0
- package/dist/_chunks/{History-wrnHqf09.mjs → History-DRwA3oMM.mjs} +24 -11
- package/dist/_chunks/History-DRwA3oMM.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-BXYPohh-.js} +14 -4
- package/dist/_chunks/ListConfigurationPage-BXYPohh-.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-BxfQJzPk.mjs} +14 -4
- package/dist/_chunks/ListConfigurationPage-BxfQJzPk.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-CELx2ysp.mjs} +47 -38
- package/dist/_chunks/ListViewPage-CELx2ysp.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-D2VD8Szg.js} +49 -40
- package/dist/_chunks/ListViewPage-D2VD8Szg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-BV9IjJSM.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-BV9IjJSM.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-DtJ9jcfk.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-DtJ9jcfk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-DWleVYK7.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-DWleVYK7.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-Dp8NpF9I.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-Dp8NpF9I.js.map} +1 -1
- package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-BTcf5xaw.mjs} +33 -24
- package/dist/_chunks/Relations-BTcf5xaw.mjs.map +1 -0
- package/dist/_chunks/{Relations-CtELXYIK.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-OerGjbAN.js → index-BdMf2lfT.js} +1921 -1758
- package/dist/_chunks/index-BdMf2lfT.js.map +1 -0
- package/dist/_chunks/{index-c_5DdJi-.mjs → index-wnqzm4Q8.mjs} +1941 -1778
- package/dist/_chunks/index-wnqzm4Q8.mjs.map +1 -0
- package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-2CfjL0T9.mjs} +22 -9
- package/dist/_chunks/layout-2CfjL0T9.mjs.map +1 -0
- package/dist/_chunks/{layout-Ci7qHlFb.js → layout-B2MyZU-_.js} +21 -8
- package/dist/_chunks/layout-B2MyZU-_.js.map +1 -0
- package/dist/_chunks/{relations-COBpStiF.js → relations-BH7JJGGe.js} +2 -2
- package/dist/_chunks/{relations-COBpStiF.js.map → relations-BH7JJGGe.js.map} +1 -1
- package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-C0w0GcXi.mjs} +2 -2
- package/dist/_chunks/{relations-BIdWFjdq.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 +170 -92
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +171 -93
- 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 +2 -1
- 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/document-metadata.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-BLsjc5F-.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
- package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
- package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
- package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
- package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
- package/dist/_chunks/History-DNQkXANT.js.map +0 -1
- package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
- package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
- package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
- package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
- package/dist/_chunks/index-OerGjbAN.js.map +0 -1
- package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
- package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
- package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -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,
|
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
|
}),
|
@@ -264,6 +278,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
264
278
|
}),
|
265
279
|
providesTags: (result, _error, arg) => {
|
266
280
|
return [
|
281
|
+
{ type: "Document", id: `ALL_LIST` },
|
267
282
|
{ type: "Document", id: `${arg.model}_LIST` },
|
268
283
|
...result?.results.map(({ documentId }) => ({
|
269
284
|
type: "Document",
|
@@ -302,6 +317,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
302
317
|
{
|
303
318
|
type: "Document",
|
304
319
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
320
|
+
},
|
321
|
+
// Make it easy to invalidate all individual documents queries for a model
|
322
|
+
{
|
323
|
+
type: "Document",
|
324
|
+
id: `${model}_ALL_ITEMS`
|
305
325
|
}
|
306
326
|
];
|
307
327
|
}
|
@@ -365,7 +385,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
365
385
|
type: "Document",
|
366
386
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
367
387
|
},
|
368
|
-
"Relations"
|
388
|
+
"Relations",
|
389
|
+
{ type: "UidAvailability", id: model }
|
369
390
|
];
|
370
391
|
},
|
371
392
|
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
@@ -448,20 +469,39 @@ const buildValidParams = (query) => {
|
|
448
469
|
const isBaseQueryError = (error) => {
|
449
470
|
return error.name !== void 0;
|
450
471
|
};
|
451
|
-
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 }) => {
|
452
491
|
const createModelSchema = (attributes2) => yup.object().shape(
|
453
492
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
454
493
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
455
494
|
return acc;
|
456
495
|
}
|
457
496
|
const validations = [
|
497
|
+
addNullableValidation,
|
458
498
|
addRequiredValidation,
|
459
499
|
addMinLengthValidation,
|
460
500
|
addMaxLengthValidation,
|
461
501
|
addMinValidation,
|
462
502
|
addMaxValidation,
|
463
503
|
addRegexValidation
|
464
|
-
].map((fn) => fn(attribute));
|
504
|
+
].map((fn) => fn(attribute, options));
|
465
505
|
const transformSchema = pipe(...validations);
|
466
506
|
switch (attribute.type) {
|
467
507
|
case "component": {
|
@@ -471,12 +511,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
471
511
|
...acc,
|
472
512
|
[name]: transformSchema(
|
473
513
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
474
|
-
)
|
514
|
+
).test(arrayValidator(attribute, options))
|
475
515
|
};
|
476
516
|
} else {
|
477
517
|
return {
|
478
518
|
...acc,
|
479
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
519
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
480
520
|
};
|
481
521
|
}
|
482
522
|
}
|
@@ -498,7 +538,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
498
538
|
}
|
499
539
|
)
|
500
540
|
)
|
501
|
-
)
|
541
|
+
).test(arrayValidator(attribute, options))
|
502
542
|
};
|
503
543
|
case "relation":
|
504
544
|
return {
|
@@ -510,7 +550,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
510
550
|
} else if (Array.isArray(value)) {
|
511
551
|
return yup.array().of(
|
512
552
|
yup.object().shape({
|
513
|
-
id: yup.
|
553
|
+
id: yup.number().required()
|
514
554
|
})
|
515
555
|
);
|
516
556
|
} else if (typeof value === "object") {
|
@@ -562,6 +602,14 @@ const createAttributeSchema = (attribute) => {
|
|
562
602
|
if (!value || typeof value === "string" && value.length === 0) {
|
563
603
|
return true;
|
564
604
|
}
|
605
|
+
if (typeof value === "object") {
|
606
|
+
try {
|
607
|
+
JSON.stringify(value);
|
608
|
+
return true;
|
609
|
+
} catch (err) {
|
610
|
+
return false;
|
611
|
+
}
|
612
|
+
}
|
565
613
|
try {
|
566
614
|
JSON.parse(value);
|
567
615
|
return true;
|
@@ -580,13 +628,7 @@ const createAttributeSchema = (attribute) => {
|
|
580
628
|
return yup.mixed();
|
581
629
|
}
|
582
630
|
};
|
583
|
-
const
|
584
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
585
|
-
return schema.min(1, translatedErrors.required);
|
586
|
-
}
|
587
|
-
if (attribute.required && attribute.type !== "relation") {
|
588
|
-
return schema.required(translatedErrors.required);
|
589
|
-
}
|
631
|
+
const nullableSchema = (schema) => {
|
590
632
|
return schema?.nullable ? schema.nullable() : (
|
591
633
|
// In some cases '.nullable' will not be available on the schema.
|
592
634
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -594,7 +636,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
594
636
|
schema
|
595
637
|
);
|
596
638
|
};
|
597
|
-
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
|
+
}
|
598
655
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
599
656
|
return schema.min(attribute.minLength, {
|
600
657
|
...translatedErrors.minLength,
|
@@ -616,32 +673,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
616
673
|
}
|
617
674
|
return schema;
|
618
675
|
};
|
619
|
-
const addMinValidation = (attribute) => (schema) => {
|
620
|
-
if ("
|
676
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
677
|
+
if (options.status === "draft") {
|
678
|
+
return schema;
|
679
|
+
}
|
680
|
+
if ("min" in attribute && "min" in schema) {
|
621
681
|
const min = toInteger(attribute.min);
|
622
|
-
if (
|
623
|
-
if (!attribute.required && "test" in schema && min) {
|
624
|
-
return schema.test(
|
625
|
-
"custom-min",
|
626
|
-
{
|
627
|
-
...translatedErrors.min,
|
628
|
-
values: {
|
629
|
-
min: attribute.min
|
630
|
-
}
|
631
|
-
},
|
632
|
-
(value) => {
|
633
|
-
if (!value) {
|
634
|
-
return true;
|
635
|
-
}
|
636
|
-
if (Array.isArray(value) && value.length === 0) {
|
637
|
-
return true;
|
638
|
-
}
|
639
|
-
return value.length >= min;
|
640
|
-
}
|
641
|
-
);
|
642
|
-
}
|
643
|
-
}
|
644
|
-
if ("min" in schema && min) {
|
682
|
+
if (min) {
|
645
683
|
return schema.min(min, {
|
646
684
|
...translatedErrors.min,
|
647
685
|
values: {
|
@@ -759,19 +797,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
759
797
|
}, {});
|
760
798
|
return componentsByKey;
|
761
799
|
};
|
762
|
-
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);
|
763
899
|
const { toggleNotification } = useNotification();
|
764
900
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
901
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
765
902
|
const {
|
766
|
-
|
767
|
-
isLoading:
|
768
|
-
|
769
|
-
|
770
|
-
} =
|
771
|
-
|
772
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
773
|
-
});
|
774
|
-
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;
|
775
909
|
React.useEffect(() => {
|
776
910
|
if (error) {
|
777
911
|
toggleNotification({
|
@@ -779,362 +913,440 @@ const useDocument = (args, opts) => {
|
|
779
913
|
message: formatAPIError(error)
|
780
914
|
});
|
781
915
|
}
|
782
|
-
}, [
|
783
|
-
const
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
(document) => {
|
791
|
-
if (!validationSchema) {
|
792
|
-
throw new Error(
|
793
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
794
|
-
);
|
795
|
-
}
|
796
|
-
try {
|
797
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
798
|
-
return null;
|
799
|
-
} catch (error2) {
|
800
|
-
if (error2 instanceof ValidationError) {
|
801
|
-
return getYupValidationErrors(error2);
|
802
|
-
}
|
803
|
-
throw error2;
|
804
|
-
}
|
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
|
805
924
|
},
|
806
|
-
[
|
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]
|
807
941
|
);
|
808
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
809
942
|
return {
|
810
|
-
|
811
|
-
document: data?.data,
|
812
|
-
meta: data?.meta,
|
943
|
+
error,
|
813
944
|
isLoading,
|
814
|
-
|
815
|
-
|
816
|
-
};
|
817
|
-
};
|
818
|
-
const useDoc = () => {
|
819
|
-
const { id, slug, collectionType, origin } = useParams();
|
820
|
-
const [{ query }] = useQueryParams();
|
821
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
822
|
-
if (!collectionType) {
|
823
|
-
throw new Error("Could not find collectionType in url params");
|
824
|
-
}
|
825
|
-
if (!slug) {
|
826
|
-
throw new Error("Could not find model in url params");
|
827
|
-
}
|
828
|
-
return {
|
829
|
-
collectionType,
|
830
|
-
model: slug,
|
831
|
-
id: origin || id === "create" ? void 0 : id,
|
832
|
-
...useDocument(
|
833
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
834
|
-
{
|
835
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
836
|
-
}
|
837
|
-
)
|
945
|
+
edit,
|
946
|
+
list: listLayout
|
838
947
|
};
|
839
948
|
};
|
840
|
-
const
|
841
|
-
|
842
|
-
|
843
|
-
}
|
844
|
-
return Object.keys(trad).reduce((acc, current) => {
|
845
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
846
|
-
return acc;
|
847
|
-
}, {});
|
848
|
-
};
|
849
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
850
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
851
|
-
id: "notification.error",
|
852
|
-
defaultMessage: "An error occurred, please try again"
|
949
|
+
const useDocLayout = () => {
|
950
|
+
const { model } = useDoc();
|
951
|
+
return useDocumentLayout(model);
|
853
952
|
};
|
854
|
-
const
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
const
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
message: formatAPIError(res.error)
|
874
|
-
});
|
875
|
-
return { error: res.error };
|
876
|
-
}
|
877
|
-
toggleNotification({
|
878
|
-
type: "success",
|
879
|
-
message: formatMessage({
|
880
|
-
id: getTranslation("success.record.delete"),
|
881
|
-
defaultMessage: "Deleted document"
|
882
|
-
})
|
883
|
-
});
|
884
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
885
|
-
return res.data;
|
886
|
-
} catch (err) {
|
887
|
-
toggleNotification({
|
888
|
-
type: "danger",
|
889
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
890
|
-
});
|
891
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
892
|
-
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([]);
|
893
972
|
}
|
894
|
-
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
const
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
});
|
912
|
-
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
|
913
990
|
}
|
914
|
-
|
915
|
-
|
916
|
-
title: formatMessage({
|
917
|
-
id: getTranslation("success.records.delete"),
|
918
|
-
defaultMessage: "Successfully deleted."
|
919
|
-
}),
|
920
|
-
message: ""
|
921
|
-
});
|
922
|
-
trackUsage("didBulkDeleteEntries");
|
923
|
-
return res.data;
|
924
|
-
} catch (err) {
|
925
|
-
toggleNotification({
|
926
|
-
type: "danger",
|
927
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
928
|
-
});
|
929
|
-
trackUsage("didNotBulkDeleteEntries");
|
930
|
-
throw err;
|
931
|
-
}
|
991
|
+
};
|
992
|
+
return acc;
|
932
993
|
},
|
933
|
-
|
994
|
+
{}
|
934
995
|
);
|
935
|
-
const
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
model,
|
942
|
-
documentId,
|
943
|
-
params
|
944
|
-
});
|
945
|
-
if ("error" in res) {
|
946
|
-
toggleNotification({
|
947
|
-
type: "danger",
|
948
|
-
message: formatAPIError(res.error)
|
949
|
-
});
|
950
|
-
return { error: res.error };
|
951
|
-
}
|
952
|
-
toggleNotification({
|
953
|
-
type: "success",
|
954
|
-
message: formatMessage({
|
955
|
-
id: "content-manager.success.record.discard",
|
956
|
-
defaultMessage: "Changes discarded"
|
957
|
-
})
|
958
|
-
});
|
959
|
-
return res.data;
|
960
|
-
} catch (err) {
|
961
|
-
toggleNotification({
|
962
|
-
type: "danger",
|
963
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
964
|
-
});
|
965
|
-
throw err;
|
966
|
-
}
|
996
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
997
|
+
(acc, [attribute, metadata]) => {
|
998
|
+
return {
|
999
|
+
...acc,
|
1000
|
+
[attribute]: metadata.edit
|
1001
|
+
};
|
967
1002
|
},
|
968
|
-
|
1003
|
+
{}
|
969
1004
|
);
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
model,
|
978
|
-
documentId,
|
979
|
-
data,
|
980
|
-
params
|
981
|
-
});
|
982
|
-
if ("error" in res) {
|
983
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
984
|
-
return { error: res.error };
|
985
|
-
}
|
986
|
-
trackUsage("didPublishEntry");
|
987
|
-
toggleNotification({
|
988
|
-
type: "success",
|
989
|
-
message: formatMessage({
|
990
|
-
id: getTranslation("success.record.publish"),
|
991
|
-
defaultMessage: "Published document"
|
992
|
-
})
|
993
|
-
});
|
994
|
-
return res.data;
|
995
|
-
} catch (err) {
|
996
|
-
toggleNotification({
|
997
|
-
type: "danger",
|
998
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
999
|
-
});
|
1000
|
-
throw err;
|
1001
|
-
}
|
1005
|
+
return {
|
1006
|
+
layout: panelledEditAttributes,
|
1007
|
+
components: componentEditAttributes,
|
1008
|
+
metadatas: editMetadatas,
|
1009
|
+
settings: {
|
1010
|
+
...data.contentType.settings,
|
1011
|
+
displayName: schema?.info.displayName
|
1002
1012
|
},
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
return { error: res.error };
|
1017
|
-
}
|
1018
|
-
toggleNotification({
|
1019
|
-
type: "success",
|
1020
|
-
message: formatMessage({
|
1021
|
-
id: getTranslation("success.record.publish"),
|
1022
|
-
defaultMessage: "Published document"
|
1023
|
-
})
|
1024
|
-
});
|
1025
|
-
return res.data;
|
1026
|
-
} catch (err) {
|
1027
|
-
toggleNotification({
|
1028
|
-
type: "danger",
|
1029
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1030
|
-
});
|
1031
|
-
throw err;
|
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;
|
1032
1026
|
}
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
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)
|
1041
1048
|
);
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
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
|
+
}
|
1045
1142
|
try {
|
1046
|
-
|
1047
|
-
|
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({
|
1048
1257
|
collectionType,
|
1049
1258
|
model,
|
1050
1259
|
documentId,
|
1051
|
-
data,
|
1052
1260
|
params
|
1053
1261
|
});
|
1054
1262
|
if ("error" in res) {
|
1055
|
-
toggleNotification({
|
1056
|
-
|
1263
|
+
toggleNotification({
|
1264
|
+
type: "danger",
|
1265
|
+
message: formatAPIError(res.error)
|
1266
|
+
});
|
1057
1267
|
return { error: res.error };
|
1058
1268
|
}
|
1059
|
-
trackUsage("didEditEntry", trackerProperty);
|
1060
1269
|
toggleNotification({
|
1061
1270
|
type: "success",
|
1062
1271
|
message: formatMessage({
|
1063
|
-
id: getTranslation("success.record.
|
1064
|
-
defaultMessage: "
|
1272
|
+
id: getTranslation("success.record.delete"),
|
1273
|
+
defaultMessage: "Deleted document"
|
1065
1274
|
})
|
1066
1275
|
});
|
1276
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1067
1277
|
return res.data;
|
1068
1278
|
} catch (err) {
|
1069
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1070
1279
|
toggleNotification({
|
1071
1280
|
type: "danger",
|
1072
1281
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1073
1282
|
});
|
1283
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1074
1284
|
throw err;
|
1075
1285
|
}
|
1076
1286
|
},
|
1077
|
-
[trackUsage,
|
1287
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1078
1288
|
);
|
1079
|
-
const [
|
1080
|
-
const
|
1081
|
-
async ({
|
1289
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1290
|
+
const deleteMany = React.useCallback(
|
1291
|
+
async ({ model, documentIds, params }) => {
|
1082
1292
|
try {
|
1083
|
-
trackUsage("
|
1084
|
-
const res = await
|
1085
|
-
collectionType,
|
1293
|
+
trackUsage("willBulkDeleteEntries");
|
1294
|
+
const res = await deleteManyDocuments({
|
1086
1295
|
model,
|
1087
|
-
|
1088
|
-
params
|
1089
|
-
data: {
|
1090
|
-
discardDraft
|
1091
|
-
}
|
1296
|
+
documentIds,
|
1297
|
+
params
|
1092
1298
|
});
|
1093
1299
|
if ("error" in res) {
|
1094
|
-
toggleNotification({
|
1300
|
+
toggleNotification({
|
1301
|
+
type: "danger",
|
1302
|
+
message: formatAPIError(res.error)
|
1303
|
+
});
|
1095
1304
|
return { error: res.error };
|
1096
1305
|
}
|
1097
|
-
trackUsage("didUnpublishEntry");
|
1098
1306
|
toggleNotification({
|
1099
1307
|
type: "success",
|
1100
|
-
|
1101
|
-
id: getTranslation("success.
|
1102
|
-
defaultMessage: "
|
1103
|
-
})
|
1308
|
+
title: formatMessage({
|
1309
|
+
id: getTranslation("success.records.delete"),
|
1310
|
+
defaultMessage: "Successfully deleted."
|
1311
|
+
}),
|
1312
|
+
message: ""
|
1104
1313
|
});
|
1314
|
+
trackUsage("didBulkDeleteEntries");
|
1105
1315
|
return res.data;
|
1106
1316
|
} catch (err) {
|
1107
1317
|
toggleNotification({
|
1108
1318
|
type: "danger",
|
1109
1319
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1110
1320
|
});
|
1321
|
+
trackUsage("didNotBulkDeleteEntries");
|
1111
1322
|
throw err;
|
1112
1323
|
}
|
1113
1324
|
},
|
1114
|
-
[trackUsage,
|
1325
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1115
1326
|
);
|
1116
|
-
const [
|
1117
|
-
const
|
1118
|
-
async ({ model,
|
1327
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1328
|
+
const discard = React.useCallback(
|
1329
|
+
async ({ collectionType, model, documentId, params }) => {
|
1119
1330
|
try {
|
1120
|
-
|
1121
|
-
|
1331
|
+
const res = await discardDocument({
|
1332
|
+
collectionType,
|
1122
1333
|
model,
|
1123
|
-
|
1334
|
+
documentId,
|
1124
1335
|
params
|
1125
1336
|
});
|
1126
1337
|
if ("error" in res) {
|
1127
|
-
toggleNotification({
|
1338
|
+
toggleNotification({
|
1339
|
+
type: "danger",
|
1340
|
+
message: formatAPIError(res.error)
|
1341
|
+
});
|
1128
1342
|
return { error: res.error };
|
1129
1343
|
}
|
1130
|
-
trackUsage("didBulkUnpublishEntries");
|
1131
1344
|
toggleNotification({
|
1132
1345
|
type: "success",
|
1133
|
-
|
1134
|
-
id:
|
1135
|
-
defaultMessage: "
|
1136
|
-
})
|
1137
|
-
message: ""
|
1346
|
+
message: formatMessage({
|
1347
|
+
id: "content-manager.success.record.discard",
|
1348
|
+
defaultMessage: "Changes discarded"
|
1349
|
+
})
|
1138
1350
|
});
|
1139
1351
|
return res.data;
|
1140
1352
|
} catch (err) {
|
@@ -1142,7 +1354,187 @@ const useDocumentActions = () => {
|
|
1142
1354
|
type: "danger",
|
1143
1355
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1144
1356
|
});
|
1145
|
-
|
1357
|
+
throw err;
|
1358
|
+
}
|
1359
|
+
},
|
1360
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1361
|
+
);
|
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");
|
1146
1538
|
throw err;
|
1147
1539
|
}
|
1148
1540
|
},
|
@@ -1170,6 +1562,7 @@ const useDocumentActions = () => {
|
|
1170
1562
|
defaultMessage: "Saved document"
|
1171
1563
|
})
|
1172
1564
|
});
|
1565
|
+
setCurrentStep("contentManager.success");
|
1173
1566
|
return res.data;
|
1174
1567
|
} catch (err) {
|
1175
1568
|
toggleNotification({
|
@@ -1209,7 +1602,7 @@ const useDocumentActions = () => {
|
|
1209
1602
|
throw err;
|
1210
1603
|
}
|
1211
1604
|
},
|
1212
|
-
[autoCloneDocument,
|
1605
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1213
1606
|
);
|
1214
1607
|
const [cloneDocument] = useCloneDocumentMutation();
|
1215
1608
|
const clone = React.useCallback(
|
@@ -1235,6 +1628,7 @@ const useDocumentActions = () => {
|
|
1235
1628
|
defaultMessage: "Cloned document"
|
1236
1629
|
})
|
1237
1630
|
});
|
1631
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1238
1632
|
return res.data;
|
1239
1633
|
} catch (err) {
|
1240
1634
|
toggleNotification({
|
@@ -1245,7 +1639,7 @@ const useDocumentActions = () => {
|
|
1245
1639
|
throw err;
|
1246
1640
|
}
|
1247
1641
|
},
|
1248
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1642
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1249
1643
|
);
|
1250
1644
|
const [getDoc] = useLazyGetDocumentQuery();
|
1251
1645
|
const getDocument = React.useCallback(
|
@@ -1271,7 +1665,7 @@ const useDocumentActions = () => {
|
|
1271
1665
|
};
|
1272
1666
|
};
|
1273
1667
|
const ProtectedHistoryPage = lazy(
|
1274
|
-
() => import("./History-
|
1668
|
+
() => import("./History-DRwA3oMM.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1275
1669
|
);
|
1276
1670
|
const routes$1 = [
|
1277
1671
|
{
|
@@ -1284,31 +1678,31 @@ const routes$1 = [
|
|
1284
1678
|
}
|
1285
1679
|
];
|
1286
1680
|
const ProtectedEditViewPage = lazy(
|
1287
|
-
() => import("./EditViewPage-
|
1681
|
+
() => import("./EditViewPage-B82x_x1b.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1288
1682
|
);
|
1289
1683
|
const ProtectedListViewPage = lazy(
|
1290
|
-
() => import("./ListViewPage-
|
1684
|
+
() => import("./ListViewPage-CELx2ysp.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1291
1685
|
);
|
1292
1686
|
const ProtectedListConfiguration = lazy(
|
1293
|
-
() => import("./ListConfigurationPage-
|
1687
|
+
() => import("./ListConfigurationPage-BxfQJzPk.mjs").then((mod) => ({
|
1294
1688
|
default: mod.ProtectedListConfiguration
|
1295
1689
|
}))
|
1296
1690
|
);
|
1297
1691
|
const ProtectedEditConfigurationPage = lazy(
|
1298
|
-
() => import("./EditConfigurationPage-
|
1692
|
+
() => import("./EditConfigurationPage-DdPNAbl3.mjs").then((mod) => ({
|
1299
1693
|
default: mod.ProtectedEditConfigurationPage
|
1300
1694
|
}))
|
1301
1695
|
);
|
1302
1696
|
const ProtectedComponentConfigurationPage = lazy(
|
1303
|
-
() => import("./ComponentConfigurationPage-
|
1697
|
+
() => import("./ComponentConfigurationPage-DfFSZQxe.mjs").then((mod) => ({
|
1304
1698
|
default: mod.ProtectedComponentConfigurationPage
|
1305
1699
|
}))
|
1306
1700
|
);
|
1307
1701
|
const NoPermissions = lazy(
|
1308
|
-
() => import("./NoPermissionsPage-
|
1702
|
+
() => import("./NoPermissionsPage-DWleVYK7.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1309
1703
|
);
|
1310
1704
|
const NoContentType = lazy(
|
1311
|
-
() => import("./NoContentTypePage-
|
1705
|
+
() => import("./NoContentTypePage-DtJ9jcfk.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1312
1706
|
);
|
1313
1707
|
const CollectionTypePages = () => {
|
1314
1708
|
const { collectionType } = useParams();
|
@@ -1349,1066 +1743,750 @@ const routes = [
|
|
1349
1743
|
{
|
1350
1744
|
path: "403",
|
1351
1745
|
Component: NoPermissions
|
1352
|
-
},
|
1353
|
-
{
|
1354
|
-
path: "no-content-types",
|
1355
|
-
Component: NoContentType
|
1356
|
-
},
|
1357
|
-
...routes$1
|
1358
|
-
];
|
1359
|
-
const DocumentActions = ({ actions: actions2 }) => {
|
1360
|
-
const { formatMessage } = useIntl();
|
1361
|
-
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1362
|
-
if (action.position === void 0) {
|
1363
|
-
return true;
|
1364
|
-
}
|
1365
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1366
|
-
return positions.includes("panel");
|
1367
|
-
});
|
1368
|
-
if (!primaryAction) {
|
1369
|
-
return null;
|
1370
|
-
}
|
1371
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1372
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1373
|
-
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1374
|
-
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1375
|
-
DocumentActionsMenu,
|
1376
|
-
{
|
1377
|
-
actions: restActions,
|
1378
|
-
label: formatMessage({
|
1379
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1380
|
-
defaultMessage: "More document actions"
|
1381
|
-
})
|
1382
|
-
}
|
1383
|
-
) : null
|
1384
|
-
] }),
|
1385
|
-
secondaryAction ? /* @__PURE__ */ jsx(
|
1386
|
-
DocumentActionButton,
|
1387
|
-
{
|
1388
|
-
...secondaryAction,
|
1389
|
-
variant: secondaryAction.variant || "secondary"
|
1390
|
-
}
|
1391
|
-
) : null
|
1392
|
-
] });
|
1393
|
-
};
|
1394
|
-
const DocumentActionButton = (action) => {
|
1395
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1396
|
-
const { toggleNotification } = useNotification();
|
1397
|
-
const handleClick = (action2) => async (e) => {
|
1398
|
-
const { onClick = () => false, dialog, id } = action2;
|
1399
|
-
const muteDialog = await onClick(e);
|
1400
|
-
if (dialog && !muteDialog) {
|
1401
|
-
switch (dialog.type) {
|
1402
|
-
case "notification":
|
1403
|
-
toggleNotification({
|
1404
|
-
title: dialog.title,
|
1405
|
-
message: dialog.content,
|
1406
|
-
type: dialog.status,
|
1407
|
-
timeout: dialog.timeout,
|
1408
|
-
onClose: dialog.onClose
|
1409
|
-
});
|
1410
|
-
break;
|
1411
|
-
case "dialog":
|
1412
|
-
case "modal":
|
1413
|
-
e.preventDefault();
|
1414
|
-
setDialogId(id);
|
1415
|
-
}
|
1416
|
-
}
|
1417
|
-
};
|
1418
|
-
const handleClose = () => {
|
1419
|
-
setDialogId(null);
|
1420
|
-
};
|
1421
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1422
|
-
/* @__PURE__ */ jsx(
|
1423
|
-
Button,
|
1424
|
-
{
|
1425
|
-
flex: 1,
|
1426
|
-
startIcon: action.icon,
|
1427
|
-
disabled: action.disabled,
|
1428
|
-
onClick: handleClick(action),
|
1429
|
-
justifyContent: "center",
|
1430
|
-
variant: action.variant || "default",
|
1431
|
-
children: action.label
|
1432
|
-
}
|
1433
|
-
),
|
1434
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1435
|
-
DocumentActionConfirmDialog,
|
1436
|
-
{
|
1437
|
-
...action.dialog,
|
1438
|
-
variant: action.dialog?.variant ?? action.variant,
|
1439
|
-
isOpen: dialogId === action.id,
|
1440
|
-
onClose: handleClose
|
1441
|
-
}
|
1442
|
-
) : null,
|
1443
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1444
|
-
DocumentActionModal,
|
1445
|
-
{
|
1446
|
-
...action.dialog,
|
1447
|
-
onModalClose: handleClose,
|
1448
|
-
isOpen: dialogId === action.id
|
1449
|
-
}
|
1450
|
-
) : null
|
1451
|
-
] });
|
1452
|
-
};
|
1453
|
-
const DocumentActionsMenu = ({
|
1454
|
-
actions: actions2,
|
1455
|
-
children,
|
1456
|
-
label,
|
1457
|
-
variant = "tertiary"
|
1458
|
-
}) => {
|
1459
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
1460
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1461
|
-
const { formatMessage } = useIntl();
|
1462
|
-
const { toggleNotification } = useNotification();
|
1463
|
-
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1464
|
-
const handleClick = (action) => async (e) => {
|
1465
|
-
const { onClick = () => false, dialog, id } = action;
|
1466
|
-
const muteDialog = await onClick(e);
|
1467
|
-
if (dialog && !muteDialog) {
|
1468
|
-
switch (dialog.type) {
|
1469
|
-
case "notification":
|
1470
|
-
toggleNotification({
|
1471
|
-
title: dialog.title,
|
1472
|
-
message: dialog.content,
|
1473
|
-
type: dialog.status,
|
1474
|
-
timeout: dialog.timeout,
|
1475
|
-
onClose: dialog.onClose
|
1476
|
-
});
|
1477
|
-
break;
|
1478
|
-
case "dialog":
|
1479
|
-
case "modal":
|
1480
|
-
setDialogId(id);
|
1481
|
-
}
|
1482
|
-
}
|
1483
|
-
};
|
1484
|
-
const handleClose = () => {
|
1485
|
-
setDialogId(null);
|
1486
|
-
setIsOpen(false);
|
1487
|
-
};
|
1488
|
-
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1489
|
-
/* @__PURE__ */ jsxs(
|
1490
|
-
Menu.Trigger,
|
1491
|
-
{
|
1492
|
-
disabled: isDisabled,
|
1493
|
-
size: "S",
|
1494
|
-
endIcon: null,
|
1495
|
-
paddingTop: "7px",
|
1496
|
-
paddingLeft: "9px",
|
1497
|
-
paddingRight: "9px",
|
1498
|
-
variant,
|
1499
|
-
children: [
|
1500
|
-
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1501
|
-
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1502
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1503
|
-
defaultMessage: "More document actions"
|
1504
|
-
}) })
|
1505
|
-
]
|
1506
|
-
}
|
1507
|
-
),
|
1508
|
-
/* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1509
|
-
actions2.map((action) => {
|
1510
|
-
return /* @__PURE__ */ jsx(
|
1511
|
-
Menu.Item,
|
1512
|
-
{
|
1513
|
-
disabled: action.disabled,
|
1514
|
-
onSelect: handleClick(action),
|
1515
|
-
display: "block",
|
1516
|
-
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1517
|
-
/* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
|
1518
|
-
/* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
|
1519
|
-
action.label
|
1520
|
-
] }),
|
1521
|
-
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1522
|
-
Flex,
|
1523
|
-
{
|
1524
|
-
alignItems: "center",
|
1525
|
-
background: "alternative100",
|
1526
|
-
borderStyle: "solid",
|
1527
|
-
borderColor: "alternative200",
|
1528
|
-
borderWidth: "1px",
|
1529
|
-
height: 5,
|
1530
|
-
paddingLeft: 2,
|
1531
|
-
paddingRight: 2,
|
1532
|
-
hasRadius: true,
|
1533
|
-
color: "alternative600",
|
1534
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1535
|
-
}
|
1536
|
-
)
|
1537
|
-
] })
|
1538
|
-
},
|
1539
|
-
action.id
|
1540
|
-
);
|
1541
|
-
}),
|
1542
|
-
children
|
1543
|
-
] }),
|
1544
|
-
actions2.map((action) => {
|
1545
|
-
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1546
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1547
|
-
DocumentActionConfirmDialog,
|
1548
|
-
{
|
1549
|
-
...action.dialog,
|
1550
|
-
variant: action.variant,
|
1551
|
-
isOpen: dialogId === action.id,
|
1552
|
-
onClose: handleClose
|
1553
|
-
}
|
1554
|
-
) : null,
|
1555
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1556
|
-
DocumentActionModal,
|
1557
|
-
{
|
1558
|
-
...action.dialog,
|
1559
|
-
onModalClose: handleClose,
|
1560
|
-
isOpen: dialogId === action.id
|
1561
|
-
}
|
1562
|
-
) : null
|
1563
|
-
] }, action.id);
|
1564
|
-
})
|
1565
|
-
] });
|
1566
|
-
};
|
1567
|
-
const convertActionVariantToColor = (variant = "secondary") => {
|
1568
|
-
switch (variant) {
|
1569
|
-
case "danger":
|
1570
|
-
return "danger600";
|
1571
|
-
case "secondary":
|
1572
|
-
return void 0;
|
1573
|
-
case "success":
|
1574
|
-
return "success600";
|
1575
|
-
default:
|
1576
|
-
return "primary600";
|
1577
|
-
}
|
1578
|
-
};
|
1579
|
-
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1580
|
-
switch (variant) {
|
1581
|
-
case "danger":
|
1582
|
-
return "danger600";
|
1583
|
-
case "secondary":
|
1584
|
-
return "neutral500";
|
1585
|
-
case "success":
|
1586
|
-
return "success600";
|
1587
|
-
default:
|
1588
|
-
return "primary600";
|
1589
|
-
}
|
1590
|
-
};
|
1591
|
-
const DocumentActionConfirmDialog = ({
|
1592
|
-
onClose,
|
1593
|
-
onCancel,
|
1594
|
-
onConfirm,
|
1595
|
-
title,
|
1596
|
-
content,
|
1597
|
-
isOpen,
|
1598
|
-
variant = "secondary"
|
1599
|
-
}) => {
|
1600
|
-
const { formatMessage } = useIntl();
|
1601
|
-
const handleClose = async () => {
|
1602
|
-
if (onCancel) {
|
1603
|
-
await onCancel();
|
1604
|
-
}
|
1605
|
-
onClose();
|
1606
|
-
};
|
1607
|
-
const handleConfirm = async () => {
|
1608
|
-
if (onConfirm) {
|
1609
|
-
await onConfirm();
|
1610
|
-
}
|
1611
|
-
onClose();
|
1612
|
-
};
|
1613
|
-
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
1614
|
-
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1615
|
-
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1616
|
-
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1617
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
1618
|
-
id: "app.components.Button.cancel",
|
1619
|
-
defaultMessage: "Cancel"
|
1620
|
-
}) }) }),
|
1621
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1622
|
-
id: "app.components.Button.confirm",
|
1623
|
-
defaultMessage: "Confirm"
|
1624
|
-
}) })
|
1625
|
-
] })
|
1626
|
-
] }) });
|
1627
|
-
};
|
1628
|
-
const DocumentActionModal = ({
|
1629
|
-
isOpen,
|
1630
|
-
title,
|
1631
|
-
onClose,
|
1632
|
-
footer: Footer,
|
1633
|
-
content: Content,
|
1634
|
-
onModalClose
|
1635
|
-
}) => {
|
1636
|
-
const handleClose = () => {
|
1637
|
-
if (onClose) {
|
1638
|
-
onClose();
|
1639
|
-
}
|
1640
|
-
onModalClose();
|
1641
|
-
};
|
1642
|
-
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1643
|
-
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1644
|
-
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
1645
|
-
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1646
|
-
] }) });
|
1647
|
-
};
|
1648
|
-
const PublishAction$1 = ({
|
1649
|
-
activeTab,
|
1650
|
-
documentId,
|
1651
|
-
model,
|
1652
|
-
collectionType,
|
1653
|
-
meta,
|
1654
|
-
document
|
1655
|
-
}) => {
|
1656
|
-
const { schema } = useDoc();
|
1657
|
-
const navigate = useNavigate();
|
1658
|
-
const { toggleNotification } = useNotification();
|
1659
|
-
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
1660
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
1661
|
-
const { formatMessage } = useIntl();
|
1662
|
-
const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
|
1663
|
-
"PublishAction",
|
1664
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1665
|
-
);
|
1666
|
-
const { publish } = useDocumentActions();
|
1667
|
-
const [
|
1668
|
-
countDraftRelations,
|
1669
|
-
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1670
|
-
] = useLazyGetDraftRelationCountQuery();
|
1671
|
-
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
1672
|
-
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1673
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1674
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1675
|
-
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
1676
|
-
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1677
|
-
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1678
|
-
const validate = useForm("PublishAction", (state) => state.validate);
|
1679
|
-
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1680
|
-
const formValues = useForm("PublishAction", ({ values }) => values);
|
1681
|
-
React.useEffect(() => {
|
1682
|
-
if (isErrorDraftRelations) {
|
1683
|
-
toggleNotification({
|
1684
|
-
type: "danger",
|
1685
|
-
message: formatMessage({
|
1686
|
-
id: getTranslation("error.records.fetch-draft-relatons"),
|
1687
|
-
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1688
|
-
})
|
1689
|
-
});
|
1690
|
-
}
|
1691
|
-
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1692
|
-
React.useEffect(() => {
|
1693
|
-
const localDraftRelations = /* @__PURE__ */ new Set();
|
1694
|
-
const extractDraftRelations = (data) => {
|
1695
|
-
const relations = data.connect || [];
|
1696
|
-
relations.forEach((relation) => {
|
1697
|
-
if (relation.status === "draft") {
|
1698
|
-
localDraftRelations.add(relation.id);
|
1699
|
-
}
|
1700
|
-
});
|
1701
|
-
};
|
1702
|
-
const traverseAndExtract = (data) => {
|
1703
|
-
Object.entries(data).forEach(([key, value]) => {
|
1704
|
-
if (key === "connect" && Array.isArray(value)) {
|
1705
|
-
extractDraftRelations({ connect: value });
|
1706
|
-
} else if (typeof value === "object" && value !== null) {
|
1707
|
-
traverseAndExtract(value);
|
1708
|
-
}
|
1709
|
-
});
|
1710
|
-
};
|
1711
|
-
if (!documentId || modified) {
|
1712
|
-
traverseAndExtract(formValues);
|
1713
|
-
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1714
|
-
}
|
1715
|
-
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1716
|
-
React.useEffect(() => {
|
1717
|
-
if (documentId) {
|
1718
|
-
const fetchDraftRelationsCount = async () => {
|
1719
|
-
const { data, error } = await countDraftRelations({
|
1720
|
-
collectionType,
|
1721
|
-
model,
|
1722
|
-
documentId,
|
1723
|
-
params
|
1724
|
-
});
|
1725
|
-
if (error) {
|
1726
|
-
throw error;
|
1727
|
-
}
|
1728
|
-
if (data) {
|
1729
|
-
setServerCountOfDraftRelations(data.data);
|
1730
|
-
}
|
1731
|
-
};
|
1732
|
-
fetchDraftRelationsCount();
|
1746
|
+
},
|
1747
|
+
{
|
1748
|
+
path: "no-content-types",
|
1749
|
+
Component: NoContentType
|
1750
|
+
},
|
1751
|
+
...routes$1
|
1752
|
+
];
|
1753
|
+
const DocumentActions = ({ actions: actions2 }) => {
|
1754
|
+
const { formatMessage } = useIntl();
|
1755
|
+
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1756
|
+
if (action.position === void 0) {
|
1757
|
+
return true;
|
1733
1758
|
}
|
1734
|
-
|
1735
|
-
|
1736
|
-
|
1759
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1760
|
+
return positions.includes("panel");
|
1761
|
+
});
|
1762
|
+
if (!primaryAction) {
|
1737
1763
|
return null;
|
1738
1764
|
}
|
1739
|
-
|
1740
|
-
|
1741
|
-
|
1742
|
-
|
1743
|
-
|
1744
|
-
toggleNotification({
|
1745
|
-
type: "danger",
|
1746
|
-
message: formatMessage({
|
1747
|
-
id: "content-manager.validation.error",
|
1748
|
-
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1749
|
-
})
|
1750
|
-
});
|
1751
|
-
return;
|
1752
|
-
}
|
1753
|
-
const res = await publish(
|
1754
|
-
{
|
1755
|
-
collectionType,
|
1756
|
-
model,
|
1757
|
-
documentId,
|
1758
|
-
params
|
1759
|
-
},
|
1760
|
-
formValues
|
1761
|
-
);
|
1762
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1763
|
-
navigate({
|
1764
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1765
|
-
search: rawQuery
|
1766
|
-
});
|
1767
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1768
|
-
setErrors(formatValidationErrors(res.error));
|
1769
|
-
}
|
1770
|
-
} finally {
|
1771
|
-
setSubmitting(false);
|
1772
|
-
}
|
1773
|
-
};
|
1774
|
-
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1775
|
-
const hasDraftRelations = totalDraftRelations > 0;
|
1776
|
-
return {
|
1777
|
-
/**
|
1778
|
-
* Disabled when:
|
1779
|
-
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
1780
|
-
* - the form is submitting
|
1781
|
-
* - the active tab is the published tab
|
1782
|
-
* - the document is already published & not modified
|
1783
|
-
* - the document is being created & not modified
|
1784
|
-
* - the user doesn't have the permission to publish
|
1785
|
-
* - the user doesn't have the permission to create a new document
|
1786
|
-
* - the user doesn't have the permission to update the document
|
1787
|
-
*/
|
1788
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
|
1789
|
-
label: formatMessage({
|
1790
|
-
id: "app.utils.publish",
|
1791
|
-
defaultMessage: "Publish"
|
1792
|
-
}),
|
1793
|
-
onClick: async () => {
|
1794
|
-
if (hasDraftRelations) {
|
1795
|
-
return;
|
1796
|
-
}
|
1797
|
-
await performPublish();
|
1798
|
-
},
|
1799
|
-
dialog: hasDraftRelations ? {
|
1800
|
-
type: "dialog",
|
1801
|
-
variant: "danger",
|
1802
|
-
footer: null,
|
1803
|
-
title: formatMessage({
|
1804
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1805
|
-
defaultMessage: "Confirmation"
|
1806
|
-
}),
|
1807
|
-
content: formatMessage(
|
1808
|
-
{
|
1809
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1810
|
-
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1811
|
-
},
|
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,
|
1812
1770
|
{
|
1813
|
-
|
1771
|
+
actions: restActions,
|
1772
|
+
label: formatMessage({
|
1773
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1774
|
+
defaultMessage: "More document actions"
|
1775
|
+
})
|
1814
1776
|
}
|
1815
|
-
)
|
1816
|
-
|
1817
|
-
|
1777
|
+
) : null
|
1778
|
+
] }),
|
1779
|
+
secondaryAction ? /* @__PURE__ */ jsx(
|
1780
|
+
DocumentActionButton,
|
1781
|
+
{
|
1782
|
+
...secondaryAction,
|
1783
|
+
variant: secondaryAction.variant || "secondary"
|
1818
1784
|
}
|
1819
|
-
|
1820
|
-
};
|
1785
|
+
) : null
|
1786
|
+
] });
|
1821
1787
|
};
|
1822
|
-
|
1823
|
-
const
|
1824
|
-
activeTab,
|
1825
|
-
documentId,
|
1826
|
-
model,
|
1827
|
-
collectionType
|
1828
|
-
}) => {
|
1829
|
-
const navigate = useNavigate();
|
1788
|
+
const DocumentActionButton = (action) => {
|
1789
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1830
1790
|
const { toggleNotification } = useNotification();
|
1831
|
-
const
|
1832
|
-
|
1833
|
-
|
1834
|
-
|
1835
|
-
|
1836
|
-
|
1837
|
-
canUpdate: canUpdate2
|
1838
|
-
}));
|
1839
|
-
const { create, update, clone } = useDocumentActions();
|
1840
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1841
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1842
|
-
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1843
|
-
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
1844
|
-
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1845
|
-
const document = useForm("UpdateAction", ({ values }) => values);
|
1846
|
-
const validate = useForm("UpdateAction", (state) => state.validate);
|
1847
|
-
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1848
|
-
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1849
|
-
return {
|
1850
|
-
/**
|
1851
|
-
* Disabled when:
|
1852
|
-
* - the form is submitting
|
1853
|
-
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1854
|
-
* - the active tab is the published tab
|
1855
|
-
* - the user doesn't have the permission to create a new document
|
1856
|
-
* - the user doesn't have the permission to update the document
|
1857
|
-
*/
|
1858
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
|
1859
|
-
label: formatMessage({
|
1860
|
-
id: "content-manager.containers.Edit.save",
|
1861
|
-
defaultMessage: "Save"
|
1862
|
-
}),
|
1863
|
-
onClick: async () => {
|
1864
|
-
setSubmitting(true);
|
1865
|
-
try {
|
1866
|
-
const { errors } = await validate();
|
1867
|
-
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":
|
1868
1797
|
toggleNotification({
|
1869
|
-
|
1870
|
-
message:
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1798
|
+
title: dialog.title,
|
1799
|
+
message: dialog.content,
|
1800
|
+
type: dialog.status,
|
1801
|
+
timeout: dialog.timeout,
|
1802
|
+
onClose: dialog.onClose
|
1874
1803
|
});
|
1875
|
-
|
1876
|
-
|
1877
|
-
|
1878
|
-
|
1879
|
-
|
1880
|
-
|
1881
|
-
|
1882
|
-
|
1883
|
-
|
1884
|
-
|
1885
|
-
|
1886
|
-
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
|
1893
|
-
|
1894
|
-
|
1895
|
-
|
1896
|
-
|
1897
|
-
|
1898
|
-
|
1899
|
-
|
1900
|
-
|
1901
|
-
|
1902
|
-
|
1903
|
-
|
1904
|
-
|
1905
|
-
|
1906
|
-
|
1907
|
-
|
1908
|
-
|
1909
|
-
|
1910
|
-
|
1911
|
-
|
1912
|
-
|
1913
|
-
|
1914
|
-
|
1915
|
-
|
1916
|
-
params
|
1917
|
-
},
|
1918
|
-
document
|
1919
|
-
);
|
1920
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1921
|
-
navigate(
|
1922
|
-
{
|
1923
|
-
pathname: `../${res.data.documentId}`,
|
1924
|
-
search: rawQuery
|
1925
|
-
},
|
1926
|
-
{ replace: true, relative: "path" }
|
1927
|
-
);
|
1928
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1929
|
-
setErrors(formatValidationErrors(res.error));
|
1930
|
-
}
|
1931
|
-
}
|
1932
|
-
} finally {
|
1933
|
-
setSubmitting(false);
|
1804
|
+
break;
|
1805
|
+
case "dialog":
|
1806
|
+
case "modal":
|
1807
|
+
e.preventDefault();
|
1808
|
+
setDialogId(id);
|
1809
|
+
}
|
1810
|
+
}
|
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
|
1934
1845
|
}
|
1935
|
-
|
1936
|
-
};
|
1937
|
-
};
|
1938
|
-
UpdateAction.type = "update";
|
1939
|
-
const UNPUBLISH_DRAFT_OPTIONS = {
|
1940
|
-
KEEP: "keep",
|
1941
|
-
DISCARD: "discard"
|
1846
|
+
) : null
|
1847
|
+
] });
|
1942
1848
|
};
|
1943
|
-
const
|
1944
|
-
|
1945
|
-
|
1946
|
-
|
1947
|
-
|
1948
|
-
document
|
1849
|
+
const DocumentActionsMenu = ({
|
1850
|
+
actions: actions2,
|
1851
|
+
children,
|
1852
|
+
label,
|
1853
|
+
variant = "tertiary"
|
1949
1854
|
}) => {
|
1855
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
1856
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1950
1857
|
const { formatMessage } = useIntl();
|
1951
|
-
const { schema } = useDoc();
|
1952
|
-
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1953
|
-
const { unpublish } = useDocumentActions();
|
1954
|
-
const [{ query }] = useQueryParams();
|
1955
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1956
1858
|
const { toggleNotification } = useNotification();
|
1957
|
-
const
|
1958
|
-
const
|
1959
|
-
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
}
|
1965
|
-
return {
|
1966
|
-
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
1967
|
-
label: formatMessage({
|
1968
|
-
id: "app.utils.unpublish",
|
1969
|
-
defaultMessage: "Unpublish"
|
1970
|
-
}),
|
1971
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
1972
|
-
onClick: async () => {
|
1973
|
-
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1974
|
-
if (!documentId) {
|
1975
|
-
console.error(
|
1976
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
1977
|
-
);
|
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":
|
1978
1866
|
toggleNotification({
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1867
|
+
title: dialog.title,
|
1868
|
+
message: dialog.content,
|
1869
|
+
type: dialog.status,
|
1870
|
+
timeout: dialog.timeout,
|
1871
|
+
onClose: dialog.onClose
|
1984
1872
|
});
|
1985
|
-
|
1986
|
-
|
1873
|
+
break;
|
1874
|
+
case "dialog":
|
1875
|
+
case "modal":
|
1876
|
+
setDialogId(id);
|
1987
1877
|
}
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
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"
|
2007
1900
|
}) })
|
2008
|
-
]
|
2009
|
-
|
2010
|
-
|
2011
|
-
|
2012
|
-
|
2013
|
-
|
2014
|
-
|
2015
|
-
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2016
|
-
defaultMessage: "Choose an option to unpublish the document."
|
2017
|
-
}),
|
2018
|
-
onValueChange: handleChange,
|
2019
|
-
children: [
|
2020
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2021
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2022
|
-
defaultMessage: "Keep draft"
|
2023
|
-
}) }),
|
2024
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2025
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2026
|
-
defaultMessage: "Replace draft"
|
2027
|
-
}) })
|
2028
|
-
]
|
2029
|
-
}
|
2030
|
-
)
|
2031
|
-
] }),
|
2032
|
-
onConfirm: async () => {
|
2033
|
-
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2034
|
-
console.error(
|
2035
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2036
|
-
);
|
2037
|
-
toggleNotification({
|
2038
|
-
message: formatMessage({
|
2039
|
-
id: "content-manager.actions.unpublish.error",
|
2040
|
-
defaultMessage: "An error occurred while trying to unpublish the document."
|
2041
|
-
}),
|
2042
|
-
type: "danger"
|
2043
|
-
});
|
2044
|
-
}
|
2045
|
-
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,
|
2046
1908
|
{
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
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
|
+
] })
|
2051
1949
|
},
|
2052
|
-
|
1950
|
+
action.id
|
2053
1951
|
);
|
2054
|
-
}
|
2055
|
-
|
2056
|
-
|
2057
|
-
|
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();
|
2017
|
+
};
|
2018
|
+
const handleConfirm = async () => {
|
2019
|
+
if (onConfirm) {
|
2020
|
+
await onConfirm();
|
2021
|
+
}
|
2022
|
+
onClose();
|
2058
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
|
+
] }) });
|
2059
2038
|
};
|
2060
|
-
|
2061
|
-
|
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 = ({
|
2062
2060
|
activeTab,
|
2063
2061
|
documentId,
|
2064
2062
|
model,
|
2065
2063
|
collectionType,
|
2064
|
+
meta,
|
2066
2065
|
document
|
2067
2066
|
}) => {
|
2068
|
-
const { formatMessage } = useIntl();
|
2069
2067
|
const { schema } = useDoc();
|
2070
|
-
const
|
2071
|
-
const {
|
2072
|
-
const
|
2073
|
-
const
|
2074
|
-
if (!schema?.options?.draftAndPublish) {
|
2075
|
-
return null;
|
2076
|
-
}
|
2077
|
-
return {
|
2078
|
-
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2079
|
-
label: formatMessage({
|
2080
|
-
id: "content-manager.actions.discard.label",
|
2081
|
-
defaultMessage: "Discard changes"
|
2082
|
-
}),
|
2083
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
2084
|
-
position: ["panel", "table-row"],
|
2085
|
-
variant: "danger",
|
2086
|
-
dialog: {
|
2087
|
-
type: "dialog",
|
2088
|
-
title: formatMessage({
|
2089
|
-
id: "app.components.ConfirmDialog.title",
|
2090
|
-
defaultMessage: "Confirmation"
|
2091
|
-
}),
|
2092
|
-
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2093
|
-
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2094
|
-
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2095
|
-
id: "content-manager.actions.discard.dialog.body",
|
2096
|
-
defaultMessage: "Are you sure?"
|
2097
|
-
}) })
|
2098
|
-
] }),
|
2099
|
-
onConfirm: async () => {
|
2100
|
-
await discard({
|
2101
|
-
collectionType,
|
2102
|
-
model,
|
2103
|
-
documentId,
|
2104
|
-
params
|
2105
|
-
});
|
2106
|
-
}
|
2107
|
-
}
|
2108
|
-
};
|
2109
|
-
};
|
2110
|
-
DiscardAction.type = "discard";
|
2111
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2112
|
-
path {
|
2113
|
-
fill: currentColor;
|
2114
|
-
}
|
2115
|
-
`;
|
2116
|
-
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2117
|
-
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2118
|
-
const RelativeTime = React.forwardRef(
|
2119
|
-
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2120
|
-
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2121
|
-
const interval = intervalToDuration({
|
2122
|
-
start: timestamp,
|
2123
|
-
end: Date.now()
|
2124
|
-
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2125
|
-
});
|
2126
|
-
const unit = intervals.find((intervalUnit) => {
|
2127
|
-
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2128
|
-
});
|
2129
|
-
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2130
|
-
const customInterval = customIntervals.find(
|
2131
|
-
(custom) => interval[custom.unit] < custom.threshold
|
2132
|
-
);
|
2133
|
-
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2134
|
-
return /* @__PURE__ */ jsx(
|
2135
|
-
"time",
|
2136
|
-
{
|
2137
|
-
ref: forwardedRef,
|
2138
|
-
dateTime: timestamp.toISOString(),
|
2139
|
-
role: "time",
|
2140
|
-
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2141
|
-
...restProps,
|
2142
|
-
children: displayText
|
2143
|
-
}
|
2144
|
-
);
|
2145
|
-
}
|
2146
|
-
);
|
2147
|
-
const getDisplayName = ({
|
2148
|
-
firstname,
|
2149
|
-
lastname,
|
2150
|
-
username,
|
2151
|
-
email
|
2152
|
-
} = {}) => {
|
2153
|
-
if (username) {
|
2154
|
-
return username;
|
2155
|
-
}
|
2156
|
-
if (firstname) {
|
2157
|
-
return `${firstname} ${lastname ?? ""}`.trim();
|
2158
|
-
}
|
2159
|
-
return email ?? "";
|
2160
|
-
};
|
2161
|
-
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2162
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2163
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
2164
|
-
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2165
|
-
};
|
2166
|
-
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2167
|
-
const { formatMessage } = useIntl();
|
2068
|
+
const navigate = useNavigate();
|
2069
|
+
const { toggleNotification } = useNotification();
|
2070
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2071
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
2168
2072
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2169
|
-
const title = isCreating ? formatMessage({
|
2170
|
-
id: "content-manager.containers.edit.title.new",
|
2171
|
-
defaultMessage: "Create an entry"
|
2172
|
-
}) : documentTitle;
|
2173
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2174
|
-
/* @__PURE__ */ jsx(BackButton, {}),
|
2175
|
-
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2176
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2177
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2178
|
-
] }),
|
2179
|
-
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2180
|
-
] });
|
2181
|
-
};
|
2182
|
-
const HeaderToolbar = () => {
|
2183
2073
|
const { formatMessage } = useIntl();
|
2184
|
-
const
|
2074
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2075
|
+
const { publish } = useDocumentActions();
|
2185
2076
|
const [
|
2186
|
-
|
2187
|
-
|
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
|
+
});
|
2188
2099
|
}
|
2189
|
-
|
2190
|
-
|
2191
|
-
|
2192
|
-
|
2193
|
-
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
activeTab: status,
|
2198
|
-
model,
|
2199
|
-
documentId: id,
|
2200
|
-
document: isCloning ? void 0 : document,
|
2201
|
-
meta: isCloning ? void 0 : meta,
|
2202
|
-
collectionType
|
2203
|
-
},
|
2204
|
-
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2205
|
-
children: (actions2) => {
|
2206
|
-
if (actions2.length > 0) {
|
2207
|
-
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2208
|
-
} else {
|
2209
|
-
return null;
|
2210
|
-
}
|
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);
|
2211
2108
|
}
|
2212
|
-
}
|
2213
|
-
|
2214
|
-
|
2215
|
-
|
2216
|
-
|
2217
|
-
|
2218
|
-
|
2219
|
-
|
2220
|
-
documentId: id,
|
2221
|
-
document: isCloning ? void 0 : document,
|
2222
|
-
meta: isCloning ? void 0 : meta,
|
2223
|
-
collectionType
|
2224
|
-
},
|
2225
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2226
|
-
children: (actions2) => {
|
2227
|
-
const headerActions = actions2.filter((action) => {
|
2228
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2229
|
-
return positions.includes("header");
|
2230
|
-
});
|
2231
|
-
return /* @__PURE__ */ jsx(
|
2232
|
-
DocumentActionsMenu,
|
2233
|
-
{
|
2234
|
-
actions: headerActions,
|
2235
|
-
label: formatMessage({
|
2236
|
-
id: "content-manager.containers.edit.header.more-actions",
|
2237
|
-
defaultMessage: "More actions"
|
2238
|
-
}),
|
2239
|
-
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2240
|
-
}
|
2241
|
-
);
|
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);
|
2242
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;
|
2243
2138
|
}
|
2244
|
-
|
2245
|
-
|
2246
|
-
}
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
|
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) {
|
2251
2147
|
return null;
|
2252
2148
|
}
|
2253
|
-
const
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
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(
|
2265
2166
|
{
|
2266
|
-
|
2267
|
-
|
2167
|
+
collectionType,
|
2168
|
+
model,
|
2169
|
+
documentId,
|
2170
|
+
params
|
2268
2171
|
},
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2273
|
-
|
2274
|
-
|
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();
|
2275
2206
|
},
|
2276
|
-
{
|
2277
|
-
|
2278
|
-
|
2279
|
-
|
2280
|
-
|
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"
|
2281
2214
|
}),
|
2282
|
-
|
2215
|
+
content: formatMessage(
|
2283
2216
|
{
|
2284
|
-
id:
|
2285
|
-
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."
|
2286
2219
|
},
|
2287
2220
|
{
|
2288
|
-
|
2289
|
-
RelativeTime,
|
2290
|
-
{
|
2291
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2292
|
-
}
|
2293
|
-
),
|
2294
|
-
isAnonymous: !updator,
|
2295
|
-
author: updator
|
2221
|
+
count: totalDraftRelations
|
2296
2222
|
}
|
2297
|
-
)
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
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;
|
2319
2280
|
}
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
2335
|
-
|
2336
|
-
|
2337
|
-
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
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
|
+
}
|
2342
2339
|
}
|
2343
|
-
|
2340
|
+
};
|
2344
2341
|
};
|
2345
|
-
|
2346
|
-
|
2347
|
-
|
2348
|
-
|
2349
|
-
SingleSelect,
|
2350
|
-
{
|
2351
|
-
size: "S",
|
2352
|
-
disabled: action.disabled,
|
2353
|
-
"aria-label": action.label,
|
2354
|
-
onChange: action.onSelect,
|
2355
|
-
value: action.value,
|
2356
|
-
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2357
|
-
},
|
2358
|
-
action.id
|
2359
|
-
);
|
2360
|
-
} else {
|
2361
|
-
return null;
|
2362
|
-
}
|
2363
|
-
}) });
|
2342
|
+
UpdateAction.type = "update";
|
2343
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2344
|
+
KEEP: "keep",
|
2345
|
+
DISCARD: "discard"
|
2364
2346
|
};
|
2365
|
-
const
|
2366
|
-
|
2347
|
+
const UnpublishAction$1 = ({
|
2348
|
+
activeTab,
|
2349
|
+
documentId,
|
2350
|
+
model,
|
2351
|
+
collectionType,
|
2352
|
+
document
|
2353
|
+
}) => {
|
2367
2354
|
const { formatMessage } = useIntl();
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2372
|
-
|
2373
|
-
|
2374
|
-
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
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);
|
2378
2365
|
};
|
2379
|
-
|
2380
|
-
|
2381
|
-
|
2382
|
-
const navigate = useNavigate();
|
2383
|
-
const { formatMessage } = useIntl();
|
2366
|
+
if (!schema?.options?.draftAndPublish) {
|
2367
|
+
return null;
|
2368
|
+
}
|
2384
2369
|
return {
|
2370
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2385
2371
|
label: formatMessage({
|
2386
|
-
id: "
|
2387
|
-
defaultMessage: "
|
2372
|
+
id: "app.utils.unpublish",
|
2373
|
+
defaultMessage: "Unpublish"
|
2388
2374
|
}),
|
2389
|
-
icon: /* @__PURE__ */ jsx(
|
2390
|
-
onClick: () => {
|
2391
|
-
|
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
|
+
});
|
2392
2398
|
},
|
2393
|
-
|
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"]
|
2394
2462
|
};
|
2395
2463
|
};
|
2396
|
-
|
2397
|
-
const
|
2398
|
-
|
2464
|
+
UnpublishAction$1.type = "unpublish";
|
2465
|
+
const DiscardAction = ({
|
2466
|
+
activeTab,
|
2467
|
+
documentId,
|
2468
|
+
model,
|
2469
|
+
collectionType,
|
2470
|
+
document
|
2471
|
+
}) => {
|
2399
2472
|
const { formatMessage } = useIntl();
|
2400
|
-
const
|
2401
|
-
const
|
2402
|
-
const {
|
2403
|
-
const {
|
2404
|
-
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
|
+
}
|
2405
2481
|
return {
|
2406
|
-
disabled: !
|
2482
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2407
2483
|
label: formatMessage({
|
2408
|
-
id: "content-manager.actions.
|
2409
|
-
defaultMessage: "
|
2484
|
+
id: "content-manager.actions.discard.label",
|
2485
|
+
defaultMessage: "Discard changes"
|
2410
2486
|
}),
|
2411
|
-
icon: /* @__PURE__ */ jsx(
|
2487
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2488
|
+
position: ["panel", "table-row"],
|
2489
|
+
variant: "danger",
|
2412
2490
|
dialog: {
|
2413
2491
|
type: "dialog",
|
2414
2492
|
title: formatMessage({
|
@@ -2418,92 +2496,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2418
2496
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2419
2497
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2420
2498
|
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2421
|
-
id: "content-manager.actions.
|
2499
|
+
id: "content-manager.actions.discard.dialog.body",
|
2422
2500
|
defaultMessage: "Are you sure?"
|
2423
2501
|
}) })
|
2424
2502
|
] }),
|
2425
2503
|
onConfirm: async () => {
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
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
|
-
|
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
|
2459
2542
|
}
|
2460
|
-
|
2461
|
-
|
2462
|
-
|
2463
|
-
|
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 ?? "";
|
2464
2559
|
};
|
2465
|
-
|
2466
|
-
const
|
2467
|
-
const
|
2468
|
-
|
2469
|
-
const [
|
2470
|
-
{
|
2471
|
-
query: { status }
|
2472
|
-
}
|
2473
|
-
] = useQueryParams({
|
2474
|
-
status: "draft"
|
2475
|
-
});
|
2476
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2477
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2478
|
-
const props = {
|
2479
|
-
activeTab: status,
|
2480
|
-
model,
|
2481
|
-
documentId: id,
|
2482
|
-
document: isCloning ? void 0 : document,
|
2483
|
-
meta: isCloning ? void 0 : meta,
|
2484
|
-
collectionType
|
2485
|
-
};
|
2486
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2487
|
-
DescriptionComponentRenderer,
|
2488
|
-
{
|
2489
|
-
props,
|
2490
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2491
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2492
|
-
}
|
2493
|
-
) });
|
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) }) });
|
2494
2564
|
};
|
2495
|
-
const
|
2565
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2496
2566
|
const { formatMessage } = useIntl();
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
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
|
+
] });
|
2504
2580
|
};
|
2505
|
-
|
2506
|
-
const
|
2581
|
+
const HeaderToolbar = () => {
|
2582
|
+
const { formatMessage } = useIntl();
|
2507
2583
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2508
2584
|
const [
|
2509
2585
|
{
|
@@ -2511,355 +2587,432 @@ const ActionsPanelContent = () => {
|
|
2511
2587
|
}
|
2512
2588
|
] = useQueryParams();
|
2513
2589
|
const { model, id, document, meta, collectionType } = useDoc();
|
2514
|
-
const plugins = useStrapiApp("
|
2515
|
-
|
2516
|
-
activeTab: status,
|
2517
|
-
model,
|
2518
|
-
documentId: id,
|
2519
|
-
document: isCloning ? void 0 : document,
|
2520
|
-
meta: isCloning ? void 0 : meta,
|
2521
|
-
collectionType
|
2522
|
-
};
|
2523
|
-
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: [
|
2524
2592
|
/* @__PURE__ */ jsx(
|
2525
2593
|
DescriptionComponentRenderer,
|
2526
2594
|
{
|
2527
|
-
props
|
2528
|
-
|
2529
|
-
|
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
|
+
}
|
2530
2611
|
}
|
2531
2612
|
),
|
2532
|
-
/* @__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
|
+
)
|
2533
2644
|
] });
|
2534
2645
|
};
|
2535
|
-
const
|
2536
|
-
|
2537
|
-
|
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 = [
|
2538
2657
|
{
|
2539
|
-
|
2540
|
-
|
2541
|
-
|
2542
|
-
|
2543
|
-
borderColor: "neutral150",
|
2544
|
-
hasRadius: true,
|
2545
|
-
paddingBottom: 4,
|
2546
|
-
paddingLeft: 4,
|
2547
|
-
paddingRight: 4,
|
2548
|
-
paddingTop: 4,
|
2549
|
-
shadow: "tableShadow",
|
2550
|
-
gap: 3,
|
2551
|
-
direction: "column",
|
2552
|
-
justifyContent: "stretch",
|
2553
|
-
alignItems: "flex-start",
|
2554
|
-
children: [
|
2555
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2556
|
-
children
|
2557
|
-
]
|
2558
|
-
}
|
2559
|
-
);
|
2560
|
-
});
|
2561
|
-
const HOOKS = {
|
2562
|
-
/**
|
2563
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2564
|
-
* @constant
|
2565
|
-
* @type {string}
|
2566
|
-
*/
|
2567
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2568
|
-
/**
|
2569
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2570
|
-
* @constant
|
2571
|
-
* @type {string}
|
2572
|
-
*/
|
2573
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2574
|
-
/**
|
2575
|
-
* Hook that allows to mutate the CM's edit view layout
|
2576
|
-
* @constant
|
2577
|
-
* @type {string}
|
2578
|
-
*/
|
2579
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2580
|
-
/**
|
2581
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2582
|
-
* @constant
|
2583
|
-
* @type {string}
|
2584
|
-
*/
|
2585
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2586
|
-
};
|
2587
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2588
|
-
endpoints: (builder) => ({
|
2589
|
-
getContentTypeConfiguration: builder.query({
|
2590
|
-
query: (uid) => ({
|
2591
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2592
|
-
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"
|
2593
2662
|
}),
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2606
|
-
|
2607
|
-
|
2608
|
-
|
2609
|
-
|
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"
|
2610
2703
|
}),
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2616
|
-
{
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
}
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
2636
|
-
|
2637
|
-
|
2638
|
-
|
2639
|
-
|
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
|
+
}
|
2640
2742
|
);
|
2641
|
-
return {
|
2642
|
-
name: mainFieldName,
|
2643
|
-
type: mainFieldType ?? "string"
|
2644
|
-
};
|
2645
|
-
};
|
2646
|
-
const DEFAULT_SETTINGS = {
|
2647
|
-
bulkable: false,
|
2648
|
-
filterable: false,
|
2649
|
-
searchable: false,
|
2650
|
-
pagination: false,
|
2651
|
-
defaultSortBy: "",
|
2652
|
-
defaultSortOrder: "asc",
|
2653
|
-
mainField: "id",
|
2654
|
-
pageSize: 10
|
2655
2743
|
};
|
2656
|
-
const
|
2657
|
-
const
|
2658
|
-
const
|
2659
|
-
|
2660
|
-
|
2661
|
-
|
2662
|
-
|
2663
|
-
|
2664
|
-
|
2665
|
-
|
2666
|
-
error,
|
2667
|
-
isFetching: isFetchingConfigs
|
2668
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2669
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2670
|
-
React.useEffect(() => {
|
2671
|
-
if (error) {
|
2672
|
-
toggleNotification({
|
2673
|
-
type: "danger",
|
2674
|
-
message: formatAPIError(error)
|
2675
|
-
});
|
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
|
+
}
|
2676
2754
|
}
|
2677
|
-
}, [error, formatAPIError, toggleNotification]);
|
2678
|
-
const editLayout = React.useMemo(
|
2679
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2680
|
-
layout: [],
|
2681
|
-
components: {},
|
2682
|
-
metadatas: {},
|
2683
|
-
options: {},
|
2684
|
-
settings: DEFAULT_SETTINGS
|
2685
|
-
},
|
2686
|
-
[data, isLoading, schemas, schema, components]
|
2687
|
-
);
|
2688
|
-
const listLayout = React.useMemo(() => {
|
2689
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2690
|
-
layout: [],
|
2691
|
-
metadatas: {},
|
2692
|
-
options: {},
|
2693
|
-
settings: DEFAULT_SETTINGS
|
2694
|
-
};
|
2695
|
-
}, [data, isLoading, schemas, schema, components]);
|
2696
|
-
const { layout: edit } = React.useMemo(
|
2697
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2698
|
-
layout: editLayout,
|
2699
|
-
query
|
2700
|
-
}),
|
2701
|
-
[editLayout, query, runHookWaterfall]
|
2702
|
-
);
|
2703
|
-
return {
|
2704
|
-
error,
|
2705
|
-
isLoading,
|
2706
|
-
edit,
|
2707
|
-
list: listLayout
|
2708
2755
|
};
|
2709
|
-
|
2710
|
-
|
2711
|
-
|
2712
|
-
return
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
2724
|
-
|
2725
|
-
schemas
|
2726
|
-
).reduce((panels, row) => {
|
2727
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2728
|
-
panels.push([row]);
|
2729
|
-
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
|
+
);
|
2730
2772
|
} else {
|
2731
|
-
if (
|
2732
|
-
|
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);
|
2733
2794
|
}
|
2734
|
-
panels[currentPanelIndex].push(row);
|
2735
2795
|
}
|
2736
|
-
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
}
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
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`);
|
2762
2827
|
},
|
2763
|
-
|
2764
|
-
|
2828
|
+
position: "header"
|
2829
|
+
};
|
2830
|
+
};
|
2831
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2832
|
+
const EditTheModelAction = ({ model }) => {
|
2833
|
+
const navigate = useNavigate();
|
2834
|
+
const { formatMessage } = useIntl();
|
2765
2835
|
return {
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
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}`);
|
2772
2843
|
},
|
2773
|
-
|
2774
|
-
...schema?.options,
|
2775
|
-
...schema?.pluginOptions,
|
2776
|
-
...data.contentType.options
|
2777
|
-
}
|
2844
|
+
position: "header"
|
2778
2845
|
};
|
2779
2846
|
};
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
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
|
+
}
|
2786
2914
|
}
|
2787
|
-
const { edit: metadata } = metadatas[field.name];
|
2788
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2789
|
-
return {
|
2790
|
-
attribute,
|
2791
|
-
disabled: !metadata.editable,
|
2792
|
-
hint: metadata.description,
|
2793
|
-
label: metadata.label ?? "",
|
2794
|
-
name: field.name,
|
2795
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2796
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2797
|
-
schemas,
|
2798
|
-
components: components?.schemas ?? {}
|
2799
|
-
}),
|
2800
|
-
placeholder: metadata.placeholder ?? "",
|
2801
|
-
required: attribute.required ?? false,
|
2802
|
-
size: field.size,
|
2803
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2804
|
-
visible: metadata.visible ?? true,
|
2805
|
-
type: attribute.type
|
2806
|
-
};
|
2807
|
-
}).filter((field) => field !== null)
|
2808
|
-
);
|
2809
|
-
};
|
2810
|
-
const formatListLayout = (data, {
|
2811
|
-
schemas,
|
2812
|
-
schema,
|
2813
|
-
components
|
2814
|
-
}) => {
|
2815
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2816
|
-
(acc, [attribute, metadata]) => {
|
2817
|
-
return {
|
2818
|
-
...acc,
|
2819
|
-
[attribute]: metadata.list
|
2820
|
-
};
|
2821
2915
|
},
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2828
|
-
|
2829
|
-
|
2830
|
-
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
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))
|
2839
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, {})
|
2840
2958
|
};
|
2841
2959
|
};
|
2842
|
-
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2960
|
+
ActionsPanel.type = "actions";
|
2961
|
+
const ActionsPanelContent = () => {
|
2962
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2963
|
+
const [
|
2964
|
+
{
|
2965
|
+
query: { status = "draft" }
|
2847
2966
|
}
|
2848
|
-
|
2849
|
-
|
2850
|
-
|
2851
|
-
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2857
|
-
|
2858
|
-
|
2859
|
-
|
2860
|
-
|
2861
|
-
|
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
|
+
] });
|
2862
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
|
+
});
|
2863
3016
|
const ConfirmBulkActionDialog = ({
|
2864
3017
|
onToggleDialog,
|
2865
3018
|
isOpen = false,
|
@@ -2898,6 +3051,7 @@ const ConfirmDialogPublishAll = ({
|
|
2898
3051
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2899
3052
|
const { model, schema } = useDoc();
|
2900
3053
|
const [{ query }] = useQueryParams();
|
3054
|
+
const enableDraftRelationsCount = false;
|
2901
3055
|
const {
|
2902
3056
|
data: countDraftRelations = 0,
|
2903
3057
|
isLoading,
|
@@ -2909,7 +3063,7 @@ const ConfirmDialogPublishAll = ({
|
|
2909
3063
|
locale: query?.plugins?.i18n?.locale
|
2910
3064
|
},
|
2911
3065
|
{
|
2912
|
-
skip:
|
3066
|
+
skip: !enableDraftRelationsCount
|
2913
3067
|
}
|
2914
3068
|
);
|
2915
3069
|
React.useEffect(() => {
|
@@ -3094,7 +3248,7 @@ const SelectedEntriesTableContent = ({
|
|
3094
3248
|
status: row.status
|
3095
3249
|
}
|
3096
3250
|
) }),
|
3097
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3251
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3098
3252
|
IconButton,
|
3099
3253
|
{
|
3100
3254
|
tag: Link,
|
@@ -3117,9 +3271,10 @@ const SelectedEntriesTableContent = ({
|
|
3117
3271
|
),
|
3118
3272
|
target: "_blank",
|
3119
3273
|
marginLeft: "auto",
|
3120
|
-
|
3274
|
+
variant: "ghost",
|
3275
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3121
3276
|
}
|
3122
|
-
) })
|
3277
|
+
) }) })
|
3123
3278
|
] }, row.id)) })
|
3124
3279
|
] });
|
3125
3280
|
};
|
@@ -3156,7 +3311,13 @@ const SelectedEntriesModalContent = ({
|
|
3156
3311
|
);
|
3157
3312
|
const { rows, validationErrors } = React.useMemo(() => {
|
3158
3313
|
if (data.length > 0 && schema) {
|
3159
|
-
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
|
+
);
|
3160
3321
|
const validationErrors2 = {};
|
3161
3322
|
const rows2 = data.map((entry) => {
|
3162
3323
|
try {
|
@@ -3506,7 +3667,7 @@ const TableActions = ({ document }) => {
|
|
3506
3667
|
DescriptionComponentRenderer,
|
3507
3668
|
{
|
3508
3669
|
props,
|
3509
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3670
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3510
3671
|
children: (actions2) => {
|
3511
3672
|
const tableRowActions = actions2.filter((action) => {
|
3512
3673
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3617,7 +3778,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3617
3778
|
}),
|
3618
3779
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3619
3780
|
footer: ({ onClose }) => {
|
3620
|
-
return /* @__PURE__ */ jsxs(
|
3781
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3621
3782
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3622
3783
|
id: "cancel",
|
3623
3784
|
defaultMessage: "Cancel"
|
@@ -3848,7 +4009,7 @@ const index = {
|
|
3848
4009
|
app.router.addRoute({
|
3849
4010
|
path: "content-manager/*",
|
3850
4011
|
lazy: async () => {
|
3851
|
-
const { Layout } = await import("./layout-
|
4012
|
+
const { Layout } = await import("./layout-2CfjL0T9.mjs");
|
3852
4013
|
return {
|
3853
4014
|
Component: Layout
|
3854
4015
|
};
|
@@ -3865,7 +4026,7 @@ const index = {
|
|
3865
4026
|
async registerTrads({ locales }) {
|
3866
4027
|
const importedTrads = await Promise.all(
|
3867
4028
|
locales.map((locale) => {
|
3868
|
-
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 }) => {
|
3869
4030
|
return {
|
3870
4031
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3871
4032
|
locale
|
@@ -3886,13 +4047,15 @@ export {
|
|
3886
4047
|
BulkActionsRenderer as B,
|
3887
4048
|
COLLECTION_TYPES as C,
|
3888
4049
|
DocumentStatus as D,
|
3889
|
-
|
3890
|
-
|
3891
|
-
|
4050
|
+
extractContentTypeComponents as E,
|
4051
|
+
DEFAULT_SETTINGS as F,
|
4052
|
+
convertEditLayoutToFieldLayouts as G,
|
3892
4053
|
HOOKS as H,
|
3893
4054
|
InjectionZone as I,
|
3894
|
-
|
3895
|
-
|
4055
|
+
useDocument as J,
|
4056
|
+
index as K,
|
4057
|
+
useContentManagerContext as L,
|
4058
|
+
useDocumentActions as M,
|
3896
4059
|
Panels as P,
|
3897
4060
|
RelativeTime as R,
|
3898
4061
|
SINGLE_TYPES as S,
|
@@ -3910,18 +4073,18 @@ export {
|
|
3910
4073
|
PERMISSIONS as k,
|
3911
4074
|
DocumentRBAC as l,
|
3912
4075
|
DOCUMENT_META_FIELDS as m,
|
3913
|
-
|
3914
|
-
|
3915
|
-
|
3916
|
-
|
3917
|
-
|
4076
|
+
CLONE_PATH as n,
|
4077
|
+
useDocLayout as o,
|
4078
|
+
useGetContentTypeConfigurationQuery as p,
|
4079
|
+
CREATOR_FIELDS as q,
|
4080
|
+
getMainField as r,
|
3918
4081
|
setInitialData as s,
|
3919
|
-
|
4082
|
+
getDisplayName as t,
|
3920
4083
|
useContentTypeSchema as u,
|
3921
|
-
|
3922
|
-
|
3923
|
-
|
3924
|
-
|
3925
|
-
|
4084
|
+
checkIfAttributeIsDisplayable as v,
|
4085
|
+
useGetAllDocumentsQuery as w,
|
4086
|
+
convertListLayoutToFieldLayouts as x,
|
4087
|
+
capitalise as y,
|
4088
|
+
useUpdateContentTypeConfigurationMutation as z
|
3926
4089
|
};
|
3927
|
-
//# sourceMappingURL=index-
|
4090
|
+
//# sourceMappingURL=index-wnqzm4Q8.mjs.map
|