@strapi/i18n 5.0.0-rc.11 → 5.0.0-rc.13

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.
Files changed (27) hide show
  1. package/dist/_chunks/{SettingsPage-CbEn7zF5.mjs → SettingsPage-BjxjwEOb.mjs} +2 -2
  2. package/dist/_chunks/{SettingsPage-CbEn7zF5.mjs.map → SettingsPage-BjxjwEOb.mjs.map} +1 -1
  3. package/dist/_chunks/{SettingsPage-C0l7c5fn.js → SettingsPage-CfTmCkup.js} +2 -2
  4. package/dist/_chunks/{SettingsPage-C0l7c5fn.js.map → SettingsPage-CfTmCkup.js.map} +1 -1
  5. package/dist/_chunks/{en-CM6Pjfyv.mjs → en-2xztdZE1.mjs} +7 -1
  6. package/dist/_chunks/en-2xztdZE1.mjs.map +1 -0
  7. package/dist/_chunks/{en-BsOU9o5z.js → en-DWpfm8h5.js} +7 -1
  8. package/dist/_chunks/en-DWpfm8h5.js.map +1 -0
  9. package/dist/_chunks/{index-C0i3v7QQ.js → index-5XLZwzwx.js} +312 -115
  10. package/dist/_chunks/index-5XLZwzwx.js.map +1 -0
  11. package/dist/_chunks/{index-CkrCiZyq.mjs → index-D-qx3tz4.mjs} +319 -122
  12. package/dist/_chunks/index-D-qx3tz4.mjs.map +1 -0
  13. package/dist/admin/index.js +1 -1
  14. package/dist/admin/index.mjs +1 -1
  15. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +2 -1
  16. package/dist/admin/src/components/CMHeaderActions.d.ts +27 -3
  17. package/dist/admin/src/utils/clean.d.ts +4 -0
  18. package/dist/server/index.js +1 -1
  19. package/dist/server/index.js.map +1 -1
  20. package/dist/server/index.mjs +1 -1
  21. package/dist/server/index.mjs.map +1 -1
  22. package/dist/server/src/bootstrap.d.ts.map +1 -1
  23. package/package.json +9 -9
  24. package/dist/_chunks/en-BsOU9o5z.js.map +0 -1
  25. package/dist/_chunks/en-CM6Pjfyv.mjs.map +0 -1
  26. package/dist/_chunks/index-C0i3v7QQ.js.map +0 -1
  27. package/dist/_chunks/index-CkrCiZyq.mjs.map +0 -1
@@ -1,13 +1,13 @@
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
- import { Typography, Dialog, Field, Checkbox, Flex, Button as Button$1, 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";
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, 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";
@@ -78,11 +78,11 @@ const CheckboxConfirmation = ({
78
78
  }) }) })
79
79
  ] }) }),
80
80
  /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
81
- /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button$1, { variant: "tertiary", children: formatMessage({
81
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button, { variant: "tertiary", children: formatMessage({
82
82
  id: "components.popUpWarning.button.cancel",
83
83
  defaultMessage: "No, cancel"
84
84
  }) }) }),
85
- /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button$1, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
85
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
86
86
  id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
87
87
  defaultMessage: "Yes, disable"
88
88
  }) }) })
@@ -217,10 +217,93 @@ const relationsApi = i18nApi.injectEndpoints({
217
217
  })
218
218
  });
219
219
  const { useGetManyDraftRelationCountQuery } = relationsApi;
220
+ const cleanData = (data, schema, components) => {
221
+ const cleanedData = removeFields(data, [
222
+ "createdAt",
223
+ "createdBy",
224
+ "updatedAt",
225
+ "updatedBy",
226
+ "id",
227
+ "documentId",
228
+ "publishedAt",
229
+ "strapi_stage",
230
+ "strapi_assignee",
231
+ "locale"
232
+ ]);
233
+ const cleanedDataWithoutPasswordAndRelation = recursiveRemoveFieldTypes(
234
+ cleanedData,
235
+ schema,
236
+ components,
237
+ ["relation", "password"]
238
+ );
239
+ return cleanedDataWithoutPasswordAndRelation;
240
+ };
241
+ const removeFields = (data, fields) => {
242
+ return Object.keys(data).reduce((acc, current) => {
243
+ if (fields.includes(current)) {
244
+ return acc;
245
+ }
246
+ acc[current] = data[current];
247
+ return acc;
248
+ }, {});
249
+ };
250
+ const recursiveRemoveFieldTypes = (data, schema, components, fields) => {
251
+ return Object.keys(data).reduce((acc, current) => {
252
+ const attribute = schema.attributes[current] ?? { type: void 0 };
253
+ if (fields.includes(attribute.type)) {
254
+ return acc;
255
+ }
256
+ if (attribute.type === "dynamiczone") {
257
+ acc[current] = data[current].map((componentValue, index2) => {
258
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
259
+ componentValue,
260
+ components[componentValue.__component],
261
+ components,
262
+ fields
263
+ );
264
+ return {
265
+ ...rest,
266
+ __temp_key__: index2 + 1
267
+ };
268
+ });
269
+ } else if (attribute.type === "component") {
270
+ const { repeatable, component } = attribute;
271
+ if (repeatable) {
272
+ acc[current] = (data[current] ?? []).map((compoData, index2) => {
273
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
274
+ compoData,
275
+ components[component],
276
+ components,
277
+ fields
278
+ );
279
+ return {
280
+ ...rest,
281
+ __temp_key__: index2 + 1
282
+ };
283
+ });
284
+ } else {
285
+ const { id: _, ...rest } = recursiveRemoveFieldTypes(
286
+ data[current] ?? {},
287
+ components[component],
288
+ components,
289
+ fields
290
+ );
291
+ acc[current] = rest;
292
+ }
293
+ } else {
294
+ acc[current] = data[current];
295
+ }
296
+ return acc;
297
+ }, {});
298
+ };
220
299
  const isErrorMessageDescriptor = (object) => {
221
300
  return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
222
301
  };
223
- const EntryValidationText = ({ status = "draft", validationErrors }) => {
302
+ const EntryValidationText = ({
303
+ status = "draft",
304
+ validationErrors,
305
+ action
306
+ }) => {
224
307
  const { formatMessage } = useIntl();
225
308
  const getErrorStr = (key, value) => {
226
309
  if (typeof value === "string") {
@@ -254,30 +337,63 @@ const EntryValidationText = ({ status = "draft", validationErrors }) => {
254
337
  ) })
255
338
  ] });
256
339
  }
257
- if (status === "published") {
258
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
259
- /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
260
- /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
261
- id: "content-manager.bulk-publish.already-published",
262
- defaultMessage: "Already Published"
263
- }) })
264
- ] });
265
- }
266
- if (status === "modified") {
267
- return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
268
- /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
269
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
270
- id: "app.utils.ready-to-publish-changes",
271
- defaultMessage: "Ready to publish changes"
272
- }) })
273
- ] });
274
- }
340
+ const getStatusMessage = () => {
341
+ if (action === "bulk-publish") {
342
+ if (status === "published") {
343
+ return {
344
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
345
+ text: formatMessage({
346
+ id: "content-manager.bulk-publish.already-published",
347
+ defaultMessage: "Already Published"
348
+ }),
349
+ textColor: "success600",
350
+ fontWeight: "bold"
351
+ };
352
+ } else if (status === "modified") {
353
+ return {
354
+ icon: /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
355
+ text: formatMessage({
356
+ id: "app.utils.ready-to-publish-changes",
357
+ defaultMessage: "Ready to publish changes"
358
+ })
359
+ };
360
+ } else {
361
+ return {
362
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
363
+ text: formatMessage({
364
+ id: "app.utils.ready-to-publish",
365
+ defaultMessage: "Ready to publish"
366
+ })
367
+ };
368
+ }
369
+ } else {
370
+ if (status === "draft") {
371
+ return {
372
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
373
+ text: formatMessage({
374
+ id: "content-manager.bulk-unpublish.already-unpublished",
375
+ defaultMessage: "Already Unpublished"
376
+ }),
377
+ textColor: "success600",
378
+ fontWeight: "bold"
379
+ };
380
+ } else {
381
+ return {
382
+ icon: /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
383
+ text: formatMessage({
384
+ id: "app.utils.ready-to-unpublish-changes",
385
+ defaultMessage: "Ready to unpublish"
386
+ }),
387
+ textColor: "success600",
388
+ fontWeight: "bold"
389
+ };
390
+ }
391
+ }
392
+ };
393
+ const { icon, text, textColor = "success600", fontWeight = "normal" } = getStatusMessage();
275
394
  return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
276
- /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
277
- /* @__PURE__ */ jsx(Typography, { children: formatMessage({
278
- id: "app.utils.ready-to-publish",
279
- defaultMessage: "Ready to publish"
280
- }) })
395
+ icon,
396
+ /* @__PURE__ */ jsx(Typography, { textColor, fontWeight, children: text })
281
397
  ] });
282
398
  };
283
399
  const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
@@ -285,7 +401,8 @@ const BulkLocaleActionModal = ({
285
401
  headers,
286
402
  rows,
287
403
  localesMetadata,
288
- validationErrors = {}
404
+ validationErrors = {},
405
+ action
289
406
  }) => {
290
407
  const { formatMessage } = useIntl();
291
408
  const selectedRows = useTable(
@@ -298,22 +415,24 @@ const BulkLocaleActionModal = ({
298
415
  return acc;
299
416
  }, {});
300
417
  const localesWithErrors = Object.keys(validationErrors);
301
- const alreadyPublishedCount = selectedRows.filter(
418
+ const publishedCount = selectedRows.filter(
302
419
  ({ locale }) => currentStatusByLocale[locale] === "published"
303
420
  ).length;
304
- const readyToPublishCount = selectedRows.filter(
421
+ const draftCount = selectedRows.filter(
305
422
  ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
306
423
  ).length;
307
424
  const withErrorsCount = localesWithErrors.length;
425
+ const messageId = action === "bulk-publish" ? "content-manager.containers.list.selectedEntriesModal.selectedCount.publish" : "content-manager.containers.list.selectedEntriesModal.selectedCount.unpublish";
426
+ 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
427
  return formatMessage(
309
428
  {
310
- id: "content-manager.containers.list.selectedEntriesModal.selectedCount",
311
- defaultMessage: "<b>{alreadyPublishedCount}</b> {alreadyPublishedCount, plural, =0 {entries} one {entry} other {entries}} already published. <b>{readyToPublishCount}</b> {readyToPublishCount, plural, =0 {entries} one {entry} other {entries}} ready to publish. <b>{withErrorsCount}</b> {withErrorsCount, plural, =0 {entries} one {entry} other {entries}} waiting for action."
429
+ id: messageId,
430
+ defaultMessage
312
431
  },
313
432
  {
314
433
  withErrorsCount,
315
- readyToPublishCount,
316
- alreadyPublishedCount,
434
+ draftCount,
435
+ publishedCount,
317
436
  b: BoldChunk
318
437
  }
319
438
  );
@@ -345,7 +464,7 @@ const BulkLocaleActionModal = ({
345
464
  children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
346
465
  }
347
466
  ) }) }),
348
- /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status }) }),
467
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status, action }) }),
349
468
  /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
350
469
  IconButton,
351
470
  {
@@ -382,7 +501,13 @@ const LocalePickerAction = ({
382
501
  const [{ query }, setQuery] = useQueryParams();
383
502
  const { hasI18n, canCreate, canRead } = useI18n();
384
503
  const { data: locales = [] } = useGetLocalesQuery();
385
- const { schema } = unstable_useDocument({ model, collectionType, documentId });
504
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
505
+ const { schema } = unstable_useDocument({
506
+ model,
507
+ collectionType,
508
+ documentId,
509
+ params: { locale: currentDesiredLocale }
510
+ });
386
511
  const handleSelect = React.useCallback(
387
512
  (value) => {
388
513
  setQuery({
@@ -400,21 +525,20 @@ const LocalePickerAction = ({
400
525
  if (!Array.isArray(locales) || !hasI18n) {
401
526
  return;
402
527
  }
403
- const currentDesiredLocale = query.plugins?.i18n?.locale;
404
528
  const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);
405
529
  const defaultLocale = locales.find((locale) => locale.isDefault);
406
530
  if (!doesLocaleExist && defaultLocale?.code) {
407
531
  handleSelect(defaultLocale.code);
408
532
  }
409
- }, [handleSelect, hasI18n, locales, query.plugins?.i18n?.locale]);
410
- if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
411
- return null;
412
- }
413
- const currentLocale = query.plugins?.i18n?.locale || locales.find((loc) => loc.isDefault)?.code;
533
+ }, [handleSelect, hasI18n, locales, currentDesiredLocale]);
534
+ const currentLocale = Array.isArray(locales) ? locales.find((locale) => locale.code === currentDesiredLocale)?.code : void 0;
414
535
  const allCurrentLocales = [
415
536
  { status: getDocumentStatus(document, meta), locale: currentLocale },
416
537
  ...meta?.availableLocales ?? []
417
538
  ];
539
+ if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
540
+ return null;
541
+ }
418
542
  return {
419
543
  label: formatMessage({
420
544
  id: getTranslation("Settings.locales.modal.locales.label"),
@@ -426,7 +550,7 @@ const LocalePickerAction = ({
426
550
  );
427
551
  const status = currentLocaleDoc?.status ?? "draft";
428
552
  const permissionsToCheck = currentLocaleDoc ? canCreate : canRead;
429
- const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
553
+ const statusVariant = status === "draft" ? "secondary" : status === "published" ? "success" : "alternative";
430
554
  return {
431
555
  disabled: !permissionsToCheck.includes(locale.code),
432
556
  value: locale.code,
@@ -462,6 +586,95 @@ const getDocumentStatus = (document, meta) => {
462
586
  }
463
587
  return docStatus;
464
588
  };
589
+ const FillFromAnotherLocaleAction = ({
590
+ documentId,
591
+ meta,
592
+ model,
593
+ collectionType
594
+ }) => {
595
+ const { formatMessage } = useIntl();
596
+ const [{ query }] = useQueryParams();
597
+ const currentDesiredLocale = query.plugins?.i18n?.locale;
598
+ const [localeSelected, setLocaleSelected] = React.useState(null);
599
+ const setValues = useForm("FillFromAnotherLocale", (state) => state.setValues);
600
+ const { getDocument } = unstable_useDocumentActions();
601
+ const { schema, components } = unstable_useDocument({
602
+ model,
603
+ documentId,
604
+ collectionType,
605
+ params: { locale: currentDesiredLocale }
606
+ });
607
+ const { data: locales = [] } = useGetLocalesQuery();
608
+ const availableLocales = Array.isArray(locales) ? locales.filter((locale) => meta?.availableLocales.some((l) => l.locale === locale.code)) : [];
609
+ const fillFromLocale = (onClose) => async () => {
610
+ const response = await getDocument({
611
+ collectionType,
612
+ model,
613
+ documentId,
614
+ params: { locale: localeSelected }
615
+ });
616
+ if (!response || !schema) {
617
+ return;
618
+ }
619
+ const { data } = response;
620
+ const cleanedData = cleanData(data, schema, components);
621
+ setValues(cleanedData);
622
+ onClose();
623
+ };
624
+ return {
625
+ type: "icon",
626
+ icon: /* @__PURE__ */ jsx(Download, {}),
627
+ disabled: availableLocales.length === 0,
628
+ label: formatMessage({
629
+ id: getTranslation("CMEditViewCopyLocale.copy-text"),
630
+ defaultMessage: "Fill in from another locale"
631
+ }),
632
+ dialog: {
633
+ type: "dialog",
634
+ title: formatMessage({
635
+ id: getTranslation("CMEditViewCopyLocale.dialog.title"),
636
+ defaultMessage: "Confirmation"
637
+ }),
638
+ content: ({ onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [
639
+ /* @__PURE__ */ jsx(Dialog.Body, { children: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 3, children: [
640
+ /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
641
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
642
+ id: getTranslation("CMEditViewCopyLocale.dialog.body"),
643
+ defaultMessage: "Your current content will be erased and filled by the content of the selected locale:"
644
+ }) }),
645
+ /* @__PURE__ */ jsxs(Field.Root, { width: "100%", children: [
646
+ /* @__PURE__ */ jsx(Field.Label, { children: formatMessage({
647
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.label"),
648
+ defaultMessage: "Locale"
649
+ }) }),
650
+ /* @__PURE__ */ jsx(
651
+ SingleSelect,
652
+ {
653
+ value: localeSelected,
654
+ placeholder: formatMessage({
655
+ id: getTranslation("CMEditViewCopyLocale.dialog.field.placeholder"),
656
+ defaultMessage: "Select one locale..."
657
+ }),
658
+ onChange: (value) => setLocaleSelected(value),
659
+ children: availableLocales.map((locale) => /* @__PURE__ */ jsx(SingleSelectOption, { value: locale.code, children: locale.name }, locale.code))
660
+ }
661
+ )
662
+ ] })
663
+ ] }) }),
664
+ /* @__PURE__ */ jsx(Dialog.Footer, { children: /* @__PURE__ */ jsxs(Flex, { gap: 2, width: "100%", children: [
665
+ /* @__PURE__ */ jsx(Button, { flex: "auto", variant: "tertiary", onClick: onClose, children: formatMessage({
666
+ id: getTranslation("CMEditViewCopyLocale.cancel-text"),
667
+ defaultMessage: "No, cancel"
668
+ }) }),
669
+ /* @__PURE__ */ jsx(Button, { flex: "auto", variant: "success", onClick: fillFromLocale(onClose), children: formatMessage({
670
+ id: getTranslation("CMEditViewCopyLocale.submit-text"),
671
+ defaultMessage: "Yes, fill in"
672
+ }) })
673
+ ] }) })
674
+ ] })
675
+ }
676
+ };
677
+ };
465
678
  const DeleteLocaleAction = ({
466
679
  document,
467
680
  documentId,
@@ -525,23 +738,24 @@ const DeleteLocaleAction = ({
525
738
  }
526
739
  };
527
740
  };
528
- const BulkLocalePublishAction = ({
741
+ const BulkLocaleAction = ({
529
742
  document: baseDocument,
530
743
  documentId,
531
744
  model,
532
- collectionType
745
+ collectionType,
746
+ action
533
747
  }) => {
534
748
  const baseLocale = baseDocument?.locale ?? null;
535
749
  const [{ query }] = useQueryParams();
536
750
  const params = React.useMemo(() => buildValidParams(query), [query]);
537
- const isPublishedTab = query.status === "published";
751
+ const isOnPublishedTab = query.status === "published";
538
752
  const { formatMessage } = useIntl();
539
753
  const { hasI18n, canPublish } = useI18n();
540
754
  const { toggleNotification } = useNotification();
541
755
  const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
542
756
  const [selectedRows, setSelectedRows] = React.useState([]);
543
757
  const [isDraftRelationConfirmationOpen, setIsDraftRelationConfirmationOpen] = React.useState(false);
544
- const { publishMany: publishManyAction } = unstable_useDocumentActions();
758
+ const { publishMany: publishManyAction, unpublishMany: unpublishManyAction } = unstable_useDocumentActions();
545
759
  const {
546
760
  document,
547
761
  meta: documentMeta,
@@ -557,7 +771,7 @@ const BulkLocalePublishAction = ({
557
771
  }
558
772
  },
559
773
  {
560
- skip: !hasI18n
774
+ skip: !hasI18n || !baseLocale
561
775
  }
562
776
  );
563
777
  const { data: localesMetadata = [] } = useGetLocalesQuery(hasI18n ? void 0 : skipToken);
@@ -609,12 +823,19 @@ const BulkLocalePublishAction = ({
609
823
  }, {});
610
824
  return [rowsFromMeta, errors];
611
825
  }, [document, documentMeta?.availableLocales, validate]);
612
- const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
613
- if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
826
+ const isBulkPublish = action === "bulk-publish";
827
+ const localesForAction = selectedRows.reduce((acc, selectedRow) => {
828
+ const isValidLocale = (
829
+ // Validation errors are irrelevant if we are trying to unpublish
830
+ !isBulkPublish || !Object.keys(validationErrors).includes(selectedRow.locale)
831
+ );
832
+ const shouldAddLocale = isBulkPublish ? selectedRow.status !== "published" && isValidLocale : selectedRow.status !== "draft" && isValidLocale;
833
+ if (shouldAddLocale) {
614
834
  acc.push(selectedRow.locale);
615
835
  }
616
836
  return acc;
617
837
  }, []);
838
+ const enableDraftRelationsCount = false;
618
839
  const {
619
840
  data: draftRelationsCount = 0,
620
841
  isLoading: isDraftRelationsLoading,
@@ -623,10 +844,10 @@ const BulkLocalePublishAction = ({
623
844
  {
624
845
  model,
625
846
  documentIds: [documentId],
626
- locale: localesToPublish
847
+ locale: localesForAction
627
848
  },
628
849
  {
629
- skip: !documentId || localesToPublish.length === 0
850
+ skip: !enableDraftRelationsCount
630
851
  }
631
852
  );
632
853
  React.useEffect(() => {
@@ -652,7 +873,18 @@ const BulkLocalePublishAction = ({
652
873
  documentIds: [documentId],
653
874
  params: {
654
875
  ...params,
655
- locale: localesToPublish
876
+ locale: localesForAction
877
+ }
878
+ });
879
+ setSelectedRows([]);
880
+ };
881
+ const unpublish = async () => {
882
+ await unpublishManyAction({
883
+ model,
884
+ documentIds: [documentId],
885
+ params: {
886
+ ...params,
887
+ locale: localesForAction
656
888
  }
657
889
  });
658
890
  setSelectedRows([]);
@@ -660,14 +892,12 @@ const BulkLocalePublishAction = ({
660
892
  const handleAction = async () => {
661
893
  if (draftRelationsCount > 0) {
662
894
  setIsDraftRelationConfirmationOpen(true);
663
- } else {
895
+ } else if (isBulkPublish) {
664
896
  await publish();
897
+ } else {
898
+ await unpublish();
665
899
  }
666
900
  };
667
- const isUnpublish = document?.status === "published";
668
- if (isUnpublish) {
669
- console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
670
- }
671
901
  if (isDraftRelationConfirmationOpen) {
672
902
  return {
673
903
  label: formatMessage({
@@ -705,18 +935,18 @@ const BulkLocalePublishAction = ({
705
935
  const hasPermission = selectedRows.map(({ locale }) => locale).every((locale) => canPublish.includes(locale));
706
936
  return {
707
937
  label: formatMessage({
708
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
709
- defaultMessage: "Publish Multiple Locales"
938
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
939
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
710
940
  }),
711
- icon: /* @__PURE__ */ jsx(ListPlus, {}),
712
- disabled: isPublishedTab || canPublish.length === 0,
941
+ variant: isBulkPublish ? "secondary" : "danger",
942
+ icon: isBulkPublish ? /* @__PURE__ */ jsx(ListPlus, {}) : /* @__PURE__ */ jsx(Cross, {}),
943
+ disabled: isOnPublishedTab || canPublish.length === 0,
713
944
  position: ["panel"],
714
- variant: "secondary",
715
945
  dialog: {
716
946
  type: "modal",
717
947
  title: formatMessage({
718
- id: getTranslation("CMEditViewBulkLocale.publish-title"),
719
- defaultMessage: "Publish Multiple Locales"
948
+ id: getTranslation(`CMEditViewBulkLocale.${isBulkPublish ? "publish" : "unpublish"}-title`),
949
+ defaultMessage: `${isBulkPublish ? "Publish" : "Unpublish"} Multiple Locales`
720
950
  }),
721
951
  content: () => {
722
952
  return /* @__PURE__ */ jsx(
@@ -735,28 +965,35 @@ const BulkLocalePublishAction = ({
735
965
  validationErrors,
736
966
  headers,
737
967
  rows,
738
- localesMetadata
968
+ localesMetadata,
969
+ action: action ?? "bulk-publish"
739
970
  }
740
971
  )
741
972
  }
742
973
  );
743
974
  },
744
975
  footer: () => /* @__PURE__ */ jsx(Modal.Footer, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(
745
- Button$1,
976
+ Button,
746
977
  {
747
978
  loading: isDraftRelationsLoading,
748
- disabled: !hasPermission || localesToPublish.length === 0,
979
+ disabled: !hasPermission || localesForAction.length === 0,
749
980
  variant: "default",
750
981
  onClick: handleAction,
751
982
  children: formatMessage({
752
- id: "app.utils.publish",
753
- defaultMessage: "Publish"
983
+ id: isBulkPublish ? "app.utils.publish" : "app.utils.unpublish",
984
+ defaultMessage: isBulkPublish ? "Publish" : "Unpublish"
754
985
  })
755
986
  }
756
987
  ) })
757
988
  }
758
989
  };
759
990
  };
991
+ const BulkLocalePublishAction = (props) => {
992
+ return BulkLocaleAction({ action: "bulk-publish", ...props });
993
+ };
994
+ const BulkLocaleUnpublishAction = (props) => {
995
+ return BulkLocaleAction({ action: "bulk-unpublish", ...props });
996
+ };
760
997
  const StyledTrash = styled(Trash)`
761
998
  path {
762
999
  fill: currentColor;
@@ -976,54 +1213,13 @@ const LocaleListCell = ({
976
1213
  return locale.name;
977
1214
  }).toSorted((a, b) => formatter.compare(a, b));
978
1215
  return /* @__PURE__ */ jsxs(Popover.Root, { children: [
979
- /* @__PURE__ */ jsx(Popover.Trigger, { children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(
980
- ActionWrapper,
981
- {
982
- minWidth: "100%",
983
- alignItems: "center",
984
- justifyContent: "center",
985
- height: "3.2rem",
986
- width: "3.2rem",
987
- children: [
988
- /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", ellipsis: true, children: localesForDocument.join(", ") }),
989
- /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, {}) })
990
- ]
991
- }
992
- ) }) }),
1216
+ /* @__PURE__ */ jsx(Popover.Trigger, { children: /* @__PURE__ */ jsx(Button, { variant: "ghost", type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(Flex, { minWidth: "100%", alignItems: "center", justifyContent: "center", fontWeight: "regular", children: [
1217
+ /* @__PURE__ */ jsx(Typography, { textColor: "neutral800", ellipsis: true, marginRight: 2, children: localesForDocument.join(", ") }),
1218
+ /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, { width: "1.2rem", height: "1.2rem" }) })
1219
+ ] }) }) }),
993
1220
  /* @__PURE__ */ jsx(Popover.Content, { sideOffset: 16, children: /* @__PURE__ */ jsx("ul", { children: localesForDocument.map((name) => /* @__PURE__ */ jsx(Box, { padding: 3, tag: "li", children: /* @__PURE__ */ jsx(Typography, { children: name }) }, name)) }) })
994
1221
  ] });
995
1222
  };
996
- const Button = styled.button`
997
- width: 100%;
998
-
999
- svg {
1000
- > g,
1001
- path {
1002
- fill: ${({ theme }) => theme.colors.neutral500};
1003
- }
1004
- }
1005
- &:hover {
1006
- svg {
1007
- > g,
1008
- path {
1009
- fill: ${({ theme }) => theme.colors.neutral600};
1010
- }
1011
- }
1012
- }
1013
- &:active {
1014
- svg {
1015
- > g,
1016
- path {
1017
- fill: ${({ theme }) => theme.colors.neutral400};
1018
- }
1019
- }
1020
- }
1021
- `;
1022
- const ActionWrapper = styled(Flex)`
1023
- svg {
1024
- height: 0.4rem;
1025
- }
1026
- `;
1027
1223
  const addColumnToTableHook = ({ displayedHeaders, layout }) => {
1028
1224
  const { options } = layout;
1029
1225
  const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options) ? options.i18n.localized : false;
@@ -1221,11 +1417,11 @@ const index = {
1221
1417
  },
1222
1418
  id: "internationalization",
1223
1419
  to: "internationalization",
1224
- Component: () => import("./SettingsPage-CbEn7zF5.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1420
+ Component: () => import("./SettingsPage-BjxjwEOb.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1225
1421
  permissions: PERMISSIONS.accessMain
1226
1422
  });
1227
1423
  const contentManager = app.getPlugin("content-manager");
1228
- contentManager.apis.addDocumentHeaderAction([LocalePickerAction]);
1424
+ contentManager.apis.addDocumentHeaderAction([LocalePickerAction, FillFromAnotherLocaleAction]);
1229
1425
  contentManager.apis.addDocumentAction((actions) => {
1230
1426
  const indexOfDeleteAction = actions.findIndex((action) => action.type === "delete");
1231
1427
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
@@ -1233,6 +1429,7 @@ const index = {
1233
1429
  });
1234
1430
  contentManager.apis.addDocumentAction((actions) => {
1235
1431
  actions.splice(2, 0, BulkLocalePublishAction);
1432
+ actions.splice(5, 0, BulkLocaleUnpublishAction);
1236
1433
  return actions;
1237
1434
  });
1238
1435
  contentManager.injectComponent("listView", "actions", {
@@ -1338,7 +1535,7 @@ const index = {
1338
1535
  async registerTrads({ locales }) {
1339
1536
  const importedTrads = await Promise.all(
1340
1537
  locales.map((locale) => {
1341
- 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-CM6Pjfyv.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`).then(({ default: data }) => {
1538
+ 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-2xztdZE1.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`).then(({ default: data }) => {
1342
1539
  return {
1343
1540
  data: prefixPluginTranslations(data, pluginId),
1344
1541
  locale
@@ -1364,4 +1561,4 @@ export {
1364
1561
  index as i,
1365
1562
  useCreateLocaleMutation as u
1366
1563
  };
1367
- //# sourceMappingURL=index-CkrCiZyq.mjs.map
1564
+ //# sourceMappingURL=index-D-qx3tz4.mjs.map