@strapi/content-manager 0.0.0-experimental.59ce88771272039a9d868fba2f7b503edf715c6a → 0.0.0-experimental.5a6cf698f4104d2c95bb57a4c7beaca233d26e5a
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-gdUj_t-O.mjs → ComponentConfigurationPage-DfFSZQxe.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-gdUj_t-O.mjs.map → ComponentConfigurationPage-DfFSZQxe.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js → ComponentConfigurationPage-FqfsxQ1j.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-WRPUXGd6.js.map → ComponentConfigurationPage-FqfsxQ1j.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js → EditConfigurationPage-Cn0e8t3I.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-C1vjMBgy.js.map → EditConfigurationPage-Cn0e8t3I.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs → EditConfigurationPage-DdPNAbl3.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BwuIPOJG.mjs.map → EditConfigurationPage-DdPNAbl3.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-0MiFkXa8.mjs → EditViewPage-B82x_x1b.mjs} +30 -9
- package/dist/_chunks/EditViewPage-B82x_x1b.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-DbcGfyqK.js → EditViewPage-DlxEHhUt.js} +30 -9
- package/dist/_chunks/EditViewPage-DlxEHhUt.js.map +1 -0
- package/dist/_chunks/{Field-BG1xu38N.js → Field-COL25JiC.js} +519 -155
- package/dist/_chunks/Field-COL25JiC.js.map +1 -0
- package/dist/_chunks/{Field-BDMSCcy5.mjs → Field-DufHXW17.mjs} +517 -153
- package/dist/_chunks/Field-DufHXW17.mjs.map +1 -0
- package/dist/_chunks/{Form-9BnFyUjy.js → Form-BssUwrTO.js} +40 -18
- package/dist/_chunks/Form-BssUwrTO.js.map +1 -0
- package/dist/_chunks/{Form-CPVWavB8.mjs → Form-u_kAOhwB.mjs} +40 -18
- package/dist/_chunks/Form-u_kAOhwB.mjs.map +1 -0
- package/dist/_chunks/{History-BWWxLt2Z.js → History-C9t9UqpO.js} +63 -25
- package/dist/_chunks/History-C9t9UqpO.js.map +1 -0
- package/dist/_chunks/{History-BVpd8LP3.mjs → History-DRwA3oMM.mjs} +64 -26
- package/dist/_chunks/History-DRwA3oMM.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-6swzjdAZ.js → ListConfigurationPage-BXYPohh-.js} +20 -8
- package/dist/_chunks/ListConfigurationPage-BXYPohh-.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DozVMKcR.mjs → ListConfigurationPage-BxfQJzPk.mjs} +20 -8
- package/dist/_chunks/ListConfigurationPage-BxfQJzPk.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-Ds0ulgfG.mjs → ListViewPage-CELx2ysp.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CELx2ysp.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BlzfjS2Q.js → ListViewPage-D2VD8Szg.js} +61 -43
- package/dist/_chunks/ListViewPage-D2VD8Szg.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js → NoContentTypePage-BV9IjJSM.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-D2nCCWEl.js.map → NoContentTypePage-BV9IjJSM.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs → NoContentTypePage-DtJ9jcfk.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-BH11kaKt.mjs.map → NoContentTypePage-DtJ9jcfk.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs → NoPermissionsPage-DWleVYK7.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BT2Tn0D_.mjs.map → NoPermissionsPage-DWleVYK7.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js → NoPermissionsPage-Dp8NpF9I.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DN_JlsU2.js.map → NoPermissionsPage-Dp8NpF9I.js.map} +1 -1
- package/dist/_chunks/{Relations-Dnag3fhV.mjs → Relations-BTcf5xaw.mjs} +33 -24
- package/dist/_chunks/Relations-BTcf5xaw.mjs.map +1 -0
- package/dist/_chunks/{Relations-CcgFTcWo.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-CWpLBSt0.js → index-BdMf2lfT.js} +989 -658
- package/dist/_chunks/index-BdMf2lfT.js.map +1 -0
- package/dist/_chunks/{index-JNNNKUHs.mjs → index-wnqzm4Q8.mjs} +997 -666
- package/dist/_chunks/index-wnqzm4Q8.mjs.map +1 -0
- package/dist/_chunks/{layout-DC503LnF.mjs → layout-2CfjL0T9.mjs} +27 -14
- package/dist/_chunks/layout-2CfjL0T9.mjs.map +1 -0
- package/dist/_chunks/{layout--iHdZzRk.js → layout-B2MyZU-_.js} +25 -12
- package/dist/_chunks/layout-B2MyZU-_.js.map +1 -0
- package/dist/_chunks/{relations-BbHizA5K.js → relations-BH7JJGGe.js} +2 -2
- package/dist/_chunks/{relations-BbHizA5K.js.map → relations-BH7JJGGe.js.map} +1 -1
- package/dist/_chunks/{relations-CTje5t-a.mjs → relations-C0w0GcXi.mjs} +2 -2
- package/dist/_chunks/{relations-CTje5t-a.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 +1 -0
- 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 +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -17
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +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-0MiFkXa8.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DbcGfyqK.js.map +0 -1
- package/dist/_chunks/Field-BDMSCcy5.mjs.map +0 -1
- package/dist/_chunks/Field-BG1xu38N.js.map +0 -1
- package/dist/_chunks/Form-9BnFyUjy.js.map +0 -1
- package/dist/_chunks/Form-CPVWavB8.mjs.map +0 -1
- package/dist/_chunks/History-BVpd8LP3.mjs.map +0 -1
- package/dist/_chunks/History-BWWxLt2Z.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-6swzjdAZ.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DozVMKcR.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BlzfjS2Q.js.map +0 -1
- package/dist/_chunks/ListViewPage-Ds0ulgfG.mjs.map +0 -1
- package/dist/_chunks/Relations-CcgFTcWo.js.map +0 -1
- package/dist/_chunks/Relations-Dnag3fhV.mjs.map +0 -1
- package/dist/_chunks/index-CWpLBSt0.js.map +0 -1
- package/dist/_chunks/index-JNNNKUHs.mjs.map +0 -1
- package/dist/_chunks/layout--iHdZzRk.js.map +0 -1
- package/dist/_chunks/layout-DC503LnF.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,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 { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, SingleSelect, SingleSelectOption,
|
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,
|
@@ -1596,11 +2025,11 @@ const DocumentActionConfirmDialog = ({
|
|
1596
2025
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1597
2026
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1598
2027
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1599
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2028
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1600
2029
|
id: "app.components.Button.cancel",
|
1601
2030
|
defaultMessage: "Cancel"
|
1602
2031
|
}) }) }),
|
1603
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2032
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1604
2033
|
id: "app.components.Button.confirm",
|
1605
2034
|
defaultMessage: "Confirm"
|
1606
2035
|
}) })
|
@@ -1639,13 +2068,17 @@ const PublishAction$1 = ({
|
|
1639
2068
|
const navigate = useNavigate();
|
1640
2069
|
const { toggleNotification } = useNotification();
|
1641
2070
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2071
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1642
2072
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1643
2073
|
const { formatMessage } = useIntl();
|
1644
|
-
const { canPublish
|
1645
|
-
"PublishAction",
|
1646
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1647
|
-
);
|
2074
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1648
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);
|
1649
2082
|
const [{ query, rawQuery }] = useQueryParams();
|
1650
2083
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1651
2084
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1654,10 +2087,105 @@ const PublishAction$1 = ({
|
|
1654
2087
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1655
2088
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1656
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]);
|
1657
2145
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1658
2146
|
if (!schema?.options?.draftAndPublish) {
|
1659
2147
|
return null;
|
1660
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;
|
1661
2189
|
return {
|
1662
2190
|
/**
|
1663
2191
|
* Disabled when:
|
@@ -1667,49 +2195,36 @@ const PublishAction$1 = ({
|
|
1667
2195
|
* - the document is already published & not modified
|
1668
2196
|
* - the document is being created & not modified
|
1669
2197
|
* - the user doesn't have the permission to publish
|
1670
|
-
* - the user doesn't have the permission to create a new document
|
1671
|
-
* - the user doesn't have the permission to update the document
|
1672
2198
|
*/
|
1673
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2199
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1674
2200
|
label: formatMessage({
|
1675
2201
|
id: "app.utils.publish",
|
1676
2202
|
defaultMessage: "Publish"
|
1677
2203
|
}),
|
1678
2204
|
onClick: async () => {
|
1679
|
-
|
1680
|
-
|
1681
|
-
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
documentId,
|
1697
|
-
params
|
1698
|
-
},
|
1699
|
-
formValues
|
1700
|
-
);
|
1701
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1702
|
-
navigate({
|
1703
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1704
|
-
search: rawQuery
|
1705
|
-
});
|
1706
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1707
|
-
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
|
1708
2222
|
}
|
1709
|
-
|
1710
|
-
|
2223
|
+
),
|
2224
|
+
onConfirm: async () => {
|
2225
|
+
await performPublish();
|
1711
2226
|
}
|
1712
|
-
}
|
2227
|
+
} : void 0
|
1713
2228
|
};
|
1714
2229
|
};
|
1715
2230
|
PublishAction$1.type = "publish";
|
@@ -1725,10 +2240,6 @@ const UpdateAction = ({
|
|
1725
2240
|
const cloneMatch = useMatch(CLONE_PATH);
|
1726
2241
|
const isCloning = cloneMatch !== null;
|
1727
2242
|
const { formatMessage } = useIntl();
|
1728
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1729
|
-
canCreate: canCreate2,
|
1730
|
-
canUpdate: canUpdate2
|
1731
|
-
}));
|
1732
2243
|
const { create, update, clone } = useDocumentActions();
|
1733
2244
|
const [{ query, rawQuery }] = useQueryParams();
|
1734
2245
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1745,10 +2256,8 @@ const UpdateAction = ({
|
|
1745
2256
|
* - the form is submitting
|
1746
2257
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1747
2258
|
* - the active tab is the published tab
|
1748
|
-
* - the user doesn't have the permission to create a new document
|
1749
|
-
* - the user doesn't have the permission to update the document
|
1750
2259
|
*/
|
1751
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2260
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1752
2261
|
label: formatMessage({
|
1753
2262
|
id: "content-manager.containers.Edit.save",
|
1754
2263
|
defaultMessage: "Save"
|
@@ -1756,7 +2265,9 @@ const UpdateAction = ({
|
|
1756
2265
|
onClick: async () => {
|
1757
2266
|
setSubmitting(true);
|
1758
2267
|
try {
|
1759
|
-
const { errors } = await validate(
|
2268
|
+
const { errors } = await validate(true, {
|
2269
|
+
status: "draft"
|
2270
|
+
});
|
1760
2271
|
if (errors) {
|
1761
2272
|
toggleNotification({
|
1762
2273
|
type: "danger",
|
@@ -1777,10 +2288,13 @@ const UpdateAction = ({
|
|
1777
2288
|
document
|
1778
2289
|
);
|
1779
2290
|
if ("data" in res) {
|
1780
|
-
navigate(
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
2291
|
+
navigate(
|
2292
|
+
{
|
2293
|
+
pathname: `../${res.data.documentId}`,
|
2294
|
+
search: rawQuery
|
2295
|
+
},
|
2296
|
+
{ relative: "path" }
|
2297
|
+
);
|
1784
2298
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1785
2299
|
setErrors(formatValidationErrors(res.error));
|
1786
2300
|
}
|
@@ -1808,10 +2322,13 @@ const UpdateAction = ({
|
|
1808
2322
|
document
|
1809
2323
|
);
|
1810
2324
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1811
|
-
navigate(
|
1812
|
-
|
1813
|
-
|
1814
|
-
|
2325
|
+
navigate(
|
2326
|
+
{
|
2327
|
+
pathname: `../${res.data.documentId}`,
|
2328
|
+
search: rawQuery
|
2329
|
+
},
|
2330
|
+
{ replace: true, relative: "path" }
|
2331
|
+
);
|
1815
2332
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1816
2333
|
setErrors(formatValidationErrors(res.error));
|
1817
2334
|
}
|
@@ -1855,7 +2372,7 @@ const UnpublishAction$1 = ({
|
|
1855
2372
|
id: "app.utils.unpublish",
|
1856
2373
|
defaultMessage: "Unpublish"
|
1857
2374
|
}),
|
1858
|
-
icon: /* @__PURE__ */ jsx(
|
2375
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1859
2376
|
onClick: async () => {
|
1860
2377
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1861
2378
|
if (!documentId) {
|
@@ -1967,7 +2484,7 @@ const DiscardAction = ({
|
|
1967
2484
|
id: "content-manager.actions.discard.label",
|
1968
2485
|
defaultMessage: "Discard changes"
|
1969
2486
|
}),
|
1970
|
-
icon: /* @__PURE__ */ jsx(
|
2487
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1971
2488
|
position: ["panel", "table-row"],
|
1972
2489
|
variant: "danger",
|
1973
2490
|
dialog: {
|
@@ -1995,11 +2512,6 @@ const DiscardAction = ({
|
|
1995
2512
|
};
|
1996
2513
|
};
|
1997
2514
|
DiscardAction.type = "discard";
|
1998
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
1999
|
-
path {
|
2000
|
-
fill: currentColor;
|
2001
|
-
}
|
2002
|
-
`;
|
2003
2515
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2004
2516
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2005
2517
|
const RelativeTime = React.forwardRef(
|
@@ -2047,7 +2559,7 @@ const getDisplayName = ({
|
|
2047
2559
|
};
|
2048
2560
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2049
2561
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2050
|
-
const statusVariant = status === "draft" ? "
|
2562
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2051
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) }) });
|
2052
2564
|
};
|
2053
2565
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2057,23 +2569,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2057
2569
|
id: "content-manager.containers.edit.title.new",
|
2058
2570
|
defaultMessage: "Create an entry"
|
2059
2571
|
}) : documentTitle;
|
2060
|
-
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: [
|
2061
2573
|
/* @__PURE__ */ jsx(BackButton, {}),
|
2062
|
-
/* @__PURE__ */ jsxs(
|
2063
|
-
|
2064
|
-
{
|
2065
|
-
|
2066
|
-
|
2067
|
-
paddingTop: 1,
|
2068
|
-
gap: "80px",
|
2069
|
-
alignItems: "flex-start",
|
2070
|
-
children: [
|
2071
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2072
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2073
|
-
]
|
2074
|
-
}
|
2075
|
-
),
|
2076
|
-
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
|
2077
2579
|
] });
|
2078
2580
|
};
|
2079
2581
|
const HeaderToolbar = () => {
|
@@ -2156,12 +2658,12 @@ const Information = ({ activeTab }) => {
|
|
2156
2658
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2157
2659
|
label: formatMessage({
|
2158
2660
|
id: "content-manager.containers.edit.information.last-published.label",
|
2159
|
-
defaultMessage: "
|
2661
|
+
defaultMessage: "Published"
|
2160
2662
|
}),
|
2161
2663
|
value: formatMessage(
|
2162
2664
|
{
|
2163
2665
|
id: "content-manager.containers.edit.information.last-published.value",
|
2164
|
-
defaultMessage: `
|
2666
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2165
2667
|
},
|
2166
2668
|
{
|
2167
2669
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2174,12 +2676,12 @@ const Information = ({ activeTab }) => {
|
|
2174
2676
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2175
2677
|
label: formatMessage({
|
2176
2678
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2177
|
-
defaultMessage: "
|
2679
|
+
defaultMessage: "Updated"
|
2178
2680
|
}),
|
2179
2681
|
value: formatMessage(
|
2180
2682
|
{
|
2181
2683
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2182
|
-
defaultMessage: `
|
2684
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2183
2685
|
},
|
2184
2686
|
{
|
2185
2687
|
time: /* @__PURE__ */ jsx(
|
@@ -2197,12 +2699,12 @@ const Information = ({ activeTab }) => {
|
|
2197
2699
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2198
2700
|
label: formatMessage({
|
2199
2701
|
id: "content-manager.containers.edit.information.document.label",
|
2200
|
-
defaultMessage: "
|
2702
|
+
defaultMessage: "Created"
|
2201
2703
|
}),
|
2202
2704
|
value: formatMessage(
|
2203
2705
|
{
|
2204
2706
|
id: "content-manager.containers.edit.information.document.value",
|
2205
|
-
defaultMessage: `
|
2707
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2206
2708
|
},
|
2207
2709
|
{
|
2208
2710
|
time: /* @__PURE__ */ jsx(
|
@@ -2240,25 +2742,77 @@ const Information = ({ activeTab }) => {
|
|
2240
2742
|
);
|
2241
2743
|
};
|
2242
2744
|
const HeaderActions = ({ actions: actions2 }) => {
|
2243
|
-
|
2244
|
-
|
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) {
|
2245
2761
|
return /* @__PURE__ */ jsx(
|
2246
2762
|
SingleSelect,
|
2247
2763
|
{
|
2248
2764
|
size: "S",
|
2249
|
-
disabled: action.disabled,
|
2250
|
-
"aria-label": action.label,
|
2251
2765
|
onChange: action.onSelect,
|
2252
|
-
|
2766
|
+
"aria-label": action.label,
|
2767
|
+
...action,
|
2253
2768
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2254
2769
|
},
|
2255
2770
|
action.id
|
2256
2771
|
);
|
2257
2772
|
} else {
|
2258
|
-
|
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
|
+
}
|
2259
2795
|
}
|
2260
2796
|
}) });
|
2261
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
|
+
};
|
2262
2816
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2263
2817
|
const navigate = useNavigate();
|
2264
2818
|
const { formatMessage } = useIntl();
|
@@ -2299,12 +2853,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2299
2853
|
const { delete: deleteAction } = useDocumentActions();
|
2300
2854
|
const { toggleNotification } = useNotification();
|
2301
2855
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2856
|
+
const isLocalized = document?.locale != null;
|
2302
2857
|
return {
|
2303
2858
|
disabled: !canDelete || !document,
|
2304
|
-
label: formatMessage(
|
2305
|
-
|
2306
|
-
|
2307
|
-
|
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
|
+
),
|
2308
2866
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2309
2867
|
dialog: {
|
2310
2868
|
type: "dialog",
|
@@ -2340,423 +2898,121 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2340
2898
|
const res = await deleteAction({
|
2341
2899
|
documentId,
|
2342
2900
|
model,
|
2343
|
-
collectionType,
|
2344
|
-
params: {
|
2345
|
-
locale: "*"
|
2346
|
-
}
|
2347
|
-
});
|
2348
|
-
if (!("error" in res)) {
|
2349
|
-
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2350
|
-
}
|
2351
|
-
} finally {
|
2352
|
-
if (!listViewPathMatch) {
|
2353
|
-
setSubmitting(false);
|
2354
|
-
}
|
2355
|
-
}
|
2356
|
-
}
|
2357
|
-
},
|
2358
|
-
variant: "danger",
|
2359
|
-
position: ["header", "table-row"]
|
2360
|
-
};
|
2361
|
-
};
|
2362
|
-
DeleteAction$1.type = "delete";
|
2363
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2364
|
-
const Panels = () => {
|
2365
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2366
|
-
const [
|
2367
|
-
{
|
2368
|
-
query: { status }
|
2369
|
-
}
|
2370
|
-
] = useQueryParams({
|
2371
|
-
status: "draft"
|
2372
|
-
});
|
2373
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2374
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2375
|
-
const props = {
|
2376
|
-
activeTab: status,
|
2377
|
-
model,
|
2378
|
-
documentId: id,
|
2379
|
-
document: isCloning ? void 0 : document,
|
2380
|
-
meta: isCloning ? void 0 : meta,
|
2381
|
-
collectionType
|
2382
|
-
};
|
2383
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2384
|
-
DescriptionComponentRenderer,
|
2385
|
-
{
|
2386
|
-
props,
|
2387
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2388
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2389
|
-
}
|
2390
|
-
) });
|
2391
|
-
};
|
2392
|
-
const ActionsPanel = () => {
|
2393
|
-
const { formatMessage } = useIntl();
|
2394
|
-
return {
|
2395
|
-
title: formatMessage({
|
2396
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2397
|
-
defaultMessage: "Document"
|
2398
|
-
}),
|
2399
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2400
|
-
};
|
2401
|
-
};
|
2402
|
-
ActionsPanel.type = "actions";
|
2403
|
-
const ActionsPanelContent = () => {
|
2404
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2405
|
-
const [
|
2406
|
-
{
|
2407
|
-
query: { status = "draft" }
|
2408
|
-
}
|
2409
|
-
] = useQueryParams();
|
2410
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2411
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2412
|
-
const props = {
|
2413
|
-
activeTab: status,
|
2414
|
-
model,
|
2415
|
-
documentId: id,
|
2416
|
-
document: isCloning ? void 0 : document,
|
2417
|
-
meta: isCloning ? void 0 : meta,
|
2418
|
-
collectionType
|
2419
|
-
};
|
2420
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2421
|
-
/* @__PURE__ */ jsx(
|
2422
|
-
DescriptionComponentRenderer,
|
2423
|
-
{
|
2424
|
-
props,
|
2425
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2426
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2427
|
-
}
|
2428
|
-
),
|
2429
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2430
|
-
] });
|
2431
|
-
};
|
2432
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2433
|
-
return /* @__PURE__ */ jsxs(
|
2434
|
-
Flex,
|
2435
|
-
{
|
2436
|
-
ref,
|
2437
|
-
tag: "aside",
|
2438
|
-
"aria-labelledby": "additional-information",
|
2439
|
-
background: "neutral0",
|
2440
|
-
borderColor: "neutral150",
|
2441
|
-
hasRadius: true,
|
2442
|
-
paddingBottom: 4,
|
2443
|
-
paddingLeft: 4,
|
2444
|
-
paddingRight: 4,
|
2445
|
-
paddingTop: 4,
|
2446
|
-
shadow: "tableShadow",
|
2447
|
-
gap: 3,
|
2448
|
-
direction: "column",
|
2449
|
-
justifyContent: "stretch",
|
2450
|
-
alignItems: "flex-start",
|
2451
|
-
children: [
|
2452
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2453
|
-
children
|
2454
|
-
]
|
2455
|
-
}
|
2456
|
-
);
|
2457
|
-
});
|
2458
|
-
const HOOKS = {
|
2459
|
-
/**
|
2460
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2461
|
-
* @constant
|
2462
|
-
* @type {string}
|
2463
|
-
*/
|
2464
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2465
|
-
/**
|
2466
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2467
|
-
* @constant
|
2468
|
-
* @type {string}
|
2469
|
-
*/
|
2470
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2471
|
-
/**
|
2472
|
-
* Hook that allows to mutate the CM's edit view layout
|
2473
|
-
* @constant
|
2474
|
-
* @type {string}
|
2475
|
-
*/
|
2476
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2477
|
-
/**
|
2478
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2479
|
-
* @constant
|
2480
|
-
* @type {string}
|
2481
|
-
*/
|
2482
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2483
|
-
};
|
2484
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2485
|
-
endpoints: (builder) => ({
|
2486
|
-
getContentTypeConfiguration: builder.query({
|
2487
|
-
query: (uid) => ({
|
2488
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2489
|
-
method: "GET"
|
2490
|
-
}),
|
2491
|
-
transformResponse: (response) => response.data,
|
2492
|
-
providesTags: (_result, _error, uid) => [
|
2493
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2494
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2495
|
-
]
|
2496
|
-
}),
|
2497
|
-
getAllContentTypeSettings: builder.query({
|
2498
|
-
query: () => "/content-manager/content-types-settings",
|
2499
|
-
transformResponse: (response) => response.data,
|
2500
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2501
|
-
}),
|
2502
|
-
updateContentTypeConfiguration: builder.mutation({
|
2503
|
-
query: ({ uid, ...body }) => ({
|
2504
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2505
|
-
method: "PUT",
|
2506
|
-
data: body
|
2507
|
-
}),
|
2508
|
-
transformResponse: (response) => response.data,
|
2509
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2510
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2511
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2512
|
-
// Is this necessary?
|
2513
|
-
{ type: "InitialData" }
|
2514
|
-
]
|
2515
|
-
})
|
2516
|
-
})
|
2517
|
-
});
|
2518
|
-
const {
|
2519
|
-
useGetContentTypeConfigurationQuery,
|
2520
|
-
useGetAllContentTypeSettingsQuery,
|
2521
|
-
useUpdateContentTypeConfigurationMutation
|
2522
|
-
} = contentTypesApi;
|
2523
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2524
|
-
const { type } = attribute;
|
2525
|
-
if (type === "relation") {
|
2526
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2527
|
-
}
|
2528
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2529
|
-
};
|
2530
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2531
|
-
if (!mainFieldName) {
|
2532
|
-
return void 0;
|
2533
|
-
}
|
2534
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2535
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2536
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2537
|
-
);
|
2538
|
-
return {
|
2539
|
-
name: mainFieldName,
|
2540
|
-
type: mainFieldType ?? "string"
|
2541
|
-
};
|
2542
|
-
};
|
2543
|
-
const DEFAULT_SETTINGS = {
|
2544
|
-
bulkable: false,
|
2545
|
-
filterable: false,
|
2546
|
-
searchable: false,
|
2547
|
-
pagination: false,
|
2548
|
-
defaultSortBy: "",
|
2549
|
-
defaultSortOrder: "asc",
|
2550
|
-
mainField: "id",
|
2551
|
-
pageSize: 10
|
2552
|
-
};
|
2553
|
-
const useDocumentLayout = (model) => {
|
2554
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2555
|
-
const [{ query }] = useQueryParams();
|
2556
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2557
|
-
const { toggleNotification } = useNotification();
|
2558
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2559
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2560
|
-
const {
|
2561
|
-
data,
|
2562
|
-
isLoading: isLoadingConfigs,
|
2563
|
-
error,
|
2564
|
-
isFetching: isFetchingConfigs
|
2565
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2566
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2567
|
-
React.useEffect(() => {
|
2568
|
-
if (error) {
|
2569
|
-
toggleNotification({
|
2570
|
-
type: "danger",
|
2571
|
-
message: formatAPIError(error)
|
2572
|
-
});
|
2573
|
-
}
|
2574
|
-
}, [error, formatAPIError, toggleNotification]);
|
2575
|
-
const editLayout = React.useMemo(
|
2576
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2577
|
-
layout: [],
|
2578
|
-
components: {},
|
2579
|
-
metadatas: {},
|
2580
|
-
options: {},
|
2581
|
-
settings: DEFAULT_SETTINGS
|
2582
|
-
},
|
2583
|
-
[data, isLoading, schemas, schema, components]
|
2584
|
-
);
|
2585
|
-
const listLayout = React.useMemo(() => {
|
2586
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2587
|
-
layout: [],
|
2588
|
-
metadatas: {},
|
2589
|
-
options: {},
|
2590
|
-
settings: DEFAULT_SETTINGS
|
2591
|
-
};
|
2592
|
-
}, [data, isLoading, schemas, schema, components]);
|
2593
|
-
const { layout: edit } = React.useMemo(
|
2594
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2595
|
-
layout: editLayout,
|
2596
|
-
query
|
2597
|
-
}),
|
2598
|
-
[editLayout, query, runHookWaterfall]
|
2599
|
-
);
|
2600
|
-
return {
|
2601
|
-
error,
|
2602
|
-
isLoading,
|
2603
|
-
edit,
|
2604
|
-
list: listLayout
|
2605
|
-
};
|
2606
|
-
};
|
2607
|
-
const useDocLayout = () => {
|
2608
|
-
const { model } = useDoc();
|
2609
|
-
return useDocumentLayout(model);
|
2610
|
-
};
|
2611
|
-
const formatEditLayout = (data, {
|
2612
|
-
schemas,
|
2613
|
-
schema,
|
2614
|
-
components
|
2615
|
-
}) => {
|
2616
|
-
let currentPanelIndex = 0;
|
2617
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2618
|
-
data.contentType.layouts.edit,
|
2619
|
-
schema?.attributes,
|
2620
|
-
data.contentType.metadatas,
|
2621
|
-
{ configurations: data.components, schemas: components },
|
2622
|
-
schemas
|
2623
|
-
).reduce((panels, row) => {
|
2624
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2625
|
-
panels.push([row]);
|
2626
|
-
currentPanelIndex += 2;
|
2627
|
-
} else {
|
2628
|
-
if (!panels[currentPanelIndex]) {
|
2629
|
-
panels.push([]);
|
2630
|
-
}
|
2631
|
-
panels[currentPanelIndex].push(row);
|
2632
|
-
}
|
2633
|
-
return panels;
|
2634
|
-
}, []);
|
2635
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2636
|
-
(acc, [uid, configuration]) => {
|
2637
|
-
acc[uid] = {
|
2638
|
-
layout: convertEditLayoutToFieldLayouts(
|
2639
|
-
configuration.layouts.edit,
|
2640
|
-
components[uid].attributes,
|
2641
|
-
configuration.metadatas
|
2642
|
-
),
|
2643
|
-
settings: {
|
2644
|
-
...configuration.settings,
|
2645
|
-
icon: components[uid].info.icon,
|
2646
|
-
displayName: components[uid].info.displayName
|
2901
|
+
collectionType,
|
2902
|
+
params: {
|
2903
|
+
locale: "*"
|
2904
|
+
}
|
2905
|
+
});
|
2906
|
+
if (!("error" in res)) {
|
2907
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2908
|
+
}
|
2909
|
+
} finally {
|
2910
|
+
if (!listViewPathMatch) {
|
2911
|
+
setSubmitting(false);
|
2912
|
+
}
|
2647
2913
|
}
|
2648
|
-
}
|
2649
|
-
return acc;
|
2650
|
-
},
|
2651
|
-
{}
|
2652
|
-
);
|
2653
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2654
|
-
(acc, [attribute, metadata]) => {
|
2655
|
-
return {
|
2656
|
-
...acc,
|
2657
|
-
[attribute]: metadata.edit
|
2658
|
-
};
|
2659
|
-
},
|
2660
|
-
{}
|
2661
|
-
);
|
2662
|
-
return {
|
2663
|
-
layout: panelledEditAttributes,
|
2664
|
-
components: componentEditAttributes,
|
2665
|
-
metadatas: editMetadatas,
|
2666
|
-
settings: {
|
2667
|
-
...data.contentType.settings,
|
2668
|
-
displayName: schema?.info.displayName
|
2914
|
+
}
|
2669
2915
|
},
|
2670
|
-
|
2671
|
-
|
2672
|
-
...schema?.pluginOptions,
|
2673
|
-
...data.contentType.options
|
2674
|
-
}
|
2916
|
+
variant: "danger",
|
2917
|
+
position: ["header", "table-row"]
|
2675
2918
|
};
|
2676
2919
|
};
|
2677
|
-
|
2678
|
-
|
2679
|
-
|
2680
|
-
|
2681
|
-
|
2682
|
-
|
2683
|
-
}
|
2684
|
-
|
2685
|
-
|
2686
|
-
|
2687
|
-
|
2688
|
-
|
2689
|
-
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2696
|
-
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
}
|
2704
|
-
}
|
2705
|
-
);
|
2920
|
+
DeleteAction$1.type = "delete";
|
2921
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2922
|
+
const Panels = () => {
|
2923
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2924
|
+
const [
|
2925
|
+
{
|
2926
|
+
query: { status }
|
2927
|
+
}
|
2928
|
+
] = useQueryParams({
|
2929
|
+
status: "draft"
|
2930
|
+
});
|
2931
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2932
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2933
|
+
const props = {
|
2934
|
+
activeTab: status,
|
2935
|
+
model,
|
2936
|
+
documentId: id,
|
2937
|
+
document: isCloning ? void 0 : document,
|
2938
|
+
meta: isCloning ? void 0 : meta,
|
2939
|
+
collectionType
|
2940
|
+
};
|
2941
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2942
|
+
DescriptionComponentRenderer,
|
2943
|
+
{
|
2944
|
+
props,
|
2945
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2946
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2947
|
+
}
|
2948
|
+
) });
|
2706
2949
|
};
|
2707
|
-
const
|
2708
|
-
|
2709
|
-
schema,
|
2710
|
-
components
|
2711
|
-
}) => {
|
2712
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2713
|
-
(acc, [attribute, metadata]) => {
|
2714
|
-
return {
|
2715
|
-
...acc,
|
2716
|
-
[attribute]: metadata.list
|
2717
|
-
};
|
2718
|
-
},
|
2719
|
-
{}
|
2720
|
-
);
|
2721
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2722
|
-
data.contentType.layouts.list,
|
2723
|
-
schema?.attributes,
|
2724
|
-
listMetadatas,
|
2725
|
-
{ configurations: data.components, schemas: components },
|
2726
|
-
schemas
|
2727
|
-
);
|
2950
|
+
const ActionsPanel = () => {
|
2951
|
+
const { formatMessage } = useIntl();
|
2728
2952
|
return {
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
...schema?.pluginOptions,
|
2735
|
-
...data.contentType.options
|
2736
|
-
}
|
2953
|
+
title: formatMessage({
|
2954
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2955
|
+
defaultMessage: "Entry"
|
2956
|
+
}),
|
2957
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2737
2958
|
};
|
2738
2959
|
};
|
2739
|
-
|
2740
|
-
|
2741
|
-
|
2742
|
-
|
2743
|
-
|
2960
|
+
ActionsPanel.type = "actions";
|
2961
|
+
const ActionsPanelContent = () => {
|
2962
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2963
|
+
const [
|
2964
|
+
{
|
2965
|
+
query: { status = "draft" }
|
2744
2966
|
}
|
2745
|
-
|
2746
|
-
|
2747
|
-
|
2748
|
-
|
2749
|
-
|
2750
|
-
|
2751
|
-
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
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
|
+
] });
|
2759
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
|
+
});
|
2760
3016
|
const ConfirmBulkActionDialog = ({
|
2761
3017
|
onToggleDialog,
|
2762
3018
|
isOpen = false,
|
@@ -2764,7 +3020,7 @@ const ConfirmBulkActionDialog = ({
|
|
2764
3020
|
endAction
|
2765
3021
|
}) => {
|
2766
3022
|
const { formatMessage } = useIntl();
|
2767
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3023
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2768
3024
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2769
3025
|
id: "app.components.ConfirmDialog.title",
|
2770
3026
|
defaultMessage: "Confirmation"
|
@@ -2795,6 +3051,7 @@ const ConfirmDialogPublishAll = ({
|
|
2795
3051
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2796
3052
|
const { model, schema } = useDoc();
|
2797
3053
|
const [{ query }] = useQueryParams();
|
3054
|
+
const enableDraftRelationsCount = false;
|
2798
3055
|
const {
|
2799
3056
|
data: countDraftRelations = 0,
|
2800
3057
|
isLoading,
|
@@ -2806,7 +3063,7 @@ const ConfirmDialogPublishAll = ({
|
|
2806
3063
|
locale: query?.plugins?.i18n?.locale
|
2807
3064
|
},
|
2808
3065
|
{
|
2809
|
-
skip:
|
3066
|
+
skip: !enableDraftRelationsCount
|
2810
3067
|
}
|
2811
3068
|
);
|
2812
3069
|
React.useEffect(() => {
|
@@ -2885,7 +3142,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2885
3142
|
)
|
2886
3143
|
);
|
2887
3144
|
} else {
|
2888
|
-
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
|
+
);
|
2889
3153
|
}
|
2890
3154
|
} else {
|
2891
3155
|
messages.push(
|
@@ -2984,7 +3248,7 @@ const SelectedEntriesTableContent = ({
|
|
2984
3248
|
status: row.status
|
2985
3249
|
}
|
2986
3250
|
) }),
|
2987
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3251
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
2988
3252
|
IconButton,
|
2989
3253
|
{
|
2990
3254
|
tag: Link,
|
@@ -3007,9 +3271,10 @@ const SelectedEntriesTableContent = ({
|
|
3007
3271
|
),
|
3008
3272
|
target: "_blank",
|
3009
3273
|
marginLeft: "auto",
|
3010
|
-
|
3274
|
+
variant: "ghost",
|
3275
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3011
3276
|
}
|
3012
|
-
) })
|
3277
|
+
) }) })
|
3013
3278
|
] }, row.id)) })
|
3014
3279
|
] });
|
3015
3280
|
};
|
@@ -3046,7 +3311,13 @@ const SelectedEntriesModalContent = ({
|
|
3046
3311
|
);
|
3047
3312
|
const { rows, validationErrors } = React.useMemo(() => {
|
3048
3313
|
if (data.length > 0 && schema) {
|
3049
|
-
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
|
+
);
|
3050
3321
|
const validationErrors2 = {};
|
3051
3322
|
const rows2 = data.map((entry) => {
|
3052
3323
|
try {
|
@@ -3396,7 +3667,7 @@ const TableActions = ({ document }) => {
|
|
3396
3667
|
DescriptionComponentRenderer,
|
3397
3668
|
{
|
3398
3669
|
props,
|
3399
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3670
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3400
3671
|
children: (actions2) => {
|
3401
3672
|
const tableRowActions = actions2.filter((action) => {
|
3402
3673
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3507,7 +3778,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3507
3778
|
}),
|
3508
3779
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3509
3780
|
footer: ({ onClose }) => {
|
3510
|
-
return /* @__PURE__ */ jsxs(
|
3781
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3511
3782
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3512
3783
|
id: "cancel",
|
3513
3784
|
defaultMessage: "Cancel"
|
@@ -3548,8 +3819,7 @@ class ContentManagerPlugin {
|
|
3548
3819
|
documentActions = [
|
3549
3820
|
...DEFAULT_ACTIONS,
|
3550
3821
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3551
|
-
...DEFAULT_HEADER_ACTIONS
|
3552
|
-
HistoryAction
|
3822
|
+
...DEFAULT_HEADER_ACTIONS
|
3553
3823
|
];
|
3554
3824
|
editViewSidePanels = [ActionsPanel];
|
3555
3825
|
headerActions = [];
|
@@ -3638,6 +3908,52 @@ const getPrintableType = (value) => {
|
|
3638
3908
|
}
|
3639
3909
|
return nativeType;
|
3640
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
|
+
};
|
3641
3957
|
const initialState = {
|
3642
3958
|
collectionTypeLinks: [],
|
3643
3959
|
components: [],
|
@@ -3688,15 +4004,29 @@ const index = {
|
|
3688
4004
|
defaultMessage: "Content Manager"
|
3689
4005
|
},
|
3690
4006
|
permissions: [],
|
3691
|
-
Component: () => import("./layout-DC503LnF.mjs").then((mod) => ({ default: mod.Layout })),
|
3692
4007
|
position: 1
|
3693
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
|
+
});
|
3694
4019
|
app.registerPlugin(cm.config);
|
3695
4020
|
},
|
4021
|
+
bootstrap(app) {
|
4022
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4023
|
+
historyAdmin.bootstrap(app);
|
4024
|
+
}
|
4025
|
+
},
|
3696
4026
|
async registerTrads({ locales }) {
|
3697
4027
|
const importedTrads = await Promise.all(
|
3698
4028
|
locales.map((locale) => {
|
3699
|
-
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 }) => {
|
3700
4030
|
return {
|
3701
4031
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3702
4032
|
locale
|
@@ -3724,7 +4054,8 @@ export {
|
|
3724
4054
|
InjectionZone as I,
|
3725
4055
|
useDocument as J,
|
3726
4056
|
index as K,
|
3727
|
-
|
4057
|
+
useContentManagerContext as L,
|
4058
|
+
useDocumentActions as M,
|
3728
4059
|
Panels as P,
|
3729
4060
|
RelativeTime as R,
|
3730
4061
|
SINGLE_TYPES as S,
|
@@ -3742,11 +4073,11 @@ export {
|
|
3742
4073
|
PERMISSIONS as k,
|
3743
4074
|
DocumentRBAC as l,
|
3744
4075
|
DOCUMENT_META_FIELDS as m,
|
3745
|
-
|
3746
|
-
|
3747
|
-
|
3748
|
-
|
3749
|
-
|
4076
|
+
CLONE_PATH as n,
|
4077
|
+
useDocLayout as o,
|
4078
|
+
useGetContentTypeConfigurationQuery as p,
|
4079
|
+
CREATOR_FIELDS as q,
|
4080
|
+
getMainField as r,
|
3750
4081
|
setInitialData as s,
|
3751
4082
|
getDisplayName as t,
|
3752
4083
|
useContentTypeSchema as u,
|
@@ -3756,4 +4087,4 @@ export {
|
|
3756
4087
|
capitalise as y,
|
3757
4088
|
useUpdateContentTypeConfigurationMutation as z
|
3758
4089
|
};
|
3759
|
-
//# sourceMappingURL=index-
|
4090
|
+
//# sourceMappingURL=index-wnqzm4Q8.mjs.map
|