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