@strapi/i18n 0.0.0-experimental.da85533897155e719d784f0271223c866d2f69ab → 0.0.0-experimental.dad3c50630ca4fd9eccdcbe549ee632fc572e23d
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/{SettingsPage-DW0GwDcD.mjs → SettingsPage-B6QDUmu9.mjs} +4 -4
- package/dist/_chunks/SettingsPage-B6QDUmu9.mjs.map +1 -0
- package/dist/_chunks/{SettingsPage-a96ZyFLy.js → SettingsPage-BsHtr3lV.js} +5 -6
- package/dist/_chunks/SettingsPage-BsHtr3lV.js.map +1 -0
- package/dist/_chunks/{en-BsOU9o5z.js → en-BKBz3tro.js} +10 -3
- package/dist/_chunks/en-BKBz3tro.js.map +1 -0
- package/dist/_chunks/{en-CM6Pjfyv.mjs → en-DlXfy6Gy.mjs} +10 -3
- package/dist/_chunks/en-DlXfy6Gy.mjs.map +1 -0
- package/dist/_chunks/{index-sfNkjx75.js → index-3XgwXL6T.js} +414 -134
- package/dist/_chunks/index-3XgwXL6T.js.map +1 -0
- package/dist/_chunks/{index-4KJn181Q.mjs → index-iEQ79W05.mjs} +416 -135
- package/dist/_chunks/index-iEQ79W05.mjs.map +1 -0
- package/dist/admin/index.js +1 -1
- package/dist/admin/index.mjs +1 -1
- package/dist/admin/src/components/BulkLocaleActionModal.d.ts +2 -1
- package/dist/admin/src/components/CMHeaderActions.d.ts +29 -3
- package/dist/admin/src/components/CreateLocale.d.ts +6 -6
- package/dist/admin/src/components/LocaleListCell.d.ts +4 -4
- package/dist/admin/src/utils/clean.d.ts +4 -0
- package/dist/server/index.js +398 -487
- package/dist/server/index.js.map +1 -1
- package/dist/server/index.mjs +399 -487
- package/dist/server/index.mjs.map +1 -1
- package/dist/server/src/bootstrap.d.ts +1 -4
- package/dist/server/src/bootstrap.d.ts.map +1 -1
- package/dist/server/src/index.d.ts +7 -11
- package/dist/server/src/index.d.ts.map +1 -1
- package/dist/server/src/register.d.ts.map +1 -1
- package/dist/server/src/services/index.d.ts +6 -8
- package/dist/server/src/services/index.d.ts.map +1 -1
- package/dist/server/src/services/sanitize/index.d.ts +11 -0
- package/dist/server/src/services/sanitize/index.d.ts.map +1 -0
- package/dist/server/src/utils/index.d.ts +2 -2
- package/dist/server/src/utils/index.d.ts.map +1 -1
- package/package.json +13 -13
- package/dist/_chunks/SettingsPage-DW0GwDcD.mjs.map +0 -1
- package/dist/_chunks/SettingsPage-a96ZyFLy.js.map +0 -1
- package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
- package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
- package/dist/_chunks/index-4KJn181Q.mjs.map +0 -1
- package/dist/_chunks/index-sfNkjx75.js.map +0 -1
- package/dist/server/src/migrations/content-type/disable/index.d.ts +0 -3
- package/dist/server/src/migrations/content-type/disable/index.d.ts.map +0 -1
- package/dist/server/src/migrations/content-type/enable/index.d.ts +0 -3
- package/dist/server/src/migrations/content-type/enable/index.d.ts.map +0 -1
- package/dist/server/src/services/entity-service-decorator.d.ts +0 -29
- package/dist/server/src/services/entity-service-decorator.d.ts.map +0 -1
- package/strapi-server.js +0 -3
@@ -1,25 +1,32 @@
|
|
1
1
|
import get from "lodash/get";
|
2
2
|
import * as yup from "yup";
|
3
|
-
import { jsxs, jsx } from "react/jsx-runtime";
|
3
|
+
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
4
4
|
import * as React from "react";
|
5
5
|
import { Typography, Dialog, Field, Checkbox, Flex, Button, Modal, Box, Status, IconButton, Tooltip, SingleSelect, SingleSelectOption, VisuallyHidden, useCollator, Popover } from "@strapi/design-system";
|
6
|
-
import { WarningCircle, Pencil, CrossCircle, CheckCircle, ArrowsCounterClockwise, Trash, ListPlus, Earth, EarthStriked, CaretDown } from "@strapi/icons";
|
6
|
+
import { WarningCircle, Pencil, CrossCircle, CheckCircle, ArrowsCounterClockwise, Trash, Plus, Download, ListPlus, Cross, Earth, EarthStriked, CaretDown } from "@strapi/icons";
|
7
7
|
import { useIntl } from "react-intl";
|
8
8
|
import { styled } from "styled-components";
|
9
9
|
import { skipToken } from "@reduxjs/toolkit/query";
|
10
|
-
import { useAuth, adminApi, useTable, Table, useQueryParams, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
|
10
|
+
import { useAuth, adminApi, useTable, Table, useQueryParams, useForm, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
|
11
11
|
import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from "@strapi/content-manager/strapi-admin";
|
12
12
|
import { useParams, Link, useNavigate, matchPath } from "react-router-dom";
|
13
13
|
import * as qs from "qs";
|
14
14
|
import { stringify } from "qs";
|
15
15
|
import omit from "lodash/omit";
|
16
|
-
const __variableDynamicImportRuntimeHelper = (glob, path) => {
|
16
|
+
const __variableDynamicImportRuntimeHelper = (glob, path, segs) => {
|
17
17
|
const v = glob[path];
|
18
18
|
if (v) {
|
19
19
|
return typeof v === "function" ? v() : Promise.resolve(v);
|
20
20
|
}
|
21
21
|
return new Promise((_, reject) => {
|
22
|
-
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
22
|
+
(typeof queueMicrotask === "function" ? queueMicrotask : setTimeout)(
|
23
|
+
reject.bind(
|
24
|
+
null,
|
25
|
+
new Error(
|
26
|
+
"Unknown variable dynamic import: " + path + (path.split("/").length !== segs ? ". Note that variables only represent file names one level deep." : "")
|
27
|
+
)
|
28
|
+
)
|
29
|
+
);
|
23
30
|
});
|
24
31
|
};
|
25
32
|
const pluginId = "i18n";
|
@@ -217,10 +224,94 @@ const relationsApi = i18nApi.injectEndpoints({
|
|
217
224
|
})
|
218
225
|
});
|
219
226
|
const { useGetManyDraftRelationCountQuery } = relationsApi;
|
227
|
+
const cleanData = (data, schema, components) => {
|
228
|
+
const cleanedData = removeFields(data, [
|
229
|
+
"createdAt",
|
230
|
+
"createdBy",
|
231
|
+
"updatedAt",
|
232
|
+
"updatedBy",
|
233
|
+
"id",
|
234
|
+
"documentId",
|
235
|
+
"publishedAt",
|
236
|
+
"strapi_stage",
|
237
|
+
"strapi_assignee",
|
238
|
+
"locale",
|
239
|
+
"status"
|
240
|
+
]);
|
241
|
+
const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(
|
242
|
+
cleanedData,
|
243
|
+
schema,
|
244
|
+
components,
|
245
|
+
["relation", "password"]
|
246
|
+
);
|
247
|
+
return cleanedDataWithoutPasswordAndRelation;
|
248
|
+
};
|
249
|
+
const removeFields = (data, fields) => {
|
250
|
+
return Object.keys(data).reduce((acc, current) => {
|
251
|
+
if (fields.includes(current)) {
|
252
|
+
return acc;
|
253
|
+
}
|
254
|
+
acc[current] = data[current];
|
255
|
+
return acc;
|
256
|
+
}, {});
|
257
|
+
};
|
258
|
+
const recursiveRemoveFieldTypes = (data, schema, components, fields) => {
|
259
|
+
return Object.keys(data).reduce((acc, current) => {
|
260
|
+
const attribute = schema.attributes[current] ?? { type: void 0 };
|
261
|
+
if (fields.includes(attribute.type)) {
|
262
|
+
return acc;
|
263
|
+
}
|
264
|
+
if (attribute.type === "dynamiczone") {
|
265
|
+
acc[current] = data[current].map((componentValue, index2) => {
|
266
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(
|
267
|
+
componentValue,
|
268
|
+
components[componentValue.__component],
|
269
|
+
components,
|
270
|
+
fields
|
271
|
+
);
|
272
|
+
return {
|
273
|
+
...rest,
|
274
|
+
__temp_key__: index2 + 1
|
275
|
+
};
|
276
|
+
});
|
277
|
+
} else if (attribute.type === "component") {
|
278
|
+
const { repeatable, component } = attribute;
|
279
|
+
if (repeatable) {
|
280
|
+
acc[current] = (data[current] ?? []).map((compoData, index2) => {
|
281
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(
|
282
|
+
compoData,
|
283
|
+
components[component],
|
284
|
+
components,
|
285
|
+
fields
|
286
|
+
);
|
287
|
+
return {
|
288
|
+
...rest,
|
289
|
+
__temp_key__: index2 + 1
|
290
|
+
};
|
291
|
+
});
|
292
|
+
} else {
|
293
|
+
const { id: _, ...rest } = recursiveRemoveFieldTypes(
|
294
|
+
data[current] ?? {},
|
295
|
+
components[component],
|
296
|
+
components,
|
297
|
+
fields
|
298
|
+
);
|
299
|
+
acc[current] = rest;
|
300
|
+
}
|
301
|
+
} else {
|
302
|
+
acc[current] = data[current];
|
303
|
+
}
|
304
|
+
return acc;
|
305
|
+
}, {});
|
306
|
+
};
|
220
307
|
const isErrorMessageDescriptor = (object) => {
|
221
308
|
return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
|
222
309
|
};
|
223
|
-
const EntryValidationText = ({
|
310
|
+
const EntryValidationText = ({
|
311
|
+
status = "draft",
|
312
|
+
validationErrors,
|
313
|
+
action
|
314
|
+
}) => {
|
224
315
|
const { formatMessage } = useIntl();
|
225
316
|
const getErrorStr = (key, value) => {
|
226
317
|
if (typeof value === "string") {
|
@@ -254,30 +345,63 @@ const EntryValidationText = ({ status = "draft", validationErrors }) => {
|
|
254
345
|
) })
|
255
346
|
] });
|
256
347
|
}
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
348
|
+
const getStatusMessage = () => {
|
349
|
+
if (action === "bulk-publish") {
|
350
|
+
if (status === "published") {
|
351
|
+
return {
|
352
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
353
|
+
text: formatMessage({
|
354
|
+
id: "content-manager.bulk-publish.already-published",
|
355
|
+
defaultMessage: "Already Published"
|
356
|
+
}),
|
357
|
+
textColor: "success600",
|
358
|
+
fontWeight: "bold"
|
359
|
+
};
|
360
|
+
} else if (status === "modified") {
|
361
|
+
return {
|
362
|
+
icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
|
363
|
+
text: formatMessage({
|
364
|
+
id: "app.utils.ready-to-publish-changes",
|
365
|
+
defaultMessage: "Ready to publish changes"
|
366
|
+
})
|
367
|
+
};
|
368
|
+
} else {
|
369
|
+
return {
|
370
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
371
|
+
text: formatMessage({
|
372
|
+
id: "app.utils.ready-to-publish",
|
373
|
+
defaultMessage: "Ready to publish"
|
374
|
+
})
|
375
|
+
};
|
376
|
+
}
|
377
|
+
} else {
|
378
|
+
if (status === "draft") {
|
379
|
+
return {
|
380
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
381
|
+
text: formatMessage({
|
382
|
+
id: "content-manager.bulk-unpublish.already-unpublished",
|
383
|
+
defaultMessage: "Already Unpublished"
|
384
|
+
}),
|
385
|
+
textColor: "success600",
|
386
|
+
fontWeight: "bold"
|
387
|
+
};
|
388
|
+
} else {
|
389
|
+
return {
|
390
|
+
icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
|
391
|
+
text: formatMessage({
|
392
|
+
id: "app.utils.ready-to-unpublish-changes",
|
393
|
+
defaultMessage: "Ready to unpublish"
|
394
|
+
}),
|
395
|
+
textColor: "success600",
|
396
|
+
fontWeight: "bold"
|
397
|
+
};
|
398
|
+
}
|
399
|
+
}
|
400
|
+
};
|
401
|
+
const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
|
275
402
|
return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
276
|
-
|
277
|
-
/* @__PURE__ */ jsx(Typography, { children:
|
278
|
-
id: "app.utils.ready-to-publish",
|
279
|
-
defaultMessage: "Ready to publish"
|
280
|
-
}) })
|
403
|
+
icon,
|
404
|
+
/* @__PURE__ */ jsx(Typography, { textColor, fontWeight, children: text })
|
281
405
|
] });
|
282
406
|
};
|
283
407
|
const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
|
@@ -285,7 +409,8 @@ const BulkLocaleActionModal = ({
|
|
285
409
|
headers,
|
286
410
|
rows,
|
287
411
|
localesMetadata,
|
288
|
-
validationErrors = {}
|
412
|
+
validationErrors = {},
|
413
|
+
action
|
289
414
|
}) => {
|
290
415
|
const { formatMessage } = useIntl();
|
291
416
|
const selectedRows = useTable(
|
@@ -298,22 +423,24 @@ const BulkLocaleActionModal = ({
|
|
298
423
|
return acc;
|
299
424
|
}, {});
|
300
425
|
const localesWithErrors = Object.keys(validationErrors);
|
301
|
-
const
|
426
|
+
const publishedCount = selectedRows.filter(
|
302
427
|
({ locale }) => currentStatusByLocale[locale] === "published"
|
303
428
|
).length;
|
304
|
-
const
|
429
|
+
const draftCount = selectedRows.filter(
|
305
430
|
({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
|
306
431
|
).length;
|
307
432
|
const withErrorsCount = localesWithErrors.length;
|
433
|
+
const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
|
434
|
+
const defaultMessage = action === "bulk-publish" ? "<b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action." : "<b>{draftCount}</b> {draftCount, plural, =0 {entries} one {entry} other {entries}} already unpublished. <b>{publishedCount}</b> {publishedCount, plural, =0 {entries} one {entry} other {entries}} ready to unpublish.";
|
308
435
|
return formatMessage(
|
309
436
|
{
|
310
|
-
id:
|
311
|
-
defaultMessage
|
437
|
+
id: messageId,
|
438
|
+
defaultMessage
|
312
439
|
},
|
313
440
|
{
|
314
441
|
withErrorsCount,
|
315
|
-
|
316
|
-
|
442
|
+
draftCount,
|
443
|
+
publishedCount,
|
317
444
|
b: BoldChunk
|
318
445
|
}
|
319
446
|
);
|
@@ -339,13 +466,12 @@ const BulkLocaleActionModal = ({
|
|
339
466
|
paddingRight: "6px",
|
340
467
|
paddingTop: "2px",
|
341
468
|
paddingBottom: "2px",
|
342
|
-
showBullet: false,
|
343
469
|
size: "S",
|
344
470
|
variant: statusVariant,
|
345
471
|
children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
|
346
472
|
}
|
347
473
|
) }) }),
|
348
|
-
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status }) }),
|
474
|
+
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status, action }) }),
|
349
475
|
/* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
|
350
476
|
IconButton,
|
351
477
|
{
|
@@ -371,6 +497,47 @@ const BulkLocaleActionModal = ({
|
|
371
497
|
] }) })
|
372
498
|
] });
|
373
499
|
};
|
500
|
+
const statusVariants = {
|
501
|
+
draft: "secondary",
|
502
|
+
published: "success",
|
503
|
+
modified: "alternative"
|
504
|
+
};
|
505
|
+
const LocaleOption = ({
|
506
|
+
isDraftAndPublishEnabled,
|
507
|
+
locale,
|
508
|
+
status,
|
509
|
+
entryExists
|
510
|
+
}) => {
|
511
|
+
const { formatMessage } = useIntl();
|
512
|
+
if (!entryExists) {
|
513
|
+
return formatMessage(
|
514
|
+
{
|
515
|
+
id: getTranslation("CMEditViewLocalePicker.locale.create"),
|
516
|
+
defaultMessage: "Create <bold>{locale}</bold> locale"
|
517
|
+
},
|
518
|
+
{
|
519
|
+
bold: (locale2) => /* @__PURE__ */ jsx("b", { children: locale2 }),
|
520
|
+
locale: locale.name
|
521
|
+
}
|
522
|
+
);
|
523
|
+
}
|
524
|
+
return /* @__PURE__ */ jsxs(Flex, { width: "100%", gap: 1, justifyContent: "space-between", children: [
|
525
|
+
/* @__PURE__ */ jsx(Typography, { children: locale.name }),
|
526
|
+
isDraftAndPublishEnabled ? /* @__PURE__ */ jsx(
|
527
|
+
Status,
|
528
|
+
{
|
529
|
+
display: "flex",
|
530
|
+
paddingLeft: "6px",
|
531
|
+
paddingRight: "6px",
|
532
|
+
paddingTop: "2px",
|
533
|
+
paddingBottom: "2px",
|
534
|
+
size: "S",
|
535
|
+
variant: statusVariants[status],
|
536
|
+
children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
|
537
|
+
}
|
538
|
+
) : null
|
539
|
+
] });
|
540
|
+
};
|
374
541
|
const LocalePickerAction = ({
|
375
542
|
document,
|
376
543
|
meta,
|
@@ -382,7 +549,13 @@ const LocalePickerAction = ({
|
|
382
549
|
const [{ query }, setQuery] = useQueryParams();
|
383
550
|
const { hasI18n, canCreate, canRead } = useI18n();
|
384
551
|
const { data: locales = [] } = useGetLocalesQuery();
|
385
|
-
const
|
552
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
553
|
+
const { schema } = unstable_useDocument({
|
554
|
+
model,
|
555
|
+
collectionType,
|
556
|
+
documentId,
|
557
|
+
params: { locale: currentDesiredLocale }
|
558
|
+
});
|
386
559
|
const handleSelect = React.useCallback(
|
387
560
|
(value) => {
|
388
561
|
setQuery({
|
@@ -400,53 +573,50 @@ const LocalePickerAction = ({
|
|
400
573
|
if (!Array.isArray(locales) || !hasI18n) {
|
401
574
|
return;
|
402
575
|
}
|
403
|
-
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
404
576
|
const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
|
405
577
|
const defaultLocale = locales.find((locale) => locale.isDefault);
|
406
578
|
if (!doesLocaleExist && defaultLocale?.code) {
|
407
579
|
handleSelect(defaultLocale.code);
|
408
580
|
}
|
409
|
-
}, [handleSelect, hasI18n, locales,
|
581
|
+
}, [handleSelect, hasI18n, locales, currentDesiredLocale]);
|
582
|
+
const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale) : void 0;
|
583
|
+
const allCurrentLocales = [
|
584
|
+
{ status: getDocumentStatus(document, meta), locale: currentLocale?.code },
|
585
|
+
...document?.localizations ?? []
|
586
|
+
];
|
410
587
|
if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
|
411
588
|
return null;
|
412
589
|
}
|
413
|
-
const
|
414
|
-
|
415
|
-
|
416
|
-
...meta?.availableLocales ?? []
|
417
|
-
];
|
590
|
+
const displayedLocales = locales.filter((locale) => {
|
591
|
+
return canRead.includes(locale.code);
|
592
|
+
});
|
418
593
|
return {
|
419
594
|
label: formatMessage({
|
420
595
|
id: getTranslation("Settings.locales.modal.locales.label"),
|
421
596
|
defaultMessage: "Locales"
|
422
597
|
}),
|
423
|
-
options:
|
598
|
+
options: displayedLocales.map((locale) => {
|
599
|
+
const entryWithLocaleExists = allCurrentLocales.some((doc) => doc.locale === locale.code);
|
424
600
|
const currentLocaleDoc = allCurrentLocales.find(
|
425
601
|
(doc) => "locale" in doc ? doc.locale === locale.code : false
|
426
602
|
);
|
427
|
-
const
|
428
|
-
const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
|
429
|
-
const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
|
603
|
+
const permissionsToCheck = currentLocaleDoc ? canRead : canCreate;
|
430
604
|
return {
|
431
605
|
disabled: !permissionsToCheck.includes(locale.code),
|
432
606
|
value: locale.code,
|
433
|
-
label:
|
434
|
-
|
435
|
-
Status,
|
607
|
+
label: /* @__PURE__ */ jsx(
|
608
|
+
LocaleOption,
|
436
609
|
{
|
437
|
-
|
438
|
-
|
439
|
-
|
440
|
-
|
441
|
-
paddingBottom: "2px",
|
442
|
-
showBullet: false,
|
443
|
-
size: "S",
|
444
|
-
variant: statusVariant,
|
445
|
-
children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
|
610
|
+
isDraftAndPublishEnabled: !!schema?.options?.draftAndPublish,
|
611
|
+
locale,
|
612
|
+
status: currentLocaleDoc?.status,
|
613
|
+
entryExists: entryWithLocaleExists
|
446
614
|
}
|
447
|
-
)
|
615
|
+
),
|
616
|
+
startIcon: !entryWithLocaleExists ? /* @__PURE__ */ jsx(Plus, {}) : null
|
448
617
|
};
|
449
618
|
}),
|
619
|
+
customizeContent: () => currentLocale?.name,
|
450
620
|
onSelect: handleSelect,
|
451
621
|
value: currentLocale
|
452
622
|
};
|
@@ -462,6 +632,99 @@ const getDocumentStatus = (document, meta) => {
|
|
462
632
|
}
|
463
633
|
return docStatus;
|
464
634
|
};
|
635
|
+
const FillFromAnotherLocaleAction = ({
|
636
|
+
documentId,
|
637
|
+
meta,
|
638
|
+
model,
|
639
|
+
collectionType
|
640
|
+
}) => {
|
641
|
+
const { formatMessage } = useIntl();
|
642
|
+
const [{ query }] = useQueryParams();
|
643
|
+
const { hasI18n } = useI18n();
|
644
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
645
|
+
const [localeSelected, setLocaleSelected] = React.useState(null);
|
646
|
+
const setValues = useForm("FillFromAnotherLocale", (state) => state.setValues);
|
647
|
+
const { getDocument } = unstable_useDocumentActions();
|
648
|
+
const { schema, components } = unstable_useDocument({
|
649
|
+
model,
|
650
|
+
documentId,
|
651
|
+
collectionType,
|
652
|
+
params: { locale: currentDesiredLocale }
|
653
|
+
});
|
654
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
655
|
+
const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
|
656
|
+
const fillFromLocale = (onClose) => async () => {
|
657
|
+
const response = await getDocument({
|
658
|
+
collectionType,
|
659
|
+
model,
|
660
|
+
documentId,
|
661
|
+
params: { locale: localeSelected }
|
662
|
+
});
|
663
|
+
if (!response || !schema) {
|
664
|
+
return;
|
665
|
+
}
|
666
|
+
const { data } = response;
|
667
|
+
const cleanedData = cleanData(data, schema, components);
|
668
|
+
setValues(cleanedData);
|
669
|
+
onClose();
|
670
|
+
};
|
671
|
+
if (!hasI18n) {
|
672
|
+
return null;
|
673
|
+
}
|
674
|
+
return {
|
675
|
+
type: "icon",
|
676
|
+
icon: /* @__PURE__ */ jsx(Download, {}),
|
677
|
+
disabled: availableLocales.length === 0,
|
678
|
+
label: formatMessage({
|
679
|
+
id: getTranslation("CMEditViewCopyLocale.copy-text"),
|
680
|
+
defaultMessage: "Fill in from another locale"
|
681
|
+
}),
|
682
|
+
dialog: {
|
683
|
+
type: "dialog",
|
684
|
+
title: formatMessage({
|
685
|
+
id: getTranslation("CMEditViewCopyLocale.dialog.title"),
|
686
|
+
defaultMessage: "Confirmation"
|
687
|
+
}),
|
688
|
+
content: ({ onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [
|
689
|
+
/* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
|
690
|
+
/* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
|
691
|
+
/* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
|
692
|
+
id: getTranslation("CMEditViewCopyLocale.dialog.body"),
|
693
|
+
defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
|
694
|
+
}) }),
|
695
|
+
/* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
|
696
|
+
/* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
|
697
|
+
id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
|
698
|
+
defaultMessage: "Locale"
|
699
|
+
}) }),
|
700
|
+
/* @__PURE__ */ jsx(
|
701
|
+
SingleSelect,
|
702
|
+
{
|
703
|
+
value: localeSelected,
|
704
|
+
placeholder: formatMessage({
|
705
|
+
id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
|
706
|
+
defaultMessage: "Select one locale..."
|
707
|
+
}),
|
708
|
+
onChange: (value) => setLocaleSelected(value),
|
709
|
+
children: availableLocales.map((locale) => /* @__PURE__ */ jsx(SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
|
710
|
+
}
|
711
|
+
)
|
712
|
+
] })
|
713
|
+
] }) }),
|
714
|
+
/* @__PURE__ */ jsx(Dialog.Footer, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, width: "100%", children: [
|
715
|
+
/* @__PURE__ */ jsx(Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
|
716
|
+
id: getTranslation("CMEditViewCopyLocale.cancel-text"),
|
717
|
+
defaultMessage: "No, cancel"
|
718
|
+
}) }),
|
719
|
+
/* @__PURE__ */ jsx(Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
|
720
|
+
id: getTranslation("CMEditViewCopyLocale.submit-text"),
|
721
|
+
defaultMessage: "Yes, fill in"
|
722
|
+
}) })
|
723
|
+
] }) })
|
724
|
+
] })
|
725
|
+
}
|
726
|
+
};
|
727
|
+
};
|
465
728
|
const DeleteLocaleAction = ({
|
466
729
|
document,
|
467
730
|
documentId,
|
@@ -473,16 +736,23 @@ const DeleteLocaleAction = ({
|
|
473
736
|
const { toggleNotification } = useNotification();
|
474
737
|
const { delete: deleteAction } = unstable_useDocumentActions();
|
475
738
|
const { hasI18n, canDelete } = useI18n();
|
739
|
+
const [{ query }] = useQueryParams();
|
740
|
+
const { data: locales = [] } = useGetLocalesQuery();
|
741
|
+
const currentDesiredLocale = query.plugins?.i18n?.locale;
|
742
|
+
const locale = !("error" in locales) && locales.find((loc) => loc.code === currentDesiredLocale);
|
476
743
|
if (!hasI18n) {
|
477
744
|
return null;
|
478
745
|
}
|
479
746
|
return {
|
480
747
|
disabled: document?.locale && !canDelete.includes(document.locale) || !document || !document.id,
|
481
748
|
position: ["header", "table-row"],
|
482
|
-
label: formatMessage(
|
483
|
-
|
484
|
-
|
485
|
-
|
749
|
+
label: formatMessage(
|
750
|
+
{
|
751
|
+
id: getTranslation("actions.delete.label"),
|
752
|
+
defaultMessage: "Delete entry ({locale})"
|
753
|
+
},
|
754
|
+
{ locale: locale && locale.name }
|
755
|
+
),
|
486
756
|
icon: /* @__PURE__ */ jsx(StyledTrash, {}),
|
487
757
|
variant: "danger",
|
488
758
|
dialog: {
|
@@ -499,7 +769,12 @@ const DeleteLocaleAction = ({
|
|
499
769
|
}) })
|
500
770
|
] }),
|
501
771
|
onConfirm: async () => {
|
502
|
-
|
772
|
+
const unableToDelete = (
|
773
|
+
// We are unable to delete a collection type without a document ID
|
774
|
+
// & unable to delete generally if there is no document locale
|
775
|
+
collectionType !== "single-types" && !documentId || !document?.locale
|
776
|
+
);
|
777
|
+
if (unableToDelete) {
|
503
778
|
console.error(
|
504
779
|
"You're trying to delete a document without an id or locale, this is likely a bug with Strapi. Please open an issue."
|
505
780
|
);
|
@@ -525,39 +800,36 @@ const DeleteLocaleAction = ({
|
|
525
800
|
}
|
526
801
|
};
|
527
802
|
};
|
528
|
-
const
|
529
|
-
document
|
803
|
+
const BulkLocaleAction = ({
|
804
|
+
document,
|
530
805
|
documentId,
|
531
806
|
model,
|
532
|
-
collectionType
|
807
|
+
collectionType,
|
808
|
+
action
|
533
809
|
}) => {
|
534
|
-
const
|
810
|
+
const locale = document?.locale ?? null;
|
535
811
|
const [{ query }] = useQueryParams();
|
536
812
|
const params = React.useMemo(() => buildValidParams(query), [query]);
|
537
|
-
const
|
813
|
+
const isOnPublishedTab = query.status === "published";
|
538
814
|
const { formatMessage } = useIntl();
|
539
815
|
const { hasI18n, canPublish } = useI18n();
|
540
816
|
const { toggleNotification } = useNotification();
|
541
817
|
const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
|
542
818
|
const [selectedRows, setSelectedRows] = React.useState([]);
|
543
819
|
const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React.useState(false);
|
544
|
-
const { publishMany: publishManyAction } = unstable_useDocumentActions();
|
545
|
-
const {
|
546
|
-
document,
|
547
|
-
meta: documentMeta,
|
548
|
-
schema,
|
549
|
-
validate
|
550
|
-
} = unstable_useDocument(
|
820
|
+
const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = unstable_useDocumentActions();
|
821
|
+
const { schema, validate } = unstable_useDocument(
|
551
822
|
{
|
552
823
|
model,
|
553
824
|
collectionType,
|
554
825
|
documentId,
|
555
826
|
params: {
|
556
|
-
locale
|
827
|
+
locale
|
557
828
|
}
|
558
829
|
},
|
559
830
|
{
|
560
|
-
|
831
|
+
// No need to fetch the document, the data is already available in the `document` prop
|
832
|
+
skip: true
|
561
833
|
}
|
562
834
|
);
|
563
835
|
const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : skipToken);
|
@@ -585,18 +857,19 @@ const BulkLocalePublishAction = ({
|
|
585
857
|
}
|
586
858
|
];
|
587
859
|
const [rows, validationErrors] = React.useMemo(() => {
|
588
|
-
if (!document
|
860
|
+
if (!document) {
|
589
861
|
return [[], {}];
|
590
862
|
}
|
591
|
-
const
|
592
|
-
|
593
|
-
|
863
|
+
const localizations = document.localizations ?? [];
|
864
|
+
const locales = localizations.map((doc) => {
|
865
|
+
const { locale: locale2, status } = doc;
|
866
|
+
return { locale: locale2, status };
|
594
867
|
});
|
595
|
-
|
868
|
+
locales.unshift({
|
596
869
|
locale: document.locale,
|
597
870
|
status: document.status
|
598
871
|
});
|
599
|
-
const allDocuments = [document, ...
|
872
|
+
const allDocuments = [document, ...localizations];
|
600
873
|
const errors = allDocuments.reduce((errs, document2) => {
|
601
874
|
if (!document2) {
|
602
875
|
return errs;
|
@@ -607,14 +880,21 @@ const BulkLocalePublishAction = ({
|
|
607
880
|
}
|
608
881
|
return errs;
|
609
882
|
}, {});
|
610
|
-
return [
|
611
|
-
}, [document,
|
612
|
-
const
|
613
|
-
|
883
|
+
return [locales, errors];
|
884
|
+
}, [document, validate]);
|
885
|
+
const isBulkPublish = action === "bulk-publish";
|
886
|
+
const localesForAction = selectedRows.reduce((acc, selectedRow) => {
|
887
|
+
const isValidLocale = (
|
888
|
+
// Validation errors are irrelevant if we are trying to unpublish
|
889
|
+
!isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
|
890
|
+
);
|
891
|
+
const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
|
892
|
+
if (shouldAddLocale) {
|
614
893
|
acc.push(selectedRow.locale);
|
615
894
|
}
|
616
895
|
return acc;
|
617
896
|
}, []);
|
897
|
+
const enableDraftRelationsCount = false;
|
618
898
|
const {
|
619
899
|
data: draftRelationsCount = 0,
|
620
900
|
isLoading: isDraftRelationsLoading,
|
@@ -623,10 +903,10 @@ const BulkLocalePublishAction = ({
|
|
623
903
|
{
|
624
904
|
model,
|
625
905
|
documentIds: [documentId],
|
626
|
-
locale:
|
906
|
+
locale: localesForAction
|
627
907
|
},
|
628
908
|
{
|
629
|
-
skip: !
|
909
|
+
skip: !enableDraftRelationsCount
|
630
910
|
}
|
631
911
|
);
|
632
912
|
React.useEffect(() => {
|
@@ -652,7 +932,18 @@ const BulkLocalePublishAction = ({
|
|
652
932
|
documentIds: [documentId],
|
653
933
|
params: {
|
654
934
|
...params,
|
655
|
-
locale:
|
935
|
+
locale: localesForAction
|
936
|
+
}
|
937
|
+
});
|
938
|
+
setSelectedRows([]);
|
939
|
+
};
|
940
|
+
const unpublish = async () => {
|
941
|
+
await unpublishManyAction({
|
942
|
+
model,
|
943
|
+
documentIds: [documentId],
|
944
|
+
params: {
|
945
|
+
...params,
|
946
|
+
locale: localesForAction
|
656
947
|
}
|
657
948
|
});
|
658
949
|
setSelectedRows([]);
|
@@ -660,14 +951,12 @@ const BulkLocalePublishAction = ({
|
|
660
951
|
const handleAction = async () => {
|
661
952
|
if (draftRelationsCount > 0) {
|
662
953
|
setIsDraftRelationConfirmationOpen(true);
|
663
|
-
} else {
|
954
|
+
} else if (isBulkPublish) {
|
664
955
|
await publish();
|
956
|
+
} else {
|
957
|
+
await unpublish();
|
665
958
|
}
|
666
959
|
};
|
667
|
-
const isUnpublish = document?.status === "published";
|
668
|
-
if (isUnpublish) {
|
669
|
-
console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
|
670
|
-
}
|
671
960
|
if (isDraftRelationConfirmationOpen) {
|
672
961
|
return {
|
673
962
|
label: formatMessage({
|
@@ -702,21 +991,21 @@ const BulkLocalePublishAction = ({
|
|
702
991
|
}
|
703
992
|
};
|
704
993
|
}
|
705
|
-
const hasPermission = selectedRows.map(({ locale }) =>
|
994
|
+
const hasPermission = selectedRows.map(({ locale: locale2 }) => locale2).every((locale2) => canPublish.includes(locale2));
|
706
995
|
return {
|
707
996
|
label: formatMessage({
|
708
|
-
id: getTranslation("
|
709
|
-
defaultMessage: "Publish Multiple Locales
|
997
|
+
id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
|
998
|
+
defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
|
710
999
|
}),
|
711
|
-
|
712
|
-
|
1000
|
+
variant: isBulkPublish ? "secondary" : "danger",
|
1001
|
+
icon: isBulkPublish ? /* @__PURE__ */ jsx(ListPlus, {}) : /* @__PURE__ */ jsx(Cross, {}),
|
1002
|
+
disabled: isOnPublishedTab || canPublish.length === 0,
|
713
1003
|
position: ["panel"],
|
714
|
-
variant: "secondary",
|
715
1004
|
dialog: {
|
716
1005
|
type: "modal",
|
717
1006
|
title: formatMessage({
|
718
|
-
id: getTranslation("
|
719
|
-
defaultMessage: "Publish Multiple Locales
|
1007
|
+
id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
|
1008
|
+
defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
|
720
1009
|
}),
|
721
1010
|
content: () => {
|
722
1011
|
return /* @__PURE__ */ jsx(
|
@@ -735,7 +1024,8 @@ const BulkLocalePublishAction = ({
|
|
735
1024
|
validationErrors,
|
736
1025
|
headers,
|
737
1026
|
rows,
|
738
|
-
localesMetadata
|
1027
|
+
localesMetadata,
|
1028
|
+
action: action ?? "bulk-publish"
|
739
1029
|
}
|
740
1030
|
)
|
741
1031
|
}
|
@@ -745,18 +1035,24 @@ const BulkLocalePublishAction = ({
|
|
745
1035
|
Button,
|
746
1036
|
{
|
747
1037
|
loading: isDraftRelationsLoading,
|
748
|
-
disabled: !hasPermission ||
|
1038
|
+
disabled: !hasPermission || localesForAction.length === 0,
|
749
1039
|
variant: "default",
|
750
1040
|
onClick: handleAction,
|
751
1041
|
children: formatMessage({
|
752
|
-
id: "app.utils.publish",
|
753
|
-
defaultMessage: "Publish"
|
1042
|
+
id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
|
1043
|
+
defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
|
754
1044
|
})
|
755
1045
|
}
|
756
1046
|
) })
|
757
1047
|
}
|
758
1048
|
};
|
759
1049
|
};
|
1050
|
+
const BulkLocalePublishAction = (props) => {
|
1051
|
+
return BulkLocaleAction({ action: "bulk-publish", ...props });
|
1052
|
+
};
|
1053
|
+
const BulkLocaleUnpublishAction = (props) => {
|
1054
|
+
return BulkLocaleAction({ action: "bulk-unpublish", ...props });
|
1055
|
+
};
|
760
1056
|
const StyledTrash = styled(Trash)`
|
761
1057
|
path {
|
762
1058
|
fill: currentColor;
|
@@ -938,29 +1234,16 @@ const Span = styled(Flex)`
|
|
938
1234
|
}
|
939
1235
|
}
|
940
1236
|
`;
|
941
|
-
const LocaleListCell = ({
|
942
|
-
documentId,
|
943
|
-
locale: currentLocale,
|
944
|
-
collectionType,
|
945
|
-
model
|
946
|
-
}) => {
|
947
|
-
const { meta, isLoading } = unstable_useDocument({
|
948
|
-
documentId,
|
949
|
-
collectionType,
|
950
|
-
model,
|
951
|
-
params: {
|
952
|
-
locale: currentLocale
|
953
|
-
}
|
954
|
-
});
|
1237
|
+
const LocaleListCell = ({ locale: currentLocale, localizations }) => {
|
955
1238
|
const { locale: language } = useIntl();
|
956
1239
|
const { data: locales = [] } = useGetLocalesQuery();
|
957
1240
|
const formatter = useCollator(language, {
|
958
1241
|
sensitivity: "base"
|
959
1242
|
});
|
960
|
-
if (!Array.isArray(locales) ||
|
1243
|
+
if (!Array.isArray(locales) || !localizations) {
|
961
1244
|
return null;
|
962
1245
|
}
|
963
|
-
const availableLocales =
|
1246
|
+
const availableLocales = localizations.map((loc) => loc.locale);
|
964
1247
|
const localesForDocument = locales.reduce((acc, locale) => {
|
965
1248
|
const createdLocale = [currentLocale, ...availableLocales].find((loc) => {
|
966
1249
|
return loc === locale.code;
|
@@ -1108,9 +1391,6 @@ const localeMiddleware = (ctx) => (next) => (permissions) => {
|
|
1108
1391
|
return next(revisedPermissions);
|
1109
1392
|
};
|
1110
1393
|
const prefixPluginTranslations = (trad, pluginId2) => {
|
1111
|
-
if (!pluginId2) {
|
1112
|
-
throw new TypeError("pluginId can't be empty");
|
1113
|
-
}
|
1114
1394
|
return Object.keys(trad).reduce((acc, current) => {
|
1115
1395
|
acc[`${pluginId2}.${current}`] = trad[current];
|
1116
1396
|
return acc;
|
@@ -1180,11 +1460,11 @@ const index = {
|
|
1180
1460
|
},
|
1181
1461
|
id: "internationalization",
|
1182
1462
|
to: "internationalization",
|
1183
|
-
Component: () => import("./SettingsPage-
|
1463
|
+
Component: () => import("./SettingsPage-B6QDUmu9.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
|
1184
1464
|
permissions: PERMISSIONS.accessMain
|
1185
1465
|
});
|
1186
1466
|
const contentManager = app.getPlugin("content-manager");
|
1187
|
-
contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
|
1467
|
+
contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
|
1188
1468
|
contentManager.apis.addDocumentAction((actions) => {
|
1189
1469
|
const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
|
1190
1470
|
actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
|
@@ -1192,6 +1472,7 @@ const index = {
|
|
1192
1472
|
});
|
1193
1473
|
contentManager.apis.addDocumentAction((actions) => {
|
1194
1474
|
actions.splice(2, 0, BulkLocalePublishAction);
|
1475
|
+
actions.splice(5, 0, BulkLocaleUnpublishAction);
|
1195
1476
|
return actions;
|
1196
1477
|
});
|
1197
1478
|
contentManager.injectComponent("listView", "actions", {
|
@@ -1297,7 +1578,7 @@ const index = {
|
|
1297
1578
|
async registerTrads({ locales }) {
|
1298
1579
|
const importedTrads = await Promise.all(
|
1299
1580
|
locales.map((locale) => {
|
1300
|
-
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-9eCAqqrB.mjs"), "./translations/dk.json": () => import("./dk-2qBjxt-P.mjs"), "./translations/en.json": () => import("./en-
|
1581
|
+
return __variableDynamicImportRuntimeHelper(/* @__PURE__ */ Object.assign({ "./translations/de.json": () => import("./de-9eCAqqrB.mjs"), "./translations/dk.json": () => import("./dk-2qBjxt-P.mjs"), "./translations/en.json": () => import("./en-DlXfy6Gy.mjs"), "./translations/es.json": () => import("./es-DlmMVaBG.mjs"), "./translations/fr.json": () => import("./fr-3S6ke71d.mjs"), "./translations/ko.json": () => import("./ko-qTjQ8IMw.mjs"), "./translations/pl.json": () => import("./pl-B67TSHqT.mjs"), "./translations/ru.json": () => import("./ru-hagMa57T.mjs"), "./translations/tr.json": () => import("./tr-Dw_jmkG-.mjs"), "./translations/zh-Hans.json": () => import("./zh-Hans-Dyc-aR-h.mjs"), "./translations/zh.json": () => import("./zh-57YM4amO.mjs") }), `./translations/${locale}.json`, 3).then(({ default: data }) => {
|
1301
1582
|
return {
|
1302
1583
|
data: prefixPluginTranslations(data, pluginId),
|
1303
1584
|
locale
|
@@ -1323,4 +1604,4 @@ export {
|
|
1323
1604
|
index as i,
|
1324
1605
|
useCreateLocaleMutation as u
|
1325
1606
|
};
|
1326
|
-
//# sourceMappingURL=index-
|
1607
|
+
//# sourceMappingURL=index-iEQ79W05.mjs.map
|