@strapi/content-manager 0.0.0-experimental.d53e940834bf72ddc725f1d2fd36dac9abec30cb → 0.0.0-experimental.d65615a2b9130dd742d3c396674457d7971da928
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +18 -3
- package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js → ComponentConfigurationPage-CO977CPh.js} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-C-49MccQ.js.map → ComponentConfigurationPage-CO977CPh.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs → ComponentConfigurationPage-CQroR9Qk.mjs} +4 -4
- package/dist/_chunks/{ComponentConfigurationPage-DmwmiFQy.mjs.map → ComponentConfigurationPage-CQroR9Qk.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js → EditConfigurationPage-BPgoE-kf.js} +4 -4
- package/dist/_chunks/{EditConfigurationPage-DjFJw56M.js.map → EditConfigurationPage-BPgoE-kf.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs → EditConfigurationPage-tVCJ5vWC.mjs} +4 -4
- package/dist/_chunks/{EditConfigurationPage-JT3E7NZy.mjs.map → EditConfigurationPage-tVCJ5vWC.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-CPj61RMh.mjs → EditViewPage-8mOu02ji.mjs} +30 -9
- package/dist/_chunks/EditViewPage-8mOu02ji.mjs.map +1 -0
- package/dist/_chunks/{EditViewPage-zT3fBr4Y.js → EditViewPage-BMVgUNOX.js} +30 -9
- package/dist/_chunks/EditViewPage-BMVgUNOX.js.map +1 -0
- package/dist/_chunks/{Field-dha5VnIQ.mjs → Field-CJPYzwD7.mjs} +249 -152
- package/dist/_chunks/Field-CJPYzwD7.mjs.map +1 -0
- package/dist/_chunks/{Field-Boxf9Ajp.js → Field-CdSLKFQk.js} +251 -154
- package/dist/_chunks/Field-CdSLKFQk.js.map +1 -0
- package/dist/_chunks/{Form-DHrru2AV.mjs → Form-DJOJ-GF1.mjs} +36 -17
- package/dist/_chunks/Form-DJOJ-GF1.mjs.map +1 -0
- package/dist/_chunks/{Form-y5g1SRsh.js → Form-eP5bZwap.js} +36 -17
- package/dist/_chunks/Form-eP5bZwap.js.map +1 -0
- package/dist/_chunks/{History-CqN6K7SX.js → History-B-Mrquzu.js} +63 -25
- package/dist/_chunks/History-B-Mrquzu.js.map +1 -0
- package/dist/_chunks/{History-Bru_KoeP.mjs → History-MnQLtk1g.mjs} +64 -26
- package/dist/_chunks/History-MnQLtk1g.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-D8wGABj0.mjs → ListConfigurationPage-BcycI8Lw.mjs} +21 -9
- package/dist/_chunks/ListConfigurationPage-BcycI8Lw.mjs.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-R_p-SbHZ.js → ListConfigurationPage-C0n4rUzH.js} +21 -9
- package/dist/_chunks/ListConfigurationPage-C0n4rUzH.js.map +1 -0
- package/dist/_chunks/{ListViewPage-SID6TRb9.mjs → ListViewPage-CRXONXwZ.mjs} +59 -41
- package/dist/_chunks/ListViewPage-CRXONXwZ.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-pEw_zug9.js → ListViewPage-q0SHVPUS.js} +61 -43
- package/dist/_chunks/ListViewPage-q0SHVPUS.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js → NoContentTypePage-Bh3komDV.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-C5dcQojD.js.map → NoContentTypePage-Bh3komDV.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs → NoContentTypePage-ukzFRF3z.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CJ7UXwrQ.mjs.map → NoContentTypePage-ukzFRF3z.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs → NoPermissionsPage-B4sD7Ble.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B7syEq5E.mjs.map → NoPermissionsPage-B4sD7Ble.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js → NoPermissionsPage-BGBpj_Y1.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-BtPrImPP.js.map → NoPermissionsPage-BGBpj_Y1.js.map} +1 -1
- package/dist/_chunks/{Relations-DjTQ5kGB.js → Relations-B53wYe8g.js} +33 -24
- package/dist/_chunks/Relations-B53wYe8g.js.map +1 -0
- package/dist/_chunks/{Relations-B9Crnhnn.mjs → Relations-CIexb8gr.mjs} +33 -24
- package/dist/_chunks/Relations-CIexb8gr.mjs.map +1 -0
- package/dist/_chunks/{en-fbKQxLGn.js → en-Bm0D0IWz.js} +17 -15
- package/dist/_chunks/{en-fbKQxLGn.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-Ux26r5pl.mjs → en-DKV44jRb.mjs} +17 -15
- package/dist/_chunks/{en-Ux26r5pl.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-DJXJw9V5.mjs → index-CJ2vYwuT.mjs} +997 -690
- package/dist/_chunks/index-CJ2vYwuT.mjs.map +1 -0
- package/dist/_chunks/{index-DVPWZkbS.js → index-DbT2sx-Q.js} +978 -671
- package/dist/_chunks/index-DbT2sx-Q.js.map +1 -0
- package/dist/_chunks/{layout-Dm6fbiQj.js → layout-CeBSIkmP.js} +24 -11
- package/dist/_chunks/layout-CeBSIkmP.js.map +1 -0
- package/dist/_chunks/{layout-Bau7ZfLV.mjs → layout-vzKSrr7p.mjs} +25 -12
- package/dist/_chunks/layout-vzKSrr7p.mjs.map +1 -0
- package/dist/_chunks/{objects-gigeqt7s.js → objects-BcXOv6_9.js} +2 -4
- package/dist/_chunks/{objects-gigeqt7s.js.map → objects-BcXOv6_9.js.map} +1 -1
- package/dist/_chunks/{objects-mKMAmfec.mjs → objects-D6yBsdmx.mjs} +2 -4
- package/dist/_chunks/{objects-mKMAmfec.mjs.map → objects-D6yBsdmx.mjs.map} +1 -1
- package/dist/_chunks/{relations-CKnpRgrN.js → relations-Cl-6t9iz.js} +2 -2
- package/dist/_chunks/{relations-CKnpRgrN.js.map → relations-Cl-6t9iz.js.map} +1 -1
- package/dist/_chunks/{relations-BH_kBSJ0.mjs → relations-DI0lguF0.mjs} +2 -2
- package/dist/_chunks/{relations-BH_kBSJ0.mjs.map → relations-DI0lguF0.mjs.map} +1 -1
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/index.d.ts +3 -0
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +32 -1
- package/dist/admin/src/index.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/DocumentActions.d.ts +1 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Relations.d.ts +20 -0
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/EditorLayout.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygFooter.d.ts +2 -2
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +4 -48
- package/dist/admin/src/pages/EditView/components/Header.d.ts +11 -11
- package/dist/admin/src/services/api.d.ts +1 -1
- package/dist/admin/src/services/components.d.ts +2 -2
- package/dist/admin/src/services/contentTypes.d.ts +3 -3
- package/dist/admin/src/services/documents.d.ts +19 -17
- package/dist/admin/src/services/init.d.ts +1 -1
- package/dist/admin/src/services/relations.d.ts +2 -2
- package/dist/admin/src/services/uid.d.ts +3 -3
- package/dist/admin/src/utils/validation.d.ts +4 -1
- package/dist/server/index.js +207 -120
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +208 -121
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/controllers/collection-types.d.ts.map +1 -1
- package/dist/server/src/controllers/relations.d.ts.map +1 -1
- package/dist/server/src/controllers/uid.d.ts.map +1 -1
- package/dist/server/src/controllers/validation/dimensions.d.ts +4 -2
- package/dist/server/src/controllers/validation/dimensions.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +2 -1
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-manager.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/populate.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/_chunks/EditViewPage-CPj61RMh.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-zT3fBr4Y.js.map +0 -1
- package/dist/_chunks/Field-Boxf9Ajp.js.map +0 -1
- package/dist/_chunks/Field-dha5VnIQ.mjs.map +0 -1
- package/dist/_chunks/Form-DHrru2AV.mjs.map +0 -1
- package/dist/_chunks/Form-y5g1SRsh.js.map +0 -1
- package/dist/_chunks/History-Bru_KoeP.mjs.map +0 -1
- package/dist/_chunks/History-CqN6K7SX.js.map +0 -1
- package/dist/_chunks/ListConfigurationPage-D8wGABj0.mjs.map +0 -1
- package/dist/_chunks/ListConfigurationPage-R_p-SbHZ.js.map +0 -1
- package/dist/_chunks/ListViewPage-SID6TRb9.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-pEw_zug9.js.map +0 -1
- package/dist/_chunks/Relations-B9Crnhnn.mjs.map +0 -1
- package/dist/_chunks/Relations-DjTQ5kGB.js.map +0 -1
- package/dist/_chunks/index-DJXJw9V5.mjs.map +0 -1
- package/dist/_chunks/index-DVPWZkbS.js.map +0 -1
- package/dist/_chunks/layout-Bau7ZfLV.mjs.map +0 -1
- package/dist/_chunks/layout-Dm6fbiQj.js.map +0 -1
- package/dist/_chunks/usePrev-B9w_-eYc.js.map +0 -1
- package/dist/_chunks/usePrev-DH6iah0A.mjs +0 -16
- package/dist/_chunks/usePrev-DH6iah0A.mjs.map +0 -1
- package/strapi-server.js +0 -3
@@ -2,15 +2,15 @@
|
|
2
2
|
const Icons = require("@strapi/icons");
|
3
3
|
const jsxRuntime = require("react/jsx-runtime");
|
4
4
|
const strapiAdmin = require("@strapi/admin/strapi-admin");
|
5
|
-
const qs = require("qs");
|
6
|
-
const reactIntl = require("react-intl");
|
7
|
-
const reactRouterDom = require("react-router-dom");
|
8
5
|
const React = require("react");
|
9
6
|
const designSystem = require("@strapi/design-system");
|
10
|
-
const
|
7
|
+
const reactIntl = require("react-intl");
|
8
|
+
const reactRouterDom = require("react-router-dom");
|
11
9
|
const yup = require("yup");
|
12
10
|
const pipe = require("lodash/fp/pipe");
|
13
11
|
const dateFns = require("date-fns");
|
12
|
+
const styledComponents = require("styled-components");
|
13
|
+
const qs = require("qs");
|
14
14
|
const toolkit = require("@reduxjs/toolkit");
|
15
15
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
16
16
|
function _interopNamespace(e) {
|
@@ -70,42 +70,6 @@ const useInjectionZone = (area) => {
|
|
70
70
|
const [page, position] = area.split(".");
|
71
71
|
return contentManagerPlugin.getInjectedComponents(page, position);
|
72
72
|
};
|
73
|
-
const HistoryAction = ({ model, document }) => {
|
74
|
-
const { formatMessage } = reactIntl.useIntl();
|
75
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
76
|
-
const navigate = reactRouterDom.useNavigate();
|
77
|
-
const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
|
78
|
-
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
79
|
-
return null;
|
80
|
-
}
|
81
|
-
return {
|
82
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
|
83
|
-
label: formatMessage({
|
84
|
-
id: "content-manager.history.document-action",
|
85
|
-
defaultMessage: "Content History"
|
86
|
-
}),
|
87
|
-
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
88
|
-
disabled: (
|
89
|
-
/**
|
90
|
-
* The user is creating a new document.
|
91
|
-
* It hasn't been saved yet, so there's no history to go to
|
92
|
-
*/
|
93
|
-
!document || /**
|
94
|
-
* The document has been created but the current dimension has never been saved.
|
95
|
-
* For example, the user is creating a new locale in an existing document,
|
96
|
-
* so there's no history for the document in that locale
|
97
|
-
*/
|
98
|
-
!document.id || /**
|
99
|
-
* History is only available for content types created by the user.
|
100
|
-
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
101
|
-
* which start with `admin::` or `plugin::`
|
102
|
-
*/
|
103
|
-
!model.startsWith("api::")
|
104
|
-
),
|
105
|
-
position: "header"
|
106
|
-
};
|
107
|
-
};
|
108
|
-
HistoryAction.type = "history";
|
109
73
|
const ID = "id";
|
110
74
|
const CREATED_BY_ATTRIBUTE_NAME = "createdBy";
|
111
75
|
const UPDATED_BY_ATTRIBUTE_NAME = "updatedBy";
|
@@ -157,6 +121,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
157
121
|
if (!slug) {
|
158
122
|
throw new Error("Cannot find the slug param in the URL");
|
159
123
|
}
|
124
|
+
const [{ rawQuery }] = strapiAdmin.useQueryParams();
|
160
125
|
const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
|
161
126
|
const contentTypePermissions = React__namespace.useMemo(() => {
|
162
127
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -167,7 +132,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
167
132
|
return { ...acc, [action]: [permission] };
|
168
133
|
}, {});
|
169
134
|
}, [slug, userPermissions]);
|
170
|
-
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
135
|
+
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
136
|
+
contentTypePermissions,
|
137
|
+
permissions ?? void 0,
|
138
|
+
// TODO: useRBAC context should be typed and built differently
|
139
|
+
// We are passing raw query as context to the hook so that it can
|
140
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
141
|
+
rawQuery
|
142
|
+
);
|
171
143
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
172
144
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
173
145
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -215,7 +187,8 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
215
187
|
"Document",
|
216
188
|
"InitialData",
|
217
189
|
"HistoryVersion",
|
218
|
-
"Relations"
|
190
|
+
"Relations",
|
191
|
+
"UidAvailability"
|
219
192
|
]
|
220
193
|
});
|
221
194
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -229,7 +202,12 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
229
202
|
params: query
|
230
203
|
}
|
231
204
|
}),
|
232
|
-
invalidatesTags: (_result,
|
205
|
+
invalidatesTags: (_result, error, { model }) => {
|
206
|
+
if (error) {
|
207
|
+
return [];
|
208
|
+
}
|
209
|
+
return [{ type: "Document", id: `${model}_LIST` }];
|
210
|
+
}
|
233
211
|
}),
|
234
212
|
cloneDocument: builder.mutation({
|
235
213
|
query: ({ model, sourceId, data, params }) => ({
|
@@ -240,7 +218,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
240
218
|
params
|
241
219
|
}
|
242
220
|
}),
|
243
|
-
invalidatesTags: (_result, _error, { model }) => [
|
221
|
+
invalidatesTags: (_result, _error, { model }) => [
|
222
|
+
{ type: "Document", id: `${model}_LIST` },
|
223
|
+
{ type: "UidAvailability", id: model }
|
224
|
+
]
|
244
225
|
}),
|
245
226
|
/**
|
246
227
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -257,7 +238,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
257
238
|
}),
|
258
239
|
invalidatesTags: (result, _error, { model }) => [
|
259
240
|
{ type: "Document", id: `${model}_LIST` },
|
260
|
-
"Relations"
|
241
|
+
"Relations",
|
242
|
+
{ type: "UidAvailability", id: model }
|
261
243
|
]
|
262
244
|
}),
|
263
245
|
deleteDocument: builder.mutation({
|
@@ -298,7 +280,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
298
280
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
299
281
|
},
|
300
282
|
{ type: "Document", id: `${model}_LIST` },
|
301
|
-
"Relations"
|
283
|
+
"Relations",
|
284
|
+
{ type: "UidAvailability", id: model }
|
302
285
|
];
|
303
286
|
}
|
304
287
|
}),
|
@@ -316,6 +299,7 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
316
299
|
}),
|
317
300
|
providesTags: (result, _error, arg) => {
|
318
301
|
return [
|
302
|
+
{ type: "Document", id: `ALL_LIST` },
|
319
303
|
{ type: "Document", id: `${arg.model}_LIST` },
|
320
304
|
...result?.results.map(({ documentId }) => ({
|
321
305
|
type: "Document",
|
@@ -354,6 +338,11 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
354
338
|
{
|
355
339
|
type: "Document",
|
356
340
|
id: collectionType !== SINGLE_TYPES ? `${model}_${result && "documentId" in result ? result.documentId : documentId}` : model
|
341
|
+
},
|
342
|
+
// Make it easy to invalidate all individual documents queries for a model
|
343
|
+
{
|
344
|
+
type: "Document",
|
345
|
+
id: `${model}_ALL_ITEMS`
|
357
346
|
}
|
358
347
|
];
|
359
348
|
}
|
@@ -417,8 +406,21 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
417
406
|
type: "Document",
|
418
407
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
419
408
|
},
|
420
|
-
"Relations"
|
409
|
+
"Relations",
|
410
|
+
{ type: "UidAvailability", id: model }
|
421
411
|
];
|
412
|
+
},
|
413
|
+
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
414
|
+
const patchResult = dispatch(
|
415
|
+
documentApi.util.updateQueryData("getDocument", patch, (draft) => {
|
416
|
+
Object.assign(draft.data, data);
|
417
|
+
})
|
418
|
+
);
|
419
|
+
try {
|
420
|
+
await queryFulfilled;
|
421
|
+
} catch {
|
422
|
+
patchResult.undo();
|
423
|
+
}
|
422
424
|
}
|
423
425
|
}),
|
424
426
|
unpublishDocument: builder.mutation({
|
@@ -488,20 +490,39 @@ const buildValidParams = (query) => {
|
|
488
490
|
const isBaseQueryError = (error) => {
|
489
491
|
return error.name !== void 0;
|
490
492
|
};
|
491
|
-
const
|
493
|
+
const arrayValidator = (attribute, options) => ({
|
494
|
+
message: strapiAdmin.translatedErrors.required,
|
495
|
+
test(value) {
|
496
|
+
if (options.status === "draft") {
|
497
|
+
return true;
|
498
|
+
}
|
499
|
+
if (!attribute.required) {
|
500
|
+
return true;
|
501
|
+
}
|
502
|
+
if (!value) {
|
503
|
+
return false;
|
504
|
+
}
|
505
|
+
if (Array.isArray(value) && value.length === 0) {
|
506
|
+
return false;
|
507
|
+
}
|
508
|
+
return true;
|
509
|
+
}
|
510
|
+
});
|
511
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
492
512
|
const createModelSchema = (attributes2) => yup__namespace.object().shape(
|
493
513
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
494
514
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
495
515
|
return acc;
|
496
516
|
}
|
497
517
|
const validations = [
|
518
|
+
addNullableValidation,
|
498
519
|
addRequiredValidation,
|
499
520
|
addMinLengthValidation,
|
500
521
|
addMaxLengthValidation,
|
501
522
|
addMinValidation,
|
502
523
|
addMaxValidation,
|
503
524
|
addRegexValidation
|
504
|
-
].map((fn) => fn(attribute));
|
525
|
+
].map((fn) => fn(attribute, options));
|
505
526
|
const transformSchema = pipe__default.default(...validations);
|
506
527
|
switch (attribute.type) {
|
507
528
|
case "component": {
|
@@ -511,12 +532,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
511
532
|
...acc,
|
512
533
|
[name]: transformSchema(
|
513
534
|
yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
|
514
|
-
)
|
535
|
+
).test(arrayValidator(attribute, options))
|
515
536
|
};
|
516
537
|
} else {
|
517
538
|
return {
|
518
539
|
...acc,
|
519
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
540
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
520
541
|
};
|
521
542
|
}
|
522
543
|
}
|
@@ -538,7 +559,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
538
559
|
}
|
539
560
|
)
|
540
561
|
)
|
541
|
-
)
|
562
|
+
).test(arrayValidator(attribute, options))
|
542
563
|
};
|
543
564
|
case "relation":
|
544
565
|
return {
|
@@ -550,7 +571,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
550
571
|
} else if (Array.isArray(value)) {
|
551
572
|
return yup__namespace.array().of(
|
552
573
|
yup__namespace.object().shape({
|
553
|
-
id: yup__namespace.
|
574
|
+
id: yup__namespace.number().required()
|
554
575
|
})
|
555
576
|
);
|
556
577
|
} else if (typeof value === "object") {
|
@@ -602,6 +623,14 @@ const createAttributeSchema = (attribute) => {
|
|
602
623
|
if (!value || typeof value === "string" && value.length === 0) {
|
603
624
|
return true;
|
604
625
|
}
|
626
|
+
if (typeof value === "object") {
|
627
|
+
try {
|
628
|
+
JSON.stringify(value);
|
629
|
+
return true;
|
630
|
+
} catch (err) {
|
631
|
+
return false;
|
632
|
+
}
|
633
|
+
}
|
605
634
|
try {
|
606
635
|
JSON.parse(value);
|
607
636
|
return true;
|
@@ -620,13 +649,7 @@ const createAttributeSchema = (attribute) => {
|
|
620
649
|
return yup__namespace.mixed();
|
621
650
|
}
|
622
651
|
};
|
623
|
-
const
|
624
|
-
if (attribute.required) {
|
625
|
-
return schema.required({
|
626
|
-
id: strapiAdmin.translatedErrors.required.id,
|
627
|
-
defaultMessage: "This field is required."
|
628
|
-
});
|
629
|
-
}
|
652
|
+
const nullableSchema = (schema) => {
|
630
653
|
return schema?.nullable ? schema.nullable() : (
|
631
654
|
// In some cases '.nullable' will not be available on the schema.
|
632
655
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -634,7 +657,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
634
657
|
schema
|
635
658
|
);
|
636
659
|
};
|
637
|
-
const
|
660
|
+
const addNullableValidation = () => (schema) => {
|
661
|
+
return nullableSchema(schema);
|
662
|
+
};
|
663
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
664
|
+
if (options.status === "draft" || !attribute.required) {
|
665
|
+
return schema;
|
666
|
+
}
|
667
|
+
if (attribute.required && "required" in schema) {
|
668
|
+
return schema.required(strapiAdmin.translatedErrors.required);
|
669
|
+
}
|
670
|
+
return schema;
|
671
|
+
};
|
672
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
673
|
+
if (options.status === "draft") {
|
674
|
+
return schema;
|
675
|
+
}
|
638
676
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
639
677
|
return schema.min(attribute.minLength, {
|
640
678
|
...strapiAdmin.translatedErrors.minLength,
|
@@ -656,10 +694,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
656
694
|
}
|
657
695
|
return schema;
|
658
696
|
};
|
659
|
-
const addMinValidation = (attribute) => (schema) => {
|
660
|
-
if ("
|
697
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
698
|
+
if (options.status === "draft") {
|
699
|
+
return schema;
|
700
|
+
}
|
701
|
+
if ("min" in attribute && "min" in schema) {
|
661
702
|
const min = toInteger(attribute.min);
|
662
|
-
if (
|
703
|
+
if (min) {
|
663
704
|
return schema.min(min, {
|
664
705
|
...strapiAdmin.translatedErrors.min,
|
665
706
|
values: {
|
@@ -777,16 +818,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
777
818
|
}, {});
|
778
819
|
return componentsByKey;
|
779
820
|
};
|
780
|
-
const
|
821
|
+
const HOOKS = {
|
822
|
+
/**
|
823
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
824
|
+
* @constant
|
825
|
+
* @type {string}
|
826
|
+
*/
|
827
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
828
|
+
/**
|
829
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
830
|
+
* @constant
|
831
|
+
* @type {string}
|
832
|
+
*/
|
833
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
834
|
+
/**
|
835
|
+
* Hook that allows to mutate the CM's edit view layout
|
836
|
+
* @constant
|
837
|
+
* @type {string}
|
838
|
+
*/
|
839
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
840
|
+
/**
|
841
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
842
|
+
* @constant
|
843
|
+
* @type {string}
|
844
|
+
*/
|
845
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
846
|
+
};
|
847
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
848
|
+
endpoints: (builder) => ({
|
849
|
+
getContentTypeConfiguration: builder.query({
|
850
|
+
query: (uid) => ({
|
851
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
852
|
+
method: "GET"
|
853
|
+
}),
|
854
|
+
transformResponse: (response) => response.data,
|
855
|
+
providesTags: (_result, _error, uid) => [
|
856
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
857
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
858
|
+
]
|
859
|
+
}),
|
860
|
+
getAllContentTypeSettings: builder.query({
|
861
|
+
query: () => "/content-manager/content-types-settings",
|
862
|
+
transformResponse: (response) => response.data,
|
863
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
864
|
+
}),
|
865
|
+
updateContentTypeConfiguration: builder.mutation({
|
866
|
+
query: ({ uid, ...body }) => ({
|
867
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
868
|
+
method: "PUT",
|
869
|
+
data: body
|
870
|
+
}),
|
871
|
+
transformResponse: (response) => response.data,
|
872
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
873
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
874
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
875
|
+
// Is this necessary?
|
876
|
+
{ type: "InitialData" }
|
877
|
+
]
|
878
|
+
})
|
879
|
+
})
|
880
|
+
});
|
881
|
+
const {
|
882
|
+
useGetContentTypeConfigurationQuery,
|
883
|
+
useGetAllContentTypeSettingsQuery,
|
884
|
+
useUpdateContentTypeConfigurationMutation
|
885
|
+
} = contentTypesApi;
|
886
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
887
|
+
const { type } = attribute;
|
888
|
+
if (type === "relation") {
|
889
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
890
|
+
}
|
891
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
892
|
+
};
|
893
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
894
|
+
if (!mainFieldName) {
|
895
|
+
return void 0;
|
896
|
+
}
|
897
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
898
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
899
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
900
|
+
);
|
901
|
+
return {
|
902
|
+
name: mainFieldName,
|
903
|
+
type: mainFieldType ?? "string"
|
904
|
+
};
|
905
|
+
};
|
906
|
+
const DEFAULT_SETTINGS = {
|
907
|
+
bulkable: false,
|
908
|
+
filterable: false,
|
909
|
+
searchable: false,
|
910
|
+
pagination: false,
|
911
|
+
defaultSortBy: "",
|
912
|
+
defaultSortOrder: "asc",
|
913
|
+
mainField: "id",
|
914
|
+
pageSize: 10
|
915
|
+
};
|
916
|
+
const useDocumentLayout = (model) => {
|
917
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
918
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
919
|
+
const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
781
920
|
const { toggleNotification } = strapiAdmin.useNotification();
|
782
921
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
922
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
783
923
|
const {
|
784
|
-
|
785
|
-
isLoading:
|
786
|
-
|
787
|
-
|
788
|
-
} =
|
789
|
-
const
|
924
|
+
data,
|
925
|
+
isLoading: isLoadingConfigs,
|
926
|
+
error,
|
927
|
+
isFetching: isFetchingConfigs
|
928
|
+
} = useGetContentTypeConfigurationQuery(model);
|
929
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
790
930
|
React__namespace.useEffect(() => {
|
791
931
|
if (error) {
|
792
932
|
toggleNotification({
|
@@ -794,68 +934,321 @@ const useDocument = (args, opts) => {
|
|
794
934
|
message: formatAPIError(error)
|
795
935
|
});
|
796
936
|
}
|
797
|
-
}, [
|
798
|
-
const
|
799
|
-
|
800
|
-
|
801
|
-
|
802
|
-
|
803
|
-
|
804
|
-
|
805
|
-
(document) => {
|
806
|
-
if (!validationSchema) {
|
807
|
-
throw new Error(
|
808
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
809
|
-
);
|
810
|
-
}
|
811
|
-
try {
|
812
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
813
|
-
return null;
|
814
|
-
} catch (error2) {
|
815
|
-
if (error2 instanceof yup.ValidationError) {
|
816
|
-
return strapiAdmin.getYupValidationErrors(error2);
|
817
|
-
}
|
818
|
-
throw error2;
|
819
|
-
}
|
937
|
+
}, [error, formatAPIError, toggleNotification]);
|
938
|
+
const editLayout = React__namespace.useMemo(
|
939
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
940
|
+
layout: [],
|
941
|
+
components: {},
|
942
|
+
metadatas: {},
|
943
|
+
options: {},
|
944
|
+
settings: DEFAULT_SETTINGS
|
820
945
|
},
|
821
|
-
[
|
946
|
+
[data, isLoading, schemas, schema, components]
|
947
|
+
);
|
948
|
+
const listLayout = React__namespace.useMemo(() => {
|
949
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
950
|
+
layout: [],
|
951
|
+
metadatas: {},
|
952
|
+
options: {},
|
953
|
+
settings: DEFAULT_SETTINGS
|
954
|
+
};
|
955
|
+
}, [data, isLoading, schemas, schema, components]);
|
956
|
+
const { layout: edit } = React__namespace.useMemo(
|
957
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
958
|
+
layout: editLayout,
|
959
|
+
query
|
960
|
+
}),
|
961
|
+
[editLayout, query, runHookWaterfall]
|
822
962
|
);
|
823
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
824
963
|
return {
|
825
|
-
|
826
|
-
document: data?.data,
|
827
|
-
meta: data?.meta,
|
964
|
+
error,
|
828
965
|
isLoading,
|
829
|
-
|
830
|
-
|
966
|
+
edit,
|
967
|
+
list: listLayout
|
831
968
|
};
|
832
969
|
};
|
833
|
-
const
|
834
|
-
const {
|
835
|
-
|
836
|
-
|
837
|
-
|
838
|
-
|
839
|
-
|
840
|
-
|
970
|
+
const useDocLayout = () => {
|
971
|
+
const { model } = useDoc();
|
972
|
+
return useDocumentLayout(model);
|
973
|
+
};
|
974
|
+
const formatEditLayout = (data, {
|
975
|
+
schemas,
|
976
|
+
schema,
|
977
|
+
components
|
978
|
+
}) => {
|
979
|
+
let currentPanelIndex = 0;
|
980
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
981
|
+
data.contentType.layouts.edit,
|
982
|
+
schema?.attributes,
|
983
|
+
data.contentType.metadatas,
|
984
|
+
{ configurations: data.components, schemas: components },
|
985
|
+
schemas
|
986
|
+
).reduce((panels, row) => {
|
987
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
988
|
+
panels.push([row]);
|
989
|
+
currentPanelIndex += 2;
|
990
|
+
} else {
|
991
|
+
if (!panels[currentPanelIndex]) {
|
992
|
+
panels.push([]);
|
993
|
+
}
|
994
|
+
panels[currentPanelIndex].push(row);
|
995
|
+
}
|
996
|
+
return panels;
|
997
|
+
}, []);
|
998
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
999
|
+
(acc, [uid, configuration]) => {
|
1000
|
+
acc[uid] = {
|
1001
|
+
layout: convertEditLayoutToFieldLayouts(
|
1002
|
+
configuration.layouts.edit,
|
1003
|
+
components[uid].attributes,
|
1004
|
+
configuration.metadatas,
|
1005
|
+
{ configurations: data.components, schemas: components }
|
1006
|
+
),
|
1007
|
+
settings: {
|
1008
|
+
...configuration.settings,
|
1009
|
+
icon: components[uid].info.icon,
|
1010
|
+
displayName: components[uid].info.displayName
|
1011
|
+
}
|
1012
|
+
};
|
1013
|
+
return acc;
|
1014
|
+
},
|
1015
|
+
{}
|
1016
|
+
);
|
1017
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1018
|
+
(acc, [attribute, metadata]) => {
|
1019
|
+
return {
|
1020
|
+
...acc,
|
1021
|
+
[attribute]: metadata.edit
|
1022
|
+
};
|
1023
|
+
},
|
1024
|
+
{}
|
1025
|
+
);
|
1026
|
+
return {
|
1027
|
+
layout: panelledEditAttributes,
|
1028
|
+
components: componentEditAttributes,
|
1029
|
+
metadatas: editMetadatas,
|
1030
|
+
settings: {
|
1031
|
+
...data.contentType.settings,
|
1032
|
+
displayName: schema?.info.displayName
|
1033
|
+
},
|
1034
|
+
options: {
|
1035
|
+
...schema?.options,
|
1036
|
+
...schema?.pluginOptions,
|
1037
|
+
...data.contentType.options
|
1038
|
+
}
|
1039
|
+
};
|
1040
|
+
};
|
1041
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1042
|
+
return rows.map(
|
1043
|
+
(row) => row.map((field) => {
|
1044
|
+
const attribute = attributes[field.name];
|
1045
|
+
if (!attribute) {
|
1046
|
+
return null;
|
1047
|
+
}
|
1048
|
+
const { edit: metadata } = metadatas[field.name];
|
1049
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1050
|
+
return {
|
1051
|
+
attribute,
|
1052
|
+
disabled: !metadata.editable,
|
1053
|
+
hint: metadata.description,
|
1054
|
+
label: metadata.label ?? "",
|
1055
|
+
name: field.name,
|
1056
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1057
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1058
|
+
schemas,
|
1059
|
+
components: components?.schemas ?? {}
|
1060
|
+
}),
|
1061
|
+
placeholder: metadata.placeholder ?? "",
|
1062
|
+
required: attribute.required ?? false,
|
1063
|
+
size: field.size,
|
1064
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1065
|
+
visible: metadata.visible ?? true,
|
1066
|
+
type: attribute.type
|
1067
|
+
};
|
1068
|
+
}).filter((field) => field !== null)
|
1069
|
+
);
|
1070
|
+
};
|
1071
|
+
const formatListLayout = (data, {
|
1072
|
+
schemas,
|
1073
|
+
schema,
|
1074
|
+
components
|
1075
|
+
}) => {
|
1076
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1077
|
+
(acc, [attribute, metadata]) => {
|
1078
|
+
return {
|
1079
|
+
...acc,
|
1080
|
+
[attribute]: metadata.list
|
1081
|
+
};
|
1082
|
+
},
|
1083
|
+
{}
|
1084
|
+
);
|
1085
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1086
|
+
data.contentType.layouts.list,
|
1087
|
+
schema?.attributes,
|
1088
|
+
listMetadatas,
|
1089
|
+
{ configurations: data.components, schemas: components },
|
1090
|
+
schemas
|
1091
|
+
);
|
1092
|
+
return {
|
1093
|
+
layout: listAttributes,
|
1094
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1095
|
+
metadatas: listMetadatas,
|
1096
|
+
options: {
|
1097
|
+
...schema?.options,
|
1098
|
+
...schema?.pluginOptions,
|
1099
|
+
...data.contentType.options
|
1100
|
+
}
|
1101
|
+
};
|
1102
|
+
};
|
1103
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1104
|
+
return columns.map((name) => {
|
1105
|
+
const attribute = attributes[name];
|
1106
|
+
if (!attribute) {
|
1107
|
+
return null;
|
1108
|
+
}
|
1109
|
+
const metadata = metadatas[name];
|
1110
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1111
|
+
return {
|
1112
|
+
attribute,
|
1113
|
+
label: metadata.label ?? "",
|
1114
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1115
|
+
schemas,
|
1116
|
+
components: components?.schemas ?? {}
|
1117
|
+
}),
|
1118
|
+
name,
|
1119
|
+
searchable: metadata.searchable ?? true,
|
1120
|
+
sortable: metadata.sortable ?? true
|
1121
|
+
};
|
1122
|
+
}).filter((field) => field !== null);
|
1123
|
+
};
|
1124
|
+
const useDocument = (args, opts) => {
|
1125
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
1126
|
+
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1127
|
+
const {
|
1128
|
+
currentData: data,
|
1129
|
+
isLoading: isLoadingDocument,
|
1130
|
+
isFetching: isFetchingDocument,
|
1131
|
+
error
|
1132
|
+
} = useGetDocumentQuery(args, {
|
1133
|
+
...opts,
|
1134
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1135
|
+
});
|
1136
|
+
const {
|
1137
|
+
components,
|
1138
|
+
schema,
|
1139
|
+
schemas,
|
1140
|
+
isLoading: isLoadingSchema
|
1141
|
+
} = useContentTypeSchema(args.model);
|
1142
|
+
React__namespace.useEffect(() => {
|
1143
|
+
if (error) {
|
1144
|
+
toggleNotification({
|
1145
|
+
type: "danger",
|
1146
|
+
message: formatAPIError(error)
|
1147
|
+
});
|
1148
|
+
}
|
1149
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1150
|
+
const validationSchema = React__namespace.useMemo(() => {
|
1151
|
+
if (!schema) {
|
1152
|
+
return null;
|
1153
|
+
}
|
1154
|
+
return createYupSchema(schema.attributes, components);
|
1155
|
+
}, [schema, components]);
|
1156
|
+
const validate = React__namespace.useCallback(
|
1157
|
+
(document) => {
|
1158
|
+
if (!validationSchema) {
|
1159
|
+
throw new Error(
|
1160
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1161
|
+
);
|
1162
|
+
}
|
1163
|
+
try {
|
1164
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1165
|
+
return null;
|
1166
|
+
} catch (error2) {
|
1167
|
+
if (error2 instanceof yup.ValidationError) {
|
1168
|
+
return strapiAdmin.getYupValidationErrors(error2);
|
1169
|
+
}
|
1170
|
+
throw error2;
|
1171
|
+
}
|
1172
|
+
},
|
1173
|
+
[validationSchema]
|
1174
|
+
);
|
1175
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1176
|
+
const hasError = !!error;
|
1177
|
+
return {
|
1178
|
+
components,
|
1179
|
+
document: data?.data,
|
1180
|
+
meta: data?.meta,
|
1181
|
+
isLoading,
|
1182
|
+
hasError,
|
1183
|
+
schema,
|
1184
|
+
schemas,
|
1185
|
+
validate
|
1186
|
+
};
|
1187
|
+
};
|
1188
|
+
const useDoc = () => {
|
1189
|
+
const { id, slug, collectionType, origin } = reactRouterDom.useParams();
|
1190
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
1191
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1192
|
+
if (!collectionType) {
|
1193
|
+
throw new Error("Could not find collectionType in url params");
|
1194
|
+
}
|
1195
|
+
if (!slug) {
|
841
1196
|
throw new Error("Could not find model in url params");
|
842
1197
|
}
|
1198
|
+
const document = useDocument(
|
1199
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1200
|
+
{
|
1201
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1202
|
+
}
|
1203
|
+
);
|
1204
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
843
1205
|
return {
|
844
1206
|
collectionType,
|
845
1207
|
model: slug,
|
846
|
-
id:
|
847
|
-
...
|
848
|
-
|
849
|
-
|
850
|
-
|
851
|
-
|
852
|
-
|
1208
|
+
id: returnId,
|
1209
|
+
...document
|
1210
|
+
};
|
1211
|
+
};
|
1212
|
+
const useContentManagerContext = () => {
|
1213
|
+
const {
|
1214
|
+
collectionType,
|
1215
|
+
model,
|
1216
|
+
id,
|
1217
|
+
components,
|
1218
|
+
isLoading: isLoadingDoc,
|
1219
|
+
schema,
|
1220
|
+
schemas
|
1221
|
+
} = useDoc();
|
1222
|
+
const layout = useDocumentLayout(model);
|
1223
|
+
const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
|
1224
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1225
|
+
const slug = model;
|
1226
|
+
const isCreatingEntry = id === "create";
|
1227
|
+
useContentTypeSchema();
|
1228
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1229
|
+
const error = layout.error;
|
1230
|
+
return {
|
1231
|
+
error,
|
1232
|
+
isLoading,
|
1233
|
+
// Base metadata
|
1234
|
+
model,
|
1235
|
+
collectionType,
|
1236
|
+
id,
|
1237
|
+
slug,
|
1238
|
+
isCreatingEntry,
|
1239
|
+
isSingleType,
|
1240
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1241
|
+
// All schema infos
|
1242
|
+
components,
|
1243
|
+
contentType: schema,
|
1244
|
+
contentTypes: schemas,
|
1245
|
+
// Form state
|
1246
|
+
form,
|
1247
|
+
// layout infos
|
1248
|
+
layout
|
853
1249
|
};
|
854
1250
|
};
|
855
1251
|
const prefixPluginTranslations = (trad, pluginId) => {
|
856
|
-
if (!pluginId) {
|
857
|
-
throw new TypeError("pluginId can't be empty");
|
858
|
-
}
|
859
1252
|
return Object.keys(trad).reduce((acc, current) => {
|
860
1253
|
acc[`${pluginId}.${current}`] = trad[current];
|
861
1254
|
return acc;
|
@@ -871,6 +1264,8 @@ const useDocumentActions = () => {
|
|
871
1264
|
const { formatMessage } = reactIntl.useIntl();
|
872
1265
|
const { trackUsage } = strapiAdmin.useTracking();
|
873
1266
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1267
|
+
const navigate = reactRouterDom.useNavigate();
|
1268
|
+
const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
874
1269
|
const [deleteDocument] = useDeleteDocumentMutation();
|
875
1270
|
const _delete = React__namespace.useCallback(
|
876
1271
|
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
@@ -1185,6 +1580,7 @@ const useDocumentActions = () => {
|
|
1185
1580
|
defaultMessage: "Saved document"
|
1186
1581
|
})
|
1187
1582
|
});
|
1583
|
+
setCurrentStep("contentManager.success");
|
1188
1584
|
return res.data;
|
1189
1585
|
} catch (err) {
|
1190
1586
|
toggleNotification({
|
@@ -1206,7 +1602,6 @@ const useDocumentActions = () => {
|
|
1206
1602
|
sourceId
|
1207
1603
|
});
|
1208
1604
|
if ("error" in res) {
|
1209
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1210
1605
|
return { error: res.error };
|
1211
1606
|
}
|
1212
1607
|
toggleNotification({
|
@@ -1225,7 +1620,7 @@ const useDocumentActions = () => {
|
|
1225
1620
|
throw err;
|
1226
1621
|
}
|
1227
1622
|
},
|
1228
|
-
[autoCloneDocument,
|
1623
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1229
1624
|
);
|
1230
1625
|
const [cloneDocument] = useCloneDocumentMutation();
|
1231
1626
|
const clone = React__namespace.useCallback(
|
@@ -1251,6 +1646,7 @@ const useDocumentActions = () => {
|
|
1251
1646
|
defaultMessage: "Cloned document"
|
1252
1647
|
})
|
1253
1648
|
});
|
1649
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1254
1650
|
return res.data;
|
1255
1651
|
} catch (err) {
|
1256
1652
|
toggleNotification({
|
@@ -1261,7 +1657,7 @@ const useDocumentActions = () => {
|
|
1261
1657
|
throw err;
|
1262
1658
|
}
|
1263
1659
|
},
|
1264
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1660
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1265
1661
|
);
|
1266
1662
|
const [getDoc] = useLazyGetDocumentQuery();
|
1267
1663
|
const getDocument = React__namespace.useCallback(
|
@@ -1287,7 +1683,7 @@ const useDocumentActions = () => {
|
|
1287
1683
|
};
|
1288
1684
|
};
|
1289
1685
|
const ProtectedHistoryPage = React.lazy(
|
1290
|
-
() => Promise.resolve().then(() => require("./History-
|
1686
|
+
() => Promise.resolve().then(() => require("./History-B-Mrquzu.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1291
1687
|
);
|
1292
1688
|
const routes$1 = [
|
1293
1689
|
{
|
@@ -1300,31 +1696,31 @@ const routes$1 = [
|
|
1300
1696
|
}
|
1301
1697
|
];
|
1302
1698
|
const ProtectedEditViewPage = React.lazy(
|
1303
|
-
() => Promise.resolve().then(() => require("./EditViewPage-
|
1699
|
+
() => Promise.resolve().then(() => require("./EditViewPage-BMVgUNOX.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1304
1700
|
);
|
1305
1701
|
const ProtectedListViewPage = React.lazy(
|
1306
|
-
() => Promise.resolve().then(() => require("./ListViewPage-
|
1702
|
+
() => Promise.resolve().then(() => require("./ListViewPage-q0SHVPUS.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1307
1703
|
);
|
1308
1704
|
const ProtectedListConfiguration = React.lazy(
|
1309
|
-
() => Promise.resolve().then(() => require("./ListConfigurationPage-
|
1705
|
+
() => Promise.resolve().then(() => require("./ListConfigurationPage-C0n4rUzH.js")).then((mod) => ({
|
1310
1706
|
default: mod.ProtectedListConfiguration
|
1311
1707
|
}))
|
1312
1708
|
);
|
1313
1709
|
const ProtectedEditConfigurationPage = React.lazy(
|
1314
|
-
() => Promise.resolve().then(() => require("./EditConfigurationPage-
|
1710
|
+
() => Promise.resolve().then(() => require("./EditConfigurationPage-BPgoE-kf.js")).then((mod) => ({
|
1315
1711
|
default: mod.ProtectedEditConfigurationPage
|
1316
1712
|
}))
|
1317
1713
|
);
|
1318
1714
|
const ProtectedComponentConfigurationPage = React.lazy(
|
1319
|
-
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-
|
1715
|
+
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-CO977CPh.js")).then((mod) => ({
|
1320
1716
|
default: mod.ProtectedComponentConfigurationPage
|
1321
1717
|
}))
|
1322
1718
|
);
|
1323
1719
|
const NoPermissions = React.lazy(
|
1324
|
-
() => Promise.resolve().then(() => require("./NoPermissionsPage-
|
1720
|
+
() => Promise.resolve().then(() => require("./NoPermissionsPage-BGBpj_Y1.js")).then((mod) => ({ default: mod.NoPermissions }))
|
1325
1721
|
);
|
1326
1722
|
const NoContentType = React.lazy(
|
1327
|
-
() => Promise.resolve().then(() => require("./NoContentTypePage-
|
1723
|
+
() => Promise.resolve().then(() => require("./NoContentTypePage-Bh3komDV.js")).then((mod) => ({ default: mod.NoContentType }))
|
1328
1724
|
);
|
1329
1725
|
const CollectionTypePages = () => {
|
1330
1726
|
const { collectionType } = reactRouterDom.useParams();
|
@@ -1438,12 +1834,14 @@ const DocumentActionButton = (action) => {
|
|
1438
1834
|
/* @__PURE__ */ jsxRuntime.jsx(
|
1439
1835
|
designSystem.Button,
|
1440
1836
|
{
|
1441
|
-
flex:
|
1837
|
+
flex: "auto",
|
1442
1838
|
startIcon: action.icon,
|
1443
1839
|
disabled: action.disabled,
|
1444
1840
|
onClick: handleClick(action),
|
1445
1841
|
justifyContent: "center",
|
1446
1842
|
variant: action.variant || "default",
|
1843
|
+
paddingTop: "7px",
|
1844
|
+
paddingBottom: "7px",
|
1447
1845
|
children: action.label
|
1448
1846
|
}
|
1449
1847
|
),
|
@@ -1451,7 +1849,7 @@ const DocumentActionButton = (action) => {
|
|
1451
1849
|
DocumentActionConfirmDialog,
|
1452
1850
|
{
|
1453
1851
|
...action.dialog,
|
1454
|
-
variant: action.variant,
|
1852
|
+
variant: action.dialog?.variant ?? action.variant,
|
1455
1853
|
isOpen: dialogId === action.id,
|
1456
1854
|
onClose: handleClose
|
1457
1855
|
}
|
@@ -1508,9 +1906,9 @@ const DocumentActionsMenu = ({
|
|
1508
1906
|
disabled: isDisabled,
|
1509
1907
|
size: "S",
|
1510
1908
|
endIcon: null,
|
1511
|
-
paddingTop: "
|
1512
|
-
paddingLeft: "
|
1513
|
-
paddingRight: "
|
1909
|
+
paddingTop: "4px",
|
1910
|
+
paddingLeft: "7px",
|
1911
|
+
paddingRight: "7px",
|
1514
1912
|
variant,
|
1515
1913
|
children: [
|
1516
1914
|
/* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
|
@@ -1521,7 +1919,7 @@ const DocumentActionsMenu = ({
|
|
1521
1919
|
]
|
1522
1920
|
}
|
1523
1921
|
),
|
1524
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, {
|
1922
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1525
1923
|
actions2.map((action) => {
|
1526
1924
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
1527
1925
|
designSystem.Menu.Item,
|
@@ -1530,10 +1928,25 @@ const DocumentActionsMenu = ({
|
|
1530
1928
|
onSelect: handleClick(action),
|
1531
1929
|
display: "block",
|
1532
1930
|
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
|
1533
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
1534
|
-
|
1535
|
-
|
1536
|
-
|
1931
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
1932
|
+
designSystem.Flex,
|
1933
|
+
{
|
1934
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1935
|
+
gap: 2,
|
1936
|
+
tag: "span",
|
1937
|
+
children: [
|
1938
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
1939
|
+
designSystem.Flex,
|
1940
|
+
{
|
1941
|
+
tag: "span",
|
1942
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1943
|
+
children: action.icon
|
1944
|
+
}
|
1945
|
+
),
|
1946
|
+
action.label
|
1947
|
+
]
|
1948
|
+
}
|
1949
|
+
),
|
1537
1950
|
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
|
1538
1951
|
designSystem.Flex,
|
1539
1952
|
{
|
@@ -1630,11 +2043,11 @@ const DocumentActionConfirmDialog = ({
|
|
1630
2043
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
1631
2044
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
|
1632
2045
|
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
|
1633
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
|
2046
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
1634
2047
|
id: "app.components.Button.cancel",
|
1635
2048
|
defaultMessage: "Cancel"
|
1636
2049
|
}) }) }),
|
1637
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
|
2050
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
1638
2051
|
id: "app.components.Button.confirm",
|
1639
2052
|
defaultMessage: "Confirm"
|
1640
2053
|
}) })
|
@@ -1673,13 +2086,17 @@ const PublishAction$1 = ({
|
|
1673
2086
|
const navigate = reactRouterDom.useNavigate();
|
1674
2087
|
const { toggleNotification } = strapiAdmin.useNotification();
|
1675
2088
|
const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
|
2089
|
+
const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
|
1676
2090
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
1677
2091
|
const { formatMessage } = reactIntl.useIntl();
|
1678
|
-
const { canPublish
|
1679
|
-
"PublishAction",
|
1680
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1681
|
-
);
|
2092
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
1682
2093
|
const { publish } = useDocumentActions();
|
2094
|
+
const [
|
2095
|
+
countDraftRelations,
|
2096
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2097
|
+
] = useLazyGetDraftRelationCountQuery();
|
2098
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
|
2099
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
|
1683
2100
|
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1684
2101
|
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1685
2102
|
const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
@@ -1688,62 +2105,144 @@ const PublishAction$1 = ({
|
|
1688
2105
|
const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
|
1689
2106
|
const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
|
1690
2107
|
const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
|
1691
|
-
|
1692
|
-
|
1693
|
-
|
1694
|
-
|
1695
|
-
|
1696
|
-
|
1697
|
-
|
1698
|
-
|
1699
|
-
|
1700
|
-
|
1701
|
-
|
2108
|
+
React__namespace.useEffect(() => {
|
2109
|
+
if (isErrorDraftRelations) {
|
2110
|
+
toggleNotification({
|
2111
|
+
type: "danger",
|
2112
|
+
message: formatMessage({
|
2113
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2114
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2115
|
+
})
|
2116
|
+
});
|
2117
|
+
}
|
2118
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2119
|
+
React__namespace.useEffect(() => {
|
2120
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2121
|
+
const extractDraftRelations = (data) => {
|
2122
|
+
const relations = data.connect || [];
|
2123
|
+
relations.forEach((relation) => {
|
2124
|
+
if (relation.status === "draft") {
|
2125
|
+
localDraftRelations.add(relation.id);
|
2126
|
+
}
|
2127
|
+
});
|
2128
|
+
};
|
2129
|
+
const traverseAndExtract = (data) => {
|
2130
|
+
Object.entries(data).forEach(([key, value]) => {
|
2131
|
+
if (key === "connect" && Array.isArray(value)) {
|
2132
|
+
extractDraftRelations({ connect: value });
|
2133
|
+
} else if (typeof value === "object" && value !== null) {
|
2134
|
+
traverseAndExtract(value);
|
2135
|
+
}
|
2136
|
+
});
|
2137
|
+
};
|
2138
|
+
if (!documentId || modified) {
|
2139
|
+
traverseAndExtract(formValues);
|
2140
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2141
|
+
}
|
2142
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2143
|
+
React__namespace.useEffect(() => {
|
2144
|
+
if (!document || !document.documentId || isListView) {
|
2145
|
+
return;
|
2146
|
+
}
|
2147
|
+
const fetchDraftRelationsCount = async () => {
|
2148
|
+
const { data, error } = await countDraftRelations({
|
2149
|
+
collectionType,
|
2150
|
+
model,
|
2151
|
+
documentId,
|
2152
|
+
params
|
2153
|
+
});
|
2154
|
+
if (error) {
|
2155
|
+
throw error;
|
2156
|
+
}
|
2157
|
+
if (data) {
|
2158
|
+
setServerCountOfDraftRelations(data.data);
|
2159
|
+
}
|
2160
|
+
};
|
2161
|
+
fetchDraftRelationsCount();
|
2162
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2163
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2164
|
+
if (!schema?.options?.draftAndPublish) {
|
2165
|
+
return null;
|
2166
|
+
}
|
2167
|
+
const performPublish = async () => {
|
2168
|
+
setSubmitting(true);
|
2169
|
+
try {
|
2170
|
+
const { errors } = await validate(true, {
|
2171
|
+
status: "published"
|
2172
|
+
});
|
2173
|
+
if (errors) {
|
2174
|
+
toggleNotification({
|
2175
|
+
type: "danger",
|
2176
|
+
message: formatMessage({
|
2177
|
+
id: "content-manager.validation.error",
|
2178
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2179
|
+
})
|
2180
|
+
});
|
2181
|
+
return;
|
2182
|
+
}
|
2183
|
+
const res = await publish(
|
2184
|
+
{
|
2185
|
+
collectionType,
|
2186
|
+
model,
|
2187
|
+
documentId,
|
2188
|
+
params
|
2189
|
+
},
|
2190
|
+
formValues
|
2191
|
+
);
|
2192
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2193
|
+
navigate({
|
2194
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2195
|
+
search: rawQuery
|
2196
|
+
});
|
2197
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2198
|
+
setErrors(formatValidationErrors(res.error));
|
2199
|
+
}
|
2200
|
+
} finally {
|
2201
|
+
setSubmitting(false);
|
2202
|
+
}
|
2203
|
+
};
|
2204
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2205
|
+
const enableDraftRelationsCount = false;
|
2206
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2207
|
+
return {
|
2208
|
+
/**
|
2209
|
+
* Disabled when:
|
2210
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2211
|
+
* - the form is submitting
|
2212
|
+
* - the active tab is the published tab
|
2213
|
+
* - the document is already published & not modified
|
1702
2214
|
* - the document is being created & not modified
|
1703
2215
|
* - the user doesn't have the permission to publish
|
1704
|
-
* - the user doesn't have the permission to create a new document
|
1705
|
-
* - the user doesn't have the permission to update the document
|
1706
2216
|
*/
|
1707
|
-
disabled: isCloning || isSubmitting || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish
|
2217
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1708
2218
|
label: formatMessage({
|
1709
2219
|
id: "app.utils.publish",
|
1710
2220
|
defaultMessage: "Publish"
|
1711
2221
|
}),
|
1712
2222
|
onClick: async () => {
|
1713
|
-
|
1714
|
-
|
1715
|
-
|
1716
|
-
|
1717
|
-
|
1718
|
-
|
1719
|
-
|
1720
|
-
|
1721
|
-
|
1722
|
-
|
1723
|
-
|
1724
|
-
|
1725
|
-
|
1726
|
-
|
1727
|
-
|
1728
|
-
|
1729
|
-
|
1730
|
-
documentId,
|
1731
|
-
params
|
1732
|
-
},
|
1733
|
-
formValues
|
1734
|
-
);
|
1735
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1736
|
-
navigate({
|
1737
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1738
|
-
search: rawQuery
|
1739
|
-
});
|
1740
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1741
|
-
setErrors(formatValidationErrors(res.error));
|
2223
|
+
await performPublish();
|
2224
|
+
},
|
2225
|
+
dialog: hasDraftRelations ? {
|
2226
|
+
type: "dialog",
|
2227
|
+
variant: "danger",
|
2228
|
+
footer: null,
|
2229
|
+
title: formatMessage({
|
2230
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2231
|
+
defaultMessage: "Confirmation"
|
2232
|
+
}),
|
2233
|
+
content: formatMessage(
|
2234
|
+
{
|
2235
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2236
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2237
|
+
},
|
2238
|
+
{
|
2239
|
+
count: totalDraftRelations
|
1742
2240
|
}
|
1743
|
-
|
1744
|
-
|
2241
|
+
),
|
2242
|
+
onConfirm: async () => {
|
2243
|
+
await performPublish();
|
1745
2244
|
}
|
1746
|
-
}
|
2245
|
+
} : void 0
|
1747
2246
|
};
|
1748
2247
|
};
|
1749
2248
|
PublishAction$1.type = "publish";
|
@@ -1759,10 +2258,6 @@ const UpdateAction = ({
|
|
1759
2258
|
const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
|
1760
2259
|
const isCloning = cloneMatch !== null;
|
1761
2260
|
const { formatMessage } = reactIntl.useIntl();
|
1762
|
-
const { canCreate, canUpdate } = useDocumentRBAC("UpdateAction", ({ canCreate: canCreate2, canUpdate: canUpdate2 }) => ({
|
1763
|
-
canCreate: canCreate2,
|
1764
|
-
canUpdate: canUpdate2
|
1765
|
-
}));
|
1766
2261
|
const { create, update, clone } = useDocumentActions();
|
1767
2262
|
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1768
2263
|
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
@@ -1779,10 +2274,8 @@ const UpdateAction = ({
|
|
1779
2274
|
* - the form is submitting
|
1780
2275
|
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1781
2276
|
* - the active tab is the published tab
|
1782
|
-
* - the user doesn't have the permission to create a new document
|
1783
|
-
* - the user doesn't have the permission to update the document
|
1784
2277
|
*/
|
1785
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published"
|
2278
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1786
2279
|
label: formatMessage({
|
1787
2280
|
id: "content-manager.containers.Edit.save",
|
1788
2281
|
defaultMessage: "Save"
|
@@ -1790,7 +2283,9 @@ const UpdateAction = ({
|
|
1790
2283
|
onClick: async () => {
|
1791
2284
|
setSubmitting(true);
|
1792
2285
|
try {
|
1793
|
-
const { errors } = await validate(
|
2286
|
+
const { errors } = await validate(true, {
|
2287
|
+
status: "draft"
|
2288
|
+
});
|
1794
2289
|
if (errors) {
|
1795
2290
|
toggleNotification({
|
1796
2291
|
type: "danger",
|
@@ -1811,10 +2306,13 @@ const UpdateAction = ({
|
|
1811
2306
|
document
|
1812
2307
|
);
|
1813
2308
|
if ("data" in res) {
|
1814
|
-
navigate(
|
1815
|
-
|
1816
|
-
|
1817
|
-
|
2309
|
+
navigate(
|
2310
|
+
{
|
2311
|
+
pathname: `../${res.data.documentId}`,
|
2312
|
+
search: rawQuery
|
2313
|
+
},
|
2314
|
+
{ relative: "path" }
|
2315
|
+
);
|
1818
2316
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1819
2317
|
setErrors(formatValidationErrors(res.error));
|
1820
2318
|
}
|
@@ -1842,10 +2340,13 @@ const UpdateAction = ({
|
|
1842
2340
|
document
|
1843
2341
|
);
|
1844
2342
|
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1845
|
-
navigate(
|
1846
|
-
|
1847
|
-
|
1848
|
-
|
2343
|
+
navigate(
|
2344
|
+
{
|
2345
|
+
pathname: `../${res.data.documentId}`,
|
2346
|
+
search: rawQuery
|
2347
|
+
},
|
2348
|
+
{ replace: true, relative: "path" }
|
2349
|
+
);
|
1849
2350
|
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1850
2351
|
setErrors(formatValidationErrors(res.error));
|
1851
2352
|
}
|
@@ -1889,7 +2390,7 @@ const UnpublishAction$1 = ({
|
|
1889
2390
|
id: "app.utils.unpublish",
|
1890
2391
|
defaultMessage: "Unpublish"
|
1891
2392
|
}),
|
1892
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
2393
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
1893
2394
|
onClick: async () => {
|
1894
2395
|
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
1895
2396
|
if (!documentId) {
|
@@ -2001,7 +2502,7 @@ const DiscardAction = ({
|
|
2001
2502
|
id: "content-manager.actions.discard.label",
|
2002
2503
|
defaultMessage: "Discard changes"
|
2003
2504
|
}),
|
2004
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(
|
2505
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
2005
2506
|
position: ["panel", "table-row"],
|
2006
2507
|
variant: "danger",
|
2007
2508
|
dialog: {
|
@@ -2029,11 +2530,6 @@ const DiscardAction = ({
|
|
2029
2530
|
};
|
2030
2531
|
};
|
2031
2532
|
DiscardAction.type = "discard";
|
2032
|
-
const StyledCrossCircle = styledComponents.styled(Icons.CrossCircle)`
|
2033
|
-
path {
|
2034
|
-
fill: currentColor;
|
2035
|
-
}
|
2036
|
-
`;
|
2037
2533
|
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2038
2534
|
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2039
2535
|
const RelativeTime = React__namespace.forwardRef(
|
@@ -2081,7 +2577,7 @@ const getDisplayName = ({
|
|
2081
2577
|
};
|
2082
2578
|
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2083
2579
|
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2084
|
-
const statusVariant = status === "draft" ? "
|
2580
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2085
2581
|
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Status, { ...restProps, showBullet: false, size: "S", variant: statusVariant, children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "span", variant: "omega", fontWeight: "bold", children: capitalise(status) }) });
|
2086
2582
|
};
|
2087
2583
|
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
@@ -2091,23 +2587,13 @@ const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
|
2091
2587
|
id: "content-manager.containers.edit.title.new",
|
2092
2588
|
defaultMessage: "Create an entry"
|
2093
2589
|
}) : documentTitle;
|
2094
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop:
|
2590
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2095
2591
|
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
|
2096
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
2097
|
-
designSystem.
|
2098
|
-
{
|
2099
|
-
|
2100
|
-
|
2101
|
-
paddingTop: 1,
|
2102
|
-
gap: "80px",
|
2103
|
-
alignItems: "flex-start",
|
2104
|
-
children: [
|
2105
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2106
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2107
|
-
]
|
2108
|
-
}
|
2109
|
-
),
|
2110
|
-
status ? /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) : null
|
2592
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2593
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2594
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2595
|
+
] }),
|
2596
|
+
status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2111
2597
|
] });
|
2112
2598
|
};
|
2113
2599
|
const HeaderToolbar = () => {
|
@@ -2190,12 +2676,12 @@ const Information = ({ activeTab }) => {
|
|
2190
2676
|
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2191
2677
|
label: formatMessage({
|
2192
2678
|
id: "content-manager.containers.edit.information.last-published.label",
|
2193
|
-
defaultMessage: "
|
2679
|
+
defaultMessage: "Published"
|
2194
2680
|
}),
|
2195
2681
|
value: formatMessage(
|
2196
2682
|
{
|
2197
2683
|
id: "content-manager.containers.edit.information.last-published.value",
|
2198
|
-
defaultMessage: `
|
2684
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2199
2685
|
},
|
2200
2686
|
{
|
2201
2687
|
time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
@@ -2208,12 +2694,12 @@ const Information = ({ activeTab }) => {
|
|
2208
2694
|
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2209
2695
|
label: formatMessage({
|
2210
2696
|
id: "content-manager.containers.edit.information.last-draft.label",
|
2211
|
-
defaultMessage: "
|
2697
|
+
defaultMessage: "Updated"
|
2212
2698
|
}),
|
2213
2699
|
value: formatMessage(
|
2214
2700
|
{
|
2215
2701
|
id: "content-manager.containers.edit.information.last-draft.value",
|
2216
|
-
defaultMessage: `
|
2702
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2217
2703
|
},
|
2218
2704
|
{
|
2219
2705
|
time: /* @__PURE__ */ jsxRuntime.jsx(
|
@@ -2231,12 +2717,12 @@ const Information = ({ activeTab }) => {
|
|
2231
2717
|
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2232
2718
|
label: formatMessage({
|
2233
2719
|
id: "content-manager.containers.edit.information.document.label",
|
2234
|
-
defaultMessage: "
|
2720
|
+
defaultMessage: "Created"
|
2235
2721
|
}),
|
2236
2722
|
value: formatMessage(
|
2237
2723
|
{
|
2238
2724
|
id: "content-manager.containers.edit.information.document.value",
|
2239
|
-
defaultMessage: `
|
2725
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2240
2726
|
},
|
2241
2727
|
{
|
2242
2728
|
time: /* @__PURE__ */ jsxRuntime.jsx(
|
@@ -2274,25 +2760,77 @@ const Information = ({ activeTab }) => {
|
|
2274
2760
|
);
|
2275
2761
|
};
|
2276
2762
|
const HeaderActions = ({ actions: actions2 }) => {
|
2277
|
-
|
2278
|
-
|
2763
|
+
const [dialogId, setDialogId] = React__namespace.useState(null);
|
2764
|
+
const handleClick = (action) => async (e) => {
|
2765
|
+
if (!("options" in action)) {
|
2766
|
+
const { onClick = () => false, dialog, id } = action;
|
2767
|
+
const muteDialog = await onClick(e);
|
2768
|
+
if (dialog && !muteDialog) {
|
2769
|
+
e.preventDefault();
|
2770
|
+
setDialogId(id);
|
2771
|
+
}
|
2772
|
+
}
|
2773
|
+
};
|
2774
|
+
const handleClose = () => {
|
2775
|
+
setDialogId(null);
|
2776
|
+
};
|
2777
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
|
2778
|
+
if (action.options) {
|
2279
2779
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
2280
2780
|
designSystem.SingleSelect,
|
2281
2781
|
{
|
2282
2782
|
size: "S",
|
2283
|
-
disabled: action.disabled,
|
2284
|
-
"aria-label": action.label,
|
2285
2783
|
onChange: action.onSelect,
|
2286
|
-
|
2784
|
+
"aria-label": action.label,
|
2785
|
+
...action,
|
2287
2786
|
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
|
2288
2787
|
},
|
2289
2788
|
action.id
|
2290
2789
|
);
|
2291
2790
|
} else {
|
2292
|
-
|
2791
|
+
if (action.type === "icon") {
|
2792
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
2793
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2794
|
+
designSystem.IconButton,
|
2795
|
+
{
|
2796
|
+
disabled: action.disabled,
|
2797
|
+
label: action.label,
|
2798
|
+
size: "S",
|
2799
|
+
onClick: handleClick(action),
|
2800
|
+
children: action.icon
|
2801
|
+
}
|
2802
|
+
),
|
2803
|
+
action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
|
2804
|
+
HeaderActionDialog,
|
2805
|
+
{
|
2806
|
+
...action.dialog,
|
2807
|
+
isOpen: dialogId === action.id,
|
2808
|
+
onClose: handleClose
|
2809
|
+
}
|
2810
|
+
) : null
|
2811
|
+
] }, action.id);
|
2812
|
+
}
|
2293
2813
|
}
|
2294
2814
|
}) });
|
2295
2815
|
};
|
2816
|
+
const HeaderActionDialog = ({
|
2817
|
+
onClose,
|
2818
|
+
onCancel,
|
2819
|
+
title,
|
2820
|
+
content: Content,
|
2821
|
+
isOpen
|
2822
|
+
}) => {
|
2823
|
+
const handleClose = async () => {
|
2824
|
+
if (onCancel) {
|
2825
|
+
await onCancel();
|
2826
|
+
}
|
2827
|
+
onClose();
|
2828
|
+
};
|
2829
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
2830
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
2831
|
+
typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
|
2832
|
+
] }) });
|
2833
|
+
};
|
2296
2834
|
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2297
2835
|
const navigate = reactRouterDom.useNavigate();
|
2298
2836
|
const { formatMessage } = reactIntl.useIntl();
|
@@ -2333,12 +2871,16 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2333
2871
|
const { delete: deleteAction } = useDocumentActions();
|
2334
2872
|
const { toggleNotification } = strapiAdmin.useNotification();
|
2335
2873
|
const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
|
2874
|
+
const isLocalized = document?.locale != null;
|
2336
2875
|
return {
|
2337
2876
|
disabled: !canDelete || !document,
|
2338
|
-
label: formatMessage(
|
2339
|
-
|
2340
|
-
|
2341
|
-
|
2877
|
+
label: formatMessage(
|
2878
|
+
{
|
2879
|
+
id: "content-manager.actions.delete.label",
|
2880
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2881
|
+
},
|
2882
|
+
{ isLocalized }
|
2883
|
+
),
|
2342
2884
|
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
|
2343
2885
|
dialog: {
|
2344
2886
|
type: "dialog",
|
@@ -2372,425 +2914,123 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2372
2914
|
return;
|
2373
2915
|
}
|
2374
2916
|
const res = await deleteAction({
|
2375
|
-
documentId,
|
2376
|
-
model,
|
2377
|
-
collectionType,
|
2378
|
-
params: {
|
2379
|
-
locale: "*"
|
2380
|
-
}
|
2381
|
-
});
|
2382
|
-
if (!("error" in res)) {
|
2383
|
-
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2384
|
-
}
|
2385
|
-
} finally {
|
2386
|
-
if (!listViewPathMatch) {
|
2387
|
-
setSubmitting(false);
|
2388
|
-
}
|
2389
|
-
}
|
2390
|
-
}
|
2391
|
-
},
|
2392
|
-
variant: "danger",
|
2393
|
-
position: ["header", "table-row"]
|
2394
|
-
};
|
2395
|
-
};
|
2396
|
-
DeleteAction$1.type = "delete";
|
2397
|
-
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2398
|
-
const Panels = () => {
|
2399
|
-
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2400
|
-
const [
|
2401
|
-
{
|
2402
|
-
query: { status }
|
2403
|
-
}
|
2404
|
-
] = strapiAdmin.useQueryParams({
|
2405
|
-
status: "draft"
|
2406
|
-
});
|
2407
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2408
|
-
const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
|
2409
|
-
const props = {
|
2410
|
-
activeTab: status,
|
2411
|
-
model,
|
2412
|
-
documentId: id,
|
2413
|
-
document: isCloning ? void 0 : document,
|
2414
|
-
meta: isCloning ? void 0 : meta,
|
2415
|
-
collectionType
|
2416
|
-
};
|
2417
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
2418
|
-
strapiAdmin.DescriptionComponentRenderer,
|
2419
|
-
{
|
2420
|
-
props,
|
2421
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2422
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
2423
|
-
}
|
2424
|
-
) });
|
2425
|
-
};
|
2426
|
-
const ActionsPanel = () => {
|
2427
|
-
const { formatMessage } = reactIntl.useIntl();
|
2428
|
-
return {
|
2429
|
-
title: formatMessage({
|
2430
|
-
id: "content-manager.containers.edit.panels.default.title",
|
2431
|
-
defaultMessage: "Document"
|
2432
|
-
}),
|
2433
|
-
content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
|
2434
|
-
};
|
2435
|
-
};
|
2436
|
-
ActionsPanel.type = "actions";
|
2437
|
-
const ActionsPanelContent = () => {
|
2438
|
-
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2439
|
-
const [
|
2440
|
-
{
|
2441
|
-
query: { status = "draft" }
|
2442
|
-
}
|
2443
|
-
] = strapiAdmin.useQueryParams();
|
2444
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2445
|
-
const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2446
|
-
const props = {
|
2447
|
-
activeTab: status,
|
2448
|
-
model,
|
2449
|
-
documentId: id,
|
2450
|
-
document: isCloning ? void 0 : document,
|
2451
|
-
meta: isCloning ? void 0 : meta,
|
2452
|
-
collectionType
|
2453
|
-
};
|
2454
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2455
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
2456
|
-
strapiAdmin.DescriptionComponentRenderer,
|
2457
|
-
{
|
2458
|
-
props,
|
2459
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2460
|
-
children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
|
2461
|
-
}
|
2462
|
-
),
|
2463
|
-
/* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
2464
|
-
] });
|
2465
|
-
};
|
2466
|
-
const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
|
2467
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
2468
|
-
designSystem.Flex,
|
2469
|
-
{
|
2470
|
-
ref,
|
2471
|
-
tag: "aside",
|
2472
|
-
"aria-labelledby": "additional-information",
|
2473
|
-
background: "neutral0",
|
2474
|
-
borderColor: "neutral150",
|
2475
|
-
hasRadius: true,
|
2476
|
-
paddingBottom: 4,
|
2477
|
-
paddingLeft: 4,
|
2478
|
-
paddingRight: 4,
|
2479
|
-
paddingTop: 4,
|
2480
|
-
shadow: "tableShadow",
|
2481
|
-
gap: 3,
|
2482
|
-
direction: "column",
|
2483
|
-
justifyContent: "stretch",
|
2484
|
-
alignItems: "flex-start",
|
2485
|
-
children: [
|
2486
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2487
|
-
children
|
2488
|
-
]
|
2489
|
-
}
|
2490
|
-
);
|
2491
|
-
});
|
2492
|
-
const HOOKS = {
|
2493
|
-
/**
|
2494
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2495
|
-
* @constant
|
2496
|
-
* @type {string}
|
2497
|
-
*/
|
2498
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2499
|
-
/**
|
2500
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2501
|
-
* @constant
|
2502
|
-
* @type {string}
|
2503
|
-
*/
|
2504
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2505
|
-
/**
|
2506
|
-
* Hook that allows to mutate the CM's edit view layout
|
2507
|
-
* @constant
|
2508
|
-
* @type {string}
|
2509
|
-
*/
|
2510
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2511
|
-
/**
|
2512
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2513
|
-
* @constant
|
2514
|
-
* @type {string}
|
2515
|
-
*/
|
2516
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2517
|
-
};
|
2518
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2519
|
-
endpoints: (builder) => ({
|
2520
|
-
getContentTypeConfiguration: builder.query({
|
2521
|
-
query: (uid) => ({
|
2522
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2523
|
-
method: "GET"
|
2524
|
-
}),
|
2525
|
-
transformResponse: (response) => response.data,
|
2526
|
-
providesTags: (_result, _error, uid) => [
|
2527
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2528
|
-
{ type: "ContentTypeSettings", id: "LIST" }
|
2529
|
-
]
|
2530
|
-
}),
|
2531
|
-
getAllContentTypeSettings: builder.query({
|
2532
|
-
query: () => "/content-manager/content-types-settings",
|
2533
|
-
transformResponse: (response) => response.data,
|
2534
|
-
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
2535
|
-
}),
|
2536
|
-
updateContentTypeConfiguration: builder.mutation({
|
2537
|
-
query: ({ uid, ...body }) => ({
|
2538
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2539
|
-
method: "PUT",
|
2540
|
-
data: body
|
2541
|
-
}),
|
2542
|
-
transformResponse: (response) => response.data,
|
2543
|
-
invalidatesTags: (_result, _error, { uid }) => [
|
2544
|
-
{ type: "ContentTypesConfiguration", id: uid },
|
2545
|
-
{ type: "ContentTypeSettings", id: "LIST" },
|
2546
|
-
// Is this necessary?
|
2547
|
-
{ type: "InitialData" }
|
2548
|
-
]
|
2549
|
-
})
|
2550
|
-
})
|
2551
|
-
});
|
2552
|
-
const {
|
2553
|
-
useGetContentTypeConfigurationQuery,
|
2554
|
-
useGetAllContentTypeSettingsQuery,
|
2555
|
-
useUpdateContentTypeConfigurationMutation
|
2556
|
-
} = contentTypesApi;
|
2557
|
-
const checkIfAttributeIsDisplayable = (attribute) => {
|
2558
|
-
const { type } = attribute;
|
2559
|
-
if (type === "relation") {
|
2560
|
-
return !attribute.relation.toLowerCase().includes("morph");
|
2561
|
-
}
|
2562
|
-
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
2563
|
-
};
|
2564
|
-
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
2565
|
-
if (!mainFieldName) {
|
2566
|
-
return void 0;
|
2567
|
-
}
|
2568
|
-
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
2569
|
-
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
2570
|
-
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
2571
|
-
);
|
2572
|
-
return {
|
2573
|
-
name: mainFieldName,
|
2574
|
-
type: mainFieldType ?? "string"
|
2575
|
-
};
|
2576
|
-
};
|
2577
|
-
const DEFAULT_SETTINGS = {
|
2578
|
-
bulkable: false,
|
2579
|
-
filterable: false,
|
2580
|
-
searchable: false,
|
2581
|
-
pagination: false,
|
2582
|
-
defaultSortBy: "",
|
2583
|
-
defaultSortOrder: "asc",
|
2584
|
-
mainField: "id",
|
2585
|
-
pageSize: 10
|
2586
|
-
};
|
2587
|
-
const useDocumentLayout = (model) => {
|
2588
|
-
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
2589
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
2590
|
-
const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
2591
|
-
const { toggleNotification } = strapiAdmin.useNotification();
|
2592
|
-
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
2593
|
-
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
2594
|
-
const {
|
2595
|
-
data,
|
2596
|
-
isLoading: isLoadingConfigs,
|
2597
|
-
error,
|
2598
|
-
isFetching: isFetchingConfigs
|
2599
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2600
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2601
|
-
React__namespace.useEffect(() => {
|
2602
|
-
if (error) {
|
2603
|
-
toggleNotification({
|
2604
|
-
type: "danger",
|
2605
|
-
message: formatAPIError(error)
|
2606
|
-
});
|
2607
|
-
}
|
2608
|
-
}, [error, formatAPIError, toggleNotification]);
|
2609
|
-
const editLayout = React__namespace.useMemo(
|
2610
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2611
|
-
layout: [],
|
2612
|
-
components: {},
|
2613
|
-
metadatas: {},
|
2614
|
-
options: {},
|
2615
|
-
settings: DEFAULT_SETTINGS
|
2616
|
-
},
|
2617
|
-
[data, isLoading, schemas, schema, components]
|
2618
|
-
);
|
2619
|
-
const listLayout = React__namespace.useMemo(() => {
|
2620
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2621
|
-
layout: [],
|
2622
|
-
metadatas: {},
|
2623
|
-
options: {},
|
2624
|
-
settings: DEFAULT_SETTINGS
|
2625
|
-
};
|
2626
|
-
}, [data, isLoading, schemas, schema, components]);
|
2627
|
-
const { layout: edit } = React__namespace.useMemo(
|
2628
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2629
|
-
layout: editLayout,
|
2630
|
-
query
|
2631
|
-
}),
|
2632
|
-
[editLayout, query, runHookWaterfall]
|
2633
|
-
);
|
2634
|
-
return {
|
2635
|
-
error,
|
2636
|
-
isLoading,
|
2637
|
-
edit,
|
2638
|
-
list: listLayout
|
2639
|
-
};
|
2640
|
-
};
|
2641
|
-
const useDocLayout = () => {
|
2642
|
-
const { model } = useDoc();
|
2643
|
-
return useDocumentLayout(model);
|
2644
|
-
};
|
2645
|
-
const formatEditLayout = (data, {
|
2646
|
-
schemas,
|
2647
|
-
schema,
|
2648
|
-
components
|
2649
|
-
}) => {
|
2650
|
-
let currentPanelIndex = 0;
|
2651
|
-
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
2652
|
-
data.contentType.layouts.edit,
|
2653
|
-
schema?.attributes,
|
2654
|
-
data.contentType.metadatas,
|
2655
|
-
{ configurations: data.components, schemas: components },
|
2656
|
-
schemas
|
2657
|
-
).reduce((panels, row) => {
|
2658
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2659
|
-
panels.push([row]);
|
2660
|
-
currentPanelIndex += 2;
|
2661
|
-
} else {
|
2662
|
-
if (!panels[currentPanelIndex]) {
|
2663
|
-
panels.push([]);
|
2664
|
-
}
|
2665
|
-
panels[currentPanelIndex].push(row);
|
2666
|
-
}
|
2667
|
-
return panels;
|
2668
|
-
}, []);
|
2669
|
-
const componentEditAttributes = Object.entries(data.components).reduce(
|
2670
|
-
(acc, [uid, configuration]) => {
|
2671
|
-
acc[uid] = {
|
2672
|
-
layout: convertEditLayoutToFieldLayouts(
|
2673
|
-
configuration.layouts.edit,
|
2674
|
-
components[uid].attributes,
|
2675
|
-
configuration.metadatas
|
2676
|
-
),
|
2677
|
-
settings: {
|
2678
|
-
...configuration.settings,
|
2679
|
-
icon: components[uid].info.icon,
|
2680
|
-
displayName: components[uid].info.displayName
|
2917
|
+
documentId,
|
2918
|
+
model,
|
2919
|
+
collectionType,
|
2920
|
+
params: {
|
2921
|
+
locale: "*"
|
2922
|
+
}
|
2923
|
+
});
|
2924
|
+
if (!("error" in res)) {
|
2925
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2926
|
+
}
|
2927
|
+
} finally {
|
2928
|
+
if (!listViewPathMatch) {
|
2929
|
+
setSubmitting(false);
|
2930
|
+
}
|
2681
2931
|
}
|
2682
|
-
}
|
2683
|
-
return acc;
|
2684
|
-
},
|
2685
|
-
{}
|
2686
|
-
);
|
2687
|
-
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2688
|
-
(acc, [attribute, metadata]) => {
|
2689
|
-
return {
|
2690
|
-
...acc,
|
2691
|
-
[attribute]: metadata.edit
|
2692
|
-
};
|
2693
|
-
},
|
2694
|
-
{}
|
2695
|
-
);
|
2696
|
-
return {
|
2697
|
-
layout: panelledEditAttributes,
|
2698
|
-
components: componentEditAttributes,
|
2699
|
-
metadatas: editMetadatas,
|
2700
|
-
settings: {
|
2701
|
-
...data.contentType.settings,
|
2702
|
-
displayName: schema?.info.displayName
|
2932
|
+
}
|
2703
2933
|
},
|
2704
|
-
|
2705
|
-
|
2706
|
-
...schema?.pluginOptions,
|
2707
|
-
...data.contentType.options
|
2708
|
-
}
|
2934
|
+
variant: "danger",
|
2935
|
+
position: ["header", "table-row"]
|
2709
2936
|
};
|
2710
2937
|
};
|
2711
|
-
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
}
|
2718
|
-
|
2719
|
-
|
2720
|
-
|
2721
|
-
|
2722
|
-
|
2723
|
-
|
2724
|
-
|
2725
|
-
|
2726
|
-
|
2727
|
-
|
2728
|
-
|
2729
|
-
|
2730
|
-
|
2731
|
-
|
2732
|
-
|
2733
|
-
|
2734
|
-
|
2735
|
-
|
2736
|
-
|
2737
|
-
}
|
2738
|
-
}
|
2739
|
-
);
|
2938
|
+
DeleteAction$1.type = "delete";
|
2939
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2940
|
+
const Panels = () => {
|
2941
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2942
|
+
const [
|
2943
|
+
{
|
2944
|
+
query: { status }
|
2945
|
+
}
|
2946
|
+
] = strapiAdmin.useQueryParams({
|
2947
|
+
status: "draft"
|
2948
|
+
});
|
2949
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2950
|
+
const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
|
2951
|
+
const props = {
|
2952
|
+
activeTab: status,
|
2953
|
+
model,
|
2954
|
+
documentId: id,
|
2955
|
+
document: isCloning ? void 0 : document,
|
2956
|
+
meta: isCloning ? void 0 : meta,
|
2957
|
+
collectionType
|
2958
|
+
};
|
2959
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
2960
|
+
strapiAdmin.DescriptionComponentRenderer,
|
2961
|
+
{
|
2962
|
+
props,
|
2963
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2964
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
2965
|
+
}
|
2966
|
+
) });
|
2740
2967
|
};
|
2741
|
-
const
|
2742
|
-
|
2743
|
-
schema,
|
2744
|
-
components
|
2745
|
-
}) => {
|
2746
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2747
|
-
(acc, [attribute, metadata]) => {
|
2748
|
-
return {
|
2749
|
-
...acc,
|
2750
|
-
[attribute]: metadata.list
|
2751
|
-
};
|
2752
|
-
},
|
2753
|
-
{}
|
2754
|
-
);
|
2755
|
-
const listAttributes = convertListLayoutToFieldLayouts(
|
2756
|
-
data.contentType.layouts.list,
|
2757
|
-
schema?.attributes,
|
2758
|
-
listMetadatas,
|
2759
|
-
{ configurations: data.components, schemas: components },
|
2760
|
-
schemas
|
2761
|
-
);
|
2968
|
+
const ActionsPanel = () => {
|
2969
|
+
const { formatMessage } = reactIntl.useIntl();
|
2762
2970
|
return {
|
2763
|
-
|
2764
|
-
|
2765
|
-
|
2766
|
-
|
2767
|
-
|
2768
|
-
...schema?.pluginOptions,
|
2769
|
-
...data.contentType.options
|
2770
|
-
}
|
2971
|
+
title: formatMessage({
|
2972
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2973
|
+
defaultMessage: "Entry"
|
2974
|
+
}),
|
2975
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
|
2771
2976
|
};
|
2772
2977
|
};
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2978
|
+
ActionsPanel.type = "actions";
|
2979
|
+
const ActionsPanelContent = () => {
|
2980
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2981
|
+
const [
|
2982
|
+
{
|
2983
|
+
query: { status = "draft" }
|
2778
2984
|
}
|
2779
|
-
|
2780
|
-
|
2781
|
-
|
2782
|
-
|
2783
|
-
|
2784
|
-
|
2785
|
-
|
2786
|
-
|
2787
|
-
|
2788
|
-
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2985
|
+
] = strapiAdmin.useQueryParams();
|
2986
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2987
|
+
const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
|
2988
|
+
const props = {
|
2989
|
+
activeTab: status,
|
2990
|
+
model,
|
2991
|
+
documentId: id,
|
2992
|
+
document: isCloning ? void 0 : document,
|
2993
|
+
meta: isCloning ? void 0 : meta,
|
2994
|
+
collectionType
|
2995
|
+
};
|
2996
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2997
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2998
|
+
strapiAdmin.DescriptionComponentRenderer,
|
2999
|
+
{
|
3000
|
+
props,
|
3001
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3002
|
+
children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
|
3003
|
+
}
|
3004
|
+
),
|
3005
|
+
/* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3006
|
+
] });
|
2793
3007
|
};
|
3008
|
+
const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
|
3009
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
3010
|
+
designSystem.Flex,
|
3011
|
+
{
|
3012
|
+
ref,
|
3013
|
+
tag: "aside",
|
3014
|
+
"aria-labelledby": "additional-information",
|
3015
|
+
background: "neutral0",
|
3016
|
+
borderColor: "neutral150",
|
3017
|
+
hasRadius: true,
|
3018
|
+
paddingBottom: 4,
|
3019
|
+
paddingLeft: 4,
|
3020
|
+
paddingRight: 4,
|
3021
|
+
paddingTop: 4,
|
3022
|
+
shadow: "tableShadow",
|
3023
|
+
gap: 3,
|
3024
|
+
direction: "column",
|
3025
|
+
justifyContent: "stretch",
|
3026
|
+
alignItems: "flex-start",
|
3027
|
+
children: [
|
3028
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3029
|
+
children
|
3030
|
+
]
|
3031
|
+
}
|
3032
|
+
);
|
3033
|
+
});
|
2794
3034
|
const ConfirmBulkActionDialog = ({
|
2795
3035
|
onToggleDialog,
|
2796
3036
|
isOpen = false,
|
@@ -2798,7 +3038,7 @@ const ConfirmBulkActionDialog = ({
|
|
2798
3038
|
endAction
|
2799
3039
|
}) => {
|
2800
3040
|
const { formatMessage } = reactIntl.useIntl();
|
2801
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, {
|
3041
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
2802
3042
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: formatMessage({
|
2803
3043
|
id: "app.components.ConfirmDialog.title",
|
2804
3044
|
defaultMessage: "Confirmation"
|
@@ -2829,6 +3069,7 @@ const ConfirmDialogPublishAll = ({
|
|
2829
3069
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
|
2830
3070
|
const { model, schema } = useDoc();
|
2831
3071
|
const [{ query }] = strapiAdmin.useQueryParams();
|
3072
|
+
const enableDraftRelationsCount = false;
|
2832
3073
|
const {
|
2833
3074
|
data: countDraftRelations = 0,
|
2834
3075
|
isLoading,
|
@@ -2840,7 +3081,7 @@ const ConfirmDialogPublishAll = ({
|
|
2840
3081
|
locale: query?.plugins?.i18n?.locale
|
2841
3082
|
},
|
2842
3083
|
{
|
2843
|
-
skip:
|
3084
|
+
skip: !enableDraftRelationsCount
|
2844
3085
|
}
|
2845
3086
|
);
|
2846
3087
|
React__namespace.useEffect(() => {
|
@@ -2919,7 +3160,14 @@ const formatErrorMessages = (errors, parentKey, formatMessage) => {
|
|
2919
3160
|
)
|
2920
3161
|
);
|
2921
3162
|
} else {
|
2922
|
-
messages.push(
|
3163
|
+
messages.push(
|
3164
|
+
...formatErrorMessages(
|
3165
|
+
// @ts-expect-error TODO: check why value is not compatible with FormErrors
|
3166
|
+
value,
|
3167
|
+
currentKey,
|
3168
|
+
formatMessage
|
3169
|
+
)
|
3170
|
+
);
|
2923
3171
|
}
|
2924
3172
|
} else {
|
2925
3173
|
messages.push(
|
@@ -3018,7 +3266,7 @@ const SelectedEntriesTableContent = ({
|
|
3018
3266
|
status: row.status
|
3019
3267
|
}
|
3020
3268
|
) }),
|
3021
|
-
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3269
|
+
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3022
3270
|
designSystem.IconButton,
|
3023
3271
|
{
|
3024
3272
|
tag: reactRouterDom.Link,
|
@@ -3041,9 +3289,10 @@ const SelectedEntriesTableContent = ({
|
|
3041
3289
|
),
|
3042
3290
|
target: "_blank",
|
3043
3291
|
marginLeft: "auto",
|
3044
|
-
|
3292
|
+
variant: "ghost",
|
3293
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
|
3045
3294
|
}
|
3046
|
-
) })
|
3295
|
+
) }) })
|
3047
3296
|
] }, row.id)) })
|
3048
3297
|
] });
|
3049
3298
|
};
|
@@ -3080,7 +3329,13 @@ const SelectedEntriesModalContent = ({
|
|
3080
3329
|
);
|
3081
3330
|
const { rows, validationErrors } = React__namespace.useMemo(() => {
|
3082
3331
|
if (data.length > 0 && schema) {
|
3083
|
-
const validate = createYupSchema(
|
3332
|
+
const validate = createYupSchema(
|
3333
|
+
schema.attributes,
|
3334
|
+
components,
|
3335
|
+
// Since this is the "Publish" action, the validation
|
3336
|
+
// schema must enforce the rules for published entities
|
3337
|
+
{ status: "published" }
|
3338
|
+
);
|
3084
3339
|
const validationErrors2 = {};
|
3085
3340
|
const rows2 = data.map((entry) => {
|
3086
3341
|
try {
|
@@ -3430,7 +3685,7 @@ const TableActions = ({ document }) => {
|
|
3430
3685
|
strapiAdmin.DescriptionComponentRenderer,
|
3431
3686
|
{
|
3432
3687
|
props,
|
3433
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3688
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3434
3689
|
children: (actions2) => {
|
3435
3690
|
const tableRowActions = actions2.filter((action) => {
|
3436
3691
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3541,7 +3796,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3541
3796
|
}),
|
3542
3797
|
content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3543
3798
|
footer: ({ onClose }) => {
|
3544
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.
|
3799
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
|
3545
3800
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3546
3801
|
id: "cancel",
|
3547
3802
|
defaultMessage: "Cancel"
|
@@ -3582,8 +3837,7 @@ class ContentManagerPlugin {
|
|
3582
3837
|
documentActions = [
|
3583
3838
|
...DEFAULT_ACTIONS,
|
3584
3839
|
...DEFAULT_TABLE_ROW_ACTIONS,
|
3585
|
-
...DEFAULT_HEADER_ACTIONS
|
3586
|
-
HistoryAction
|
3840
|
+
...DEFAULT_HEADER_ACTIONS
|
3587
3841
|
];
|
3588
3842
|
editViewSidePanels = [ActionsPanel];
|
3589
3843
|
headerActions = [];
|
@@ -3672,6 +3926,52 @@ const getPrintableType = (value) => {
|
|
3672
3926
|
}
|
3673
3927
|
return nativeType;
|
3674
3928
|
};
|
3929
|
+
const HistoryAction = ({ model, document }) => {
|
3930
|
+
const { formatMessage } = reactIntl.useIntl();
|
3931
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
3932
|
+
const navigate = reactRouterDom.useNavigate();
|
3933
|
+
const pluginsQueryParams = qs.stringify({ plugins: query.plugins }, { encode: false });
|
3934
|
+
if (!window.strapi.features.isEnabled("cms-content-history")) {
|
3935
|
+
return null;
|
3936
|
+
}
|
3937
|
+
return {
|
3938
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ClockCounterClockwise, {}),
|
3939
|
+
label: formatMessage({
|
3940
|
+
id: "content-manager.history.document-action",
|
3941
|
+
defaultMessage: "Content History"
|
3942
|
+
}),
|
3943
|
+
onClick: () => navigate({ pathname: "history", search: pluginsQueryParams }),
|
3944
|
+
disabled: (
|
3945
|
+
/**
|
3946
|
+
* The user is creating a new document.
|
3947
|
+
* It hasn't been saved yet, so there's no history to go to
|
3948
|
+
*/
|
3949
|
+
!document || /**
|
3950
|
+
* The document has been created but the current dimension has never been saved.
|
3951
|
+
* For example, the user is creating a new locale in an existing document,
|
3952
|
+
* so there's no history for the document in that locale
|
3953
|
+
*/
|
3954
|
+
!document.id || /**
|
3955
|
+
* History is only available for content types created by the user.
|
3956
|
+
* These have the `api::` prefix, as opposed to the ones created by Strapi or plugins,
|
3957
|
+
* which start with `admin::` or `plugin::`
|
3958
|
+
*/
|
3959
|
+
!model.startsWith("api::")
|
3960
|
+
),
|
3961
|
+
position: "header"
|
3962
|
+
};
|
3963
|
+
};
|
3964
|
+
HistoryAction.type = "history";
|
3965
|
+
const historyAdmin = {
|
3966
|
+
bootstrap(app) {
|
3967
|
+
const { addDocumentAction } = app.getPlugin("content-manager").apis;
|
3968
|
+
addDocumentAction((actions2) => {
|
3969
|
+
const indexOfDeleteAction = actions2.findIndex((action) => action.type === "delete");
|
3970
|
+
actions2.splice(indexOfDeleteAction, 0, HistoryAction);
|
3971
|
+
return actions2;
|
3972
|
+
});
|
3973
|
+
}
|
3974
|
+
};
|
3675
3975
|
const initialState = {
|
3676
3976
|
collectionTypeLinks: [],
|
3677
3977
|
components: [],
|
@@ -3727,7 +4027,7 @@ const index = {
|
|
3727
4027
|
app.router.addRoute({
|
3728
4028
|
path: "content-manager/*",
|
3729
4029
|
lazy: async () => {
|
3730
|
-
const { Layout } = await Promise.resolve().then(() => require("./layout-
|
4030
|
+
const { Layout } = await Promise.resolve().then(() => require("./layout-CeBSIkmP.js"));
|
3731
4031
|
return {
|
3732
4032
|
Component: Layout
|
3733
4033
|
};
|
@@ -3736,10 +4036,15 @@ const index = {
|
|
3736
4036
|
});
|
3737
4037
|
app.registerPlugin(cm.config);
|
3738
4038
|
},
|
4039
|
+
bootstrap(app) {
|
4040
|
+
if (typeof historyAdmin.bootstrap === "function") {
|
4041
|
+
historyAdmin.bootstrap(app);
|
4042
|
+
}
|
4043
|
+
},
|
3739
4044
|
async registerTrads({ locales }) {
|
3740
4045
|
const importedTrads = await Promise.all(
|
3741
4046
|
locales.map((locale) => {
|
3742
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-
|
4047
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/ar.json": () => Promise.resolve().then(() => require("./ar-BUUWXIYu.js")), "./translations/ca.json": () => Promise.resolve().then(() => require("./ca-Cmk45QO6.js")), "./translations/cs.json": () => Promise.resolve().then(() => require("./cs-CkJy6B2v.js")), "./translations/de.json": () => Promise.resolve().then(() => require("./de-CCEmbAah.js")), "./translations/en.json": () => Promise.resolve().then(() => require("./en-Bm0D0IWz.js")), "./translations/es.json": () => Promise.resolve().then(() => require("./es-EUonQTon.js")), "./translations/eu.json": () => Promise.resolve().then(() => require("./eu-VDH-3ovk.js")), "./translations/fr.json": () => Promise.resolve().then(() => require("./fr-B7kGGg3E.js")), "./translations/gu.json": () => Promise.resolve().then(() => require("./gu-BRmF601H.js")), "./translations/hi.json": () => Promise.resolve().then(() => require("./hi-CCJBptSq.js")), "./translations/hu.json": () => Promise.resolve().then(() => require("./hu-sNV_yLYy.js")), "./translations/id.json": () => Promise.resolve().then(() => require("./id-B5Ser98A.js")), "./translations/it.json": () => Promise.resolve().then(() => require("./it-DkBIs7vD.js")), "./translations/ja.json": () => Promise.resolve().then(() => require("./ja-CcFe8diO.js")), "./translations/ko.json": () => Promise.resolve().then(() => require("./ko-woFZPmLk.js")), "./translations/ml.json": () => Promise.resolve().then(() => require("./ml-C2W8N8k1.js")), "./translations/ms.json": () => Promise.resolve().then(() => require("./ms-BuFotyP_.js")), "./translations/nl.json": () => Promise.resolve().then(() => require("./nl-bbEOHChV.js")), "./translations/pl.json": () => Promise.resolve().then(() => require("./pl-uzwG-hk7.js")), "./translations/pt-BR.json": () => Promise.resolve().then(() => require("./pt-BR-BiOz37D9.js")), "./translations/pt.json": () => Promise.resolve().then(() => require("./pt-CeXQuq50.js")), "./translations/ru.json": () => Promise.resolve().then(() => require("./ru-BT3ybNny.js")), "./translations/sa.json": () => Promise.resolve().then(() => require("./sa-CcvkYInH.js")), "./translations/sk.json": () => Promise.resolve().then(() => require("./sk-CvY09Xjv.js")), "./translations/sv.json": () => Promise.resolve().then(() => require("./sv-MYDuzgvT.js")), "./translations/th.json": () => Promise.resolve().then(() => require("./th-D9_GfAjc.js")), "./translations/tr.json": () => Promise.resolve().then(() => require("./tr-D9UH-O_R.js")), "./translations/uk.json": () => Promise.resolve().then(() => require("./uk-C8EiqJY7.js")), "./translations/vi.json": () => Promise.resolve().then(() => require("./vi-CJlYDheJ.js")), "./translations/zh-Hans.json": () => Promise.resolve().then(() => require("./zh-Hans-9kOncHGw.js")), "./translations/zh.json": () => Promise.resolve().then(() => require("./zh-CQQfszqR.js")) }), `./translations/${locale}.json`).then(({ default: data }) => {
|
3743
4048
|
return {
|
3744
4049
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3745
4050
|
locale
|
@@ -3757,6 +4062,7 @@ const index = {
|
|
3757
4062
|
};
|
3758
4063
|
exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
|
3759
4064
|
exports.BulkActionsRenderer = BulkActionsRenderer;
|
4065
|
+
exports.CLONE_PATH = CLONE_PATH;
|
3760
4066
|
exports.COLLECTION_TYPES = COLLECTION_TYPES;
|
3761
4067
|
exports.CREATOR_FIELDS = CREATOR_FIELDS;
|
3762
4068
|
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
@@ -3784,6 +4090,7 @@ exports.getMainField = getMainField;
|
|
3784
4090
|
exports.getTranslation = getTranslation;
|
3785
4091
|
exports.index = index;
|
3786
4092
|
exports.setInitialData = setInitialData;
|
4093
|
+
exports.useContentManagerContext = useContentManagerContext;
|
3787
4094
|
exports.useContentTypeSchema = useContentTypeSchema;
|
3788
4095
|
exports.useDoc = useDoc;
|
3789
4096
|
exports.useDocLayout = useDocLayout;
|
@@ -3796,4 +4103,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
|
|
3796
4103
|
exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
|
3797
4104
|
exports.useGetInitialDataQuery = useGetInitialDataQuery;
|
3798
4105
|
exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
|
3799
|
-
//# sourceMappingURL=index-
|
4106
|
+
//# sourceMappingURL=index-DbT2sx-Q.js.map
|