@strapi/content-manager 0.0.0-experimental.edc24aaa3bb5a90fa5fd4fee208167dd4e2e38d4 → 0.0.0-experimental.f0a0bc26f5ef0693aaea2a616bc6b816cfee54b6
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/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs → ComponentConfigurationPage-DhWA-JzT.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-BAgyHiMm.mjs.map → ComponentConfigurationPage-DhWA-JzT.mjs.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js → ComponentConfigurationPage-UduDBv3m.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-5ukroXAh.js.map → ComponentConfigurationPage-UduDBv3m.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs → EditConfigurationPage-5tmx_7Hp.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-DmoXawIh.mjs.map → EditConfigurationPage-5tmx_7Hp.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js → EditConfigurationPage-Cp9UzUfs.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-Xp7lun0f.js.map → EditConfigurationPage-Cp9UzUfs.js.map} +1 -1
- package/dist/_chunks/{EditViewPage-BLsjc5F-.mjs → EditViewPage-BKoISUOu.mjs} +63 -12
- package/dist/_chunks/EditViewPage-BKoISUOu.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-C-ukDOB7.js → EditViewPage-C7l2Emuj.js} +62 -11
- package/dist/_chunks/EditViewPage-C7l2Emuj.js.map +1 -0
- package/dist/_chunks/{Field-Bfph5SOd.js → Field-BPSJpDfE.js} +211 -120
- package/dist/_chunks/Field-BPSJpDfE.js.map +1 -0
- package/dist/_chunks/{Field-Cs7duwWd.mjs → Field-BZxzYf1x.mjs} +210 -119
- package/dist/_chunks/Field-BZxzYf1x.mjs.map +1 -0
- package/dist/_chunks/{Form-Dg_GS5TQ.mjs → Form-8qyOU6YG.mjs} +36 -17
- package/dist/_chunks/Form-8qyOU6YG.mjs.map +1 -0
- package/dist/_chunks/{Form-CPYqIWDG.js → Form-DLkqDd2G.js} +36 -17
- package/dist/_chunks/Form-DLkqDd2G.js.map +1 -0
- package/dist/_chunks/{History-DNQkXANT.js → History-DYMicybF.js} +41 -98
- package/dist/_chunks/History-DYMicybF.js.map +1 -0
- package/dist/_chunks/{History-wrnHqf09.mjs → History-N_kRb1Yr.mjs} +43 -100
- package/dist/_chunks/History-N_kRb1Yr.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-DScmJVkW.mjs → ListConfigurationPage-BM3qVxug.mjs} +18 -7
- package/dist/_chunks/ListConfigurationPage-BM3qVxug.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CUQxfpjT.js → ListConfigurationPage-rUF9iGWq.js} +17 -6
- package/dist/_chunks/ListConfigurationPage-rUF9iGWq.js.map +1 -0
- package/dist/_chunks/{ListViewPage-BsLiH2-2.js → ListViewPage-BSLzd7cZ.js} +108 -76
- package/dist/_chunks/ListViewPage-BSLzd7cZ.js.map +1 -0
- package/dist/_chunks/{ListViewPage-C4IvrMgY.mjs → ListViewPage-CWilGbZb.mjs} +106 -74
- package/dist/_chunks/ListViewPage-CWilGbZb.mjs.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js → NoContentTypePage-CQccVhIX.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BZ-PnGAf.js.map → NoContentTypePage-CQccVhIX.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs → NoContentTypePage-VWYlePwI.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-Djg8nPlj.mjs.map → NoContentTypePage-VWYlePwI.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js → NoPermissionsPage-Af32Gg2m.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-_lUqjGW3.js.map → NoPermissionsPage-Af32Gg2m.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs → NoPermissionsPage-CS2tCmfr.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-DSP7R-hv.mjs.map → NoPermissionsPage-CS2tCmfr.mjs.map} +1 -1
- package/dist/_chunks/Preview-D4KzuJFL.js +291 -0
- package/dist/_chunks/Preview-D4KzuJFL.js.map +1 -0
- package/dist/_chunks/Preview-kPkuZbBJ.mjs +272 -0
- package/dist/_chunks/Preview-kPkuZbBJ.mjs.map +1 -0
- package/dist/_chunks/{Relations-BZr8tL0R.mjs → Relations-5k27Rh54.mjs} +73 -37
- package/dist/_chunks/Relations-5k27Rh54.mjs.map +1 -0
- package/dist/_chunks/{Relations-CtELXYIK.js → Relations-D_Ki5aVM.js} +72 -36
- package/dist/_chunks/Relations-D_Ki5aVM.js.map +1 -0
- package/dist/_chunks/{en-uOUIxfcQ.js → en-BK8Xyl5I.js} +28 -15
- package/dist/_chunks/{en-uOUIxfcQ.js.map → en-BK8Xyl5I.js.map} +1 -1
- package/dist/_chunks/{en-BrCTWlZv.mjs → en-Dtk_ot79.mjs} +28 -15
- package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-Dtk_ot79.mjs.map} +1 -1
- package/dist/_chunks/{es-EUonQTon.js → es-9K52xZIr.js} +2 -2
- package/dist/_chunks/{ja-CcFe8diO.js.map → es-9K52xZIr.js.map} +1 -1
- package/dist/_chunks/{es-CeXiYflN.mjs → es-D34tqjMw.mjs} +2 -2
- package/dist/_chunks/{es-CeXiYflN.mjs.map → es-D34tqjMw.mjs.map} +1 -1
- package/dist/_chunks/{fr-CD9VFbPM.mjs → fr--pg5jUbt.mjs} +13 -3
- package/dist/_chunks/{fr-CD9VFbPM.mjs.map → fr--pg5jUbt.mjs.map} +1 -1
- package/dist/_chunks/{fr-B7kGGg3E.js → fr-B2Kyv8Z9.js} +13 -3
- package/dist/_chunks/{fr-B7kGGg3E.js.map → fr-B2Kyv8Z9.js.map} +1 -1
- package/dist/_chunks/{index-c_5DdJi-.mjs → index-BLPa8Dq-.mjs} +1201 -924
- package/dist/_chunks/index-BLPa8Dq-.mjs.map +1 -0
- package/dist/_chunks/{index-OerGjbAN.js → index-DwOsF7wF.js} +1182 -904
- package/dist/_chunks/index-DwOsF7wF.js.map +1 -0
- package/dist/_chunks/{ja-CcFe8diO.js → ja-7sfIbjxE.js} +2 -2
- package/dist/_chunks/{es-EUonQTon.js.map → ja-7sfIbjxE.js.map} +1 -1
- package/dist/_chunks/{ja-CtsUxOvk.mjs → ja-BHqhDq4V.mjs} +2 -2
- package/dist/_chunks/{ja-CtsUxOvk.mjs.map → ja-BHqhDq4V.mjs.map} +1 -1
- package/dist/_chunks/{layout-oPBiO7RY.mjs → layout-2Si0j0jO.mjs} +22 -9
- package/dist/_chunks/layout-2Si0j0jO.mjs.map +1 -0
- package/dist/_chunks/{layout-Ci7qHlFb.js → layout-CN2bFL9V.js} +21 -8
- package/dist/_chunks/layout-CN2bFL9V.js.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-COBpStiF.js → relations-B0E0XUY7.js} +6 -7
- package/dist/_chunks/relations-B0E0XUY7.js.map +1 -0
- package/dist/_chunks/{relations-BIdWFjdq.mjs → relations-CAxDjUJF.mjs} +6 -7
- package/dist/_chunks/relations-CAxDjUJF.mjs.map +1 -0
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +32 -1
- package/dist/admin/src/pages/EditView/EditViewPage.d.ts +9 -1
- package/dist/admin/src/pages/EditView/components/DocumentStatus.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/preview/components/PreviewContent.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewHeader.d.ts +2 -0
- package/dist/admin/src/preview/components/PreviewSidePanel.d.ts +3 -0
- package/dist/admin/src/preview/constants.d.ts +1 -0
- package/dist/admin/src/preview/index.d.ts +4 -0
- package/dist/admin/src/preview/pages/Preview.d.ts +11 -0
- package/dist/admin/src/preview/routes.d.ts +3 -0
- package/dist/admin/src/preview/services/preview.d.ts +3 -0
- package/dist/admin/src/router.d.ts +1 -1
- 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 -20
- 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 +560 -235
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +561 -236
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/index.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/utils/metadata.d.ts +15 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/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 +4 -4
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/preview/constants.d.ts +2 -0
- package/dist/server/src/preview/constants.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/index.d.ts +2 -0
- package/dist/server/src/preview/controllers/index.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/preview.d.ts +13 -0
- package/dist/server/src/preview/controllers/preview.d.ts.map +1 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts +6 -0
- package/dist/server/src/preview/controllers/validation/preview.d.ts.map +1 -0
- package/dist/server/src/preview/index.d.ts +4 -0
- package/dist/server/src/preview/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/index.d.ts +8 -0
- package/dist/server/src/preview/routes/index.d.ts.map +1 -0
- package/dist/server/src/preview/routes/preview.d.ts +4 -0
- package/dist/server/src/preview/routes/preview.d.ts.map +1 -0
- package/dist/server/src/preview/services/index.d.ts +16 -0
- package/dist/server/src/preview/services/index.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview-config.d.ts +32 -0
- package/dist/server/src/preview/services/preview-config.d.ts.map +1 -0
- package/dist/server/src/preview/services/preview.d.ts +12 -0
- package/dist/server/src/preview/services/preview.d.ts.map +1 -0
- package/dist/server/src/preview/utils.d.ts +19 -0
- package/dist/server/src/preview/utils.d.ts.map +1 -0
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/routes/index.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -8
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -4
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/dist/shared/contracts/index.d.ts +1 -0
- package/dist/shared/contracts/index.d.ts.map +1 -1
- package/dist/shared/contracts/preview.d.ts +27 -0
- package/dist/shared/contracts/preview.d.ts.map +1 -0
- package/dist/shared/index.js +4 -0
- package/dist/shared/index.js.map +1 -1
- package/dist/shared/index.mjs +4 -0
- package/dist/shared/index.mjs.map +1 -1
- package/package.json +14 -14
- package/dist/_chunks/EditViewPage-BLsjc5F-.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-C-ukDOB7.js.map +0 -1
- package/dist/_chunks/Field-Bfph5SOd.js.map +0 -1
- package/dist/_chunks/Field-Cs7duwWd.mjs.map +0 -1
- package/dist/_chunks/Form-CPYqIWDG.js.map +0 -1
- package/dist/_chunks/Form-Dg_GS5TQ.mjs.map +0 -1
- package/dist/_chunks/History-DNQkXANT.js.map +0 -1
- package/dist/_chunks/History-wrnHqf09.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-CUQxfpjT.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-DScmJVkW.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-BsLiH2-2.js.map +0 -1
- package/dist/_chunks/ListViewPage-C4IvrMgY.mjs.map +0 -1
- package/dist/_chunks/Relations-BZr8tL0R.mjs.map +0 -1
- package/dist/_chunks/Relations-CtELXYIK.js.map +0 -1
- package/dist/_chunks/index-OerGjbAN.js.map +0 -1
- package/dist/_chunks/index-c_5DdJi-.mjs.map +0 -1
- package/dist/_chunks/layout-Ci7qHlFb.js.map +0 -1
- package/dist/_chunks/layout-oPBiO7RY.mjs.map +0 -1
- package/dist/_chunks/relations-BIdWFjdq.mjs.map +0 -1
- package/dist/_chunks/relations-COBpStiF.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,18 @@
|
|
1
|
-
import {
|
1
|
+
import { More, Cross, WarningCircle, ListPlus, Pencil, Trash, Check, CrossCircle, CheckCircle, ArrowsCounterClockwise, ChevronRight, Duplicate, ClockCounterClockwise, Feather } from "@strapi/icons";
|
2
2
|
import { jsx, Fragment, jsxs } from "react/jsx-runtime";
|
3
|
-
import { useStrapiApp, createContext, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors,
|
3
|
+
import { useStrapiApp, createContext, useQueryParams, useAuth, useRBAC, Page, adminApi, translatedErrors, useNotification, useAPIErrorHandler, getYupValidationErrors, useForm, useTracking, useGuidedTour, BackButton, DescriptionComponentRenderer, useTable, Table } from "@strapi/admin/strapi-admin";
|
4
4
|
import * as React from "react";
|
5
5
|
import { lazy } from "react";
|
6
|
-
import {
|
6
|
+
import { Menu, Button, VisuallyHidden, Flex, Dialog, Modal, Typography, Radio, Status, Box, SingleSelect, SingleSelectOption, IconButton, Loader, Tooltip, LinkButton } from "@strapi/design-system";
|
7
|
+
import mapValues from "lodash/fp/mapValues";
|
7
8
|
import { useIntl } from "react-intl";
|
8
|
-
import { useParams,
|
9
|
+
import { useParams, useNavigate, Navigate, useMatch, useLocation, Link, NavLink } from "react-router-dom";
|
9
10
|
import { styled } from "styled-components";
|
10
11
|
import * as yup from "yup";
|
11
12
|
import { ValidationError } from "yup";
|
13
|
+
import { stringify } from "qs";
|
12
14
|
import pipe from "lodash/fp/pipe";
|
13
15
|
import { intervalToDuration, isPast } from "date-fns";
|
14
|
-
import { stringify } from "qs";
|
15
16
|
import { createSlice, combineReducers } from "@reduxjs/toolkit";
|
16
17
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
17
18
|
const v = glob[path];
|
@@ -100,6 +101,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
100
101
|
if (!slug) {
|
101
102
|
throw new Error("Cannot find the slug param in the URL");
|
102
103
|
}
|
104
|
+
const [{ rawQuery }] = useQueryParams();
|
103
105
|
const userPermissions = useAuth("DocumentRBAC", (state) => state.permissions);
|
104
106
|
const contentTypePermissions = React.useMemo(() => {
|
105
107
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -110,7 +112,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
110
112
|
return { ...acc, [action]: [permission] };
|
111
113
|
}, {});
|
112
114
|
}, [slug, userPermissions]);
|
113
|
-
const { isLoading, allowedActions } = useRBAC(
|
115
|
+
const { isLoading, allowedActions } = useRBAC(
|
116
|
+
contentTypePermissions,
|
117
|
+
permissions ?? void 0,
|
118
|
+
// TODO: useRBAC context should be typed and built differently
|
119
|
+
// We are passing raw query as context to the hook so that it can
|
120
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
121
|
+
rawQuery
|
122
|
+
);
|
114
123
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
115
124
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
116
125
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -158,7 +167,8 @@ const contentManagerApi = adminApi.enhanceEndpoints({
|
|
158
167
|
"Document",
|
159
168
|
"InitialData",
|
160
169
|
"HistoryVersion",
|
161
|
-
"Relations"
|
170
|
+
"Relations",
|
171
|
+
"UidAvailability"
|
162
172
|
]
|
163
173
|
});
|
164
174
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -188,7 +198,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
188
198
|
params
|
189
199
|
}
|
190
200
|
}),
|
191
|
-
invalidatesTags: (_result, _error, { model }) => [
|
201
|
+
invalidatesTags: (_result, _error, { model }) => [
|
202
|
+
{ type: "Document", id: `${model}_LIST` },
|
203
|
+
{ type: "UidAvailability", id: model }
|
204
|
+
]
|
192
205
|
}),
|
193
206
|
/**
|
194
207
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -205,7 +218,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
205
218
|
}),
|
206
219
|
invalidatesTags: (result, _error, { model }) => [
|
207
220
|
{ type: "Document", id: `${model}_LIST` },
|
208
|
-
"Relations"
|
221
|
+
"Relations",
|
222
|
+
{ type: "UidAvailability", id: model }
|
209
223
|
]
|
210
224
|
}),
|
211
225
|
deleteDocument: builder.mutation({
|
@@ -246,7 +260,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
246
260
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
247
261
|
},
|
248
262
|
{ type: "Document", id: `${model}_LIST` },
|
249
|
-
"Relations"
|
263
|
+
"Relations",
|
264
|
+
{ type: "UidAvailability", id: model }
|
250
265
|
];
|
251
266
|
}
|
252
267
|
}),
|
@@ -259,11 +274,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
259
274
|
url: `/content-manager/collection-types/${model}`,
|
260
275
|
method: "GET",
|
261
276
|
config: {
|
262
|
-
params
|
277
|
+
params: stringify(params, { encode: true })
|
263
278
|
}
|
264
279
|
}),
|
265
280
|
providesTags: (result, _error, arg) => {
|
266
281
|
return [
|
282
|
+
{ type: "Document", id: `ALL_LIST` },
|
267
283
|
{ type: "Document", id: `${arg.model}_LIST` },
|
268
284
|
...result?.results.map(({ documentId }) => ({
|
269
285
|
type: "Document",
|
@@ -302,6 +318,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
302
318
|
{
|
303
319
|
type: "Document",
|
304
320
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
321
|
+
},
|
322
|
+
// Make it easy to invalidate all individual documents queries for a model
|
323
|
+
{
|
324
|
+
type: "Document",
|
325
|
+
id: `${model}_ALL_ITEMS`
|
305
326
|
}
|
306
327
|
];
|
307
328
|
}
|
@@ -365,7 +386,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
365
386
|
type: "Document",
|
366
387
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
367
388
|
},
|
368
|
-
"Relations"
|
389
|
+
"Relations",
|
390
|
+
{ type: "UidAvailability", id: model }
|
369
391
|
];
|
370
392
|
},
|
371
393
|
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
@@ -440,28 +462,44 @@ const buildValidParams = (query) => {
|
|
440
462
|
{}
|
441
463
|
)
|
442
464
|
};
|
443
|
-
if ("_q" in validQueryParams) {
|
444
|
-
validQueryParams._q = encodeURIComponent(validQueryParams._q);
|
445
|
-
}
|
446
465
|
return validQueryParams;
|
447
466
|
};
|
448
467
|
const isBaseQueryError = (error) => {
|
449
468
|
return error.name !== void 0;
|
450
469
|
};
|
451
|
-
const
|
470
|
+
const arrayValidator = (attribute, options) => ({
|
471
|
+
message: translatedErrors.required,
|
472
|
+
test(value) {
|
473
|
+
if (options.status === "draft") {
|
474
|
+
return true;
|
475
|
+
}
|
476
|
+
if (!attribute.required) {
|
477
|
+
return true;
|
478
|
+
}
|
479
|
+
if (!value) {
|
480
|
+
return false;
|
481
|
+
}
|
482
|
+
if (Array.isArray(value) && value.length === 0) {
|
483
|
+
return false;
|
484
|
+
}
|
485
|
+
return true;
|
486
|
+
}
|
487
|
+
});
|
488
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
452
489
|
const createModelSchema = (attributes2) => yup.object().shape(
|
453
490
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
454
491
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
455
492
|
return acc;
|
456
493
|
}
|
457
494
|
const validations = [
|
495
|
+
addNullableValidation,
|
458
496
|
addRequiredValidation,
|
459
497
|
addMinLengthValidation,
|
460
498
|
addMaxLengthValidation,
|
461
499
|
addMinValidation,
|
462
500
|
addMaxValidation,
|
463
501
|
addRegexValidation
|
464
|
-
].map((fn) => fn(attribute));
|
502
|
+
].map((fn) => fn(attribute, options));
|
465
503
|
const transformSchema = pipe(...validations);
|
466
504
|
switch (attribute.type) {
|
467
505
|
case "component": {
|
@@ -471,12 +509,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
471
509
|
...acc,
|
472
510
|
[name]: transformSchema(
|
473
511
|
yup.array().of(createModelSchema(attributes3).nullable(false))
|
474
|
-
)
|
512
|
+
).test(arrayValidator(attribute, options))
|
475
513
|
};
|
476
514
|
} else {
|
477
515
|
return {
|
478
516
|
...acc,
|
479
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
517
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
480
518
|
};
|
481
519
|
}
|
482
520
|
}
|
@@ -498,7 +536,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
498
536
|
}
|
499
537
|
)
|
500
538
|
)
|
501
|
-
)
|
539
|
+
).test(arrayValidator(attribute, options))
|
502
540
|
};
|
503
541
|
case "relation":
|
504
542
|
return {
|
@@ -510,7 +548,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
510
548
|
} else if (Array.isArray(value)) {
|
511
549
|
return yup.array().of(
|
512
550
|
yup.object().shape({
|
513
|
-
id: yup.
|
551
|
+
id: yup.number().required()
|
514
552
|
})
|
515
553
|
);
|
516
554
|
} else if (typeof value === "object") {
|
@@ -562,6 +600,14 @@ const createAttributeSchema = (attribute) => {
|
|
562
600
|
if (!value || typeof value === "string" && value.length === 0) {
|
563
601
|
return true;
|
564
602
|
}
|
603
|
+
if (typeof value === "object") {
|
604
|
+
try {
|
605
|
+
JSON.stringify(value);
|
606
|
+
return true;
|
607
|
+
} catch (err) {
|
608
|
+
return false;
|
609
|
+
}
|
610
|
+
}
|
565
611
|
try {
|
566
612
|
JSON.parse(value);
|
567
613
|
return true;
|
@@ -580,13 +626,7 @@ const createAttributeSchema = (attribute) => {
|
|
580
626
|
return yup.mixed();
|
581
627
|
}
|
582
628
|
};
|
583
|
-
const
|
584
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
585
|
-
return schema.min(1, translatedErrors.required);
|
586
|
-
}
|
587
|
-
if (attribute.required && attribute.type !== "relation") {
|
588
|
-
return schema.required(translatedErrors.required);
|
589
|
-
}
|
629
|
+
const nullableSchema = (schema) => {
|
590
630
|
return schema?.nullable ? schema.nullable() : (
|
591
631
|
// In some cases '.nullable' will not be available on the schema.
|
592
632
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -594,7 +634,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
594
634
|
schema
|
595
635
|
);
|
596
636
|
};
|
597
|
-
const
|
637
|
+
const addNullableValidation = () => (schema) => {
|
638
|
+
return nullableSchema(schema);
|
639
|
+
};
|
640
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
641
|
+
if (options.status === "draft" || !attribute.required) {
|
642
|
+
return schema;
|
643
|
+
}
|
644
|
+
if (attribute.required && "required" in schema) {
|
645
|
+
return schema.required(translatedErrors.required);
|
646
|
+
}
|
647
|
+
return schema;
|
648
|
+
};
|
649
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
650
|
+
if (options.status === "draft") {
|
651
|
+
return schema;
|
652
|
+
}
|
598
653
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
599
654
|
return schema.min(attribute.minLength, {
|
600
655
|
...translatedErrors.minLength,
|
@@ -616,32 +671,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
616
671
|
}
|
617
672
|
return schema;
|
618
673
|
};
|
619
|
-
const addMinValidation = (attribute) => (schema) => {
|
620
|
-
if ("
|
674
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
675
|
+
if (options.status === "draft") {
|
676
|
+
return schema;
|
677
|
+
}
|
678
|
+
if ("min" in attribute && "min" in schema) {
|
621
679
|
const min = toInteger(attribute.min);
|
622
|
-
if (
|
623
|
-
if (!attribute.required && "test" in schema && min) {
|
624
|
-
return schema.test(
|
625
|
-
"custom-min",
|
626
|
-
{
|
627
|
-
...translatedErrors.min,
|
628
|
-
values: {
|
629
|
-
min: attribute.min
|
630
|
-
}
|
631
|
-
},
|
632
|
-
(value) => {
|
633
|
-
if (!value) {
|
634
|
-
return true;
|
635
|
-
}
|
636
|
-
if (Array.isArray(value) && value.length === 0) {
|
637
|
-
return true;
|
638
|
-
}
|
639
|
-
return value.length >= min;
|
640
|
-
}
|
641
|
-
);
|
642
|
-
}
|
643
|
-
}
|
644
|
-
if ("min" in schema && min) {
|
680
|
+
if (min) {
|
645
681
|
return schema.min(min, {
|
646
682
|
...translatedErrors.min,
|
647
683
|
values: {
|
@@ -759,19 +795,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
759
795
|
}, {});
|
760
796
|
return componentsByKey;
|
761
797
|
};
|
762
|
-
const
|
798
|
+
const HOOKS = {
|
799
|
+
/**
|
800
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
801
|
+
* @constant
|
802
|
+
* @type {string}
|
803
|
+
*/
|
804
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
805
|
+
/**
|
806
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
807
|
+
* @constant
|
808
|
+
* @type {string}
|
809
|
+
*/
|
810
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
811
|
+
/**
|
812
|
+
* Hook that allows to mutate the CM's edit view layout
|
813
|
+
* @constant
|
814
|
+
* @type {string}
|
815
|
+
*/
|
816
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
817
|
+
/**
|
818
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
819
|
+
* @constant
|
820
|
+
* @type {string}
|
821
|
+
*/
|
822
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
823
|
+
};
|
824
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
825
|
+
endpoints: (builder) => ({
|
826
|
+
getContentTypeConfiguration: builder.query({
|
827
|
+
query: (uid) => ({
|
828
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
829
|
+
method: "GET"
|
830
|
+
}),
|
831
|
+
transformResponse: (response) => response.data,
|
832
|
+
providesTags: (_result, _error, uid) => [
|
833
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
834
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
835
|
+
]
|
836
|
+
}),
|
837
|
+
getAllContentTypeSettings: builder.query({
|
838
|
+
query: () => "/content-manager/content-types-settings",
|
839
|
+
transformResponse: (response) => response.data,
|
840
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
841
|
+
}),
|
842
|
+
updateContentTypeConfiguration: builder.mutation({
|
843
|
+
query: ({ uid, ...body }) => ({
|
844
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
845
|
+
method: "PUT",
|
846
|
+
data: body
|
847
|
+
}),
|
848
|
+
transformResponse: (response) => response.data,
|
849
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
850
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
851
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
852
|
+
// Is this necessary?
|
853
|
+
{ type: "InitialData" }
|
854
|
+
]
|
855
|
+
})
|
856
|
+
})
|
857
|
+
});
|
858
|
+
const {
|
859
|
+
useGetContentTypeConfigurationQuery,
|
860
|
+
useGetAllContentTypeSettingsQuery,
|
861
|
+
useUpdateContentTypeConfigurationMutation
|
862
|
+
} = contentTypesApi;
|
863
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
864
|
+
const { type } = attribute;
|
865
|
+
if (type === "relation") {
|
866
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
867
|
+
}
|
868
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
869
|
+
};
|
870
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
871
|
+
if (!mainFieldName) {
|
872
|
+
return void 0;
|
873
|
+
}
|
874
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
875
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
876
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
877
|
+
);
|
878
|
+
return {
|
879
|
+
name: mainFieldName,
|
880
|
+
type: mainFieldType ?? "string"
|
881
|
+
};
|
882
|
+
};
|
883
|
+
const DEFAULT_SETTINGS = {
|
884
|
+
bulkable: false,
|
885
|
+
filterable: false,
|
886
|
+
searchable: false,
|
887
|
+
pagination: false,
|
888
|
+
defaultSortBy: "",
|
889
|
+
defaultSortOrder: "asc",
|
890
|
+
mainField: "id",
|
891
|
+
pageSize: 10
|
892
|
+
};
|
893
|
+
const useDocumentLayout = (model) => {
|
894
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
895
|
+
const [{ query }] = useQueryParams();
|
896
|
+
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
763
897
|
const { toggleNotification } = useNotification();
|
764
898
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
899
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
765
900
|
const {
|
766
|
-
|
767
|
-
isLoading:
|
768
|
-
|
769
|
-
|
770
|
-
} =
|
771
|
-
|
772
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
773
|
-
});
|
774
|
-
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
901
|
+
data,
|
902
|
+
isLoading: isLoadingConfigs,
|
903
|
+
error,
|
904
|
+
isFetching: isFetchingConfigs
|
905
|
+
} = useGetContentTypeConfigurationQuery(model);
|
906
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
775
907
|
React.useEffect(() => {
|
776
908
|
if (error) {
|
777
909
|
toggleNotification({
|
@@ -779,362 +911,438 @@ const useDocument = (args, opts) => {
|
|
779
911
|
message: formatAPIError(error)
|
780
912
|
});
|
781
913
|
}
|
782
|
-
}, [
|
783
|
-
const
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
(document) => {
|
791
|
-
if (!validationSchema) {
|
792
|
-
throw new Error(
|
793
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
794
|
-
);
|
795
|
-
}
|
796
|
-
try {
|
797
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
798
|
-
return null;
|
799
|
-
} catch (error2) {
|
800
|
-
if (error2 instanceof ValidationError) {
|
801
|
-
return getYupValidationErrors(error2);
|
802
|
-
}
|
803
|
-
throw error2;
|
804
|
-
}
|
914
|
+
}, [error, formatAPIError, toggleNotification]);
|
915
|
+
const editLayout = React.useMemo(
|
916
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
917
|
+
layout: [],
|
918
|
+
components: {},
|
919
|
+
metadatas: {},
|
920
|
+
options: {},
|
921
|
+
settings: DEFAULT_SETTINGS
|
805
922
|
},
|
806
|
-
[
|
923
|
+
[data, isLoading, schemas, schema, components]
|
924
|
+
);
|
925
|
+
const listLayout = React.useMemo(() => {
|
926
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
927
|
+
layout: [],
|
928
|
+
metadatas: {},
|
929
|
+
options: {},
|
930
|
+
settings: DEFAULT_SETTINGS
|
931
|
+
};
|
932
|
+
}, [data, isLoading, schemas, schema, components]);
|
933
|
+
const { layout: edit } = React.useMemo(
|
934
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
935
|
+
layout: editLayout,
|
936
|
+
query
|
937
|
+
}),
|
938
|
+
[editLayout, query, runHookWaterfall]
|
807
939
|
);
|
808
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
809
940
|
return {
|
810
|
-
|
811
|
-
document: data?.data,
|
812
|
-
meta: data?.meta,
|
941
|
+
error,
|
813
942
|
isLoading,
|
814
|
-
|
815
|
-
|
816
|
-
};
|
817
|
-
};
|
818
|
-
const useDoc = () => {
|
819
|
-
const { id, slug, collectionType, origin } = useParams();
|
820
|
-
const [{ query }] = useQueryParams();
|
821
|
-
const params = React.useMemo(() => buildValidParams(query), [query]);
|
822
|
-
if (!collectionType) {
|
823
|
-
throw new Error("Could not find collectionType in url params");
|
824
|
-
}
|
825
|
-
if (!slug) {
|
826
|
-
throw new Error("Could not find model in url params");
|
827
|
-
}
|
828
|
-
return {
|
829
|
-
collectionType,
|
830
|
-
model: slug,
|
831
|
-
id: origin || id === "create" ? void 0 : id,
|
832
|
-
...useDocument(
|
833
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
834
|
-
{
|
835
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
836
|
-
}
|
837
|
-
)
|
943
|
+
edit,
|
944
|
+
list: listLayout
|
838
945
|
};
|
839
946
|
};
|
840
|
-
const
|
841
|
-
|
842
|
-
|
843
|
-
}
|
844
|
-
return Object.keys(trad).reduce((acc, current) => {
|
845
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
846
|
-
return acc;
|
847
|
-
}, {});
|
848
|
-
};
|
849
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
850
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
851
|
-
id: "notification.error",
|
852
|
-
defaultMessage: "An error occurred, please try again"
|
947
|
+
const useDocLayout = () => {
|
948
|
+
const { model } = useDoc();
|
949
|
+
return useDocumentLayout(model);
|
853
950
|
};
|
854
|
-
const
|
855
|
-
|
856
|
-
|
857
|
-
|
858
|
-
|
859
|
-
|
860
|
-
const
|
861
|
-
|
862
|
-
|
863
|
-
|
864
|
-
|
865
|
-
|
866
|
-
|
867
|
-
|
868
|
-
|
869
|
-
|
870
|
-
|
871
|
-
|
872
|
-
|
873
|
-
|
874
|
-
|
875
|
-
return { error: res.error };
|
876
|
-
}
|
877
|
-
toggleNotification({
|
878
|
-
type: "success",
|
879
|
-
message: formatMessage({
|
880
|
-
id: getTranslation("success.record.delete"),
|
881
|
-
defaultMessage: "Deleted document"
|
882
|
-
})
|
883
|
-
});
|
884
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
885
|
-
return res.data;
|
886
|
-
} catch (err) {
|
887
|
-
toggleNotification({
|
888
|
-
type: "danger",
|
889
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
890
|
-
});
|
891
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
892
|
-
throw err;
|
951
|
+
const formatEditLayout = (data, {
|
952
|
+
schemas,
|
953
|
+
schema,
|
954
|
+
components
|
955
|
+
}) => {
|
956
|
+
let currentPanelIndex = 0;
|
957
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
958
|
+
data.contentType.layouts.edit,
|
959
|
+
schema?.attributes,
|
960
|
+
data.contentType.metadatas,
|
961
|
+
{ configurations: data.components, schemas: components },
|
962
|
+
schemas
|
963
|
+
).reduce((panels, row) => {
|
964
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
965
|
+
panels.push([row]);
|
966
|
+
currentPanelIndex += 2;
|
967
|
+
} else {
|
968
|
+
if (!panels[currentPanelIndex]) {
|
969
|
+
panels.push([row]);
|
970
|
+
} else {
|
971
|
+
panels[currentPanelIndex].push(row);
|
893
972
|
}
|
894
|
-
}
|
895
|
-
|
896
|
-
);
|
897
|
-
const
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
|
909
|
-
|
910
|
-
message: formatAPIError(res.error)
|
911
|
-
});
|
912
|
-
return { error: res.error };
|
973
|
+
}
|
974
|
+
return panels;
|
975
|
+
}, []);
|
976
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
977
|
+
(acc, [uid, configuration]) => {
|
978
|
+
acc[uid] = {
|
979
|
+
layout: convertEditLayoutToFieldLayouts(
|
980
|
+
configuration.layouts.edit,
|
981
|
+
components[uid].attributes,
|
982
|
+
configuration.metadatas,
|
983
|
+
{ configurations: data.components, schemas: components }
|
984
|
+
),
|
985
|
+
settings: {
|
986
|
+
...configuration.settings,
|
987
|
+
icon: components[uid].info.icon,
|
988
|
+
displayName: components[uid].info.displayName
|
913
989
|
}
|
914
|
-
|
915
|
-
|
916
|
-
title: formatMessage({
|
917
|
-
id: getTranslation("success.records.delete"),
|
918
|
-
defaultMessage: "Successfully deleted."
|
919
|
-
}),
|
920
|
-
message: ""
|
921
|
-
});
|
922
|
-
trackUsage("didBulkDeleteEntries");
|
923
|
-
return res.data;
|
924
|
-
} catch (err) {
|
925
|
-
toggleNotification({
|
926
|
-
type: "danger",
|
927
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
928
|
-
});
|
929
|
-
trackUsage("didNotBulkDeleteEntries");
|
930
|
-
throw err;
|
931
|
-
}
|
990
|
+
};
|
991
|
+
return acc;
|
932
992
|
},
|
933
|
-
|
993
|
+
{}
|
934
994
|
);
|
935
|
-
const
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
model,
|
942
|
-
documentId,
|
943
|
-
params
|
944
|
-
});
|
945
|
-
if ("error" in res) {
|
946
|
-
toggleNotification({
|
947
|
-
type: "danger",
|
948
|
-
message: formatAPIError(res.error)
|
949
|
-
});
|
950
|
-
return { error: res.error };
|
951
|
-
}
|
952
|
-
toggleNotification({
|
953
|
-
type: "success",
|
954
|
-
message: formatMessage({
|
955
|
-
id: "content-manager.success.record.discard",
|
956
|
-
defaultMessage: "Changes discarded"
|
957
|
-
})
|
958
|
-
});
|
959
|
-
return res.data;
|
960
|
-
} catch (err) {
|
961
|
-
toggleNotification({
|
962
|
-
type: "danger",
|
963
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
964
|
-
});
|
965
|
-
throw err;
|
966
|
-
}
|
995
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
996
|
+
(acc, [attribute, metadata]) => {
|
997
|
+
return {
|
998
|
+
...acc,
|
999
|
+
[attribute]: metadata.edit
|
1000
|
+
};
|
967
1001
|
},
|
968
|
-
|
1002
|
+
{}
|
969
1003
|
);
|
970
|
-
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
|
977
|
-
model,
|
978
|
-
documentId,
|
979
|
-
data,
|
980
|
-
params
|
981
|
-
});
|
982
|
-
if ("error" in res) {
|
983
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
984
|
-
return { error: res.error };
|
985
|
-
}
|
986
|
-
trackUsage("didPublishEntry");
|
987
|
-
toggleNotification({
|
988
|
-
type: "success",
|
989
|
-
message: formatMessage({
|
990
|
-
id: getTranslation("success.record.publish"),
|
991
|
-
defaultMessage: "Published document"
|
992
|
-
})
|
993
|
-
});
|
994
|
-
return res.data;
|
995
|
-
} catch (err) {
|
996
|
-
toggleNotification({
|
997
|
-
type: "danger",
|
998
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
999
|
-
});
|
1000
|
-
throw err;
|
1001
|
-
}
|
1004
|
+
return {
|
1005
|
+
layout: panelledEditAttributes,
|
1006
|
+
components: componentEditAttributes,
|
1007
|
+
metadatas: editMetadatas,
|
1008
|
+
settings: {
|
1009
|
+
...data.contentType.settings,
|
1010
|
+
displayName: schema?.info.displayName
|
1002
1011
|
},
|
1003
|
-
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
return { error: res.error };
|
1017
|
-
}
|
1018
|
-
toggleNotification({
|
1019
|
-
type: "success",
|
1020
|
-
message: formatMessage({
|
1021
|
-
id: getTranslation("success.record.publish"),
|
1022
|
-
defaultMessage: "Published document"
|
1023
|
-
})
|
1024
|
-
});
|
1025
|
-
return res.data;
|
1026
|
-
} catch (err) {
|
1027
|
-
toggleNotification({
|
1028
|
-
type: "danger",
|
1029
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1030
|
-
});
|
1031
|
-
throw err;
|
1012
|
+
options: {
|
1013
|
+
...schema?.options,
|
1014
|
+
...schema?.pluginOptions,
|
1015
|
+
...data.contentType.options
|
1016
|
+
}
|
1017
|
+
};
|
1018
|
+
};
|
1019
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1020
|
+
return rows.map(
|
1021
|
+
(row) => row.map((field) => {
|
1022
|
+
const attribute = attributes[field.name];
|
1023
|
+
if (!attribute) {
|
1024
|
+
return null;
|
1032
1025
|
}
|
1033
|
-
|
1034
|
-
|
1035
|
-
|
1036
|
-
|
1037
|
-
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1026
|
+
const { edit: metadata } = metadatas[field.name];
|
1027
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1028
|
+
return {
|
1029
|
+
attribute,
|
1030
|
+
disabled: !metadata.editable,
|
1031
|
+
hint: metadata.description,
|
1032
|
+
label: metadata.label ?? "",
|
1033
|
+
name: field.name,
|
1034
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1035
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1036
|
+
schemas,
|
1037
|
+
components: components?.schemas ?? {}
|
1038
|
+
}),
|
1039
|
+
placeholder: metadata.placeholder ?? "",
|
1040
|
+
required: attribute.required ?? false,
|
1041
|
+
size: field.size,
|
1042
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1043
|
+
visible: metadata.visible ?? true,
|
1044
|
+
type: attribute.type
|
1045
|
+
};
|
1046
|
+
}).filter((field) => field !== null)
|
1041
1047
|
);
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1048
|
+
};
|
1049
|
+
const formatListLayout = (data, {
|
1050
|
+
schemas,
|
1051
|
+
schema,
|
1052
|
+
components
|
1053
|
+
}) => {
|
1054
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1055
|
+
(acc, [attribute, metadata]) => {
|
1056
|
+
return {
|
1057
|
+
...acc,
|
1058
|
+
[attribute]: metadata.list
|
1059
|
+
};
|
1060
|
+
},
|
1061
|
+
{}
|
1062
|
+
);
|
1063
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1064
|
+
data.contentType.layouts.list,
|
1065
|
+
schema?.attributes,
|
1066
|
+
listMetadatas,
|
1067
|
+
{ configurations: data.components, schemas: components },
|
1068
|
+
schemas
|
1069
|
+
);
|
1070
|
+
return {
|
1071
|
+
layout: listAttributes,
|
1072
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1073
|
+
metadatas: listMetadatas,
|
1074
|
+
options: {
|
1075
|
+
...schema?.options,
|
1076
|
+
...schema?.pluginOptions,
|
1077
|
+
...data.contentType.options
|
1078
|
+
}
|
1079
|
+
};
|
1080
|
+
};
|
1081
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1082
|
+
return columns.map((name) => {
|
1083
|
+
const attribute = attributes[name];
|
1084
|
+
if (!attribute) {
|
1085
|
+
return null;
|
1086
|
+
}
|
1087
|
+
const metadata = metadatas[name];
|
1088
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1089
|
+
return {
|
1090
|
+
attribute,
|
1091
|
+
label: metadata.label ?? "",
|
1092
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1093
|
+
schemas,
|
1094
|
+
components: components?.schemas ?? {}
|
1095
|
+
}),
|
1096
|
+
name,
|
1097
|
+
searchable: metadata.searchable ?? true,
|
1098
|
+
sortable: metadata.sortable ?? true
|
1099
|
+
};
|
1100
|
+
}).filter((field) => field !== null);
|
1101
|
+
};
|
1102
|
+
const useDocument = (args, opts) => {
|
1103
|
+
const { toggleNotification } = useNotification();
|
1104
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1105
|
+
const {
|
1106
|
+
currentData: data,
|
1107
|
+
isLoading: isLoadingDocument,
|
1108
|
+
isFetching: isFetchingDocument,
|
1109
|
+
error
|
1110
|
+
} = useGetDocumentQuery(args, {
|
1111
|
+
...opts,
|
1112
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1113
|
+
});
|
1114
|
+
const {
|
1115
|
+
components,
|
1116
|
+
schema,
|
1117
|
+
schemas,
|
1118
|
+
isLoading: isLoadingSchema
|
1119
|
+
} = useContentTypeSchema(args.model);
|
1120
|
+
React.useEffect(() => {
|
1121
|
+
if (error) {
|
1122
|
+
toggleNotification({
|
1123
|
+
type: "danger",
|
1124
|
+
message: formatAPIError(error)
|
1125
|
+
});
|
1126
|
+
}
|
1127
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1128
|
+
const validationSchema = React.useMemo(() => {
|
1129
|
+
if (!schema) {
|
1130
|
+
return null;
|
1131
|
+
}
|
1132
|
+
return createYupSchema(schema.attributes, components);
|
1133
|
+
}, [schema, components]);
|
1134
|
+
const validate = React.useCallback(
|
1135
|
+
(document) => {
|
1136
|
+
if (!validationSchema) {
|
1137
|
+
throw new Error(
|
1138
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1139
|
+
);
|
1140
|
+
}
|
1045
1141
|
try {
|
1046
|
-
|
1047
|
-
|
1142
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1143
|
+
return null;
|
1144
|
+
} catch (error2) {
|
1145
|
+
if (error2 instanceof ValidationError) {
|
1146
|
+
return getYupValidationErrors(error2);
|
1147
|
+
}
|
1148
|
+
throw error2;
|
1149
|
+
}
|
1150
|
+
},
|
1151
|
+
[validationSchema]
|
1152
|
+
);
|
1153
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1154
|
+
const hasError = !!error;
|
1155
|
+
return {
|
1156
|
+
components,
|
1157
|
+
document: data?.data,
|
1158
|
+
meta: data?.meta,
|
1159
|
+
isLoading,
|
1160
|
+
hasError,
|
1161
|
+
schema,
|
1162
|
+
schemas,
|
1163
|
+
validate
|
1164
|
+
};
|
1165
|
+
};
|
1166
|
+
const useDoc = () => {
|
1167
|
+
const { id, slug, collectionType, origin } = useParams();
|
1168
|
+
const [{ query }] = useQueryParams();
|
1169
|
+
const params = React.useMemo(() => buildValidParams(query), [query]);
|
1170
|
+
if (!collectionType) {
|
1171
|
+
throw new Error("Could not find collectionType in url params");
|
1172
|
+
}
|
1173
|
+
if (!slug) {
|
1174
|
+
throw new Error("Could not find model in url params");
|
1175
|
+
}
|
1176
|
+
const document = useDocument(
|
1177
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1178
|
+
{
|
1179
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1180
|
+
}
|
1181
|
+
);
|
1182
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
1183
|
+
return {
|
1184
|
+
collectionType,
|
1185
|
+
model: slug,
|
1186
|
+
id: returnId,
|
1187
|
+
...document
|
1188
|
+
};
|
1189
|
+
};
|
1190
|
+
const useContentManagerContext = () => {
|
1191
|
+
const {
|
1192
|
+
collectionType,
|
1193
|
+
model,
|
1194
|
+
id,
|
1195
|
+
components,
|
1196
|
+
isLoading: isLoadingDoc,
|
1197
|
+
schema,
|
1198
|
+
schemas
|
1199
|
+
} = useDoc();
|
1200
|
+
const layout = useDocumentLayout(model);
|
1201
|
+
const form = useForm("useContentManagerContext", (state) => state);
|
1202
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1203
|
+
const slug = model;
|
1204
|
+
const isCreatingEntry = id === "create";
|
1205
|
+
useContentTypeSchema();
|
1206
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1207
|
+
const error = layout.error;
|
1208
|
+
return {
|
1209
|
+
error,
|
1210
|
+
isLoading,
|
1211
|
+
// Base metadata
|
1212
|
+
model,
|
1213
|
+
collectionType,
|
1214
|
+
id,
|
1215
|
+
slug,
|
1216
|
+
isCreatingEntry,
|
1217
|
+
isSingleType,
|
1218
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1219
|
+
// All schema infos
|
1220
|
+
components,
|
1221
|
+
contentType: schema,
|
1222
|
+
contentTypes: schemas,
|
1223
|
+
// Form state
|
1224
|
+
form,
|
1225
|
+
// layout infos
|
1226
|
+
layout
|
1227
|
+
};
|
1228
|
+
};
|
1229
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
1230
|
+
return Object.keys(trad).reduce((acc, current) => {
|
1231
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1232
|
+
return acc;
|
1233
|
+
}, {});
|
1234
|
+
};
|
1235
|
+
const getTranslation = (id) => `content-manager.${id}`;
|
1236
|
+
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
1237
|
+
id: "notification.error",
|
1238
|
+
defaultMessage: "An error occurred, please try again"
|
1239
|
+
};
|
1240
|
+
const useDocumentActions = () => {
|
1241
|
+
const { toggleNotification } = useNotification();
|
1242
|
+
const { formatMessage } = useIntl();
|
1243
|
+
const { trackUsage } = useTracking();
|
1244
|
+
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
1245
|
+
const navigate = useNavigate();
|
1246
|
+
const setCurrentStep = useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
1247
|
+
const [deleteDocument] = useDeleteDocumentMutation();
|
1248
|
+
const _delete = React.useCallback(
|
1249
|
+
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
1250
|
+
try {
|
1251
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1252
|
+
const res = await deleteDocument({
|
1048
1253
|
collectionType,
|
1049
1254
|
model,
|
1050
1255
|
documentId,
|
1051
|
-
data,
|
1052
1256
|
params
|
1053
1257
|
});
|
1054
1258
|
if ("error" in res) {
|
1055
|
-
toggleNotification({
|
1056
|
-
|
1259
|
+
toggleNotification({
|
1260
|
+
type: "danger",
|
1261
|
+
message: formatAPIError(res.error)
|
1262
|
+
});
|
1057
1263
|
return { error: res.error };
|
1058
1264
|
}
|
1059
|
-
trackUsage("didEditEntry", trackerProperty);
|
1060
1265
|
toggleNotification({
|
1061
1266
|
type: "success",
|
1062
1267
|
message: formatMessage({
|
1063
|
-
id: getTranslation("success.record.
|
1064
|
-
defaultMessage: "
|
1268
|
+
id: getTranslation("success.record.delete"),
|
1269
|
+
defaultMessage: "Deleted document"
|
1065
1270
|
})
|
1066
1271
|
});
|
1272
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1067
1273
|
return res.data;
|
1068
1274
|
} catch (err) {
|
1069
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1070
1275
|
toggleNotification({
|
1071
1276
|
type: "danger",
|
1072
1277
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1073
1278
|
});
|
1279
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1074
1280
|
throw err;
|
1075
1281
|
}
|
1076
1282
|
},
|
1077
|
-
[trackUsage,
|
1283
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1078
1284
|
);
|
1079
|
-
const [
|
1080
|
-
const
|
1081
|
-
async ({
|
1285
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1286
|
+
const deleteMany = React.useCallback(
|
1287
|
+
async ({ model, documentIds, params }) => {
|
1082
1288
|
try {
|
1083
|
-
trackUsage("
|
1084
|
-
const res = await
|
1085
|
-
collectionType,
|
1289
|
+
trackUsage("willBulkDeleteEntries");
|
1290
|
+
const res = await deleteManyDocuments({
|
1086
1291
|
model,
|
1087
|
-
|
1088
|
-
params
|
1089
|
-
data: {
|
1090
|
-
discardDraft
|
1091
|
-
}
|
1292
|
+
documentIds,
|
1293
|
+
params
|
1092
1294
|
});
|
1093
1295
|
if ("error" in res) {
|
1094
|
-
toggleNotification({
|
1296
|
+
toggleNotification({
|
1297
|
+
type: "danger",
|
1298
|
+
message: formatAPIError(res.error)
|
1299
|
+
});
|
1095
1300
|
return { error: res.error };
|
1096
1301
|
}
|
1097
|
-
trackUsage("didUnpublishEntry");
|
1098
1302
|
toggleNotification({
|
1099
1303
|
type: "success",
|
1100
|
-
|
1101
|
-
id: getTranslation("success.
|
1102
|
-
defaultMessage: "
|
1103
|
-
})
|
1304
|
+
title: formatMessage({
|
1305
|
+
id: getTranslation("success.records.delete"),
|
1306
|
+
defaultMessage: "Successfully deleted."
|
1307
|
+
}),
|
1308
|
+
message: ""
|
1104
1309
|
});
|
1310
|
+
trackUsage("didBulkDeleteEntries");
|
1105
1311
|
return res.data;
|
1106
1312
|
} catch (err) {
|
1107
1313
|
toggleNotification({
|
1108
1314
|
type: "danger",
|
1109
1315
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1110
1316
|
});
|
1317
|
+
trackUsage("didNotBulkDeleteEntries");
|
1111
1318
|
throw err;
|
1112
1319
|
}
|
1113
1320
|
},
|
1114
|
-
[trackUsage,
|
1321
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1115
1322
|
);
|
1116
|
-
const [
|
1117
|
-
const
|
1118
|
-
async ({ model,
|
1323
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1324
|
+
const discard = React.useCallback(
|
1325
|
+
async ({ collectionType, model, documentId, params }) => {
|
1119
1326
|
try {
|
1120
|
-
|
1121
|
-
|
1327
|
+
const res = await discardDocument({
|
1328
|
+
collectionType,
|
1122
1329
|
model,
|
1123
|
-
|
1330
|
+
documentId,
|
1124
1331
|
params
|
1125
1332
|
});
|
1126
1333
|
if ("error" in res) {
|
1127
|
-
toggleNotification({
|
1334
|
+
toggleNotification({
|
1335
|
+
type: "danger",
|
1336
|
+
message: formatAPIError(res.error)
|
1337
|
+
});
|
1128
1338
|
return { error: res.error };
|
1129
1339
|
}
|
1130
|
-
trackUsage("didBulkUnpublishEntries");
|
1131
1340
|
toggleNotification({
|
1132
1341
|
type: "success",
|
1133
|
-
|
1134
|
-
id:
|
1135
|
-
defaultMessage: "
|
1136
|
-
})
|
1137
|
-
message: ""
|
1342
|
+
message: formatMessage({
|
1343
|
+
id: "content-manager.success.record.discard",
|
1344
|
+
defaultMessage: "Changes discarded"
|
1345
|
+
})
|
1138
1346
|
});
|
1139
1347
|
return res.data;
|
1140
1348
|
} catch (err) {
|
@@ -1142,14 +1350,194 @@ const useDocumentActions = () => {
|
|
1142
1350
|
type: "danger",
|
1143
1351
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1144
1352
|
});
|
1145
|
-
trackUsage("didNotBulkUnpublishEntries");
|
1146
1353
|
throw err;
|
1147
1354
|
}
|
1148
1355
|
},
|
1149
|
-
[
|
1356
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1150
1357
|
);
|
1151
|
-
const [
|
1152
|
-
const
|
1358
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1359
|
+
const publish = React.useCallback(
|
1360
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1361
|
+
try {
|
1362
|
+
trackUsage("willPublishEntry");
|
1363
|
+
const res = await publishDocument({
|
1364
|
+
collectionType,
|
1365
|
+
model,
|
1366
|
+
documentId,
|
1367
|
+
data,
|
1368
|
+
params
|
1369
|
+
});
|
1370
|
+
if ("error" in res) {
|
1371
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1372
|
+
return { error: res.error };
|
1373
|
+
}
|
1374
|
+
trackUsage("didPublishEntry");
|
1375
|
+
toggleNotification({
|
1376
|
+
type: "success",
|
1377
|
+
message: formatMessage({
|
1378
|
+
id: getTranslation("success.record.publish"),
|
1379
|
+
defaultMessage: "Published document"
|
1380
|
+
})
|
1381
|
+
});
|
1382
|
+
return res.data;
|
1383
|
+
} catch (err) {
|
1384
|
+
toggleNotification({
|
1385
|
+
type: "danger",
|
1386
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1387
|
+
});
|
1388
|
+
throw err;
|
1389
|
+
}
|
1390
|
+
},
|
1391
|
+
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1392
|
+
);
|
1393
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1394
|
+
const publishMany = React.useCallback(
|
1395
|
+
async ({ model, documentIds, params }) => {
|
1396
|
+
try {
|
1397
|
+
const res = await publishManyDocuments({
|
1398
|
+
model,
|
1399
|
+
documentIds,
|
1400
|
+
params
|
1401
|
+
});
|
1402
|
+
if ("error" in res) {
|
1403
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1404
|
+
return { error: res.error };
|
1405
|
+
}
|
1406
|
+
toggleNotification({
|
1407
|
+
type: "success",
|
1408
|
+
message: formatMessage({
|
1409
|
+
id: getTranslation("success.record.publish"),
|
1410
|
+
defaultMessage: "Published document"
|
1411
|
+
})
|
1412
|
+
});
|
1413
|
+
return res.data;
|
1414
|
+
} catch (err) {
|
1415
|
+
toggleNotification({
|
1416
|
+
type: "danger",
|
1417
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1418
|
+
});
|
1419
|
+
throw err;
|
1420
|
+
}
|
1421
|
+
},
|
1422
|
+
[
|
1423
|
+
// trackUsage,
|
1424
|
+
publishManyDocuments,
|
1425
|
+
toggleNotification,
|
1426
|
+
formatMessage,
|
1427
|
+
formatAPIError
|
1428
|
+
]
|
1429
|
+
);
|
1430
|
+
const [updateDocument] = useUpdateDocumentMutation();
|
1431
|
+
const update = React.useCallback(
|
1432
|
+
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
1433
|
+
try {
|
1434
|
+
trackUsage("willEditEntry", trackerProperty);
|
1435
|
+
const res = await updateDocument({
|
1436
|
+
collectionType,
|
1437
|
+
model,
|
1438
|
+
documentId,
|
1439
|
+
data,
|
1440
|
+
params
|
1441
|
+
});
|
1442
|
+
if ("error" in res) {
|
1443
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1444
|
+
trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
|
1445
|
+
return { error: res.error };
|
1446
|
+
}
|
1447
|
+
trackUsage("didEditEntry", trackerProperty);
|
1448
|
+
toggleNotification({
|
1449
|
+
type: "success",
|
1450
|
+
message: formatMessage({
|
1451
|
+
id: getTranslation("success.record.save"),
|
1452
|
+
defaultMessage: "Saved document"
|
1453
|
+
})
|
1454
|
+
});
|
1455
|
+
return res.data;
|
1456
|
+
} catch (err) {
|
1457
|
+
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1458
|
+
toggleNotification({
|
1459
|
+
type: "danger",
|
1460
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1461
|
+
});
|
1462
|
+
throw err;
|
1463
|
+
}
|
1464
|
+
},
|
1465
|
+
[trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
|
1466
|
+
);
|
1467
|
+
const [unpublishDocument] = useUnpublishDocumentMutation();
|
1468
|
+
const unpublish = React.useCallback(
|
1469
|
+
async ({ collectionType, model, documentId, params }, discardDraft = false) => {
|
1470
|
+
try {
|
1471
|
+
trackUsage("willUnpublishEntry");
|
1472
|
+
const res = await unpublishDocument({
|
1473
|
+
collectionType,
|
1474
|
+
model,
|
1475
|
+
documentId,
|
1476
|
+
params,
|
1477
|
+
data: {
|
1478
|
+
discardDraft
|
1479
|
+
}
|
1480
|
+
});
|
1481
|
+
if ("error" in res) {
|
1482
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1483
|
+
return { error: res.error };
|
1484
|
+
}
|
1485
|
+
trackUsage("didUnpublishEntry");
|
1486
|
+
toggleNotification({
|
1487
|
+
type: "success",
|
1488
|
+
message: formatMessage({
|
1489
|
+
id: getTranslation("success.record.unpublish"),
|
1490
|
+
defaultMessage: "Unpublished document"
|
1491
|
+
})
|
1492
|
+
});
|
1493
|
+
return res.data;
|
1494
|
+
} catch (err) {
|
1495
|
+
toggleNotification({
|
1496
|
+
type: "danger",
|
1497
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1498
|
+
});
|
1499
|
+
throw err;
|
1500
|
+
}
|
1501
|
+
},
|
1502
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1503
|
+
);
|
1504
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1505
|
+
const unpublishMany = React.useCallback(
|
1506
|
+
async ({ model, documentIds, params }) => {
|
1507
|
+
try {
|
1508
|
+
trackUsage("willBulkUnpublishEntries");
|
1509
|
+
const res = await unpublishManyDocuments({
|
1510
|
+
model,
|
1511
|
+
documentIds,
|
1512
|
+
params
|
1513
|
+
});
|
1514
|
+
if ("error" in res) {
|
1515
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1516
|
+
return { error: res.error };
|
1517
|
+
}
|
1518
|
+
trackUsage("didBulkUnpublishEntries");
|
1519
|
+
toggleNotification({
|
1520
|
+
type: "success",
|
1521
|
+
title: formatMessage({
|
1522
|
+
id: getTranslation("success.records.unpublish"),
|
1523
|
+
defaultMessage: "Successfully unpublished."
|
1524
|
+
}),
|
1525
|
+
message: ""
|
1526
|
+
});
|
1527
|
+
return res.data;
|
1528
|
+
} catch (err) {
|
1529
|
+
toggleNotification({
|
1530
|
+
type: "danger",
|
1531
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1532
|
+
});
|
1533
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1534
|
+
throw err;
|
1535
|
+
}
|
1536
|
+
},
|
1537
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1538
|
+
);
|
1539
|
+
const [createDocument] = useCreateDocumentMutation();
|
1540
|
+
const create = React.useCallback(
|
1153
1541
|
async ({ model, params }, data, trackerProperty) => {
|
1154
1542
|
try {
|
1155
1543
|
const res = await createDocument({
|
@@ -1170,6 +1558,7 @@ const useDocumentActions = () => {
|
|
1170
1558
|
defaultMessage: "Saved document"
|
1171
1559
|
})
|
1172
1560
|
});
|
1561
|
+
setCurrentStep("contentManager.success");
|
1173
1562
|
return res.data;
|
1174
1563
|
} catch (err) {
|
1175
1564
|
toggleNotification({
|
@@ -1209,7 +1598,7 @@ const useDocumentActions = () => {
|
|
1209
1598
|
throw err;
|
1210
1599
|
}
|
1211
1600
|
},
|
1212
|
-
[autoCloneDocument,
|
1601
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1213
1602
|
);
|
1214
1603
|
const [cloneDocument] = useCloneDocumentMutation();
|
1215
1604
|
const clone = React.useCallback(
|
@@ -1235,6 +1624,7 @@ const useDocumentActions = () => {
|
|
1235
1624
|
defaultMessage: "Cloned document"
|
1236
1625
|
})
|
1237
1626
|
});
|
1627
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1238
1628
|
return res.data;
|
1239
1629
|
} catch (err) {
|
1240
1630
|
toggleNotification({
|
@@ -1245,7 +1635,7 @@ const useDocumentActions = () => {
|
|
1245
1635
|
throw err;
|
1246
1636
|
}
|
1247
1637
|
},
|
1248
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1638
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1249
1639
|
);
|
1250
1640
|
const [getDoc] = useLazyGetDocumentQuery();
|
1251
1641
|
const getDocument = React.useCallback(
|
@@ -1270,10 +1660,10 @@ const useDocumentActions = () => {
|
|
1270
1660
|
update
|
1271
1661
|
};
|
1272
1662
|
};
|
1273
|
-
const ProtectedHistoryPage = lazy(
|
1274
|
-
() => import("./History-
|
1663
|
+
const ProtectedHistoryPage = React.lazy(
|
1664
|
+
() => import("./History-N_kRb1Yr.mjs").then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1275
1665
|
);
|
1276
|
-
const routes$
|
1666
|
+
const routes$2 = [
|
1277
1667
|
{
|
1278
1668
|
path: ":collectionType/:slug/:id/history",
|
1279
1669
|
Component: ProtectedHistoryPage
|
@@ -1283,32 +1673,45 @@ const routes$1 = [
|
|
1283
1673
|
Component: ProtectedHistoryPage
|
1284
1674
|
}
|
1285
1675
|
];
|
1676
|
+
const ProtectedPreviewPage = React.lazy(
|
1677
|
+
() => import("./Preview-kPkuZbBJ.mjs").then((mod) => ({ default: mod.ProtectedPreviewPage }))
|
1678
|
+
);
|
1679
|
+
const routes$1 = [
|
1680
|
+
{
|
1681
|
+
path: ":collectionType/:slug/:id/preview",
|
1682
|
+
Component: ProtectedPreviewPage
|
1683
|
+
},
|
1684
|
+
{
|
1685
|
+
path: ":collectionType/:slug/preview",
|
1686
|
+
Component: ProtectedPreviewPage
|
1687
|
+
}
|
1688
|
+
];
|
1286
1689
|
const ProtectedEditViewPage = lazy(
|
1287
|
-
() => import("./EditViewPage-
|
1690
|
+
() => import("./EditViewPage-BKoISUOu.mjs").then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1288
1691
|
);
|
1289
1692
|
const ProtectedListViewPage = lazy(
|
1290
|
-
() => import("./ListViewPage-
|
1693
|
+
() => import("./ListViewPage-CWilGbZb.mjs").then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1291
1694
|
);
|
1292
1695
|
const ProtectedListConfiguration = lazy(
|
1293
|
-
() => import("./ListConfigurationPage-
|
1696
|
+
() => import("./ListConfigurationPage-BM3qVxug.mjs").then((mod) => ({
|
1294
1697
|
default: mod.ProtectedListConfiguration
|
1295
1698
|
}))
|
1296
1699
|
);
|
1297
1700
|
const ProtectedEditConfigurationPage = lazy(
|
1298
|
-
() => import("./EditConfigurationPage-
|
1701
|
+
() => import("./EditConfigurationPage-5tmx_7Hp.mjs").then((mod) => ({
|
1299
1702
|
default: mod.ProtectedEditConfigurationPage
|
1300
1703
|
}))
|
1301
1704
|
);
|
1302
1705
|
const ProtectedComponentConfigurationPage = lazy(
|
1303
|
-
() => import("./ComponentConfigurationPage-
|
1706
|
+
() => import("./ComponentConfigurationPage-DhWA-JzT.mjs").then((mod) => ({
|
1304
1707
|
default: mod.ProtectedComponentConfigurationPage
|
1305
1708
|
}))
|
1306
1709
|
);
|
1307
1710
|
const NoPermissions = lazy(
|
1308
|
-
() => import("./NoPermissionsPage-
|
1711
|
+
() => import("./NoPermissionsPage-CS2tCmfr.mjs").then((mod) => ({ default: mod.NoPermissions }))
|
1309
1712
|
);
|
1310
1713
|
const NoContentType = lazy(
|
1311
|
-
() => import("./NoContentTypePage-
|
1714
|
+
() => import("./NoContentTypePage-VWYlePwI.mjs").then((mod) => ({ default: mod.NoContentType }))
|
1312
1715
|
);
|
1313
1716
|
const CollectionTypePages = () => {
|
1314
1717
|
const { collectionType } = useParams();
|
@@ -1320,7 +1723,7 @@ const CollectionTypePages = () => {
|
|
1320
1723
|
const CLONE_RELATIVE_PATH = ":collectionType/:slug/clone/:origin";
|
1321
1724
|
const CLONE_PATH = `/content-manager/${CLONE_RELATIVE_PATH}`;
|
1322
1725
|
const LIST_RELATIVE_PATH = ":collectionType/:slug";
|
1323
|
-
const LIST_PATH = `/content-manager
|
1726
|
+
const LIST_PATH = `/content-manager/collection-types/:slug`;
|
1324
1727
|
const routes = [
|
1325
1728
|
{
|
1326
1729
|
path: LIST_RELATIVE_PATH,
|
@@ -1354,6 +1757,7 @@ const routes = [
|
|
1354
1757
|
path: "no-content-types",
|
1355
1758
|
Component: NoContentType
|
1356
1759
|
},
|
1760
|
+
...routes$2,
|
1357
1761
|
...routes$1
|
1358
1762
|
];
|
1359
1763
|
const DocumentActions = ({ actions: actions2 }) => {
|
@@ -1422,12 +1826,14 @@ const DocumentActionButton = (action) => {
|
|
1422
1826
|
/* @__PURE__ */ jsx(
|
1423
1827
|
Button,
|
1424
1828
|
{
|
1425
|
-
flex:
|
1829
|
+
flex: "auto",
|
1426
1830
|
startIcon: action.icon,
|
1427
1831
|
disabled: action.disabled,
|
1428
1832
|
onClick: handleClick(action),
|
1429
1833
|
justifyContent: "center",
|
1430
1834
|
variant: action.variant || "default",
|
1835
|
+
paddingTop: "7px",
|
1836
|
+
paddingBottom: "7px",
|
1431
1837
|
children: action.label
|
1432
1838
|
}
|
1433
1839
|
),
|
@@ -1450,6 +1856,11 @@ const DocumentActionButton = (action) => {
|
|
1450
1856
|
) : null
|
1451
1857
|
] });
|
1452
1858
|
};
|
1859
|
+
const MenuItem = styled(Menu.Item)`
|
1860
|
+
&:hover {
|
1861
|
+
background: ${({ theme, isVariantDanger, isDisabled }) => isVariantDanger && !isDisabled ? theme.colors.danger100 : "neutral"};
|
1862
|
+
}
|
1863
|
+
`;
|
1453
1864
|
const DocumentActionsMenu = ({
|
1454
1865
|
actions: actions2,
|
1455
1866
|
children,
|
@@ -1492,9 +1903,9 @@ const DocumentActionsMenu = ({
|
|
1492
1903
|
disabled: isDisabled,
|
1493
1904
|
size: "S",
|
1494
1905
|
endIcon: null,
|
1495
|
-
paddingTop: "
|
1496
|
-
paddingLeft: "
|
1497
|
-
paddingRight: "
|
1906
|
+
paddingTop: "4px",
|
1907
|
+
paddingLeft: "7px",
|
1908
|
+
paddingRight: "7px",
|
1498
1909
|
variant,
|
1499
1910
|
children: [
|
1500
1911
|
/* @__PURE__ */ jsx(More, { "aria-hidden": true, focusable: false }),
|
@@ -1505,36 +1916,35 @@ const DocumentActionsMenu = ({
|
|
1505
1916
|
]
|
1506
1917
|
}
|
1507
1918
|
),
|
1508
|
-
/* @__PURE__ */ jsxs(Menu.Content, {
|
1919
|
+
/* @__PURE__ */ jsxs(Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1509
1920
|
actions2.map((action) => {
|
1510
1921
|
return /* @__PURE__ */ jsx(
|
1511
|
-
|
1922
|
+
MenuItem,
|
1512
1923
|
{
|
1513
1924
|
disabled: action.disabled,
|
1514
1925
|
onSelect: handleClick(action),
|
1515
1926
|
display: "block",
|
1516
|
-
|
1517
|
-
|
1518
|
-
|
1519
|
-
|
1520
|
-
|
1521
|
-
|
1522
|
-
|
1523
|
-
|
1524
|
-
|
1525
|
-
|
1526
|
-
|
1527
|
-
|
1528
|
-
|
1529
|
-
|
1530
|
-
|
1531
|
-
|
1532
|
-
|
1533
|
-
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1537
|
-
] })
|
1927
|
+
isVariantDanger: action.variant === "danger",
|
1928
|
+
isDisabled: action.disabled,
|
1929
|
+
children: /* @__PURE__ */ jsx(Flex, { justifyContent: "space-between", gap: 4, children: /* @__PURE__ */ jsxs(
|
1930
|
+
Flex,
|
1931
|
+
{
|
1932
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1933
|
+
gap: 2,
|
1934
|
+
tag: "span",
|
1935
|
+
children: [
|
1936
|
+
/* @__PURE__ */ jsx(
|
1937
|
+
Flex,
|
1938
|
+
{
|
1939
|
+
tag: "span",
|
1940
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1941
|
+
children: action.icon
|
1942
|
+
}
|
1943
|
+
),
|
1944
|
+
action.label
|
1945
|
+
]
|
1946
|
+
}
|
1947
|
+
) })
|
1538
1948
|
},
|
1539
1949
|
action.id
|
1540
1950
|
);
|
@@ -1614,11 +2024,11 @@ const DocumentActionConfirmDialog = ({
|
|
1614
2024
|
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
1615
2025
|
/* @__PURE__ */ jsx(Dialog.Body, { children: content }),
|
1616
2026
|
/* @__PURE__ */ jsxs(Dialog.Footer, { children: [
|
1617
|
-
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
|
2027
|
+
/* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1618
2028
|
id: "app.components.Button.cancel",
|
1619
2029
|
defaultMessage: "Cancel"
|
1620
2030
|
}) }) }),
|
1621
|
-
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2031
|
+
/* @__PURE__ */ jsx(Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1622
2032
|
id: "app.components.Button.confirm",
|
1623
2033
|
defaultMessage: "Confirm"
|
1624
2034
|
}) })
|
@@ -1645,6 +2055,18 @@ const DocumentActionModal = ({
|
|
1645
2055
|
typeof Footer === "function" ? /* @__PURE__ */ jsx(Footer, { onClose: handleClose }) : Footer
|
1646
2056
|
] }) });
|
1647
2057
|
};
|
2058
|
+
const transformData = (data) => {
|
2059
|
+
if (Array.isArray(data)) {
|
2060
|
+
return data.map(transformData);
|
2061
|
+
}
|
2062
|
+
if (typeof data === "object" && data !== null) {
|
2063
|
+
if ("apiData" in data) {
|
2064
|
+
return data.apiData;
|
2065
|
+
}
|
2066
|
+
return mapValues(transformData)(data);
|
2067
|
+
}
|
2068
|
+
return data;
|
2069
|
+
};
|
1648
2070
|
const PublishAction$1 = ({
|
1649
2071
|
activeTab,
|
1650
2072
|
documentId,
|
@@ -1657,12 +2079,11 @@ const PublishAction$1 = ({
|
|
1657
2079
|
const navigate = useNavigate();
|
1658
2080
|
const { toggleNotification } = useNotification();
|
1659
2081
|
const { _unstableFormatValidationErrors: formatValidationErrors } = useAPIErrorHandler();
|
2082
|
+
const isListView = useMatch(LIST_PATH) !== null;
|
1660
2083
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2084
|
+
const { id } = useParams();
|
1661
2085
|
const { formatMessage } = useIntl();
|
1662
|
-
const { canPublish
|
1663
|
-
"PublishAction",
|
1664
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1665
|
-
);
|
2086
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1666
2087
|
const { publish } = useDocumentActions();
|
1667
2088
|
const [
|
1668
2089
|
countDraftRelations,
|
@@ -1714,24 +2135,25 @@ const PublishAction$1 = ({
|
|
1714
2135
|
}
|
1715
2136
|
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1716
2137
|
React.useEffect(() => {
|
1717
|
-
if (documentId) {
|
1718
|
-
|
1719
|
-
const { data, error } = await countDraftRelations({
|
1720
|
-
collectionType,
|
1721
|
-
model,
|
1722
|
-
documentId,
|
1723
|
-
params
|
1724
|
-
});
|
1725
|
-
if (error) {
|
1726
|
-
throw error;
|
1727
|
-
}
|
1728
|
-
if (data) {
|
1729
|
-
setServerCountOfDraftRelations(data.data);
|
1730
|
-
}
|
1731
|
-
};
|
1732
|
-
fetchDraftRelationsCount();
|
2138
|
+
if (!document || !document.documentId || isListView) {
|
2139
|
+
return;
|
1733
2140
|
}
|
1734
|
-
|
2141
|
+
const fetchDraftRelationsCount = async () => {
|
2142
|
+
const { data, error } = await countDraftRelations({
|
2143
|
+
collectionType,
|
2144
|
+
model,
|
2145
|
+
documentId,
|
2146
|
+
params
|
2147
|
+
});
|
2148
|
+
if (error) {
|
2149
|
+
throw error;
|
2150
|
+
}
|
2151
|
+
if (data) {
|
2152
|
+
setServerCountOfDraftRelations(data.data);
|
2153
|
+
}
|
2154
|
+
};
|
2155
|
+
fetchDraftRelationsCount();
|
2156
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
1735
2157
|
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1736
2158
|
if (!schema?.options?.draftAndPublish) {
|
1737
2159
|
return null;
|
@@ -1739,7 +2161,9 @@ const PublishAction$1 = ({
|
|
1739
2161
|
const performPublish = async () => {
|
1740
2162
|
setSubmitting(true);
|
1741
2163
|
try {
|
1742
|
-
const { errors } = await validate(
|
2164
|
+
const { errors } = await validate(true, {
|
2165
|
+
status: "published"
|
2166
|
+
});
|
1743
2167
|
if (errors) {
|
1744
2168
|
toggleNotification({
|
1745
2169
|
type: "danger",
|
@@ -1757,13 +2181,15 @@ const PublishAction$1 = ({
|
|
1757
2181
|
documentId,
|
1758
2182
|
params
|
1759
2183
|
},
|
1760
|
-
formValues
|
2184
|
+
transformData(formValues)
|
1761
2185
|
);
|
1762
2186
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1763
|
-
|
1764
|
-
|
1765
|
-
|
1766
|
-
|
2187
|
+
if (id === "create") {
|
2188
|
+
navigate({
|
2189
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2190
|
+
search: rawQuery
|
2191
|
+
});
|
2192
|
+
}
|
1767
2193
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1768
2194
|
setErrors(formatValidationErrors(res.error));
|
1769
2195
|
}
|
@@ -1772,7 +2198,8 @@ const PublishAction$1 = ({
|
|
1772
2198
|
}
|
1773
2199
|
};
|
1774
2200
|
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1775
|
-
const
|
2201
|
+
const enableDraftRelationsCount = false;
|
2202
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
1776
2203
|
return {
|
1777
2204
|
/**
|
1778
2205
|
* Disabled when:
|
@@ -1782,18 +2209,13 @@ const PublishAction$1 = ({
|
|
1782
2209
|
* - the document is already published & not modified
|
1783
2210
|
* - the document is being created & not modified
|
1784
2211
|
* - the user doesn't have the permission to publish
|
1785
|
-
* - the user doesn't have the permission to create a new document
|
1786
|
-
* - the user doesn't have the permission to update the document
|
1787
2212
|
*/
|
1788
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2213
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1789
2214
|
label: formatMessage({
|
1790
2215
|
id: "app.utils.publish",
|
1791
2216
|
defaultMessage: "Publish"
|
1792
2217
|
}),
|
1793
2218
|
onClick: async () => {
|
1794
|
-
if (hasDraftRelations) {
|
1795
|
-
return;
|
1796
|
-
}
|
1797
2219
|
await performPublish();
|
1798
2220
|
},
|
1799
2221
|
dialog: hasDraftRelations ? {
|
@@ -1832,10 +2254,6 @@ const UpdateAction = ({
|
|
1832
2254
|
const cloneMatch = useMatch(CLONE_PATH);
|
1833
2255
|
const isCloning = cloneMatch !== null;
|
1834
2256
|
const { formatMessage } = useIntl();
|
1835
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1836
|
-
canCreate: canCreate2,
|
1837
|
-
canUpdate: canUpdate2
|
1838
|
-
}));
|
1839
2257
|
const { create, update, clone } = useDocumentActions();
|
1840
2258
|
const [{ query, rawQuery }] = useQueryParams();
|
1841
2259
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
@@ -1852,18 +2270,18 @@ const UpdateAction = ({
|
|
1852
2270
|
* - the form is submitting
|
1853
2271
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1854
2272
|
* - the active tab is the published tab
|
1855
|
-
* - the user doesn't have the permission to create a new document
|
1856
|
-
* - the user doesn't have the permission to update the document
|
1857
2273
|
*/
|
1858
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2274
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1859
2275
|
label: formatMessage({
|
1860
|
-
id: "
|
2276
|
+
id: "global.save",
|
1861
2277
|
defaultMessage: "Save"
|
1862
2278
|
}),
|
1863
2279
|
onClick: async () => {
|
1864
2280
|
setSubmitting(true);
|
1865
2281
|
try {
|
1866
|
-
const { errors } = await validate(
|
2282
|
+
const { errors } = await validate(true, {
|
2283
|
+
status: "draft"
|
2284
|
+
});
|
1867
2285
|
if (errors) {
|
1868
2286
|
toggleNotification({
|
1869
2287
|
type: "danger",
|
@@ -1881,7 +2299,7 @@ const UpdateAction = ({
|
|
1881
2299
|
documentId: cloneMatch.params.origin,
|
1882
2300
|
params
|
1883
2301
|
},
|
1884
|
-
document
|
2302
|
+
transformData(document)
|
1885
2303
|
);
|
1886
2304
|
if ("data" in res) {
|
1887
2305
|
navigate(
|
@@ -1902,7 +2320,7 @@ const UpdateAction = ({
|
|
1902
2320
|
documentId,
|
1903
2321
|
params
|
1904
2322
|
},
|
1905
|
-
document
|
2323
|
+
transformData(document)
|
1906
2324
|
);
|
1907
2325
|
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1908
2326
|
setErrors(formatValidationErrors(res.error));
|
@@ -1915,7 +2333,7 @@ const UpdateAction = ({
|
|
1915
2333
|
model,
|
1916
2334
|
params
|
1917
2335
|
},
|
1918
|
-
document
|
2336
|
+
transformData(document)
|
1919
2337
|
);
|
1920
2338
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1921
2339
|
navigate(
|
@@ -1968,7 +2386,7 @@ const UnpublishAction$1 = ({
|
|
1968
2386
|
id: "app.utils.unpublish",
|
1969
2387
|
defaultMessage: "Unpublish"
|
1970
2388
|
}),
|
1971
|
-
icon: /* @__PURE__ */ jsx(
|
2389
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
1972
2390
|
onClick: async () => {
|
1973
2391
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1974
2392
|
if (!documentId) {
|
@@ -2080,7 +2498,7 @@ const DiscardAction = ({
|
|
2080
2498
|
id: "content-manager.actions.discard.label",
|
2081
2499
|
defaultMessage: "Discard changes"
|
2082
2500
|
}),
|
2083
|
-
icon: /* @__PURE__ */ jsx(
|
2501
|
+
icon: /* @__PURE__ */ jsx(Cross, {}),
|
2084
2502
|
position: ["panel", "table-row"],
|
2085
2503
|
variant: "danger",
|
2086
2504
|
dialog: {
|
@@ -2108,11 +2526,6 @@ const DiscardAction = ({
|
|
2108
2526
|
};
|
2109
2527
|
};
|
2110
2528
|
DiscardAction.type = "discard";
|
2111
|
-
const StyledCrossCircle = styled(CrossCircle)`
|
2112
|
-
path {
|
2113
|
-
fill: currentColor;
|
2114
|
-
}
|
2115
|
-
`;
|
2116
2529
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2117
2530
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2118
2531
|
const RelativeTime = React.forwardRef(
|
@@ -2125,7 +2538,7 @@ const RelativeTime = React.forwardRef(
|
|
2125
2538
|
});
|
2126
2539
|
const unit = intervals.find((intervalUnit) => {
|
2127
2540
|
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2128
|
-
});
|
2541
|
+
}) ?? "seconds";
|
2129
2542
|
const relativeTime = isPast(timestamp) ? -interval[unit] : interval[unit];
|
2130
2543
|
const customInterval = customIntervals.find(
|
2131
2544
|
(custom) => interval[custom.unit] < custom.threshold
|
@@ -2159,19 +2572,29 @@ const getDisplayName = ({
|
|
2159
2572
|
return email ?? "";
|
2160
2573
|
};
|
2161
2574
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2162
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2163
|
-
const statusVariant = status === "draft" ? "
|
2164
|
-
|
2575
|
+
const DocumentStatus = ({ status = "draft", size = "S", ...restProps }) => {
|
2576
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2577
|
+
const { formatMessage } = useIntl();
|
2578
|
+
return /* @__PURE__ */ jsx(Status, { ...restProps, size, variant: statusVariant, children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: formatMessage({
|
2579
|
+
id: `content-manager.containers.List.${status}`,
|
2580
|
+
defaultMessage: capitalise(status)
|
2581
|
+
}) }) });
|
2165
2582
|
};
|
2166
2583
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2167
2584
|
const { formatMessage } = useIntl();
|
2168
2585
|
const isCloning = useMatch(CLONE_PATH) !== null;
|
2586
|
+
const params = useParams();
|
2169
2587
|
const title = isCreating ? formatMessage({
|
2170
2588
|
id: "content-manager.containers.edit.title.new",
|
2171
2589
|
defaultMessage: "Create an entry"
|
2172
2590
|
}) : documentTitle;
|
2173
2591
|
return /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2174
|
-
/* @__PURE__ */ jsx(
|
2592
|
+
/* @__PURE__ */ jsx(
|
2593
|
+
BackButton,
|
2594
|
+
{
|
2595
|
+
fallback: params.collectionType === SINGLE_TYPES ? void 0 : `../${COLLECTION_TYPES}/${params.slug}`
|
2596
|
+
}
|
2597
|
+
),
|
2175
2598
|
/* @__PURE__ */ jsxs(Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2176
2599
|
/* @__PURE__ */ jsx(Typography, { variant: "alpha", tag: "h1", children: title }),
|
2177
2600
|
/* @__PURE__ */ jsx(HeaderToolbar, {})
|
@@ -2259,12 +2682,12 @@ const Information = ({ activeTab }) => {
|
|
2259
2682
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2260
2683
|
label: formatMessage({
|
2261
2684
|
id: "content-manager.containers.edit.information.last-published.label",
|
2262
|
-
defaultMessage: "
|
2685
|
+
defaultMessage: "Published"
|
2263
2686
|
}),
|
2264
2687
|
value: formatMessage(
|
2265
2688
|
{
|
2266
2689
|
id: "content-manager.containers.edit.information.last-published.value",
|
2267
|
-
defaultMessage: `
|
2690
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2268
2691
|
},
|
2269
2692
|
{
|
2270
2693
|
time: /* @__PURE__ */ jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2277,12 +2700,12 @@ const Information = ({ activeTab }) => {
|
|
2277
2700
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2278
2701
|
label: formatMessage({
|
2279
2702
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2280
|
-
defaultMessage: "
|
2703
|
+
defaultMessage: "Updated"
|
2281
2704
|
}),
|
2282
2705
|
value: formatMessage(
|
2283
2706
|
{
|
2284
2707
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2285
|
-
defaultMessage: `
|
2708
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2286
2709
|
},
|
2287
2710
|
{
|
2288
2711
|
time: /* @__PURE__ */ jsx(
|
@@ -2300,12 +2723,12 @@ const Information = ({ activeTab }) => {
|
|
2300
2723
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2301
2724
|
label: formatMessage({
|
2302
2725
|
id: "content-manager.containers.edit.information.document.label",
|
2303
|
-
defaultMessage: "
|
2726
|
+
defaultMessage: "Created"
|
2304
2727
|
}),
|
2305
2728
|
value: formatMessage(
|
2306
2729
|
{
|
2307
2730
|
id: "content-manager.containers.edit.information.document.value",
|
2308
|
-
defaultMessage: `
|
2731
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2309
2732
|
},
|
2310
2733
|
{
|
2311
2734
|
time: /* @__PURE__ */ jsx(
|
@@ -2343,28 +2766,80 @@ const Information = ({ activeTab }) => {
|
|
2343
2766
|
);
|
2344
2767
|
};
|
2345
2768
|
const HeaderActions = ({ actions: actions2 }) => {
|
2346
|
-
|
2347
|
-
|
2769
|
+
const [dialogId, setDialogId] = React.useState(null);
|
2770
|
+
const handleClick = (action) => async (e) => {
|
2771
|
+
if (!("options" in action)) {
|
2772
|
+
const { onClick = () => false, dialog, id } = action;
|
2773
|
+
const muteDialog = await onClick(e);
|
2774
|
+
if (dialog && !muteDialog) {
|
2775
|
+
e.preventDefault();
|
2776
|
+
setDialogId(id);
|
2777
|
+
}
|
2778
|
+
}
|
2779
|
+
};
|
2780
|
+
const handleClose = () => {
|
2781
|
+
setDialogId(null);
|
2782
|
+
};
|
2783
|
+
return /* @__PURE__ */ jsx(Flex, { gap: 1, children: actions2.map((action) => {
|
2784
|
+
if (action.options) {
|
2348
2785
|
return /* @__PURE__ */ jsx(
|
2349
2786
|
SingleSelect,
|
2350
2787
|
{
|
2351
2788
|
size: "S",
|
2352
|
-
disabled: action.disabled,
|
2353
|
-
"aria-label": action.label,
|
2354
2789
|
onChange: action.onSelect,
|
2355
|
-
|
2790
|
+
"aria-label": action.label,
|
2791
|
+
...action,
|
2356
2792
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsx(SingleSelectOption, { ...option, children: label }, option.value))
|
2357
2793
|
},
|
2358
2794
|
action.id
|
2359
2795
|
);
|
2360
2796
|
} else {
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2797
|
+
if (action.type === "icon") {
|
2798
|
+
return /* @__PURE__ */ jsxs(React.Fragment, { children: [
|
2799
|
+
/* @__PURE__ */ jsx(
|
2800
|
+
IconButton,
|
2801
|
+
{
|
2802
|
+
disabled: action.disabled,
|
2803
|
+
label: action.label,
|
2804
|
+
size: "S",
|
2805
|
+
onClick: handleClick(action),
|
2806
|
+
children: action.icon
|
2807
|
+
}
|
2808
|
+
),
|
2809
|
+
action.dialog ? /* @__PURE__ */ jsx(
|
2810
|
+
HeaderActionDialog,
|
2811
|
+
{
|
2812
|
+
...action.dialog,
|
2813
|
+
isOpen: dialogId === action.id,
|
2814
|
+
onClose: handleClose
|
2815
|
+
}
|
2816
|
+
) : null
|
2817
|
+
] }, action.id);
|
2818
|
+
}
|
2819
|
+
}
|
2820
|
+
}) });
|
2821
|
+
};
|
2822
|
+
const HeaderActionDialog = ({
|
2823
|
+
onClose,
|
2824
|
+
onCancel,
|
2825
|
+
title,
|
2826
|
+
content: Content,
|
2827
|
+
isOpen
|
2828
|
+
}) => {
|
2829
|
+
const handleClose = async () => {
|
2830
|
+
if (onCancel) {
|
2831
|
+
await onCancel();
|
2832
|
+
}
|
2833
|
+
onClose();
|
2834
|
+
};
|
2835
|
+
return /* @__PURE__ */ jsx(Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxs(Dialog.Content, { children: [
|
2836
|
+
/* @__PURE__ */ jsx(Dialog.Header, { children: title }),
|
2837
|
+
typeof Content === "function" ? /* @__PURE__ */ jsx(Content, { onClose: handleClose }) : Content
|
2838
|
+
] }) });
|
2839
|
+
};
|
2840
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2841
|
+
const navigate = useNavigate();
|
2842
|
+
const { formatMessage } = useIntl();
|
2368
2843
|
return {
|
2369
2844
|
label: formatMessage({
|
2370
2845
|
id: "app.links.configure-view",
|
@@ -2402,12 +2877,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2402
2877
|
const { delete: deleteAction } = useDocumentActions();
|
2403
2878
|
const { toggleNotification } = useNotification();
|
2404
2879
|
const setSubmitting = useForm("DeleteAction", (state) => state.setSubmitting);
|
2880
|
+
const isLocalized = document?.locale != null;
|
2405
2881
|
return {
|
2406
2882
|
disabled: !canDelete || !document,
|
2407
|
-
label: formatMessage(
|
2408
|
-
|
2409
|
-
|
2410
|
-
|
2883
|
+
label: formatMessage(
|
2884
|
+
{
|
2885
|
+
id: "content-manager.actions.delete.label",
|
2886
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2887
|
+
},
|
2888
|
+
{ isLocalized }
|
2889
|
+
),
|
2411
2890
|
icon: /* @__PURE__ */ jsx(Trash, {}),
|
2412
2891
|
dialog: {
|
2413
2892
|
type: "dialog",
|
@@ -2444,422 +2923,120 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2444
2923
|
documentId,
|
2445
2924
|
model,
|
2446
2925
|
collectionType,
|
2447
|
-
params: {
|
2448
|
-
locale: "*"
|
2449
|
-
}
|
2450
|
-
});
|
2451
|
-
if (!("error" in res)) {
|
2452
|
-
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2453
|
-
}
|
2454
|
-
} finally {
|
2455
|
-
if (!listViewPathMatch) {
|
2456
|
-
setSubmitting(false);
|
2457
|
-
}
|
2458
|
-
}
|
2459
|
-
}
|
2460
|
-
},
|
2461
|
-
variant: "danger",
|
2462
|
-
position: ["header", "table-row"]
|
2463
|
-
};
|
2464
|
-
};
|
2465
|
-
DeleteAction$1.type = "delete";
|
2466
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2467
|
-
const Panels = () => {
|
2468
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2469
|
-
const [
|
2470
|
-
{
|
2471
|
-
query: { status }
|
2472
|
-
}
|
2473
|
-
] = useQueryParams({
|
2474
|
-
status: "draft"
|
2475
|
-
});
|
2476
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2477
|
-
const plugins = useStrapiApp("Panels", (state) => state.plugins);
|
2478
|
-
const props = {
|
2479
|
-
activeTab: status,
|
2480
|
-
model,
|
2481
|
-
documentId: id,
|
2482
|
-
document: isCloning ? void 0 : document,
|
2483
|
-
meta: isCloning ? void 0 : meta,
|
2484
|
-
collectionType
|
2485
|
-
};
|
2486
|
-
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2487
|
-
DescriptionComponentRenderer,
|
2488
|
-
{
|
2489
|
-
props,
|
2490
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2491
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2492
|
-
}
|
2493
|
-
) });
|
2494
|
-
};
|
2495
|
-
const ActionsPanel = () => {
|
2496
|
-
const { formatMessage } = useIntl();
|
2497
|
-
return {
|
2498
|
-
title: formatMessage({
|
2499
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2500
|
-
defaultMessage: "Document"
|
2501
|
-
}),
|
2502
|
-
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2503
|
-
};
|
2504
|
-
};
|
2505
|
-
ActionsPanel.type = "actions";
|
2506
|
-
const ActionsPanelContent = () => {
|
2507
|
-
const isCloning = useMatch(CLONE_PATH) !== null;
|
2508
|
-
const [
|
2509
|
-
{
|
2510
|
-
query: { status = "draft" }
|
2511
|
-
}
|
2512
|
-
] = useQueryParams();
|
2513
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2514
|
-
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2515
|
-
const props = {
|
2516
|
-
activeTab: status,
|
2517
|
-
model,
|
2518
|
-
documentId: id,
|
2519
|
-
document: isCloning ? void 0 : document,
|
2520
|
-
meta: isCloning ? void 0 : meta,
|
2521
|
-
collectionType
|
2522
|
-
};
|
2523
|
-
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2524
|
-
/* @__PURE__ */ jsx(
|
2525
|
-
DescriptionComponentRenderer,
|
2526
|
-
{
|
2527
|
-
props,
|
2528
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2529
|
-
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
2530
|
-
}
|
2531
|
-
),
|
2532
|
-
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2533
|
-
] });
|
2534
|
-
};
|
2535
|
-
const Panel = React.forwardRef(({ children, title }, ref) => {
|
2536
|
-
return /* @__PURE__ */ jsxs(
|
2537
|
-
Flex,
|
2538
|
-
{
|
2539
|
-
ref,
|
2540
|
-
tag: "aside",
|
2541
|
-
"aria-labelledby": "additional-information",
|
2542
|
-
background: "neutral0",
|
2543
|
-
borderColor: "neutral150",
|
2544
|
-
hasRadius: true,
|
2545
|
-
paddingBottom: 4,
|
2546
|
-
paddingLeft: 4,
|
2547
|
-
paddingRight: 4,
|
2548
|
-
paddingTop: 4,
|
2549
|
-
shadow: "tableShadow",
|
2550
|
-
gap: 3,
|
2551
|
-
direction: "column",
|
2552
|
-
justifyContent: "stretch",
|
2553
|
-
alignItems: "flex-start",
|
2554
|
-
children: [
|
2555
|
-
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2556
|
-
children
|
2557
|
-
]
|
2558
|
-
}
|
2559
|
-
);
|
2560
|
-
});
|
2561
|
-
const HOOKS = {
|
2562
|
-
/**
|
2563
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2564
|
-
* @constant
|
2565
|
-
* @type {string}
|
2566
|
-
*/
|
2567
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2568
|
-
/**
|
2569
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2570
|
-
* @constant
|
2571
|
-
* @type {string}
|
2572
|
-
*/
|
2573
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2574
|
-
/**
|
2575
|
-
* Hook that allows to mutate the CM's edit view layout
|
2576
|
-
* @constant
|
2577
|
-
* @type {string}
|
2578
|
-
*/
|
2579
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2580
|
-
/**
|
2581
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2582
|
-
* @constant
|
2583
|
-
* @type {string}
|
2584
|
-
*/
|
2585
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2586
|
-
};
|
2587
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2588
|
-
endpoints: (builder) => ({
|
2589
|
-
getContentTypeConfiguration: builder.query({
|
2590
|
-
query: (uid) => ({
|
2591
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2592
|
-
method: "GET"
|
2593
|
-
}),
|
2594
|
-
transformResponse: (response) => response.data,
|
2595
|
-
providesTags: (_result, _error, uid) => [
|
2596
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2597
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2598
|
-
]
|
2599
|
-
}),
|
2600
|
-
getAllContentTypeSettings: builder.query({
|
2601
|
-
query: () => "/content-manager/content-types-settings",
|
2602
|
-
transformResponse: (response) => response.data,
|
2603
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2604
|
-
}),
|
2605
|
-
updateContentTypeConfiguration: builder.mutation({
|
2606
|
-
query: ({ uid, ...body }) => ({
|
2607
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2608
|
-
method: "PUT",
|
2609
|
-
data: body
|
2610
|
-
}),
|
2611
|
-
transformResponse: (response) => response.data,
|
2612
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2613
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2614
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2615
|
-
// Is this necessary?
|
2616
|
-
{ type: "InitialData" }
|
2617
|
-
]
|
2618
|
-
})
|
2619
|
-
})
|
2620
|
-
});
|
2621
|
-
const {
|
2622
|
-
useGetContentTypeConfigurationQuery,
|
2623
|
-
useGetAllContentTypeSettingsQuery,
|
2624
|
-
useUpdateContentTypeConfigurationMutation
|
2625
|
-
} = contentTypesApi;
|
2626
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2627
|
-
const { type } = attribute;
|
2628
|
-
if (type === "relation") {
|
2629
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2630
|
-
}
|
2631
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2632
|
-
};
|
2633
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2634
|
-
if (!mainFieldName) {
|
2635
|
-
return void 0;
|
2636
|
-
}
|
2637
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2638
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2639
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2640
|
-
);
|
2641
|
-
return {
|
2642
|
-
name: mainFieldName,
|
2643
|
-
type: mainFieldType ?? "string"
|
2644
|
-
};
|
2645
|
-
};
|
2646
|
-
const DEFAULT_SETTINGS = {
|
2647
|
-
bulkable: false,
|
2648
|
-
filterable: false,
|
2649
|
-
searchable: false,
|
2650
|
-
pagination: false,
|
2651
|
-
defaultSortBy: "",
|
2652
|
-
defaultSortOrder: "asc",
|
2653
|
-
mainField: "id",
|
2654
|
-
pageSize: 10
|
2655
|
-
};
|
2656
|
-
const useDocumentLayout = (model) => {
|
2657
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2658
|
-
const [{ query }] = useQueryParams();
|
2659
|
-
const runHookWaterfall = useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2660
|
-
const { toggleNotification } = useNotification();
|
2661
|
-
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
2662
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2663
|
-
const {
|
2664
|
-
data,
|
2665
|
-
isLoading: isLoadingConfigs,
|
2666
|
-
error,
|
2667
|
-
isFetching: isFetchingConfigs
|
2668
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2669
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2670
|
-
React.useEffect(() => {
|
2671
|
-
if (error) {
|
2672
|
-
toggleNotification({
|
2673
|
-
type: "danger",
|
2674
|
-
message: formatAPIError(error)
|
2675
|
-
});
|
2676
|
-
}
|
2677
|
-
}, [error, formatAPIError, toggleNotification]);
|
2678
|
-
const editLayout = React.useMemo(
|
2679
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2680
|
-
layout: [],
|
2681
|
-
components: {},
|
2682
|
-
metadatas: {},
|
2683
|
-
options: {},
|
2684
|
-
settings: DEFAULT_SETTINGS
|
2685
|
-
},
|
2686
|
-
[data, isLoading, schemas, schema, components]
|
2687
|
-
);
|
2688
|
-
const listLayout = React.useMemo(() => {
|
2689
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2690
|
-
layout: [],
|
2691
|
-
metadatas: {},
|
2692
|
-
options: {},
|
2693
|
-
settings: DEFAULT_SETTINGS
|
2694
|
-
};
|
2695
|
-
}, [data, isLoading, schemas, schema, components]);
|
2696
|
-
const { layout: edit } = React.useMemo(
|
2697
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2698
|
-
layout: editLayout,
|
2699
|
-
query
|
2700
|
-
}),
|
2701
|
-
[editLayout, query, runHookWaterfall]
|
2702
|
-
);
|
2703
|
-
return {
|
2704
|
-
error,
|
2705
|
-
isLoading,
|
2706
|
-
edit,
|
2707
|
-
list: listLayout
|
2708
|
-
};
|
2709
|
-
};
|
2710
|
-
const useDocLayout = () => {
|
2711
|
-
const { model } = useDoc();
|
2712
|
-
return useDocumentLayout(model);
|
2713
|
-
};
|
2714
|
-
const formatEditLayout = (data, {
|
2715
|
-
schemas,
|
2716
|
-
schema,
|
2717
|
-
components
|
2718
|
-
}) => {
|
2719
|
-
let currentPanelIndex = 0;
|
2720
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2721
|
-
data.contentType.layouts.edit,
|
2722
|
-
schema?.attributes,
|
2723
|
-
data.contentType.metadatas,
|
2724
|
-
{ configurations: data.components, schemas: components },
|
2725
|
-
schemas
|
2726
|
-
).reduce((panels, row) => {
|
2727
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2728
|
-
panels.push([row]);
|
2729
|
-
currentPanelIndex += 2;
|
2730
|
-
} else {
|
2731
|
-
if (!panels[currentPanelIndex]) {
|
2732
|
-
panels.push([]);
|
2733
|
-
}
|
2734
|
-
panels[currentPanelIndex].push(row);
|
2735
|
-
}
|
2736
|
-
return panels;
|
2737
|
-
}, []);
|
2738
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2739
|
-
(acc, [uid, configuration]) => {
|
2740
|
-
acc[uid] = {
|
2741
|
-
layout: convertEditLayoutToFieldLayouts(
|
2742
|
-
configuration.layouts.edit,
|
2743
|
-
components[uid].attributes,
|
2744
|
-
configuration.metadatas
|
2745
|
-
),
|
2746
|
-
settings: {
|
2747
|
-
...configuration.settings,
|
2748
|
-
icon: components[uid].info.icon,
|
2749
|
-
displayName: components[uid].info.displayName
|
2926
|
+
params: {
|
2927
|
+
locale: "*"
|
2928
|
+
}
|
2929
|
+
});
|
2930
|
+
if (!("error" in res)) {
|
2931
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2932
|
+
}
|
2933
|
+
} finally {
|
2934
|
+
if (!listViewPathMatch) {
|
2935
|
+
setSubmitting(false);
|
2936
|
+
}
|
2750
2937
|
}
|
2751
|
-
}
|
2752
|
-
return acc;
|
2753
|
-
},
|
2754
|
-
{}
|
2755
|
-
);
|
2756
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2757
|
-
(acc, [attribute, metadata]) => {
|
2758
|
-
return {
|
2759
|
-
...acc,
|
2760
|
-
[attribute]: metadata.edit
|
2761
|
-
};
|
2762
|
-
},
|
2763
|
-
{}
|
2764
|
-
);
|
2765
|
-
return {
|
2766
|
-
layout: panelledEditAttributes,
|
2767
|
-
components: componentEditAttributes,
|
2768
|
-
metadatas: editMetadatas,
|
2769
|
-
settings: {
|
2770
|
-
...data.contentType.settings,
|
2771
|
-
displayName: schema?.info.displayName
|
2938
|
+
}
|
2772
2939
|
},
|
2773
|
-
|
2774
|
-
|
2775
|
-
...schema?.pluginOptions,
|
2776
|
-
...data.contentType.options
|
2777
|
-
}
|
2940
|
+
variant: "danger",
|
2941
|
+
position: ["header", "table-row"]
|
2778
2942
|
};
|
2779
2943
|
};
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
}
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
}
|
2807
|
-
}
|
2808
|
-
);
|
2944
|
+
DeleteAction$1.type = "delete";
|
2945
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2946
|
+
const Panels = () => {
|
2947
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2948
|
+
const [
|
2949
|
+
{
|
2950
|
+
query: { status }
|
2951
|
+
}
|
2952
|
+
] = useQueryParams({
|
2953
|
+
status: "draft"
|
2954
|
+
});
|
2955
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2956
|
+
const plugins = useStrapiApp("Panels", (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
|
2964
|
+
};
|
2965
|
+
return /* @__PURE__ */ jsx(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsx(
|
2966
|
+
DescriptionComponentRenderer,
|
2967
|
+
{
|
2968
|
+
props,
|
2969
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2970
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsx(Panel, { ...description, children: content }, id2))
|
2971
|
+
}
|
2972
|
+
) });
|
2809
2973
|
};
|
2810
|
-
const
|
2811
|
-
|
2812
|
-
schema,
|
2813
|
-
components
|
2814
|
-
}) => {
|
2815
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2816
|
-
(acc, [attribute, metadata]) => {
|
2817
|
-
return {
|
2818
|
-
...acc,
|
2819
|
-
[attribute]: metadata.list
|
2820
|
-
};
|
2821
|
-
},
|
2822
|
-
{}
|
2823
|
-
);
|
2824
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2825
|
-
data.contentType.layouts.list,
|
2826
|
-
schema?.attributes,
|
2827
|
-
listMetadatas,
|
2828
|
-
{ configurations: data.components, schemas: components },
|
2829
|
-
schemas
|
2830
|
-
);
|
2974
|
+
const ActionsPanel = () => {
|
2975
|
+
const { formatMessage } = useIntl();
|
2831
2976
|
return {
|
2832
|
-
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
...schema?.pluginOptions,
|
2838
|
-
...data.contentType.options
|
2839
|
-
}
|
2977
|
+
title: formatMessage({
|
2978
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2979
|
+
defaultMessage: "Entry"
|
2980
|
+
}),
|
2981
|
+
content: /* @__PURE__ */ jsx(ActionsPanelContent, {})
|
2840
2982
|
};
|
2841
2983
|
};
|
2842
|
-
|
2843
|
-
|
2844
|
-
|
2845
|
-
|
2846
|
-
|
2984
|
+
ActionsPanel.type = "actions";
|
2985
|
+
const ActionsPanelContent = () => {
|
2986
|
+
const isCloning = useMatch(CLONE_PATH) !== null;
|
2987
|
+
const [
|
2988
|
+
{
|
2989
|
+
query: { status = "draft" }
|
2847
2990
|
}
|
2848
|
-
|
2849
|
-
|
2850
|
-
|
2851
|
-
|
2852
|
-
|
2853
|
-
|
2854
|
-
|
2855
|
-
|
2856
|
-
|
2857
|
-
|
2858
|
-
|
2859
|
-
|
2860
|
-
|
2861
|
-
|
2991
|
+
] = useQueryParams();
|
2992
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2993
|
+
const plugins = useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2994
|
+
const props = {
|
2995
|
+
activeTab: status,
|
2996
|
+
model,
|
2997
|
+
documentId: id,
|
2998
|
+
document: isCloning ? void 0 : document,
|
2999
|
+
meta: isCloning ? void 0 : meta,
|
3000
|
+
collectionType
|
3001
|
+
};
|
3002
|
+
return /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3003
|
+
/* @__PURE__ */ jsx(
|
3004
|
+
DescriptionComponentRenderer,
|
3005
|
+
{
|
3006
|
+
props,
|
3007
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3008
|
+
children: (actions2) => /* @__PURE__ */ jsx(DocumentActions, { actions: actions2 })
|
3009
|
+
}
|
3010
|
+
),
|
3011
|
+
/* @__PURE__ */ jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3012
|
+
] });
|
2862
3013
|
};
|
3014
|
+
const Panel = React.forwardRef(({ children, title }, ref) => {
|
3015
|
+
return /* @__PURE__ */ jsxs(
|
3016
|
+
Flex,
|
3017
|
+
{
|
3018
|
+
ref,
|
3019
|
+
tag: "aside",
|
3020
|
+
"aria-labelledby": "additional-information",
|
3021
|
+
background: "neutral0",
|
3022
|
+
borderColor: "neutral150",
|
3023
|
+
hasRadius: true,
|
3024
|
+
paddingBottom: 4,
|
3025
|
+
paddingLeft: 4,
|
3026
|
+
paddingRight: 4,
|
3027
|
+
paddingTop: 4,
|
3028
|
+
shadow: "tableShadow",
|
3029
|
+
gap: 3,
|
3030
|
+
direction: "column",
|
3031
|
+
justifyContent: "stretch",
|
3032
|
+
alignItems: "flex-start",
|
3033
|
+
children: [
|
3034
|
+
/* @__PURE__ */ jsx(Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", textColor: "neutral600", children: title }),
|
3035
|
+
children
|
3036
|
+
]
|
3037
|
+
}
|
3038
|
+
);
|
3039
|
+
});
|
2863
3040
|
const ConfirmBulkActionDialog = ({
|
2864
3041
|
onToggleDialog,
|
2865
3042
|
isOpen = false,
|
@@ -2898,6 +3075,7 @@ const ConfirmDialogPublishAll = ({
|
|
2898
3075
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler(getTranslation);
|
2899
3076
|
const { model, schema } = useDoc();
|
2900
3077
|
const [{ query }] = useQueryParams();
|
3078
|
+
const enableDraftRelationsCount = false;
|
2901
3079
|
const {
|
2902
3080
|
data: countDraftRelations = 0,
|
2903
3081
|
isLoading,
|
@@ -2909,7 +3087,7 @@ const ConfirmDialogPublishAll = ({
|
|
2909
3087
|
locale: query?.plugins?.i18n?.locale
|
2910
3088
|
},
|
2911
3089
|
{
|
2912
|
-
skip:
|
3090
|
+
skip: !enableDraftRelationsCount
|
2913
3091
|
}
|
2914
3092
|
);
|
2915
3093
|
React.useEffect(() => {
|
@@ -3094,7 +3272,7 @@ const SelectedEntriesTableContent = ({
|
|
3094
3272
|
status: row.status
|
3095
3273
|
}
|
3096
3274
|
) }),
|
3097
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
3275
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(
|
3098
3276
|
IconButton,
|
3099
3277
|
{
|
3100
3278
|
tag: Link,
|
@@ -3103,23 +3281,16 @@ const SelectedEntriesTableContent = ({
|
|
3103
3281
|
search: row.locale && `?plugins[i18n][locale]=${row.locale}`
|
3104
3282
|
},
|
3105
3283
|
state: { from: pathname },
|
3106
|
-
label: formatMessage(
|
3107
|
-
|
3108
|
-
|
3109
|
-
|
3110
|
-
{
|
3111
|
-
id: "content-manager.components.ListViewHelperPluginTable.row-line",
|
3112
|
-
defaultMessage: "item line {number}"
|
3113
|
-
},
|
3114
|
-
{ number: index2 + 1 }
|
3115
|
-
)
|
3116
|
-
}
|
3117
|
-
),
|
3284
|
+
label: formatMessage({
|
3285
|
+
id: "content-manager.bulk-publish.edit",
|
3286
|
+
defaultMessage: "Edit"
|
3287
|
+
}),
|
3118
3288
|
target: "_blank",
|
3119
3289
|
marginLeft: "auto",
|
3120
|
-
|
3290
|
+
variant: "ghost",
|
3291
|
+
children: /* @__PURE__ */ jsx(Pencil, { width: "1.6rem", height: "1.6rem" })
|
3121
3292
|
}
|
3122
|
-
) })
|
3293
|
+
) }) })
|
3123
3294
|
] }, row.id)) })
|
3124
3295
|
] });
|
3125
3296
|
};
|
@@ -3156,7 +3327,13 @@ const SelectedEntriesModalContent = ({
|
|
3156
3327
|
);
|
3157
3328
|
const { rows, validationErrors } = React.useMemo(() => {
|
3158
3329
|
if (data.length > 0 && schema) {
|
3159
|
-
const validate = createYupSchema(
|
3330
|
+
const validate = createYupSchema(
|
3331
|
+
schema.attributes,
|
3332
|
+
components,
|
3333
|
+
// Since this is the "Publish" action, the validation
|
3334
|
+
// schema must enforce the rules for published entities
|
3335
|
+
{ status: "published" }
|
3336
|
+
);
|
3160
3337
|
const validationErrors2 = {};
|
3161
3338
|
const rows2 = data.map((entry) => {
|
3162
3339
|
try {
|
@@ -3506,7 +3683,7 @@ const TableActions = ({ document }) => {
|
|
3506
3683
|
DescriptionComponentRenderer,
|
3507
3684
|
{
|
3508
3685
|
props,
|
3509
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3686
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3510
3687
|
children: (actions2) => {
|
3511
3688
|
const tableRowActions = actions2.filter((action) => {
|
3512
3689
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3617,7 +3794,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3617
3794
|
}),
|
3618
3795
|
content: /* @__PURE__ */ jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3619
3796
|
footer: ({ onClose }) => {
|
3620
|
-
return /* @__PURE__ */ jsxs(
|
3797
|
+
return /* @__PURE__ */ jsxs(Modal.Footer, { children: [
|
3621
3798
|
/* @__PURE__ */ jsx(Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3622
3799
|
id: "cancel",
|
3623
3800
|
defaultMessage: "Cancel"
|
@@ -3751,17 +3928,27 @@ const HistoryAction = ({ model, document }) => {
|
|
3751
3928
|
const { formatMessage } = useIntl();
|
3752
3929
|
const [{ query }] = useQueryParams();
|
3753
3930
|
const navigate = useNavigate();
|
3931
|
+
const { trackUsage } = useTracking();
|
3932
|
+
const { pathname } = useLocation();
|
3754
3933
|
const pluginsQueryParams = stringify({ plugins: query.plugins }, { encode: false });
|
3755
3934
|
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3756
3935
|
return null;
|
3757
3936
|
}
|
3937
|
+
const handleOnClick = () => {
|
3938
|
+
const destination = { pathname: "history", search: pluginsQueryParams };
|
3939
|
+
trackUsage("willNavigate", {
|
3940
|
+
from: pathname,
|
3941
|
+
to: `${pathname}/${destination.pathname}`
|
3942
|
+
});
|
3943
|
+
navigate(destination);
|
3944
|
+
};
|
3758
3945
|
return {
|
3759
3946
|
icon: /* @__PURE__ */ jsx(ClockCounterClockwise, {}),
|
3760
3947
|
label: formatMessage({
|
3761
3948
|
id: "content-manager.history.document-action",
|
3762
3949
|
defaultMessage: "Content History"
|
3763
3950
|
}),
|
3764
|
-
onClick:
|
3951
|
+
onClick: handleOnClick,
|
3765
3952
|
disabled: (
|
3766
3953
|
/**
|
3767
3954
|
* The user is creating a new document.
|
@@ -3829,6 +4016,90 @@ const { setInitialData } = actions;
|
|
3829
4016
|
const reducer = combineReducers({
|
3830
4017
|
app: reducer$1
|
3831
4018
|
});
|
4019
|
+
const previewApi = contentManagerApi.injectEndpoints({
|
4020
|
+
endpoints: (builder) => ({
|
4021
|
+
getPreviewUrl: builder.query({
|
4022
|
+
query({ query, params }) {
|
4023
|
+
return {
|
4024
|
+
url: `/content-manager/preview/url/${params.contentType}`,
|
4025
|
+
method: "GET",
|
4026
|
+
config: {
|
4027
|
+
params: query
|
4028
|
+
}
|
4029
|
+
};
|
4030
|
+
}
|
4031
|
+
})
|
4032
|
+
})
|
4033
|
+
});
|
4034
|
+
const { useGetPreviewUrlQuery } = previewApi;
|
4035
|
+
const ConditionalTooltip = ({ isShown, label, children }) => {
|
4036
|
+
if (isShown) {
|
4037
|
+
return /* @__PURE__ */ jsx(Tooltip, { label, children });
|
4038
|
+
}
|
4039
|
+
return children;
|
4040
|
+
};
|
4041
|
+
const PreviewSidePanel = ({ model, documentId, document }) => {
|
4042
|
+
const { formatMessage } = useIntl();
|
4043
|
+
const { trackUsage } = useTracking();
|
4044
|
+
const { pathname } = useLocation();
|
4045
|
+
const [{ query }] = useQueryParams();
|
4046
|
+
const isModified = useForm("PreviewSidePanel", (state) => state.modified);
|
4047
|
+
const { data, error } = useGetPreviewUrlQuery({
|
4048
|
+
params: {
|
4049
|
+
contentType: model
|
4050
|
+
},
|
4051
|
+
query: {
|
4052
|
+
documentId,
|
4053
|
+
locale: document?.locale,
|
4054
|
+
status: document?.status
|
4055
|
+
}
|
4056
|
+
});
|
4057
|
+
if (!data?.data?.url || error) {
|
4058
|
+
return null;
|
4059
|
+
}
|
4060
|
+
const trackNavigation = () => {
|
4061
|
+
const destinationPathname = pathname.replace(/\/$/, "") + "/preview";
|
4062
|
+
trackUsage("willNavigate", { from: pathname, to: destinationPathname });
|
4063
|
+
};
|
4064
|
+
return {
|
4065
|
+
title: formatMessage({ id: "content-manager.preview.panel.title", defaultMessage: "Preview" }),
|
4066
|
+
content: /* @__PURE__ */ jsx(Flex, { gap: 2, width: "100%", children: /* @__PURE__ */ jsx(
|
4067
|
+
ConditionalTooltip,
|
4068
|
+
{
|
4069
|
+
label: formatMessage({
|
4070
|
+
id: "content-manager.preview.panel.button-disabled-tooltip",
|
4071
|
+
defaultMessage: "Please save to open the preview"
|
4072
|
+
}),
|
4073
|
+
isShown: isModified,
|
4074
|
+
children: /* @__PURE__ */ jsx(
|
4075
|
+
Button,
|
4076
|
+
{
|
4077
|
+
variant: "tertiary",
|
4078
|
+
tag: Link,
|
4079
|
+
to: { pathname: "preview", search: stringify(query, { encode: false }) },
|
4080
|
+
onClick: trackNavigation,
|
4081
|
+
flex: "auto",
|
4082
|
+
disabled: isModified,
|
4083
|
+
children: formatMessage({
|
4084
|
+
id: "content-manager.preview.panel.button",
|
4085
|
+
defaultMessage: "Open preview"
|
4086
|
+
})
|
4087
|
+
}
|
4088
|
+
)
|
4089
|
+
}
|
4090
|
+
) })
|
4091
|
+
};
|
4092
|
+
};
|
4093
|
+
const FEATURE_ID = "preview";
|
4094
|
+
const previewAdmin = {
|
4095
|
+
bootstrap(app) {
|
4096
|
+
if (!window.strapi.future.isEnabled(FEATURE_ID)) {
|
4097
|
+
return;
|
4098
|
+
}
|
4099
|
+
const contentManagerPluginApis = app.getPlugin("content-manager").apis;
|
4100
|
+
contentManagerPluginApis.addEditViewSidePanel([PreviewSidePanel]);
|
4101
|
+
}
|
4102
|
+
};
|
3832
4103
|
const index = {
|
3833
4104
|
register(app) {
|
3834
4105
|
const cm = new ContentManagerPlugin();
|
@@ -3848,7 +4119,7 @@ const index = {
|
|
3848
4119
|
app.router.addRoute({
|
3849
4120
|
path: "content-manager/*",
|
3850
4121
|
lazy: async () => {
|
3851
|
-
const { Layout } = await import("./layout-
|
4122
|
+
const { Layout } = await import("./layout-2Si0j0jO.mjs");
|
3852
4123
|
return {
|
3853
4124
|
Component: Layout
|
3854
4125
|
};
|
@@ -3861,11 +4132,14 @@ const index = {
|
|
3861
4132
|
if (typeof historyAdmin.bootstrap === "function") {
|
3862
4133
|
historyAdmin.bootstrap(app);
|
3863
4134
|
}
|
4135
|
+
if (typeof previewAdmin.bootstrap === "function") {
|
4136
|
+
previewAdmin.bootstrap(app);
|
4137
|
+
}
|
3864
4138
|
},
|
3865
4139
|
async registerTrads({ locales }) {
|
3866
4140
|
const importedTrads = await Promise.all(
|
3867
4141
|
locales.map((locale) => {
|
3868
|
-
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-
|
4142
|
+
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-Dtk_ot79.mjs"), "./translations/es.json": () => import("./es-D34tqjMw.mjs"), "./translations/eu.json": () => import("./eu-CdALomew.mjs"), "./translations/fr.json": () => import("./fr--pg5jUbt.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-BHqhDq4V.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 }) => {
|
3869
4143
|
return {
|
3870
4144
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3871
4145
|
locale
|
@@ -3886,13 +4160,16 @@ export {
|
|
3886
4160
|
BulkActionsRenderer as B,
|
3887
4161
|
COLLECTION_TYPES as C,
|
3888
4162
|
DocumentStatus as D,
|
3889
|
-
|
3890
|
-
|
3891
|
-
|
4163
|
+
extractContentTypeComponents as E,
|
4164
|
+
DEFAULT_SETTINGS as F,
|
4165
|
+
convertEditLayoutToFieldLayouts as G,
|
3892
4166
|
HOOKS as H,
|
3893
4167
|
InjectionZone as I,
|
3894
|
-
|
3895
|
-
|
4168
|
+
useDocument as J,
|
4169
|
+
useGetPreviewUrlQuery as K,
|
4170
|
+
index as L,
|
4171
|
+
useContentManagerContext as M,
|
4172
|
+
useDocumentActions as N,
|
3896
4173
|
Panels as P,
|
3897
4174
|
RelativeTime as R,
|
3898
4175
|
SINGLE_TYPES as S,
|
@@ -3910,18 +4187,18 @@ export {
|
|
3910
4187
|
PERMISSIONS as k,
|
3911
4188
|
DocumentRBAC as l,
|
3912
4189
|
DOCUMENT_META_FIELDS as m,
|
3913
|
-
|
3914
|
-
|
3915
|
-
|
3916
|
-
|
3917
|
-
|
4190
|
+
CLONE_PATH as n,
|
4191
|
+
useDocLayout as o,
|
4192
|
+
useGetContentTypeConfigurationQuery as p,
|
4193
|
+
CREATOR_FIELDS as q,
|
4194
|
+
getMainField as r,
|
3918
4195
|
setInitialData as s,
|
3919
|
-
|
4196
|
+
getDisplayName as t,
|
3920
4197
|
useContentTypeSchema as u,
|
3921
|
-
|
3922
|
-
|
3923
|
-
|
3924
|
-
|
3925
|
-
|
4198
|
+
checkIfAttributeIsDisplayable as v,
|
4199
|
+
useGetAllDocumentsQuery as w,
|
4200
|
+
convertListLayoutToFieldLayouts as x,
|
4201
|
+
capitalise as y,
|
4202
|
+
useUpdateContentTypeConfigurationMutation as z
|
3926
4203
|
};
|
3927
|
-
//# sourceMappingURL=index-
|
4204
|
+
//# sourceMappingURL=index-BLPa8Dq-.mjs.map
|