@strapi/content-manager 0.0.0-experimental.dd3311938ac827f1fa8560c8840a9a394f5896c0 → 0.0.0-experimental.e02b4637b3906c6d31048d00600d09a23a0edc3d
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/LICENSE +18 -3
- package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs → ComponentConfigurationPage-DfFSZQxe.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-BMajAl1u.mjs.map → ComponentConfigurationPage-DfFSZQxe.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js → ComponentConfigurationPage-FqfsxQ1j.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-y_7iLdmB.js.map → ComponentConfigurationPage-FqfsxQ1j.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js → EditConfigurationPage-Cn0e8t3I.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CPVB8Uqc.js.map → EditConfigurationPage-Cn0e8t3I.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs → EditConfigurationPage-DdPNAbl3.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CcOoD26O.mjs.map → EditConfigurationPage-DdPNAbl3.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DWb0DE7R.mjs → EditViewPage-B82x_x1b.mjs} +69 -48
- package/dist/_chunks/EditViewPage-B82x_x1b.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-CTTDHKkQ.js → EditViewPage-DlxEHhUt.js} +68 -47
- package/dist/_chunks/EditViewPage-DlxEHhUt.js.map +1 -0
- package/dist/_chunks/{Field-C5Z1Ivdv.js → Field-COL25JiC.js} +581 -229
- package/dist/_chunks/Field-COL25JiC.js.map +1 -0
- package/dist/_chunks/{Field-DnStdvQw.mjs → Field-DufHXW17.mjs} +579 -227
- package/dist/_chunks/Field-DufHXW17.mjs.map +1 -0
- package/dist/_chunks/{Form-B81OtW-k.js → Form-BssUwrTO.js} +52 -34
- package/dist/_chunks/Form-BssUwrTO.js.map +1 -0
- package/dist/_chunks/{Form-DqGgE55Q.mjs → Form-u_kAOhwB.mjs} +54 -36
- package/dist/_chunks/Form-u_kAOhwB.mjs.map +1 -0
- package/dist/_chunks/{History-4NbOq2dX.js → History-C9t9UqpO.js} +68 -32
- package/dist/_chunks/History-C9t9UqpO.js.map +1 -0
- package/dist/_chunks/{History-DS6-HCYX.mjs → History-DRwA3oMM.mjs} +69 -33
- package/dist/_chunks/History-DRwA3oMM.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CpfstlYY.js → ListConfigurationPage-BXYPohh-.js} +57 -46
- package/dist/_chunks/ListConfigurationPage-BXYPohh-.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DQJJltko.mjs → ListConfigurationPage-BxfQJzPk.mjs} +58 -48
- package/dist/_chunks/ListConfigurationPage-BxfQJzPk.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-nQrOQuVo.mjs → ListViewPage-CELx2ysp.mjs} +103 -102
- package/dist/_chunks/ListViewPage-CELx2ysp.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CA3I75m5.js → ListViewPage-D2VD8Szg.js} +105 -104
- package/dist/_chunks/ListViewPage-D2VD8Szg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js → NoContentTypePage-BV9IjJSM.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-Dldu-_Mx.js.map → NoContentTypePage-BV9IjJSM.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs → NoContentTypePage-DtJ9jcfk.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-DbnHE22g.mjs.map → NoContentTypePage-DtJ9jcfk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs → NoPermissionsPage-DWleVYK7.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-fOIkQM0v.mjs.map → NoPermissionsPage-DWleVYK7.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CO2MK200.js → NoPermissionsPage-Dp8NpF9I.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CO2MK200.js.map → NoPermissionsPage-Dp8NpF9I.js.map} +1 -1
- package/dist/_chunks/{Relations-BDRl99Ux.mjs → Relations-BTcf5xaw.mjs} +33 -24
- package/dist/_chunks/Relations-BTcf5xaw.mjs.map +1 -0
- package/dist/_chunks/{Relations-DG2jnOcr.js → Relations-DR7EUgyC.js} +33 -24
- package/dist/_chunks/Relations-DR7EUgyC.js.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-Bm0D0IWz.js} +17 -15
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-DKV44jRb.mjs} +17 -15
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-BZoNZMXL.js → index-BdMf2lfT.js} +1015 -862
- package/dist/_chunks/index-BdMf2lfT.js.map +1 -0
- package/dist/_chunks/{index-Drt2DN7v.mjs → index-wnqzm4Q8.mjs} +1025 -872
- package/dist/_chunks/index-wnqzm4Q8.mjs.map +1 -0
- package/dist/_chunks/{layout-BzAbmoO6.mjs → layout-2CfjL0T9.mjs} +27 -14
- package/dist/_chunks/layout-2CfjL0T9.mjs.map +1 -0
- package/dist/_chunks/{layout-DEYBqgF1.js → layout-B2MyZU-_.js} +25 -12
- package/dist/_chunks/layout-B2MyZU-_.js.map +1 -0
- package/dist/_chunks/{relations-D0eZ4VWw.js → relations-BH7JJGGe.js} +2 -2
- package/dist/_chunks/{relations-D0eZ4VWw.js.map → relations-BH7JJGGe.js.map} +1 -1
- package/dist/_chunks/{relations-D26zVRdi.mjs → relations-C0w0GcXi.mjs} +2 -2
- package/dist/_chunks/{relations-D26zVRdi.mjs.map → relations-C0w0GcXi.mjs.map} +1 -1
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +3 -2
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- 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/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +8 -3
- package/dist/admin/src/pages/EditView/components/FormInputs/BlocksInput/utils/constants.d.ts +4 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- 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 +6 -58
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/pages/ListView/components/BulkActions/Actions.d.ts +3 -30
- package/dist/admin/src/pages/ListView/components/BulkActions/ConfirmBulkActionDialog.d.ts +2 -2
- 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 +208 -123
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +209 -124
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/_chunks/EditViewPage-CTTDHKkQ.js.map +0 -1
- package/dist/_chunks/EditViewPage-DWb0DE7R.mjs.map +0 -1
- package/dist/_chunks/Field-C5Z1Ivdv.js.map +0 -1
- package/dist/_chunks/Field-DnStdvQw.mjs.map +0 -1
- package/dist/_chunks/Form-B81OtW-k.js.map +0 -1
- package/dist/_chunks/Form-DqGgE55Q.mjs.map +0 -1
- package/dist/_chunks/History-4NbOq2dX.js.map +0 -1
- package/dist/_chunks/History-DS6-HCYX.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-CpfstlYY.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DQJJltko.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-CA3I75m5.js.map +0 -1
- package/dist/_chunks/ListViewPage-nQrOQuVo.mjs.map +0 -1
- package/dist/_chunks/Relations-BDRl99Ux.mjs.map +0 -1
- package/dist/_chunks/Relations-DG2jnOcr.js.map +0 -1
- package/dist/_chunks/index-BZoNZMXL.js.map +0 -1
- package/dist/_chunks/index-Drt2DN7v.mjs.map +0 -1
- package/dist/_chunks/layout-BzAbmoO6.mjs.map +0 -1
- package/dist/_chunks/layout-DEYBqgF1.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,17 +1,17 @@
|
|
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,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
7
4
|
import * as React from "react";
|
8
5
|
import { lazy } from "react";
|
9
|
-
import { Menu, VisuallyHidden, Flex, Typography, Dialog,
|
10
|
-
import {
|
6
|
+
import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import { useIntl } from "react-intl";
|
8
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
11
9
|
import * as yup from "yup";
|
12
10
|
import { ValidationError } from "yup";
|
13
11
|
import pipe from "lodash/fp/pipe";
|
14
12
|
import { intervalToDuration, isPast } from "date-fns";
|
13
|
+
import { styled } from "styled-components";
|
14
|
+
import { stringify } from "qs";
|
15
15
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
16
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
17
|
const v = glob[path];
|
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
|
|
49
49
|
const [page, position] = area.split(".");
|
50
50
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
51
51
|
};
|
52
|
-
const HistoryAction = ({ model, document }) => {
|
53
|
-
const { formatMessage } = useIntl();
|
54
|
-
const [{ query }] = useQueryParams();
|
55
|
-
const navigate = useNavigate();
|
56
|
-
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
57
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
58
|
-
return null;
|
59
|
-
}
|
60
|
-
return {
|
61
|
-
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
62
|
-
label: formatMessage({
|
63
|
-
id: "content-manager.history.document-action",
|
64
|
-
defaultMessage: "Content History"
|
65
|
-
}),
|
66
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
67
|
-
disabled: (
|
68
|
-
/**
|
69
|
-
* The user is creating a new document.
|
70
|
-
* It hasn't been saved yet, so there's no history to go to
|
71
|
-
*/
|
72
|
-
!document || /**
|
73
|
-
* The document has been created but the current dimension has never been saved.
|
74
|
-
* For example, the user is creating a new locale in an existing document,
|
75
|
-
* so there's no history for the document in that locale
|
76
|
-
*/
|
77
|
-
!document.id || /**
|
78
|
-
* History is only available for content types created by the user.
|
79
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
80
|
-
* which start with `admin::` or `plugin::`
|
81
|
-
*/
|
82
|
-
!model.startsWith("api::")
|
83
|
-
),
|
84
|
-
position: "header"
|
85
|
-
};
|
86
|
-
};
|
87
|
-
HistoryAction.type = "history";
|
88
52
|
const ID = "id";
|
89
53
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
90
54
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -136,6 +100,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
136
100
|
if (!slug) {
|
137
101
|
throw new Error("Cannot find the slug param in the URL");
|
138
102
|
}
|
103
|
+
const [{ rawQuery }] = useQueryParams();
|
139
104
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
140
105
|
const contentTypePermissions = React.useMemo(() => {
|
141
106
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -146,7 +111,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
146
111
|
return { ...acc, [action]: [permission] };
|
147
112
|
}, {});
|
148
113
|
}, [slug, userPermissions]);
|
149
|
-
const { isLoading, allowedActions } = useRBAC(
|
114
|
+
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
contentTypePermissions,
|
116
|
+
permissions ?? void 0,
|
117
|
+
// TODO: useRBAC context should be typed and built differently
|
118
|
+
// We are passing raw query as context to the hook so that it can
|
119
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
120
|
+
rawQuery
|
121
|
+
);
|
150
122
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
151
123
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
152
124
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -194,10 +166,12 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
194
166
|
"Document",
|
195
167
|
"InitialData",
|
196
168
|
"HistoryVersion",
|
197
|
-
"Relations"
|
169
|
+
"Relations",
|
170
|
+
"UidAvailability"
|
198
171
|
]
|
199
172
|
});
|
200
173
|
const documentApi = contentManagerApi.injectEndpoints({
|
174
|
+
overrideExisting: true,
|
201
175
|
endpoints: (builder) => ({
|
202
176
|
autoCloneDocument: builder.mutation({
|
203
177
|
query: ({ model, sourceId, query }) => ({
|
@@ -207,7 +181,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
207
181
|
params: query
|
208
182
|
}
|
209
183
|
}),
|
210
|
-
invalidatesTags: (_result,
|
184
|
+
invalidatesTags: (_result, error, { model }) => {
|
185
|
+
if (error) {
|
186
|
+
return [];
|
187
|
+
}
|
188
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
189
|
+
}
|
211
190
|
}),
|
212
191
|
cloneDocument: builder.mutation({
|
213
192
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -218,7 +197,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
218
197
|
params
|
219
198
|
}
|
220
199
|
}),
|
221
|
-
invalidatesTags: (_result, _error, { model }) => [
|
200
|
+
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
{ type: "Document", id: `${model}_LIST` },
|
202
|
+
{ type: "UidAvailability", id: model }
|
203
|
+
]
|
222
204
|
}),
|
223
205
|
/**
|
224
206
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -235,7 +217,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
235
217
|
}),
|
236
218
|
invalidatesTags: (result, _error, { model }) => [
|
237
219
|
{ type: "Document", id: `${model}_LIST` },
|
238
|
-
"Relations"
|
220
|
+
"Relations",
|
221
|
+
{ type: "UidAvailability", id: model }
|
239
222
|
]
|
240
223
|
}),
|
241
224
|
deleteDocument: builder.mutation({
|
@@ -276,7 +259,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
276
259
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
277
260
|
},
|
278
261
|
{ type: "Document", id: `${model}_LIST` },
|
279
|
-
"Relations"
|
262
|
+
"Relations",
|
263
|
+
{ type: "UidAvailability", id: model }
|
280
264
|
];
|
281
265
|
}
|
282
266
|
}),
|
@@ -294,6 +278,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
294
278
|
}),
|
295
279
|
providesTags: (result, _error, arg) => {
|
296
280
|
return [
|
281
|
+
{ type: "Document", id: `ALL_LIST` },
|
297
282
|
{ type: "Document", id: `${arg.model}_LIST` },
|
298
283
|
...result?.results.map(({ documentId }) => ({
|
299
284
|
type: "Document",
|
@@ -332,6 +317,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
332
317
|
{
|
333
318
|
type: "Document",
|
334
319
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
320
|
+
},
|
321
|
+
// Make it easy to invalidate all individual documents queries for a model
|
322
|
+
{
|
323
|
+
type: "Document",
|
324
|
+
id: `${model}_ALL_ITEMS`
|
335
325
|
}
|
336
326
|
];
|
337
327
|
}
|
@@ -395,8 +385,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
395
385
|
type: "Document",
|
396
386
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
397
387
|
},
|
398
|
-
"Relations"
|
388
|
+
"Relations",
|
389
|
+
{ type: "UidAvailability", id: model }
|
399
390
|
];
|
391
|
+
},
|
392
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
393
|
+
const patchResult = dispatch(
|
394
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
395
|
+
Object.assign(draft.data, data);
|
396
|
+
})
|
397
|
+
);
|
398
|
+
try {
|
399
|
+
await queryFulfilled;
|
400
|
+
} catch {
|
401
|
+
patchResult.undo();
|
402
|
+
}
|
400
403
|
}
|
401
404
|
}),
|
402
405
|
unpublishDocument: builder.mutation({
|
@@ -466,20 +469,39 @@ const buildValidParams = (query) => {
|
|
466
469
|
const isBaseQueryError = (error) => {
|
467
470
|
return error.name !== void 0;
|
468
471
|
};
|
469
|
-
const
|
472
|
+
const arrayValidator = (attribute, options) => ({
|
473
|
+
message: translatedErrors.required,
|
474
|
+
test(value) {
|
475
|
+
if (options.status === "draft") {
|
476
|
+
return true;
|
477
|
+
}
|
478
|
+
if (!attribute.required) {
|
479
|
+
return true;
|
480
|
+
}
|
481
|
+
if (!value) {
|
482
|
+
return false;
|
483
|
+
}
|
484
|
+
if (Array.isArray(value) && value.length === 0) {
|
485
|
+
return false;
|
486
|
+
}
|
487
|
+
return true;
|
488
|
+
}
|
489
|
+
});
|
490
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
470
491
|
const createModelSchema = (attributes2) => yup.object().shape(
|
471
492
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
472
493
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
473
494
|
return acc;
|
474
495
|
}
|
475
496
|
const validations = [
|
497
|
+
addNullableValidation,
|
476
498
|
addRequiredValidation,
|
477
499
|
addMinLengthValidation,
|
478
500
|
addMaxLengthValidation,
|
479
501
|
addMinValidation,
|
480
502
|
addMaxValidation,
|
481
503
|
addRegexValidation
|
482
|
-
].map((fn) => fn(attribute));
|
504
|
+
].map((fn) => fn(attribute, options));
|
483
505
|
const transformSchema = pipe(...validations);
|
484
506
|
switch (attribute.type) {
|
485
507
|
case "component": {
|
@@ -489,12 +511,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
489
511
|
...acc,
|
490
512
|
[name]: transformSchema(
|
491
513
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
492
|
-
)
|
514
|
+
).test(arrayValidator(attribute, options))
|
493
515
|
};
|
494
516
|
} else {
|
495
517
|
return {
|
496
518
|
...acc,
|
497
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
519
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
498
520
|
};
|
499
521
|
}
|
500
522
|
}
|
@@ -516,7 +538,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
516
538
|
}
|
517
539
|
)
|
518
540
|
)
|
519
|
-
)
|
541
|
+
).test(arrayValidator(attribute, options))
|
520
542
|
};
|
521
543
|
case "relation":
|
522
544
|
return {
|
@@ -528,7 +550,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
528
550
|
} else if (Array.isArray(value)) {
|
529
551
|
return yup.array().of(
|
530
552
|
yup.object().shape({
|
531
|
-
id: yup.
|
553
|
+
id: yup.number().required()
|
532
554
|
})
|
533
555
|
);
|
534
556
|
} else if (typeof value === "object") {
|
@@ -580,6 +602,14 @@ const createAttributeSchema = (attribute) => {
|
|
580
602
|
if (!value || typeof value === "string" && value.length === 0) {
|
581
603
|
return true;
|
582
604
|
}
|
605
|
+
if (typeof value === "object") {
|
606
|
+
try {
|
607
|
+
JSON.stringify(value);
|
608
|
+
return true;
|
609
|
+
} catch (err) {
|
610
|
+
return false;
|
611
|
+
}
|
612
|
+
}
|
583
613
|
try {
|
584
614
|
JSON.parse(value);
|
585
615
|
return true;
|
@@ -598,13 +628,7 @@ const createAttributeSchema = (attribute) => {
|
|
598
628
|
return yup.mixed();
|
599
629
|
}
|
600
630
|
};
|
601
|
-
const
|
602
|
-
if (attribute.required) {
|
603
|
-
return schema.required({
|
604
|
-
id: translatedErrors.required.id,
|
605
|
-
defaultMessage: "This field is required."
|
606
|
-
});
|
607
|
-
}
|
631
|
+
const nullableSchema = (schema) => {
|
608
632
|
return schema?.nullable ? schema.nullable() : (
|
609
633
|
// In some cases '.nullable' will not be available on the schema.
|
610
634
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -612,7 +636,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
612
636
|
schema
|
613
637
|
);
|
614
638
|
};
|
615
|
-
const
|
639
|
+
const addNullableValidation = () => (schema) => {
|
640
|
+
return nullableSchema(schema);
|
641
|
+
};
|
642
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
643
|
+
if (options.status === "draft" || !attribute.required) {
|
644
|
+
return schema;
|
645
|
+
}
|
646
|
+
if (attribute.required && "required" in schema) {
|
647
|
+
return schema.required(translatedErrors.required);
|
648
|
+
}
|
649
|
+
return schema;
|
650
|
+
};
|
651
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
652
|
+
if (options.status === "draft") {
|
653
|
+
return schema;
|
654
|
+
}
|
616
655
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
617
656
|
return schema.min(attribute.minLength, {
|
618
657
|
...translatedErrors.minLength,
|
@@ -634,10 +673,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
634
673
|
}
|
635
674
|
return schema;
|
636
675
|
};
|
637
|
-
const addMinValidation = (attribute) => (schema) => {
|
638
|
-
if ("
|
676
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
677
|
+
if (options.status === "draft") {
|
678
|
+
return schema;
|
679
|
+
}
|
680
|
+
if ("min" in attribute && "min" in schema) {
|
639
681
|
const min = toInteger(attribute.min);
|
640
|
-
if (
|
682
|
+
if (min) {
|
641
683
|
return schema.min(min, {
|
642
684
|
...translatedErrors.min,
|
643
685
|
values: {
|
@@ -755,16 +797,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
755
797
|
}, {});
|
756
798
|
return componentsByKey;
|
757
799
|
};
|
758
|
-
const
|
800
|
+
const HOOKS = {
|
801
|
+
/**
|
802
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
803
|
+
* @constant
|
804
|
+
* @type {string}
|
805
|
+
*/
|
806
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
807
|
+
/**
|
808
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
809
|
+
* @constant
|
810
|
+
* @type {string}
|
811
|
+
*/
|
812
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
813
|
+
/**
|
814
|
+
* Hook that allows to mutate the CM's edit view layout
|
815
|
+
* @constant
|
816
|
+
* @type {string}
|
817
|
+
*/
|
818
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
819
|
+
/**
|
820
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
821
|
+
* @constant
|
822
|
+
* @type {string}
|
823
|
+
*/
|
824
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
825
|
+
};
|
826
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
827
|
+
endpoints: (builder) => ({
|
828
|
+
getContentTypeConfiguration: builder.query({
|
829
|
+
query: (uid) => ({
|
830
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
831
|
+
method: "GET"
|
832
|
+
}),
|
833
|
+
transformResponse: (response) => response.data,
|
834
|
+
providesTags: (_result, _error, uid) => [
|
835
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
836
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
837
|
+
]
|
838
|
+
}),
|
839
|
+
getAllContentTypeSettings: builder.query({
|
840
|
+
query: () => "/content-manager/content-types-settings",
|
841
|
+
transformResponse: (response) => response.data,
|
842
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
843
|
+
}),
|
844
|
+
updateContentTypeConfiguration: builder.mutation({
|
845
|
+
query: ({ uid, ...body }) => ({
|
846
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
847
|
+
method: "PUT",
|
848
|
+
data: body
|
849
|
+
}),
|
850
|
+
transformResponse: (response) => response.data,
|
851
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
852
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
853
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
854
|
+
// Is this necessary?
|
855
|
+
{ type: "InitialData" }
|
856
|
+
]
|
857
|
+
})
|
858
|
+
})
|
859
|
+
});
|
860
|
+
const {
|
861
|
+
useGetContentTypeConfigurationQuery,
|
862
|
+
useGetAllContentTypeSettingsQuery,
|
863
|
+
useUpdateContentTypeConfigurationMutation
|
864
|
+
} = contentTypesApi;
|
865
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
866
|
+
const { type } = attribute;
|
867
|
+
if (type === "relation") {
|
868
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
869
|
+
}
|
870
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
871
|
+
};
|
872
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
873
|
+
if (!mainFieldName) {
|
874
|
+
return void 0;
|
875
|
+
}
|
876
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
877
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
878
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
879
|
+
);
|
880
|
+
return {
|
881
|
+
name: mainFieldName,
|
882
|
+
type: mainFieldType ?? "string"
|
883
|
+
};
|
884
|
+
};
|
885
|
+
const DEFAULT_SETTINGS = {
|
886
|
+
bulkable: false,
|
887
|
+
filterable: false,
|
888
|
+
searchable: false,
|
889
|
+
pagination: false,
|
890
|
+
defaultSortBy: "",
|
891
|
+
defaultSortOrder: "asc",
|
892
|
+
mainField: "id",
|
893
|
+
pageSize: 10
|
894
|
+
};
|
895
|
+
const useDocumentLayout = (model) => {
|
896
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
897
|
+
const [{ query }] = useQueryParams();
|
898
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
759
899
|
const { toggleNotification } = useNotification();
|
760
900
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
901
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
761
902
|
const {
|
762
|
-
|
763
|
-
isLoading:
|
764
|
-
|
765
|
-
|
766
|
-
} =
|
767
|
-
const
|
903
|
+
data,
|
904
|
+
isLoading: isLoadingConfigs,
|
905
|
+
error,
|
906
|
+
isFetching: isFetchingConfigs
|
907
|
+
} = useGetContentTypeConfigurationQuery(model);
|
908
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
768
909
|
React.useEffect(() => {
|
769
910
|
if (error) {
|
770
911
|
toggleNotification({
|
@@ -772,62 +913,318 @@ const useDocument = (args, opts) => {
|
|
772
913
|
message: formatAPIError(error)
|
773
914
|
});
|
774
915
|
}
|
775
|
-
}, [
|
776
|
-
const
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
(document) => {
|
784
|
-
if (!validationSchema) {
|
785
|
-
throw new Error(
|
786
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
787
|
-
);
|
788
|
-
}
|
789
|
-
try {
|
790
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
791
|
-
return null;
|
792
|
-
} catch (error2) {
|
793
|
-
if (error2 instanceof ValidationError) {
|
794
|
-
return getYupValidationErrors(error2);
|
795
|
-
}
|
796
|
-
throw error2;
|
797
|
-
}
|
916
|
+
}, [error, formatAPIError, toggleNotification]);
|
917
|
+
const editLayout = React.useMemo(
|
918
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
919
|
+
layout: [],
|
920
|
+
components: {},
|
921
|
+
metadatas: {},
|
922
|
+
options: {},
|
923
|
+
settings: DEFAULT_SETTINGS
|
798
924
|
},
|
799
|
-
[
|
925
|
+
[data, isLoading, schemas, schema, components]
|
926
|
+
);
|
927
|
+
const listLayout = React.useMemo(() => {
|
928
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
929
|
+
layout: [],
|
930
|
+
metadatas: {},
|
931
|
+
options: {},
|
932
|
+
settings: DEFAULT_SETTINGS
|
933
|
+
};
|
934
|
+
}, [data, isLoading, schemas, schema, components]);
|
935
|
+
const { layout: edit } = React.useMemo(
|
936
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
937
|
+
layout: editLayout,
|
938
|
+
query
|
939
|
+
}),
|
940
|
+
[editLayout, query, runHookWaterfall]
|
800
941
|
);
|
801
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
802
942
|
return {
|
803
|
-
|
804
|
-
document: data?.data,
|
805
|
-
meta: data?.meta,
|
943
|
+
error,
|
806
944
|
isLoading,
|
807
|
-
|
808
|
-
|
945
|
+
edit,
|
946
|
+
list: listLayout
|
809
947
|
};
|
810
948
|
};
|
811
|
-
const
|
812
|
-
const {
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
949
|
+
const useDocLayout = () => {
|
950
|
+
const { model } = useDoc();
|
951
|
+
return useDocumentLayout(model);
|
952
|
+
};
|
953
|
+
const formatEditLayout = (data, {
|
954
|
+
schemas,
|
955
|
+
schema,
|
956
|
+
components
|
957
|
+
}) => {
|
958
|
+
let currentPanelIndex = 0;
|
959
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
960
|
+
data.contentType.layouts.edit,
|
961
|
+
schema?.attributes,
|
962
|
+
data.contentType.metadatas,
|
963
|
+
{ configurations: data.components, schemas: components },
|
964
|
+
schemas
|
965
|
+
).reduce((panels, row) => {
|
966
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
967
|
+
panels.push([row]);
|
968
|
+
currentPanelIndex += 2;
|
969
|
+
} else {
|
970
|
+
if (!panels[currentPanelIndex]) {
|
971
|
+
panels.push([]);
|
972
|
+
}
|
973
|
+
panels[currentPanelIndex].push(row);
|
974
|
+
}
|
975
|
+
return panels;
|
976
|
+
}, []);
|
977
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
978
|
+
(acc, [uid, configuration]) => {
|
979
|
+
acc[uid] = {
|
980
|
+
layout: convertEditLayoutToFieldLayouts(
|
981
|
+
configuration.layouts.edit,
|
982
|
+
components[uid].attributes,
|
983
|
+
configuration.metadatas,
|
984
|
+
{ configurations: data.components, schemas: components }
|
985
|
+
),
|
986
|
+
settings: {
|
987
|
+
...configuration.settings,
|
988
|
+
icon: components[uid].info.icon,
|
989
|
+
displayName: components[uid].info.displayName
|
990
|
+
}
|
991
|
+
};
|
992
|
+
return acc;
|
993
|
+
},
|
994
|
+
{}
|
995
|
+
);
|
996
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
997
|
+
(acc, [attribute, metadata]) => {
|
998
|
+
return {
|
999
|
+
...acc,
|
1000
|
+
[attribute]: metadata.edit
|
1001
|
+
};
|
1002
|
+
},
|
1003
|
+
{}
|
1004
|
+
);
|
1005
|
+
return {
|
1006
|
+
layout: panelledEditAttributes,
|
1007
|
+
components: componentEditAttributes,
|
1008
|
+
metadatas: editMetadatas,
|
1009
|
+
settings: {
|
1010
|
+
...data.contentType.settings,
|
1011
|
+
displayName: schema?.info.displayName
|
1012
|
+
},
|
1013
|
+
options: {
|
1014
|
+
...schema?.options,
|
1015
|
+
...schema?.pluginOptions,
|
1016
|
+
...data.contentType.options
|
1017
|
+
}
|
1018
|
+
};
|
1019
|
+
};
|
1020
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1021
|
+
return rows.map(
|
1022
|
+
(row) => row.map((field) => {
|
1023
|
+
const attribute = attributes[field.name];
|
1024
|
+
if (!attribute) {
|
1025
|
+
return null;
|
1026
|
+
}
|
1027
|
+
const { edit: metadata } = metadatas[field.name];
|
1028
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1029
|
+
return {
|
1030
|
+
attribute,
|
1031
|
+
disabled: !metadata.editable,
|
1032
|
+
hint: metadata.description,
|
1033
|
+
label: metadata.label ?? "",
|
1034
|
+
name: field.name,
|
1035
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1036
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1037
|
+
schemas,
|
1038
|
+
components: components?.schemas ?? {}
|
1039
|
+
}),
|
1040
|
+
placeholder: metadata.placeholder ?? "",
|
1041
|
+
required: attribute.required ?? false,
|
1042
|
+
size: field.size,
|
1043
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1044
|
+
visible: metadata.visible ?? true,
|
1045
|
+
type: attribute.type
|
1046
|
+
};
|
1047
|
+
}).filter((field) => field !== null)
|
1048
|
+
);
|
1049
|
+
};
|
1050
|
+
const formatListLayout = (data, {
|
1051
|
+
schemas,
|
1052
|
+
schema,
|
1053
|
+
components
|
1054
|
+
}) => {
|
1055
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1056
|
+
(acc, [attribute, metadata]) => {
|
1057
|
+
return {
|
1058
|
+
...acc,
|
1059
|
+
[attribute]: metadata.list
|
1060
|
+
};
|
1061
|
+
},
|
1062
|
+
{}
|
1063
|
+
);
|
1064
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1065
|
+
data.contentType.layouts.list,
|
1066
|
+
schema?.attributes,
|
1067
|
+
listMetadatas,
|
1068
|
+
{ configurations: data.components, schemas: components },
|
1069
|
+
schemas
|
1070
|
+
);
|
1071
|
+
return {
|
1072
|
+
layout: listAttributes,
|
1073
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1074
|
+
metadatas: listMetadatas,
|
1075
|
+
options: {
|
1076
|
+
...schema?.options,
|
1077
|
+
...schema?.pluginOptions,
|
1078
|
+
...data.contentType.options
|
1079
|
+
}
|
1080
|
+
};
|
1081
|
+
};
|
1082
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1083
|
+
return columns.map((name) => {
|
1084
|
+
const attribute = attributes[name];
|
1085
|
+
if (!attribute) {
|
1086
|
+
return null;
|
1087
|
+
}
|
1088
|
+
const metadata = metadatas[name];
|
1089
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1090
|
+
return {
|
1091
|
+
attribute,
|
1092
|
+
label: metadata.label ?? "",
|
1093
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1094
|
+
schemas,
|
1095
|
+
components: components?.schemas ?? {}
|
1096
|
+
}),
|
1097
|
+
name,
|
1098
|
+
searchable: metadata.searchable ?? true,
|
1099
|
+
sortable: metadata.sortable ?? true
|
1100
|
+
};
|
1101
|
+
}).filter((field) => field !== null);
|
1102
|
+
};
|
1103
|
+
const useDocument = (args, opts) => {
|
1104
|
+
const { toggleNotification } = useNotification();
|
1105
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1106
|
+
const {
|
1107
|
+
currentData: data,
|
1108
|
+
isLoading: isLoadingDocument,
|
1109
|
+
isFetching: isFetchingDocument,
|
1110
|
+
error
|
1111
|
+
} = useGetDocumentQuery(args, {
|
1112
|
+
...opts,
|
1113
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1114
|
+
});
|
1115
|
+
const {
|
1116
|
+
components,
|
1117
|
+
schema,
|
1118
|
+
schemas,
|
1119
|
+
isLoading: isLoadingSchema
|
1120
|
+
} = useContentTypeSchema(args.model);
|
1121
|
+
React.useEffect(() => {
|
1122
|
+
if (error) {
|
1123
|
+
toggleNotification({
|
1124
|
+
type: "danger",
|
1125
|
+
message: formatAPIError(error)
|
1126
|
+
});
|
1127
|
+
}
|
1128
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1129
|
+
const validationSchema = React.useMemo(() => {
|
1130
|
+
if (!schema) {
|
1131
|
+
return null;
|
1132
|
+
}
|
1133
|
+
return createYupSchema(schema.attributes, components);
|
1134
|
+
}, [schema, components]);
|
1135
|
+
const validate = React.useCallback(
|
1136
|
+
(document) => {
|
1137
|
+
if (!validationSchema) {
|
1138
|
+
throw new Error(
|
1139
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1140
|
+
);
|
1141
|
+
}
|
1142
|
+
try {
|
1143
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1144
|
+
return null;
|
1145
|
+
} catch (error2) {
|
1146
|
+
if (error2 instanceof ValidationError) {
|
1147
|
+
return getYupValidationErrors(error2);
|
1148
|
+
}
|
1149
|
+
throw error2;
|
1150
|
+
}
|
1151
|
+
},
|
1152
|
+
[validationSchema]
|
1153
|
+
);
|
1154
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1155
|
+
const hasError = !!error;
|
1156
|
+
return {
|
1157
|
+
components,
|
1158
|
+
document: data?.data,
|
1159
|
+
meta: data?.meta,
|
1160
|
+
isLoading,
|
1161
|
+
hasError,
|
1162
|
+
schema,
|
1163
|
+
schemas,
|
1164
|
+
validate
|
1165
|
+
};
|
1166
|
+
};
|
1167
|
+
const useDoc = () => {
|
1168
|
+
const { id, slug, collectionType, origin } = useParams();
|
1169
|
+
const [{ query }] = useQueryParams();
|
1170
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1171
|
+
if (!collectionType) {
|
1172
|
+
throw new Error("Could not find collectionType in url params");
|
1173
|
+
}
|
1174
|
+
if (!slug) {
|
1175
|
+
throw new Error("Could not find model in url params");
|
1176
|
+
}
|
1177
|
+
const document = useDocument(
|
1178
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1179
|
+
{
|
1180
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1181
|
+
}
|
1182
|
+
);
|
1183
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
821
1184
|
return {
|
822
1185
|
collectionType,
|
823
1186
|
model: slug,
|
824
|
-
id:
|
825
|
-
...
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
1187
|
+
id: returnId,
|
1188
|
+
...document
|
1189
|
+
};
|
1190
|
+
};
|
1191
|
+
const useContentManagerContext = () => {
|
1192
|
+
const {
|
1193
|
+
collectionType,
|
1194
|
+
model,
|
1195
|
+
id,
|
1196
|
+
components,
|
1197
|
+
isLoading: isLoadingDoc,
|
1198
|
+
schema,
|
1199
|
+
schemas
|
1200
|
+
} = useDoc();
|
1201
|
+
const layout = useDocumentLayout(model);
|
1202
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1203
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1204
|
+
const slug = model;
|
1205
|
+
const isCreatingEntry = id === "create";
|
1206
|
+
useContentTypeSchema();
|
1207
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1208
|
+
const error = layout.error;
|
1209
|
+
return {
|
1210
|
+
error,
|
1211
|
+
isLoading,
|
1212
|
+
// Base metadata
|
1213
|
+
model,
|
1214
|
+
collectionType,
|
1215
|
+
id,
|
1216
|
+
slug,
|
1217
|
+
isCreatingEntry,
|
1218
|
+
isSingleType,
|
1219
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1220
|
+
// All schema infos
|
1221
|
+
components,
|
1222
|
+
contentType: schema,
|
1223
|
+
contentTypes: schemas,
|
1224
|
+
// Form state
|
1225
|
+
form,
|
1226
|
+
// layout infos
|
1227
|
+
layout
|
831
1228
|
};
|
832
1229
|
};
|
833
1230
|
const prefixPluginTranslations = (trad, pluginId) => {
|
@@ -849,6 +1246,8 @@ const useDocumentActions = () => {
|
|
849
1246
|
const { formatMessage } = useIntl();
|
850
1247
|
const { trackUsage } = useTracking();
|
851
1248
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1249
|
+
const navigate = useNavigate();
|
1250
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
852
1251
|
const [deleteDocument] = useDeleteDocumentMutation();
|
853
1252
|
const _delete = React.useCallback(
|
854
1253
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1163,6 +1562,7 @@ const useDocumentActions = () => {
|
|
1163
1562
|
defaultMessage: "Saved document"
|
1164
1563
|
})
|
1165
1564
|
});
|
1565
|
+
setCurrentStep("contentManager.success");
|
1166
1566
|
return res.data;
|
1167
1567
|
} catch (err) {
|
1168
1568
|
toggleNotification({
|
@@ -1184,7 +1584,6 @@ const useDocumentActions = () => {
|
|
1184
1584
|
sourceId
|
1185
1585
|
});
|
1186
1586
|
if ("error" in res) {
|
1187
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1188
1587
|
return { error: res.error };
|
1189
1588
|
}
|
1190
1589
|
toggleNotification({
|
@@ -1203,7 +1602,7 @@ const useDocumentActions = () => {
|
|
1203
1602
|
throw err;
|
1204
1603
|
}
|
1205
1604
|
},
|
1206
|
-
[autoCloneDocument,
|
1605
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1207
1606
|
);
|
1208
1607
|
const [cloneDocument] = useCloneDocumentMutation();
|
1209
1608
|
const clone = React.useCallback(
|
@@ -1229,6 +1628,7 @@ const useDocumentActions = () => {
|
|
1229
1628
|
defaultMessage: "Cloned document"
|
1230
1629
|
})
|
1231
1630
|
});
|
1631
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1232
1632
|
return res.data;
|
1233
1633
|
} catch (err) {
|
1234
1634
|
toggleNotification({
|
@@ -1239,7 +1639,7 @@ const useDocumentActions = () => {
|
|
1239
1639
|
throw err;
|
1240
1640
|
}
|
1241
1641
|
},
|
1242
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1642
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1243
1643
|
);
|
1244
1644
|
const [getDoc] = useLazyGetDocumentQuery();
|
1245
1645
|
const getDocument = React.useCallback(
|
@@ -1265,7 +1665,7 @@ const useDocumentActions = () => {
|
|
1265
1665
|
};
|
1266
1666
|
};
|
1267
1667
|
const ProtectedHistoryPage = lazy(
|
1268
|
-
() => import("./History-
|
1668
|
+
() => import("./History-DRwA3oMM.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1269
1669
|
);
|
1270
1670
|
const routes$1 = [
|
1271
1671
|
{
|
@@ -1278,31 +1678,31 @@ const routes$1 = [
|
|
1278
1678
|
}
|
1279
1679
|
];
|
1280
1680
|
const ProtectedEditViewPage = lazy(
|
1281
|
-
() => import("./EditViewPage-
|
1681
|
+
() => import("./EditViewPage-B82x_x1b.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1282
1682
|
);
|
1283
1683
|
const ProtectedListViewPage = lazy(
|
1284
|
-
() => import("./ListViewPage-
|
1684
|
+
() => import("./ListViewPage-CELx2ysp.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1285
1685
|
);
|
1286
1686
|
const ProtectedListConfiguration = lazy(
|
1287
|
-
() => import("./ListConfigurationPage-
|
1687
|
+
() => import("./ListConfigurationPage-BxfQJzPk.mjs").then((mod) => ({
|
1288
1688
|
default: mod.ProtectedListConfiguration
|
1289
1689
|
}))
|
1290
1690
|
);
|
1291
1691
|
const ProtectedEditConfigurationPage = lazy(
|
1292
|
-
() => import("./EditConfigurationPage-
|
1692
|
+
() => import("./EditConfigurationPage-DdPNAbl3.mjs").then((mod) => ({
|
1293
1693
|
default: mod.ProtectedEditConfigurationPage
|
1294
1694
|
}))
|
1295
1695
|
);
|
1296
1696
|
const ProtectedComponentConfigurationPage = lazy(
|
1297
|
-
() => import("./ComponentConfigurationPage-
|
1697
|
+
() => import("./ComponentConfigurationPage-DfFSZQxe.mjs").then((mod) => ({
|
1298
1698
|
default: mod.ProtectedComponentConfigurationPage
|
1299
1699
|
}))
|
1300
1700
|
);
|
1301
1701
|
const NoPermissions = lazy(
|
1302
|
-
() => import("./NoPermissionsPage-
|
1702
|
+
() => import("./NoPermissionsPage-DWleVYK7.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1303
1703
|
);
|
1304
1704
|
const NoContentType = lazy(
|
1305
|
-
() => import("./NoContentTypePage-
|
1705
|
+
() => import("./NoContentTypePage-DtJ9jcfk.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1306
1706
|
);
|
1307
1707
|
const CollectionTypePages = () => {
|
1308
1708
|
const { collectionType } = useParams();
|
@@ -1416,12 +1816,14 @@ const DocumentActionButton = (action) => {
|
|
1416
1816
|
/* @__PURE__ */ jsx(
|
1417
1817
|
Button,
|
1418
1818
|
{
|
1419
|
-
flex:
|
1819
|
+
flex: "auto",
|
1420
1820
|
startIcon: action.icon,
|
1421
1821
|
disabled: action.disabled,
|
1422
1822
|
onClick: handleClick(action),
|
1423
1823
|
justifyContent: "center",
|
1424
1824
|
variant: action.variant || "default",
|
1825
|
+
paddingTop: "7px",
|
1826
|
+
paddingBottom: "7px",
|
1425
1827
|
children: action.label
|
1426
1828
|
}
|
1427
1829
|
),
|
@@ -1429,7 +1831,7 @@ const DocumentActionButton = (action) => {
|
|
1429
1831
|
DocumentActionConfirmDialog,
|
1430
1832
|
{
|
1431
1833
|
...action.dialog,
|
1432
|
-
variant: action.variant,
|
1834
|
+
variant: action.dialog?.variant ?? action.variant,
|
1433
1835
|
isOpen: dialogId === action.id,
|
1434
1836
|
onClose: handleClose
|
1435
1837
|
}
|
@@ -1486,9 +1888,9 @@ const DocumentActionsMenu = ({
|
|
1486
1888
|
disabled: isDisabled,
|
1487
1889
|
size: "S",
|
1488
1890
|
endIcon: null,
|
1489
|
-
paddingTop: "
|
1490
|
-
paddingLeft: "
|
1491
|
-
paddingRight: "
|
1891
|
+
paddingTop: "4px",
|
1892
|
+
paddingLeft: "7px",
|
1893
|
+
paddingRight: "7px",
|
1492
1894
|
variant,
|
1493
1895
|
children: [
|
1494
1896
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1499,7 +1901,7 @@ const DocumentActionsMenu = ({
|
|
1499
1901
|
]
|
1500
1902
|
}
|
1501
1903
|
),
|
1502
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1904
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1503
1905
|
actions2.map((action) => {
|
1504
1906
|
return /* @__PURE__ */ jsx(
|
1505
1907
|
Menu.Item,
|
@@ -1508,10 +1910,25 @@ const DocumentActionsMenu = ({
|
|
1508
1910
|
onSelect: handleClick(action),
|
1509
1911
|
display: "block",
|
1510
1912
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1511
|
-
/* @__PURE__ */ jsxs(
|
1512
|
-
|
1513
|
-
|
1514
|
-
|
1913
|
+
/* @__PURE__ */ jsxs(
|
1914
|
+
Flex,
|
1915
|
+
{
|
1916
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1917
|
+
gap: 2,
|
1918
|
+
tag: "span",
|
1919
|
+
children: [
|
1920
|
+
/* @__PURE__ */ jsx(
|
1921
|
+
Flex,
|
1922
|
+
{
|
1923
|
+
tag: "span",
|
1924
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1925
|
+
children: action.icon
|
1926
|
+
}
|
1927
|
+
),
|
1928
|
+
action.label
|
1929
|
+
]
|
1930
|
+
}
|
1931
|
+
),
|
1515
1932
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1516
1933
|
Flex,
|
1517
1934
|
{
|
@@ -1570,6 +1987,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
|
|
1570
1987
|
return "primary600";
|
1571
1988
|
}
|
1572
1989
|
};
|
1990
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1991
|
+
switch (variant) {
|
1992
|
+
case "danger":
|
1993
|
+
return "danger600";
|
1994
|
+
case "secondary":
|
1995
|
+
return "neutral500";
|
1996
|
+
case "success":
|
1997
|
+
return "success600";
|
1998
|
+
default:
|
1999
|
+
return "primary600";
|
2000
|
+
}
|
2001
|
+
};
|
1573
2002
|
const DocumentActionConfirmDialog = ({
|
1574
2003
|
onClose,
|
1575
2004
|
onCancel,
|
@@ -1592,22 +2021,20 @@ const DocumentActionConfirmDialog = ({
|
|
1592
2021
|
}
|
1593
2022
|
onClose();
|
1594
2023
|
};
|
1595
|
-
return /* @__PURE__ */
|
1596
|
-
/* @__PURE__ */ jsx(
|
1597
|
-
/* @__PURE__ */ jsx(
|
1598
|
-
|
1599
|
-
{
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
|
1609
|
-
)
|
1610
|
-
] });
|
2024
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2025
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2026
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2027
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2028
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2029
|
+
id: "app.components.Button.cancel",
|
2030
|
+
defaultMessage: "Cancel"
|
2031
|
+
}) }) }),
|
2032
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2033
|
+
id: "app.components.Button.confirm",
|
2034
|
+
defaultMessage: "Confirm"
|
2035
|
+
}) })
|
2036
|
+
] })
|
2037
|
+
] }) });
|
1611
2038
|
};
|
1612
2039
|
const DocumentActionModal = ({
|
1613
2040
|
isOpen,
|
@@ -1617,34 +2044,17 @@ const DocumentActionModal = ({
|
|
1617
2044
|
content: Content,
|
1618
2045
|
onModalClose
|
1619
2046
|
}) => {
|
1620
|
-
const id = React.useId();
|
1621
|
-
if (!isOpen) {
|
1622
|
-
return null;
|
1623
|
-
}
|
1624
2047
|
const handleClose = () => {
|
1625
2048
|
if (onClose) {
|
1626
2049
|
onClose();
|
1627
2050
|
}
|
1628
2051
|
onModalClose();
|
1629
2052
|
};
|
1630
|
-
return /* @__PURE__ */
|
1631
|
-
/* @__PURE__ */ jsx(
|
1632
|
-
|
1633
|
-
/* @__PURE__ */ jsx(
|
1634
|
-
|
1635
|
-
{
|
1636
|
-
paddingTop: 4,
|
1637
|
-
paddingBottom: 4,
|
1638
|
-
paddingLeft: 5,
|
1639
|
-
paddingRight: 5,
|
1640
|
-
borderWidth: "1px 0 0 0",
|
1641
|
-
borderStyle: "solid",
|
1642
|
-
borderColor: "neutral150",
|
1643
|
-
background: "neutral100",
|
1644
|
-
children: typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1645
|
-
}
|
1646
|
-
)
|
1647
|
-
] });
|
2053
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2054
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2055
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2056
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2057
|
+
] }) });
|
1648
2058
|
};
|
1649
2059
|
const PublishAction$1 = ({
|
1650
2060
|
activeTab,
|
@@ -1658,13 +2068,17 @@ const PublishAction$1 = ({
|
|
1658
2068
|
const navigate = useNavigate();
|
1659
2069
|
const { toggleNotification } = useNotification();
|
1660
2070
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2071
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1661
2072
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1662
2073
|
const { formatMessage } = useIntl();
|
1663
|
-
const { canPublish
|
1664
|
-
"PublishAction",
|
1665
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1666
|
-
);
|
2074
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1667
2075
|
const { publish } = useDocumentActions();
|
2076
|
+
const [
|
2077
|
+
countDraftRelations,
|
2078
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2079
|
+
] = useLazyGetDraftRelationCountQuery();
|
2080
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2081
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1668
2082
|
const [{ query, rawQuery }] = useQueryParams();
|
1669
2083
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1670
2084
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1673,10 +2087,105 @@ const PublishAction$1 = ({
|
|
1673
2087
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1674
2088
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1675
2089
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
2090
|
+
React.useEffect(() => {
|
2091
|
+
if (isErrorDraftRelations) {
|
2092
|
+
toggleNotification({
|
2093
|
+
type: "danger",
|
2094
|
+
message: formatMessage({
|
2095
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2096
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2097
|
+
})
|
2098
|
+
});
|
2099
|
+
}
|
2100
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2101
|
+
React.useEffect(() => {
|
2102
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2103
|
+
const extractDraftRelations = (data) => {
|
2104
|
+
const relations = data.connect || [];
|
2105
|
+
relations.forEach((relation) => {
|
2106
|
+
if (relation.status === "draft") {
|
2107
|
+
localDraftRelations.add(relation.id);
|
2108
|
+
}
|
2109
|
+
});
|
2110
|
+
};
|
2111
|
+
const traverseAndExtract = (data) => {
|
2112
|
+
Object.entries(data).forEach(([key, value]) => {
|
2113
|
+
if (key === "connect" && Array.isArray(value)) {
|
2114
|
+
extractDraftRelations({ connect: value });
|
2115
|
+
} else if (typeof value === "object" && value !== null) {
|
2116
|
+
traverseAndExtract(value);
|
2117
|
+
}
|
2118
|
+
});
|
2119
|
+
};
|
2120
|
+
if (!documentId || modified) {
|
2121
|
+
traverseAndExtract(formValues);
|
2122
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2123
|
+
}
|
2124
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2125
|
+
React.useEffect(() => {
|
2126
|
+
if (!document || !document.documentId || isListView) {
|
2127
|
+
return;
|
2128
|
+
}
|
2129
|
+
const fetchDraftRelationsCount = async () => {
|
2130
|
+
const { data, error } = await countDraftRelations({
|
2131
|
+
collectionType,
|
2132
|
+
model,
|
2133
|
+
documentId,
|
2134
|
+
params
|
2135
|
+
});
|
2136
|
+
if (error) {
|
2137
|
+
throw error;
|
2138
|
+
}
|
2139
|
+
if (data) {
|
2140
|
+
setServerCountOfDraftRelations(data.data);
|
2141
|
+
}
|
2142
|
+
};
|
2143
|
+
fetchDraftRelationsCount();
|
2144
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1676
2145
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1677
2146
|
if (!schema?.options?.draftAndPublish) {
|
1678
2147
|
return null;
|
1679
2148
|
}
|
2149
|
+
const performPublish = async () => {
|
2150
|
+
setSubmitting(true);
|
2151
|
+
try {
|
2152
|
+
const { errors } = await validate(true, {
|
2153
|
+
status: "published"
|
2154
|
+
});
|
2155
|
+
if (errors) {
|
2156
|
+
toggleNotification({
|
2157
|
+
type: "danger",
|
2158
|
+
message: formatMessage({
|
2159
|
+
id: "content-manager.validation.error",
|
2160
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2161
|
+
})
|
2162
|
+
});
|
2163
|
+
return;
|
2164
|
+
}
|
2165
|
+
const res = await publish(
|
2166
|
+
{
|
2167
|
+
collectionType,
|
2168
|
+
model,
|
2169
|
+
documentId,
|
2170
|
+
params
|
2171
|
+
},
|
2172
|
+
formValues
|
2173
|
+
);
|
2174
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2175
|
+
navigate({
|
2176
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2177
|
+
search: rawQuery
|
2178
|
+
});
|
2179
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2180
|
+
setErrors(formatValidationErrors(res.error));
|
2181
|
+
}
|
2182
|
+
} finally {
|
2183
|
+
setSubmitting(false);
|
2184
|
+
}
|
2185
|
+
};
|
2186
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2187
|
+
const enableDraftRelationsCount = false;
|
2188
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1680
2189
|
return {
|
1681
2190
|
/**
|
1682
2191
|
* Disabled when:
|
@@ -1686,49 +2195,36 @@ const PublishAction$1 = ({
|
|
1686
2195
|
* - the document is already published & not modified
|
1687
2196
|
* - the document is being created & not modified
|
1688
2197
|
* - the user doesn't have the permission to publish
|
1689
|
-
* - the user doesn't have the permission to create a new document
|
1690
|
-
* - the user doesn't have the permission to update the document
|
1691
2198
|
*/
|
1692
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2199
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1693
2200
|
label: formatMessage({
|
1694
2201
|
id: "app.utils.publish",
|
1695
2202
|
defaultMessage: "Publish"
|
1696
2203
|
}),
|
1697
2204
|
onClick: async () => {
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
documentId,
|
1716
|
-
params
|
1717
|
-
},
|
1718
|
-
formValues
|
1719
|
-
);
|
1720
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1721
|
-
navigate({
|
1722
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1723
|
-
search: rawQuery
|
1724
|
-
});
|
1725
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1726
|
-
setErrors(formatValidationErrors(res.error));
|
2205
|
+
await performPublish();
|
2206
|
+
},
|
2207
|
+
dialog: hasDraftRelations ? {
|
2208
|
+
type: "dialog",
|
2209
|
+
variant: "danger",
|
2210
|
+
footer: null,
|
2211
|
+
title: formatMessage({
|
2212
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2213
|
+
defaultMessage: "Confirmation"
|
2214
|
+
}),
|
2215
|
+
content: formatMessage(
|
2216
|
+
{
|
2217
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2218
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2219
|
+
},
|
2220
|
+
{
|
2221
|
+
count: totalDraftRelations
|
1727
2222
|
}
|
1728
|
-
|
1729
|
-
|
2223
|
+
),
|
2224
|
+
onConfirm: async () => {
|
2225
|
+
await performPublish();
|
1730
2226
|
}
|
1731
|
-
}
|
2227
|
+
} : void 0
|
1732
2228
|
};
|
1733
2229
|
};
|
1734
2230
|
PublishAction$1.type = "publish";
|
@@ -1744,10 +2240,6 @@ const UpdateAction = ({
|
|
1744
2240
|
const cloneMatch = useMatch(CLONE_PATH);
|
1745
2241
|
const isCloning = cloneMatch !== null;
|
1746
2242
|
const { formatMessage } = useIntl();
|
1747
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1748
|
-
canCreate: canCreate2,
|
1749
|
-
canUpdate: canUpdate2
|
1750
|
-
}));
|
1751
2243
|
const { create, update, clone } = useDocumentActions();
|
1752
2244
|
const [{ query, rawQuery }] = useQueryParams();
|
1753
2245
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1764,10 +2256,8 @@ const UpdateAction = ({
|
|
1764
2256
|
* - the form is submitting
|
1765
2257
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1766
2258
|
* - the active tab is the published tab
|
1767
|
-
* - the user doesn't have the permission to create a new document
|
1768
|
-
* - the user doesn't have the permission to update the document
|
1769
2259
|
*/
|
1770
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2260
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1771
2261
|
label: formatMessage({
|
1772
2262
|
id: "content-manager.containers.Edit.save",
|
1773
2263
|
defaultMessage: "Save"
|
@@ -1775,7 +2265,9 @@ const UpdateAction = ({
|
|
1775
2265
|
onClick: async () => {
|
1776
2266
|
setSubmitting(true);
|
1777
2267
|
try {
|
1778
|
-
const { errors } = await validate(
|
2268
|
+
const { errors } = await validate(true, {
|
2269
|
+
status: "draft"
|
2270
|
+
});
|
1779
2271
|
if (errors) {
|
1780
2272
|
toggleNotification({
|
1781
2273
|
type: "danger",
|
@@ -1796,10 +2288,13 @@ const UpdateAction = ({
|
|
1796
2288
|
document
|
1797
2289
|
);
|
1798
2290
|
if ("data" in res) {
|
1799
|
-
navigate(
|
1800
|
-
|
1801
|
-
|
1802
|
-
|
2291
|
+
navigate(
|
2292
|
+
{
|
2293
|
+
pathname: `../${res.data.documentId}`,
|
2294
|
+
search: rawQuery
|
2295
|
+
},
|
2296
|
+
{ relative: "path" }
|
2297
|
+
);
|
1803
2298
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1804
2299
|
setErrors(formatValidationErrors(res.error));
|
1805
2300
|
}
|
@@ -1827,10 +2322,13 @@ const UpdateAction = ({
|
|
1827
2322
|
document
|
1828
2323
|
);
|
1829
2324
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1830
|
-
navigate(
|
1831
|
-
|
1832
|
-
|
1833
|
-
|
2325
|
+
navigate(
|
2326
|
+
{
|
2327
|
+
pathname: `../${res.data.documentId}`,
|
2328
|
+
search: rawQuery
|
2329
|
+
},
|
2330
|
+
{ replace: true, relative: "path" }
|
2331
|
+
);
|
1834
2332
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1835
2333
|
setErrors(formatValidationErrors(res.error));
|
1836
2334
|
}
|
@@ -1862,10 +2360,8 @@ const UnpublishAction$1 = ({
|
|
1862
2360
|
const { toggleNotification } = useNotification();
|
1863
2361
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1864
2362
|
const isDocumentModified = document?.status === "modified";
|
1865
|
-
const handleChange = (
|
1866
|
-
|
1867
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1868
|
-
}
|
2363
|
+
const handleChange = (value) => {
|
2364
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1869
2365
|
};
|
1870
2366
|
if (!schema?.options?.draftAndPublish) {
|
1871
2367
|
return null;
|
@@ -1876,7 +2372,7 @@ const UnpublishAction$1 = ({
|
|
1876
2372
|
id: "app.utils.unpublish",
|
1877
2373
|
defaultMessage: "Unpublish"
|
1878
2374
|
}),
|
1879
|
-
icon: /* @__PURE__ */ jsx(
|
2375
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1880
2376
|
onClick: async () => {
|
1881
2377
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1882
2378
|
if (!documentId) {
|
@@ -1915,40 +2411,24 @@ const UnpublishAction$1 = ({
|
|
1915
2411
|
}) })
|
1916
2412
|
] }),
|
1917
2413
|
/* @__PURE__ */ jsxs(
|
1918
|
-
|
2414
|
+
Radio.Group,
|
1919
2415
|
{
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
1925
|
-
|
2416
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2417
|
+
name: "discard-options",
|
2418
|
+
"aria-label": formatMessage({
|
2419
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2420
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2421
|
+
}),
|
2422
|
+
onValueChange: handleChange,
|
1926
2423
|
children: [
|
1927
|
-
/* @__PURE__ */ jsx(
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
|
1934
|
-
|
1935
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
1936
|
-
defaultMessage: "Keep draft"
|
1937
|
-
})
|
1938
|
-
}
|
1939
|
-
),
|
1940
|
-
/* @__PURE__ */ jsx(
|
1941
|
-
Radio,
|
1942
|
-
{
|
1943
|
-
checked: !shouldKeepDraft,
|
1944
|
-
value: UNPUBLISH_DRAFT_OPTIONS.DISCARD,
|
1945
|
-
name: "discard-options",
|
1946
|
-
children: formatMessage({
|
1947
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
1948
|
-
defaultMessage: "Replace draft"
|
1949
|
-
})
|
1950
|
-
}
|
1951
|
-
)
|
2424
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2425
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2426
|
+
defaultMessage: "Keep draft"
|
2427
|
+
}) }),
|
2428
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2429
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2430
|
+
defaultMessage: "Replace draft"
|
2431
|
+
}) })
|
1952
2432
|
]
|
1953
2433
|
}
|
1954
2434
|
)
|
@@ -2004,7 +2484,7 @@ const DiscardAction = ({
|
|
2004
2484
|
id: "content-manager.actions.discard.label",
|
2005
2485
|
defaultMessage: "Discard changes"
|
2006
2486
|
}),
|
2007
|
-
icon: /* @__PURE__ */ jsx(
|
2487
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2008
2488
|
position: ["panel", "table-row"],
|
2009
2489
|
variant: "danger",
|
2010
2490
|
dialog: {
|
@@ -2032,11 +2512,6 @@ const DiscardAction = ({
|
|
2032
2512
|
};
|
2033
2513
|
};
|
2034
2514
|
DiscardAction.type = "discard";
|
2035
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2036
|
-
path {
|
2037
|
-
fill: currentColor;
|
2038
|
-
}
|
2039
|
-
`;
|
2040
2515
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2041
2516
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2042
2517
|
const RelativeTime = React.forwardRef(
|
@@ -2084,7 +2559,7 @@ const getDisplayName = ({
|
|
2084
2559
|
};
|
2085
2560
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2086
2561
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2087
|
-
const statusVariant = status === "draft" ? "
|
2562
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2088
2563
|
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2089
2564
|
};
|
2090
2565
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2094,23 +2569,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2094
2569
|
id: "content-manager.containers.edit.title.new",
|
2095
2570
|
defaultMessage: "Create an entry"
|
2096
2571
|
}) : documentTitle;
|
2097
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2572
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2098
2573
|
/* @__PURE__ */ jsx(BackButton, {}),
|
2099
|
-
/* @__PURE__ */ jsxs(
|
2100
|
-
|
2101
|
-
{
|
2102
|
-
|
2103
|
-
|
2104
|
-
paddingTop: 1,
|
2105
|
-
gap: "80px",
|
2106
|
-
alignItems: "flex-start",
|
2107
|
-
children: [
|
2108
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2109
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2110
|
-
]
|
2111
|
-
}
|
2112
|
-
),
|
2113
|
-
status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
|
2574
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2575
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2576
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2577
|
+
] }),
|
2578
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2114
2579
|
] });
|
2115
2580
|
};
|
2116
2581
|
const HeaderToolbar = () => {
|
@@ -2193,12 +2658,12 @@ const Information = ({ activeTab }) => {
|
|
2193
2658
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2194
2659
|
label: formatMessage({
|
2195
2660
|
id: "content-manager.containers.edit.information.last-published.label",
|
2196
|
-
defaultMessage: "
|
2661
|
+
defaultMessage: "Published"
|
2197
2662
|
}),
|
2198
2663
|
value: formatMessage(
|
2199
2664
|
{
|
2200
2665
|
id: "content-manager.containers.edit.information.last-published.value",
|
2201
|
-
defaultMessage: `
|
2666
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2202
2667
|
},
|
2203
2668
|
{
|
2204
2669
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2211,12 +2676,12 @@ const Information = ({ activeTab }) => {
|
|
2211
2676
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2212
2677
|
label: formatMessage({
|
2213
2678
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2214
|
-
defaultMessage: "
|
2679
|
+
defaultMessage: "Updated"
|
2215
2680
|
}),
|
2216
2681
|
value: formatMessage(
|
2217
2682
|
{
|
2218
2683
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2219
|
-
defaultMessage: `
|
2684
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2220
2685
|
},
|
2221
2686
|
{
|
2222
2687
|
time: /* @__PURE__ */ jsx(
|
@@ -2234,12 +2699,12 @@ const Information = ({ activeTab }) => {
|
|
2234
2699
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2235
2700
|
label: formatMessage({
|
2236
2701
|
id: "content-manager.containers.edit.information.document.label",
|
2237
|
-
defaultMessage: "
|
2702
|
+
defaultMessage: "Created"
|
2238
2703
|
}),
|
2239
2704
|
value: formatMessage(
|
2240
2705
|
{
|
2241
2706
|
id: "content-manager.containers.edit.information.document.value",
|
2242
|
-
defaultMessage: `
|
2707
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2243
2708
|
},
|
2244
2709
|
{
|
2245
2710
|
time: /* @__PURE__ */ jsx(
|
@@ -2277,25 +2742,77 @@ const Information = ({ activeTab }) => {
|
|
2277
2742
|
);
|
2278
2743
|
};
|
2279
2744
|
const HeaderActions = ({ actions: actions2 }) => {
|
2280
|
-
|
2281
|
-
|
2745
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2746
|
+
const handleClick = (action) => async (e) => {
|
2747
|
+
if (!("options" in action)) {
|
2748
|
+
const { onClick = () => false, dialog, id } = action;
|
2749
|
+
const muteDialog = await onClick(e);
|
2750
|
+
if (dialog && !muteDialog) {
|
2751
|
+
e.preventDefault();
|
2752
|
+
setDialogId(id);
|
2753
|
+
}
|
2754
|
+
}
|
2755
|
+
};
|
2756
|
+
const handleClose = () => {
|
2757
|
+
setDialogId(null);
|
2758
|
+
};
|
2759
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2760
|
+
if (action.options) {
|
2282
2761
|
return /* @__PURE__ */ jsx(
|
2283
2762
|
SingleSelect,
|
2284
2763
|
{
|
2285
2764
|
size: "S",
|
2286
|
-
disabled: action.disabled,
|
2287
|
-
"aria-label": action.label,
|
2288
2765
|
onChange: action.onSelect,
|
2289
|
-
|
2766
|
+
"aria-label": action.label,
|
2767
|
+
...action,
|
2290
2768
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2291
2769
|
},
|
2292
2770
|
action.id
|
2293
2771
|
);
|
2294
2772
|
} else {
|
2295
|
-
|
2773
|
+
if (action.type === "icon") {
|
2774
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2775
|
+
/* @__PURE__ */ jsx(
|
2776
|
+
IconButton,
|
2777
|
+
{
|
2778
|
+
disabled: action.disabled,
|
2779
|
+
label: action.label,
|
2780
|
+
size: "S",
|
2781
|
+
onClick: handleClick(action),
|
2782
|
+
children: action.icon
|
2783
|
+
}
|
2784
|
+
),
|
2785
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2786
|
+
HeaderActionDialog,
|
2787
|
+
{
|
2788
|
+
...action.dialog,
|
2789
|
+
isOpen: dialogId === action.id,
|
2790
|
+
onClose: handleClose
|
2791
|
+
}
|
2792
|
+
) : null
|
2793
|
+
] }, action.id);
|
2794
|
+
}
|
2296
2795
|
}
|
2297
2796
|
}) });
|
2298
2797
|
};
|
2798
|
+
const HeaderActionDialog = ({
|
2799
|
+
onClose,
|
2800
|
+
onCancel,
|
2801
|
+
title,
|
2802
|
+
content: Content,
|
2803
|
+
isOpen
|
2804
|
+
}) => {
|
2805
|
+
const handleClose = async () => {
|
2806
|
+
if (onCancel) {
|
2807
|
+
await onCancel();
|
2808
|
+
}
|
2809
|
+
onClose();
|
2810
|
+
};
|
2811
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2812
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2813
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2814
|
+
] }) });
|
2815
|
+
};
|
2299
2816
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2300
2817
|
const navigate = useNavigate();
|
2301
2818
|
const { formatMessage } = useIntl();
|
@@ -2336,12 +2853,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2336
2853
|
const { delete: deleteAction } = useDocumentActions();
|
2337
2854
|
const { toggleNotification } = useNotification();
|
2338
2855
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2856
|
+
const isLocalized = document?.locale != null;
|
2339
2857
|
return {
|
2340
2858
|
disabled: !canDelete || !document,
|
2341
|
-
label: formatMessage(
|
2342
|
-
|
2343
|
-
|
2344
|
-
|
2859
|
+
label: formatMessage(
|
2860
|
+
{
|
2861
|
+
id: "content-manager.actions.delete.label",
|
2862
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2863
|
+
},
|
2864
|
+
{ isLocalized }
|
2865
|
+
),
|
2345
2866
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2346
2867
|
dialog: {
|
2347
2868
|
type: "dialog",
|
@@ -2428,372 +2949,70 @@ const Panels = () => {
|
|
2428
2949
|
};
|
2429
2950
|
const ActionsPanel = () => {
|
2430
2951
|
const { formatMessage } = useIntl();
|
2431
|
-
return {
|
2432
|
-
title: formatMessage({
|
2433
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2434
|
-
defaultMessage: "
|
2435
|
-
}),
|
2436
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2437
|
-
};
|
2438
|
-
};
|
2439
|
-
ActionsPanel.type = "actions";
|
2440
|
-
const ActionsPanelContent = () => {
|
2441
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2442
|
-
const [
|
2443
|
-
{
|
2444
|
-
query: { status = "draft" }
|
2445
|
-
}
|
2446
|
-
] = useQueryParams();
|
2447
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2448
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2449
|
-
const props = {
|
2450
|
-
activeTab: status,
|
2451
|
-
model,
|
2452
|
-
documentId: id,
|
2453
|
-
document: isCloning ? void 0 : document,
|
2454
|
-
meta: isCloning ? void 0 : meta,
|
2455
|
-
collectionType
|
2456
|
-
};
|
2457
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2458
|
-
/* @__PURE__ */ jsx(
|
2459
|
-
DescriptionComponentRenderer,
|
2460
|
-
{
|
2461
|
-
props,
|
2462
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2463
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2464
|
-
}
|
2465
|
-
),
|
2466
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2467
|
-
] });
|
2468
|
-
};
|
2469
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2470
|
-
return /* @__PURE__ */ jsxs(
|
2471
|
-
Flex,
|
2472
|
-
{
|
2473
|
-
ref,
|
2474
|
-
tag: "aside",
|
2475
|
-
"aria-labelledby": "additional-information",
|
2476
|
-
background: "neutral0",
|
2477
|
-
borderColor: "neutral150",
|
2478
|
-
hasRadius: true,
|
2479
|
-
paddingBottom: 4,
|
2480
|
-
paddingLeft: 4,
|
2481
|
-
paddingRight: 4,
|
2482
|
-
paddingTop: 4,
|
2483
|
-
shadow: "tableShadow",
|
2484
|
-
gap: 3,
|
2485
|
-
direction: "column",
|
2486
|
-
justifyContent: "stretch",
|
2487
|
-
alignItems: "flex-start",
|
2488
|
-
children: [
|
2489
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2490
|
-
children
|
2491
|
-
]
|
2492
|
-
}
|
2493
|
-
);
|
2494
|
-
});
|
2495
|
-
const HOOKS = {
|
2496
|
-
/**
|
2497
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2498
|
-
* @constant
|
2499
|
-
* @type {string}
|
2500
|
-
*/
|
2501
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2502
|
-
/**
|
2503
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2504
|
-
* @constant
|
2505
|
-
* @type {string}
|
2506
|
-
*/
|
2507
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2508
|
-
/**
|
2509
|
-
* Hook that allows to mutate the CM's edit view layout
|
2510
|
-
* @constant
|
2511
|
-
* @type {string}
|
2512
|
-
*/
|
2513
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2514
|
-
/**
|
2515
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2516
|
-
* @constant
|
2517
|
-
* @type {string}
|
2518
|
-
*/
|
2519
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2520
|
-
};
|
2521
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2522
|
-
endpoints: (builder) => ({
|
2523
|
-
getContentTypeConfiguration: builder.query({
|
2524
|
-
query: (uid) => ({
|
2525
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2526
|
-
method: "GET"
|
2527
|
-
}),
|
2528
|
-
transformResponse: (response) => response.data,
|
2529
|
-
providesTags: (_result, _error, uid) => [
|
2530
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2531
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2532
|
-
]
|
2533
|
-
}),
|
2534
|
-
getAllContentTypeSettings: builder.query({
|
2535
|
-
query: () => "/content-manager/content-types-settings",
|
2536
|
-
transformResponse: (response) => response.data,
|
2537
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2538
|
-
}),
|
2539
|
-
updateContentTypeConfiguration: builder.mutation({
|
2540
|
-
query: ({ uid, ...body }) => ({
|
2541
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2542
|
-
method: "PUT",
|
2543
|
-
data: body
|
2544
|
-
}),
|
2545
|
-
transformResponse: (response) => response.data,
|
2546
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2547
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2548
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2549
|
-
// Is this necessary?
|
2550
|
-
{ type: "InitialData" }
|
2551
|
-
]
|
2552
|
-
})
|
2553
|
-
})
|
2554
|
-
});
|
2555
|
-
const {
|
2556
|
-
useGetContentTypeConfigurationQuery,
|
2557
|
-
useGetAllContentTypeSettingsQuery,
|
2558
|
-
useUpdateContentTypeConfigurationMutation
|
2559
|
-
} = contentTypesApi;
|
2560
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2561
|
-
const { type } = attribute;
|
2562
|
-
if (type === "relation") {
|
2563
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2564
|
-
}
|
2565
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2566
|
-
};
|
2567
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2568
|
-
if (!mainFieldName) {
|
2569
|
-
return void 0;
|
2570
|
-
}
|
2571
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2572
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2573
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2574
|
-
);
|
2575
|
-
return {
|
2576
|
-
name: mainFieldName,
|
2577
|
-
type: mainFieldType ?? "string"
|
2578
|
-
};
|
2579
|
-
};
|
2580
|
-
const DEFAULT_SETTINGS = {
|
2581
|
-
bulkable: false,
|
2582
|
-
filterable: false,
|
2583
|
-
searchable: false,
|
2584
|
-
pagination: false,
|
2585
|
-
defaultSortBy: "",
|
2586
|
-
defaultSortOrder: "asc",
|
2587
|
-
mainField: "id",
|
2588
|
-
pageSize: 10
|
2589
|
-
};
|
2590
|
-
const useDocumentLayout = (model) => {
|
2591
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2592
|
-
const [{ query }] = useQueryParams();
|
2593
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2594
|
-
const { toggleNotification } = useNotification();
|
2595
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2596
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2597
|
-
const {
|
2598
|
-
data,
|
2599
|
-
isLoading: isLoadingConfigs,
|
2600
|
-
error,
|
2601
|
-
isFetching: isFetchingConfigs
|
2602
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2603
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2604
|
-
React.useEffect(() => {
|
2605
|
-
if (error) {
|
2606
|
-
toggleNotification({
|
2607
|
-
type: "danger",
|
2608
|
-
message: formatAPIError(error)
|
2609
|
-
});
|
2610
|
-
}
|
2611
|
-
}, [error, formatAPIError, toggleNotification]);
|
2612
|
-
const editLayout = React.useMemo(
|
2613
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2614
|
-
layout: [],
|
2615
|
-
components: {},
|
2616
|
-
metadatas: {},
|
2617
|
-
options: {},
|
2618
|
-
settings: DEFAULT_SETTINGS
|
2619
|
-
},
|
2620
|
-
[data, isLoading, schemas, schema, components]
|
2621
|
-
);
|
2622
|
-
const listLayout = React.useMemo(() => {
|
2623
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2624
|
-
layout: [],
|
2625
|
-
metadatas: {},
|
2626
|
-
options: {},
|
2627
|
-
settings: DEFAULT_SETTINGS
|
2628
|
-
};
|
2629
|
-
}, [data, isLoading, schemas, schema, components]);
|
2630
|
-
const { layout: edit } = React.useMemo(
|
2631
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2632
|
-
layout: editLayout,
|
2633
|
-
query
|
2634
|
-
}),
|
2635
|
-
[editLayout, query, runHookWaterfall]
|
2636
|
-
);
|
2637
|
-
return {
|
2638
|
-
error,
|
2639
|
-
isLoading,
|
2640
|
-
edit,
|
2641
|
-
list: listLayout
|
2642
|
-
};
|
2643
|
-
};
|
2644
|
-
const useDocLayout = () => {
|
2645
|
-
const { model } = useDoc();
|
2646
|
-
return useDocumentLayout(model);
|
2647
|
-
};
|
2648
|
-
const formatEditLayout = (data, {
|
2649
|
-
schemas,
|
2650
|
-
schema,
|
2651
|
-
components
|
2652
|
-
}) => {
|
2653
|
-
let currentPanelIndex = 0;
|
2654
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2655
|
-
data.contentType.layouts.edit,
|
2656
|
-
schema?.attributes,
|
2657
|
-
data.contentType.metadatas,
|
2658
|
-
{ configurations: data.components, schemas: components },
|
2659
|
-
schemas
|
2660
|
-
).reduce((panels, row) => {
|
2661
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2662
|
-
panels.push([row]);
|
2663
|
-
currentPanelIndex += 2;
|
2664
|
-
} else {
|
2665
|
-
if (!panels[currentPanelIndex]) {
|
2666
|
-
panels.push([]);
|
2667
|
-
}
|
2668
|
-
panels[currentPanelIndex].push(row);
|
2669
|
-
}
|
2670
|
-
return panels;
|
2671
|
-
}, []);
|
2672
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2673
|
-
(acc, [uid, configuration]) => {
|
2674
|
-
acc[uid] = {
|
2675
|
-
layout: convertEditLayoutToFieldLayouts(
|
2676
|
-
configuration.layouts.edit,
|
2677
|
-
components[uid].attributes,
|
2678
|
-
configuration.metadatas
|
2679
|
-
),
|
2680
|
-
settings: {
|
2681
|
-
...configuration.settings,
|
2682
|
-
icon: components[uid].info.icon,
|
2683
|
-
displayName: components[uid].info.displayName
|
2684
|
-
}
|
2685
|
-
};
|
2686
|
-
return acc;
|
2687
|
-
},
|
2688
|
-
{}
|
2689
|
-
);
|
2690
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2691
|
-
(acc, [attribute, metadata]) => {
|
2692
|
-
return {
|
2693
|
-
...acc,
|
2694
|
-
[attribute]: metadata.edit
|
2695
|
-
};
|
2696
|
-
},
|
2697
|
-
{}
|
2698
|
-
);
|
2699
|
-
return {
|
2700
|
-
layout: panelledEditAttributes,
|
2701
|
-
components: componentEditAttributes,
|
2702
|
-
metadatas: editMetadatas,
|
2703
|
-
settings: {
|
2704
|
-
...data.contentType.settings,
|
2705
|
-
displayName: schema?.info.displayName
|
2706
|
-
},
|
2707
|
-
options: {
|
2708
|
-
...schema?.options,
|
2709
|
-
...schema?.pluginOptions,
|
2710
|
-
...data.contentType.options
|
2711
|
-
}
|
2712
|
-
};
|
2713
|
-
};
|
2714
|
-
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
2715
|
-
return rows.map(
|
2716
|
-
(row) => row.map((field) => {
|
2717
|
-
const attribute = attributes[field.name];
|
2718
|
-
if (!attribute) {
|
2719
|
-
return null;
|
2720
|
-
}
|
2721
|
-
const { edit: metadata } = metadatas[field.name];
|
2722
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2723
|
-
return {
|
2724
|
-
attribute,
|
2725
|
-
disabled: !metadata.editable,
|
2726
|
-
hint: metadata.description,
|
2727
|
-
label: metadata.label ?? "",
|
2728
|
-
name: field.name,
|
2729
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2730
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2731
|
-
schemas,
|
2732
|
-
components: components?.schemas ?? {}
|
2733
|
-
}),
|
2734
|
-
placeholder: metadata.placeholder ?? "",
|
2735
|
-
required: attribute.required ?? false,
|
2736
|
-
size: field.size,
|
2737
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2738
|
-
visible: metadata.visible ?? true,
|
2739
|
-
type: attribute.type
|
2740
|
-
};
|
2741
|
-
}).filter((field) => field !== null)
|
2742
|
-
);
|
2743
|
-
};
|
2744
|
-
const formatListLayout = (data, {
|
2745
|
-
schemas,
|
2746
|
-
schema,
|
2747
|
-
components
|
2748
|
-
}) => {
|
2749
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2750
|
-
(acc, [attribute, metadata]) => {
|
2751
|
-
return {
|
2752
|
-
...acc,
|
2753
|
-
[attribute]: metadata.list
|
2754
|
-
};
|
2755
|
-
},
|
2756
|
-
{}
|
2757
|
-
);
|
2758
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2759
|
-
data.contentType.layouts.list,
|
2760
|
-
schema?.attributes,
|
2761
|
-
listMetadatas,
|
2762
|
-
{ configurations: data.components, schemas: components },
|
2763
|
-
schemas
|
2764
|
-
);
|
2765
|
-
return {
|
2766
|
-
layout: listAttributes,
|
2767
|
-
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
2768
|
-
metadatas: listMetadatas,
|
2769
|
-
options: {
|
2770
|
-
...schema?.options,
|
2771
|
-
...schema?.pluginOptions,
|
2772
|
-
...data.contentType.options
|
2773
|
-
}
|
2952
|
+
return {
|
2953
|
+
title: formatMessage({
|
2954
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2955
|
+
defaultMessage: "Entry"
|
2956
|
+
}),
|
2957
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2774
2958
|
};
|
2775
2959
|
};
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2780
|
-
|
2960
|
+
ActionsPanel.type = "actions";
|
2961
|
+
const ActionsPanelContent = () => {
|
2962
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2963
|
+
const [
|
2964
|
+
{
|
2965
|
+
query: { status = "draft" }
|
2781
2966
|
}
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2967
|
+
] = useQueryParams();
|
2968
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2969
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2970
|
+
const props = {
|
2971
|
+
activeTab: status,
|
2972
|
+
model,
|
2973
|
+
documentId: id,
|
2974
|
+
document: isCloning ? void 0 : document,
|
2975
|
+
meta: isCloning ? void 0 : meta,
|
2976
|
+
collectionType
|
2977
|
+
};
|
2978
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2979
|
+
/* @__PURE__ */ jsx(
|
2980
|
+
DescriptionComponentRenderer,
|
2981
|
+
{
|
2982
|
+
props,
|
2983
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2984
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2985
|
+
}
|
2986
|
+
),
|
2987
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2988
|
+
] });
|
2796
2989
|
};
|
2990
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2991
|
+
return /* @__PURE__ */ jsxs(
|
2992
|
+
Flex,
|
2993
|
+
{
|
2994
|
+
ref,
|
2995
|
+
tag: "aside",
|
2996
|
+
"aria-labelledby": "additional-information",
|
2997
|
+
background: "neutral0",
|
2998
|
+
borderColor: "neutral150",
|
2999
|
+
hasRadius: true,
|
3000
|
+
paddingBottom: 4,
|
3001
|
+
paddingLeft: 4,
|
3002
|
+
paddingRight: 4,
|
3003
|
+
paddingTop: 4,
|
3004
|
+
shadow: "tableShadow",
|
3005
|
+
gap: 3,
|
3006
|
+
direction: "column",
|
3007
|
+
justifyContent: "stretch",
|
3008
|
+
alignItems: "flex-start",
|
3009
|
+
children: [
|
3010
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3011
|
+
children
|
3012
|
+
]
|
3013
|
+
}
|
3014
|
+
);
|
3015
|
+
});
|
2797
3016
|
const ConfirmBulkActionDialog = ({
|
2798
3017
|
onToggleDialog,
|
2799
3018
|
isOpen = false,
|
@@ -2801,30 +3020,23 @@ const ConfirmBulkActionDialog = ({
|
|
2801
3020
|
endAction
|
2802
3021
|
}) => {
|
2803
3022
|
const { formatMessage } = useIntl();
|
2804
|
-
return /* @__PURE__ */ jsxs(
|
2805
|
-
Dialog,
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2820
|
-
|
2821
|
-
}) }),
|
2822
|
-
endAction
|
2823
|
-
}
|
2824
|
-
)
|
2825
|
-
]
|
2826
|
-
}
|
2827
|
-
);
|
3023
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3024
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
3025
|
+
id: "app.components.ConfirmDialog.title",
|
3026
|
+
defaultMessage: "Confirmation"
|
3027
|
+
}) }),
|
3028
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3029
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3030
|
+
dialogBody
|
3031
|
+
] }) }),
|
3032
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
3033
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
3034
|
+
id: "app.components.Button.cancel",
|
3035
|
+
defaultMessage: "Cancel"
|
3036
|
+
}) }) }),
|
3037
|
+
endAction
|
3038
|
+
] })
|
3039
|
+
] }) });
|
2828
3040
|
};
|
2829
3041
|
const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
2830
3042
|
const ConfirmDialogPublishAll = ({
|
@@ -2839,6 +3051,7 @@ const ConfirmDialogPublishAll = ({
|
|
2839
3051
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2840
3052
|
const { model, schema } = useDoc();
|
2841
3053
|
const [{ query }] = useQueryParams();
|
3054
|
+
const enableDraftRelationsCount = false;
|
2842
3055
|
const {
|
2843
3056
|
data: countDraftRelations = 0,
|
2844
3057
|
isLoading,
|
@@ -2850,7 +3063,7 @@ const ConfirmDialogPublishAll = ({
|
|
2850
3063
|
locale: query?.plugins?.i18n?.locale
|
2851
3064
|
},
|
2852
3065
|
{
|
2853
|
-
skip:
|
3066
|
+
skip: !enableDraftRelationsCount
|
2854
3067
|
}
|
2855
3068
|
);
|
2856
3069
|
React.useEffect(() => {
|
@@ -2929,7 +3142,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2929
3142
|
)
|
2930
3143
|
);
|
2931
3144
|
} else {
|
2932
|
-
messages.push(
|
3145
|
+
messages.push(
|
3146
|
+
...formatErrorMessages(
|
3147
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3148
|
+
value,
|
3149
|
+
currentKey,
|
3150
|
+
formatMessage
|
3151
|
+
)
|
3152
|
+
);
|
2933
3153
|
}
|
2934
3154
|
} else {
|
2935
3155
|
messages.push(
|
@@ -3028,7 +3248,7 @@ const SelectedEntriesTableContent = ({
|
|
3028
3248
|
status: row.status
|
3029
3249
|
}
|
3030
3250
|
) }),
|
3031
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3251
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3032
3252
|
IconButton,
|
3033
3253
|
{
|
3034
3254
|
tag: Link,
|
@@ -3051,9 +3271,10 @@ const SelectedEntriesTableContent = ({
|
|
3051
3271
|
),
|
3052
3272
|
target: "_blank",
|
3053
3273
|
marginLeft: "auto",
|
3054
|
-
|
3274
|
+
variant: "ghost",
|
3275
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3055
3276
|
}
|
3056
|
-
) })
|
3277
|
+
) }) })
|
3057
3278
|
] }, row.id)) })
|
3058
3279
|
] });
|
3059
3280
|
};
|
@@ -3090,7 +3311,13 @@ const SelectedEntriesModalContent = ({
|
|
3090
3311
|
);
|
3091
3312
|
const { rows, validationErrors } = React.useMemo(() => {
|
3092
3313
|
if (data.length > 0 && schema) {
|
3093
|
-
const validate = createYupSchema(
|
3314
|
+
const validate = createYupSchema(
|
3315
|
+
schema.attributes,
|
3316
|
+
components,
|
3317
|
+
// Since this is the "Publish" action, the validation
|
3318
|
+
// schema must enforce the rules for published entities
|
3319
|
+
{ status: "published" }
|
3320
|
+
);
|
3094
3321
|
const validationErrors2 = {};
|
3095
3322
|
const rows2 = data.map((entry) => {
|
3096
3323
|
try {
|
@@ -3166,7 +3393,7 @@ const SelectedEntriesModalContent = ({
|
|
3166
3393
|
);
|
3167
3394
|
};
|
3168
3395
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3169
|
-
/* @__PURE__ */ jsxs(
|
3396
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3170
3397
|
/* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
|
3171
3398
|
/* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
|
3172
3399
|
SelectedEntriesTableContent,
|
@@ -3178,27 +3405,24 @@ const SelectedEntriesModalContent = ({
|
|
3178
3405
|
}
|
3179
3406
|
) })
|
3180
3407
|
] }),
|
3181
|
-
/* @__PURE__ */
|
3182
|
-
|
3183
|
-
|
3184
|
-
|
3185
|
-
|
3186
|
-
|
3187
|
-
}) }),
|
3188
|
-
|
3189
|
-
|
3190
|
-
|
3191
|
-
|
3192
|
-
|
3193
|
-
|
3194
|
-
|
3195
|
-
|
3196
|
-
|
3197
|
-
|
3198
|
-
|
3199
|
-
] })
|
3200
|
-
}
|
3201
|
-
),
|
3408
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3409
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3410
|
+
id: "app.components.Button.cancel",
|
3411
|
+
defaultMessage: "Cancel"
|
3412
|
+
}) }),
|
3413
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3414
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3415
|
+
/* @__PURE__ */ jsx(
|
3416
|
+
Button,
|
3417
|
+
{
|
3418
|
+
onClick: toggleDialog,
|
3419
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
|
3420
|
+
loading: isSubmittingForm,
|
3421
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3422
|
+
}
|
3423
|
+
)
|
3424
|
+
] })
|
3425
|
+
] }),
|
3202
3426
|
/* @__PURE__ */ jsx(
|
3203
3427
|
ConfirmDialogPublishAll,
|
3204
3428
|
{
|
@@ -3263,143 +3487,10 @@ const BulkActionsRenderer = () => {
|
|
3263
3487
|
documents: selectedRows
|
3264
3488
|
},
|
3265
3489
|
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3266
|
-
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(
|
3490
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
3267
3491
|
}
|
3268
3492
|
) });
|
3269
3493
|
};
|
3270
|
-
const BulkActionAction = (action) => {
|
3271
|
-
const [dialogId, setDialogId] = React.useState(null);
|
3272
|
-
const { toggleNotification } = useNotification();
|
3273
|
-
const handleClick = (action2) => (e) => {
|
3274
|
-
const { onClick, dialog, id } = action2;
|
3275
|
-
if (onClick) {
|
3276
|
-
onClick(e);
|
3277
|
-
}
|
3278
|
-
if (dialog) {
|
3279
|
-
switch (dialog.type) {
|
3280
|
-
case "notification":
|
3281
|
-
toggleNotification({
|
3282
|
-
title: dialog.title,
|
3283
|
-
message: dialog.content,
|
3284
|
-
type: dialog.status,
|
3285
|
-
timeout: dialog.timeout,
|
3286
|
-
onClose: dialog.onClose
|
3287
|
-
});
|
3288
|
-
break;
|
3289
|
-
case "dialog":
|
3290
|
-
case "modal": {
|
3291
|
-
e.preventDefault();
|
3292
|
-
setDialogId(id);
|
3293
|
-
}
|
3294
|
-
}
|
3295
|
-
}
|
3296
|
-
};
|
3297
|
-
const handleClose = () => {
|
3298
|
-
setDialogId(null);
|
3299
|
-
if (action.dialog?.type === "modal" && action.dialog?.onClose) {
|
3300
|
-
action.dialog.onClose();
|
3301
|
-
}
|
3302
|
-
};
|
3303
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3304
|
-
/* @__PURE__ */ jsx(
|
3305
|
-
Button,
|
3306
|
-
{
|
3307
|
-
disabled: action.disabled,
|
3308
|
-
startIcon: action.icon,
|
3309
|
-
variant: action.variant,
|
3310
|
-
onClick: handleClick(action),
|
3311
|
-
children: action.label
|
3312
|
-
}
|
3313
|
-
),
|
3314
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
3315
|
-
BulkActionConfirmDialog,
|
3316
|
-
{
|
3317
|
-
...action.dialog,
|
3318
|
-
variant: action.variant,
|
3319
|
-
isOpen: dialogId === action.id,
|
3320
|
-
onClose: handleClose
|
3321
|
-
}
|
3322
|
-
) : null,
|
3323
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
3324
|
-
BulkActionModal,
|
3325
|
-
{
|
3326
|
-
...action.dialog,
|
3327
|
-
onModalClose: handleClose,
|
3328
|
-
isOpen: dialogId === action.id
|
3329
|
-
}
|
3330
|
-
) : null
|
3331
|
-
] });
|
3332
|
-
};
|
3333
|
-
const BulkActionConfirmDialog = ({
|
3334
|
-
onClose,
|
3335
|
-
onCancel,
|
3336
|
-
onConfirm,
|
3337
|
-
title,
|
3338
|
-
content,
|
3339
|
-
confirmButton,
|
3340
|
-
isOpen,
|
3341
|
-
variant = "secondary"
|
3342
|
-
}) => {
|
3343
|
-
const { formatMessage } = useIntl();
|
3344
|
-
const handleClose = async () => {
|
3345
|
-
if (onCancel) {
|
3346
|
-
await onCancel();
|
3347
|
-
}
|
3348
|
-
onClose();
|
3349
|
-
};
|
3350
|
-
const handleConfirm = async () => {
|
3351
|
-
if (onConfirm) {
|
3352
|
-
await onConfirm();
|
3353
|
-
}
|
3354
|
-
onClose();
|
3355
|
-
};
|
3356
|
-
return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
|
3357
|
-
/* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
|
3358
|
-
/* @__PURE__ */ jsx(
|
3359
|
-
DialogFooter,
|
3360
|
-
{
|
3361
|
-
startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
|
3362
|
-
id: "app.components.Button.cancel",
|
3363
|
-
defaultMessage: "Cancel"
|
3364
|
-
}) }),
|
3365
|
-
endAction: /* @__PURE__ */ jsx(
|
3366
|
-
Button,
|
3367
|
-
{
|
3368
|
-
onClick: handleConfirm,
|
3369
|
-
variant: variant === "danger-light" ? variant : "secondary",
|
3370
|
-
startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
|
3371
|
-
children: confirmButton ? confirmButton : formatMessage({
|
3372
|
-
id: "app.components.Button.confirm",
|
3373
|
-
defaultMessage: "Confirm"
|
3374
|
-
})
|
3375
|
-
}
|
3376
|
-
)
|
3377
|
-
}
|
3378
|
-
)
|
3379
|
-
] });
|
3380
|
-
};
|
3381
|
-
const BulkActionModal = ({
|
3382
|
-
isOpen,
|
3383
|
-
title,
|
3384
|
-
onClose,
|
3385
|
-
content: Content,
|
3386
|
-
onModalClose
|
3387
|
-
}) => {
|
3388
|
-
const id = React.useId();
|
3389
|
-
if (!isOpen) {
|
3390
|
-
return null;
|
3391
|
-
}
|
3392
|
-
const handleClose = () => {
|
3393
|
-
if (onClose) {
|
3394
|
-
onClose();
|
3395
|
-
}
|
3396
|
-
onModalClose();
|
3397
|
-
};
|
3398
|
-
return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
|
3399
|
-
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
|
3400
|
-
/* @__PURE__ */ jsx(Content, { onClose: handleClose })
|
3401
|
-
] });
|
3402
|
-
};
|
3403
3494
|
const DeleteAction = ({ documents, model }) => {
|
3404
3495
|
const { formatMessage } = useIntl();
|
3405
3496
|
const { schema: contentType } = useDoc();
|
@@ -3432,6 +3523,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
3432
3523
|
defaultMessage: "Confirmation"
|
3433
3524
|
}),
|
3434
3525
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3526
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3435
3527
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3436
3528
|
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
3437
3529
|
defaultMessage: "Are you sure you want to delete these entries?"
|
@@ -3481,6 +3573,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3481
3573
|
defaultMessage: "Confirmation"
|
3482
3574
|
}),
|
3483
3575
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3576
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3484
3577
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3485
3578
|
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
3486
3579
|
defaultMessage: "Are you sure you want to unpublish these entries?"
|
@@ -3574,7 +3667,7 @@ const TableActions = ({ document }) => {
|
|
3574
3667
|
DescriptionComponentRenderer,
|
3575
3668
|
{
|
3576
3669
|
props,
|
3577
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3670
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3578
3671
|
children: (actions2) => {
|
3579
3672
|
const tableRowActions = actions2.filter((action) => {
|
3580
3673
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3685,7 +3778,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3685
3778
|
}),
|
3686
3779
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3687
3780
|
footer: ({ onClose }) => {
|
3688
|
-
return /* @__PURE__ */ jsxs(
|
3781
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3689
3782
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3690
3783
|
id: "cancel",
|
3691
3784
|
defaultMessage: "Cancel"
|
@@ -3726,8 +3819,7 @@ class ContentManagerPlugin {
|
|
3726
3819
|
documentActions = [
|
3727
3820
|
...DEFAULT_ACTIONS,
|
3728
3821
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3729
|
-
...DEFAULT_HEADER_ACTIONS
|
3730
|
-
HistoryAction
|
3822
|
+
...DEFAULT_HEADER_ACTIONS
|
3731
3823
|
];
|
3732
3824
|
editViewSidePanels = [ActionsPanel];
|
3733
3825
|
headerActions = [];
|
@@ -3816,6 +3908,52 @@ const getPrintableType = (value) => {
|
|
3816
3908
|
}
|
3817
3909
|
return nativeType;
|
3818
3910
|
};
|
3911
|
+
const HistoryAction = ({ model, document }) => {
|
3912
|
+
const { formatMessage } = useIntl();
|
3913
|
+
const [{ query }] = useQueryParams();
|
3914
|
+
const navigate = useNavigate();
|
3915
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3916
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3917
|
+
return null;
|
3918
|
+
}
|
3919
|
+
return {
|
3920
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3921
|
+
label: formatMessage({
|
3922
|
+
id: "content-manager.history.document-action",
|
3923
|
+
defaultMessage: "Content History"
|
3924
|
+
}),
|
3925
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3926
|
+
disabled: (
|
3927
|
+
/**
|
3928
|
+
* The user is creating a new document.
|
3929
|
+
* It hasn't been saved yet, so there's no history to go to
|
3930
|
+
*/
|
3931
|
+
!document || /**
|
3932
|
+
* The document has been created but the current dimension has never been saved.
|
3933
|
+
* For example, the user is creating a new locale in an existing document,
|
3934
|
+
* so there's no history for the document in that locale
|
3935
|
+
*/
|
3936
|
+
!document.id || /**
|
3937
|
+
* History is only available for content types created by the user.
|
3938
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3939
|
+
* which start with `admin::` or `plugin::`
|
3940
|
+
*/
|
3941
|
+
!model.startsWith("api::")
|
3942
|
+
),
|
3943
|
+
position: "header"
|
3944
|
+
};
|
3945
|
+
};
|
3946
|
+
HistoryAction.type = "history";
|
3947
|
+
const historyAdmin = {
|
3948
|
+
bootstrap(app) {
|
3949
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3950
|
+
addDocumentAction((actions2) => {
|
3951
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3952
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3953
|
+
return actions2;
|
3954
|
+
});
|
3955
|
+
}
|
3956
|
+
};
|
3819
3957
|
const initialState = {
|
3820
3958
|
collectionTypeLinks: [],
|
3821
3959
|
components: [],
|
@@ -3866,15 +4004,29 @@ const index = {
|
|
3866
4004
|
defaultMessage: "Content Manager"
|
3867
4005
|
},
|
3868
4006
|
permissions: [],
|
3869
|
-
Component: () => import("./layout-BzAbmoO6.mjs").then((mod) => ({ default: mod.Layout })),
|
3870
4007
|
position: 1
|
3871
4008
|
});
|
4009
|
+
app.router.addRoute({
|
4010
|
+
path: "content-manager/*",
|
4011
|
+
lazy: async () => {
|
4012
|
+
const { Layout } = await import("./layout-2CfjL0T9.mjs");
|
4013
|
+
return {
|
4014
|
+
Component: Layout
|
4015
|
+
};
|
4016
|
+
},
|
4017
|
+
children: routes
|
4018
|
+
});
|
3872
4019
|
app.registerPlugin(cm.config);
|
3873
4020
|
},
|
4021
|
+
bootstrap(app) {
|
4022
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4023
|
+
historyAdmin.bootstrap(app);
|
4024
|
+
}
|
4025
|
+
},
|
3874
4026
|
async registerTrads({ locales }) {
|
3875
4027
|
const importedTrads = await Promise.all(
|
3876
4028
|
locales.map((locale) => {
|
3877
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-
|
4029
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-DKV44jRb.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
|
3878
4030
|
return {
|
3879
4031
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3880
4032
|
locale
|
@@ -3902,7 +4054,8 @@ export {
|
|
3902
4054
|
InjectionZone as I,
|
3903
4055
|
useDocument as J,
|
3904
4056
|
index as K,
|
3905
|
-
|
4057
|
+
useContentManagerContext as L,
|
4058
|
+
useDocumentActions as M,
|
3906
4059
|
Panels as P,
|
3907
4060
|
RelativeTime as R,
|
3908
4061
|
SINGLE_TYPES as S,
|
@@ -3920,11 +4073,11 @@ export {
|
|
3920
4073
|
PERMISSIONS as k,
|
3921
4074
|
DocumentRBAC as l,
|
3922
4075
|
DOCUMENT_META_FIELDS as m,
|
3923
|
-
|
3924
|
-
|
3925
|
-
|
3926
|
-
|
3927
|
-
|
4076
|
+
CLONE_PATH as n,
|
4077
|
+
useDocLayout as o,
|
4078
|
+
useGetContentTypeConfigurationQuery as p,
|
4079
|
+
CREATOR_FIELDS as q,
|
4080
|
+
getMainField as r,
|
3928
4081
|
setInitialData as s,
|
3929
4082
|
getDisplayName as t,
|
3930
4083
|
useContentTypeSchema as u,
|
@@ -3934,4 +4087,4 @@ export {
|
|
3934
4087
|
capitalise as y,
|
3935
4088
|
useUpdateContentTypeConfigurationMutation as z
|
3936
4089
|
};
|
3937
|
-
//# sourceMappingURL=index-
|
4090
|
+
//# sourceMappingURL=index-wnqzm4Q8.mjs.map
|