@strapi/content-manager 0.0.0-experimental.62ce06180fe9a772eaeb3d43d238b26644f39f7c → 0.0.0-experimental.646ad2aaf2b8f9970409242af8d77b0512d19bd1
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-D1SEOQBu.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-Cl7eB3s4.js.map → ComponentConfigurationPage-D1SEOQBu.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs → ComponentConfigurationPage-oqdZo6l8.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DErJQEVW.mjs.map → ComponentConfigurationPage-oqdZo6l8.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js → EditConfigurationPage-BP94U6vG.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CyfFvH6-.js.map → EditConfigurationPage-BP94U6vG.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs → EditConfigurationPage-DVLmpXPs.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CBosWqQ7.mjs.map → EditConfigurationPage-DVLmpXPs.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DxyAOItK.js → EditViewPage-BfAywbBE.js} +30 -9
- package/dist/_chunks/EditViewPage-BfAywbBE.js.map +1 -0
- package/dist/_chunks/{EditViewPage-ClIueJnM.mjs → EditViewPage-Cvjs7D6M.mjs} +30 -9
- package/dist/_chunks/EditViewPage-Cvjs7D6M.mjs.map +1 -0
- package/dist/_chunks/{Field-BZBYmvaf.mjs → Field-CJrfStLX.mjs} +517 -153
- package/dist/_chunks/Field-CJrfStLX.mjs.map +1 -0
- package/dist/_chunks/{Field-C0Y_SR9e.js → Field-DC7FM64m.js} +519 -155
- package/dist/_chunks/Field-DC7FM64m.js.map +1 -0
- package/dist/_chunks/{Form-DwvGnISS.js → Form-Ahp2hi7E.js} +36 -17
- package/dist/_chunks/Form-Ahp2hi7E.js.map +1 -0
- package/dist/_chunks/{Form-jwRSC2kV.mjs → Form-BTgUlCEm.mjs} +36 -17
- package/dist/_chunks/Form-BTgUlCEm.mjs.map +1 -0
- package/dist/_chunks/{History-Cda0Yjzz.js → History-DZ9T1ZL6.js} +63 -25
- package/dist/_chunks/History-DZ9T1ZL6.js.map +1 -0
- package/dist/_chunks/{History-BgzAIj0G.mjs → History-Drr6mxnK.mjs} +64 -26
- package/dist/_chunks/History-Drr6mxnK.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-C29EF97r.js → ListConfigurationPage-B8bYMcVE.js} +20 -8
- package/dist/_chunks/ListConfigurationPage-B8bYMcVE.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-GH55qfoT.mjs → ListConfigurationPage-C6calJtW.mjs} +20 -8
- package/dist/_chunks/ListConfigurationPage-C6calJtW.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CnRt0UT7.js → ListViewPage-BfiTNTUl.js} +61 -43
- package/dist/_chunks/ListViewPage-BfiTNTUl.js.map +1 -0
- package/dist/_chunks/{ListViewPage-QU03PFj1.mjs → ListViewPage-CQb0CL40.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CQb0CL40.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs → NoContentTypePage-C-BK38Ai.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CPs2CnzH.mjs.map → NoContentTypePage-C-BK38Ai.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js → NoContentTypePage-wJwVyqoZ.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DFDjxByI.js.map → NoContentTypePage-wJwVyqoZ.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs → NoPermissionsPage-BBdxJ-4m.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-ct58lcY0.mjs.map → NoPermissionsPage-BBdxJ-4m.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js → NoPermissionsPage-DKaXyuK9.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BVHI-jv5.js.map → NoPermissionsPage-DKaXyuK9.js.map} +1 -1
- package/dist/_chunks/{Relations-BjpPPCKp.js → Relations-D7NskJzt.js} +69 -36
- package/dist/_chunks/Relations-D7NskJzt.js.map +1 -0
- package/dist/_chunks/{Relations-KMf5qEN0.mjs → Relations-DApDLUXv.mjs} +70 -37
- package/dist/_chunks/Relations-DApDLUXv.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-Bz1SCyIj.mjs} +1005 -686
- package/dist/_chunks/index-Bz1SCyIj.mjs.map +1 -0
- package/dist/_chunks/{index-D9ZwczCV.js → index-D3u7haqj.js} +998 -678
- package/dist/_chunks/index-D3u7haqj.js.map +1 -0
- package/dist/_chunks/{layout-BJfBoBiF.js → layout-C_0aK53L.js} +25 -12
- package/dist/_chunks/layout-C_0aK53L.js.map +1 -0
- package/dist/_chunks/{layout-B1Z-9koY.mjs → layout-PNlIceEV.mjs} +27 -14
- package/dist/_chunks/layout-PNlIceEV.mjs.map +1 -0
- package/dist/_chunks/{relations-CgZg7Pyx.mjs → relations-BAIQsBLx.mjs} +3 -7
- package/dist/_chunks/relations-BAIQsBLx.mjs.map +1 -0
- package/dist/_chunks/{relations-CMvjzyU3.js → relations-ClRXiXcM.js} +3 -7
- package/dist/_chunks/relations-ClRXiXcM.js.map +1 -0
- 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 +245 -132
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +246 -133
- 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/utils/metadata.d.ts +15 -1
- package/dist/server/src/controllers/utils/metadata.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/index.d.ts +4 -4
- 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 +8 -8
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -4
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.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/relations-CMvjzyU3.js.map +0 -1
- package/dist/_chunks/relations-CgZg7Pyx.mjs.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,17 +1,18 @@
|
|
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 mapValues from "lodash/fp/mapValues";
|
8
|
+
import { useIntl } from "react-intl";
|
9
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
11
10
|
import * as yup from "yup";
|
12
11
|
import { ValidationError } from "yup";
|
13
12
|
import pipe from "lodash/fp/pipe";
|
14
13
|
import { intervalToDuration, isPast } from "date-fns";
|
14
|
+
import { styled } from "styled-components";
|
15
|
+
import { stringify } from "qs";
|
15
16
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
17
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
18
|
const v = glob[path];
|
@@ -49,42 +50,6 @@ const useInjectionZone = (area) => {
|
|
49
50
|
const [page, position] = area.split(".");
|
50
51
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
51
52
|
};
|
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
53
|
const ID = "id";
|
89
54
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
90
55
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -136,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
136
101
|
if (!slug) {
|
137
102
|
throw new Error("Cannot find the slug param in the URL");
|
138
103
|
}
|
104
|
+
const [{ rawQuery }] = useQueryParams();
|
139
105
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
140
106
|
const contentTypePermissions = React.useMemo(() => {
|
141
107
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -146,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
146
112
|
return { ...acc, [action]: [permission] };
|
147
113
|
}, {});
|
148
114
|
}, [slug, userPermissions]);
|
149
|
-
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
const { isLoading, allowedActions } = useRBAC(
|
116
|
+
contentTypePermissions,
|
117
|
+
permissions ?? void 0,
|
118
|
+
// TODO: useRBAC context should be typed and built differently
|
119
|
+
// We are passing raw query as context to the hook so that it can
|
120
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
121
|
+
rawQuery
|
122
|
+
);
|
150
123
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
151
124
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
152
125
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -195,8 +168,7 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
195
168
|
"InitialData",
|
196
169
|
"HistoryVersion",
|
197
170
|
"Relations",
|
198
|
-
"
|
199
|
-
"ReleaseAction"
|
171
|
+
"UidAvailability"
|
200
172
|
]
|
201
173
|
});
|
202
174
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -210,7 +182,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
210
182
|
params: query
|
211
183
|
}
|
212
184
|
}),
|
213
|
-
invalidatesTags: (_result,
|
185
|
+
invalidatesTags: (_result, error, { model }) => {
|
186
|
+
if (error) {
|
187
|
+
return [];
|
188
|
+
}
|
189
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
190
|
+
}
|
214
191
|
}),
|
215
192
|
cloneDocument: builder.mutation({
|
216
193
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -221,7 +198,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
221
198
|
params
|
222
199
|
}
|
223
200
|
}),
|
224
|
-
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
invalidatesTags: (_result, _error, { model }) => [
|
202
|
+
{ type: "Document", id: `${model}_LIST` },
|
203
|
+
{ type: "UidAvailability", id: model }
|
204
|
+
]
|
225
205
|
}),
|
226
206
|
/**
|
227
207
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -238,7 +218,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
238
218
|
}),
|
239
219
|
invalidatesTags: (result, _error, { model }) => [
|
240
220
|
{ type: "Document", id: `${model}_LIST` },
|
241
|
-
"Relations"
|
221
|
+
"Relations",
|
222
|
+
{ type: "UidAvailability", id: model }
|
242
223
|
]
|
243
224
|
}),
|
244
225
|
deleteDocument: builder.mutation({
|
@@ -250,9 +231,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
250
231
|
}
|
251
232
|
}),
|
252
233
|
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" }
|
234
|
+
{ type: "Document", id: collectionType !== SINGLE_TYPES ? `${model}_LIST` : model }
|
256
235
|
]
|
257
236
|
}),
|
258
237
|
deleteManyDocuments: builder.mutation({
|
@@ -264,11 +243,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
264
243
|
params
|
265
244
|
}
|
266
245
|
}),
|
267
|
-
invalidatesTags: (_res, _error, { model }) => [
|
268
|
-
{ type: "Document", id: `${model}_LIST` },
|
269
|
-
{ type: "Release", id: "LIST" },
|
270
|
-
{ type: "ReleaseAction", id: "LIST" }
|
271
|
-
]
|
246
|
+
invalidatesTags: (_res, _error, { model }) => [{ type: "Document", id: `${model}_LIST` }]
|
272
247
|
}),
|
273
248
|
discardDocument: builder.mutation({
|
274
249
|
query: ({ collectionType, model, documentId, params }) => ({
|
@@ -286,8 +261,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
286
261
|
},
|
287
262
|
{ type: "Document", id: `${model}_LIST` },
|
288
263
|
"Relations",
|
289
|
-
{ type: "
|
290
|
-
{ type: "ReleaseAction", id: "LIST" }
|
264
|
+
{ type: "UidAvailability", id: model }
|
291
265
|
];
|
292
266
|
}
|
293
267
|
}),
|
@@ -305,6 +279,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
305
279
|
}),
|
306
280
|
providesTags: (result, _error, arg) => {
|
307
281
|
return [
|
282
|
+
{ type: "Document", id: `ALL_LIST` },
|
308
283
|
{ type: "Document", id: `${arg.model}_LIST` },
|
309
284
|
...result?.results.map(({ documentId }) => ({
|
310
285
|
type: "Document",
|
@@ -343,6 +318,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
343
318
|
{
|
344
319
|
type: "Document",
|
345
320
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
321
|
+
},
|
322
|
+
// Make it easy to invalidate all individual documents queries for a model
|
323
|
+
{
|
324
|
+
type: "Document",
|
325
|
+
id: `${model}_ALL_ITEMS`
|
346
326
|
}
|
347
327
|
];
|
348
328
|
}
|
@@ -407,9 +387,20 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
407
387
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
408
388
|
},
|
409
389
|
"Relations",
|
410
|
-
{ type: "
|
411
|
-
{ type: "ReleaseAction", id: "LIST" }
|
390
|
+
{ type: "UidAvailability", id: model }
|
412
391
|
];
|
392
|
+
},
|
393
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
394
|
+
const patchResult = dispatch(
|
395
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
396
|
+
Object.assign(draft.data, data);
|
397
|
+
})
|
398
|
+
);
|
399
|
+
try {
|
400
|
+
await queryFulfilled;
|
401
|
+
} catch {
|
402
|
+
patchResult.undo();
|
403
|
+
}
|
413
404
|
}
|
414
405
|
}),
|
415
406
|
unpublishDocument: builder.mutation({
|
@@ -479,20 +470,39 @@ const buildValidParams = (query) => {
|
|
479
470
|
const isBaseQueryError = (error) => {
|
480
471
|
return error.name !== void 0;
|
481
472
|
};
|
482
|
-
const
|
473
|
+
const arrayValidator = (attribute, options) => ({
|
474
|
+
message: translatedErrors.required,
|
475
|
+
test(value) {
|
476
|
+
if (options.status === "draft") {
|
477
|
+
return true;
|
478
|
+
}
|
479
|
+
if (!attribute.required) {
|
480
|
+
return true;
|
481
|
+
}
|
482
|
+
if (!value) {
|
483
|
+
return false;
|
484
|
+
}
|
485
|
+
if (Array.isArray(value) && value.length === 0) {
|
486
|
+
return false;
|
487
|
+
}
|
488
|
+
return true;
|
489
|
+
}
|
490
|
+
});
|
491
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
483
492
|
const createModelSchema = (attributes2) => yup.object().shape(
|
484
493
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
485
494
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
486
495
|
return acc;
|
487
496
|
}
|
488
497
|
const validations = [
|
498
|
+
addNullableValidation,
|
489
499
|
addRequiredValidation,
|
490
500
|
addMinLengthValidation,
|
491
501
|
addMaxLengthValidation,
|
492
502
|
addMinValidation,
|
493
503
|
addMaxValidation,
|
494
504
|
addRegexValidation
|
495
|
-
].map((fn) => fn(attribute));
|
505
|
+
].map((fn) => fn(attribute, options));
|
496
506
|
const transformSchema = pipe(...validations);
|
497
507
|
switch (attribute.type) {
|
498
508
|
case "component": {
|
@@ -502,12 +512,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
502
512
|
...acc,
|
503
513
|
[name]: transformSchema(
|
504
514
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
505
|
-
)
|
515
|
+
).test(arrayValidator(attribute, options))
|
506
516
|
};
|
507
517
|
} else {
|
508
518
|
return {
|
509
519
|
...acc,
|
510
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
520
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
511
521
|
};
|
512
522
|
}
|
513
523
|
}
|
@@ -529,7 +539,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
529
539
|
}
|
530
540
|
)
|
531
541
|
)
|
532
|
-
)
|
542
|
+
).test(arrayValidator(attribute, options))
|
533
543
|
};
|
534
544
|
case "relation":
|
535
545
|
return {
|
@@ -541,7 +551,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
541
551
|
} else if (Array.isArray(value)) {
|
542
552
|
return yup.array().of(
|
543
553
|
yup.object().shape({
|
544
|
-
id: yup.
|
554
|
+
id: yup.number().required()
|
545
555
|
})
|
546
556
|
);
|
547
557
|
} else if (typeof value === "object") {
|
@@ -593,6 +603,14 @@ const createAttributeSchema = (attribute) => {
|
|
593
603
|
if (!value || typeof value === "string" && value.length === 0) {
|
594
604
|
return true;
|
595
605
|
}
|
606
|
+
if (typeof value === "object") {
|
607
|
+
try {
|
608
|
+
JSON.stringify(value);
|
609
|
+
return true;
|
610
|
+
} catch (err) {
|
611
|
+
return false;
|
612
|
+
}
|
613
|
+
}
|
596
614
|
try {
|
597
615
|
JSON.parse(value);
|
598
616
|
return true;
|
@@ -611,13 +629,7 @@ const createAttributeSchema = (attribute) => {
|
|
611
629
|
return yup.mixed();
|
612
630
|
}
|
613
631
|
};
|
614
|
-
const
|
615
|
-
if (attribute.required) {
|
616
|
-
return schema.required({
|
617
|
-
id: translatedErrors.required.id,
|
618
|
-
defaultMessage: "This field is required."
|
619
|
-
});
|
620
|
-
}
|
632
|
+
const nullableSchema = (schema) => {
|
621
633
|
return schema?.nullable ? schema.nullable() : (
|
622
634
|
// In some cases '.nullable' will not be available on the schema.
|
623
635
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -625,7 +637,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
625
637
|
schema
|
626
638
|
);
|
627
639
|
};
|
628
|
-
const
|
640
|
+
const addNullableValidation = () => (schema) => {
|
641
|
+
return nullableSchema(schema);
|
642
|
+
};
|
643
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
644
|
+
if (options.status === "draft" || !attribute.required) {
|
645
|
+
return schema;
|
646
|
+
}
|
647
|
+
if (attribute.required && "required" in schema) {
|
648
|
+
return schema.required(translatedErrors.required);
|
649
|
+
}
|
650
|
+
return schema;
|
651
|
+
};
|
652
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
653
|
+
if (options.status === "draft") {
|
654
|
+
return schema;
|
655
|
+
}
|
629
656
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
630
657
|
return schema.min(attribute.minLength, {
|
631
658
|
...translatedErrors.minLength,
|
@@ -647,10 +674,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
647
674
|
}
|
648
675
|
return schema;
|
649
676
|
};
|
650
|
-
const addMinValidation = (attribute) => (schema) => {
|
651
|
-
if ("
|
677
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
678
|
+
if (options.status === "draft") {
|
679
|
+
return schema;
|
680
|
+
}
|
681
|
+
if ("min" in attribute && "min" in schema) {
|
652
682
|
const min = toInteger(attribute.min);
|
653
|
-
if (
|
683
|
+
if (min) {
|
654
684
|
return schema.min(min, {
|
655
685
|
...translatedErrors.min,
|
656
686
|
values: {
|
@@ -768,16 +798,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
768
798
|
}, {});
|
769
799
|
return componentsByKey;
|
770
800
|
};
|
771
|
-
const
|
801
|
+
const HOOKS = {
|
802
|
+
/**
|
803
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
804
|
+
* @constant
|
805
|
+
* @type {string}
|
806
|
+
*/
|
807
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
808
|
+
/**
|
809
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
810
|
+
* @constant
|
811
|
+
* @type {string}
|
812
|
+
*/
|
813
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
814
|
+
/**
|
815
|
+
* Hook that allows to mutate the CM's edit view layout
|
816
|
+
* @constant
|
817
|
+
* @type {string}
|
818
|
+
*/
|
819
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
820
|
+
/**
|
821
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
822
|
+
* @constant
|
823
|
+
* @type {string}
|
824
|
+
*/
|
825
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
826
|
+
};
|
827
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
828
|
+
endpoints: (builder) => ({
|
829
|
+
getContentTypeConfiguration: builder.query({
|
830
|
+
query: (uid) => ({
|
831
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
832
|
+
method: "GET"
|
833
|
+
}),
|
834
|
+
transformResponse: (response) => response.data,
|
835
|
+
providesTags: (_result, _error, uid) => [
|
836
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
837
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
838
|
+
]
|
839
|
+
}),
|
840
|
+
getAllContentTypeSettings: builder.query({
|
841
|
+
query: () => "/content-manager/content-types-settings",
|
842
|
+
transformResponse: (response) => response.data,
|
843
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
844
|
+
}),
|
845
|
+
updateContentTypeConfiguration: builder.mutation({
|
846
|
+
query: ({ uid, ...body }) => ({
|
847
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
848
|
+
method: "PUT",
|
849
|
+
data: body
|
850
|
+
}),
|
851
|
+
transformResponse: (response) => response.data,
|
852
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
853
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
854
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
855
|
+
// Is this necessary?
|
856
|
+
{ type: "InitialData" }
|
857
|
+
]
|
858
|
+
})
|
859
|
+
})
|
860
|
+
});
|
861
|
+
const {
|
862
|
+
useGetContentTypeConfigurationQuery,
|
863
|
+
useGetAllContentTypeSettingsQuery,
|
864
|
+
useUpdateContentTypeConfigurationMutation
|
865
|
+
} = contentTypesApi;
|
866
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
867
|
+
const { type } = attribute;
|
868
|
+
if (type === "relation") {
|
869
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
870
|
+
}
|
871
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
872
|
+
};
|
873
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
874
|
+
if (!mainFieldName) {
|
875
|
+
return void 0;
|
876
|
+
}
|
877
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
878
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
879
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
880
|
+
);
|
881
|
+
return {
|
882
|
+
name: mainFieldName,
|
883
|
+
type: mainFieldType ?? "string"
|
884
|
+
};
|
885
|
+
};
|
886
|
+
const DEFAULT_SETTINGS = {
|
887
|
+
bulkable: false,
|
888
|
+
filterable: false,
|
889
|
+
searchable: false,
|
890
|
+
pagination: false,
|
891
|
+
defaultSortBy: "",
|
892
|
+
defaultSortOrder: "asc",
|
893
|
+
mainField: "id",
|
894
|
+
pageSize: 10
|
895
|
+
};
|
896
|
+
const useDocumentLayout = (model) => {
|
897
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
898
|
+
const [{ query }] = useQueryParams();
|
899
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
772
900
|
const { toggleNotification } = useNotification();
|
773
901
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
902
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
774
903
|
const {
|
775
|
-
|
776
|
-
isLoading:
|
777
|
-
|
778
|
-
|
779
|
-
} =
|
780
|
-
const
|
904
|
+
data,
|
905
|
+
isLoading: isLoadingConfigs,
|
906
|
+
error,
|
907
|
+
isFetching: isFetchingConfigs
|
908
|
+
} = useGetContentTypeConfigurationQuery(model);
|
909
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
781
910
|
React.useEffect(() => {
|
782
911
|
if (error) {
|
783
912
|
toggleNotification({
|
@@ -785,62 +914,318 @@ const useDocument = (args, opts) => {
|
|
785
914
|
message: formatAPIError(error)
|
786
915
|
});
|
787
916
|
}
|
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
|
-
}
|
917
|
+
}, [error, formatAPIError, toggleNotification]);
|
918
|
+
const editLayout = React.useMemo(
|
919
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
920
|
+
layout: [],
|
921
|
+
components: {},
|
922
|
+
metadatas: {},
|
923
|
+
options: {},
|
924
|
+
settings: DEFAULT_SETTINGS
|
811
925
|
},
|
812
|
-
[
|
926
|
+
[data, isLoading, schemas, schema, components]
|
927
|
+
);
|
928
|
+
const listLayout = React.useMemo(() => {
|
929
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
930
|
+
layout: [],
|
931
|
+
metadatas: {},
|
932
|
+
options: {},
|
933
|
+
settings: DEFAULT_SETTINGS
|
934
|
+
};
|
935
|
+
}, [data, isLoading, schemas, schema, components]);
|
936
|
+
const { layout: edit } = React.useMemo(
|
937
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
938
|
+
layout: editLayout,
|
939
|
+
query
|
940
|
+
}),
|
941
|
+
[editLayout, query, runHookWaterfall]
|
813
942
|
);
|
814
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
815
943
|
return {
|
816
|
-
|
817
|
-
document: data?.data,
|
818
|
-
meta: data?.meta,
|
944
|
+
error,
|
819
945
|
isLoading,
|
820
|
-
|
821
|
-
|
946
|
+
edit,
|
947
|
+
list: listLayout
|
822
948
|
};
|
823
949
|
};
|
824
|
-
const
|
825
|
-
const {
|
826
|
-
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
832
|
-
|
833
|
-
|
950
|
+
const useDocLayout = () => {
|
951
|
+
const { model } = useDoc();
|
952
|
+
return useDocumentLayout(model);
|
953
|
+
};
|
954
|
+
const formatEditLayout = (data, {
|
955
|
+
schemas,
|
956
|
+
schema,
|
957
|
+
components
|
958
|
+
}) => {
|
959
|
+
let currentPanelIndex = 0;
|
960
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
961
|
+
data.contentType.layouts.edit,
|
962
|
+
schema?.attributes,
|
963
|
+
data.contentType.metadatas,
|
964
|
+
{ configurations: data.components, schemas: components },
|
965
|
+
schemas
|
966
|
+
).reduce((panels, row) => {
|
967
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
968
|
+
panels.push([row]);
|
969
|
+
currentPanelIndex += 2;
|
970
|
+
} else {
|
971
|
+
if (!panels[currentPanelIndex]) {
|
972
|
+
panels.push([]);
|
973
|
+
}
|
974
|
+
panels[currentPanelIndex].push(row);
|
975
|
+
}
|
976
|
+
return panels;
|
977
|
+
}, []);
|
978
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
979
|
+
(acc, [uid, configuration]) => {
|
980
|
+
acc[uid] = {
|
981
|
+
layout: convertEditLayoutToFieldLayouts(
|
982
|
+
configuration.layouts.edit,
|
983
|
+
components[uid].attributes,
|
984
|
+
configuration.metadatas,
|
985
|
+
{ configurations: data.components, schemas: components }
|
986
|
+
),
|
987
|
+
settings: {
|
988
|
+
...configuration.settings,
|
989
|
+
icon: components[uid].info.icon,
|
990
|
+
displayName: components[uid].info.displayName
|
991
|
+
}
|
992
|
+
};
|
993
|
+
return acc;
|
994
|
+
},
|
995
|
+
{}
|
996
|
+
);
|
997
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
998
|
+
(acc, [attribute, metadata]) => {
|
999
|
+
return {
|
1000
|
+
...acc,
|
1001
|
+
[attribute]: metadata.edit
|
1002
|
+
};
|
1003
|
+
},
|
1004
|
+
{}
|
1005
|
+
);
|
1006
|
+
return {
|
1007
|
+
layout: panelledEditAttributes,
|
1008
|
+
components: componentEditAttributes,
|
1009
|
+
metadatas: editMetadatas,
|
1010
|
+
settings: {
|
1011
|
+
...data.contentType.settings,
|
1012
|
+
displayName: schema?.info.displayName
|
1013
|
+
},
|
1014
|
+
options: {
|
1015
|
+
...schema?.options,
|
1016
|
+
...schema?.pluginOptions,
|
1017
|
+
...data.contentType.options
|
1018
|
+
}
|
1019
|
+
};
|
1020
|
+
};
|
1021
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1022
|
+
return rows.map(
|
1023
|
+
(row) => row.map((field) => {
|
1024
|
+
const attribute = attributes[field.name];
|
1025
|
+
if (!attribute) {
|
1026
|
+
return null;
|
1027
|
+
}
|
1028
|
+
const { edit: metadata } = metadatas[field.name];
|
1029
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1030
|
+
return {
|
1031
|
+
attribute,
|
1032
|
+
disabled: !metadata.editable,
|
1033
|
+
hint: metadata.description,
|
1034
|
+
label: metadata.label ?? "",
|
1035
|
+
name: field.name,
|
1036
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1037
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1038
|
+
schemas,
|
1039
|
+
components: components?.schemas ?? {}
|
1040
|
+
}),
|
1041
|
+
placeholder: metadata.placeholder ?? "",
|
1042
|
+
required: attribute.required ?? false,
|
1043
|
+
size: field.size,
|
1044
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1045
|
+
visible: metadata.visible ?? true,
|
1046
|
+
type: attribute.type
|
1047
|
+
};
|
1048
|
+
}).filter((field) => field !== null)
|
1049
|
+
);
|
1050
|
+
};
|
1051
|
+
const formatListLayout = (data, {
|
1052
|
+
schemas,
|
1053
|
+
schema,
|
1054
|
+
components
|
1055
|
+
}) => {
|
1056
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1057
|
+
(acc, [attribute, metadata]) => {
|
1058
|
+
return {
|
1059
|
+
...acc,
|
1060
|
+
[attribute]: metadata.list
|
1061
|
+
};
|
1062
|
+
},
|
1063
|
+
{}
|
1064
|
+
);
|
1065
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1066
|
+
data.contentType.layouts.list,
|
1067
|
+
schema?.attributes,
|
1068
|
+
listMetadatas,
|
1069
|
+
{ configurations: data.components, schemas: components },
|
1070
|
+
schemas
|
1071
|
+
);
|
1072
|
+
return {
|
1073
|
+
layout: listAttributes,
|
1074
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1075
|
+
metadatas: listMetadatas,
|
1076
|
+
options: {
|
1077
|
+
...schema?.options,
|
1078
|
+
...schema?.pluginOptions,
|
1079
|
+
...data.contentType.options
|
1080
|
+
}
|
1081
|
+
};
|
1082
|
+
};
|
1083
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1084
|
+
return columns.map((name) => {
|
1085
|
+
const attribute = attributes[name];
|
1086
|
+
if (!attribute) {
|
1087
|
+
return null;
|
1088
|
+
}
|
1089
|
+
const metadata = metadatas[name];
|
1090
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1091
|
+
return {
|
1092
|
+
attribute,
|
1093
|
+
label: metadata.label ?? "",
|
1094
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1095
|
+
schemas,
|
1096
|
+
components: components?.schemas ?? {}
|
1097
|
+
}),
|
1098
|
+
name,
|
1099
|
+
searchable: metadata.searchable ?? true,
|
1100
|
+
sortable: metadata.sortable ?? true
|
1101
|
+
};
|
1102
|
+
}).filter((field) => field !== null);
|
1103
|
+
};
|
1104
|
+
const useDocument = (args, opts) => {
|
1105
|
+
const { toggleNotification } = useNotification();
|
1106
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1107
|
+
const {
|
1108
|
+
currentData: data,
|
1109
|
+
isLoading: isLoadingDocument,
|
1110
|
+
isFetching: isFetchingDocument,
|
1111
|
+
error
|
1112
|
+
} = useGetDocumentQuery(args, {
|
1113
|
+
...opts,
|
1114
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1115
|
+
});
|
1116
|
+
const {
|
1117
|
+
components,
|
1118
|
+
schema,
|
1119
|
+
schemas,
|
1120
|
+
isLoading: isLoadingSchema
|
1121
|
+
} = useContentTypeSchema(args.model);
|
1122
|
+
React.useEffect(() => {
|
1123
|
+
if (error) {
|
1124
|
+
toggleNotification({
|
1125
|
+
type: "danger",
|
1126
|
+
message: formatAPIError(error)
|
1127
|
+
});
|
1128
|
+
}
|
1129
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1130
|
+
const validationSchema = React.useMemo(() => {
|
1131
|
+
if (!schema) {
|
1132
|
+
return null;
|
1133
|
+
}
|
1134
|
+
return createYupSchema(schema.attributes, components);
|
1135
|
+
}, [schema, components]);
|
1136
|
+
const validate = React.useCallback(
|
1137
|
+
(document) => {
|
1138
|
+
if (!validationSchema) {
|
1139
|
+
throw new Error(
|
1140
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1141
|
+
);
|
1142
|
+
}
|
1143
|
+
try {
|
1144
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1145
|
+
return null;
|
1146
|
+
} catch (error2) {
|
1147
|
+
if (error2 instanceof ValidationError) {
|
1148
|
+
return getYupValidationErrors(error2);
|
1149
|
+
}
|
1150
|
+
throw error2;
|
1151
|
+
}
|
1152
|
+
},
|
1153
|
+
[validationSchema]
|
1154
|
+
);
|
1155
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1156
|
+
const hasError = !!error;
|
1157
|
+
return {
|
1158
|
+
components,
|
1159
|
+
document: data?.data,
|
1160
|
+
meta: data?.meta,
|
1161
|
+
isLoading,
|
1162
|
+
hasError,
|
1163
|
+
schema,
|
1164
|
+
schemas,
|
1165
|
+
validate
|
1166
|
+
};
|
1167
|
+
};
|
1168
|
+
const useDoc = () => {
|
1169
|
+
const { id, slug, collectionType, origin } = useParams();
|
1170
|
+
const [{ query }] = useQueryParams();
|
1171
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1172
|
+
if (!collectionType) {
|
1173
|
+
throw new Error("Could not find collectionType in url params");
|
1174
|
+
}
|
1175
|
+
if (!slug) {
|
1176
|
+
throw new Error("Could not find model in url params");
|
1177
|
+
}
|
1178
|
+
const document = useDocument(
|
1179
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1180
|
+
{
|
1181
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1182
|
+
}
|
1183
|
+
);
|
1184
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
834
1185
|
return {
|
835
1186
|
collectionType,
|
836
1187
|
model: slug,
|
837
|
-
id:
|
838
|
-
...
|
839
|
-
|
840
|
-
|
841
|
-
|
842
|
-
|
843
|
-
|
1188
|
+
id: returnId,
|
1189
|
+
...document
|
1190
|
+
};
|
1191
|
+
};
|
1192
|
+
const useContentManagerContext = () => {
|
1193
|
+
const {
|
1194
|
+
collectionType,
|
1195
|
+
model,
|
1196
|
+
id,
|
1197
|
+
components,
|
1198
|
+
isLoading: isLoadingDoc,
|
1199
|
+
schema,
|
1200
|
+
schemas
|
1201
|
+
} = useDoc();
|
1202
|
+
const layout = useDocumentLayout(model);
|
1203
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1204
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1205
|
+
const slug = model;
|
1206
|
+
const isCreatingEntry = id === "create";
|
1207
|
+
useContentTypeSchema();
|
1208
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1209
|
+
const error = layout.error;
|
1210
|
+
return {
|
1211
|
+
error,
|
1212
|
+
isLoading,
|
1213
|
+
// Base metadata
|
1214
|
+
model,
|
1215
|
+
collectionType,
|
1216
|
+
id,
|
1217
|
+
slug,
|
1218
|
+
isCreatingEntry,
|
1219
|
+
isSingleType,
|
1220
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1221
|
+
// All schema infos
|
1222
|
+
components,
|
1223
|
+
contentType: schema,
|
1224
|
+
contentTypes: schemas,
|
1225
|
+
// Form state
|
1226
|
+
form,
|
1227
|
+
// layout infos
|
1228
|
+
layout
|
844
1229
|
};
|
845
1230
|
};
|
846
1231
|
const prefixPluginTranslations = (trad, pluginId) => {
|
@@ -862,6 +1247,8 @@ const useDocumentActions = () => {
|
|
862
1247
|
const { formatMessage } = useIntl();
|
863
1248
|
const { trackUsage } = useTracking();
|
864
1249
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1250
|
+
const navigate = useNavigate();
|
1251
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
865
1252
|
const [deleteDocument] = useDeleteDocumentMutation();
|
866
1253
|
const _delete = React.useCallback(
|
867
1254
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1176,6 +1563,7 @@ const useDocumentActions = () => {
|
|
1176
1563
|
defaultMessage: "Saved document"
|
1177
1564
|
})
|
1178
1565
|
});
|
1566
|
+
setCurrentStep("contentManager.success");
|
1179
1567
|
return res.data;
|
1180
1568
|
} catch (err) {
|
1181
1569
|
toggleNotification({
|
@@ -1197,7 +1585,6 @@ const useDocumentActions = () => {
|
|
1197
1585
|
sourceId
|
1198
1586
|
});
|
1199
1587
|
if ("error" in res) {
|
1200
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1201
1588
|
return { error: res.error };
|
1202
1589
|
}
|
1203
1590
|
toggleNotification({
|
@@ -1216,7 +1603,7 @@ const useDocumentActions = () => {
|
|
1216
1603
|
throw err;
|
1217
1604
|
}
|
1218
1605
|
},
|
1219
|
-
[autoCloneDocument,
|
1606
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1220
1607
|
);
|
1221
1608
|
const [cloneDocument] = useCloneDocumentMutation();
|
1222
1609
|
const clone = React.useCallback(
|
@@ -1242,6 +1629,7 @@ const useDocumentActions = () => {
|
|
1242
1629
|
defaultMessage: "Cloned document"
|
1243
1630
|
})
|
1244
1631
|
});
|
1632
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1245
1633
|
return res.data;
|
1246
1634
|
} catch (err) {
|
1247
1635
|
toggleNotification({
|
@@ -1252,7 +1640,7 @@ const useDocumentActions = () => {
|
|
1252
1640
|
throw err;
|
1253
1641
|
}
|
1254
1642
|
},
|
1255
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1643
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1256
1644
|
);
|
1257
1645
|
const [getDoc] = useLazyGetDocumentQuery();
|
1258
1646
|
const getDocument = React.useCallback(
|
@@ -1278,7 +1666,7 @@ const useDocumentActions = () => {
|
|
1278
1666
|
};
|
1279
1667
|
};
|
1280
1668
|
const ProtectedHistoryPage = lazy(
|
1281
|
-
() => import("./History-
|
1669
|
+
() => import("./History-Drr6mxnK.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1282
1670
|
);
|
1283
1671
|
const routes$1 = [
|
1284
1672
|
{
|
@@ -1291,31 +1679,31 @@ const routes$1 = [
|
|
1291
1679
|
}
|
1292
1680
|
];
|
1293
1681
|
const ProtectedEditViewPage = lazy(
|
1294
|
-
() => import("./EditViewPage-
|
1682
|
+
() => import("./EditViewPage-Cvjs7D6M.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1295
1683
|
);
|
1296
1684
|
const ProtectedListViewPage = lazy(
|
1297
|
-
() => import("./ListViewPage-
|
1685
|
+
() => import("./ListViewPage-CQb0CL40.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1298
1686
|
);
|
1299
1687
|
const ProtectedListConfiguration = lazy(
|
1300
|
-
() => import("./ListConfigurationPage-
|
1688
|
+
() => import("./ListConfigurationPage-C6calJtW.mjs").then((mod) => ({
|
1301
1689
|
default: mod.ProtectedListConfiguration
|
1302
1690
|
}))
|
1303
1691
|
);
|
1304
1692
|
const ProtectedEditConfigurationPage = lazy(
|
1305
|
-
() => import("./EditConfigurationPage-
|
1693
|
+
() => import("./EditConfigurationPage-DVLmpXPs.mjs").then((mod) => ({
|
1306
1694
|
default: mod.ProtectedEditConfigurationPage
|
1307
1695
|
}))
|
1308
1696
|
);
|
1309
1697
|
const ProtectedComponentConfigurationPage = lazy(
|
1310
|
-
() => import("./ComponentConfigurationPage-
|
1698
|
+
() => import("./ComponentConfigurationPage-oqdZo6l8.mjs").then((mod) => ({
|
1311
1699
|
default: mod.ProtectedComponentConfigurationPage
|
1312
1700
|
}))
|
1313
1701
|
);
|
1314
1702
|
const NoPermissions = lazy(
|
1315
|
-
() => import("./NoPermissionsPage-
|
1703
|
+
() => import("./NoPermissionsPage-BBdxJ-4m.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1316
1704
|
);
|
1317
1705
|
const NoContentType = lazy(
|
1318
|
-
() => import("./NoContentTypePage-
|
1706
|
+
() => import("./NoContentTypePage-C-BK38Ai.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1319
1707
|
);
|
1320
1708
|
const CollectionTypePages = () => {
|
1321
1709
|
const { collectionType } = useParams();
|
@@ -1429,12 +1817,14 @@ const DocumentActionButton = (action) => {
|
|
1429
1817
|
/* @__PURE__ */ jsx(
|
1430
1818
|
Button,
|
1431
1819
|
{
|
1432
|
-
flex:
|
1820
|
+
flex: "auto",
|
1433
1821
|
startIcon: action.icon,
|
1434
1822
|
disabled: action.disabled,
|
1435
1823
|
onClick: handleClick(action),
|
1436
1824
|
justifyContent: "center",
|
1437
1825
|
variant: action.variant || "default",
|
1826
|
+
paddingTop: "7px",
|
1827
|
+
paddingBottom: "7px",
|
1438
1828
|
children: action.label
|
1439
1829
|
}
|
1440
1830
|
),
|
@@ -1442,7 +1832,7 @@ const DocumentActionButton = (action) => {
|
|
1442
1832
|
DocumentActionConfirmDialog,
|
1443
1833
|
{
|
1444
1834
|
...action.dialog,
|
1445
|
-
variant: action.variant,
|
1835
|
+
variant: action.dialog?.variant ?? action.variant,
|
1446
1836
|
isOpen: dialogId === action.id,
|
1447
1837
|
onClose: handleClose
|
1448
1838
|
}
|
@@ -1499,9 +1889,9 @@ const DocumentActionsMenu = ({
|
|
1499
1889
|
disabled: isDisabled,
|
1500
1890
|
size: "S",
|
1501
1891
|
endIcon: null,
|
1502
|
-
paddingTop: "
|
1503
|
-
paddingLeft: "
|
1504
|
-
paddingRight: "
|
1892
|
+
paddingTop: "4px",
|
1893
|
+
paddingLeft: "7px",
|
1894
|
+
paddingRight: "7px",
|
1505
1895
|
variant,
|
1506
1896
|
children: [
|
1507
1897
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1512,7 +1902,7 @@ const DocumentActionsMenu = ({
|
|
1512
1902
|
]
|
1513
1903
|
}
|
1514
1904
|
),
|
1515
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1905
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1516
1906
|
actions2.map((action) => {
|
1517
1907
|
return /* @__PURE__ */ jsx(
|
1518
1908
|
Menu.Item,
|
@@ -1521,10 +1911,25 @@ const DocumentActionsMenu = ({
|
|
1521
1911
|
onSelect: handleClick(action),
|
1522
1912
|
display: "block",
|
1523
1913
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1524
|
-
/* @__PURE__ */ jsxs(
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1914
|
+
/* @__PURE__ */ jsxs(
|
1915
|
+
Flex,
|
1916
|
+
{
|
1917
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1918
|
+
gap: 2,
|
1919
|
+
tag: "span",
|
1920
|
+
children: [
|
1921
|
+
/* @__PURE__ */ jsx(
|
1922
|
+
Flex,
|
1923
|
+
{
|
1924
|
+
tag: "span",
|
1925
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1926
|
+
children: action.icon
|
1927
|
+
}
|
1928
|
+
),
|
1929
|
+
action.label
|
1930
|
+
]
|
1931
|
+
}
|
1932
|
+
),
|
1528
1933
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1529
1934
|
Flex,
|
1530
1935
|
{
|
@@ -1621,11 +2026,11 @@ const DocumentActionConfirmDialog = ({
|
|
1621
2026
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1622
2027
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1623
2028
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1624
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2029
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1625
2030
|
id: "app.components.Button.cancel",
|
1626
2031
|
defaultMessage: "Cancel"
|
1627
2032
|
}) }) }),
|
1628
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2033
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1629
2034
|
id: "app.components.Button.confirm",
|
1630
2035
|
defaultMessage: "Confirm"
|
1631
2036
|
}) })
|
@@ -1652,6 +2057,18 @@ const DocumentActionModal = ({
|
|
1652
2057
|
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1653
2058
|
] }) });
|
1654
2059
|
};
|
2060
|
+
const transformData = (data) => {
|
2061
|
+
if (Array.isArray(data)) {
|
2062
|
+
return data.map(transformData);
|
2063
|
+
}
|
2064
|
+
if (typeof data === "object" && data !== null) {
|
2065
|
+
if ("apiData" in data) {
|
2066
|
+
return data.apiData;
|
2067
|
+
}
|
2068
|
+
return mapValues(transformData)(data);
|
2069
|
+
}
|
2070
|
+
return data;
|
2071
|
+
};
|
1655
2072
|
const PublishAction$1 = ({
|
1656
2073
|
activeTab,
|
1657
2074
|
documentId,
|
@@ -1664,13 +2081,17 @@ const PublishAction$1 = ({
|
|
1664
2081
|
const navigate = useNavigate();
|
1665
2082
|
const { toggleNotification } = useNotification();
|
1666
2083
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2084
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1667
2085
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1668
2086
|
const { formatMessage } = useIntl();
|
1669
|
-
const { canPublish
|
1670
|
-
"PublishAction",
|
1671
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1672
|
-
);
|
2087
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1673
2088
|
const { publish } = useDocumentActions();
|
2089
|
+
const [
|
2090
|
+
countDraftRelations,
|
2091
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2092
|
+
] = useLazyGetDraftRelationCountQuery();
|
2093
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2094
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1674
2095
|
const [{ query, rawQuery }] = useQueryParams();
|
1675
2096
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1676
2097
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1679,12 +2100,107 @@ const PublishAction$1 = ({
|
|
1679
2100
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1680
2101
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1681
2102
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1682
|
-
|
1683
|
-
|
1684
|
-
|
1685
|
-
|
1686
|
-
|
1687
|
-
|
2103
|
+
React.useEffect(() => {
|
2104
|
+
if (isErrorDraftRelations) {
|
2105
|
+
toggleNotification({
|
2106
|
+
type: "danger",
|
2107
|
+
message: formatMessage({
|
2108
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2109
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2110
|
+
})
|
2111
|
+
});
|
2112
|
+
}
|
2113
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2114
|
+
React.useEffect(() => {
|
2115
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2116
|
+
const extractDraftRelations = (data) => {
|
2117
|
+
const relations = data.connect || [];
|
2118
|
+
relations.forEach((relation) => {
|
2119
|
+
if (relation.status === "draft") {
|
2120
|
+
localDraftRelations.add(relation.id);
|
2121
|
+
}
|
2122
|
+
});
|
2123
|
+
};
|
2124
|
+
const traverseAndExtract = (data) => {
|
2125
|
+
Object.entries(data).forEach(([key, value]) => {
|
2126
|
+
if (key === "connect" && Array.isArray(value)) {
|
2127
|
+
extractDraftRelations({ connect: value });
|
2128
|
+
} else if (typeof value === "object" && value !== null) {
|
2129
|
+
traverseAndExtract(value);
|
2130
|
+
}
|
2131
|
+
});
|
2132
|
+
};
|
2133
|
+
if (!documentId || modified) {
|
2134
|
+
traverseAndExtract(formValues);
|
2135
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2136
|
+
}
|
2137
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2138
|
+
React.useEffect(() => {
|
2139
|
+
if (!document || !document.documentId || isListView) {
|
2140
|
+
return;
|
2141
|
+
}
|
2142
|
+
const fetchDraftRelationsCount = async () => {
|
2143
|
+
const { data, error } = await countDraftRelations({
|
2144
|
+
collectionType,
|
2145
|
+
model,
|
2146
|
+
documentId,
|
2147
|
+
params
|
2148
|
+
});
|
2149
|
+
if (error) {
|
2150
|
+
throw error;
|
2151
|
+
}
|
2152
|
+
if (data) {
|
2153
|
+
setServerCountOfDraftRelations(data.data);
|
2154
|
+
}
|
2155
|
+
};
|
2156
|
+
fetchDraftRelationsCount();
|
2157
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2158
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2159
|
+
if (!schema?.options?.draftAndPublish) {
|
2160
|
+
return null;
|
2161
|
+
}
|
2162
|
+
const performPublish = async () => {
|
2163
|
+
setSubmitting(true);
|
2164
|
+
try {
|
2165
|
+
const { errors } = await validate(true, {
|
2166
|
+
status: "published"
|
2167
|
+
});
|
2168
|
+
if (errors) {
|
2169
|
+
toggleNotification({
|
2170
|
+
type: "danger",
|
2171
|
+
message: formatMessage({
|
2172
|
+
id: "content-manager.validation.error",
|
2173
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2174
|
+
})
|
2175
|
+
});
|
2176
|
+
return;
|
2177
|
+
}
|
2178
|
+
const res = await publish(
|
2179
|
+
{
|
2180
|
+
collectionType,
|
2181
|
+
model,
|
2182
|
+
documentId,
|
2183
|
+
params
|
2184
|
+
},
|
2185
|
+
transformData(formValues)
|
2186
|
+
);
|
2187
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2188
|
+
navigate({
|
2189
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2190
|
+
search: rawQuery
|
2191
|
+
});
|
2192
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2193
|
+
setErrors(formatValidationErrors(res.error));
|
2194
|
+
}
|
2195
|
+
} finally {
|
2196
|
+
setSubmitting(false);
|
2197
|
+
}
|
2198
|
+
};
|
2199
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2200
|
+
const enableDraftRelationsCount = false;
|
2201
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2202
|
+
return {
|
2203
|
+
/**
|
1688
2204
|
* Disabled when:
|
1689
2205
|
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
1690
2206
|
* - the form is submitting
|
@@ -1692,49 +2208,36 @@ const PublishAction$1 = ({
|
|
1692
2208
|
* - the document is already published & not modified
|
1693
2209
|
* - the document is being created & not modified
|
1694
2210
|
* - 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
2211
|
*/
|
1698
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2212
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1699
2213
|
label: formatMessage({
|
1700
2214
|
id: "app.utils.publish",
|
1701
2215
|
defaultMessage: "Publish"
|
1702
2216
|
}),
|
1703
2217
|
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));
|
2218
|
+
await performPublish();
|
2219
|
+
},
|
2220
|
+
dialog: hasDraftRelations ? {
|
2221
|
+
type: "dialog",
|
2222
|
+
variant: "danger",
|
2223
|
+
footer: null,
|
2224
|
+
title: formatMessage({
|
2225
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2226
|
+
defaultMessage: "Confirmation"
|
2227
|
+
}),
|
2228
|
+
content: formatMessage(
|
2229
|
+
{
|
2230
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2231
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2232
|
+
},
|
2233
|
+
{
|
2234
|
+
count: totalDraftRelations
|
1733
2235
|
}
|
1734
|
-
|
1735
|
-
|
2236
|
+
),
|
2237
|
+
onConfirm: async () => {
|
2238
|
+
await performPublish();
|
1736
2239
|
}
|
1737
|
-
}
|
2240
|
+
} : void 0
|
1738
2241
|
};
|
1739
2242
|
};
|
1740
2243
|
PublishAction$1.type = "publish";
|
@@ -1750,10 +2253,6 @@ const UpdateAction = ({
|
|
1750
2253
|
const cloneMatch = useMatch(CLONE_PATH);
|
1751
2254
|
const isCloning = cloneMatch !== null;
|
1752
2255
|
const { formatMessage } = useIntl();
|
1753
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1754
|
-
canCreate: canCreate2,
|
1755
|
-
canUpdate: canUpdate2
|
1756
|
-
}));
|
1757
2256
|
const { create, update, clone } = useDocumentActions();
|
1758
2257
|
const [{ query, rawQuery }] = useQueryParams();
|
1759
2258
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1770,10 +2269,8 @@ const UpdateAction = ({
|
|
1770
2269
|
* - the form is submitting
|
1771
2270
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1772
2271
|
* - 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
2272
|
*/
|
1776
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2273
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1777
2274
|
label: formatMessage({
|
1778
2275
|
id: "content-manager.containers.Edit.save",
|
1779
2276
|
defaultMessage: "Save"
|
@@ -1781,7 +2278,9 @@ const UpdateAction = ({
|
|
1781
2278
|
onClick: async () => {
|
1782
2279
|
setSubmitting(true);
|
1783
2280
|
try {
|
1784
|
-
const { errors } = await validate(
|
2281
|
+
const { errors } = await validate(true, {
|
2282
|
+
status: "draft"
|
2283
|
+
});
|
1785
2284
|
if (errors) {
|
1786
2285
|
toggleNotification({
|
1787
2286
|
type: "danger",
|
@@ -1799,13 +2298,16 @@ const UpdateAction = ({
|
|
1799
2298
|
documentId: cloneMatch.params.origin,
|
1800
2299
|
params
|
1801
2300
|
},
|
1802
|
-
document
|
2301
|
+
transformData(document)
|
1803
2302
|
);
|
1804
2303
|
if ("data" in res) {
|
1805
|
-
navigate(
|
1806
|
-
|
1807
|
-
|
1808
|
-
|
2304
|
+
navigate(
|
2305
|
+
{
|
2306
|
+
pathname: `../${res.data.documentId}`,
|
2307
|
+
search: rawQuery
|
2308
|
+
},
|
2309
|
+
{ relative: "path" }
|
2310
|
+
);
|
1809
2311
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1810
2312
|
setErrors(formatValidationErrors(res.error));
|
1811
2313
|
}
|
@@ -1817,7 +2319,7 @@ const UpdateAction = ({
|
|
1817
2319
|
documentId,
|
1818
2320
|
params
|
1819
2321
|
},
|
1820
|
-
document
|
2322
|
+
transformData(document)
|
1821
2323
|
);
|
1822
2324
|
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1823
2325
|
setErrors(formatValidationErrors(res.error));
|
@@ -1830,13 +2332,16 @@ const UpdateAction = ({
|
|
1830
2332
|
model,
|
1831
2333
|
params
|
1832
2334
|
},
|
1833
|
-
document
|
2335
|
+
transformData(document)
|
1834
2336
|
);
|
1835
2337
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1836
|
-
navigate(
|
1837
|
-
|
1838
|
-
|
1839
|
-
|
2338
|
+
navigate(
|
2339
|
+
{
|
2340
|
+
pathname: `../${res.data.documentId}`,
|
2341
|
+
search: rawQuery
|
2342
|
+
},
|
2343
|
+
{ replace: true, relative: "path" }
|
2344
|
+
);
|
1840
2345
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1841
2346
|
setErrors(formatValidationErrors(res.error));
|
1842
2347
|
}
|
@@ -1880,7 +2385,7 @@ const UnpublishAction$1 = ({
|
|
1880
2385
|
id: "app.utils.unpublish",
|
1881
2386
|
defaultMessage: "Unpublish"
|
1882
2387
|
}),
|
1883
|
-
icon: /* @__PURE__ */ jsx(
|
2388
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1884
2389
|
onClick: async () => {
|
1885
2390
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1886
2391
|
if (!documentId) {
|
@@ -1992,7 +2497,7 @@ const DiscardAction = ({
|
|
1992
2497
|
id: "content-manager.actions.discard.label",
|
1993
2498
|
defaultMessage: "Discard changes"
|
1994
2499
|
}),
|
1995
|
-
icon: /* @__PURE__ */ jsx(
|
2500
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1996
2501
|
position: ["panel", "table-row"],
|
1997
2502
|
variant: "danger",
|
1998
2503
|
dialog: {
|
@@ -2020,11 +2525,6 @@ const DiscardAction = ({
|
|
2020
2525
|
};
|
2021
2526
|
};
|
2022
2527
|
DiscardAction.type = "discard";
|
2023
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2024
|
-
path {
|
2025
|
-
fill: currentColor;
|
2026
|
-
}
|
2027
|
-
`;
|
2028
2528
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2029
2529
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2030
2530
|
const RelativeTime = React.forwardRef(
|
@@ -2072,7 +2572,7 @@ const getDisplayName = ({
|
|
2072
2572
|
};
|
2073
2573
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2074
2574
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2075
|
-
const statusVariant = status === "draft" ? "
|
2575
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2076
2576
|
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
2577
|
};
|
2078
2578
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2082,23 +2582,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2082
2582
|
id: "content-manager.containers.edit.title.new",
|
2083
2583
|
defaultMessage: "Create an entry"
|
2084
2584
|
}) : documentTitle;
|
2085
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2585
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2086
2586
|
/* @__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
|
2587
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2588
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2589
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2590
|
+
] }),
|
2591
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2102
2592
|
] });
|
2103
2593
|
};
|
2104
2594
|
const HeaderToolbar = () => {
|
@@ -2181,12 +2671,12 @@ const Information = ({ activeTab }) => {
|
|
2181
2671
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2182
2672
|
label: formatMessage({
|
2183
2673
|
id: "content-manager.containers.edit.information.last-published.label",
|
2184
|
-
defaultMessage: "
|
2674
|
+
defaultMessage: "Published"
|
2185
2675
|
}),
|
2186
2676
|
value: formatMessage(
|
2187
2677
|
{
|
2188
2678
|
id: "content-manager.containers.edit.information.last-published.value",
|
2189
|
-
defaultMessage: `
|
2679
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2190
2680
|
},
|
2191
2681
|
{
|
2192
2682
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2199,12 +2689,12 @@ const Information = ({ activeTab }) => {
|
|
2199
2689
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2200
2690
|
label: formatMessage({
|
2201
2691
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2202
|
-
defaultMessage: "
|
2692
|
+
defaultMessage: "Updated"
|
2203
2693
|
}),
|
2204
2694
|
value: formatMessage(
|
2205
2695
|
{
|
2206
2696
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2207
|
-
defaultMessage: `
|
2697
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2208
2698
|
},
|
2209
2699
|
{
|
2210
2700
|
time: /* @__PURE__ */ jsx(
|
@@ -2222,12 +2712,12 @@ const Information = ({ activeTab }) => {
|
|
2222
2712
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2223
2713
|
label: formatMessage({
|
2224
2714
|
id: "content-manager.containers.edit.information.document.label",
|
2225
|
-
defaultMessage: "
|
2715
|
+
defaultMessage: "Created"
|
2226
2716
|
}),
|
2227
2717
|
value: formatMessage(
|
2228
2718
|
{
|
2229
2719
|
id: "content-manager.containers.edit.information.document.value",
|
2230
|
-
defaultMessage: `
|
2720
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2231
2721
|
},
|
2232
2722
|
{
|
2233
2723
|
time: /* @__PURE__ */ jsx(
|
@@ -2265,25 +2755,77 @@ const Information = ({ activeTab }) => {
|
|
2265
2755
|
);
|
2266
2756
|
};
|
2267
2757
|
const HeaderActions = ({ actions: actions2 }) => {
|
2268
|
-
|
2269
|
-
|
2758
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2759
|
+
const handleClick = (action) => async (e) => {
|
2760
|
+
if (!("options" in action)) {
|
2761
|
+
const { onClick = () => false, dialog, id } = action;
|
2762
|
+
const muteDialog = await onClick(e);
|
2763
|
+
if (dialog && !muteDialog) {
|
2764
|
+
e.preventDefault();
|
2765
|
+
setDialogId(id);
|
2766
|
+
}
|
2767
|
+
}
|
2768
|
+
};
|
2769
|
+
const handleClose = () => {
|
2770
|
+
setDialogId(null);
|
2771
|
+
};
|
2772
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2773
|
+
if (action.options) {
|
2270
2774
|
return /* @__PURE__ */ jsx(
|
2271
2775
|
SingleSelect,
|
2272
2776
|
{
|
2273
2777
|
size: "S",
|
2274
|
-
disabled: action.disabled,
|
2275
|
-
"aria-label": action.label,
|
2276
2778
|
onChange: action.onSelect,
|
2277
|
-
|
2779
|
+
"aria-label": action.label,
|
2780
|
+
...action,
|
2278
2781
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2279
2782
|
},
|
2280
2783
|
action.id
|
2281
2784
|
);
|
2282
2785
|
} else {
|
2283
|
-
|
2786
|
+
if (action.type === "icon") {
|
2787
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2788
|
+
/* @__PURE__ */ jsx(
|
2789
|
+
IconButton,
|
2790
|
+
{
|
2791
|
+
disabled: action.disabled,
|
2792
|
+
label: action.label,
|
2793
|
+
size: "S",
|
2794
|
+
onClick: handleClick(action),
|
2795
|
+
children: action.icon
|
2796
|
+
}
|
2797
|
+
),
|
2798
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2799
|
+
HeaderActionDialog,
|
2800
|
+
{
|
2801
|
+
...action.dialog,
|
2802
|
+
isOpen: dialogId === action.id,
|
2803
|
+
onClose: handleClose
|
2804
|
+
}
|
2805
|
+
) : null
|
2806
|
+
] }, action.id);
|
2807
|
+
}
|
2284
2808
|
}
|
2285
2809
|
}) });
|
2286
2810
|
};
|
2811
|
+
const HeaderActionDialog = ({
|
2812
|
+
onClose,
|
2813
|
+
onCancel,
|
2814
|
+
title,
|
2815
|
+
content: Content,
|
2816
|
+
isOpen
|
2817
|
+
}) => {
|
2818
|
+
const handleClose = async () => {
|
2819
|
+
if (onCancel) {
|
2820
|
+
await onCancel();
|
2821
|
+
}
|
2822
|
+
onClose();
|
2823
|
+
};
|
2824
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2825
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2826
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2827
|
+
] }) });
|
2828
|
+
};
|
2287
2829
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2288
2830
|
const navigate = useNavigate();
|
2289
2831
|
const { formatMessage } = useIntl();
|
@@ -2324,12 +2866,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2324
2866
|
const { delete: deleteAction } = useDocumentActions();
|
2325
2867
|
const { toggleNotification } = useNotification();
|
2326
2868
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2869
|
+
const isLocalized = document?.locale != null;
|
2327
2870
|
return {
|
2328
2871
|
disabled: !canDelete || !document,
|
2329
|
-
label: formatMessage(
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2872
|
+
label: formatMessage(
|
2873
|
+
{
|
2874
|
+
id: "content-manager.actions.delete.label",
|
2875
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2876
|
+
},
|
2877
|
+
{ isLocalized }
|
2878
|
+
),
|
2333
2879
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2334
2880
|
dialog: {
|
2335
2881
|
type: "dialog",
|
@@ -2365,423 +2911,121 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2365
2911
|
const res = await deleteAction({
|
2366
2912
|
documentId,
|
2367
2913
|
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
|
2914
|
+
collectionType,
|
2915
|
+
params: {
|
2916
|
+
locale: "*"
|
2917
|
+
}
|
2918
|
+
});
|
2919
|
+
if (!("error" in res)) {
|
2920
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2921
|
+
}
|
2922
|
+
} finally {
|
2923
|
+
if (!listViewPathMatch) {
|
2924
|
+
setSubmitting(false);
|
2925
|
+
}
|
2672
2926
|
}
|
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
|
2927
|
+
}
|
2694
2928
|
},
|
2695
|
-
|
2696
|
-
|
2697
|
-
...schema?.pluginOptions,
|
2698
|
-
...data.contentType.options
|
2699
|
-
}
|
2929
|
+
variant: "danger",
|
2930
|
+
position: ["header", "table-row"]
|
2700
2931
|
};
|
2701
2932
|
};
|
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
|
-
);
|
2933
|
+
DeleteAction$1.type = "delete";
|
2934
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2935
|
+
const Panels = () => {
|
2936
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2937
|
+
const [
|
2938
|
+
{
|
2939
|
+
query: { status }
|
2940
|
+
}
|
2941
|
+
] = useQueryParams({
|
2942
|
+
status: "draft"
|
2943
|
+
});
|
2944
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2945
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2946
|
+
const props = {
|
2947
|
+
activeTab: status,
|
2948
|
+
model,
|
2949
|
+
documentId: id,
|
2950
|
+
document: isCloning ? void 0 : document,
|
2951
|
+
meta: isCloning ? void 0 : meta,
|
2952
|
+
collectionType
|
2953
|
+
};
|
2954
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2955
|
+
DescriptionComponentRenderer,
|
2956
|
+
{
|
2957
|
+
props,
|
2958
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2959
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2960
|
+
}
|
2961
|
+
) });
|
2731
2962
|
};
|
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
|
-
);
|
2963
|
+
const ActionsPanel = () => {
|
2964
|
+
const { formatMessage } = useIntl();
|
2753
2965
|
return {
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2757
|
-
|
2758
|
-
|
2759
|
-
...schema?.pluginOptions,
|
2760
|
-
...data.contentType.options
|
2761
|
-
}
|
2966
|
+
title: formatMessage({
|
2967
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2968
|
+
defaultMessage: "Entry"
|
2969
|
+
}),
|
2970
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2762
2971
|
};
|
2763
2972
|
};
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2973
|
+
ActionsPanel.type = "actions";
|
2974
|
+
const ActionsPanelContent = () => {
|
2975
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2976
|
+
const [
|
2977
|
+
{
|
2978
|
+
query: { status = "draft" }
|
2769
2979
|
}
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2980
|
+
] = useQueryParams();
|
2981
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2982
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2983
|
+
const props = {
|
2984
|
+
activeTab: status,
|
2985
|
+
model,
|
2986
|
+
documentId: id,
|
2987
|
+
document: isCloning ? void 0 : document,
|
2988
|
+
meta: isCloning ? void 0 : meta,
|
2989
|
+
collectionType
|
2990
|
+
};
|
2991
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2992
|
+
/* @__PURE__ */ jsx(
|
2993
|
+
DescriptionComponentRenderer,
|
2994
|
+
{
|
2995
|
+
props,
|
2996
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2997
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2998
|
+
}
|
2999
|
+
),
|
3000
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3001
|
+
] });
|
2784
3002
|
};
|
3003
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
3004
|
+
return /* @__PURE__ */ jsxs(
|
3005
|
+
Flex,
|
3006
|
+
{
|
3007
|
+
ref,
|
3008
|
+
tag: "aside",
|
3009
|
+
"aria-labelledby": "additional-information",
|
3010
|
+
background: "neutral0",
|
3011
|
+
borderColor: "neutral150",
|
3012
|
+
hasRadius: true,
|
3013
|
+
paddingBottom: 4,
|
3014
|
+
paddingLeft: 4,
|
3015
|
+
paddingRight: 4,
|
3016
|
+
paddingTop: 4,
|
3017
|
+
shadow: "tableShadow",
|
3018
|
+
gap: 3,
|
3019
|
+
direction: "column",
|
3020
|
+
justifyContent: "stretch",
|
3021
|
+
alignItems: "flex-start",
|
3022
|
+
children: [
|
3023
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3024
|
+
children
|
3025
|
+
]
|
3026
|
+
}
|
3027
|
+
);
|
3028
|
+
});
|
2785
3029
|
const ConfirmBulkActionDialog = ({
|
2786
3030
|
onToggleDialog,
|
2787
3031
|
isOpen = false,
|
@@ -2789,7 +3033,7 @@ const ConfirmBulkActionDialog = ({
|
|
2789
3033
|
endAction
|
2790
3034
|
}) => {
|
2791
3035
|
const { formatMessage } = useIntl();
|
2792
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3036
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2793
3037
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2794
3038
|
id: "app.components.ConfirmDialog.title",
|
2795
3039
|
defaultMessage: "Confirmation"
|
@@ -2820,6 +3064,7 @@ const ConfirmDialogPublishAll = ({
|
|
2820
3064
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2821
3065
|
const { model, schema } = useDoc();
|
2822
3066
|
const [{ query }] = useQueryParams();
|
3067
|
+
const enableDraftRelationsCount = false;
|
2823
3068
|
const {
|
2824
3069
|
data: countDraftRelations = 0,
|
2825
3070
|
isLoading,
|
@@ -2831,7 +3076,7 @@ const ConfirmDialogPublishAll = ({
|
|
2831
3076
|
locale: query?.plugins?.i18n?.locale
|
2832
3077
|
},
|
2833
3078
|
{
|
2834
|
-
skip:
|
3079
|
+
skip: !enableDraftRelationsCount
|
2835
3080
|
}
|
2836
3081
|
);
|
2837
3082
|
React.useEffect(() => {
|
@@ -2910,7 +3155,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2910
3155
|
)
|
2911
3156
|
);
|
2912
3157
|
} else {
|
2913
|
-
messages.push(
|
3158
|
+
messages.push(
|
3159
|
+
...formatErrorMessages(
|
3160
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3161
|
+
value,
|
3162
|
+
currentKey,
|
3163
|
+
formatMessage
|
3164
|
+
)
|
3165
|
+
);
|
2914
3166
|
}
|
2915
3167
|
} else {
|
2916
3168
|
messages.push(
|
@@ -3009,7 +3261,7 @@ const SelectedEntriesTableContent = ({
|
|
3009
3261
|
status: row.status
|
3010
3262
|
}
|
3011
3263
|
) }),
|
3012
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3264
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3013
3265
|
IconButton,
|
3014
3266
|
{
|
3015
3267
|
tag: Link,
|
@@ -3032,9 +3284,10 @@ const SelectedEntriesTableContent = ({
|
|
3032
3284
|
),
|
3033
3285
|
target: "_blank",
|
3034
3286
|
marginLeft: "auto",
|
3035
|
-
|
3287
|
+
variant: "ghost",
|
3288
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3036
3289
|
}
|
3037
|
-
) })
|
3290
|
+
) }) })
|
3038
3291
|
] }, row.id)) })
|
3039
3292
|
] });
|
3040
3293
|
};
|
@@ -3071,7 +3324,13 @@ const SelectedEntriesModalContent = ({
|
|
3071
3324
|
);
|
3072
3325
|
const { rows, validationErrors } = React.useMemo(() => {
|
3073
3326
|
if (data.length > 0 && schema) {
|
3074
|
-
const validate = createYupSchema(
|
3327
|
+
const validate = createYupSchema(
|
3328
|
+
schema.attributes,
|
3329
|
+
components,
|
3330
|
+
// Since this is the "Publish" action, the validation
|
3331
|
+
// schema must enforce the rules for published entities
|
3332
|
+
{ status: "published" }
|
3333
|
+
);
|
3075
3334
|
const validationErrors2 = {};
|
3076
3335
|
const rows2 = data.map((entry) => {
|
3077
3336
|
try {
|
@@ -3421,7 +3680,7 @@ const TableActions = ({ document }) => {
|
|
3421
3680
|
DescriptionComponentRenderer,
|
3422
3681
|
{
|
3423
3682
|
props,
|
3424
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3683
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3425
3684
|
children: (actions2) => {
|
3426
3685
|
const tableRowActions = actions2.filter((action) => {
|
3427
3686
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3532,7 +3791,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3532
3791
|
}),
|
3533
3792
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3534
3793
|
footer: ({ onClose }) => {
|
3535
|
-
return /* @__PURE__ */ jsxs(
|
3794
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3536
3795
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3537
3796
|
id: "cancel",
|
3538
3797
|
defaultMessage: "Cancel"
|
@@ -3573,8 +3832,7 @@ class ContentManagerPlugin {
|
|
3573
3832
|
documentActions = [
|
3574
3833
|
...DEFAULT_ACTIONS,
|
3575
3834
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3576
|
-
...DEFAULT_HEADER_ACTIONS
|
3577
|
-
HistoryAction
|
3835
|
+
...DEFAULT_HEADER_ACTIONS
|
3578
3836
|
];
|
3579
3837
|
editViewSidePanels = [ActionsPanel];
|
3580
3838
|
headerActions = [];
|
@@ -3663,6 +3921,52 @@ const getPrintableType = (value) => {
|
|
3663
3921
|
}
|
3664
3922
|
return nativeType;
|
3665
3923
|
};
|
3924
|
+
const HistoryAction = ({ model, document }) => {
|
3925
|
+
const { formatMessage } = useIntl();
|
3926
|
+
const [{ query }] = useQueryParams();
|
3927
|
+
const navigate = useNavigate();
|
3928
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3929
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3930
|
+
return null;
|
3931
|
+
}
|
3932
|
+
return {
|
3933
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3934
|
+
label: formatMessage({
|
3935
|
+
id: "content-manager.history.document-action",
|
3936
|
+
defaultMessage: "Content History"
|
3937
|
+
}),
|
3938
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3939
|
+
disabled: (
|
3940
|
+
/**
|
3941
|
+
* The user is creating a new document.
|
3942
|
+
* It hasn't been saved yet, so there's no history to go to
|
3943
|
+
*/
|
3944
|
+
!document || /**
|
3945
|
+
* The document has been created but the current dimension has never been saved.
|
3946
|
+
* For example, the user is creating a new locale in an existing document,
|
3947
|
+
* so there's no history for the document in that locale
|
3948
|
+
*/
|
3949
|
+
!document.id || /**
|
3950
|
+
* History is only available for content types created by the user.
|
3951
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3952
|
+
* which start with `admin::` or `plugin::`
|
3953
|
+
*/
|
3954
|
+
!model.startsWith("api::")
|
3955
|
+
),
|
3956
|
+
position: "header"
|
3957
|
+
};
|
3958
|
+
};
|
3959
|
+
HistoryAction.type = "history";
|
3960
|
+
const historyAdmin = {
|
3961
|
+
bootstrap(app) {
|
3962
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3963
|
+
addDocumentAction((actions2) => {
|
3964
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3965
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3966
|
+
return actions2;
|
3967
|
+
});
|
3968
|
+
}
|
3969
|
+
};
|
3666
3970
|
const initialState = {
|
3667
3971
|
collectionTypeLinks: [],
|
3668
3972
|
components: [],
|
@@ -3713,15 +4017,29 @@ const index = {
|
|
3713
4017
|
defaultMessage: "Content Manager"
|
3714
4018
|
},
|
3715
4019
|
permissions: [],
|
3716
|
-
Component: () => import("./layout-B1Z-9koY.mjs").then((mod) => ({ default: mod.Layout })),
|
3717
4020
|
position: 1
|
3718
4021
|
});
|
4022
|
+
app.router.addRoute({
|
4023
|
+
path: "content-manager/*",
|
4024
|
+
lazy: async () => {
|
4025
|
+
const { Layout } = await import("./layout-PNlIceEV.mjs");
|
4026
|
+
return {
|
4027
|
+
Component: Layout
|
4028
|
+
};
|
4029
|
+
},
|
4030
|
+
children: routes
|
4031
|
+
});
|
3719
4032
|
app.registerPlugin(cm.config);
|
3720
4033
|
},
|
4034
|
+
bootstrap(app) {
|
4035
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4036
|
+
historyAdmin.bootstrap(app);
|
4037
|
+
}
|
4038
|
+
},
|
3721
4039
|
async registerTrads({ locales }) {
|
3722
4040
|
const importedTrads = await Promise.all(
|
3723
4041
|
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-
|
4042
|
+
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
4043
|
return {
|
3726
4044
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3727
4045
|
locale
|
@@ -3749,7 +4067,8 @@ export {
|
|
3749
4067
|
InjectionZone as I,
|
3750
4068
|
useDocument as J,
|
3751
4069
|
index as K,
|
3752
|
-
|
4070
|
+
useContentManagerContext as L,
|
4071
|
+
useDocumentActions as M,
|
3753
4072
|
Panels as P,
|
3754
4073
|
RelativeTime as R,
|
3755
4074
|
SINGLE_TYPES as S,
|
@@ -3767,11 +4086,11 @@ export {
|
|
3767
4086
|
PERMISSIONS as k,
|
3768
4087
|
DocumentRBAC as l,
|
3769
4088
|
DOCUMENT_META_FIELDS as m,
|
3770
|
-
|
3771
|
-
|
3772
|
-
|
3773
|
-
|
3774
|
-
|
4089
|
+
CLONE_PATH as n,
|
4090
|
+
useDocLayout as o,
|
4091
|
+
useGetContentTypeConfigurationQuery as p,
|
4092
|
+
CREATOR_FIELDS as q,
|
4093
|
+
getMainField as r,
|
3775
4094
|
setInitialData as s,
|
3776
4095
|
getDisplayName as t,
|
3777
4096
|
useContentTypeSchema as u,
|
@@ -3781,4 +4100,4 @@ export {
|
|
3781
4100
|
capitalise as y,
|
3782
4101
|
useUpdateContentTypeConfigurationMutation as z
|
3783
4102
|
};
|
3784
|
-
//# sourceMappingURL=index-
|
4103
|
+
//# sourceMappingURL=index-Bz1SCyIj.mjs.map
|