@strapi/content-manager 0.0.0-experimental.779667bd163026468f566293decf331a0246fff9 → 0.0.0-experimental.7b750d18de359d0a42233cb8707e3c31c5983345
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-Bqgx7Mes.js → ComponentConfigurationPage-DnnZJc1F.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-Bqgx7Mes.js.map → ComponentConfigurationPage-DnnZJc1F.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-B1bIXVuX.mjs → ComponentConfigurationPage-hLMNf7KI.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-B1bIXVuX.mjs.map → ComponentConfigurationPage-hLMNf7KI.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js → EditConfigurationPage-CpLj5gYZ.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js.map → EditConfigurationPage-CpLj5gYZ.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs → EditConfigurationPage-Dh6sq-G4.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs.map → EditConfigurationPage-Dh6sq-G4.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DlLEyUL6.mjs → EditViewPage-BU1ugeVi.mjs} +19 -8
- package/dist/_chunks/EditViewPage-BU1ugeVi.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-DA95Ha6J.js → EditViewPage-D2QVRr_2.js} +19 -8
- package/dist/_chunks/EditViewPage-D2QVRr_2.js.map +1 -0
- package/dist/_chunks/{Field-CnK8dO8N.js → Field-BEDX9i_V.js} +125 -97
- package/dist/_chunks/Field-BEDX9i_V.js.map +1 -0
- package/dist/_chunks/{Field-Dq7bDnuh.mjs → Field-VSPY6uzs.mjs} +123 -95
- package/dist/_chunks/Field-VSPY6uzs.mjs.map +1 -0
- package/dist/_chunks/{Form-B_JE0dbz.mjs → Form-05Oaes1N.mjs} +35 -16
- package/dist/_chunks/Form-05Oaes1N.mjs.map +1 -0
- package/dist/_chunks/{Form-BpiR4piS.js → Form-DCaY8xBX.js} +35 -16
- package/dist/_chunks/Form-DCaY8xBX.js.map +1 -0
- package/dist/_chunks/{History-CBNGU7a-.mjs → History-BqO2G3MV.mjs} +21 -11
- package/dist/_chunks/History-BqO2G3MV.mjs.map +1 -0
- package/dist/_chunks/{History-DdIstl8b.js → History-BrJ1tUvt.js} +21 -11
- package/dist/_chunks/History-BrJ1tUvt.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-5dr4qpue.mjs → ListConfigurationPage-C6rsFlme.mjs} +14 -4
- package/dist/_chunks/ListConfigurationPage-C6rsFlme.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DkKRparB.js → ListConfigurationPage-Eane5LKE.js} +14 -4
- package/dist/_chunks/ListConfigurationPage-Eane5LKE.js.map +1 -0
- package/dist/_chunks/{ListViewPage-wE0lXqoD.js → ListViewPage-Coj-RPsx.js} +49 -40
- package/dist/_chunks/ListViewPage-Coj-RPsx.js.map +1 -0
- package/dist/_chunks/{ListViewPage-DecLrYV6.mjs → ListViewPage-yE_zYhcI.mjs} +47 -38
- package/dist/_chunks/ListViewPage-yE_zYhcI.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js → NoContentTypePage-BDJ0dshy.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js.map → NoContentTypePage-BDJ0dshy.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs → NoContentTypePage-NW_FSVdY.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs.map → NoContentTypePage-NW_FSVdY.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js → NoPermissionsPage-BOtb5FTM.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js.map → NoPermissionsPage-BOtb5FTM.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs → NoPermissionsPage-h0I3ImsX.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs.map → NoPermissionsPage-h0I3ImsX.mjs.map} +1 -1
- package/dist/_chunks/{Relations-L0xYRoSQ.js → Relations-CVh0DOKv.js} +4 -4
- package/dist/_chunks/{Relations-L0xYRoSQ.js.map → Relations-CVh0DOKv.js.map} +1 -1
- package/dist/_chunks/{Relations-Dqz0C1fz.mjs → Relations-FP0uWpBz.mjs} +4 -4
- package/dist/_chunks/{Relations-Dqz0C1fz.mjs.map → Relations-FP0uWpBz.mjs.map} +1 -1
- package/dist/_chunks/{en-uOUIxfcQ.js → en-BlhnxQfj.js} +7 -6
- package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BlhnxQfj.js.map} +1 -1
- package/dist/_chunks/{en-BrCTWlZv.mjs → en-C8YBvRrK.mjs} +7 -6
- package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
- package/dist/_chunks/{index-BSn97i8U.mjs → index-CPCHQ3X_.mjs} +1942 -1773
- package/dist/_chunks/index-CPCHQ3X_.mjs.map +1 -0
- package/dist/_chunks/{index-DyvUPg1a.js → index-DTKVhcla.js} +1922 -1753
- package/dist/_chunks/index-DTKVhcla.js.map +1 -0
- package/dist/_chunks/{layout-DPaHUusj.mjs → layout-B4UhJ8MJ.mjs} +22 -9
- package/dist/_chunks/layout-B4UhJ8MJ.mjs.map +1 -0
- package/dist/_chunks/{layout-TPqF2oJ5.js → layout-CWgZzMYf.js} +21 -8
- package/dist/_chunks/layout-CWgZzMYf.js.map +1 -0
- package/dist/_chunks/{relations-Ck7-ecDT.mjs → relations-B83Ge9a7.mjs} +2 -2
- package/dist/_chunks/{relations-Ck7-ecDT.mjs.map → relations-B83Ge9a7.mjs.map} +1 -1
- package/dist/_chunks/{relations-BWYS9gkn.js → relations-D81a_2zw.js} +2 -2
- package/dist/_chunks/{relations-BWYS9gkn.js.map → relations-D81a_2zw.js.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 +30 -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 +10 -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 +178 -108
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +179 -109
- 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/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/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-manager.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/server/src/services/utils/populate.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 +11 -11
- package/dist/_chunks/EditViewPage-DA95Ha6J.js.map +0 -1
- package/dist/_chunks/EditViewPage-DlLEyUL6.mjs.map +0 -1
- package/dist/_chunks/Field-CnK8dO8N.js.map +0 -1
- package/dist/_chunks/Field-Dq7bDnuh.mjs.map +0 -1
- package/dist/_chunks/Form-B_JE0dbz.mjs.map +0 -1
- package/dist/_chunks/Form-BpiR4piS.js.map +0 -1
- package/dist/_chunks/History-CBNGU7a-.mjs.map +0 -1
- package/dist/_chunks/History-DdIstl8b.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-5dr4qpue.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DkKRparB.js.map +0 -1
- package/dist/_chunks/ListViewPage-DecLrYV6.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-wE0lXqoD.js.map +0 -1
- package/dist/_chunks/index-BSn97i8U.mjs.map +0 -1
- package/dist/_chunks/index-DyvUPg1a.js.map +0 -1
- package/dist/_chunks/layout-DPaHUusj.mjs.map +0 -1
- package/dist/_chunks/layout-TPqF2oJ5.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,16 +1,16 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors,
|
3
|
+
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, useQueryParams, 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) => {
|
@@ -158,7 +158,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
158
158
|
"Document",
|
159
159
|
"InitialData",
|
160
160
|
"HistoryVersion",
|
161
|
-
"Relations"
|
161
|
+
"Relations",
|
162
|
+
"UidAvailability"
|
162
163
|
]
|
163
164
|
});
|
164
165
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -172,7 +173,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
172
173
|
params: query
|
173
174
|
}
|
174
175
|
}),
|
175
|
-
invalidatesTags: (_result,
|
176
|
+
invalidatesTags: (_result, error, { model }) => {
|
177
|
+
if (error) {
|
178
|
+
return [];
|
179
|
+
}
|
180
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
181
|
+
}
|
176
182
|
}),
|
177
183
|
cloneDocument: builder.mutation({
|
178
184
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -183,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
183
189
|
params
|
184
190
|
}
|
185
191
|
}),
|
186
|
-
invalidatesTags: (_result, _error, { model }) => [
|
192
|
+
invalidatesTags: (_result, _error, { model }) => [
|
193
|
+
{ type: "Document", id: `${model}_LIST` },
|
194
|
+
{ type: "UidAvailability", id: model }
|
195
|
+
]
|
187
196
|
}),
|
188
197
|
/**
|
189
198
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -200,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
200
209
|
}),
|
201
210
|
invalidatesTags: (result, _error, { model }) => [
|
202
211
|
{ type: "Document", id: `${model}_LIST` },
|
203
|
-
"Relations"
|
212
|
+
"Relations",
|
213
|
+
{ type: "UidAvailability", id: model }
|
204
214
|
]
|
205
215
|
}),
|
206
216
|
deleteDocument: builder.mutation({
|
@@ -241,7 +251,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
241
251
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
242
252
|
},
|
243
253
|
{ type: "Document", id: `${model}_LIST` },
|
244
|
-
"Relations"
|
254
|
+
"Relations",
|
255
|
+
{ type: "UidAvailability", id: model }
|
245
256
|
];
|
246
257
|
}
|
247
258
|
}),
|
@@ -259,6 +270,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
259
270
|
}),
|
260
271
|
providesTags: (result, _error, arg) => {
|
261
272
|
return [
|
273
|
+
{ type: "Document", id: `ALL_LIST` },
|
262
274
|
{ type: "Document", id: `${arg.model}_LIST` },
|
263
275
|
...result?.results.map(({ documentId }) => ({
|
264
276
|
type: "Document",
|
@@ -297,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
297
309
|
{
|
298
310
|
type: "Document",
|
299
311
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
312
|
+
},
|
313
|
+
// Make it easy to invalidate all individual documents queries for a model
|
314
|
+
{
|
315
|
+
type: "Document",
|
316
|
+
id: `${model}_ALL_ITEMS`
|
300
317
|
}
|
301
318
|
];
|
302
319
|
}
|
@@ -360,8 +377,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
360
377
|
type: "Document",
|
361
378
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
362
379
|
},
|
363
|
-
"Relations"
|
380
|
+
"Relations",
|
381
|
+
{ type: "UidAvailability", id: model }
|
364
382
|
];
|
383
|
+
},
|
384
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
385
|
+
const patchResult = dispatch(
|
386
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
387
|
+
Object.assign(draft.data, data);
|
388
|
+
})
|
389
|
+
);
|
390
|
+
try {
|
391
|
+
await queryFulfilled;
|
392
|
+
} catch {
|
393
|
+
patchResult.undo();
|
394
|
+
}
|
365
395
|
}
|
366
396
|
}),
|
367
397
|
unpublishDocument: builder.mutation({
|
@@ -431,7 +461,7 @@ const buildValidParams = (query) => {
|
|
431
461
|
const isBaseQueryError = (error) => {
|
432
462
|
return error.name !== void 0;
|
433
463
|
};
|
434
|
-
const createYupSchema = (attributes = {}, components = {}) => {
|
464
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
435
465
|
const createModelSchema = (attributes2) => yup.object().shape(
|
436
466
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
437
467
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
@@ -444,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
444
474
|
addMinValidation,
|
445
475
|
addMaxValidation,
|
446
476
|
addRegexValidation
|
447
|
-
].map((fn) => fn(attribute));
|
477
|
+
].map((fn) => fn(attribute, options));
|
448
478
|
const transformSchema = pipe(...validations);
|
449
479
|
switch (attribute.type) {
|
450
480
|
case "component": {
|
@@ -545,6 +575,14 @@ const createAttributeSchema = (attribute) => {
|
|
545
575
|
if (!value || typeof value === "string" && value.length === 0) {
|
546
576
|
return true;
|
547
577
|
}
|
578
|
+
if (typeof value === "object") {
|
579
|
+
try {
|
580
|
+
JSON.stringify(value);
|
581
|
+
return true;
|
582
|
+
} catch (err) {
|
583
|
+
return false;
|
584
|
+
}
|
585
|
+
}
|
548
586
|
try {
|
549
587
|
JSON.parse(value);
|
550
588
|
return true;
|
@@ -563,13 +601,7 @@ const createAttributeSchema = (attribute) => {
|
|
563
601
|
return yup.mixed();
|
564
602
|
}
|
565
603
|
};
|
566
|
-
const
|
567
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
568
|
-
return schema.min(1, translatedErrors.required);
|
569
|
-
}
|
570
|
-
if (attribute.required && attribute.type !== "relation") {
|
571
|
-
return schema.required(translatedErrors.required);
|
572
|
-
}
|
604
|
+
const nullableSchema = (schema) => {
|
573
605
|
return schema?.nullable ? schema.nullable() : (
|
574
606
|
// In some cases '.nullable' will not be available on the schema.
|
575
607
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -577,7 +609,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
577
609
|
schema
|
578
610
|
);
|
579
611
|
};
|
580
|
-
const
|
612
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
613
|
+
if (options.status === "draft") {
|
614
|
+
return nullableSchema(schema);
|
615
|
+
}
|
616
|
+
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
617
|
+
return schema.min(1, translatedErrors.required);
|
618
|
+
}
|
619
|
+
if (attribute.required && attribute.type !== "relation") {
|
620
|
+
return schema.required(translatedErrors.required);
|
621
|
+
}
|
622
|
+
return nullableSchema(schema);
|
623
|
+
};
|
624
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
625
|
+
if (options.status === "draft") {
|
626
|
+
return schema;
|
627
|
+
}
|
581
628
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
582
629
|
return schema.min(attribute.minLength, {
|
583
630
|
...translatedErrors.minLength,
|
@@ -599,11 +646,11 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
599
646
|
}
|
600
647
|
return schema;
|
601
648
|
};
|
602
|
-
const addMinValidation = (attribute) => (schema) => {
|
649
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
603
650
|
if ("min" in attribute) {
|
604
651
|
const min = toInteger(attribute.min);
|
605
652
|
if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
|
606
|
-
if (!attribute.required && "test" in schema && min) {
|
653
|
+
if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
|
607
654
|
return schema.test(
|
608
655
|
"custom-min",
|
609
656
|
{
|
@@ -742,19 +789,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
742
789
|
}, {});
|
743
790
|
return componentsByKey;
|
744
791
|
};
|
745
|
-
const
|
792
|
+
const HOOKS = {
|
793
|
+
/**
|
794
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
795
|
+
* @constant
|
796
|
+
* @type {string}
|
797
|
+
*/
|
798
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
799
|
+
/**
|
800
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
801
|
+
* @constant
|
802
|
+
* @type {string}
|
803
|
+
*/
|
804
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
805
|
+
/**
|
806
|
+
* Hook that allows to mutate the CM's edit view layout
|
807
|
+
* @constant
|
808
|
+
* @type {string}
|
809
|
+
*/
|
810
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
811
|
+
/**
|
812
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
813
|
+
* @constant
|
814
|
+
* @type {string}
|
815
|
+
*/
|
816
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
817
|
+
};
|
818
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
819
|
+
endpoints: (builder) => ({
|
820
|
+
getContentTypeConfiguration: builder.query({
|
821
|
+
query: (uid) => ({
|
822
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
823
|
+
method: "GET"
|
824
|
+
}),
|
825
|
+
transformResponse: (response) => response.data,
|
826
|
+
providesTags: (_result, _error, uid) => [
|
827
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
828
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
829
|
+
]
|
830
|
+
}),
|
831
|
+
getAllContentTypeSettings: builder.query({
|
832
|
+
query: () => "/content-manager/content-types-settings",
|
833
|
+
transformResponse: (response) => response.data,
|
834
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
835
|
+
}),
|
836
|
+
updateContentTypeConfiguration: builder.mutation({
|
837
|
+
query: ({ uid, ...body }) => ({
|
838
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
839
|
+
method: "PUT",
|
840
|
+
data: body
|
841
|
+
}),
|
842
|
+
transformResponse: (response) => response.data,
|
843
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
844
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
845
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
846
|
+
// Is this necessary?
|
847
|
+
{ type: "InitialData" }
|
848
|
+
]
|
849
|
+
})
|
850
|
+
})
|
851
|
+
});
|
852
|
+
const {
|
853
|
+
useGetContentTypeConfigurationQuery,
|
854
|
+
useGetAllContentTypeSettingsQuery,
|
855
|
+
useUpdateContentTypeConfigurationMutation
|
856
|
+
} = contentTypesApi;
|
857
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
858
|
+
const { type } = attribute;
|
859
|
+
if (type === "relation") {
|
860
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
861
|
+
}
|
862
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
863
|
+
};
|
864
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
865
|
+
if (!mainFieldName) {
|
866
|
+
return void 0;
|
867
|
+
}
|
868
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
869
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
870
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
871
|
+
);
|
872
|
+
return {
|
873
|
+
name: mainFieldName,
|
874
|
+
type: mainFieldType ?? "string"
|
875
|
+
};
|
876
|
+
};
|
877
|
+
const DEFAULT_SETTINGS = {
|
878
|
+
bulkable: false,
|
879
|
+
filterable: false,
|
880
|
+
searchable: false,
|
881
|
+
pagination: false,
|
882
|
+
defaultSortBy: "",
|
883
|
+
defaultSortOrder: "asc",
|
884
|
+
mainField: "id",
|
885
|
+
pageSize: 10
|
886
|
+
};
|
887
|
+
const useDocumentLayout = (model) => {
|
888
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
889
|
+
const [{ query }] = useQueryParams();
|
890
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
746
891
|
const { toggleNotification } = useNotification();
|
747
892
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
893
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
748
894
|
const {
|
749
|
-
|
750
|
-
isLoading:
|
751
|
-
|
752
|
-
|
753
|
-
} =
|
754
|
-
|
755
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
756
|
-
});
|
757
|
-
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
895
|
+
data,
|
896
|
+
isLoading: isLoadingConfigs,
|
897
|
+
error,
|
898
|
+
isFetching: isFetchingConfigs
|
899
|
+
} = useGetContentTypeConfigurationQuery(model);
|
900
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
758
901
|
React.useEffect(() => {
|
759
902
|
if (error) {
|
760
903
|
toggleNotification({
|
@@ -762,382 +905,636 @@ const useDocument = (args, opts) => {
|
|
762
905
|
message: formatAPIError(error)
|
763
906
|
});
|
764
907
|
}
|
765
|
-
}, [
|
766
|
-
const
|
767
|
-
|
768
|
-
|
769
|
-
|
770
|
-
|
771
|
-
|
772
|
-
|
773
|
-
(document) => {
|
774
|
-
if (!validationSchema) {
|
775
|
-
throw new Error(
|
776
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
777
|
-
);
|
778
|
-
}
|
779
|
-
try {
|
780
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
781
|
-
return null;
|
782
|
-
} catch (error2) {
|
783
|
-
if (error2 instanceof ValidationError) {
|
784
|
-
return getYupValidationErrors(error2);
|
785
|
-
}
|
786
|
-
throw error2;
|
787
|
-
}
|
908
|
+
}, [error, formatAPIError, toggleNotification]);
|
909
|
+
const editLayout = React.useMemo(
|
910
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
911
|
+
layout: [],
|
912
|
+
components: {},
|
913
|
+
metadatas: {},
|
914
|
+
options: {},
|
915
|
+
settings: DEFAULT_SETTINGS
|
788
916
|
},
|
789
|
-
[
|
917
|
+
[data, isLoading, schemas, schema, components]
|
918
|
+
);
|
919
|
+
const listLayout = React.useMemo(() => {
|
920
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
921
|
+
layout: [],
|
922
|
+
metadatas: {},
|
923
|
+
options: {},
|
924
|
+
settings: DEFAULT_SETTINGS
|
925
|
+
};
|
926
|
+
}, [data, isLoading, schemas, schema, components]);
|
927
|
+
const { layout: edit } = React.useMemo(
|
928
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
929
|
+
layout: editLayout,
|
930
|
+
query
|
931
|
+
}),
|
932
|
+
[editLayout, query, runHookWaterfall]
|
790
933
|
);
|
791
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
792
934
|
return {
|
793
|
-
|
794
|
-
document: data?.data,
|
795
|
-
meta: data?.meta,
|
935
|
+
error,
|
796
936
|
isLoading,
|
797
|
-
|
798
|
-
|
799
|
-
};
|
800
|
-
};
|
801
|
-
const useDoc = () => {
|
802
|
-
const { id, slug, collectionType, origin } = useParams();
|
803
|
-
const [{ query }] = useQueryParams();
|
804
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
805
|
-
if (!collectionType) {
|
806
|
-
throw new Error("Could not find collectionType in url params");
|
807
|
-
}
|
808
|
-
if (!slug) {
|
809
|
-
throw new Error("Could not find model in url params");
|
810
|
-
}
|
811
|
-
return {
|
812
|
-
collectionType,
|
813
|
-
model: slug,
|
814
|
-
id: origin || id === "create" ? void 0 : id,
|
815
|
-
...useDocument(
|
816
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
817
|
-
{
|
818
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
819
|
-
}
|
820
|
-
)
|
937
|
+
edit,
|
938
|
+
list: listLayout
|
821
939
|
};
|
822
940
|
};
|
823
|
-
const
|
824
|
-
|
825
|
-
|
826
|
-
}
|
827
|
-
return Object.keys(trad).reduce((acc, current) => {
|
828
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
829
|
-
return acc;
|
830
|
-
}, {});
|
831
|
-
};
|
832
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
833
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
834
|
-
id: "notification.error",
|
835
|
-
defaultMessage: "An error occurred, please try again"
|
941
|
+
const useDocLayout = () => {
|
942
|
+
const { model } = useDoc();
|
943
|
+
return useDocumentLayout(model);
|
836
944
|
};
|
837
|
-
const
|
838
|
-
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
const
|
844
|
-
|
845
|
-
|
846
|
-
|
847
|
-
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
853
|
-
|
854
|
-
|
855
|
-
|
856
|
-
message: formatAPIError(res.error)
|
857
|
-
});
|
858
|
-
return { error: res.error };
|
859
|
-
}
|
860
|
-
toggleNotification({
|
861
|
-
type: "success",
|
862
|
-
message: formatMessage({
|
863
|
-
id: getTranslation("success.record.delete"),
|
864
|
-
defaultMessage: "Deleted document"
|
865
|
-
})
|
866
|
-
});
|
867
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
868
|
-
return res.data;
|
869
|
-
} catch (err) {
|
870
|
-
toggleNotification({
|
871
|
-
type: "danger",
|
872
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
873
|
-
});
|
874
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
875
|
-
throw err;
|
945
|
+
const formatEditLayout = (data, {
|
946
|
+
schemas,
|
947
|
+
schema,
|
948
|
+
components
|
949
|
+
}) => {
|
950
|
+
let currentPanelIndex = 0;
|
951
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
952
|
+
data.contentType.layouts.edit,
|
953
|
+
schema?.attributes,
|
954
|
+
data.contentType.metadatas,
|
955
|
+
{ configurations: data.components, schemas: components },
|
956
|
+
schemas
|
957
|
+
).reduce((panels, row) => {
|
958
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
959
|
+
panels.push([row]);
|
960
|
+
currentPanelIndex += 2;
|
961
|
+
} else {
|
962
|
+
if (!panels[currentPanelIndex]) {
|
963
|
+
panels.push([]);
|
876
964
|
}
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
const
|
882
|
-
|
883
|
-
|
884
|
-
|
885
|
-
|
886
|
-
|
887
|
-
|
888
|
-
|
889
|
-
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
});
|
895
|
-
return { error: res.error };
|
965
|
+
panels[currentPanelIndex].push(row);
|
966
|
+
}
|
967
|
+
return panels;
|
968
|
+
}, []);
|
969
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
970
|
+
(acc, [uid, configuration]) => {
|
971
|
+
acc[uid] = {
|
972
|
+
layout: convertEditLayoutToFieldLayouts(
|
973
|
+
configuration.layouts.edit,
|
974
|
+
components[uid].attributes,
|
975
|
+
configuration.metadatas,
|
976
|
+
{ configurations: data.components, schemas: components }
|
977
|
+
),
|
978
|
+
settings: {
|
979
|
+
...configuration.settings,
|
980
|
+
icon: components[uid].info.icon,
|
981
|
+
displayName: components[uid].info.displayName
|
896
982
|
}
|
897
|
-
|
898
|
-
|
899
|
-
title: formatMessage({
|
900
|
-
id: getTranslation("success.records.delete"),
|
901
|
-
defaultMessage: "Successfully deleted."
|
902
|
-
}),
|
903
|
-
message: ""
|
904
|
-
});
|
905
|
-
trackUsage("didBulkDeleteEntries");
|
906
|
-
return res.data;
|
907
|
-
} catch (err) {
|
908
|
-
toggleNotification({
|
909
|
-
type: "danger",
|
910
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
911
|
-
});
|
912
|
-
trackUsage("didNotBulkDeleteEntries");
|
913
|
-
throw err;
|
914
|
-
}
|
983
|
+
};
|
984
|
+
return acc;
|
915
985
|
},
|
916
|
-
|
986
|
+
{}
|
917
987
|
);
|
918
|
-
const
|
919
|
-
|
920
|
-
|
921
|
-
|
922
|
-
|
923
|
-
|
924
|
-
model,
|
925
|
-
documentId,
|
926
|
-
params
|
927
|
-
});
|
928
|
-
if ("error" in res) {
|
929
|
-
toggleNotification({
|
930
|
-
type: "danger",
|
931
|
-
message: formatAPIError(res.error)
|
932
|
-
});
|
933
|
-
return { error: res.error };
|
934
|
-
}
|
935
|
-
toggleNotification({
|
936
|
-
type: "success",
|
937
|
-
message: formatMessage({
|
938
|
-
id: "content-manager.success.record.discard",
|
939
|
-
defaultMessage: "Changes discarded"
|
940
|
-
})
|
941
|
-
});
|
942
|
-
return res.data;
|
943
|
-
} catch (err) {
|
944
|
-
toggleNotification({
|
945
|
-
type: "danger",
|
946
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
947
|
-
});
|
948
|
-
throw err;
|
949
|
-
}
|
988
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
989
|
+
(acc, [attribute, metadata]) => {
|
990
|
+
return {
|
991
|
+
...acc,
|
992
|
+
[attribute]: metadata.edit
|
993
|
+
};
|
950
994
|
},
|
951
|
-
|
995
|
+
{}
|
952
996
|
);
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
model,
|
961
|
-
documentId,
|
962
|
-
data,
|
963
|
-
params
|
964
|
-
});
|
965
|
-
if ("error" in res) {
|
966
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
967
|
-
return { error: res.error };
|
968
|
-
}
|
969
|
-
trackUsage("didPublishEntry");
|
970
|
-
toggleNotification({
|
971
|
-
type: "success",
|
972
|
-
message: formatMessage({
|
973
|
-
id: getTranslation("success.record.publish"),
|
974
|
-
defaultMessage: "Published document"
|
975
|
-
})
|
976
|
-
});
|
977
|
-
return res.data;
|
978
|
-
} catch (err) {
|
979
|
-
toggleNotification({
|
980
|
-
type: "danger",
|
981
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
982
|
-
});
|
983
|
-
throw err;
|
984
|
-
}
|
997
|
+
return {
|
998
|
+
layout: panelledEditAttributes,
|
999
|
+
components: componentEditAttributes,
|
1000
|
+
metadatas: editMetadatas,
|
1001
|
+
settings: {
|
1002
|
+
...data.contentType.settings,
|
1003
|
+
displayName: schema?.info.displayName
|
985
1004
|
},
|
986
|
-
|
987
|
-
|
988
|
-
|
989
|
-
|
990
|
-
|
991
|
-
|
992
|
-
|
993
|
-
|
994
|
-
|
995
|
-
|
996
|
-
|
997
|
-
|
998
|
-
|
999
|
-
return { error: res.error };
|
1000
|
-
}
|
1001
|
-
toggleNotification({
|
1002
|
-
type: "success",
|
1003
|
-
message: formatMessage({
|
1004
|
-
id: getTranslation("success.record.publish"),
|
1005
|
-
defaultMessage: "Published document"
|
1006
|
-
})
|
1007
|
-
});
|
1008
|
-
return res.data;
|
1009
|
-
} catch (err) {
|
1010
|
-
toggleNotification({
|
1011
|
-
type: "danger",
|
1012
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1013
|
-
});
|
1014
|
-
throw err;
|
1005
|
+
options: {
|
1006
|
+
...schema?.options,
|
1007
|
+
...schema?.pluginOptions,
|
1008
|
+
...data.contentType.options
|
1009
|
+
}
|
1010
|
+
};
|
1011
|
+
};
|
1012
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1013
|
+
return rows.map(
|
1014
|
+
(row) => row.map((field) => {
|
1015
|
+
const attribute = attributes[field.name];
|
1016
|
+
if (!attribute) {
|
1017
|
+
return null;
|
1015
1018
|
}
|
1016
|
-
|
1017
|
-
|
1018
|
-
|
1019
|
-
|
1020
|
-
|
1021
|
-
|
1022
|
-
|
1023
|
-
|
1019
|
+
const { edit: metadata } = metadatas[field.name];
|
1020
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1021
|
+
return {
|
1022
|
+
attribute,
|
1023
|
+
disabled: !metadata.editable,
|
1024
|
+
hint: metadata.description,
|
1025
|
+
label: metadata.label ?? "",
|
1026
|
+
name: field.name,
|
1027
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1028
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1029
|
+
schemas,
|
1030
|
+
components: components?.schemas ?? {}
|
1031
|
+
}),
|
1032
|
+
placeholder: metadata.placeholder ?? "",
|
1033
|
+
required: attribute.required ?? false,
|
1034
|
+
size: field.size,
|
1035
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1036
|
+
visible: metadata.visible ?? true,
|
1037
|
+
type: attribute.type
|
1038
|
+
};
|
1039
|
+
}).filter((field) => field !== null)
|
1024
1040
|
);
|
1025
|
-
|
1026
|
-
|
1027
|
-
|
1028
|
-
|
1029
|
-
|
1030
|
-
|
1031
|
-
|
1032
|
-
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
+
};
|
1042
|
+
const formatListLayout = (data, {
|
1043
|
+
schemas,
|
1044
|
+
schema,
|
1045
|
+
components
|
1046
|
+
}) => {
|
1047
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1048
|
+
(acc, [attribute, metadata]) => {
|
1049
|
+
return {
|
1050
|
+
...acc,
|
1051
|
+
[attribute]: metadata.list
|
1052
|
+
};
|
1053
|
+
},
|
1054
|
+
{}
|
1055
|
+
);
|
1056
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1057
|
+
data.contentType.layouts.list,
|
1058
|
+
schema?.attributes,
|
1059
|
+
listMetadatas,
|
1060
|
+
{ configurations: data.components, schemas: components },
|
1061
|
+
schemas
|
1062
|
+
);
|
1063
|
+
return {
|
1064
|
+
layout: listAttributes,
|
1065
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1066
|
+
metadatas: listMetadatas,
|
1067
|
+
options: {
|
1068
|
+
...schema?.options,
|
1069
|
+
...schema?.pluginOptions,
|
1070
|
+
...data.contentType.options
|
1071
|
+
}
|
1072
|
+
};
|
1073
|
+
};
|
1074
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1075
|
+
return columns.map((name) => {
|
1076
|
+
const attribute = attributes[name];
|
1077
|
+
if (!attribute) {
|
1078
|
+
return null;
|
1079
|
+
}
|
1080
|
+
const metadata = metadatas[name];
|
1081
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1082
|
+
return {
|
1083
|
+
attribute,
|
1084
|
+
label: metadata.label ?? "",
|
1085
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1086
|
+
schemas,
|
1087
|
+
components: components?.schemas ?? {}
|
1088
|
+
}),
|
1089
|
+
name,
|
1090
|
+
searchable: metadata.searchable ?? true,
|
1091
|
+
sortable: metadata.sortable ?? true
|
1092
|
+
};
|
1093
|
+
}).filter((field) => field !== null);
|
1094
|
+
};
|
1095
|
+
const useDocument = (args, opts) => {
|
1096
|
+
const { toggleNotification } = useNotification();
|
1097
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1098
|
+
const {
|
1099
|
+
currentData: data,
|
1100
|
+
isLoading: isLoadingDocument,
|
1101
|
+
isFetching: isFetchingDocument,
|
1102
|
+
error
|
1103
|
+
} = useGetDocumentQuery(args, {
|
1104
|
+
...opts,
|
1105
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1106
|
+
});
|
1107
|
+
const {
|
1108
|
+
components,
|
1109
|
+
schema,
|
1110
|
+
schemas,
|
1111
|
+
isLoading: isLoadingSchema
|
1112
|
+
} = useContentTypeSchema(args.model);
|
1113
|
+
React.useEffect(() => {
|
1114
|
+
if (error) {
|
1115
|
+
toggleNotification({
|
1116
|
+
type: "danger",
|
1117
|
+
message: formatAPIError(error)
|
1118
|
+
});
|
1119
|
+
}
|
1120
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1121
|
+
const validationSchema = React.useMemo(() => {
|
1122
|
+
if (!schema) {
|
1123
|
+
return null;
|
1124
|
+
}
|
1125
|
+
return createYupSchema(schema.attributes, components);
|
1126
|
+
}, [schema, components]);
|
1127
|
+
const validate = React.useCallback(
|
1128
|
+
(document) => {
|
1129
|
+
if (!validationSchema) {
|
1130
|
+
throw new Error(
|
1131
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1132
|
+
);
|
1133
|
+
}
|
1134
|
+
try {
|
1135
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1136
|
+
return null;
|
1137
|
+
} catch (error2) {
|
1138
|
+
if (error2 instanceof ValidationError) {
|
1139
|
+
return getYupValidationErrors(error2);
|
1041
1140
|
}
|
1042
|
-
|
1043
|
-
toggleNotification({
|
1044
|
-
type: "success",
|
1045
|
-
message: formatMessage({
|
1046
|
-
id: getTranslation("success.record.save"),
|
1047
|
-
defaultMessage: "Saved document"
|
1048
|
-
})
|
1049
|
-
});
|
1050
|
-
return res.data;
|
1051
|
-
} catch (err) {
|
1052
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1053
|
-
toggleNotification({
|
1054
|
-
type: "danger",
|
1055
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1056
|
-
});
|
1057
|
-
throw err;
|
1141
|
+
throw error2;
|
1058
1142
|
}
|
1059
1143
|
},
|
1060
|
-
[
|
1144
|
+
[validationSchema]
|
1061
1145
|
);
|
1062
|
-
const
|
1063
|
-
|
1064
|
-
|
1146
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1147
|
+
return {
|
1148
|
+
components,
|
1149
|
+
document: data?.data,
|
1150
|
+
meta: data?.meta,
|
1151
|
+
isLoading,
|
1152
|
+
schema,
|
1153
|
+
schemas,
|
1154
|
+
validate
|
1155
|
+
};
|
1156
|
+
};
|
1157
|
+
const useDoc = () => {
|
1158
|
+
const { id, slug, collectionType, origin } = useParams();
|
1159
|
+
const [{ query }] = useQueryParams();
|
1160
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1161
|
+
if (!collectionType) {
|
1162
|
+
throw new Error("Could not find collectionType in url params");
|
1163
|
+
}
|
1164
|
+
if (!slug) {
|
1165
|
+
throw new Error("Could not find model in url params");
|
1166
|
+
}
|
1167
|
+
return {
|
1168
|
+
collectionType,
|
1169
|
+
model: slug,
|
1170
|
+
id: origin || id === "create" ? void 0 : id,
|
1171
|
+
...useDocument(
|
1172
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1173
|
+
{
|
1174
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1175
|
+
}
|
1176
|
+
)
|
1177
|
+
};
|
1178
|
+
};
|
1179
|
+
const useContentManagerContext = () => {
|
1180
|
+
const {
|
1181
|
+
collectionType,
|
1182
|
+
model,
|
1183
|
+
id,
|
1184
|
+
components,
|
1185
|
+
isLoading: isLoadingDoc,
|
1186
|
+
schema,
|
1187
|
+
schemas
|
1188
|
+
} = useDoc();
|
1189
|
+
const layout = useDocumentLayout(model);
|
1190
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1191
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1192
|
+
const slug = model;
|
1193
|
+
const isCreatingEntry = id === "create";
|
1194
|
+
useContentTypeSchema();
|
1195
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1196
|
+
const error = layout.error;
|
1197
|
+
return {
|
1198
|
+
error,
|
1199
|
+
isLoading,
|
1200
|
+
// Base metadata
|
1201
|
+
model,
|
1202
|
+
collectionType,
|
1203
|
+
id,
|
1204
|
+
slug,
|
1205
|
+
isCreatingEntry,
|
1206
|
+
isSingleType,
|
1207
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1208
|
+
// All schema infos
|
1209
|
+
components,
|
1210
|
+
contentType: schema,
|
1211
|
+
contentTypes: schemas,
|
1212
|
+
// Form state
|
1213
|
+
form,
|
1214
|
+
// layout infos
|
1215
|
+
layout
|
1216
|
+
};
|
1217
|
+
};
|
1218
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
1219
|
+
if (!pluginId) {
|
1220
|
+
throw new TypeError("pluginId can't be empty");
|
1221
|
+
}
|
1222
|
+
return Object.keys(trad).reduce((acc, current) => {
|
1223
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1224
|
+
return acc;
|
1225
|
+
}, {});
|
1226
|
+
};
|
1227
|
+
const getTranslation = (id) => `content-manager.${id}`;
|
1228
|
+
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
1229
|
+
id: "notification.error",
|
1230
|
+
defaultMessage: "An error occurred, please try again"
|
1231
|
+
};
|
1232
|
+
const useDocumentActions = () => {
|
1233
|
+
const { toggleNotification } = useNotification();
|
1234
|
+
const { formatMessage } = useIntl();
|
1235
|
+
const { trackUsage } = useTracking();
|
1236
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1237
|
+
const navigate = useNavigate();
|
1238
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
1239
|
+
const [deleteDocument] = useDeleteDocumentMutation();
|
1240
|
+
const _delete = React.useCallback(
|
1241
|
+
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
1065
1242
|
try {
|
1066
|
-
trackUsage("
|
1067
|
-
const res = await
|
1243
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1244
|
+
const res = await deleteDocument({
|
1068
1245
|
collectionType,
|
1069
1246
|
model,
|
1070
1247
|
documentId,
|
1071
|
-
params
|
1072
|
-
data: {
|
1073
|
-
discardDraft
|
1074
|
-
}
|
1248
|
+
params
|
1075
1249
|
});
|
1076
1250
|
if ("error" in res) {
|
1077
|
-
toggleNotification({
|
1251
|
+
toggleNotification({
|
1252
|
+
type: "danger",
|
1253
|
+
message: formatAPIError(res.error)
|
1254
|
+
});
|
1078
1255
|
return { error: res.error };
|
1079
1256
|
}
|
1080
|
-
trackUsage("didUnpublishEntry");
|
1081
1257
|
toggleNotification({
|
1082
1258
|
type: "success",
|
1083
1259
|
message: formatMessage({
|
1084
|
-
id: getTranslation("success.record.
|
1085
|
-
defaultMessage: "
|
1260
|
+
id: getTranslation("success.record.delete"),
|
1261
|
+
defaultMessage: "Deleted document"
|
1086
1262
|
})
|
1087
1263
|
});
|
1264
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1088
1265
|
return res.data;
|
1089
1266
|
} catch (err) {
|
1090
1267
|
toggleNotification({
|
1091
1268
|
type: "danger",
|
1092
1269
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1093
1270
|
});
|
1271
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1094
1272
|
throw err;
|
1095
1273
|
}
|
1096
1274
|
},
|
1097
|
-
[trackUsage,
|
1275
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1098
1276
|
);
|
1099
|
-
const [
|
1100
|
-
const
|
1277
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1278
|
+
const deleteMany = React.useCallback(
|
1101
1279
|
async ({ model, documentIds, params }) => {
|
1102
1280
|
try {
|
1103
|
-
trackUsage("
|
1104
|
-
const res = await
|
1281
|
+
trackUsage("willBulkDeleteEntries");
|
1282
|
+
const res = await deleteManyDocuments({
|
1105
1283
|
model,
|
1106
1284
|
documentIds,
|
1107
1285
|
params
|
1108
1286
|
});
|
1109
1287
|
if ("error" in res) {
|
1110
|
-
toggleNotification({
|
1288
|
+
toggleNotification({
|
1289
|
+
type: "danger",
|
1290
|
+
message: formatAPIError(res.error)
|
1291
|
+
});
|
1111
1292
|
return { error: res.error };
|
1112
1293
|
}
|
1113
|
-
trackUsage("didBulkUnpublishEntries");
|
1114
1294
|
toggleNotification({
|
1115
1295
|
type: "success",
|
1116
1296
|
title: formatMessage({
|
1117
|
-
id: getTranslation("success.records.
|
1118
|
-
defaultMessage: "Successfully
|
1297
|
+
id: getTranslation("success.records.delete"),
|
1298
|
+
defaultMessage: "Successfully deleted."
|
1119
1299
|
}),
|
1120
1300
|
message: ""
|
1121
1301
|
});
|
1302
|
+
trackUsage("didBulkDeleteEntries");
|
1122
1303
|
return res.data;
|
1123
1304
|
} catch (err) {
|
1124
1305
|
toggleNotification({
|
1125
1306
|
type: "danger",
|
1126
1307
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1127
1308
|
});
|
1128
|
-
trackUsage("
|
1309
|
+
trackUsage("didNotBulkDeleteEntries");
|
1129
1310
|
throw err;
|
1130
1311
|
}
|
1131
1312
|
},
|
1132
|
-
[trackUsage,
|
1313
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1133
1314
|
);
|
1134
|
-
const [
|
1135
|
-
const
|
1136
|
-
async ({ model, params }
|
1315
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1316
|
+
const discard = React.useCallback(
|
1317
|
+
async ({ collectionType, model, documentId, params }) => {
|
1137
1318
|
try {
|
1138
|
-
const res = await
|
1319
|
+
const res = await discardDocument({
|
1320
|
+
collectionType,
|
1139
1321
|
model,
|
1140
|
-
|
1322
|
+
documentId,
|
1323
|
+
params
|
1324
|
+
});
|
1325
|
+
if ("error" in res) {
|
1326
|
+
toggleNotification({
|
1327
|
+
type: "danger",
|
1328
|
+
message: formatAPIError(res.error)
|
1329
|
+
});
|
1330
|
+
return { error: res.error };
|
1331
|
+
}
|
1332
|
+
toggleNotification({
|
1333
|
+
type: "success",
|
1334
|
+
message: formatMessage({
|
1335
|
+
id: "content-manager.success.record.discard",
|
1336
|
+
defaultMessage: "Changes discarded"
|
1337
|
+
})
|
1338
|
+
});
|
1339
|
+
return res.data;
|
1340
|
+
} catch (err) {
|
1341
|
+
toggleNotification({
|
1342
|
+
type: "danger",
|
1343
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1344
|
+
});
|
1345
|
+
throw err;
|
1346
|
+
}
|
1347
|
+
},
|
1348
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1349
|
+
);
|
1350
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1351
|
+
const publish = React.useCallback(
|
1352
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1353
|
+
try {
|
1354
|
+
trackUsage("willPublishEntry");
|
1355
|
+
const res = await publishDocument({
|
1356
|
+
collectionType,
|
1357
|
+
model,
|
1358
|
+
documentId,
|
1359
|
+
data,
|
1360
|
+
params
|
1361
|
+
});
|
1362
|
+
if ("error" in res) {
|
1363
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1364
|
+
return { error: res.error };
|
1365
|
+
}
|
1366
|
+
trackUsage("didPublishEntry");
|
1367
|
+
toggleNotification({
|
1368
|
+
type: "success",
|
1369
|
+
message: formatMessage({
|
1370
|
+
id: getTranslation("success.record.publish"),
|
1371
|
+
defaultMessage: "Published document"
|
1372
|
+
})
|
1373
|
+
});
|
1374
|
+
return res.data;
|
1375
|
+
} catch (err) {
|
1376
|
+
toggleNotification({
|
1377
|
+
type: "danger",
|
1378
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1379
|
+
});
|
1380
|
+
throw err;
|
1381
|
+
}
|
1382
|
+
},
|
1383
|
+
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1384
|
+
);
|
1385
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1386
|
+
const publishMany = React.useCallback(
|
1387
|
+
async ({ model, documentIds, params }) => {
|
1388
|
+
try {
|
1389
|
+
const res = await publishManyDocuments({
|
1390
|
+
model,
|
1391
|
+
documentIds,
|
1392
|
+
params
|
1393
|
+
});
|
1394
|
+
if ("error" in res) {
|
1395
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1396
|
+
return { error: res.error };
|
1397
|
+
}
|
1398
|
+
toggleNotification({
|
1399
|
+
type: "success",
|
1400
|
+
message: formatMessage({
|
1401
|
+
id: getTranslation("success.record.publish"),
|
1402
|
+
defaultMessage: "Published document"
|
1403
|
+
})
|
1404
|
+
});
|
1405
|
+
return res.data;
|
1406
|
+
} catch (err) {
|
1407
|
+
toggleNotification({
|
1408
|
+
type: "danger",
|
1409
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1410
|
+
});
|
1411
|
+
throw err;
|
1412
|
+
}
|
1413
|
+
},
|
1414
|
+
[
|
1415
|
+
// trackUsage,
|
1416
|
+
publishManyDocuments,
|
1417
|
+
toggleNotification,
|
1418
|
+
formatMessage,
|
1419
|
+
formatAPIError
|
1420
|
+
]
|
1421
|
+
);
|
1422
|
+
const [updateDocument] = useUpdateDocumentMutation();
|
1423
|
+
const update = React.useCallback(
|
1424
|
+
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
1425
|
+
try {
|
1426
|
+
trackUsage("willEditEntry", trackerProperty);
|
1427
|
+
const res = await updateDocument({
|
1428
|
+
collectionType,
|
1429
|
+
model,
|
1430
|
+
documentId,
|
1431
|
+
data,
|
1432
|
+
params
|
1433
|
+
});
|
1434
|
+
if ("error" in res) {
|
1435
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1436
|
+
trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
|
1437
|
+
return { error: res.error };
|
1438
|
+
}
|
1439
|
+
trackUsage("didEditEntry", trackerProperty);
|
1440
|
+
toggleNotification({
|
1441
|
+
type: "success",
|
1442
|
+
message: formatMessage({
|
1443
|
+
id: getTranslation("success.record.save"),
|
1444
|
+
defaultMessage: "Saved document"
|
1445
|
+
})
|
1446
|
+
});
|
1447
|
+
return res.data;
|
1448
|
+
} catch (err) {
|
1449
|
+
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1450
|
+
toggleNotification({
|
1451
|
+
type: "danger",
|
1452
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1453
|
+
});
|
1454
|
+
throw err;
|
1455
|
+
}
|
1456
|
+
},
|
1457
|
+
[trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
|
1458
|
+
);
|
1459
|
+
const [unpublishDocument] = useUnpublishDocumentMutation();
|
1460
|
+
const unpublish = React.useCallback(
|
1461
|
+
async ({ collectionType, model, documentId, params }, discardDraft = false) => {
|
1462
|
+
try {
|
1463
|
+
trackUsage("willUnpublishEntry");
|
1464
|
+
const res = await unpublishDocument({
|
1465
|
+
collectionType,
|
1466
|
+
model,
|
1467
|
+
documentId,
|
1468
|
+
params,
|
1469
|
+
data: {
|
1470
|
+
discardDraft
|
1471
|
+
}
|
1472
|
+
});
|
1473
|
+
if ("error" in res) {
|
1474
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1475
|
+
return { error: res.error };
|
1476
|
+
}
|
1477
|
+
trackUsage("didUnpublishEntry");
|
1478
|
+
toggleNotification({
|
1479
|
+
type: "success",
|
1480
|
+
message: formatMessage({
|
1481
|
+
id: getTranslation("success.record.unpublish"),
|
1482
|
+
defaultMessage: "Unpublished document"
|
1483
|
+
})
|
1484
|
+
});
|
1485
|
+
return res.data;
|
1486
|
+
} catch (err) {
|
1487
|
+
toggleNotification({
|
1488
|
+
type: "danger",
|
1489
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1490
|
+
});
|
1491
|
+
throw err;
|
1492
|
+
}
|
1493
|
+
},
|
1494
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1495
|
+
);
|
1496
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1497
|
+
const unpublishMany = React.useCallback(
|
1498
|
+
async ({ model, documentIds, params }) => {
|
1499
|
+
try {
|
1500
|
+
trackUsage("willBulkUnpublishEntries");
|
1501
|
+
const res = await unpublishManyDocuments({
|
1502
|
+
model,
|
1503
|
+
documentIds,
|
1504
|
+
params
|
1505
|
+
});
|
1506
|
+
if ("error" in res) {
|
1507
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1508
|
+
return { error: res.error };
|
1509
|
+
}
|
1510
|
+
trackUsage("didBulkUnpublishEntries");
|
1511
|
+
toggleNotification({
|
1512
|
+
type: "success",
|
1513
|
+
title: formatMessage({
|
1514
|
+
id: getTranslation("success.records.unpublish"),
|
1515
|
+
defaultMessage: "Successfully unpublished."
|
1516
|
+
}),
|
1517
|
+
message: ""
|
1518
|
+
});
|
1519
|
+
return res.data;
|
1520
|
+
} catch (err) {
|
1521
|
+
toggleNotification({
|
1522
|
+
type: "danger",
|
1523
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1524
|
+
});
|
1525
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1526
|
+
throw err;
|
1527
|
+
}
|
1528
|
+
},
|
1529
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1530
|
+
);
|
1531
|
+
const [createDocument] = useCreateDocumentMutation();
|
1532
|
+
const create = React.useCallback(
|
1533
|
+
async ({ model, params }, data, trackerProperty) => {
|
1534
|
+
try {
|
1535
|
+
const res = await createDocument({
|
1536
|
+
model,
|
1537
|
+
data,
|
1141
1538
|
params
|
1142
1539
|
});
|
1143
1540
|
if ("error" in res) {
|
@@ -1153,6 +1550,7 @@ const useDocumentActions = () => {
|
|
1153
1550
|
defaultMessage: "Saved document"
|
1154
1551
|
})
|
1155
1552
|
});
|
1553
|
+
setCurrentStep("contentManager.success");
|
1156
1554
|
return res.data;
|
1157
1555
|
} catch (err) {
|
1158
1556
|
toggleNotification({
|
@@ -1174,7 +1572,6 @@ const useDocumentActions = () => {
|
|
1174
1572
|
sourceId
|
1175
1573
|
});
|
1176
1574
|
if ("error" in res) {
|
1177
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1178
1575
|
return { error: res.error };
|
1179
1576
|
}
|
1180
1577
|
toggleNotification({
|
@@ -1193,7 +1590,7 @@ const useDocumentActions = () => {
|
|
1193
1590
|
throw err;
|
1194
1591
|
}
|
1195
1592
|
},
|
1196
|
-
[autoCloneDocument,
|
1593
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1197
1594
|
);
|
1198
1595
|
const [cloneDocument] = useCloneDocumentMutation();
|
1199
1596
|
const clone = React.useCallback(
|
@@ -1219,6 +1616,7 @@ const useDocumentActions = () => {
|
|
1219
1616
|
defaultMessage: "Cloned document"
|
1220
1617
|
})
|
1221
1618
|
});
|
1619
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1222
1620
|
return res.data;
|
1223
1621
|
} catch (err) {
|
1224
1622
|
toggleNotification({
|
@@ -1229,7 +1627,7 @@ const useDocumentActions = () => {
|
|
1229
1627
|
throw err;
|
1230
1628
|
}
|
1231
1629
|
},
|
1232
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1630
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1233
1631
|
);
|
1234
1632
|
const [getDoc] = useLazyGetDocumentQuery();
|
1235
1633
|
const getDocument = React.useCallback(
|
@@ -1255,7 +1653,7 @@ const useDocumentActions = () => {
|
|
1255
1653
|
};
|
1256
1654
|
};
|
1257
1655
|
const ProtectedHistoryPage = lazy(
|
1258
|
-
() => import("./History-
|
1656
|
+
() => import("./History-BqO2G3MV.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1259
1657
|
);
|
1260
1658
|
const routes$1 = [
|
1261
1659
|
{
|
@@ -1268,31 +1666,31 @@ const routes$1 = [
|
|
1268
1666
|
}
|
1269
1667
|
];
|
1270
1668
|
const ProtectedEditViewPage = lazy(
|
1271
|
-
() => import("./EditViewPage-
|
1669
|
+
() => import("./EditViewPage-BU1ugeVi.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1272
1670
|
);
|
1273
1671
|
const ProtectedListViewPage = lazy(
|
1274
|
-
() => import("./ListViewPage-
|
1672
|
+
() => import("./ListViewPage-yE_zYhcI.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1275
1673
|
);
|
1276
1674
|
const ProtectedListConfiguration = lazy(
|
1277
|
-
() => import("./ListConfigurationPage-
|
1675
|
+
() => import("./ListConfigurationPage-C6rsFlme.mjs").then((mod) => ({
|
1278
1676
|
default: mod.ProtectedListConfiguration
|
1279
1677
|
}))
|
1280
1678
|
);
|
1281
1679
|
const ProtectedEditConfigurationPage = lazy(
|
1282
|
-
() => import("./EditConfigurationPage-
|
1680
|
+
() => import("./EditConfigurationPage-Dh6sq-G4.mjs").then((mod) => ({
|
1283
1681
|
default: mod.ProtectedEditConfigurationPage
|
1284
1682
|
}))
|
1285
1683
|
);
|
1286
1684
|
const ProtectedComponentConfigurationPage = lazy(
|
1287
|
-
() => import("./ComponentConfigurationPage-
|
1685
|
+
() => import("./ComponentConfigurationPage-hLMNf7KI.mjs").then((mod) => ({
|
1288
1686
|
default: mod.ProtectedComponentConfigurationPage
|
1289
1687
|
}))
|
1290
1688
|
);
|
1291
1689
|
const NoPermissions = lazy(
|
1292
|
-
() => import("./NoPermissionsPage-
|
1690
|
+
() => import("./NoPermissionsPage-h0I3ImsX.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1293
1691
|
);
|
1294
1692
|
const NoContentType = lazy(
|
1295
|
-
() => import("./NoContentTypePage-
|
1693
|
+
() => import("./NoContentTypePage-NW_FSVdY.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1296
1694
|
);
|
1297
1695
|
const CollectionTypePages = () => {
|
1298
1696
|
const { collectionType } = useParams();
|
@@ -1325,1071 +1723,756 @@ const routes = [
|
|
1325
1723
|
{
|
1326
1724
|
path: "components/:slug/configurations/edit",
|
1327
1725
|
Component: ProtectedComponentConfigurationPage
|
1328
|
-
},
|
1329
|
-
{
|
1330
|
-
path: ":collectionType/:slug/configurations/edit",
|
1331
|
-
Component: ProtectedEditConfigurationPage
|
1332
|
-
},
|
1333
|
-
{
|
1334
|
-
path: "403",
|
1335
|
-
Component: NoPermissions
|
1336
|
-
},
|
1337
|
-
{
|
1338
|
-
path: "no-content-types",
|
1339
|
-
Component: NoContentType
|
1340
|
-
},
|
1341
|
-
...routes$1
|
1342
|
-
];
|
1343
|
-
const DocumentActions = ({ actions: actions2 }) => {
|
1344
|
-
const { formatMessage } = useIntl();
|
1345
|
-
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1346
|
-
if (action.position === void 0) {
|
1347
|
-
return true;
|
1348
|
-
}
|
1349
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1350
|
-
return positions.includes("panel");
|
1351
|
-
});
|
1352
|
-
if (!primaryAction) {
|
1353
|
-
return null;
|
1354
|
-
}
|
1355
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1356
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1357
|
-
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1358
|
-
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1359
|
-
DocumentActionsMenu,
|
1360
|
-
{
|
1361
|
-
actions: restActions,
|
1362
|
-
label: formatMessage({
|
1363
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1364
|
-
defaultMessage: "More document actions"
|
1365
|
-
})
|
1366
|
-
}
|
1367
|
-
) : null
|
1368
|
-
] }),
|
1369
|
-
secondaryAction ? /* @__PURE__ */ jsx(
|
1370
|
-
DocumentActionButton,
|
1371
|
-
{
|
1372
|
-
...secondaryAction,
|
1373
|
-
variant: secondaryAction.variant || "secondary"
|
1374
|
-
}
|
1375
|
-
) : null
|
1376
|
-
] });
|
1377
|
-
};
|
1378
|
-
const DocumentActionButton = (action) => {
|
1379
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1380
|
-
const { toggleNotification } = useNotification();
|
1381
|
-
const handleClick = (action2) => async (e) => {
|
1382
|
-
const { onClick = () => false, dialog, id } = action2;
|
1383
|
-
const muteDialog = await onClick(e);
|
1384
|
-
if (dialog && !muteDialog) {
|
1385
|
-
switch (dialog.type) {
|
1386
|
-
case "notification":
|
1387
|
-
toggleNotification({
|
1388
|
-
title: dialog.title,
|
1389
|
-
message: dialog.content,
|
1390
|
-
type: dialog.status,
|
1391
|
-
timeout: dialog.timeout,
|
1392
|
-
onClose: dialog.onClose
|
1393
|
-
});
|
1394
|
-
break;
|
1395
|
-
case "dialog":
|
1396
|
-
case "modal":
|
1397
|
-
e.preventDefault();
|
1398
|
-
setDialogId(id);
|
1399
|
-
}
|
1400
|
-
}
|
1401
|
-
};
|
1402
|
-
const handleClose = () => {
|
1403
|
-
setDialogId(null);
|
1404
|
-
};
|
1405
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1406
|
-
/* @__PURE__ */ jsx(
|
1407
|
-
Button,
|
1408
|
-
{
|
1409
|
-
flex: 1,
|
1410
|
-
startIcon: action.icon,
|
1411
|
-
disabled: action.disabled,
|
1412
|
-
onClick: handleClick(action),
|
1413
|
-
justifyContent: "center",
|
1414
|
-
variant: action.variant || "default",
|
1415
|
-
children: action.label
|
1416
|
-
}
|
1417
|
-
),
|
1418
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1419
|
-
DocumentActionConfirmDialog,
|
1420
|
-
{
|
1421
|
-
...action.dialog,
|
1422
|
-
variant: action.dialog?.variant ?? action.variant,
|
1423
|
-
isOpen: dialogId === action.id,
|
1424
|
-
onClose: handleClose
|
1425
|
-
}
|
1426
|
-
) : null,
|
1427
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1428
|
-
DocumentActionModal,
|
1429
|
-
{
|
1430
|
-
...action.dialog,
|
1431
|
-
onModalClose: handleClose,
|
1432
|
-
isOpen: dialogId === action.id
|
1433
|
-
}
|
1434
|
-
) : null
|
1435
|
-
] });
|
1436
|
-
};
|
1437
|
-
const DocumentActionsMenu = ({
|
1438
|
-
actions: actions2,
|
1439
|
-
children,
|
1440
|
-
label,
|
1441
|
-
variant = "tertiary"
|
1442
|
-
}) => {
|
1443
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
1444
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1445
|
-
const { formatMessage } = useIntl();
|
1446
|
-
const { toggleNotification } = useNotification();
|
1447
|
-
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1448
|
-
const handleClick = (action) => async (e) => {
|
1449
|
-
const { onClick = () => false, dialog, id } = action;
|
1450
|
-
const muteDialog = await onClick(e);
|
1451
|
-
if (dialog && !muteDialog) {
|
1452
|
-
switch (dialog.type) {
|
1453
|
-
case "notification":
|
1454
|
-
toggleNotification({
|
1455
|
-
title: dialog.title,
|
1456
|
-
message: dialog.content,
|
1457
|
-
type: dialog.status,
|
1458
|
-
timeout: dialog.timeout,
|
1459
|
-
onClose: dialog.onClose
|
1460
|
-
});
|
1461
|
-
break;
|
1462
|
-
case "dialog":
|
1463
|
-
case "modal":
|
1464
|
-
setDialogId(id);
|
1465
|
-
}
|
1466
|
-
}
|
1467
|
-
};
|
1468
|
-
const handleClose = () => {
|
1469
|
-
setDialogId(null);
|
1470
|
-
setIsOpen(false);
|
1471
|
-
};
|
1472
|
-
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1473
|
-
/* @__PURE__ */ jsxs(
|
1474
|
-
Menu.Trigger,
|
1475
|
-
{
|
1476
|
-
disabled: isDisabled,
|
1477
|
-
size: "S",
|
1478
|
-
endIcon: null,
|
1479
|
-
paddingTop: "7px",
|
1480
|
-
paddingLeft: "9px",
|
1481
|
-
paddingRight: "9px",
|
1482
|
-
variant,
|
1483
|
-
children: [
|
1484
|
-
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1485
|
-
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1486
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1487
|
-
defaultMessage: "More document actions"
|
1488
|
-
}) })
|
1489
|
-
]
|
1490
|
-
}
|
1491
|
-
),
|
1492
|
-
/* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1493
|
-
actions2.map((action) => {
|
1494
|
-
return /* @__PURE__ */ jsx(
|
1495
|
-
Menu.Item,
|
1496
|
-
{
|
1497
|
-
disabled: action.disabled,
|
1498
|
-
onSelect: handleClick(action),
|
1499
|
-
display: "block",
|
1500
|
-
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1501
|
-
/* @__PURE__ */ jsxs(Flex, { color: convertActionVariantToColor(action.variant), gap: 2, tag: "span", children: [
|
1502
|
-
/* @__PURE__ */ jsx(Box, { tag: "span", color: convertActionVariantToIconColor(action.variant), children: action.icon }),
|
1503
|
-
action.label
|
1504
|
-
] }),
|
1505
|
-
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1506
|
-
Flex,
|
1507
|
-
{
|
1508
|
-
alignItems: "center",
|
1509
|
-
background: "alternative100",
|
1510
|
-
borderStyle: "solid",
|
1511
|
-
borderColor: "alternative200",
|
1512
|
-
borderWidth: "1px",
|
1513
|
-
height: 5,
|
1514
|
-
paddingLeft: 2,
|
1515
|
-
paddingRight: 2,
|
1516
|
-
hasRadius: true,
|
1517
|
-
color: "alternative600",
|
1518
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1519
|
-
}
|
1520
|
-
)
|
1521
|
-
] })
|
1522
|
-
},
|
1523
|
-
action.id
|
1524
|
-
);
|
1525
|
-
}),
|
1526
|
-
children
|
1527
|
-
] }),
|
1528
|
-
actions2.map((action) => {
|
1529
|
-
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1530
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1531
|
-
DocumentActionConfirmDialog,
|
1532
|
-
{
|
1533
|
-
...action.dialog,
|
1534
|
-
variant: action.variant,
|
1535
|
-
isOpen: dialogId === action.id,
|
1536
|
-
onClose: handleClose
|
1537
|
-
}
|
1538
|
-
) : null,
|
1539
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1540
|
-
DocumentActionModal,
|
1541
|
-
{
|
1542
|
-
...action.dialog,
|
1543
|
-
onModalClose: handleClose,
|
1544
|
-
isOpen: dialogId === action.id
|
1545
|
-
}
|
1546
|
-
) : null
|
1547
|
-
] }, action.id);
|
1548
|
-
})
|
1549
|
-
] });
|
1550
|
-
};
|
1551
|
-
const convertActionVariantToColor = (variant = "secondary") => {
|
1552
|
-
switch (variant) {
|
1553
|
-
case "danger":
|
1554
|
-
return "danger600";
|
1555
|
-
case "secondary":
|
1556
|
-
return void 0;
|
1557
|
-
case "success":
|
1558
|
-
return "success600";
|
1559
|
-
default:
|
1560
|
-
return "primary600";
|
1561
|
-
}
|
1562
|
-
};
|
1563
|
-
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1564
|
-
switch (variant) {
|
1565
|
-
case "danger":
|
1566
|
-
return "danger600";
|
1567
|
-
case "secondary":
|
1568
|
-
return "neutral500";
|
1569
|
-
case "success":
|
1570
|
-
return "success600";
|
1571
|
-
default:
|
1572
|
-
return "primary600";
|
1573
|
-
}
|
1574
|
-
};
|
1575
|
-
const DocumentActionConfirmDialog = ({
|
1576
|
-
onClose,
|
1577
|
-
onCancel,
|
1578
|
-
onConfirm,
|
1579
|
-
title,
|
1580
|
-
content,
|
1581
|
-
isOpen,
|
1582
|
-
variant = "secondary"
|
1583
|
-
}) => {
|
1584
|
-
const { formatMessage } = useIntl();
|
1585
|
-
const handleClose = async () => {
|
1586
|
-
if (onCancel) {
|
1587
|
-
await onCancel();
|
1588
|
-
}
|
1589
|
-
onClose();
|
1590
|
-
};
|
1591
|
-
const handleConfirm = async () => {
|
1592
|
-
if (onConfirm) {
|
1593
|
-
await onConfirm();
|
1594
|
-
}
|
1595
|
-
onClose();
|
1596
|
-
};
|
1597
|
-
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
1598
|
-
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1599
|
-
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1600
|
-
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1601
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
1602
|
-
id: "app.components.Button.cancel",
|
1603
|
-
defaultMessage: "Cancel"
|
1604
|
-
}) }) }),
|
1605
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1606
|
-
id: "app.components.Button.confirm",
|
1607
|
-
defaultMessage: "Confirm"
|
1608
|
-
}) })
|
1609
|
-
] })
|
1610
|
-
] }) });
|
1611
|
-
};
|
1612
|
-
const DocumentActionModal = ({
|
1613
|
-
isOpen,
|
1614
|
-
title,
|
1615
|
-
onClose,
|
1616
|
-
footer: Footer,
|
1617
|
-
content: Content,
|
1618
|
-
onModalClose
|
1619
|
-
}) => {
|
1620
|
-
const handleClose = () => {
|
1621
|
-
if (onClose) {
|
1622
|
-
onClose();
|
1623
|
-
}
|
1624
|
-
onModalClose();
|
1625
|
-
};
|
1626
|
-
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1627
|
-
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1628
|
-
/* @__PURE__ */ jsx(Modal.Body, { children: typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content }),
|
1629
|
-
/* @__PURE__ */ jsx(Modal.Footer, { children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer })
|
1630
|
-
] }) });
|
1631
|
-
};
|
1632
|
-
const PublishAction$1 = ({
|
1633
|
-
activeTab,
|
1634
|
-
documentId,
|
1635
|
-
model,
|
1636
|
-
collectionType,
|
1637
|
-
meta,
|
1638
|
-
document
|
1639
|
-
}) => {
|
1640
|
-
const { schema } = useDoc();
|
1641
|
-
const navigate = useNavigate();
|
1642
|
-
const { toggleNotification } = useNotification();
|
1643
|
-
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
1644
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
1645
|
-
const { formatMessage } = useIntl();
|
1646
|
-
const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
|
1647
|
-
"PublishAction",
|
1648
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1649
|
-
);
|
1650
|
-
const { publish } = useDocumentActions();
|
1651
|
-
const [
|
1652
|
-
countDraftRelations,
|
1653
|
-
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1654
|
-
] = useLazyGetDraftRelationCountQuery();
|
1655
|
-
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
1656
|
-
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1657
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1658
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1659
|
-
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
1660
|
-
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1661
|
-
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1662
|
-
const validate = useForm("PublishAction", (state) => state.validate);
|
1663
|
-
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1664
|
-
const formValues = useForm("PublishAction", ({ values }) => values);
|
1665
|
-
React.useEffect(() => {
|
1666
|
-
if (isErrorDraftRelations) {
|
1667
|
-
toggleNotification({
|
1668
|
-
type: "danger",
|
1669
|
-
message: formatMessage({
|
1670
|
-
id: getTranslation("error.records.fetch-draft-relatons"),
|
1671
|
-
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1672
|
-
})
|
1673
|
-
});
|
1674
|
-
}
|
1675
|
-
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1676
|
-
React.useEffect(() => {
|
1677
|
-
const localDraftRelations = /* @__PURE__ */ new Set();
|
1678
|
-
const extractDraftRelations = (data) => {
|
1679
|
-
const relations = data.connect || [];
|
1680
|
-
relations.forEach((relation) => {
|
1681
|
-
if (relation.status === "draft") {
|
1682
|
-
localDraftRelations.add(relation.id);
|
1683
|
-
}
|
1684
|
-
});
|
1685
|
-
};
|
1686
|
-
const traverseAndExtract = (data) => {
|
1687
|
-
Object.entries(data).forEach(([key, value]) => {
|
1688
|
-
if (key === "connect" && Array.isArray(value)) {
|
1689
|
-
extractDraftRelations({ connect: value });
|
1690
|
-
} else if (typeof value === "object" && value !== null) {
|
1691
|
-
traverseAndExtract(value);
|
1692
|
-
}
|
1693
|
-
});
|
1694
|
-
};
|
1695
|
-
if (!documentId || modified) {
|
1696
|
-
traverseAndExtract(formValues);
|
1697
|
-
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1698
|
-
}
|
1699
|
-
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1700
|
-
React.useEffect(() => {
|
1701
|
-
if (documentId) {
|
1702
|
-
const fetchDraftRelationsCount = async () => {
|
1703
|
-
const { data, error } = await countDraftRelations({
|
1704
|
-
collectionType,
|
1705
|
-
model,
|
1706
|
-
documentId,
|
1707
|
-
params
|
1708
|
-
});
|
1709
|
-
if (error) {
|
1710
|
-
throw error;
|
1711
|
-
}
|
1712
|
-
if (data) {
|
1713
|
-
setServerCountOfDraftRelations(data.data);
|
1714
|
-
}
|
1715
|
-
};
|
1716
|
-
fetchDraftRelationsCount();
|
1726
|
+
},
|
1727
|
+
{
|
1728
|
+
path: ":collectionType/:slug/configurations/edit",
|
1729
|
+
Component: ProtectedEditConfigurationPage
|
1730
|
+
},
|
1731
|
+
{
|
1732
|
+
path: "403",
|
1733
|
+
Component: NoPermissions
|
1734
|
+
},
|
1735
|
+
{
|
1736
|
+
path: "no-content-types",
|
1737
|
+
Component: NoContentType
|
1738
|
+
},
|
1739
|
+
...routes$1
|
1740
|
+
];
|
1741
|
+
const DocumentActions = ({ actions: actions2 }) => {
|
1742
|
+
const { formatMessage } = useIntl();
|
1743
|
+
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1744
|
+
if (action.position === void 0) {
|
1745
|
+
return true;
|
1717
1746
|
}
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1747
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1748
|
+
return positions.includes("panel");
|
1749
|
+
});
|
1750
|
+
if (!primaryAction) {
|
1721
1751
|
return null;
|
1722
1752
|
}
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
toggleNotification({
|
1729
|
-
type: "danger",
|
1730
|
-
message: formatMessage({
|
1731
|
-
id: "content-manager.validation.error",
|
1732
|
-
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1733
|
-
})
|
1734
|
-
});
|
1735
|
-
return;
|
1736
|
-
}
|
1737
|
-
const res = await publish(
|
1738
|
-
{
|
1739
|
-
collectionType,
|
1740
|
-
model,
|
1741
|
-
documentId,
|
1742
|
-
params
|
1743
|
-
},
|
1744
|
-
formValues
|
1745
|
-
);
|
1746
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1747
|
-
navigate({
|
1748
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1749
|
-
search: rawQuery
|
1750
|
-
});
|
1751
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1752
|
-
setErrors(formatValidationErrors(res.error));
|
1753
|
-
}
|
1754
|
-
} finally {
|
1755
|
-
setSubmitting(false);
|
1756
|
-
}
|
1757
|
-
};
|
1758
|
-
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1759
|
-
const hasDraftRelations = totalDraftRelations > 0;
|
1760
|
-
return {
|
1761
|
-
/**
|
1762
|
-
* Disabled when:
|
1763
|
-
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
1764
|
-
* - the form is submitting
|
1765
|
-
* - the active tab is the published tab
|
1766
|
-
* - the document is already published & not modified
|
1767
|
-
* - the document is being created & not modified
|
1768
|
-
* - the user doesn't have the permission to publish
|
1769
|
-
* - the user doesn't have the permission to create a new document
|
1770
|
-
* - the user doesn't have the permission to update the document
|
1771
|
-
*/
|
1772
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish || Boolean(!document?.documentId && !canCreate || document?.documentId && !canUpdate),
|
1773
|
-
label: formatMessage({
|
1774
|
-
id: "app.utils.publish",
|
1775
|
-
defaultMessage: "Publish"
|
1776
|
-
}),
|
1777
|
-
onClick: async () => {
|
1778
|
-
if (hasDraftRelations) {
|
1779
|
-
return;
|
1780
|
-
}
|
1781
|
-
await performPublish();
|
1782
|
-
},
|
1783
|
-
dialog: hasDraftRelations ? {
|
1784
|
-
type: "dialog",
|
1785
|
-
variant: "danger",
|
1786
|
-
footer: null,
|
1787
|
-
title: formatMessage({
|
1788
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1789
|
-
defaultMessage: "Confirmation"
|
1790
|
-
}),
|
1791
|
-
content: formatMessage(
|
1792
|
-
{
|
1793
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1794
|
-
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1795
|
-
},
|
1753
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1754
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1755
|
+
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1756
|
+
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1757
|
+
DocumentActionsMenu,
|
1796
1758
|
{
|
1797
|
-
|
1759
|
+
actions: restActions,
|
1760
|
+
label: formatMessage({
|
1761
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1762
|
+
defaultMessage: "More document actions"
|
1763
|
+
})
|
1798
1764
|
}
|
1799
|
-
)
|
1800
|
-
|
1801
|
-
|
1765
|
+
) : null
|
1766
|
+
] }),
|
1767
|
+
secondaryAction ? /* @__PURE__ */ jsx(
|
1768
|
+
DocumentActionButton,
|
1769
|
+
{
|
1770
|
+
...secondaryAction,
|
1771
|
+
variant: secondaryAction.variant || "secondary"
|
1802
1772
|
}
|
1803
|
-
|
1804
|
-
};
|
1773
|
+
) : null
|
1774
|
+
] });
|
1805
1775
|
};
|
1806
|
-
|
1807
|
-
const
|
1808
|
-
activeTab,
|
1809
|
-
documentId,
|
1810
|
-
model,
|
1811
|
-
collectionType
|
1812
|
-
}) => {
|
1813
|
-
const navigate = useNavigate();
|
1776
|
+
const DocumentActionButton = (action) => {
|
1777
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1814
1778
|
const { toggleNotification } = useNotification();
|
1815
|
-
const
|
1816
|
-
|
1817
|
-
|
1818
|
-
|
1819
|
-
|
1820
|
-
|
1821
|
-
canUpdate: canUpdate2
|
1822
|
-
}));
|
1823
|
-
const { create, update, clone } = useDocumentActions();
|
1824
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1825
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1826
|
-
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1827
|
-
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
1828
|
-
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1829
|
-
const document = useForm("UpdateAction", ({ values }) => values);
|
1830
|
-
const validate = useForm("UpdateAction", (state) => state.validate);
|
1831
|
-
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1832
|
-
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1833
|
-
return {
|
1834
|
-
/**
|
1835
|
-
* Disabled when:
|
1836
|
-
* - the form is submitting
|
1837
|
-
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1838
|
-
* - the active tab is the published tab
|
1839
|
-
* - the user doesn't have the permission to create a new document
|
1840
|
-
* - the user doesn't have the permission to update the document
|
1841
|
-
*/
|
1842
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published" || Boolean(!documentId && !canCreate || documentId && !canUpdate),
|
1843
|
-
label: formatMessage({
|
1844
|
-
id: "content-manager.containers.Edit.save",
|
1845
|
-
defaultMessage: "Save"
|
1846
|
-
}),
|
1847
|
-
onClick: async () => {
|
1848
|
-
setSubmitting(true);
|
1849
|
-
try {
|
1850
|
-
const { errors } = await validate();
|
1851
|
-
if (errors) {
|
1779
|
+
const handleClick = (action2) => async (e) => {
|
1780
|
+
const { onClick = () => false, dialog, id } = action2;
|
1781
|
+
const muteDialog = await onClick(e);
|
1782
|
+
if (dialog && !muteDialog) {
|
1783
|
+
switch (dialog.type) {
|
1784
|
+
case "notification":
|
1852
1785
|
toggleNotification({
|
1853
|
-
|
1854
|
-
message:
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1786
|
+
title: dialog.title,
|
1787
|
+
message: dialog.content,
|
1788
|
+
type: dialog.status,
|
1789
|
+
timeout: dialog.timeout,
|
1790
|
+
onClose: dialog.onClose
|
1858
1791
|
});
|
1859
|
-
|
1860
|
-
|
1861
|
-
|
1862
|
-
|
1863
|
-
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1867
|
-
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
|
1874
|
-
|
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
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1902
|
-
navigate(
|
1903
|
-
{
|
1904
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1905
|
-
search: rawQuery
|
1906
|
-
},
|
1907
|
-
{ replace: true }
|
1908
|
-
);
|
1909
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1910
|
-
setErrors(formatValidationErrors(res.error));
|
1911
|
-
}
|
1912
|
-
}
|
1913
|
-
} finally {
|
1914
|
-
setSubmitting(false);
|
1792
|
+
break;
|
1793
|
+
case "dialog":
|
1794
|
+
case "modal":
|
1795
|
+
e.preventDefault();
|
1796
|
+
setDialogId(id);
|
1797
|
+
}
|
1798
|
+
}
|
1799
|
+
};
|
1800
|
+
const handleClose = () => {
|
1801
|
+
setDialogId(null);
|
1802
|
+
};
|
1803
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1804
|
+
/* @__PURE__ */ jsx(
|
1805
|
+
Button,
|
1806
|
+
{
|
1807
|
+
flex: "auto",
|
1808
|
+
startIcon: action.icon,
|
1809
|
+
disabled: action.disabled,
|
1810
|
+
onClick: handleClick(action),
|
1811
|
+
justifyContent: "center",
|
1812
|
+
variant: action.variant || "default",
|
1813
|
+
paddingTop: "7px",
|
1814
|
+
paddingBottom: "7px",
|
1815
|
+
children: action.label
|
1816
|
+
}
|
1817
|
+
),
|
1818
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1819
|
+
DocumentActionConfirmDialog,
|
1820
|
+
{
|
1821
|
+
...action.dialog,
|
1822
|
+
variant: action.dialog?.variant ?? action.variant,
|
1823
|
+
isOpen: dialogId === action.id,
|
1824
|
+
onClose: handleClose
|
1825
|
+
}
|
1826
|
+
) : null,
|
1827
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1828
|
+
DocumentActionModal,
|
1829
|
+
{
|
1830
|
+
...action.dialog,
|
1831
|
+
onModalClose: handleClose,
|
1832
|
+
isOpen: dialogId === action.id
|
1915
1833
|
}
|
1916
|
-
|
1917
|
-
};
|
1918
|
-
};
|
1919
|
-
UpdateAction.type = "update";
|
1920
|
-
const UNPUBLISH_DRAFT_OPTIONS = {
|
1921
|
-
KEEP: "keep",
|
1922
|
-
DISCARD: "discard"
|
1834
|
+
) : null
|
1835
|
+
] });
|
1923
1836
|
};
|
1924
|
-
const
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
document
|
1837
|
+
const DocumentActionsMenu = ({
|
1838
|
+
actions: actions2,
|
1839
|
+
children,
|
1840
|
+
label,
|
1841
|
+
variant = "tertiary"
|
1930
1842
|
}) => {
|
1843
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
1844
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1931
1845
|
const { formatMessage } = useIntl();
|
1932
|
-
const { schema } = useDoc();
|
1933
|
-
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1934
|
-
const { unpublish } = useDocumentActions();
|
1935
|
-
const [{ query }] = useQueryParams();
|
1936
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1937
1846
|
const { toggleNotification } = useNotification();
|
1938
|
-
const
|
1939
|
-
const
|
1940
|
-
|
1941
|
-
|
1942
|
-
|
1943
|
-
|
1944
|
-
|
1945
|
-
}
|
1946
|
-
return {
|
1947
|
-
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
1948
|
-
label: formatMessage({
|
1949
|
-
id: "app.utils.unpublish",
|
1950
|
-
defaultMessage: "Unpublish"
|
1951
|
-
}),
|
1952
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
1953
|
-
onClick: async () => {
|
1954
|
-
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1955
|
-
if (!documentId) {
|
1956
|
-
console.error(
|
1957
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
1958
|
-
);
|
1847
|
+
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1848
|
+
const handleClick = (action) => async (e) => {
|
1849
|
+
const { onClick = () => false, dialog, id } = action;
|
1850
|
+
const muteDialog = await onClick(e);
|
1851
|
+
if (dialog && !muteDialog) {
|
1852
|
+
switch (dialog.type) {
|
1853
|
+
case "notification":
|
1959
1854
|
toggleNotification({
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1855
|
+
title: dialog.title,
|
1856
|
+
message: dialog.content,
|
1857
|
+
type: dialog.status,
|
1858
|
+
timeout: dialog.timeout,
|
1859
|
+
onClose: dialog.onClose
|
1965
1860
|
});
|
1966
|
-
|
1967
|
-
|
1861
|
+
break;
|
1862
|
+
case "dialog":
|
1863
|
+
case "modal":
|
1864
|
+
setDialogId(id);
|
1968
1865
|
}
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1866
|
+
}
|
1867
|
+
};
|
1868
|
+
const handleClose = () => {
|
1869
|
+
setDialogId(null);
|
1870
|
+
setIsOpen(false);
|
1871
|
+
};
|
1872
|
+
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1873
|
+
/* @__PURE__ */ jsxs(
|
1874
|
+
Menu.Trigger,
|
1875
|
+
{
|
1876
|
+
disabled: isDisabled,
|
1877
|
+
size: "S",
|
1878
|
+
endIcon: null,
|
1879
|
+
paddingTop: "4px",
|
1880
|
+
paddingLeft: "7px",
|
1881
|
+
paddingRight: "7px",
|
1882
|
+
variant,
|
1883
|
+
children: [
|
1884
|
+
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1885
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1886
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1887
|
+
defaultMessage: "More document actions"
|
1988
1888
|
}) })
|
1989
|
-
]
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
id: "content-manager.actions.unpublish.dialog.radio-label",
|
1997
|
-
defaultMessage: "Choose an option to unpublish the document."
|
1998
|
-
}),
|
1999
|
-
onValueChange: handleChange,
|
2000
|
-
children: [
|
2001
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2002
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2003
|
-
defaultMessage: "Keep draft"
|
2004
|
-
}) }),
|
2005
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2006
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2007
|
-
defaultMessage: "Replace draft"
|
2008
|
-
}) })
|
2009
|
-
]
|
2010
|
-
}
|
2011
|
-
)
|
2012
|
-
] }),
|
2013
|
-
onConfirm: async () => {
|
2014
|
-
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2015
|
-
console.error(
|
2016
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2017
|
-
);
|
2018
|
-
toggleNotification({
|
2019
|
-
message: formatMessage({
|
2020
|
-
id: "content-manager.actions.unpublish.error",
|
2021
|
-
defaultMessage: "An error occurred while trying to unpublish the document."
|
2022
|
-
}),
|
2023
|
-
type: "danger"
|
2024
|
-
});
|
2025
|
-
}
|
2026
|
-
await unpublish(
|
1889
|
+
]
|
1890
|
+
}
|
1891
|
+
),
|
1892
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1893
|
+
actions2.map((action) => {
|
1894
|
+
return /* @__PURE__ */ jsx(
|
1895
|
+
Menu.Item,
|
2027
1896
|
{
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
1897
|
+
disabled: action.disabled,
|
1898
|
+
onSelect: handleClick(action),
|
1899
|
+
display: "block",
|
1900
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1901
|
+
/* @__PURE__ */ jsxs(
|
1902
|
+
Flex,
|
1903
|
+
{
|
1904
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1905
|
+
gap: 2,
|
1906
|
+
tag: "span",
|
1907
|
+
children: [
|
1908
|
+
/* @__PURE__ */ jsx(
|
1909
|
+
Flex,
|
1910
|
+
{
|
1911
|
+
tag: "span",
|
1912
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1913
|
+
children: action.icon
|
1914
|
+
}
|
1915
|
+
),
|
1916
|
+
action.label
|
1917
|
+
]
|
1918
|
+
}
|
1919
|
+
),
|
1920
|
+
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1921
|
+
Flex,
|
1922
|
+
{
|
1923
|
+
alignItems: "center",
|
1924
|
+
background: "alternative100",
|
1925
|
+
borderStyle: "solid",
|
1926
|
+
borderColor: "alternative200",
|
1927
|
+
borderWidth: "1px",
|
1928
|
+
height: 5,
|
1929
|
+
paddingLeft: 2,
|
1930
|
+
paddingRight: 2,
|
1931
|
+
hasRadius: true,
|
1932
|
+
color: "alternative600",
|
1933
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1934
|
+
}
|
1935
|
+
)
|
1936
|
+
] })
|
2032
1937
|
},
|
2033
|
-
|
1938
|
+
action.id
|
2034
1939
|
);
|
2035
|
-
}
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
1940
|
+
}),
|
1941
|
+
children
|
1942
|
+
] }),
|
1943
|
+
actions2.map((action) => {
|
1944
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1945
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1946
|
+
DocumentActionConfirmDialog,
|
1947
|
+
{
|
1948
|
+
...action.dialog,
|
1949
|
+
variant: action.variant,
|
1950
|
+
isOpen: dialogId === action.id,
|
1951
|
+
onClose: handleClose
|
1952
|
+
}
|
1953
|
+
) : null,
|
1954
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1955
|
+
DocumentActionModal,
|
1956
|
+
{
|
1957
|
+
...action.dialog,
|
1958
|
+
onModalClose: handleClose,
|
1959
|
+
isOpen: dialogId === action.id
|
1960
|
+
}
|
1961
|
+
) : null
|
1962
|
+
] }, action.id);
|
1963
|
+
})
|
1964
|
+
] });
|
1965
|
+
};
|
1966
|
+
const convertActionVariantToColor = (variant = "secondary") => {
|
1967
|
+
switch (variant) {
|
1968
|
+
case "danger":
|
1969
|
+
return "danger600";
|
1970
|
+
case "secondary":
|
1971
|
+
return void 0;
|
1972
|
+
case "success":
|
1973
|
+
return "success600";
|
1974
|
+
default:
|
1975
|
+
return "primary600";
|
1976
|
+
}
|
1977
|
+
};
|
1978
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1979
|
+
switch (variant) {
|
1980
|
+
case "danger":
|
1981
|
+
return "danger600";
|
1982
|
+
case "secondary":
|
1983
|
+
return "neutral500";
|
1984
|
+
case "success":
|
1985
|
+
return "success600";
|
1986
|
+
default:
|
1987
|
+
return "primary600";
|
1988
|
+
}
|
1989
|
+
};
|
1990
|
+
const DocumentActionConfirmDialog = ({
|
1991
|
+
onClose,
|
1992
|
+
onCancel,
|
1993
|
+
onConfirm,
|
1994
|
+
title,
|
1995
|
+
content,
|
1996
|
+
isOpen,
|
1997
|
+
variant = "secondary"
|
1998
|
+
}) => {
|
1999
|
+
const { formatMessage } = useIntl();
|
2000
|
+
const handleClose = async () => {
|
2001
|
+
if (onCancel) {
|
2002
|
+
await onCancel();
|
2003
|
+
}
|
2004
|
+
onClose();
|
2005
|
+
};
|
2006
|
+
const handleConfirm = async () => {
|
2007
|
+
if (onConfirm) {
|
2008
|
+
await onConfirm();
|
2009
|
+
}
|
2010
|
+
onClose();
|
2039
2011
|
};
|
2012
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2013
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2014
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2015
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2016
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2017
|
+
id: "app.components.Button.cancel",
|
2018
|
+
defaultMessage: "Cancel"
|
2019
|
+
}) }) }),
|
2020
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2021
|
+
id: "app.components.Button.confirm",
|
2022
|
+
defaultMessage: "Confirm"
|
2023
|
+
}) })
|
2024
|
+
] })
|
2025
|
+
] }) });
|
2040
2026
|
};
|
2041
|
-
|
2042
|
-
|
2027
|
+
const DocumentActionModal = ({
|
2028
|
+
isOpen,
|
2029
|
+
title,
|
2030
|
+
onClose,
|
2031
|
+
footer: Footer,
|
2032
|
+
content: Content,
|
2033
|
+
onModalClose
|
2034
|
+
}) => {
|
2035
|
+
const handleClose = () => {
|
2036
|
+
if (onClose) {
|
2037
|
+
onClose();
|
2038
|
+
}
|
2039
|
+
onModalClose();
|
2040
|
+
};
|
2041
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2042
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2043
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2044
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2045
|
+
] }) });
|
2046
|
+
};
|
2047
|
+
const PublishAction$1 = ({
|
2043
2048
|
activeTab,
|
2044
2049
|
documentId,
|
2045
2050
|
model,
|
2046
2051
|
collectionType,
|
2052
|
+
meta,
|
2047
2053
|
document
|
2048
2054
|
}) => {
|
2049
|
-
const { formatMessage } = useIntl();
|
2050
2055
|
const { schema } = useDoc();
|
2051
|
-
const
|
2052
|
-
const {
|
2053
|
-
const
|
2054
|
-
const
|
2055
|
-
if (!schema?.options?.draftAndPublish) {
|
2056
|
-
return null;
|
2057
|
-
}
|
2058
|
-
return {
|
2059
|
-
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2060
|
-
label: formatMessage({
|
2061
|
-
id: "content-manager.actions.discard.label",
|
2062
|
-
defaultMessage: "Discard changes"
|
2063
|
-
}),
|
2064
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
2065
|
-
position: ["panel", "table-row"],
|
2066
|
-
variant: "danger",
|
2067
|
-
dialog: {
|
2068
|
-
type: "dialog",
|
2069
|
-
title: formatMessage({
|
2070
|
-
id: "app.components.ConfirmDialog.title",
|
2071
|
-
defaultMessage: "Confirmation"
|
2072
|
-
}),
|
2073
|
-
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2074
|
-
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2075
|
-
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2076
|
-
id: "content-manager.actions.discard.dialog.body",
|
2077
|
-
defaultMessage: "Are you sure?"
|
2078
|
-
}) })
|
2079
|
-
] }),
|
2080
|
-
onConfirm: async () => {
|
2081
|
-
await discard({
|
2082
|
-
collectionType,
|
2083
|
-
model,
|
2084
|
-
documentId,
|
2085
|
-
params
|
2086
|
-
});
|
2087
|
-
}
|
2088
|
-
}
|
2089
|
-
};
|
2090
|
-
};
|
2091
|
-
DiscardAction.type = "discard";
|
2092
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2093
|
-
path {
|
2094
|
-
fill: currentColor;
|
2095
|
-
}
|
2096
|
-
`;
|
2097
|
-
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2098
|
-
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2099
|
-
const RelativeTime = React.forwardRef(
|
2100
|
-
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2101
|
-
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2102
|
-
const interval = intervalToDuration({
|
2103
|
-
start: timestamp,
|
2104
|
-
end: Date.now()
|
2105
|
-
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2106
|
-
});
|
2107
|
-
const unit = intervals.find((intervalUnit) => {
|
2108
|
-
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2109
|
-
});
|
2110
|
-
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2111
|
-
const customInterval = customIntervals.find(
|
2112
|
-
(custom) => interval[custom.unit] < custom.threshold
|
2113
|
-
);
|
2114
|
-
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2115
|
-
return /* @__PURE__ */ jsx(
|
2116
|
-
"time",
|
2117
|
-
{
|
2118
|
-
ref: forwardedRef,
|
2119
|
-
dateTime: timestamp.toISOString(),
|
2120
|
-
role: "time",
|
2121
|
-
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2122
|
-
...restProps,
|
2123
|
-
children: displayText
|
2124
|
-
}
|
2125
|
-
);
|
2126
|
-
}
|
2127
|
-
);
|
2128
|
-
const getDisplayName = ({
|
2129
|
-
firstname,
|
2130
|
-
lastname,
|
2131
|
-
username,
|
2132
|
-
email
|
2133
|
-
} = {}) => {
|
2134
|
-
if (username) {
|
2135
|
-
return username;
|
2136
|
-
}
|
2137
|
-
if (firstname) {
|
2138
|
-
return `${firstname} ${lastname ?? ""}`.trim();
|
2139
|
-
}
|
2140
|
-
return email ?? "";
|
2141
|
-
};
|
2142
|
-
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2143
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2144
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
2145
|
-
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2146
|
-
};
|
2147
|
-
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2148
|
-
const { formatMessage } = useIntl();
|
2056
|
+
const navigate = useNavigate();
|
2057
|
+
const { toggleNotification } = useNotification();
|
2058
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2059
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
2149
2060
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2150
|
-
const title = isCreating ? formatMessage({
|
2151
|
-
id: "content-manager.containers.edit.title.new",
|
2152
|
-
defaultMessage: "Create an entry"
|
2153
|
-
}) : documentTitle;
|
2154
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2155
|
-
/* @__PURE__ */ jsx(BackButton, {}),
|
2156
|
-
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2157
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2158
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2159
|
-
] }),
|
2160
|
-
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2161
|
-
] });
|
2162
|
-
};
|
2163
|
-
const HeaderToolbar = () => {
|
2164
2061
|
const { formatMessage } = useIntl();
|
2165
|
-
const
|
2062
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2063
|
+
const { publish } = useDocumentActions();
|
2166
2064
|
const [
|
2167
|
-
|
2168
|
-
|
2065
|
+
countDraftRelations,
|
2066
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2067
|
+
] = useLazyGetDraftRelationCountQuery();
|
2068
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2069
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
2070
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2071
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2072
|
+
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
2073
|
+
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2074
|
+
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2075
|
+
const validate = useForm("PublishAction", (state) => state.validate);
|
2076
|
+
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
2077
|
+
const formValues = useForm("PublishAction", ({ values }) => values);
|
2078
|
+
React.useEffect(() => {
|
2079
|
+
if (isErrorDraftRelations) {
|
2080
|
+
toggleNotification({
|
2081
|
+
type: "danger",
|
2082
|
+
message: formatMessage({
|
2083
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2084
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2085
|
+
})
|
2086
|
+
});
|
2169
2087
|
}
|
2170
|
-
|
2171
|
-
|
2172
|
-
|
2173
|
-
|
2174
|
-
|
2175
|
-
|
2176
|
-
|
2177
|
-
|
2178
|
-
activeTab: status,
|
2179
|
-
model,
|
2180
|
-
documentId: id,
|
2181
|
-
document: isCloning ? void 0 : document,
|
2182
|
-
meta: isCloning ? void 0 : meta,
|
2183
|
-
collectionType
|
2184
|
-
},
|
2185
|
-
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2186
|
-
children: (actions2) => {
|
2187
|
-
if (actions2.length > 0) {
|
2188
|
-
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2189
|
-
} else {
|
2190
|
-
return null;
|
2191
|
-
}
|
2088
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2089
|
+
React.useEffect(() => {
|
2090
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2091
|
+
const extractDraftRelations = (data) => {
|
2092
|
+
const relations = data.connect || [];
|
2093
|
+
relations.forEach((relation) => {
|
2094
|
+
if (relation.status === "draft") {
|
2095
|
+
localDraftRelations.add(relation.id);
|
2192
2096
|
}
|
2193
|
-
}
|
2194
|
-
|
2195
|
-
|
2196
|
-
|
2197
|
-
|
2198
|
-
|
2199
|
-
|
2200
|
-
|
2201
|
-
documentId: id,
|
2202
|
-
document: isCloning ? void 0 : document,
|
2203
|
-
meta: isCloning ? void 0 : meta,
|
2204
|
-
collectionType
|
2205
|
-
},
|
2206
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2207
|
-
children: (actions2) => {
|
2208
|
-
const headerActions = actions2.filter((action) => {
|
2209
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2210
|
-
return positions.includes("header");
|
2211
|
-
});
|
2212
|
-
return /* @__PURE__ */ jsx(
|
2213
|
-
DocumentActionsMenu,
|
2214
|
-
{
|
2215
|
-
actions: headerActions,
|
2216
|
-
label: formatMessage({
|
2217
|
-
id: "content-manager.containers.edit.header.more-actions",
|
2218
|
-
defaultMessage: "More actions"
|
2219
|
-
}),
|
2220
|
-
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2221
|
-
}
|
2222
|
-
);
|
2097
|
+
});
|
2098
|
+
};
|
2099
|
+
const traverseAndExtract = (data) => {
|
2100
|
+
Object.entries(data).forEach(([key, value]) => {
|
2101
|
+
if (key === "connect" && Array.isArray(value)) {
|
2102
|
+
extractDraftRelations({ connect: value });
|
2103
|
+
} else if (typeof value === "object" && value !== null) {
|
2104
|
+
traverseAndExtract(value);
|
2223
2105
|
}
|
2106
|
+
});
|
2107
|
+
};
|
2108
|
+
if (!documentId || modified) {
|
2109
|
+
traverseAndExtract(formValues);
|
2110
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2111
|
+
}
|
2112
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2113
|
+
React.useEffect(() => {
|
2114
|
+
if (!document || !document.documentId || isListView) {
|
2115
|
+
return;
|
2116
|
+
}
|
2117
|
+
const fetchDraftRelationsCount = async () => {
|
2118
|
+
const { data, error } = await countDraftRelations({
|
2119
|
+
collectionType,
|
2120
|
+
model,
|
2121
|
+
documentId,
|
2122
|
+
params
|
2123
|
+
});
|
2124
|
+
if (error) {
|
2125
|
+
throw error;
|
2224
2126
|
}
|
2225
|
-
|
2226
|
-
|
2227
|
-
}
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2127
|
+
if (data) {
|
2128
|
+
setServerCountOfDraftRelations(data.data);
|
2129
|
+
}
|
2130
|
+
};
|
2131
|
+
fetchDraftRelationsCount();
|
2132
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2133
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2134
|
+
if (!schema?.options?.draftAndPublish) {
|
2232
2135
|
return null;
|
2233
2136
|
}
|
2234
|
-
const
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2137
|
+
const performPublish = async () => {
|
2138
|
+
setSubmitting(true);
|
2139
|
+
try {
|
2140
|
+
const { errors } = await validate();
|
2141
|
+
if (errors) {
|
2142
|
+
toggleNotification({
|
2143
|
+
type: "danger",
|
2144
|
+
message: formatMessage({
|
2145
|
+
id: "content-manager.validation.error",
|
2146
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2147
|
+
})
|
2148
|
+
});
|
2149
|
+
return;
|
2150
|
+
}
|
2151
|
+
const res = await publish(
|
2246
2152
|
{
|
2247
|
-
|
2248
|
-
|
2153
|
+
collectionType,
|
2154
|
+
model,
|
2155
|
+
documentId,
|
2156
|
+
params
|
2249
2157
|
},
|
2250
|
-
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2158
|
+
formValues
|
2159
|
+
);
|
2160
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2161
|
+
navigate({
|
2162
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2163
|
+
search: rawQuery
|
2164
|
+
});
|
2165
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2166
|
+
setErrors(formatValidationErrors(res.error));
|
2167
|
+
}
|
2168
|
+
} finally {
|
2169
|
+
setSubmitting(false);
|
2170
|
+
}
|
2171
|
+
};
|
2172
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2173
|
+
const enableDraftRelationsCount = false;
|
2174
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2175
|
+
return {
|
2176
|
+
/**
|
2177
|
+
* Disabled when:
|
2178
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2179
|
+
* - the form is submitting
|
2180
|
+
* - the active tab is the published tab
|
2181
|
+
* - the document is already published & not modified
|
2182
|
+
* - the document is being created & not modified
|
2183
|
+
* - the user doesn't have the permission to publish
|
2184
|
+
*/
|
2185
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
2186
|
+
label: formatMessage({
|
2187
|
+
id: "app.utils.publish",
|
2188
|
+
defaultMessage: "Publish"
|
2189
|
+
}),
|
2190
|
+
onClick: async () => {
|
2191
|
+
await performPublish();
|
2256
2192
|
},
|
2257
|
-
{
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2193
|
+
dialog: hasDraftRelations ? {
|
2194
|
+
type: "dialog",
|
2195
|
+
variant: "danger",
|
2196
|
+
footer: null,
|
2197
|
+
title: formatMessage({
|
2198
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2199
|
+
defaultMessage: "Confirmation"
|
2262
2200
|
}),
|
2263
|
-
|
2201
|
+
content: formatMessage(
|
2264
2202
|
{
|
2265
|
-
id:
|
2266
|
-
defaultMessage:
|
2203
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2204
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2267
2205
|
},
|
2268
2206
|
{
|
2269
|
-
|
2270
|
-
RelativeTime,
|
2271
|
-
{
|
2272
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2273
|
-
}
|
2274
|
-
),
|
2275
|
-
isAnonymous: !updator,
|
2276
|
-
author: updator
|
2207
|
+
count: totalDraftRelations
|
2277
2208
|
}
|
2278
|
-
)
|
2279
|
-
|
2280
|
-
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2290
|
-
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2209
|
+
),
|
2210
|
+
onConfirm: async () => {
|
2211
|
+
await performPublish();
|
2212
|
+
}
|
2213
|
+
} : void 0
|
2214
|
+
};
|
2215
|
+
};
|
2216
|
+
PublishAction$1.type = "publish";
|
2217
|
+
const UpdateAction = ({
|
2218
|
+
activeTab,
|
2219
|
+
documentId,
|
2220
|
+
model,
|
2221
|
+
collectionType
|
2222
|
+
}) => {
|
2223
|
+
const navigate = useNavigate();
|
2224
|
+
const { toggleNotification } = useNotification();
|
2225
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2226
|
+
const cloneMatch = useMatch(CLONE_PATH);
|
2227
|
+
const isCloning = cloneMatch !== null;
|
2228
|
+
const { formatMessage } = useIntl();
|
2229
|
+
const { create, update, clone } = useDocumentActions();
|
2230
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2231
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2232
|
+
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2233
|
+
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
2234
|
+
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2235
|
+
const document = useForm("UpdateAction", ({ values }) => values);
|
2236
|
+
const validate = useForm("UpdateAction", (state) => state.validate);
|
2237
|
+
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
2238
|
+
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
2239
|
+
return {
|
2240
|
+
/**
|
2241
|
+
* Disabled when:
|
2242
|
+
* - the form is submitting
|
2243
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2244
|
+
* - the active tab is the published tab
|
2245
|
+
*/
|
2246
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2247
|
+
label: formatMessage({
|
2248
|
+
id: "content-manager.containers.Edit.save",
|
2249
|
+
defaultMessage: "Save"
|
2250
|
+
}),
|
2251
|
+
onClick: async () => {
|
2252
|
+
setSubmitting(true);
|
2253
|
+
try {
|
2254
|
+
if (activeTab !== "draft") {
|
2255
|
+
const { errors } = await validate();
|
2256
|
+
if (errors) {
|
2257
|
+
toggleNotification({
|
2258
|
+
type: "danger",
|
2259
|
+
message: formatMessage({
|
2260
|
+
id: "content-manager.validation.error",
|
2261
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2262
|
+
})
|
2263
|
+
});
|
2264
|
+
return;
|
2265
|
+
}
|
2266
|
+
}
|
2267
|
+
if (isCloning) {
|
2268
|
+
const res = await clone(
|
2294
2269
|
{
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2270
|
+
model,
|
2271
|
+
documentId: cloneMatch.params.origin,
|
2272
|
+
params
|
2273
|
+
},
|
2274
|
+
document
|
2275
|
+
);
|
2276
|
+
if ("data" in res) {
|
2277
|
+
navigate(
|
2278
|
+
{
|
2279
|
+
pathname: `../${res.data.documentId}`,
|
2280
|
+
search: rawQuery
|
2281
|
+
},
|
2282
|
+
{ relative: "path" }
|
2283
|
+
);
|
2284
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2285
|
+
setErrors(formatValidationErrors(res.error));
|
2286
|
+
}
|
2287
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2288
|
+
const res = await update(
|
2289
|
+
{
|
2290
|
+
collectionType,
|
2291
|
+
model,
|
2292
|
+
documentId,
|
2293
|
+
params
|
2294
|
+
},
|
2295
|
+
document
|
2296
|
+
);
|
2297
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2298
|
+
setErrors(formatValidationErrors(res.error));
|
2299
|
+
} else {
|
2300
|
+
resetForm();
|
2301
|
+
}
|
2302
|
+
} else {
|
2303
|
+
const res = await create(
|
2304
|
+
{
|
2305
|
+
model,
|
2306
|
+
params
|
2307
|
+
},
|
2308
|
+
document
|
2309
|
+
);
|
2310
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2311
|
+
navigate(
|
2312
|
+
{
|
2313
|
+
pathname: `../${res.data.documentId}`,
|
2314
|
+
search: rawQuery
|
2315
|
+
},
|
2316
|
+
{ replace: true, relative: "path" }
|
2317
|
+
);
|
2318
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2319
|
+
setErrors(formatValidationErrors(res.error));
|
2320
|
+
}
|
2300
2321
|
}
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
return /* @__PURE__ */ jsx(
|
2305
|
-
Flex,
|
2306
|
-
{
|
2307
|
-
borderWidth: "1px 0 0 0",
|
2308
|
-
borderStyle: "solid",
|
2309
|
-
borderColor: "neutral150",
|
2310
|
-
direction: "column",
|
2311
|
-
marginTop: 2,
|
2312
|
-
tag: "dl",
|
2313
|
-
padding: 5,
|
2314
|
-
gap: 3,
|
2315
|
-
alignItems: "flex-start",
|
2316
|
-
marginLeft: "-0.4rem",
|
2317
|
-
marginRight: "-0.4rem",
|
2318
|
-
width: "calc(100% + 8px)",
|
2319
|
-
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2320
|
-
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2321
|
-
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2322
|
-
] }, info.label))
|
2322
|
+
} finally {
|
2323
|
+
setSubmitting(false);
|
2324
|
+
}
|
2323
2325
|
}
|
2324
|
-
|
2326
|
+
};
|
2325
2327
|
};
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
SingleSelect,
|
2331
|
-
{
|
2332
|
-
size: "S",
|
2333
|
-
disabled: action.disabled,
|
2334
|
-
"aria-label": action.label,
|
2335
|
-
onChange: action.onSelect,
|
2336
|
-
value: action.value,
|
2337
|
-
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2338
|
-
},
|
2339
|
-
action.id
|
2340
|
-
);
|
2341
|
-
} else {
|
2342
|
-
return null;
|
2343
|
-
}
|
2344
|
-
}) });
|
2328
|
+
UpdateAction.type = "update";
|
2329
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2330
|
+
KEEP: "keep",
|
2331
|
+
DISCARD: "discard"
|
2345
2332
|
};
|
2346
|
-
const
|
2347
|
-
|
2333
|
+
const UnpublishAction$1 = ({
|
2334
|
+
activeTab,
|
2335
|
+
documentId,
|
2336
|
+
model,
|
2337
|
+
collectionType,
|
2338
|
+
document
|
2339
|
+
}) => {
|
2348
2340
|
const { formatMessage } = useIntl();
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2341
|
+
const { schema } = useDoc();
|
2342
|
+
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2343
|
+
const { unpublish } = useDocumentActions();
|
2344
|
+
const [{ query }] = useQueryParams();
|
2345
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2346
|
+
const { toggleNotification } = useNotification();
|
2347
|
+
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
2348
|
+
const isDocumentModified = document?.status === "modified";
|
2349
|
+
const handleChange = (value) => {
|
2350
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
2359
2351
|
};
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
const navigate = useNavigate();
|
2364
|
-
const { formatMessage } = useIntl();
|
2352
|
+
if (!schema?.options?.draftAndPublish) {
|
2353
|
+
return null;
|
2354
|
+
}
|
2365
2355
|
return {
|
2356
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2366
2357
|
label: formatMessage({
|
2367
|
-
id: "
|
2368
|
-
defaultMessage: "
|
2358
|
+
id: "app.utils.unpublish",
|
2359
|
+
defaultMessage: "Unpublish"
|
2369
2360
|
}),
|
2370
|
-
icon: /* @__PURE__ */ jsx(
|
2371
|
-
onClick: () => {
|
2372
|
-
|
2361
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2362
|
+
onClick: async () => {
|
2363
|
+
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2364
|
+
if (!documentId) {
|
2365
|
+
console.error(
|
2366
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2367
|
+
);
|
2368
|
+
toggleNotification({
|
2369
|
+
message: formatMessage({
|
2370
|
+
id: "content-manager.actions.unpublish.error",
|
2371
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2372
|
+
}),
|
2373
|
+
type: "danger"
|
2374
|
+
});
|
2375
|
+
}
|
2376
|
+
return;
|
2377
|
+
}
|
2378
|
+
await unpublish({
|
2379
|
+
collectionType,
|
2380
|
+
model,
|
2381
|
+
documentId,
|
2382
|
+
params
|
2383
|
+
});
|
2373
2384
|
},
|
2374
|
-
|
2385
|
+
dialog: isDocumentModified ? {
|
2386
|
+
type: "dialog",
|
2387
|
+
title: formatMessage({
|
2388
|
+
id: "app.components.ConfirmDialog.title",
|
2389
|
+
defaultMessage: "Confirmation"
|
2390
|
+
}),
|
2391
|
+
content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
2392
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
|
2393
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2394
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2395
|
+
id: "content-manager.actions.unpublish.dialog.body",
|
2396
|
+
defaultMessage: "Are you sure?"
|
2397
|
+
}) })
|
2398
|
+
] }),
|
2399
|
+
/* @__PURE__ */ jsxs(
|
2400
|
+
Radio.Group,
|
2401
|
+
{
|
2402
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2403
|
+
name: "discard-options",
|
2404
|
+
"aria-label": formatMessage({
|
2405
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2406
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2407
|
+
}),
|
2408
|
+
onValueChange: handleChange,
|
2409
|
+
children: [
|
2410
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2411
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2412
|
+
defaultMessage: "Keep draft"
|
2413
|
+
}) }),
|
2414
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2415
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2416
|
+
defaultMessage: "Replace draft"
|
2417
|
+
}) })
|
2418
|
+
]
|
2419
|
+
}
|
2420
|
+
)
|
2421
|
+
] }),
|
2422
|
+
onConfirm: async () => {
|
2423
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2424
|
+
console.error(
|
2425
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2426
|
+
);
|
2427
|
+
toggleNotification({
|
2428
|
+
message: formatMessage({
|
2429
|
+
id: "content-manager.actions.unpublish.error",
|
2430
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2431
|
+
}),
|
2432
|
+
type: "danger"
|
2433
|
+
});
|
2434
|
+
}
|
2435
|
+
await unpublish(
|
2436
|
+
{
|
2437
|
+
collectionType,
|
2438
|
+
model,
|
2439
|
+
documentId,
|
2440
|
+
params
|
2441
|
+
},
|
2442
|
+
!shouldKeepDraft
|
2443
|
+
);
|
2444
|
+
}
|
2445
|
+
} : void 0,
|
2446
|
+
variant: "danger",
|
2447
|
+
position: ["panel", "table-row"]
|
2375
2448
|
};
|
2376
2449
|
};
|
2377
|
-
|
2378
|
-
const
|
2379
|
-
|
2450
|
+
UnpublishAction$1.type = "unpublish";
|
2451
|
+
const DiscardAction = ({
|
2452
|
+
activeTab,
|
2453
|
+
documentId,
|
2454
|
+
model,
|
2455
|
+
collectionType,
|
2456
|
+
document
|
2457
|
+
}) => {
|
2380
2458
|
const { formatMessage } = useIntl();
|
2381
|
-
const
|
2382
|
-
const
|
2383
|
-
const {
|
2384
|
-
const {
|
2385
|
-
const
|
2459
|
+
const { schema } = useDoc();
|
2460
|
+
const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
|
2461
|
+
const { discard } = useDocumentActions();
|
2462
|
+
const [{ query }] = useQueryParams();
|
2463
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2464
|
+
if (!schema?.options?.draftAndPublish) {
|
2465
|
+
return null;
|
2466
|
+
}
|
2386
2467
|
return {
|
2387
|
-
disabled: !
|
2468
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2388
2469
|
label: formatMessage({
|
2389
|
-
id: "content-manager.actions.
|
2390
|
-
defaultMessage: "
|
2470
|
+
id: "content-manager.actions.discard.label",
|
2471
|
+
defaultMessage: "Discard changes"
|
2391
2472
|
}),
|
2392
|
-
icon: /* @__PURE__ */ jsx(
|
2473
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2474
|
+
position: ["panel", "table-row"],
|
2475
|
+
variant: "danger",
|
2393
2476
|
dialog: {
|
2394
2477
|
type: "dialog",
|
2395
2478
|
title: formatMessage({
|
@@ -2399,92 +2482,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2399
2482
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2400
2483
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2401
2484
|
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2402
|
-
id: "content-manager.actions.
|
2485
|
+
id: "content-manager.actions.discard.dialog.body",
|
2403
2486
|
defaultMessage: "Are you sure?"
|
2404
2487
|
}) })
|
2405
2488
|
] }),
|
2406
2489
|
onConfirm: async () => {
|
2407
|
-
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2411
|
-
|
2412
|
-
|
2413
|
-
|
2414
|
-
|
2415
|
-
|
2416
|
-
|
2417
|
-
|
2418
|
-
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
|
2439
|
-
|
2490
|
+
await discard({
|
2491
|
+
collectionType,
|
2492
|
+
model,
|
2493
|
+
documentId,
|
2494
|
+
params
|
2495
|
+
});
|
2496
|
+
}
|
2497
|
+
}
|
2498
|
+
};
|
2499
|
+
};
|
2500
|
+
DiscardAction.type = "discard";
|
2501
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2502
|
+
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2503
|
+
const RelativeTime = React.forwardRef(
|
2504
|
+
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2505
|
+
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2506
|
+
const interval = intervalToDuration({
|
2507
|
+
start: timestamp,
|
2508
|
+
end: Date.now()
|
2509
|
+
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2510
|
+
});
|
2511
|
+
const unit = intervals.find((intervalUnit) => {
|
2512
|
+
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2513
|
+
});
|
2514
|
+
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2515
|
+
const customInterval = customIntervals.find(
|
2516
|
+
(custom) => interval[custom.unit] < custom.threshold
|
2517
|
+
);
|
2518
|
+
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2519
|
+
return /* @__PURE__ */ jsx(
|
2520
|
+
"time",
|
2521
|
+
{
|
2522
|
+
ref: forwardedRef,
|
2523
|
+
dateTime: timestamp.toISOString(),
|
2524
|
+
role: "time",
|
2525
|
+
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2526
|
+
...restProps,
|
2527
|
+
children: displayText
|
2440
2528
|
}
|
2441
|
-
|
2442
|
-
|
2443
|
-
|
2444
|
-
|
2529
|
+
);
|
2530
|
+
}
|
2531
|
+
);
|
2532
|
+
const getDisplayName = ({
|
2533
|
+
firstname,
|
2534
|
+
lastname,
|
2535
|
+
username,
|
2536
|
+
email
|
2537
|
+
} = {}) => {
|
2538
|
+
if (username) {
|
2539
|
+
return username;
|
2540
|
+
}
|
2541
|
+
if (firstname) {
|
2542
|
+
return `${firstname} ${lastname ?? ""}`.trim();
|
2543
|
+
}
|
2544
|
+
return email ?? "";
|
2445
2545
|
};
|
2446
|
-
|
2447
|
-
const
|
2448
|
-
const
|
2449
|
-
|
2450
|
-
const [
|
2451
|
-
{
|
2452
|
-
query: { status }
|
2453
|
-
}
|
2454
|
-
] = useQueryParams({
|
2455
|
-
status: "draft"
|
2456
|
-
});
|
2457
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2458
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2459
|
-
const props = {
|
2460
|
-
activeTab: status,
|
2461
|
-
model,
|
2462
|
-
documentId: id,
|
2463
|
-
document: isCloning ? void 0 : document,
|
2464
|
-
meta: isCloning ? void 0 : meta,
|
2465
|
-
collectionType
|
2466
|
-
};
|
2467
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2468
|
-
DescriptionComponentRenderer,
|
2469
|
-
{
|
2470
|
-
props,
|
2471
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2472
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2473
|
-
}
|
2474
|
-
) });
|
2546
|
+
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2547
|
+
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2548
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2549
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2475
2550
|
};
|
2476
|
-
const
|
2551
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2477
2552
|
const { formatMessage } = useIntl();
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2553
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2554
|
+
const title = isCreating ? formatMessage({
|
2555
|
+
id: "content-manager.containers.edit.title.new",
|
2556
|
+
defaultMessage: "Create an entry"
|
2557
|
+
}) : documentTitle;
|
2558
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2559
|
+
/* @__PURE__ */ jsx(BackButton, {}),
|
2560
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2561
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2562
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2563
|
+
] }),
|
2564
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2565
|
+
] });
|
2485
2566
|
};
|
2486
|
-
|
2487
|
-
const
|
2567
|
+
const HeaderToolbar = () => {
|
2568
|
+
const { formatMessage } = useIntl();
|
2488
2569
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2489
2570
|
const [
|
2490
2571
|
{
|
@@ -2492,355 +2573,433 @@ const ActionsPanelContent = () => {
|
|
2492
2573
|
}
|
2493
2574
|
] = useQueryParams();
|
2494
2575
|
const { model, id, document, meta, collectionType } = useDoc();
|
2495
|
-
const plugins = useStrapiApp("
|
2496
|
-
|
2497
|
-
activeTab: status,
|
2498
|
-
model,
|
2499
|
-
documentId: id,
|
2500
|
-
document: isCloning ? void 0 : document,
|
2501
|
-
meta: isCloning ? void 0 : meta,
|
2502
|
-
collectionType
|
2503
|
-
};
|
2504
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2576
|
+
const plugins = useStrapiApp("HeaderToolbar", (state) => state.plugins);
|
2577
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
2505
2578
|
/* @__PURE__ */ jsx(
|
2506
2579
|
DescriptionComponentRenderer,
|
2507
2580
|
{
|
2508
|
-
props
|
2509
|
-
|
2510
|
-
|
2581
|
+
props: {
|
2582
|
+
activeTab: status,
|
2583
|
+
model,
|
2584
|
+
documentId: id,
|
2585
|
+
document: isCloning ? void 0 : document,
|
2586
|
+
meta: isCloning ? void 0 : meta,
|
2587
|
+
collectionType
|
2588
|
+
},
|
2589
|
+
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2590
|
+
children: (actions2) => {
|
2591
|
+
if (actions2.length > 0) {
|
2592
|
+
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2593
|
+
} else {
|
2594
|
+
return null;
|
2595
|
+
}
|
2596
|
+
}
|
2511
2597
|
}
|
2512
2598
|
),
|
2513
|
-
/* @__PURE__ */ jsx(
|
2599
|
+
/* @__PURE__ */ jsx(
|
2600
|
+
DescriptionComponentRenderer,
|
2601
|
+
{
|
2602
|
+
props: {
|
2603
|
+
activeTab: status,
|
2604
|
+
model,
|
2605
|
+
documentId: id,
|
2606
|
+
document: isCloning ? void 0 : document,
|
2607
|
+
meta: isCloning ? void 0 : meta,
|
2608
|
+
collectionType
|
2609
|
+
},
|
2610
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2611
|
+
children: (actions2) => {
|
2612
|
+
const headerActions = actions2.filter((action) => {
|
2613
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2614
|
+
return positions.includes("header");
|
2615
|
+
});
|
2616
|
+
return /* @__PURE__ */ jsx(
|
2617
|
+
DocumentActionsMenu,
|
2618
|
+
{
|
2619
|
+
actions: headerActions,
|
2620
|
+
label: formatMessage({
|
2621
|
+
id: "content-manager.containers.edit.header.more-actions",
|
2622
|
+
defaultMessage: "More actions"
|
2623
|
+
}),
|
2624
|
+
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2625
|
+
}
|
2626
|
+
);
|
2627
|
+
}
|
2628
|
+
}
|
2629
|
+
)
|
2514
2630
|
] });
|
2515
2631
|
};
|
2516
|
-
const
|
2517
|
-
|
2518
|
-
|
2632
|
+
const Information = ({ activeTab }) => {
|
2633
|
+
const { formatMessage } = useIntl();
|
2634
|
+
const { document, meta } = useDoc();
|
2635
|
+
if (!document || !document.id) {
|
2636
|
+
return null;
|
2637
|
+
}
|
2638
|
+
const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
|
2639
|
+
const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
|
2640
|
+
const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
|
2641
|
+
const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
|
2642
|
+
const information = [
|
2519
2643
|
{
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
borderColor: "neutral150",
|
2525
|
-
hasRadius: true,
|
2526
|
-
paddingBottom: 4,
|
2527
|
-
paddingLeft: 4,
|
2528
|
-
paddingRight: 4,
|
2529
|
-
paddingTop: 4,
|
2530
|
-
shadow: "tableShadow",
|
2531
|
-
gap: 3,
|
2532
|
-
direction: "column",
|
2533
|
-
justifyContent: "stretch",
|
2534
|
-
alignItems: "flex-start",
|
2535
|
-
children: [
|
2536
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2537
|
-
children
|
2538
|
-
]
|
2539
|
-
}
|
2540
|
-
);
|
2541
|
-
});
|
2542
|
-
const HOOKS = {
|
2543
|
-
/**
|
2544
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2545
|
-
* @constant
|
2546
|
-
* @type {string}
|
2547
|
-
*/
|
2548
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2549
|
-
/**
|
2550
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2551
|
-
* @constant
|
2552
|
-
* @type {string}
|
2553
|
-
*/
|
2554
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2555
|
-
/**
|
2556
|
-
* Hook that allows to mutate the CM's edit view layout
|
2557
|
-
* @constant
|
2558
|
-
* @type {string}
|
2559
|
-
*/
|
2560
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2561
|
-
/**
|
2562
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2563
|
-
* @constant
|
2564
|
-
* @type {string}
|
2565
|
-
*/
|
2566
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2567
|
-
};
|
2568
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2569
|
-
endpoints: (builder) => ({
|
2570
|
-
getContentTypeConfiguration: builder.query({
|
2571
|
-
query: (uid) => ({
|
2572
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2573
|
-
method: "GET"
|
2644
|
+
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2645
|
+
label: formatMessage({
|
2646
|
+
id: "content-manager.containers.edit.information.last-published.label",
|
2647
|
+
defaultMessage: "Last published"
|
2574
2648
|
}),
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
2583
|
-
|
2584
|
-
|
2585
|
-
|
2586
|
-
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2649
|
+
value: formatMessage(
|
2650
|
+
{
|
2651
|
+
id: "content-manager.containers.edit.information.last-published.value",
|
2652
|
+
defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
|
2653
|
+
},
|
2654
|
+
{
|
2655
|
+
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
2656
|
+
isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
|
2657
|
+
author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
|
2658
|
+
}
|
2659
|
+
)
|
2660
|
+
},
|
2661
|
+
{
|
2662
|
+
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2663
|
+
label: formatMessage({
|
2664
|
+
id: "content-manager.containers.edit.information.last-draft.label",
|
2665
|
+
defaultMessage: "Last draft"
|
2666
|
+
}),
|
2667
|
+
value: formatMessage(
|
2668
|
+
{
|
2669
|
+
id: "content-manager.containers.edit.information.last-draft.value",
|
2670
|
+
defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
|
2671
|
+
},
|
2672
|
+
{
|
2673
|
+
time: /* @__PURE__ */ jsx(
|
2674
|
+
RelativeTime,
|
2675
|
+
{
|
2676
|
+
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2677
|
+
}
|
2678
|
+
),
|
2679
|
+
isAnonymous: !updator,
|
2680
|
+
author: updator
|
2681
|
+
}
|
2682
|
+
)
|
2683
|
+
},
|
2684
|
+
{
|
2685
|
+
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2686
|
+
label: formatMessage({
|
2687
|
+
id: "content-manager.containers.edit.information.document.label",
|
2688
|
+
defaultMessage: "Document"
|
2591
2689
|
}),
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
{
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2606
|
-
}
|
2607
|
-
|
2608
|
-
|
2609
|
-
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2616
|
-
|
2617
|
-
|
2618
|
-
|
2619
|
-
|
2620
|
-
|
2690
|
+
value: formatMessage(
|
2691
|
+
{
|
2692
|
+
id: "content-manager.containers.edit.information.document.value",
|
2693
|
+
defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
|
2694
|
+
},
|
2695
|
+
{
|
2696
|
+
time: /* @__PURE__ */ jsx(
|
2697
|
+
RelativeTime,
|
2698
|
+
{
|
2699
|
+
timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
|
2700
|
+
}
|
2701
|
+
),
|
2702
|
+
isAnonymous: !creator,
|
2703
|
+
author: creator
|
2704
|
+
}
|
2705
|
+
)
|
2706
|
+
}
|
2707
|
+
].filter((info) => info.isDisplayed);
|
2708
|
+
return /* @__PURE__ */ jsx(
|
2709
|
+
Flex,
|
2710
|
+
{
|
2711
|
+
borderWidth: "1px 0 0 0",
|
2712
|
+
borderStyle: "solid",
|
2713
|
+
borderColor: "neutral150",
|
2714
|
+
direction: "column",
|
2715
|
+
marginTop: 2,
|
2716
|
+
tag: "dl",
|
2717
|
+
padding: 5,
|
2718
|
+
gap: 3,
|
2719
|
+
alignItems: "flex-start",
|
2720
|
+
marginLeft: "-0.4rem",
|
2721
|
+
marginRight: "-0.4rem",
|
2722
|
+
width: "calc(100% + 8px)",
|
2723
|
+
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2724
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2725
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2726
|
+
] }, info.label))
|
2727
|
+
}
|
2621
2728
|
);
|
2622
|
-
return {
|
2623
|
-
name: mainFieldName,
|
2624
|
-
type: mainFieldType ?? "string"
|
2625
|
-
};
|
2626
|
-
};
|
2627
|
-
const DEFAULT_SETTINGS = {
|
2628
|
-
bulkable: false,
|
2629
|
-
filterable: false,
|
2630
|
-
searchable: false,
|
2631
|
-
pagination: false,
|
2632
|
-
defaultSortBy: "",
|
2633
|
-
defaultSortOrder: "asc",
|
2634
|
-
mainField: "id",
|
2635
|
-
pageSize: 10
|
2636
2729
|
};
|
2637
|
-
const
|
2638
|
-
const
|
2639
|
-
const
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
2643
|
-
|
2644
|
-
|
2645
|
-
|
2646
|
-
|
2647
|
-
error,
|
2648
|
-
isFetching: isFetchingConfigs
|
2649
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2650
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2651
|
-
React.useEffect(() => {
|
2652
|
-
if (error) {
|
2653
|
-
toggleNotification({
|
2654
|
-
type: "danger",
|
2655
|
-
message: formatAPIError(error)
|
2656
|
-
});
|
2730
|
+
const HeaderActions = ({ actions: actions2 }) => {
|
2731
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2732
|
+
const handleClick = (action) => async (e) => {
|
2733
|
+
if (!("options" in action)) {
|
2734
|
+
const { onClick = () => false, dialog, id } = action;
|
2735
|
+
const muteDialog = await onClick(e);
|
2736
|
+
if (dialog && !muteDialog) {
|
2737
|
+
e.preventDefault();
|
2738
|
+
setDialogId(id);
|
2739
|
+
}
|
2657
2740
|
}
|
2658
|
-
}, [error, formatAPIError, toggleNotification]);
|
2659
|
-
const editLayout = React.useMemo(
|
2660
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2661
|
-
layout: [],
|
2662
|
-
components: {},
|
2663
|
-
metadatas: {},
|
2664
|
-
options: {},
|
2665
|
-
settings: DEFAULT_SETTINGS
|
2666
|
-
},
|
2667
|
-
[data, isLoading, schemas, schema, components]
|
2668
|
-
);
|
2669
|
-
const listLayout = React.useMemo(() => {
|
2670
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2671
|
-
layout: [],
|
2672
|
-
metadatas: {},
|
2673
|
-
options: {},
|
2674
|
-
settings: DEFAULT_SETTINGS
|
2675
|
-
};
|
2676
|
-
}, [data, isLoading, schemas, schema, components]);
|
2677
|
-
const { layout: edit } = React.useMemo(
|
2678
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2679
|
-
layout: editLayout,
|
2680
|
-
query
|
2681
|
-
}),
|
2682
|
-
[editLayout, query, runHookWaterfall]
|
2683
|
-
);
|
2684
|
-
return {
|
2685
|
-
error,
|
2686
|
-
isLoading,
|
2687
|
-
edit,
|
2688
|
-
list: listLayout
|
2689
2741
|
};
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
return
|
2694
|
-
|
2695
|
-
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2706
|
-
|
2707
|
-
).reduce((panels, row) => {
|
2708
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2709
|
-
panels.push([row]);
|
2710
|
-
currentPanelIndex += 2;
|
2742
|
+
const handleClose = () => {
|
2743
|
+
setDialogId(null);
|
2744
|
+
};
|
2745
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2746
|
+
if (action.options) {
|
2747
|
+
return /* @__PURE__ */ jsx(
|
2748
|
+
SingleSelect,
|
2749
|
+
{
|
2750
|
+
size: "S",
|
2751
|
+
disabled: action.disabled,
|
2752
|
+
"aria-label": action.label,
|
2753
|
+
onChange: action.onSelect,
|
2754
|
+
value: action.value,
|
2755
|
+
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2756
|
+
},
|
2757
|
+
action.id
|
2758
|
+
);
|
2711
2759
|
} else {
|
2712
|
-
if (
|
2713
|
-
|
2760
|
+
if (action.type === "icon") {
|
2761
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2762
|
+
/* @__PURE__ */ jsx(
|
2763
|
+
IconButton,
|
2764
|
+
{
|
2765
|
+
disabled: action.disabled,
|
2766
|
+
label: action.label,
|
2767
|
+
size: "S",
|
2768
|
+
onClick: handleClick(action),
|
2769
|
+
children: action.icon
|
2770
|
+
}
|
2771
|
+
),
|
2772
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2773
|
+
HeaderActionDialog,
|
2774
|
+
{
|
2775
|
+
...action.dialog,
|
2776
|
+
isOpen: dialogId === action.id,
|
2777
|
+
onClose: handleClose
|
2778
|
+
}
|
2779
|
+
) : null
|
2780
|
+
] }, action.id);
|
2714
2781
|
}
|
2715
|
-
panels[currentPanelIndex].push(row);
|
2716
2782
|
}
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
}
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2783
|
+
}) });
|
2784
|
+
};
|
2785
|
+
const HeaderActionDialog = ({
|
2786
|
+
onClose,
|
2787
|
+
onCancel,
|
2788
|
+
title,
|
2789
|
+
content: Content,
|
2790
|
+
isOpen
|
2791
|
+
}) => {
|
2792
|
+
const handleClose = async () => {
|
2793
|
+
if (onCancel) {
|
2794
|
+
await onCancel();
|
2795
|
+
}
|
2796
|
+
onClose();
|
2797
|
+
};
|
2798
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2799
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2800
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2801
|
+
] }) });
|
2802
|
+
};
|
2803
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2804
|
+
const navigate = useNavigate();
|
2805
|
+
const { formatMessage } = useIntl();
|
2806
|
+
return {
|
2807
|
+
label: formatMessage({
|
2808
|
+
id: "app.links.configure-view",
|
2809
|
+
defaultMessage: "Configure the view"
|
2810
|
+
}),
|
2811
|
+
icon: /* @__PURE__ */ jsx(ListPlus, {}),
|
2812
|
+
onClick: () => {
|
2813
|
+
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2743
2814
|
},
|
2744
|
-
|
2745
|
-
|
2815
|
+
position: "header"
|
2816
|
+
};
|
2817
|
+
};
|
2818
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2819
|
+
const EditTheModelAction = ({ model }) => {
|
2820
|
+
const navigate = useNavigate();
|
2821
|
+
const { formatMessage } = useIntl();
|
2746
2822
|
return {
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2823
|
+
label: formatMessage({
|
2824
|
+
id: "content-manager.link-to-ctb",
|
2825
|
+
defaultMessage: "Edit the model"
|
2826
|
+
}),
|
2827
|
+
icon: /* @__PURE__ */ jsx(Pencil, {}),
|
2828
|
+
onClick: () => {
|
2829
|
+
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2753
2830
|
},
|
2754
|
-
|
2755
|
-
...schema?.options,
|
2756
|
-
...schema?.pluginOptions,
|
2757
|
-
...data.contentType.options
|
2758
|
-
}
|
2831
|
+
position: "header"
|
2759
2832
|
};
|
2760
2833
|
};
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2834
|
+
EditTheModelAction.type = "edit-the-model";
|
2835
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2836
|
+
const navigate = useNavigate();
|
2837
|
+
const { formatMessage } = useIntl();
|
2838
|
+
const listViewPathMatch = useMatch(LIST_PATH);
|
2839
|
+
const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
|
2840
|
+
const { delete: deleteAction } = useDocumentActions();
|
2841
|
+
const { toggleNotification } = useNotification();
|
2842
|
+
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2843
|
+
const isLocalized = document?.locale != null;
|
2844
|
+
return {
|
2845
|
+
disabled: !canDelete || !document,
|
2846
|
+
label: formatMessage(
|
2847
|
+
{
|
2848
|
+
id: "content-manager.actions.delete.label",
|
2849
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2850
|
+
},
|
2851
|
+
{ isLocalized }
|
2852
|
+
),
|
2853
|
+
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2854
|
+
dialog: {
|
2855
|
+
type: "dialog",
|
2856
|
+
title: formatMessage({
|
2857
|
+
id: "app.components.ConfirmDialog.title",
|
2858
|
+
defaultMessage: "Confirmation"
|
2859
|
+
}),
|
2860
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2861
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2862
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2863
|
+
id: "content-manager.actions.delete.dialog.body",
|
2864
|
+
defaultMessage: "Are you sure?"
|
2865
|
+
}) })
|
2866
|
+
] }),
|
2867
|
+
onConfirm: async () => {
|
2868
|
+
if (!listViewPathMatch) {
|
2869
|
+
setSubmitting(true);
|
2870
|
+
}
|
2871
|
+
try {
|
2872
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2873
|
+
console.error(
|
2874
|
+
"You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2875
|
+
);
|
2876
|
+
toggleNotification({
|
2877
|
+
message: formatMessage({
|
2878
|
+
id: "content-manager.actions.delete.error",
|
2879
|
+
defaultMessage: "An error occurred while trying to delete the document."
|
2880
|
+
}),
|
2881
|
+
type: "danger"
|
2882
|
+
});
|
2883
|
+
return;
|
2884
|
+
}
|
2885
|
+
const res = await deleteAction({
|
2886
|
+
documentId,
|
2887
|
+
model,
|
2888
|
+
collectionType,
|
2889
|
+
params: {
|
2890
|
+
locale: "*"
|
2891
|
+
}
|
2892
|
+
});
|
2893
|
+
if (!("error" in res)) {
|
2894
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2895
|
+
}
|
2896
|
+
} finally {
|
2897
|
+
if (!listViewPathMatch) {
|
2898
|
+
setSubmitting(false);
|
2899
|
+
}
|
2900
|
+
}
|
2767
2901
|
}
|
2768
|
-
const { edit: metadata } = metadatas[field.name];
|
2769
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2770
|
-
return {
|
2771
|
-
attribute,
|
2772
|
-
disabled: !metadata.editable,
|
2773
|
-
hint: metadata.description,
|
2774
|
-
label: metadata.label ?? "",
|
2775
|
-
name: field.name,
|
2776
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2777
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2778
|
-
schemas,
|
2779
|
-
components: components?.schemas ?? {}
|
2780
|
-
}),
|
2781
|
-
placeholder: metadata.placeholder ?? "",
|
2782
|
-
required: attribute.required ?? false,
|
2783
|
-
size: field.size,
|
2784
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2785
|
-
visible: metadata.visible ?? true,
|
2786
|
-
type: attribute.type
|
2787
|
-
};
|
2788
|
-
}).filter((field) => field !== null)
|
2789
|
-
);
|
2790
|
-
};
|
2791
|
-
const formatListLayout = (data, {
|
2792
|
-
schemas,
|
2793
|
-
schema,
|
2794
|
-
components
|
2795
|
-
}) => {
|
2796
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2797
|
-
(acc, [attribute, metadata]) => {
|
2798
|
-
return {
|
2799
|
-
...acc,
|
2800
|
-
[attribute]: metadata.list
|
2801
|
-
};
|
2802
2902
|
},
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2903
|
+
variant: "danger",
|
2904
|
+
position: ["header", "table-row"]
|
2905
|
+
};
|
2906
|
+
};
|
2907
|
+
DeleteAction$1.type = "delete";
|
2908
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2909
|
+
const Panels = () => {
|
2910
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2911
|
+
const [
|
2912
|
+
{
|
2913
|
+
query: { status }
|
2914
|
+
}
|
2915
|
+
] = useQueryParams({
|
2916
|
+
status: "draft"
|
2917
|
+
});
|
2918
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2919
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2920
|
+
const props = {
|
2921
|
+
activeTab: status,
|
2922
|
+
model,
|
2923
|
+
documentId: id,
|
2924
|
+
document: isCloning ? void 0 : document,
|
2925
|
+
meta: isCloning ? void 0 : meta,
|
2926
|
+
collectionType
|
2927
|
+
};
|
2928
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2929
|
+
DescriptionComponentRenderer,
|
2930
|
+
{
|
2931
|
+
props,
|
2932
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2933
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2820
2934
|
}
|
2935
|
+
) });
|
2936
|
+
};
|
2937
|
+
const ActionsPanel = () => {
|
2938
|
+
const { formatMessage } = useIntl();
|
2939
|
+
return {
|
2940
|
+
title: formatMessage({
|
2941
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2942
|
+
defaultMessage: "Entry"
|
2943
|
+
}),
|
2944
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2821
2945
|
};
|
2822
2946
|
};
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2947
|
+
ActionsPanel.type = "actions";
|
2948
|
+
const ActionsPanelContent = () => {
|
2949
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2950
|
+
const [
|
2951
|
+
{
|
2952
|
+
query: { status = "draft" }
|
2828
2953
|
}
|
2829
|
-
|
2830
|
-
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
2839
|
-
|
2840
|
-
|
2841
|
-
|
2842
|
-
|
2954
|
+
] = useQueryParams();
|
2955
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2956
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2957
|
+
const props = {
|
2958
|
+
activeTab: status,
|
2959
|
+
model,
|
2960
|
+
documentId: id,
|
2961
|
+
document: isCloning ? void 0 : document,
|
2962
|
+
meta: isCloning ? void 0 : meta,
|
2963
|
+
collectionType
|
2964
|
+
};
|
2965
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2966
|
+
/* @__PURE__ */ jsx(
|
2967
|
+
DescriptionComponentRenderer,
|
2968
|
+
{
|
2969
|
+
props,
|
2970
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2971
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2972
|
+
}
|
2973
|
+
),
|
2974
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2975
|
+
] });
|
2843
2976
|
};
|
2977
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2978
|
+
return /* @__PURE__ */ jsxs(
|
2979
|
+
Flex,
|
2980
|
+
{
|
2981
|
+
ref,
|
2982
|
+
tag: "aside",
|
2983
|
+
"aria-labelledby": "additional-information",
|
2984
|
+
background: "neutral0",
|
2985
|
+
borderColor: "neutral150",
|
2986
|
+
hasRadius: true,
|
2987
|
+
paddingBottom: 4,
|
2988
|
+
paddingLeft: 4,
|
2989
|
+
paddingRight: 4,
|
2990
|
+
paddingTop: 4,
|
2991
|
+
shadow: "tableShadow",
|
2992
|
+
gap: 3,
|
2993
|
+
direction: "column",
|
2994
|
+
justifyContent: "stretch",
|
2995
|
+
alignItems: "flex-start",
|
2996
|
+
children: [
|
2997
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2998
|
+
children
|
2999
|
+
]
|
3000
|
+
}
|
3001
|
+
);
|
3002
|
+
});
|
2844
3003
|
const ConfirmBulkActionDialog = ({
|
2845
3004
|
onToggleDialog,
|
2846
3005
|
isOpen = false,
|
@@ -2879,6 +3038,7 @@ const ConfirmDialogPublishAll = ({
|
|
2879
3038
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2880
3039
|
const { model, schema } = useDoc();
|
2881
3040
|
const [{ query }] = useQueryParams();
|
3041
|
+
const enableDraftRelationsCount = false;
|
2882
3042
|
const {
|
2883
3043
|
data: countDraftRelations = 0,
|
2884
3044
|
isLoading,
|
@@ -2890,7 +3050,7 @@ const ConfirmDialogPublishAll = ({
|
|
2890
3050
|
locale: query?.plugins?.i18n?.locale
|
2891
3051
|
},
|
2892
3052
|
{
|
2893
|
-
skip:
|
3053
|
+
skip: !enableDraftRelationsCount
|
2894
3054
|
}
|
2895
3055
|
);
|
2896
3056
|
React.useEffect(() => {
|
@@ -3075,7 +3235,7 @@ const SelectedEntriesTableContent = ({
|
|
3075
3235
|
status: row.status
|
3076
3236
|
}
|
3077
3237
|
) }),
|
3078
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3238
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3079
3239
|
IconButton,
|
3080
3240
|
{
|
3081
3241
|
tag: Link,
|
@@ -3098,9 +3258,10 @@ const SelectedEntriesTableContent = ({
|
|
3098
3258
|
),
|
3099
3259
|
target: "_blank",
|
3100
3260
|
marginLeft: "auto",
|
3101
|
-
|
3261
|
+
variant: "ghost",
|
3262
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3102
3263
|
}
|
3103
|
-
) })
|
3264
|
+
) }) })
|
3104
3265
|
] }, row.id)) })
|
3105
3266
|
] });
|
3106
3267
|
};
|
@@ -3137,7 +3298,13 @@ const SelectedEntriesModalContent = ({
|
|
3137
3298
|
);
|
3138
3299
|
const { rows, validationErrors } = React.useMemo(() => {
|
3139
3300
|
if (data.length > 0 && schema) {
|
3140
|
-
const validate = createYupSchema(
|
3301
|
+
const validate = createYupSchema(
|
3302
|
+
schema.attributes,
|
3303
|
+
components,
|
3304
|
+
// Since this is the "Publish" action, the validation
|
3305
|
+
// schema must enforce the rules for published entities
|
3306
|
+
{ status: "published" }
|
3307
|
+
);
|
3141
3308
|
const validationErrors2 = {};
|
3142
3309
|
const rows2 = data.map((entry) => {
|
3143
3310
|
try {
|
@@ -3487,7 +3654,7 @@ const TableActions = ({ document }) => {
|
|
3487
3654
|
DescriptionComponentRenderer,
|
3488
3655
|
{
|
3489
3656
|
props,
|
3490
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3657
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3491
3658
|
children: (actions2) => {
|
3492
3659
|
const tableRowActions = actions2.filter((action) => {
|
3493
3660
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3598,7 +3765,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3598
3765
|
}),
|
3599
3766
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3600
3767
|
footer: ({ onClose }) => {
|
3601
|
-
return /* @__PURE__ */ jsxs(
|
3768
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3602
3769
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3603
3770
|
id: "cancel",
|
3604
3771
|
defaultMessage: "Cancel"
|
@@ -3829,7 +3996,7 @@ const index = {
|
|
3829
3996
|
app.router.addRoute({
|
3830
3997
|
path: "content-manager/*",
|
3831
3998
|
lazy: async () => {
|
3832
|
-
const { Layout } = await import("./layout-
|
3999
|
+
const { Layout } = await import("./layout-B4UhJ8MJ.mjs");
|
3833
4000
|
return {
|
3834
4001
|
Component: Layout
|
3835
4002
|
};
|
@@ -3846,7 +4013,7 @@ const index = {
|
|
3846
4013
|
async registerTrads({ locales }) {
|
3847
4014
|
const importedTrads = await Promise.all(
|
3848
4015
|
locales.map((locale) => {
|
3849
|
-
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-
|
4016
|
+
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-C8YBvRrK.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 }) => {
|
3850
4017
|
return {
|
3851
4018
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3852
4019
|
locale
|
@@ -3867,13 +4034,15 @@ export {
|
|
3867
4034
|
BulkActionsRenderer as B,
|
3868
4035
|
COLLECTION_TYPES as C,
|
3869
4036
|
DocumentStatus as D,
|
3870
|
-
|
3871
|
-
|
3872
|
-
|
4037
|
+
extractContentTypeComponents as E,
|
4038
|
+
DEFAULT_SETTINGS as F,
|
4039
|
+
convertEditLayoutToFieldLayouts as G,
|
3873
4040
|
HOOKS as H,
|
3874
4041
|
InjectionZone as I,
|
3875
|
-
|
3876
|
-
|
4042
|
+
useDocument as J,
|
4043
|
+
index as K,
|
4044
|
+
useContentManagerContext as L,
|
4045
|
+
useDocumentActions as M,
|
3877
4046
|
Panels as P,
|
3878
4047
|
RelativeTime as R,
|
3879
4048
|
SINGLE_TYPES as S,
|
@@ -3891,18 +4060,18 @@ export {
|
|
3891
4060
|
PERMISSIONS as k,
|
3892
4061
|
DocumentRBAC as l,
|
3893
4062
|
DOCUMENT_META_FIELDS as m,
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
3897
|
-
|
3898
|
-
|
4063
|
+
CLONE_PATH as n,
|
4064
|
+
useDocLayout as o,
|
4065
|
+
useGetContentTypeConfigurationQuery as p,
|
4066
|
+
CREATOR_FIELDS as q,
|
4067
|
+
getMainField as r,
|
3899
4068
|
setInitialData as s,
|
3900
|
-
|
4069
|
+
getDisplayName as t,
|
3901
4070
|
useContentTypeSchema as u,
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
4071
|
+
checkIfAttributeIsDisplayable as v,
|
4072
|
+
useGetAllDocumentsQuery as w,
|
4073
|
+
convertListLayoutToFieldLayouts as x,
|
4074
|
+
capitalise as y,
|
4075
|
+
useUpdateContentTypeConfigurationMutation as z
|
3907
4076
|
};
|
3908
|
-
//# sourceMappingURL=index-
|
4077
|
+
//# sourceMappingURL=index-CPCHQ3X_.mjs.map
|