@strapi/content-manager 0.0.0-experimental.7afdc9b682bc83a53ce599c4fb7c9e4506b31fff → 0.0.0-experimental.7b750d18de359d0a42233cb8707e3c31c5983345
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-DJcn1DrO.js → ComponentConfigurationPage-DnnZJc1F.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-DJcn1DrO.js.map → ComponentConfigurationPage-DnnZJc1F.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs → ComponentConfigurationPage-hLMNf7KI.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-CR5XdR33.mjs.map → ComponentConfigurationPage-hLMNf7KI.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js → EditConfigurationPage-CpLj5gYZ.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-tDtWj7R2.js.map → EditConfigurationPage-CpLj5gYZ.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs → EditConfigurationPage-Dh6sq-G4.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-DmCIb4kD.mjs.map → EditConfigurationPage-Dh6sq-G4.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-DvaV7U9b.mjs → EditViewPage-BU1ugeVi.mjs} +58 -47
- package/dist/_chunks/EditViewPage-BU1ugeVi.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-CoQEnFlC.js → EditViewPage-D2QVRr_2.js} +57 -46
- package/dist/_chunks/EditViewPage-D2QVRr_2.js.map +1 -0
- package/dist/_chunks/{Field-ZdrmmQ4Y.js → Field-BEDX9i_V.js} +528 -220
- package/dist/_chunks/Field-BEDX9i_V.js.map +1 -0
- package/dist/_chunks/{Field-Cz_J9551.mjs → Field-VSPY6uzs.mjs} +526 -218
- package/dist/_chunks/Field-VSPY6uzs.mjs.map +1 -0
- package/dist/_chunks/{Form-Dxmihyw8.mjs → Form-05Oaes1N.mjs} +53 -35
- package/dist/_chunks/Form-05Oaes1N.mjs.map +1 -0
- package/dist/_chunks/{Form-Bpig5rch.js → Form-DCaY8xBX.js} +51 -33
- package/dist/_chunks/Form-DCaY8xBX.js.map +1 -0
- package/dist/_chunks/{History-BZP8n7KT.mjs → History-BqO2G3MV.mjs} +141 -37
- package/dist/_chunks/History-BqO2G3MV.mjs.map +1 -0
- package/dist/_chunks/{History-BfX6XmZK.js → History-BrJ1tUvt.js} +140 -36
- package/dist/_chunks/History-BrJ1tUvt.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DxKuVkKz.mjs → ListConfigurationPage-C6rsFlme.mjs} +58 -48
- package/dist/_chunks/ListConfigurationPage-C6rsFlme.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-B3CXj8PY.js → ListConfigurationPage-Eane5LKE.js} +57 -46
- package/dist/_chunks/ListConfigurationPage-Eane5LKE.js.map +1 -0
- package/dist/_chunks/{ListViewPage-Bk9VO__I.js → ListViewPage-Coj-RPsx.js} +105 -104
- package/dist/_chunks/ListViewPage-Coj-RPsx.js.map +1 -0
- package/dist/_chunks/{ListViewPage-D5D3tVPq.mjs → ListViewPage-yE_zYhcI.mjs} +103 -102
- package/dist/_chunks/ListViewPage-yE_zYhcI.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js → NoContentTypePage-BDJ0dshy.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-DsB2F7Z1.js.map → NoContentTypePage-BDJ0dshy.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs → NoContentTypePage-NW_FSVdY.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-DnMeuQCj.mjs.map → NoContentTypePage-NW_FSVdY.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js → NoPermissionsPage-BOtb5FTM.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BQDM64_b.js.map → NoPermissionsPage-BOtb5FTM.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs → NoPermissionsPage-h0I3ImsX.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-OyoME_Tf.mjs.map → NoPermissionsPage-h0I3ImsX.mjs.map} +1 -1
- package/dist/_chunks/{Relations-B6B3A3mb.js → Relations-CVh0DOKv.js} +4 -4
- package/dist/_chunks/Relations-CVh0DOKv.js.map +1 -0
- package/dist/_chunks/{Relations-BOYZmuWy.mjs → Relations-FP0uWpBz.mjs} +4 -4
- package/dist/_chunks/Relations-FP0uWpBz.mjs.map +1 -0
- package/dist/_chunks/{en-BN1bvFK7.js → en-BlhnxQfj.js} +14 -9
- package/dist/_chunks/{en-BN1bvFK7.js.map → en-BlhnxQfj.js.map} +1 -1
- package/dist/_chunks/{en-Dzv55oQw.mjs → en-C8YBvRrK.mjs} +14 -9
- package/dist/_chunks/{en-Dzv55oQw.mjs.map → en-C8YBvRrK.mjs.map} +1 -1
- package/dist/_chunks/{index-VHviNMeW.mjs → index-CPCHQ3X_.mjs} +1031 -874
- package/dist/_chunks/index-CPCHQ3X_.mjs.map +1 -0
- package/dist/_chunks/{index-DzN3kBgx.js → index-DTKVhcla.js} +1008 -851
- package/dist/_chunks/index-DTKVhcla.js.map +1 -0
- package/dist/_chunks/{layout-CPn1PM6x.mjs → layout-B4UhJ8MJ.mjs} +41 -23
- package/dist/_chunks/layout-B4UhJ8MJ.mjs.map +1 -0
- package/dist/_chunks/{layout-b91XRlD2.js → layout-CWgZzMYf.js} +39 -21
- package/dist/_chunks/layout-CWgZzMYf.js.map +1 -0
- package/dist/_chunks/{relations-BsqxS6tR.mjs → relations-B83Ge9a7.mjs} +2 -2
- package/dist/_chunks/{relations-BsqxS6tR.mjs.map → relations-B83Ge9a7.mjs.map} +1 -1
- package/dist/_chunks/{relations-CA7IYmcP.js → relations-D81a_2zw.js} +2 -2
- package/dist/_chunks/{relations-CA7IYmcP.js.map → relations-D81a_2zw.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 +30 -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 +10 -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/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 +183 -108
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +184 -109
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +11 -11
- package/dist/_chunks/EditViewPage-CoQEnFlC.js.map +0 -1
- package/dist/_chunks/EditViewPage-DvaV7U9b.mjs.map +0 -1
- package/dist/_chunks/Field-Cz_J9551.mjs.map +0 -1
- package/dist/_chunks/Field-ZdrmmQ4Y.js.map +0 -1
- package/dist/_chunks/Form-Bpig5rch.js.map +0 -1
- package/dist/_chunks/Form-Dxmihyw8.mjs.map +0 -1
- package/dist/_chunks/History-BZP8n7KT.mjs.map +0 -1
- package/dist/_chunks/History-BfX6XmZK.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-B3CXj8PY.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DxKuVkKz.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-Bk9VO__I.js.map +0 -1
- package/dist/_chunks/ListViewPage-D5D3tVPq.mjs.map +0 -1
- package/dist/_chunks/Relations-B6B3A3mb.js.map +0 -1
- package/dist/_chunks/Relations-BOYZmuWy.mjs.map +0 -1
- package/dist/_chunks/index-DzN3kBgx.js.map +0 -1
- package/dist/_chunks/index-VHviNMeW.mjs.map +0 -1
- package/dist/_chunks/layout-CPn1PM6x.mjs.map +0 -1
- package/dist/_chunks/layout-b91XRlD2.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,17 +1,17 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp,
|
4
|
-
import { stringify } from "qs";
|
5
|
-
import { useIntl } from "react-intl";
|
6
|
-
import { useNavigate, useParams, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
3
|
+
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, useQueryParams, 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";
|
@@ -194,10 +158,12 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
194
158
|
"Document",
|
195
159
|
"InitialData",
|
196
160
|
"HistoryVersion",
|
197
|
-
"Relations"
|
161
|
+
"Relations",
|
162
|
+
"UidAvailability"
|
198
163
|
]
|
199
164
|
});
|
200
165
|
const documentApi = contentManagerApi.injectEndpoints({
|
166
|
+
overrideExisting: true,
|
201
167
|
endpoints: (builder) => ({
|
202
168
|
autoCloneDocument: builder.mutation({
|
203
169
|
query: ({ model, sourceId, query }) => ({
|
@@ -207,7 +173,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
207
173
|
params: query
|
208
174
|
}
|
209
175
|
}),
|
210
|
-
invalidatesTags: (_result,
|
176
|
+
invalidatesTags: (_result, error, { model }) => {
|
177
|
+
if (error) {
|
178
|
+
return [];
|
179
|
+
}
|
180
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
181
|
+
}
|
211
182
|
}),
|
212
183
|
cloneDocument: builder.mutation({
|
213
184
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -218,7 +189,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
218
189
|
params
|
219
190
|
}
|
220
191
|
}),
|
221
|
-
invalidatesTags: (_result, _error, { model }) => [
|
192
|
+
invalidatesTags: (_result, _error, { model }) => [
|
193
|
+
{ type: "Document", id: `${model}_LIST` },
|
194
|
+
{ type: "UidAvailability", id: model }
|
195
|
+
]
|
222
196
|
}),
|
223
197
|
/**
|
224
198
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -235,7 +209,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
235
209
|
}),
|
236
210
|
invalidatesTags: (result, _error, { model }) => [
|
237
211
|
{ type: "Document", id: `${model}_LIST` },
|
238
|
-
"Relations"
|
212
|
+
"Relations",
|
213
|
+
{ type: "UidAvailability", id: model }
|
239
214
|
]
|
240
215
|
}),
|
241
216
|
deleteDocument: builder.mutation({
|
@@ -276,7 +251,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
276
251
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
277
252
|
},
|
278
253
|
{ type: "Document", id: `${model}_LIST` },
|
279
|
-
"Relations"
|
254
|
+
"Relations",
|
255
|
+
{ type: "UidAvailability", id: model }
|
280
256
|
];
|
281
257
|
}
|
282
258
|
}),
|
@@ -294,6 +270,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
294
270
|
}),
|
295
271
|
providesTags: (result, _error, arg) => {
|
296
272
|
return [
|
273
|
+
{ type: "Document", id: `ALL_LIST` },
|
297
274
|
{ type: "Document", id: `${arg.model}_LIST` },
|
298
275
|
...result?.results.map(({ documentId }) => ({
|
299
276
|
type: "Document",
|
@@ -332,6 +309,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
332
309
|
{
|
333
310
|
type: "Document",
|
334
311
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
312
|
+
},
|
313
|
+
// Make it easy to invalidate all individual documents queries for a model
|
314
|
+
{
|
315
|
+
type: "Document",
|
316
|
+
id: `${model}_ALL_ITEMS`
|
335
317
|
}
|
336
318
|
];
|
337
319
|
}
|
@@ -395,8 +377,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
395
377
|
type: "Document",
|
396
378
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
397
379
|
},
|
398
|
-
"Relations"
|
380
|
+
"Relations",
|
381
|
+
{ type: "UidAvailability", id: model }
|
399
382
|
];
|
383
|
+
},
|
384
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
385
|
+
const patchResult = dispatch(
|
386
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
387
|
+
Object.assign(draft.data, data);
|
388
|
+
})
|
389
|
+
);
|
390
|
+
try {
|
391
|
+
await queryFulfilled;
|
392
|
+
} catch {
|
393
|
+
patchResult.undo();
|
394
|
+
}
|
400
395
|
}
|
401
396
|
}),
|
402
397
|
unpublishDocument: builder.mutation({
|
@@ -466,7 +461,7 @@ const buildValidParams = (query) => {
|
|
466
461
|
const isBaseQueryError = (error) => {
|
467
462
|
return error.name !== void 0;
|
468
463
|
};
|
469
|
-
const createYupSchema = (attributes = {}, components = {}) => {
|
464
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
470
465
|
const createModelSchema = (attributes2) => yup.object().shape(
|
471
466
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
472
467
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
@@ -479,7 +474,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
479
474
|
addMinValidation,
|
480
475
|
addMaxValidation,
|
481
476
|
addRegexValidation
|
482
|
-
].map((fn) => fn(attribute));
|
477
|
+
].map((fn) => fn(attribute, options));
|
483
478
|
const transformSchema = pipe(...validations);
|
484
479
|
switch (attribute.type) {
|
485
480
|
case "component": {
|
@@ -580,6 +575,14 @@ const createAttributeSchema = (attribute) => {
|
|
580
575
|
if (!value || typeof value === "string" && value.length === 0) {
|
581
576
|
return true;
|
582
577
|
}
|
578
|
+
if (typeof value === "object") {
|
579
|
+
try {
|
580
|
+
JSON.stringify(value);
|
581
|
+
return true;
|
582
|
+
} catch (err) {
|
583
|
+
return false;
|
584
|
+
}
|
585
|
+
}
|
583
586
|
try {
|
584
587
|
JSON.parse(value);
|
585
588
|
return true;
|
@@ -598,13 +601,7 @@ const createAttributeSchema = (attribute) => {
|
|
598
601
|
return yup.mixed();
|
599
602
|
}
|
600
603
|
};
|
601
|
-
const
|
602
|
-
if (attribute.required) {
|
603
|
-
return schema.required({
|
604
|
-
id: translatedErrors.required.id,
|
605
|
-
defaultMessage: "This field is required."
|
606
|
-
});
|
607
|
-
}
|
604
|
+
const nullableSchema = (schema) => {
|
608
605
|
return schema?.nullable ? schema.nullable() : (
|
609
606
|
// In some cases '.nullable' will not be available on the schema.
|
610
607
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -612,7 +609,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
612
609
|
schema
|
613
610
|
);
|
614
611
|
};
|
615
|
-
const
|
612
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
613
|
+
if (options.status === "draft") {
|
614
|
+
return nullableSchema(schema);
|
615
|
+
}
|
616
|
+
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
617
|
+
return schema.min(1, translatedErrors.required);
|
618
|
+
}
|
619
|
+
if (attribute.required && attribute.type !== "relation") {
|
620
|
+
return schema.required(translatedErrors.required);
|
621
|
+
}
|
622
|
+
return nullableSchema(schema);
|
623
|
+
};
|
624
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
625
|
+
if (options.status === "draft") {
|
626
|
+
return schema;
|
627
|
+
}
|
616
628
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
617
629
|
return schema.min(attribute.minLength, {
|
618
630
|
...translatedErrors.minLength,
|
@@ -634,9 +646,31 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
634
646
|
}
|
635
647
|
return schema;
|
636
648
|
};
|
637
|
-
const addMinValidation = (attribute) => (schema) => {
|
649
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
638
650
|
if ("min" in attribute) {
|
639
651
|
const min = toInteger(attribute.min);
|
652
|
+
if (attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") {
|
653
|
+
if (options.status !== "draft" && !attribute.required && "test" in schema && min) {
|
654
|
+
return schema.test(
|
655
|
+
"custom-min",
|
656
|
+
{
|
657
|
+
...translatedErrors.min,
|
658
|
+
values: {
|
659
|
+
min: attribute.min
|
660
|
+
}
|
661
|
+
},
|
662
|
+
(value) => {
|
663
|
+
if (!value) {
|
664
|
+
return true;
|
665
|
+
}
|
666
|
+
if (Array.isArray(value) && value.length === 0) {
|
667
|
+
return true;
|
668
|
+
}
|
669
|
+
return value.length >= min;
|
670
|
+
}
|
671
|
+
);
|
672
|
+
}
|
673
|
+
}
|
640
674
|
if ("min" in schema && min) {
|
641
675
|
return schema.min(min, {
|
642
676
|
...translatedErrors.min,
|
@@ -755,16 +789,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
755
789
|
}, {});
|
756
790
|
return componentsByKey;
|
757
791
|
};
|
758
|
-
const
|
792
|
+
const HOOKS = {
|
793
|
+
/**
|
794
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
795
|
+
* @constant
|
796
|
+
* @type {string}
|
797
|
+
*/
|
798
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
799
|
+
/**
|
800
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
801
|
+
* @constant
|
802
|
+
* @type {string}
|
803
|
+
*/
|
804
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
805
|
+
/**
|
806
|
+
* Hook that allows to mutate the CM's edit view layout
|
807
|
+
* @constant
|
808
|
+
* @type {string}
|
809
|
+
*/
|
810
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
811
|
+
/**
|
812
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
813
|
+
* @constant
|
814
|
+
* @type {string}
|
815
|
+
*/
|
816
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
817
|
+
};
|
818
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
819
|
+
endpoints: (builder) => ({
|
820
|
+
getContentTypeConfiguration: builder.query({
|
821
|
+
query: (uid) => ({
|
822
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
823
|
+
method: "GET"
|
824
|
+
}),
|
825
|
+
transformResponse: (response) => response.data,
|
826
|
+
providesTags: (_result, _error, uid) => [
|
827
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
828
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
829
|
+
]
|
830
|
+
}),
|
831
|
+
getAllContentTypeSettings: builder.query({
|
832
|
+
query: () => "/content-manager/content-types-settings",
|
833
|
+
transformResponse: (response) => response.data,
|
834
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
835
|
+
}),
|
836
|
+
updateContentTypeConfiguration: builder.mutation({
|
837
|
+
query: ({ uid, ...body }) => ({
|
838
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
839
|
+
method: "PUT",
|
840
|
+
data: body
|
841
|
+
}),
|
842
|
+
transformResponse: (response) => response.data,
|
843
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
844
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
845
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
846
|
+
// Is this necessary?
|
847
|
+
{ type: "InitialData" }
|
848
|
+
]
|
849
|
+
})
|
850
|
+
})
|
851
|
+
});
|
852
|
+
const {
|
853
|
+
useGetContentTypeConfigurationQuery,
|
854
|
+
useGetAllContentTypeSettingsQuery,
|
855
|
+
useUpdateContentTypeConfigurationMutation
|
856
|
+
} = contentTypesApi;
|
857
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
858
|
+
const { type } = attribute;
|
859
|
+
if (type === "relation") {
|
860
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
861
|
+
}
|
862
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
863
|
+
};
|
864
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
865
|
+
if (!mainFieldName) {
|
866
|
+
return void 0;
|
867
|
+
}
|
868
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
869
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
870
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
871
|
+
);
|
872
|
+
return {
|
873
|
+
name: mainFieldName,
|
874
|
+
type: mainFieldType ?? "string"
|
875
|
+
};
|
876
|
+
};
|
877
|
+
const DEFAULT_SETTINGS = {
|
878
|
+
bulkable: false,
|
879
|
+
filterable: false,
|
880
|
+
searchable: false,
|
881
|
+
pagination: false,
|
882
|
+
defaultSortBy: "",
|
883
|
+
defaultSortOrder: "asc",
|
884
|
+
mainField: "id",
|
885
|
+
pageSize: 10
|
886
|
+
};
|
887
|
+
const useDocumentLayout = (model) => {
|
888
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
889
|
+
const [{ query }] = useQueryParams();
|
890
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
759
891
|
const { toggleNotification } = useNotification();
|
760
892
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
893
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
761
894
|
const {
|
762
|
-
|
763
|
-
isLoading:
|
764
|
-
|
765
|
-
|
766
|
-
} =
|
767
|
-
const
|
895
|
+
data,
|
896
|
+
isLoading: isLoadingConfigs,
|
897
|
+
error,
|
898
|
+
isFetching: isFetchingConfigs
|
899
|
+
} = useGetContentTypeConfigurationQuery(model);
|
900
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
768
901
|
React.useEffect(() => {
|
769
902
|
if (error) {
|
770
903
|
toggleNotification({
|
@@ -772,56 +905,269 @@ const useDocument = (args, opts) => {
|
|
772
905
|
message: formatAPIError(error)
|
773
906
|
});
|
774
907
|
}
|
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
|
-
}
|
908
|
+
}, [error, formatAPIError, toggleNotification]);
|
909
|
+
const editLayout = React.useMemo(
|
910
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
911
|
+
layout: [],
|
912
|
+
components: {},
|
913
|
+
metadatas: {},
|
914
|
+
options: {},
|
915
|
+
settings: DEFAULT_SETTINGS
|
798
916
|
},
|
799
|
-
[
|
917
|
+
[data, isLoading, schemas, schema, components]
|
918
|
+
);
|
919
|
+
const listLayout = React.useMemo(() => {
|
920
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
921
|
+
layout: [],
|
922
|
+
metadatas: {},
|
923
|
+
options: {},
|
924
|
+
settings: DEFAULT_SETTINGS
|
925
|
+
};
|
926
|
+
}, [data, isLoading, schemas, schema, components]);
|
927
|
+
const { layout: edit } = React.useMemo(
|
928
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
929
|
+
layout: editLayout,
|
930
|
+
query
|
931
|
+
}),
|
932
|
+
[editLayout, query, runHookWaterfall]
|
800
933
|
);
|
801
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
802
934
|
return {
|
803
|
-
|
804
|
-
document: data?.data,
|
805
|
-
meta: data?.meta,
|
935
|
+
error,
|
806
936
|
isLoading,
|
807
|
-
|
808
|
-
|
937
|
+
edit,
|
938
|
+
list: listLayout
|
809
939
|
};
|
810
940
|
};
|
811
|
-
const
|
812
|
-
const {
|
813
|
-
|
814
|
-
|
815
|
-
|
816
|
-
|
817
|
-
|
818
|
-
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
941
|
+
const useDocLayout = () => {
|
942
|
+
const { model } = useDoc();
|
943
|
+
return useDocumentLayout(model);
|
944
|
+
};
|
945
|
+
const formatEditLayout = (data, {
|
946
|
+
schemas,
|
947
|
+
schema,
|
948
|
+
components
|
949
|
+
}) => {
|
950
|
+
let currentPanelIndex = 0;
|
951
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
952
|
+
data.contentType.layouts.edit,
|
953
|
+
schema?.attributes,
|
954
|
+
data.contentType.metadatas,
|
955
|
+
{ configurations: data.components, schemas: components },
|
956
|
+
schemas
|
957
|
+
).reduce((panels, row) => {
|
958
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
959
|
+
panels.push([row]);
|
960
|
+
currentPanelIndex += 2;
|
961
|
+
} else {
|
962
|
+
if (!panels[currentPanelIndex]) {
|
963
|
+
panels.push([]);
|
964
|
+
}
|
965
|
+
panels[currentPanelIndex].push(row);
|
966
|
+
}
|
967
|
+
return panels;
|
968
|
+
}, []);
|
969
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
970
|
+
(acc, [uid, configuration]) => {
|
971
|
+
acc[uid] = {
|
972
|
+
layout: convertEditLayoutToFieldLayouts(
|
973
|
+
configuration.layouts.edit,
|
974
|
+
components[uid].attributes,
|
975
|
+
configuration.metadatas,
|
976
|
+
{ configurations: data.components, schemas: components }
|
977
|
+
),
|
978
|
+
settings: {
|
979
|
+
...configuration.settings,
|
980
|
+
icon: components[uid].info.icon,
|
981
|
+
displayName: components[uid].info.displayName
|
982
|
+
}
|
983
|
+
};
|
984
|
+
return acc;
|
985
|
+
},
|
986
|
+
{}
|
987
|
+
);
|
988
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
989
|
+
(acc, [attribute, metadata]) => {
|
990
|
+
return {
|
991
|
+
...acc,
|
992
|
+
[attribute]: metadata.edit
|
993
|
+
};
|
994
|
+
},
|
995
|
+
{}
|
996
|
+
);
|
997
|
+
return {
|
998
|
+
layout: panelledEditAttributes,
|
999
|
+
components: componentEditAttributes,
|
1000
|
+
metadatas: editMetadatas,
|
1001
|
+
settings: {
|
1002
|
+
...data.contentType.settings,
|
1003
|
+
displayName: schema?.info.displayName
|
1004
|
+
},
|
1005
|
+
options: {
|
1006
|
+
...schema?.options,
|
1007
|
+
...schema?.pluginOptions,
|
1008
|
+
...data.contentType.options
|
1009
|
+
}
|
1010
|
+
};
|
1011
|
+
};
|
1012
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1013
|
+
return rows.map(
|
1014
|
+
(row) => row.map((field) => {
|
1015
|
+
const attribute = attributes[field.name];
|
1016
|
+
if (!attribute) {
|
1017
|
+
return null;
|
1018
|
+
}
|
1019
|
+
const { edit: metadata } = metadatas[field.name];
|
1020
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1021
|
+
return {
|
1022
|
+
attribute,
|
1023
|
+
disabled: !metadata.editable,
|
1024
|
+
hint: metadata.description,
|
1025
|
+
label: metadata.label ?? "",
|
1026
|
+
name: field.name,
|
1027
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1028
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1029
|
+
schemas,
|
1030
|
+
components: components?.schemas ?? {}
|
1031
|
+
}),
|
1032
|
+
placeholder: metadata.placeholder ?? "",
|
1033
|
+
required: attribute.required ?? false,
|
1034
|
+
size: field.size,
|
1035
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1036
|
+
visible: metadata.visible ?? true,
|
1037
|
+
type: attribute.type
|
1038
|
+
};
|
1039
|
+
}).filter((field) => field !== null)
|
1040
|
+
);
|
1041
|
+
};
|
1042
|
+
const formatListLayout = (data, {
|
1043
|
+
schemas,
|
1044
|
+
schema,
|
1045
|
+
components
|
1046
|
+
}) => {
|
1047
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1048
|
+
(acc, [attribute, metadata]) => {
|
1049
|
+
return {
|
1050
|
+
...acc,
|
1051
|
+
[attribute]: metadata.list
|
1052
|
+
};
|
1053
|
+
},
|
1054
|
+
{}
|
1055
|
+
);
|
1056
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1057
|
+
data.contentType.layouts.list,
|
1058
|
+
schema?.attributes,
|
1059
|
+
listMetadatas,
|
1060
|
+
{ configurations: data.components, schemas: components },
|
1061
|
+
schemas
|
1062
|
+
);
|
1063
|
+
return {
|
1064
|
+
layout: listAttributes,
|
1065
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1066
|
+
metadatas: listMetadatas,
|
1067
|
+
options: {
|
1068
|
+
...schema?.options,
|
1069
|
+
...schema?.pluginOptions,
|
1070
|
+
...data.contentType.options
|
1071
|
+
}
|
1072
|
+
};
|
1073
|
+
};
|
1074
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1075
|
+
return columns.map((name) => {
|
1076
|
+
const attribute = attributes[name];
|
1077
|
+
if (!attribute) {
|
1078
|
+
return null;
|
1079
|
+
}
|
1080
|
+
const metadata = metadatas[name];
|
1081
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1082
|
+
return {
|
1083
|
+
attribute,
|
1084
|
+
label: metadata.label ?? "",
|
1085
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1086
|
+
schemas,
|
1087
|
+
components: components?.schemas ?? {}
|
1088
|
+
}),
|
1089
|
+
name,
|
1090
|
+
searchable: metadata.searchable ?? true,
|
1091
|
+
sortable: metadata.sortable ?? true
|
1092
|
+
};
|
1093
|
+
}).filter((field) => field !== null);
|
1094
|
+
};
|
1095
|
+
const useDocument = (args, opts) => {
|
1096
|
+
const { toggleNotification } = useNotification();
|
1097
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1098
|
+
const {
|
1099
|
+
currentData: data,
|
1100
|
+
isLoading: isLoadingDocument,
|
1101
|
+
isFetching: isFetchingDocument,
|
1102
|
+
error
|
1103
|
+
} = useGetDocumentQuery(args, {
|
1104
|
+
...opts,
|
1105
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1106
|
+
});
|
1107
|
+
const {
|
1108
|
+
components,
|
1109
|
+
schema,
|
1110
|
+
schemas,
|
1111
|
+
isLoading: isLoadingSchema
|
1112
|
+
} = useContentTypeSchema(args.model);
|
1113
|
+
React.useEffect(() => {
|
1114
|
+
if (error) {
|
1115
|
+
toggleNotification({
|
1116
|
+
type: "danger",
|
1117
|
+
message: formatAPIError(error)
|
1118
|
+
});
|
1119
|
+
}
|
1120
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1121
|
+
const validationSchema = React.useMemo(() => {
|
1122
|
+
if (!schema) {
|
1123
|
+
return null;
|
1124
|
+
}
|
1125
|
+
return createYupSchema(schema.attributes, components);
|
1126
|
+
}, [schema, components]);
|
1127
|
+
const validate = React.useCallback(
|
1128
|
+
(document) => {
|
1129
|
+
if (!validationSchema) {
|
1130
|
+
throw new Error(
|
1131
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1132
|
+
);
|
1133
|
+
}
|
1134
|
+
try {
|
1135
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1136
|
+
return null;
|
1137
|
+
} catch (error2) {
|
1138
|
+
if (error2 instanceof ValidationError) {
|
1139
|
+
return getYupValidationErrors(error2);
|
1140
|
+
}
|
1141
|
+
throw error2;
|
1142
|
+
}
|
1143
|
+
},
|
1144
|
+
[validationSchema]
|
1145
|
+
);
|
1146
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1147
|
+
return {
|
1148
|
+
components,
|
1149
|
+
document: data?.data,
|
1150
|
+
meta: data?.meta,
|
1151
|
+
isLoading,
|
1152
|
+
schema,
|
1153
|
+
schemas,
|
1154
|
+
validate
|
1155
|
+
};
|
1156
|
+
};
|
1157
|
+
const useDoc = () => {
|
1158
|
+
const { id, slug, collectionType, origin } = useParams();
|
1159
|
+
const [{ query }] = useQueryParams();
|
1160
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1161
|
+
if (!collectionType) {
|
1162
|
+
throw new Error("Could not find collectionType in url params");
|
1163
|
+
}
|
1164
|
+
if (!slug) {
|
1165
|
+
throw new Error("Could not find model in url params");
|
1166
|
+
}
|
1167
|
+
return {
|
1168
|
+
collectionType,
|
1169
|
+
model: slug,
|
1170
|
+
id: origin || id === "create" ? void 0 : id,
|
825
1171
|
...useDocument(
|
826
1172
|
{ documentId: origin || id, model: slug, collectionType, params },
|
827
1173
|
{
|
@@ -830,6 +1176,45 @@ const useDoc = () => {
|
|
830
1176
|
)
|
831
1177
|
};
|
832
1178
|
};
|
1179
|
+
const useContentManagerContext = () => {
|
1180
|
+
const {
|
1181
|
+
collectionType,
|
1182
|
+
model,
|
1183
|
+
id,
|
1184
|
+
components,
|
1185
|
+
isLoading: isLoadingDoc,
|
1186
|
+
schema,
|
1187
|
+
schemas
|
1188
|
+
} = useDoc();
|
1189
|
+
const layout = useDocumentLayout(model);
|
1190
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1191
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1192
|
+
const slug = model;
|
1193
|
+
const isCreatingEntry = id === "create";
|
1194
|
+
useContentTypeSchema();
|
1195
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1196
|
+
const error = layout.error;
|
1197
|
+
return {
|
1198
|
+
error,
|
1199
|
+
isLoading,
|
1200
|
+
// Base metadata
|
1201
|
+
model,
|
1202
|
+
collectionType,
|
1203
|
+
id,
|
1204
|
+
slug,
|
1205
|
+
isCreatingEntry,
|
1206
|
+
isSingleType,
|
1207
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1208
|
+
// All schema infos
|
1209
|
+
components,
|
1210
|
+
contentType: schema,
|
1211
|
+
contentTypes: schemas,
|
1212
|
+
// Form state
|
1213
|
+
form,
|
1214
|
+
// layout infos
|
1215
|
+
layout
|
1216
|
+
};
|
1217
|
+
};
|
833
1218
|
const prefixPluginTranslations = (trad, pluginId) => {
|
834
1219
|
if (!pluginId) {
|
835
1220
|
throw new TypeError("pluginId can't be empty");
|
@@ -849,6 +1234,8 @@ const useDocumentActions = () => {
|
|
849
1234
|
const { formatMessage } = useIntl();
|
850
1235
|
const { trackUsage } = useTracking();
|
851
1236
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1237
|
+
const navigate = useNavigate();
|
1238
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
852
1239
|
const [deleteDocument] = useDeleteDocumentMutation();
|
853
1240
|
const _delete = React.useCallback(
|
854
1241
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -927,12 +1314,13 @@ const useDocumentActions = () => {
|
|
927
1314
|
);
|
928
1315
|
const [discardDocument] = useDiscardDocumentMutation();
|
929
1316
|
const discard = React.useCallback(
|
930
|
-
async ({ collectionType, model, documentId }) => {
|
1317
|
+
async ({ collectionType, model, documentId, params }) => {
|
931
1318
|
try {
|
932
1319
|
const res = await discardDocument({
|
933
1320
|
collectionType,
|
934
1321
|
model,
|
935
|
-
documentId
|
1322
|
+
documentId,
|
1323
|
+
params
|
936
1324
|
});
|
937
1325
|
if ("error" in res) {
|
938
1326
|
toggleNotification({
|
@@ -1162,6 +1550,7 @@ const useDocumentActions = () => {
|
|
1162
1550
|
defaultMessage: "Saved document"
|
1163
1551
|
})
|
1164
1552
|
});
|
1553
|
+
setCurrentStep("contentManager.success");
|
1165
1554
|
return res.data;
|
1166
1555
|
} catch (err) {
|
1167
1556
|
toggleNotification({
|
@@ -1183,7 +1572,6 @@ const useDocumentActions = () => {
|
|
1183
1572
|
sourceId
|
1184
1573
|
});
|
1185
1574
|
if ("error" in res) {
|
1186
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1187
1575
|
return { error: res.error };
|
1188
1576
|
}
|
1189
1577
|
toggleNotification({
|
@@ -1202,7 +1590,7 @@ const useDocumentActions = () => {
|
|
1202
1590
|
throw err;
|
1203
1591
|
}
|
1204
1592
|
},
|
1205
|
-
[autoCloneDocument,
|
1593
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1206
1594
|
);
|
1207
1595
|
const [cloneDocument] = useCloneDocumentMutation();
|
1208
1596
|
const clone = React.useCallback(
|
@@ -1228,6 +1616,7 @@ const useDocumentActions = () => {
|
|
1228
1616
|
defaultMessage: "Cloned document"
|
1229
1617
|
})
|
1230
1618
|
});
|
1619
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1231
1620
|
return res.data;
|
1232
1621
|
} catch (err) {
|
1233
1622
|
toggleNotification({
|
@@ -1238,7 +1627,7 @@ const useDocumentActions = () => {
|
|
1238
1627
|
throw err;
|
1239
1628
|
}
|
1240
1629
|
},
|
1241
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1630
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1242
1631
|
);
|
1243
1632
|
const [getDoc] = useLazyGetDocumentQuery();
|
1244
1633
|
const getDocument = React.useCallback(
|
@@ -1264,7 +1653,7 @@ const useDocumentActions = () => {
|
|
1264
1653
|
};
|
1265
1654
|
};
|
1266
1655
|
const ProtectedHistoryPage = lazy(
|
1267
|
-
() => import("./History-
|
1656
|
+
() => import("./History-BqO2G3MV.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1268
1657
|
);
|
1269
1658
|
const routes$1 = [
|
1270
1659
|
{
|
@@ -1277,31 +1666,31 @@ const routes$1 = [
|
|
1277
1666
|
}
|
1278
1667
|
];
|
1279
1668
|
const ProtectedEditViewPage = lazy(
|
1280
|
-
() => import("./EditViewPage-
|
1669
|
+
() => import("./EditViewPage-BU1ugeVi.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1281
1670
|
);
|
1282
1671
|
const ProtectedListViewPage = lazy(
|
1283
|
-
() => import("./ListViewPage-
|
1672
|
+
() => import("./ListViewPage-yE_zYhcI.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1284
1673
|
);
|
1285
1674
|
const ProtectedListConfiguration = lazy(
|
1286
|
-
() => import("./ListConfigurationPage-
|
1675
|
+
() => import("./ListConfigurationPage-C6rsFlme.mjs").then((mod) => ({
|
1287
1676
|
default: mod.ProtectedListConfiguration
|
1288
1677
|
}))
|
1289
1678
|
);
|
1290
1679
|
const ProtectedEditConfigurationPage = lazy(
|
1291
|
-
() => import("./EditConfigurationPage-
|
1680
|
+
() => import("./EditConfigurationPage-Dh6sq-G4.mjs").then((mod) => ({
|
1292
1681
|
default: mod.ProtectedEditConfigurationPage
|
1293
1682
|
}))
|
1294
1683
|
);
|
1295
1684
|
const ProtectedComponentConfigurationPage = lazy(
|
1296
|
-
() => import("./ComponentConfigurationPage-
|
1685
|
+
() => import("./ComponentConfigurationPage-hLMNf7KI.mjs").then((mod) => ({
|
1297
1686
|
default: mod.ProtectedComponentConfigurationPage
|
1298
1687
|
}))
|
1299
1688
|
);
|
1300
1689
|
const NoPermissions = lazy(
|
1301
|
-
() => import("./NoPermissionsPage-
|
1690
|
+
() => import("./NoPermissionsPage-h0I3ImsX.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1302
1691
|
);
|
1303
1692
|
const NoContentType = lazy(
|
1304
|
-
() => import("./NoContentTypePage-
|
1693
|
+
() => import("./NoContentTypePage-NW_FSVdY.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1305
1694
|
);
|
1306
1695
|
const CollectionTypePages = () => {
|
1307
1696
|
const { collectionType } = useParams();
|
@@ -1415,12 +1804,14 @@ const DocumentActionButton = (action) => {
|
|
1415
1804
|
/* @__PURE__ */ jsx(
|
1416
1805
|
Button,
|
1417
1806
|
{
|
1418
|
-
flex:
|
1807
|
+
flex: "auto",
|
1419
1808
|
startIcon: action.icon,
|
1420
1809
|
disabled: action.disabled,
|
1421
1810
|
onClick: handleClick(action),
|
1422
1811
|
justifyContent: "center",
|
1423
1812
|
variant: action.variant || "default",
|
1813
|
+
paddingTop: "7px",
|
1814
|
+
paddingBottom: "7px",
|
1424
1815
|
children: action.label
|
1425
1816
|
}
|
1426
1817
|
),
|
@@ -1428,7 +1819,7 @@ const DocumentActionButton = (action) => {
|
|
1428
1819
|
DocumentActionConfirmDialog,
|
1429
1820
|
{
|
1430
1821
|
...action.dialog,
|
1431
|
-
variant: action.variant,
|
1822
|
+
variant: action.dialog?.variant ?? action.variant,
|
1432
1823
|
isOpen: dialogId === action.id,
|
1433
1824
|
onClose: handleClose
|
1434
1825
|
}
|
@@ -1485,9 +1876,9 @@ const DocumentActionsMenu = ({
|
|
1485
1876
|
disabled: isDisabled,
|
1486
1877
|
size: "S",
|
1487
1878
|
endIcon: null,
|
1488
|
-
paddingTop: "
|
1489
|
-
paddingLeft: "
|
1490
|
-
paddingRight: "
|
1879
|
+
paddingTop: "4px",
|
1880
|
+
paddingLeft: "7px",
|
1881
|
+
paddingRight: "7px",
|
1491
1882
|
variant,
|
1492
1883
|
children: [
|
1493
1884
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1498,7 +1889,7 @@ const DocumentActionsMenu = ({
|
|
1498
1889
|
]
|
1499
1890
|
}
|
1500
1891
|
),
|
1501
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1892
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1502
1893
|
actions2.map((action) => {
|
1503
1894
|
return /* @__PURE__ */ jsx(
|
1504
1895
|
Menu.Item,
|
@@ -1507,10 +1898,25 @@ const DocumentActionsMenu = ({
|
|
1507
1898
|
onSelect: handleClick(action),
|
1508
1899
|
display: "block",
|
1509
1900
|
children: /* @__PURE__ */ jsxs(Flex, { justifyContent: "space-between", gap: 4, children: [
|
1510
|
-
/* @__PURE__ */ jsxs(
|
1511
|
-
|
1512
|
-
|
1513
|
-
|
1901
|
+
/* @__PURE__ */ jsxs(
|
1902
|
+
Flex,
|
1903
|
+
{
|
1904
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1905
|
+
gap: 2,
|
1906
|
+
tag: "span",
|
1907
|
+
children: [
|
1908
|
+
/* @__PURE__ */ jsx(
|
1909
|
+
Flex,
|
1910
|
+
{
|
1911
|
+
tag: "span",
|
1912
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1913
|
+
children: action.icon
|
1914
|
+
}
|
1915
|
+
),
|
1916
|
+
action.label
|
1917
|
+
]
|
1918
|
+
}
|
1919
|
+
),
|
1514
1920
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsx(
|
1515
1921
|
Flex,
|
1516
1922
|
{
|
@@ -1569,6 +1975,18 @@ const convertActionVariantToColor = (variant = "secondary") => {
|
|
1569
1975
|
return "primary600";
|
1570
1976
|
}
|
1571
1977
|
};
|
1978
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1979
|
+
switch (variant) {
|
1980
|
+
case "danger":
|
1981
|
+
return "danger600";
|
1982
|
+
case "secondary":
|
1983
|
+
return "neutral500";
|
1984
|
+
case "success":
|
1985
|
+
return "success600";
|
1986
|
+
default:
|
1987
|
+
return "primary600";
|
1988
|
+
}
|
1989
|
+
};
|
1572
1990
|
const DocumentActionConfirmDialog = ({
|
1573
1991
|
onClose,
|
1574
1992
|
onCancel,
|
@@ -1591,22 +2009,20 @@ const DocumentActionConfirmDialog = ({
|
|
1591
2009
|
}
|
1592
2010
|
onClose();
|
1593
2011
|
};
|
1594
|
-
return /* @__PURE__ */
|
1595
|
-
/* @__PURE__ */ jsx(
|
1596
|
-
/* @__PURE__ */ jsx(
|
1597
|
-
|
1598
|
-
{
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
1603
|
-
|
1604
|
-
|
1605
|
-
|
1606
|
-
|
1607
|
-
|
1608
|
-
)
|
1609
|
-
] });
|
2012
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2013
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2014
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
2015
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
2016
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2017
|
+
id: "app.components.Button.cancel",
|
2018
|
+
defaultMessage: "Cancel"
|
2019
|
+
}) }) }),
|
2020
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2021
|
+
id: "app.components.Button.confirm",
|
2022
|
+
defaultMessage: "Confirm"
|
2023
|
+
}) })
|
2024
|
+
] })
|
2025
|
+
] }) });
|
1610
2026
|
};
|
1611
2027
|
const DocumentActionModal = ({
|
1612
2028
|
isOpen,
|
@@ -1616,34 +2032,17 @@ const DocumentActionModal = ({
|
|
1616
2032
|
content: Content,
|
1617
2033
|
onModalClose
|
1618
2034
|
}) => {
|
1619
|
-
const id = React.useId();
|
1620
|
-
if (!isOpen) {
|
1621
|
-
return null;
|
1622
|
-
}
|
1623
2035
|
const handleClose = () => {
|
1624
2036
|
if (onClose) {
|
1625
2037
|
onClose();
|
1626
2038
|
}
|
1627
2039
|
onModalClose();
|
1628
2040
|
};
|
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
|
-
] });
|
2041
|
+
return /* @__PURE__ */ jsx(Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Modal.Content, { children: [
|
2042
|
+
/* @__PURE__ */ jsx(Modal.Header, { children: /* @__PURE__ */ jsx(Modal.Title, { children: title }) }),
|
2043
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsx(Modal.Body, { children: Content }),
|
2044
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
2045
|
+
] }) });
|
1647
2046
|
};
|
1648
2047
|
const PublishAction$1 = ({
|
1649
2048
|
activeTab,
|
@@ -1657,13 +2056,17 @@ const PublishAction$1 = ({
|
|
1657
2056
|
const navigate = useNavigate();
|
1658
2057
|
const { toggleNotification } = useNotification();
|
1659
2058
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2059
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1660
2060
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
1661
2061
|
const { formatMessage } = useIntl();
|
1662
|
-
const { canPublish
|
1663
|
-
"PublishAction",
|
1664
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1665
|
-
);
|
2062
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1666
2063
|
const { publish } = useDocumentActions();
|
2064
|
+
const [
|
2065
|
+
countDraftRelations,
|
2066
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2067
|
+
] = useLazyGetDraftRelationCountQuery();
|
2068
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React.useState(0);
|
2069
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React.useState(0);
|
1667
2070
|
const [{ query, rawQuery }] = useQueryParams();
|
1668
2071
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1669
2072
|
const modified = useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1672,10 +2075,103 @@ const PublishAction$1 = ({
|
|
1672
2075
|
const validate = useForm("PublishAction", (state) => state.validate);
|
1673
2076
|
const setErrors = useForm("PublishAction", (state) => state.setErrors);
|
1674
2077
|
const formValues = useForm("PublishAction", ({ values }) => values);
|
2078
|
+
React.useEffect(() => {
|
2079
|
+
if (isErrorDraftRelations) {
|
2080
|
+
toggleNotification({
|
2081
|
+
type: "danger",
|
2082
|
+
message: formatMessage({
|
2083
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2084
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2085
|
+
})
|
2086
|
+
});
|
2087
|
+
}
|
2088
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2089
|
+
React.useEffect(() => {
|
2090
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2091
|
+
const extractDraftRelations = (data) => {
|
2092
|
+
const relations = data.connect || [];
|
2093
|
+
relations.forEach((relation) => {
|
2094
|
+
if (relation.status === "draft") {
|
2095
|
+
localDraftRelations.add(relation.id);
|
2096
|
+
}
|
2097
|
+
});
|
2098
|
+
};
|
2099
|
+
const traverseAndExtract = (data) => {
|
2100
|
+
Object.entries(data).forEach(([key, value]) => {
|
2101
|
+
if (key === "connect" && Array.isArray(value)) {
|
2102
|
+
extractDraftRelations({ connect: value });
|
2103
|
+
} else if (typeof value === "object" && value !== null) {
|
2104
|
+
traverseAndExtract(value);
|
2105
|
+
}
|
2106
|
+
});
|
2107
|
+
};
|
2108
|
+
if (!documentId || modified) {
|
2109
|
+
traverseAndExtract(formValues);
|
2110
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2111
|
+
}
|
2112
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2113
|
+
React.useEffect(() => {
|
2114
|
+
if (!document || !document.documentId || isListView) {
|
2115
|
+
return;
|
2116
|
+
}
|
2117
|
+
const fetchDraftRelationsCount = async () => {
|
2118
|
+
const { data, error } = await countDraftRelations({
|
2119
|
+
collectionType,
|
2120
|
+
model,
|
2121
|
+
documentId,
|
2122
|
+
params
|
2123
|
+
});
|
2124
|
+
if (error) {
|
2125
|
+
throw error;
|
2126
|
+
}
|
2127
|
+
if (data) {
|
2128
|
+
setServerCountOfDraftRelations(data.data);
|
2129
|
+
}
|
2130
|
+
};
|
2131
|
+
fetchDraftRelationsCount();
|
2132
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1675
2133
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1676
2134
|
if (!schema?.options?.draftAndPublish) {
|
1677
2135
|
return null;
|
1678
2136
|
}
|
2137
|
+
const performPublish = async () => {
|
2138
|
+
setSubmitting(true);
|
2139
|
+
try {
|
2140
|
+
const { errors } = await validate();
|
2141
|
+
if (errors) {
|
2142
|
+
toggleNotification({
|
2143
|
+
type: "danger",
|
2144
|
+
message: formatMessage({
|
2145
|
+
id: "content-manager.validation.error",
|
2146
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2147
|
+
})
|
2148
|
+
});
|
2149
|
+
return;
|
2150
|
+
}
|
2151
|
+
const res = await publish(
|
2152
|
+
{
|
2153
|
+
collectionType,
|
2154
|
+
model,
|
2155
|
+
documentId,
|
2156
|
+
params
|
2157
|
+
},
|
2158
|
+
formValues
|
2159
|
+
);
|
2160
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2161
|
+
navigate({
|
2162
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2163
|
+
search: rawQuery
|
2164
|
+
});
|
2165
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2166
|
+
setErrors(formatValidationErrors(res.error));
|
2167
|
+
}
|
2168
|
+
} finally {
|
2169
|
+
setSubmitting(false);
|
2170
|
+
}
|
2171
|
+
};
|
2172
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2173
|
+
const enableDraftRelationsCount = false;
|
2174
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1679
2175
|
return {
|
1680
2176
|
/**
|
1681
2177
|
* Disabled when:
|
@@ -1685,49 +2181,36 @@ const PublishAction$1 = ({
|
|
1685
2181
|
* - the document is already published & not modified
|
1686
2182
|
* - the document is being created & not modified
|
1687
2183
|
* - 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
2184
|
*/
|
1691
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2185
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1692
2186
|
label: formatMessage({
|
1693
2187
|
id: "app.utils.publish",
|
1694
2188
|
defaultMessage: "Publish"
|
1695
2189
|
}),
|
1696
2190
|
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));
|
2191
|
+
await performPublish();
|
2192
|
+
},
|
2193
|
+
dialog: hasDraftRelations ? {
|
2194
|
+
type: "dialog",
|
2195
|
+
variant: "danger",
|
2196
|
+
footer: null,
|
2197
|
+
title: formatMessage({
|
2198
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2199
|
+
defaultMessage: "Confirmation"
|
2200
|
+
}),
|
2201
|
+
content: formatMessage(
|
2202
|
+
{
|
2203
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2204
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2205
|
+
},
|
2206
|
+
{
|
2207
|
+
count: totalDraftRelations
|
1726
2208
|
}
|
1727
|
-
|
1728
|
-
|
2209
|
+
),
|
2210
|
+
onConfirm: async () => {
|
2211
|
+
await performPublish();
|
1729
2212
|
}
|
1730
|
-
}
|
2213
|
+
} : void 0
|
1731
2214
|
};
|
1732
2215
|
};
|
1733
2216
|
PublishAction$1.type = "publish";
|
@@ -1743,10 +2226,6 @@ const UpdateAction = ({
|
|
1743
2226
|
const cloneMatch = useMatch(CLONE_PATH);
|
1744
2227
|
const isCloning = cloneMatch !== null;
|
1745
2228
|
const { formatMessage } = useIntl();
|
1746
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1747
|
-
canCreate: canCreate2,
|
1748
|
-
canUpdate: canUpdate2
|
1749
|
-
}));
|
1750
2229
|
const { create, update, clone } = useDocumentActions();
|
1751
2230
|
const [{ query, rawQuery }] = useQueryParams();
|
1752
2231
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1763,10 +2242,8 @@ const UpdateAction = ({
|
|
1763
2242
|
* - the form is submitting
|
1764
2243
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1765
2244
|
* - 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
2245
|
*/
|
1769
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2246
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1770
2247
|
label: formatMessage({
|
1771
2248
|
id: "content-manager.containers.Edit.save",
|
1772
2249
|
defaultMessage: "Save"
|
@@ -1774,16 +2251,18 @@ const UpdateAction = ({
|
|
1774
2251
|
onClick: async () => {
|
1775
2252
|
setSubmitting(true);
|
1776
2253
|
try {
|
1777
|
-
|
1778
|
-
|
1779
|
-
|
1780
|
-
|
1781
|
-
|
1782
|
-
|
1783
|
-
|
1784
|
-
|
1785
|
-
|
1786
|
-
|
2254
|
+
if (activeTab !== "draft") {
|
2255
|
+
const { errors } = await validate();
|
2256
|
+
if (errors) {
|
2257
|
+
toggleNotification({
|
2258
|
+
type: "danger",
|
2259
|
+
message: formatMessage({
|
2260
|
+
id: "content-manager.validation.error",
|
2261
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2262
|
+
})
|
2263
|
+
});
|
2264
|
+
return;
|
2265
|
+
}
|
1787
2266
|
}
|
1788
2267
|
if (isCloning) {
|
1789
2268
|
const res = await clone(
|
@@ -1795,10 +2274,13 @@ const UpdateAction = ({
|
|
1795
2274
|
document
|
1796
2275
|
);
|
1797
2276
|
if ("data" in res) {
|
1798
|
-
navigate(
|
1799
|
-
|
1800
|
-
|
1801
|
-
|
2277
|
+
navigate(
|
2278
|
+
{
|
2279
|
+
pathname: `../${res.data.documentId}`,
|
2280
|
+
search: rawQuery
|
2281
|
+
},
|
2282
|
+
{ relative: "path" }
|
2283
|
+
);
|
1802
2284
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1803
2285
|
setErrors(formatValidationErrors(res.error));
|
1804
2286
|
}
|
@@ -1826,10 +2308,13 @@ const UpdateAction = ({
|
|
1826
2308
|
document
|
1827
2309
|
);
|
1828
2310
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1829
|
-
navigate(
|
1830
|
-
|
1831
|
-
|
1832
|
-
|
2311
|
+
navigate(
|
2312
|
+
{
|
2313
|
+
pathname: `../${res.data.documentId}`,
|
2314
|
+
search: rawQuery
|
2315
|
+
},
|
2316
|
+
{ replace: true, relative: "path" }
|
2317
|
+
);
|
1833
2318
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1834
2319
|
setErrors(formatValidationErrors(res.error));
|
1835
2320
|
}
|
@@ -1861,10 +2346,8 @@ const UnpublishAction$1 = ({
|
|
1861
2346
|
const { toggleNotification } = useNotification();
|
1862
2347
|
const [shouldKeepDraft, setShouldKeepDraft] = React.useState(true);
|
1863
2348
|
const isDocumentModified = document?.status === "modified";
|
1864
|
-
const handleChange = (
|
1865
|
-
|
1866
|
-
setShouldKeepDraft(e.target.value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1867
|
-
}
|
2349
|
+
const handleChange = (value) => {
|
2350
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
1868
2351
|
};
|
1869
2352
|
if (!schema?.options?.draftAndPublish) {
|
1870
2353
|
return null;
|
@@ -1875,7 +2358,7 @@ const UnpublishAction$1 = ({
|
|
1875
2358
|
id: "app.utils.unpublish",
|
1876
2359
|
defaultMessage: "Unpublish"
|
1877
2360
|
}),
|
1878
|
-
icon: /* @__PURE__ */ jsx(
|
2361
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1879
2362
|
onClick: async () => {
|
1880
2363
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1881
2364
|
if (!documentId) {
|
@@ -1914,40 +2397,24 @@ const UnpublishAction$1 = ({
|
|
1914
2397
|
}) })
|
1915
2398
|
] }),
|
1916
2399
|
/* @__PURE__ */ jsxs(
|
1917
|
-
|
2400
|
+
Radio.Group,
|
1918
2401
|
{
|
1919
|
-
|
1920
|
-
|
1921
|
-
|
1922
|
-
|
1923
|
-
|
1924
|
-
|
2402
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2403
|
+
name: "discard-options",
|
2404
|
+
"aria-label": formatMessage({
|
2405
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2406
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2407
|
+
}),
|
2408
|
+
onValueChange: handleChange,
|
1925
2409
|
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
|
-
)
|
2410
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2411
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2412
|
+
defaultMessage: "Keep draft"
|
2413
|
+
}) }),
|
2414
|
+
/* @__PURE__ */ jsx(Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2415
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2416
|
+
defaultMessage: "Replace draft"
|
2417
|
+
}) })
|
1951
2418
|
]
|
1952
2419
|
}
|
1953
2420
|
)
|
@@ -2003,7 +2470,7 @@ const DiscardAction = ({
|
|
2003
2470
|
id: "content-manager.actions.discard.label",
|
2004
2471
|
defaultMessage: "Discard changes"
|
2005
2472
|
}),
|
2006
|
-
icon: /* @__PURE__ */ jsx(
|
2473
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2007
2474
|
position: ["panel", "table-row"],
|
2008
2475
|
variant: "danger",
|
2009
2476
|
dialog: {
|
@@ -2031,11 +2498,6 @@ const DiscardAction = ({
|
|
2031
2498
|
};
|
2032
2499
|
};
|
2033
2500
|
DiscardAction.type = "discard";
|
2034
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2035
|
-
path {
|
2036
|
-
fill: currentColor;
|
2037
|
-
}
|
2038
|
-
`;
|
2039
2501
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2040
2502
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2041
2503
|
const RelativeTime = React.forwardRef(
|
@@ -2083,7 +2545,7 @@ const getDisplayName = ({
|
|
2083
2545
|
};
|
2084
2546
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2085
2547
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2086
|
-
const statusVariant = status === "draft" ? "
|
2548
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2087
2549
|
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
2550
|
};
|
2089
2551
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2093,23 +2555,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2093
2555
|
id: "content-manager.containers.edit.title.new",
|
2094
2556
|
defaultMessage: "Create an entry"
|
2095
2557
|
}) : documentTitle;
|
2096
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2558
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2097
2559
|
/* @__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
|
2560
|
+
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2561
|
+
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2562
|
+
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
2563
|
+
] }),
|
2564
|
+
status ? /* @__PURE__ */ jsx(Box, { marginTop: 1, children: /* @__PURE__ */ jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2113
2565
|
] });
|
2114
2566
|
};
|
2115
2567
|
const HeaderToolbar = () => {
|
@@ -2276,8 +2728,22 @@ const Information = ({ activeTab }) => {
|
|
2276
2728
|
);
|
2277
2729
|
};
|
2278
2730
|
const HeaderActions = ({ actions: actions2 }) => {
|
2279
|
-
|
2280
|
-
|
2731
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2732
|
+
const handleClick = (action) => async (e) => {
|
2733
|
+
if (!("options" in action)) {
|
2734
|
+
const { onClick = () => false, dialog, id } = action;
|
2735
|
+
const muteDialog = await onClick(e);
|
2736
|
+
if (dialog && !muteDialog) {
|
2737
|
+
e.preventDefault();
|
2738
|
+
setDialogId(id);
|
2739
|
+
}
|
2740
|
+
}
|
2741
|
+
};
|
2742
|
+
const handleClose = () => {
|
2743
|
+
setDialogId(null);
|
2744
|
+
};
|
2745
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2746
|
+
if (action.options) {
|
2281
2747
|
return /* @__PURE__ */ jsx(
|
2282
2748
|
SingleSelect,
|
2283
2749
|
{
|
@@ -2291,10 +2757,49 @@ const HeaderActions = ({ actions: actions2 }) => {
|
|
2291
2757
|
action.id
|
2292
2758
|
);
|
2293
2759
|
} else {
|
2294
|
-
|
2760
|
+
if (action.type === "icon") {
|
2761
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2762
|
+
/* @__PURE__ */ jsx(
|
2763
|
+
IconButton,
|
2764
|
+
{
|
2765
|
+
disabled: action.disabled,
|
2766
|
+
label: action.label,
|
2767
|
+
size: "S",
|
2768
|
+
onClick: handleClick(action),
|
2769
|
+
children: action.icon
|
2770
|
+
}
|
2771
|
+
),
|
2772
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2773
|
+
HeaderActionDialog,
|
2774
|
+
{
|
2775
|
+
...action.dialog,
|
2776
|
+
isOpen: dialogId === action.id,
|
2777
|
+
onClose: handleClose
|
2778
|
+
}
|
2779
|
+
) : null
|
2780
|
+
] }, action.id);
|
2781
|
+
}
|
2295
2782
|
}
|
2296
2783
|
}) });
|
2297
2784
|
};
|
2785
|
+
const HeaderActionDialog = ({
|
2786
|
+
onClose,
|
2787
|
+
onCancel,
|
2788
|
+
title,
|
2789
|
+
content: Content,
|
2790
|
+
isOpen
|
2791
|
+
}) => {
|
2792
|
+
const handleClose = async () => {
|
2793
|
+
if (onCancel) {
|
2794
|
+
await onCancel();
|
2795
|
+
}
|
2796
|
+
onClose();
|
2797
|
+
};
|
2798
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2799
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2800
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2801
|
+
] }) });
|
2802
|
+
};
|
2298
2803
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2299
2804
|
const navigate = useNavigate();
|
2300
2805
|
const { formatMessage } = useIntl();
|
@@ -2335,12 +2840,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2335
2840
|
const { delete: deleteAction } = useDocumentActions();
|
2336
2841
|
const { toggleNotification } = useNotification();
|
2337
2842
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2843
|
+
const isLocalized = document?.locale != null;
|
2338
2844
|
return {
|
2339
2845
|
disabled: !canDelete || !document,
|
2340
|
-
label: formatMessage(
|
2341
|
-
|
2342
|
-
|
2343
|
-
|
2846
|
+
label: formatMessage(
|
2847
|
+
{
|
2848
|
+
id: "content-manager.actions.delete.label",
|
2849
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2850
|
+
},
|
2851
|
+
{ isLocalized }
|
2852
|
+
),
|
2344
2853
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2345
2854
|
dialog: {
|
2346
2855
|
type: "dialog",
|
@@ -2430,7 +2939,7 @@ const ActionsPanel = () => {
|
|
2430
2939
|
return {
|
2431
2940
|
title: formatMessage({
|
2432
2941
|
id: "content-manager.containers.edit.panels.default.title",
|
2433
|
-
defaultMessage: "
|
2942
|
+
defaultMessage: "Entry"
|
2434
2943
|
}),
|
2435
2944
|
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2436
2945
|
};
|
@@ -2438,361 +2947,59 @@ const ActionsPanel = () => {
|
|
2438
2947
|
ActionsPanel.type = "actions";
|
2439
2948
|
const ActionsPanelContent = () => {
|
2440
2949
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2441
|
-
const [
|
2442
|
-
{
|
2443
|
-
query: { status = "draft" }
|
2444
|
-
}
|
2445
|
-
] = useQueryParams();
|
2446
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2447
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2448
|
-
const props = {
|
2449
|
-
activeTab: status,
|
2450
|
-
model,
|
2451
|
-
documentId: id,
|
2452
|
-
document: isCloning ? void 0 : document,
|
2453
|
-
meta: isCloning ? void 0 : meta,
|
2454
|
-
collectionType
|
2455
|
-
};
|
2456
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2457
|
-
/* @__PURE__ */ jsx(
|
2458
|
-
DescriptionComponentRenderer,
|
2459
|
-
{
|
2460
|
-
props,
|
2461
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2462
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2463
|
-
}
|
2464
|
-
),
|
2465
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2466
|
-
] });
|
2467
|
-
};
|
2468
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2469
|
-
return /* @__PURE__ */ jsxs(
|
2470
|
-
Flex,
|
2471
|
-
{
|
2472
|
-
ref,
|
2473
|
-
tag: "aside",
|
2474
|
-
"aria-labelledby": "additional-information",
|
2475
|
-
background: "neutral0",
|
2476
|
-
borderColor: "neutral150",
|
2477
|
-
hasRadius: true,
|
2478
|
-
paddingBottom: 4,
|
2479
|
-
paddingLeft: 4,
|
2480
|
-
paddingRight: 4,
|
2481
|
-
paddingTop: 4,
|
2482
|
-
shadow: "tableShadow",
|
2483
|
-
gap: 3,
|
2484
|
-
direction: "column",
|
2485
|
-
justifyContent: "stretch",
|
2486
|
-
alignItems: "flex-start",
|
2487
|
-
children: [
|
2488
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2489
|
-
children
|
2490
|
-
]
|
2491
|
-
}
|
2492
|
-
);
|
2493
|
-
});
|
2494
|
-
const HOOKS = {
|
2495
|
-
/**
|
2496
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2497
|
-
* @constant
|
2498
|
-
* @type {string}
|
2499
|
-
*/
|
2500
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2501
|
-
/**
|
2502
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2503
|
-
* @constant
|
2504
|
-
* @type {string}
|
2505
|
-
*/
|
2506
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2507
|
-
/**
|
2508
|
-
* Hook that allows to mutate the CM's edit view layout
|
2509
|
-
* @constant
|
2510
|
-
* @type {string}
|
2511
|
-
*/
|
2512
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2513
|
-
/**
|
2514
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2515
|
-
* @constant
|
2516
|
-
* @type {string}
|
2517
|
-
*/
|
2518
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2519
|
-
};
|
2520
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2521
|
-
endpoints: (builder) => ({
|
2522
|
-
getContentTypeConfiguration: builder.query({
|
2523
|
-
query: (uid) => ({
|
2524
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2525
|
-
method: "GET"
|
2526
|
-
}),
|
2527
|
-
transformResponse: (response) => response.data,
|
2528
|
-
providesTags: (_result, _error, uid) => [
|
2529
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2530
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2531
|
-
]
|
2532
|
-
}),
|
2533
|
-
getAllContentTypeSettings: builder.query({
|
2534
|
-
query: () => "/content-manager/content-types-settings",
|
2535
|
-
transformResponse: (response) => response.data,
|
2536
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2537
|
-
}),
|
2538
|
-
updateContentTypeConfiguration: builder.mutation({
|
2539
|
-
query: ({ uid, ...body }) => ({
|
2540
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2541
|
-
method: "PUT",
|
2542
|
-
data: body
|
2543
|
-
}),
|
2544
|
-
transformResponse: (response) => response.data,
|
2545
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2546
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2547
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2548
|
-
// Is this necessary?
|
2549
|
-
{ type: "InitialData" }
|
2550
|
-
]
|
2551
|
-
})
|
2552
|
-
})
|
2553
|
-
});
|
2554
|
-
const {
|
2555
|
-
useGetContentTypeConfigurationQuery,
|
2556
|
-
useGetAllContentTypeSettingsQuery,
|
2557
|
-
useUpdateContentTypeConfigurationMutation
|
2558
|
-
} = contentTypesApi;
|
2559
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2560
|
-
const { type } = attribute;
|
2561
|
-
if (type === "relation") {
|
2562
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2563
|
-
}
|
2564
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2565
|
-
};
|
2566
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2567
|
-
if (!mainFieldName) {
|
2568
|
-
return void 0;
|
2569
|
-
}
|
2570
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2571
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2572
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2573
|
-
);
|
2574
|
-
return {
|
2575
|
-
name: mainFieldName,
|
2576
|
-
type: mainFieldType ?? "string"
|
2577
|
-
};
|
2578
|
-
};
|
2579
|
-
const DEFAULT_SETTINGS = {
|
2580
|
-
bulkable: false,
|
2581
|
-
filterable: false,
|
2582
|
-
searchable: false,
|
2583
|
-
pagination: false,
|
2584
|
-
defaultSortBy: "",
|
2585
|
-
defaultSortOrder: "asc",
|
2586
|
-
mainField: "id",
|
2587
|
-
pageSize: 10
|
2588
|
-
};
|
2589
|
-
const useDocumentLayout = (model) => {
|
2590
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2591
|
-
const [{ query }] = useQueryParams();
|
2592
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2593
|
-
const { toggleNotification } = useNotification();
|
2594
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2595
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2596
|
-
const {
|
2597
|
-
data,
|
2598
|
-
isLoading: isLoadingConfigs,
|
2599
|
-
error,
|
2600
|
-
isFetching: isFetchingConfigs
|
2601
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2602
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2603
|
-
React.useEffect(() => {
|
2604
|
-
if (error) {
|
2605
|
-
toggleNotification({
|
2606
|
-
type: "danger",
|
2607
|
-
message: formatAPIError(error)
|
2608
|
-
});
|
2609
|
-
}
|
2610
|
-
}, [error, formatAPIError, toggleNotification]);
|
2611
|
-
const editLayout = React.useMemo(
|
2612
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2613
|
-
layout: [],
|
2614
|
-
components: {},
|
2615
|
-
metadatas: {},
|
2616
|
-
options: {},
|
2617
|
-
settings: DEFAULT_SETTINGS
|
2618
|
-
},
|
2619
|
-
[data, isLoading, schemas, schema, components]
|
2620
|
-
);
|
2621
|
-
const listLayout = React.useMemo(() => {
|
2622
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2623
|
-
layout: [],
|
2624
|
-
metadatas: {},
|
2625
|
-
options: {},
|
2626
|
-
settings: DEFAULT_SETTINGS
|
2627
|
-
};
|
2628
|
-
}, [data, isLoading, schemas, schema, components]);
|
2629
|
-
const { layout: edit } = React.useMemo(
|
2630
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2631
|
-
layout: editLayout,
|
2632
|
-
query
|
2633
|
-
}),
|
2634
|
-
[editLayout, query, runHookWaterfall]
|
2635
|
-
);
|
2636
|
-
return {
|
2637
|
-
error,
|
2638
|
-
isLoading,
|
2639
|
-
edit,
|
2640
|
-
list: listLayout
|
2641
|
-
};
|
2642
|
-
};
|
2643
|
-
const useDocLayout = () => {
|
2644
|
-
const { model } = useDoc();
|
2645
|
-
return useDocumentLayout(model);
|
2646
|
-
};
|
2647
|
-
const formatEditLayout = (data, {
|
2648
|
-
schemas,
|
2649
|
-
schema,
|
2650
|
-
components
|
2651
|
-
}) => {
|
2652
|
-
let currentPanelIndex = 0;
|
2653
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2654
|
-
data.contentType.layouts.edit,
|
2655
|
-
schema?.attributes,
|
2656
|
-
data.contentType.metadatas,
|
2657
|
-
{ configurations: data.components, schemas: components },
|
2658
|
-
schemas
|
2659
|
-
).reduce((panels, row) => {
|
2660
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2661
|
-
panels.push([row]);
|
2662
|
-
currentPanelIndex += 2;
|
2663
|
-
} else {
|
2664
|
-
if (!panels[currentPanelIndex]) {
|
2665
|
-
panels.push([]);
|
2666
|
-
}
|
2667
|
-
panels[currentPanelIndex].push(row);
|
2668
|
-
}
|
2669
|
-
return panels;
|
2670
|
-
}, []);
|
2671
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2672
|
-
(acc, [uid, configuration]) => {
|
2673
|
-
acc[uid] = {
|
2674
|
-
layout: convertEditLayoutToFieldLayouts(
|
2675
|
-
configuration.layouts.edit,
|
2676
|
-
components[uid].attributes,
|
2677
|
-
configuration.metadatas
|
2678
|
-
),
|
2679
|
-
settings: {
|
2680
|
-
...configuration.settings,
|
2681
|
-
icon: components[uid].info.icon,
|
2682
|
-
displayName: components[uid].info.displayName
|
2683
|
-
}
|
2684
|
-
};
|
2685
|
-
return acc;
|
2686
|
-
},
|
2687
|
-
{}
|
2688
|
-
);
|
2689
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2690
|
-
(acc, [attribute, metadata]) => {
|
2691
|
-
return {
|
2692
|
-
...acc,
|
2693
|
-
[attribute]: metadata.edit
|
2694
|
-
};
|
2695
|
-
},
|
2696
|
-
{}
|
2697
|
-
);
|
2698
|
-
return {
|
2699
|
-
layout: panelledEditAttributes,
|
2700
|
-
components: componentEditAttributes,
|
2701
|
-
metadatas: editMetadatas,
|
2702
|
-
settings: {
|
2703
|
-
...data.contentType.settings,
|
2704
|
-
displayName: schema?.info.displayName
|
2705
|
-
},
|
2706
|
-
options: {
|
2707
|
-
...schema?.options,
|
2708
|
-
...schema?.pluginOptions,
|
2709
|
-
...data.contentType.options
|
2710
|
-
}
|
2711
|
-
};
|
2712
|
-
};
|
2713
|
-
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
2714
|
-
return rows.map(
|
2715
|
-
(row) => row.map((field) => {
|
2716
|
-
const attribute = attributes[field.name];
|
2717
|
-
if (!attribute) {
|
2718
|
-
return null;
|
2719
|
-
}
|
2720
|
-
const { edit: metadata } = metadatas[field.name];
|
2721
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2722
|
-
return {
|
2723
|
-
attribute,
|
2724
|
-
disabled: !metadata.editable,
|
2725
|
-
hint: metadata.description,
|
2726
|
-
label: metadata.label ?? "",
|
2727
|
-
name: field.name,
|
2728
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2729
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2730
|
-
schemas,
|
2731
|
-
components: components?.schemas ?? {}
|
2732
|
-
}),
|
2733
|
-
placeholder: metadata.placeholder ?? "",
|
2734
|
-
required: attribute.required ?? false,
|
2735
|
-
size: field.size,
|
2736
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2737
|
-
visible: metadata.visible ?? true,
|
2738
|
-
type: attribute.type
|
2739
|
-
};
|
2740
|
-
}).filter((field) => field !== null)
|
2741
|
-
);
|
2742
|
-
};
|
2743
|
-
const formatListLayout = (data, {
|
2744
|
-
schemas,
|
2745
|
-
schema,
|
2746
|
-
components
|
2747
|
-
}) => {
|
2748
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2749
|
-
(acc, [attribute, metadata]) => {
|
2750
|
-
return {
|
2751
|
-
...acc,
|
2752
|
-
[attribute]: metadata.list
|
2753
|
-
};
|
2754
|
-
},
|
2755
|
-
{}
|
2756
|
-
);
|
2757
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2758
|
-
data.contentType.layouts.list,
|
2759
|
-
schema?.attributes,
|
2760
|
-
listMetadatas,
|
2761
|
-
{ configurations: data.components, schemas: components },
|
2762
|
-
schemas
|
2763
|
-
);
|
2764
|
-
return {
|
2765
|
-
layout: listAttributes,
|
2766
|
-
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
2767
|
-
metadatas: listMetadatas,
|
2768
|
-
options: {
|
2769
|
-
...schema?.options,
|
2770
|
-
...schema?.pluginOptions,
|
2771
|
-
...data.contentType.options
|
2950
|
+
const [
|
2951
|
+
{
|
2952
|
+
query: { status = "draft" }
|
2772
2953
|
}
|
2954
|
+
] = useQueryParams();
|
2955
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2956
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2957
|
+
const props = {
|
2958
|
+
activeTab: status,
|
2959
|
+
model,
|
2960
|
+
documentId: id,
|
2961
|
+
document: isCloning ? void 0 : document,
|
2962
|
+
meta: isCloning ? void 0 : meta,
|
2963
|
+
collectionType
|
2773
2964
|
};
|
2965
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2966
|
+
/* @__PURE__ */ jsx(
|
2967
|
+
DescriptionComponentRenderer,
|
2968
|
+
{
|
2969
|
+
props,
|
2970
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2971
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2972
|
+
}
|
2973
|
+
),
|
2974
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2975
|
+
] });
|
2774
2976
|
};
|
2775
|
-
const
|
2776
|
-
return
|
2777
|
-
|
2778
|
-
|
2779
|
-
|
2977
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2978
|
+
return /* @__PURE__ */ jsxs(
|
2979
|
+
Flex,
|
2980
|
+
{
|
2981
|
+
ref,
|
2982
|
+
tag: "aside",
|
2983
|
+
"aria-labelledby": "additional-information",
|
2984
|
+
background: "neutral0",
|
2985
|
+
borderColor: "neutral150",
|
2986
|
+
hasRadius: true,
|
2987
|
+
paddingBottom: 4,
|
2988
|
+
paddingLeft: 4,
|
2989
|
+
paddingRight: 4,
|
2990
|
+
paddingTop: 4,
|
2991
|
+
shadow: "tableShadow",
|
2992
|
+
gap: 3,
|
2993
|
+
direction: "column",
|
2994
|
+
justifyContent: "stretch",
|
2995
|
+
alignItems: "flex-start",
|
2996
|
+
children: [
|
2997
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2998
|
+
children
|
2999
|
+
]
|
2780
3000
|
}
|
2781
|
-
|
2782
|
-
|
2783
|
-
return {
|
2784
|
-
attribute,
|
2785
|
-
label: metadata.label ?? "",
|
2786
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2787
|
-
schemas,
|
2788
|
-
components: components?.schemas ?? {}
|
2789
|
-
}),
|
2790
|
-
name,
|
2791
|
-
searchable: metadata.searchable ?? true,
|
2792
|
-
sortable: metadata.sortable ?? true
|
2793
|
-
};
|
2794
|
-
}).filter((field) => field !== null);
|
2795
|
-
};
|
3001
|
+
);
|
3002
|
+
});
|
2796
3003
|
const ConfirmBulkActionDialog = ({
|
2797
3004
|
onToggleDialog,
|
2798
3005
|
isOpen = false,
|
@@ -2800,30 +3007,23 @@ const ConfirmBulkActionDialog = ({
|
|
2800
3007
|
endAction
|
2801
3008
|
}) => {
|
2802
3009
|
const { formatMessage } = useIntl();
|
2803
|
-
return /* @__PURE__ */ jsxs(
|
2804
|
-
Dialog,
|
2805
|
-
|
2806
|
-
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2815
|
-
|
2816
|
-
|
2817
|
-
|
2818
|
-
|
2819
|
-
|
2820
|
-
}) }),
|
2821
|
-
endAction
|
2822
|
-
}
|
2823
|
-
)
|
2824
|
-
]
|
2825
|
-
}
|
2826
|
-
);
|
3010
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
3011
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
|
3012
|
+
id: "app.components.ConfirmDialog.title",
|
3013
|
+
defaultMessage: "Confirmation"
|
3014
|
+
}) }),
|
3015
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3016
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3017
|
+
dialogBody
|
3018
|
+
] }) }),
|
3019
|
+
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
3020
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { fullWidth: true, onClick: onToggleDialog, variant: "tertiary", children: formatMessage({
|
3021
|
+
id: "app.components.Button.cancel",
|
3022
|
+
defaultMessage: "Cancel"
|
3023
|
+
}) }) }),
|
3024
|
+
endAction
|
3025
|
+
] })
|
3026
|
+
] }) });
|
2827
3027
|
};
|
2828
3028
|
const BoldChunk$1 = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
2829
3029
|
const ConfirmDialogPublishAll = ({
|
@@ -2838,6 +3038,7 @@ const ConfirmDialogPublishAll = ({
|
|
2838
3038
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2839
3039
|
const { model, schema } = useDoc();
|
2840
3040
|
const [{ query }] = useQueryParams();
|
3041
|
+
const enableDraftRelationsCount = false;
|
2841
3042
|
const {
|
2842
3043
|
data: countDraftRelations = 0,
|
2843
3044
|
isLoading,
|
@@ -2849,7 +3050,7 @@ const ConfirmDialogPublishAll = ({
|
|
2849
3050
|
locale: query?.plugins?.i18n?.locale
|
2850
3051
|
},
|
2851
3052
|
{
|
2852
|
-
skip:
|
3053
|
+
skip: !enableDraftRelationsCount
|
2853
3054
|
}
|
2854
3055
|
);
|
2855
3056
|
React.useEffect(() => {
|
@@ -2928,16 +3129,30 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2928
3129
|
)
|
2929
3130
|
);
|
2930
3131
|
} else {
|
2931
|
-
messages.push(
|
3132
|
+
messages.push(
|
3133
|
+
...formatErrorMessages(
|
3134
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3135
|
+
value,
|
3136
|
+
currentKey,
|
3137
|
+
formatMessage
|
3138
|
+
)
|
3139
|
+
);
|
2932
3140
|
}
|
3141
|
+
} else {
|
3142
|
+
messages.push(
|
3143
|
+
formatMessage(
|
3144
|
+
{
|
3145
|
+
id: `${value}.withField`,
|
3146
|
+
defaultMessage: value
|
3147
|
+
},
|
3148
|
+
{ field: currentKey }
|
3149
|
+
)
|
3150
|
+
);
|
2933
3151
|
}
|
2934
3152
|
});
|
2935
3153
|
return messages;
|
2936
3154
|
};
|
2937
|
-
const EntryValidationText = ({
|
2938
|
-
validationErrors,
|
2939
|
-
isPublished = false
|
2940
|
-
}) => {
|
3155
|
+
const EntryValidationText = ({ validationErrors, status }) => {
|
2941
3156
|
const { formatMessage } = useIntl();
|
2942
3157
|
if (validationErrors) {
|
2943
3158
|
const validationErrorsMessages = formatErrorMessages(validationErrors, "", formatMessage).join(
|
@@ -2948,7 +3163,7 @@ const EntryValidationText = ({
|
|
2948
3163
|
/* @__PURE__ */ jsx(Tooltip, { description: validationErrorsMessages, children: /* @__PURE__ */ jsx(TypographyMaxWidth, { textColor: "danger600", variant: "omega", fontWeight: "semiBold", ellipsis: true, children: validationErrorsMessages }) })
|
2949
3164
|
] });
|
2950
3165
|
}
|
2951
|
-
if (
|
3166
|
+
if (status === "published") {
|
2952
3167
|
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
2953
3168
|
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
2954
3169
|
/* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
|
@@ -2957,6 +3172,15 @@ const EntryValidationText = ({
|
|
2957
3172
|
}) })
|
2958
3173
|
] });
|
2959
3174
|
}
|
3175
|
+
if (status === "modified") {
|
3176
|
+
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3177
|
+
/* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
3178
|
+
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
3179
|
+
id: "content-manager.bulk-publish.modified",
|
3180
|
+
defaultMessage: "Ready to publish changes"
|
3181
|
+
}) })
|
3182
|
+
] });
|
3183
|
+
}
|
2960
3184
|
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
2961
3185
|
/* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
2962
3186
|
/* @__PURE__ */ jsx(Typography, { children: formatMessage({
|
@@ -3008,10 +3232,10 @@ const SelectedEntriesTableContent = ({
|
|
3008
3232
|
EntryValidationText,
|
3009
3233
|
{
|
3010
3234
|
validationErrors: validationErrors[row.documentId],
|
3011
|
-
|
3235
|
+
status: row.status
|
3012
3236
|
}
|
3013
3237
|
) }),
|
3014
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3238
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3015
3239
|
IconButton,
|
3016
3240
|
{
|
3017
3241
|
tag: Link,
|
@@ -3034,9 +3258,10 @@ const SelectedEntriesTableContent = ({
|
|
3034
3258
|
),
|
3035
3259
|
target: "_blank",
|
3036
3260
|
marginLeft: "auto",
|
3037
|
-
|
3261
|
+
variant: "ghost",
|
3262
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3038
3263
|
}
|
3039
|
-
) })
|
3264
|
+
) }) })
|
3040
3265
|
] }, row.id)) })
|
3041
3266
|
] });
|
3042
3267
|
};
|
@@ -3073,7 +3298,13 @@ const SelectedEntriesModalContent = ({
|
|
3073
3298
|
);
|
3074
3299
|
const { rows, validationErrors } = React.useMemo(() => {
|
3075
3300
|
if (data.length > 0 && schema) {
|
3076
|
-
const validate = createYupSchema(
|
3301
|
+
const validate = createYupSchema(
|
3302
|
+
schema.attributes,
|
3303
|
+
components,
|
3304
|
+
// Since this is the "Publish" action, the validation
|
3305
|
+
// schema must enforce the rules for published entities
|
3306
|
+
{ status: "published" }
|
3307
|
+
);
|
3077
3308
|
const validationErrors2 = {};
|
3078
3309
|
const rows2 = data.map((entry) => {
|
3079
3310
|
try {
|
@@ -3149,7 +3380,7 @@ const SelectedEntriesModalContent = ({
|
|
3149
3380
|
);
|
3150
3381
|
};
|
3151
3382
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3152
|
-
/* @__PURE__ */ jsxs(
|
3383
|
+
/* @__PURE__ */ jsxs(Modal.Body, { children: [
|
3153
3384
|
/* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
|
3154
3385
|
/* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsx(
|
3155
3386
|
SelectedEntriesTableContent,
|
@@ -3161,27 +3392,24 @@ const SelectedEntriesModalContent = ({
|
|
3161
3392
|
}
|
3162
3393
|
) })
|
3163
3394
|
] }),
|
3164
|
-
/* @__PURE__ */
|
3165
|
-
|
3166
|
-
|
3167
|
-
|
3168
|
-
|
3169
|
-
|
3170
|
-
}) }),
|
3171
|
-
|
3172
|
-
|
3173
|
-
|
3174
|
-
|
3175
|
-
|
3176
|
-
|
3177
|
-
|
3178
|
-
|
3179
|
-
|
3180
|
-
|
3181
|
-
|
3182
|
-
] })
|
3183
|
-
}
|
3184
|
-
),
|
3395
|
+
/* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3396
|
+
/* @__PURE__ */ jsx(Button, { onClick: toggleModal, variant: "tertiary", children: formatMessage({
|
3397
|
+
id: "app.components.Button.cancel",
|
3398
|
+
defaultMessage: "Cancel"
|
3399
|
+
}) }),
|
3400
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
3401
|
+
/* @__PURE__ */ jsx(Button, { onClick: refetch, variant: "tertiary", loading: isFetching, children: formatMessage({ id: "app.utils.refresh", defaultMessage: "Refresh" }) }),
|
3402
|
+
/* @__PURE__ */ jsx(
|
3403
|
+
Button,
|
3404
|
+
{
|
3405
|
+
onClick: toggleDialog,
|
3406
|
+
disabled: selectedEntries.length === 0 || selectedEntries.length === selectedEntriesWithErrorsCount || selectedEntriesPublished === selectedEntries.length || isLoading,
|
3407
|
+
loading: isSubmittingForm,
|
3408
|
+
children: formatMessage({ id: "app.utils.publish", defaultMessage: "Publish" })
|
3409
|
+
}
|
3410
|
+
)
|
3411
|
+
] })
|
3412
|
+
] }),
|
3185
3413
|
/* @__PURE__ */ jsx(
|
3186
3414
|
ConfirmDialogPublishAll,
|
3187
3415
|
{
|
@@ -3246,143 +3474,10 @@ const BulkActionsRenderer = () => {
|
|
3246
3474
|
documents: selectedRows
|
3247
3475
|
},
|
3248
3476
|
descriptions: plugins["content-manager"].apis.getBulkActions(),
|
3249
|
-
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(
|
3477
|
+
children: (actions2) => actions2.map((action) => /* @__PURE__ */ jsx(DocumentActionButton, { ...action }, action.id))
|
3250
3478
|
}
|
3251
3479
|
) });
|
3252
3480
|
};
|
3253
|
-
const BulkActionAction = (action) => {
|
3254
|
-
const [dialogId, setDialogId] = React.useState(null);
|
3255
|
-
const { toggleNotification } = useNotification();
|
3256
|
-
const handleClick = (action2) => (e) => {
|
3257
|
-
const { onClick, dialog, id } = action2;
|
3258
|
-
if (onClick) {
|
3259
|
-
onClick(e);
|
3260
|
-
}
|
3261
|
-
if (dialog) {
|
3262
|
-
switch (dialog.type) {
|
3263
|
-
case "notification":
|
3264
|
-
toggleNotification({
|
3265
|
-
title: dialog.title,
|
3266
|
-
message: dialog.content,
|
3267
|
-
type: dialog.status,
|
3268
|
-
timeout: dialog.timeout,
|
3269
|
-
onClose: dialog.onClose
|
3270
|
-
});
|
3271
|
-
break;
|
3272
|
-
case "dialog":
|
3273
|
-
case "modal": {
|
3274
|
-
e.preventDefault();
|
3275
|
-
setDialogId(id);
|
3276
|
-
}
|
3277
|
-
}
|
3278
|
-
}
|
3279
|
-
};
|
3280
|
-
const handleClose = () => {
|
3281
|
-
setDialogId(null);
|
3282
|
-
if (action.dialog?.type === "modal" && action.dialog?.onClose) {
|
3283
|
-
action.dialog.onClose();
|
3284
|
-
}
|
3285
|
-
};
|
3286
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
3287
|
-
/* @__PURE__ */ jsx(
|
3288
|
-
Button,
|
3289
|
-
{
|
3290
|
-
disabled: action.disabled,
|
3291
|
-
startIcon: action.icon,
|
3292
|
-
variant: action.variant,
|
3293
|
-
onClick: handleClick(action),
|
3294
|
-
children: action.label
|
3295
|
-
}
|
3296
|
-
),
|
3297
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsx(
|
3298
|
-
BulkActionConfirmDialog,
|
3299
|
-
{
|
3300
|
-
...action.dialog,
|
3301
|
-
variant: action.variant,
|
3302
|
-
isOpen: dialogId === action.id,
|
3303
|
-
onClose: handleClose
|
3304
|
-
}
|
3305
|
-
) : null,
|
3306
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsx(
|
3307
|
-
BulkActionModal,
|
3308
|
-
{
|
3309
|
-
...action.dialog,
|
3310
|
-
onModalClose: handleClose,
|
3311
|
-
isOpen: dialogId === action.id
|
3312
|
-
}
|
3313
|
-
) : null
|
3314
|
-
] });
|
3315
|
-
};
|
3316
|
-
const BulkActionConfirmDialog = ({
|
3317
|
-
onClose,
|
3318
|
-
onCancel,
|
3319
|
-
onConfirm,
|
3320
|
-
title,
|
3321
|
-
content,
|
3322
|
-
confirmButton,
|
3323
|
-
isOpen,
|
3324
|
-
variant = "secondary"
|
3325
|
-
}) => {
|
3326
|
-
const { formatMessage } = useIntl();
|
3327
|
-
const handleClose = async () => {
|
3328
|
-
if (onCancel) {
|
3329
|
-
await onCancel();
|
3330
|
-
}
|
3331
|
-
onClose();
|
3332
|
-
};
|
3333
|
-
const handleConfirm = async () => {
|
3334
|
-
if (onConfirm) {
|
3335
|
-
await onConfirm();
|
3336
|
-
}
|
3337
|
-
onClose();
|
3338
|
-
};
|
3339
|
-
return /* @__PURE__ */ jsxs(Dialog, { isOpen, title, onClose: handleClose, children: [
|
3340
|
-
/* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: content }),
|
3341
|
-
/* @__PURE__ */ jsx(
|
3342
|
-
DialogFooter,
|
3343
|
-
{
|
3344
|
-
startAction: /* @__PURE__ */ jsx(Button, { onClick: handleClose, variant: "tertiary", children: formatMessage({
|
3345
|
-
id: "app.components.Button.cancel",
|
3346
|
-
defaultMessage: "Cancel"
|
3347
|
-
}) }),
|
3348
|
-
endAction: /* @__PURE__ */ jsx(
|
3349
|
-
Button,
|
3350
|
-
{
|
3351
|
-
onClick: handleConfirm,
|
3352
|
-
variant: variant === "danger-light" ? variant : "secondary",
|
3353
|
-
startIcon: variant === "danger-light" ? /* @__PURE__ */ jsx(Trash, {}) : /* @__PURE__ */ jsx(Check, {}),
|
3354
|
-
children: confirmButton ? confirmButton : formatMessage({
|
3355
|
-
id: "app.components.Button.confirm",
|
3356
|
-
defaultMessage: "Confirm"
|
3357
|
-
})
|
3358
|
-
}
|
3359
|
-
)
|
3360
|
-
}
|
3361
|
-
)
|
3362
|
-
] });
|
3363
|
-
};
|
3364
|
-
const BulkActionModal = ({
|
3365
|
-
isOpen,
|
3366
|
-
title,
|
3367
|
-
onClose,
|
3368
|
-
content: Content,
|
3369
|
-
onModalClose
|
3370
|
-
}) => {
|
3371
|
-
const id = React.useId();
|
3372
|
-
if (!isOpen) {
|
3373
|
-
return null;
|
3374
|
-
}
|
3375
|
-
const handleClose = () => {
|
3376
|
-
if (onClose) {
|
3377
|
-
onClose();
|
3378
|
-
}
|
3379
|
-
onModalClose();
|
3380
|
-
};
|
3381
|
-
return /* @__PURE__ */ jsxs(ModalLayout, { borderRadius: "4px", overflow: "hidden", onClose: handleClose, labelledBy: id, children: [
|
3382
|
-
/* @__PURE__ */ jsx(ModalHeader, { children: /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", textColor: "neutral800", tag: "h2", id, children: title }) }),
|
3383
|
-
/* @__PURE__ */ jsx(Content, { onClose: handleClose })
|
3384
|
-
] });
|
3385
|
-
};
|
3386
3481
|
const DeleteAction = ({ documents, model }) => {
|
3387
3482
|
const { formatMessage } = useIntl();
|
3388
3483
|
const { schema: contentType } = useDoc();
|
@@ -3415,6 +3510,7 @@ const DeleteAction = ({ documents, model }) => {
|
|
3415
3510
|
defaultMessage: "Confirmation"
|
3416
3511
|
}),
|
3417
3512
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3513
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3418
3514
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3419
3515
|
id: "popUpWarning.bodyMessage.contentType.delete.all",
|
3420
3516
|
defaultMessage: "Are you sure you want to delete these entries?"
|
@@ -3451,7 +3547,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3451
3547
|
selectRow([]);
|
3452
3548
|
}
|
3453
3549
|
};
|
3454
|
-
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published");
|
3550
|
+
const showUnpublishButton = hasDraftAndPublishEnabled && hasPublishPermission && documents.some((entry) => entry.status === "published" || entry.status === "modified");
|
3455
3551
|
if (!showUnpublishButton)
|
3456
3552
|
return null;
|
3457
3553
|
return {
|
@@ -3464,6 +3560,7 @@ const UnpublishAction = ({ documents, model }) => {
|
|
3464
3560
|
defaultMessage: "Confirmation"
|
3465
3561
|
}),
|
3466
3562
|
content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
|
3563
|
+
/* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }) }),
|
3467
3564
|
/* @__PURE__ */ jsx(Typography, { id: "confirm-description", textAlign: "center", children: formatMessage({
|
3468
3565
|
id: "popUpWarning.bodyMessage.contentType.unpublish.all",
|
3469
3566
|
defaultMessage: "Are you sure you want to unpublish these entries?"
|
@@ -3557,7 +3654,7 @@ const TableActions = ({ document }) => {
|
|
3557
3654
|
DescriptionComponentRenderer,
|
3558
3655
|
{
|
3559
3656
|
props,
|
3560
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3657
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3561
3658
|
children: (actions2) => {
|
3562
3659
|
const tableRowActions = actions2.filter((action) => {
|
3563
3660
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3668,7 +3765,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3668
3765
|
}),
|
3669
3766
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3670
3767
|
footer: ({ onClose }) => {
|
3671
|
-
return /* @__PURE__ */ jsxs(
|
3768
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3672
3769
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3673
3770
|
id: "cancel",
|
3674
3771
|
defaultMessage: "Cancel"
|
@@ -3709,8 +3806,7 @@ class ContentManagerPlugin {
|
|
3709
3806
|
documentActions = [
|
3710
3807
|
...DEFAULT_ACTIONS,
|
3711
3808
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3712
|
-
...DEFAULT_HEADER_ACTIONS
|
3713
|
-
HistoryAction
|
3809
|
+
...DEFAULT_HEADER_ACTIONS
|
3714
3810
|
];
|
3715
3811
|
editViewSidePanels = [ActionsPanel];
|
3716
3812
|
headerActions = [];
|
@@ -3799,6 +3895,52 @@ const getPrintableType = (value) => {
|
|
3799
3895
|
}
|
3800
3896
|
return nativeType;
|
3801
3897
|
};
|
3898
|
+
const HistoryAction = ({ model, document }) => {
|
3899
|
+
const { formatMessage } = useIntl();
|
3900
|
+
const [{ query }] = useQueryParams();
|
3901
|
+
const navigate = useNavigate();
|
3902
|
+
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3903
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3904
|
+
return null;
|
3905
|
+
}
|
3906
|
+
return {
|
3907
|
+
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3908
|
+
label: formatMessage({
|
3909
|
+
id: "content-manager.history.document-action",
|
3910
|
+
defaultMessage: "Content History"
|
3911
|
+
}),
|
3912
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3913
|
+
disabled: (
|
3914
|
+
/**
|
3915
|
+
* The user is creating a new document.
|
3916
|
+
* It hasn't been saved yet, so there's no history to go to
|
3917
|
+
*/
|
3918
|
+
!document || /**
|
3919
|
+
* The document has been created but the current dimension has never been saved.
|
3920
|
+
* For example, the user is creating a new locale in an existing document,
|
3921
|
+
* so there's no history for the document in that locale
|
3922
|
+
*/
|
3923
|
+
!document.id || /**
|
3924
|
+
* History is only available for content types created by the user.
|
3925
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3926
|
+
* which start with `admin::` or `plugin::`
|
3927
|
+
*/
|
3928
|
+
!model.startsWith("api::")
|
3929
|
+
),
|
3930
|
+
position: "header"
|
3931
|
+
};
|
3932
|
+
};
|
3933
|
+
HistoryAction.type = "history";
|
3934
|
+
const historyAdmin = {
|
3935
|
+
bootstrap(app) {
|
3936
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3937
|
+
addDocumentAction((actions2) => {
|
3938
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3939
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3940
|
+
return actions2;
|
3941
|
+
});
|
3942
|
+
}
|
3943
|
+
};
|
3802
3944
|
const initialState = {
|
3803
3945
|
collectionTypeLinks: [],
|
3804
3946
|
components: [],
|
@@ -3849,15 +3991,29 @@ const index = {
|
|
3849
3991
|
defaultMessage: "Content Manager"
|
3850
3992
|
},
|
3851
3993
|
permissions: [],
|
3852
|
-
Component: () => import("./layout-CPn1PM6x.mjs").then((mod) => ({ default: mod.Layout })),
|
3853
3994
|
position: 1
|
3854
3995
|
});
|
3996
|
+
app.router.addRoute({
|
3997
|
+
path: "content-manager/*",
|
3998
|
+
lazy: async () => {
|
3999
|
+
const { Layout } = await import("./layout-B4UhJ8MJ.mjs");
|
4000
|
+
return {
|
4001
|
+
Component: Layout
|
4002
|
+
};
|
4003
|
+
},
|
4004
|
+
children: routes
|
4005
|
+
});
|
3855
4006
|
app.registerPlugin(cm.config);
|
3856
4007
|
},
|
4008
|
+
bootstrap(app) {
|
4009
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4010
|
+
historyAdmin.bootstrap(app);
|
4011
|
+
}
|
4012
|
+
},
|
3857
4013
|
async registerTrads({ locales }) {
|
3858
4014
|
const importedTrads = await Promise.all(
|
3859
4015
|
locales.map((locale) => {
|
3860
|
-
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-
|
4016
|
+
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-C8YBvRrK.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 }) => {
|
3861
4017
|
return {
|
3862
4018
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3863
4019
|
locale
|
@@ -3885,36 +4041,37 @@ export {
|
|
3885
4041
|
InjectionZone as I,
|
3886
4042
|
useDocument as J,
|
3887
4043
|
index as K,
|
3888
|
-
|
4044
|
+
useContentManagerContext as L,
|
4045
|
+
useDocumentActions as M,
|
3889
4046
|
Panels as P,
|
3890
4047
|
RelativeTime as R,
|
3891
4048
|
SINGLE_TYPES as S,
|
3892
4049
|
TableActions as T,
|
3893
|
-
|
3894
|
-
|
3895
|
-
|
3896
|
-
|
3897
|
-
|
3898
|
-
|
4050
|
+
useGetInitialDataQuery as a,
|
4051
|
+
useGetAllContentTypeSettingsQuery as b,
|
4052
|
+
useDoc as c,
|
4053
|
+
buildValidParams as d,
|
4054
|
+
contentManagerApi as e,
|
4055
|
+
useDocumentRBAC as f,
|
3899
4056
|
getTranslation as g,
|
3900
|
-
|
3901
|
-
|
3902
|
-
|
3903
|
-
|
3904
|
-
|
3905
|
-
|
3906
|
-
|
3907
|
-
|
3908
|
-
|
3909
|
-
|
3910
|
-
|
4057
|
+
useDocumentLayout as h,
|
4058
|
+
createYupSchema as i,
|
4059
|
+
Header as j,
|
4060
|
+
PERMISSIONS as k,
|
4061
|
+
DocumentRBAC as l,
|
4062
|
+
DOCUMENT_META_FIELDS as m,
|
4063
|
+
CLONE_PATH as n,
|
4064
|
+
useDocLayout as o,
|
4065
|
+
useGetContentTypeConfigurationQuery as p,
|
4066
|
+
CREATOR_FIELDS as q,
|
4067
|
+
getMainField as r,
|
3911
4068
|
setInitialData as s,
|
3912
4069
|
getDisplayName as t,
|
3913
|
-
|
4070
|
+
useContentTypeSchema as u,
|
3914
4071
|
checkIfAttributeIsDisplayable as v,
|
3915
4072
|
useGetAllDocumentsQuery as w,
|
3916
4073
|
convertListLayoutToFieldLayouts as x,
|
3917
4074
|
capitalise as y,
|
3918
4075
|
useUpdateContentTypeConfigurationMutation as z
|
3919
4076
|
};
|
3920
|
-
//# sourceMappingURL=index-
|
4077
|
+
//# sourceMappingURL=index-CPCHQ3X_.mjs.map
|