@strapi/content-manager 0.0.0-experimental.f75e3c6d67cc47c64ab37479efdbb7b43be50b78 → 0.0.0-experimental.fed75ee8e64c57dbed0b670b25ef026b69baab10
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-BVM7LScS.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-CuWgXugY.mjs.map → ComponentConfigurationPage-BVM7LScS.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js → ComponentConfigurationPage-DNRPa10q.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-by0e_kNd.js.map → ComponentConfigurationPage-DNRPa10q.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs → EditConfigurationPage-BWq-9Zhk.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DbI4KMyz.mjs.map → EditConfigurationPage-BWq-9Zhk.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js → EditConfigurationPage-BrG0mEfF.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-CqBeCPGH.js.map → EditConfigurationPage-BrG0mEfF.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-ChgloMyO.js → EditViewPage-BbY0bNNE.js} +68 -47
- package/dist/_chunks/EditViewPage-BbY0bNNE.js.map +1 -0
- package/dist/_chunks/{EditViewPage-dFPBya9U.mjs → EditViewPage-Dx0QnTxn.mjs} +69 -48
- package/dist/_chunks/EditViewPage-Dx0QnTxn.mjs.map +1 -0
- package/dist/_chunks/{Field-dLk-vgLL.js → Field-CglKum3X.js} +581 -229
- package/dist/_chunks/Field-CglKum3X.js.map +1 -0
- package/dist/_chunks/{Field-C1nUKcdS.mjs → Field-DVZSGAon.mjs} +579 -227
- package/dist/_chunks/Field-DVZSGAon.mjs.map +1 -0
- package/dist/_chunks/{Form-CbXtmHC_.js → Form-B7nYNIUm.js} +52 -34
- package/dist/_chunks/Form-B7nYNIUm.js.map +1 -0
- package/dist/_chunks/{Form-DOlpi7Js.mjs → Form-BQwxPqu3.mjs} +54 -36
- package/dist/_chunks/Form-BQwxPqu3.mjs.map +1 -0
- package/dist/_chunks/{History-BjDfohBr.js → History-3JN4BIS1.js} +158 -40
- package/dist/_chunks/History-3JN4BIS1.js.map +1 -0
- package/dist/_chunks/{History-BFNUAiGc.mjs → History-Bmu6tx6s.mjs} +159 -41
- package/dist/_chunks/History-Bmu6tx6s.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-IQBgWTaa.js → ListConfigurationPage-BcC28SV0.js} +57 -46
- package/dist/_chunks/ListConfigurationPage-BcC28SV0.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DDi0KqFm.mjs → ListConfigurationPage-DwijcJ17.mjs} +58 -48
- package/dist/_chunks/ListConfigurationPage-DwijcJ17.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-BPjljUsH.mjs → ListViewPage-DzhuS3CW.mjs} +116 -103
- package/dist/_chunks/ListViewPage-DzhuS3CW.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-CZYGqlvF.js → ListViewPage-ZPNQ6jWC.js} +117 -104
- package/dist/_chunks/ListViewPage-ZPNQ6jWC.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs → NoContentTypePage-BKMgOyd3.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-DaWw67K-.mjs.map → NoContentTypePage-BKMgOyd3.mjs.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js → NoContentTypePage-DzwJNXvn.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BOAI6VZ1.js.map → NoContentTypePage-DzwJNXvn.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs → NoPermissionsPage-DBbGJqL9.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-CZrJH00p.mjs.map → NoPermissionsPage-DBbGJqL9.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js → NoPermissionsPage-GaweP-NG.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-cYEtLc_e.js.map → NoPermissionsPage-GaweP-NG.js.map} +1 -1
- package/dist/_chunks/{Relations-DTowyge2.mjs → Relations-B7VtRA3g.mjs} +35 -25
- package/dist/_chunks/Relations-B7VtRA3g.mjs.map +1 -0
- package/dist/_chunks/{Relations-DU6B7irU.js → Relations-BHXq_cKF.js} +35 -25
- package/dist/_chunks/Relations-BHXq_cKF.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-DcA8_tJw.js} +1391 -751
- package/dist/_chunks/index-DcA8_tJw.js.map +1 -0
- package/dist/_chunks/{index-BaGHmIir.mjs → index-TaRzG09p.mjs} +1424 -784
- package/dist/_chunks/index-TaRzG09p.mjs.map +1 -0
- package/dist/_chunks/{layout-ni_L9kT1.js → layout-CrgXpOxT.js} +39 -21
- package/dist/_chunks/layout-CrgXpOxT.js.map +1 -0
- package/dist/_chunks/{layout-BinjszSQ.mjs → layout-aX-RJhd5.mjs} +41 -23
- package/dist/_chunks/layout-aX-RJhd5.mjs.map +1 -0
- package/dist/_chunks/{relations-c91ji5eR.mjs → relations-D3Hlx6QX.mjs} +2 -2
- package/dist/_chunks/{relations-c91ji5eR.mjs.map → relations-D3Hlx6QX.mjs.map} +1 -1
- package/dist/_chunks/{relations-CeJAJc5I.js → relations-Z6RA1sBS.js} +2 -2
- package/dist/_chunks/{relations-CeJAJc5I.js.map → relations-Z6RA1sBS.js.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-Bmu6tx6s.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-Dx0QnTxn.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1281
1682
|
);
|
1282
1683
|
const ProtectedListViewPage = lazy(
|
1283
|
-
() => import("./ListViewPage-
|
1684
|
+
() => import("./ListViewPage-DzhuS3CW.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1284
1685
|
);
|
1285
1686
|
const ProtectedListConfiguration = lazy(
|
1286
|
-
() => import("./ListConfigurationPage-
|
1687
|
+
() => import("./ListConfigurationPage-DwijcJ17.mjs").then((mod) => ({
|
1287
1688
|
default: mod.ProtectedListConfiguration
|
1288
1689
|
}))
|
1289
1690
|
);
|
1290
1691
|
const ProtectedEditConfigurationPage = lazy(
|
1291
|
-
() => import("./EditConfigurationPage-
|
1692
|
+
() => import("./EditConfigurationPage-BWq-9Zhk.mjs").then((mod) => ({
|
1292
1693
|
default: mod.ProtectedEditConfigurationPage
|
1293
1694
|
}))
|
1294
1695
|
);
|
1295
1696
|
const ProtectedComponentConfigurationPage = lazy(
|
1296
|
-
() => import("./ComponentConfigurationPage-
|
1697
|
+
() => import("./ComponentConfigurationPage-BVM7LScS.mjs").then((mod) => ({
|
1297
1698
|
default: mod.ProtectedComponentConfigurationPage
|
1298
1699
|
}))
|
1299
1700
|
);
|
1300
1701
|
const NoPermissions = lazy(
|
1301
|
-
() => import("./NoPermissionsPage-
|
1702
|
+
() => import("./NoPermissionsPage-DBbGJqL9.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1302
1703
|
);
|
1303
1704
|
const NoContentType = lazy(
|
1304
|
-
() => import("./NoContentTypePage-
|
1705
|
+
() => import("./NoContentTypePage-BKMgOyd3.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
|
+
formDocumentToData(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,69 @@ 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";
|
2231
|
+
const formDocumentToData = (document) => {
|
2232
|
+
return Object.keys(document).reduce((acc, key) => {
|
2233
|
+
if (document[key] !== void 0) {
|
2234
|
+
acc[key] = document[key];
|
2235
|
+
}
|
2236
|
+
if (typeof document[key] === "object" && document[key] !== null) {
|
2237
|
+
if ("connect" in document[key] && document[key].connect !== null) {
|
2238
|
+
acc[key] = {
|
2239
|
+
...acc[key],
|
2240
|
+
connect: document[key].connect.map((item) => {
|
2241
|
+
return {
|
2242
|
+
documentId: item.documentId
|
2243
|
+
};
|
2244
|
+
})
|
2245
|
+
};
|
2246
|
+
}
|
2247
|
+
if ("disconnect" in document[key] && document[key].disconnect !== null) {
|
2248
|
+
acc[key] = {
|
2249
|
+
...acc[key],
|
2250
|
+
disconnect: document[key].disconnect.map((item) => {
|
2251
|
+
return {
|
2252
|
+
documentId: item.documentId
|
2253
|
+
};
|
2254
|
+
})
|
2255
|
+
};
|
2256
|
+
}
|
2257
|
+
}
|
2258
|
+
return acc;
|
2259
|
+
}, {});
|
2260
|
+
};
|
1734
2261
|
const UpdateAction = ({
|
1735
2262
|
activeTab,
|
1736
2263
|
documentId,
|
@@ -1743,10 +2270,6 @@ const UpdateAction = ({
|
|
1743
2270
|
const cloneMatch = useMatch(CLONE_PATH);
|
1744
2271
|
const isCloning = cloneMatch !== null;
|
1745
2272
|
const { formatMessage } = useIntl();
|
1746
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1747
|
-
canCreate: canCreate2,
|
1748
|
-
canUpdate: canUpdate2
|
1749
|
-
}));
|
1750
2273
|
const { create, update, clone } = useDocumentActions();
|
1751
2274
|
const [{ query, rawQuery }] = useQueryParams();
|
1752
2275
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1763,10 +2286,8 @@ const UpdateAction = ({
|
|
1763
2286
|
* - the form is submitting
|
1764
2287
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1765
2288
|
* - 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
2289
|
*/
|
1769
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2290
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1770
2291
|
label: formatMessage({
|
1771
2292
|
id: "content-manager.containers.Edit.save",
|
1772
2293
|
defaultMessage: "Save"
|
@@ -1774,7 +2295,9 @@ const UpdateAction = ({
|
|
1774
2295
|
onClick: async () => {
|
1775
2296
|
setSubmitting(true);
|
1776
2297
|
try {
|
1777
|
-
const { errors } = await validate(
|
2298
|
+
const { errors } = await validate(true, {
|
2299
|
+
status: "draft"
|
2300
|
+
});
|
1778
2301
|
if (errors) {
|
1779
2302
|
toggleNotification({
|
1780
2303
|
type: "danger",
|
@@ -1792,13 +2315,16 @@ const UpdateAction = ({
|
|
1792
2315
|
documentId: cloneMatch.params.origin,
|
1793
2316
|
params
|
1794
2317
|
},
|
1795
|
-
document
|
2318
|
+
formDocumentToData(document)
|
1796
2319
|
);
|
1797
2320
|
if ("data" in res) {
|
1798
|
-
navigate(
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
2321
|
+
navigate(
|
2322
|
+
{
|
2323
|
+
pathname: `../${res.data.documentId}`,
|
2324
|
+
search: rawQuery
|
2325
|
+
},
|
2326
|
+
{ relative: "path" }
|
2327
|
+
);
|
1802
2328
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1803
2329
|
setErrors(formatValidationErrors(res.error));
|
1804
2330
|
}
|
@@ -1810,7 +2336,7 @@ const UpdateAction = ({
|
|
1810
2336
|
documentId,
|
1811
2337
|
params
|
1812
2338
|
},
|
1813
|
-
document
|
2339
|
+
formDocumentToData(document)
|
1814
2340
|
);
|
1815
2341
|
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1816
2342
|
setErrors(formatValidationErrors(res.error));
|
@@ -1823,13 +2349,16 @@ const UpdateAction = ({
|
|
1823
2349
|
model,
|
1824
2350
|
params
|
1825
2351
|
},
|
1826
|
-
document
|
2352
|
+
formDocumentToData(document)
|
1827
2353
|
);
|
1828
2354
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1829
|
-
navigate(
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
2355
|
+
navigate(
|
2356
|
+
{
|
2357
|
+
pathname: `../${res.data.documentId}`,
|
2358
|
+
search: rawQuery
|
2359
|
+
},
|
2360
|
+
{ replace: true, relative: "path" }
|
2361
|
+
);
|
1833
2362
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1834
2363
|
setErrors(formatValidationErrors(res.error));
|
1835
2364
|
}
|
@@ -1861,10 +2390,8 @@ const UnpublishAction$1 = ({
|
|
1861
2390
|
const { toggleNotification } = useNotification();
|
1862
2391
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1863
2392
|
const isDocumentModified = document?.status === "modified";
|
1864
|
-
const handleChange = (
|
1865
|
-
|
1866
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1867
|
-
}
|
2393
|
+
const handleChange = (value) => {
|
2394
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1868
2395
|
};
|
1869
2396
|
if (!schema?.options?.draftAndPublish) {
|
1870
2397
|
return null;
|
@@ -1875,7 +2402,7 @@ const UnpublishAction$1 = ({
|
|
1875
2402
|
id: "app.utils.unpublish",
|
1876
2403
|
defaultMessage: "Unpublish"
|
1877
2404
|
}),
|
1878
|
-
icon: /* @__PURE__ */ jsx(
|
2405
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1879
2406
|
onClick: async () => {
|
1880
2407
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1881
2408
|
if (!documentId) {
|
@@ -1914,40 +2441,24 @@ const UnpublishAction$1 = ({
|
|
1914
2441
|
}) })
|
1915
2442
|
] }),
|
1916
2443
|
/* @__PURE__ */ jsxs(
|
1917
|
-
|
2444
|
+
Radio.Group,
|
1918
2445
|
{
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
2446
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2447
|
+
name: "discard-options",
|
2448
|
+
"aria-label": formatMessage({
|
2449
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2450
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2451
|
+
}),
|
2452
|
+
onValueChange: handleChange,
|
1925
2453
|
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
|
-
)
|
2454
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2455
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2456
|
+
defaultMessage: "Keep draft"
|
2457
|
+
}) }),
|
2458
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2459
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2460
|
+
defaultMessage: "Replace draft"
|
2461
|
+
}) })
|
1951
2462
|
]
|
1952
2463
|
}
|
1953
2464
|
)
|
@@ -2003,7 +2514,7 @@ const DiscardAction = ({
|
|
2003
2514
|
id: "content-manager.actions.discard.label",
|
2004
2515
|
defaultMessage: "Discard changes"
|
2005
2516
|
}),
|
2006
|
-
icon: /* @__PURE__ */ jsx(
|
2517
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2007
2518
|
position: ["panel", "table-row"],
|
2008
2519
|
variant: "danger",
|
2009
2520
|
dialog: {
|
@@ -2031,12 +2542,7 @@ const DiscardAction = ({
|
|
2031
2542
|
};
|
2032
2543
|
};
|
2033
2544
|
DiscardAction.type = "discard";
|
2034
|
-
const
|
2035
|
-
path {
|
2036
|
-
fill: currentColor;
|
2037
|
-
}
|
2038
|
-
`;
|
2039
|
-
const DEFAULT_ACTIONS = [PublishAction, UpdateAction, UnpublishAction$1, DiscardAction];
|
2545
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2040
2546
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2041
2547
|
const RelativeTime = React.forwardRef(
|
2042
2548
|
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
@@ -2083,7 +2589,7 @@ const getDisplayName = ({
|
|
2083
2589
|
};
|
2084
2590
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2085
2591
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2086
|
-
const statusVariant = status === "draft" ? "
|
2592
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2087
2593
|
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
2594
|
};
|
2089
2595
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2093,23 +2599,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2093
2599
|
id: "content-manager.containers.edit.title.new",
|
2094
2600
|
defaultMessage: "Create an entry"
|
2095
2601
|
}) : documentTitle;
|
2096
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2602
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2097
2603
|
/* @__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
|
2604
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2605
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2606
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2607
|
+
] }),
|
2608
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2113
2609
|
] });
|
2114
2610
|
};
|
2115
2611
|
const HeaderToolbar = () => {
|
@@ -2192,12 +2688,12 @@ const Information = ({ activeTab }) => {
|
|
2192
2688
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2193
2689
|
label: formatMessage({
|
2194
2690
|
id: "content-manager.containers.edit.information.last-published.label",
|
2195
|
-
defaultMessage: "
|
2691
|
+
defaultMessage: "Published"
|
2196
2692
|
}),
|
2197
2693
|
value: formatMessage(
|
2198
2694
|
{
|
2199
2695
|
id: "content-manager.containers.edit.information.last-published.value",
|
2200
|
-
defaultMessage: `
|
2696
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2201
2697
|
},
|
2202
2698
|
{
|
2203
2699
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2210,12 +2706,12 @@ const Information = ({ activeTab }) => {
|
|
2210
2706
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2211
2707
|
label: formatMessage({
|
2212
2708
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2213
|
-
defaultMessage: "
|
2709
|
+
defaultMessage: "Updated"
|
2214
2710
|
}),
|
2215
2711
|
value: formatMessage(
|
2216
2712
|
{
|
2217
2713
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2218
|
-
defaultMessage: `
|
2714
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2219
2715
|
},
|
2220
2716
|
{
|
2221
2717
|
time: /* @__PURE__ */ jsx(
|
@@ -2233,12 +2729,12 @@ const Information = ({ activeTab }) => {
|
|
2233
2729
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2234
2730
|
label: formatMessage({
|
2235
2731
|
id: "content-manager.containers.edit.information.document.label",
|
2236
|
-
defaultMessage: "
|
2732
|
+
defaultMessage: "Created"
|
2237
2733
|
}),
|
2238
2734
|
value: formatMessage(
|
2239
2735
|
{
|
2240
2736
|
id: "content-manager.containers.edit.information.document.value",
|
2241
|
-
defaultMessage: `
|
2737
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2242
2738
|
},
|
2243
2739
|
{
|
2244
2740
|
time: /* @__PURE__ */ jsx(
|
@@ -2276,25 +2772,77 @@ const Information = ({ activeTab }) => {
|
|
2276
2772
|
);
|
2277
2773
|
};
|
2278
2774
|
const HeaderActions = ({ actions: actions2 }) => {
|
2279
|
-
|
2280
|
-
|
2775
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2776
|
+
const handleClick = (action) => async (e) => {
|
2777
|
+
if (!("options" in action)) {
|
2778
|
+
const { onClick = () => false, dialog, id } = action;
|
2779
|
+
const muteDialog = await onClick(e);
|
2780
|
+
if (dialog && !muteDialog) {
|
2781
|
+
e.preventDefault();
|
2782
|
+
setDialogId(id);
|
2783
|
+
}
|
2784
|
+
}
|
2785
|
+
};
|
2786
|
+
const handleClose = () => {
|
2787
|
+
setDialogId(null);
|
2788
|
+
};
|
2789
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2790
|
+
if (action.options) {
|
2281
2791
|
return /* @__PURE__ */ jsx(
|
2282
2792
|
SingleSelect,
|
2283
2793
|
{
|
2284
2794
|
size: "S",
|
2285
|
-
disabled: action.disabled,
|
2286
|
-
"aria-label": action.label,
|
2287
2795
|
onChange: action.onSelect,
|
2288
|
-
|
2796
|
+
"aria-label": action.label,
|
2797
|
+
...action,
|
2289
2798
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2290
2799
|
},
|
2291
2800
|
action.id
|
2292
2801
|
);
|
2293
2802
|
} else {
|
2294
|
-
|
2803
|
+
if (action.type === "icon") {
|
2804
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2805
|
+
/* @__PURE__ */ jsx(
|
2806
|
+
IconButton,
|
2807
|
+
{
|
2808
|
+
disabled: action.disabled,
|
2809
|
+
label: action.label,
|
2810
|
+
size: "S",
|
2811
|
+
onClick: handleClick(action),
|
2812
|
+
children: action.icon
|
2813
|
+
}
|
2814
|
+
),
|
2815
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2816
|
+
HeaderActionDialog,
|
2817
|
+
{
|
2818
|
+
...action.dialog,
|
2819
|
+
isOpen: dialogId === action.id,
|
2820
|
+
onClose: handleClose
|
2821
|
+
}
|
2822
|
+
) : null
|
2823
|
+
] }, action.id);
|
2824
|
+
}
|
2295
2825
|
}
|
2296
2826
|
}) });
|
2297
2827
|
};
|
2828
|
+
const HeaderActionDialog = ({
|
2829
|
+
onClose,
|
2830
|
+
onCancel,
|
2831
|
+
title,
|
2832
|
+
content: Content,
|
2833
|
+
isOpen
|
2834
|
+
}) => {
|
2835
|
+
const handleClose = async () => {
|
2836
|
+
if (onCancel) {
|
2837
|
+
await onCancel();
|
2838
|
+
}
|
2839
|
+
onClose();
|
2840
|
+
};
|
2841
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2842
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2843
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2844
|
+
] }) });
|
2845
|
+
};
|
2298
2846
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2299
2847
|
const navigate = useNavigate();
|
2300
2848
|
const { formatMessage } = useIntl();
|
@@ -2335,12 +2883,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2335
2883
|
const { delete: deleteAction } = useDocumentActions();
|
2336
2884
|
const { toggleNotification } = useNotification();
|
2337
2885
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2886
|
+
const isLocalized = document?.locale != null;
|
2338
2887
|
return {
|
2339
2888
|
disabled: !canDelete || !document,
|
2340
|
-
label: formatMessage(
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2889
|
+
label: formatMessage(
|
2890
|
+
{
|
2891
|
+
id: "content-manager.actions.delete.label",
|
2892
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2893
|
+
},
|
2894
|
+
{ isLocalized }
|
2895
|
+
),
|
2344
2896
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2345
2897
|
dialog: {
|
2346
2898
|
type: "dialog",
|
@@ -2430,7 +2982,7 @@ const ActionsPanel = () => {
|
|
2430
2982
|
return {
|
2431
2983
|
title: formatMessage({
|
2432
2984
|
id: "content-manager.containers.edit.panels.default.title",
|
2433
|
-
defaultMessage: "
|
2985
|
+
defaultMessage: "Entry"
|
2434
2986
|
}),
|
2435
2987
|
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2436
2988
|
};
|
@@ -2491,155 +3043,483 @@ const Panel = React.forwardRef(({ children, title }, ref) => {
|
|
2491
3043
|
}
|
2492
3044
|
);
|
2493
3045
|
});
|
2494
|
-
const
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2507
|
-
|
2508
|
-
|
2509
|
-
|
3046
|
+
const ConfirmBulkActionDialog = ({
|
3047
|
+
onToggleDialog,
|
3048
|
+
isOpen = false,
|
3049
|
+
dialogBody,
|
3050
|
+
endAction
|
3051
|
+
}) => {
|
3052
|
+
const { formatMessage } = useIntl();
|
3053
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3054
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
3055
|
+
id: "app.components.ConfirmDialog.title",
|
3056
|
+
defaultMessage: "Confirmation"
|
3057
|
+
}) }),
|
3058
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3059
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3060
|
+
dialogBody
|
3061
|
+
] }) }),
|
3062
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
3063
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
3064
|
+
id: "app.components.Button.cancel",
|
3065
|
+
defaultMessage: "Cancel"
|
3066
|
+
}) }) }),
|
3067
|
+
endAction
|
3068
|
+
] })
|
3069
|
+
] }) });
|
2510
3070
|
};
|
2511
|
-
const
|
2512
|
-
|
3071
|
+
const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3072
|
+
const ConfirmDialogPublishAll = ({
|
3073
|
+
isOpen,
|
3074
|
+
onToggleDialog,
|
3075
|
+
isConfirmButtonLoading = false,
|
3076
|
+
onConfirm
|
3077
|
+
}) => {
|
3078
|
+
const { formatMessage } = useIntl();
|
3079
|
+
const selectedEntries = useTable("ConfirmDialogPublishAll", (state) => state.selectedRows);
|
2513
3080
|
const { toggleNotification } = useNotification();
|
2514
|
-
const
|
2515
|
-
|
2516
|
-
|
2517
|
-
|
2518
|
-
|
2519
|
-
|
2520
|
-
|
2521
|
-
|
2522
|
-
|
2523
|
-
|
2524
|
-
|
2525
|
-
|
2526
|
-
|
2527
|
-
|
2528
|
-
|
2529
|
-
|
2530
|
-
case "dialog":
|
2531
|
-
case "modal": {
|
2532
|
-
e.preventDefault();
|
2533
|
-
setDialogId(id);
|
2534
|
-
}
|
2535
|
-
}
|
3081
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
3082
|
+
const { model, schema } = useDoc();
|
3083
|
+
const [{ query }] = useQueryParams();
|
3084
|
+
const enableDraftRelationsCount = false;
|
3085
|
+
const {
|
3086
|
+
data: countDraftRelations = 0,
|
3087
|
+
isLoading,
|
3088
|
+
error
|
3089
|
+
} = useGetManyDraftRelationCountQuery(
|
3090
|
+
{
|
3091
|
+
model,
|
3092
|
+
documentIds: selectedEntries.map((entry) => entry.documentId),
|
3093
|
+
locale: query?.plugins?.i18n?.locale
|
3094
|
+
},
|
3095
|
+
{
|
3096
|
+
skip: !enableDraftRelationsCount
|
2536
3097
|
}
|
2537
|
-
|
2538
|
-
|
2539
|
-
|
2540
|
-
|
2541
|
-
action.dialog.onClose();
|
3098
|
+
);
|
3099
|
+
React.useEffect(() => {
|
3100
|
+
if (error) {
|
3101
|
+
toggleNotification({ type: "danger", message: formatAPIError(error) });
|
2542
3102
|
}
|
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
|
-
|
3103
|
+
}, [error, formatAPIError, toggleNotification]);
|
3104
|
+
if (error) {
|
3105
|
+
return null;
|
3106
|
+
}
|
3107
|
+
return /* @__PURE__ */ jsx(
|
3108
|
+
ConfirmBulkActionDialog,
|
3109
|
+
{
|
3110
|
+
isOpen: isOpen && !isLoading,
|
3111
|
+
onToggleDialog,
|
3112
|
+
dialogBody: /* @__PURE__ */ jsxs(Fragment, { children: [
|
3113
|
+
/* @__PURE__ */ jsxs(Typography, { id: "confirm-description", textAlign: "center", children: [
|
3114
|
+
countDraftRelations > 0 && formatMessage(
|
3115
|
+
{
|
3116
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
3117
|
+
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. "
|
3118
|
+
},
|
3119
|
+
{
|
3120
|
+
b: BoldChunk$1,
|
3121
|
+
count: countDraftRelations,
|
3122
|
+
entities: selectedEntries.length
|
3123
|
+
}
|
3124
|
+
),
|
3125
|
+
formatMessage({
|
3126
|
+
id: getTranslation("popUpWarning.bodyMessage.contentType.publish.all"),
|
3127
|
+
defaultMessage: "Are you sure you want to publish these entries?"
|
3128
|
+
})
|
3129
|
+
] }),
|
3130
|
+
schema?.pluginOptions && "i18n" in schema.pluginOptions && schema?.pluginOptions.i18n && /* @__PURE__ */ jsx(Typography, { textColor: "danger500", textAlign: "center", children: formatMessage(
|
3131
|
+
{
|
3132
|
+
id: getTranslation("Settings.list.actions.publishAdditionalInfos"),
|
3133
|
+
defaultMessage: "This will publish the active locale versions <em>(from Internationalization)</em>"
|
3134
|
+
},
|
3135
|
+
{
|
3136
|
+
em: Emphasis
|
3137
|
+
}
|
3138
|
+
) })
|
3139
|
+
] }),
|
3140
|
+
endAction: /* @__PURE__ */ jsx(
|
3141
|
+
Button,
|
3142
|
+
{
|
3143
|
+
onClick: onConfirm,
|
3144
|
+
variant: "secondary",
|
3145
|
+
startIcon: /* @__PURE__ */ jsx(Check, {}),
|
3146
|
+
loading: isConfirmButtonLoading,
|
3147
|
+
children: formatMessage({
|
3148
|
+
id: "app.utils.publish",
|
3149
|
+
defaultMessage: "Publish"
|
3150
|
+
})
|
3151
|
+
}
|
3152
|
+
)
|
3153
|
+
}
|
3154
|
+
);
|
3155
|
+
};
|
3156
|
+
const TypographyMaxWidth = styled(Typography)`
|
3157
|
+
max-width: 300px;
|
3158
|
+
`;
|
3159
|
+
const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
3160
|
+
const messages = [];
|
3161
|
+
Object.entries(errors).forEach(([key, value]) => {
|
3162
|
+
const currentKey = parentKey ? `${parentKey}.${key}` : key;
|
3163
|
+
if (typeof value === "object" && value !== null && !Array.isArray(value)) {
|
3164
|
+
if ("id" in value && "defaultMessage" in value) {
|
3165
|
+
messages.push(
|
3166
|
+
formatMessage(
|
3167
|
+
{
|
3168
|
+
id: `${value.id}.withField`,
|
3169
|
+
defaultMessage: value.defaultMessage
|
3170
|
+
},
|
3171
|
+
{ field: currentKey }
|
3172
|
+
)
|
3173
|
+
);
|
3174
|
+
} else {
|
3175
|
+
messages.push(
|
3176
|
+
...formatErrorMessages(
|
3177
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3178
|
+
value,
|
3179
|
+
currentKey,
|
3180
|
+
formatMessage
|
3181
|
+
)
|
3182
|
+
);
|
2570
3183
|
}
|
2571
|
-
|
3184
|
+
} else {
|
3185
|
+
messages.push(
|
3186
|
+
formatMessage(
|
3187
|
+
{
|
3188
|
+
id: `${value}.withField`,
|
3189
|
+
defaultMessage: value
|
3190
|
+
},
|
3191
|
+
{ field: currentKey }
|
3192
|
+
)
|
3193
|
+
);
|
3194
|
+
}
|
3195
|
+
});
|
3196
|
+
return messages;
|
3197
|
+
};
|
3198
|
+
const EntryValidationText = ({ validationErrors, status }) => {
|
3199
|
+
const { formatMessage } = useIntl();
|
3200
|
+
if (validationErrors) {
|
3201
|
+
const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
|
3202
|
+
" "
|
3203
|
+
);
|
3204
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3205
|
+
/* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
|
3206
|
+
/* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
|
3207
|
+
] });
|
3208
|
+
}
|
3209
|
+
if (status === "published") {
|
3210
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3211
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3212
|
+
/* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
|
3213
|
+
id: "content-manager.bulk-publish.already-published",
|
3214
|
+
defaultMessage: "Already Published"
|
3215
|
+
}) })
|
3216
|
+
] });
|
3217
|
+
}
|
3218
|
+
if (status === "modified") {
|
3219
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3220
|
+
/* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3221
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3222
|
+
id: "content-manager.bulk-publish.modified",
|
3223
|
+
defaultMessage: "Ready to publish changes"
|
3224
|
+
}) })
|
3225
|
+
] });
|
3226
|
+
}
|
3227
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3228
|
+
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
3229
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3230
|
+
id: "app.utils.ready-to-publish",
|
3231
|
+
defaultMessage: "Ready to publish"
|
3232
|
+
}) })
|
2572
3233
|
] });
|
2573
3234
|
};
|
2574
|
-
const
|
2575
|
-
|
2576
|
-
|
2577
|
-
|
2578
|
-
|
2579
|
-
|
2580
|
-
|
2581
|
-
|
2582
|
-
|
3235
|
+
const TABLE_HEADERS = [
|
3236
|
+
{ name: "id", label: "id" },
|
3237
|
+
{ name: "name", label: "name" },
|
3238
|
+
{ name: "status", label: "status" },
|
3239
|
+
{ name: "publicationStatus", label: "Publication status" }
|
3240
|
+
];
|
3241
|
+
const SelectedEntriesTableContent = ({
|
3242
|
+
isPublishing,
|
3243
|
+
rowsToDisplay = [],
|
3244
|
+
entriesToPublish = [],
|
3245
|
+
validationErrors = {}
|
2583
3246
|
}) => {
|
3247
|
+
const { pathname } = useLocation();
|
2584
3248
|
const { formatMessage } = useIntl();
|
2585
|
-
const
|
2586
|
-
|
2587
|
-
|
3249
|
+
const {
|
3250
|
+
list: {
|
3251
|
+
settings: { mainField }
|
2588
3252
|
}
|
2589
|
-
|
2590
|
-
|
2591
|
-
|
2592
|
-
|
2593
|
-
|
3253
|
+
} = useDocLayout();
|
3254
|
+
const shouldDisplayMainField = mainField != null && mainField !== "id";
|
3255
|
+
return /* @__PURE__ */ jsxs(Table.Content, { children: [
|
3256
|
+
/* @__PURE__ */ jsxs(Table.Head, { children: [
|
3257
|
+
/* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
|
3258
|
+
TABLE_HEADERS.filter((head) => head.name !== "name" || shouldDisplayMainField).map(
|
3259
|
+
(head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name)
|
3260
|
+
)
|
3261
|
+
] }),
|
3262
|
+
/* @__PURE__ */ jsx(Table.Loading, {}),
|
3263
|
+
/* @__PURE__ */ jsx(Table.Body, { children: rowsToDisplay.map((row, index2) => /* @__PURE__ */ jsxs(Table.Row, { children: [
|
3264
|
+
/* @__PURE__ */ jsx(Table.CheckboxCell, { id: row.id }),
|
3265
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row.id }) }),
|
3266
|
+
shouldDisplayMainField && /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { children: row[mainField] }) }),
|
3267
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(DocumentStatus, { status: row.status, maxWidth: "min-content" }) }),
|
3268
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: isPublishing && entriesToPublish.includes(row.documentId) ? /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3269
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3270
|
+
id: "content-manager.success.record.publishing",
|
3271
|
+
defaultMessage: "Publishing..."
|
3272
|
+
}) }),
|
3273
|
+
/* @__PURE__ */ jsx(Loader, { small: true })
|
3274
|
+
] }) : /* @__PURE__ */ jsx(
|
3275
|
+
EntryValidationText,
|
3276
|
+
{
|
3277
|
+
validationErrors: validationErrors[row.documentId],
|
3278
|
+
status: row.status
|
3279
|
+
}
|
3280
|
+
) }),
|
3281
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3282
|
+
IconButton,
|
3283
|
+
{
|
3284
|
+
tag: Link,
|
3285
|
+
to: {
|
3286
|
+
pathname: `${pathname}/${row.documentId}`,
|
3287
|
+
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3288
|
+
},
|
3289
|
+
state: { from: pathname },
|
3290
|
+
label: formatMessage(
|
3291
|
+
{ id: "app.component.HelperPluginTable.edit", defaultMessage: "Edit {target}" },
|
3292
|
+
{
|
3293
|
+
target: formatMessage(
|
3294
|
+
{
|
3295
|
+
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3296
|
+
defaultMessage: "item line {number}"
|
3297
|
+
},
|
3298
|
+
{ number: index2 + 1 }
|
3299
|
+
)
|
3300
|
+
}
|
3301
|
+
),
|
3302
|
+
target: "_blank",
|
3303
|
+
marginLeft: "auto",
|
3304
|
+
variant: "ghost",
|
3305
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3306
|
+
}
|
3307
|
+
) }) })
|
3308
|
+
] }, row.id)) })
|
3309
|
+
] });
|
3310
|
+
};
|
3311
|
+
const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
3312
|
+
const SelectedEntriesModalContent = ({
|
3313
|
+
listViewSelectedEntries,
|
3314
|
+
toggleModal,
|
3315
|
+
setListViewSelectedDocuments,
|
3316
|
+
model
|
3317
|
+
}) => {
|
3318
|
+
const { formatMessage } = useIntl();
|
3319
|
+
const { schema, components } = useContentTypeSchema(model);
|
3320
|
+
const documentIds = listViewSelectedEntries.map(({ documentId }) => documentId);
|
3321
|
+
const [{ query }] = useQueryParams();
|
3322
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
3323
|
+
const { data, isLoading, isFetching, refetch } = useGetAllDocumentsQuery(
|
3324
|
+
{
|
3325
|
+
model,
|
3326
|
+
params: {
|
3327
|
+
page: "1",
|
3328
|
+
pageSize: documentIds.length.toString(),
|
3329
|
+
sort: query.sort,
|
3330
|
+
filters: {
|
3331
|
+
documentId: {
|
3332
|
+
$in: documentIds
|
3333
|
+
}
|
3334
|
+
},
|
3335
|
+
locale: query.plugins?.i18n?.locale
|
3336
|
+
}
|
3337
|
+
},
|
3338
|
+
{
|
3339
|
+
selectFromResult: ({ data: data2, ...restRes }) => ({ data: data2?.results ?? [], ...restRes })
|
3340
|
+
}
|
3341
|
+
);
|
3342
|
+
const { rows, validationErrors } = React.useMemo(() => {
|
3343
|
+
if (data.length > 0 && schema) {
|
3344
|
+
const validate = createYupSchema(
|
3345
|
+
schema.attributes,
|
3346
|
+
components,
|
3347
|
+
// Since this is the "Publish" action, the validation
|
3348
|
+
// schema must enforce the rules for published entities
|
3349
|
+
{ status: "published" }
|
3350
|
+
);
|
3351
|
+
const validationErrors2 = {};
|
3352
|
+
const rows2 = data.map((entry) => {
|
3353
|
+
try {
|
3354
|
+
validate.validateSync(entry, { abortEarly: false });
|
3355
|
+
return entry;
|
3356
|
+
} catch (e) {
|
3357
|
+
if (e instanceof ValidationError) {
|
3358
|
+
validationErrors2[entry.documentId] = getYupValidationErrors(e);
|
3359
|
+
}
|
3360
|
+
return entry;
|
3361
|
+
}
|
3362
|
+
});
|
3363
|
+
return { rows: rows2, validationErrors: validationErrors2 };
|
3364
|
+
}
|
3365
|
+
return {
|
3366
|
+
rows: [],
|
3367
|
+
validationErrors: {}
|
3368
|
+
};
|
3369
|
+
}, [components, data, schema]);
|
3370
|
+
const [publishedCount, setPublishedCount] = React.useState(0);
|
3371
|
+
const [isDialogOpen, setIsDialogOpen] = React.useState(false);
|
3372
|
+
const { publishMany: bulkPublishAction } = useDocumentActions();
|
3373
|
+
const [, { isLoading: isSubmittingForm }] = usePublishManyDocumentsMutation();
|
3374
|
+
const selectedRows = useTable("publishAction", (state) => state.selectedRows);
|
3375
|
+
const selectedEntries = rows.filter(
|
3376
|
+
(entry) => selectedRows.some((selectedEntry) => selectedEntry.documentId === entry.documentId)
|
3377
|
+
);
|
3378
|
+
const entriesToPublish = selectedEntries.filter((entry) => !validationErrors[entry.documentId]).map((entry) => entry.documentId);
|
3379
|
+
const selectedEntriesWithErrorsCount = selectedEntries.filter(
|
3380
|
+
({ documentId }) => validationErrors[documentId]
|
3381
|
+
).length;
|
3382
|
+
const selectedEntriesPublished = selectedEntries.filter(
|
3383
|
+
({ status }) => status === "published"
|
3384
|
+
).length;
|
3385
|
+
const selectedEntriesWithNoErrorsCount = selectedEntries.length - selectedEntriesWithErrorsCount - selectedEntriesPublished;
|
3386
|
+
const toggleDialog = () => setIsDialogOpen((prev) => !prev);
|
3387
|
+
const handleConfirmBulkPublish = async () => {
|
3388
|
+
toggleDialog();
|
3389
|
+
const res = await bulkPublishAction({ model, documentIds: entriesToPublish, params });
|
3390
|
+
if (!("error" in res)) {
|
3391
|
+
setPublishedCount(res.count);
|
3392
|
+
const unpublishedEntries = rows.filter((row) => {
|
3393
|
+
return !entriesToPublish.includes(row.documentId);
|
3394
|
+
});
|
3395
|
+
setListViewSelectedDocuments(unpublishedEntries);
|
2594
3396
|
}
|
2595
|
-
onClose();
|
2596
3397
|
};
|
2597
|
-
|
2598
|
-
|
2599
|
-
|
2600
|
-
|
3398
|
+
const getFormattedCountMessage = () => {
|
3399
|
+
if (publishedCount) {
|
3400
|
+
return formatMessage(
|
3401
|
+
{
|
3402
|
+
id: getTranslation("containers.list.selectedEntriesModal.publishedCount"),
|
3403
|
+
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."
|
3404
|
+
},
|
3405
|
+
{
|
3406
|
+
publishedCount,
|
3407
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3408
|
+
b: BoldChunk
|
3409
|
+
}
|
3410
|
+
);
|
3411
|
+
}
|
3412
|
+
return formatMessage(
|
2601
3413
|
{
|
2602
|
-
|
2603
|
-
|
2604
|
-
|
2605
|
-
|
2606
|
-
|
3414
|
+
id: getTranslation("containers.list.selectedEntriesModal.selectedCount"),
|
3415
|
+
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."
|
3416
|
+
},
|
3417
|
+
{
|
3418
|
+
readyToPublishCount: selectedEntriesWithNoErrorsCount,
|
3419
|
+
withErrorsCount: selectedEntriesWithErrorsCount,
|
3420
|
+
alreadyPublishedCount: selectedEntriesPublished,
|
3421
|
+
b: BoldChunk
|
3422
|
+
}
|
3423
|
+
);
|
3424
|
+
};
|
3425
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3426
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3427
|
+
/* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
|
3428
|
+
/* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
|
3429
|
+
SelectedEntriesTableContent,
|
3430
|
+
{
|
3431
|
+
isPublishing: isSubmittingForm,
|
3432
|
+
rowsToDisplay: rows,
|
3433
|
+
entriesToPublish,
|
3434
|
+
validationErrors
|
3435
|
+
}
|
3436
|
+
) })
|
3437
|
+
] }),
|
3438
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3439
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3440
|
+
id: "app.components.Button.cancel",
|
3441
|
+
defaultMessage: "Cancel"
|
3442
|
+
}) }),
|
3443
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3444
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3445
|
+
/* @__PURE__ */ jsx(
|
2607
3446
|
Button,
|
2608
3447
|
{
|
2609
|
-
onClick:
|
2610
|
-
|
2611
|
-
|
2612
|
-
children:
|
2613
|
-
id: "app.components.Button.confirm",
|
2614
|
-
defaultMessage: "Confirm"
|
2615
|
-
})
|
3448
|
+
onClick: toggleDialog,
|
3449
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
|
3450
|
+
loading: isSubmittingForm,
|
3451
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
2616
3452
|
}
|
2617
3453
|
)
|
3454
|
+
] })
|
3455
|
+
] }),
|
3456
|
+
/* @__PURE__ */ jsx(
|
3457
|
+
ConfirmDialogPublishAll,
|
3458
|
+
{
|
3459
|
+
isOpen: isDialogOpen,
|
3460
|
+
onToggleDialog: toggleDialog,
|
3461
|
+
isConfirmButtonLoading: isSubmittingForm,
|
3462
|
+
onConfirm: handleConfirmBulkPublish
|
2618
3463
|
}
|
2619
3464
|
)
|
2620
3465
|
] });
|
2621
3466
|
};
|
2622
|
-
const
|
2623
|
-
|
2624
|
-
|
2625
|
-
|
2626
|
-
|
2627
|
-
|
2628
|
-
|
2629
|
-
|
2630
|
-
if (!
|
3467
|
+
const PublishAction = ({ documents, model }) => {
|
3468
|
+
const { formatMessage } = useIntl();
|
3469
|
+
const hasPublishPermission = useDocumentRBAC("unpublishAction", (state) => state.canPublish);
|
3470
|
+
const showPublishButton = hasPublishPermission && documents.some(({ status }) => status !== "published");
|
3471
|
+
const setListViewSelectedDocuments = useTable("publishAction", (state) => state.selectRow);
|
3472
|
+
const refetchList = () => {
|
3473
|
+
contentManagerApi.util.invalidateTags([{ type: "Document", id: `${model}_LIST` }]);
|
3474
|
+
};
|
3475
|
+
if (!showPublishButton)
|
2631
3476
|
return null;
|
2632
|
-
|
2633
|
-
|
2634
|
-
|
2635
|
-
|
3477
|
+
return {
|
3478
|
+
actionType: "publish",
|
3479
|
+
variant: "tertiary",
|
3480
|
+
label: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" }),
|
3481
|
+
dialog: {
|
3482
|
+
type: "modal",
|
3483
|
+
title: formatMessage({
|
3484
|
+
id: getTranslation("containers.ListPage.selectedEntriesModal.title"),
|
3485
|
+
defaultMessage: "Publish entries"
|
3486
|
+
}),
|
3487
|
+
content: ({ onClose }) => {
|
3488
|
+
return /* @__PURE__ */ jsx(Table.Root, { rows: documents, defaultSelectedRows: documents, headers: TABLE_HEADERS, children: /* @__PURE__ */ jsx(
|
3489
|
+
SelectedEntriesModalContent,
|
3490
|
+
{
|
3491
|
+
listViewSelectedEntries: documents,
|
3492
|
+
toggleModal: () => {
|
3493
|
+
onClose();
|
3494
|
+
refetchList();
|
3495
|
+
},
|
3496
|
+
setListViewSelectedDocuments,
|
3497
|
+
model
|
3498
|
+
}
|
3499
|
+
) });
|
3500
|
+
},
|
3501
|
+
onClose: () => {
|
3502
|
+
refetchList();
|
3503
|
+
}
|
2636
3504
|
}
|
2637
|
-
onModalClose();
|
2638
3505
|
};
|
2639
|
-
|
2640
|
-
|
2641
|
-
|
2642
|
-
|
3506
|
+
};
|
3507
|
+
const BulkActionsRenderer = () => {
|
3508
|
+
const plugins = useStrapiApp("BulkActionsRenderer", (state) => state.plugins);
|
3509
|
+
const { model, collectionType } = useDoc();
|
3510
|
+
const { selectedRows } = useTable("BulkActionsRenderer", (state) => state);
|
3511
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 2, children: /* @__PURE__ */ jsx(
|
3512
|
+
DescriptionComponentRenderer,
|
3513
|
+
{
|
3514
|
+
props: {
|
3515
|
+
model,
|
3516
|
+
collectionType,
|
3517
|
+
documents: selectedRows
|
3518
|
+
},
|
3519
|
+
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3520
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
3521
|
+
}
|
3522
|
+
) });
|
2643
3523
|
};
|
2644
3524
|
const DeleteAction = ({ documents, model }) => {
|
2645
3525
|
const { formatMessage } = useIntl();
|
@@ -2673,6 +3553,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
2673
3553
|
defaultMessage: "Confirmation"
|
2674
3554
|
}),
|
2675
3555
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3556
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
2676
3557
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
2677
3558
|
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
2678
3559
|
defaultMessage: "Are you sure you want to delete these entries?"
|
@@ -2709,7 +3590,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
2709
3590
|
selectRow([]);
|
2710
3591
|
}
|
2711
3592
|
};
|
2712
|
-
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
|
3593
|
+
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
2713
3594
|
if (!showUnpublishButton)
|
2714
3595
|
return null;
|
2715
3596
|
return {
|
@@ -2722,6 +3603,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
2722
3603
|
defaultMessage: "Confirmation"
|
2723
3604
|
}),
|
2724
3605
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3606
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
2725
3607
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
2726
3608
|
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
2727
3609
|
defaultMessage: "Are you sure you want to unpublish these entries?"
|
@@ -2746,7 +3628,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
2746
3628
|
};
|
2747
3629
|
UnpublishAction.type = "unpublish";
|
2748
3630
|
const Emphasis = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", textColor: "danger500", children: chunks });
|
2749
|
-
const DEFAULT_BULK_ACTIONS = [UnpublishAction, DeleteAction];
|
3631
|
+
const DEFAULT_BULK_ACTIONS = [PublishAction, UnpublishAction, DeleteAction];
|
2750
3632
|
const AutoCloneFailureModalBody = ({ prohibitedFields }) => {
|
2751
3633
|
const { formatMessage } = useIntl();
|
2752
3634
|
const getDefaultErrorMessage = (reason) => {
|
@@ -2815,7 +3697,7 @@ const TableActions = ({ document }) => {
|
|
2815
3697
|
DescriptionComponentRenderer,
|
2816
3698
|
{
|
2817
3699
|
props,
|
2818
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3700
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
2819
3701
|
children: (actions2) => {
|
2820
3702
|
const tableRowActions = actions2.filter((action) => {
|
2821
3703
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -2926,7 +3808,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
2926
3808
|
}),
|
2927
3809
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
2928
3810
|
footer: ({ onClose }) => {
|
2929
|
-
return /* @__PURE__ */ jsxs(
|
3811
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
2930
3812
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
2931
3813
|
id: "cancel",
|
2932
3814
|
defaultMessage: "Cancel"
|
@@ -2967,8 +3849,7 @@ class ContentManagerPlugin {
|
|
2967
3849
|
documentActions = [
|
2968
3850
|
...DEFAULT_ACTIONS,
|
2969
3851
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
2970
|
-
...DEFAULT_HEADER_ACTIONS
|
2971
|
-
HistoryAction
|
3852
|
+
...DEFAULT_HEADER_ACTIONS
|
2972
3853
|
];
|
2973
3854
|
editViewSidePanels = [ActionsPanel];
|
2974
3855
|
headerActions = [];
|
@@ -3057,6 +3938,52 @@ const getPrintableType = (value) => {
|
|
3057
3938
|
}
|
3058
3939
|
return nativeType;
|
3059
3940
|
};
|
3941
|
+
const HistoryAction = ({ model, document }) => {
|
3942
|
+
const { formatMessage } = useIntl();
|
3943
|
+
const [{ query }] = useQueryParams();
|
3944
|
+
const navigate = useNavigate();
|
3945
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3946
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3947
|
+
return null;
|
3948
|
+
}
|
3949
|
+
return {
|
3950
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3951
|
+
label: formatMessage({
|
3952
|
+
id: "content-manager.history.document-action",
|
3953
|
+
defaultMessage: "Content History"
|
3954
|
+
}),
|
3955
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3956
|
+
disabled: (
|
3957
|
+
/**
|
3958
|
+
* The user is creating a new document.
|
3959
|
+
* It hasn't been saved yet, so there's no history to go to
|
3960
|
+
*/
|
3961
|
+
!document || /**
|
3962
|
+
* The document has been created but the current dimension has never been saved.
|
3963
|
+
* For example, the user is creating a new locale in an existing document,
|
3964
|
+
* so there's no history for the document in that locale
|
3965
|
+
*/
|
3966
|
+
!document.id || /**
|
3967
|
+
* History is only available for content types created by the user.
|
3968
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3969
|
+
* which start with `admin::` or `plugin::`
|
3970
|
+
*/
|
3971
|
+
!model.startsWith("api::")
|
3972
|
+
),
|
3973
|
+
position: "header"
|
3974
|
+
};
|
3975
|
+
};
|
3976
|
+
HistoryAction.type = "history";
|
3977
|
+
const historyAdmin = {
|
3978
|
+
bootstrap(app) {
|
3979
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3980
|
+
addDocumentAction((actions2) => {
|
3981
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3982
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3983
|
+
return actions2;
|
3984
|
+
});
|
3985
|
+
}
|
3986
|
+
};
|
3060
3987
|
const initialState = {
|
3061
3988
|
collectionTypeLinks: [],
|
3062
3989
|
components: [],
|
@@ -3093,308 +4020,6 @@ const { setInitialData } = actions;
|
|
3093
4020
|
const reducer = combineReducers({
|
3094
4021
|
app: reducer$1
|
3095
4022
|
});
|
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
4023
|
const index = {
|
3399
4024
|
register(app) {
|
3400
4025
|
const cm = new ContentManagerPlugin();
|
@@ -3409,15 +4034,29 @@ const index = {
|
|
3409
4034
|
defaultMessage: "Content Manager"
|
3410
4035
|
},
|
3411
4036
|
permissions: [],
|
3412
|
-
Component: () => import("./layout-BinjszSQ.mjs").then((mod) => ({ default: mod.Layout })),
|
3413
4037
|
position: 1
|
3414
4038
|
});
|
4039
|
+
app.router.addRoute({
|
4040
|
+
path: "content-manager/*",
|
4041
|
+
lazy: async () => {
|
4042
|
+
const { Layout } = await import("./layout-aX-RJhd5.mjs");
|
4043
|
+
return {
|
4044
|
+
Component: Layout
|
4045
|
+
};
|
4046
|
+
},
|
4047
|
+
children: routes
|
4048
|
+
});
|
3415
4049
|
app.registerPlugin(cm.config);
|
3416
4050
|
},
|
4051
|
+
bootstrap(app) {
|
4052
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4053
|
+
historyAdmin.bootstrap(app);
|
4054
|
+
}
|
4055
|
+
},
|
3417
4056
|
async registerTrads({ locales }) {
|
3418
4057
|
const importedTrads = await Promise.all(
|
3419
4058
|
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-
|
4059
|
+
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
4060
|
return {
|
3422
4061
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3423
4062
|
locale
|
@@ -3445,36 +4084,37 @@ export {
|
|
3445
4084
|
InjectionZone as I,
|
3446
4085
|
useDocument as J,
|
3447
4086
|
index as K,
|
3448
|
-
|
4087
|
+
useContentManagerContext as L,
|
4088
|
+
useDocumentActions as M,
|
3449
4089
|
Panels as P,
|
3450
4090
|
RelativeTime as R,
|
3451
4091
|
SINGLE_TYPES as S,
|
3452
4092
|
TableActions as T,
|
3453
|
-
|
3454
|
-
|
3455
|
-
|
3456
|
-
|
3457
|
-
|
3458
|
-
|
4093
|
+
useGetInitialDataQuery as a,
|
4094
|
+
useGetAllContentTypeSettingsQuery as b,
|
4095
|
+
useDoc as c,
|
4096
|
+
buildValidParams as d,
|
4097
|
+
contentManagerApi as e,
|
4098
|
+
useDocumentRBAC as f,
|
3459
4099
|
getTranslation as g,
|
3460
|
-
|
3461
|
-
|
3462
|
-
|
3463
|
-
|
3464
|
-
|
3465
|
-
|
3466
|
-
|
3467
|
-
|
3468
|
-
|
3469
|
-
|
3470
|
-
|
4100
|
+
useDocumentLayout as h,
|
4101
|
+
createYupSchema as i,
|
4102
|
+
Header as j,
|
4103
|
+
PERMISSIONS as k,
|
4104
|
+
DocumentRBAC as l,
|
4105
|
+
DOCUMENT_META_FIELDS as m,
|
4106
|
+
CLONE_PATH as n,
|
4107
|
+
useDocLayout as o,
|
4108
|
+
useGetContentTypeConfigurationQuery as p,
|
4109
|
+
CREATOR_FIELDS as q,
|
4110
|
+
getMainField as r,
|
3471
4111
|
setInitialData as s,
|
3472
4112
|
getDisplayName as t,
|
3473
|
-
|
4113
|
+
useContentTypeSchema as u,
|
3474
4114
|
checkIfAttributeIsDisplayable as v,
|
3475
4115
|
useGetAllDocumentsQuery as w,
|
3476
4116
|
convertListLayoutToFieldLayouts as x,
|
3477
4117
|
capitalise as y,
|
3478
4118
|
useUpdateContentTypeConfigurationMutation as z
|
3479
4119
|
};
|
3480
|
-
//# sourceMappingURL=index-
|
4120
|
+
//# sourceMappingURL=index-TaRzG09p.mjs.map
|