@strapi/content-manager 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb → 0.0.0-experimental.d65615a2b9130dd742d3c396674457d7971da928
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-C-49MccQ.js → ComponentConfigurationPage-CO977CPh.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-CO977CPh.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-CQroR9Qk.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-CQroR9Qk.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-BPgoE-kf.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-BPgoE-kf.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-tVCJ5vWC.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-tVCJ5vWC.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-8mOu02ji.mjs} +30 -9
- package/dist/_chunks/EditViewPage-8mOu02ji.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-BMVgUNOX.js} +30 -9
- package/dist/_chunks/EditViewPage-BMVgUNOX.js.map +1 -0
- package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-CJPYzwD7.mjs} +249 -152
- package/dist/_chunks/Field-CJPYzwD7.mjs.map +1 -0
- package/dist/_chunks/{Field-Boxf9Ajp.js → Field-CdSLKFQk.js} +251 -154
- package/dist/_chunks/Field-CdSLKFQk.js.map +1 -0
- package/dist/_chunks/{Form-DHrru2AV.mjs → Form-DJOJ-GF1.mjs} +36 -17
- package/dist/_chunks/Form-DJOJ-GF1.mjs.map +1 -0
- package/dist/_chunks/{Form-y5g1SRsh.js → Form-eP5bZwap.js} +36 -17
- package/dist/_chunks/Form-eP5bZwap.js.map +1 -0
- package/dist/_chunks/{History-CqN6K7SX.js → History-B-Mrquzu.js} +63 -25
- package/dist/_chunks/History-B-Mrquzu.js.map +1 -0
- package/dist/_chunks/{History-Bru_KoeP.mjs → History-MnQLtk1g.mjs} +64 -26
- package/dist/_chunks/History-MnQLtk1g.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BcycI8Lw.mjs} +21 -9
- package/dist/_chunks/ListConfigurationPage-BcycI8Lw.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-C0n4rUzH.js} +21 -9
- package/dist/_chunks/ListConfigurationPage-C0n4rUzH.js.map +1 -0
- package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-CRXONXwZ.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CRXONXwZ.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-q0SHVPUS.js} +61 -43
- package/dist/_chunks/ListViewPage-q0SHVPUS.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-Bh3komDV.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-Bh3komDV.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-ukzFRF3z.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-ukzFRF3z.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-B4sD7Ble.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-B4sD7Ble.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-BGBpj_Y1.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-BGBpj_Y1.js.map} +1 -1
- package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-B53wYe8g.js} +33 -24
- package/dist/_chunks/Relations-B53wYe8g.js.map +1 -0
- package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-CIexb8gr.mjs} +33 -24
- package/dist/_chunks/Relations-CIexb8gr.mjs.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-Bm0D0IWz.js} +17 -15
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-DKV44jRb.mjs} +17 -15
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-DJXJw9V5.mjs → index-CJ2vYwuT.mjs} +997 -690
- package/dist/_chunks/index-CJ2vYwuT.mjs.map +1 -0
- package/dist/_chunks/{index-DVPWZkbS.js → index-DbT2sx-Q.js} +978 -671
- package/dist/_chunks/index-DbT2sx-Q.js.map +1 -0
- package/dist/_chunks/{layout-Dm6fbiQj.js → layout-CeBSIkmP.js} +24 -11
- package/dist/_chunks/layout-CeBSIkmP.js.map +1 -0
- package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-vzKSrr7p.mjs} +25 -12
- package/dist/_chunks/layout-vzKSrr7p.mjs.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CKnpRgrN.js → relations-Cl-6t9iz.js} +2 -2
- package/dist/_chunks/{relations-CKnpRgrN.js.map → relations-Cl-6t9iz.js.map} +1 -1
- package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-DI0lguF0.mjs} +2 -2
- package/dist/_chunks/{relations-BH_kBSJ0.mjs.map → relations-DI0lguF0.mjs.map} +1 -1
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- 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/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 +207 -120
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +208 -121
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
- package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
- package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
- package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
- package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
- package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
- package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
- package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
- package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
- package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
- package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
- package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
- package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
- package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,17 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
7
4
|
import * as React from "react";
|
8
5
|
import { lazy } from "react";
|
9
|
-
import { Button, Menu, VisuallyHidden, Flex,
|
10
|
-
import {
|
6
|
+
import { Button, Menu, VisuallyHidden, Flex, Typography, Dialog, Modal, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import { useIntl } from "react-intl";
|
8
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
11
9
|
import * as yup from "yup";
|
12
10
|
import { ValidationError } from "yup";
|
13
11
|
import pipe from "lodash/fp/pipe";
|
14
12
|
import { intervalToDuration, isPast } from "date-fns";
|
13
|
+
import { styled } from "styled-components";
|
14
|
+
import { stringify } from "qs";
|
15
15
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
16
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
17
|
const v = glob[path];
|
@@ -49,42 +49,6 @@ const useInjectionZone = (area) => {
|
|
49
49
|
const [page, position] = area.split(".");
|
50
50
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
51
51
|
};
|
52
|
-
const HistoryAction = ({ model, document }) => {
|
53
|
-
const { formatMessage } = useIntl();
|
54
|
-
const [{ query }] = useQueryParams();
|
55
|
-
const navigate = useNavigate();
|
56
|
-
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
57
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
58
|
-
return null;
|
59
|
-
}
|
60
|
-
return {
|
61
|
-
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
62
|
-
label: formatMessage({
|
63
|
-
id: "content-manager.history.document-action",
|
64
|
-
defaultMessage: "Content History"
|
65
|
-
}),
|
66
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
67
|
-
disabled: (
|
68
|
-
/**
|
69
|
-
* The user is creating a new document.
|
70
|
-
* It hasn't been saved yet, so there's no history to go to
|
71
|
-
*/
|
72
|
-
!document || /**
|
73
|
-
* The document has been created but the current dimension has never been saved.
|
74
|
-
* For example, the user is creating a new locale in an existing document,
|
75
|
-
* so there's no history for the document in that locale
|
76
|
-
*/
|
77
|
-
!document.id || /**
|
78
|
-
* History is only available for content types created by the user.
|
79
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
80
|
-
* which start with `admin::` or `plugin::`
|
81
|
-
*/
|
82
|
-
!model.startsWith("api::")
|
83
|
-
),
|
84
|
-
position: "header"
|
85
|
-
};
|
86
|
-
};
|
87
|
-
HistoryAction.type = "history";
|
88
52
|
const ID = "id";
|
89
53
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
90
54
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -136,6 +100,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
136
100
|
if (!slug) {
|
137
101
|
throw new Error("Cannot find the slug param in the URL");
|
138
102
|
}
|
103
|
+
const [{ rawQuery }] = useQueryParams();
|
139
104
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
140
105
|
const contentTypePermissions = React.useMemo(() => {
|
141
106
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -146,7 +111,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
146
111
|
return { ...acc, [action]: [permission] };
|
147
112
|
}, {});
|
148
113
|
}, [slug, userPermissions]);
|
149
|
-
const { isLoading, allowedActions } = useRBAC(
|
114
|
+
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
contentTypePermissions,
|
116
|
+
permissions ?? void 0,
|
117
|
+
// TODO: useRBAC context should be typed and built differently
|
118
|
+
// We are passing raw query as context to the hook so that it can
|
119
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
120
|
+
rawQuery
|
121
|
+
);
|
150
122
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
151
123
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
152
124
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -194,7 +166,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
194
166
|
"Document",
|
195
167
|
"InitialData",
|
196
168
|
"HistoryVersion",
|
197
|
-
"Relations"
|
169
|
+
"Relations",
|
170
|
+
"UidAvailability"
|
198
171
|
]
|
199
172
|
});
|
200
173
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -208,7 +181,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
208
181
|
params: query
|
209
182
|
}
|
210
183
|
}),
|
211
|
-
invalidatesTags: (_result,
|
184
|
+
invalidatesTags: (_result, error, { model }) => {
|
185
|
+
if (error) {
|
186
|
+
return [];
|
187
|
+
}
|
188
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
189
|
+
}
|
212
190
|
}),
|
213
191
|
cloneDocument: builder.mutation({
|
214
192
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -219,7 +197,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
219
197
|
params
|
220
198
|
}
|
221
199
|
}),
|
222
|
-
invalidatesTags: (_result, _error, { model }) => [
|
200
|
+
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
{ type: "Document", id: `${model}_LIST` },
|
202
|
+
{ type: "UidAvailability", id: model }
|
203
|
+
]
|
223
204
|
}),
|
224
205
|
/**
|
225
206
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -236,7 +217,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
236
217
|
}),
|
237
218
|
invalidatesTags: (result, _error, { model }) => [
|
238
219
|
{ type: "Document", id: `${model}_LIST` },
|
239
|
-
"Relations"
|
220
|
+
"Relations",
|
221
|
+
{ type: "UidAvailability", id: model }
|
240
222
|
]
|
241
223
|
}),
|
242
224
|
deleteDocument: builder.mutation({
|
@@ -277,7 +259,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
277
259
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
278
260
|
},
|
279
261
|
{ type: "Document", id: `${model}_LIST` },
|
280
|
-
"Relations"
|
262
|
+
"Relations",
|
263
|
+
{ type: "UidAvailability", id: model }
|
281
264
|
];
|
282
265
|
}
|
283
266
|
}),
|
@@ -295,6 +278,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
295
278
|
}),
|
296
279
|
providesTags: (result, _error, arg) => {
|
297
280
|
return [
|
281
|
+
{ type: "Document", id: `ALL_LIST` },
|
298
282
|
{ type: "Document", id: `${arg.model}_LIST` },
|
299
283
|
...result?.results.map(({ documentId }) => ({
|
300
284
|
type: "Document",
|
@@ -333,6 +317,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
333
317
|
{
|
334
318
|
type: "Document",
|
335
319
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
320
|
+
},
|
321
|
+
// Make it easy to invalidate all individual documents queries for a model
|
322
|
+
{
|
323
|
+
type: "Document",
|
324
|
+
id: `${model}_ALL_ITEMS`
|
336
325
|
}
|
337
326
|
];
|
338
327
|
}
|
@@ -396,8 +385,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
396
385
|
type: "Document",
|
397
386
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
398
387
|
},
|
399
|
-
"Relations"
|
388
|
+
"Relations",
|
389
|
+
{ type: "UidAvailability", id: model }
|
400
390
|
];
|
391
|
+
},
|
392
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
393
|
+
const patchResult = dispatch(
|
394
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
395
|
+
Object.assign(draft.data, data);
|
396
|
+
})
|
397
|
+
);
|
398
|
+
try {
|
399
|
+
await queryFulfilled;
|
400
|
+
} catch {
|
401
|
+
patchResult.undo();
|
402
|
+
}
|
401
403
|
}
|
402
404
|
}),
|
403
405
|
unpublishDocument: builder.mutation({
|
@@ -467,20 +469,39 @@ const buildValidParams = (query) => {
|
|
467
469
|
const isBaseQueryError = (error) => {
|
468
470
|
return error.name !== void 0;
|
469
471
|
};
|
470
|
-
const
|
472
|
+
const arrayValidator = (attribute, options) => ({
|
473
|
+
message: translatedErrors.required,
|
474
|
+
test(value) {
|
475
|
+
if (options.status === "draft") {
|
476
|
+
return true;
|
477
|
+
}
|
478
|
+
if (!attribute.required) {
|
479
|
+
return true;
|
480
|
+
}
|
481
|
+
if (!value) {
|
482
|
+
return false;
|
483
|
+
}
|
484
|
+
if (Array.isArray(value) && value.length === 0) {
|
485
|
+
return false;
|
486
|
+
}
|
487
|
+
return true;
|
488
|
+
}
|
489
|
+
});
|
490
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
471
491
|
const createModelSchema = (attributes2) => yup.object().shape(
|
472
492
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
473
493
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
474
494
|
return acc;
|
475
495
|
}
|
476
496
|
const validations = [
|
497
|
+
addNullableValidation,
|
477
498
|
addRequiredValidation,
|
478
499
|
addMinLengthValidation,
|
479
500
|
addMaxLengthValidation,
|
480
501
|
addMinValidation,
|
481
502
|
addMaxValidation,
|
482
503
|
addRegexValidation
|
483
|
-
].map((fn) => fn(attribute));
|
504
|
+
].map((fn) => fn(attribute, options));
|
484
505
|
const transformSchema = pipe(...validations);
|
485
506
|
switch (attribute.type) {
|
486
507
|
case "component": {
|
@@ -490,12 +511,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
490
511
|
...acc,
|
491
512
|
[name]: transformSchema(
|
492
513
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
493
|
-
)
|
514
|
+
).test(arrayValidator(attribute, options))
|
494
515
|
};
|
495
516
|
} else {
|
496
517
|
return {
|
497
518
|
...acc,
|
498
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
519
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
499
520
|
};
|
500
521
|
}
|
501
522
|
}
|
@@ -517,7 +538,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
517
538
|
}
|
518
539
|
)
|
519
540
|
)
|
520
|
-
)
|
541
|
+
).test(arrayValidator(attribute, options))
|
521
542
|
};
|
522
543
|
case "relation":
|
523
544
|
return {
|
@@ -529,7 +550,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
529
550
|
} else if (Array.isArray(value)) {
|
530
551
|
return yup.array().of(
|
531
552
|
yup.object().shape({
|
532
|
-
id: yup.
|
553
|
+
id: yup.number().required()
|
533
554
|
})
|
534
555
|
);
|
535
556
|
} else if (typeof value === "object") {
|
@@ -581,6 +602,14 @@ const createAttributeSchema = (attribute) => {
|
|
581
602
|
if (!value || typeof value === "string" && value.length === 0) {
|
582
603
|
return true;
|
583
604
|
}
|
605
|
+
if (typeof value === "object") {
|
606
|
+
try {
|
607
|
+
JSON.stringify(value);
|
608
|
+
return true;
|
609
|
+
} catch (err) {
|
610
|
+
return false;
|
611
|
+
}
|
612
|
+
}
|
584
613
|
try {
|
585
614
|
JSON.parse(value);
|
586
615
|
return true;
|
@@ -599,13 +628,7 @@ const createAttributeSchema = (attribute) => {
|
|
599
628
|
return yup.mixed();
|
600
629
|
}
|
601
630
|
};
|
602
|
-
const
|
603
|
-
if (attribute.required) {
|
604
|
-
return schema.required({
|
605
|
-
id: translatedErrors.required.id,
|
606
|
-
defaultMessage: "This field is required."
|
607
|
-
});
|
608
|
-
}
|
631
|
+
const nullableSchema = (schema) => {
|
609
632
|
return schema?.nullable ? schema.nullable() : (
|
610
633
|
// In some cases '.nullable' will not be available on the schema.
|
611
634
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -613,7 +636,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
613
636
|
schema
|
614
637
|
);
|
615
638
|
};
|
616
|
-
const
|
639
|
+
const addNullableValidation = () => (schema) => {
|
640
|
+
return nullableSchema(schema);
|
641
|
+
};
|
642
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
643
|
+
if (options.status === "draft" || !attribute.required) {
|
644
|
+
return schema;
|
645
|
+
}
|
646
|
+
if (attribute.required && "required" in schema) {
|
647
|
+
return schema.required(translatedErrors.required);
|
648
|
+
}
|
649
|
+
return schema;
|
650
|
+
};
|
651
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
652
|
+
if (options.status === "draft") {
|
653
|
+
return schema;
|
654
|
+
}
|
617
655
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
618
656
|
return schema.min(attribute.minLength, {
|
619
657
|
...translatedErrors.minLength,
|
@@ -635,10 +673,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
635
673
|
}
|
636
674
|
return schema;
|
637
675
|
};
|
638
|
-
const addMinValidation = (attribute) => (schema) => {
|
639
|
-
if ("
|
676
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
677
|
+
if (options.status === "draft") {
|
678
|
+
return schema;
|
679
|
+
}
|
680
|
+
if ("min" in attribute && "min" in schema) {
|
640
681
|
const min = toInteger(attribute.min);
|
641
|
-
if (
|
682
|
+
if (min) {
|
642
683
|
return schema.min(min, {
|
643
684
|
...translatedErrors.min,
|
644
685
|
values: {
|
@@ -756,16 +797,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
756
797
|
}, {});
|
757
798
|
return componentsByKey;
|
758
799
|
};
|
759
|
-
const
|
800
|
+
const HOOKS = {
|
801
|
+
/**
|
802
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
803
|
+
* @constant
|
804
|
+
* @type {string}
|
805
|
+
*/
|
806
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
807
|
+
/**
|
808
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
809
|
+
* @constant
|
810
|
+
* @type {string}
|
811
|
+
*/
|
812
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
813
|
+
/**
|
814
|
+
* Hook that allows to mutate the CM's edit view layout
|
815
|
+
* @constant
|
816
|
+
* @type {string}
|
817
|
+
*/
|
818
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
819
|
+
/**
|
820
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
821
|
+
* @constant
|
822
|
+
* @type {string}
|
823
|
+
*/
|
824
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
825
|
+
};
|
826
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
827
|
+
endpoints: (builder) => ({
|
828
|
+
getContentTypeConfiguration: builder.query({
|
829
|
+
query: (uid) => ({
|
830
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
831
|
+
method: "GET"
|
832
|
+
}),
|
833
|
+
transformResponse: (response) => response.data,
|
834
|
+
providesTags: (_result, _error, uid) => [
|
835
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
836
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
837
|
+
]
|
838
|
+
}),
|
839
|
+
getAllContentTypeSettings: builder.query({
|
840
|
+
query: () => "/content-manager/content-types-settings",
|
841
|
+
transformResponse: (response) => response.data,
|
842
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
843
|
+
}),
|
844
|
+
updateContentTypeConfiguration: builder.mutation({
|
845
|
+
query: ({ uid, ...body }) => ({
|
846
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
847
|
+
method: "PUT",
|
848
|
+
data: body
|
849
|
+
}),
|
850
|
+
transformResponse: (response) => response.data,
|
851
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
852
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
853
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
854
|
+
// Is this necessary?
|
855
|
+
{ type: "InitialData" }
|
856
|
+
]
|
857
|
+
})
|
858
|
+
})
|
859
|
+
});
|
860
|
+
const {
|
861
|
+
useGetContentTypeConfigurationQuery,
|
862
|
+
useGetAllContentTypeSettingsQuery,
|
863
|
+
useUpdateContentTypeConfigurationMutation
|
864
|
+
} = contentTypesApi;
|
865
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
866
|
+
const { type } = attribute;
|
867
|
+
if (type === "relation") {
|
868
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
869
|
+
}
|
870
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
871
|
+
};
|
872
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
873
|
+
if (!mainFieldName) {
|
874
|
+
return void 0;
|
875
|
+
}
|
876
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
877
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
878
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
879
|
+
);
|
880
|
+
return {
|
881
|
+
name: mainFieldName,
|
882
|
+
type: mainFieldType ?? "string"
|
883
|
+
};
|
884
|
+
};
|
885
|
+
const DEFAULT_SETTINGS = {
|
886
|
+
bulkable: false,
|
887
|
+
filterable: false,
|
888
|
+
searchable: false,
|
889
|
+
pagination: false,
|
890
|
+
defaultSortBy: "",
|
891
|
+
defaultSortOrder: "asc",
|
892
|
+
mainField: "id",
|
893
|
+
pageSize: 10
|
894
|
+
};
|
895
|
+
const useDocumentLayout = (model) => {
|
896
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
897
|
+
const [{ query }] = useQueryParams();
|
898
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
760
899
|
const { toggleNotification } = useNotification();
|
761
900
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
901
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
762
902
|
const {
|
763
|
-
|
764
|
-
isLoading:
|
765
|
-
|
766
|
-
|
767
|
-
} =
|
768
|
-
const
|
903
|
+
data,
|
904
|
+
isLoading: isLoadingConfigs,
|
905
|
+
error,
|
906
|
+
isFetching: isFetchingConfigs
|
907
|
+
} = useGetContentTypeConfigurationQuery(model);
|
908
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
769
909
|
React.useEffect(() => {
|
770
910
|
if (error) {
|
771
911
|
toggleNotification({
|
@@ -773,68 +913,321 @@ const useDocument = (args, opts) => {
|
|
773
913
|
message: formatAPIError(error)
|
774
914
|
});
|
775
915
|
}
|
776
|
-
}, [
|
777
|
-
const
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
(document) => {
|
785
|
-
if (!validationSchema) {
|
786
|
-
throw new Error(
|
787
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
788
|
-
);
|
789
|
-
}
|
790
|
-
try {
|
791
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
792
|
-
return null;
|
793
|
-
} catch (error2) {
|
794
|
-
if (error2 instanceof ValidationError) {
|
795
|
-
return getYupValidationErrors(error2);
|
796
|
-
}
|
797
|
-
throw error2;
|
798
|
-
}
|
916
|
+
}, [error, formatAPIError, toggleNotification]);
|
917
|
+
const editLayout = React.useMemo(
|
918
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
919
|
+
layout: [],
|
920
|
+
components: {},
|
921
|
+
metadatas: {},
|
922
|
+
options: {},
|
923
|
+
settings: DEFAULT_SETTINGS
|
799
924
|
},
|
800
|
-
[
|
925
|
+
[data, isLoading, schemas, schema, components]
|
926
|
+
);
|
927
|
+
const listLayout = React.useMemo(() => {
|
928
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
929
|
+
layout: [],
|
930
|
+
metadatas: {},
|
931
|
+
options: {},
|
932
|
+
settings: DEFAULT_SETTINGS
|
933
|
+
};
|
934
|
+
}, [data, isLoading, schemas, schema, components]);
|
935
|
+
const { layout: edit } = React.useMemo(
|
936
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
937
|
+
layout: editLayout,
|
938
|
+
query
|
939
|
+
}),
|
940
|
+
[editLayout, query, runHookWaterfall]
|
801
941
|
);
|
802
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
803
942
|
return {
|
804
|
-
|
805
|
-
document: data?.data,
|
806
|
-
meta: data?.meta,
|
943
|
+
error,
|
807
944
|
isLoading,
|
808
|
-
|
809
|
-
|
945
|
+
edit,
|
946
|
+
list: listLayout
|
810
947
|
};
|
811
948
|
};
|
812
|
-
const
|
813
|
-
const {
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
949
|
+
const useDocLayout = () => {
|
950
|
+
const { model } = useDoc();
|
951
|
+
return useDocumentLayout(model);
|
952
|
+
};
|
953
|
+
const formatEditLayout = (data, {
|
954
|
+
schemas,
|
955
|
+
schema,
|
956
|
+
components
|
957
|
+
}) => {
|
958
|
+
let currentPanelIndex = 0;
|
959
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
960
|
+
data.contentType.layouts.edit,
|
961
|
+
schema?.attributes,
|
962
|
+
data.contentType.metadatas,
|
963
|
+
{ configurations: data.components, schemas: components },
|
964
|
+
schemas
|
965
|
+
).reduce((panels, row) => {
|
966
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
967
|
+
panels.push([row]);
|
968
|
+
currentPanelIndex += 2;
|
969
|
+
} else {
|
970
|
+
if (!panels[currentPanelIndex]) {
|
971
|
+
panels.push([]);
|
972
|
+
}
|
973
|
+
panels[currentPanelIndex].push(row);
|
974
|
+
}
|
975
|
+
return panels;
|
976
|
+
}, []);
|
977
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
978
|
+
(acc, [uid, configuration]) => {
|
979
|
+
acc[uid] = {
|
980
|
+
layout: convertEditLayoutToFieldLayouts(
|
981
|
+
configuration.layouts.edit,
|
982
|
+
components[uid].attributes,
|
983
|
+
configuration.metadatas,
|
984
|
+
{ configurations: data.components, schemas: components }
|
985
|
+
),
|
986
|
+
settings: {
|
987
|
+
...configuration.settings,
|
988
|
+
icon: components[uid].info.icon,
|
989
|
+
displayName: components[uid].info.displayName
|
990
|
+
}
|
991
|
+
};
|
992
|
+
return acc;
|
993
|
+
},
|
994
|
+
{}
|
995
|
+
);
|
996
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
997
|
+
(acc, [attribute, metadata]) => {
|
998
|
+
return {
|
999
|
+
...acc,
|
1000
|
+
[attribute]: metadata.edit
|
1001
|
+
};
|
1002
|
+
},
|
1003
|
+
{}
|
1004
|
+
);
|
1005
|
+
return {
|
1006
|
+
layout: panelledEditAttributes,
|
1007
|
+
components: componentEditAttributes,
|
1008
|
+
metadatas: editMetadatas,
|
1009
|
+
settings: {
|
1010
|
+
...data.contentType.settings,
|
1011
|
+
displayName: schema?.info.displayName
|
1012
|
+
},
|
1013
|
+
options: {
|
1014
|
+
...schema?.options,
|
1015
|
+
...schema?.pluginOptions,
|
1016
|
+
...data.contentType.options
|
1017
|
+
}
|
1018
|
+
};
|
1019
|
+
};
|
1020
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1021
|
+
return rows.map(
|
1022
|
+
(row) => row.map((field) => {
|
1023
|
+
const attribute = attributes[field.name];
|
1024
|
+
if (!attribute) {
|
1025
|
+
return null;
|
1026
|
+
}
|
1027
|
+
const { edit: metadata } = metadatas[field.name];
|
1028
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1029
|
+
return {
|
1030
|
+
attribute,
|
1031
|
+
disabled: !metadata.editable,
|
1032
|
+
hint: metadata.description,
|
1033
|
+
label: metadata.label ?? "",
|
1034
|
+
name: field.name,
|
1035
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1036
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1037
|
+
schemas,
|
1038
|
+
components: components?.schemas ?? {}
|
1039
|
+
}),
|
1040
|
+
placeholder: metadata.placeholder ?? "",
|
1041
|
+
required: attribute.required ?? false,
|
1042
|
+
size: field.size,
|
1043
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1044
|
+
visible: metadata.visible ?? true,
|
1045
|
+
type: attribute.type
|
1046
|
+
};
|
1047
|
+
}).filter((field) => field !== null)
|
1048
|
+
);
|
1049
|
+
};
|
1050
|
+
const formatListLayout = (data, {
|
1051
|
+
schemas,
|
1052
|
+
schema,
|
1053
|
+
components
|
1054
|
+
}) => {
|
1055
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1056
|
+
(acc, [attribute, metadata]) => {
|
1057
|
+
return {
|
1058
|
+
...acc,
|
1059
|
+
[attribute]: metadata.list
|
1060
|
+
};
|
1061
|
+
},
|
1062
|
+
{}
|
1063
|
+
);
|
1064
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1065
|
+
data.contentType.layouts.list,
|
1066
|
+
schema?.attributes,
|
1067
|
+
listMetadatas,
|
1068
|
+
{ configurations: data.components, schemas: components },
|
1069
|
+
schemas
|
1070
|
+
);
|
1071
|
+
return {
|
1072
|
+
layout: listAttributes,
|
1073
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1074
|
+
metadatas: listMetadatas,
|
1075
|
+
options: {
|
1076
|
+
...schema?.options,
|
1077
|
+
...schema?.pluginOptions,
|
1078
|
+
...data.contentType.options
|
1079
|
+
}
|
1080
|
+
};
|
1081
|
+
};
|
1082
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1083
|
+
return columns.map((name) => {
|
1084
|
+
const attribute = attributes[name];
|
1085
|
+
if (!attribute) {
|
1086
|
+
return null;
|
1087
|
+
}
|
1088
|
+
const metadata = metadatas[name];
|
1089
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1090
|
+
return {
|
1091
|
+
attribute,
|
1092
|
+
label: metadata.label ?? "",
|
1093
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1094
|
+
schemas,
|
1095
|
+
components: components?.schemas ?? {}
|
1096
|
+
}),
|
1097
|
+
name,
|
1098
|
+
searchable: metadata.searchable ?? true,
|
1099
|
+
sortable: metadata.sortable ?? true
|
1100
|
+
};
|
1101
|
+
}).filter((field) => field !== null);
|
1102
|
+
};
|
1103
|
+
const useDocument = (args, opts) => {
|
1104
|
+
const { toggleNotification } = useNotification();
|
1105
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1106
|
+
const {
|
1107
|
+
currentData: data,
|
1108
|
+
isLoading: isLoadingDocument,
|
1109
|
+
isFetching: isFetchingDocument,
|
1110
|
+
error
|
1111
|
+
} = useGetDocumentQuery(args, {
|
1112
|
+
...opts,
|
1113
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1114
|
+
});
|
1115
|
+
const {
|
1116
|
+
components,
|
1117
|
+
schema,
|
1118
|
+
schemas,
|
1119
|
+
isLoading: isLoadingSchema
|
1120
|
+
} = useContentTypeSchema(args.model);
|
1121
|
+
React.useEffect(() => {
|
1122
|
+
if (error) {
|
1123
|
+
toggleNotification({
|
1124
|
+
type: "danger",
|
1125
|
+
message: formatAPIError(error)
|
1126
|
+
});
|
1127
|
+
}
|
1128
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1129
|
+
const validationSchema = React.useMemo(() => {
|
1130
|
+
if (!schema) {
|
1131
|
+
return null;
|
1132
|
+
}
|
1133
|
+
return createYupSchema(schema.attributes, components);
|
1134
|
+
}, [schema, components]);
|
1135
|
+
const validate = React.useCallback(
|
1136
|
+
(document) => {
|
1137
|
+
if (!validationSchema) {
|
1138
|
+
throw new Error(
|
1139
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1140
|
+
);
|
1141
|
+
}
|
1142
|
+
try {
|
1143
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1144
|
+
return null;
|
1145
|
+
} catch (error2) {
|
1146
|
+
if (error2 instanceof ValidationError) {
|
1147
|
+
return getYupValidationErrors(error2);
|
1148
|
+
}
|
1149
|
+
throw error2;
|
1150
|
+
}
|
1151
|
+
},
|
1152
|
+
[validationSchema]
|
1153
|
+
);
|
1154
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1155
|
+
const hasError = !!error;
|
1156
|
+
return {
|
1157
|
+
components,
|
1158
|
+
document: data?.data,
|
1159
|
+
meta: data?.meta,
|
1160
|
+
isLoading,
|
1161
|
+
hasError,
|
1162
|
+
schema,
|
1163
|
+
schemas,
|
1164
|
+
validate
|
1165
|
+
};
|
1166
|
+
};
|
1167
|
+
const useDoc = () => {
|
1168
|
+
const { id, slug, collectionType, origin } = useParams();
|
1169
|
+
const [{ query }] = useQueryParams();
|
1170
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1171
|
+
if (!collectionType) {
|
1172
|
+
throw new Error("Could not find collectionType in url params");
|
1173
|
+
}
|
1174
|
+
if (!slug) {
|
1175
|
+
throw new Error("Could not find model in url params");
|
1176
|
+
}
|
1177
|
+
const document = useDocument(
|
1178
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1179
|
+
{
|
1180
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1181
|
+
}
|
1182
|
+
);
|
1183
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
822
1184
|
return {
|
823
1185
|
collectionType,
|
824
1186
|
model: slug,
|
825
|
-
id:
|
826
|
-
...
|
827
|
-
|
828
|
-
|
829
|
-
|
830
|
-
|
831
|
-
|
1187
|
+
id: returnId,
|
1188
|
+
...document
|
1189
|
+
};
|
1190
|
+
};
|
1191
|
+
const useContentManagerContext = () => {
|
1192
|
+
const {
|
1193
|
+
collectionType,
|
1194
|
+
model,
|
1195
|
+
id,
|
1196
|
+
components,
|
1197
|
+
isLoading: isLoadingDoc,
|
1198
|
+
schema,
|
1199
|
+
schemas
|
1200
|
+
} = useDoc();
|
1201
|
+
const layout = useDocumentLayout(model);
|
1202
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1203
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1204
|
+
const slug = model;
|
1205
|
+
const isCreatingEntry = id === "create";
|
1206
|
+
useContentTypeSchema();
|
1207
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1208
|
+
const error = layout.error;
|
1209
|
+
return {
|
1210
|
+
error,
|
1211
|
+
isLoading,
|
1212
|
+
// Base metadata
|
1213
|
+
model,
|
1214
|
+
collectionType,
|
1215
|
+
id,
|
1216
|
+
slug,
|
1217
|
+
isCreatingEntry,
|
1218
|
+
isSingleType,
|
1219
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1220
|
+
// All schema infos
|
1221
|
+
components,
|
1222
|
+
contentType: schema,
|
1223
|
+
contentTypes: schemas,
|
1224
|
+
// Form state
|
1225
|
+
form,
|
1226
|
+
// layout infos
|
1227
|
+
layout
|
832
1228
|
};
|
833
1229
|
};
|
834
1230
|
const prefixPluginTranslations = (trad, pluginId) => {
|
835
|
-
if (!pluginId) {
|
836
|
-
throw new TypeError("pluginId can't be empty");
|
837
|
-
}
|
838
1231
|
return Object.keys(trad).reduce((acc, current) => {
|
839
1232
|
acc[`${pluginId}.${current}`] = trad[current];
|
840
1233
|
return acc;
|
@@ -850,6 +1243,8 @@ const useDocumentActions = () => {
|
|
850
1243
|
const { formatMessage } = useIntl();
|
851
1244
|
const { trackUsage } = useTracking();
|
852
1245
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1246
|
+
const navigate = useNavigate();
|
1247
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
853
1248
|
const [deleteDocument] = useDeleteDocumentMutation();
|
854
1249
|
const _delete = React.useCallback(
|
855
1250
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1164,6 +1559,7 @@ const useDocumentActions = () => {
|
|
1164
1559
|
defaultMessage: "Saved document"
|
1165
1560
|
})
|
1166
1561
|
});
|
1562
|
+
setCurrentStep("contentManager.success");
|
1167
1563
|
return res.data;
|
1168
1564
|
} catch (err) {
|
1169
1565
|
toggleNotification({
|
@@ -1185,7 +1581,6 @@ const useDocumentActions = () => {
|
|
1185
1581
|
sourceId
|
1186
1582
|
});
|
1187
1583
|
if ("error" in res) {
|
1188
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1189
1584
|
return { error: res.error };
|
1190
1585
|
}
|
1191
1586
|
toggleNotification({
|
@@ -1204,7 +1599,7 @@ const useDocumentActions = () => {
|
|
1204
1599
|
throw err;
|
1205
1600
|
}
|
1206
1601
|
},
|
1207
|
-
[autoCloneDocument,
|
1602
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1208
1603
|
);
|
1209
1604
|
const [cloneDocument] = useCloneDocumentMutation();
|
1210
1605
|
const clone = React.useCallback(
|
@@ -1230,6 +1625,7 @@ const useDocumentActions = () => {
|
|
1230
1625
|
defaultMessage: "Cloned document"
|
1231
1626
|
})
|
1232
1627
|
});
|
1628
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1233
1629
|
return res.data;
|
1234
1630
|
} catch (err) {
|
1235
1631
|
toggleNotification({
|
@@ -1240,7 +1636,7 @@ const useDocumentActions = () => {
|
|
1240
1636
|
throw err;
|
1241
1637
|
}
|
1242
1638
|
},
|
1243
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1639
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1244
1640
|
);
|
1245
1641
|
const [getDoc] = useLazyGetDocumentQuery();
|
1246
1642
|
const getDocument = React.useCallback(
|
@@ -1266,7 +1662,7 @@ const useDocumentActions = () => {
|
|
1266
1662
|
};
|
1267
1663
|
};
|
1268
1664
|
const ProtectedHistoryPage = lazy(
|
1269
|
-
() => import("./History-
|
1665
|
+
() => import("./History-MnQLtk1g.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1270
1666
|
);
|
1271
1667
|
const routes$1 = [
|
1272
1668
|
{
|
@@ -1279,31 +1675,31 @@ const routes$1 = [
|
|
1279
1675
|
}
|
1280
1676
|
];
|
1281
1677
|
const ProtectedEditViewPage = lazy(
|
1282
|
-
() => import("./EditViewPage-
|
1678
|
+
() => import("./EditViewPage-8mOu02ji.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1283
1679
|
);
|
1284
1680
|
const ProtectedListViewPage = lazy(
|
1285
|
-
() => import("./ListViewPage-
|
1681
|
+
() => import("./ListViewPage-CRXONXwZ.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1286
1682
|
);
|
1287
1683
|
const ProtectedListConfiguration = lazy(
|
1288
|
-
() => import("./ListConfigurationPage-
|
1684
|
+
() => import("./ListConfigurationPage-BcycI8Lw.mjs").then((mod) => ({
|
1289
1685
|
default: mod.ProtectedListConfiguration
|
1290
1686
|
}))
|
1291
1687
|
);
|
1292
1688
|
const ProtectedEditConfigurationPage = lazy(
|
1293
|
-
() => import("./EditConfigurationPage-
|
1689
|
+
() => import("./EditConfigurationPage-tVCJ5vWC.mjs").then((mod) => ({
|
1294
1690
|
default: mod.ProtectedEditConfigurationPage
|
1295
1691
|
}))
|
1296
1692
|
);
|
1297
1693
|
const ProtectedComponentConfigurationPage = lazy(
|
1298
|
-
() => import("./ComponentConfigurationPage-
|
1694
|
+
() => import("./ComponentConfigurationPage-CQroR9Qk.mjs").then((mod) => ({
|
1299
1695
|
default: mod.ProtectedComponentConfigurationPage
|
1300
1696
|
}))
|
1301
1697
|
);
|
1302
1698
|
const NoPermissions = lazy(
|
1303
|
-
() => import("./NoPermissionsPage-
|
1699
|
+
() => import("./NoPermissionsPage-B4sD7Ble.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1304
1700
|
);
|
1305
1701
|
const NoContentType = lazy(
|
1306
|
-
() => import("./NoContentTypePage-
|
1702
|
+
() => import("./NoContentTypePage-ukzFRF3z.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1307
1703
|
);
|
1308
1704
|
const CollectionTypePages = () => {
|
1309
1705
|
const { collectionType } = useParams();
|
@@ -1417,12 +1813,14 @@ const DocumentActionButton = (action) => {
|
|
1417
1813
|
/* @__PURE__ */ jsx(
|
1418
1814
|
Button,
|
1419
1815
|
{
|
1420
|
-
flex:
|
1816
|
+
flex: "auto",
|
1421
1817
|
startIcon: action.icon,
|
1422
1818
|
disabled: action.disabled,
|
1423
1819
|
onClick: handleClick(action),
|
1424
1820
|
justifyContent: "center",
|
1425
1821
|
variant: action.variant || "default",
|
1822
|
+
paddingTop: "7px",
|
1823
|
+
paddingBottom: "7px",
|
1426
1824
|
children: action.label
|
1427
1825
|
}
|
1428
1826
|
),
|
@@ -1430,7 +1828,7 @@ const DocumentActionButton = (action) => {
|
|
1430
1828
|
DocumentActionConfirmDialog,
|
1431
1829
|
{
|
1432
1830
|
...action.dialog,
|
1433
|
-
variant: action.variant,
|
1831
|
+
variant: action.dialog?.variant ?? action.variant,
|
1434
1832
|
isOpen: dialogId === action.id,
|
1435
1833
|
onClose: handleClose
|
1436
1834
|
}
|
@@ -1487,9 +1885,9 @@ const DocumentActionsMenu = ({
|
|
1487
1885
|
disabled: isDisabled,
|
1488
1886
|
size: "S",
|
1489
1887
|
endIcon: null,
|
1490
|
-
paddingTop: "
|
1491
|
-
paddingLeft: "
|
1492
|
-
paddingRight: "
|
1888
|
+
paddingTop: "4px",
|
1889
|
+
paddingLeft: "7px",
|
1890
|
+
paddingRight: "7px",
|
1493
1891
|
variant,
|
1494
1892
|
children: [
|
1495
1893
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1500,7 +1898,7 @@ const DocumentActionsMenu = ({
|
|
1500
1898
|
]
|
1501
1899
|
}
|
1502
1900
|
),
|
1503
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1901
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1504
1902
|
actions2.map((action) => {
|
1505
1903
|
return /* @__PURE__ */ jsx(
|
1506
1904
|
Menu.Item,
|
@@ -1509,10 +1907,25 @@ const DocumentActionsMenu = ({
|
|
1509
1907
|
onSelect: handleClick(action),
|
1510
1908
|
display: "block",
|
1511
1909
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1512
|
-
/* @__PURE__ */ jsxs(
|
1513
|
-
|
1514
|
-
|
1515
|
-
|
1910
|
+
/* @__PURE__ */ jsxs(
|
1911
|
+
Flex,
|
1912
|
+
{
|
1913
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1914
|
+
gap: 2,
|
1915
|
+
tag: "span",
|
1916
|
+
children: [
|
1917
|
+
/* @__PURE__ */ jsx(
|
1918
|
+
Flex,
|
1919
|
+
{
|
1920
|
+
tag: "span",
|
1921
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1922
|
+
children: action.icon
|
1923
|
+
}
|
1924
|
+
),
|
1925
|
+
action.label
|
1926
|
+
]
|
1927
|
+
}
|
1928
|
+
),
|
1516
1929
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1517
1930
|
Flex,
|
1518
1931
|
{
|
@@ -1609,11 +2022,11 @@ const DocumentActionConfirmDialog = ({
|
|
1609
2022
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1610
2023
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1611
2024
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1612
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2025
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1613
2026
|
id: "app.components.Button.cancel",
|
1614
2027
|
defaultMessage: "Cancel"
|
1615
2028
|
}) }) }),
|
1616
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2029
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1617
2030
|
id: "app.components.Button.confirm",
|
1618
2031
|
defaultMessage: "Confirm"
|
1619
2032
|
}) })
|
@@ -1652,13 +2065,17 @@ const PublishAction$1 = ({
|
|
1652
2065
|
const navigate = useNavigate();
|
1653
2066
|
const { toggleNotification } = useNotification();
|
1654
2067
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2068
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1655
2069
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1656
2070
|
const { formatMessage } = useIntl();
|
1657
|
-
const { canPublish
|
1658
|
-
"PublishAction",
|
1659
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1660
|
-
);
|
2071
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1661
2072
|
const { publish } = useDocumentActions();
|
2073
|
+
const [
|
2074
|
+
countDraftRelations,
|
2075
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2076
|
+
] = useLazyGetDraftRelationCountQuery();
|
2077
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2078
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1662
2079
|
const [{ query, rawQuery }] = useQueryParams();
|
1663
2080
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1664
2081
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1667,62 +2084,144 @@ const PublishAction$1 = ({
|
|
1667
2084
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1668
2085
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1669
2086
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
1670
|
-
|
1671
|
-
|
1672
|
-
|
1673
|
-
|
1674
|
-
|
1675
|
-
|
1676
|
-
|
1677
|
-
|
1678
|
-
|
2087
|
+
React.useEffect(() => {
|
2088
|
+
if (isErrorDraftRelations) {
|
2089
|
+
toggleNotification({
|
2090
|
+
type: "danger",
|
2091
|
+
message: formatMessage({
|
2092
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2093
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2094
|
+
})
|
2095
|
+
});
|
2096
|
+
}
|
2097
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2098
|
+
React.useEffect(() => {
|
2099
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2100
|
+
const extractDraftRelations = (data) => {
|
2101
|
+
const relations = data.connect || [];
|
2102
|
+
relations.forEach((relation) => {
|
2103
|
+
if (relation.status === "draft") {
|
2104
|
+
localDraftRelations.add(relation.id);
|
2105
|
+
}
|
2106
|
+
});
|
2107
|
+
};
|
2108
|
+
const traverseAndExtract = (data) => {
|
2109
|
+
Object.entries(data).forEach(([key, value]) => {
|
2110
|
+
if (key === "connect" && Array.isArray(value)) {
|
2111
|
+
extractDraftRelations({ connect: value });
|
2112
|
+
} else if (typeof value === "object" && value !== null) {
|
2113
|
+
traverseAndExtract(value);
|
2114
|
+
}
|
2115
|
+
});
|
2116
|
+
};
|
2117
|
+
if (!documentId || modified) {
|
2118
|
+
traverseAndExtract(formValues);
|
2119
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2120
|
+
}
|
2121
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2122
|
+
React.useEffect(() => {
|
2123
|
+
if (!document || !document.documentId || isListView) {
|
2124
|
+
return;
|
2125
|
+
}
|
2126
|
+
const fetchDraftRelationsCount = async () => {
|
2127
|
+
const { data, error } = await countDraftRelations({
|
2128
|
+
collectionType,
|
2129
|
+
model,
|
2130
|
+
documentId,
|
2131
|
+
params
|
2132
|
+
});
|
2133
|
+
if (error) {
|
2134
|
+
throw error;
|
2135
|
+
}
|
2136
|
+
if (data) {
|
2137
|
+
setServerCountOfDraftRelations(data.data);
|
2138
|
+
}
|
2139
|
+
};
|
2140
|
+
fetchDraftRelationsCount();
|
2141
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2142
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2143
|
+
if (!schema?.options?.draftAndPublish) {
|
2144
|
+
return null;
|
2145
|
+
}
|
2146
|
+
const performPublish = async () => {
|
2147
|
+
setSubmitting(true);
|
2148
|
+
try {
|
2149
|
+
const { errors } = await validate(true, {
|
2150
|
+
status: "published"
|
2151
|
+
});
|
2152
|
+
if (errors) {
|
2153
|
+
toggleNotification({
|
2154
|
+
type: "danger",
|
2155
|
+
message: formatMessage({
|
2156
|
+
id: "content-manager.validation.error",
|
2157
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2158
|
+
})
|
2159
|
+
});
|
2160
|
+
return;
|
2161
|
+
}
|
2162
|
+
const res = await publish(
|
2163
|
+
{
|
2164
|
+
collectionType,
|
2165
|
+
model,
|
2166
|
+
documentId,
|
2167
|
+
params
|
2168
|
+
},
|
2169
|
+
formValues
|
2170
|
+
);
|
2171
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2172
|
+
navigate({
|
2173
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2174
|
+
search: rawQuery
|
2175
|
+
});
|
2176
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2177
|
+
setErrors(formatValidationErrors(res.error));
|
2178
|
+
}
|
2179
|
+
} finally {
|
2180
|
+
setSubmitting(false);
|
2181
|
+
}
|
2182
|
+
};
|
2183
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2184
|
+
const enableDraftRelationsCount = false;
|
2185
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2186
|
+
return {
|
2187
|
+
/**
|
2188
|
+
* Disabled when:
|
2189
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2190
|
+
* - the form is submitting
|
1679
2191
|
* - the active tab is the published tab
|
1680
2192
|
* - the document is already published & not modified
|
1681
2193
|
* - the document is being created & not modified
|
1682
2194
|
* - the user doesn't have the permission to publish
|
1683
|
-
* - the user doesn't have the permission to create a new document
|
1684
|
-
* - the user doesn't have the permission to update the document
|
1685
2195
|
*/
|
1686
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2196
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1687
2197
|
label: formatMessage({
|
1688
2198
|
id: "app.utils.publish",
|
1689
2199
|
defaultMessage: "Publish"
|
1690
2200
|
}),
|
1691
2201
|
onClick: async () => {
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
1702
|
-
|
1703
|
-
|
1704
|
-
|
1705
|
-
|
1706
|
-
|
1707
|
-
|
1708
|
-
|
1709
|
-
documentId,
|
1710
|
-
params
|
1711
|
-
},
|
1712
|
-
formValues
|
1713
|
-
);
|
1714
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1715
|
-
navigate({
|
1716
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1717
|
-
search: rawQuery
|
1718
|
-
});
|
1719
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1720
|
-
setErrors(formatValidationErrors(res.error));
|
2202
|
+
await performPublish();
|
2203
|
+
},
|
2204
|
+
dialog: hasDraftRelations ? {
|
2205
|
+
type: "dialog",
|
2206
|
+
variant: "danger",
|
2207
|
+
footer: null,
|
2208
|
+
title: formatMessage({
|
2209
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2210
|
+
defaultMessage: "Confirmation"
|
2211
|
+
}),
|
2212
|
+
content: formatMessage(
|
2213
|
+
{
|
2214
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2215
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2216
|
+
},
|
2217
|
+
{
|
2218
|
+
count: totalDraftRelations
|
1721
2219
|
}
|
1722
|
-
|
1723
|
-
|
2220
|
+
),
|
2221
|
+
onConfirm: async () => {
|
2222
|
+
await performPublish();
|
1724
2223
|
}
|
1725
|
-
}
|
2224
|
+
} : void 0
|
1726
2225
|
};
|
1727
2226
|
};
|
1728
2227
|
PublishAction$1.type = "publish";
|
@@ -1738,10 +2237,6 @@ const UpdateAction = ({
|
|
1738
2237
|
const cloneMatch = useMatch(CLONE_PATH);
|
1739
2238
|
const isCloning = cloneMatch !== null;
|
1740
2239
|
const { formatMessage } = useIntl();
|
1741
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1742
|
-
canCreate: canCreate2,
|
1743
|
-
canUpdate: canUpdate2
|
1744
|
-
}));
|
1745
2240
|
const { create, update, clone } = useDocumentActions();
|
1746
2241
|
const [{ query, rawQuery }] = useQueryParams();
|
1747
2242
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1758,10 +2253,8 @@ const UpdateAction = ({
|
|
1758
2253
|
* - the form is submitting
|
1759
2254
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1760
2255
|
* - the active tab is the published tab
|
1761
|
-
* - the user doesn't have the permission to create a new document
|
1762
|
-
* - the user doesn't have the permission to update the document
|
1763
2256
|
*/
|
1764
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2257
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1765
2258
|
label: formatMessage({
|
1766
2259
|
id: "content-manager.containers.Edit.save",
|
1767
2260
|
defaultMessage: "Save"
|
@@ -1769,7 +2262,9 @@ const UpdateAction = ({
|
|
1769
2262
|
onClick: async () => {
|
1770
2263
|
setSubmitting(true);
|
1771
2264
|
try {
|
1772
|
-
const { errors } = await validate(
|
2265
|
+
const { errors } = await validate(true, {
|
2266
|
+
status: "draft"
|
2267
|
+
});
|
1773
2268
|
if (errors) {
|
1774
2269
|
toggleNotification({
|
1775
2270
|
type: "danger",
|
@@ -1790,10 +2285,13 @@ const UpdateAction = ({
|
|
1790
2285
|
document
|
1791
2286
|
);
|
1792
2287
|
if ("data" in res) {
|
1793
|
-
navigate(
|
1794
|
-
|
1795
|
-
|
1796
|
-
|
2288
|
+
navigate(
|
2289
|
+
{
|
2290
|
+
pathname: `../${res.data.documentId}`,
|
2291
|
+
search: rawQuery
|
2292
|
+
},
|
2293
|
+
{ relative: "path" }
|
2294
|
+
);
|
1797
2295
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1798
2296
|
setErrors(formatValidationErrors(res.error));
|
1799
2297
|
}
|
@@ -1821,10 +2319,13 @@ const UpdateAction = ({
|
|
1821
2319
|
document
|
1822
2320
|
);
|
1823
2321
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1824
|
-
navigate(
|
1825
|
-
|
1826
|
-
|
1827
|
-
|
2322
|
+
navigate(
|
2323
|
+
{
|
2324
|
+
pathname: `../${res.data.documentId}`,
|
2325
|
+
search: rawQuery
|
2326
|
+
},
|
2327
|
+
{ replace: true, relative: "path" }
|
2328
|
+
);
|
1828
2329
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1829
2330
|
setErrors(formatValidationErrors(res.error));
|
1830
2331
|
}
|
@@ -1868,7 +2369,7 @@ const UnpublishAction$1 = ({
|
|
1868
2369
|
id: "app.utils.unpublish",
|
1869
2370
|
defaultMessage: "Unpublish"
|
1870
2371
|
}),
|
1871
|
-
icon: /* @__PURE__ */ jsx(
|
2372
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1872
2373
|
onClick: async () => {
|
1873
2374
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1874
2375
|
if (!documentId) {
|
@@ -1980,7 +2481,7 @@ const DiscardAction = ({
|
|
1980
2481
|
id: "content-manager.actions.discard.label",
|
1981
2482
|
defaultMessage: "Discard changes"
|
1982
2483
|
}),
|
1983
|
-
icon: /* @__PURE__ */ jsx(
|
2484
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1984
2485
|
position: ["panel", "table-row"],
|
1985
2486
|
variant: "danger",
|
1986
2487
|
dialog: {
|
@@ -2008,11 +2509,6 @@ const DiscardAction = ({
|
|
2008
2509
|
};
|
2009
2510
|
};
|
2010
2511
|
DiscardAction.type = "discard";
|
2011
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2012
|
-
path {
|
2013
|
-
fill: currentColor;
|
2014
|
-
}
|
2015
|
-
`;
|
2016
2512
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2017
2513
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2018
2514
|
const RelativeTime = React.forwardRef(
|
@@ -2060,7 +2556,7 @@ const getDisplayName = ({
|
|
2060
2556
|
};
|
2061
2557
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2062
2558
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2063
|
-
const statusVariant = status === "draft" ? "
|
2559
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2064
2560
|
return /* @__PURE__ */ jsx(Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2065
2561
|
};
|
2066
2562
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2070,23 +2566,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2070
2566
|
id: "content-manager.containers.edit.title.new",
|
2071
2567
|
defaultMessage: "Create an entry"
|
2072
2568
|
}) : documentTitle;
|
2073
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2569
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2074
2570
|
/* @__PURE__ */ jsx(BackButton, {}),
|
2075
|
-
/* @__PURE__ */ jsxs(
|
2076
|
-
|
2077
|
-
{
|
2078
|
-
|
2079
|
-
|
2080
|
-
paddingTop: 1,
|
2081
|
-
gap: "80px",
|
2082
|
-
alignItems: "flex-start",
|
2083
|
-
children: [
|
2084
|
-
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2085
|
-
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2086
|
-
]
|
2087
|
-
}
|
2088
|
-
),
|
2089
|
-
status ? /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
|
2571
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2572
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2573
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2574
|
+
] }),
|
2575
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2090
2576
|
] });
|
2091
2577
|
};
|
2092
2578
|
const HeaderToolbar = () => {
|
@@ -2169,12 +2655,12 @@ const Information = ({ activeTab }) => {
|
|
2169
2655
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2170
2656
|
label: formatMessage({
|
2171
2657
|
id: "content-manager.containers.edit.information.last-published.label",
|
2172
|
-
defaultMessage: "
|
2658
|
+
defaultMessage: "Published"
|
2173
2659
|
}),
|
2174
2660
|
value: formatMessage(
|
2175
2661
|
{
|
2176
2662
|
id: "content-manager.containers.edit.information.last-published.value",
|
2177
|
-
defaultMessage: `
|
2663
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2178
2664
|
},
|
2179
2665
|
{
|
2180
2666
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2187,12 +2673,12 @@ const Information = ({ activeTab }) => {
|
|
2187
2673
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2188
2674
|
label: formatMessage({
|
2189
2675
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2190
|
-
defaultMessage: "
|
2676
|
+
defaultMessage: "Updated"
|
2191
2677
|
}),
|
2192
2678
|
value: formatMessage(
|
2193
2679
|
{
|
2194
2680
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2195
|
-
defaultMessage: `
|
2681
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2196
2682
|
},
|
2197
2683
|
{
|
2198
2684
|
time: /* @__PURE__ */ jsx(
|
@@ -2210,12 +2696,12 @@ const Information = ({ activeTab }) => {
|
|
2210
2696
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2211
2697
|
label: formatMessage({
|
2212
2698
|
id: "content-manager.containers.edit.information.document.label",
|
2213
|
-
defaultMessage: "
|
2699
|
+
defaultMessage: "Created"
|
2214
2700
|
}),
|
2215
2701
|
value: formatMessage(
|
2216
2702
|
{
|
2217
2703
|
id: "content-manager.containers.edit.information.document.value",
|
2218
|
-
defaultMessage: `
|
2704
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2219
2705
|
},
|
2220
2706
|
{
|
2221
2707
|
time: /* @__PURE__ */ jsx(
|
@@ -2253,25 +2739,77 @@ const Information = ({ activeTab }) => {
|
|
2253
2739
|
);
|
2254
2740
|
};
|
2255
2741
|
const HeaderActions = ({ actions: actions2 }) => {
|
2256
|
-
|
2257
|
-
|
2742
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2743
|
+
const handleClick = (action) => async (e) => {
|
2744
|
+
if (!("options" in action)) {
|
2745
|
+
const { onClick = () => false, dialog, id } = action;
|
2746
|
+
const muteDialog = await onClick(e);
|
2747
|
+
if (dialog && !muteDialog) {
|
2748
|
+
e.preventDefault();
|
2749
|
+
setDialogId(id);
|
2750
|
+
}
|
2751
|
+
}
|
2752
|
+
};
|
2753
|
+
const handleClose = () => {
|
2754
|
+
setDialogId(null);
|
2755
|
+
};
|
2756
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2757
|
+
if (action.options) {
|
2258
2758
|
return /* @__PURE__ */ jsx(
|
2259
2759
|
SingleSelect,
|
2260
2760
|
{
|
2261
2761
|
size: "S",
|
2262
|
-
disabled: action.disabled,
|
2263
|
-
"aria-label": action.label,
|
2264
2762
|
onChange: action.onSelect,
|
2265
|
-
|
2763
|
+
"aria-label": action.label,
|
2764
|
+
...action,
|
2266
2765
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2267
2766
|
},
|
2268
2767
|
action.id
|
2269
2768
|
);
|
2270
2769
|
} else {
|
2271
|
-
|
2770
|
+
if (action.type === "icon") {
|
2771
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2772
|
+
/* @__PURE__ */ jsx(
|
2773
|
+
IconButton,
|
2774
|
+
{
|
2775
|
+
disabled: action.disabled,
|
2776
|
+
label: action.label,
|
2777
|
+
size: "S",
|
2778
|
+
onClick: handleClick(action),
|
2779
|
+
children: action.icon
|
2780
|
+
}
|
2781
|
+
),
|
2782
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2783
|
+
HeaderActionDialog,
|
2784
|
+
{
|
2785
|
+
...action.dialog,
|
2786
|
+
isOpen: dialogId === action.id,
|
2787
|
+
onClose: handleClose
|
2788
|
+
}
|
2789
|
+
) : null
|
2790
|
+
] }, action.id);
|
2791
|
+
}
|
2272
2792
|
}
|
2273
2793
|
}) });
|
2274
2794
|
};
|
2795
|
+
const HeaderActionDialog = ({
|
2796
|
+
onClose,
|
2797
|
+
onCancel,
|
2798
|
+
title,
|
2799
|
+
content: Content,
|
2800
|
+
isOpen
|
2801
|
+
}) => {
|
2802
|
+
const handleClose = async () => {
|
2803
|
+
if (onCancel) {
|
2804
|
+
await onCancel();
|
2805
|
+
}
|
2806
|
+
onClose();
|
2807
|
+
};
|
2808
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2809
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2810
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2811
|
+
] }) });
|
2812
|
+
};
|
2275
2813
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2276
2814
|
const navigate = useNavigate();
|
2277
2815
|
const { formatMessage } = useIntl();
|
@@ -2312,12 +2850,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2312
2850
|
const { delete: deleteAction } = useDocumentActions();
|
2313
2851
|
const { toggleNotification } = useNotification();
|
2314
2852
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2853
|
+
const isLocalized = document?.locale != null;
|
2315
2854
|
return {
|
2316
2855
|
disabled: !canDelete || !document,
|
2317
|
-
label: formatMessage(
|
2318
|
-
|
2319
|
-
|
2320
|
-
|
2856
|
+
label: formatMessage(
|
2857
|
+
{
|
2858
|
+
id: "content-manager.actions.delete.label",
|
2859
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2860
|
+
},
|
2861
|
+
{ isLocalized }
|
2862
|
+
),
|
2321
2863
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2322
2864
|
dialog: {
|
2323
2865
|
type: "dialog",
|
@@ -2351,425 +2893,123 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2351
2893
|
return;
|
2352
2894
|
}
|
2353
2895
|
const res = await deleteAction({
|
2354
|
-
documentId,
|
2355
|
-
model,
|
2356
|
-
collectionType,
|
2357
|
-
params: {
|
2358
|
-
locale: "*"
|
2359
|
-
}
|
2360
|
-
});
|
2361
|
-
if (!("error" in res)) {
|
2362
|
-
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2363
|
-
}
|
2364
|
-
} finally {
|
2365
|
-
if (!listViewPathMatch) {
|
2366
|
-
setSubmitting(false);
|
2367
|
-
}
|
2368
|
-
}
|
2369
|
-
}
|
2370
|
-
},
|
2371
|
-
variant: "danger",
|
2372
|
-
position: ["header", "table-row"]
|
2373
|
-
};
|
2374
|
-
};
|
2375
|
-
DeleteAction$1.type = "delete";
|
2376
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2377
|
-
const Panels = () => {
|
2378
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2379
|
-
const [
|
2380
|
-
{
|
2381
|
-
query: { status }
|
2382
|
-
}
|
2383
|
-
] = useQueryParams({
|
2384
|
-
status: "draft"
|
2385
|
-
});
|
2386
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2387
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2388
|
-
const props = {
|
2389
|
-
activeTab: status,
|
2390
|
-
model,
|
2391
|
-
documentId: id,
|
2392
|
-
document: isCloning ? void 0 : document,
|
2393
|
-
meta: isCloning ? void 0 : meta,
|
2394
|
-
collectionType
|
2395
|
-
};
|
2396
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2397
|
-
DescriptionComponentRenderer,
|
2398
|
-
{
|
2399
|
-
props,
|
2400
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2401
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2402
|
-
}
|
2403
|
-
) });
|
2404
|
-
};
|
2405
|
-
const ActionsPanel = () => {
|
2406
|
-
const { formatMessage } = useIntl();
|
2407
|
-
return {
|
2408
|
-
title: formatMessage({
|
2409
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2410
|
-
defaultMessage: "Document"
|
2411
|
-
}),
|
2412
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2413
|
-
};
|
2414
|
-
};
|
2415
|
-
ActionsPanel.type = "actions";
|
2416
|
-
const ActionsPanelContent = () => {
|
2417
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2418
|
-
const [
|
2419
|
-
{
|
2420
|
-
query: { status = "draft" }
|
2421
|
-
}
|
2422
|
-
] = useQueryParams();
|
2423
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2424
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2425
|
-
const props = {
|
2426
|
-
activeTab: status,
|
2427
|
-
model,
|
2428
|
-
documentId: id,
|
2429
|
-
document: isCloning ? void 0 : document,
|
2430
|
-
meta: isCloning ? void 0 : meta,
|
2431
|
-
collectionType
|
2432
|
-
};
|
2433
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2434
|
-
/* @__PURE__ */ jsx(
|
2435
|
-
DescriptionComponentRenderer,
|
2436
|
-
{
|
2437
|
-
props,
|
2438
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2439
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2440
|
-
}
|
2441
|
-
),
|
2442
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2443
|
-
] });
|
2444
|
-
};
|
2445
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2446
|
-
return /* @__PURE__ */ jsxs(
|
2447
|
-
Flex,
|
2448
|
-
{
|
2449
|
-
ref,
|
2450
|
-
tag: "aside",
|
2451
|
-
"aria-labelledby": "additional-information",
|
2452
|
-
background: "neutral0",
|
2453
|
-
borderColor: "neutral150",
|
2454
|
-
hasRadius: true,
|
2455
|
-
paddingBottom: 4,
|
2456
|
-
paddingLeft: 4,
|
2457
|
-
paddingRight: 4,
|
2458
|
-
paddingTop: 4,
|
2459
|
-
shadow: "tableShadow",
|
2460
|
-
gap: 3,
|
2461
|
-
direction: "column",
|
2462
|
-
justifyContent: "stretch",
|
2463
|
-
alignItems: "flex-start",
|
2464
|
-
children: [
|
2465
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2466
|
-
children
|
2467
|
-
]
|
2468
|
-
}
|
2469
|
-
);
|
2470
|
-
});
|
2471
|
-
const HOOKS = {
|
2472
|
-
/**
|
2473
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2474
|
-
* @constant
|
2475
|
-
* @type {string}
|
2476
|
-
*/
|
2477
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2478
|
-
/**
|
2479
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2480
|
-
* @constant
|
2481
|
-
* @type {string}
|
2482
|
-
*/
|
2483
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2484
|
-
/**
|
2485
|
-
* Hook that allows to mutate the CM's edit view layout
|
2486
|
-
* @constant
|
2487
|
-
* @type {string}
|
2488
|
-
*/
|
2489
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2490
|
-
/**
|
2491
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2492
|
-
* @constant
|
2493
|
-
* @type {string}
|
2494
|
-
*/
|
2495
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2496
|
-
};
|
2497
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2498
|
-
endpoints: (builder) => ({
|
2499
|
-
getContentTypeConfiguration: builder.query({
|
2500
|
-
query: (uid) => ({
|
2501
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2502
|
-
method: "GET"
|
2503
|
-
}),
|
2504
|
-
transformResponse: (response) => response.data,
|
2505
|
-
providesTags: (_result, _error, uid) => [
|
2506
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2507
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2508
|
-
]
|
2509
|
-
}),
|
2510
|
-
getAllContentTypeSettings: builder.query({
|
2511
|
-
query: () => "/content-manager/content-types-settings",
|
2512
|
-
transformResponse: (response) => response.data,
|
2513
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2514
|
-
}),
|
2515
|
-
updateContentTypeConfiguration: builder.mutation({
|
2516
|
-
query: ({ uid, ...body }) => ({
|
2517
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2518
|
-
method: "PUT",
|
2519
|
-
data: body
|
2520
|
-
}),
|
2521
|
-
transformResponse: (response) => response.data,
|
2522
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2523
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2524
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2525
|
-
// Is this necessary?
|
2526
|
-
{ type: "InitialData" }
|
2527
|
-
]
|
2528
|
-
})
|
2529
|
-
})
|
2530
|
-
});
|
2531
|
-
const {
|
2532
|
-
useGetContentTypeConfigurationQuery,
|
2533
|
-
useGetAllContentTypeSettingsQuery,
|
2534
|
-
useUpdateContentTypeConfigurationMutation
|
2535
|
-
} = contentTypesApi;
|
2536
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2537
|
-
const { type } = attribute;
|
2538
|
-
if (type === "relation") {
|
2539
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2540
|
-
}
|
2541
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2542
|
-
};
|
2543
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2544
|
-
if (!mainFieldName) {
|
2545
|
-
return void 0;
|
2546
|
-
}
|
2547
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2548
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2549
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2550
|
-
);
|
2551
|
-
return {
|
2552
|
-
name: mainFieldName,
|
2553
|
-
type: mainFieldType ?? "string"
|
2554
|
-
};
|
2555
|
-
};
|
2556
|
-
const DEFAULT_SETTINGS = {
|
2557
|
-
bulkable: false,
|
2558
|
-
filterable: false,
|
2559
|
-
searchable: false,
|
2560
|
-
pagination: false,
|
2561
|
-
defaultSortBy: "",
|
2562
|
-
defaultSortOrder: "asc",
|
2563
|
-
mainField: "id",
|
2564
|
-
pageSize: 10
|
2565
|
-
};
|
2566
|
-
const useDocumentLayout = (model) => {
|
2567
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2568
|
-
const [{ query }] = useQueryParams();
|
2569
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2570
|
-
const { toggleNotification } = useNotification();
|
2571
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2572
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2573
|
-
const {
|
2574
|
-
data,
|
2575
|
-
isLoading: isLoadingConfigs,
|
2576
|
-
error,
|
2577
|
-
isFetching: isFetchingConfigs
|
2578
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2579
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2580
|
-
React.useEffect(() => {
|
2581
|
-
if (error) {
|
2582
|
-
toggleNotification({
|
2583
|
-
type: "danger",
|
2584
|
-
message: formatAPIError(error)
|
2585
|
-
});
|
2586
|
-
}
|
2587
|
-
}, [error, formatAPIError, toggleNotification]);
|
2588
|
-
const editLayout = React.useMemo(
|
2589
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2590
|
-
layout: [],
|
2591
|
-
components: {},
|
2592
|
-
metadatas: {},
|
2593
|
-
options: {},
|
2594
|
-
settings: DEFAULT_SETTINGS
|
2595
|
-
},
|
2596
|
-
[data, isLoading, schemas, schema, components]
|
2597
|
-
);
|
2598
|
-
const listLayout = React.useMemo(() => {
|
2599
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2600
|
-
layout: [],
|
2601
|
-
metadatas: {},
|
2602
|
-
options: {},
|
2603
|
-
settings: DEFAULT_SETTINGS
|
2604
|
-
};
|
2605
|
-
}, [data, isLoading, schemas, schema, components]);
|
2606
|
-
const { layout: edit } = React.useMemo(
|
2607
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2608
|
-
layout: editLayout,
|
2609
|
-
query
|
2610
|
-
}),
|
2611
|
-
[editLayout, query, runHookWaterfall]
|
2612
|
-
);
|
2613
|
-
return {
|
2614
|
-
error,
|
2615
|
-
isLoading,
|
2616
|
-
edit,
|
2617
|
-
list: listLayout
|
2618
|
-
};
|
2619
|
-
};
|
2620
|
-
const useDocLayout = () => {
|
2621
|
-
const { model } = useDoc();
|
2622
|
-
return useDocumentLayout(model);
|
2623
|
-
};
|
2624
|
-
const formatEditLayout = (data, {
|
2625
|
-
schemas,
|
2626
|
-
schema,
|
2627
|
-
components
|
2628
|
-
}) => {
|
2629
|
-
let currentPanelIndex = 0;
|
2630
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2631
|
-
data.contentType.layouts.edit,
|
2632
|
-
schema?.attributes,
|
2633
|
-
data.contentType.metadatas,
|
2634
|
-
{ configurations: data.components, schemas: components },
|
2635
|
-
schemas
|
2636
|
-
).reduce((panels, row) => {
|
2637
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2638
|
-
panels.push([row]);
|
2639
|
-
currentPanelIndex += 2;
|
2640
|
-
} else {
|
2641
|
-
if (!panels[currentPanelIndex]) {
|
2642
|
-
panels.push([]);
|
2643
|
-
}
|
2644
|
-
panels[currentPanelIndex].push(row);
|
2645
|
-
}
|
2646
|
-
return panels;
|
2647
|
-
}, []);
|
2648
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2649
|
-
(acc, [uid, configuration]) => {
|
2650
|
-
acc[uid] = {
|
2651
|
-
layout: convertEditLayoutToFieldLayouts(
|
2652
|
-
configuration.layouts.edit,
|
2653
|
-
components[uid].attributes,
|
2654
|
-
configuration.metadatas
|
2655
|
-
),
|
2656
|
-
settings: {
|
2657
|
-
...configuration.settings,
|
2658
|
-
icon: components[uid].info.icon,
|
2659
|
-
displayName: components[uid].info.displayName
|
2896
|
+
documentId,
|
2897
|
+
model,
|
2898
|
+
collectionType,
|
2899
|
+
params: {
|
2900
|
+
locale: "*"
|
2901
|
+
}
|
2902
|
+
});
|
2903
|
+
if (!("error" in res)) {
|
2904
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2905
|
+
}
|
2906
|
+
} finally {
|
2907
|
+
if (!listViewPathMatch) {
|
2908
|
+
setSubmitting(false);
|
2909
|
+
}
|
2660
2910
|
}
|
2661
|
-
}
|
2662
|
-
return acc;
|
2663
|
-
},
|
2664
|
-
{}
|
2665
|
-
);
|
2666
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2667
|
-
(acc, [attribute, metadata]) => {
|
2668
|
-
return {
|
2669
|
-
...acc,
|
2670
|
-
[attribute]: metadata.edit
|
2671
|
-
};
|
2672
|
-
},
|
2673
|
-
{}
|
2674
|
-
);
|
2675
|
-
return {
|
2676
|
-
layout: panelledEditAttributes,
|
2677
|
-
components: componentEditAttributes,
|
2678
|
-
metadatas: editMetadatas,
|
2679
|
-
settings: {
|
2680
|
-
...data.contentType.settings,
|
2681
|
-
displayName: schema?.info.displayName
|
2911
|
+
}
|
2682
2912
|
},
|
2683
|
-
|
2684
|
-
|
2685
|
-
...schema?.pluginOptions,
|
2686
|
-
...data.contentType.options
|
2687
|
-
}
|
2913
|
+
variant: "danger",
|
2914
|
+
position: ["header", "table-row"]
|
2688
2915
|
};
|
2689
2916
|
};
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2693
|
-
|
2694
|
-
|
2695
|
-
|
2696
|
-
}
|
2697
|
-
|
2698
|
-
|
2699
|
-
|
2700
|
-
|
2701
|
-
|
2702
|
-
|
2703
|
-
|
2704
|
-
|
2705
|
-
|
2706
|
-
|
2707
|
-
|
2708
|
-
|
2709
|
-
|
2710
|
-
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
}
|
2717
|
-
}
|
2718
|
-
);
|
2917
|
+
DeleteAction$1.type = "delete";
|
2918
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2919
|
+
const Panels = () => {
|
2920
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2921
|
+
const [
|
2922
|
+
{
|
2923
|
+
query: { status }
|
2924
|
+
}
|
2925
|
+
] = useQueryParams({
|
2926
|
+
status: "draft"
|
2927
|
+
});
|
2928
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2929
|
+
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2930
|
+
const props = {
|
2931
|
+
activeTab: status,
|
2932
|
+
model,
|
2933
|
+
documentId: id,
|
2934
|
+
document: isCloning ? void 0 : document,
|
2935
|
+
meta: isCloning ? void 0 : meta,
|
2936
|
+
collectionType
|
2937
|
+
};
|
2938
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2939
|
+
DescriptionComponentRenderer,
|
2940
|
+
{
|
2941
|
+
props,
|
2942
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2943
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2944
|
+
}
|
2945
|
+
) });
|
2719
2946
|
};
|
2720
|
-
const
|
2721
|
-
|
2722
|
-
schema,
|
2723
|
-
components
|
2724
|
-
}) => {
|
2725
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2726
|
-
(acc, [attribute, metadata]) => {
|
2727
|
-
return {
|
2728
|
-
...acc,
|
2729
|
-
[attribute]: metadata.list
|
2730
|
-
};
|
2731
|
-
},
|
2732
|
-
{}
|
2733
|
-
);
|
2734
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2735
|
-
data.contentType.layouts.list,
|
2736
|
-
schema?.attributes,
|
2737
|
-
listMetadatas,
|
2738
|
-
{ configurations: data.components, schemas: components },
|
2739
|
-
schemas
|
2740
|
-
);
|
2947
|
+
const ActionsPanel = () => {
|
2948
|
+
const { formatMessage } = useIntl();
|
2741
2949
|
return {
|
2742
|
-
|
2743
|
-
|
2744
|
-
|
2745
|
-
|
2746
|
-
|
2747
|
-
...schema?.pluginOptions,
|
2748
|
-
...data.contentType.options
|
2749
|
-
}
|
2950
|
+
title: formatMessage({
|
2951
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2952
|
+
defaultMessage: "Entry"
|
2953
|
+
}),
|
2954
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2750
2955
|
};
|
2751
2956
|
};
|
2752
|
-
|
2753
|
-
|
2754
|
-
|
2755
|
-
|
2756
|
-
|
2957
|
+
ActionsPanel.type = "actions";
|
2958
|
+
const ActionsPanelContent = () => {
|
2959
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2960
|
+
const [
|
2961
|
+
{
|
2962
|
+
query: { status = "draft" }
|
2757
2963
|
}
|
2758
|
-
|
2759
|
-
|
2760
|
-
|
2761
|
-
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2964
|
+
] = useQueryParams();
|
2965
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2966
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2967
|
+
const props = {
|
2968
|
+
activeTab: status,
|
2969
|
+
model,
|
2970
|
+
documentId: id,
|
2971
|
+
document: isCloning ? void 0 : document,
|
2972
|
+
meta: isCloning ? void 0 : meta,
|
2973
|
+
collectionType
|
2974
|
+
};
|
2975
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2976
|
+
/* @__PURE__ */ jsx(
|
2977
|
+
DescriptionComponentRenderer,
|
2978
|
+
{
|
2979
|
+
props,
|
2980
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2981
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2982
|
+
}
|
2983
|
+
),
|
2984
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2985
|
+
] });
|
2772
2986
|
};
|
2987
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2988
|
+
return /* @__PURE__ */ jsxs(
|
2989
|
+
Flex,
|
2990
|
+
{
|
2991
|
+
ref,
|
2992
|
+
tag: "aside",
|
2993
|
+
"aria-labelledby": "additional-information",
|
2994
|
+
background: "neutral0",
|
2995
|
+
borderColor: "neutral150",
|
2996
|
+
hasRadius: true,
|
2997
|
+
paddingBottom: 4,
|
2998
|
+
paddingLeft: 4,
|
2999
|
+
paddingRight: 4,
|
3000
|
+
paddingTop: 4,
|
3001
|
+
shadow: "tableShadow",
|
3002
|
+
gap: 3,
|
3003
|
+
direction: "column",
|
3004
|
+
justifyContent: "stretch",
|
3005
|
+
alignItems: "flex-start",
|
3006
|
+
children: [
|
3007
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3008
|
+
children
|
3009
|
+
]
|
3010
|
+
}
|
3011
|
+
);
|
3012
|
+
});
|
2773
3013
|
const ConfirmBulkActionDialog = ({
|
2774
3014
|
onToggleDialog,
|
2775
3015
|
isOpen = false,
|
@@ -2777,7 +3017,7 @@ const ConfirmBulkActionDialog = ({
|
|
2777
3017
|
endAction
|
2778
3018
|
}) => {
|
2779
3019
|
const { formatMessage } = useIntl();
|
2780
|
-
return /* @__PURE__ */ jsx(Dialog.Root, {
|
3020
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2781
3021
|
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
2782
3022
|
id: "app.components.ConfirmDialog.title",
|
2783
3023
|
defaultMessage: "Confirmation"
|
@@ -2808,6 +3048,7 @@ const ConfirmDialogPublishAll = ({
|
|
2808
3048
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2809
3049
|
const { model, schema } = useDoc();
|
2810
3050
|
const [{ query }] = useQueryParams();
|
3051
|
+
const enableDraftRelationsCount = false;
|
2811
3052
|
const {
|
2812
3053
|
data: countDraftRelations = 0,
|
2813
3054
|
isLoading,
|
@@ -2819,7 +3060,7 @@ const ConfirmDialogPublishAll = ({
|
|
2819
3060
|
locale: query?.plugins?.i18n?.locale
|
2820
3061
|
},
|
2821
3062
|
{
|
2822
|
-
skip:
|
3063
|
+
skip: !enableDraftRelationsCount
|
2823
3064
|
}
|
2824
3065
|
);
|
2825
3066
|
React.useEffect(() => {
|
@@ -2898,7 +3139,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2898
3139
|
)
|
2899
3140
|
);
|
2900
3141
|
} else {
|
2901
|
-
messages.push(
|
3142
|
+
messages.push(
|
3143
|
+
...formatErrorMessages(
|
3144
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3145
|
+
value,
|
3146
|
+
currentKey,
|
3147
|
+
formatMessage
|
3148
|
+
)
|
3149
|
+
);
|
2902
3150
|
}
|
2903
3151
|
} else {
|
2904
3152
|
messages.push(
|
@@ -2997,7 +3245,7 @@ const SelectedEntriesTableContent = ({
|
|
2997
3245
|
status: row.status
|
2998
3246
|
}
|
2999
3247
|
) }),
|
3000
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3248
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3001
3249
|
IconButton,
|
3002
3250
|
{
|
3003
3251
|
tag: Link,
|
@@ -3020,9 +3268,10 @@ const SelectedEntriesTableContent = ({
|
|
3020
3268
|
),
|
3021
3269
|
target: "_blank",
|
3022
3270
|
marginLeft: "auto",
|
3023
|
-
|
3271
|
+
variant: "ghost",
|
3272
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3024
3273
|
}
|
3025
|
-
) })
|
3274
|
+
) }) })
|
3026
3275
|
] }, row.id)) })
|
3027
3276
|
] });
|
3028
3277
|
};
|
@@ -3059,7 +3308,13 @@ const SelectedEntriesModalContent = ({
|
|
3059
3308
|
);
|
3060
3309
|
const { rows, validationErrors } = React.useMemo(() => {
|
3061
3310
|
if (data.length > 0 && schema) {
|
3062
|
-
const validate = createYupSchema(
|
3311
|
+
const validate = createYupSchema(
|
3312
|
+
schema.attributes,
|
3313
|
+
components,
|
3314
|
+
// Since this is the "Publish" action, the validation
|
3315
|
+
// schema must enforce the rules for published entities
|
3316
|
+
{ status: "published" }
|
3317
|
+
);
|
3063
3318
|
const validationErrors2 = {};
|
3064
3319
|
const rows2 = data.map((entry) => {
|
3065
3320
|
try {
|
@@ -3409,7 +3664,7 @@ const TableActions = ({ document }) => {
|
|
3409
3664
|
DescriptionComponentRenderer,
|
3410
3665
|
{
|
3411
3666
|
props,
|
3412
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3667
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3413
3668
|
children: (actions2) => {
|
3414
3669
|
const tableRowActions = actions2.filter((action) => {
|
3415
3670
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3520,7 +3775,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3520
3775
|
}),
|
3521
3776
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3522
3777
|
footer: ({ onClose }) => {
|
3523
|
-
return /* @__PURE__ */ jsxs(
|
3778
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3524
3779
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3525
3780
|
id: "cancel",
|
3526
3781
|
defaultMessage: "Cancel"
|
@@ -3561,8 +3816,7 @@ class ContentManagerPlugin {
|
|
3561
3816
|
documentActions = [
|
3562
3817
|
...DEFAULT_ACTIONS,
|
3563
3818
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3564
|
-
...DEFAULT_HEADER_ACTIONS
|
3565
|
-
HistoryAction
|
3819
|
+
...DEFAULT_HEADER_ACTIONS
|
3566
3820
|
];
|
3567
3821
|
editViewSidePanels = [ActionsPanel];
|
3568
3822
|
headerActions = [];
|
@@ -3651,6 +3905,52 @@ const getPrintableType = (value) => {
|
|
3651
3905
|
}
|
3652
3906
|
return nativeType;
|
3653
3907
|
};
|
3908
|
+
const HistoryAction = ({ model, document }) => {
|
3909
|
+
const { formatMessage } = useIntl();
|
3910
|
+
const [{ query }] = useQueryParams();
|
3911
|
+
const navigate = useNavigate();
|
3912
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3913
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3914
|
+
return null;
|
3915
|
+
}
|
3916
|
+
return {
|
3917
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3918
|
+
label: formatMessage({
|
3919
|
+
id: "content-manager.history.document-action",
|
3920
|
+
defaultMessage: "Content History"
|
3921
|
+
}),
|
3922
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3923
|
+
disabled: (
|
3924
|
+
/**
|
3925
|
+
* The user is creating a new document.
|
3926
|
+
* It hasn't been saved yet, so there's no history to go to
|
3927
|
+
*/
|
3928
|
+
!document || /**
|
3929
|
+
* The document has been created but the current dimension has never been saved.
|
3930
|
+
* For example, the user is creating a new locale in an existing document,
|
3931
|
+
* so there's no history for the document in that locale
|
3932
|
+
*/
|
3933
|
+
!document.id || /**
|
3934
|
+
* History is only available for content types created by the user.
|
3935
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3936
|
+
* which start with `admin::` or `plugin::`
|
3937
|
+
*/
|
3938
|
+
!model.startsWith("api::")
|
3939
|
+
),
|
3940
|
+
position: "header"
|
3941
|
+
};
|
3942
|
+
};
|
3943
|
+
HistoryAction.type = "history";
|
3944
|
+
const historyAdmin = {
|
3945
|
+
bootstrap(app) {
|
3946
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3947
|
+
addDocumentAction((actions2) => {
|
3948
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3949
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3950
|
+
return actions2;
|
3951
|
+
});
|
3952
|
+
}
|
3953
|
+
};
|
3654
3954
|
const initialState = {
|
3655
3955
|
collectionTypeLinks: [],
|
3656
3956
|
components: [],
|
@@ -3706,7 +4006,7 @@ const index = {
|
|
3706
4006
|
app.router.addRoute({
|
3707
4007
|
path: "content-manager/*",
|
3708
4008
|
lazy: async () => {
|
3709
|
-
const { Layout } = await import("./layout-
|
4009
|
+
const { Layout } = await import("./layout-vzKSrr7p.mjs");
|
3710
4010
|
return {
|
3711
4011
|
Component: Layout
|
3712
4012
|
};
|
@@ -3715,10 +4015,15 @@ const index = {
|
|
3715
4015
|
});
|
3716
4016
|
app.registerPlugin(cm.config);
|
3717
4017
|
},
|
4018
|
+
bootstrap(app) {
|
4019
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4020
|
+
historyAdmin.bootstrap(app);
|
4021
|
+
}
|
4022
|
+
},
|
3718
4023
|
async registerTrads({ locales }) {
|
3719
4024
|
const importedTrads = await Promise.all(
|
3720
4025
|
locales.map((locale) => {
|
3721
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-
|
4026
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => import("./ar-CCEVvqGG.mjs"), "./translations/ca.json": () => import("./ca-5U32ON2v.mjs"), "./translations/cs.json": () => import("./cs-CM2aBUar.mjs"), "./translations/de.json": () => import("./de-C72KDNOl.mjs"), "./translations/en.json": () => import("./en-DKV44jRb.mjs"), "./translations/es.json": () => import("./es-CeXiYflN.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr-CD9VFbPM.mjs"), "./translations/gu.json": () => import("./gu-CNpaMDpH.mjs"), "./translations/hi.json": () => import("./hi-Dwvd04m3.mjs"), "./translations/hu.json": () => import("./hu-CeYvaaO0.mjs"), "./translations/id.json": () => import("./id-BtwA9WJT.mjs"), "./translations/it.json": () => import("./it-BrVPqaf1.mjs"), "./translations/ja.json": () => import("./ja-CtsUxOvk.mjs"), "./translations/ko.json": () => import("./ko-HVQRlfUI.mjs"), "./translations/ml.json": () => import("./ml-BihZwQit.mjs"), "./translations/ms.json": () => import("./ms-m_WjyWx7.mjs"), "./translations/nl.json": () => import("./nl-D4R9gHx5.mjs"), "./translations/pl.json": () => import("./pl-sbx9mSt_.mjs"), "./translations/pt-BR.json": () => import("./pt-BR-C71iDxnh.mjs"), "./translations/pt.json": () => import("./pt-BsaFvS8-.mjs"), "./translations/ru.json": () => import("./ru-BE6A4Exp.mjs"), "./translations/sa.json": () => import("./sa-Dag0k-Z8.mjs"), "./translations/sk.json": () => import("./sk-BFg-R8qJ.mjs"), "./translations/sv.json": () => import("./sv-CUnfWGsh.mjs"), "./translations/th.json": () => import("./th-BqbI8lIT.mjs"), "./translations/tr.json": () => import("./tr-CgeK3wJM.mjs"), "./translations/uk.json": () => import("./uk-CR-zDhAY.mjs"), "./translations/vi.json": () => import("./vi-DUXIk_fw.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-BPQcRIyH.mjs"), "./translations/zh.json": () => import("./zh-BWZspA60.mjs") }), `./translations/${locale}.json`).then(({ default: data }) => {
|
3722
4027
|
return {
|
3723
4028
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3724
4029
|
locale
|
@@ -3739,13 +4044,15 @@ export {
|
|
3739
4044
|
BulkActionsRenderer as B,
|
3740
4045
|
COLLECTION_TYPES as C,
|
3741
4046
|
DocumentStatus as D,
|
3742
|
-
|
3743
|
-
|
3744
|
-
|
4047
|
+
extractContentTypeComponents as E,
|
4048
|
+
DEFAULT_SETTINGS as F,
|
4049
|
+
convertEditLayoutToFieldLayouts as G,
|
3745
4050
|
HOOKS as H,
|
3746
4051
|
InjectionZone as I,
|
3747
|
-
|
3748
|
-
|
4052
|
+
useDocument as J,
|
4053
|
+
index as K,
|
4054
|
+
useContentManagerContext as L,
|
4055
|
+
useDocumentActions as M,
|
3749
4056
|
Panels as P,
|
3750
4057
|
RelativeTime as R,
|
3751
4058
|
SINGLE_TYPES as S,
|
@@ -3763,18 +4070,18 @@ export {
|
|
3763
4070
|
PERMISSIONS as k,
|
3764
4071
|
DocumentRBAC as l,
|
3765
4072
|
DOCUMENT_META_FIELDS as m,
|
3766
|
-
|
3767
|
-
|
3768
|
-
|
3769
|
-
|
3770
|
-
|
4073
|
+
CLONE_PATH as n,
|
4074
|
+
useDocLayout as o,
|
4075
|
+
useGetContentTypeConfigurationQuery as p,
|
4076
|
+
CREATOR_FIELDS as q,
|
4077
|
+
getMainField as r,
|
3771
4078
|
setInitialData as s,
|
3772
|
-
|
4079
|
+
getDisplayName as t,
|
3773
4080
|
useContentTypeSchema as u,
|
3774
|
-
|
3775
|
-
|
3776
|
-
|
3777
|
-
|
3778
|
-
|
4081
|
+
checkIfAttributeIsDisplayable as v,
|
4082
|
+
useGetAllDocumentsQuery as w,
|
4083
|
+
convertListLayoutToFieldLayouts as x,
|
4084
|
+
capitalise as y,
|
4085
|
+
useUpdateContentTypeConfigurationMutation as z
|
3779
4086
|
};
|
3780
|
-
//# sourceMappingURL=index-
|
4087
|
+
//# sourceMappingURL=index-CJ2vYwuT.mjs.map
|