@strapi/i18n 0.0.0-experimental.17b4116f461a49b8ce5386f7c8d79c511d40fb3b → 0.0.0-experimental.25e22c6cc9bc6b35392bb55d09f641a0a65e7403

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 (29) hide show
  1. package/dist/_chunks/{SettingsPage-CeqfDjsb.mjs → SettingsPage-Dsi2qGtq.mjs} +109 -125
  2. package/dist/_chunks/SettingsPage-Dsi2qGtq.mjs.map +1 -0
  3. package/dist/_chunks/{SettingsPage-Djqsdrzs.js → SettingsPage-VN7sTzkb.js} +109 -125
  4. package/dist/_chunks/SettingsPage-VN7sTzkb.js.map +1 -0
  5. package/dist/_chunks/{en-CnrTsjWS.mjs → en-18tWw4P6.mjs} +4 -1
  6. package/dist/_chunks/en-18tWw4P6.mjs.map +1 -0
  7. package/dist/_chunks/{en-BuBc6LKZ.js → en-Kv6y9zPQ.js} +4 -1
  8. package/dist/_chunks/en-Kv6y9zPQ.js.map +1 -0
  9. package/dist/_chunks/{index-BDU1w_fd.mjs → index-DhtjJYrx.mjs} +445 -131
  10. package/dist/_chunks/index-DhtjJYrx.mjs.map +1 -0
  11. package/dist/_chunks/{index-DMXJeGjN.js → index-kedPlCo6.js} +439 -127
  12. package/dist/_chunks/index-kedPlCo6.js.map +1 -0
  13. package/dist/admin/index.js +1 -1
  14. package/dist/admin/index.mjs +2 -2
  15. package/dist/admin/src/components/BulkLocaleActionModal.d.ts +15 -0
  16. package/dist/admin/src/components/CMHeaderActions.d.ts +7 -1
  17. package/dist/admin/src/components/EditLocale.d.ts +5 -4
  18. package/dist/admin/src/services/api.d.ts +2 -3
  19. package/dist/admin/src/services/locales.d.ts +1 -1
  20. package/dist/admin/src/services/relations.d.ts +7 -0
  21. package/dist/admin/src/utils/baseQuery.d.ts +4 -19
  22. package/dist/shared/contracts/content-manager.d.ts +20 -1
  23. package/package.json +15 -16
  24. package/dist/_chunks/SettingsPage-CeqfDjsb.mjs.map +0 -1
  25. package/dist/_chunks/SettingsPage-Djqsdrzs.js.map +0 -1
  26. package/dist/_chunks/en-BuBc6LKZ.js.map +0 -1
  27. package/dist/_chunks/en-CnrTsjWS.mjs.map +0 -1
  28. package/dist/_chunks/index-BDU1w_fd.mjs.map +0 -1
  29. package/dist/_chunks/index-DMXJeGjN.js.map +0 -1
@@ -1,17 +1,16 @@
1
1
  import get from "lodash/get";
2
2
  import * as yup from "yup";
3
- import { jsxs, Fragment, jsx } from "react/jsx-runtime";
3
+ import { jsxs, jsx } from "react/jsx-runtime";
4
4
  import * as React from "react";
5
- import { Typography, Checkbox, Dialog, DialogBody, Flex, DialogFooter, Button as Button$1, Status, SingleSelect, SingleSelectOption, VisuallyHidden, useCollator, Popover, Box } from "@strapi/design-system";
6
- import { WarningCircle, Trash, Earth, EarthStriked, CaretDown } from "@strapi/icons";
5
+ import { Typography, Dialog, Field, Checkbox, Flex, Button as Button$1, 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";
7
7
  import { useIntl } from "react-intl";
8
- import styled from "styled-components";
9
- import { useAuth, getFetchClient, useQueryParams, useNotification } from "@strapi/admin/strapi-admin";
10
- import { unstable_useDocument, unstable_useDocumentActions } from "@strapi/content-manager/strapi-admin";
11
- import { useParams, useNavigate, matchPath } from "react-router-dom";
12
- import { createApi } from "@reduxjs/toolkit/query/react";
13
- import { isAxiosError } from "axios";
8
+ import { styled } from "styled-components";
9
+ import { useAuth, adminApi, useTable, Table, useQueryParams, useNotification, useAPIErrorHandler } from "@strapi/admin/strapi-admin";
10
+ import { unstable_useDocument, unstable_useDocumentActions, buildValidParams } from "@strapi/content-manager/strapi-admin";
11
+ import { useParams, Link, useNavigate, matchPath } from "react-router-dom";
14
12
  import * as qs from "qs";
13
+ import { stringify } from "qs";
15
14
  import omit from "lodash/omit";
16
15
  const __variableDynamicImportRuntimeHelper = (glob, path) => {
17
16
  const v = glob[path];
@@ -48,9 +47,7 @@ const CheckboxConfirmation = ({
48
47
  };
49
48
  const handleConfirm = () => {
50
49
  onChange({ target: { name, value: false, type: "checkbox" } });
51
- setIsOpen(false);
52
50
  };
53
- const handleToggle = () => setIsOpen((prev) => !prev);
54
51
  const label = intlLabel.id ? formatMessage(
55
52
  { id: intlLabel.id, defaultMessage: intlLabel.defaultMessage },
56
53
  { ...intlLabel.values }
@@ -59,43 +56,36 @@ const CheckboxConfirmation = ({
59
56
  { id: description.id, defaultMessage: description.defaultMessage },
60
57
  { ...description.values }
61
58
  ) : "";
62
- return /* @__PURE__ */ jsxs(Fragment, { children: [
63
- /* @__PURE__ */ jsx(
64
- Checkbox,
65
- {
66
- hint,
67
- id: name,
68
- name,
69
- onValueChange: handleChange,
70
- value,
71
- type: "checkbox",
72
- children: label
73
- }
74
- ),
75
- isOpen && /* @__PURE__ */ jsxs(Dialog, { onClose: handleToggle, title: "Confirmation", isOpen, children: [
76
- /* @__PURE__ */ jsx(DialogBody, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
77
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(TextAlignTypography, { id: "confirm-description", children: formatMessage({
59
+ return /* @__PURE__ */ jsxs(Dialog.Root, { open: isOpen, onOpenChange: setIsOpen, children: [
60
+ /* @__PURE__ */ jsxs(Field.Root, { hint, name, children: [
61
+ /* @__PURE__ */ jsx(Checkbox, { onCheckedChange: handleChange, checked: value, children: label }),
62
+ /* @__PURE__ */ jsx(Field.Hint, {})
63
+ ] }),
64
+ /* @__PURE__ */ jsxs(Dialog.Content, { children: [
65
+ /* @__PURE__ */ jsx(Dialog.Header, { children: formatMessage({
66
+ id: getTranslation("CheckboxConfirmation.Modal.title"),
67
+ defaultMessage: "Disable localization"
68
+ }) }),
69
+ /* @__PURE__ */ jsx(Dialog.Body, { icon: /* @__PURE__ */ jsx(WarningCircle, {}), children: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "stretch", gap: 2, children: [
70
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(TextAlignTypography, { children: formatMessage({
78
71
  id: getTranslation("CheckboxConfirmation.Modal.content"),
79
72
  defaultMessage: "Disabling localization will engender the deletion of all your content but the one associated to your default locale (if existing)."
80
73
  }) }) }),
81
- /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", id: "confirm-description", children: formatMessage({
74
+ /* @__PURE__ */ jsx(Flex, { justifyContent: "center", children: /* @__PURE__ */ jsx(Typography, { fontWeight: "semiBold", children: formatMessage({
82
75
  id: getTranslation("CheckboxConfirmation.Modal.body"),
83
76
  defaultMessage: "Do you want to disable it?"
84
77
  }) }) })
85
78
  ] }) }),
86
- /* @__PURE__ */ jsx(
87
- DialogFooter,
88
- {
89
- startAction: /* @__PURE__ */ jsx(Button$1, { onClick: handleToggle, variant: "tertiary", children: formatMessage({
90
- id: "components.popUpWarning.button.cancel",
91
- defaultMessage: "No, cancel"
92
- }) }),
93
- endAction: /* @__PURE__ */ jsx(Button$1, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
94
- id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
95
- defaultMessage: "Yes, disable"
96
- }) })
97
- }
98
- )
79
+ /* @__PURE__ */ jsxs(Dialog.Footer, { children: [
80
+ /* @__PURE__ */ jsx(Dialog.Cancel, { children: /* @__PURE__ */ jsx(Button$1, { variant: "tertiary", children: formatMessage({
81
+ id: "components.popUpWarning.button.cancel",
82
+ defaultMessage: "No, cancel"
83
+ }) }) }),
84
+ /* @__PURE__ */ jsx(Dialog.Action, { children: /* @__PURE__ */ jsx(Button$1, { variant: "danger-light", onClick: handleConfirm, children: formatMessage({
85
+ id: getTranslation("CheckboxConfirmation.Modal.button-confirm"),
86
+ defaultMessage: "Yes, disable"
87
+ }) }) })
88
+ ] })
99
89
  ] })
100
90
  ] });
101
91
  };
@@ -160,64 +150,8 @@ const useI18n = () => {
160
150
  ...actions
161
151
  };
162
152
  };
163
- const axiosBaseQuery = () => async (query, { signal }) => {
164
- try {
165
- const { get: get2, post, del, put } = getFetchClient();
166
- if (typeof query === "string") {
167
- const result = await get2(query, { signal });
168
- return { data: result.data };
169
- } else {
170
- const { url, method = "GET", data, config } = query;
171
- if (method === "POST") {
172
- const result2 = await post(url, data, { ...config, signal });
173
- return { data: result2.data };
174
- }
175
- if (method === "DELETE") {
176
- const result2 = await del(url, { ...config, signal });
177
- return { data: result2.data };
178
- }
179
- if (method === "PUT") {
180
- const result2 = await put(url, data, { ...config, signal });
181
- return { data: result2.data };
182
- }
183
- const result = await get2(url, { ...config, signal });
184
- return { data: result.data };
185
- }
186
- } catch (err) {
187
- if (isAxiosError(err)) {
188
- if (typeof err.response?.data === "object" && err.response?.data !== null && "error" in err.response?.data) {
189
- return { data: void 0, error: err.response?.data.error };
190
- } else {
191
- return {
192
- data: void 0,
193
- error: {
194
- name: "UnknownError",
195
- message: "There was an unknown error response from the API",
196
- details: err.response?.data,
197
- status: err.response?.status
198
- }
199
- };
200
- }
201
- }
202
- const error = err;
203
- return {
204
- data: void 0,
205
- error: {
206
- name: error.name,
207
- message: error.message,
208
- stack: error.stack
209
- }
210
- };
211
- }
212
- };
213
- const isBaseQueryError = (error) => {
214
- return error.name !== void 0;
215
- };
216
- const i18nApi = createApi({
217
- reducerPath: "i18nApi",
218
- baseQuery: axiosBaseQuery(),
219
- tagTypes: ["Locale"],
220
- endpoints: () => ({})
153
+ const i18nApi = adminApi.enhanceEndpoints({
154
+ addTagTypes: ["Locale"]
221
155
  });
222
156
  const localesApi = i18nApi.injectEndpoints({
223
157
  endpoints: (builder) => ({
@@ -266,6 +200,176 @@ const {
266
200
  useGetDefaultLocalesQuery,
267
201
  useUpdateLocaleMutation
268
202
  } = localesApi;
203
+ const relationsApi = i18nApi.injectEndpoints({
204
+ overrideExisting: true,
205
+ endpoints: (builder) => ({
206
+ getManyDraftRelationCount: builder.query({
207
+ query: ({ model, ...params }) => ({
208
+ url: `/content-manager/collection-types/${model}/actions/countManyEntriesDraftRelations`,
209
+ method: "GET",
210
+ config: {
211
+ params
212
+ }
213
+ }),
214
+ transformResponse: (response) => response.data
215
+ })
216
+ })
217
+ });
218
+ const { useGetManyDraftRelationCountQuery } = relationsApi;
219
+ const isErrorMessageDescriptor = (object) => {
220
+ return typeof object === "object" && object !== null && "id" in object && "defaultMessage" in object;
221
+ };
222
+ const EntryValidationText = ({ status = "draft", validationErrors }) => {
223
+ const { formatMessage } = useIntl();
224
+ const getErrorStr = (key, value) => {
225
+ if (typeof value === "string") {
226
+ return `${key}: ${value}`;
227
+ } else if (isErrorMessageDescriptor(value)) {
228
+ return `${key}: ${formatMessage(value)}`;
229
+ } else if (Array.isArray(value)) {
230
+ return value.map((v) => getErrorStr(key, v)).join(" ");
231
+ } else if (typeof value === "object" && !Array.isArray(value)) {
232
+ return Object.entries(value).map(([k, v]) => getErrorStr(k, v)).join(" ");
233
+ } else {
234
+ return "";
235
+ }
236
+ };
237
+ if (validationErrors) {
238
+ const validationErrorsMessages = Object.entries(validationErrors).map(([key, value]) => {
239
+ return getErrorStr(key, value);
240
+ }).join(" ");
241
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
242
+ /* @__PURE__ */ jsx(CrossCircle, { fill: "danger600" }),
243
+ /* @__PURE__ */ jsx(Tooltip, { label: validationErrorsMessages, children: /* @__PURE__ */ jsx(
244
+ Typography,
245
+ {
246
+ maxWidth: "30rem",
247
+ textColor: "danger600",
248
+ variant: "omega",
249
+ fontWeight: "semiBold",
250
+ ellipsis: true,
251
+ children: validationErrorsMessages
252
+ }
253
+ ) })
254
+ ] });
255
+ }
256
+ if (status === "published") {
257
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
258
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
259
+ /* @__PURE__ */ jsx(Typography, { textColor: "success600", fontWeight: "bold", children: formatMessage({
260
+ id: "content-manager.bulk-publish.already-published",
261
+ defaultMessage: "Already Published"
262
+ }) })
263
+ ] });
264
+ }
265
+ if (status === "modified") {
266
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
267
+ /* @__PURE__ */ jsx(ArrowsCounterClockwise, { fill: "alternative600" }),
268
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
269
+ id: "app.utils.ready-to-publish-changes",
270
+ defaultMessage: "Ready to publish changes"
271
+ }) })
272
+ ] });
273
+ }
274
+ return /* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
275
+ /* @__PURE__ */ jsx(CheckCircle, { fill: "success600" }),
276
+ /* @__PURE__ */ jsx(Typography, { children: formatMessage({
277
+ id: "app.utils.ready-to-publish",
278
+ defaultMessage: "Ready to publish"
279
+ }) })
280
+ ] });
281
+ };
282
+ const BoldChunk = (chunks) => /* @__PURE__ */ jsx(Typography, { fontWeight: "bold", children: chunks });
283
+ const BulkLocaleActionModal = ({
284
+ headers,
285
+ rows,
286
+ localesMetadata,
287
+ validationErrors = {}
288
+ }) => {
289
+ const { formatMessage } = useIntl();
290
+ const selectedRows = useTable(
291
+ "BulkLocaleActionModal",
292
+ (state) => state.selectedRows
293
+ );
294
+ const getFormattedCountMessage = () => {
295
+ const currentStatusByLocale = rows.reduce((acc, { locale, status }) => {
296
+ acc[locale] = status;
297
+ return acc;
298
+ }, {});
299
+ const localesWithErrors = Object.keys(validationErrors);
300
+ const alreadyPublishedCount = selectedRows.filter(
301
+ ({ locale }) => currentStatusByLocale[locale] === "published"
302
+ ).length;
303
+ const readyToPublishCount = selectedRows.filter(
304
+ ({ locale }) => (currentStatusByLocale[locale] === "draft" || currentStatusByLocale[locale] === "modified") && !localesWithErrors.includes(locale)
305
+ ).length;
306
+ const withErrorsCount = localesWithErrors.length;
307
+ return formatMessage(
308
+ {
309
+ id: "content-manager.containers.list.selectedEntriesModal.selectedCount",
310
+ 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."
311
+ },
312
+ {
313
+ withErrorsCount,
314
+ readyToPublishCount,
315
+ alreadyPublishedCount,
316
+ b: BoldChunk
317
+ }
318
+ );
319
+ };
320
+ return /* @__PURE__ */ jsxs(React.Fragment, { children: [
321
+ /* @__PURE__ */ jsx(Typography, { children: getFormattedCountMessage() }),
322
+ /* @__PURE__ */ jsx(Box, { marginTop: 5, children: /* @__PURE__ */ jsxs(Table.Content, { children: [
323
+ /* @__PURE__ */ jsxs(Table.Head, { children: [
324
+ /* @__PURE__ */ jsx(Table.HeaderCheckboxCell, {}),
325
+ headers.map((head) => /* @__PURE__ */ jsx(Table.HeaderCell, { ...head }, head.name))
326
+ ] }),
327
+ /* @__PURE__ */ jsx(Table.Body, { children: rows.map(({ locale, status }, index2) => {
328
+ const error = validationErrors?.[locale] ?? null;
329
+ const statusVariant = status === "draft" ? "primary" : status === "published" ? "success" : "alternative";
330
+ return /* @__PURE__ */ jsxs(Table.Row, { children: [
331
+ /* @__PURE__ */ jsx(Table.CheckboxCell, { id: locale, "aria-label": `Select ${locale}` }),
332
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Typography, { variant: "sigma", textColor: "neutral600", children: Array.isArray(localesMetadata) ? localesMetadata.find((localeEntry) => localeEntry.code === locale)?.name : locale }) }),
333
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(Box, { display: "flex", children: /* @__PURE__ */ jsx(
334
+ Status,
335
+ {
336
+ display: "flex",
337
+ paddingLeft: "6px",
338
+ paddingRight: "6px",
339
+ paddingTop: "2px",
340
+ paddingBottom: "2px",
341
+ showBullet: false,
342
+ size: "S",
343
+ variant: statusVariant,
344
+ children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
345
+ }
346
+ ) }) }),
347
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(EntryValidationText, { validationErrors: error, status }) }),
348
+ /* @__PURE__ */ jsx(Table.Cell, { children: /* @__PURE__ */ jsx(
349
+ IconButton,
350
+ {
351
+ tag: Link,
352
+ to: {
353
+ search: stringify({ plugins: { i18n: { locale } } })
354
+ },
355
+ label: formatMessage(
356
+ {
357
+ id: getTranslation("Settings.list.actions.edit"),
358
+ defaultMessage: "Edit {name} locale"
359
+ },
360
+ {
361
+ name: locale
362
+ }
363
+ ),
364
+ borderWidth: 0,
365
+ children: /* @__PURE__ */ jsx(Pencil, {})
366
+ }
367
+ ) })
368
+ ] }, index2);
369
+ }) })
370
+ ] }) })
371
+ ] });
372
+ };
269
373
  const LocalePickerAction = ({
270
374
  document,
271
375
  meta,
@@ -337,7 +441,7 @@ const LocalePickerAction = ({
337
441
  showBullet: false,
338
442
  size: "S",
339
443
  variant: statusVariant,
340
- children: /* @__PURE__ */ jsx(Typography, { as: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
444
+ children: /* @__PURE__ */ jsx(Typography, { tag: "span", variant: "pi", fontWeight: "bold", children: capitalize(status) })
341
445
  }
342
446
  ) : null
343
447
  };
@@ -388,7 +492,7 @@ const DeleteLocaleAction = ({
388
492
  }),
389
493
  content: /* @__PURE__ */ jsxs(Flex, { direction: "column", gap: 2, children: [
390
494
  /* @__PURE__ */ jsx(WarningCircle, { width: "24px", height: "24px", fill: "danger600" }),
391
- /* @__PURE__ */ jsx(Typography, { as: "p", variant: "omega", textAlign: "center", children: formatMessage({
495
+ /* @__PURE__ */ jsx(Typography, { tag: "p", variant: "omega", textAlign: "center", children: formatMessage({
392
496
  id: getTranslation("actions.delete.dialog.body"),
393
497
  defaultMessage: "Are you sure?"
394
498
  }) })
@@ -420,6 +524,228 @@ const DeleteLocaleAction = ({
420
524
  }
421
525
  };
422
526
  };
527
+ const BulkLocalePublishAction = ({
528
+ document: baseDocument,
529
+ documentId,
530
+ model,
531
+ collectionType
532
+ }) => {
533
+ const baseLocale = baseDocument?.locale ?? null;
534
+ const [{ query }] = useQueryParams();
535
+ const params = React.useMemo(() => buildValidParams(query), [query]);
536
+ const isPublishedTab = query.status === "published";
537
+ const { formatMessage } = useIntl();
538
+ const { hasI18n, canPublish } = useI18n();
539
+ const { toggleNotification } = useNotification();
540
+ const { _unstableFormatAPIError: formatAPIError } = useAPIErrorHandler();
541
+ const [selectedRows, setSelectedRows] = React.useState([]);
542
+ const [isConfirmationOpen, setIsConfirmationOpen] = React.useState(false);
543
+ const { publishMany: publishManyAction } = unstable_useDocumentActions();
544
+ const {
545
+ document,
546
+ meta: documentMeta,
547
+ schema,
548
+ validate
549
+ } = unstable_useDocument({
550
+ model,
551
+ collectionType,
552
+ documentId,
553
+ params: {
554
+ locale: baseLocale
555
+ }
556
+ });
557
+ const { data: localesMetadata = [] } = useGetLocalesQuery();
558
+ const headers = [
559
+ {
560
+ label: formatMessage({
561
+ id: "global.name",
562
+ defaultMessage: "Name"
563
+ }),
564
+ name: "name"
565
+ },
566
+ {
567
+ label: formatMessage({
568
+ id: getTranslation("CMEditViewBulkLocale.status"),
569
+ defaultMessage: "Status"
570
+ }),
571
+ name: "status"
572
+ },
573
+ {
574
+ label: formatMessage({
575
+ id: getTranslation("CMEditViewBulkLocale.publication-status"),
576
+ defaultMessage: "Publication Status"
577
+ }),
578
+ name: "publication-status"
579
+ }
580
+ ];
581
+ const [rows, validationErrors] = React.useMemo(() => {
582
+ if (!document || !documentMeta?.availableLocales) {
583
+ return [[], {}];
584
+ }
585
+ const rowsFromMeta = documentMeta?.availableLocales.map((doc) => {
586
+ const { locale, status } = doc;
587
+ return { locale, status };
588
+ });
589
+ rowsFromMeta.unshift({
590
+ locale: document.locale,
591
+ status: document.status
592
+ });
593
+ const allDocuments = [document, ...documentMeta?.availableLocales ?? []];
594
+ const errors = allDocuments.reduce((errs, document2) => {
595
+ if (!document2) {
596
+ return errs;
597
+ }
598
+ const validation = validate(document2);
599
+ if (validation !== null) {
600
+ errs[document2.locale] = validation;
601
+ }
602
+ return errs;
603
+ }, {});
604
+ return [rowsFromMeta, errors];
605
+ }, [document, documentMeta?.availableLocales, validate]);
606
+ const localesToPublish = selectedRows.reduce((acc, selectedRow) => {
607
+ if (selectedRow.status !== "published" && !Object.keys(validationErrors).includes(selectedRow.locale)) {
608
+ acc.push(selectedRow.locale);
609
+ }
610
+ return acc;
611
+ }, []);
612
+ const {
613
+ data: draftRelationsCount = 0,
614
+ isLoading: isDraftRelationsLoading,
615
+ error: isDraftRelationsError
616
+ } = useGetManyDraftRelationCountQuery(
617
+ {
618
+ model,
619
+ documentIds: [documentId],
620
+ locale: localesToPublish
621
+ },
622
+ {
623
+ skip: !documentId || localesToPublish.length === 0
624
+ }
625
+ );
626
+ React.useEffect(() => {
627
+ if (isDraftRelationsError) {
628
+ toggleNotification({
629
+ type: "danger",
630
+ message: formatAPIError(isDraftRelationsError)
631
+ });
632
+ }
633
+ }, [isDraftRelationsError, toggleNotification, formatAPIError]);
634
+ if (!schema?.options?.draftAndPublish) {
635
+ return null;
636
+ }
637
+ if (!hasI18n) {
638
+ return null;
639
+ }
640
+ if (!documentId) {
641
+ return null;
642
+ }
643
+ const publish = async () => {
644
+ await publishManyAction({
645
+ model,
646
+ documentIds: [documentId],
647
+ params: {
648
+ ...params,
649
+ locale: localesToPublish
650
+ }
651
+ });
652
+ setSelectedRows([]);
653
+ };
654
+ const handleAction = async () => {
655
+ if (draftRelationsCount > 0) {
656
+ setIsConfirmationOpen(true);
657
+ } else {
658
+ await publish();
659
+ }
660
+ };
661
+ const isUnpublish = document?.status === "published";
662
+ if (isUnpublish) {
663
+ console.warn(["I18N"], "Bulk locale unpublish modal not implemented");
664
+ }
665
+ if (isConfirmationOpen) {
666
+ return {
667
+ label: formatMessage({
668
+ id: "app.components.ConfirmDialog.title",
669
+ defaultMessage: "Confirmation"
670
+ }),
671
+ variant: "danger",
672
+ dialog: {
673
+ onCancel: () => {
674
+ setIsConfirmationOpen(false);
675
+ },
676
+ onConfirm: async () => {
677
+ await publish();
678
+ setIsConfirmationOpen(false);
679
+ },
680
+ type: "dialog",
681
+ title: formatMessage({
682
+ id: getTranslation("actions.publish.dialog.title"),
683
+ defaultMessage: "Confirmation"
684
+ }),
685
+ content: /* @__PURE__ */ jsxs(Flex, { direction: "column", alignItems: "center", gap: 2, children: [
686
+ /* @__PURE__ */ jsx(WarningCircle, { width: "2.4rem", height: "2.4rem", fill: "danger600" }),
687
+ /* @__PURE__ */ jsx(Typography, { textAlign: "center", children: formatMessage({
688
+ id: "content-manager.actions.discard.dialog.body",
689
+ defaultMessage: "Are you sure you want to discard the changes? This action is irreversible."
690
+ }) })
691
+ ] })
692
+ }
693
+ };
694
+ }
695
+ return {
696
+ label: formatMessage({
697
+ id: getTranslation("CMEditViewBulkLocale.publish-title"),
698
+ defaultMessage: "Publish Multiple Locales"
699
+ }),
700
+ icon: /* @__PURE__ */ jsx(ListPlus, {}),
701
+ disabled: isPublishedTab || !canPublish,
702
+ position: ["panel"],
703
+ variant: "secondary",
704
+ dialog: {
705
+ type: "modal",
706
+ title: formatMessage({
707
+ id: getTranslation("CMEditViewBulkLocale.publish-title"),
708
+ defaultMessage: "Publish Multiple Locales"
709
+ }),
710
+ content: () => {
711
+ return /* @__PURE__ */ jsx(
712
+ Table.Root,
713
+ {
714
+ headers,
715
+ rows: rows.map((row) => ({
716
+ ...row,
717
+ id: row.locale
718
+ })),
719
+ selectedRows,
720
+ onSelectedRowsChange: (tableSelectedRows) => setSelectedRows(tableSelectedRows),
721
+ children: /* @__PURE__ */ jsx(
722
+ BulkLocaleActionModal,
723
+ {
724
+ validationErrors,
725
+ headers,
726
+ rows,
727
+ localesMetadata
728
+ }
729
+ )
730
+ }
731
+ );
732
+ },
733
+ footer: () => /* @__PURE__ */ jsx(Flex, { justifyContent: "flex-end", children: /* @__PURE__ */ jsx(
734
+ Button$1,
735
+ {
736
+ loading: isDraftRelationsLoading,
737
+ disabled: localesToPublish.length === 0,
738
+ variant: "default",
739
+ onClick: handleAction,
740
+ children: formatMessage({
741
+ id: "app.utils.publish",
742
+ defaultMessage: "Publish"
743
+ })
744
+ }
745
+ ) })
746
+ }
747
+ };
748
+ };
423
749
  const StyledTrash = styled(Trash)`
424
750
  path {
425
751
  fill: currentColor;
@@ -542,7 +868,7 @@ const PERMISSIONS = {
542
868
  read: [{ action: "plugin::i18n.locale.read", subject: null }]
543
869
  };
544
870
  const mutateEditViewHook = ({ layout }) => {
545
- if ("i18n" in layout.options && typeof layout.options.i18n === "object" && layout.options.i18n !== null && "localized" in layout.options.i18n && !layout.options.i18n.localized) {
871
+ if (!("i18n" in layout.options) || typeof layout.options.i18n === "object" && layout.options.i18n !== null && "localized" in layout.options.i18n && !layout.options.i18n.localized) {
546
872
  return { layout };
547
873
  }
548
874
  const components = Object.entries(layout.components).reduce(
@@ -587,8 +913,8 @@ const doesFieldHaveI18nPluginOpt = (pluginOpts) => {
587
913
  };
588
914
  const LabelAction = ({ title, icon }) => {
589
915
  const { formatMessage } = useIntl();
590
- return /* @__PURE__ */ jsxs(Span, { as: "span", children: [
591
- /* @__PURE__ */ jsx(VisuallyHidden, { as: "span", children: `(${formatMessage(title)})` }),
916
+ return /* @__PURE__ */ jsxs(Span, { tag: "span", children: [
917
+ /* @__PURE__ */ jsx(VisuallyHidden, { tag: "span", children: formatMessage(title) }),
592
918
  React.cloneElement(icon, {
593
919
  "aria-hidden": true,
594
920
  focusable: false
@@ -623,13 +949,7 @@ const LocaleListCell = ({
623
949
  }
624
950
  });
625
951
  const { locale: language } = useIntl();
626
- const [visible, setVisible] = React.useState(false);
627
- const buttonRef = React.useRef(null);
628
952
  const { data: locales = [] } = useGetLocalesQuery();
629
- const handleTogglePopover = (e) => {
630
- e.stopPropagation();
631
- setVisible((prev) => !prev);
632
- };
633
953
  const formatter = useCollator(language, {
634
954
  sensitivity: "base"
635
955
  });
@@ -651,8 +971,8 @@ const LocaleListCell = ({
651
971
  }
652
972
  return locale.name;
653
973
  }).toSorted((a, b) => formatter.compare(a, b));
654
- return /* @__PURE__ */ jsxs(Button, { type: "button", onClick: handleTogglePopover, ref: buttonRef, children: [
655
- /* @__PURE__ */ jsxs(
974
+ return /* @__PURE__ */ jsxs(Popover.Root, { children: [
975
+ /* @__PURE__ */ jsx(Popover.Trigger, { children: /* @__PURE__ */ jsx(Button, { type: "button", onClick: (e) => e.stopPropagation(), children: /* @__PURE__ */ jsxs(
656
976
  ActionWrapper,
657
977
  {
658
978
  minWidth: "100%",
@@ -665,17 +985,8 @@ const LocaleListCell = ({
665
985
  /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(CaretDown, {}) })
666
986
  ]
667
987
  }
668
- ),
669
- visible && /* @__PURE__ */ jsx(
670
- Popover,
671
- {
672
- onDismiss: () => setVisible(false),
673
- source: buttonRef,
674
- spacing: 16,
675
- centered: true,
676
- children: /* @__PURE__ */ jsx("ul", { children: localesForDocument.map((name) => /* @__PURE__ */ jsx(Box, { padding: 3, as: "li", children: /* @__PURE__ */ jsx(Typography, { children: name }) }, name)) })
677
- }
678
- )
988
+ ) }) }),
989
+ /* @__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)) }) })
679
990
  ] });
680
991
  };
681
992
  const Button = styled.button`
@@ -915,7 +1226,7 @@ const index = {
915
1226
  },
916
1227
  id: "internationalization",
917
1228
  to: "internationalization",
918
- Component: () => import("./SettingsPage-CeqfDjsb.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
1229
+ Component: () => import("./SettingsPage-Dsi2qGtq.mjs").then((mod) => ({ default: mod.ProtectedSettingsPage })),
919
1230
  permissions: PERMISSIONS.accessMain
920
1231
  });
921
1232
  const contentManager = app.getPlugin("content-manager");
@@ -925,6 +1236,10 @@ const index = {
925
1236
  actions.splice(indexOfDeleteAction, 0, DeleteLocaleAction);
926
1237
  return actions;
927
1238
  });
1239
+ contentManager.apis.addDocumentAction((actions) => {
1240
+ actions.splice(2, 0, BulkLocalePublishAction);
1241
+ return actions;
1242
+ });
928
1243
  contentManager.injectComponent("listView", "actions", {
929
1244
  name: "i18n-locale-filter",
930
1245
  Component: LocalePicker
@@ -1028,7 +1343,7 @@ const index = {
1028
1343
  async registerTrads({ locales }) {
1029
1344
  const importedTrads = await Promise.all(
1030
1345
  locales.map((locale) => {
1031
- 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-CnrTsjWS.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 }) => {
1346
+ 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-18tWw4P6.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 }) => {
1032
1347
  return {
1033
1348
  data: prefixPluginTranslations(data, pluginId),
1034
1349
  locale
@@ -1047,12 +1362,11 @@ const index = {
1047
1362
  export {
1048
1363
  PERMISSIONS as P,
1049
1364
  useGetDefaultLocalesQuery as a,
1050
- useGetLocalesQuery as b,
1051
- useDeleteLocaleMutation as c,
1052
- useUpdateLocaleMutation as d,
1053
- index as e,
1365
+ useDeleteLocaleMutation as b,
1366
+ useUpdateLocaleMutation as c,
1367
+ useGetLocalesQuery as d,
1054
1368
  getTranslation as g,
1055
- isBaseQueryError as i,
1369
+ index as i,
1056
1370
  useCreateLocaleMutation as u
1057
1371
  };
1058
- //# sourceMappingURL=index-BDU1w_fd.mjs.map
1372
+ //# sourceMappingURL=index-DhtjJYrx.mjs.map