@strapi/content-manager 0.0.0-experimental.779667bd163026468f566293decf331a0246fff9 → 0.0.0-experimental.78b47df46708173ab4833373f694257729db4b9e
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-B1bIXVuX.mjs → ComponentConfigurationPage-7-qB29e7.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-B1bIXVuX.mjs.map → ComponentConfigurationPage-7-qB29e7.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-Bqgx7Mes.js → ComponentConfigurationPage-DP7AC0UU.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-Bqgx7Mes.js.map → ComponentConfigurationPage-DP7AC0UU.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs → EditConfigurationPage-CI4XoymK.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-ZO0vOO8q.mjs.map → EditConfigurationPage-CI4XoymK.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js → EditConfigurationPage-DITVliEI.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BFEwvdMW.js.map → EditConfigurationPage-DITVliEI.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-DA95Ha6J.js → EditViewPage-CUS2EAhB.js} +24 -9
- package/dist/_chunks/EditViewPage-CUS2EAhB.js.map +1 -0
- package/dist/_chunks/{EditViewPage-DlLEyUL6.mjs → EditViewPage-Dzpno8xI.mjs} +24 -9
- package/dist/_chunks/EditViewPage-Dzpno8xI.mjs.map +1 -0
- package/dist/_chunks/{Field-Dq7bDnuh.mjs → Field-B_jG_EV9.mjs} +139 -99
- package/dist/_chunks/Field-B_jG_EV9.mjs.map +1 -0
- package/dist/_chunks/{Field-CnK8dO8N.js → Field-CtUU1Fg8.js} +141 -101
- package/dist/_chunks/Field-CtUU1Fg8.js.map +1 -0
- package/dist/_chunks/{Form-B_JE0dbz.mjs → Form-BXHao2mZ.mjs} +35 -16
- package/dist/_chunks/Form-BXHao2mZ.mjs.map +1 -0
- package/dist/_chunks/{Form-BpiR4piS.js → Form-DTqO0ymI.js} +35 -16
- package/dist/_chunks/Form-DTqO0ymI.js.map +1 -0
- package/dist/_chunks/{History-CBNGU7a-.mjs → History-2Ah2CQ4T.mjs} +21 -11
- package/dist/_chunks/History-2Ah2CQ4T.mjs.map +1 -0
- package/dist/_chunks/{History-DdIstl8b.js → History-C_uSGzO5.js} +21 -11
- package/dist/_chunks/History-C_uSGzO5.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-5dr4qpue.mjs → ListConfigurationPage-BjSJlaoC.mjs} +14 -4
- package/dist/_chunks/ListConfigurationPage-BjSJlaoC.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DkKRparB.js → ListConfigurationPage-nyuP7OSy.js} +14 -4
- package/dist/_chunks/ListConfigurationPage-nyuP7OSy.js.map +1 -0
- package/dist/_chunks/{ListViewPage-DecLrYV6.mjs → ListViewPage-B75x3nz2.mjs} +47 -38
- package/dist/_chunks/ListViewPage-B75x3nz2.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-wE0lXqoD.js → ListViewPage-DHgHD8Xg.js} +49 -40
- package/dist/_chunks/ListViewPage-DHgHD8Xg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js → NoContentTypePage-CDUKdZ7d.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DEKR6tf9.js.map → NoContentTypePage-CDUKdZ7d.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs → NoContentTypePage-DUacQSyF.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CiIcfYsd.mjs.map → NoContentTypePage-DUacQSyF.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs → NoPermissionsPage-SFllMekk.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CM5UD8ee.mjs.map → NoPermissionsPage-SFllMekk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js → NoPermissionsPage-zwIZydDI.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DmNfF2Bb.js.map → NoPermissionsPage-zwIZydDI.js.map} +1 -1
- package/dist/_chunks/{Relations-Dqz0C1fz.mjs → Relations-D2NRW8fC.mjs} +14 -10
- package/dist/_chunks/Relations-D2NRW8fC.mjs.map +1 -0
- package/dist/_chunks/{Relations-L0xYRoSQ.js → Relations-NFLaRNPr.js} +14 -10
- package/dist/_chunks/Relations-NFLaRNPr.js.map +1 -0
- 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-C9HxCo5R.mjs} +1947 -1777
- package/dist/_chunks/index-C9HxCo5R.mjs.map +1 -0
- package/dist/_chunks/{index-DyvUPg1a.js → index-ovJRE1FM.js} +1927 -1757
- package/dist/_chunks/index-ovJRE1FM.js.map +1 -0
- package/dist/_chunks/{layout-DPaHUusj.mjs → layout-DaUjDiWQ.mjs} +22 -9
- package/dist/_chunks/layout-DaUjDiWQ.mjs.map +1 -0
- package/dist/_chunks/{layout-TPqF2oJ5.js → layout-UNWstw_s.js} +21 -8
- package/dist/_chunks/layout-UNWstw_s.js.map +1 -0
- package/dist/_chunks/{relations-Ck7-ecDT.mjs → relations-D8iFAeRu.mjs} +2 -2
- package/dist/_chunks/{relations-Ck7-ecDT.mjs.map → relations-D8iFAeRu.mjs.map} +1 -1
- package/dist/_chunks/{relations-BWYS9gkn.js → relations-NN3coOG5.js} +2 -2
- package/dist/_chunks/{relations-BWYS9gkn.js.map → relations-NN3coOG5.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 +32 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -17
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +184 -108
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +185 -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/Relations-Dqz0C1fz.mjs.map +0 -1
- package/dist/_chunks/Relations-L0xYRoSQ.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": {
|
@@ -493,7 +523,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
493
523
|
} else if (Array.isArray(value)) {
|
494
524
|
return yup.array().of(
|
495
525
|
yup.object().shape({
|
496
|
-
id: yup.
|
526
|
+
id: yup.number().required()
|
497
527
|
})
|
498
528
|
);
|
499
529
|
} else if (typeof value === "object") {
|
@@ -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,638 @@ 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
|
-
const
|
1064
|
-
|
1146
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1147
|
+
const hasError = !!error;
|
1148
|
+
return {
|
1149
|
+
components,
|
1150
|
+
document: data?.data,
|
1151
|
+
meta: data?.meta,
|
1152
|
+
isLoading,
|
1153
|
+
hasError,
|
1154
|
+
schema,
|
1155
|
+
schemas,
|
1156
|
+
validate
|
1157
|
+
};
|
1158
|
+
};
|
1159
|
+
const useDoc = () => {
|
1160
|
+
const { id, slug, collectionType, origin } = useParams();
|
1161
|
+
const [{ query }] = useQueryParams();
|
1162
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1163
|
+
if (!collectionType) {
|
1164
|
+
throw new Error("Could not find collectionType in url params");
|
1165
|
+
}
|
1166
|
+
if (!slug) {
|
1167
|
+
throw new Error("Could not find model in url params");
|
1168
|
+
}
|
1169
|
+
return {
|
1170
|
+
collectionType,
|
1171
|
+
model: slug,
|
1172
|
+
id: origin || id === "create" ? void 0 : id,
|
1173
|
+
...useDocument(
|
1174
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1175
|
+
{
|
1176
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1177
|
+
}
|
1178
|
+
)
|
1179
|
+
};
|
1180
|
+
};
|
1181
|
+
const useContentManagerContext = () => {
|
1182
|
+
const {
|
1183
|
+
collectionType,
|
1184
|
+
model,
|
1185
|
+
id,
|
1186
|
+
components,
|
1187
|
+
isLoading: isLoadingDoc,
|
1188
|
+
schema,
|
1189
|
+
schemas
|
1190
|
+
} = useDoc();
|
1191
|
+
const layout = useDocumentLayout(model);
|
1192
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1193
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1194
|
+
const slug = model;
|
1195
|
+
const isCreatingEntry = id === "create";
|
1196
|
+
useContentTypeSchema();
|
1197
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1198
|
+
const error = layout.error;
|
1199
|
+
return {
|
1200
|
+
error,
|
1201
|
+
isLoading,
|
1202
|
+
// Base metadata
|
1203
|
+
model,
|
1204
|
+
collectionType,
|
1205
|
+
id,
|
1206
|
+
slug,
|
1207
|
+
isCreatingEntry,
|
1208
|
+
isSingleType,
|
1209
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1210
|
+
// All schema infos
|
1211
|
+
components,
|
1212
|
+
contentType: schema,
|
1213
|
+
contentTypes: schemas,
|
1214
|
+
// Form state
|
1215
|
+
form,
|
1216
|
+
// layout infos
|
1217
|
+
layout
|
1218
|
+
};
|
1219
|
+
};
|
1220
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
1221
|
+
if (!pluginId) {
|
1222
|
+
throw new TypeError("pluginId can't be empty");
|
1223
|
+
}
|
1224
|
+
return Object.keys(trad).reduce((acc, current) => {
|
1225
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1226
|
+
return acc;
|
1227
|
+
}, {});
|
1228
|
+
};
|
1229
|
+
const getTranslation = (id) => `content-manager.${id}`;
|
1230
|
+
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
1231
|
+
id: "notification.error",
|
1232
|
+
defaultMessage: "An error occurred, please try again"
|
1233
|
+
};
|
1234
|
+
const useDocumentActions = () => {
|
1235
|
+
const { toggleNotification } = useNotification();
|
1236
|
+
const { formatMessage } = useIntl();
|
1237
|
+
const { trackUsage } = useTracking();
|
1238
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1239
|
+
const navigate = useNavigate();
|
1240
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
1241
|
+
const [deleteDocument] = useDeleteDocumentMutation();
|
1242
|
+
const _delete = React.useCallback(
|
1243
|
+
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
1065
1244
|
try {
|
1066
|
-
trackUsage("
|
1067
|
-
const res = await
|
1245
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1246
|
+
const res = await deleteDocument({
|
1068
1247
|
collectionType,
|
1069
1248
|
model,
|
1070
1249
|
documentId,
|
1071
|
-
params
|
1072
|
-
data: {
|
1073
|
-
discardDraft
|
1074
|
-
}
|
1250
|
+
params
|
1075
1251
|
});
|
1076
1252
|
if ("error" in res) {
|
1077
|
-
toggleNotification({
|
1253
|
+
toggleNotification({
|
1254
|
+
type: "danger",
|
1255
|
+
message: formatAPIError(res.error)
|
1256
|
+
});
|
1078
1257
|
return { error: res.error };
|
1079
1258
|
}
|
1080
|
-
trackUsage("didUnpublishEntry");
|
1081
1259
|
toggleNotification({
|
1082
1260
|
type: "success",
|
1083
1261
|
message: formatMessage({
|
1084
|
-
id: getTranslation("success.record.
|
1085
|
-
defaultMessage: "
|
1262
|
+
id: getTranslation("success.record.delete"),
|
1263
|
+
defaultMessage: "Deleted document"
|
1086
1264
|
})
|
1087
1265
|
});
|
1266
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1088
1267
|
return res.data;
|
1089
1268
|
} catch (err) {
|
1090
1269
|
toggleNotification({
|
1091
1270
|
type: "danger",
|
1092
1271
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1093
1272
|
});
|
1273
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1094
1274
|
throw err;
|
1095
1275
|
}
|
1096
1276
|
},
|
1097
|
-
[trackUsage,
|
1277
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1098
1278
|
);
|
1099
|
-
const [
|
1100
|
-
const
|
1279
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1280
|
+
const deleteMany = React.useCallback(
|
1101
1281
|
async ({ model, documentIds, params }) => {
|
1102
1282
|
try {
|
1103
|
-
trackUsage("
|
1104
|
-
const res = await
|
1283
|
+
trackUsage("willBulkDeleteEntries");
|
1284
|
+
const res = await deleteManyDocuments({
|
1105
1285
|
model,
|
1106
1286
|
documentIds,
|
1107
1287
|
params
|
1108
1288
|
});
|
1109
1289
|
if ("error" in res) {
|
1110
|
-
toggleNotification({
|
1290
|
+
toggleNotification({
|
1291
|
+
type: "danger",
|
1292
|
+
message: formatAPIError(res.error)
|
1293
|
+
});
|
1111
1294
|
return { error: res.error };
|
1112
1295
|
}
|
1113
|
-
trackUsage("didBulkUnpublishEntries");
|
1114
1296
|
toggleNotification({
|
1115
1297
|
type: "success",
|
1116
1298
|
title: formatMessage({
|
1117
|
-
id: getTranslation("success.records.
|
1118
|
-
defaultMessage: "Successfully
|
1299
|
+
id: getTranslation("success.records.delete"),
|
1300
|
+
defaultMessage: "Successfully deleted."
|
1119
1301
|
}),
|
1120
1302
|
message: ""
|
1121
1303
|
});
|
1304
|
+
trackUsage("didBulkDeleteEntries");
|
1122
1305
|
return res.data;
|
1123
1306
|
} catch (err) {
|
1124
1307
|
toggleNotification({
|
1125
1308
|
type: "danger",
|
1126
1309
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1127
1310
|
});
|
1128
|
-
trackUsage("
|
1311
|
+
trackUsage("didNotBulkDeleteEntries");
|
1129
1312
|
throw err;
|
1130
1313
|
}
|
1131
1314
|
},
|
1132
|
-
[trackUsage,
|
1315
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1133
1316
|
);
|
1134
|
-
const [
|
1135
|
-
const
|
1136
|
-
async ({ model, params }
|
1317
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1318
|
+
const discard = React.useCallback(
|
1319
|
+
async ({ collectionType, model, documentId, params }) => {
|
1137
1320
|
try {
|
1138
|
-
const res = await
|
1321
|
+
const res = await discardDocument({
|
1322
|
+
collectionType,
|
1139
1323
|
model,
|
1140
|
-
|
1324
|
+
documentId,
|
1325
|
+
params
|
1326
|
+
});
|
1327
|
+
if ("error" in res) {
|
1328
|
+
toggleNotification({
|
1329
|
+
type: "danger",
|
1330
|
+
message: formatAPIError(res.error)
|
1331
|
+
});
|
1332
|
+
return { error: res.error };
|
1333
|
+
}
|
1334
|
+
toggleNotification({
|
1335
|
+
type: "success",
|
1336
|
+
message: formatMessage({
|
1337
|
+
id: "content-manager.success.record.discard",
|
1338
|
+
defaultMessage: "Changes discarded"
|
1339
|
+
})
|
1340
|
+
});
|
1341
|
+
return res.data;
|
1342
|
+
} catch (err) {
|
1343
|
+
toggleNotification({
|
1344
|
+
type: "danger",
|
1345
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1346
|
+
});
|
1347
|
+
throw err;
|
1348
|
+
}
|
1349
|
+
},
|
1350
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1351
|
+
);
|
1352
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1353
|
+
const publish = React.useCallback(
|
1354
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1355
|
+
try {
|
1356
|
+
trackUsage("willPublishEntry");
|
1357
|
+
const res = await publishDocument({
|
1358
|
+
collectionType,
|
1359
|
+
model,
|
1360
|
+
documentId,
|
1361
|
+
data,
|
1362
|
+
params
|
1363
|
+
});
|
1364
|
+
if ("error" in res) {
|
1365
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1366
|
+
return { error: res.error };
|
1367
|
+
}
|
1368
|
+
trackUsage("didPublishEntry");
|
1369
|
+
toggleNotification({
|
1370
|
+
type: "success",
|
1371
|
+
message: formatMessage({
|
1372
|
+
id: getTranslation("success.record.publish"),
|
1373
|
+
defaultMessage: "Published document"
|
1374
|
+
})
|
1375
|
+
});
|
1376
|
+
return res.data;
|
1377
|
+
} catch (err) {
|
1378
|
+
toggleNotification({
|
1379
|
+
type: "danger",
|
1380
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1381
|
+
});
|
1382
|
+
throw err;
|
1383
|
+
}
|
1384
|
+
},
|
1385
|
+
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1386
|
+
);
|
1387
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1388
|
+
const publishMany = React.useCallback(
|
1389
|
+
async ({ model, documentIds, params }) => {
|
1390
|
+
try {
|
1391
|
+
const res = await publishManyDocuments({
|
1392
|
+
model,
|
1393
|
+
documentIds,
|
1394
|
+
params
|
1395
|
+
});
|
1396
|
+
if ("error" in res) {
|
1397
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1398
|
+
return { error: res.error };
|
1399
|
+
}
|
1400
|
+
toggleNotification({
|
1401
|
+
type: "success",
|
1402
|
+
message: formatMessage({
|
1403
|
+
id: getTranslation("success.record.publish"),
|
1404
|
+
defaultMessage: "Published document"
|
1405
|
+
})
|
1406
|
+
});
|
1407
|
+
return res.data;
|
1408
|
+
} catch (err) {
|
1409
|
+
toggleNotification({
|
1410
|
+
type: "danger",
|
1411
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1412
|
+
});
|
1413
|
+
throw err;
|
1414
|
+
}
|
1415
|
+
},
|
1416
|
+
[
|
1417
|
+
// trackUsage,
|
1418
|
+
publishManyDocuments,
|
1419
|
+
toggleNotification,
|
1420
|
+
formatMessage,
|
1421
|
+
formatAPIError
|
1422
|
+
]
|
1423
|
+
);
|
1424
|
+
const [updateDocument] = useUpdateDocumentMutation();
|
1425
|
+
const update = React.useCallback(
|
1426
|
+
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
1427
|
+
try {
|
1428
|
+
trackUsage("willEditEntry", trackerProperty);
|
1429
|
+
const res = await updateDocument({
|
1430
|
+
collectionType,
|
1431
|
+
model,
|
1432
|
+
documentId,
|
1433
|
+
data,
|
1434
|
+
params
|
1435
|
+
});
|
1436
|
+
if ("error" in res) {
|
1437
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1438
|
+
trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
|
1439
|
+
return { error: res.error };
|
1440
|
+
}
|
1441
|
+
trackUsage("didEditEntry", trackerProperty);
|
1442
|
+
toggleNotification({
|
1443
|
+
type: "success",
|
1444
|
+
message: formatMessage({
|
1445
|
+
id: getTranslation("success.record.save"),
|
1446
|
+
defaultMessage: "Saved document"
|
1447
|
+
})
|
1448
|
+
});
|
1449
|
+
return res.data;
|
1450
|
+
} catch (err) {
|
1451
|
+
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1452
|
+
toggleNotification({
|
1453
|
+
type: "danger",
|
1454
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1455
|
+
});
|
1456
|
+
throw err;
|
1457
|
+
}
|
1458
|
+
},
|
1459
|
+
[trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
|
1460
|
+
);
|
1461
|
+
const [unpublishDocument] = useUnpublishDocumentMutation();
|
1462
|
+
const unpublish = React.useCallback(
|
1463
|
+
async ({ collectionType, model, documentId, params }, discardDraft = false) => {
|
1464
|
+
try {
|
1465
|
+
trackUsage("willUnpublishEntry");
|
1466
|
+
const res = await unpublishDocument({
|
1467
|
+
collectionType,
|
1468
|
+
model,
|
1469
|
+
documentId,
|
1470
|
+
params,
|
1471
|
+
data: {
|
1472
|
+
discardDraft
|
1473
|
+
}
|
1474
|
+
});
|
1475
|
+
if ("error" in res) {
|
1476
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1477
|
+
return { error: res.error };
|
1478
|
+
}
|
1479
|
+
trackUsage("didUnpublishEntry");
|
1480
|
+
toggleNotification({
|
1481
|
+
type: "success",
|
1482
|
+
message: formatMessage({
|
1483
|
+
id: getTranslation("success.record.unpublish"),
|
1484
|
+
defaultMessage: "Unpublished document"
|
1485
|
+
})
|
1486
|
+
});
|
1487
|
+
return res.data;
|
1488
|
+
} catch (err) {
|
1489
|
+
toggleNotification({
|
1490
|
+
type: "danger",
|
1491
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1492
|
+
});
|
1493
|
+
throw err;
|
1494
|
+
}
|
1495
|
+
},
|
1496
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1497
|
+
);
|
1498
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1499
|
+
const unpublishMany = React.useCallback(
|
1500
|
+
async ({ model, documentIds, params }) => {
|
1501
|
+
try {
|
1502
|
+
trackUsage("willBulkUnpublishEntries");
|
1503
|
+
const res = await unpublishManyDocuments({
|
1504
|
+
model,
|
1505
|
+
documentIds,
|
1506
|
+
params
|
1507
|
+
});
|
1508
|
+
if ("error" in res) {
|
1509
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1510
|
+
return { error: res.error };
|
1511
|
+
}
|
1512
|
+
trackUsage("didBulkUnpublishEntries");
|
1513
|
+
toggleNotification({
|
1514
|
+
type: "success",
|
1515
|
+
title: formatMessage({
|
1516
|
+
id: getTranslation("success.records.unpublish"),
|
1517
|
+
defaultMessage: "Successfully unpublished."
|
1518
|
+
}),
|
1519
|
+
message: ""
|
1520
|
+
});
|
1521
|
+
return res.data;
|
1522
|
+
} catch (err) {
|
1523
|
+
toggleNotification({
|
1524
|
+
type: "danger",
|
1525
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1526
|
+
});
|
1527
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1528
|
+
throw err;
|
1529
|
+
}
|
1530
|
+
},
|
1531
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1532
|
+
);
|
1533
|
+
const [createDocument] = useCreateDocumentMutation();
|
1534
|
+
const create = React.useCallback(
|
1535
|
+
async ({ model, params }, data, trackerProperty) => {
|
1536
|
+
try {
|
1537
|
+
const res = await createDocument({
|
1538
|
+
model,
|
1539
|
+
data,
|
1141
1540
|
params
|
1142
1541
|
});
|
1143
1542
|
if ("error" in res) {
|
@@ -1153,6 +1552,7 @@ const useDocumentActions = () => {
|
|
1153
1552
|
defaultMessage: "Saved document"
|
1154
1553
|
})
|
1155
1554
|
});
|
1555
|
+
setCurrentStep("contentManager.success");
|
1156
1556
|
return res.data;
|
1157
1557
|
} catch (err) {
|
1158
1558
|
toggleNotification({
|
@@ -1174,7 +1574,6 @@ const useDocumentActions = () => {
|
|
1174
1574
|
sourceId
|
1175
1575
|
});
|
1176
1576
|
if ("error" in res) {
|
1177
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1178
1577
|
return { error: res.error };
|
1179
1578
|
}
|
1180
1579
|
toggleNotification({
|
@@ -1193,7 +1592,7 @@ const useDocumentActions = () => {
|
|
1193
1592
|
throw err;
|
1194
1593
|
}
|
1195
1594
|
},
|
1196
|
-
[autoCloneDocument,
|
1595
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1197
1596
|
);
|
1198
1597
|
const [cloneDocument] = useCloneDocumentMutation();
|
1199
1598
|
const clone = React.useCallback(
|
@@ -1219,6 +1618,7 @@ const useDocumentActions = () => {
|
|
1219
1618
|
defaultMessage: "Cloned document"
|
1220
1619
|
})
|
1221
1620
|
});
|
1621
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1222
1622
|
return res.data;
|
1223
1623
|
} catch (err) {
|
1224
1624
|
toggleNotification({
|
@@ -1229,7 +1629,7 @@ const useDocumentActions = () => {
|
|
1229
1629
|
throw err;
|
1230
1630
|
}
|
1231
1631
|
},
|
1232
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1632
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1233
1633
|
);
|
1234
1634
|
const [getDoc] = useLazyGetDocumentQuery();
|
1235
1635
|
const getDocument = React.useCallback(
|
@@ -1255,7 +1655,7 @@ const useDocumentActions = () => {
|
|
1255
1655
|
};
|
1256
1656
|
};
|
1257
1657
|
const ProtectedHistoryPage = lazy(
|
1258
|
-
() => import("./History-
|
1658
|
+
() => import("./History-2Ah2CQ4T.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1259
1659
|
);
|
1260
1660
|
const routes$1 = [
|
1261
1661
|
{
|
@@ -1268,31 +1668,31 @@ const routes$1 = [
|
|
1268
1668
|
}
|
1269
1669
|
];
|
1270
1670
|
const ProtectedEditViewPage = lazy(
|
1271
|
-
() => import("./EditViewPage-
|
1671
|
+
() => import("./EditViewPage-Dzpno8xI.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1272
1672
|
);
|
1273
1673
|
const ProtectedListViewPage = lazy(
|
1274
|
-
() => import("./ListViewPage-
|
1674
|
+
() => import("./ListViewPage-B75x3nz2.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1275
1675
|
);
|
1276
1676
|
const ProtectedListConfiguration = lazy(
|
1277
|
-
() => import("./ListConfigurationPage-
|
1677
|
+
() => import("./ListConfigurationPage-BjSJlaoC.mjs").then((mod) => ({
|
1278
1678
|
default: mod.ProtectedListConfiguration
|
1279
1679
|
}))
|
1280
1680
|
);
|
1281
1681
|
const ProtectedEditConfigurationPage = lazy(
|
1282
|
-
() => import("./EditConfigurationPage-
|
1682
|
+
() => import("./EditConfigurationPage-CI4XoymK.mjs").then((mod) => ({
|
1283
1683
|
default: mod.ProtectedEditConfigurationPage
|
1284
1684
|
}))
|
1285
1685
|
);
|
1286
1686
|
const ProtectedComponentConfigurationPage = lazy(
|
1287
|
-
() => import("./ComponentConfigurationPage-
|
1687
|
+
() => import("./ComponentConfigurationPage-7-qB29e7.mjs").then((mod) => ({
|
1288
1688
|
default: mod.ProtectedComponentConfigurationPage
|
1289
1689
|
}))
|
1290
1690
|
);
|
1291
1691
|
const NoPermissions = lazy(
|
1292
|
-
() => import("./NoPermissionsPage-
|
1692
|
+
() => import("./NoPermissionsPage-SFllMekk.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1293
1693
|
);
|
1294
1694
|
const NoContentType = lazy(
|
1295
|
-
() => import("./NoContentTypePage-
|
1695
|
+
() => import("./NoContentTypePage-DUacQSyF.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1296
1696
|
);
|
1297
1697
|
const CollectionTypePages = () => {
|
1298
1698
|
const { collectionType } = useParams();
|
@@ -1323,1073 +1723,758 @@ const routes = [
|
|
1323
1723
|
Component: ProtectedListConfiguration
|
1324
1724
|
},
|
1325
1725
|
{
|
1326
|
-
path: "components/:slug/configurations/edit",
|
1327
|
-
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
|
+
path: "components/:slug/configurations/edit",
|
1727
|
+
Component: ProtectedComponentConfigurationPage
|
1728
|
+
},
|
1729
|
+
{
|
1730
|
+
path: ":collectionType/:slug/configurations/edit",
|
1731
|
+
Component: ProtectedEditConfigurationPage
|
1732
|
+
},
|
1733
|
+
{
|
1734
|
+
path: "403",
|
1735
|
+
Component: NoPermissions
|
1736
|
+
},
|
1737
|
+
{
|
1738
|
+
path: "no-content-types",
|
1739
|
+
Component: NoContentType
|
1740
|
+
},
|
1741
|
+
...routes$1
|
1742
|
+
];
|
1743
|
+
const DocumentActions = ({ actions: actions2 }) => {
|
1744
|
+
const { formatMessage } = useIntl();
|
1745
|
+
const [primaryAction, secondaryAction, ...restActions] = actions2.filter((action) => {
|
1746
|
+
if (action.position === void 0) {
|
1747
|
+
return true;
|
1717
1748
|
}
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1749
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1750
|
+
return positions.includes("panel");
|
1751
|
+
});
|
1752
|
+
if (!primaryAction) {
|
1721
1753
|
return null;
|
1722
1754
|
}
|
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
|
-
},
|
1755
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1756
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1757
|
+
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1758
|
+
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1759
|
+
DocumentActionsMenu,
|
1796
1760
|
{
|
1797
|
-
|
1761
|
+
actions: restActions,
|
1762
|
+
label: formatMessage({
|
1763
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1764
|
+
defaultMessage: "More document actions"
|
1765
|
+
})
|
1798
1766
|
}
|
1799
|
-
)
|
1800
|
-
|
1801
|
-
|
1767
|
+
) : null
|
1768
|
+
] }),
|
1769
|
+
secondaryAction ? /* @__PURE__ */ jsx(
|
1770
|
+
DocumentActionButton,
|
1771
|
+
{
|
1772
|
+
...secondaryAction,
|
1773
|
+
variant: secondaryAction.variant || "secondary"
|
1802
1774
|
}
|
1803
|
-
|
1804
|
-
};
|
1775
|
+
) : null
|
1776
|
+
] });
|
1805
1777
|
};
|
1806
|
-
|
1807
|
-
const
|
1808
|
-
activeTab,
|
1809
|
-
documentId,
|
1810
|
-
model,
|
1811
|
-
collectionType
|
1812
|
-
}) => {
|
1813
|
-
const navigate = useNavigate();
|
1778
|
+
const DocumentActionButton = (action) => {
|
1779
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1814
1780
|
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) {
|
1781
|
+
const handleClick = (action2) => async (e) => {
|
1782
|
+
const { onClick = () => false, dialog, id } = action2;
|
1783
|
+
const muteDialog = await onClick(e);
|
1784
|
+
if (dialog && !muteDialog) {
|
1785
|
+
switch (dialog.type) {
|
1786
|
+
case "notification":
|
1852
1787
|
toggleNotification({
|
1853
|
-
|
1854
|
-
message:
|
1855
|
-
|
1856
|
-
|
1857
|
-
|
1788
|
+
title: dialog.title,
|
1789
|
+
message: dialog.content,
|
1790
|
+
type: dialog.status,
|
1791
|
+
timeout: dialog.timeout,
|
1792
|
+
onClose: dialog.onClose
|
1858
1793
|
});
|
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);
|
1794
|
+
break;
|
1795
|
+
case "dialog":
|
1796
|
+
case "modal":
|
1797
|
+
e.preventDefault();
|
1798
|
+
setDialogId(id);
|
1799
|
+
}
|
1800
|
+
}
|
1801
|
+
};
|
1802
|
+
const handleClose = () => {
|
1803
|
+
setDialogId(null);
|
1804
|
+
};
|
1805
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1806
|
+
/* @__PURE__ */ jsx(
|
1807
|
+
Button,
|
1808
|
+
{
|
1809
|
+
flex: "auto",
|
1810
|
+
startIcon: action.icon,
|
1811
|
+
disabled: action.disabled,
|
1812
|
+
onClick: handleClick(action),
|
1813
|
+
justifyContent: "center",
|
1814
|
+
variant: action.variant || "default",
|
1815
|
+
paddingTop: "7px",
|
1816
|
+
paddingBottom: "7px",
|
1817
|
+
children: action.label
|
1818
|
+
}
|
1819
|
+
),
|
1820
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1821
|
+
DocumentActionConfirmDialog,
|
1822
|
+
{
|
1823
|
+
...action.dialog,
|
1824
|
+
variant: action.dialog?.variant ?? action.variant,
|
1825
|
+
isOpen: dialogId === action.id,
|
1826
|
+
onClose: handleClose
|
1827
|
+
}
|
1828
|
+
) : null,
|
1829
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1830
|
+
DocumentActionModal,
|
1831
|
+
{
|
1832
|
+
...action.dialog,
|
1833
|
+
onModalClose: handleClose,
|
1834
|
+
isOpen: dialogId === action.id
|
1915
1835
|
}
|
1916
|
-
|
1917
|
-
};
|
1918
|
-
};
|
1919
|
-
UpdateAction.type = "update";
|
1920
|
-
const UNPUBLISH_DRAFT_OPTIONS = {
|
1921
|
-
KEEP: "keep",
|
1922
|
-
DISCARD: "discard"
|
1836
|
+
) : null
|
1837
|
+
] });
|
1923
1838
|
};
|
1924
|
-
const
|
1925
|
-
|
1926
|
-
|
1927
|
-
|
1928
|
-
|
1929
|
-
document
|
1839
|
+
const DocumentActionsMenu = ({
|
1840
|
+
actions: actions2,
|
1841
|
+
children,
|
1842
|
+
label,
|
1843
|
+
variant = "tertiary"
|
1930
1844
|
}) => {
|
1845
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
1846
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1931
1847
|
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
1848
|
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
|
-
);
|
1849
|
+
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1850
|
+
const handleClick = (action) => async (e) => {
|
1851
|
+
const { onClick = () => false, dialog, id } = action;
|
1852
|
+
const muteDialog = await onClick(e);
|
1853
|
+
if (dialog && !muteDialog) {
|
1854
|
+
switch (dialog.type) {
|
1855
|
+
case "notification":
|
1959
1856
|
toggleNotification({
|
1960
|
-
|
1961
|
-
|
1962
|
-
|
1963
|
-
|
1964
|
-
|
1857
|
+
title: dialog.title,
|
1858
|
+
message: dialog.content,
|
1859
|
+
type: dialog.status,
|
1860
|
+
timeout: dialog.timeout,
|
1861
|
+
onClose: dialog.onClose
|
1965
1862
|
});
|
1966
|
-
|
1967
|
-
|
1863
|
+
break;
|
1864
|
+
case "dialog":
|
1865
|
+
case "modal":
|
1866
|
+
setDialogId(id);
|
1968
1867
|
}
|
1969
|
-
|
1970
|
-
|
1971
|
-
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1977
|
-
|
1978
|
-
|
1979
|
-
|
1980
|
-
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1868
|
+
}
|
1869
|
+
};
|
1870
|
+
const handleClose = () => {
|
1871
|
+
setDialogId(null);
|
1872
|
+
setIsOpen(false);
|
1873
|
+
};
|
1874
|
+
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1875
|
+
/* @__PURE__ */ jsxs(
|
1876
|
+
Menu.Trigger,
|
1877
|
+
{
|
1878
|
+
disabled: isDisabled,
|
1879
|
+
size: "S",
|
1880
|
+
endIcon: null,
|
1881
|
+
paddingTop: "4px",
|
1882
|
+
paddingLeft: "7px",
|
1883
|
+
paddingRight: "7px",
|
1884
|
+
variant,
|
1885
|
+
children: [
|
1886
|
+
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1887
|
+
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1888
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1889
|
+
defaultMessage: "More document actions"
|
1988
1890
|
}) })
|
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(
|
1891
|
+
]
|
1892
|
+
}
|
1893
|
+
),
|
1894
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1895
|
+
actions2.map((action) => {
|
1896
|
+
return /* @__PURE__ */ jsx(
|
1897
|
+
Menu.Item,
|
2027
1898
|
{
|
2028
|
-
|
2029
|
-
|
2030
|
-
|
2031
|
-
|
1899
|
+
disabled: action.disabled,
|
1900
|
+
onSelect: handleClick(action),
|
1901
|
+
display: "block",
|
1902
|
+
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1903
|
+
/* @__PURE__ */ jsxs(
|
1904
|
+
Flex,
|
1905
|
+
{
|
1906
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1907
|
+
gap: 2,
|
1908
|
+
tag: "span",
|
1909
|
+
children: [
|
1910
|
+
/* @__PURE__ */ jsx(
|
1911
|
+
Flex,
|
1912
|
+
{
|
1913
|
+
tag: "span",
|
1914
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1915
|
+
children: action.icon
|
1916
|
+
}
|
1917
|
+
),
|
1918
|
+
action.label
|
1919
|
+
]
|
1920
|
+
}
|
1921
|
+
),
|
1922
|
+
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1923
|
+
Flex,
|
1924
|
+
{
|
1925
|
+
alignItems: "center",
|
1926
|
+
background: "alternative100",
|
1927
|
+
borderStyle: "solid",
|
1928
|
+
borderColor: "alternative200",
|
1929
|
+
borderWidth: "1px",
|
1930
|
+
height: 5,
|
1931
|
+
paddingLeft: 2,
|
1932
|
+
paddingRight: 2,
|
1933
|
+
hasRadius: true,
|
1934
|
+
color: "alternative600",
|
1935
|
+
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1936
|
+
}
|
1937
|
+
)
|
1938
|
+
] })
|
2032
1939
|
},
|
2033
|
-
|
1940
|
+
action.id
|
2034
1941
|
);
|
2035
|
-
}
|
2036
|
-
|
2037
|
-
|
2038
|
-
|
1942
|
+
}),
|
1943
|
+
children
|
1944
|
+
] }),
|
1945
|
+
actions2.map((action) => {
|
1946
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1947
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1948
|
+
DocumentActionConfirmDialog,
|
1949
|
+
{
|
1950
|
+
...action.dialog,
|
1951
|
+
variant: action.variant,
|
1952
|
+
isOpen: dialogId === action.id,
|
1953
|
+
onClose: handleClose
|
1954
|
+
}
|
1955
|
+
) : null,
|
1956
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1957
|
+
DocumentActionModal,
|
1958
|
+
{
|
1959
|
+
...action.dialog,
|
1960
|
+
onModalClose: handleClose,
|
1961
|
+
isOpen: dialogId === action.id
|
1962
|
+
}
|
1963
|
+
) : null
|
1964
|
+
] }, action.id);
|
1965
|
+
})
|
1966
|
+
] });
|
1967
|
+
};
|
1968
|
+
const convertActionVariantToColor = (variant = "secondary") => {
|
1969
|
+
switch (variant) {
|
1970
|
+
case "danger":
|
1971
|
+
return "danger600";
|
1972
|
+
case "secondary":
|
1973
|
+
return void 0;
|
1974
|
+
case "success":
|
1975
|
+
return "success600";
|
1976
|
+
default:
|
1977
|
+
return "primary600";
|
1978
|
+
}
|
1979
|
+
};
|
1980
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1981
|
+
switch (variant) {
|
1982
|
+
case "danger":
|
1983
|
+
return "danger600";
|
1984
|
+
case "secondary":
|
1985
|
+
return "neutral500";
|
1986
|
+
case "success":
|
1987
|
+
return "success600";
|
1988
|
+
default:
|
1989
|
+
return "primary600";
|
1990
|
+
}
|
1991
|
+
};
|
1992
|
+
const DocumentActionConfirmDialog = ({
|
1993
|
+
onClose,
|
1994
|
+
onCancel,
|
1995
|
+
onConfirm,
|
1996
|
+
title,
|
1997
|
+
content,
|
1998
|
+
isOpen,
|
1999
|
+
variant = "secondary"
|
2000
|
+
}) => {
|
2001
|
+
const { formatMessage } = useIntl();
|
2002
|
+
const handleClose = async () => {
|
2003
|
+
if (onCancel) {
|
2004
|
+
await onCancel();
|
2005
|
+
}
|
2006
|
+
onClose();
|
2039
2007
|
};
|
2008
|
+
const handleConfirm = async () => {
|
2009
|
+
if (onConfirm) {
|
2010
|
+
await onConfirm();
|
2011
|
+
}
|
2012
|
+
onClose();
|
2013
|
+
};
|
2014
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2015
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2016
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2017
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2018
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2019
|
+
id: "app.components.Button.cancel",
|
2020
|
+
defaultMessage: "Cancel"
|
2021
|
+
}) }) }),
|
2022
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2023
|
+
id: "app.components.Button.confirm",
|
2024
|
+
defaultMessage: "Confirm"
|
2025
|
+
}) })
|
2026
|
+
] })
|
2027
|
+
] }) });
|
2040
2028
|
};
|
2041
|
-
|
2042
|
-
|
2029
|
+
const DocumentActionModal = ({
|
2030
|
+
isOpen,
|
2031
|
+
title,
|
2032
|
+
onClose,
|
2033
|
+
footer: Footer,
|
2034
|
+
content: Content,
|
2035
|
+
onModalClose
|
2036
|
+
}) => {
|
2037
|
+
const handleClose = () => {
|
2038
|
+
if (onClose) {
|
2039
|
+
onClose();
|
2040
|
+
}
|
2041
|
+
onModalClose();
|
2042
|
+
};
|
2043
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2044
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2045
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2046
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2047
|
+
] }) });
|
2048
|
+
};
|
2049
|
+
const PublishAction$1 = ({
|
2043
2050
|
activeTab,
|
2044
2051
|
documentId,
|
2045
2052
|
model,
|
2046
2053
|
collectionType,
|
2054
|
+
meta,
|
2047
2055
|
document
|
2048
2056
|
}) => {
|
2049
|
-
const { formatMessage } = useIntl();
|
2050
2057
|
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();
|
2058
|
+
const navigate = useNavigate();
|
2059
|
+
const { toggleNotification } = useNotification();
|
2060
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2061
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
2149
2062
|
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
2063
|
const { formatMessage } = useIntl();
|
2165
|
-
const
|
2064
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2065
|
+
const { publish } = useDocumentActions();
|
2166
2066
|
const [
|
2167
|
-
|
2168
|
-
|
2067
|
+
countDraftRelations,
|
2068
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2069
|
+
] = useLazyGetDraftRelationCountQuery();
|
2070
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2071
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
2072
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2073
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2074
|
+
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
2075
|
+
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2076
|
+
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2077
|
+
const validate = useForm("PublishAction", (state) => state.validate);
|
2078
|
+
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
2079
|
+
const formValues = useForm("PublishAction", ({ values }) => values);
|
2080
|
+
React.useEffect(() => {
|
2081
|
+
if (isErrorDraftRelations) {
|
2082
|
+
toggleNotification({
|
2083
|
+
type: "danger",
|
2084
|
+
message: formatMessage({
|
2085
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2086
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2087
|
+
})
|
2088
|
+
});
|
2169
2089
|
}
|
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
|
-
}
|
2090
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2091
|
+
React.useEffect(() => {
|
2092
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2093
|
+
const extractDraftRelations = (data) => {
|
2094
|
+
const relations = data.connect || [];
|
2095
|
+
relations.forEach((relation) => {
|
2096
|
+
if (relation.status === "draft") {
|
2097
|
+
localDraftRelations.add(relation.id);
|
2192
2098
|
}
|
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
|
-
);
|
2099
|
+
});
|
2100
|
+
};
|
2101
|
+
const traverseAndExtract = (data) => {
|
2102
|
+
Object.entries(data).forEach(([key, value]) => {
|
2103
|
+
if (key === "connect" && Array.isArray(value)) {
|
2104
|
+
extractDraftRelations({ connect: value });
|
2105
|
+
} else if (typeof value === "object" && value !== null) {
|
2106
|
+
traverseAndExtract(value);
|
2223
2107
|
}
|
2108
|
+
});
|
2109
|
+
};
|
2110
|
+
if (!documentId || modified) {
|
2111
|
+
traverseAndExtract(formValues);
|
2112
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2113
|
+
}
|
2114
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2115
|
+
React.useEffect(() => {
|
2116
|
+
if (!document || !document.documentId || isListView) {
|
2117
|
+
return;
|
2118
|
+
}
|
2119
|
+
const fetchDraftRelationsCount = async () => {
|
2120
|
+
const { data, error } = await countDraftRelations({
|
2121
|
+
collectionType,
|
2122
|
+
model,
|
2123
|
+
documentId,
|
2124
|
+
params
|
2125
|
+
});
|
2126
|
+
if (error) {
|
2127
|
+
throw error;
|
2224
2128
|
}
|
2225
|
-
|
2226
|
-
|
2227
|
-
}
|
2228
|
-
|
2229
|
-
|
2230
|
-
|
2231
|
-
|
2129
|
+
if (data) {
|
2130
|
+
setServerCountOfDraftRelations(data.data);
|
2131
|
+
}
|
2132
|
+
};
|
2133
|
+
fetchDraftRelationsCount();
|
2134
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2135
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2136
|
+
if (!schema?.options?.draftAndPublish) {
|
2232
2137
|
return null;
|
2233
2138
|
}
|
2234
|
-
const
|
2235
|
-
|
2236
|
-
|
2237
|
-
|
2238
|
-
|
2239
|
-
|
2240
|
-
|
2241
|
-
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2139
|
+
const performPublish = async () => {
|
2140
|
+
setSubmitting(true);
|
2141
|
+
try {
|
2142
|
+
const { errors } = await validate();
|
2143
|
+
if (errors) {
|
2144
|
+
toggleNotification({
|
2145
|
+
type: "danger",
|
2146
|
+
message: formatMessage({
|
2147
|
+
id: "content-manager.validation.error",
|
2148
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2149
|
+
})
|
2150
|
+
});
|
2151
|
+
return;
|
2152
|
+
}
|
2153
|
+
const res = await publish(
|
2246
2154
|
{
|
2247
|
-
|
2248
|
-
|
2155
|
+
collectionType,
|
2156
|
+
model,
|
2157
|
+
documentId,
|
2158
|
+
params
|
2249
2159
|
},
|
2250
|
-
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2160
|
+
formValues
|
2161
|
+
);
|
2162
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2163
|
+
navigate({
|
2164
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2165
|
+
search: rawQuery
|
2166
|
+
});
|
2167
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2168
|
+
setErrors(formatValidationErrors(res.error));
|
2169
|
+
}
|
2170
|
+
} finally {
|
2171
|
+
setSubmitting(false);
|
2172
|
+
}
|
2173
|
+
};
|
2174
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2175
|
+
const enableDraftRelationsCount = false;
|
2176
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2177
|
+
return {
|
2178
|
+
/**
|
2179
|
+
* Disabled when:
|
2180
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2181
|
+
* - the form is submitting
|
2182
|
+
* - the active tab is the published tab
|
2183
|
+
* - the document is already published & not modified
|
2184
|
+
* - the document is being created & not modified
|
2185
|
+
* - the user doesn't have the permission to publish
|
2186
|
+
*/
|
2187
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
2188
|
+
label: formatMessage({
|
2189
|
+
id: "app.utils.publish",
|
2190
|
+
defaultMessage: "Publish"
|
2191
|
+
}),
|
2192
|
+
onClick: async () => {
|
2193
|
+
await performPublish();
|
2256
2194
|
},
|
2257
|
-
{
|
2258
|
-
|
2259
|
-
|
2260
|
-
|
2261
|
-
|
2195
|
+
dialog: hasDraftRelations ? {
|
2196
|
+
type: "dialog",
|
2197
|
+
variant: "danger",
|
2198
|
+
footer: null,
|
2199
|
+
title: formatMessage({
|
2200
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2201
|
+
defaultMessage: "Confirmation"
|
2262
2202
|
}),
|
2263
|
-
|
2203
|
+
content: formatMessage(
|
2264
2204
|
{
|
2265
|
-
id:
|
2266
|
-
defaultMessage:
|
2205
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2206
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2267
2207
|
},
|
2268
2208
|
{
|
2269
|
-
|
2270
|
-
RelativeTime,
|
2271
|
-
{
|
2272
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2273
|
-
}
|
2274
|
-
),
|
2275
|
-
isAnonymous: !updator,
|
2276
|
-
author: updator
|
2209
|
+
count: totalDraftRelations
|
2277
2210
|
}
|
2278
|
-
)
|
2279
|
-
|
2280
|
-
|
2281
|
-
|
2282
|
-
|
2283
|
-
|
2284
|
-
|
2285
|
-
|
2286
|
-
|
2287
|
-
|
2288
|
-
|
2289
|
-
|
2290
|
-
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2211
|
+
),
|
2212
|
+
onConfirm: async () => {
|
2213
|
+
await performPublish();
|
2214
|
+
}
|
2215
|
+
} : void 0
|
2216
|
+
};
|
2217
|
+
};
|
2218
|
+
PublishAction$1.type = "publish";
|
2219
|
+
const UpdateAction = ({
|
2220
|
+
activeTab,
|
2221
|
+
documentId,
|
2222
|
+
model,
|
2223
|
+
collectionType
|
2224
|
+
}) => {
|
2225
|
+
const navigate = useNavigate();
|
2226
|
+
const { toggleNotification } = useNotification();
|
2227
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2228
|
+
const cloneMatch = useMatch(CLONE_PATH);
|
2229
|
+
const isCloning = cloneMatch !== null;
|
2230
|
+
const { formatMessage } = useIntl();
|
2231
|
+
const { create, update, clone } = useDocumentActions();
|
2232
|
+
const [{ query, rawQuery }] = useQueryParams();
|
2233
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2234
|
+
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2235
|
+
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
2236
|
+
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2237
|
+
const document = useForm("UpdateAction", ({ values }) => values);
|
2238
|
+
const validate = useForm("UpdateAction", (state) => state.validate);
|
2239
|
+
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
2240
|
+
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
2241
|
+
return {
|
2242
|
+
/**
|
2243
|
+
* Disabled when:
|
2244
|
+
* - the form is submitting
|
2245
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2246
|
+
* - the active tab is the published tab
|
2247
|
+
*/
|
2248
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2249
|
+
label: formatMessage({
|
2250
|
+
id: "content-manager.containers.Edit.save",
|
2251
|
+
defaultMessage: "Save"
|
2252
|
+
}),
|
2253
|
+
onClick: async () => {
|
2254
|
+
setSubmitting(true);
|
2255
|
+
try {
|
2256
|
+
if (activeTab !== "draft") {
|
2257
|
+
const { errors } = await validate();
|
2258
|
+
if (errors) {
|
2259
|
+
toggleNotification({
|
2260
|
+
type: "danger",
|
2261
|
+
message: formatMessage({
|
2262
|
+
id: "content-manager.validation.error",
|
2263
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2264
|
+
})
|
2265
|
+
});
|
2266
|
+
return;
|
2267
|
+
}
|
2300
2268
|
}
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2269
|
+
if (isCloning) {
|
2270
|
+
const res = await clone(
|
2271
|
+
{
|
2272
|
+
model,
|
2273
|
+
documentId: cloneMatch.params.origin,
|
2274
|
+
params
|
2275
|
+
},
|
2276
|
+
document
|
2277
|
+
);
|
2278
|
+
if ("data" in res) {
|
2279
|
+
navigate(
|
2280
|
+
{
|
2281
|
+
pathname: `../${res.data.documentId}`,
|
2282
|
+
search: rawQuery
|
2283
|
+
},
|
2284
|
+
{ relative: "path" }
|
2285
|
+
);
|
2286
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2287
|
+
setErrors(formatValidationErrors(res.error));
|
2288
|
+
}
|
2289
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2290
|
+
const res = await update(
|
2291
|
+
{
|
2292
|
+
collectionType,
|
2293
|
+
model,
|
2294
|
+
documentId,
|
2295
|
+
params
|
2296
|
+
},
|
2297
|
+
document
|
2298
|
+
);
|
2299
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2300
|
+
setErrors(formatValidationErrors(res.error));
|
2301
|
+
} else {
|
2302
|
+
resetForm();
|
2303
|
+
}
|
2304
|
+
} else {
|
2305
|
+
const res = await create(
|
2306
|
+
{
|
2307
|
+
model,
|
2308
|
+
params
|
2309
|
+
},
|
2310
|
+
document
|
2311
|
+
);
|
2312
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2313
|
+
navigate(
|
2314
|
+
{
|
2315
|
+
pathname: `../${res.data.documentId}`,
|
2316
|
+
search: rawQuery
|
2317
|
+
},
|
2318
|
+
{ replace: true, relative: "path" }
|
2319
|
+
);
|
2320
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2321
|
+
setErrors(formatValidationErrors(res.error));
|
2322
|
+
}
|
2323
|
+
}
|
2324
|
+
} finally {
|
2325
|
+
setSubmitting(false);
|
2326
|
+
}
|
2323
2327
|
}
|
2324
|
-
|
2328
|
+
};
|
2325
2329
|
};
|
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
|
-
}) });
|
2330
|
+
UpdateAction.type = "update";
|
2331
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2332
|
+
KEEP: "keep",
|
2333
|
+
DISCARD: "discard"
|
2345
2334
|
};
|
2346
|
-
const
|
2347
|
-
|
2335
|
+
const UnpublishAction$1 = ({
|
2336
|
+
activeTab,
|
2337
|
+
documentId,
|
2338
|
+
model,
|
2339
|
+
collectionType,
|
2340
|
+
document
|
2341
|
+
}) => {
|
2348
2342
|
const { formatMessage } = useIntl();
|
2349
|
-
|
2350
|
-
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2343
|
+
const { schema } = useDoc();
|
2344
|
+
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2345
|
+
const { unpublish } = useDocumentActions();
|
2346
|
+
const [{ query }] = useQueryParams();
|
2347
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2348
|
+
const { toggleNotification } = useNotification();
|
2349
|
+
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
2350
|
+
const isDocumentModified = document?.status === "modified";
|
2351
|
+
const handleChange = (value) => {
|
2352
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
2359
2353
|
};
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
const navigate = useNavigate();
|
2364
|
-
const { formatMessage } = useIntl();
|
2354
|
+
if (!schema?.options?.draftAndPublish) {
|
2355
|
+
return null;
|
2356
|
+
}
|
2365
2357
|
return {
|
2358
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2366
2359
|
label: formatMessage({
|
2367
|
-
id: "
|
2368
|
-
defaultMessage: "
|
2360
|
+
id: "app.utils.unpublish",
|
2361
|
+
defaultMessage: "Unpublish"
|
2369
2362
|
}),
|
2370
|
-
icon: /* @__PURE__ */ jsx(
|
2371
|
-
onClick: () => {
|
2372
|
-
|
2363
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2364
|
+
onClick: async () => {
|
2365
|
+
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2366
|
+
if (!documentId) {
|
2367
|
+
console.error(
|
2368
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2369
|
+
);
|
2370
|
+
toggleNotification({
|
2371
|
+
message: formatMessage({
|
2372
|
+
id: "content-manager.actions.unpublish.error",
|
2373
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2374
|
+
}),
|
2375
|
+
type: "danger"
|
2376
|
+
});
|
2377
|
+
}
|
2378
|
+
return;
|
2379
|
+
}
|
2380
|
+
await unpublish({
|
2381
|
+
collectionType,
|
2382
|
+
model,
|
2383
|
+
documentId,
|
2384
|
+
params
|
2385
|
+
});
|
2373
2386
|
},
|
2374
|
-
|
2387
|
+
dialog: isDocumentModified ? {
|
2388
|
+
type: "dialog",
|
2389
|
+
title: formatMessage({
|
2390
|
+
id: "app.components.ConfirmDialog.title",
|
2391
|
+
defaultMessage: "Confirmation"
|
2392
|
+
}),
|
2393
|
+
content: /* @__PURE__ */ jsxs(Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
2394
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", direction: "column", gap: 2, children: [
|
2395
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2396
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2397
|
+
id: "content-manager.actions.unpublish.dialog.body",
|
2398
|
+
defaultMessage: "Are you sure?"
|
2399
|
+
}) })
|
2400
|
+
] }),
|
2401
|
+
/* @__PURE__ */ jsxs(
|
2402
|
+
Radio.Group,
|
2403
|
+
{
|
2404
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2405
|
+
name: "discard-options",
|
2406
|
+
"aria-label": formatMessage({
|
2407
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2408
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2409
|
+
}),
|
2410
|
+
onValueChange: handleChange,
|
2411
|
+
children: [
|
2412
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2413
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2414
|
+
defaultMessage: "Keep draft"
|
2415
|
+
}) }),
|
2416
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2417
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2418
|
+
defaultMessage: "Replace draft"
|
2419
|
+
}) })
|
2420
|
+
]
|
2421
|
+
}
|
2422
|
+
)
|
2423
|
+
] }),
|
2424
|
+
onConfirm: async () => {
|
2425
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2426
|
+
console.error(
|
2427
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2428
|
+
);
|
2429
|
+
toggleNotification({
|
2430
|
+
message: formatMessage({
|
2431
|
+
id: "content-manager.actions.unpublish.error",
|
2432
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2433
|
+
}),
|
2434
|
+
type: "danger"
|
2435
|
+
});
|
2436
|
+
}
|
2437
|
+
await unpublish(
|
2438
|
+
{
|
2439
|
+
collectionType,
|
2440
|
+
model,
|
2441
|
+
documentId,
|
2442
|
+
params
|
2443
|
+
},
|
2444
|
+
!shouldKeepDraft
|
2445
|
+
);
|
2446
|
+
}
|
2447
|
+
} : void 0,
|
2448
|
+
variant: "danger",
|
2449
|
+
position: ["panel", "table-row"]
|
2375
2450
|
};
|
2376
2451
|
};
|
2377
|
-
|
2378
|
-
const
|
2379
|
-
|
2452
|
+
UnpublishAction$1.type = "unpublish";
|
2453
|
+
const DiscardAction = ({
|
2454
|
+
activeTab,
|
2455
|
+
documentId,
|
2456
|
+
model,
|
2457
|
+
collectionType,
|
2458
|
+
document
|
2459
|
+
}) => {
|
2380
2460
|
const { formatMessage } = useIntl();
|
2381
|
-
const
|
2382
|
-
const
|
2383
|
-
const {
|
2384
|
-
const {
|
2385
|
-
const
|
2461
|
+
const { schema } = useDoc();
|
2462
|
+
const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
|
2463
|
+
const { discard } = useDocumentActions();
|
2464
|
+
const [{ query }] = useQueryParams();
|
2465
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
2466
|
+
if (!schema?.options?.draftAndPublish) {
|
2467
|
+
return null;
|
2468
|
+
}
|
2386
2469
|
return {
|
2387
|
-
disabled: !
|
2470
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2388
2471
|
label: formatMessage({
|
2389
|
-
id: "content-manager.actions.
|
2390
|
-
defaultMessage: "
|
2472
|
+
id: "content-manager.actions.discard.label",
|
2473
|
+
defaultMessage: "Discard changes"
|
2391
2474
|
}),
|
2392
|
-
icon: /* @__PURE__ */ jsx(
|
2475
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2476
|
+
position: ["panel", "table-row"],
|
2477
|
+
variant: "danger",
|
2393
2478
|
dialog: {
|
2394
2479
|
type: "dialog",
|
2395
2480
|
title: formatMessage({
|
@@ -2399,92 +2484,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2399
2484
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2400
2485
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2401
2486
|
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2402
|
-
id: "content-manager.actions.
|
2487
|
+
id: "content-manager.actions.discard.dialog.body",
|
2403
2488
|
defaultMessage: "Are you sure?"
|
2404
2489
|
}) })
|
2405
2490
|
] }),
|
2406
2491
|
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
|
-
|
2492
|
+
await discard({
|
2493
|
+
collectionType,
|
2494
|
+
model,
|
2495
|
+
documentId,
|
2496
|
+
params
|
2497
|
+
});
|
2498
|
+
}
|
2499
|
+
}
|
2500
|
+
};
|
2501
|
+
};
|
2502
|
+
DiscardAction.type = "discard";
|
2503
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2504
|
+
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2505
|
+
const RelativeTime = React.forwardRef(
|
2506
|
+
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2507
|
+
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2508
|
+
const interval = intervalToDuration({
|
2509
|
+
start: timestamp,
|
2510
|
+
end: Date.now()
|
2511
|
+
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2512
|
+
});
|
2513
|
+
const unit = intervals.find((intervalUnit) => {
|
2514
|
+
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2515
|
+
});
|
2516
|
+
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2517
|
+
const customInterval = customIntervals.find(
|
2518
|
+
(custom) => interval[custom.unit] < custom.threshold
|
2519
|
+
);
|
2520
|
+
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2521
|
+
return /* @__PURE__ */ jsx(
|
2522
|
+
"time",
|
2523
|
+
{
|
2524
|
+
ref: forwardedRef,
|
2525
|
+
dateTime: timestamp.toISOString(),
|
2526
|
+
role: "time",
|
2527
|
+
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2528
|
+
...restProps,
|
2529
|
+
children: displayText
|
2440
2530
|
}
|
2441
|
-
|
2442
|
-
|
2443
|
-
|
2444
|
-
|
2531
|
+
);
|
2532
|
+
}
|
2533
|
+
);
|
2534
|
+
const getDisplayName = ({
|
2535
|
+
firstname,
|
2536
|
+
lastname,
|
2537
|
+
username,
|
2538
|
+
email
|
2539
|
+
} = {}) => {
|
2540
|
+
if (username) {
|
2541
|
+
return username;
|
2542
|
+
}
|
2543
|
+
if (firstname) {
|
2544
|
+
return `${firstname} ${lastname ?? ""}`.trim();
|
2545
|
+
}
|
2546
|
+
return email ?? "";
|
2445
2547
|
};
|
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
|
-
) });
|
2548
|
+
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2549
|
+
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2550
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2551
|
+
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
2552
|
};
|
2476
|
-
const
|
2553
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2477
2554
|
const { formatMessage } = useIntl();
|
2478
|
-
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2555
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2556
|
+
const title = isCreating ? formatMessage({
|
2557
|
+
id: "content-manager.containers.edit.title.new",
|
2558
|
+
defaultMessage: "Create an entry"
|
2559
|
+
}) : documentTitle;
|
2560
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2561
|
+
/* @__PURE__ */ jsx(BackButton, {}),
|
2562
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2563
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2564
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2565
|
+
] }),
|
2566
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2567
|
+
] });
|
2485
2568
|
};
|
2486
|
-
|
2487
|
-
const
|
2569
|
+
const HeaderToolbar = () => {
|
2570
|
+
const { formatMessage } = useIntl();
|
2488
2571
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2489
2572
|
const [
|
2490
2573
|
{
|
@@ -2492,355 +2575,432 @@ const ActionsPanelContent = () => {
|
|
2492
2575
|
}
|
2493
2576
|
] = useQueryParams();
|
2494
2577
|
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: [
|
2578
|
+
const plugins = useStrapiApp("HeaderToolbar", (state) => state.plugins);
|
2579
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
2505
2580
|
/* @__PURE__ */ jsx(
|
2506
2581
|
DescriptionComponentRenderer,
|
2507
2582
|
{
|
2508
|
-
props
|
2509
|
-
|
2510
|
-
|
2583
|
+
props: {
|
2584
|
+
activeTab: status,
|
2585
|
+
model,
|
2586
|
+
documentId: id,
|
2587
|
+
document: isCloning ? void 0 : document,
|
2588
|
+
meta: isCloning ? void 0 : meta,
|
2589
|
+
collectionType
|
2590
|
+
},
|
2591
|
+
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2592
|
+
children: (actions2) => {
|
2593
|
+
if (actions2.length > 0) {
|
2594
|
+
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2595
|
+
} else {
|
2596
|
+
return null;
|
2597
|
+
}
|
2598
|
+
}
|
2511
2599
|
}
|
2512
2600
|
),
|
2513
|
-
/* @__PURE__ */ jsx(
|
2601
|
+
/* @__PURE__ */ jsx(
|
2602
|
+
DescriptionComponentRenderer,
|
2603
|
+
{
|
2604
|
+
props: {
|
2605
|
+
activeTab: status,
|
2606
|
+
model,
|
2607
|
+
documentId: id,
|
2608
|
+
document: isCloning ? void 0 : document,
|
2609
|
+
meta: isCloning ? void 0 : meta,
|
2610
|
+
collectionType
|
2611
|
+
},
|
2612
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2613
|
+
children: (actions2) => {
|
2614
|
+
const headerActions = actions2.filter((action) => {
|
2615
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2616
|
+
return positions.includes("header");
|
2617
|
+
});
|
2618
|
+
return /* @__PURE__ */ jsx(
|
2619
|
+
DocumentActionsMenu,
|
2620
|
+
{
|
2621
|
+
actions: headerActions,
|
2622
|
+
label: formatMessage({
|
2623
|
+
id: "content-manager.containers.edit.header.more-actions",
|
2624
|
+
defaultMessage: "More actions"
|
2625
|
+
}),
|
2626
|
+
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2627
|
+
}
|
2628
|
+
);
|
2629
|
+
}
|
2630
|
+
}
|
2631
|
+
)
|
2514
2632
|
] });
|
2515
2633
|
};
|
2516
|
-
const
|
2517
|
-
|
2518
|
-
|
2634
|
+
const Information = ({ activeTab }) => {
|
2635
|
+
const { formatMessage } = useIntl();
|
2636
|
+
const { document, meta } = useDoc();
|
2637
|
+
if (!document || !document.id) {
|
2638
|
+
return null;
|
2639
|
+
}
|
2640
|
+
const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
|
2641
|
+
const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
|
2642
|
+
const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
|
2643
|
+
const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
|
2644
|
+
const information = [
|
2519
2645
|
{
|
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"
|
2646
|
+
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2647
|
+
label: formatMessage({
|
2648
|
+
id: "content-manager.containers.edit.information.last-published.label",
|
2649
|
+
defaultMessage: "Last published"
|
2574
2650
|
}),
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
2583
|
-
|
2584
|
-
|
2585
|
-
|
2586
|
-
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2651
|
+
value: formatMessage(
|
2652
|
+
{
|
2653
|
+
id: "content-manager.containers.edit.information.last-published.value",
|
2654
|
+
defaultMessage: `Published {time}{isAnonymous, select, true {} other { by {author}}}`
|
2655
|
+
},
|
2656
|
+
{
|
2657
|
+
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
2658
|
+
isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
|
2659
|
+
author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
|
2660
|
+
}
|
2661
|
+
)
|
2662
|
+
},
|
2663
|
+
{
|
2664
|
+
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2665
|
+
label: formatMessage({
|
2666
|
+
id: "content-manager.containers.edit.information.last-draft.label",
|
2667
|
+
defaultMessage: "Last draft"
|
2668
|
+
}),
|
2669
|
+
value: formatMessage(
|
2670
|
+
{
|
2671
|
+
id: "content-manager.containers.edit.information.last-draft.value",
|
2672
|
+
defaultMessage: `Modified {time}{isAnonymous, select, true {} other { by {author}}}`
|
2673
|
+
},
|
2674
|
+
{
|
2675
|
+
time: /* @__PURE__ */ jsx(
|
2676
|
+
RelativeTime,
|
2677
|
+
{
|
2678
|
+
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2679
|
+
}
|
2680
|
+
),
|
2681
|
+
isAnonymous: !updator,
|
2682
|
+
author: updator
|
2683
|
+
}
|
2684
|
+
)
|
2685
|
+
},
|
2686
|
+
{
|
2687
|
+
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2688
|
+
label: formatMessage({
|
2689
|
+
id: "content-manager.containers.edit.information.document.label",
|
2690
|
+
defaultMessage: "Document"
|
2591
2691
|
}),
|
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
|
-
|
2692
|
+
value: formatMessage(
|
2693
|
+
{
|
2694
|
+
id: "content-manager.containers.edit.information.document.value",
|
2695
|
+
defaultMessage: `Created {time}{isAnonymous, select, true {} other { by {author}}}`
|
2696
|
+
},
|
2697
|
+
{
|
2698
|
+
time: /* @__PURE__ */ jsx(
|
2699
|
+
RelativeTime,
|
2700
|
+
{
|
2701
|
+
timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
|
2702
|
+
}
|
2703
|
+
),
|
2704
|
+
isAnonymous: !creator,
|
2705
|
+
author: creator
|
2706
|
+
}
|
2707
|
+
)
|
2708
|
+
}
|
2709
|
+
].filter((info) => info.isDisplayed);
|
2710
|
+
return /* @__PURE__ */ jsx(
|
2711
|
+
Flex,
|
2712
|
+
{
|
2713
|
+
borderWidth: "1px 0 0 0",
|
2714
|
+
borderStyle: "solid",
|
2715
|
+
borderColor: "neutral150",
|
2716
|
+
direction: "column",
|
2717
|
+
marginTop: 2,
|
2718
|
+
tag: "dl",
|
2719
|
+
padding: 5,
|
2720
|
+
gap: 3,
|
2721
|
+
alignItems: "flex-start",
|
2722
|
+
marginLeft: "-0.4rem",
|
2723
|
+
marginRight: "-0.4rem",
|
2724
|
+
width: "calc(100% + 8px)",
|
2725
|
+
children: information.map((info) => /* @__PURE__ */ jsxs(Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2726
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2727
|
+
/* @__PURE__ */ jsx(Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2728
|
+
] }, info.label))
|
2729
|
+
}
|
2621
2730
|
);
|
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
2731
|
};
|
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
|
-
});
|
2732
|
+
const HeaderActions = ({ actions: actions2 }) => {
|
2733
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2734
|
+
const handleClick = (action) => async (e) => {
|
2735
|
+
if (!("options" in action)) {
|
2736
|
+
const { onClick = () => false, dialog, id } = action;
|
2737
|
+
const muteDialog = await onClick(e);
|
2738
|
+
if (dialog && !muteDialog) {
|
2739
|
+
e.preventDefault();
|
2740
|
+
setDialogId(id);
|
2741
|
+
}
|
2657
2742
|
}
|
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
2743
|
};
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
return
|
2694
|
-
|
2695
|
-
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2706
|
-
schemas
|
2707
|
-
).reduce((panels, row) => {
|
2708
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2709
|
-
panels.push([row]);
|
2710
|
-
currentPanelIndex += 2;
|
2744
|
+
const handleClose = () => {
|
2745
|
+
setDialogId(null);
|
2746
|
+
};
|
2747
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2748
|
+
if (action.options) {
|
2749
|
+
return /* @__PURE__ */ jsx(
|
2750
|
+
SingleSelect,
|
2751
|
+
{
|
2752
|
+
size: "S",
|
2753
|
+
onChange: action.onSelect,
|
2754
|
+
"aria-label": action.label,
|
2755
|
+
...action,
|
2756
|
+
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2757
|
+
},
|
2758
|
+
action.id
|
2759
|
+
);
|
2711
2760
|
} else {
|
2712
|
-
if (
|
2713
|
-
|
2761
|
+
if (action.type === "icon") {
|
2762
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2763
|
+
/* @__PURE__ */ jsx(
|
2764
|
+
IconButton,
|
2765
|
+
{
|
2766
|
+
disabled: action.disabled,
|
2767
|
+
label: action.label,
|
2768
|
+
size: "S",
|
2769
|
+
onClick: handleClick(action),
|
2770
|
+
children: action.icon
|
2771
|
+
}
|
2772
|
+
),
|
2773
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2774
|
+
HeaderActionDialog,
|
2775
|
+
{
|
2776
|
+
...action.dialog,
|
2777
|
+
isOpen: dialogId === action.id,
|
2778
|
+
onClose: handleClose
|
2779
|
+
}
|
2780
|
+
) : null
|
2781
|
+
] }, action.id);
|
2714
2782
|
}
|
2715
|
-
panels[currentPanelIndex].push(row);
|
2716
2783
|
}
|
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
|
-
|
2784
|
+
}) });
|
2785
|
+
};
|
2786
|
+
const HeaderActionDialog = ({
|
2787
|
+
onClose,
|
2788
|
+
onCancel,
|
2789
|
+
title,
|
2790
|
+
content: Content,
|
2791
|
+
isOpen
|
2792
|
+
}) => {
|
2793
|
+
const handleClose = async () => {
|
2794
|
+
if (onCancel) {
|
2795
|
+
await onCancel();
|
2796
|
+
}
|
2797
|
+
onClose();
|
2798
|
+
};
|
2799
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2800
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2801
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2802
|
+
] }) });
|
2803
|
+
};
|
2804
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2805
|
+
const navigate = useNavigate();
|
2806
|
+
const { formatMessage } = useIntl();
|
2807
|
+
return {
|
2808
|
+
label: formatMessage({
|
2809
|
+
id: "app.links.configure-view",
|
2810
|
+
defaultMessage: "Configure the view"
|
2811
|
+
}),
|
2812
|
+
icon: /* @__PURE__ */ jsx(ListPlus, {}),
|
2813
|
+
onClick: () => {
|
2814
|
+
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2743
2815
|
},
|
2744
|
-
|
2745
|
-
|
2816
|
+
position: "header"
|
2817
|
+
};
|
2818
|
+
};
|
2819
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2820
|
+
const EditTheModelAction = ({ model }) => {
|
2821
|
+
const navigate = useNavigate();
|
2822
|
+
const { formatMessage } = useIntl();
|
2746
2823
|
return {
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2824
|
+
label: formatMessage({
|
2825
|
+
id: "content-manager.link-to-ctb",
|
2826
|
+
defaultMessage: "Edit the model"
|
2827
|
+
}),
|
2828
|
+
icon: /* @__PURE__ */ jsx(Pencil, {}),
|
2829
|
+
onClick: () => {
|
2830
|
+
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2753
2831
|
},
|
2754
|
-
|
2755
|
-
...schema?.options,
|
2756
|
-
...schema?.pluginOptions,
|
2757
|
-
...data.contentType.options
|
2758
|
-
}
|
2832
|
+
position: "header"
|
2759
2833
|
};
|
2760
2834
|
};
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2835
|
+
EditTheModelAction.type = "edit-the-model";
|
2836
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2837
|
+
const navigate = useNavigate();
|
2838
|
+
const { formatMessage } = useIntl();
|
2839
|
+
const listViewPathMatch = useMatch(LIST_PATH);
|
2840
|
+
const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
|
2841
|
+
const { delete: deleteAction } = useDocumentActions();
|
2842
|
+
const { toggleNotification } = useNotification();
|
2843
|
+
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2844
|
+
const isLocalized = document?.locale != null;
|
2845
|
+
return {
|
2846
|
+
disabled: !canDelete || !document,
|
2847
|
+
label: formatMessage(
|
2848
|
+
{
|
2849
|
+
id: "content-manager.actions.delete.label",
|
2850
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2851
|
+
},
|
2852
|
+
{ isLocalized }
|
2853
|
+
),
|
2854
|
+
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2855
|
+
dialog: {
|
2856
|
+
type: "dialog",
|
2857
|
+
title: formatMessage({
|
2858
|
+
id: "app.components.ConfirmDialog.title",
|
2859
|
+
defaultMessage: "Confirmation"
|
2860
|
+
}),
|
2861
|
+
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2862
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2863
|
+
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2864
|
+
id: "content-manager.actions.delete.dialog.body",
|
2865
|
+
defaultMessage: "Are you sure?"
|
2866
|
+
}) })
|
2867
|
+
] }),
|
2868
|
+
onConfirm: async () => {
|
2869
|
+
if (!listViewPathMatch) {
|
2870
|
+
setSubmitting(true);
|
2871
|
+
}
|
2872
|
+
try {
|
2873
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2874
|
+
console.error(
|
2875
|
+
"You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2876
|
+
);
|
2877
|
+
toggleNotification({
|
2878
|
+
message: formatMessage({
|
2879
|
+
id: "content-manager.actions.delete.error",
|
2880
|
+
defaultMessage: "An error occurred while trying to delete the document."
|
2881
|
+
}),
|
2882
|
+
type: "danger"
|
2883
|
+
});
|
2884
|
+
return;
|
2885
|
+
}
|
2886
|
+
const res = await deleteAction({
|
2887
|
+
documentId,
|
2888
|
+
model,
|
2889
|
+
collectionType,
|
2890
|
+
params: {
|
2891
|
+
locale: "*"
|
2892
|
+
}
|
2893
|
+
});
|
2894
|
+
if (!("error" in res)) {
|
2895
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2896
|
+
}
|
2897
|
+
} finally {
|
2898
|
+
if (!listViewPathMatch) {
|
2899
|
+
setSubmitting(false);
|
2900
|
+
}
|
2901
|
+
}
|
2767
2902
|
}
|
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
2903
|
},
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2904
|
+
variant: "danger",
|
2905
|
+
position: ["header", "table-row"]
|
2906
|
+
};
|
2907
|
+
};
|
2908
|
+
DeleteAction$1.type = "delete";
|
2909
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2910
|
+
const Panels = () => {
|
2911
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2912
|
+
const [
|
2913
|
+
{
|
2914
|
+
query: { status }
|
2915
|
+
}
|
2916
|
+
] = useQueryParams({
|
2917
|
+
status: "draft"
|
2918
|
+
});
|
2919
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2920
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2921
|
+
const props = {
|
2922
|
+
activeTab: status,
|
2923
|
+
model,
|
2924
|
+
documentId: id,
|
2925
|
+
document: isCloning ? void 0 : document,
|
2926
|
+
meta: isCloning ? void 0 : meta,
|
2927
|
+
collectionType
|
2928
|
+
};
|
2929
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2930
|
+
DescriptionComponentRenderer,
|
2931
|
+
{
|
2932
|
+
props,
|
2933
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2934
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2820
2935
|
}
|
2936
|
+
) });
|
2937
|
+
};
|
2938
|
+
const ActionsPanel = () => {
|
2939
|
+
const { formatMessage } = useIntl();
|
2940
|
+
return {
|
2941
|
+
title: formatMessage({
|
2942
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2943
|
+
defaultMessage: "Entry"
|
2944
|
+
}),
|
2945
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2821
2946
|
};
|
2822
2947
|
};
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2948
|
+
ActionsPanel.type = "actions";
|
2949
|
+
const ActionsPanelContent = () => {
|
2950
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2951
|
+
const [
|
2952
|
+
{
|
2953
|
+
query: { status = "draft" }
|
2828
2954
|
}
|
2829
|
-
|
2830
|
-
|
2831
|
-
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
2839
|
-
|
2840
|
-
|
2841
|
-
|
2842
|
-
|
2955
|
+
] = useQueryParams();
|
2956
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2957
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2958
|
+
const props = {
|
2959
|
+
activeTab: status,
|
2960
|
+
model,
|
2961
|
+
documentId: id,
|
2962
|
+
document: isCloning ? void 0 : document,
|
2963
|
+
meta: isCloning ? void 0 : meta,
|
2964
|
+
collectionType
|
2965
|
+
};
|
2966
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2967
|
+
/* @__PURE__ */ jsx(
|
2968
|
+
DescriptionComponentRenderer,
|
2969
|
+
{
|
2970
|
+
props,
|
2971
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2972
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2973
|
+
}
|
2974
|
+
),
|
2975
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2976
|
+
] });
|
2843
2977
|
};
|
2978
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2979
|
+
return /* @__PURE__ */ jsxs(
|
2980
|
+
Flex,
|
2981
|
+
{
|
2982
|
+
ref,
|
2983
|
+
tag: "aside",
|
2984
|
+
"aria-labelledby": "additional-information",
|
2985
|
+
background: "neutral0",
|
2986
|
+
borderColor: "neutral150",
|
2987
|
+
hasRadius: true,
|
2988
|
+
paddingBottom: 4,
|
2989
|
+
paddingLeft: 4,
|
2990
|
+
paddingRight: 4,
|
2991
|
+
paddingTop: 4,
|
2992
|
+
shadow: "tableShadow",
|
2993
|
+
gap: 3,
|
2994
|
+
direction: "column",
|
2995
|
+
justifyContent: "stretch",
|
2996
|
+
alignItems: "flex-start",
|
2997
|
+
children: [
|
2998
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2999
|
+
children
|
3000
|
+
]
|
3001
|
+
}
|
3002
|
+
);
|
3003
|
+
});
|
2844
3004
|
const ConfirmBulkActionDialog = ({
|
2845
3005
|
onToggleDialog,
|
2846
3006
|
isOpen = false,
|
@@ -2879,6 +3039,7 @@ const ConfirmDialogPublishAll = ({
|
|
2879
3039
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2880
3040
|
const { model, schema } = useDoc();
|
2881
3041
|
const [{ query }] = useQueryParams();
|
3042
|
+
const enableDraftRelationsCount = false;
|
2882
3043
|
const {
|
2883
3044
|
data: countDraftRelations = 0,
|
2884
3045
|
isLoading,
|
@@ -2890,7 +3051,7 @@ const ConfirmDialogPublishAll = ({
|
|
2890
3051
|
locale: query?.plugins?.i18n?.locale
|
2891
3052
|
},
|
2892
3053
|
{
|
2893
|
-
skip:
|
3054
|
+
skip: !enableDraftRelationsCount
|
2894
3055
|
}
|
2895
3056
|
);
|
2896
3057
|
React.useEffect(() => {
|
@@ -3075,7 +3236,7 @@ const SelectedEntriesTableContent = ({
|
|
3075
3236
|
status: row.status
|
3076
3237
|
}
|
3077
3238
|
) }),
|
3078
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3239
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3079
3240
|
IconButton,
|
3080
3241
|
{
|
3081
3242
|
tag: Link,
|
@@ -3098,9 +3259,10 @@ const SelectedEntriesTableContent = ({
|
|
3098
3259
|
),
|
3099
3260
|
target: "_blank",
|
3100
3261
|
marginLeft: "auto",
|
3101
|
-
|
3262
|
+
variant: "ghost",
|
3263
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3102
3264
|
}
|
3103
|
-
) })
|
3265
|
+
) }) })
|
3104
3266
|
] }, row.id)) })
|
3105
3267
|
] });
|
3106
3268
|
};
|
@@ -3137,7 +3299,13 @@ const SelectedEntriesModalContent = ({
|
|
3137
3299
|
);
|
3138
3300
|
const { rows, validationErrors } = React.useMemo(() => {
|
3139
3301
|
if (data.length > 0 && schema) {
|
3140
|
-
const validate = createYupSchema(
|
3302
|
+
const validate = createYupSchema(
|
3303
|
+
schema.attributes,
|
3304
|
+
components,
|
3305
|
+
// Since this is the "Publish" action, the validation
|
3306
|
+
// schema must enforce the rules for published entities
|
3307
|
+
{ status: "published" }
|
3308
|
+
);
|
3141
3309
|
const validationErrors2 = {};
|
3142
3310
|
const rows2 = data.map((entry) => {
|
3143
3311
|
try {
|
@@ -3487,7 +3655,7 @@ const TableActions = ({ document }) => {
|
|
3487
3655
|
DescriptionComponentRenderer,
|
3488
3656
|
{
|
3489
3657
|
props,
|
3490
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3658
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3491
3659
|
children: (actions2) => {
|
3492
3660
|
const tableRowActions = actions2.filter((action) => {
|
3493
3661
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3598,7 +3766,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3598
3766
|
}),
|
3599
3767
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3600
3768
|
footer: ({ onClose }) => {
|
3601
|
-
return /* @__PURE__ */ jsxs(
|
3769
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3602
3770
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3603
3771
|
id: "cancel",
|
3604
3772
|
defaultMessage: "Cancel"
|
@@ -3829,7 +3997,7 @@ const index = {
|
|
3829
3997
|
app.router.addRoute({
|
3830
3998
|
path: "content-manager/*",
|
3831
3999
|
lazy: async () => {
|
3832
|
-
const { Layout } = await import("./layout-
|
4000
|
+
const { Layout } = await import("./layout-DaUjDiWQ.mjs");
|
3833
4001
|
return {
|
3834
4002
|
Component: Layout
|
3835
4003
|
};
|
@@ -3846,7 +4014,7 @@ const index = {
|
|
3846
4014
|
async registerTrads({ locales }) {
|
3847
4015
|
const importedTrads = await Promise.all(
|
3848
4016
|
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-
|
4017
|
+
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
4018
|
return {
|
3851
4019
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3852
4020
|
locale
|
@@ -3867,13 +4035,15 @@ export {
|
|
3867
4035
|
BulkActionsRenderer as B,
|
3868
4036
|
COLLECTION_TYPES as C,
|
3869
4037
|
DocumentStatus as D,
|
3870
|
-
|
3871
|
-
|
3872
|
-
|
4038
|
+
extractContentTypeComponents as E,
|
4039
|
+
DEFAULT_SETTINGS as F,
|
4040
|
+
convertEditLayoutToFieldLayouts as G,
|
3873
4041
|
HOOKS as H,
|
3874
4042
|
InjectionZone as I,
|
3875
|
-
|
3876
|
-
|
4043
|
+
useDocument as J,
|
4044
|
+
index as K,
|
4045
|
+
useContentManagerContext as L,
|
4046
|
+
useDocumentActions as M,
|
3877
4047
|
Panels as P,
|
3878
4048
|
RelativeTime as R,
|
3879
4049
|
SINGLE_TYPES as S,
|
@@ -3891,18 +4061,18 @@ export {
|
|
3891
4061
|
PERMISSIONS as k,
|
3892
4062
|
DocumentRBAC as l,
|
3893
4063
|
DOCUMENT_META_FIELDS as m,
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
3897
|
-
|
3898
|
-
|
4064
|
+
CLONE_PATH as n,
|
4065
|
+
useDocLayout as o,
|
4066
|
+
useGetContentTypeConfigurationQuery as p,
|
4067
|
+
CREATOR_FIELDS as q,
|
4068
|
+
getMainField as r,
|
3899
4069
|
setInitialData as s,
|
3900
|
-
|
4070
|
+
getDisplayName as t,
|
3901
4071
|
useContentTypeSchema as u,
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
4072
|
+
checkIfAttributeIsDisplayable as v,
|
4073
|
+
useGetAllDocumentsQuery as w,
|
4074
|
+
convertListLayoutToFieldLayouts as x,
|
4075
|
+
capitalise as y,
|
4076
|
+
useUpdateContentTypeConfigurationMutation as z
|
3907
4077
|
};
|
3908
|
-
//# sourceMappingURL=index-
|
4078
|
+
//# sourceMappingURL=index-C9HxCo5R.mjs.map
|