@strapi/content-manager 0.0.0-experimental.62ce06180fe9a772eaeb3d43d238b26644f39f7c → 0.0.0-experimental.65b9961ce81496e349024ceb95be1d5946f2c429
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-Cl7eB3s4.js → ComponentConfigurationPage-CO977CPh.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js.map → ComponentConfigurationPage-CO977CPh.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs → ComponentConfigurationPage-CQroR9Qk.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs.map → ComponentConfigurationPage-CQroR9Qk.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js → EditConfigurationPage-BPgoE-kf.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js.map → EditConfigurationPage-BPgoE-kf.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs → EditConfigurationPage-tVCJ5vWC.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs.map → EditConfigurationPage-tVCJ5vWC.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-ClIueJnM.mjs → EditViewPage-8mOu02ji.mjs} +30 -9
- package/dist/_chunks/EditViewPage-8mOu02ji.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-DxyAOItK.js → EditViewPage-BMVgUNOX.js} +30 -9
- package/dist/_chunks/EditViewPage-BMVgUNOX.js.map +1 -0
- package/dist/_chunks/{Field-BZBYmvaf.mjs → Field-CJPYzwD7.mjs} +518 -154
- package/dist/_chunks/Field-CJPYzwD7.mjs.map +1 -0
- package/dist/_chunks/{Field-C0Y_SR9e.js → Field-CdSLKFQk.js} +520 -156
- package/dist/_chunks/Field-CdSLKFQk.js.map +1 -0
- package/dist/_chunks/{Form-jwRSC2kV.mjs → Form-DJOJ-GF1.mjs} +36 -17
- package/dist/_chunks/Form-DJOJ-GF1.mjs.map +1 -0
- package/dist/_chunks/{Form-DwvGnISS.js → Form-eP5bZwap.js} +36 -17
- package/dist/_chunks/Form-eP5bZwap.js.map +1 -0
- package/dist/_chunks/{History-Cda0Yjzz.js → History-B-Mrquzu.js} +63 -25
- package/dist/_chunks/History-B-Mrquzu.js.map +1 -0
- package/dist/_chunks/{History-BgzAIj0G.mjs → History-MnQLtk1g.mjs} +64 -26
- package/dist/_chunks/History-MnQLtk1g.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-GH55qfoT.mjs → ListConfigurationPage-BcycI8Lw.mjs} +21 -9
- package/dist/_chunks/ListConfigurationPage-BcycI8Lw.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-C29EF97r.js → ListConfigurationPage-C0n4rUzH.js} +21 -9
- package/dist/_chunks/ListConfigurationPage-C0n4rUzH.js.map +1 -0
- package/dist/_chunks/{ListViewPage-QU03PFj1.mjs → ListViewPage-CRXONXwZ.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CRXONXwZ.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CnRt0UT7.js → ListViewPage-q0SHVPUS.js} +61 -43
- package/dist/_chunks/ListViewPage-q0SHVPUS.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js → NoContentTypePage-Bh3komDV.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js.map → NoContentTypePage-Bh3komDV.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs → NoContentTypePage-ukzFRF3z.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs.map → NoContentTypePage-ukzFRF3z.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs → NoPermissionsPage-B4sD7Ble.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs.map → NoPermissionsPage-B4sD7Ble.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js → NoPermissionsPage-BGBpj_Y1.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js.map → NoPermissionsPage-BGBpj_Y1.js.map} +1 -1
- package/dist/_chunks/{Relations-BjpPPCKp.js → Relations-B53wYe8g.js} +33 -24
- package/dist/_chunks/Relations-B53wYe8g.js.map +1 -0
- package/dist/_chunks/{Relations-KMf5qEN0.mjs → Relations-CIexb8gr.mjs} +33 -24
- package/dist/_chunks/Relations-CIexb8gr.mjs.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-6kKXK7y8.mjs → index-CJ2vYwuT.mjs} +992 -689
- package/dist/_chunks/index-CJ2vYwuT.mjs.map +1 -0
- package/dist/_chunks/{index-D9ZwczCV.js → index-DbT2sx-Q.js} +984 -681
- package/dist/_chunks/index-DbT2sx-Q.js.map +1 -0
- package/dist/_chunks/{layout-BJfBoBiF.js → layout-CeBSIkmP.js} +25 -12
- package/dist/_chunks/layout-CeBSIkmP.js.map +1 -0
- package/dist/_chunks/{layout-B1Z-9koY.mjs → layout-vzKSrr7p.mjs} +27 -14
- package/dist/_chunks/layout-vzKSrr7p.mjs.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CMvjzyU3.js → relations-Cl-6t9iz.js} +2 -2
- package/dist/_chunks/{relations-CMvjzyU3.js.map → relations-Cl-6t9iz.js.map} +1 -1
- package/dist/_chunks/{relations-CgZg7Pyx.mjs → relations-DI0lguF0.mjs} +2 -2
- package/dist/_chunks/{relations-CgZg7Pyx.mjs.map → relations-DI0lguF0.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 +205 -118
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +206 -119
- 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-ClIueJnM.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-DxyAOItK.js.map +0 -1
- package/dist/_chunks/Field-BZBYmvaf.mjs.map +0 -1
- package/dist/_chunks/Field-C0Y_SR9e.js.map +0 -1
- package/dist/_chunks/Form-DwvGnISS.js.map +0 -1
- package/dist/_chunks/Form-jwRSC2kV.mjs.map +0 -1
- package/dist/_chunks/History-BgzAIj0G.mjs.map +0 -1
- package/dist/_chunks/History-Cda0Yjzz.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-C29EF97r.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-GH55qfoT.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-CnRt0UT7.js.map +0 -1
- package/dist/_chunks/ListViewPage-QU03PFj1.mjs.map +0 -1
- package/dist/_chunks/Relations-BjpPPCKp.js.map +0 -1
- package/dist/_chunks/Relations-KMf5qEN0.mjs.map +0 -1
- package/dist/_chunks/index-6kKXK7y8.mjs.map +0 -1
- package/dist/_chunks/index-D9ZwczCV.js.map +0 -1
- package/dist/_chunks/layout-B1Z-9koY.mjs.map +0 -1
- package/dist/_chunks/layout-BJfBoBiF.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,17 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
7
4
|
import * as React from "react";
|
8
5
|
import { lazy } from "react";
|
9
|
-
import { Button, Menu, VisuallyHidden, Flex,
|
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) : [];
|
@@ -195,8 +167,7 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
195
167
|
"InitialData",
|
196
168
|
"HistoryVersion",
|
197
169
|
"Relations",
|
198
|
-
"
|
199
|
-
"ReleaseAction"
|
170
|
+
"UidAvailability"
|
200
171
|
]
|
201
172
|
});
|
202
173
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -210,7 +181,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
210
181
|
params: query
|
211
182
|
}
|
212
183
|
}),
|
213
|
-
invalidatesTags: (_result,
|
184
|
+
invalidatesTags: (_result, error, { model }) => {
|
185
|
+
if (error) {
|
186
|
+
return [];
|
187
|
+
}
|
188
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
189
|
+
}
|
214
190
|
}),
|
215
191
|
cloneDocument: builder.mutation({
|
216
192
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -221,7 +197,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
221
197
|
params
|
222
198
|
}
|
223
199
|
}),
|
224
|
-
invalidatesTags: (_result, _error, { model }) => [
|
200
|
+
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
{ type: "Document", id: `${model}_LIST` },
|
202
|
+
{ type: "UidAvailability", id: model }
|
203
|
+
]
|
225
204
|
}),
|
226
205
|
/**
|
227
206
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -238,7 +217,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
238
217
|
}),
|
239
218
|
invalidatesTags: (result, _error, { model }) => [
|
240
219
|
{ type: "Document", id: `${model}_LIST` },
|
241
|
-
"Relations"
|
220
|
+
"Relations",
|
221
|
+
{ type: "UidAvailability", id: model }
|
242
222
|
]
|
243
223
|
}),
|
244
224
|
deleteDocument: builder.mutation({
|
@@ -250,9 +230,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
250
230
|
}
|
251
231
|
}),
|
252
232
|
invalidatesTags: (_result, _error, { collectionType, model }) => [
|
253
|
-
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
254
|
-
{ type: "Release", id: "LIST" },
|
255
|
-
{ type: "ReleaseAction", id: "LIST" }
|
233
|
+
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
256
234
|
]
|
257
235
|
}),
|
258
236
|
deleteManyDocuments: builder.mutation({
|
@@ -264,11 +242,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
264
242
|
params
|
265
243
|
}
|
266
244
|
}),
|
267
|
-
invalidatesTags: (_res, _error, { model }) => [
|
268
|
-
{ type: "Document", id: `${model}_LIST` },
|
269
|
-
{ type: "Release", id: "LIST" },
|
270
|
-
{ type: "ReleaseAction", id: "LIST" }
|
271
|
-
]
|
245
|
+
invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
|
272
246
|
}),
|
273
247
|
discardDocument: builder.mutation({
|
274
248
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -286,8 +260,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
286
260
|
},
|
287
261
|
{ type: "Document", id: `${model}_LIST` },
|
288
262
|
"Relations",
|
289
|
-
{ type: "
|
290
|
-
{ type: "ReleaseAction", id: "LIST" }
|
263
|
+
{ type: "UidAvailability", id: model }
|
291
264
|
];
|
292
265
|
}
|
293
266
|
}),
|
@@ -305,6 +278,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
305
278
|
}),
|
306
279
|
providesTags: (result, _error, arg) => {
|
307
280
|
return [
|
281
|
+
{ type: "Document", id: `ALL_LIST` },
|
308
282
|
{ type: "Document", id: `${arg.model}_LIST` },
|
309
283
|
...result?.results.map(({ documentId }) => ({
|
310
284
|
type: "Document",
|
@@ -343,6 +317,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
343
317
|
{
|
344
318
|
type: "Document",
|
345
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`
|
346
325
|
}
|
347
326
|
];
|
348
327
|
}
|
@@ -407,9 +386,20 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
407
386
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
408
387
|
},
|
409
388
|
"Relations",
|
410
|
-
{ type: "
|
411
|
-
{ type: "ReleaseAction", id: "LIST" }
|
389
|
+
{ type: "UidAvailability", id: model }
|
412
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
|
+
}
|
413
403
|
}
|
414
404
|
}),
|
415
405
|
unpublishDocument: builder.mutation({
|
@@ -479,20 +469,39 @@ const buildValidParams = (query) => {
|
|
479
469
|
const isBaseQueryError = (error) => {
|
480
470
|
return error.name !== void 0;
|
481
471
|
};
|
482
|
-
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 }) => {
|
483
491
|
const createModelSchema = (attributes2) => yup.object().shape(
|
484
492
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
485
493
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
486
494
|
return acc;
|
487
495
|
}
|
488
496
|
const validations = [
|
497
|
+
addNullableValidation,
|
489
498
|
addRequiredValidation,
|
490
499
|
addMinLengthValidation,
|
491
500
|
addMaxLengthValidation,
|
492
501
|
addMinValidation,
|
493
502
|
addMaxValidation,
|
494
503
|
addRegexValidation
|
495
|
-
].map((fn) => fn(attribute));
|
504
|
+
].map((fn) => fn(attribute, options));
|
496
505
|
const transformSchema = pipe(...validations);
|
497
506
|
switch (attribute.type) {
|
498
507
|
case "component": {
|
@@ -502,12 +511,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
502
511
|
...acc,
|
503
512
|
[name]: transformSchema(
|
504
513
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
505
|
-
)
|
514
|
+
).test(arrayValidator(attribute, options))
|
506
515
|
};
|
507
516
|
} else {
|
508
517
|
return {
|
509
518
|
...acc,
|
510
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
519
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
511
520
|
};
|
512
521
|
}
|
513
522
|
}
|
@@ -529,7 +538,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
529
538
|
}
|
530
539
|
)
|
531
540
|
)
|
532
|
-
)
|
541
|
+
).test(arrayValidator(attribute, options))
|
533
542
|
};
|
534
543
|
case "relation":
|
535
544
|
return {
|
@@ -541,7 +550,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
541
550
|
} else if (Array.isArray(value)) {
|
542
551
|
return yup.array().of(
|
543
552
|
yup.object().shape({
|
544
|
-
id: yup.
|
553
|
+
id: yup.number().required()
|
545
554
|
})
|
546
555
|
);
|
547
556
|
} else if (typeof value === "object") {
|
@@ -593,6 +602,14 @@ const createAttributeSchema = (attribute) => {
|
|
593
602
|
if (!value || typeof value === "string" && value.length === 0) {
|
594
603
|
return true;
|
595
604
|
}
|
605
|
+
if (typeof value === "object") {
|
606
|
+
try {
|
607
|
+
JSON.stringify(value);
|
608
|
+
return true;
|
609
|
+
} catch (err) {
|
610
|
+
return false;
|
611
|
+
}
|
612
|
+
}
|
596
613
|
try {
|
597
614
|
JSON.parse(value);
|
598
615
|
return true;
|
@@ -611,13 +628,7 @@ const createAttributeSchema = (attribute) => {
|
|
611
628
|
return yup.mixed();
|
612
629
|
}
|
613
630
|
};
|
614
|
-
const
|
615
|
-
if (attribute.required) {
|
616
|
-
return schema.required({
|
617
|
-
id: translatedErrors.required.id,
|
618
|
-
defaultMessage: "This field is required."
|
619
|
-
});
|
620
|
-
}
|
631
|
+
const nullableSchema = (schema) => {
|
621
632
|
return schema?.nullable ? schema.nullable() : (
|
622
633
|
// In some cases '.nullable' will not be available on the schema.
|
623
634
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -625,7 +636,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
625
636
|
schema
|
626
637
|
);
|
627
638
|
};
|
628
|
-
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
|
+
}
|
629
655
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
630
656
|
return schema.min(attribute.minLength, {
|
631
657
|
...translatedErrors.minLength,
|
@@ -647,10 +673,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
647
673
|
}
|
648
674
|
return schema;
|
649
675
|
};
|
650
|
-
const addMinValidation = (attribute) => (schema) => {
|
651
|
-
if ("
|
676
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
677
|
+
if (options.status === "draft") {
|
678
|
+
return schema;
|
679
|
+
}
|
680
|
+
if ("min" in attribute && "min" in schema) {
|
652
681
|
const min = toInteger(attribute.min);
|
653
|
-
if (
|
682
|
+
if (min) {
|
654
683
|
return schema.min(min, {
|
655
684
|
...translatedErrors.min,
|
656
685
|
values: {
|
@@ -768,16 +797,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
768
797
|
}, {});
|
769
798
|
return componentsByKey;
|
770
799
|
};
|
771
|
-
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);
|
772
899
|
const { toggleNotification } = useNotification();
|
773
900
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
901
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
774
902
|
const {
|
775
|
-
|
776
|
-
isLoading:
|
777
|
-
|
778
|
-
|
779
|
-
} =
|
780
|
-
const
|
903
|
+
data,
|
904
|
+
isLoading: isLoadingConfigs,
|
905
|
+
error,
|
906
|
+
isFetching: isFetchingConfigs
|
907
|
+
} = useGetContentTypeConfigurationQuery(model);
|
908
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
781
909
|
React.useEffect(() => {
|
782
910
|
if (error) {
|
783
911
|
toggleNotification({
|
@@ -785,68 +913,321 @@ const useDocument = (args, opts) => {
|
|
785
913
|
message: formatAPIError(error)
|
786
914
|
});
|
787
915
|
}
|
788
|
-
}, [
|
789
|
-
const
|
790
|
-
|
791
|
-
|
792
|
-
|
793
|
-
|
794
|
-
|
795
|
-
|
796
|
-
(document) => {
|
797
|
-
if (!validationSchema) {
|
798
|
-
throw new Error(
|
799
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
800
|
-
);
|
801
|
-
}
|
802
|
-
try {
|
803
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
804
|
-
return null;
|
805
|
-
} catch (error2) {
|
806
|
-
if (error2 instanceof ValidationError) {
|
807
|
-
return getYupValidationErrors(error2);
|
808
|
-
}
|
809
|
-
throw error2;
|
810
|
-
}
|
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
|
811
924
|
},
|
812
|
-
[
|
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]
|
813
941
|
);
|
814
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
815
942
|
return {
|
816
|
-
|
817
|
-
document: data?.data,
|
818
|
-
meta: data?.meta,
|
943
|
+
error,
|
819
944
|
isLoading,
|
820
|
-
|
821
|
-
|
945
|
+
edit,
|
946
|
+
list: listLayout
|
822
947
|
};
|
823
948
|
};
|
824
|
-
const
|
825
|
-
const {
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
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;
|
834
1184
|
return {
|
835
1185
|
collectionType,
|
836
1186
|
model: slug,
|
837
|
-
id:
|
838
|
-
...
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
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
|
844
1228
|
};
|
845
1229
|
};
|
846
1230
|
const prefixPluginTranslations = (trad, pluginId) => {
|
847
|
-
if (!pluginId) {
|
848
|
-
throw new TypeError("pluginId can't be empty");
|
849
|
-
}
|
850
1231
|
return Object.keys(trad).reduce((acc, current) => {
|
851
1232
|
acc[`${pluginId}.${current}`] = trad[current];
|
852
1233
|
return acc;
|
@@ -862,6 +1243,8 @@ const useDocumentActions = () => {
|
|
862
1243
|
const { formatMessage } = useIntl();
|
863
1244
|
const { trackUsage } = useTracking();
|
864
1245
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1246
|
+
const navigate = useNavigate();
|
1247
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
865
1248
|
const [deleteDocument] = useDeleteDocumentMutation();
|
866
1249
|
const _delete = React.useCallback(
|
867
1250
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1176,6 +1559,7 @@ const useDocumentActions = () => {
|
|
1176
1559
|
defaultMessage: "Saved document"
|
1177
1560
|
})
|
1178
1561
|
});
|
1562
|
+
setCurrentStep("contentManager.success");
|
1179
1563
|
return res.data;
|
1180
1564
|
} catch (err) {
|
1181
1565
|
toggleNotification({
|
@@ -1197,7 +1581,6 @@ const useDocumentActions = () => {
|
|
1197
1581
|
sourceId
|
1198
1582
|
});
|
1199
1583
|
if ("error" in res) {
|
1200
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1201
1584
|
return { error: res.error };
|
1202
1585
|
}
|
1203
1586
|
toggleNotification({
|
@@ -1216,7 +1599,7 @@ const useDocumentActions = () => {
|
|
1216
1599
|
throw err;
|
1217
1600
|
}
|
1218
1601
|
},
|
1219
|
-
[autoCloneDocument,
|
1602
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1220
1603
|
);
|
1221
1604
|
const [cloneDocument] = useCloneDocumentMutation();
|
1222
1605
|
const clone = React.useCallback(
|
@@ -1242,6 +1625,7 @@ const useDocumentActions = () => {
|
|
1242
1625
|
defaultMessage: "Cloned document"
|
1243
1626
|
})
|
1244
1627
|
});
|
1628
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1245
1629
|
return res.data;
|
1246
1630
|
} catch (err) {
|
1247
1631
|
toggleNotification({
|
@@ -1252,7 +1636,7 @@ const useDocumentActions = () => {
|
|
1252
1636
|
throw err;
|
1253
1637
|
}
|
1254
1638
|
},
|
1255
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1639
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1256
1640
|
);
|
1257
1641
|
const [getDoc] = useLazyGetDocumentQuery();
|
1258
1642
|
const getDocument = React.useCallback(
|
@@ -1278,7 +1662,7 @@ const useDocumentActions = () => {
|
|
1278
1662
|
};
|
1279
1663
|
};
|
1280
1664
|
const ProtectedHistoryPage = lazy(
|
1281
|
-
() => import("./History-
|
1665
|
+
() => import("./History-MnQLtk1g.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1282
1666
|
);
|
1283
1667
|
const routes$1 = [
|
1284
1668
|
{
|
@@ -1291,31 +1675,31 @@ const routes$1 = [
|
|
1291
1675
|
}
|
1292
1676
|
];
|
1293
1677
|
const ProtectedEditViewPage = lazy(
|
1294
|
-
() => import("./EditViewPage-
|
1678
|
+
() => import("./EditViewPage-8mOu02ji.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1295
1679
|
);
|
1296
1680
|
const ProtectedListViewPage = lazy(
|
1297
|
-
() => import("./ListViewPage-
|
1681
|
+
() => import("./ListViewPage-CRXONXwZ.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1298
1682
|
);
|
1299
1683
|
const ProtectedListConfiguration = lazy(
|
1300
|
-
() => import("./ListConfigurationPage-
|
1684
|
+
() => import("./ListConfigurationPage-BcycI8Lw.mjs").then((mod) => ({
|
1301
1685
|
default: mod.ProtectedListConfiguration
|
1302
1686
|
}))
|
1303
1687
|
);
|
1304
1688
|
const ProtectedEditConfigurationPage = lazy(
|
1305
|
-
() => import("./EditConfigurationPage-
|
1689
|
+
() => import("./EditConfigurationPage-tVCJ5vWC.mjs").then((mod) => ({
|
1306
1690
|
default: mod.ProtectedEditConfigurationPage
|
1307
1691
|
}))
|
1308
1692
|
);
|
1309
1693
|
const ProtectedComponentConfigurationPage = lazy(
|
1310
|
-
() => import("./ComponentConfigurationPage-
|
1694
|
+
() => import("./ComponentConfigurationPage-CQroR9Qk.mjs").then((mod) => ({
|
1311
1695
|
default: mod.ProtectedComponentConfigurationPage
|
1312
1696
|
}))
|
1313
1697
|
);
|
1314
1698
|
const NoPermissions = lazy(
|
1315
|
-
() => import("./NoPermissionsPage-
|
1699
|
+
() => import("./NoPermissionsPage-B4sD7Ble.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1316
1700
|
);
|
1317
1701
|
const NoContentType = lazy(
|
1318
|
-
() => import("./NoContentTypePage-
|
1702
|
+
() => import("./NoContentTypePage-ukzFRF3z.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1319
1703
|
);
|
1320
1704
|
const CollectionTypePages = () => {
|
1321
1705
|
const { collectionType } = useParams();
|
@@ -1429,12 +1813,14 @@ const DocumentActionButton = (action) => {
|
|
1429
1813
|
/* @__PURE__ */ jsx(
|
1430
1814
|
Button,
|
1431
1815
|
{
|
1432
|
-
flex:
|
1816
|
+
flex: "auto",
|
1433
1817
|
startIcon: action.icon,
|
1434
1818
|
disabled: action.disabled,
|
1435
1819
|
onClick: handleClick(action),
|
1436
1820
|
justifyContent: "center",
|
1437
1821
|
variant: action.variant || "default",
|
1822
|
+
paddingTop: "7px",
|
1823
|
+
paddingBottom: "7px",
|
1438
1824
|
children: action.label
|
1439
1825
|
}
|
1440
1826
|
),
|
@@ -1442,7 +1828,7 @@ const DocumentActionButton = (action) => {
|
|
1442
1828
|
DocumentActionConfirmDialog,
|
1443
1829
|
{
|
1444
1830
|
...action.dialog,
|
1445
|
-
variant: action.variant,
|
1831
|
+
variant: action.dialog?.variant ?? action.variant,
|
1446
1832
|
isOpen: dialogId === action.id,
|
1447
1833
|
onClose: handleClose
|
1448
1834
|
}
|
@@ -1499,9 +1885,9 @@ const DocumentActionsMenu = ({
|
|
1499
1885
|
disabled: isDisabled,
|
1500
1886
|
size: "S",
|
1501
1887
|
endIcon: null,
|
1502
|
-
paddingTop: "
|
1503
|
-
paddingLeft: "
|
1504
|
-
paddingRight: "
|
1888
|
+
paddingTop: "4px",
|
1889
|
+
paddingLeft: "7px",
|
1890
|
+
paddingRight: "7px",
|
1505
1891
|
variant,
|
1506
1892
|
children: [
|
1507
1893
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1512,7 +1898,7 @@ const DocumentActionsMenu = ({
|
|
1512
1898
|
]
|
1513
1899
|
}
|
1514
1900
|
),
|
1515
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1901
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1516
1902
|
actions2.map((action) => {
|
1517
1903
|
return /* @__PURE__ */ jsx(
|
1518
1904
|
Menu.Item,
|
@@ -1521,10 +1907,25 @@ const DocumentActionsMenu = ({
|
|
1521
1907
|
onSelect: handleClick(action),
|
1522
1908
|
display: "block",
|
1523
1909
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1524
|
-
/* @__PURE__ */ jsxs(
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1910
|
+
/* @__PURE__ */ jsxs(
|
1911
|
+
Flex,
|
1912
|
+
{
|
1913
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1914
|
+
gap: 2,
|
1915
|
+
tag: "span",
|
1916
|
+
children: [
|
1917
|
+
/* @__PURE__ */ jsx(
|
1918
|
+
Flex,
|
1919
|
+
{
|
1920
|
+
tag: "span",
|
1921
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1922
|
+
children: action.icon
|
1923
|
+
}
|
1924
|
+
),
|
1925
|
+
action.label
|
1926
|
+
]
|
1927
|
+
}
|
1928
|
+
),
|
1528
1929
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1529
1930
|
Flex,
|
1530
1931
|
{
|
@@ -1621,11 +2022,11 @@ const DocumentActionConfirmDialog = ({
|
|
1621
2022
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1622
2023
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1623
2024
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1624
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2025
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1625
2026
|
id: "app.components.Button.cancel",
|
1626
2027
|
defaultMessage: "Cancel"
|
1627
2028
|
}) }) }),
|
1628
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2029
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1629
2030
|
id: "app.components.Button.confirm",
|
1630
2031
|
defaultMessage: "Confirm"
|
1631
2032
|
}) })
|
@@ -1664,13 +2065,17 @@ const PublishAction$1 = ({
|
|
1664
2065
|
const navigate = useNavigate();
|
1665
2066
|
const { toggleNotification } = useNotification();
|
1666
2067
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2068
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1667
2069
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1668
2070
|
const { formatMessage } = useIntl();
|
1669
|
-
const { canPublish
|
1670
|
-
"PublishAction",
|
1671
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1672
|
-
);
|
2071
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1673
2072
|
const { publish } = useDocumentActions();
|
2073
|
+
const [
|
2074
|
+
countDraftRelations,
|
2075
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2076
|
+
] = useLazyGetDraftRelationCountQuery();
|
2077
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2078
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1674
2079
|
const [{ query, rawQuery }] = useQueryParams();
|
1675
2080
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1676
2081
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1679,62 +2084,144 @@ const PublishAction$1 = ({
|
|
1679
2084
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1680
2085
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1681
2086
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
1688
|
-
|
1689
|
-
|
1690
|
-
|
2087
|
+
React.useEffect(() => {
|
2088
|
+
if (isErrorDraftRelations) {
|
2089
|
+
toggleNotification({
|
2090
|
+
type: "danger",
|
2091
|
+
message: formatMessage({
|
2092
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2093
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2094
|
+
})
|
2095
|
+
});
|
2096
|
+
}
|
2097
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2098
|
+
React.useEffect(() => {
|
2099
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2100
|
+
const extractDraftRelations = (data) => {
|
2101
|
+
const relations = data.connect || [];
|
2102
|
+
relations.forEach((relation) => {
|
2103
|
+
if (relation.status === "draft") {
|
2104
|
+
localDraftRelations.add(relation.id);
|
2105
|
+
}
|
2106
|
+
});
|
2107
|
+
};
|
2108
|
+
const traverseAndExtract = (data) => {
|
2109
|
+
Object.entries(data).forEach(([key, value]) => {
|
2110
|
+
if (key === "connect" && Array.isArray(value)) {
|
2111
|
+
extractDraftRelations({ connect: value });
|
2112
|
+
} else if (typeof value === "object" && value !== null) {
|
2113
|
+
traverseAndExtract(value);
|
2114
|
+
}
|
2115
|
+
});
|
2116
|
+
};
|
2117
|
+
if (!documentId || modified) {
|
2118
|
+
traverseAndExtract(formValues);
|
2119
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2120
|
+
}
|
2121
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2122
|
+
React.useEffect(() => {
|
2123
|
+
if (!document || !document.documentId || isListView) {
|
2124
|
+
return;
|
2125
|
+
}
|
2126
|
+
const fetchDraftRelationsCount = async () => {
|
2127
|
+
const { data, error } = await countDraftRelations({
|
2128
|
+
collectionType,
|
2129
|
+
model,
|
2130
|
+
documentId,
|
2131
|
+
params
|
2132
|
+
});
|
2133
|
+
if (error) {
|
2134
|
+
throw error;
|
2135
|
+
}
|
2136
|
+
if (data) {
|
2137
|
+
setServerCountOfDraftRelations(data.data);
|
2138
|
+
}
|
2139
|
+
};
|
2140
|
+
fetchDraftRelationsCount();
|
2141
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2142
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2143
|
+
if (!schema?.options?.draftAndPublish) {
|
2144
|
+
return null;
|
2145
|
+
}
|
2146
|
+
const performPublish = async () => {
|
2147
|
+
setSubmitting(true);
|
2148
|
+
try {
|
2149
|
+
const { errors } = await validate(true, {
|
2150
|
+
status: "published"
|
2151
|
+
});
|
2152
|
+
if (errors) {
|
2153
|
+
toggleNotification({
|
2154
|
+
type: "danger",
|
2155
|
+
message: formatMessage({
|
2156
|
+
id: "content-manager.validation.error",
|
2157
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2158
|
+
})
|
2159
|
+
});
|
2160
|
+
return;
|
2161
|
+
}
|
2162
|
+
const res = await publish(
|
2163
|
+
{
|
2164
|
+
collectionType,
|
2165
|
+
model,
|
2166
|
+
documentId,
|
2167
|
+
params
|
2168
|
+
},
|
2169
|
+
formValues
|
2170
|
+
);
|
2171
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2172
|
+
navigate({
|
2173
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2174
|
+
search: rawQuery
|
2175
|
+
});
|
2176
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2177
|
+
setErrors(formatValidationErrors(res.error));
|
2178
|
+
}
|
2179
|
+
} finally {
|
2180
|
+
setSubmitting(false);
|
2181
|
+
}
|
2182
|
+
};
|
2183
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2184
|
+
const enableDraftRelationsCount = false;
|
2185
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2186
|
+
return {
|
2187
|
+
/**
|
2188
|
+
* Disabled when:
|
2189
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2190
|
+
* - the form is submitting
|
1691
2191
|
* - the active tab is the published tab
|
1692
2192
|
* - the document is already published & not modified
|
1693
2193
|
* - the document is being created & not modified
|
1694
2194
|
* - the user doesn't have the permission to publish
|
1695
|
-
* - the user doesn't have the permission to create a new document
|
1696
|
-
* - the user doesn't have the permission to update the document
|
1697
2195
|
*/
|
1698
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2196
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1699
2197
|
label: formatMessage({
|
1700
2198
|
id: "app.utils.publish",
|
1701
2199
|
defaultMessage: "Publish"
|
1702
2200
|
}),
|
1703
2201
|
onClick: async () => {
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
|
1710
|
-
|
1711
|
-
|
1712
|
-
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
documentId,
|
1722
|
-
params
|
1723
|
-
},
|
1724
|
-
formValues
|
1725
|
-
);
|
1726
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1727
|
-
navigate({
|
1728
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1729
|
-
search: rawQuery
|
1730
|
-
});
|
1731
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1732
|
-
setErrors(formatValidationErrors(res.error));
|
2202
|
+
await performPublish();
|
2203
|
+
},
|
2204
|
+
dialog: hasDraftRelations ? {
|
2205
|
+
type: "dialog",
|
2206
|
+
variant: "danger",
|
2207
|
+
footer: null,
|
2208
|
+
title: formatMessage({
|
2209
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2210
|
+
defaultMessage: "Confirmation"
|
2211
|
+
}),
|
2212
|
+
content: formatMessage(
|
2213
|
+
{
|
2214
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2215
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2216
|
+
},
|
2217
|
+
{
|
2218
|
+
count: totalDraftRelations
|
1733
2219
|
}
|
1734
|
-
|
1735
|
-
|
2220
|
+
),
|
2221
|
+
onConfirm: async () => {
|
2222
|
+
await performPublish();
|
1736
2223
|
}
|
1737
|
-
}
|
2224
|
+
} : void 0
|
1738
2225
|
};
|
1739
2226
|
};
|
1740
2227
|
PublishAction$1.type = "publish";
|
@@ -1750,10 +2237,6 @@ const UpdateAction = ({
|
|
1750
2237
|
const cloneMatch = useMatch(CLONE_PATH);
|
1751
2238
|
const isCloning = cloneMatch !== null;
|
1752
2239
|
const { formatMessage } = useIntl();
|
1753
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1754
|
-
canCreate: canCreate2,
|
1755
|
-
canUpdate: canUpdate2
|
1756
|
-
}));
|
1757
2240
|
const { create, update, clone } = useDocumentActions();
|
1758
2241
|
const [{ query, rawQuery }] = useQueryParams();
|
1759
2242
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1770,10 +2253,8 @@ const UpdateAction = ({
|
|
1770
2253
|
* - the form is submitting
|
1771
2254
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1772
2255
|
* - the active tab is the published tab
|
1773
|
-
* - the user doesn't have the permission to create a new document
|
1774
|
-
* - the user doesn't have the permission to update the document
|
1775
2256
|
*/
|
1776
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2257
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1777
2258
|
label: formatMessage({
|
1778
2259
|
id: "content-manager.containers.Edit.save",
|
1779
2260
|
defaultMessage: "Save"
|
@@ -1781,7 +2262,9 @@ const UpdateAction = ({
|
|
1781
2262
|
onClick: async () => {
|
1782
2263
|
setSubmitting(true);
|
1783
2264
|
try {
|
1784
|
-
const { errors } = await validate(
|
2265
|
+
const { errors } = await validate(true, {
|
2266
|
+
status: "draft"
|
2267
|
+
});
|
1785
2268
|
if (errors) {
|
1786
2269
|
toggleNotification({
|
1787
2270
|
type: "danger",
|
@@ -1802,10 +2285,13 @@ const UpdateAction = ({
|
|
1802
2285
|
document
|
1803
2286
|
);
|
1804
2287
|
if ("data" in res) {
|
1805
|
-
navigate(
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
2288
|
+
navigate(
|
2289
|
+
{
|
2290
|
+
pathname: `../${res.data.documentId}`,
|
2291
|
+
search: rawQuery
|
2292
|
+
},
|
2293
|
+
{ relative: "path" }
|
2294
|
+
);
|
1809
2295
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1810
2296
|
setErrors(formatValidationErrors(res.error));
|
1811
2297
|
}
|
@@ -1833,10 +2319,13 @@ const UpdateAction = ({
|
|
1833
2319
|
document
|
1834
2320
|
);
|
1835
2321
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1836
|
-
navigate(
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
2322
|
+
navigate(
|
2323
|
+
{
|
2324
|
+
pathname: `../${res.data.documentId}`,
|
2325
|
+
search: rawQuery
|
2326
|
+
},
|
2327
|
+
{ replace: true, relative: "path" }
|
2328
|
+
);
|
1840
2329
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1841
2330
|
setErrors(formatValidationErrors(res.error));
|
1842
2331
|
}
|
@@ -1880,7 +2369,7 @@ const UnpublishAction$1 = ({
|
|
1880
2369
|
id: "app.utils.unpublish",
|
1881
2370
|
defaultMessage: "Unpublish"
|
1882
2371
|
}),
|
1883
|
-
icon: /* @__PURE__ */ jsx(
|
2372
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1884
2373
|
onClick: async () => {
|
1885
2374
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1886
2375
|
if (!documentId) {
|
@@ -1992,7 +2481,7 @@ const DiscardAction = ({
|
|
1992
2481
|
id: "content-manager.actions.discard.label",
|
1993
2482
|
defaultMessage: "Discard changes"
|
1994
2483
|
}),
|
1995
|
-
icon: /* @__PURE__ */ jsx(
|
2484
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1996
2485
|
position: ["panel", "table-row"],
|
1997
2486
|
variant: "danger",
|
1998
2487
|
dialog: {
|
@@ -2020,11 +2509,6 @@ const DiscardAction = ({
|
|
2020
2509
|
};
|
2021
2510
|
};
|
2022
2511
|
DiscardAction.type = "discard";
|
2023
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2024
|
-
path {
|
2025
|
-
fill: currentColor;
|
2026
|
-
}
|
2027
|
-
`;
|
2028
2512
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2029
2513
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2030
2514
|
const RelativeTime = React.forwardRef(
|
@@ -2072,7 +2556,7 @@ const getDisplayName = ({
|
|
2072
2556
|
};
|
2073
2557
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2074
2558
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2075
|
-
const statusVariant = status === "draft" ? "
|
2559
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2076
2560
|
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2077
2561
|
};
|
2078
2562
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2082,23 +2566,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2082
2566
|
id: "content-manager.containers.edit.title.new",
|
2083
2567
|
defaultMessage: "Create an entry"
|
2084
2568
|
}) : documentTitle;
|
2085
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2569
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2086
2570
|
/* @__PURE__ */ jsx(BackButton, {}),
|
2087
|
-
/* @__PURE__ */ jsxs(
|
2088
|
-
|
2089
|
-
{
|
2090
|
-
|
2091
|
-
|
2092
|
-
paddingTop: 1,
|
2093
|
-
gap: "80px",
|
2094
|
-
alignItems: "flex-start",
|
2095
|
-
children: [
|
2096
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2097
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2098
|
-
]
|
2099
|
-
}
|
2100
|
-
),
|
2101
|
-
status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
|
2571
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2572
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2573
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2574
|
+
] }),
|
2575
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2102
2576
|
] });
|
2103
2577
|
};
|
2104
2578
|
const HeaderToolbar = () => {
|
@@ -2181,12 +2655,12 @@ const Information = ({ activeTab }) => {
|
|
2181
2655
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2182
2656
|
label: formatMessage({
|
2183
2657
|
id: "content-manager.containers.edit.information.last-published.label",
|
2184
|
-
defaultMessage: "
|
2658
|
+
defaultMessage: "Published"
|
2185
2659
|
}),
|
2186
2660
|
value: formatMessage(
|
2187
2661
|
{
|
2188
2662
|
id: "content-manager.containers.edit.information.last-published.value",
|
2189
|
-
defaultMessage: `
|
2663
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2190
2664
|
},
|
2191
2665
|
{
|
2192
2666
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2199,12 +2673,12 @@ const Information = ({ activeTab }) => {
|
|
2199
2673
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2200
2674
|
label: formatMessage({
|
2201
2675
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2202
|
-
defaultMessage: "
|
2676
|
+
defaultMessage: "Updated"
|
2203
2677
|
}),
|
2204
2678
|
value: formatMessage(
|
2205
2679
|
{
|
2206
2680
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2207
|
-
defaultMessage: `
|
2681
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2208
2682
|
},
|
2209
2683
|
{
|
2210
2684
|
time: /* @__PURE__ */ jsx(
|
@@ -2222,12 +2696,12 @@ const Information = ({ activeTab }) => {
|
|
2222
2696
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2223
2697
|
label: formatMessage({
|
2224
2698
|
id: "content-manager.containers.edit.information.document.label",
|
2225
|
-
defaultMessage: "
|
2699
|
+
defaultMessage: "Created"
|
2226
2700
|
}),
|
2227
2701
|
value: formatMessage(
|
2228
2702
|
{
|
2229
2703
|
id: "content-manager.containers.edit.information.document.value",
|
2230
|
-
defaultMessage: `
|
2704
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2231
2705
|
},
|
2232
2706
|
{
|
2233
2707
|
time: /* @__PURE__ */ jsx(
|
@@ -2265,25 +2739,77 @@ const Information = ({ activeTab }) => {
|
|
2265
2739
|
);
|
2266
2740
|
};
|
2267
2741
|
const HeaderActions = ({ actions: actions2 }) => {
|
2268
|
-
|
2269
|
-
|
2742
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2743
|
+
const handleClick = (action) => async (e) => {
|
2744
|
+
if (!("options" in action)) {
|
2745
|
+
const { onClick = () => false, dialog, id } = action;
|
2746
|
+
const muteDialog = await onClick(e);
|
2747
|
+
if (dialog && !muteDialog) {
|
2748
|
+
e.preventDefault();
|
2749
|
+
setDialogId(id);
|
2750
|
+
}
|
2751
|
+
}
|
2752
|
+
};
|
2753
|
+
const handleClose = () => {
|
2754
|
+
setDialogId(null);
|
2755
|
+
};
|
2756
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2757
|
+
if (action.options) {
|
2270
2758
|
return /* @__PURE__ */ jsx(
|
2271
2759
|
SingleSelect,
|
2272
2760
|
{
|
2273
2761
|
size: "S",
|
2274
|
-
disabled: action.disabled,
|
2275
|
-
"aria-label": action.label,
|
2276
2762
|
onChange: action.onSelect,
|
2277
|
-
|
2763
|
+
"aria-label": action.label,
|
2764
|
+
...action,
|
2278
2765
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2279
2766
|
},
|
2280
2767
|
action.id
|
2281
2768
|
);
|
2282
2769
|
} else {
|
2283
|
-
|
2770
|
+
if (action.type === "icon") {
|
2771
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2772
|
+
/* @__PURE__ */ jsx(
|
2773
|
+
IconButton,
|
2774
|
+
{
|
2775
|
+
disabled: action.disabled,
|
2776
|
+
label: action.label,
|
2777
|
+
size: "S",
|
2778
|
+
onClick: handleClick(action),
|
2779
|
+
children: action.icon
|
2780
|
+
}
|
2781
|
+
),
|
2782
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2783
|
+
HeaderActionDialog,
|
2784
|
+
{
|
2785
|
+
...action.dialog,
|
2786
|
+
isOpen: dialogId === action.id,
|
2787
|
+
onClose: handleClose
|
2788
|
+
}
|
2789
|
+
) : null
|
2790
|
+
] }, action.id);
|
2791
|
+
}
|
2284
2792
|
}
|
2285
2793
|
}) });
|
2286
2794
|
};
|
2795
|
+
const HeaderActionDialog = ({
|
2796
|
+
onClose,
|
2797
|
+
onCancel,
|
2798
|
+
title,
|
2799
|
+
content: Content,
|
2800
|
+
isOpen
|
2801
|
+
}) => {
|
2802
|
+
const handleClose = async () => {
|
2803
|
+
if (onCancel) {
|
2804
|
+
await onCancel();
|
2805
|
+
}
|
2806
|
+
onClose();
|
2807
|
+
};
|
2808
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2809
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2810
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2811
|
+
] }) });
|
2812
|
+
};
|
2287
2813
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2288
2814
|
const navigate = useNavigate();
|
2289
2815
|
const { formatMessage } = useIntl();
|
@@ -2324,12 +2850,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2324
2850
|
const { delete: deleteAction } = useDocumentActions();
|
2325
2851
|
const { toggleNotification } = useNotification();
|
2326
2852
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2853
|
+
const isLocalized = document?.locale != null;
|
2327
2854
|
return {
|
2328
2855
|
disabled: !canDelete || !document,
|
2329
|
-
label: formatMessage(
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2856
|
+
label: formatMessage(
|
2857
|
+
{
|
2858
|
+
id: "content-manager.actions.delete.label",
|
2859
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2860
|
+
},
|
2861
|
+
{ isLocalized }
|
2862
|
+
),
|
2333
2863
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2334
2864
|
dialog: {
|
2335
2865
|
type: "dialog",
|
@@ -2365,423 +2895,121 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2365
2895
|
const res = await deleteAction({
|
2366
2896
|
documentId,
|
2367
2897
|
model,
|
2368
|
-
collectionType,
|
2369
|
-
params: {
|
2370
|
-
locale: "*"
|
2371
|
-
}
|
2372
|
-
});
|
2373
|
-
if (!("error" in res)) {
|
2374
|
-
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2375
|
-
}
|
2376
|
-
} finally {
|
2377
|
-
if (!listViewPathMatch) {
|
2378
|
-
setSubmitting(false);
|
2379
|
-
}
|
2380
|
-
}
|
2381
|
-
}
|
2382
|
-
},
|
2383
|
-
variant: "danger",
|
2384
|
-
position: ["header", "table-row"]
|
2385
|
-
};
|
2386
|
-
};
|
2387
|
-
DeleteAction$1.type = "delete";
|
2388
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2389
|
-
const Panels = () => {
|
2390
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2391
|
-
const [
|
2392
|
-
{
|
2393
|
-
query: { status }
|
2394
|
-
}
|
2395
|
-
] = useQueryParams({
|
2396
|
-
status: "draft"
|
2397
|
-
});
|
2398
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2399
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2400
|
-
const props = {
|
2401
|
-
activeTab: status,
|
2402
|
-
model,
|
2403
|
-
documentId: id,
|
2404
|
-
document: isCloning ? void 0 : document,
|
2405
|
-
meta: isCloning ? void 0 : meta,
|
2406
|
-
collectionType
|
2407
|
-
};
|
2408
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2409
|
-
DescriptionComponentRenderer,
|
2410
|
-
{
|
2411
|
-
props,
|
2412
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2413
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2414
|
-
}
|
2415
|
-
) });
|
2416
|
-
};
|
2417
|
-
const ActionsPanel = () => {
|
2418
|
-
const { formatMessage } = useIntl();
|
2419
|
-
return {
|
2420
|
-
title: formatMessage({
|
2421
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2422
|
-
defaultMessage: "Document"
|
2423
|
-
}),
|
2424
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2425
|
-
};
|
2426
|
-
};
|
2427
|
-
ActionsPanel.type = "actions";
|
2428
|
-
const ActionsPanelContent = () => {
|
2429
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2430
|
-
const [
|
2431
|
-
{
|
2432
|
-
query: { status = "draft" }
|
2433
|
-
}
|
2434
|
-
] = useQueryParams();
|
2435
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2436
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2437
|
-
const props = {
|
2438
|
-
activeTab: status,
|
2439
|
-
model,
|
2440
|
-
documentId: id,
|
2441
|
-
document: isCloning ? void 0 : document,
|
2442
|
-
meta: isCloning ? void 0 : meta,
|
2443
|
-
collectionType
|
2444
|
-
};
|
2445
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2446
|
-
/* @__PURE__ */ jsx(
|
2447
|
-
DescriptionComponentRenderer,
|
2448
|
-
{
|
2449
|
-
props,
|
2450
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2451
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2452
|
-
}
|
2453
|
-
),
|
2454
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2455
|
-
] });
|
2456
|
-
};
|
2457
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2458
|
-
return /* @__PURE__ */ jsxs(
|
2459
|
-
Flex,
|
2460
|
-
{
|
2461
|
-
ref,
|
2462
|
-
tag: "aside",
|
2463
|
-
"aria-labelledby": "additional-information",
|
2464
|
-
background: "neutral0",
|
2465
|
-
borderColor: "neutral150",
|
2466
|
-
hasRadius: true,
|
2467
|
-
paddingBottom: 4,
|
2468
|
-
paddingLeft: 4,
|
2469
|
-
paddingRight: 4,
|
2470
|
-
paddingTop: 4,
|
2471
|
-
shadow: "tableShadow",
|
2472
|
-
gap: 3,
|
2473
|
-
direction: "column",
|
2474
|
-
justifyContent: "stretch",
|
2475
|
-
alignItems: "flex-start",
|
2476
|
-
children: [
|
2477
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2478
|
-
children
|
2479
|
-
]
|
2480
|
-
}
|
2481
|
-
);
|
2482
|
-
});
|
2483
|
-
const HOOKS = {
|
2484
|
-
/**
|
2485
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2486
|
-
* @constant
|
2487
|
-
* @type {string}
|
2488
|
-
*/
|
2489
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2490
|
-
/**
|
2491
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2492
|
-
* @constant
|
2493
|
-
* @type {string}
|
2494
|
-
*/
|
2495
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2496
|
-
/**
|
2497
|
-
* Hook that allows to mutate the CM's edit view layout
|
2498
|
-
* @constant
|
2499
|
-
* @type {string}
|
2500
|
-
*/
|
2501
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2502
|
-
/**
|
2503
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2504
|
-
* @constant
|
2505
|
-
* @type {string}
|
2506
|
-
*/
|
2507
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2508
|
-
};
|
2509
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2510
|
-
endpoints: (builder) => ({
|
2511
|
-
getContentTypeConfiguration: builder.query({
|
2512
|
-
query: (uid) => ({
|
2513
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2514
|
-
method: "GET"
|
2515
|
-
}),
|
2516
|
-
transformResponse: (response) => response.data,
|
2517
|
-
providesTags: (_result, _error, uid) => [
|
2518
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2519
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2520
|
-
]
|
2521
|
-
}),
|
2522
|
-
getAllContentTypeSettings: builder.query({
|
2523
|
-
query: () => "/content-manager/content-types-settings",
|
2524
|
-
transformResponse: (response) => response.data,
|
2525
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2526
|
-
}),
|
2527
|
-
updateContentTypeConfiguration: builder.mutation({
|
2528
|
-
query: ({ uid, ...body }) => ({
|
2529
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2530
|
-
method: "PUT",
|
2531
|
-
data: body
|
2532
|
-
}),
|
2533
|
-
transformResponse: (response) => response.data,
|
2534
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2535
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2536
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2537
|
-
// Is this necessary?
|
2538
|
-
{ type: "InitialData" }
|
2539
|
-
]
|
2540
|
-
})
|
2541
|
-
})
|
2542
|
-
});
|
2543
|
-
const {
|
2544
|
-
useGetContentTypeConfigurationQuery,
|
2545
|
-
useGetAllContentTypeSettingsQuery,
|
2546
|
-
useUpdateContentTypeConfigurationMutation
|
2547
|
-
} = contentTypesApi;
|
2548
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2549
|
-
const { type } = attribute;
|
2550
|
-
if (type === "relation") {
|
2551
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2552
|
-
}
|
2553
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2554
|
-
};
|
2555
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2556
|
-
if (!mainFieldName) {
|
2557
|
-
return void 0;
|
2558
|
-
}
|
2559
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2560
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2561
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2562
|
-
);
|
2563
|
-
return {
|
2564
|
-
name: mainFieldName,
|
2565
|
-
type: mainFieldType ?? "string"
|
2566
|
-
};
|
2567
|
-
};
|
2568
|
-
const DEFAULT_SETTINGS = {
|
2569
|
-
bulkable: false,
|
2570
|
-
filterable: false,
|
2571
|
-
searchable: false,
|
2572
|
-
pagination: false,
|
2573
|
-
defaultSortBy: "",
|
2574
|
-
defaultSortOrder: "asc",
|
2575
|
-
mainField: "id",
|
2576
|
-
pageSize: 10
|
2577
|
-
};
|
2578
|
-
const useDocumentLayout = (model) => {
|
2579
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2580
|
-
const [{ query }] = useQueryParams();
|
2581
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2582
|
-
const { toggleNotification } = useNotification();
|
2583
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2584
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2585
|
-
const {
|
2586
|
-
data,
|
2587
|
-
isLoading: isLoadingConfigs,
|
2588
|
-
error,
|
2589
|
-
isFetching: isFetchingConfigs
|
2590
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2591
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2592
|
-
React.useEffect(() => {
|
2593
|
-
if (error) {
|
2594
|
-
toggleNotification({
|
2595
|
-
type: "danger",
|
2596
|
-
message: formatAPIError(error)
|
2597
|
-
});
|
2598
|
-
}
|
2599
|
-
}, [error, formatAPIError, toggleNotification]);
|
2600
|
-
const editLayout = React.useMemo(
|
2601
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2602
|
-
layout: [],
|
2603
|
-
components: {},
|
2604
|
-
metadatas: {},
|
2605
|
-
options: {},
|
2606
|
-
settings: DEFAULT_SETTINGS
|
2607
|
-
},
|
2608
|
-
[data, isLoading, schemas, schema, components]
|
2609
|
-
);
|
2610
|
-
const listLayout = React.useMemo(() => {
|
2611
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2612
|
-
layout: [],
|
2613
|
-
metadatas: {},
|
2614
|
-
options: {},
|
2615
|
-
settings: DEFAULT_SETTINGS
|
2616
|
-
};
|
2617
|
-
}, [data, isLoading, schemas, schema, components]);
|
2618
|
-
const { layout: edit } = React.useMemo(
|
2619
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2620
|
-
layout: editLayout,
|
2621
|
-
query
|
2622
|
-
}),
|
2623
|
-
[editLayout, query, runHookWaterfall]
|
2624
|
-
);
|
2625
|
-
return {
|
2626
|
-
error,
|
2627
|
-
isLoading,
|
2628
|
-
edit,
|
2629
|
-
list: listLayout
|
2630
|
-
};
|
2631
|
-
};
|
2632
|
-
const useDocLayout = () => {
|
2633
|
-
const { model } = useDoc();
|
2634
|
-
return useDocumentLayout(model);
|
2635
|
-
};
|
2636
|
-
const formatEditLayout = (data, {
|
2637
|
-
schemas,
|
2638
|
-
schema,
|
2639
|
-
components
|
2640
|
-
}) => {
|
2641
|
-
let currentPanelIndex = 0;
|
2642
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2643
|
-
data.contentType.layouts.edit,
|
2644
|
-
schema?.attributes,
|
2645
|
-
data.contentType.metadatas,
|
2646
|
-
{ configurations: data.components, schemas: components },
|
2647
|
-
schemas
|
2648
|
-
).reduce((panels, row) => {
|
2649
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2650
|
-
panels.push([row]);
|
2651
|
-
currentPanelIndex += 2;
|
2652
|
-
} else {
|
2653
|
-
if (!panels[currentPanelIndex]) {
|
2654
|
-
panels.push([]);
|
2655
|
-
}
|
2656
|
-
panels[currentPanelIndex].push(row);
|
2657
|
-
}
|
2658
|
-
return panels;
|
2659
|
-
}, []);
|
2660
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2661
|
-
(acc, [uid, configuration]) => {
|
2662
|
-
acc[uid] = {
|
2663
|
-
layout: convertEditLayoutToFieldLayouts(
|
2664
|
-
configuration.layouts.edit,
|
2665
|
-
components[uid].attributes,
|
2666
|
-
configuration.metadatas
|
2667
|
-
),
|
2668
|
-
settings: {
|
2669
|
-
...configuration.settings,
|
2670
|
-
icon: components[uid].info.icon,
|
2671
|
-
displayName: components[uid].info.displayName
|
2898
|
+
collectionType,
|
2899
|
+
params: {
|
2900
|
+
locale: "*"
|
2901
|
+
}
|
2902
|
+
});
|
2903
|
+
if (!("error" in res)) {
|
2904
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2905
|
+
}
|
2906
|
+
} finally {
|
2907
|
+
if (!listViewPathMatch) {
|
2908
|
+
setSubmitting(false);
|
2909
|
+
}
|
2672
2910
|
}
|
2673
|
-
}
|
2674
|
-
return acc;
|
2675
|
-
},
|
2676
|
-
{}
|
2677
|
-
);
|
2678
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2679
|
-
(acc, [attribute, metadata]) => {
|
2680
|
-
return {
|
2681
|
-
...acc,
|
2682
|
-
[attribute]: metadata.edit
|
2683
|
-
};
|
2684
|
-
},
|
2685
|
-
{}
|
2686
|
-
);
|
2687
|
-
return {
|
2688
|
-
layout: panelledEditAttributes,
|
2689
|
-
components: componentEditAttributes,
|
2690
|
-
metadatas: editMetadatas,
|
2691
|
-
settings: {
|
2692
|
-
...data.contentType.settings,
|
2693
|
-
displayName: schema?.info.displayName
|
2911
|
+
}
|
2694
2912
|
},
|
2695
|
-
|
2696
|
-
|
2697
|
-
...schema?.pluginOptions,
|
2698
|
-
...data.contentType.options
|
2699
|
-
}
|
2913
|
+
variant: "danger",
|
2914
|
+
position: ["header", "table-row"]
|
2700
2915
|
};
|
2701
2916
|
};
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2706
|
-
|
2707
|
-
|
2708
|
-
}
|
2709
|
-
|
2710
|
-
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
}
|
2729
|
-
}
|
2730
|
-
);
|
2917
|
+
DeleteAction$1.type = "delete";
|
2918
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2919
|
+
const Panels = () => {
|
2920
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2921
|
+
const [
|
2922
|
+
{
|
2923
|
+
query: { status }
|
2924
|
+
}
|
2925
|
+
] = useQueryParams({
|
2926
|
+
status: "draft"
|
2927
|
+
});
|
2928
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2929
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2930
|
+
const props = {
|
2931
|
+
activeTab: status,
|
2932
|
+
model,
|
2933
|
+
documentId: id,
|
2934
|
+
document: isCloning ? void 0 : document,
|
2935
|
+
meta: isCloning ? void 0 : meta,
|
2936
|
+
collectionType
|
2937
|
+
};
|
2938
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2939
|
+
DescriptionComponentRenderer,
|
2940
|
+
{
|
2941
|
+
props,
|
2942
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2943
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2944
|
+
}
|
2945
|
+
) });
|
2731
2946
|
};
|
2732
|
-
const
|
2733
|
-
|
2734
|
-
schema,
|
2735
|
-
components
|
2736
|
-
}) => {
|
2737
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2738
|
-
(acc, [attribute, metadata]) => {
|
2739
|
-
return {
|
2740
|
-
...acc,
|
2741
|
-
[attribute]: metadata.list
|
2742
|
-
};
|
2743
|
-
},
|
2744
|
-
{}
|
2745
|
-
);
|
2746
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2747
|
-
data.contentType.layouts.list,
|
2748
|
-
schema?.attributes,
|
2749
|
-
listMetadatas,
|
2750
|
-
{ configurations: data.components, schemas: components },
|
2751
|
-
schemas
|
2752
|
-
);
|
2947
|
+
const ActionsPanel = () => {
|
2948
|
+
const { formatMessage } = useIntl();
|
2753
2949
|
return {
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
...schema?.pluginOptions,
|
2760
|
-
...data.contentType.options
|
2761
|
-
}
|
2950
|
+
title: formatMessage({
|
2951
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2952
|
+
defaultMessage: "Entry"
|
2953
|
+
}),
|
2954
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2762
2955
|
};
|
2763
2956
|
};
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2957
|
+
ActionsPanel.type = "actions";
|
2958
|
+
const ActionsPanelContent = () => {
|
2959
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2960
|
+
const [
|
2961
|
+
{
|
2962
|
+
query: { status = "draft" }
|
2769
2963
|
}
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2964
|
+
] = useQueryParams();
|
2965
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2966
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2967
|
+
const props = {
|
2968
|
+
activeTab: status,
|
2969
|
+
model,
|
2970
|
+
documentId: id,
|
2971
|
+
document: isCloning ? void 0 : document,
|
2972
|
+
meta: isCloning ? void 0 : meta,
|
2973
|
+
collectionType
|
2974
|
+
};
|
2975
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2976
|
+
/* @__PURE__ */ jsx(
|
2977
|
+
DescriptionComponentRenderer,
|
2978
|
+
{
|
2979
|
+
props,
|
2980
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2981
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2982
|
+
}
|
2983
|
+
),
|
2984
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2985
|
+
] });
|
2784
2986
|
};
|
2987
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2988
|
+
return /* @__PURE__ */ jsxs(
|
2989
|
+
Flex,
|
2990
|
+
{
|
2991
|
+
ref,
|
2992
|
+
tag: "aside",
|
2993
|
+
"aria-labelledby": "additional-information",
|
2994
|
+
background: "neutral0",
|
2995
|
+
borderColor: "neutral150",
|
2996
|
+
hasRadius: true,
|
2997
|
+
paddingBottom: 4,
|
2998
|
+
paddingLeft: 4,
|
2999
|
+
paddingRight: 4,
|
3000
|
+
paddingTop: 4,
|
3001
|
+
shadow: "tableShadow",
|
3002
|
+
gap: 3,
|
3003
|
+
direction: "column",
|
3004
|
+
justifyContent: "stretch",
|
3005
|
+
alignItems: "flex-start",
|
3006
|
+
children: [
|
3007
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3008
|
+
children
|
3009
|
+
]
|
3010
|
+
}
|
3011
|
+
);
|
3012
|
+
});
|
2785
3013
|
const ConfirmBulkActionDialog = ({
|
2786
3014
|
onToggleDialog,
|
2787
3015
|
isOpen = false,
|
@@ -2789,7 +3017,7 @@ const ConfirmBulkActionDialog = ({
|
|
2789
3017
|
endAction
|
2790
3018
|
}) => {
|
2791
3019
|
const { formatMessage } = useIntl();
|
2792
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3020
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2793
3021
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2794
3022
|
id: "app.components.ConfirmDialog.title",
|
2795
3023
|
defaultMessage: "Confirmation"
|
@@ -2820,6 +3048,7 @@ const ConfirmDialogPublishAll = ({
|
|
2820
3048
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2821
3049
|
const { model, schema } = useDoc();
|
2822
3050
|
const [{ query }] = useQueryParams();
|
3051
|
+
const enableDraftRelationsCount = false;
|
2823
3052
|
const {
|
2824
3053
|
data: countDraftRelations = 0,
|
2825
3054
|
isLoading,
|
@@ -2831,7 +3060,7 @@ const ConfirmDialogPublishAll = ({
|
|
2831
3060
|
locale: query?.plugins?.i18n?.locale
|
2832
3061
|
},
|
2833
3062
|
{
|
2834
|
-
skip:
|
3063
|
+
skip: !enableDraftRelationsCount
|
2835
3064
|
}
|
2836
3065
|
);
|
2837
3066
|
React.useEffect(() => {
|
@@ -2910,7 +3139,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2910
3139
|
)
|
2911
3140
|
);
|
2912
3141
|
} else {
|
2913
|
-
messages.push(
|
3142
|
+
messages.push(
|
3143
|
+
...formatErrorMessages(
|
3144
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3145
|
+
value,
|
3146
|
+
currentKey,
|
3147
|
+
formatMessage
|
3148
|
+
)
|
3149
|
+
);
|
2914
3150
|
}
|
2915
3151
|
} else {
|
2916
3152
|
messages.push(
|
@@ -3009,7 +3245,7 @@ const SelectedEntriesTableContent = ({
|
|
3009
3245
|
status: row.status
|
3010
3246
|
}
|
3011
3247
|
) }),
|
3012
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3248
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3013
3249
|
IconButton,
|
3014
3250
|
{
|
3015
3251
|
tag: Link,
|
@@ -3032,9 +3268,10 @@ const SelectedEntriesTableContent = ({
|
|
3032
3268
|
),
|
3033
3269
|
target: "_blank",
|
3034
3270
|
marginLeft: "auto",
|
3035
|
-
|
3271
|
+
variant: "ghost",
|
3272
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3036
3273
|
}
|
3037
|
-
) })
|
3274
|
+
) }) })
|
3038
3275
|
] }, row.id)) })
|
3039
3276
|
] });
|
3040
3277
|
};
|
@@ -3071,7 +3308,13 @@ const SelectedEntriesModalContent = ({
|
|
3071
3308
|
);
|
3072
3309
|
const { rows, validationErrors } = React.useMemo(() => {
|
3073
3310
|
if (data.length > 0 && schema) {
|
3074
|
-
const validate = createYupSchema(
|
3311
|
+
const validate = createYupSchema(
|
3312
|
+
schema.attributes,
|
3313
|
+
components,
|
3314
|
+
// Since this is the "Publish" action, the validation
|
3315
|
+
// schema must enforce the rules for published entities
|
3316
|
+
{ status: "published" }
|
3317
|
+
);
|
3075
3318
|
const validationErrors2 = {};
|
3076
3319
|
const rows2 = data.map((entry) => {
|
3077
3320
|
try {
|
@@ -3421,7 +3664,7 @@ const TableActions = ({ document }) => {
|
|
3421
3664
|
DescriptionComponentRenderer,
|
3422
3665
|
{
|
3423
3666
|
props,
|
3424
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3667
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3425
3668
|
children: (actions2) => {
|
3426
3669
|
const tableRowActions = actions2.filter((action) => {
|
3427
3670
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3532,7 +3775,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3532
3775
|
}),
|
3533
3776
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3534
3777
|
footer: ({ onClose }) => {
|
3535
|
-
return /* @__PURE__ */ jsxs(
|
3778
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3536
3779
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3537
3780
|
id: "cancel",
|
3538
3781
|
defaultMessage: "Cancel"
|
@@ -3573,8 +3816,7 @@ class ContentManagerPlugin {
|
|
3573
3816
|
documentActions = [
|
3574
3817
|
...DEFAULT_ACTIONS,
|
3575
3818
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3576
|
-
...DEFAULT_HEADER_ACTIONS
|
3577
|
-
HistoryAction
|
3819
|
+
...DEFAULT_HEADER_ACTIONS
|
3578
3820
|
];
|
3579
3821
|
editViewSidePanels = [ActionsPanel];
|
3580
3822
|
headerActions = [];
|
@@ -3663,6 +3905,52 @@ const getPrintableType = (value) => {
|
|
3663
3905
|
}
|
3664
3906
|
return nativeType;
|
3665
3907
|
};
|
3908
|
+
const HistoryAction = ({ model, document }) => {
|
3909
|
+
const { formatMessage } = useIntl();
|
3910
|
+
const [{ query }] = useQueryParams();
|
3911
|
+
const navigate = useNavigate();
|
3912
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3913
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3914
|
+
return null;
|
3915
|
+
}
|
3916
|
+
return {
|
3917
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3918
|
+
label: formatMessage({
|
3919
|
+
id: "content-manager.history.document-action",
|
3920
|
+
defaultMessage: "Content History"
|
3921
|
+
}),
|
3922
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3923
|
+
disabled: (
|
3924
|
+
/**
|
3925
|
+
* The user is creating a new document.
|
3926
|
+
* It hasn't been saved yet, so there's no history to go to
|
3927
|
+
*/
|
3928
|
+
!document || /**
|
3929
|
+
* The document has been created but the current dimension has never been saved.
|
3930
|
+
* For example, the user is creating a new locale in an existing document,
|
3931
|
+
* so there's no history for the document in that locale
|
3932
|
+
*/
|
3933
|
+
!document.id || /**
|
3934
|
+
* History is only available for content types created by the user.
|
3935
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3936
|
+
* which start with `admin::` or `plugin::`
|
3937
|
+
*/
|
3938
|
+
!model.startsWith("api::")
|
3939
|
+
),
|
3940
|
+
position: "header"
|
3941
|
+
};
|
3942
|
+
};
|
3943
|
+
HistoryAction.type = "history";
|
3944
|
+
const historyAdmin = {
|
3945
|
+
bootstrap(app) {
|
3946
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3947
|
+
addDocumentAction((actions2) => {
|
3948
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3949
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3950
|
+
return actions2;
|
3951
|
+
});
|
3952
|
+
}
|
3953
|
+
};
|
3666
3954
|
const initialState = {
|
3667
3955
|
collectionTypeLinks: [],
|
3668
3956
|
components: [],
|
@@ -3713,15 +4001,29 @@ const index = {
|
|
3713
4001
|
defaultMessage: "Content Manager"
|
3714
4002
|
},
|
3715
4003
|
permissions: [],
|
3716
|
-
Component: () => import("./layout-B1Z-9koY.mjs").then((mod) => ({ default: mod.Layout })),
|
3717
4004
|
position: 1
|
3718
4005
|
});
|
4006
|
+
app.router.addRoute({
|
4007
|
+
path: "content-manager/*",
|
4008
|
+
lazy: async () => {
|
4009
|
+
const { Layout } = await import("./layout-vzKSrr7p.mjs");
|
4010
|
+
return {
|
4011
|
+
Component: Layout
|
4012
|
+
};
|
4013
|
+
},
|
4014
|
+
children: routes
|
4015
|
+
});
|
3719
4016
|
app.registerPlugin(cm.config);
|
3720
4017
|
},
|
4018
|
+
bootstrap(app) {
|
4019
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4020
|
+
historyAdmin.bootstrap(app);
|
4021
|
+
}
|
4022
|
+
},
|
3721
4023
|
async registerTrads({ locales }) {
|
3722
4024
|
const importedTrads = await Promise.all(
|
3723
4025
|
locales.map((locale) => {
|
3724
|
-
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-
|
4026
|
+
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 }) => {
|
3725
4027
|
return {
|
3726
4028
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3727
4029
|
locale
|
@@ -3749,7 +4051,8 @@ export {
|
|
3749
4051
|
InjectionZone as I,
|
3750
4052
|
useDocument as J,
|
3751
4053
|
index as K,
|
3752
|
-
|
4054
|
+
useContentManagerContext as L,
|
4055
|
+
useDocumentActions as M,
|
3753
4056
|
Panels as P,
|
3754
4057
|
RelativeTime as R,
|
3755
4058
|
SINGLE_TYPES as S,
|
@@ -3767,11 +4070,11 @@ export {
|
|
3767
4070
|
PERMISSIONS as k,
|
3768
4071
|
DocumentRBAC as l,
|
3769
4072
|
DOCUMENT_META_FIELDS as m,
|
3770
|
-
|
3771
|
-
|
3772
|
-
|
3773
|
-
|
3774
|
-
|
4073
|
+
CLONE_PATH as n,
|
4074
|
+
useDocLayout as o,
|
4075
|
+
useGetContentTypeConfigurationQuery as p,
|
4076
|
+
CREATOR_FIELDS as q,
|
4077
|
+
getMainField as r,
|
3775
4078
|
setInitialData as s,
|
3776
4079
|
getDisplayName as t,
|
3777
4080
|
useContentTypeSchema as u,
|
@@ -3781,4 +4084,4 @@ export {
|
|
3781
4084
|
capitalise as y,
|
3782
4085
|
useUpdateContentTypeConfigurationMutation as z
|
3783
4086
|
};
|
3784
|
-
//# sourceMappingURL=index-
|
4087
|
+
//# sourceMappingURL=index-CJ2vYwuT.mjs.map
|