@strapi/content-manager 0.0.0-experimental.abc → 0.0.0-experimental.b1d7921ddb1b36c84b58a3946e1dc9dbda91b2dc
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/_chunks/{ComponentConfigurationPage-KXSuLnQD.js → ComponentConfigurationPage-CQDCxI8x.js} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-KXSuLnQD.js.map → ComponentConfigurationPage-CQDCxI8x.js.map} +1 -1
- package/dist/_chunks/{ComponentConfigurationPage-B3yDbeU1.mjs → ComponentConfigurationPage-jmWwucg_.mjs} +3 -3
- package/dist/_chunks/{ComponentConfigurationPage-B3yDbeU1.mjs.map → ComponentConfigurationPage-jmWwucg_.mjs.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-BQ17--5R.js → EditConfigurationPage-Ce4bIm4n.js} +3 -3
- package/dist/_chunks/{EditConfigurationPage-BQ17--5R.js.map → EditConfigurationPage-Ce4bIm4n.js.map} +1 -1
- package/dist/_chunks/{EditConfigurationPage-D7PrLO8j.mjs → EditConfigurationPage-W07CEdm2.mjs} +3 -3
- package/dist/_chunks/{EditConfigurationPage-D7PrLO8j.mjs.map → EditConfigurationPage-W07CEdm2.mjs.map} +1 -1
- package/dist/_chunks/{EditViewPage-BgjdnGz2.js → EditViewPage-CqHMM0P0.js} +15 -5
- package/dist/_chunks/EditViewPage-CqHMM0P0.js.map +1 -0
- package/dist/_chunks/{EditViewPage-B7VgwJaG.mjs → EditViewPage-al5OO1NR.mjs} +15 -5
- package/dist/_chunks/EditViewPage-al5OO1NR.mjs.map +1 -0
- package/dist/_chunks/{Field-CdK7ZLmv.js → Field-DSOUlTCm.js} +100 -87
- package/dist/_chunks/Field-DSOUlTCm.js.map +1 -0
- package/dist/_chunks/{Field-tHCw4lGA.mjs → Field-EeG6NQ7x.mjs} +97 -84
- package/dist/_chunks/Field-EeG6NQ7x.mjs.map +1 -0
- package/dist/_chunks/{Form-BJxdTv3Q.mjs → Form-BAo9ANb_.mjs} +16 -8
- package/dist/_chunks/Form-BAo9ANb_.mjs.map +1 -0
- package/dist/_chunks/{Form-C_0KTVvV.js → Form-DAEfHKzm.js} +16 -8
- package/dist/_chunks/Form-DAEfHKzm.js.map +1 -0
- package/dist/_chunks/{History-DR2txJLE.mjs → History-BpLIu67W.mjs} +24 -11
- package/dist/_chunks/History-BpLIu67W.mjs.map +1 -0
- package/dist/_chunks/{History-nuEzM5qm.js → History-CTFvy6XH.js} +23 -10
- package/dist/_chunks/History-CTFvy6XH.js.map +1 -0
- package/dist/_chunks/{ListConfigurationPage-CnB86Psm.js → ListConfigurationPage-CDzlMBz_.js} +2 -2
- package/dist/_chunks/{ListConfigurationPage-CnB86Psm.js.map → ListConfigurationPage-CDzlMBz_.js.map} +1 -1
- package/dist/_chunks/{ListConfigurationPage-voFVtXu6.mjs → ListConfigurationPage-DOqj5f8Y.mjs} +2 -2
- package/dist/_chunks/{ListConfigurationPage-voFVtXu6.mjs.map → ListConfigurationPage-DOqj5f8Y.mjs.map} +1 -1
- package/dist/_chunks/{ListViewPage-B_GaWgRH.mjs → ListViewPage-BbXYNI0v.mjs} +40 -36
- package/dist/_chunks/ListViewPage-BbXYNI0v.mjs.map +1 -0
- package/dist/_chunks/{ListViewPage-SXIXm-RM.js → ListViewPage-D0fpPYKp.js} +43 -39
- package/dist/_chunks/ListViewPage-D0fpPYKp.js.map +1 -0
- package/dist/_chunks/{NoContentTypePage-BzsQ3hLZ.js → NoContentTypePage-DTzkSAV5.js} +2 -2
- package/dist/_chunks/{NoContentTypePage-BzsQ3hLZ.js.map → NoContentTypePage-DTzkSAV5.js.map} +1 -1
- package/dist/_chunks/{NoContentTypePage-CYiGpsbj.mjs → NoContentTypePage-w2Q0VVOT.mjs} +2 -2
- package/dist/_chunks/{NoContentTypePage-CYiGpsbj.mjs.map → NoContentTypePage-w2Q0VVOT.mjs.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-IGkId4C5.js → NoPermissionsPage-BoI2rU68.js} +2 -2
- package/dist/_chunks/{NoPermissionsPage-IGkId4C5.js.map → NoPermissionsPage-BoI2rU68.js.map} +1 -1
- package/dist/_chunks/{NoPermissionsPage-B5baIHal.mjs → NoPermissionsPage-Km0Vk5Wp.mjs} +2 -2
- package/dist/_chunks/{NoPermissionsPage-B5baIHal.mjs.map → NoPermissionsPage-Km0Vk5Wp.mjs.map} +1 -1
- package/dist/_chunks/{Relations-CIYDdKU-.mjs → Relations-C_bpmSuQ.mjs} +50 -28
- package/dist/_chunks/Relations-C_bpmSuQ.mjs.map +1 -0
- package/dist/_chunks/{Relations-Dhuurpx2.js → Relations-D6Nz5ksc.js} +50 -28
- package/dist/_chunks/Relations-D6Nz5ksc.js.map +1 -0
- package/dist/_chunks/{en-uOUIxfcQ.js → en-Bm0D0IWz.js} +13 -12
- package/dist/_chunks/{en-uOUIxfcQ.js.map → en-Bm0D0IWz.js.map} +1 -1
- package/dist/_chunks/{en-BrCTWlZv.mjs → en-DKV44jRb.mjs} +13 -12
- package/dist/_chunks/{en-BrCTWlZv.mjs.map → en-DKV44jRb.mjs.map} +1 -1
- package/dist/_chunks/{index-CdT0kHZ8.js → index-BsMu2oVP.js} +1907 -1762
- package/dist/_chunks/index-BsMu2oVP.js.map +1 -0
- package/dist/_chunks/{index-C9TJPyni.mjs → index-DcQ6xogO.mjs} +1926 -1782
- package/dist/_chunks/index-DcQ6xogO.mjs.map +1 -0
- package/dist/_chunks/{layout-C6dxWYT7.js → layout-B4aCAdTt.js} +5 -4
- package/dist/_chunks/{layout-C6dxWYT7.js.map → layout-B4aCAdTt.js.map} +1 -1
- package/dist/_chunks/{layout-BNqvLR_b.mjs → layout-BavJ6v4B.mjs} +5 -4
- package/dist/_chunks/{layout-BNqvLR_b.mjs.map → layout-BavJ6v4B.mjs.map} +1 -1
- package/dist/_chunks/{relations-CkKqKw65.mjs → relations-DMG453Od.mjs} +2 -2
- package/dist/_chunks/{relations-CkKqKw65.mjs.map → relations-DMG453Od.mjs.map} +1 -1
- package/dist/_chunks/{relations-DtFaDnP1.js → relations-Lrm9nz_m.js} +2 -2
- package/dist/_chunks/{relations-DtFaDnP1.js.map → relations-Lrm9nz_m.js.map} +1 -1
- package/dist/_chunks/{usePrev-B9w_-eYc.js → useDebounce-CtcjDB3L.js} +14 -1
- package/dist/_chunks/useDebounce-CtcjDB3L.js.map +1 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs +29 -0
- package/dist/_chunks/useDebounce-DmuSJIF3.mjs.map +1 -0
- package/dist/admin/index.js +2 -1
- package/dist/admin/index.js.map +1 -1
- package/dist/admin/index.mjs +5 -4
- package/dist/admin/src/exports.d.ts +1 -1
- package/dist/admin/src/history/services/historyVersion.d.ts +1 -1
- package/dist/admin/src/hooks/useDocument.d.ts +32 -1
- package/dist/admin/src/pages/EditView/components/FormInputs/Wysiwyg/WysiwygStyles.d.ts +0 -32
- 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 +117 -53
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +117 -53
- 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/utils/metadata.d.ts +15 -1
- package/dist/server/src/controllers/utils/metadata.d.ts.map +1 -1
- package/dist/server/src/history/services/history.d.ts.map +1 -1
- package/dist/server/src/history/services/lifecycles.d.ts.map +1 -1
- package/dist/server/src/history/services/utils.d.ts +1 -0
- package/dist/server/src/history/services/utils.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +4 -4
- package/dist/server/src/policies/hasPermissions.d.ts.map +1 -1
- package/dist/server/src/services/document-metadata.d.ts +8 -8
- package/dist/server/src/services/document-metadata.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +4 -4
- package/dist/server/src/services/permission-checker.d.ts.map +1 -1
- package/dist/server/src/services/utils/configuration/index.d.ts +2 -2
- package/dist/server/src/services/utils/configuration/layouts.d.ts +2 -2
- package/dist/server/src/utils/index.d.ts +2 -0
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/dist/shared/contracts/collection-types.d.ts +3 -1
- package/dist/shared/contracts/collection-types.d.ts.map +1 -1
- package/package.json +12 -12
- package/dist/_chunks/EditViewPage-B7VgwJaG.mjs.map +0 -1
- package/dist/_chunks/EditViewPage-BgjdnGz2.js.map +0 -1
- package/dist/_chunks/Field-CdK7ZLmv.js.map +0 -1
- package/dist/_chunks/Field-tHCw4lGA.mjs.map +0 -1
- package/dist/_chunks/Form-BJxdTv3Q.mjs.map +0 -1
- package/dist/_chunks/Form-C_0KTVvV.js.map +0 -1
- package/dist/_chunks/History-DR2txJLE.mjs.map +0 -1
- package/dist/_chunks/History-nuEzM5qm.js.map +0 -1
- package/dist/_chunks/ListViewPage-B_GaWgRH.mjs.map +0 -1
- package/dist/_chunks/ListViewPage-SXIXm-RM.js.map +0 -1
- package/dist/_chunks/Relations-CIYDdKU-.mjs.map +0 -1
- package/dist/_chunks/Relations-Dhuurpx2.js.map +0 -1
- package/dist/_chunks/index-C9TJPyni.mjs.map +0 -1
- package/dist/_chunks/index-CdT0kHZ8.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
@@ -4,12 +4,13 @@ const jsxRuntime = require("react/jsx-runtime");
|
|
4
4
|
const strapiAdmin = require("@strapi/admin/strapi-admin");
|
5
5
|
const React = require("react");
|
6
6
|
const designSystem = require("@strapi/design-system");
|
7
|
+
const mapValues = require("lodash/fp/mapValues");
|
7
8
|
const reactIntl = require("react-intl");
|
8
9
|
const reactRouterDom = require("react-router-dom");
|
9
|
-
const styledComponents = require("styled-components");
|
10
10
|
const yup = require("yup");
|
11
11
|
const pipe = require("lodash/fp/pipe");
|
12
12
|
const dateFns = require("date-fns");
|
13
|
+
const styledComponents = require("styled-components");
|
13
14
|
const qs = require("qs");
|
14
15
|
const toolkit = require("@reduxjs/toolkit");
|
15
16
|
const _interopDefault = (e) => e && e.__esModule ? e : { default: e };
|
@@ -32,6 +33,7 @@ function _interopNamespace(e) {
|
|
32
33
|
return Object.freeze(n);
|
33
34
|
}
|
34
35
|
const React__namespace = /* @__PURE__ */ _interopNamespace(React);
|
36
|
+
const mapValues__default = /* @__PURE__ */ _interopDefault(mapValues);
|
35
37
|
const yup__namespace = /* @__PURE__ */ _interopNamespace(yup);
|
36
38
|
const pipe__default = /* @__PURE__ */ _interopDefault(pipe);
|
37
39
|
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
@@ -121,6 +123,7 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
121
123
|
if (!slug) {
|
122
124
|
throw new Error("Cannot find the slug param in the URL");
|
123
125
|
}
|
126
|
+
const [{ rawQuery }] = strapiAdmin.useQueryParams();
|
124
127
|
const userPermissions = strapiAdmin.useAuth("DocumentRBAC", (state) => state.permissions);
|
125
128
|
const contentTypePermissions = React__namespace.useMemo(() => {
|
126
129
|
const contentTypePermissions2 = userPermissions.filter(
|
@@ -131,7 +134,14 @@ const DocumentRBAC = ({ children, permissions }) => {
|
|
131
134
|
return { ...acc, [action]: [permission] };
|
132
135
|
}, {});
|
133
136
|
}, [slug, userPermissions]);
|
134
|
-
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
137
|
+
const { isLoading, allowedActions } = strapiAdmin.useRBAC(
|
138
|
+
contentTypePermissions,
|
139
|
+
permissions ?? void 0,
|
140
|
+
// TODO: useRBAC context should be typed and built differently
|
141
|
+
// We are passing raw query as context to the hook so that it can
|
142
|
+
// rely on the locale provided from DocumentRBAC for its permission calculations.
|
143
|
+
rawQuery
|
144
|
+
);
|
135
145
|
const canCreateFields = !isLoading && allowedActions.canCreate ? extractAndDedupeFields(contentTypePermissions.create) : [];
|
136
146
|
const canReadFields = !isLoading && allowedActions.canRead ? extractAndDedupeFields(contentTypePermissions.read) : [];
|
137
147
|
const canUpdateFields = !isLoading && allowedActions.canUpdate ? extractAndDedupeFields(contentTypePermissions.update) : [];
|
@@ -179,7 +189,8 @@ const contentManagerApi = strapiAdmin.adminApi.enhanceEndpoints({
|
|
179
189
|
"Document",
|
180
190
|
"InitialData",
|
181
191
|
"HistoryVersion",
|
182
|
-
"Relations"
|
192
|
+
"Relations",
|
193
|
+
"UidAvailability"
|
183
194
|
]
|
184
195
|
});
|
185
196
|
const documentApi = contentManagerApi.injectEndpoints({
|
@@ -209,7 +220,10 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
209
220
|
params
|
210
221
|
}
|
211
222
|
}),
|
212
|
-
invalidatesTags: (_result, _error, { model }) => [
|
223
|
+
invalidatesTags: (_result, _error, { model }) => [
|
224
|
+
{ type: "Document", id: `${model}_LIST` },
|
225
|
+
{ type: "UidAvailability", id: model }
|
226
|
+
]
|
213
227
|
}),
|
214
228
|
/**
|
215
229
|
* Creates a new collection-type document. This should ONLY be used for collection-types.
|
@@ -226,7 +240,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
226
240
|
}),
|
227
241
|
invalidatesTags: (result, _error, { model }) => [
|
228
242
|
{ type: "Document", id: `${model}_LIST` },
|
229
|
-
"Relations"
|
243
|
+
"Relations",
|
244
|
+
{ type: "UidAvailability", id: model }
|
230
245
|
]
|
231
246
|
}),
|
232
247
|
deleteDocument: builder.mutation({
|
@@ -267,7 +282,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
267
282
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
268
283
|
},
|
269
284
|
{ type: "Document", id: `${model}_LIST` },
|
270
|
-
"Relations"
|
285
|
+
"Relations",
|
286
|
+
{ type: "UidAvailability", id: model }
|
271
287
|
];
|
272
288
|
}
|
273
289
|
}),
|
@@ -392,7 +408,8 @@ const documentApi = contentManagerApi.injectEndpoints({
|
|
392
408
|
type: "Document",
|
393
409
|
id: collectionType !== SINGLE_TYPES ? `${model}_${documentId}` : model
|
394
410
|
},
|
395
|
-
"Relations"
|
411
|
+
"Relations",
|
412
|
+
{ type: "UidAvailability", id: model }
|
396
413
|
];
|
397
414
|
},
|
398
415
|
async onQueryStarted({ data, ...patch }, { dispatch, queryFulfilled }) {
|
@@ -475,20 +492,39 @@ const buildValidParams = (query) => {
|
|
475
492
|
const isBaseQueryError = (error) => {
|
476
493
|
return error.name !== void 0;
|
477
494
|
};
|
478
|
-
const
|
495
|
+
const arrayValidator = (attribute, options) => ({
|
496
|
+
message: strapiAdmin.translatedErrors.required,
|
497
|
+
test(value) {
|
498
|
+
if (options.status === "draft") {
|
499
|
+
return true;
|
500
|
+
}
|
501
|
+
if (!attribute.required) {
|
502
|
+
return true;
|
503
|
+
}
|
504
|
+
if (!value) {
|
505
|
+
return false;
|
506
|
+
}
|
507
|
+
if (Array.isArray(value) && value.length === 0) {
|
508
|
+
return false;
|
509
|
+
}
|
510
|
+
return true;
|
511
|
+
}
|
512
|
+
});
|
513
|
+
const createYupSchema = (attributes = {}, components = {}, options = { status: null }) => {
|
479
514
|
const createModelSchema = (attributes2) => yup__namespace.object().shape(
|
480
515
|
Object.entries(attributes2).reduce((acc, [name, attribute]) => {
|
481
516
|
if (DOCUMENT_META_FIELDS.includes(name)) {
|
482
517
|
return acc;
|
483
518
|
}
|
484
519
|
const validations = [
|
520
|
+
addNullableValidation,
|
485
521
|
addRequiredValidation,
|
486
522
|
addMinLengthValidation,
|
487
523
|
addMaxLengthValidation,
|
488
524
|
addMinValidation,
|
489
525
|
addMaxValidation,
|
490
526
|
addRegexValidation
|
491
|
-
].map((fn) => fn(attribute));
|
527
|
+
].map((fn) => fn(attribute, options));
|
492
528
|
const transformSchema = pipe__default.default(...validations);
|
493
529
|
switch (attribute.type) {
|
494
530
|
case "component": {
|
@@ -498,12 +534,12 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
498
534
|
...acc,
|
499
535
|
[name]: transformSchema(
|
500
536
|
yup__namespace.array().of(createModelSchema(attributes3).nullable(false))
|
501
|
-
)
|
537
|
+
).test(arrayValidator(attribute, options))
|
502
538
|
};
|
503
539
|
} else {
|
504
540
|
return {
|
505
541
|
...acc,
|
506
|
-
[name]: transformSchema(createModelSchema(attributes3))
|
542
|
+
[name]: transformSchema(createModelSchema(attributes3).nullable())
|
507
543
|
};
|
508
544
|
}
|
509
545
|
}
|
@@ -525,7 +561,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
525
561
|
}
|
526
562
|
)
|
527
563
|
)
|
528
|
-
)
|
564
|
+
).test(arrayValidator(attribute, options))
|
529
565
|
};
|
530
566
|
case "relation":
|
531
567
|
return {
|
@@ -537,7 +573,7 @@ const createYupSchema = (attributes = {}, components = {}) => {
|
|
537
573
|
} else if (Array.isArray(value)) {
|
538
574
|
return yup__namespace.array().of(
|
539
575
|
yup__namespace.object().shape({
|
540
|
-
id: yup__namespace.
|
576
|
+
id: yup__namespace.number().required()
|
541
577
|
})
|
542
578
|
);
|
543
579
|
} else if (typeof value === "object") {
|
@@ -615,13 +651,7 @@ const createAttributeSchema = (attribute) => {
|
|
615
651
|
return yup__namespace.mixed();
|
616
652
|
}
|
617
653
|
};
|
618
|
-
const
|
619
|
-
if ((attribute.type === "component" && attribute.repeatable || attribute.type === "dynamiczone") && attribute.required && "min" in schema) {
|
620
|
-
return schema.min(1, strapiAdmin.translatedErrors.required);
|
621
|
-
}
|
622
|
-
if (attribute.required && attribute.type !== "relation") {
|
623
|
-
return schema.required(strapiAdmin.translatedErrors.required);
|
624
|
-
}
|
654
|
+
const nullableSchema = (schema) => {
|
625
655
|
return schema?.nullable ? schema.nullable() : (
|
626
656
|
// In some cases '.nullable' will not be available on the schema.
|
627
657
|
// e.g. when the schema has been built using yup.lazy (e.g. for relations).
|
@@ -629,7 +659,22 @@ const addRequiredValidation = (attribute) => (schema) => {
|
|
629
659
|
schema
|
630
660
|
);
|
631
661
|
};
|
632
|
-
const
|
662
|
+
const addNullableValidation = () => (schema) => {
|
663
|
+
return nullableSchema(schema);
|
664
|
+
};
|
665
|
+
const addRequiredValidation = (attribute, options) => (schema) => {
|
666
|
+
if (options.status === "draft" || !attribute.required) {
|
667
|
+
return schema;
|
668
|
+
}
|
669
|
+
if (attribute.required && "required" in schema) {
|
670
|
+
return schema.required(strapiAdmin.translatedErrors.required);
|
671
|
+
}
|
672
|
+
return schema;
|
673
|
+
};
|
674
|
+
const addMinLengthValidation = (attribute, options) => (schema) => {
|
675
|
+
if (options.status === "draft") {
|
676
|
+
return schema;
|
677
|
+
}
|
633
678
|
if ("minLength" in attribute && attribute.minLength && Number.isInteger(attribute.minLength) && "min" in schema) {
|
634
679
|
return schema.min(attribute.minLength, {
|
635
680
|
...strapiAdmin.translatedErrors.minLength,
|
@@ -651,32 +696,13 @@ const addMaxLengthValidation = (attribute) => (schema) => {
|
|
651
696
|
}
|
652
697
|
return schema;
|
653
698
|
};
|
654
|
-
const addMinValidation = (attribute) => (schema) => {
|
655
|
-
if ("
|
699
|
+
const addMinValidation = (attribute, options) => (schema) => {
|
700
|
+
if (options.status === "draft") {
|
701
|
+
return schema;
|
702
|
+
}
|
703
|
+
if ("min" in attribute && "min" in schema) {
|
656
704
|
const min = toInteger(attribute.min);
|
657
|
-
if (
|
658
|
-
if (!attribute.required && "test" in schema && min) {
|
659
|
-
return schema.test(
|
660
|
-
"custom-min",
|
661
|
-
{
|
662
|
-
...strapiAdmin.translatedErrors.min,
|
663
|
-
values: {
|
664
|
-
min: attribute.min
|
665
|
-
}
|
666
|
-
},
|
667
|
-
(value) => {
|
668
|
-
if (!value) {
|
669
|
-
return true;
|
670
|
-
}
|
671
|
-
if (Array.isArray(value) && value.length === 0) {
|
672
|
-
return true;
|
673
|
-
}
|
674
|
-
return value.length >= min;
|
675
|
-
}
|
676
|
-
);
|
677
|
-
}
|
678
|
-
}
|
679
|
-
if ("min" in schema && min) {
|
705
|
+
if (min) {
|
680
706
|
return schema.min(min, {
|
681
707
|
...strapiAdmin.translatedErrors.min,
|
682
708
|
values: {
|
@@ -794,19 +820,115 @@ const extractContentTypeComponents = (attributes = {}, allComponents = {}) => {
|
|
794
820
|
}, {});
|
795
821
|
return componentsByKey;
|
796
822
|
};
|
797
|
-
const
|
823
|
+
const HOOKS = {
|
824
|
+
/**
|
825
|
+
* Hook that allows to mutate the displayed headers of the list view table
|
826
|
+
* @constant
|
827
|
+
* @type {string}
|
828
|
+
*/
|
829
|
+
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
830
|
+
/**
|
831
|
+
* Hook that allows to mutate the CM's collection types links pre-set filters
|
832
|
+
* @constant
|
833
|
+
* @type {string}
|
834
|
+
*/
|
835
|
+
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
836
|
+
/**
|
837
|
+
* Hook that allows to mutate the CM's edit view layout
|
838
|
+
* @constant
|
839
|
+
* @type {string}
|
840
|
+
*/
|
841
|
+
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
842
|
+
/**
|
843
|
+
* Hook that allows to mutate the CM's single types links pre-set filters
|
844
|
+
* @constant
|
845
|
+
* @type {string}
|
846
|
+
*/
|
847
|
+
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
848
|
+
};
|
849
|
+
const contentTypesApi = contentManagerApi.injectEndpoints({
|
850
|
+
endpoints: (builder) => ({
|
851
|
+
getContentTypeConfiguration: builder.query({
|
852
|
+
query: (uid) => ({
|
853
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
854
|
+
method: "GET"
|
855
|
+
}),
|
856
|
+
transformResponse: (response) => response.data,
|
857
|
+
providesTags: (_result, _error, uid) => [
|
858
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
859
|
+
{ type: "ContentTypeSettings", id: "LIST" }
|
860
|
+
]
|
861
|
+
}),
|
862
|
+
getAllContentTypeSettings: builder.query({
|
863
|
+
query: () => "/content-manager/content-types-settings",
|
864
|
+
transformResponse: (response) => response.data,
|
865
|
+
providesTags: [{ type: "ContentTypeSettings", id: "LIST" }]
|
866
|
+
}),
|
867
|
+
updateContentTypeConfiguration: builder.mutation({
|
868
|
+
query: ({ uid, ...body }) => ({
|
869
|
+
url: `/content-manager/content-types/${uid}/configuration`,
|
870
|
+
method: "PUT",
|
871
|
+
data: body
|
872
|
+
}),
|
873
|
+
transformResponse: (response) => response.data,
|
874
|
+
invalidatesTags: (_result, _error, { uid }) => [
|
875
|
+
{ type: "ContentTypesConfiguration", id: uid },
|
876
|
+
{ type: "ContentTypeSettings", id: "LIST" },
|
877
|
+
// Is this necessary?
|
878
|
+
{ type: "InitialData" }
|
879
|
+
]
|
880
|
+
})
|
881
|
+
})
|
882
|
+
});
|
883
|
+
const {
|
884
|
+
useGetContentTypeConfigurationQuery,
|
885
|
+
useGetAllContentTypeSettingsQuery,
|
886
|
+
useUpdateContentTypeConfigurationMutation
|
887
|
+
} = contentTypesApi;
|
888
|
+
const checkIfAttributeIsDisplayable = (attribute) => {
|
889
|
+
const { type } = attribute;
|
890
|
+
if (type === "relation") {
|
891
|
+
return !attribute.relation.toLowerCase().includes("morph");
|
892
|
+
}
|
893
|
+
return !["json", "dynamiczone", "richtext", "password", "blocks"].includes(type) && !!type;
|
894
|
+
};
|
895
|
+
const getMainField = (attribute, mainFieldName, { schemas, components }) => {
|
896
|
+
if (!mainFieldName) {
|
897
|
+
return void 0;
|
898
|
+
}
|
899
|
+
const mainFieldType = attribute.type === "component" ? components[attribute.component].attributes[mainFieldName].type : (
|
900
|
+
// @ts-expect-error – `targetModel` does exist on the attribute for a relation.
|
901
|
+
schemas.find((schema) => schema.uid === attribute.targetModel)?.attributes[mainFieldName].type
|
902
|
+
);
|
903
|
+
return {
|
904
|
+
name: mainFieldName,
|
905
|
+
type: mainFieldType ?? "string"
|
906
|
+
};
|
907
|
+
};
|
908
|
+
const DEFAULT_SETTINGS = {
|
909
|
+
bulkable: false,
|
910
|
+
filterable: false,
|
911
|
+
searchable: false,
|
912
|
+
pagination: false,
|
913
|
+
defaultSortBy: "",
|
914
|
+
defaultSortOrder: "asc",
|
915
|
+
mainField: "id",
|
916
|
+
pageSize: 10
|
917
|
+
};
|
918
|
+
const useDocumentLayout = (model) => {
|
919
|
+
const { schema, components } = useDocument({ model, collectionType: "" }, { skip: true });
|
920
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
921
|
+
const runHookWaterfall = strapiAdmin.useStrapiApp("useDocumentLayout", (state) => state.runHookWaterfall);
|
798
922
|
const { toggleNotification } = strapiAdmin.useNotification();
|
799
923
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
924
|
+
const { isLoading: isLoadingSchemas, schemas } = useContentTypeSchema();
|
800
925
|
const {
|
801
|
-
|
802
|
-
isLoading:
|
803
|
-
|
804
|
-
|
805
|
-
} =
|
806
|
-
|
807
|
-
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
808
|
-
});
|
809
|
-
const { components, schema, isLoading: isLoadingSchema } = useContentTypeSchema(args.model);
|
926
|
+
data,
|
927
|
+
isLoading: isLoadingConfigs,
|
928
|
+
error,
|
929
|
+
isFetching: isFetchingConfigs
|
930
|
+
} = useGetContentTypeConfigurationQuery(model);
|
931
|
+
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
810
932
|
React__namespace.useEffect(() => {
|
811
933
|
if (error) {
|
812
934
|
toggleNotification({
|
@@ -814,362 +936,440 @@ const useDocument = (args, opts) => {
|
|
814
936
|
message: formatAPIError(error)
|
815
937
|
});
|
816
938
|
}
|
817
|
-
}, [
|
818
|
-
const
|
819
|
-
|
820
|
-
|
821
|
-
|
822
|
-
|
823
|
-
|
824
|
-
|
825
|
-
(document) => {
|
826
|
-
if (!validationSchema) {
|
827
|
-
throw new Error(
|
828
|
-
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
829
|
-
);
|
830
|
-
}
|
831
|
-
try {
|
832
|
-
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
833
|
-
return null;
|
834
|
-
} catch (error2) {
|
835
|
-
if (error2 instanceof yup.ValidationError) {
|
836
|
-
return strapiAdmin.getYupValidationErrors(error2);
|
837
|
-
}
|
838
|
-
throw error2;
|
839
|
-
}
|
939
|
+
}, [error, formatAPIError, toggleNotification]);
|
940
|
+
const editLayout = React__namespace.useMemo(
|
941
|
+
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
942
|
+
layout: [],
|
943
|
+
components: {},
|
944
|
+
metadatas: {},
|
945
|
+
options: {},
|
946
|
+
settings: DEFAULT_SETTINGS
|
840
947
|
},
|
841
|
-
[
|
948
|
+
[data, isLoading, schemas, schema, components]
|
949
|
+
);
|
950
|
+
const listLayout = React__namespace.useMemo(() => {
|
951
|
+
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
952
|
+
layout: [],
|
953
|
+
metadatas: {},
|
954
|
+
options: {},
|
955
|
+
settings: DEFAULT_SETTINGS
|
956
|
+
};
|
957
|
+
}, [data, isLoading, schemas, schema, components]);
|
958
|
+
const { layout: edit } = React__namespace.useMemo(
|
959
|
+
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
960
|
+
layout: editLayout,
|
961
|
+
query
|
962
|
+
}),
|
963
|
+
[editLayout, query, runHookWaterfall]
|
842
964
|
);
|
843
|
-
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
844
965
|
return {
|
845
|
-
|
846
|
-
document: data?.data,
|
847
|
-
meta: data?.meta,
|
966
|
+
error,
|
848
967
|
isLoading,
|
849
|
-
|
850
|
-
|
851
|
-
};
|
852
|
-
};
|
853
|
-
const useDoc = () => {
|
854
|
-
const { id, slug, collectionType, origin } = reactRouterDom.useParams();
|
855
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
856
|
-
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
857
|
-
if (!collectionType) {
|
858
|
-
throw new Error("Could not find collectionType in url params");
|
859
|
-
}
|
860
|
-
if (!slug) {
|
861
|
-
throw new Error("Could not find model in url params");
|
862
|
-
}
|
863
|
-
return {
|
864
|
-
collectionType,
|
865
|
-
model: slug,
|
866
|
-
id: origin || id === "create" ? void 0 : id,
|
867
|
-
...useDocument(
|
868
|
-
{ documentId: origin || id, model: slug, collectionType, params },
|
869
|
-
{
|
870
|
-
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
871
|
-
}
|
872
|
-
)
|
968
|
+
edit,
|
969
|
+
list: listLayout
|
873
970
|
};
|
874
971
|
};
|
875
|
-
const
|
876
|
-
|
877
|
-
|
878
|
-
}
|
879
|
-
return Object.keys(trad).reduce((acc, current) => {
|
880
|
-
acc[`${pluginId}.${current}`] = trad[current];
|
881
|
-
return acc;
|
882
|
-
}, {});
|
883
|
-
};
|
884
|
-
const getTranslation = (id) => `content-manager.${id}`;
|
885
|
-
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
886
|
-
id: "notification.error",
|
887
|
-
defaultMessage: "An error occurred, please try again"
|
972
|
+
const useDocLayout = () => {
|
973
|
+
const { model } = useDoc();
|
974
|
+
return useDocumentLayout(model);
|
888
975
|
};
|
889
|
-
const
|
890
|
-
|
891
|
-
|
892
|
-
|
893
|
-
|
894
|
-
|
895
|
-
const
|
896
|
-
|
897
|
-
|
898
|
-
|
899
|
-
|
900
|
-
|
901
|
-
|
902
|
-
|
903
|
-
|
904
|
-
|
905
|
-
|
906
|
-
|
907
|
-
|
908
|
-
message: formatAPIError(res.error)
|
909
|
-
});
|
910
|
-
return { error: res.error };
|
911
|
-
}
|
912
|
-
toggleNotification({
|
913
|
-
type: "success",
|
914
|
-
message: formatMessage({
|
915
|
-
id: getTranslation("success.record.delete"),
|
916
|
-
defaultMessage: "Deleted document"
|
917
|
-
})
|
918
|
-
});
|
919
|
-
trackUsage("didDeleteEntry", trackerProperty);
|
920
|
-
return res.data;
|
921
|
-
} catch (err) {
|
922
|
-
toggleNotification({
|
923
|
-
type: "danger",
|
924
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
925
|
-
});
|
926
|
-
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
927
|
-
throw err;
|
976
|
+
const formatEditLayout = (data, {
|
977
|
+
schemas,
|
978
|
+
schema,
|
979
|
+
components
|
980
|
+
}) => {
|
981
|
+
let currentPanelIndex = 0;
|
982
|
+
const panelledEditAttributes = convertEditLayoutToFieldLayouts(
|
983
|
+
data.contentType.layouts.edit,
|
984
|
+
schema?.attributes,
|
985
|
+
data.contentType.metadatas,
|
986
|
+
{ configurations: data.components, schemas: components },
|
987
|
+
schemas
|
988
|
+
).reduce((panels, row) => {
|
989
|
+
if (row.some((field) => field.type === "dynamiczone")) {
|
990
|
+
panels.push([row]);
|
991
|
+
currentPanelIndex += 2;
|
992
|
+
} else {
|
993
|
+
if (!panels[currentPanelIndex]) {
|
994
|
+
panels.push([]);
|
928
995
|
}
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
933
|
-
const
|
934
|
-
|
935
|
-
|
936
|
-
|
937
|
-
|
938
|
-
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
});
|
947
|
-
return { error: res.error };
|
996
|
+
panels[currentPanelIndex].push(row);
|
997
|
+
}
|
998
|
+
return panels;
|
999
|
+
}, []);
|
1000
|
+
const componentEditAttributes = Object.entries(data.components).reduce(
|
1001
|
+
(acc, [uid, configuration]) => {
|
1002
|
+
acc[uid] = {
|
1003
|
+
layout: convertEditLayoutToFieldLayouts(
|
1004
|
+
configuration.layouts.edit,
|
1005
|
+
components[uid].attributes,
|
1006
|
+
configuration.metadatas,
|
1007
|
+
{ configurations: data.components, schemas: components }
|
1008
|
+
),
|
1009
|
+
settings: {
|
1010
|
+
...configuration.settings,
|
1011
|
+
icon: components[uid].info.icon,
|
1012
|
+
displayName: components[uid].info.displayName
|
948
1013
|
}
|
949
|
-
|
950
|
-
|
951
|
-
title: formatMessage({
|
952
|
-
id: getTranslation("success.records.delete"),
|
953
|
-
defaultMessage: "Successfully deleted."
|
954
|
-
}),
|
955
|
-
message: ""
|
956
|
-
});
|
957
|
-
trackUsage("didBulkDeleteEntries");
|
958
|
-
return res.data;
|
959
|
-
} catch (err) {
|
960
|
-
toggleNotification({
|
961
|
-
type: "danger",
|
962
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
963
|
-
});
|
964
|
-
trackUsage("didNotBulkDeleteEntries");
|
965
|
-
throw err;
|
966
|
-
}
|
1014
|
+
};
|
1015
|
+
return acc;
|
967
1016
|
},
|
968
|
-
|
1017
|
+
{}
|
969
1018
|
);
|
970
|
-
const
|
971
|
-
|
972
|
-
|
973
|
-
|
974
|
-
|
975
|
-
|
976
|
-
model,
|
977
|
-
documentId,
|
978
|
-
params
|
979
|
-
});
|
980
|
-
if ("error" in res) {
|
981
|
-
toggleNotification({
|
982
|
-
type: "danger",
|
983
|
-
message: formatAPIError(res.error)
|
984
|
-
});
|
985
|
-
return { error: res.error };
|
986
|
-
}
|
987
|
-
toggleNotification({
|
988
|
-
type: "success",
|
989
|
-
message: formatMessage({
|
990
|
-
id: "content-manager.success.record.discard",
|
991
|
-
defaultMessage: "Changes discarded"
|
992
|
-
})
|
993
|
-
});
|
994
|
-
return res.data;
|
995
|
-
} catch (err) {
|
996
|
-
toggleNotification({
|
997
|
-
type: "danger",
|
998
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
999
|
-
});
|
1000
|
-
throw err;
|
1001
|
-
}
|
1019
|
+
const editMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1020
|
+
(acc, [attribute, metadata]) => {
|
1021
|
+
return {
|
1022
|
+
...acc,
|
1023
|
+
[attribute]: metadata.edit
|
1024
|
+
};
|
1002
1025
|
},
|
1003
|
-
|
1026
|
+
{}
|
1004
1027
|
);
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
|
1010
|
-
|
1011
|
-
|
1012
|
-
model,
|
1013
|
-
documentId,
|
1014
|
-
data,
|
1015
|
-
params
|
1016
|
-
});
|
1017
|
-
if ("error" in res) {
|
1018
|
-
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1019
|
-
return { error: res.error };
|
1020
|
-
}
|
1021
|
-
trackUsage("didPublishEntry");
|
1022
|
-
toggleNotification({
|
1023
|
-
type: "success",
|
1024
|
-
message: formatMessage({
|
1025
|
-
id: getTranslation("success.record.publish"),
|
1026
|
-
defaultMessage: "Published document"
|
1027
|
-
})
|
1028
|
-
});
|
1029
|
-
return res.data;
|
1030
|
-
} catch (err) {
|
1031
|
-
toggleNotification({
|
1032
|
-
type: "danger",
|
1033
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1034
|
-
});
|
1035
|
-
throw err;
|
1036
|
-
}
|
1028
|
+
return {
|
1029
|
+
layout: panelledEditAttributes,
|
1030
|
+
components: componentEditAttributes,
|
1031
|
+
metadatas: editMetadatas,
|
1032
|
+
settings: {
|
1033
|
+
...data.contentType.settings,
|
1034
|
+
displayName: schema?.info.displayName
|
1037
1035
|
},
|
1038
|
-
|
1039
|
-
|
1040
|
-
|
1041
|
-
|
1042
|
-
|
1043
|
-
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1048
|
-
|
1049
|
-
|
1050
|
-
|
1051
|
-
return { error: res.error };
|
1052
|
-
}
|
1053
|
-
toggleNotification({
|
1054
|
-
type: "success",
|
1055
|
-
message: formatMessage({
|
1056
|
-
id: getTranslation("success.record.publish"),
|
1057
|
-
defaultMessage: "Published document"
|
1058
|
-
})
|
1059
|
-
});
|
1060
|
-
return res.data;
|
1061
|
-
} catch (err) {
|
1062
|
-
toggleNotification({
|
1063
|
-
type: "danger",
|
1064
|
-
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1065
|
-
});
|
1066
|
-
throw err;
|
1036
|
+
options: {
|
1037
|
+
...schema?.options,
|
1038
|
+
...schema?.pluginOptions,
|
1039
|
+
...data.contentType.options
|
1040
|
+
}
|
1041
|
+
};
|
1042
|
+
};
|
1043
|
+
const convertEditLayoutToFieldLayouts = (rows, attributes = {}, metadatas, components, schemas = []) => {
|
1044
|
+
return rows.map(
|
1045
|
+
(row) => row.map((field) => {
|
1046
|
+
const attribute = attributes[field.name];
|
1047
|
+
if (!attribute) {
|
1048
|
+
return null;
|
1067
1049
|
}
|
1068
|
-
|
1069
|
-
|
1070
|
-
|
1071
|
-
|
1072
|
-
|
1073
|
-
|
1074
|
-
|
1075
|
-
|
1050
|
+
const { edit: metadata } = metadatas[field.name];
|
1051
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1052
|
+
return {
|
1053
|
+
attribute,
|
1054
|
+
disabled: !metadata.editable,
|
1055
|
+
hint: metadata.description,
|
1056
|
+
label: metadata.label ?? "",
|
1057
|
+
name: field.name,
|
1058
|
+
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
1059
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1060
|
+
schemas,
|
1061
|
+
components: components?.schemas ?? {}
|
1062
|
+
}),
|
1063
|
+
placeholder: metadata.placeholder ?? "",
|
1064
|
+
required: attribute.required ?? false,
|
1065
|
+
size: field.size,
|
1066
|
+
unique: "unique" in attribute ? attribute.unique : false,
|
1067
|
+
visible: metadata.visible ?? true,
|
1068
|
+
type: attribute.type
|
1069
|
+
};
|
1070
|
+
}).filter((field) => field !== null)
|
1076
1071
|
);
|
1077
|
-
|
1078
|
-
|
1079
|
-
|
1080
|
-
|
1081
|
-
|
1082
|
-
|
1072
|
+
};
|
1073
|
+
const formatListLayout = (data, {
|
1074
|
+
schemas,
|
1075
|
+
schema,
|
1076
|
+
components
|
1077
|
+
}) => {
|
1078
|
+
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
1079
|
+
(acc, [attribute, metadata]) => {
|
1080
|
+
return {
|
1081
|
+
...acc,
|
1082
|
+
[attribute]: metadata.list
|
1083
|
+
};
|
1084
|
+
},
|
1085
|
+
{}
|
1086
|
+
);
|
1087
|
+
const listAttributes = convertListLayoutToFieldLayouts(
|
1088
|
+
data.contentType.layouts.list,
|
1089
|
+
schema?.attributes,
|
1090
|
+
listMetadatas,
|
1091
|
+
{ configurations: data.components, schemas: components },
|
1092
|
+
schemas
|
1093
|
+
);
|
1094
|
+
return {
|
1095
|
+
layout: listAttributes,
|
1096
|
+
settings: { ...data.contentType.settings, displayName: schema?.info.displayName },
|
1097
|
+
metadatas: listMetadatas,
|
1098
|
+
options: {
|
1099
|
+
...schema?.options,
|
1100
|
+
...schema?.pluginOptions,
|
1101
|
+
...data.contentType.options
|
1102
|
+
}
|
1103
|
+
};
|
1104
|
+
};
|
1105
|
+
const convertListLayoutToFieldLayouts = (columns, attributes = {}, metadatas, components, schemas = []) => {
|
1106
|
+
return columns.map((name) => {
|
1107
|
+
const attribute = attributes[name];
|
1108
|
+
if (!attribute) {
|
1109
|
+
return null;
|
1110
|
+
}
|
1111
|
+
const metadata = metadatas[name];
|
1112
|
+
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
1113
|
+
return {
|
1114
|
+
attribute,
|
1115
|
+
label: metadata.label ?? "",
|
1116
|
+
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
1117
|
+
schemas,
|
1118
|
+
components: components?.schemas ?? {}
|
1119
|
+
}),
|
1120
|
+
name,
|
1121
|
+
searchable: metadata.searchable ?? true,
|
1122
|
+
sortable: metadata.sortable ?? true
|
1123
|
+
};
|
1124
|
+
}).filter((field) => field !== null);
|
1125
|
+
};
|
1126
|
+
const useDocument = (args, opts) => {
|
1127
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
1128
|
+
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1129
|
+
const {
|
1130
|
+
currentData: data,
|
1131
|
+
isLoading: isLoadingDocument,
|
1132
|
+
isFetching: isFetchingDocument,
|
1133
|
+
error
|
1134
|
+
} = useGetDocumentQuery(args, {
|
1135
|
+
...opts,
|
1136
|
+
skip: !args.documentId && args.collectionType !== SINGLE_TYPES || opts?.skip
|
1137
|
+
});
|
1138
|
+
const {
|
1139
|
+
components,
|
1140
|
+
schema,
|
1141
|
+
schemas,
|
1142
|
+
isLoading: isLoadingSchema
|
1143
|
+
} = useContentTypeSchema(args.model);
|
1144
|
+
React__namespace.useEffect(() => {
|
1145
|
+
if (error) {
|
1146
|
+
toggleNotification({
|
1147
|
+
type: "danger",
|
1148
|
+
message: formatAPIError(error)
|
1149
|
+
});
|
1150
|
+
}
|
1151
|
+
}, [toggleNotification, error, formatAPIError, args.collectionType]);
|
1152
|
+
const validationSchema = React__namespace.useMemo(() => {
|
1153
|
+
if (!schema) {
|
1154
|
+
return null;
|
1155
|
+
}
|
1156
|
+
return createYupSchema(schema.attributes, components);
|
1157
|
+
}, [schema, components]);
|
1158
|
+
const validate = React__namespace.useCallback(
|
1159
|
+
(document) => {
|
1160
|
+
if (!validationSchema) {
|
1161
|
+
throw new Error(
|
1162
|
+
"There is no validation schema generated, this is likely due to the schema not being loaded yet."
|
1163
|
+
);
|
1164
|
+
}
|
1165
|
+
try {
|
1166
|
+
validationSchema.validateSync(document, { abortEarly: false, strict: true });
|
1167
|
+
return null;
|
1168
|
+
} catch (error2) {
|
1169
|
+
if (error2 instanceof yup.ValidationError) {
|
1170
|
+
return strapiAdmin.getYupValidationErrors(error2);
|
1171
|
+
}
|
1172
|
+
throw error2;
|
1173
|
+
}
|
1174
|
+
},
|
1175
|
+
[validationSchema]
|
1176
|
+
);
|
1177
|
+
const isLoading = isLoadingDocument || isFetchingDocument || isLoadingSchema;
|
1178
|
+
const hasError = !!error;
|
1179
|
+
return {
|
1180
|
+
components,
|
1181
|
+
document: data?.data,
|
1182
|
+
meta: data?.meta,
|
1183
|
+
isLoading,
|
1184
|
+
hasError,
|
1185
|
+
schema,
|
1186
|
+
schemas,
|
1187
|
+
validate
|
1188
|
+
};
|
1189
|
+
};
|
1190
|
+
const useDoc = () => {
|
1191
|
+
const { id, slug, collectionType, origin } = reactRouterDom.useParams();
|
1192
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
1193
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1194
|
+
if (!collectionType) {
|
1195
|
+
throw new Error("Could not find collectionType in url params");
|
1196
|
+
}
|
1197
|
+
if (!slug) {
|
1198
|
+
throw new Error("Could not find model in url params");
|
1199
|
+
}
|
1200
|
+
const document = useDocument(
|
1201
|
+
{ documentId: origin || id, model: slug, collectionType, params },
|
1202
|
+
{
|
1203
|
+
skip: id === "create" || !origin && !id && collectionType !== SINGLE_TYPES
|
1204
|
+
}
|
1205
|
+
);
|
1206
|
+
const returnId = origin || id === "create" ? void 0 : id;
|
1207
|
+
return {
|
1208
|
+
collectionType,
|
1209
|
+
model: slug,
|
1210
|
+
id: returnId,
|
1211
|
+
...document
|
1212
|
+
};
|
1213
|
+
};
|
1214
|
+
const useContentManagerContext = () => {
|
1215
|
+
const {
|
1216
|
+
collectionType,
|
1217
|
+
model,
|
1218
|
+
id,
|
1219
|
+
components,
|
1220
|
+
isLoading: isLoadingDoc,
|
1221
|
+
schema,
|
1222
|
+
schemas
|
1223
|
+
} = useDoc();
|
1224
|
+
const layout = useDocumentLayout(model);
|
1225
|
+
const form = strapiAdmin.useForm("useContentManagerContext", (state) => state);
|
1226
|
+
const isSingleType = collectionType === SINGLE_TYPES;
|
1227
|
+
const slug = model;
|
1228
|
+
const isCreatingEntry = id === "create";
|
1229
|
+
useContentTypeSchema();
|
1230
|
+
const isLoading = isLoadingDoc || layout.isLoading;
|
1231
|
+
const error = layout.error;
|
1232
|
+
return {
|
1233
|
+
error,
|
1234
|
+
isLoading,
|
1235
|
+
// Base metadata
|
1236
|
+
model,
|
1237
|
+
collectionType,
|
1238
|
+
id,
|
1239
|
+
slug,
|
1240
|
+
isCreatingEntry,
|
1241
|
+
isSingleType,
|
1242
|
+
hasDraftAndPublish: schema?.options?.draftAndPublish ?? false,
|
1243
|
+
// All schema infos
|
1244
|
+
components,
|
1245
|
+
contentType: schema,
|
1246
|
+
contentTypes: schemas,
|
1247
|
+
// Form state
|
1248
|
+
form,
|
1249
|
+
// layout infos
|
1250
|
+
layout
|
1251
|
+
};
|
1252
|
+
};
|
1253
|
+
const prefixPluginTranslations = (trad, pluginId) => {
|
1254
|
+
if (!pluginId) {
|
1255
|
+
throw new TypeError("pluginId can't be empty");
|
1256
|
+
}
|
1257
|
+
return Object.keys(trad).reduce((acc, current) => {
|
1258
|
+
acc[`${pluginId}.${current}`] = trad[current];
|
1259
|
+
return acc;
|
1260
|
+
}, {});
|
1261
|
+
};
|
1262
|
+
const getTranslation = (id) => `content-manager.${id}`;
|
1263
|
+
const DEFAULT_UNEXPECTED_ERROR_MSG = {
|
1264
|
+
id: "notification.error",
|
1265
|
+
defaultMessage: "An error occurred, please try again"
|
1266
|
+
};
|
1267
|
+
const useDocumentActions = () => {
|
1268
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
1269
|
+
const { formatMessage } = reactIntl.useIntl();
|
1270
|
+
const { trackUsage } = strapiAdmin.useTracking();
|
1271
|
+
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler();
|
1272
|
+
const navigate = reactRouterDom.useNavigate();
|
1273
|
+
const setCurrentStep = strapiAdmin.useGuidedTour("useDocumentActions", (state) => state.setCurrentStep);
|
1274
|
+
const [deleteDocument] = useDeleteDocumentMutation();
|
1275
|
+
const _delete = React__namespace.useCallback(
|
1276
|
+
async ({ collectionType, model, documentId, params }, trackerProperty) => {
|
1277
|
+
try {
|
1278
|
+
trackUsage("willDeleteEntry", trackerProperty);
|
1279
|
+
const res = await deleteDocument({
|
1083
1280
|
collectionType,
|
1084
1281
|
model,
|
1085
1282
|
documentId,
|
1086
|
-
data,
|
1087
1283
|
params
|
1088
1284
|
});
|
1089
1285
|
if ("error" in res) {
|
1090
|
-
toggleNotification({
|
1091
|
-
|
1286
|
+
toggleNotification({
|
1287
|
+
type: "danger",
|
1288
|
+
message: formatAPIError(res.error)
|
1289
|
+
});
|
1092
1290
|
return { error: res.error };
|
1093
1291
|
}
|
1094
|
-
trackUsage("didEditEntry", trackerProperty);
|
1095
1292
|
toggleNotification({
|
1096
1293
|
type: "success",
|
1097
1294
|
message: formatMessage({
|
1098
|
-
id: getTranslation("success.record.
|
1099
|
-
defaultMessage: "
|
1295
|
+
id: getTranslation("success.record.delete"),
|
1296
|
+
defaultMessage: "Deleted document"
|
1100
1297
|
})
|
1101
1298
|
});
|
1299
|
+
trackUsage("didDeleteEntry", trackerProperty);
|
1102
1300
|
return res.data;
|
1103
1301
|
} catch (err) {
|
1104
|
-
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1105
1302
|
toggleNotification({
|
1106
1303
|
type: "danger",
|
1107
1304
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1108
1305
|
});
|
1306
|
+
trackUsage("didNotDeleteEntry", { error: err, ...trackerProperty });
|
1109
1307
|
throw err;
|
1110
1308
|
}
|
1111
1309
|
},
|
1112
|
-
[trackUsage,
|
1310
|
+
[trackUsage, deleteDocument, toggleNotification, formatMessage, formatAPIError]
|
1113
1311
|
);
|
1114
|
-
const [
|
1115
|
-
const
|
1116
|
-
async ({
|
1312
|
+
const [deleteManyDocuments] = useDeleteManyDocumentsMutation();
|
1313
|
+
const deleteMany = React__namespace.useCallback(
|
1314
|
+
async ({ model, documentIds, params }) => {
|
1117
1315
|
try {
|
1118
|
-
trackUsage("
|
1119
|
-
const res = await
|
1120
|
-
collectionType,
|
1316
|
+
trackUsage("willBulkDeleteEntries");
|
1317
|
+
const res = await deleteManyDocuments({
|
1121
1318
|
model,
|
1122
|
-
|
1123
|
-
params
|
1124
|
-
data: {
|
1125
|
-
discardDraft
|
1126
|
-
}
|
1319
|
+
documentIds,
|
1320
|
+
params
|
1127
1321
|
});
|
1128
1322
|
if ("error" in res) {
|
1129
|
-
toggleNotification({
|
1323
|
+
toggleNotification({
|
1324
|
+
type: "danger",
|
1325
|
+
message: formatAPIError(res.error)
|
1326
|
+
});
|
1130
1327
|
return { error: res.error };
|
1131
1328
|
}
|
1132
|
-
trackUsage("didUnpublishEntry");
|
1133
1329
|
toggleNotification({
|
1134
1330
|
type: "success",
|
1135
|
-
|
1136
|
-
id: getTranslation("success.
|
1137
|
-
defaultMessage: "
|
1138
|
-
})
|
1331
|
+
title: formatMessage({
|
1332
|
+
id: getTranslation("success.records.delete"),
|
1333
|
+
defaultMessage: "Successfully deleted."
|
1334
|
+
}),
|
1335
|
+
message: ""
|
1139
1336
|
});
|
1337
|
+
trackUsage("didBulkDeleteEntries");
|
1140
1338
|
return res.data;
|
1141
1339
|
} catch (err) {
|
1142
1340
|
toggleNotification({
|
1143
1341
|
type: "danger",
|
1144
1342
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1145
1343
|
});
|
1344
|
+
trackUsage("didNotBulkDeleteEntries");
|
1146
1345
|
throw err;
|
1147
1346
|
}
|
1148
1347
|
},
|
1149
|
-
[trackUsage,
|
1348
|
+
[trackUsage, deleteManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1150
1349
|
);
|
1151
|
-
const [
|
1152
|
-
const
|
1153
|
-
async ({ model,
|
1350
|
+
const [discardDocument] = useDiscardDocumentMutation();
|
1351
|
+
const discard = React__namespace.useCallback(
|
1352
|
+
async ({ collectionType, model, documentId, params }) => {
|
1154
1353
|
try {
|
1155
|
-
|
1156
|
-
|
1354
|
+
const res = await discardDocument({
|
1355
|
+
collectionType,
|
1157
1356
|
model,
|
1158
|
-
|
1357
|
+
documentId,
|
1159
1358
|
params
|
1160
1359
|
});
|
1161
1360
|
if ("error" in res) {
|
1162
|
-
toggleNotification({
|
1361
|
+
toggleNotification({
|
1362
|
+
type: "danger",
|
1363
|
+
message: formatAPIError(res.error)
|
1364
|
+
});
|
1163
1365
|
return { error: res.error };
|
1164
1366
|
}
|
1165
|
-
trackUsage("didBulkUnpublishEntries");
|
1166
1367
|
toggleNotification({
|
1167
1368
|
type: "success",
|
1168
|
-
|
1169
|
-
id:
|
1170
|
-
defaultMessage: "
|
1171
|
-
})
|
1172
|
-
message: ""
|
1369
|
+
message: formatMessage({
|
1370
|
+
id: "content-manager.success.record.discard",
|
1371
|
+
defaultMessage: "Changes discarded"
|
1372
|
+
})
|
1173
1373
|
});
|
1174
1374
|
return res.data;
|
1175
1375
|
} catch (err) {
|
@@ -1177,13 +1377,193 @@ const useDocumentActions = () => {
|
|
1177
1377
|
type: "danger",
|
1178
1378
|
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1179
1379
|
});
|
1180
|
-
trackUsage("didNotBulkUnpublishEntries");
|
1181
1380
|
throw err;
|
1182
1381
|
}
|
1183
1382
|
},
|
1184
|
-
[
|
1383
|
+
[discardDocument, formatAPIError, formatMessage, toggleNotification]
|
1185
1384
|
);
|
1186
|
-
const [
|
1385
|
+
const [publishDocument] = usePublishDocumentMutation();
|
1386
|
+
const publish = React__namespace.useCallback(
|
1387
|
+
async ({ collectionType, model, documentId, params }, data) => {
|
1388
|
+
try {
|
1389
|
+
trackUsage("willPublishEntry");
|
1390
|
+
const res = await publishDocument({
|
1391
|
+
collectionType,
|
1392
|
+
model,
|
1393
|
+
documentId,
|
1394
|
+
data,
|
1395
|
+
params
|
1396
|
+
});
|
1397
|
+
if ("error" in res) {
|
1398
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1399
|
+
return { error: res.error };
|
1400
|
+
}
|
1401
|
+
trackUsage("didPublishEntry");
|
1402
|
+
toggleNotification({
|
1403
|
+
type: "success",
|
1404
|
+
message: formatMessage({
|
1405
|
+
id: getTranslation("success.record.publish"),
|
1406
|
+
defaultMessage: "Published document"
|
1407
|
+
})
|
1408
|
+
});
|
1409
|
+
return res.data;
|
1410
|
+
} catch (err) {
|
1411
|
+
toggleNotification({
|
1412
|
+
type: "danger",
|
1413
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1414
|
+
});
|
1415
|
+
throw err;
|
1416
|
+
}
|
1417
|
+
},
|
1418
|
+
[trackUsage, publishDocument, toggleNotification, formatMessage, formatAPIError]
|
1419
|
+
);
|
1420
|
+
const [publishManyDocuments] = usePublishManyDocumentsMutation();
|
1421
|
+
const publishMany = React__namespace.useCallback(
|
1422
|
+
async ({ model, documentIds, params }) => {
|
1423
|
+
try {
|
1424
|
+
const res = await publishManyDocuments({
|
1425
|
+
model,
|
1426
|
+
documentIds,
|
1427
|
+
params
|
1428
|
+
});
|
1429
|
+
if ("error" in res) {
|
1430
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1431
|
+
return { error: res.error };
|
1432
|
+
}
|
1433
|
+
toggleNotification({
|
1434
|
+
type: "success",
|
1435
|
+
message: formatMessage({
|
1436
|
+
id: getTranslation("success.record.publish"),
|
1437
|
+
defaultMessage: "Published document"
|
1438
|
+
})
|
1439
|
+
});
|
1440
|
+
return res.data;
|
1441
|
+
} catch (err) {
|
1442
|
+
toggleNotification({
|
1443
|
+
type: "danger",
|
1444
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1445
|
+
});
|
1446
|
+
throw err;
|
1447
|
+
}
|
1448
|
+
},
|
1449
|
+
[
|
1450
|
+
// trackUsage,
|
1451
|
+
publishManyDocuments,
|
1452
|
+
toggleNotification,
|
1453
|
+
formatMessage,
|
1454
|
+
formatAPIError
|
1455
|
+
]
|
1456
|
+
);
|
1457
|
+
const [updateDocument] = useUpdateDocumentMutation();
|
1458
|
+
const update = React__namespace.useCallback(
|
1459
|
+
async ({ collectionType, model, documentId, params }, data, trackerProperty) => {
|
1460
|
+
try {
|
1461
|
+
trackUsage("willEditEntry", trackerProperty);
|
1462
|
+
const res = await updateDocument({
|
1463
|
+
collectionType,
|
1464
|
+
model,
|
1465
|
+
documentId,
|
1466
|
+
data,
|
1467
|
+
params
|
1468
|
+
});
|
1469
|
+
if ("error" in res) {
|
1470
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1471
|
+
trackUsage("didNotEditEntry", { error: res.error, ...trackerProperty });
|
1472
|
+
return { error: res.error };
|
1473
|
+
}
|
1474
|
+
trackUsage("didEditEntry", trackerProperty);
|
1475
|
+
toggleNotification({
|
1476
|
+
type: "success",
|
1477
|
+
message: formatMessage({
|
1478
|
+
id: getTranslation("success.record.save"),
|
1479
|
+
defaultMessage: "Saved document"
|
1480
|
+
})
|
1481
|
+
});
|
1482
|
+
return res.data;
|
1483
|
+
} catch (err) {
|
1484
|
+
trackUsage("didNotEditEntry", { error: err, ...trackerProperty });
|
1485
|
+
toggleNotification({
|
1486
|
+
type: "danger",
|
1487
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1488
|
+
});
|
1489
|
+
throw err;
|
1490
|
+
}
|
1491
|
+
},
|
1492
|
+
[trackUsage, updateDocument, toggleNotification, formatMessage, formatAPIError]
|
1493
|
+
);
|
1494
|
+
const [unpublishDocument] = useUnpublishDocumentMutation();
|
1495
|
+
const unpublish = React__namespace.useCallback(
|
1496
|
+
async ({ collectionType, model, documentId, params }, discardDraft = false) => {
|
1497
|
+
try {
|
1498
|
+
trackUsage("willUnpublishEntry");
|
1499
|
+
const res = await unpublishDocument({
|
1500
|
+
collectionType,
|
1501
|
+
model,
|
1502
|
+
documentId,
|
1503
|
+
params,
|
1504
|
+
data: {
|
1505
|
+
discardDraft
|
1506
|
+
}
|
1507
|
+
});
|
1508
|
+
if ("error" in res) {
|
1509
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1510
|
+
return { error: res.error };
|
1511
|
+
}
|
1512
|
+
trackUsage("didUnpublishEntry");
|
1513
|
+
toggleNotification({
|
1514
|
+
type: "success",
|
1515
|
+
message: formatMessage({
|
1516
|
+
id: getTranslation("success.record.unpublish"),
|
1517
|
+
defaultMessage: "Unpublished document"
|
1518
|
+
})
|
1519
|
+
});
|
1520
|
+
return res.data;
|
1521
|
+
} catch (err) {
|
1522
|
+
toggleNotification({
|
1523
|
+
type: "danger",
|
1524
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1525
|
+
});
|
1526
|
+
throw err;
|
1527
|
+
}
|
1528
|
+
},
|
1529
|
+
[trackUsage, unpublishDocument, toggleNotification, formatMessage, formatAPIError]
|
1530
|
+
);
|
1531
|
+
const [unpublishManyDocuments] = useUnpublishManyDocumentsMutation();
|
1532
|
+
const unpublishMany = React__namespace.useCallback(
|
1533
|
+
async ({ model, documentIds, params }) => {
|
1534
|
+
try {
|
1535
|
+
trackUsage("willBulkUnpublishEntries");
|
1536
|
+
const res = await unpublishManyDocuments({
|
1537
|
+
model,
|
1538
|
+
documentIds,
|
1539
|
+
params
|
1540
|
+
});
|
1541
|
+
if ("error" in res) {
|
1542
|
+
toggleNotification({ type: "danger", message: formatAPIError(res.error) });
|
1543
|
+
return { error: res.error };
|
1544
|
+
}
|
1545
|
+
trackUsage("didBulkUnpublishEntries");
|
1546
|
+
toggleNotification({
|
1547
|
+
type: "success",
|
1548
|
+
title: formatMessage({
|
1549
|
+
id: getTranslation("success.records.unpublish"),
|
1550
|
+
defaultMessage: "Successfully unpublished."
|
1551
|
+
}),
|
1552
|
+
message: ""
|
1553
|
+
});
|
1554
|
+
return res.data;
|
1555
|
+
} catch (err) {
|
1556
|
+
toggleNotification({
|
1557
|
+
type: "danger",
|
1558
|
+
message: formatMessage(DEFAULT_UNEXPECTED_ERROR_MSG)
|
1559
|
+
});
|
1560
|
+
trackUsage("didNotBulkUnpublishEntries");
|
1561
|
+
throw err;
|
1562
|
+
}
|
1563
|
+
},
|
1564
|
+
[trackUsage, unpublishManyDocuments, toggleNotification, formatMessage, formatAPIError]
|
1565
|
+
);
|
1566
|
+
const [createDocument] = useCreateDocumentMutation();
|
1187
1567
|
const create = React__namespace.useCallback(
|
1188
1568
|
async ({ model, params }, data, trackerProperty) => {
|
1189
1569
|
try {
|
@@ -1205,6 +1585,7 @@ const useDocumentActions = () => {
|
|
1205
1585
|
defaultMessage: "Saved document"
|
1206
1586
|
})
|
1207
1587
|
});
|
1588
|
+
setCurrentStep("contentManager.success");
|
1208
1589
|
return res.data;
|
1209
1590
|
} catch (err) {
|
1210
1591
|
toggleNotification({
|
@@ -1244,7 +1625,7 @@ const useDocumentActions = () => {
|
|
1244
1625
|
throw err;
|
1245
1626
|
}
|
1246
1627
|
},
|
1247
|
-
[autoCloneDocument,
|
1628
|
+
[autoCloneDocument, formatMessage, toggleNotification]
|
1248
1629
|
);
|
1249
1630
|
const [cloneDocument] = useCloneDocumentMutation();
|
1250
1631
|
const clone = React__namespace.useCallback(
|
@@ -1270,6 +1651,7 @@ const useDocumentActions = () => {
|
|
1270
1651
|
defaultMessage: "Cloned document"
|
1271
1652
|
})
|
1272
1653
|
});
|
1654
|
+
navigate(`../../${res.data.data.documentId}`, { relative: "path" });
|
1273
1655
|
return res.data;
|
1274
1656
|
} catch (err) {
|
1275
1657
|
toggleNotification({
|
@@ -1280,7 +1662,7 @@ const useDocumentActions = () => {
|
|
1280
1662
|
throw err;
|
1281
1663
|
}
|
1282
1664
|
},
|
1283
|
-
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError]
|
1665
|
+
[cloneDocument, trackUsage, toggleNotification, formatMessage, formatAPIError, navigate]
|
1284
1666
|
);
|
1285
1667
|
const [getDoc] = useLazyGetDocumentQuery();
|
1286
1668
|
const getDocument = React__namespace.useCallback(
|
@@ -1306,7 +1688,7 @@ const useDocumentActions = () => {
|
|
1306
1688
|
};
|
1307
1689
|
};
|
1308
1690
|
const ProtectedHistoryPage = React.lazy(
|
1309
|
-
() => Promise.resolve().then(() => require("./History-
|
1691
|
+
() => Promise.resolve().then(() => require("./History-CTFvy6XH.js")).then((mod) => ({ default: mod.ProtectedHistoryPage }))
|
1310
1692
|
);
|
1311
1693
|
const routes$1 = [
|
1312
1694
|
{
|
@@ -1319,31 +1701,31 @@ const routes$1 = [
|
|
1319
1701
|
}
|
1320
1702
|
];
|
1321
1703
|
const ProtectedEditViewPage = React.lazy(
|
1322
|
-
() => Promise.resolve().then(() => require("./EditViewPage-
|
1704
|
+
() => Promise.resolve().then(() => require("./EditViewPage-CqHMM0P0.js")).then((mod) => ({ default: mod.ProtectedEditViewPage }))
|
1323
1705
|
);
|
1324
1706
|
const ProtectedListViewPage = React.lazy(
|
1325
|
-
() => Promise.resolve().then(() => require("./ListViewPage-
|
1707
|
+
() => Promise.resolve().then(() => require("./ListViewPage-D0fpPYKp.js")).then((mod) => ({ default: mod.ProtectedListViewPage }))
|
1326
1708
|
);
|
1327
1709
|
const ProtectedListConfiguration = React.lazy(
|
1328
|
-
() => Promise.resolve().then(() => require("./ListConfigurationPage-
|
1710
|
+
() => Promise.resolve().then(() => require("./ListConfigurationPage-CDzlMBz_.js")).then((mod) => ({
|
1329
1711
|
default: mod.ProtectedListConfiguration
|
1330
1712
|
}))
|
1331
1713
|
);
|
1332
1714
|
const ProtectedEditConfigurationPage = React.lazy(
|
1333
|
-
() => Promise.resolve().then(() => require("./EditConfigurationPage-
|
1715
|
+
() => Promise.resolve().then(() => require("./EditConfigurationPage-Ce4bIm4n.js")).then((mod) => ({
|
1334
1716
|
default: mod.ProtectedEditConfigurationPage
|
1335
1717
|
}))
|
1336
1718
|
);
|
1337
1719
|
const ProtectedComponentConfigurationPage = React.lazy(
|
1338
|
-
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-
|
1720
|
+
() => Promise.resolve().then(() => require("./ComponentConfigurationPage-CQDCxI8x.js")).then((mod) => ({
|
1339
1721
|
default: mod.ProtectedComponentConfigurationPage
|
1340
1722
|
}))
|
1341
1723
|
);
|
1342
1724
|
const NoPermissions = React.lazy(
|
1343
|
-
() => Promise.resolve().then(() => require("./NoPermissionsPage-
|
1725
|
+
() => Promise.resolve().then(() => require("./NoPermissionsPage-BoI2rU68.js")).then((mod) => ({ default: mod.NoPermissions }))
|
1344
1726
|
);
|
1345
1727
|
const NoContentType = React.lazy(
|
1346
|
-
() => Promise.resolve().then(() => require("./NoContentTypePage-
|
1728
|
+
() => Promise.resolve().then(() => require("./NoContentTypePage-DTzkSAV5.js")).then((mod) => ({ default: mod.NoContentType }))
|
1347
1729
|
);
|
1348
1730
|
const CollectionTypePages = () => {
|
1349
1731
|
const { collectionType } = reactRouterDom.useParams();
|
@@ -1403,1065 +1785,743 @@ const DocumentActions = ({ actions: actions2 }) => {
|
|
1403
1785
|
if (!primaryAction) {
|
1404
1786
|
return null;
|
1405
1787
|
}
|
1406
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1407
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
1408
|
-
/* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1409
|
-
restActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
1410
|
-
DocumentActionsMenu,
|
1411
|
-
{
|
1412
|
-
actions: restActions,
|
1413
|
-
label: formatMessage({
|
1414
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1415
|
-
defaultMessage: "More document actions"
|
1416
|
-
})
|
1417
|
-
}
|
1418
|
-
) : null
|
1419
|
-
] }),
|
1420
|
-
secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
|
1421
|
-
DocumentActionButton,
|
1422
|
-
{
|
1423
|
-
...secondaryAction,
|
1424
|
-
variant: secondaryAction.variant || "secondary"
|
1425
|
-
}
|
1426
|
-
) : null
|
1427
|
-
] });
|
1428
|
-
};
|
1429
|
-
const DocumentActionButton = (action) => {
|
1430
|
-
const [dialogId, setDialogId] = React__namespace.useState(null);
|
1431
|
-
const { toggleNotification } = strapiAdmin.useNotification();
|
1432
|
-
const handleClick = (action2) => async (e) => {
|
1433
|
-
const { onClick = () => false, dialog, id } = action2;
|
1434
|
-
const muteDialog = await onClick(e);
|
1435
|
-
if (dialog && !muteDialog) {
|
1436
|
-
switch (dialog.type) {
|
1437
|
-
case "notification":
|
1438
|
-
toggleNotification({
|
1439
|
-
title: dialog.title,
|
1440
|
-
message: dialog.content,
|
1441
|
-
type: dialog.status,
|
1442
|
-
timeout: dialog.timeout,
|
1443
|
-
onClose: dialog.onClose
|
1444
|
-
});
|
1445
|
-
break;
|
1446
|
-
case "dialog":
|
1447
|
-
case "modal":
|
1448
|
-
e.preventDefault();
|
1449
|
-
setDialogId(id);
|
1450
|
-
}
|
1451
|
-
}
|
1452
|
-
};
|
1453
|
-
const handleClose = () => {
|
1454
|
-
setDialogId(null);
|
1455
|
-
};
|
1456
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
1457
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
1458
|
-
designSystem.Button,
|
1459
|
-
{
|
1460
|
-
flex: "auto",
|
1461
|
-
startIcon: action.icon,
|
1462
|
-
disabled: action.disabled,
|
1463
|
-
onClick: handleClick(action),
|
1464
|
-
justifyContent: "center",
|
1465
|
-
variant: action.variant || "default",
|
1466
|
-
paddingTop: "7px",
|
1467
|
-
paddingBottom: "7px",
|
1468
|
-
children: action.label
|
1469
|
-
}
|
1470
|
-
),
|
1471
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1472
|
-
DocumentActionConfirmDialog,
|
1473
|
-
{
|
1474
|
-
...action.dialog,
|
1475
|
-
variant: action.dialog?.variant ?? action.variant,
|
1476
|
-
isOpen: dialogId === action.id,
|
1477
|
-
onClose: handleClose
|
1478
|
-
}
|
1479
|
-
) : null,
|
1480
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1481
|
-
DocumentActionModal,
|
1482
|
-
{
|
1483
|
-
...action.dialog,
|
1484
|
-
onModalClose: handleClose,
|
1485
|
-
isOpen: dialogId === action.id
|
1486
|
-
}
|
1487
|
-
) : null
|
1488
|
-
] });
|
1489
|
-
};
|
1490
|
-
const DocumentActionsMenu = ({
|
1491
|
-
actions: actions2,
|
1492
|
-
children,
|
1493
|
-
label,
|
1494
|
-
variant = "tertiary"
|
1495
|
-
}) => {
|
1496
|
-
const [isOpen, setIsOpen] = React__namespace.useState(false);
|
1497
|
-
const [dialogId, setDialogId] = React__namespace.useState(null);
|
1498
|
-
const { formatMessage } = reactIntl.useIntl();
|
1499
|
-
const { toggleNotification } = strapiAdmin.useNotification();
|
1500
|
-
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1501
|
-
const handleClick = (action) => async (e) => {
|
1502
|
-
const { onClick = () => false, dialog, id } = action;
|
1503
|
-
const muteDialog = await onClick(e);
|
1504
|
-
if (dialog && !muteDialog) {
|
1505
|
-
switch (dialog.type) {
|
1506
|
-
case "notification":
|
1507
|
-
toggleNotification({
|
1508
|
-
title: dialog.title,
|
1509
|
-
message: dialog.content,
|
1510
|
-
type: dialog.status,
|
1511
|
-
timeout: dialog.timeout,
|
1512
|
-
onClose: dialog.onClose
|
1513
|
-
});
|
1514
|
-
break;
|
1515
|
-
case "dialog":
|
1516
|
-
case "modal":
|
1517
|
-
setDialogId(id);
|
1518
|
-
}
|
1519
|
-
}
|
1520
|
-
};
|
1521
|
-
const handleClose = () => {
|
1522
|
-
setDialogId(null);
|
1523
|
-
setIsOpen(false);
|
1524
|
-
};
|
1525
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1526
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
1527
|
-
StyledMoreButton,
|
1528
|
-
{
|
1529
|
-
disabled: isDisabled,
|
1530
|
-
size: "S",
|
1531
|
-
endIcon: null,
|
1532
|
-
paddingTop: "4px",
|
1533
|
-
paddingLeft: "7px",
|
1534
|
-
paddingRight: "7px",
|
1535
|
-
variant,
|
1536
|
-
children: [
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
|
1538
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1539
|
-
id: "content-manager.containers.edit.panels.default.more-actions",
|
1540
|
-
defaultMessage: "More document actions"
|
1541
|
-
}) })
|
1542
|
-
]
|
1543
|
-
}
|
1544
|
-
),
|
1545
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { top: "4px", maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1546
|
-
actions2.map((action) => {
|
1547
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
1548
|
-
designSystem.Menu.Item,
|
1549
|
-
{
|
1550
|
-
disabled: action.disabled,
|
1551
|
-
onSelect: handleClick(action),
|
1552
|
-
display: "block",
|
1553
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
|
1554
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
1555
|
-
designSystem.Flex,
|
1556
|
-
{
|
1557
|
-
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1558
|
-
gap: 2,
|
1559
|
-
tag: "span",
|
1560
|
-
children: [
|
1561
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
1562
|
-
designSystem.Flex,
|
1563
|
-
{
|
1564
|
-
tag: "span",
|
1565
|
-
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1566
|
-
children: action.icon
|
1567
|
-
}
|
1568
|
-
),
|
1569
|
-
action.label
|
1570
|
-
]
|
1571
|
-
}
|
1572
|
-
),
|
1573
|
-
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
|
1574
|
-
designSystem.Flex,
|
1575
|
-
{
|
1576
|
-
alignItems: "center",
|
1577
|
-
background: "alternative100",
|
1578
|
-
borderStyle: "solid",
|
1579
|
-
borderColor: "alternative200",
|
1580
|
-
borderWidth: "1px",
|
1581
|
-
height: 5,
|
1582
|
-
paddingLeft: 2,
|
1583
|
-
paddingRight: 2,
|
1584
|
-
hasRadius: true,
|
1585
|
-
color: "alternative600",
|
1586
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1587
|
-
}
|
1588
|
-
)
|
1589
|
-
] })
|
1590
|
-
},
|
1591
|
-
action.id
|
1592
|
-
);
|
1593
|
-
}),
|
1594
|
-
children
|
1595
|
-
] }),
|
1596
|
-
actions2.map((action) => {
|
1597
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
1598
|
-
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1599
|
-
DocumentActionConfirmDialog,
|
1600
|
-
{
|
1601
|
-
...action.dialog,
|
1602
|
-
variant: action.variant,
|
1603
|
-
isOpen: dialogId === action.id,
|
1604
|
-
onClose: handleClose
|
1605
|
-
}
|
1606
|
-
) : null,
|
1607
|
-
action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1608
|
-
DocumentActionModal,
|
1609
|
-
{
|
1610
|
-
...action.dialog,
|
1611
|
-
onModalClose: handleClose,
|
1612
|
-
isOpen: dialogId === action.id
|
1613
|
-
}
|
1614
|
-
) : null
|
1615
|
-
] }, action.id);
|
1616
|
-
})
|
1617
|
-
] });
|
1618
|
-
};
|
1619
|
-
const convertActionVariantToColor = (variant = "secondary") => {
|
1620
|
-
switch (variant) {
|
1621
|
-
case "danger":
|
1622
|
-
return "danger600";
|
1623
|
-
case "secondary":
|
1624
|
-
return void 0;
|
1625
|
-
case "success":
|
1626
|
-
return "success600";
|
1627
|
-
default:
|
1628
|
-
return "primary600";
|
1629
|
-
}
|
1630
|
-
};
|
1631
|
-
const convertActionVariantToIconColor = (variant = "secondary") => {
|
1632
|
-
switch (variant) {
|
1633
|
-
case "danger":
|
1634
|
-
return "danger600";
|
1635
|
-
case "secondary":
|
1636
|
-
return "neutral500";
|
1637
|
-
case "success":
|
1638
|
-
return "success600";
|
1639
|
-
default:
|
1640
|
-
return "primary600";
|
1641
|
-
}
|
1642
|
-
};
|
1643
|
-
const StyledMoreButton = styledComponents.styled(designSystem.Menu.Trigger)`
|
1644
|
-
& > span {
|
1645
|
-
display: flex;
|
1646
|
-
}
|
1647
|
-
`;
|
1648
|
-
const DocumentActionConfirmDialog = ({
|
1649
|
-
onClose,
|
1650
|
-
onCancel,
|
1651
|
-
onConfirm,
|
1652
|
-
title,
|
1653
|
-
content,
|
1654
|
-
isOpen,
|
1655
|
-
variant = "secondary"
|
1656
|
-
}) => {
|
1657
|
-
const { formatMessage } = reactIntl.useIntl();
|
1658
|
-
const handleClose = async () => {
|
1659
|
-
if (onCancel) {
|
1660
|
-
await onCancel();
|
1661
|
-
}
|
1662
|
-
onClose();
|
1663
|
-
};
|
1664
|
-
const handleConfirm = async () => {
|
1665
|
-
if (onConfirm) {
|
1666
|
-
await onConfirm();
|
1667
|
-
}
|
1668
|
-
onClose();
|
1669
|
-
};
|
1670
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
1671
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
1672
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
|
1673
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
|
1674
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", children: formatMessage({
|
1675
|
-
id: "app.components.Button.cancel",
|
1676
|
-
defaultMessage: "Cancel"
|
1677
|
-
}) }) }),
|
1678
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, children: formatMessage({
|
1679
|
-
id: "app.components.Button.confirm",
|
1680
|
-
defaultMessage: "Confirm"
|
1681
|
-
}) })
|
1682
|
-
] })
|
1683
|
-
] }) });
|
1684
|
-
};
|
1685
|
-
const DocumentActionModal = ({
|
1686
|
-
isOpen,
|
1687
|
-
title,
|
1688
|
-
onClose,
|
1689
|
-
footer: Footer,
|
1690
|
-
content: Content,
|
1691
|
-
onModalClose
|
1692
|
-
}) => {
|
1693
|
-
const handleClose = () => {
|
1694
|
-
if (onClose) {
|
1695
|
-
onClose();
|
1696
|
-
}
|
1697
|
-
onModalClose();
|
1698
|
-
};
|
1699
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
|
1700
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
|
1701
|
-
typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
|
1702
|
-
typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
|
1703
|
-
] }) });
|
1704
|
-
};
|
1705
|
-
const PublishAction$1 = ({
|
1706
|
-
activeTab,
|
1707
|
-
documentId,
|
1708
|
-
model,
|
1709
|
-
collectionType,
|
1710
|
-
meta,
|
1711
|
-
document
|
1712
|
-
}) => {
|
1713
|
-
const { schema } = useDoc();
|
1714
|
-
const navigate = reactRouterDom.useNavigate();
|
1715
|
-
const { toggleNotification } = strapiAdmin.useNotification();
|
1716
|
-
const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
|
1717
|
-
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
1718
|
-
const { formatMessage } = reactIntl.useIntl();
|
1719
|
-
const { canPublish, canCreate, canUpdate } = useDocumentRBAC(
|
1720
|
-
"PublishAction",
|
1721
|
-
({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 }) => ({ canPublish: canPublish2, canCreate: canCreate2, canUpdate: canUpdate2 })
|
1722
|
-
);
|
1723
|
-
const { publish } = useDocumentActions();
|
1724
|
-
const [
|
1725
|
-
countDraftRelations,
|
1726
|
-
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
1727
|
-
] = useLazyGetDraftRelationCountQuery();
|
1728
|
-
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
|
1729
|
-
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
|
1730
|
-
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1731
|
-
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1732
|
-
const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
1733
|
-
const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1734
|
-
const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1735
|
-
const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
|
1736
|
-
const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
|
1737
|
-
const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
|
1738
|
-
React__namespace.useEffect(() => {
|
1739
|
-
if (isErrorDraftRelations) {
|
1740
|
-
toggleNotification({
|
1741
|
-
type: "danger",
|
1742
|
-
message: formatMessage({
|
1743
|
-
id: getTranslation("error.records.fetch-draft-relatons"),
|
1744
|
-
defaultMessage: "An error occurred while fetching draft relations on this document."
|
1745
|
-
})
|
1746
|
-
});
|
1747
|
-
}
|
1748
|
-
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
1749
|
-
React__namespace.useEffect(() => {
|
1750
|
-
const localDraftRelations = /* @__PURE__ */ new Set();
|
1751
|
-
const extractDraftRelations = (data) => {
|
1752
|
-
const relations = data.connect || [];
|
1753
|
-
relations.forEach((relation) => {
|
1754
|
-
if (relation.status === "draft") {
|
1755
|
-
localDraftRelations.add(relation.id);
|
1756
|
-
}
|
1757
|
-
});
|
1758
|
-
};
|
1759
|
-
const traverseAndExtract = (data) => {
|
1760
|
-
Object.entries(data).forEach(([key, value]) => {
|
1761
|
-
if (key === "connect" && Array.isArray(value)) {
|
1762
|
-
extractDraftRelations({ connect: value });
|
1763
|
-
} else if (typeof value === "object" && value !== null) {
|
1764
|
-
traverseAndExtract(value);
|
1765
|
-
}
|
1766
|
-
});
|
1767
|
-
};
|
1768
|
-
if (!documentId || modified) {
|
1769
|
-
traverseAndExtract(formValues);
|
1770
|
-
setLocalCountOfDraftRelations(localDraftRelations.size);
|
1771
|
-
}
|
1772
|
-
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
1773
|
-
React__namespace.useEffect(() => {
|
1774
|
-
if (documentId) {
|
1775
|
-
const fetchDraftRelationsCount = async () => {
|
1776
|
-
const { data, error } = await countDraftRelations({
|
1777
|
-
collectionType,
|
1778
|
-
model,
|
1779
|
-
documentId,
|
1780
|
-
params
|
1781
|
-
});
|
1782
|
-
if (error) {
|
1783
|
-
throw error;
|
1784
|
-
}
|
1785
|
-
if (data) {
|
1786
|
-
setServerCountOfDraftRelations(data.data);
|
1787
|
-
}
|
1788
|
-
};
|
1789
|
-
fetchDraftRelationsCount();
|
1790
|
-
}
|
1791
|
-
}, [documentId, countDraftRelations, collectionType, model, params]);
|
1792
|
-
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
1793
|
-
if (!schema?.options?.draftAndPublish) {
|
1794
|
-
return null;
|
1795
|
-
}
|
1796
|
-
const performPublish = async () => {
|
1797
|
-
setSubmitting(true);
|
1798
|
-
try {
|
1799
|
-
const { errors } = await validate();
|
1800
|
-
if (errors) {
|
1801
|
-
toggleNotification({
|
1802
|
-
type: "danger",
|
1803
|
-
message: formatMessage({
|
1804
|
-
id: "content-manager.validation.error",
|
1805
|
-
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
1806
|
-
})
|
1807
|
-
});
|
1808
|
-
return;
|
1809
|
-
}
|
1810
|
-
const res = await publish(
|
1811
|
-
{
|
1812
|
-
collectionType,
|
1813
|
-
model,
|
1814
|
-
documentId,
|
1815
|
-
params
|
1816
|
-
},
|
1817
|
-
formValues
|
1818
|
-
);
|
1819
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1820
|
-
navigate({
|
1821
|
-
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
1822
|
-
search: rawQuery
|
1823
|
-
});
|
1824
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1825
|
-
setErrors(formatValidationErrors(res.error));
|
1826
|
-
}
|
1827
|
-
} finally {
|
1828
|
-
setSubmitting(false);
|
1829
|
-
}
|
1830
|
-
};
|
1831
|
-
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
1832
|
-
const hasDraftRelations = totalDraftRelations > 0;
|
1833
|
-
return {
|
1834
|
-
/**
|
1835
|
-
* Disabled when:
|
1836
|
-
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
1837
|
-
* - the form is submitting
|
1838
|
-
* - the active tab is the published tab
|
1839
|
-
* - the document is already published & not modified
|
1840
|
-
* - the document is being created & not modified
|
1841
|
-
* - the user doesn't have the permission to publish
|
1842
|
-
*/
|
1843
|
-
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
1844
|
-
label: formatMessage({
|
1845
|
-
id: "app.utils.publish",
|
1846
|
-
defaultMessage: "Publish"
|
1847
|
-
}),
|
1848
|
-
onClick: async () => {
|
1849
|
-
if (hasDraftRelations) {
|
1850
|
-
return;
|
1851
|
-
}
|
1852
|
-
await performPublish();
|
1853
|
-
},
|
1854
|
-
dialog: hasDraftRelations ? {
|
1855
|
-
type: "dialog",
|
1856
|
-
variant: "danger",
|
1857
|
-
footer: null,
|
1858
|
-
title: formatMessage({
|
1859
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
1860
|
-
defaultMessage: "Confirmation"
|
1861
|
-
}),
|
1862
|
-
content: formatMessage(
|
1863
|
-
{
|
1864
|
-
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
1865
|
-
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
1866
|
-
},
|
1788
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, alignItems: "stretch", width: "100%", children: [
|
1789
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
1790
|
+
/* @__PURE__ */ jsxRuntime.jsx(DocumentActionButton, { ...primaryAction, variant: primaryAction.variant || "default" }),
|
1791
|
+
restActions.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx(
|
1792
|
+
DocumentActionsMenu,
|
1867
1793
|
{
|
1868
|
-
|
1794
|
+
actions: restActions,
|
1795
|
+
label: formatMessage({
|
1796
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1797
|
+
defaultMessage: "More document actions"
|
1798
|
+
})
|
1869
1799
|
}
|
1870
|
-
)
|
1871
|
-
|
1872
|
-
|
1800
|
+
) : null
|
1801
|
+
] }),
|
1802
|
+
secondaryAction ? /* @__PURE__ */ jsxRuntime.jsx(
|
1803
|
+
DocumentActionButton,
|
1804
|
+
{
|
1805
|
+
...secondaryAction,
|
1806
|
+
variant: secondaryAction.variant || "secondary"
|
1873
1807
|
}
|
1874
|
-
|
1875
|
-
};
|
1808
|
+
) : null
|
1809
|
+
] });
|
1876
1810
|
};
|
1877
|
-
|
1878
|
-
const
|
1879
|
-
activeTab,
|
1880
|
-
documentId,
|
1881
|
-
model,
|
1882
|
-
collectionType
|
1883
|
-
}) => {
|
1884
|
-
const navigate = reactRouterDom.useNavigate();
|
1811
|
+
const DocumentActionButton = (action) => {
|
1812
|
+
const [dialogId, setDialogId] = React__namespace.useState(null);
|
1885
1813
|
const { toggleNotification } = strapiAdmin.useNotification();
|
1886
|
-
const
|
1887
|
-
|
1888
|
-
|
1889
|
-
|
1890
|
-
|
1891
|
-
|
1892
|
-
canUpdate: canUpdate2
|
1893
|
-
}));
|
1894
|
-
const { create, update, clone } = useDocumentActions();
|
1895
|
-
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
1896
|
-
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
1897
|
-
const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
1898
|
-
const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
1899
|
-
const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
1900
|
-
const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
|
1901
|
-
const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
|
1902
|
-
const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
|
1903
|
-
const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
1904
|
-
return {
|
1905
|
-
/**
|
1906
|
-
* Disabled when:
|
1907
|
-
* - the form is submitting
|
1908
|
-
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
1909
|
-
* - the active tab is the published tab
|
1910
|
-
*/
|
1911
|
-
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
1912
|
-
label: formatMessage({
|
1913
|
-
id: "content-manager.containers.Edit.save",
|
1914
|
-
defaultMessage: "Save"
|
1915
|
-
}),
|
1916
|
-
onClick: async () => {
|
1917
|
-
setSubmitting(true);
|
1918
|
-
try {
|
1919
|
-
const { errors } = await validate();
|
1920
|
-
if (errors) {
|
1814
|
+
const handleClick = (action2) => async (e) => {
|
1815
|
+
const { onClick = () => false, dialog, id } = action2;
|
1816
|
+
const muteDialog = await onClick(e);
|
1817
|
+
if (dialog && !muteDialog) {
|
1818
|
+
switch (dialog.type) {
|
1819
|
+
case "notification":
|
1921
1820
|
toggleNotification({
|
1922
|
-
|
1923
|
-
message:
|
1924
|
-
|
1925
|
-
|
1926
|
-
|
1821
|
+
title: dialog.title,
|
1822
|
+
message: dialog.content,
|
1823
|
+
type: dialog.status,
|
1824
|
+
timeout: dialog.timeout,
|
1825
|
+
onClose: dialog.onClose
|
1927
1826
|
});
|
1928
|
-
|
1929
|
-
|
1930
|
-
|
1931
|
-
|
1932
|
-
|
1933
|
-
model,
|
1934
|
-
documentId: cloneMatch.params.origin,
|
1935
|
-
params
|
1936
|
-
},
|
1937
|
-
document
|
1938
|
-
);
|
1939
|
-
if ("data" in res) {
|
1940
|
-
navigate(
|
1941
|
-
{
|
1942
|
-
pathname: `../${res.data.documentId}`,
|
1943
|
-
search: rawQuery
|
1944
|
-
},
|
1945
|
-
{ relative: "path" }
|
1946
|
-
);
|
1947
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1948
|
-
setErrors(formatValidationErrors(res.error));
|
1949
|
-
}
|
1950
|
-
} else if (documentId || collectionType === SINGLE_TYPES) {
|
1951
|
-
const res = await update(
|
1952
|
-
{
|
1953
|
-
collectionType,
|
1954
|
-
model,
|
1955
|
-
documentId,
|
1956
|
-
params
|
1957
|
-
},
|
1958
|
-
document
|
1959
|
-
);
|
1960
|
-
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1961
|
-
setErrors(formatValidationErrors(res.error));
|
1962
|
-
} else {
|
1963
|
-
resetForm();
|
1964
|
-
}
|
1965
|
-
} else {
|
1966
|
-
const res = await create(
|
1967
|
-
{
|
1968
|
-
model,
|
1969
|
-
params
|
1970
|
-
},
|
1971
|
-
document
|
1972
|
-
);
|
1973
|
-
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
1974
|
-
navigate(
|
1975
|
-
{
|
1976
|
-
pathname: `../${res.data.documentId}`,
|
1977
|
-
search: rawQuery
|
1978
|
-
},
|
1979
|
-
{ replace: true, relative: "path" }
|
1980
|
-
);
|
1981
|
-
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
1982
|
-
setErrors(formatValidationErrors(res.error));
|
1983
|
-
}
|
1984
|
-
}
|
1985
|
-
} finally {
|
1986
|
-
setSubmitting(false);
|
1827
|
+
break;
|
1828
|
+
case "dialog":
|
1829
|
+
case "modal":
|
1830
|
+
e.preventDefault();
|
1831
|
+
setDialogId(id);
|
1987
1832
|
}
|
1988
1833
|
}
|
1989
1834
|
};
|
1990
|
-
|
1991
|
-
|
1992
|
-
|
1993
|
-
|
1994
|
-
|
1995
|
-
|
1996
|
-
|
1997
|
-
|
1998
|
-
|
1999
|
-
|
2000
|
-
|
2001
|
-
|
1835
|
+
const handleClose = () => {
|
1836
|
+
setDialogId(null);
|
1837
|
+
};
|
1838
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
1839
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
1840
|
+
designSystem.Button,
|
1841
|
+
{
|
1842
|
+
flex: "auto",
|
1843
|
+
startIcon: action.icon,
|
1844
|
+
disabled: action.disabled,
|
1845
|
+
onClick: handleClick(action),
|
1846
|
+
justifyContent: "center",
|
1847
|
+
variant: action.variant || "default",
|
1848
|
+
paddingTop: "7px",
|
1849
|
+
paddingBottom: "7px",
|
1850
|
+
children: action.label
|
1851
|
+
}
|
1852
|
+
),
|
1853
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1854
|
+
DocumentActionConfirmDialog,
|
1855
|
+
{
|
1856
|
+
...action.dialog,
|
1857
|
+
variant: action.dialog?.variant ?? action.variant,
|
1858
|
+
isOpen: dialogId === action.id,
|
1859
|
+
onClose: handleClose
|
1860
|
+
}
|
1861
|
+
) : null,
|
1862
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1863
|
+
DocumentActionModal,
|
1864
|
+
{
|
1865
|
+
...action.dialog,
|
1866
|
+
onModalClose: handleClose,
|
1867
|
+
isOpen: dialogId === action.id
|
1868
|
+
}
|
1869
|
+
) : null
|
1870
|
+
] });
|
1871
|
+
};
|
1872
|
+
const DocumentActionsMenu = ({
|
1873
|
+
actions: actions2,
|
1874
|
+
children,
|
1875
|
+
label,
|
1876
|
+
variant = "tertiary"
|
2002
1877
|
}) => {
|
1878
|
+
const [isOpen, setIsOpen] = React__namespace.useState(false);
|
1879
|
+
const [dialogId, setDialogId] = React__namespace.useState(null);
|
2003
1880
|
const { formatMessage } = reactIntl.useIntl();
|
2004
|
-
const { schema } = useDoc();
|
2005
|
-
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2006
|
-
const { unpublish } = useDocumentActions();
|
2007
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
2008
|
-
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2009
1881
|
const { toggleNotification } = strapiAdmin.useNotification();
|
2010
|
-
const
|
2011
|
-
const
|
2012
|
-
|
2013
|
-
|
2014
|
-
|
2015
|
-
|
2016
|
-
|
2017
|
-
}
|
2018
|
-
return {
|
2019
|
-
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2020
|
-
label: formatMessage({
|
2021
|
-
id: "app.utils.unpublish",
|
2022
|
-
defaultMessage: "Unpublish"
|
2023
|
-
}),
|
2024
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
|
2025
|
-
onClick: async () => {
|
2026
|
-
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2027
|
-
if (!documentId) {
|
2028
|
-
console.error(
|
2029
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2030
|
-
);
|
1882
|
+
const isDisabled = actions2.every((action) => action.disabled) || actions2.length === 0;
|
1883
|
+
const handleClick = (action) => async (e) => {
|
1884
|
+
const { onClick = () => false, dialog, id } = action;
|
1885
|
+
const muteDialog = await onClick(e);
|
1886
|
+
if (dialog && !muteDialog) {
|
1887
|
+
switch (dialog.type) {
|
1888
|
+
case "notification":
|
2031
1889
|
toggleNotification({
|
2032
|
-
|
2033
|
-
|
2034
|
-
|
2035
|
-
|
2036
|
-
|
1890
|
+
title: dialog.title,
|
1891
|
+
message: dialog.content,
|
1892
|
+
type: dialog.status,
|
1893
|
+
timeout: dialog.timeout,
|
1894
|
+
onClose: dialog.onClose
|
2037
1895
|
});
|
2038
|
-
|
2039
|
-
|
1896
|
+
break;
|
1897
|
+
case "dialog":
|
1898
|
+
case "modal":
|
1899
|
+
setDialogId(id);
|
2040
1900
|
}
|
2041
|
-
|
2042
|
-
|
2043
|
-
|
2044
|
-
|
2045
|
-
|
2046
|
-
|
2047
|
-
|
2048
|
-
|
2049
|
-
|
2050
|
-
|
2051
|
-
|
2052
|
-
|
2053
|
-
|
2054
|
-
|
2055
|
-
|
2056
|
-
|
2057
|
-
|
2058
|
-
|
2059
|
-
|
1901
|
+
}
|
1902
|
+
};
|
1903
|
+
const handleClose = () => {
|
1904
|
+
setDialogId(null);
|
1905
|
+
setIsOpen(false);
|
1906
|
+
};
|
1907
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
|
1908
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
1909
|
+
designSystem.Menu.Trigger,
|
1910
|
+
{
|
1911
|
+
disabled: isDisabled,
|
1912
|
+
size: "S",
|
1913
|
+
endIcon: null,
|
1914
|
+
paddingTop: "4px",
|
1915
|
+
paddingLeft: "7px",
|
1916
|
+
paddingRight: "7px",
|
1917
|
+
variant,
|
1918
|
+
children: [
|
1919
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.More, { "aria-hidden": true, focusable: false }),
|
1920
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.VisuallyHidden, { tag: "span", children: label || formatMessage({
|
1921
|
+
id: "content-manager.containers.edit.panels.default.more-actions",
|
1922
|
+
defaultMessage: "More document actions"
|
2060
1923
|
}) })
|
2061
|
-
]
|
2062
|
-
|
2063
|
-
|
2064
|
-
|
2065
|
-
|
2066
|
-
|
2067
|
-
|
2068
|
-
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2069
|
-
defaultMessage: "Choose an option to unpublish the document."
|
2070
|
-
}),
|
2071
|
-
onValueChange: handleChange,
|
2072
|
-
children: [
|
2073
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2074
|
-
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2075
|
-
defaultMessage: "Keep draft"
|
2076
|
-
}) }),
|
2077
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2078
|
-
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2079
|
-
defaultMessage: "Replace draft"
|
2080
|
-
}) })
|
2081
|
-
]
|
2082
|
-
}
|
2083
|
-
)
|
2084
|
-
] }),
|
2085
|
-
onConfirm: async () => {
|
2086
|
-
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2087
|
-
console.error(
|
2088
|
-
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2089
|
-
);
|
2090
|
-
toggleNotification({
|
2091
|
-
message: formatMessage({
|
2092
|
-
id: "content-manager.actions.unpublish.error",
|
2093
|
-
defaultMessage: "An error occurred while trying to unpublish the document."
|
2094
|
-
}),
|
2095
|
-
type: "danger"
|
2096
|
-
});
|
2097
|
-
}
|
2098
|
-
await unpublish(
|
1924
|
+
]
|
1925
|
+
}
|
1926
|
+
),
|
1927
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Menu.Content, { maxHeight: void 0, popoverPlacement: "bottom-end", children: [
|
1928
|
+
actions2.map((action) => {
|
1929
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
1930
|
+
designSystem.Menu.Item,
|
2099
1931
|
{
|
2100
|
-
|
2101
|
-
|
2102
|
-
|
2103
|
-
|
1932
|
+
disabled: action.disabled,
|
1933
|
+
onSelect: handleClick(action),
|
1934
|
+
display: "block",
|
1935
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { justifyContent: "space-between", gap: 4, children: [
|
1936
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
1937
|
+
designSystem.Flex,
|
1938
|
+
{
|
1939
|
+
color: !action.disabled ? convertActionVariantToColor(action.variant) : "inherit",
|
1940
|
+
gap: 2,
|
1941
|
+
tag: "span",
|
1942
|
+
children: [
|
1943
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
1944
|
+
designSystem.Flex,
|
1945
|
+
{
|
1946
|
+
tag: "span",
|
1947
|
+
color: !action.disabled ? convertActionVariantToIconColor(action.variant) : "inherit",
|
1948
|
+
children: action.icon
|
1949
|
+
}
|
1950
|
+
),
|
1951
|
+
action.label
|
1952
|
+
]
|
1953
|
+
}
|
1954
|
+
),
|
1955
|
+
action.id.startsWith("HistoryAction") && /* @__PURE__ */ jsxRuntime.jsx(
|
1956
|
+
designSystem.Flex,
|
1957
|
+
{
|
1958
|
+
alignItems: "center",
|
1959
|
+
background: "alternative100",
|
1960
|
+
borderStyle: "solid",
|
1961
|
+
borderColor: "alternative200",
|
1962
|
+
borderWidth: "1px",
|
1963
|
+
height: 5,
|
1964
|
+
paddingLeft: 2,
|
1965
|
+
paddingRight: 2,
|
1966
|
+
hasRadius: true,
|
1967
|
+
color: "alternative600",
|
1968
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "sigma", fontWeight: "bold", lineHeight: 1, children: formatMessage({ id: "global.new", defaultMessage: "New" }) })
|
1969
|
+
}
|
1970
|
+
)
|
1971
|
+
] })
|
2104
1972
|
},
|
2105
|
-
|
1973
|
+
action.id
|
2106
1974
|
);
|
2107
|
-
}
|
2108
|
-
|
2109
|
-
|
2110
|
-
|
1975
|
+
}),
|
1976
|
+
children
|
1977
|
+
] }),
|
1978
|
+
actions2.map((action) => {
|
1979
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
1980
|
+
action.dialog?.type === "dialog" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1981
|
+
DocumentActionConfirmDialog,
|
1982
|
+
{
|
1983
|
+
...action.dialog,
|
1984
|
+
variant: action.variant,
|
1985
|
+
isOpen: dialogId === action.id,
|
1986
|
+
onClose: handleClose
|
1987
|
+
}
|
1988
|
+
) : null,
|
1989
|
+
action.dialog?.type === "modal" ? /* @__PURE__ */ jsxRuntime.jsx(
|
1990
|
+
DocumentActionModal,
|
1991
|
+
{
|
1992
|
+
...action.dialog,
|
1993
|
+
onModalClose: handleClose,
|
1994
|
+
isOpen: dialogId === action.id
|
1995
|
+
}
|
1996
|
+
) : null
|
1997
|
+
] }, action.id);
|
1998
|
+
})
|
1999
|
+
] });
|
2000
|
+
};
|
2001
|
+
const convertActionVariantToColor = (variant = "secondary") => {
|
2002
|
+
switch (variant) {
|
2003
|
+
case "danger":
|
2004
|
+
return "danger600";
|
2005
|
+
case "secondary":
|
2006
|
+
return void 0;
|
2007
|
+
case "success":
|
2008
|
+
return "success600";
|
2009
|
+
default:
|
2010
|
+
return "primary600";
|
2011
|
+
}
|
2012
|
+
};
|
2013
|
+
const convertActionVariantToIconColor = (variant = "secondary") => {
|
2014
|
+
switch (variant) {
|
2015
|
+
case "danger":
|
2016
|
+
return "danger600";
|
2017
|
+
case "secondary":
|
2018
|
+
return "neutral500";
|
2019
|
+
case "success":
|
2020
|
+
return "success600";
|
2021
|
+
default:
|
2022
|
+
return "primary600";
|
2023
|
+
}
|
2024
|
+
};
|
2025
|
+
const DocumentActionConfirmDialog = ({
|
2026
|
+
onClose,
|
2027
|
+
onCancel,
|
2028
|
+
onConfirm,
|
2029
|
+
title,
|
2030
|
+
content,
|
2031
|
+
isOpen,
|
2032
|
+
variant = "secondary"
|
2033
|
+
}) => {
|
2034
|
+
const { formatMessage } = reactIntl.useIntl();
|
2035
|
+
const handleClose = async () => {
|
2036
|
+
if (onCancel) {
|
2037
|
+
await onCancel();
|
2038
|
+
}
|
2039
|
+
onClose();
|
2111
2040
|
};
|
2041
|
+
const handleConfirm = async () => {
|
2042
|
+
if (onConfirm) {
|
2043
|
+
await onConfirm();
|
2044
|
+
}
|
2045
|
+
onClose();
|
2046
|
+
};
|
2047
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
2048
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
2049
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Body, { children: content }),
|
2050
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Footer, { children: [
|
2051
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Cancel, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { variant: "tertiary", fullWidth: true, children: formatMessage({
|
2052
|
+
id: "app.components.Button.cancel",
|
2053
|
+
defaultMessage: "Cancel"
|
2054
|
+
}) }) }),
|
2055
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: handleConfirm, variant, fullWidth: true, children: formatMessage({
|
2056
|
+
id: "app.components.Button.confirm",
|
2057
|
+
defaultMessage: "Confirm"
|
2058
|
+
}) })
|
2059
|
+
] })
|
2060
|
+
] }) });
|
2112
2061
|
};
|
2113
|
-
|
2114
|
-
|
2115
|
-
|
2116
|
-
|
2117
|
-
|
2118
|
-
|
2119
|
-
|
2062
|
+
const DocumentActionModal = ({
|
2063
|
+
isOpen,
|
2064
|
+
title,
|
2065
|
+
onClose,
|
2066
|
+
footer: Footer,
|
2067
|
+
content: Content,
|
2068
|
+
onModalClose
|
2120
2069
|
}) => {
|
2121
|
-
const
|
2122
|
-
|
2123
|
-
|
2124
|
-
const { discard } = useDocumentActions();
|
2125
|
-
const [{ query }] = strapiAdmin.useQueryParams();
|
2126
|
-
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2127
|
-
if (!schema?.options?.draftAndPublish) {
|
2128
|
-
return null;
|
2129
|
-
}
|
2130
|
-
return {
|
2131
|
-
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2132
|
-
label: formatMessage({
|
2133
|
-
id: "content-manager.actions.discard.label",
|
2134
|
-
defaultMessage: "Discard changes"
|
2135
|
-
}),
|
2136
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(StyledCrossCircle, {}),
|
2137
|
-
position: ["panel", "table-row"],
|
2138
|
-
variant: "danger",
|
2139
|
-
dialog: {
|
2140
|
-
type: "dialog",
|
2141
|
-
title: formatMessage({
|
2142
|
-
id: "app.components.ConfirmDialog.title",
|
2143
|
-
defaultMessage: "Confirmation"
|
2144
|
-
}),
|
2145
|
-
content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
|
2146
|
-
/* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2147
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2148
|
-
id: "content-manager.actions.discard.dialog.body",
|
2149
|
-
defaultMessage: "Are you sure?"
|
2150
|
-
}) })
|
2151
|
-
] }),
|
2152
|
-
onConfirm: async () => {
|
2153
|
-
await discard({
|
2154
|
-
collectionType,
|
2155
|
-
model,
|
2156
|
-
documentId,
|
2157
|
-
params
|
2158
|
-
});
|
2159
|
-
}
|
2070
|
+
const handleClose = () => {
|
2071
|
+
if (onClose) {
|
2072
|
+
onClose();
|
2160
2073
|
}
|
2074
|
+
onModalClose();
|
2161
2075
|
};
|
2076
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Content, { children: [
|
2077
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Header, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Title, { children: title }) }),
|
2078
|
+
typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : /* @__PURE__ */ jsxRuntime.jsx(designSystem.Modal.Body, { children: Content }),
|
2079
|
+
typeof Footer === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Footer, { onClose: handleClose }) : Footer
|
2080
|
+
] }) });
|
2162
2081
|
};
|
2163
|
-
|
2164
|
-
|
2165
|
-
|
2166
|
-
fill: currentColor;
|
2167
|
-
}
|
2168
|
-
`;
|
2169
|
-
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2170
|
-
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2171
|
-
const RelativeTime = React__namespace.forwardRef(
|
2172
|
-
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2173
|
-
const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
|
2174
|
-
const interval = dateFns.intervalToDuration({
|
2175
|
-
start: timestamp,
|
2176
|
-
end: Date.now()
|
2177
|
-
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2178
|
-
});
|
2179
|
-
const unit = intervals.find((intervalUnit) => {
|
2180
|
-
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2181
|
-
});
|
2182
|
-
const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
|
2183
|
-
const customInterval = customIntervals.find(
|
2184
|
-
(custom) => interval[custom.unit] < custom.threshold
|
2185
|
-
);
|
2186
|
-
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2187
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
2188
|
-
"time",
|
2189
|
-
{
|
2190
|
-
ref: forwardedRef,
|
2191
|
-
dateTime: timestamp.toISOString(),
|
2192
|
-
role: "time",
|
2193
|
-
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2194
|
-
...restProps,
|
2195
|
-
children: displayText
|
2196
|
-
}
|
2197
|
-
);
|
2198
|
-
}
|
2199
|
-
);
|
2200
|
-
const getDisplayName = ({
|
2201
|
-
firstname,
|
2202
|
-
lastname,
|
2203
|
-
username,
|
2204
|
-
email
|
2205
|
-
} = {}) => {
|
2206
|
-
if (username) {
|
2207
|
-
return username;
|
2082
|
+
const transformData = (data) => {
|
2083
|
+
if (Array.isArray(data)) {
|
2084
|
+
return data.map(transformData);
|
2208
2085
|
}
|
2209
|
-
if (
|
2210
|
-
|
2086
|
+
if (typeof data === "object" && data !== null) {
|
2087
|
+
if ("apiData" in data) {
|
2088
|
+
return data.apiData;
|
2089
|
+
}
|
2090
|
+
return mapValues__default.default(transformData)(data);
|
2211
2091
|
}
|
2212
|
-
return
|
2213
|
-
};
|
2214
|
-
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2215
|
-
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2216
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
2217
|
-
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) }) });
|
2092
|
+
return data;
|
2218
2093
|
};
|
2219
|
-
const
|
2220
|
-
|
2094
|
+
const PublishAction$1 = ({
|
2095
|
+
activeTab,
|
2096
|
+
documentId,
|
2097
|
+
model,
|
2098
|
+
collectionType,
|
2099
|
+
meta,
|
2100
|
+
document
|
2101
|
+
}) => {
|
2102
|
+
const { schema } = useDoc();
|
2103
|
+
const navigate = reactRouterDom.useNavigate();
|
2104
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
2105
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
|
2106
|
+
const isListView = reactRouterDom.useMatch(LIST_PATH) !== null;
|
2221
2107
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2222
|
-
const title = isCreating ? formatMessage({
|
2223
|
-
id: "content-manager.containers.edit.title.new",
|
2224
|
-
defaultMessage: "Create an entry"
|
2225
|
-
}) : documentTitle;
|
2226
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2227
|
-
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
|
2228
|
-
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2229
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2230
|
-
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2231
|
-
] }),
|
2232
|
-
status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2233
|
-
] });
|
2234
|
-
};
|
2235
|
-
const HeaderToolbar = () => {
|
2236
2108
|
const { formatMessage } = reactIntl.useIntl();
|
2237
|
-
const
|
2109
|
+
const canPublish = useDocumentRBAC("PublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2110
|
+
const { publish } = useDocumentActions();
|
2238
2111
|
const [
|
2239
|
-
|
2240
|
-
|
2112
|
+
countDraftRelations,
|
2113
|
+
{ isLoading: isLoadingDraftRelations, isError: isErrorDraftRelations }
|
2114
|
+
] = useLazyGetDraftRelationCountQuery();
|
2115
|
+
const [localCountOfDraftRelations, setLocalCountOfDraftRelations] = React__namespace.useState(0);
|
2116
|
+
const [serverCountOfDraftRelations, setServerCountOfDraftRelations] = React__namespace.useState(0);
|
2117
|
+
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
2118
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2119
|
+
const modified = strapiAdmin.useForm("PublishAction", ({ modified: modified2 }) => modified2);
|
2120
|
+
const setSubmitting = strapiAdmin.useForm("PublishAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2121
|
+
const isSubmitting = strapiAdmin.useForm("PublishAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2122
|
+
const validate = strapiAdmin.useForm("PublishAction", (state) => state.validate);
|
2123
|
+
const setErrors = strapiAdmin.useForm("PublishAction", (state) => state.setErrors);
|
2124
|
+
const formValues = strapiAdmin.useForm("PublishAction", ({ values }) => values);
|
2125
|
+
React__namespace.useEffect(() => {
|
2126
|
+
if (isErrorDraftRelations) {
|
2127
|
+
toggleNotification({
|
2128
|
+
type: "danger",
|
2129
|
+
message: formatMessage({
|
2130
|
+
id: getTranslation("error.records.fetch-draft-relatons"),
|
2131
|
+
defaultMessage: "An error occurred while fetching draft relations on this document."
|
2132
|
+
})
|
2133
|
+
});
|
2241
2134
|
}
|
2242
|
-
|
2243
|
-
|
2244
|
-
|
2245
|
-
|
2246
|
-
|
2247
|
-
|
2248
|
-
|
2249
|
-
|
2250
|
-
activeTab: status,
|
2251
|
-
model,
|
2252
|
-
documentId: id,
|
2253
|
-
document: isCloning ? void 0 : document,
|
2254
|
-
meta: isCloning ? void 0 : meta,
|
2255
|
-
collectionType
|
2256
|
-
},
|
2257
|
-
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2258
|
-
children: (actions2) => {
|
2259
|
-
if (actions2.length > 0) {
|
2260
|
-
return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
|
2261
|
-
} else {
|
2262
|
-
return null;
|
2263
|
-
}
|
2135
|
+
}, [isErrorDraftRelations, toggleNotification, formatMessage]);
|
2136
|
+
React__namespace.useEffect(() => {
|
2137
|
+
const localDraftRelations = /* @__PURE__ */ new Set();
|
2138
|
+
const extractDraftRelations = (data) => {
|
2139
|
+
const relations = data.connect || [];
|
2140
|
+
relations.forEach((relation) => {
|
2141
|
+
if (relation.status === "draft") {
|
2142
|
+
localDraftRelations.add(relation.id);
|
2264
2143
|
}
|
2265
|
-
}
|
2266
|
-
|
2267
|
-
|
2268
|
-
|
2269
|
-
|
2270
|
-
|
2271
|
-
|
2272
|
-
|
2273
|
-
documentId: id,
|
2274
|
-
document: isCloning ? void 0 : document,
|
2275
|
-
meta: isCloning ? void 0 : meta,
|
2276
|
-
collectionType
|
2277
|
-
},
|
2278
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2279
|
-
children: (actions2) => {
|
2280
|
-
const headerActions = actions2.filter((action) => {
|
2281
|
-
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2282
|
-
return positions.includes("header");
|
2283
|
-
});
|
2284
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
2285
|
-
DocumentActionsMenu,
|
2286
|
-
{
|
2287
|
-
actions: headerActions,
|
2288
|
-
label: formatMessage({
|
2289
|
-
id: "content-manager.containers.edit.header.more-actions",
|
2290
|
-
defaultMessage: "More actions"
|
2291
|
-
}),
|
2292
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
|
2293
|
-
}
|
2294
|
-
);
|
2144
|
+
});
|
2145
|
+
};
|
2146
|
+
const traverseAndExtract = (data) => {
|
2147
|
+
Object.entries(data).forEach(([key, value]) => {
|
2148
|
+
if (key === "connect" && Array.isArray(value)) {
|
2149
|
+
extractDraftRelations({ connect: value });
|
2150
|
+
} else if (typeof value === "object" && value !== null) {
|
2151
|
+
traverseAndExtract(value);
|
2295
2152
|
}
|
2153
|
+
});
|
2154
|
+
};
|
2155
|
+
if (!documentId || modified) {
|
2156
|
+
traverseAndExtract(formValues);
|
2157
|
+
setLocalCountOfDraftRelations(localDraftRelations.size);
|
2158
|
+
}
|
2159
|
+
}, [documentId, modified, formValues, setLocalCountOfDraftRelations]);
|
2160
|
+
React__namespace.useEffect(() => {
|
2161
|
+
if (!document || !document.documentId || isListView) {
|
2162
|
+
return;
|
2163
|
+
}
|
2164
|
+
const fetchDraftRelationsCount = async () => {
|
2165
|
+
const { data, error } = await countDraftRelations({
|
2166
|
+
collectionType,
|
2167
|
+
model,
|
2168
|
+
documentId,
|
2169
|
+
params
|
2170
|
+
});
|
2171
|
+
if (error) {
|
2172
|
+
throw error;
|
2296
2173
|
}
|
2297
|
-
|
2298
|
-
|
2299
|
-
}
|
2300
|
-
|
2301
|
-
|
2302
|
-
|
2303
|
-
|
2174
|
+
if (data) {
|
2175
|
+
setServerCountOfDraftRelations(data.data);
|
2176
|
+
}
|
2177
|
+
};
|
2178
|
+
fetchDraftRelationsCount();
|
2179
|
+
}, [isListView, document, documentId, countDraftRelations, collectionType, model, params]);
|
2180
|
+
const isDocumentPublished = (document?.[PUBLISHED_AT_ATTRIBUTE_NAME] || meta?.availableStatus.some((doc) => doc[PUBLISHED_AT_ATTRIBUTE_NAME] !== null)) && document?.status !== "modified";
|
2181
|
+
if (!schema?.options?.draftAndPublish) {
|
2304
2182
|
return null;
|
2305
2183
|
}
|
2306
|
-
const
|
2307
|
-
|
2308
|
-
|
2309
|
-
|
2310
|
-
|
2311
|
-
|
2312
|
-
|
2313
|
-
|
2314
|
-
|
2315
|
-
|
2316
|
-
|
2317
|
-
|
2184
|
+
const performPublish = async () => {
|
2185
|
+
setSubmitting(true);
|
2186
|
+
try {
|
2187
|
+
const { errors } = await validate(true, {
|
2188
|
+
status: "published"
|
2189
|
+
});
|
2190
|
+
if (errors) {
|
2191
|
+
toggleNotification({
|
2192
|
+
type: "danger",
|
2193
|
+
message: formatMessage({
|
2194
|
+
id: "content-manager.validation.error",
|
2195
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2196
|
+
})
|
2197
|
+
});
|
2198
|
+
return;
|
2199
|
+
}
|
2200
|
+
const res = await publish(
|
2318
2201
|
{
|
2319
|
-
|
2320
|
-
|
2202
|
+
collectionType,
|
2203
|
+
model,
|
2204
|
+
documentId,
|
2205
|
+
params
|
2321
2206
|
},
|
2322
|
-
|
2323
|
-
|
2324
|
-
|
2325
|
-
|
2326
|
-
|
2327
|
-
|
2207
|
+
transformData(formValues)
|
2208
|
+
);
|
2209
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2210
|
+
navigate({
|
2211
|
+
pathname: `../${collectionType}/${model}/${res.data.documentId}`,
|
2212
|
+
search: rawQuery
|
2213
|
+
});
|
2214
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2215
|
+
setErrors(formatValidationErrors(res.error));
|
2216
|
+
}
|
2217
|
+
} finally {
|
2218
|
+
setSubmitting(false);
|
2219
|
+
}
|
2220
|
+
};
|
2221
|
+
const totalDraftRelations = localCountOfDraftRelations + serverCountOfDraftRelations;
|
2222
|
+
const enableDraftRelationsCount = false;
|
2223
|
+
const hasDraftRelations = enableDraftRelationsCount;
|
2224
|
+
return {
|
2225
|
+
/**
|
2226
|
+
* Disabled when:
|
2227
|
+
* - currently if you're cloning a document we don't support publish & clone at the same time.
|
2228
|
+
* - the form is submitting
|
2229
|
+
* - the active tab is the published tab
|
2230
|
+
* - the document is already published & not modified
|
2231
|
+
* - the document is being created & not modified
|
2232
|
+
* - the user doesn't have the permission to publish
|
2233
|
+
*/
|
2234
|
+
disabled: isCloning || isSubmitting || isLoadingDraftRelations || activeTab === "published" || !modified && isDocumentPublished || !modified && !document?.documentId || !canPublish,
|
2235
|
+
label: formatMessage({
|
2236
|
+
id: "app.utils.publish",
|
2237
|
+
defaultMessage: "Publish"
|
2238
|
+
}),
|
2239
|
+
onClick: async () => {
|
2240
|
+
await performPublish();
|
2328
2241
|
},
|
2329
|
-
{
|
2330
|
-
|
2331
|
-
|
2332
|
-
|
2333
|
-
|
2242
|
+
dialog: hasDraftRelations ? {
|
2243
|
+
type: "dialog",
|
2244
|
+
variant: "danger",
|
2245
|
+
footer: null,
|
2246
|
+
title: formatMessage({
|
2247
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.title`),
|
2248
|
+
defaultMessage: "Confirmation"
|
2334
2249
|
}),
|
2335
|
-
|
2250
|
+
content: formatMessage(
|
2336
2251
|
{
|
2337
|
-
id:
|
2338
|
-
defaultMessage:
|
2252
|
+
id: getTranslation(`popUpwarning.warning.bulk-has-draft-relations.message`),
|
2253
|
+
defaultMessage: "This entry is related to {count, plural, one {# draft entry} other {# draft entries}}. Publishing it could leave broken links in your app."
|
2339
2254
|
},
|
2340
2255
|
{
|
2341
|
-
|
2342
|
-
RelativeTime,
|
2343
|
-
{
|
2344
|
-
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2345
|
-
}
|
2346
|
-
),
|
2347
|
-
isAnonymous: !updator,
|
2348
|
-
author: updator
|
2256
|
+
count: totalDraftRelations
|
2349
2257
|
}
|
2350
|
-
)
|
2351
|
-
|
2352
|
-
|
2353
|
-
|
2354
|
-
|
2355
|
-
|
2356
|
-
|
2357
|
-
|
2358
|
-
|
2359
|
-
|
2360
|
-
|
2361
|
-
|
2362
|
-
|
2363
|
-
|
2364
|
-
|
2365
|
-
|
2366
|
-
|
2367
|
-
|
2368
|
-
|
2369
|
-
|
2370
|
-
|
2371
|
-
|
2258
|
+
),
|
2259
|
+
onConfirm: async () => {
|
2260
|
+
await performPublish();
|
2261
|
+
}
|
2262
|
+
} : void 0
|
2263
|
+
};
|
2264
|
+
};
|
2265
|
+
PublishAction$1.type = "publish";
|
2266
|
+
const UpdateAction = ({
|
2267
|
+
activeTab,
|
2268
|
+
documentId,
|
2269
|
+
model,
|
2270
|
+
collectionType
|
2271
|
+
}) => {
|
2272
|
+
const navigate = reactRouterDom.useNavigate();
|
2273
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
2274
|
+
const { _unstableFormatValidationErrors: formatValidationErrors } = strapiAdmin.useAPIErrorHandler();
|
2275
|
+
const cloneMatch = reactRouterDom.useMatch(CLONE_PATH);
|
2276
|
+
const isCloning = cloneMatch !== null;
|
2277
|
+
const { formatMessage } = reactIntl.useIntl();
|
2278
|
+
const { create, update, clone } = useDocumentActions();
|
2279
|
+
const [{ query, rawQuery }] = strapiAdmin.useQueryParams();
|
2280
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2281
|
+
const isSubmitting = strapiAdmin.useForm("UpdateAction", ({ isSubmitting: isSubmitting2 }) => isSubmitting2);
|
2282
|
+
const modified = strapiAdmin.useForm("UpdateAction", ({ modified: modified2 }) => modified2);
|
2283
|
+
const setSubmitting = strapiAdmin.useForm("UpdateAction", ({ setSubmitting: setSubmitting2 }) => setSubmitting2);
|
2284
|
+
const document = strapiAdmin.useForm("UpdateAction", ({ values }) => values);
|
2285
|
+
const validate = strapiAdmin.useForm("UpdateAction", (state) => state.validate);
|
2286
|
+
const setErrors = strapiAdmin.useForm("UpdateAction", (state) => state.setErrors);
|
2287
|
+
const resetForm = strapiAdmin.useForm("PublishAction", ({ resetForm: resetForm2 }) => resetForm2);
|
2288
|
+
return {
|
2289
|
+
/**
|
2290
|
+
* Disabled when:
|
2291
|
+
* - the form is submitting
|
2292
|
+
* - the document is not modified & we're not cloning (you can save a clone entity straight away)
|
2293
|
+
* - the active tab is the published tab
|
2294
|
+
*/
|
2295
|
+
disabled: isSubmitting || !modified && !isCloning || activeTab === "published",
|
2296
|
+
label: formatMessage({
|
2297
|
+
id: "content-manager.containers.Edit.save",
|
2298
|
+
defaultMessage: "Save"
|
2299
|
+
}),
|
2300
|
+
onClick: async () => {
|
2301
|
+
setSubmitting(true);
|
2302
|
+
try {
|
2303
|
+
const { errors } = await validate(true, {
|
2304
|
+
status: "draft"
|
2305
|
+
});
|
2306
|
+
if (errors) {
|
2307
|
+
toggleNotification({
|
2308
|
+
type: "danger",
|
2309
|
+
message: formatMessage({
|
2310
|
+
id: "content-manager.validation.error",
|
2311
|
+
defaultMessage: "There are validation errors in your document. Please fix them before saving."
|
2312
|
+
})
|
2313
|
+
});
|
2314
|
+
return;
|
2372
2315
|
}
|
2373
|
-
|
2374
|
-
|
2375
|
-
|
2376
|
-
|
2377
|
-
|
2378
|
-
|
2379
|
-
|
2380
|
-
|
2381
|
-
|
2382
|
-
|
2383
|
-
|
2384
|
-
|
2385
|
-
|
2386
|
-
|
2387
|
-
|
2388
|
-
|
2389
|
-
|
2390
|
-
|
2391
|
-
|
2392
|
-
|
2393
|
-
|
2394
|
-
|
2316
|
+
if (isCloning) {
|
2317
|
+
const res = await clone(
|
2318
|
+
{
|
2319
|
+
model,
|
2320
|
+
documentId: cloneMatch.params.origin,
|
2321
|
+
params
|
2322
|
+
},
|
2323
|
+
transformData(document)
|
2324
|
+
);
|
2325
|
+
if ("data" in res) {
|
2326
|
+
navigate(
|
2327
|
+
{
|
2328
|
+
pathname: `../${res.data.documentId}`,
|
2329
|
+
search: rawQuery
|
2330
|
+
},
|
2331
|
+
{ relative: "path" }
|
2332
|
+
);
|
2333
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2334
|
+
setErrors(formatValidationErrors(res.error));
|
2335
|
+
}
|
2336
|
+
} else if (documentId || collectionType === SINGLE_TYPES) {
|
2337
|
+
const res = await update(
|
2338
|
+
{
|
2339
|
+
collectionType,
|
2340
|
+
model,
|
2341
|
+
documentId,
|
2342
|
+
params
|
2343
|
+
},
|
2344
|
+
transformData(document)
|
2345
|
+
);
|
2346
|
+
if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2347
|
+
setErrors(formatValidationErrors(res.error));
|
2348
|
+
} else {
|
2349
|
+
resetForm();
|
2350
|
+
}
|
2351
|
+
} else {
|
2352
|
+
const res = await create(
|
2353
|
+
{
|
2354
|
+
model,
|
2355
|
+
params
|
2356
|
+
},
|
2357
|
+
transformData(document)
|
2358
|
+
);
|
2359
|
+
if ("data" in res && collectionType !== SINGLE_TYPES) {
|
2360
|
+
navigate(
|
2361
|
+
{
|
2362
|
+
pathname: `../${res.data.documentId}`,
|
2363
|
+
search: rawQuery
|
2364
|
+
},
|
2365
|
+
{ replace: true, relative: "path" }
|
2366
|
+
);
|
2367
|
+
} else if ("error" in res && isBaseQueryError(res.error) && res.error.name === "ValidationError") {
|
2368
|
+
setErrors(formatValidationErrors(res.error));
|
2369
|
+
}
|
2370
|
+
}
|
2371
|
+
} finally {
|
2372
|
+
setSubmitting(false);
|
2373
|
+
}
|
2395
2374
|
}
|
2396
|
-
|
2375
|
+
};
|
2397
2376
|
};
|
2398
|
-
|
2399
|
-
|
2400
|
-
|
2401
|
-
|
2402
|
-
designSystem.SingleSelect,
|
2403
|
-
{
|
2404
|
-
size: "S",
|
2405
|
-
disabled: action.disabled,
|
2406
|
-
"aria-label": action.label,
|
2407
|
-
onChange: action.onSelect,
|
2408
|
-
value: action.value,
|
2409
|
-
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
|
2410
|
-
},
|
2411
|
-
action.id
|
2412
|
-
);
|
2413
|
-
} else {
|
2414
|
-
return null;
|
2415
|
-
}
|
2416
|
-
}) });
|
2377
|
+
UpdateAction.type = "update";
|
2378
|
+
const UNPUBLISH_DRAFT_OPTIONS = {
|
2379
|
+
KEEP: "keep",
|
2380
|
+
DISCARD: "discard"
|
2417
2381
|
};
|
2418
|
-
const
|
2419
|
-
|
2382
|
+
const UnpublishAction$1 = ({
|
2383
|
+
activeTab,
|
2384
|
+
documentId,
|
2385
|
+
model,
|
2386
|
+
collectionType,
|
2387
|
+
document
|
2388
|
+
}) => {
|
2420
2389
|
const { formatMessage } = reactIntl.useIntl();
|
2421
|
-
|
2422
|
-
|
2423
|
-
|
2424
|
-
|
2425
|
-
|
2426
|
-
|
2427
|
-
|
2428
|
-
|
2429
|
-
|
2430
|
-
|
2390
|
+
const { schema } = useDoc();
|
2391
|
+
const canPublish = useDocumentRBAC("UnpublishAction", ({ canPublish: canPublish2 }) => canPublish2);
|
2392
|
+
const { unpublish } = useDocumentActions();
|
2393
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
2394
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2395
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
2396
|
+
const [shouldKeepDraft, setShouldKeepDraft] = React__namespace.useState(true);
|
2397
|
+
const isDocumentModified = document?.status === "modified";
|
2398
|
+
const handleChange = (value) => {
|
2399
|
+
setShouldKeepDraft(value === UNPUBLISH_DRAFT_OPTIONS.KEEP);
|
2431
2400
|
};
|
2432
|
-
|
2433
|
-
|
2434
|
-
|
2435
|
-
const navigate = reactRouterDom.useNavigate();
|
2436
|
-
const { formatMessage } = reactIntl.useIntl();
|
2401
|
+
if (!schema?.options?.draftAndPublish) {
|
2402
|
+
return null;
|
2403
|
+
}
|
2437
2404
|
return {
|
2405
|
+
disabled: !canPublish || activeTab === "published" || document?.status !== "published" && document?.status !== "modified",
|
2438
2406
|
label: formatMessage({
|
2439
|
-
id: "
|
2440
|
-
defaultMessage: "
|
2407
|
+
id: "app.utils.unpublish",
|
2408
|
+
defaultMessage: "Unpublish"
|
2441
2409
|
}),
|
2442
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.
|
2443
|
-
onClick: () => {
|
2444
|
-
|
2410
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
2411
|
+
onClick: async () => {
|
2412
|
+
if (!documentId && collectionType !== SINGLE_TYPES || isDocumentModified) {
|
2413
|
+
if (!documentId) {
|
2414
|
+
console.error(
|
2415
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2416
|
+
);
|
2417
|
+
toggleNotification({
|
2418
|
+
message: formatMessage({
|
2419
|
+
id: "content-manager.actions.unpublish.error",
|
2420
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2421
|
+
}),
|
2422
|
+
type: "danger"
|
2423
|
+
});
|
2424
|
+
}
|
2425
|
+
return;
|
2426
|
+
}
|
2427
|
+
await unpublish({
|
2428
|
+
collectionType,
|
2429
|
+
model,
|
2430
|
+
documentId,
|
2431
|
+
params
|
2432
|
+
});
|
2445
2433
|
},
|
2446
|
-
|
2434
|
+
dialog: isDocumentModified ? {
|
2435
|
+
type: "dialog",
|
2436
|
+
title: formatMessage({
|
2437
|
+
id: "app.components.ConfirmDialog.title",
|
2438
|
+
defaultMessage: "Confirmation"
|
2439
|
+
}),
|
2440
|
+
content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { alignItems: "flex-start", direction: "column", gap: 6, children: [
|
2441
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", direction: "column", gap: 2, children: [
|
2442
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2443
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2444
|
+
id: "content-manager.actions.unpublish.dialog.body",
|
2445
|
+
defaultMessage: "Are you sure?"
|
2446
|
+
}) })
|
2447
|
+
] }),
|
2448
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
2449
|
+
designSystem.Radio.Group,
|
2450
|
+
{
|
2451
|
+
defaultValue: UNPUBLISH_DRAFT_OPTIONS.KEEP,
|
2452
|
+
name: "discard-options",
|
2453
|
+
"aria-label": formatMessage({
|
2454
|
+
id: "content-manager.actions.unpublish.dialog.radio-label",
|
2455
|
+
defaultMessage: "Choose an option to unpublish the document."
|
2456
|
+
}),
|
2457
|
+
onValueChange: handleChange,
|
2458
|
+
children: [
|
2459
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.KEEP, children: formatMessage({
|
2460
|
+
id: "content-manager.actions.unpublish.dialog.option.keep-draft",
|
2461
|
+
defaultMessage: "Keep draft"
|
2462
|
+
}) }),
|
2463
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Radio.Item, { checked: !shouldKeepDraft, value: UNPUBLISH_DRAFT_OPTIONS.DISCARD, children: formatMessage({
|
2464
|
+
id: "content-manager.actions.unpublish.dialog.option.replace-draft",
|
2465
|
+
defaultMessage: "Replace draft"
|
2466
|
+
}) })
|
2467
|
+
]
|
2468
|
+
}
|
2469
|
+
)
|
2470
|
+
] }),
|
2471
|
+
onConfirm: async () => {
|
2472
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2473
|
+
console.error(
|
2474
|
+
"You're trying to unpublish a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2475
|
+
);
|
2476
|
+
toggleNotification({
|
2477
|
+
message: formatMessage({
|
2478
|
+
id: "content-manager.actions.unpublish.error",
|
2479
|
+
defaultMessage: "An error occurred while trying to unpublish the document."
|
2480
|
+
}),
|
2481
|
+
type: "danger"
|
2482
|
+
});
|
2483
|
+
}
|
2484
|
+
await unpublish(
|
2485
|
+
{
|
2486
|
+
collectionType,
|
2487
|
+
model,
|
2488
|
+
documentId,
|
2489
|
+
params
|
2490
|
+
},
|
2491
|
+
!shouldKeepDraft
|
2492
|
+
);
|
2493
|
+
}
|
2494
|
+
} : void 0,
|
2495
|
+
variant: "danger",
|
2496
|
+
position: ["panel", "table-row"]
|
2447
2497
|
};
|
2448
2498
|
};
|
2449
|
-
|
2450
|
-
const
|
2451
|
-
|
2499
|
+
UnpublishAction$1.type = "unpublish";
|
2500
|
+
const DiscardAction = ({
|
2501
|
+
activeTab,
|
2502
|
+
documentId,
|
2503
|
+
model,
|
2504
|
+
collectionType,
|
2505
|
+
document
|
2506
|
+
}) => {
|
2452
2507
|
const { formatMessage } = reactIntl.useIntl();
|
2453
|
-
const
|
2454
|
-
const
|
2455
|
-
const {
|
2456
|
-
const {
|
2457
|
-
const
|
2508
|
+
const { schema } = useDoc();
|
2509
|
+
const canUpdate = useDocumentRBAC("DiscardAction", ({ canUpdate: canUpdate2 }) => canUpdate2);
|
2510
|
+
const { discard } = useDocumentActions();
|
2511
|
+
const [{ query }] = strapiAdmin.useQueryParams();
|
2512
|
+
const params = React__namespace.useMemo(() => buildValidParams(query), [query]);
|
2513
|
+
if (!schema?.options?.draftAndPublish) {
|
2514
|
+
return null;
|
2515
|
+
}
|
2458
2516
|
return {
|
2459
|
-
disabled: !
|
2517
|
+
disabled: !canUpdate || activeTab === "published" || document?.status !== "modified",
|
2460
2518
|
label: formatMessage({
|
2461
|
-
id: "content-manager.actions.
|
2462
|
-
defaultMessage: "
|
2519
|
+
id: "content-manager.actions.discard.label",
|
2520
|
+
defaultMessage: "Discard changes"
|
2463
2521
|
}),
|
2464
|
-
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.
|
2522
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Cross, {}),
|
2523
|
+
position: ["panel", "table-row"],
|
2524
|
+
variant: "danger",
|
2465
2525
|
dialog: {
|
2466
2526
|
type: "dialog",
|
2467
2527
|
title: formatMessage({
|
@@ -2471,92 +2531,90 @@ const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
|
2471
2531
|
content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
|
2472
2532
|
/* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2473
2533
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2474
|
-
id: "content-manager.actions.
|
2534
|
+
id: "content-manager.actions.discard.dialog.body",
|
2475
2535
|
defaultMessage: "Are you sure?"
|
2476
2536
|
}) })
|
2477
2537
|
] }),
|
2478
2538
|
onConfirm: async () => {
|
2479
|
-
|
2480
|
-
|
2481
|
-
|
2482
|
-
|
2483
|
-
|
2484
|
-
|
2485
|
-
|
2486
|
-
|
2487
|
-
|
2488
|
-
|
2489
|
-
|
2490
|
-
|
2491
|
-
|
2492
|
-
|
2493
|
-
|
2494
|
-
|
2495
|
-
|
2496
|
-
|
2497
|
-
|
2498
|
-
|
2499
|
-
|
2500
|
-
|
2501
|
-
|
2502
|
-
|
2503
|
-
|
2504
|
-
|
2505
|
-
|
2506
|
-
|
2507
|
-
|
2508
|
-
|
2509
|
-
|
2510
|
-
|
2511
|
-
|
2539
|
+
await discard({
|
2540
|
+
collectionType,
|
2541
|
+
model,
|
2542
|
+
documentId,
|
2543
|
+
params
|
2544
|
+
});
|
2545
|
+
}
|
2546
|
+
}
|
2547
|
+
};
|
2548
|
+
};
|
2549
|
+
DiscardAction.type = "discard";
|
2550
|
+
const DEFAULT_ACTIONS = [PublishAction$1, UpdateAction, UnpublishAction$1, DiscardAction];
|
2551
|
+
const intervals = ["years", "months", "days", "hours", "minutes", "seconds"];
|
2552
|
+
const RelativeTime = React__namespace.forwardRef(
|
2553
|
+
({ timestamp, customIntervals = [], ...restProps }, forwardedRef) => {
|
2554
|
+
const { formatRelativeTime, formatDate, formatTime } = reactIntl.useIntl();
|
2555
|
+
const interval = dateFns.intervalToDuration({
|
2556
|
+
start: timestamp,
|
2557
|
+
end: Date.now()
|
2558
|
+
// see https://github.com/date-fns/date-fns/issues/2891 – No idea why it's all partial it returns it every time.
|
2559
|
+
});
|
2560
|
+
const unit = intervals.find((intervalUnit) => {
|
2561
|
+
return interval[intervalUnit] > 0 && Object.keys(interval).includes(intervalUnit);
|
2562
|
+
});
|
2563
|
+
const relativeTime = dateFns.isPast(timestamp) ? -interval[unit] : interval[unit];
|
2564
|
+
const customInterval = customIntervals.find(
|
2565
|
+
(custom) => interval[custom.unit] < custom.threshold
|
2566
|
+
);
|
2567
|
+
const displayText = customInterval ? customInterval.text : formatRelativeTime(relativeTime, unit, { numeric: "auto" });
|
2568
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
2569
|
+
"time",
|
2570
|
+
{
|
2571
|
+
ref: forwardedRef,
|
2572
|
+
dateTime: timestamp.toISOString(),
|
2573
|
+
role: "time",
|
2574
|
+
title: `${formatDate(timestamp)} ${formatTime(timestamp)}`,
|
2575
|
+
...restProps,
|
2576
|
+
children: displayText
|
2512
2577
|
}
|
2513
|
-
|
2514
|
-
|
2515
|
-
|
2516
|
-
|
2578
|
+
);
|
2579
|
+
}
|
2580
|
+
);
|
2581
|
+
const getDisplayName = ({
|
2582
|
+
firstname,
|
2583
|
+
lastname,
|
2584
|
+
username,
|
2585
|
+
email
|
2586
|
+
} = {}) => {
|
2587
|
+
if (username) {
|
2588
|
+
return username;
|
2589
|
+
}
|
2590
|
+
if (firstname) {
|
2591
|
+
return `${firstname} ${lastname ?? ""}`.trim();
|
2592
|
+
}
|
2593
|
+
return email ?? "";
|
2517
2594
|
};
|
2518
|
-
|
2519
|
-
const
|
2520
|
-
const
|
2521
|
-
|
2522
|
-
const [
|
2523
|
-
{
|
2524
|
-
query: { status }
|
2525
|
-
}
|
2526
|
-
] = strapiAdmin.useQueryParams({
|
2527
|
-
status: "draft"
|
2528
|
-
});
|
2529
|
-
const { model, id, document, meta, collectionType } = useDoc();
|
2530
|
-
const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
|
2531
|
-
const props = {
|
2532
|
-
activeTab: status,
|
2533
|
-
model,
|
2534
|
-
documentId: id,
|
2535
|
-
document: isCloning ? void 0 : document,
|
2536
|
-
meta: isCloning ? void 0 : meta,
|
2537
|
-
collectionType
|
2538
|
-
};
|
2539
|
-
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
2540
|
-
strapiAdmin.DescriptionComponentRenderer,
|
2541
|
-
{
|
2542
|
-
props,
|
2543
|
-
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2544
|
-
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
2545
|
-
}
|
2546
|
-
) });
|
2595
|
+
const capitalise = (str) => str.charAt(0).toUpperCase() + str.slice(1);
|
2596
|
+
const DocumentStatus = ({ status = "draft", ...restProps }) => {
|
2597
|
+
const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
|
2598
|
+
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) }) });
|
2547
2599
|
};
|
2548
|
-
const
|
2600
|
+
const Header = ({ isCreating, status, title: documentTitle = "Untitled" }) => {
|
2549
2601
|
const { formatMessage } = reactIntl.useIntl();
|
2550
|
-
|
2551
|
-
|
2552
|
-
|
2553
|
-
|
2554
|
-
|
2555
|
-
|
2556
|
-
|
2602
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2603
|
+
const title = isCreating ? formatMessage({
|
2604
|
+
id: "content-manager.containers.edit.title.new",
|
2605
|
+
defaultMessage: "Create an entry"
|
2606
|
+
}) : documentTitle;
|
2607
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", alignItems: "flex-start", paddingTop: 6, paddingBottom: 4, gap: 2, children: [
|
2608
|
+
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.BackButton, {}),
|
2609
|
+
/* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { width: "100%", justifyContent: "space-between", gap: "80px", alignItems: "flex-start", children: [
|
2610
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { variant: "alpha", tag: "h1", children: title }),
|
2611
|
+
/* @__PURE__ */ jsxRuntime.jsx(HeaderToolbar, {})
|
2612
|
+
] }),
|
2613
|
+
status ? /* @__PURE__ */ jsxRuntime.jsx(designSystem.Box, { marginTop: 1, children: /* @__PURE__ */ jsxRuntime.jsx(DocumentStatus, { status: isCloning ? "draft" : status }) }) : null
|
2614
|
+
] });
|
2557
2615
|
};
|
2558
|
-
|
2559
|
-
const
|
2616
|
+
const HeaderToolbar = () => {
|
2617
|
+
const { formatMessage } = reactIntl.useIntl();
|
2560
2618
|
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2561
2619
|
const [
|
2562
2620
|
{
|
@@ -2564,355 +2622,432 @@ const ActionsPanelContent = () => {
|
|
2564
2622
|
}
|
2565
2623
|
] = strapiAdmin.useQueryParams();
|
2566
2624
|
const { model, id, document, meta, collectionType } = useDoc();
|
2567
|
-
const plugins = strapiAdmin.useStrapiApp("
|
2568
|
-
|
2569
|
-
activeTab: status,
|
2570
|
-
model,
|
2571
|
-
documentId: id,
|
2572
|
-
document: isCloning ? void 0 : document,
|
2573
|
-
meta: isCloning ? void 0 : meta,
|
2574
|
-
collectionType
|
2575
|
-
};
|
2576
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
2625
|
+
const plugins = strapiAdmin.useStrapiApp("HeaderToolbar", (state) => state.plugins);
|
2626
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 2, children: [
|
2577
2627
|
/* @__PURE__ */ jsxRuntime.jsx(
|
2578
2628
|
strapiAdmin.DescriptionComponentRenderer,
|
2579
2629
|
{
|
2580
|
-
props
|
2581
|
-
|
2582
|
-
|
2630
|
+
props: {
|
2631
|
+
activeTab: status,
|
2632
|
+
model,
|
2633
|
+
documentId: id,
|
2634
|
+
document: isCloning ? void 0 : document,
|
2635
|
+
meta: isCloning ? void 0 : meta,
|
2636
|
+
collectionType
|
2637
|
+
},
|
2638
|
+
descriptions: plugins["content-manager"].apis.getHeaderActions(),
|
2639
|
+
children: (actions2) => {
|
2640
|
+
if (actions2.length > 0) {
|
2641
|
+
return /* @__PURE__ */ jsxRuntime.jsx(HeaderActions, { actions: actions2 });
|
2642
|
+
} else {
|
2643
|
+
return null;
|
2644
|
+
}
|
2645
|
+
}
|
2583
2646
|
}
|
2584
2647
|
),
|
2585
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
2648
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2649
|
+
strapiAdmin.DescriptionComponentRenderer,
|
2650
|
+
{
|
2651
|
+
props: {
|
2652
|
+
activeTab: status,
|
2653
|
+
model,
|
2654
|
+
documentId: id,
|
2655
|
+
document: isCloning ? void 0 : document,
|
2656
|
+
meta: isCloning ? void 0 : meta,
|
2657
|
+
collectionType
|
2658
|
+
},
|
2659
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
2660
|
+
children: (actions2) => {
|
2661
|
+
const headerActions = actions2.filter((action) => {
|
2662
|
+
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
2663
|
+
return positions.includes("header");
|
2664
|
+
});
|
2665
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
2666
|
+
DocumentActionsMenu,
|
2667
|
+
{
|
2668
|
+
actions: headerActions,
|
2669
|
+
label: formatMessage({
|
2670
|
+
id: "content-manager.containers.edit.header.more-actions",
|
2671
|
+
defaultMessage: "More actions"
|
2672
|
+
}),
|
2673
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Information, { activeTab: status })
|
2674
|
+
}
|
2675
|
+
);
|
2676
|
+
}
|
2677
|
+
}
|
2678
|
+
)
|
2586
2679
|
] });
|
2587
2680
|
};
|
2588
|
-
const
|
2589
|
-
|
2590
|
-
|
2681
|
+
const Information = ({ activeTab }) => {
|
2682
|
+
const { formatMessage } = reactIntl.useIntl();
|
2683
|
+
const { document, meta } = useDoc();
|
2684
|
+
if (!document || !document.id) {
|
2685
|
+
return null;
|
2686
|
+
}
|
2687
|
+
const createAndUpdateDocument = activeTab === "draft" ? document : meta?.availableStatus.find((status) => status.publishedAt === null);
|
2688
|
+
const publishDocument = activeTab === "published" ? document : meta?.availableStatus.find((status) => status.publishedAt !== null);
|
2689
|
+
const creator = createAndUpdateDocument?.[CREATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[CREATED_BY_ATTRIBUTE_NAME]) : null;
|
2690
|
+
const updator = createAndUpdateDocument?.[UPDATED_BY_ATTRIBUTE_NAME] ? getDisplayName(createAndUpdateDocument[UPDATED_BY_ATTRIBUTE_NAME]) : null;
|
2691
|
+
const information = [
|
2591
2692
|
{
|
2592
|
-
|
2593
|
-
|
2594
|
-
|
2595
|
-
|
2596
|
-
borderColor: "neutral150",
|
2597
|
-
hasRadius: true,
|
2598
|
-
paddingBottom: 4,
|
2599
|
-
paddingLeft: 4,
|
2600
|
-
paddingRight: 4,
|
2601
|
-
paddingTop: 4,
|
2602
|
-
shadow: "tableShadow",
|
2603
|
-
gap: 3,
|
2604
|
-
direction: "column",
|
2605
|
-
justifyContent: "stretch",
|
2606
|
-
alignItems: "flex-start",
|
2607
|
-
children: [
|
2608
|
-
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
2609
|
-
children
|
2610
|
-
]
|
2611
|
-
}
|
2612
|
-
);
|
2613
|
-
});
|
2614
|
-
const HOOKS = {
|
2615
|
-
/**
|
2616
|
-
* Hook that allows to mutate the displayed headers of the list view table
|
2617
|
-
* @constant
|
2618
|
-
* @type {string}
|
2619
|
-
*/
|
2620
|
-
INJECT_COLUMN_IN_TABLE: "Admin/CM/pages/ListView/inject-column-in-table",
|
2621
|
-
/**
|
2622
|
-
* Hook that allows to mutate the CM's collection types links pre-set filters
|
2623
|
-
* @constant
|
2624
|
-
* @type {string}
|
2625
|
-
*/
|
2626
|
-
MUTATE_COLLECTION_TYPES_LINKS: "Admin/CM/pages/App/mutate-collection-types-links",
|
2627
|
-
/**
|
2628
|
-
* Hook that allows to mutate the CM's edit view layout
|
2629
|
-
* @constant
|
2630
|
-
* @type {string}
|
2631
|
-
*/
|
2632
|
-
MUTATE_EDIT_VIEW_LAYOUT: "Admin/CM/pages/EditView/mutate-edit-view-layout",
|
2633
|
-
/**
|
2634
|
-
* Hook that allows to mutate the CM's single types links pre-set filters
|
2635
|
-
* @constant
|
2636
|
-
* @type {string}
|
2637
|
-
*/
|
2638
|
-
MUTATE_SINGLE_TYPES_LINKS: "Admin/CM/pages/App/mutate-single-types-links"
|
2639
|
-
};
|
2640
|
-
const contentTypesApi = contentManagerApi.injectEndpoints({
|
2641
|
-
endpoints: (builder) => ({
|
2642
|
-
getContentTypeConfiguration: builder.query({
|
2643
|
-
query: (uid) => ({
|
2644
|
-
url: `/content-manager/content-types/${uid}/configuration`,
|
2645
|
-
method: "GET"
|
2693
|
+
isDisplayed: !!publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME],
|
2694
|
+
label: formatMessage({
|
2695
|
+
id: "content-manager.containers.edit.information.last-published.label",
|
2696
|
+
defaultMessage: "Published"
|
2646
2697
|
}),
|
2647
|
-
|
2648
|
-
|
2649
|
-
|
2650
|
-
|
2651
|
-
|
2652
|
-
|
2653
|
-
|
2654
|
-
|
2655
|
-
|
2656
|
-
|
2657
|
-
|
2658
|
-
|
2659
|
-
|
2660
|
-
|
2661
|
-
|
2662
|
-
|
2698
|
+
value: formatMessage(
|
2699
|
+
{
|
2700
|
+
id: "content-manager.containers.edit.information.last-published.value",
|
2701
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2702
|
+
},
|
2703
|
+
{
|
2704
|
+
time: /* @__PURE__ */ jsxRuntime.jsx(RelativeTime, { timestamp: new Date(publishDocument?.[PUBLISHED_AT_ATTRIBUTE_NAME]) }),
|
2705
|
+
isAnonymous: !publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME],
|
2706
|
+
author: publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME] ? getDisplayName(publishDocument?.[PUBLISHED_BY_ATTRIBUTE_NAME]) : null
|
2707
|
+
}
|
2708
|
+
)
|
2709
|
+
},
|
2710
|
+
{
|
2711
|
+
isDisplayed: !!createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME],
|
2712
|
+
label: formatMessage({
|
2713
|
+
id: "content-manager.containers.edit.information.last-draft.label",
|
2714
|
+
defaultMessage: "Updated"
|
2715
|
+
}),
|
2716
|
+
value: formatMessage(
|
2717
|
+
{
|
2718
|
+
id: "content-manager.containers.edit.information.last-draft.value",
|
2719
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2720
|
+
},
|
2721
|
+
{
|
2722
|
+
time: /* @__PURE__ */ jsxRuntime.jsx(
|
2723
|
+
RelativeTime,
|
2724
|
+
{
|
2725
|
+
timestamp: new Date(createAndUpdateDocument?.[UPDATED_AT_ATTRIBUTE_NAME])
|
2726
|
+
}
|
2727
|
+
),
|
2728
|
+
isAnonymous: !updator,
|
2729
|
+
author: updator
|
2730
|
+
}
|
2731
|
+
)
|
2732
|
+
},
|
2733
|
+
{
|
2734
|
+
isDisplayed: !!createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME],
|
2735
|
+
label: formatMessage({
|
2736
|
+
id: "content-manager.containers.edit.information.document.label",
|
2737
|
+
defaultMessage: "Created"
|
2663
2738
|
}),
|
2664
|
-
|
2665
|
-
|
2666
|
-
|
2667
|
-
|
2668
|
-
|
2669
|
-
{
|
2670
|
-
|
2671
|
-
|
2672
|
-
|
2673
|
-
|
2674
|
-
|
2675
|
-
|
2676
|
-
|
2677
|
-
|
2678
|
-
}
|
2679
|
-
|
2680
|
-
|
2681
|
-
|
2682
|
-
|
2683
|
-
|
2684
|
-
|
2685
|
-
|
2686
|
-
|
2687
|
-
|
2688
|
-
|
2689
|
-
|
2690
|
-
|
2691
|
-
|
2692
|
-
|
2739
|
+
value: formatMessage(
|
2740
|
+
{
|
2741
|
+
id: "content-manager.containers.edit.information.document.value",
|
2742
|
+
defaultMessage: `{time}{isAnonymous, select, true {} other { by {author}}}`
|
2743
|
+
},
|
2744
|
+
{
|
2745
|
+
time: /* @__PURE__ */ jsxRuntime.jsx(
|
2746
|
+
RelativeTime,
|
2747
|
+
{
|
2748
|
+
timestamp: new Date(createAndUpdateDocument?.[CREATED_AT_ATTRIBUTE_NAME])
|
2749
|
+
}
|
2750
|
+
),
|
2751
|
+
isAnonymous: !creator,
|
2752
|
+
author: creator
|
2753
|
+
}
|
2754
|
+
)
|
2755
|
+
}
|
2756
|
+
].filter((info) => info.isDisplayed);
|
2757
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
2758
|
+
designSystem.Flex,
|
2759
|
+
{
|
2760
|
+
borderWidth: "1px 0 0 0",
|
2761
|
+
borderStyle: "solid",
|
2762
|
+
borderColor: "neutral150",
|
2763
|
+
direction: "column",
|
2764
|
+
marginTop: 2,
|
2765
|
+
tag: "dl",
|
2766
|
+
padding: 5,
|
2767
|
+
gap: 3,
|
2768
|
+
alignItems: "flex-start",
|
2769
|
+
marginLeft: "-0.4rem",
|
2770
|
+
marginRight: "-0.4rem",
|
2771
|
+
width: "calc(100% + 8px)",
|
2772
|
+
children: information.map((info) => /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { gap: 1, direction: "column", alignItems: "flex-start", children: [
|
2773
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dt", variant: "pi", fontWeight: "bold", children: info.label }),
|
2774
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "dd", variant: "pi", textColor: "neutral600", children: info.value })
|
2775
|
+
] }, info.label))
|
2776
|
+
}
|
2693
2777
|
);
|
2694
|
-
return {
|
2695
|
-
name: mainFieldName,
|
2696
|
-
type: mainFieldType ?? "string"
|
2697
|
-
};
|
2698
|
-
};
|
2699
|
-
const DEFAULT_SETTINGS = {
|
2700
|
-
bulkable: false,
|
2701
|
-
filterable: false,
|
2702
|
-
searchable: false,
|
2703
|
-
pagination: false,
|
2704
|
-
defaultSortBy: "",
|
2705
|
-
defaultSortOrder: "asc",
|
2706
|
-
mainField: "id",
|
2707
|
-
pageSize: 10
|
2708
2778
|
};
|
2709
|
-
const
|
2710
|
-
const
|
2711
|
-
const
|
2712
|
-
|
2713
|
-
|
2714
|
-
|
2715
|
-
|
2716
|
-
|
2717
|
-
|
2718
|
-
|
2719
|
-
error,
|
2720
|
-
isFetching: isFetchingConfigs
|
2721
|
-
} = useGetContentTypeConfigurationQuery(model);
|
2722
|
-
const isLoading = isLoadingSchemas || isFetchingConfigs || isLoadingConfigs;
|
2723
|
-
React__namespace.useEffect(() => {
|
2724
|
-
if (error) {
|
2725
|
-
toggleNotification({
|
2726
|
-
type: "danger",
|
2727
|
-
message: formatAPIError(error)
|
2728
|
-
});
|
2779
|
+
const HeaderActions = ({ actions: actions2 }) => {
|
2780
|
+
const [dialogId, setDialogId] = React__namespace.useState(null);
|
2781
|
+
const handleClick = (action) => async (e) => {
|
2782
|
+
if (!("options" in action)) {
|
2783
|
+
const { onClick = () => false, dialog, id } = action;
|
2784
|
+
const muteDialog = await onClick(e);
|
2785
|
+
if (dialog && !muteDialog) {
|
2786
|
+
e.preventDefault();
|
2787
|
+
setDialogId(id);
|
2788
|
+
}
|
2729
2789
|
}
|
2730
|
-
}, [error, formatAPIError, toggleNotification]);
|
2731
|
-
const editLayout = React__namespace.useMemo(
|
2732
|
-
() => data && !isLoading ? formatEditLayout(data, { schemas, schema, components }) : {
|
2733
|
-
layout: [],
|
2734
|
-
components: {},
|
2735
|
-
metadatas: {},
|
2736
|
-
options: {},
|
2737
|
-
settings: DEFAULT_SETTINGS
|
2738
|
-
},
|
2739
|
-
[data, isLoading, schemas, schema, components]
|
2740
|
-
);
|
2741
|
-
const listLayout = React__namespace.useMemo(() => {
|
2742
|
-
return data && !isLoading ? formatListLayout(data, { schemas, schema, components }) : {
|
2743
|
-
layout: [],
|
2744
|
-
metadatas: {},
|
2745
|
-
options: {},
|
2746
|
-
settings: DEFAULT_SETTINGS
|
2747
|
-
};
|
2748
|
-
}, [data, isLoading, schemas, schema, components]);
|
2749
|
-
const { layout: edit } = React__namespace.useMemo(
|
2750
|
-
() => runHookWaterfall(HOOKS.MUTATE_EDIT_VIEW_LAYOUT, {
|
2751
|
-
layout: editLayout,
|
2752
|
-
query
|
2753
|
-
}),
|
2754
|
-
[editLayout, query, runHookWaterfall]
|
2755
|
-
);
|
2756
|
-
return {
|
2757
|
-
error,
|
2758
|
-
isLoading,
|
2759
|
-
edit,
|
2760
|
-
list: listLayout
|
2761
2790
|
};
|
2762
|
-
|
2763
|
-
|
2764
|
-
|
2765
|
-
return
|
2766
|
-
|
2767
|
-
|
2768
|
-
|
2769
|
-
|
2770
|
-
|
2771
|
-
|
2772
|
-
|
2773
|
-
|
2774
|
-
|
2775
|
-
|
2776
|
-
|
2777
|
-
|
2778
|
-
schemas
|
2779
|
-
).reduce((panels, row) => {
|
2780
|
-
if (row.some((field) => field.type === "dynamiczone")) {
|
2781
|
-
panels.push([row]);
|
2782
|
-
currentPanelIndex += 2;
|
2791
|
+
const handleClose = () => {
|
2792
|
+
setDialogId(null);
|
2793
|
+
};
|
2794
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { gap: 1, children: actions2.map((action) => {
|
2795
|
+
if (action.options) {
|
2796
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
2797
|
+
designSystem.SingleSelect,
|
2798
|
+
{
|
2799
|
+
size: "S",
|
2800
|
+
onChange: action.onSelect,
|
2801
|
+
"aria-label": action.label,
|
2802
|
+
...action,
|
2803
|
+
children: action.options.map(({ label, ...option }) => /* @__PURE__ */ jsxRuntime.jsx(designSystem.SingleSelectOption, { ...option, children: label }, option.value))
|
2804
|
+
},
|
2805
|
+
action.id
|
2806
|
+
);
|
2783
2807
|
} else {
|
2784
|
-
if (
|
2785
|
-
|
2808
|
+
if (action.type === "icon") {
|
2809
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(React__namespace.Fragment, { children: [
|
2810
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
2811
|
+
designSystem.IconButton,
|
2812
|
+
{
|
2813
|
+
disabled: action.disabled,
|
2814
|
+
label: action.label,
|
2815
|
+
size: "S",
|
2816
|
+
onClick: handleClick(action),
|
2817
|
+
children: action.icon
|
2818
|
+
}
|
2819
|
+
),
|
2820
|
+
action.dialog ? /* @__PURE__ */ jsxRuntime.jsx(
|
2821
|
+
HeaderActionDialog,
|
2822
|
+
{
|
2823
|
+
...action.dialog,
|
2824
|
+
isOpen: dialogId === action.id,
|
2825
|
+
onClose: handleClose
|
2826
|
+
}
|
2827
|
+
) : null
|
2828
|
+
] }, action.id);
|
2786
2829
|
}
|
2787
|
-
panels[currentPanelIndex].push(row);
|
2788
2830
|
}
|
2789
|
-
|
2790
|
-
|
2791
|
-
|
2792
|
-
|
2793
|
-
|
2794
|
-
|
2795
|
-
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
2800
|
-
|
2801
|
-
|
2802
|
-
|
2803
|
-
|
2804
|
-
|
2805
|
-
|
2806
|
-
}
|
2807
|
-
|
2808
|
-
|
2809
|
-
|
2810
|
-
|
2811
|
-
|
2812
|
-
|
2813
|
-
|
2814
|
-
|
2831
|
+
}) });
|
2832
|
+
};
|
2833
|
+
const HeaderActionDialog = ({
|
2834
|
+
onClose,
|
2835
|
+
onCancel,
|
2836
|
+
title,
|
2837
|
+
content: Content,
|
2838
|
+
isOpen
|
2839
|
+
}) => {
|
2840
|
+
const handleClose = async () => {
|
2841
|
+
if (onCancel) {
|
2842
|
+
await onCancel();
|
2843
|
+
}
|
2844
|
+
onClose();
|
2845
|
+
};
|
2846
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Root, { open: isOpen, onOpenChange: handleClose, children: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Dialog.Content, { children: [
|
2847
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Dialog.Header, { children: title }),
|
2848
|
+
typeof Content === "function" ? /* @__PURE__ */ jsxRuntime.jsx(Content, { onClose: handleClose }) : Content
|
2849
|
+
] }) });
|
2850
|
+
};
|
2851
|
+
const ConfigureTheViewAction = ({ collectionType, model }) => {
|
2852
|
+
const navigate = reactRouterDom.useNavigate();
|
2853
|
+
const { formatMessage } = reactIntl.useIntl();
|
2854
|
+
return {
|
2855
|
+
label: formatMessage({
|
2856
|
+
id: "app.links.configure-view",
|
2857
|
+
defaultMessage: "Configure the view"
|
2858
|
+
}),
|
2859
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.ListPlus, {}),
|
2860
|
+
onClick: () => {
|
2861
|
+
navigate(`../${collectionType}/${model}/configurations/edit`);
|
2815
2862
|
},
|
2816
|
-
|
2817
|
-
|
2863
|
+
position: "header"
|
2864
|
+
};
|
2865
|
+
};
|
2866
|
+
ConfigureTheViewAction.type = "configure-the-view";
|
2867
|
+
const EditTheModelAction = ({ model }) => {
|
2868
|
+
const navigate = reactRouterDom.useNavigate();
|
2869
|
+
const { formatMessage } = reactIntl.useIntl();
|
2818
2870
|
return {
|
2819
|
-
|
2820
|
-
|
2821
|
-
|
2822
|
-
|
2823
|
-
|
2824
|
-
|
2871
|
+
label: formatMessage({
|
2872
|
+
id: "content-manager.link-to-ctb",
|
2873
|
+
defaultMessage: "Edit the model"
|
2874
|
+
}),
|
2875
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, {}),
|
2876
|
+
onClick: () => {
|
2877
|
+
navigate(`/plugins/content-type-builder/content-types/${model}`);
|
2825
2878
|
},
|
2826
|
-
|
2827
|
-
...schema?.options,
|
2828
|
-
...schema?.pluginOptions,
|
2829
|
-
...data.contentType.options
|
2830
|
-
}
|
2879
|
+
position: "header"
|
2831
2880
|
};
|
2832
2881
|
};
|
2833
|
-
|
2834
|
-
|
2835
|
-
|
2836
|
-
|
2837
|
-
|
2838
|
-
|
2882
|
+
EditTheModelAction.type = "edit-the-model";
|
2883
|
+
const DeleteAction$1 = ({ documentId, model, collectionType, document }) => {
|
2884
|
+
const navigate = reactRouterDom.useNavigate();
|
2885
|
+
const { formatMessage } = reactIntl.useIntl();
|
2886
|
+
const listViewPathMatch = reactRouterDom.useMatch(LIST_PATH);
|
2887
|
+
const canDelete = useDocumentRBAC("DeleteAction", (state) => state.canDelete);
|
2888
|
+
const { delete: deleteAction } = useDocumentActions();
|
2889
|
+
const { toggleNotification } = strapiAdmin.useNotification();
|
2890
|
+
const setSubmitting = strapiAdmin.useForm("DeleteAction", (state) => state.setSubmitting);
|
2891
|
+
const isLocalized = document?.locale != null;
|
2892
|
+
return {
|
2893
|
+
disabled: !canDelete || !document,
|
2894
|
+
label: formatMessage(
|
2895
|
+
{
|
2896
|
+
id: "content-manager.actions.delete.label",
|
2897
|
+
defaultMessage: "Delete entry{isLocalized, select, true { (all locales)} other {}}"
|
2898
|
+
},
|
2899
|
+
{ isLocalized }
|
2900
|
+
),
|
2901
|
+
icon: /* @__PURE__ */ jsxRuntime.jsx(Icons.Trash, {}),
|
2902
|
+
dialog: {
|
2903
|
+
type: "dialog",
|
2904
|
+
title: formatMessage({
|
2905
|
+
id: "app.components.ConfirmDialog.title",
|
2906
|
+
defaultMessage: "Confirmation"
|
2907
|
+
}),
|
2908
|
+
content: /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, children: [
|
2909
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icons.WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
2910
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
|
2911
|
+
id: "content-manager.actions.delete.dialog.body",
|
2912
|
+
defaultMessage: "Are you sure?"
|
2913
|
+
}) })
|
2914
|
+
] }),
|
2915
|
+
onConfirm: async () => {
|
2916
|
+
if (!listViewPathMatch) {
|
2917
|
+
setSubmitting(true);
|
2918
|
+
}
|
2919
|
+
try {
|
2920
|
+
if (!documentId && collectionType !== SINGLE_TYPES) {
|
2921
|
+
console.error(
|
2922
|
+
"You're trying to delete a document without an id, this is likely a bug with Strapi. Please open an issue."
|
2923
|
+
);
|
2924
|
+
toggleNotification({
|
2925
|
+
message: formatMessage({
|
2926
|
+
id: "content-manager.actions.delete.error",
|
2927
|
+
defaultMessage: "An error occurred while trying to delete the document."
|
2928
|
+
}),
|
2929
|
+
type: "danger"
|
2930
|
+
});
|
2931
|
+
return;
|
2932
|
+
}
|
2933
|
+
const res = await deleteAction({
|
2934
|
+
documentId,
|
2935
|
+
model,
|
2936
|
+
collectionType,
|
2937
|
+
params: {
|
2938
|
+
locale: "*"
|
2939
|
+
}
|
2940
|
+
});
|
2941
|
+
if (!("error" in res)) {
|
2942
|
+
navigate({ pathname: `../${collectionType}/${model}` }, { replace: true });
|
2943
|
+
}
|
2944
|
+
} finally {
|
2945
|
+
if (!listViewPathMatch) {
|
2946
|
+
setSubmitting(false);
|
2947
|
+
}
|
2948
|
+
}
|
2839
2949
|
}
|
2840
|
-
const { edit: metadata } = metadatas[field.name];
|
2841
|
-
const settings = attribute.type === "component" && components ? components.configurations[attribute.component].settings : {};
|
2842
|
-
return {
|
2843
|
-
attribute,
|
2844
|
-
disabled: !metadata.editable,
|
2845
|
-
hint: metadata.description,
|
2846
|
-
label: metadata.label ?? "",
|
2847
|
-
name: field.name,
|
2848
|
-
// @ts-expect-error – mainField does exist on the metadata for a relation.
|
2849
|
-
mainField: getMainField(attribute, metadata.mainField || settings.mainField, {
|
2850
|
-
schemas,
|
2851
|
-
components: components?.schemas ?? {}
|
2852
|
-
}),
|
2853
|
-
placeholder: metadata.placeholder ?? "",
|
2854
|
-
required: attribute.required ?? false,
|
2855
|
-
size: field.size,
|
2856
|
-
unique: "unique" in attribute ? attribute.unique : false,
|
2857
|
-
visible: metadata.visible ?? true,
|
2858
|
-
type: attribute.type
|
2859
|
-
};
|
2860
|
-
}).filter((field) => field !== null)
|
2861
|
-
);
|
2862
|
-
};
|
2863
|
-
const formatListLayout = (data, {
|
2864
|
-
schemas,
|
2865
|
-
schema,
|
2866
|
-
components
|
2867
|
-
}) => {
|
2868
|
-
const listMetadatas = Object.entries(data.contentType.metadatas).reduce(
|
2869
|
-
(acc, [attribute, metadata]) => {
|
2870
|
-
return {
|
2871
|
-
...acc,
|
2872
|
-
[attribute]: metadata.list
|
2873
|
-
};
|
2874
2950
|
},
|
2875
|
-
|
2876
|
-
|
2877
|
-
|
2878
|
-
|
2879
|
-
|
2880
|
-
|
2881
|
-
|
2882
|
-
|
2883
|
-
|
2884
|
-
|
2885
|
-
|
2886
|
-
|
2887
|
-
|
2888
|
-
|
2889
|
-
|
2890
|
-
|
2891
|
-
|
2951
|
+
variant: "danger",
|
2952
|
+
position: ["header", "table-row"]
|
2953
|
+
};
|
2954
|
+
};
|
2955
|
+
DeleteAction$1.type = "delete";
|
2956
|
+
const DEFAULT_HEADER_ACTIONS = [EditTheModelAction, ConfigureTheViewAction, DeleteAction$1];
|
2957
|
+
const Panels = () => {
|
2958
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2959
|
+
const [
|
2960
|
+
{
|
2961
|
+
query: { status }
|
2962
|
+
}
|
2963
|
+
] = strapiAdmin.useQueryParams({
|
2964
|
+
status: "draft"
|
2965
|
+
});
|
2966
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
2967
|
+
const plugins = strapiAdmin.useStrapiApp("Panels", (state) => state.plugins);
|
2968
|
+
const props = {
|
2969
|
+
activeTab: status,
|
2970
|
+
model,
|
2971
|
+
documentId: id,
|
2972
|
+
document: isCloning ? void 0 : document,
|
2973
|
+
meta: isCloning ? void 0 : meta,
|
2974
|
+
collectionType
|
2975
|
+
};
|
2976
|
+
return /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { direction: "column", alignItems: "stretch", gap: 2, children: /* @__PURE__ */ jsxRuntime.jsx(
|
2977
|
+
strapiAdmin.DescriptionComponentRenderer,
|
2978
|
+
{
|
2979
|
+
props,
|
2980
|
+
descriptions: plugins["content-manager"].apis.getEditViewSidePanels(),
|
2981
|
+
children: (panels) => panels.map(({ content, id: id2, ...description }) => /* @__PURE__ */ jsxRuntime.jsx(Panel, { ...description, children: content }, id2))
|
2892
2982
|
}
|
2983
|
+
) });
|
2984
|
+
};
|
2985
|
+
const ActionsPanel = () => {
|
2986
|
+
const { formatMessage } = reactIntl.useIntl();
|
2987
|
+
return {
|
2988
|
+
title: formatMessage({
|
2989
|
+
id: "content-manager.containers.edit.panels.default.title",
|
2990
|
+
defaultMessage: "Entry"
|
2991
|
+
}),
|
2992
|
+
content: /* @__PURE__ */ jsxRuntime.jsx(ActionsPanelContent, {})
|
2893
2993
|
};
|
2894
2994
|
};
|
2895
|
-
|
2896
|
-
|
2897
|
-
|
2898
|
-
|
2899
|
-
|
2995
|
+
ActionsPanel.type = "actions";
|
2996
|
+
const ActionsPanelContent = () => {
|
2997
|
+
const isCloning = reactRouterDom.useMatch(CLONE_PATH) !== null;
|
2998
|
+
const [
|
2999
|
+
{
|
3000
|
+
query: { status = "draft" }
|
2900
3001
|
}
|
2901
|
-
|
2902
|
-
|
2903
|
-
|
2904
|
-
|
2905
|
-
|
2906
|
-
|
2907
|
-
|
2908
|
-
|
2909
|
-
|
2910
|
-
|
2911
|
-
|
2912
|
-
|
2913
|
-
|
2914
|
-
|
3002
|
+
] = strapiAdmin.useQueryParams();
|
3003
|
+
const { model, id, document, meta, collectionType } = useDoc();
|
3004
|
+
const plugins = strapiAdmin.useStrapiApp("ActionsPanel", (state) => state.plugins);
|
3005
|
+
const props = {
|
3006
|
+
activeTab: status,
|
3007
|
+
model,
|
3008
|
+
documentId: id,
|
3009
|
+
document: isCloning ? void 0 : document,
|
3010
|
+
meta: isCloning ? void 0 : meta,
|
3011
|
+
collectionType
|
3012
|
+
};
|
3013
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Flex, { direction: "column", gap: 2, width: "100%", children: [
|
3014
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
3015
|
+
strapiAdmin.DescriptionComponentRenderer,
|
3016
|
+
{
|
3017
|
+
props,
|
3018
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3019
|
+
children: (actions2) => /* @__PURE__ */ jsxRuntime.jsx(DocumentActions, { actions: actions2 })
|
3020
|
+
}
|
3021
|
+
),
|
3022
|
+
/* @__PURE__ */ jsxRuntime.jsx(InjectionZone, { area: "editView.right-links", slug: model })
|
3023
|
+
] });
|
2915
3024
|
};
|
3025
|
+
const Panel = React__namespace.forwardRef(({ children, title }, ref) => {
|
3026
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
3027
|
+
designSystem.Flex,
|
3028
|
+
{
|
3029
|
+
ref,
|
3030
|
+
tag: "aside",
|
3031
|
+
"aria-labelledby": "additional-information",
|
3032
|
+
background: "neutral0",
|
3033
|
+
borderColor: "neutral150",
|
3034
|
+
hasRadius: true,
|
3035
|
+
paddingBottom: 4,
|
3036
|
+
paddingLeft: 4,
|
3037
|
+
paddingRight: 4,
|
3038
|
+
paddingTop: 4,
|
3039
|
+
shadow: "tableShadow",
|
3040
|
+
gap: 3,
|
3041
|
+
direction: "column",
|
3042
|
+
justifyContent: "stretch",
|
3043
|
+
alignItems: "flex-start",
|
3044
|
+
children: [
|
3045
|
+
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Typography, { tag: "h2", variant: "sigma", textTransform: "uppercase", children: title }),
|
3046
|
+
children
|
3047
|
+
]
|
3048
|
+
}
|
3049
|
+
);
|
3050
|
+
});
|
2916
3051
|
const ConfirmBulkActionDialog = ({
|
2917
3052
|
onToggleDialog,
|
2918
3053
|
isOpen = false,
|
@@ -2951,6 +3086,7 @@ const ConfirmDialogPublishAll = ({
|
|
2951
3086
|
const { _unstableFormatAPIError: formatAPIError } = strapiAdmin.useAPIErrorHandler(getTranslation);
|
2952
3087
|
const { model, schema } = useDoc();
|
2953
3088
|
const [{ query }] = strapiAdmin.useQueryParams();
|
3089
|
+
const enableDraftRelationsCount = false;
|
2954
3090
|
const {
|
2955
3091
|
data: countDraftRelations = 0,
|
2956
3092
|
isLoading,
|
@@ -2962,7 +3098,7 @@ const ConfirmDialogPublishAll = ({
|
|
2962
3098
|
locale: query?.plugins?.i18n?.locale
|
2963
3099
|
},
|
2964
3100
|
{
|
2965
|
-
skip:
|
3101
|
+
skip: !enableDraftRelationsCount
|
2966
3102
|
}
|
2967
3103
|
);
|
2968
3104
|
React__namespace.useEffect(() => {
|
@@ -3147,7 +3283,7 @@ const SelectedEntriesTableContent = ({
|
|
3147
3283
|
status: row.status
|
3148
3284
|
}
|
3149
3285
|
) }),
|
3150
|
-
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3286
|
+
/* @__PURE__ */ jsxRuntime.jsx(strapiAdmin.Table.Cell, { children: /* @__PURE__ */ jsxRuntime.jsx(designSystem.Flex, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
3151
3287
|
designSystem.IconButton,
|
3152
3288
|
{
|
3153
3289
|
tag: reactRouterDom.Link,
|
@@ -3170,9 +3306,10 @@ const SelectedEntriesTableContent = ({
|
|
3170
3306
|
),
|
3171
3307
|
target: "_blank",
|
3172
3308
|
marginLeft: "auto",
|
3173
|
-
|
3309
|
+
variant: "ghost",
|
3310
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(Icons.Pencil, { width: "1.6rem", height: "1.6rem" })
|
3174
3311
|
}
|
3175
|
-
) })
|
3312
|
+
) }) })
|
3176
3313
|
] }, row.id)) })
|
3177
3314
|
] });
|
3178
3315
|
};
|
@@ -3209,7 +3346,13 @@ const SelectedEntriesModalContent = ({
|
|
3209
3346
|
);
|
3210
3347
|
const { rows, validationErrors } = React__namespace.useMemo(() => {
|
3211
3348
|
if (data.length > 0 && schema) {
|
3212
|
-
const validate = createYupSchema(
|
3349
|
+
const validate = createYupSchema(
|
3350
|
+
schema.attributes,
|
3351
|
+
components,
|
3352
|
+
// Since this is the "Publish" action, the validation
|
3353
|
+
// schema must enforce the rules for published entities
|
3354
|
+
{ status: "published" }
|
3355
|
+
);
|
3213
3356
|
const validationErrors2 = {};
|
3214
3357
|
const rows2 = data.map((entry) => {
|
3215
3358
|
try {
|
@@ -3559,7 +3702,7 @@ const TableActions = ({ document }) => {
|
|
3559
3702
|
strapiAdmin.DescriptionComponentRenderer,
|
3560
3703
|
{
|
3561
3704
|
props,
|
3562
|
-
descriptions: plugins["content-manager"].apis.getDocumentActions(),
|
3705
|
+
descriptions: plugins["content-manager"].apis.getDocumentActions().filter((action) => action.name !== "PublishAction"),
|
3563
3706
|
children: (actions2) => {
|
3564
3707
|
const tableRowActions = actions2.filter((action) => {
|
3565
3708
|
const positions = Array.isArray(action.position) ? action.position : [action.position];
|
@@ -3670,7 +3813,7 @@ const CloneAction = ({ model, documentId }) => {
|
|
3670
3813
|
}),
|
3671
3814
|
content: /* @__PURE__ */ jsxRuntime.jsx(AutoCloneFailureModalBody, { prohibitedFields }),
|
3672
3815
|
footer: ({ onClose }) => {
|
3673
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.
|
3816
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(designSystem.Modal.Footer, { children: [
|
3674
3817
|
/* @__PURE__ */ jsxRuntime.jsx(designSystem.Button, { onClick: onClose, variant: "tertiary", children: formatMessage({
|
3675
3818
|
id: "cancel",
|
3676
3819
|
defaultMessage: "Cancel"
|
@@ -3901,7 +4044,7 @@ const index = {
|
|
3901
4044
|
app.router.addRoute({
|
3902
4045
|
path: "content-manager/*",
|
3903
4046
|
lazy: async () => {
|
3904
|
-
const { Layout } = await Promise.resolve().then(() => require("./layout-
|
4047
|
+
const { Layout } = await Promise.resolve().then(() => require("./layout-B4aCAdTt.js"));
|
3905
4048
|
return {
|
3906
4049
|
Component: Layout
|
3907
4050
|
};
|
@@ -3918,7 +4061,7 @@ const index = {
|
|
3918
4061
|
async registerTrads({ locales }) {
|
3919
4062
|
const importedTrads = await Promise.all(
|
3920
4063
|
locales.map((locale) => {
|
3921
|
-
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-
|
4064
|
+
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 }) => {
|
3922
4065
|
return {
|
3923
4066
|
data: prefixPluginTranslations(data, PLUGIN_ID),
|
3924
4067
|
locale
|
@@ -3936,6 +4079,7 @@ const index = {
|
|
3936
4079
|
};
|
3937
4080
|
exports.ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD = ATTRIBUTE_TYPES_THAT_CANNOT_BE_MAIN_FIELD;
|
3938
4081
|
exports.BulkActionsRenderer = BulkActionsRenderer;
|
4082
|
+
exports.CLONE_PATH = CLONE_PATH;
|
3939
4083
|
exports.COLLECTION_TYPES = COLLECTION_TYPES;
|
3940
4084
|
exports.CREATOR_FIELDS = CREATOR_FIELDS;
|
3941
4085
|
exports.DEFAULT_SETTINGS = DEFAULT_SETTINGS;
|
@@ -3963,6 +4107,7 @@ exports.getMainField = getMainField;
|
|
3963
4107
|
exports.getTranslation = getTranslation;
|
3964
4108
|
exports.index = index;
|
3965
4109
|
exports.setInitialData = setInitialData;
|
4110
|
+
exports.useContentManagerContext = useContentManagerContext;
|
3966
4111
|
exports.useContentTypeSchema = useContentTypeSchema;
|
3967
4112
|
exports.useDoc = useDoc;
|
3968
4113
|
exports.useDocLayout = useDocLayout;
|
@@ -3975,4 +4120,4 @@ exports.useGetAllDocumentsQuery = useGetAllDocumentsQuery;
|
|
3975
4120
|
exports.useGetContentTypeConfigurationQuery = useGetContentTypeConfigurationQuery;
|
3976
4121
|
exports.useGetInitialDataQuery = useGetInitialDataQuery;
|
3977
4122
|
exports.useUpdateContentTypeConfigurationMutation = useUpdateContentTypeConfigurationMutation;
|
3978
|
-
//# sourceMappingURL=index-
|
4123
|
+
//# sourceMappingURL=index-BsMu2oVP.js.map
|