@strapi/content-manager 0.0.0-experimental.c5235059f5636c4549ea2118c75c43b92e2615c8 → 0.0.0-experimental.c592deb623aed3f74ef7fdacfad9757ed59d34f7
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-o2HOTHL4.mjs → ComponentConfigurationPage-7-qB29e7.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-o2HOTHL4.mjs.map → ComponentConfigurationPage-7-qB29e7.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-k6fnZytn.js → ComponentConfigurationPage-DP7AC0UU.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-k6fnZytn.js.map → ComponentConfigurationPage-DP7AC0UU.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-HNi0pVX4.mjs → EditConfigurationPage-CI4XoymK.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-HNi0pVX4.mjs.map → EditConfigurationPage-CI4XoymK.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DKtok23W.js → EditConfigurationPage-DITVliEI.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DKtok23W.js.map → EditConfigurationPage-DITVliEI.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-CrX5Iz3h.js → EditViewPage-CUS2EAhB.js} +24 -9
- package/dist/_chunks/EditViewPage-CUS2EAhB.js.map +1 -0
- package/dist/_chunks/{EditViewPage-DGnFsrTV.mjs → EditViewPage-Dzpno8xI.mjs} +24 -9
- package/dist/_chunks/EditViewPage-Dzpno8xI.mjs.map +1 -0
- package/dist/_chunks/{Field-DlWgNyun.mjs → Field-B_jG_EV9.mjs} +134 -94
- package/dist/_chunks/Field-B_jG_EV9.mjs.map +1 -0
- package/dist/_chunks/{Field-DvDdA59J.js → Field-CtUU1Fg8.js} +136 -96
- package/dist/_chunks/Field-CtUU1Fg8.js.map +1 -0
- package/dist/_chunks/{Form-B7VJjkXr.mjs → Form-BXHao2mZ.mjs} +35 -16
- package/dist/_chunks/Form-BXHao2mZ.mjs.map +1 -0
- package/dist/_chunks/{Form-D9w2wzOa.js → Form-DTqO0ymI.js} +35 -16
- package/dist/_chunks/Form-DTqO0ymI.js.map +1 -0
- package/dist/_chunks/{History-84QY4Lau.mjs → History-2Ah2CQ4T.mjs} +4 -4
- package/dist/_chunks/{History-84QY4Lau.mjs.map → History-2Ah2CQ4T.mjs.map} +1 -1
- package/dist/_chunks/{History-GCscEVds.js → History-C_uSGzO5.js} +4 -4
- package/dist/_chunks/{History-GCscEVds.js.map → History-C_uSGzO5.js.map} +1 -1
- package/dist/_chunks/{ListConfigurationPage-C_S6OFYL.mjs → ListConfigurationPage-BjSJlaoC.mjs} +14 -4
- package/dist/_chunks/ListConfigurationPage-BjSJlaoC.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-Ck-lKA_g.js → ListConfigurationPage-nyuP7OSy.js} +14 -4
- package/dist/_chunks/ListConfigurationPage-nyuP7OSy.js.map +1 -0
- package/dist/_chunks/{ListViewPage-DkQT6AN6.mjs → ListViewPage-B75x3nz2.mjs} +40 -36
- package/dist/_chunks/ListViewPage-B75x3nz2.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-D1vAbQW4.js → ListViewPage-DHgHD8Xg.js} +43 -39
- package/dist/_chunks/ListViewPage-DHgHD8Xg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DnMToxdO.js → NoContentTypePage-CDUKdZ7d.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DnMToxdO.js.map → NoContentTypePage-CDUKdZ7d.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-D5QYn9pN.mjs → NoContentTypePage-DUacQSyF.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-D5QYn9pN.mjs.map → NoContentTypePage-DUacQSyF.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-eV9XOUs6.mjs → NoPermissionsPage-SFllMekk.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-eV9XOUs6.mjs.map → NoPermissionsPage-SFllMekk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-COirbirm.js → NoPermissionsPage-zwIZydDI.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-COirbirm.js.map → NoPermissionsPage-zwIZydDI.js.map} +1 -1
- package/dist/_chunks/{Relations-CMu33f0Q.mjs → Relations-D2NRW8fC.mjs} +14 -10
- package/dist/_chunks/Relations-D2NRW8fC.mjs.map +1 -0
- package/dist/_chunks/{Relations-CvSHeSTB.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-DYjyBm-q.mjs → index-C9HxCo5R.mjs} +1908 -1750
- package/dist/_chunks/index-C9HxCo5R.mjs.map +1 -0
- package/dist/_chunks/{index-BU73akFF.js → index-ovJRE1FM.js} +1888 -1730
- package/dist/_chunks/index-ovJRE1FM.js.map +1 -0
- package/dist/_chunks/{layout-CK49ltFD.mjs → layout-DaUjDiWQ.mjs} +8 -7
- package/dist/_chunks/layout-DaUjDiWQ.mjs.map +1 -0
- package/dist/_chunks/{layout-IJUR2XBA.js → layout-UNWstw_s.js} +8 -7
- package/dist/_chunks/layout-UNWstw_s.js.map +1 -0
- package/dist/_chunks/{relations-Dl8Jk9_i.mjs → relations-D8iFAeRu.mjs} +2 -2
- package/dist/_chunks/{relations-Dl8Jk9_i.mjs.map → relations-D8iFAeRu.mjs.map} +1 -1
- package/dist/_chunks/{relations-T1zuutNL.js → relations-NN3coOG5.js} +2 -2
- package/dist/_chunks/{relations-T1zuutNL.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 +60 -29
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +60 -29
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +1 -0
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +11 -11
- package/dist/_chunks/EditViewPage-CrX5Iz3h.js.map +0 -1
- package/dist/_chunks/EditViewPage-DGnFsrTV.mjs.map +0 -1
- package/dist/_chunks/Field-DlWgNyun.mjs.map +0 -1
- package/dist/_chunks/Field-DvDdA59J.js.map +0 -1
- package/dist/_chunks/Form-B7VJjkXr.mjs.map +0 -1
- package/dist/_chunks/Form-D9w2wzOa.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-C_S6OFYL.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-Ck-lKA_g.js.map +0 -1
- package/dist/_chunks/ListViewPage-D1vAbQW4.js.map +0 -1
- package/dist/_chunks/ListViewPage-DkQT6AN6.mjs.map +0 -1
- package/dist/_chunks/Relations-CMu33f0Q.mjs.map +0 -1
- package/dist/_chunks/Relations-CvSHeSTB.js.map +0 -1
- package/dist/_chunks/index-BU73akFF.js.map +0 -1
- package/dist/_chunks/index-DYjyBm-q.mjs.map +0 -1
- package/dist/_chunks/layout-CK49ltFD.mjs.map +0 -1
- package/dist/_chunks/layout-IJUR2XBA.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, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption,
|
6
|
+
import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
7
|
import { useIntl } from "react-intl";
|
8
|
-
import { useParams,
|
9
|
-
import { styled } from "styled-components";
|
8
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
10
9
|
import * as yup from "yup";
|
11
10
|
import { ValidationError } from "yup";
|
12
11
|
import pipe from "lodash/fp/pipe";
|
13
12
|
import { intervalToDuration, isPast } from "date-fns";
|
13
|
+
import { styled } from "styled-components";
|
14
14
|
import { stringify } from "qs";
|
15
15
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
16
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
@@ -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({
|
@@ -188,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
188
189
|
params
|
189
190
|
}
|
190
191
|
}),
|
191
|
-
invalidatesTags: (_result, _error, { model }) => [
|
192
|
+
invalidatesTags: (_result, _error, { model }) => [
|
193
|
+
{ type: "Document", id: `${model}_LIST` },
|
194
|
+
{ type: "UidAvailability", id: model }
|
195
|
+
]
|
192
196
|
}),
|
193
197
|
/**
|
194
198
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -205,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
205
209
|
}),
|
206
210
|
invalidatesTags: (result, _error, { model }) => [
|
207
211
|
{ type: "Document", id: `${model}_LIST` },
|
208
|
-
"Relations"
|
212
|
+
"Relations",
|
213
|
+
{ type: "UidAvailability", id: model }
|
209
214
|
]
|
210
215
|
}),
|
211
216
|
deleteDocument: builder.mutation({
|
@@ -246,7 +251,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
246
251
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
247
252
|
},
|
248
253
|
{ type: "Document", id: `${model}_LIST` },
|
249
|
-
"Relations"
|
254
|
+
"Relations",
|
255
|
+
{ type: "UidAvailability", id: model }
|
250
256
|
];
|
251
257
|
}
|
252
258
|
}),
|
@@ -303,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
303
309
|
{
|
304
310
|
type: "Document",
|
305
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`
|
306
317
|
}
|
307
318
|
];
|
308
319
|
}
|
@@ -366,7 +377,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
366
377
|
type: "Document",
|
367
378
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
368
379
|
},
|
369
|
-
"Relations"
|
380
|
+
"Relations",
|
381
|
+
{ type: "UidAvailability", id: model }
|
370
382
|
];
|
371
383
|
},
|
372
384
|
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
@@ -449,7 +461,7 @@ const buildValidParams = (query) => {
|
|
449
461
|
const isBaseQueryError = (error) => {
|
450
462
|
return error.name !== void 0;
|
451
463
|
};
|
452
|
-
const createYupSchema = (attributes = {}, components = {}) => {
|
464
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
453
465
|
const createModelSchema = (attributes2) => yup.object().shape(
|
454
466
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
455
467
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
@@ -462,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
462
474
|
addMinValidation,
|
463
475
|
addMaxValidation,
|
464
476
|
addRegexValidation
|
465
|
-
].map((fn) => fn(attribute));
|
477
|
+
].map((fn) => fn(attribute, options));
|
466
478
|
const transformSchema = pipe(...validations);
|
467
479
|
switch (attribute.type) {
|
468
480
|
case "component": {
|
@@ -511,7 +523,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
511
523
|
} else if (Array.isArray(value)) {
|
512
524
|
return yup.array().of(
|
513
525
|
yup.object().shape({
|
514
|
-
id: yup.
|
526
|
+
id: yup.number().required()
|
515
527
|
})
|
516
528
|
);
|
517
529
|
} else if (typeof value === "object") {
|
@@ -563,6 +575,14 @@ const createAttributeSchema = (attribute) => {
|
|
563
575
|
if (!value || typeof value === "string" && value.length === 0) {
|
564
576
|
return true;
|
565
577
|
}
|
578
|
+
if (typeof value === "object") {
|
579
|
+
try {
|
580
|
+
JSON.stringify(value);
|
581
|
+
return true;
|
582
|
+
} catch (err) {
|
583
|
+
return false;
|
584
|
+
}
|
585
|
+
}
|
566
586
|
try {
|
567
587
|
JSON.parse(value);
|
568
588
|
return true;
|
@@ -581,13 +601,7 @@ const createAttributeSchema = (attribute) => {
|
|
581
601
|
return yup.mixed();
|
582
602
|
}
|
583
603
|
};
|
584
|
-
const
|
585
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
586
|
-
return schema.min(1, translatedErrors.required);
|
587
|
-
}
|
588
|
-
if (attribute.required && attribute.type !== "relation") {
|
589
|
-
return schema.required(translatedErrors.required);
|
590
|
-
}
|
604
|
+
const nullableSchema = (schema) => {
|
591
605
|
return schema?.nullable ? schema.nullable() : (
|
592
606
|
// In some cases '.nullable' will not be available on the schema.
|
593
607
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -595,7 +609,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
595
609
|
schema
|
596
610
|
);
|
597
611
|
};
|
598
|
-
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
|
+
}
|
599
628
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
600
629
|
return schema.min(attribute.minLength, {
|
601
630
|
...translatedErrors.minLength,
|
@@ -617,11 +646,11 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
617
646
|
}
|
618
647
|
return schema;
|
619
648
|
};
|
620
|
-
const addMinValidation = (attribute) => (schema) => {
|
649
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
621
650
|
if ("min" in attribute) {
|
622
651
|
const min = toInteger(attribute.min);
|
623
652
|
if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
|
624
|
-
if (!attribute.required && "test" in schema && min) {
|
653
|
+
if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
|
625
654
|
return schema.test(
|
626
655
|
"custom-min",
|
627
656
|
{
|
@@ -760,19 +789,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
760
789
|
}, {});
|
761
790
|
return componentsByKey;
|
762
791
|
};
|
763
|
-
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);
|
764
891
|
const { toggleNotification } = useNotification();
|
765
892
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
893
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
766
894
|
const {
|
767
|
-
|
768
|
-
isLoading:
|
769
|
-
|
770
|
-
|
771
|
-
} =
|
772
|
-
|
773
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
774
|
-
});
|
775
|
-
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;
|
776
901
|
React.useEffect(() => {
|
777
902
|
if (error) {
|
778
903
|
toggleNotification({
|
@@ -780,397 +905,654 @@ const useDocument = (args, opts) => {
|
|
780
905
|
message: formatAPIError(error)
|
781
906
|
});
|
782
907
|
}
|
783
|
-
}, [
|
784
|
-
const
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
(document) => {
|
792
|
-
if (!validationSchema) {
|
793
|
-
throw new Error(
|
794
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
795
|
-
);
|
796
|
-
}
|
797
|
-
try {
|
798
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
799
|
-
return null;
|
800
|
-
} catch (error2) {
|
801
|
-
if (error2 instanceof ValidationError) {
|
802
|
-
return getYupValidationErrors(error2);
|
803
|
-
}
|
804
|
-
throw error2;
|
805
|
-
}
|
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
|
806
916
|
},
|
807
|
-
[
|
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]
|
808
933
|
);
|
809
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
810
934
|
return {
|
811
|
-
|
812
|
-
document: data?.data,
|
813
|
-
meta: data?.meta,
|
935
|
+
error,
|
814
936
|
isLoading,
|
815
|
-
|
816
|
-
|
817
|
-
};
|
818
|
-
};
|
819
|
-
const useDoc = () => {
|
820
|
-
const { id, slug, collectionType, origin } = useParams();
|
821
|
-
const [{ query }] = useQueryParams();
|
822
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
823
|
-
if (!collectionType) {
|
824
|
-
throw new Error("Could not find collectionType in url params");
|
825
|
-
}
|
826
|
-
if (!slug) {
|
827
|
-
throw new Error("Could not find model in url params");
|
828
|
-
}
|
829
|
-
return {
|
830
|
-
collectionType,
|
831
|
-
model: slug,
|
832
|
-
id: origin || id === "create" ? void 0 : id,
|
833
|
-
...useDocument(
|
834
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
835
|
-
{
|
836
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
837
|
-
}
|
838
|
-
)
|
937
|
+
edit,
|
938
|
+
list: listLayout
|
839
939
|
};
|
840
940
|
};
|
841
|
-
const
|
842
|
-
|
843
|
-
|
844
|
-
}
|
845
|
-
return Object.keys(trad).reduce((acc, current) => {
|
846
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
847
|
-
return acc;
|
848
|
-
}, {});
|
849
|
-
};
|
850
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
851
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
852
|
-
id: "notification.error",
|
853
|
-
defaultMessage: "An error occurred, please try again"
|
941
|
+
const useDocLayout = () => {
|
942
|
+
const { model } = useDoc();
|
943
|
+
return useDocumentLayout(model);
|
854
944
|
};
|
855
|
-
const
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
|
861
|
-
const
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
message: formatAPIError(res.error)
|
875
|
-
});
|
876
|
-
return { error: res.error };
|
877
|
-
}
|
878
|
-
toggleNotification({
|
879
|
-
type: "success",
|
880
|
-
message: formatMessage({
|
881
|
-
id: getTranslation("success.record.delete"),
|
882
|
-
defaultMessage: "Deleted document"
|
883
|
-
})
|
884
|
-
});
|
885
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
886
|
-
return res.data;
|
887
|
-
} catch (err) {
|
888
|
-
toggleNotification({
|
889
|
-
type: "danger",
|
890
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
891
|
-
});
|
892
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
893
|
-
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([]);
|
894
964
|
}
|
895
|
-
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
const
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
|
911
|
-
|
912
|
-
});
|
913
|
-
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
|
914
982
|
}
|
915
|
-
|
916
|
-
|
917
|
-
title: formatMessage({
|
918
|
-
id: getTranslation("success.records.delete"),
|
919
|
-
defaultMessage: "Successfully deleted."
|
920
|
-
}),
|
921
|
-
message: ""
|
922
|
-
});
|
923
|
-
trackUsage("didBulkDeleteEntries");
|
924
|
-
return res.data;
|
925
|
-
} catch (err) {
|
926
|
-
toggleNotification({
|
927
|
-
type: "danger",
|
928
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
929
|
-
});
|
930
|
-
trackUsage("didNotBulkDeleteEntries");
|
931
|
-
throw err;
|
932
|
-
}
|
983
|
+
};
|
984
|
+
return acc;
|
933
985
|
},
|
934
|
-
|
986
|
+
{}
|
935
987
|
);
|
936
|
-
const
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
model,
|
943
|
-
documentId,
|
944
|
-
params
|
945
|
-
});
|
946
|
-
if ("error" in res) {
|
947
|
-
toggleNotification({
|
948
|
-
type: "danger",
|
949
|
-
message: formatAPIError(res.error)
|
950
|
-
});
|
951
|
-
return { error: res.error };
|
952
|
-
}
|
953
|
-
toggleNotification({
|
954
|
-
type: "success",
|
955
|
-
message: formatMessage({
|
956
|
-
id: "content-manager.success.record.discard",
|
957
|
-
defaultMessage: "Changes discarded"
|
958
|
-
})
|
959
|
-
});
|
960
|
-
return res.data;
|
961
|
-
} catch (err) {
|
962
|
-
toggleNotification({
|
963
|
-
type: "danger",
|
964
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
965
|
-
});
|
966
|
-
throw err;
|
967
|
-
}
|
988
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
989
|
+
(acc, [attribute, metadata]) => {
|
990
|
+
return {
|
991
|
+
...acc,
|
992
|
+
[attribute]: metadata.edit
|
993
|
+
};
|
968
994
|
},
|
969
|
-
|
995
|
+
{}
|
970
996
|
);
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
|
978
|
-
model,
|
979
|
-
documentId,
|
980
|
-
data,
|
981
|
-
params
|
982
|
-
});
|
983
|
-
if ("error" in res) {
|
984
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
985
|
-
return { error: res.error };
|
986
|
-
}
|
987
|
-
trackUsage("didPublishEntry");
|
988
|
-
toggleNotification({
|
989
|
-
type: "success",
|
990
|
-
message: formatMessage({
|
991
|
-
id: getTranslation("success.record.publish"),
|
992
|
-
defaultMessage: "Published document"
|
993
|
-
})
|
994
|
-
});
|
995
|
-
return res.data;
|
996
|
-
} catch (err) {
|
997
|
-
toggleNotification({
|
998
|
-
type: "danger",
|
999
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1000
|
-
});
|
1001
|
-
throw err;
|
1002
|
-
}
|
997
|
+
return {
|
998
|
+
layout: panelledEditAttributes,
|
999
|
+
components: componentEditAttributes,
|
1000
|
+
metadatas: editMetadatas,
|
1001
|
+
settings: {
|
1002
|
+
...data.contentType.settings,
|
1003
|
+
displayName: schema?.info.displayName
|
1003
1004
|
},
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1017
|
-
return { error: res.error };
|
1018
|
-
}
|
1019
|
-
toggleNotification({
|
1020
|
-
type: "success",
|
1021
|
-
message: formatMessage({
|
1022
|
-
id: getTranslation("success.record.publish"),
|
1023
|
-
defaultMessage: "Published document"
|
1024
|
-
})
|
1025
|
-
});
|
1026
|
-
return res.data;
|
1027
|
-
} catch (err) {
|
1028
|
-
toggleNotification({
|
1029
|
-
type: "danger",
|
1030
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1031
|
-
});
|
1032
|
-
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;
|
1033
1018
|
}
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
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)
|
1042
1040
|
);
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
|
1052
|
-
|
1053
|
-
|
1054
|
-
|
1055
|
-
|
1056
|
-
|
1057
|
-
|
1058
|
-
|
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);
|
1059
1140
|
}
|
1060
|
-
|
1061
|
-
toggleNotification({
|
1062
|
-
type: "success",
|
1063
|
-
message: formatMessage({
|
1064
|
-
id: getTranslation("success.record.save"),
|
1065
|
-
defaultMessage: "Saved document"
|
1066
|
-
})
|
1067
|
-
});
|
1068
|
-
return res.data;
|
1069
|
-
} catch (err) {
|
1070
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1071
|
-
toggleNotification({
|
1072
|
-
type: "danger",
|
1073
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1074
|
-
});
|
1075
|
-
throw err;
|
1141
|
+
throw error2;
|
1076
1142
|
}
|
1077
1143
|
},
|
1078
|
-
[
|
1144
|
+
[validationSchema]
|
1079
1145
|
);
|
1080
|
-
const
|
1081
|
-
const
|
1082
|
-
|
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) => {
|
1083
1244
|
try {
|
1084
|
-
trackUsage("
|
1085
|
-
const res = await
|
1245
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1246
|
+
const res = await deleteDocument({
|
1086
1247
|
collectionType,
|
1087
1248
|
model,
|
1088
1249
|
documentId,
|
1089
|
-
params
|
1090
|
-
data: {
|
1091
|
-
discardDraft
|
1092
|
-
}
|
1250
|
+
params
|
1093
1251
|
});
|
1094
1252
|
if ("error" in res) {
|
1095
|
-
toggleNotification({
|
1253
|
+
toggleNotification({
|
1254
|
+
type: "danger",
|
1255
|
+
message: formatAPIError(res.error)
|
1256
|
+
});
|
1096
1257
|
return { error: res.error };
|
1097
1258
|
}
|
1098
|
-
trackUsage("didUnpublishEntry");
|
1099
1259
|
toggleNotification({
|
1100
1260
|
type: "success",
|
1101
1261
|
message: formatMessage({
|
1102
|
-
id: getTranslation("success.record.
|
1103
|
-
defaultMessage: "
|
1262
|
+
id: getTranslation("success.record.delete"),
|
1263
|
+
defaultMessage: "Deleted document"
|
1104
1264
|
})
|
1105
1265
|
});
|
1266
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1106
1267
|
return res.data;
|
1107
1268
|
} catch (err) {
|
1108
1269
|
toggleNotification({
|
1109
1270
|
type: "danger",
|
1110
1271
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1111
1272
|
});
|
1273
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1112
1274
|
throw err;
|
1113
1275
|
}
|
1114
1276
|
},
|
1115
|
-
[trackUsage,
|
1277
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1116
1278
|
);
|
1117
|
-
const [
|
1118
|
-
const
|
1279
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1280
|
+
const deleteMany = React.useCallback(
|
1119
1281
|
async ({ model, documentIds, params }) => {
|
1120
1282
|
try {
|
1121
|
-
trackUsage("
|
1122
|
-
const res = await
|
1283
|
+
trackUsage("willBulkDeleteEntries");
|
1284
|
+
const res = await deleteManyDocuments({
|
1123
1285
|
model,
|
1124
1286
|
documentIds,
|
1125
1287
|
params
|
1126
1288
|
});
|
1127
1289
|
if ("error" in res) {
|
1128
|
-
toggleNotification({
|
1290
|
+
toggleNotification({
|
1291
|
+
type: "danger",
|
1292
|
+
message: formatAPIError(res.error)
|
1293
|
+
});
|
1129
1294
|
return { error: res.error };
|
1130
1295
|
}
|
1131
|
-
trackUsage("didBulkUnpublishEntries");
|
1132
1296
|
toggleNotification({
|
1133
1297
|
type: "success",
|
1134
1298
|
title: formatMessage({
|
1135
|
-
id: getTranslation("success.records.
|
1136
|
-
defaultMessage: "Successfully
|
1299
|
+
id: getTranslation("success.records.delete"),
|
1300
|
+
defaultMessage: "Successfully deleted."
|
1137
1301
|
}),
|
1138
1302
|
message: ""
|
1139
1303
|
});
|
1304
|
+
trackUsage("didBulkDeleteEntries");
|
1140
1305
|
return res.data;
|
1141
1306
|
} catch (err) {
|
1142
1307
|
toggleNotification({
|
1143
1308
|
type: "danger",
|
1144
1309
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1145
1310
|
});
|
1146
|
-
trackUsage("
|
1311
|
+
trackUsage("didNotBulkDeleteEntries");
|
1147
1312
|
throw err;
|
1148
1313
|
}
|
1149
1314
|
},
|
1150
|
-
[trackUsage,
|
1315
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1151
1316
|
);
|
1152
|
-
const [
|
1153
|
-
const
|
1154
|
-
async ({ model, params }
|
1317
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1318
|
+
const discard = React.useCallback(
|
1319
|
+
async ({ collectionType, model, documentId, params }) => {
|
1155
1320
|
try {
|
1156
|
-
const res = await
|
1321
|
+
const res = await discardDocument({
|
1322
|
+
collectionType,
|
1157
1323
|
model,
|
1158
|
-
|
1324
|
+
documentId,
|
1159
1325
|
params
|
1160
1326
|
});
|
1161
1327
|
if ("error" in res) {
|
1162
|
-
toggleNotification({
|
1163
|
-
|
1328
|
+
toggleNotification({
|
1329
|
+
type: "danger",
|
1330
|
+
message: formatAPIError(res.error)
|
1331
|
+
});
|
1164
1332
|
return { error: res.error };
|
1165
1333
|
}
|
1166
|
-
trackUsage("didCreateEntry", trackerProperty);
|
1167
1334
|
toggleNotification({
|
1168
1335
|
type: "success",
|
1169
1336
|
message: formatMessage({
|
1170
|
-
id:
|
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,
|
1540
|
+
params
|
1541
|
+
});
|
1542
|
+
if ("error" in res) {
|
1543
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1544
|
+
trackUsage("didNotCreateEntry", { error: res.error, ...trackerProperty });
|
1545
|
+
return { error: res.error };
|
1546
|
+
}
|
1547
|
+
trackUsage("didCreateEntry", trackerProperty);
|
1548
|
+
toggleNotification({
|
1549
|
+
type: "success",
|
1550
|
+
message: formatMessage({
|
1551
|
+
id: getTranslation("success.record.save"),
|
1171
1552
|
defaultMessage: "Saved document"
|
1172
1553
|
})
|
1173
1554
|
});
|
1555
|
+
setCurrentStep("contentManager.success");
|
1174
1556
|
return res.data;
|
1175
1557
|
} catch (err) {
|
1176
1558
|
toggleNotification({
|
@@ -1210,7 +1592,7 @@ const useDocumentActions = () => {
|
|
1210
1592
|
throw err;
|
1211
1593
|
}
|
1212
1594
|
},
|
1213
|
-
[autoCloneDocument,
|
1595
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1214
1596
|
);
|
1215
1597
|
const [cloneDocument] = useCloneDocumentMutation();
|
1216
1598
|
const clone = React.useCallback(
|
@@ -1236,6 +1618,7 @@ const useDocumentActions = () => {
|
|
1236
1618
|
defaultMessage: "Cloned document"
|
1237
1619
|
})
|
1238
1620
|
});
|
1621
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1239
1622
|
return res.data;
|
1240
1623
|
} catch (err) {
|
1241
1624
|
toggleNotification({
|
@@ -1246,7 +1629,7 @@ const useDocumentActions = () => {
|
|
1246
1629
|
throw err;
|
1247
1630
|
}
|
1248
1631
|
},
|
1249
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1632
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1250
1633
|
);
|
1251
1634
|
const [getDoc] = useLazyGetDocumentQuery();
|
1252
1635
|
const getDocument = React.useCallback(
|
@@ -1272,7 +1655,7 @@ const useDocumentActions = () => {
|
|
1272
1655
|
};
|
1273
1656
|
};
|
1274
1657
|
const ProtectedHistoryPage = lazy(
|
1275
|
-
() => import("./History-
|
1658
|
+
() => import("./History-2Ah2CQ4T.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1276
1659
|
);
|
1277
1660
|
const routes$1 = [
|
1278
1661
|
{
|
@@ -1285,31 +1668,31 @@ const routes$1 = [
|
|
1285
1668
|
}
|
1286
1669
|
];
|
1287
1670
|
const ProtectedEditViewPage = lazy(
|
1288
|
-
() => import("./EditViewPage-
|
1671
|
+
() => import("./EditViewPage-Dzpno8xI.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1289
1672
|
);
|
1290
1673
|
const ProtectedListViewPage = lazy(
|
1291
|
-
() => import("./ListViewPage-
|
1674
|
+
() => import("./ListViewPage-B75x3nz2.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1292
1675
|
);
|
1293
1676
|
const ProtectedListConfiguration = lazy(
|
1294
|
-
() => import("./ListConfigurationPage-
|
1677
|
+
() => import("./ListConfigurationPage-BjSJlaoC.mjs").then((mod) => ({
|
1295
1678
|
default: mod.ProtectedListConfiguration
|
1296
1679
|
}))
|
1297
1680
|
);
|
1298
1681
|
const ProtectedEditConfigurationPage = lazy(
|
1299
|
-
() => import("./EditConfigurationPage-
|
1682
|
+
() => import("./EditConfigurationPage-CI4XoymK.mjs").then((mod) => ({
|
1300
1683
|
default: mod.ProtectedEditConfigurationPage
|
1301
1684
|
}))
|
1302
1685
|
);
|
1303
1686
|
const ProtectedComponentConfigurationPage = lazy(
|
1304
|
-
() => import("./ComponentConfigurationPage-
|
1687
|
+
() => import("./ComponentConfigurationPage-7-qB29e7.mjs").then((mod) => ({
|
1305
1688
|
default: mod.ProtectedComponentConfigurationPage
|
1306
1689
|
}))
|
1307
1690
|
);
|
1308
1691
|
const NoPermissions = lazy(
|
1309
|
-
() => import("./NoPermissionsPage-
|
1692
|
+
() => import("./NoPermissionsPage-SFllMekk.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1310
1693
|
);
|
1311
1694
|
const NoContentType = lazy(
|
1312
|
-
() => import("./NoContentTypePage-
|
1695
|
+
() => import("./NoContentTypePage-DUacQSyF.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1313
1696
|
);
|
1314
1697
|
const CollectionTypePages = () => {
|
1315
1698
|
const { collectionType } = useParams();
|
@@ -1364,1044 +1747,734 @@ const DocumentActions = ({ actions: actions2 }) => {
|
|
1364
1747
|
return true;
|
1365
1748
|
}
|
1366
1749
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
1367
|
-
return positions.includes("panel");
|
1368
|
-
});
|
1369
|
-
if (!primaryAction) {
|
1370
|
-
return null;
|
1371
|
-
}
|
1372
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1373
|
-
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
1374
|
-
/* @__PURE__ */ jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1375
|
-
restActions.length > 0 ? /* @__PURE__ */ jsx(
|
1376
|
-
DocumentActionsMenu,
|
1377
|
-
{
|
1378
|
-
actions: restActions,
|
1379
|
-
label: formatMessage({
|
1380
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1381
|
-
defaultMessage: "More document actions"
|
1382
|
-
})
|
1383
|
-
}
|
1384
|
-
) : null
|
1385
|
-
] }),
|
1386
|
-
secondaryAction ? /* @__PURE__ */ jsx(
|
1387
|
-
DocumentActionButton,
|
1388
|
-
{
|
1389
|
-
...secondaryAction,
|
1390
|
-
variant: secondaryAction.variant || "secondary"
|
1391
|
-
}
|
1392
|
-
) : null
|
1393
|
-
] });
|
1394
|
-
};
|
1395
|
-
const DocumentActionButton = (action) => {
|
1396
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1397
|
-
const { toggleNotification } = useNotification();
|
1398
|
-
const handleClick = (action2) => async (e) => {
|
1399
|
-
const { onClick = () => false, dialog, id } = action2;
|
1400
|
-
const muteDialog = await onClick(e);
|
1401
|
-
if (dialog && !muteDialog) {
|
1402
|
-
switch (dialog.type) {
|
1403
|
-
case "notification":
|
1404
|
-
toggleNotification({
|
1405
|
-
title: dialog.title,
|
1406
|
-
message: dialog.content,
|
1407
|
-
type: dialog.status,
|
1408
|
-
timeout: dialog.timeout,
|
1409
|
-
onClose: dialog.onClose
|
1410
|
-
});
|
1411
|
-
break;
|
1412
|
-
case "dialog":
|
1413
|
-
case "modal":
|
1414
|
-
e.preventDefault();
|
1415
|
-
setDialogId(id);
|
1416
|
-
}
|
1417
|
-
}
|
1418
|
-
};
|
1419
|
-
const handleClose = () => {
|
1420
|
-
setDialogId(null);
|
1421
|
-
};
|
1422
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
1423
|
-
/* @__PURE__ */ jsx(
|
1424
|
-
Button,
|
1425
|
-
{
|
1426
|
-
flex: "auto",
|
1427
|
-
startIcon: action.icon,
|
1428
|
-
disabled: action.disabled,
|
1429
|
-
onClick: handleClick(action),
|
1430
|
-
justifyContent: "center",
|
1431
|
-
variant: action.variant || "default",
|
1432
|
-
children: action.label
|
1433
|
-
}
|
1434
|
-
),
|
1435
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1436
|
-
DocumentActionConfirmDialog,
|
1437
|
-
{
|
1438
|
-
...action.dialog,
|
1439
|
-
variant: action.dialog?.variant ?? action.variant,
|
1440
|
-
isOpen: dialogId === action.id,
|
1441
|
-
onClose: handleClose
|
1442
|
-
}
|
1443
|
-
) : null,
|
1444
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1445
|
-
DocumentActionModal,
|
1446
|
-
{
|
1447
|
-
...action.dialog,
|
1448
|
-
onModalClose: handleClose,
|
1449
|
-
isOpen: dialogId === action.id
|
1450
|
-
}
|
1451
|
-
) : null
|
1452
|
-
] });
|
1453
|
-
};
|
1454
|
-
const DocumentActionsMenu = ({
|
1455
|
-
actions: actions2,
|
1456
|
-
children,
|
1457
|
-
label,
|
1458
|
-
variant = "tertiary"
|
1459
|
-
}) => {
|
1460
|
-
const [isOpen, setIsOpen] = React.useState(false);
|
1461
|
-
const [dialogId, setDialogId] = React.useState(null);
|
1462
|
-
const { formatMessage } = useIntl();
|
1463
|
-
const { toggleNotification } = useNotification();
|
1464
|
-
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1465
|
-
const handleClick = (action) => async (e) => {
|
1466
|
-
const { onClick = () => false, dialog, id } = action;
|
1467
|
-
const muteDialog = await onClick(e);
|
1468
|
-
if (dialog && !muteDialog) {
|
1469
|
-
switch (dialog.type) {
|
1470
|
-
case "notification":
|
1471
|
-
toggleNotification({
|
1472
|
-
title: dialog.title,
|
1473
|
-
message: dialog.content,
|
1474
|
-
type: dialog.status,
|
1475
|
-
timeout: dialog.timeout,
|
1476
|
-
onClose: dialog.onClose
|
1477
|
-
});
|
1478
|
-
break;
|
1479
|
-
case "dialog":
|
1480
|
-
case "modal":
|
1481
|
-
setDialogId(id);
|
1482
|
-
}
|
1483
|
-
}
|
1484
|
-
};
|
1485
|
-
const handleClose = () => {
|
1486
|
-
setDialogId(null);
|
1487
|
-
setIsOpen(false);
|
1488
|
-
};
|
1489
|
-
return /* @__PURE__ */ jsxs(Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1490
|
-
/* @__PURE__ */ jsxs(
|
1491
|
-
Menu.Trigger,
|
1492
|
-
{
|
1493
|
-
disabled: isDisabled,
|
1494
|
-
size: "S",
|
1495
|
-
endIcon: null,
|
1496
|
-
paddingTop: "4px",
|
1497
|
-
paddingLeft: "7px",
|
1498
|
-
paddingRight: "7px",
|
1499
|
-
variant,
|
1500
|
-
children: [
|
1501
|
-
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
1502
|
-
/* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1503
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1504
|
-
defaultMessage: "More document actions"
|
1505
|
-
}) })
|
1506
|
-
]
|
1507
|
-
}
|
1508
|
-
),
|
1509
|
-
/* @__PURE__ */ jsxs(Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1510
|
-
actions2.map((action) => {
|
1511
|
-
return /* @__PURE__ */ jsx(
|
1512
|
-
Menu.Item,
|
1513
|
-
{
|
1514
|
-
disabled: action.disabled,
|
1515
|
-
onSelect: handleClick(action),
|
1516
|
-
display: "block",
|
1517
|
-
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1518
|
-
/* @__PURE__ */ jsxs(
|
1519
|
-
Flex,
|
1520
|
-
{
|
1521
|
-
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1522
|
-
gap: 2,
|
1523
|
-
tag: "span",
|
1524
|
-
children: [
|
1525
|
-
/* @__PURE__ */ jsx("span", { children: action.icon }),
|
1526
|
-
action.label
|
1527
|
-
]
|
1528
|
-
}
|
1529
|
-
),
|
1530
|
-
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1531
|
-
Flex,
|
1532
|
-
{
|
1533
|
-
alignItems: "center",
|
1534
|
-
background: "alternative100",
|
1535
|
-
borderStyle: "solid",
|
1536
|
-
borderColor: "alternative200",
|
1537
|
-
borderWidth: "1px",
|
1538
|
-
height: 5,
|
1539
|
-
paddingLeft: 2,
|
1540
|
-
paddingRight: 2,
|
1541
|
-
hasRadius: true,
|
1542
|
-
color: "alternative600",
|
1543
|
-
children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1544
|
-
}
|
1545
|
-
)
|
1546
|
-
] })
|
1547
|
-
},
|
1548
|
-
action.id
|
1549
|
-
);
|
1550
|
-
}),
|
1551
|
-
children
|
1552
|
-
] }),
|
1553
|
-
actions2.map((action) => {
|
1554
|
-
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
1555
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
1556
|
-
DocumentActionConfirmDialog,
|
1557
|
-
{
|
1558
|
-
...action.dialog,
|
1559
|
-
variant: action.variant,
|
1560
|
-
isOpen: dialogId === action.id,
|
1561
|
-
onClose: handleClose
|
1562
|
-
}
|
1563
|
-
) : null,
|
1564
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
1565
|
-
DocumentActionModal,
|
1566
|
-
{
|
1567
|
-
...action.dialog,
|
1568
|
-
onModalClose: handleClose,
|
1569
|
-
isOpen: dialogId === action.id
|
1570
|
-
}
|
1571
|
-
) : null
|
1572
|
-
] }, action.id);
|
1573
|
-
})
|
1574
|
-
] });
|
1575
|
-
};
|
1576
|
-
const convertActionVariantToColor = (variant = "secondary") => {
|
1577
|
-
switch (variant) {
|
1578
|
-
case "danger":
|
1579
|
-
return "danger600";
|
1580
|
-
case "secondary":
|
1581
|
-
return void 0;
|
1582
|
-
case "success":
|
1583
|
-
return "success600";
|
1584
|
-
default:
|
1585
|
-
return "primary600";
|
1586
|
-
}
|
1587
|
-
};
|
1588
|
-
const DocumentActionConfirmDialog = ({
|
1589
|
-
onClose,
|
1590
|
-
onCancel,
|
1591
|
-
onConfirm,
|
1592
|
-
title,
|
1593
|
-
content,
|
1594
|
-
isOpen,
|
1595
|
-
variant = "secondary"
|
1596
|
-
}) => {
|
1597
|
-
const { formatMessage } = useIntl();
|
1598
|
-
const handleClose = async () => {
|
1599
|
-
if (onCancel) {
|
1600
|
-
await onCancel();
|
1601
|
-
}
|
1602
|
-
onClose();
|
1603
|
-
};
|
1604
|
-
const handleConfirm = async () => {
|
1605
|
-
if (onConfirm) {
|
1606
|
-
await onConfirm();
|
1607
|
-
}
|
1608
|
-
onClose();
|
1609
|
-
};
|
1610
|
-
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
1611
|
-
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1612
|
-
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1613
|
-
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1614
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
1615
|
-
id: "app.components.Button.cancel",
|
1616
|
-
defaultMessage: "Cancel"
|
1617
|
-
}) }) }),
|
1618
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1619
|
-
id: "app.components.Button.confirm",
|
1620
|
-
defaultMessage: "Confirm"
|
1621
|
-
}) })
|
1622
|
-
] })
|
1623
|
-
] }) });
|
1624
|
-
};
|
1625
|
-
const DocumentActionModal = ({
|
1626
|
-
isOpen,
|
1627
|
-
title,
|
1628
|
-
onClose,
|
1629
|
-
footer: Footer,
|
1630
|
-
content: Content,
|
1631
|
-
onModalClose
|
1632
|
-
}) => {
|
1633
|
-
const handleClose = () => {
|
1634
|
-
if (onClose) {
|
1635
|
-
onClose();
|
1636
|
-
}
|
1637
|
-
onModalClose();
|
1638
|
-
};
|
1639
|
-
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
1640
|
-
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
1641
|
-
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
1642
|
-
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1643
|
-
] }) });
|
1644
|
-
};
|
1645
|
-
const PublishAction$1 = ({
|
1646
|
-
activeTab,
|
1647
|
-
documentId,
|
1648
|
-
model,
|
1649
|
-
collectionType,
|
1650
|
-
meta,
|
1651
|
-
document
|
1652
|
-
}) => {
|
1653
|
-
const { schema } = useDoc();
|
1654
|
-
const navigate = useNavigate();
|
1655
|
-
const { toggleNotification } = useNotification();
|
1656
|
-
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
1657
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
1658
|
-
const { formatMessage } = useIntl();
|
1659
|
-
const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
|
1660
|
-
"PublishAction",
|
1661
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1662
|
-
);
|
1663
|
-
const { publish } = useDocumentActions();
|
1664
|
-
const [
|
1665
|
-
countDraftRelations,
|
1666
|
-
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1667
|
-
] = useLazyGetDraftRelationCountQuery();
|
1668
|
-
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
1669
|
-
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1670
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1671
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1672
|
-
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
1673
|
-
const setSubmitting = useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1674
|
-
const isSubmitting = useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1675
|
-
const validate = useForm("PublishAction", (state) => state.validate);
|
1676
|
-
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1677
|
-
const formValues = useForm("PublishAction", ({ values }) => values);
|
1678
|
-
React.useEffect(() => {
|
1679
|
-
if (isErrorDraftRelations) {
|
1680
|
-
toggleNotification({
|
1681
|
-
type: "danger",
|
1682
|
-
message: formatMessage({
|
1683
|
-
id: getTranslation("error.records.fetch-draft-relatons"),
|
1684
|
-
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1685
|
-
})
|
1686
|
-
});
|
1687
|
-
}
|
1688
|
-
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1689
|
-
React.useEffect(() => {
|
1690
|
-
const localDraftRelations = /* @__PURE__ */ new Set();
|
1691
|
-
const extractDraftRelations = (data) => {
|
1692
|
-
const relations = data.connect || [];
|
1693
|
-
relations.forEach((relation) => {
|
1694
|
-
if (relation.status === "draft") {
|
1695
|
-
localDraftRelations.add(relation.id);
|
1696
|
-
}
|
1697
|
-
});
|
1698
|
-
};
|
1699
|
-
const traverseAndExtract = (data) => {
|
1700
|
-
Object.entries(data).forEach(([key, value]) => {
|
1701
|
-
if (key === "connect" && Array.isArray(value)) {
|
1702
|
-
extractDraftRelations({ connect: value });
|
1703
|
-
} else if (typeof value === "object" && value !== null) {
|
1704
|
-
traverseAndExtract(value);
|
1705
|
-
}
|
1706
|
-
});
|
1707
|
-
};
|
1708
|
-
if (!documentId || modified) {
|
1709
|
-
traverseAndExtract(formValues);
|
1710
|
-
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1711
|
-
}
|
1712
|
-
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1713
|
-
React.useEffect(() => {
|
1714
|
-
if (documentId) {
|
1715
|
-
const fetchDraftRelationsCount = async () => {
|
1716
|
-
const { data, error } = await countDraftRelations({
|
1717
|
-
collectionType,
|
1718
|
-
model,
|
1719
|
-
documentId,
|
1720
|
-
params
|
1721
|
-
});
|
1722
|
-
if (error) {
|
1723
|
-
throw error;
|
1724
|
-
}
|
1725
|
-
if (data) {
|
1726
|
-
setServerCountOfDraftRelations(data.data);
|
1727
|
-
}
|
1728
|
-
};
|
1729
|
-
fetchDraftRelationsCount();
|
1730
|
-
}
|
1731
|
-
}, [documentId, countDraftRelations, collectionType, model, params]);
|
1732
|
-
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1733
|
-
if (!schema?.options?.draftAndPublish) {
|
1750
|
+
return positions.includes("panel");
|
1751
|
+
});
|
1752
|
+
if (!primaryAction) {
|
1734
1753
|
return null;
|
1735
1754
|
}
|
1736
|
-
|
1737
|
-
|
1738
|
-
|
1739
|
-
|
1740
|
-
|
1741
|
-
toggleNotification({
|
1742
|
-
type: "danger",
|
1743
|
-
message: formatMessage({
|
1744
|
-
id: "content-manager.validation.error",
|
1745
|
-
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1746
|
-
})
|
1747
|
-
});
|
1748
|
-
return;
|
1749
|
-
}
|
1750
|
-
const res = await publish(
|
1751
|
-
{
|
1752
|
-
collectionType,
|
1753
|
-
model,
|
1754
|
-
documentId,
|
1755
|
-
params
|
1756
|
-
},
|
1757
|
-
formValues
|
1758
|
-
);
|
1759
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1760
|
-
navigate({
|
1761
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1762
|
-
search: rawQuery
|
1763
|
-
});
|
1764
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1765
|
-
setErrors(formatValidationErrors(res.error));
|
1766
|
-
}
|
1767
|
-
} finally {
|
1768
|
-
setSubmitting(false);
|
1769
|
-
}
|
1770
|
-
};
|
1771
|
-
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1772
|
-
const hasDraftRelations = totalDraftRelations > 0;
|
1773
|
-
return {
|
1774
|
-
/**
|
1775
|
-
* Disabled when:
|
1776
|
-
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
1777
|
-
* - the form is submitting
|
1778
|
-
* - the active tab is the published tab
|
1779
|
-
* - the document is already published & not modified
|
1780
|
-
* - the document is being created & not modified
|
1781
|
-
* - the user doesn't have the permission to publish
|
1782
|
-
*/
|
1783
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1784
|
-
label: formatMessage({
|
1785
|
-
id: "app.utils.publish",
|
1786
|
-
defaultMessage: "Publish"
|
1787
|
-
}),
|
1788
|
-
onClick: async () => {
|
1789
|
-
if (hasDraftRelations) {
|
1790
|
-
return;
|
1791
|
-
}
|
1792
|
-
await performPublish();
|
1793
|
-
},
|
1794
|
-
dialog: hasDraftRelations ? {
|
1795
|
-
type: "dialog",
|
1796
|
-
variant: "danger",
|
1797
|
-
footer: null,
|
1798
|
-
title: formatMessage({
|
1799
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1800
|
-
defaultMessage: "Confirmation"
|
1801
|
-
}),
|
1802
|
-
content: formatMessage(
|
1803
|
-
{
|
1804
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1805
|
-
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1806
|
-
},
|
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,
|
1807
1760
|
{
|
1808
|
-
|
1761
|
+
actions: restActions,
|
1762
|
+
label: formatMessage({
|
1763
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1764
|
+
defaultMessage: "More document actions"
|
1765
|
+
})
|
1809
1766
|
}
|
1810
|
-
)
|
1811
|
-
|
1812
|
-
|
1767
|
+
) : null
|
1768
|
+
] }),
|
1769
|
+
secondaryAction ? /* @__PURE__ */ jsx(
|
1770
|
+
DocumentActionButton,
|
1771
|
+
{
|
1772
|
+
...secondaryAction,
|
1773
|
+
variant: secondaryAction.variant || "secondary"
|
1813
1774
|
}
|
1814
|
-
|
1815
|
-
};
|
1775
|
+
) : null
|
1776
|
+
] });
|
1816
1777
|
};
|
1817
|
-
|
1818
|
-
const
|
1819
|
-
activeTab,
|
1820
|
-
documentId,
|
1821
|
-
model,
|
1822
|
-
collectionType
|
1823
|
-
}) => {
|
1824
|
-
const navigate = useNavigate();
|
1778
|
+
const DocumentActionButton = (action) => {
|
1779
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1825
1780
|
const { toggleNotification } = useNotification();
|
1826
|
-
const
|
1827
|
-
|
1828
|
-
|
1829
|
-
|
1830
|
-
|
1831
|
-
|
1832
|
-
canUpdate: canUpdate2
|
1833
|
-
}));
|
1834
|
-
const { create, update, clone } = useDocumentActions();
|
1835
|
-
const [{ query, rawQuery }] = useQueryParams();
|
1836
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1837
|
-
const isSubmitting = useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1838
|
-
const modified = useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
1839
|
-
const setSubmitting = useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1840
|
-
const document = useForm("UpdateAction", ({ values }) => values);
|
1841
|
-
const validate = useForm("UpdateAction", (state) => state.validate);
|
1842
|
-
const setErrors = useForm("UpdateAction", (state) => state.setErrors);
|
1843
|
-
const resetForm = useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1844
|
-
return {
|
1845
|
-
/**
|
1846
|
-
* Disabled when:
|
1847
|
-
* - the form is submitting
|
1848
|
-
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1849
|
-
* - the active tab is the published tab
|
1850
|
-
*/
|
1851
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1852
|
-
label: formatMessage({
|
1853
|
-
id: "content-manager.containers.Edit.save",
|
1854
|
-
defaultMessage: "Save"
|
1855
|
-
}),
|
1856
|
-
onClick: async () => {
|
1857
|
-
setSubmitting(true);
|
1858
|
-
try {
|
1859
|
-
const { errors } = await validate();
|
1860
|
-
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":
|
1861
1787
|
toggleNotification({
|
1862
|
-
|
1863
|
-
message:
|
1864
|
-
|
1865
|
-
|
1866
|
-
|
1788
|
+
title: dialog.title,
|
1789
|
+
message: dialog.content,
|
1790
|
+
type: dialog.status,
|
1791
|
+
timeout: dialog.timeout,
|
1792
|
+
onClose: dialog.onClose
|
1867
1793
|
});
|
1868
|
-
|
1869
|
-
|
1870
|
-
|
1871
|
-
|
1872
|
-
|
1873
|
-
model,
|
1874
|
-
documentId: cloneMatch.params.origin,
|
1875
|
-
params
|
1876
|
-
},
|
1877
|
-
document
|
1878
|
-
);
|
1879
|
-
if ("data" in res) {
|
1880
|
-
navigate(
|
1881
|
-
{
|
1882
|
-
pathname: `../${res.data.documentId}`,
|
1883
|
-
search: rawQuery
|
1884
|
-
},
|
1885
|
-
{ relative: "path" }
|
1886
|
-
);
|
1887
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1888
|
-
setErrors(formatValidationErrors(res.error));
|
1889
|
-
}
|
1890
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1891
|
-
const res = await update(
|
1892
|
-
{
|
1893
|
-
collectionType,
|
1894
|
-
model,
|
1895
|
-
documentId,
|
1896
|
-
params
|
1897
|
-
},
|
1898
|
-
document
|
1899
|
-
);
|
1900
|
-
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1901
|
-
setErrors(formatValidationErrors(res.error));
|
1902
|
-
} else {
|
1903
|
-
resetForm();
|
1904
|
-
}
|
1905
|
-
} else {
|
1906
|
-
const res = await create(
|
1907
|
-
{
|
1908
|
-
model,
|
1909
|
-
params
|
1910
|
-
},
|
1911
|
-
document
|
1912
|
-
);
|
1913
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1914
|
-
navigate(
|
1915
|
-
{
|
1916
|
-
pathname: `../${res.data.documentId}`,
|
1917
|
-
search: rawQuery
|
1918
|
-
},
|
1919
|
-
{ replace: true, relative: "path" }
|
1920
|
-
);
|
1921
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1922
|
-
setErrors(formatValidationErrors(res.error));
|
1923
|
-
}
|
1924
|
-
}
|
1925
|
-
} finally {
|
1926
|
-
setSubmitting(false);
|
1794
|
+
break;
|
1795
|
+
case "dialog":
|
1796
|
+
case "modal":
|
1797
|
+
e.preventDefault();
|
1798
|
+
setDialogId(id);
|
1927
1799
|
}
|
1928
1800
|
}
|
1929
1801
|
};
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
|
1935
|
-
|
1936
|
-
|
1937
|
-
|
1938
|
-
|
1939
|
-
|
1940
|
-
|
1941
|
-
|
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
|
1835
|
+
}
|
1836
|
+
) : null
|
1837
|
+
] });
|
1838
|
+
};
|
1839
|
+
const DocumentActionsMenu = ({
|
1840
|
+
actions: actions2,
|
1841
|
+
children,
|
1842
|
+
label,
|
1843
|
+
variant = "tertiary"
|
1942
1844
|
}) => {
|
1845
|
+
const [isOpen, setIsOpen] = React.useState(false);
|
1846
|
+
const [dialogId, setDialogId] = React.useState(null);
|
1943
1847
|
const { formatMessage } = useIntl();
|
1944
|
-
const { schema } = useDoc();
|
1945
|
-
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1946
|
-
const { unpublish } = useDocumentActions();
|
1947
|
-
const [{ query }] = useQueryParams();
|
1948
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1949
1848
|
const { toggleNotification } = useNotification();
|
1950
|
-
const
|
1951
|
-
const
|
1952
|
-
|
1953
|
-
|
1954
|
-
|
1955
|
-
|
1956
|
-
|
1957
|
-
}
|
1958
|
-
return {
|
1959
|
-
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
1960
|
-
label: formatMessage({
|
1961
|
-
id: "app.utils.unpublish",
|
1962
|
-
defaultMessage: "Unpublish"
|
1963
|
-
}),
|
1964
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
1965
|
-
onClick: async () => {
|
1966
|
-
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1967
|
-
if (!documentId) {
|
1968
|
-
console.error(
|
1969
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
1970
|
-
);
|
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":
|
1971
1856
|
toggleNotification({
|
1972
|
-
|
1973
|
-
|
1974
|
-
|
1975
|
-
|
1976
|
-
|
1857
|
+
title: dialog.title,
|
1858
|
+
message: dialog.content,
|
1859
|
+
type: dialog.status,
|
1860
|
+
timeout: dialog.timeout,
|
1861
|
+
onClose: dialog.onClose
|
1977
1862
|
});
|
1978
|
-
|
1979
|
-
|
1863
|
+
break;
|
1864
|
+
case "dialog":
|
1865
|
+
case "modal":
|
1866
|
+
setDialogId(id);
|
1980
1867
|
}
|
1981
|
-
|
1982
|
-
|
1983
|
-
|
1984
|
-
|
1985
|
-
|
1986
|
-
|
1987
|
-
|
1988
|
-
|
1989
|
-
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
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"
|
2000
1890
|
}) })
|
2001
|
-
]
|
2002
|
-
|
2003
|
-
|
2004
|
-
|
2005
|
-
|
2006
|
-
|
2007
|
-
|
2008
|
-
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2009
|
-
defaultMessage: "Choose an option to unpublish the document."
|
2010
|
-
}),
|
2011
|
-
onValueChange: handleChange,
|
2012
|
-
children: [
|
2013
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2014
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2015
|
-
defaultMessage: "Keep draft"
|
2016
|
-
}) }),
|
2017
|
-
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2018
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2019
|
-
defaultMessage: "Replace draft"
|
2020
|
-
}) })
|
2021
|
-
]
|
2022
|
-
}
|
2023
|
-
)
|
2024
|
-
] }),
|
2025
|
-
onConfirm: async () => {
|
2026
|
-
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2027
|
-
console.error(
|
2028
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2029
|
-
);
|
2030
|
-
toggleNotification({
|
2031
|
-
message: formatMessage({
|
2032
|
-
id: "content-manager.actions.unpublish.error",
|
2033
|
-
defaultMessage: "An error occurred while trying to unpublish the document."
|
2034
|
-
}),
|
2035
|
-
type: "danger"
|
2036
|
-
});
|
2037
|
-
}
|
2038
|
-
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,
|
2039
1898
|
{
|
2040
|
-
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
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
|
+
] })
|
2044
1939
|
},
|
2045
|
-
|
1940
|
+
action.id
|
2046
1941
|
);
|
2047
|
-
}
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
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();
|
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
|
+
] }) });
|
2028
|
+
};
|
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();
|
2051
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
|
+
] }) });
|
2052
2048
|
};
|
2053
|
-
|
2054
|
-
const DiscardAction = ({
|
2049
|
+
const PublishAction$1 = ({
|
2055
2050
|
activeTab,
|
2056
2051
|
documentId,
|
2057
2052
|
model,
|
2058
2053
|
collectionType,
|
2054
|
+
meta,
|
2059
2055
|
document
|
2060
2056
|
}) => {
|
2061
|
-
const { formatMessage } = useIntl();
|
2062
2057
|
const { schema } = useDoc();
|
2063
|
-
const
|
2064
|
-
const {
|
2065
|
-
const
|
2066
|
-
const
|
2067
|
-
if (!schema?.options?.draftAndPublish) {
|
2068
|
-
return null;
|
2069
|
-
}
|
2070
|
-
return {
|
2071
|
-
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2072
|
-
label: formatMessage({
|
2073
|
-
id: "content-manager.actions.discard.label",
|
2074
|
-
defaultMessage: "Discard changes"
|
2075
|
-
}),
|
2076
|
-
icon: /* @__PURE__ */ jsx(StyledCrossCircle, {}),
|
2077
|
-
position: ["panel", "table-row"],
|
2078
|
-
variant: "danger",
|
2079
|
-
dialog: {
|
2080
|
-
type: "dialog",
|
2081
|
-
title: formatMessage({
|
2082
|
-
id: "app.components.ConfirmDialog.title",
|
2083
|
-
defaultMessage: "Confirmation"
|
2084
|
-
}),
|
2085
|
-
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2086
|
-
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2087
|
-
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2088
|
-
id: "content-manager.actions.discard.dialog.body",
|
2089
|
-
defaultMessage: "Are you sure?"
|
2090
|
-
}) })
|
2091
|
-
] }),
|
2092
|
-
onConfirm: async () => {
|
2093
|
-
await discard({
|
2094
|
-
collectionType,
|
2095
|
-
model,
|
2096
|
-
documentId,
|
2097
|
-
params
|
2098
|
-
});
|
2099
|
-
}
|
2100
|
-
}
|
2101
|
-
};
|
2102
|
-
};
|
2103
|
-
DiscardAction.type = "discard";
|
2104
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2105
|
-
path {
|
2106
|
-
fill: currentColor;
|
2107
|
-
}
|
2108
|
-
`;
|
2109
|
-
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2110
|
-
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2111
|
-
const RelativeTime = React.forwardRef(
|
2112
|
-
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2113
|
-
const { formatRelativeTime, formatDate, formatTime } = useIntl();
|
2114
|
-
const interval = intervalToDuration({
|
2115
|
-
start: timestamp,
|
2116
|
-
end: Date.now()
|
2117
|
-
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2118
|
-
});
|
2119
|
-
const unit = intervals.find((intervalUnit) => {
|
2120
|
-
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2121
|
-
});
|
2122
|
-
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2123
|
-
const customInterval = customIntervals.find(
|
2124
|
-
(custom) => interval[custom.unit] < custom.threshold
|
2125
|
-
);
|
2126
|
-
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2127
|
-
return /* @__PURE__ */ jsx(
|
2128
|
-
"time",
|
2129
|
-
{
|
2130
|
-
ref: forwardedRef,
|
2131
|
-
dateTime: timestamp.toISOString(),
|
2132
|
-
role: "time",
|
2133
|
-
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2134
|
-
...restProps,
|
2135
|
-
children: displayText
|
2136
|
-
}
|
2137
|
-
);
|
2138
|
-
}
|
2139
|
-
);
|
2140
|
-
const getDisplayName = ({
|
2141
|
-
firstname,
|
2142
|
-
lastname,
|
2143
|
-
username,
|
2144
|
-
email
|
2145
|
-
} = {}) => {
|
2146
|
-
if (username) {
|
2147
|
-
return username;
|
2148
|
-
}
|
2149
|
-
if (firstname) {
|
2150
|
-
return `${firstname} ${lastname ?? ""}`.trim();
|
2151
|
-
}
|
2152
|
-
return email ?? "";
|
2153
|
-
};
|
2154
|
-
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2155
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2156
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
2157
|
-
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2158
|
-
};
|
2159
|
-
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2160
|
-
const { formatMessage } = useIntl();
|
2058
|
+
const navigate = useNavigate();
|
2059
|
+
const { toggleNotification } = useNotification();
|
2060
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2061
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
2161
2062
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2162
|
-
const title = isCreating ? formatMessage({
|
2163
|
-
id: "content-manager.containers.edit.title.new",
|
2164
|
-
defaultMessage: "Create an entry"
|
2165
|
-
}) : documentTitle;
|
2166
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2167
|
-
/* @__PURE__ */ jsx(BackButton, {}),
|
2168
|
-
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2169
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2170
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2171
|
-
] }),
|
2172
|
-
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2173
|
-
] });
|
2174
|
-
};
|
2175
|
-
const HeaderToolbar = () => {
|
2176
2063
|
const { formatMessage } = useIntl();
|
2177
|
-
const
|
2064
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2065
|
+
const { publish } = useDocumentActions();
|
2178
2066
|
const [
|
2179
|
-
|
2180
|
-
|
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
|
+
});
|
2181
2089
|
}
|
2182
|
-
|
2183
|
-
|
2184
|
-
|
2185
|
-
|
2186
|
-
|
2187
|
-
|
2188
|
-
|
2189
|
-
|
2190
|
-
activeTab: status,
|
2191
|
-
model,
|
2192
|
-
documentId: id,
|
2193
|
-
document: isCloning ? void 0 : document,
|
2194
|
-
meta: isCloning ? void 0 : meta,
|
2195
|
-
collectionType
|
2196
|
-
},
|
2197
|
-
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2198
|
-
children: (actions2) => {
|
2199
|
-
if (actions2.length > 0) {
|
2200
|
-
return /* @__PURE__ */ jsx(HeaderActions, { actions: actions2 });
|
2201
|
-
} else {
|
2202
|
-
return null;
|
2203
|
-
}
|
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);
|
2204
2098
|
}
|
2205
|
-
}
|
2206
|
-
|
2207
|
-
|
2208
|
-
|
2209
|
-
|
2210
|
-
|
2211
|
-
|
2212
|
-
|
2213
|
-
documentId: id,
|
2214
|
-
document: isCloning ? void 0 : document,
|
2215
|
-
meta: isCloning ? void 0 : meta,
|
2216
|
-
collectionType
|
2217
|
-
},
|
2218
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2219
|
-
children: (actions2) => {
|
2220
|
-
const headerActions = actions2.filter((action) => {
|
2221
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2222
|
-
return positions.includes("header");
|
2223
|
-
});
|
2224
|
-
return /* @__PURE__ */ jsx(
|
2225
|
-
DocumentActionsMenu,
|
2226
|
-
{
|
2227
|
-
actions: headerActions,
|
2228
|
-
label: formatMessage({
|
2229
|
-
id: "content-manager.containers.edit.header.more-actions",
|
2230
|
-
defaultMessage: "More actions"
|
2231
|
-
}),
|
2232
|
-
children: /* @__PURE__ */ jsx(Information, { activeTab: status })
|
2233
|
-
}
|
2234
|
-
);
|
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);
|
2235
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;
|
2128
|
+
}
|
2129
|
+
if (data) {
|
2130
|
+
setServerCountOfDraftRelations(data.data);
|
2236
2131
|
}
|
2237
|
-
|
2238
|
-
|
2239
|
-
};
|
2240
|
-
const
|
2241
|
-
|
2242
|
-
const { document, meta } = useDoc();
|
2243
|
-
if (!document || !document.id) {
|
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) {
|
2244
2137
|
return null;
|
2245
2138
|
}
|
2246
|
-
const
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
|
2251
|
-
|
2252
|
-
|
2253
|
-
|
2254
|
-
|
2255
|
-
|
2256
|
-
|
2257
|
-
|
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(
|
2258
2154
|
{
|
2259
|
-
|
2260
|
-
|
2155
|
+
collectionType,
|
2156
|
+
model,
|
2157
|
+
documentId,
|
2158
|
+
params
|
2261
2159
|
},
|
2262
|
-
|
2263
|
-
|
2264
|
-
|
2265
|
-
|
2266
|
-
|
2267
|
-
|
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();
|
2268
2194
|
},
|
2269
|
-
{
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2273
|
-
|
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"
|
2274
2202
|
}),
|
2275
|
-
|
2203
|
+
content: formatMessage(
|
2276
2204
|
{
|
2277
|
-
id:
|
2278
|
-
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."
|
2279
2207
|
},
|
2280
2208
|
{
|
2281
|
-
|
2282
|
-
RelativeTime,
|
2283
|
-
{
|
2284
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2285
|
-
}
|
2286
|
-
),
|
2287
|
-
isAnonymous: !updator,
|
2288
|
-
author: updator
|
2209
|
+
count: totalDraftRelations
|
2289
2210
|
}
|
2290
|
-
)
|
2291
|
-
|
2292
|
-
|
2293
|
-
|
2294
|
-
|
2295
|
-
|
2296
|
-
|
2297
|
-
|
2298
|
-
|
2299
|
-
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2304
|
-
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
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
|
+
}
|
2312
2268
|
}
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2321
|
-
|
2322
|
-
|
2323
|
-
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2328
|
-
|
2329
|
-
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2334
|
-
|
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
|
+
}
|
2335
2327
|
}
|
2336
|
-
|
2328
|
+
};
|
2337
2329
|
};
|
2338
|
-
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2342
|
-
SingleSelect,
|
2343
|
-
{
|
2344
|
-
size: "S",
|
2345
|
-
disabled: action.disabled,
|
2346
|
-
"aria-label": action.label,
|
2347
|
-
onChange: action.onSelect,
|
2348
|
-
value: action.value,
|
2349
|
-
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2350
|
-
},
|
2351
|
-
action.id
|
2352
|
-
);
|
2353
|
-
} else {
|
2354
|
-
return null;
|
2355
|
-
}
|
2356
|
-
}) });
|
2330
|
+
UpdateAction.type = "update";
|
2331
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2332
|
+
KEEP: "keep",
|
2333
|
+
DISCARD: "discard"
|
2357
2334
|
};
|
2358
|
-
const
|
2359
|
-
|
2335
|
+
const UnpublishAction$1 = ({
|
2336
|
+
activeTab,
|
2337
|
+
documentId,
|
2338
|
+
model,
|
2339
|
+
collectionType,
|
2340
|
+
document
|
2341
|
+
}) => {
|
2360
2342
|
const { formatMessage } = useIntl();
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
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);
|
2371
2353
|
};
|
2372
|
-
|
2373
|
-
|
2374
|
-
|
2375
|
-
const navigate = useNavigate();
|
2376
|
-
const { formatMessage } = useIntl();
|
2354
|
+
if (!schema?.options?.draftAndPublish) {
|
2355
|
+
return null;
|
2356
|
+
}
|
2377
2357
|
return {
|
2358
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2378
2359
|
label: formatMessage({
|
2379
|
-
id: "
|
2380
|
-
defaultMessage: "
|
2360
|
+
id: "app.utils.unpublish",
|
2361
|
+
defaultMessage: "Unpublish"
|
2381
2362
|
}),
|
2382
|
-
icon: /* @__PURE__ */ jsx(
|
2383
|
-
onClick: () => {
|
2384
|
-
|
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
|
+
});
|
2385
2386
|
},
|
2386
|
-
|
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"]
|
2387
2450
|
};
|
2388
2451
|
};
|
2389
|
-
|
2390
|
-
const
|
2391
|
-
|
2452
|
+
UnpublishAction$1.type = "unpublish";
|
2453
|
+
const DiscardAction = ({
|
2454
|
+
activeTab,
|
2455
|
+
documentId,
|
2456
|
+
model,
|
2457
|
+
collectionType,
|
2458
|
+
document
|
2459
|
+
}) => {
|
2392
2460
|
const { formatMessage } = useIntl();
|
2393
|
-
const
|
2394
|
-
const
|
2395
|
-
const {
|
2396
|
-
const {
|
2397
|
-
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
|
+
}
|
2398
2469
|
return {
|
2399
|
-
disabled: !
|
2470
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2400
2471
|
label: formatMessage({
|
2401
|
-
id: "content-manager.actions.
|
2402
|
-
defaultMessage: "
|
2472
|
+
id: "content-manager.actions.discard.label",
|
2473
|
+
defaultMessage: "Discard changes"
|
2403
2474
|
}),
|
2404
|
-
icon: /* @__PURE__ */ jsx(
|
2475
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2476
|
+
position: ["panel", "table-row"],
|
2477
|
+
variant: "danger",
|
2405
2478
|
dialog: {
|
2406
2479
|
type: "dialog",
|
2407
2480
|
title: formatMessage({
|
@@ -2411,92 +2484,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2411
2484
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
|
2412
2485
|
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2413
2486
|
/* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2414
|
-
id: "content-manager.actions.
|
2487
|
+
id: "content-manager.actions.discard.dialog.body",
|
2415
2488
|
defaultMessage: "Are you sure?"
|
2416
2489
|
}) })
|
2417
2490
|
] }),
|
2418
2491
|
onConfirm: async () => {
|
2419
|
-
|
2420
|
-
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2431
|
-
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
|
2436
|
-
|
2437
|
-
|
2438
|
-
|
2439
|
-
|
2440
|
-
|
2441
|
-
|
2442
|
-
|
2443
|
-
|
2444
|
-
|
2445
|
-
|
2446
|
-
|
2447
|
-
|
2448
|
-
|
2449
|
-
|
2450
|
-
|
2451
|
-
|
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
|
2452
2530
|
}
|
2453
|
-
|
2454
|
-
|
2455
|
-
|
2456
|
-
|
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 ?? "";
|
2457
2547
|
};
|
2458
|
-
|
2459
|
-
const
|
2460
|
-
const
|
2461
|
-
|
2462
|
-
const [
|
2463
|
-
{
|
2464
|
-
query: { status }
|
2465
|
-
}
|
2466
|
-
] = useQueryParams({
|
2467
|
-
status: "draft"
|
2468
|
-
});
|
2469
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2470
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2471
|
-
const props = {
|
2472
|
-
activeTab: status,
|
2473
|
-
model,
|
2474
|
-
documentId: id,
|
2475
|
-
document: isCloning ? void 0 : document,
|
2476
|
-
meta: isCloning ? void 0 : meta,
|
2477
|
-
collectionType
|
2478
|
-
};
|
2479
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2480
|
-
DescriptionComponentRenderer,
|
2481
|
-
{
|
2482
|
-
props,
|
2483
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2484
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2485
|
-
}
|
2486
|
-
) });
|
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) }) });
|
2487
2552
|
};
|
2488
|
-
const
|
2553
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2489
2554
|
const { formatMessage } = useIntl();
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
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
|
+
] });
|
2497
2568
|
};
|
2498
|
-
|
2499
|
-
const
|
2569
|
+
const HeaderToolbar = () => {
|
2570
|
+
const { formatMessage } = useIntl();
|
2500
2571
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2501
2572
|
const [
|
2502
2573
|
{
|
@@ -2504,355 +2575,432 @@ const ActionsPanelContent = () => {
|
|
2504
2575
|
}
|
2505
2576
|
] = useQueryParams();
|
2506
2577
|
const { model, id, document, meta, collectionType } = useDoc();
|
2507
|
-
const plugins = useStrapiApp("
|
2508
|
-
|
2509
|
-
activeTab: status,
|
2510
|
-
model,
|
2511
|
-
documentId: id,
|
2512
|
-
document: isCloning ? void 0 : document,
|
2513
|
-
meta: isCloning ? void 0 : meta,
|
2514
|
-
collectionType
|
2515
|
-
};
|
2516
|
-
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: [
|
2517
2580
|
/* @__PURE__ */ jsx(
|
2518
2581
|
DescriptionComponentRenderer,
|
2519
2582
|
{
|
2520
|
-
props
|
2521
|
-
|
2522
|
-
|
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
|
+
}
|
2523
2599
|
}
|
2524
2600
|
),
|
2525
|
-
/* @__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
|
+
)
|
2526
2632
|
] });
|
2527
2633
|
};
|
2528
|
-
const
|
2529
|
-
|
2530
|
-
|
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 = [
|
2531
2645
|
{
|
2532
|
-
|
2533
|
-
|
2534
|
-
|
2535
|
-
|
2536
|
-
borderColor: "neutral150",
|
2537
|
-
hasRadius: true,
|
2538
|
-
paddingBottom: 4,
|
2539
|
-
paddingLeft: 4,
|
2540
|
-
paddingRight: 4,
|
2541
|
-
paddingTop: 4,
|
2542
|
-
shadow: "tableShadow",
|
2543
|
-
gap: 3,
|
2544
|
-
direction: "column",
|
2545
|
-
justifyContent: "stretch",
|
2546
|
-
alignItems: "flex-start",
|
2547
|
-
children: [
|
2548
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2549
|
-
children
|
2550
|
-
]
|
2551
|
-
}
|
2552
|
-
);
|
2553
|
-
});
|
2554
|
-
const HOOKS = {
|
2555
|
-
/**
|
2556
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2557
|
-
* @constant
|
2558
|
-
* @type {string}
|
2559
|
-
*/
|
2560
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2561
|
-
/**
|
2562
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2563
|
-
* @constant
|
2564
|
-
* @type {string}
|
2565
|
-
*/
|
2566
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2567
|
-
/**
|
2568
|
-
* Hook that allows to mutate the CM's edit view layout
|
2569
|
-
* @constant
|
2570
|
-
* @type {string}
|
2571
|
-
*/
|
2572
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2573
|
-
/**
|
2574
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2575
|
-
* @constant
|
2576
|
-
* @type {string}
|
2577
|
-
*/
|
2578
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2579
|
-
};
|
2580
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2581
|
-
endpoints: (builder) => ({
|
2582
|
-
getContentTypeConfiguration: builder.query({
|
2583
|
-
query: (uid) => ({
|
2584
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2585
|
-
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"
|
2586
2650
|
}),
|
2587
|
-
|
2588
|
-
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2596
|
-
|
2597
|
-
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
2601
|
-
|
2602
|
-
|
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"
|
2603
2691
|
}),
|
2604
|
-
|
2605
|
-
|
2606
|
-
|
2607
|
-
|
2608
|
-
|
2609
|
-
{
|
2610
|
-
|
2611
|
-
|
2612
|
-
|
2613
|
-
|
2614
|
-
|
2615
|
-
|
2616
|
-
|
2617
|
-
|
2618
|
-
}
|
2619
|
-
|
2620
|
-
|
2621
|
-
|
2622
|
-
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
|
2631
|
-
|
2632
|
-
|
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
|
+
}
|
2633
2730
|
);
|
2634
|
-
return {
|
2635
|
-
name: mainFieldName,
|
2636
|
-
type: mainFieldType ?? "string"
|
2637
|
-
};
|
2638
|
-
};
|
2639
|
-
const DEFAULT_SETTINGS = {
|
2640
|
-
bulkable: false,
|
2641
|
-
filterable: false,
|
2642
|
-
searchable: false,
|
2643
|
-
pagination: false,
|
2644
|
-
defaultSortBy: "",
|
2645
|
-
defaultSortOrder: "asc",
|
2646
|
-
mainField: "id",
|
2647
|
-
pageSize: 10
|
2648
2731
|
};
|
2649
|
-
const
|
2650
|
-
const
|
2651
|
-
const
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
2658
|
-
|
2659
|
-
error,
|
2660
|
-
isFetching: isFetchingConfigs
|
2661
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2662
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2663
|
-
React.useEffect(() => {
|
2664
|
-
if (error) {
|
2665
|
-
toggleNotification({
|
2666
|
-
type: "danger",
|
2667
|
-
message: formatAPIError(error)
|
2668
|
-
});
|
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
|
+
}
|
2669
2742
|
}
|
2670
|
-
}, [error, formatAPIError, toggleNotification]);
|
2671
|
-
const editLayout = React.useMemo(
|
2672
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2673
|
-
layout: [],
|
2674
|
-
components: {},
|
2675
|
-
metadatas: {},
|
2676
|
-
options: {},
|
2677
|
-
settings: DEFAULT_SETTINGS
|
2678
|
-
},
|
2679
|
-
[data, isLoading, schemas, schema, components]
|
2680
|
-
);
|
2681
|
-
const listLayout = React.useMemo(() => {
|
2682
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2683
|
-
layout: [],
|
2684
|
-
metadatas: {},
|
2685
|
-
options: {},
|
2686
|
-
settings: DEFAULT_SETTINGS
|
2687
|
-
};
|
2688
|
-
}, [data, isLoading, schemas, schema, components]);
|
2689
|
-
const { layout: edit } = React.useMemo(
|
2690
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2691
|
-
layout: editLayout,
|
2692
|
-
query
|
2693
|
-
}),
|
2694
|
-
[editLayout, query, runHookWaterfall]
|
2695
|
-
);
|
2696
|
-
return {
|
2697
|
-
error,
|
2698
|
-
isLoading,
|
2699
|
-
edit,
|
2700
|
-
list: listLayout
|
2701
2743
|
};
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
return
|
2706
|
-
|
2707
|
-
|
2708
|
-
|
2709
|
-
|
2710
|
-
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
schemas
|
2719
|
-
).reduce((panels, row) => {
|
2720
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2721
|
-
panels.push([row]);
|
2722
|
-
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
|
+
);
|
2723
2760
|
} else {
|
2724
|
-
if (
|
2725
|
-
|
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);
|
2726
2782
|
}
|
2727
|
-
panels[currentPanelIndex].push(row);
|
2728
2783
|
}
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
|
2738
|
-
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
}
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
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`);
|
2755
2815
|
},
|
2756
|
-
|
2757
|
-
|
2816
|
+
position: "header"
|
2817
|
+
};
|
2818
|
+
};
|
2819
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2820
|
+
const EditTheModelAction = ({ model }) => {
|
2821
|
+
const navigate = useNavigate();
|
2822
|
+
const { formatMessage } = useIntl();
|
2758
2823
|
return {
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
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}`);
|
2765
2831
|
},
|
2766
|
-
|
2767
|
-
...schema?.options,
|
2768
|
-
...schema?.pluginOptions,
|
2769
|
-
...data.contentType.options
|
2770
|
-
}
|
2832
|
+
position: "header"
|
2771
2833
|
};
|
2772
2834
|
};
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
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
|
+
}
|
2779
2902
|
}
|
2780
|
-
const { edit: metadata } = metadatas[field.name];
|
2781
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2782
|
-
return {
|
2783
|
-
attribute,
|
2784
|
-
disabled: !metadata.editable,
|
2785
|
-
hint: metadata.description,
|
2786
|
-
label: metadata.label ?? "",
|
2787
|
-
name: field.name,
|
2788
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2789
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2790
|
-
schemas,
|
2791
|
-
components: components?.schemas ?? {}
|
2792
|
-
}),
|
2793
|
-
placeholder: metadata.placeholder ?? "",
|
2794
|
-
required: attribute.required ?? false,
|
2795
|
-
size: field.size,
|
2796
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2797
|
-
visible: metadata.visible ?? true,
|
2798
|
-
type: attribute.type
|
2799
|
-
};
|
2800
|
-
}).filter((field) => field !== null)
|
2801
|
-
);
|
2802
|
-
};
|
2803
|
-
const formatListLayout = (data, {
|
2804
|
-
schemas,
|
2805
|
-
schema,
|
2806
|
-
components
|
2807
|
-
}) => {
|
2808
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2809
|
-
(acc, [attribute, metadata]) => {
|
2810
|
-
return {
|
2811
|
-
...acc,
|
2812
|
-
[attribute]: metadata.list
|
2813
|
-
};
|
2814
2903
|
},
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2820
|
-
|
2821
|
-
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2825
|
-
|
2826
|
-
|
2827
|
-
|
2828
|
-
|
2829
|
-
|
2830
|
-
|
2831
|
-
|
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))
|
2832
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, {})
|
2833
2946
|
};
|
2834
2947
|
};
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
2839
|
-
|
2948
|
+
ActionsPanel.type = "actions";
|
2949
|
+
const ActionsPanelContent = () => {
|
2950
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2951
|
+
const [
|
2952
|
+
{
|
2953
|
+
query: { status = "draft" }
|
2840
2954
|
}
|
2841
|
-
|
2842
|
-
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2847
|
-
|
2848
|
-
|
2849
|
-
|
2850
|
-
|
2851
|
-
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
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
|
+
] });
|
2855
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
|
+
});
|
2856
3004
|
const ConfirmBulkActionDialog = ({
|
2857
3005
|
onToggleDialog,
|
2858
3006
|
isOpen = false,
|
@@ -2891,6 +3039,7 @@ const ConfirmDialogPublishAll = ({
|
|
2891
3039
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2892
3040
|
const { model, schema } = useDoc();
|
2893
3041
|
const [{ query }] = useQueryParams();
|
3042
|
+
const enableDraftRelationsCount = false;
|
2894
3043
|
const {
|
2895
3044
|
data: countDraftRelations = 0,
|
2896
3045
|
isLoading,
|
@@ -2902,7 +3051,7 @@ const ConfirmDialogPublishAll = ({
|
|
2902
3051
|
locale: query?.plugins?.i18n?.locale
|
2903
3052
|
},
|
2904
3053
|
{
|
2905
|
-
skip:
|
3054
|
+
skip: !enableDraftRelationsCount
|
2906
3055
|
}
|
2907
3056
|
);
|
2908
3057
|
React.useEffect(() => {
|
@@ -3087,7 +3236,7 @@ const SelectedEntriesTableContent = ({
|
|
3087
3236
|
status: row.status
|
3088
3237
|
}
|
3089
3238
|
) }),
|
3090
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3239
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3091
3240
|
IconButton,
|
3092
3241
|
{
|
3093
3242
|
tag: Link,
|
@@ -3110,9 +3259,10 @@ const SelectedEntriesTableContent = ({
|
|
3110
3259
|
),
|
3111
3260
|
target: "_blank",
|
3112
3261
|
marginLeft: "auto",
|
3113
|
-
|
3262
|
+
variant: "ghost",
|
3263
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3114
3264
|
}
|
3115
|
-
) })
|
3265
|
+
) }) })
|
3116
3266
|
] }, row.id)) })
|
3117
3267
|
] });
|
3118
3268
|
};
|
@@ -3149,7 +3299,13 @@ const SelectedEntriesModalContent = ({
|
|
3149
3299
|
);
|
3150
3300
|
const { rows, validationErrors } = React.useMemo(() => {
|
3151
3301
|
if (data.length > 0 && schema) {
|
3152
|
-
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
|
+
);
|
3153
3309
|
const validationErrors2 = {};
|
3154
3310
|
const rows2 = data.map((entry) => {
|
3155
3311
|
try {
|
@@ -3499,7 +3655,7 @@ const TableActions = ({ document }) => {
|
|
3499
3655
|
DescriptionComponentRenderer,
|
3500
3656
|
{
|
3501
3657
|
props,
|
3502
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3658
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3503
3659
|
children: (actions2) => {
|
3504
3660
|
const tableRowActions = actions2.filter((action) => {
|
3505
3661
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3610,7 +3766,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3610
3766
|
}),
|
3611
3767
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3612
3768
|
footer: ({ onClose }) => {
|
3613
|
-
return /* @__PURE__ */ jsxs(
|
3769
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3614
3770
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3615
3771
|
id: "cancel",
|
3616
3772
|
defaultMessage: "Cancel"
|
@@ -3841,7 +3997,7 @@ const index = {
|
|
3841
3997
|
app.router.addRoute({
|
3842
3998
|
path: "content-manager/*",
|
3843
3999
|
lazy: async () => {
|
3844
|
-
const { Layout } = await import("./layout-
|
4000
|
+
const { Layout } = await import("./layout-DaUjDiWQ.mjs");
|
3845
4001
|
return {
|
3846
4002
|
Component: Layout
|
3847
4003
|
};
|
@@ -3858,7 +4014,7 @@ const index = {
|
|
3858
4014
|
async registerTrads({ locales }) {
|
3859
4015
|
const importedTrads = await Promise.all(
|
3860
4016
|
locales.map((locale) => {
|
3861
|
-
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 }) => {
|
3862
4018
|
return {
|
3863
4019
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3864
4020
|
locale
|
@@ -3879,13 +4035,15 @@ export {
|
|
3879
4035
|
BulkActionsRenderer as B,
|
3880
4036
|
COLLECTION_TYPES as C,
|
3881
4037
|
DocumentStatus as D,
|
3882
|
-
|
3883
|
-
|
3884
|
-
|
4038
|
+
extractContentTypeComponents as E,
|
4039
|
+
DEFAULT_SETTINGS as F,
|
4040
|
+
convertEditLayoutToFieldLayouts as G,
|
3885
4041
|
HOOKS as H,
|
3886
4042
|
InjectionZone as I,
|
3887
|
-
|
3888
|
-
|
4043
|
+
useDocument as J,
|
4044
|
+
index as K,
|
4045
|
+
useContentManagerContext as L,
|
4046
|
+
useDocumentActions as M,
|
3889
4047
|
Panels as P,
|
3890
4048
|
RelativeTime as R,
|
3891
4049
|
SINGLE_TYPES as S,
|
@@ -3903,18 +4061,18 @@ export {
|
|
3903
4061
|
PERMISSIONS as k,
|
3904
4062
|
DocumentRBAC as l,
|
3905
4063
|
DOCUMENT_META_FIELDS as m,
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
3909
|
-
|
3910
|
-
|
4064
|
+
CLONE_PATH as n,
|
4065
|
+
useDocLayout as o,
|
4066
|
+
useGetContentTypeConfigurationQuery as p,
|
4067
|
+
CREATOR_FIELDS as q,
|
4068
|
+
getMainField as r,
|
3911
4069
|
setInitialData as s,
|
3912
|
-
|
4070
|
+
getDisplayName as t,
|
3913
4071
|
useContentTypeSchema as u,
|
3914
|
-
|
3915
|
-
|
3916
|
-
|
3917
|
-
|
3918
|
-
|
4072
|
+
checkIfAttributeIsDisplayable as v,
|
4073
|
+
useGetAllDocumentsQuery as w,
|
4074
|
+
convertListLayoutToFieldLayouts as x,
|
4075
|
+
capitalise as y,
|
4076
|
+
useUpdateContentTypeConfigurationMutation as z
|
3919
4077
|
};
|
3920
|
-
//# sourceMappingURL=index-
|
4078
|
+
//# sourceMappingURL=index-C9HxCo5R.mjs.map
|