@strapi/i18n 0.0.0-next.e1a19b9e52cdcb526515883c8289522a64c9871a → 0.0.0-next.e2e3ca14971ee768e1a227a209362264fd0132d4

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 (167) hide show
  1. package/dist/admin/components/BulkLocaleActionModal.js +2 -2
  2. package/dist/admin/components/BulkLocaleActionModal.js.map +1 -1
  3. package/dist/admin/components/BulkLocaleActionModal.mjs +2 -2
  4. package/dist/admin/components/BulkLocaleActionModal.mjs.map +1 -1
  5. package/dist/admin/components/CMHeaderActions.js +294 -20
  6. package/dist/admin/components/CMHeaderActions.js.map +1 -1
  7. package/dist/admin/components/CMHeaderActions.mjs +298 -25
  8. package/dist/admin/components/CMHeaderActions.mjs.map +1 -1
  9. package/dist/admin/components/CreateLocale.js +11 -5
  10. package/dist/admin/components/CreateLocale.js.map +1 -1
  11. package/dist/admin/components/CreateLocale.mjs +12 -6
  12. package/dist/admin/components/CreateLocale.mjs.map +1 -1
  13. package/dist/admin/components/LocaleListCell.js +65 -45
  14. package/dist/admin/components/LocaleListCell.js.map +1 -1
  15. package/dist/admin/components/LocaleListCell.mjs +66 -46
  16. package/dist/admin/components/LocaleListCell.mjs.map +1 -1
  17. package/dist/admin/components/LocalePicker.js +18 -11
  18. package/dist/admin/components/LocalePicker.js.map +1 -1
  19. package/dist/admin/components/LocalePicker.mjs +19 -12
  20. package/dist/admin/components/LocalePicker.mjs.map +1 -1
  21. package/dist/admin/contentManagerHooks/editView.js +6 -3
  22. package/dist/admin/contentManagerHooks/editView.js.map +1 -1
  23. package/dist/admin/contentManagerHooks/editView.mjs +7 -4
  24. package/dist/admin/contentManagerHooks/editView.mjs.map +1 -1
  25. package/dist/admin/contentManagerHooks/listView.js +2 -1
  26. package/dist/admin/contentManagerHooks/listView.js.map +1 -1
  27. package/dist/admin/contentManagerHooks/listView.mjs +2 -1
  28. package/dist/admin/contentManagerHooks/listView.mjs.map +1 -1
  29. package/dist/admin/hooks/useAILocalizationJobsPolling.js +110 -0
  30. package/dist/admin/hooks/useAILocalizationJobsPolling.js.map +1 -0
  31. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs +89 -0
  32. package/dist/admin/hooks/useAILocalizationJobsPolling.mjs.map +1 -0
  33. package/dist/admin/hooks/useI18n.js +4 -4
  34. package/dist/admin/hooks/useI18n.js.map +1 -1
  35. package/dist/admin/hooks/useI18n.mjs +4 -4
  36. package/dist/admin/hooks/useI18n.mjs.map +1 -1
  37. package/dist/admin/index.js +1 -0
  38. package/dist/admin/index.js.map +1 -1
  39. package/dist/admin/index.mjs +2 -1
  40. package/dist/admin/index.mjs.map +1 -1
  41. package/dist/admin/pages/SettingsPage.js +121 -46
  42. package/dist/admin/pages/SettingsPage.js.map +1 -1
  43. package/dist/admin/pages/SettingsPage.mjs +124 -30
  44. package/dist/admin/pages/SettingsPage.mjs.map +1 -1
  45. package/dist/admin/services/aiLocalizationJobs.js +26 -0
  46. package/dist/admin/services/aiLocalizationJobs.js.map +1 -0
  47. package/dist/admin/services/aiLocalizationJobs.mjs +24 -0
  48. package/dist/admin/services/aiLocalizationJobs.mjs.map +1 -0
  49. package/dist/admin/services/api.js +3 -1
  50. package/dist/admin/services/api.js.map +1 -1
  51. package/dist/admin/services/api.mjs +3 -1
  52. package/dist/admin/services/api.mjs.map +1 -1
  53. package/dist/admin/services/locales.js.map +1 -1
  54. package/dist/admin/services/locales.mjs.map +1 -1
  55. package/dist/admin/services/settings.js +30 -0
  56. package/dist/admin/services/settings.js.map +1 -0
  57. package/dist/admin/services/settings.mjs +27 -0
  58. package/dist/admin/services/settings.mjs.map +1 -0
  59. package/dist/admin/src/components/CMHeaderActions.d.ts +17 -4
  60. package/dist/admin/src/components/LocaleListCell.d.ts +2 -1
  61. package/dist/admin/src/hooks/useAILocalizationJobsPolling.d.ts +9 -0
  62. package/dist/admin/src/services/aiLocalizationJobs.d.ts +6 -0
  63. package/dist/admin/src/services/api.d.ts +1 -1
  64. package/dist/admin/src/services/locales.d.ts +1 -1
  65. package/dist/admin/src/services/relations.d.ts +1 -1
  66. package/dist/admin/src/services/settings.d.ts +5 -0
  67. package/dist/admin/translations/en.json.js +10 -0
  68. package/dist/admin/translations/en.json.js.map +1 -1
  69. package/dist/admin/translations/en.json.mjs +10 -0
  70. package/dist/admin/translations/en.json.mjs.map +1 -1
  71. package/dist/admin/utils/clean.js +2 -2
  72. package/dist/admin/utils/clean.js.map +1 -1
  73. package/dist/admin/utils/clean.mjs +2 -2
  74. package/dist/admin/utils/clean.mjs.map +1 -1
  75. package/dist/admin/utils/getTranslation.js.map +1 -1
  76. package/dist/admin/utils/getTranslation.mjs.map +1 -1
  77. package/dist/admin/utils/prefixPluginTranslations.js.map +1 -1
  78. package/dist/admin/utils/prefixPluginTranslations.mjs.map +1 -1
  79. package/dist/server/bootstrap.js +24 -8
  80. package/dist/server/bootstrap.js.map +1 -1
  81. package/dist/server/bootstrap.mjs +24 -8
  82. package/dist/server/bootstrap.mjs.map +1 -1
  83. package/dist/server/constants/iso-locales.json.js +4 -0
  84. package/dist/server/constants/iso-locales.json.js.map +1 -1
  85. package/dist/server/constants/iso-locales.json.mjs +4 -0
  86. package/dist/server/constants/iso-locales.json.mjs.map +1 -1
  87. package/dist/server/controllers/ai-localization-jobs.js +47 -0
  88. package/dist/server/controllers/ai-localization-jobs.js.map +1 -0
  89. package/dist/server/controllers/ai-localization-jobs.mjs +45 -0
  90. package/dist/server/controllers/ai-localization-jobs.mjs.map +1 -0
  91. package/dist/server/controllers/index.js +5 -1
  92. package/dist/server/controllers/index.js.map +1 -1
  93. package/dist/server/controllers/index.mjs +5 -1
  94. package/dist/server/controllers/index.mjs.map +1 -1
  95. package/dist/server/controllers/settings.js +24 -0
  96. package/dist/server/controllers/settings.js.map +1 -0
  97. package/dist/server/controllers/settings.mjs +22 -0
  98. package/dist/server/controllers/settings.mjs.map +1 -0
  99. package/dist/server/models/ai-localization-job.js +60 -0
  100. package/dist/server/models/ai-localization-job.js.map +1 -0
  101. package/dist/server/models/ai-localization-job.mjs +57 -0
  102. package/dist/server/models/ai-localization-job.mjs.map +1 -0
  103. package/dist/server/register.js +3 -1
  104. package/dist/server/register.js.map +1 -1
  105. package/dist/server/register.mjs +3 -1
  106. package/dist/server/register.mjs.map +1 -1
  107. package/dist/server/routes/admin.js +40 -0
  108. package/dist/server/routes/admin.js.map +1 -1
  109. package/dist/server/routes/admin.mjs +40 -0
  110. package/dist/server/routes/admin.mjs.map +1 -1
  111. package/dist/server/services/ai-localization-jobs.js +64 -0
  112. package/dist/server/services/ai-localization-jobs.js.map +1 -0
  113. package/dist/server/services/ai-localization-jobs.mjs +62 -0
  114. package/dist/server/services/ai-localization-jobs.mjs.map +1 -0
  115. package/dist/server/services/ai-localizations.js +268 -0
  116. package/dist/server/services/ai-localizations.js.map +1 -0
  117. package/dist/server/services/ai-localizations.mjs +266 -0
  118. package/dist/server/services/ai-localizations.mjs.map +1 -0
  119. package/dist/server/services/content-types.js.map +1 -1
  120. package/dist/server/services/content-types.mjs.map +1 -1
  121. package/dist/server/services/index.js +7 -1
  122. package/dist/server/services/index.js.map +1 -1
  123. package/dist/server/services/index.mjs +7 -1
  124. package/dist/server/services/index.mjs.map +1 -1
  125. package/dist/server/services/settings.js +25 -0
  126. package/dist/server/services/settings.js.map +1 -0
  127. package/dist/server/services/settings.mjs +23 -0
  128. package/dist/server/services/settings.mjs.map +1 -0
  129. package/dist/server/src/bootstrap.d.ts.map +1 -1
  130. package/dist/server/src/controllers/ai-localization-jobs.d.ts +17 -0
  131. package/dist/server/src/controllers/ai-localization-jobs.d.ts.map +1 -0
  132. package/dist/server/src/controllers/index.d.ts +10 -0
  133. package/dist/server/src/controllers/index.d.ts.map +1 -1
  134. package/dist/server/src/controllers/settings.d.ts +7 -0
  135. package/dist/server/src/controllers/settings.d.ts.map +1 -0
  136. package/dist/server/src/index.d.ts +44 -1
  137. package/dist/server/src/index.d.ts.map +1 -1
  138. package/dist/server/src/models/ai-localization-job.d.ts +5 -0
  139. package/dist/server/src/models/ai-localization-job.d.ts.map +1 -0
  140. package/dist/server/src/models/index.d.ts +5 -0
  141. package/dist/server/src/models/index.d.ts.map +1 -0
  142. package/dist/server/src/register.d.ts +1 -1
  143. package/dist/server/src/register.d.ts.map +1 -1
  144. package/dist/server/src/routes/admin.d.ts.map +1 -1
  145. package/dist/server/src/services/ai-localization-jobs.d.ts +26 -0
  146. package/dist/server/src/services/ai-localization-jobs.d.ts.map +1 -0
  147. package/dist/server/src/services/ai-localizations.d.ts +18 -0
  148. package/dist/server/src/services/ai-localizations.d.ts.map +1 -0
  149. package/dist/server/src/services/index.d.ts +33 -0
  150. package/dist/server/src/services/index.d.ts.map +1 -1
  151. package/dist/server/src/services/settings.d.ts +13 -0
  152. package/dist/server/src/services/settings.d.ts.map +1 -0
  153. package/dist/server/src/utils/index.d.ts +7 -1
  154. package/dist/server/src/utils/index.d.ts.map +1 -1
  155. package/dist/server/src/validation/settings.d.ts +12 -0
  156. package/dist/server/src/validation/settings.d.ts.map +1 -0
  157. package/dist/server/utils/index.js.map +1 -1
  158. package/dist/server/utils/index.mjs.map +1 -1
  159. package/dist/server/validation/settings.js +11 -0
  160. package/dist/server/validation/settings.js.map +1 -0
  161. package/dist/server/validation/settings.mjs +9 -0
  162. package/dist/server/validation/settings.mjs.map +1 -0
  163. package/dist/shared/contracts/ai-localization-jobs.d.ts +27 -0
  164. package/dist/shared/contracts/ai-localization-jobs.d.ts.map +1 -0
  165. package/dist/shared/contracts/settings.d.ts +40 -0
  166. package/dist/shared/contracts/shared.d.ts.map +1 -0
  167. package/package.json +11 -9
@@ -1,7 +1,7 @@
1
1
  import { jsx } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { useQueryParams } from '@strapi/admin/strapi-admin';
4
- import { SingleSelect, SingleSelectOption } from '@strapi/design-system';
4
+ import { SingleSelectOption, SingleSelect } from '@strapi/design-system';
5
5
  import { useIntl } from 'react-intl';
6
6
  import { useI18n } from '../hooks/useI18n.mjs';
7
7
  import { useGetLocalesQuery } from '../services/locales.mjs';
@@ -47,16 +47,26 @@ const LocalePicker = ()=>{
47
47
  locales,
48
48
  query.plugins?.i18n?.locale
49
49
  ]);
50
+ const sortedLocaleOptions = React.useMemo(()=>{
51
+ const displayedLocales = Array.isArray(locales) ? locales.filter((locale)=>{
52
+ /**
53
+ * If you can create or read we allow you to see the locale exists
54
+ * this is because in the ListView, you may be able to create a new entry
55
+ * in a locale you can't read.
56
+ */ return canCreate.includes(locale.code) || canRead.includes(locale.code);
57
+ }) : [];
58
+ return displayedLocales.sort((a, b)=>a.name.localeCompare(b.name)).map((locale)=>/*#__PURE__*/ jsx(SingleSelectOption, {
59
+ value: locale.code,
60
+ children: locale.name
61
+ }, locale.id));
62
+ }, [
63
+ locales,
64
+ canCreate,
65
+ canRead
66
+ ]);
50
67
  if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {
51
68
  return null;
52
69
  }
53
- const displayedLocales = locales.filter((locale)=>{
54
- /**
55
- * If you can create or read we allow you to see the locale exists
56
- * this is because in the ListView, you may be able to create a new entry
57
- * in a locale you can't read.
58
- */ return canCreate.includes(locale.code) || canRead.includes(locale.code);
59
- });
60
70
  return /*#__PURE__*/ jsx(SingleSelect, {
61
71
  size: "S",
62
72
  "aria-label": formatMessage({
@@ -66,10 +76,7 @@ const LocalePicker = ()=>{
66
76
  value: query.plugins?.i18n?.locale || locales.find((locale)=>locale.isDefault)?.code,
67
77
  // @ts-expect-error – This can be removed in V2 of the DS.
68
78
  onChange: handleChange,
69
- children: displayedLocales.map((locale)=>/*#__PURE__*/ jsx(SingleSelectOption, {
70
- value: locale.code,
71
- children: locale.name
72
- }, locale.id))
79
+ children: sortedLocaleOptions
73
80
  });
74
81
  };
75
82
 
@@ -1 +1 @@
1
- {"version":3,"file":"LocalePicker.mjs","sources":["../../../admin/src/components/LocalePicker.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useQueryParams } from '@strapi/admin/strapi-admin';\nimport { SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { useI18n } from '../hooks/useI18n';\nimport { useGetLocalesQuery } from '../services/locales';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { I18nBaseQuery } from '../types';\n\ninterface Query extends I18nBaseQuery {\n page?: number;\n}\n\nconst LocalePicker = () => {\n const { formatMessage } = useIntl();\n const [{ query }, setQuery] = useQueryParams<Query>();\n\n const { hasI18n, canRead, canCreate } = useI18n();\n const { data: locales = [] } = useGetLocalesQuery(undefined, {\n skip: !hasI18n,\n });\n\n const handleChange = React.useCallback(\n (code: string, replace = false) => {\n setQuery(\n {\n page: 1,\n plugins: { ...query.plugins, i18n: { locale: code } },\n },\n 'push',\n replace\n );\n },\n [query.plugins, setQuery]\n );\n\n React.useEffect(() => {\n if (!Array.isArray(locales) || !hasI18n) {\n return;\n }\n /**\n * Handle the case where the current locale query param doesn't exist\n * in the list of available locales, so we redirect to the default locale.\n */\n const currentDesiredLocale = query.plugins?.i18n?.locale;\n const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);\n const defaultLocale = locales.find((locale) => locale.isDefault);\n if (!doesLocaleExist && defaultLocale?.code) {\n handleChange(defaultLocale.code, true);\n }\n }, [hasI18n, handleChange, locales, query.plugins?.i18n?.locale]);\n\n if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {\n return null;\n }\n\n const displayedLocales = locales.filter((locale) => {\n /**\n * If you can create or read we allow you to see the locale exists\n * this is because in the ListView, you may be able to create a new entry\n * in a locale you can't read.\n */\n return canCreate.includes(locale.code) || canRead.includes(locale.code);\n });\n\n return (\n <SingleSelect\n size=\"S\"\n aria-label={formatMessage({\n id: getTranslation('actions.select-locale'),\n defaultMessage: 'Select locale',\n })}\n value={query.plugins?.i18n?.locale || locales.find((locale) => locale.isDefault)?.code}\n // @ts-expect-error – This can be removed in V2 of the DS.\n onChange={handleChange}\n >\n {displayedLocales.map((locale) => (\n <SingleSelectOption key={locale.id} value={locale.code}>\n {locale.name}\n </SingleSelectOption>\n ))}\n </SingleSelect>\n );\n};\n\nexport { LocalePicker };\n"],"names":["LocalePicker","formatMessage","useIntl","query","setQuery","useQueryParams","hasI18n","canRead","canCreate","useI18n","data","locales","useGetLocalesQuery","undefined","skip","handleChange","React","useCallback","code","replace","page","plugins","i18n","locale","useEffect","Array","isArray","currentDesiredLocale","doesLocaleExist","find","loc","defaultLocale","isDefault","length","displayedLocales","filter","includes","_jsx","SingleSelect","size","aria-label","id","getTranslation","defaultMessage","value","onChange","map","SingleSelectOption","name"],"mappings":"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"}
1
+ {"version":3,"file":"LocalePicker.mjs","sources":["../../../admin/src/components/LocalePicker.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { useQueryParams } from '@strapi/admin/strapi-admin';\nimport { SingleSelect, SingleSelectOption } from '@strapi/design-system';\nimport { useIntl } from 'react-intl';\n\nimport { useI18n } from '../hooks/useI18n';\nimport { useGetLocalesQuery } from '../services/locales';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { I18nBaseQuery } from '../types';\n\ninterface Query extends I18nBaseQuery {\n page?: number;\n}\n\nconst LocalePicker = () => {\n const { formatMessage } = useIntl();\n const [{ query }, setQuery] = useQueryParams<Query>();\n\n const { hasI18n, canRead, canCreate } = useI18n();\n const { data: locales = [] } = useGetLocalesQuery(undefined, {\n skip: !hasI18n,\n });\n\n const handleChange = React.useCallback(\n (code: string, replace = false) => {\n setQuery(\n {\n page: 1,\n plugins: { ...query.plugins, i18n: { locale: code } },\n },\n 'push',\n replace\n );\n },\n [query.plugins, setQuery]\n );\n\n React.useEffect(() => {\n if (!Array.isArray(locales) || !hasI18n) {\n return;\n }\n /**\n * Handle the case where the current locale query param doesn't exist\n * in the list of available locales, so we redirect to the default locale.\n */\n const currentDesiredLocale = query.plugins?.i18n?.locale;\n const doesLocaleExist = locales.find((loc) => loc.code === currentDesiredLocale);\n const defaultLocale = locales.find((locale) => locale.isDefault);\n if (!doesLocaleExist && defaultLocale?.code) {\n handleChange(defaultLocale.code, true);\n }\n }, [hasI18n, handleChange, locales, query.plugins?.i18n?.locale]);\n\n const sortedLocaleOptions = React.useMemo(() => {\n const displayedLocales = Array.isArray(locales)\n ? locales.filter((locale) => {\n /**\n * If you can create or read we allow you to see the locale exists\n * this is because in the ListView, you may be able to create a new entry\n * in a locale you can't read.\n */\n return canCreate.includes(locale.code) || canRead.includes(locale.code);\n })\n : [];\n\n return displayedLocales\n .sort((a, b) => a.name.localeCompare(b.name))\n .map((locale) => (\n <SingleSelectOption key={locale.id} value={locale.code}>\n {locale.name}\n </SingleSelectOption>\n ));\n }, [locales, canCreate, canRead]);\n\n if (!hasI18n || !Array.isArray(locales) || locales.length === 0) {\n return null;\n }\n\n return (\n <SingleSelect\n size=\"S\"\n aria-label={formatMessage({\n id: getTranslation('actions.select-locale'),\n defaultMessage: 'Select locale',\n })}\n value={query.plugins?.i18n?.locale || locales.find((locale) => locale.isDefault)?.code}\n // @ts-expect-error – This can be removed in V2 of the DS.\n onChange={handleChange}\n >\n {sortedLocaleOptions}\n </SingleSelect>\n );\n};\n\nexport { LocalePicker };\n"],"names":["LocalePicker","formatMessage","useIntl","query","setQuery","useQueryParams","hasI18n","canRead","canCreate","useI18n","data","locales","useGetLocalesQuery","undefined","skip","handleChange","React","useCallback","code","replace","page","plugins","i18n","locale","useEffect","Array","isArray","currentDesiredLocale","doesLocaleExist","find","loc","defaultLocale","isDefault","sortedLocaleOptions","useMemo","displayedLocales","filter","includes","sort","a","b","name","localeCompare","map","_jsx","SingleSelectOption","value","id","length","SingleSelect","size","aria-label","getTranslation","defaultMessage","onChange"],"mappings":"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"}
@@ -82,9 +82,12 @@ const LabelAction = ({ title, icon })=>{
82
82
  tag: "span",
83
83
  children: formatMessage(title)
84
84
  }),
85
- /*#__PURE__*/ React__namespace.cloneElement(icon, {
86
- 'aria-hidden': true,
87
- focusable: false
85
+ /*#__PURE__*/ jsxRuntime.jsx(designSystem.Tooltip, {
86
+ label: formatMessage(title),
87
+ children: /*#__PURE__*/ React__namespace.cloneElement(icon, {
88
+ 'aria-hidden': true,
89
+ focusable: false
90
+ })
88
91
  })
89
92
  ]
90
93
  });
@@ -1 +1 @@
1
- {"version":3,"file":"editView.js","sources":["../../../admin/src/contentManagerHooks/editView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport * as React from 'react';\n\nimport { Flex, VisuallyHidden } from '@strapi/design-system';\nimport { Earth, EarthStriked } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { EditFieldLayout, EditLayout } from '@strapi/content-manager/strapi-admin';\n\ninterface MutateEditViewArgs {\n layout: EditLayout;\n}\n\nconst mutateEditViewHook = ({ layout }: MutateEditViewArgs): MutateEditViewArgs => {\n // If i18n isn't explicitly enabled on the content type, then no field can be localized\n if (\n !('i18n' in layout.options) ||\n (typeof layout.options.i18n === 'object' &&\n layout.options.i18n !== null &&\n 'localized' in layout.options.i18n &&\n !layout.options.i18n.localized)\n ) {\n return { layout };\n }\n\n const components = Object.entries(layout.components).reduce<EditLayout['components']>(\n (acc, [key, componentLayout]) => {\n return {\n ...acc,\n [key]: {\n ...componentLayout,\n layout: componentLayout.layout.map((row) => row.map(addLabelActionToField)),\n },\n };\n },\n {}\n );\n\n return {\n layout: {\n ...layout,\n components,\n layout: layout.layout.map((panel) => panel.map((row) => row.map(addLabelActionToField))),\n },\n } satisfies Pick<MutateEditViewArgs, 'layout'>;\n};\n\nconst addLabelActionToField = (field: EditFieldLayout) => {\n const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions)\n ? field.attribute.pluginOptions.i18n.localized\n : true || ['uid', 'relation'].includes(field.attribute.type);\n\n const labelActionProps = {\n title: {\n id: isFieldLocalized\n ? getTranslation('Field.localized')\n : getTranslation('Field.not-localized'),\n defaultMessage: isFieldLocalized\n ? 'This value is unique for the selected locale'\n : 'This value is the same across all locales',\n },\n icon: isFieldLocalized ? <Earth /> : null,\n };\n\n return {\n ...field,\n labelAction: isFieldLocalized ? <LabelAction {...labelActionProps} /> : null,\n };\n};\n\nconst doesFieldHaveI18nPluginOpt = (\n pluginOpts?: object\n): pluginOpts is { i18n: { localized: boolean } } => {\n if (!pluginOpts) {\n return false;\n }\n\n return (\n 'i18n' in pluginOpts &&\n typeof pluginOpts.i18n === 'object' &&\n pluginOpts.i18n !== null &&\n 'localized' in pluginOpts.i18n\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * LabelAction\n * -----------------------------------------------------------------------------------------------*/\n\ninterface LabelActionProps {\n title: MessageDescriptor;\n icon: React.ReactNode;\n}\n\nconst LabelAction = ({ title, icon }: LabelActionProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Span tag=\"span\">\n <VisuallyHidden tag=\"span\">{formatMessage(title)}</VisuallyHidden>\n {React.cloneElement(icon as React.ReactElement, {\n 'aria-hidden': true,\n focusable: false, // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable\n })}\n </Span>\n );\n};\n\nconst Span = styled(Flex)`\n svg {\n width: 12px;\n height: 12px;\n\n fill: ${({ theme }) => theme.colors.neutral500};\n\n path {\n fill: ${({ theme }) => theme.colors.neutral500};\n }\n }\n`;\n\nexport { mutateEditViewHook };\n"],"names":["mutateEditViewHook","layout","options","i18n","localized","components","Object","entries","reduce","acc","key","componentLayout","map","row","addLabelActionToField","panel","field","isFieldLocalized","doesFieldHaveI18nPluginOpt","attribute","pluginOptions","labelActionProps","title","id","getTranslation","defaultMessage","icon","_jsx","Earth","labelAction","LabelAction","pluginOpts","formatMessage","useIntl","_jsxs","Span","tag","VisuallyHidden","React","cloneElement","focusable","styled","Flex","theme","colors","neutral500"],"mappings":"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"}
1
+ {"version":3,"file":"editView.js","sources":["../../../admin/src/contentManagerHooks/editView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport * as React from 'react';\n\nimport { Flex, Tooltip, VisuallyHidden } from '@strapi/design-system';\nimport { Earth } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { EditFieldLayout, EditLayout } from '@strapi/content-manager/strapi-admin';\n\ninterface MutateEditViewArgs {\n layout: EditLayout;\n}\n\nconst mutateEditViewHook = ({ layout }: MutateEditViewArgs): MutateEditViewArgs => {\n // If i18n isn't explicitly enabled on the content type, then no field can be localized\n if (\n !('i18n' in layout.options) ||\n (typeof layout.options.i18n === 'object' &&\n layout.options.i18n !== null &&\n 'localized' in layout.options.i18n &&\n !layout.options.i18n.localized)\n ) {\n return { layout };\n }\n\n const components = Object.entries(layout.components).reduce<EditLayout['components']>(\n (acc, [key, componentLayout]) => {\n return {\n ...acc,\n [key]: {\n ...componentLayout,\n layout: componentLayout.layout.map((row) => row.map(addLabelActionToField)),\n },\n };\n },\n {}\n );\n\n return {\n layout: {\n ...layout,\n components,\n layout: layout.layout.map((panel) => panel.map((row) => row.map(addLabelActionToField))),\n },\n } satisfies Pick<MutateEditViewArgs, 'layout'>;\n};\n\nconst addLabelActionToField = (field: EditFieldLayout) => {\n const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions)\n ? field.attribute.pluginOptions.i18n.localized\n : true || ['uid', 'relation'].includes(field.attribute.type);\n\n const labelActionProps = {\n title: {\n id: isFieldLocalized\n ? getTranslation('Field.localized')\n : getTranslation('Field.not-localized'),\n defaultMessage: isFieldLocalized\n ? 'This value is unique for the selected locale'\n : 'This value is the same across all locales',\n },\n icon: isFieldLocalized ? <Earth /> : null,\n };\n\n return {\n ...field,\n labelAction: isFieldLocalized ? <LabelAction {...labelActionProps} /> : null,\n };\n};\n\nconst doesFieldHaveI18nPluginOpt = (\n pluginOpts?: object\n): pluginOpts is { i18n: { localized: boolean } } => {\n if (!pluginOpts) {\n return false;\n }\n\n return (\n 'i18n' in pluginOpts &&\n typeof pluginOpts.i18n === 'object' &&\n pluginOpts.i18n !== null &&\n 'localized' in pluginOpts.i18n\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * LabelAction\n * -----------------------------------------------------------------------------------------------*/\n\ninterface LabelActionProps {\n title: MessageDescriptor;\n icon: React.ReactNode;\n}\n\nconst LabelAction = ({ title, icon }: LabelActionProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Span tag=\"span\">\n <VisuallyHidden tag=\"span\">{formatMessage(title)}</VisuallyHidden>\n <Tooltip label={formatMessage(title)}>\n {React.cloneElement(icon as React.ReactElement, {\n 'aria-hidden': true,\n focusable: false, // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable\n })}\n </Tooltip>\n </Span>\n );\n};\n\nconst Span = styled(Flex)`\n svg {\n width: 12px;\n height: 12px;\n\n fill: ${({ theme }) => theme.colors.neutral500};\n\n path {\n fill: ${({ theme }) => theme.colors.neutral500};\n }\n }\n`;\n\nexport { mutateEditViewHook };\n"],"names":["mutateEditViewHook","layout","options","i18n","localized","components","Object","entries","reduce","acc","key","componentLayout","map","row","addLabelActionToField","panel","field","isFieldLocalized","doesFieldHaveI18nPluginOpt","attribute","pluginOptions","labelActionProps","title","id","getTranslation","defaultMessage","icon","_jsx","Earth","labelAction","LabelAction","pluginOpts","formatMessage","useIntl","_jsxs","Span","tag","VisuallyHidden","Tooltip","label","React","cloneElement","focusable","styled","Flex","theme","colors","neutral500"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
1
  import { jsx, jsxs } from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
- import { Flex, VisuallyHidden } from '@strapi/design-system';
3
+ import { Flex, VisuallyHidden, Tooltip } from '@strapi/design-system';
4
4
  import { Earth } from '@strapi/icons';
5
5
  import { useIntl } from 'react-intl';
6
6
  import { styled } from 'styled-components';
@@ -61,9 +61,12 @@ const LabelAction = ({ title, icon })=>{
61
61
  tag: "span",
62
62
  children: formatMessage(title)
63
63
  }),
64
- /*#__PURE__*/ React.cloneElement(icon, {
65
- 'aria-hidden': true,
66
- focusable: false
64
+ /*#__PURE__*/ jsx(Tooltip, {
65
+ label: formatMessage(title),
66
+ children: /*#__PURE__*/ React.cloneElement(icon, {
67
+ 'aria-hidden': true,
68
+ focusable: false
69
+ })
67
70
  })
68
71
  ]
69
72
  });
@@ -1 +1 @@
1
- {"version":3,"file":"editView.mjs","sources":["../../../admin/src/contentManagerHooks/editView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport * as React from 'react';\n\nimport { Flex, VisuallyHidden } from '@strapi/design-system';\nimport { Earth, EarthStriked } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { EditFieldLayout, EditLayout } from '@strapi/content-manager/strapi-admin';\n\ninterface MutateEditViewArgs {\n layout: EditLayout;\n}\n\nconst mutateEditViewHook = ({ layout }: MutateEditViewArgs): MutateEditViewArgs => {\n // If i18n isn't explicitly enabled on the content type, then no field can be localized\n if (\n !('i18n' in layout.options) ||\n (typeof layout.options.i18n === 'object' &&\n layout.options.i18n !== null &&\n 'localized' in layout.options.i18n &&\n !layout.options.i18n.localized)\n ) {\n return { layout };\n }\n\n const components = Object.entries(layout.components).reduce<EditLayout['components']>(\n (acc, [key, componentLayout]) => {\n return {\n ...acc,\n [key]: {\n ...componentLayout,\n layout: componentLayout.layout.map((row) => row.map(addLabelActionToField)),\n },\n };\n },\n {}\n );\n\n return {\n layout: {\n ...layout,\n components,\n layout: layout.layout.map((panel) => panel.map((row) => row.map(addLabelActionToField))),\n },\n } satisfies Pick<MutateEditViewArgs, 'layout'>;\n};\n\nconst addLabelActionToField = (field: EditFieldLayout) => {\n const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions)\n ? field.attribute.pluginOptions.i18n.localized\n : true || ['uid', 'relation'].includes(field.attribute.type);\n\n const labelActionProps = {\n title: {\n id: isFieldLocalized\n ? getTranslation('Field.localized')\n : getTranslation('Field.not-localized'),\n defaultMessage: isFieldLocalized\n ? 'This value is unique for the selected locale'\n : 'This value is the same across all locales',\n },\n icon: isFieldLocalized ? <Earth /> : null,\n };\n\n return {\n ...field,\n labelAction: isFieldLocalized ? <LabelAction {...labelActionProps} /> : null,\n };\n};\n\nconst doesFieldHaveI18nPluginOpt = (\n pluginOpts?: object\n): pluginOpts is { i18n: { localized: boolean } } => {\n if (!pluginOpts) {\n return false;\n }\n\n return (\n 'i18n' in pluginOpts &&\n typeof pluginOpts.i18n === 'object' &&\n pluginOpts.i18n !== null &&\n 'localized' in pluginOpts.i18n\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * LabelAction\n * -----------------------------------------------------------------------------------------------*/\n\ninterface LabelActionProps {\n title: MessageDescriptor;\n icon: React.ReactNode;\n}\n\nconst LabelAction = ({ title, icon }: LabelActionProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Span tag=\"span\">\n <VisuallyHidden tag=\"span\">{formatMessage(title)}</VisuallyHidden>\n {React.cloneElement(icon as React.ReactElement, {\n 'aria-hidden': true,\n focusable: false, // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable\n })}\n </Span>\n );\n};\n\nconst Span = styled(Flex)`\n svg {\n width: 12px;\n height: 12px;\n\n fill: ${({ theme }) => theme.colors.neutral500};\n\n path {\n fill: ${({ theme }) => theme.colors.neutral500};\n }\n }\n`;\n\nexport { mutateEditViewHook };\n"],"names":["mutateEditViewHook","layout","options","i18n","localized","components","Object","entries","reduce","acc","key","componentLayout","map","row","addLabelActionToField","panel","field","isFieldLocalized","doesFieldHaveI18nPluginOpt","attribute","pluginOptions","labelActionProps","title","id","getTranslation","defaultMessage","icon","_jsx","Earth","labelAction","LabelAction","pluginOpts","formatMessage","useIntl","_jsxs","Span","tag","VisuallyHidden","React","cloneElement","focusable","styled","Flex","theme","colors","neutral500"],"mappings":"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"}
1
+ {"version":3,"file":"editView.mjs","sources":["../../../admin/src/contentManagerHooks/editView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport * as React from 'react';\n\nimport { Flex, Tooltip, VisuallyHidden } from '@strapi/design-system';\nimport { Earth } from '@strapi/icons';\nimport { MessageDescriptor, useIntl } from 'react-intl';\nimport { styled } from 'styled-components';\n\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { EditFieldLayout, EditLayout } from '@strapi/content-manager/strapi-admin';\n\ninterface MutateEditViewArgs {\n layout: EditLayout;\n}\n\nconst mutateEditViewHook = ({ layout }: MutateEditViewArgs): MutateEditViewArgs => {\n // If i18n isn't explicitly enabled on the content type, then no field can be localized\n if (\n !('i18n' in layout.options) ||\n (typeof layout.options.i18n === 'object' &&\n layout.options.i18n !== null &&\n 'localized' in layout.options.i18n &&\n !layout.options.i18n.localized)\n ) {\n return { layout };\n }\n\n const components = Object.entries(layout.components).reduce<EditLayout['components']>(\n (acc, [key, componentLayout]) => {\n return {\n ...acc,\n [key]: {\n ...componentLayout,\n layout: componentLayout.layout.map((row) => row.map(addLabelActionToField)),\n },\n };\n },\n {}\n );\n\n return {\n layout: {\n ...layout,\n components,\n layout: layout.layout.map((panel) => panel.map((row) => row.map(addLabelActionToField))),\n },\n } satisfies Pick<MutateEditViewArgs, 'layout'>;\n};\n\nconst addLabelActionToField = (field: EditFieldLayout) => {\n const isFieldLocalized = doesFieldHaveI18nPluginOpt(field.attribute.pluginOptions)\n ? field.attribute.pluginOptions.i18n.localized\n : true || ['uid', 'relation'].includes(field.attribute.type);\n\n const labelActionProps = {\n title: {\n id: isFieldLocalized\n ? getTranslation('Field.localized')\n : getTranslation('Field.not-localized'),\n defaultMessage: isFieldLocalized\n ? 'This value is unique for the selected locale'\n : 'This value is the same across all locales',\n },\n icon: isFieldLocalized ? <Earth /> : null,\n };\n\n return {\n ...field,\n labelAction: isFieldLocalized ? <LabelAction {...labelActionProps} /> : null,\n };\n};\n\nconst doesFieldHaveI18nPluginOpt = (\n pluginOpts?: object\n): pluginOpts is { i18n: { localized: boolean } } => {\n if (!pluginOpts) {\n return false;\n }\n\n return (\n 'i18n' in pluginOpts &&\n typeof pluginOpts.i18n === 'object' &&\n pluginOpts.i18n !== null &&\n 'localized' in pluginOpts.i18n\n );\n};\n\n/* -------------------------------------------------------------------------------------------------\n * LabelAction\n * -----------------------------------------------------------------------------------------------*/\n\ninterface LabelActionProps {\n title: MessageDescriptor;\n icon: React.ReactNode;\n}\n\nconst LabelAction = ({ title, icon }: LabelActionProps) => {\n const { formatMessage } = useIntl();\n\n return (\n <Span tag=\"span\">\n <VisuallyHidden tag=\"span\">{formatMessage(title)}</VisuallyHidden>\n <Tooltip label={formatMessage(title)}>\n {React.cloneElement(icon as React.ReactElement, {\n 'aria-hidden': true,\n focusable: false, // See: https://allyjs.io/tutorials/focusing-in-svg.html#making-svg-elements-focusable\n })}\n </Tooltip>\n </Span>\n );\n};\n\nconst Span = styled(Flex)`\n svg {\n width: 12px;\n height: 12px;\n\n fill: ${({ theme }) => theme.colors.neutral500};\n\n path {\n fill: ${({ theme }) => theme.colors.neutral500};\n }\n }\n`;\n\nexport { mutateEditViewHook };\n"],"names":["mutateEditViewHook","layout","options","i18n","localized","components","Object","entries","reduce","acc","key","componentLayout","map","row","addLabelActionToField","panel","field","isFieldLocalized","doesFieldHaveI18nPluginOpt","attribute","pluginOptions","labelActionProps","title","id","getTranslation","defaultMessage","icon","_jsx","Earth","labelAction","LabelAction","pluginOpts","formatMessage","useIntl","_jsxs","Span","tag","VisuallyHidden","Tooltip","label","React","cloneElement","focusable","styled","Flex","theme","colors","neutral500"],"mappings":"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"}
@@ -31,7 +31,8 @@ const addColumnToTableHook = ({ displayedHeaders, layout })=>{
31
31
  // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.
32
32
  cellFormatter: (props, _header, meta)=>/*#__PURE__*/ jsxRuntime.jsx(LocaleListCell.LocaleListCell, {
33
33
  ...props,
34
- ...meta
34
+ ...meta,
35
+ documentId: props.documentId
35
36
  })
36
37
  }
37
38
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"listView.js","sources":["../../../admin/src/contentManagerHooks/listView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { LocaleListCell } from '../components/LocaleListCell';\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { ListFieldLayout, ListLayout } from '@strapi/content-manager/strapi-admin';\n\n/* -------------------------------------------------------------------------------------------------\n * addColumnToTableHook\n * -----------------------------------------------------------------------------------------------*/\ninterface AddColumnToTableHookArgs {\n layout: ListLayout;\n displayedHeaders: ListFieldLayout[];\n}\n\nconst addColumnToTableHook = ({ displayedHeaders, layout }: AddColumnToTableHookArgs) => {\n const { options } = layout;\n\n const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options)\n ? options.i18n.localized\n : false;\n\n if (!isFieldLocalized) {\n return { displayedHeaders, layout };\n }\n\n return {\n displayedHeaders: [\n ...displayedHeaders,\n {\n attribute: { type: 'string' },\n label: {\n id: getTranslation('list-view.table.header.label'),\n defaultMessage: 'Available in',\n },\n searchable: false,\n sortable: false,\n name: 'locales',\n // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.\n cellFormatter: (props, _header, meta) => <LocaleListCell {...props} {...meta} />,\n },\n ],\n layout,\n };\n};\n\nexport { addColumnToTableHook };\n"],"names":["addColumnToTableHook","displayedHeaders","layout","options","isFieldLocalized","doesPluginOptionsHaveI18nLocalized","i18n","localized","attribute","type","label","id","getTranslation","defaultMessage","searchable","sortable","name","cellFormatter","props","_header","meta","_jsx","LocaleListCell"],"mappings":";;;;;;;AAeA,MAAMA,uBAAuB,CAAC,EAAEC,gBAAgB,EAAEC,MAAM,EAA4B,GAAA;IAClF,MAAM,EAAEC,OAAO,EAAE,GAAGD,MAAAA;AAEpB,IAAA,MAAME,mBAAmBC,yCAAmCF,CAAAA,OAAAA,CAAAA,GACxDA,QAAQG,IAAI,CAACC,SAAS,GACtB,KAAA;AAEJ,IAAA,IAAI,CAACH,gBAAkB,EAAA;QACrB,OAAO;AAAEH,YAAAA,gBAAAA;AAAkBC,YAAAA;AAAO,SAAA;AACpC;IAEA,OAAO;QACLD,gBAAkB,EAAA;AACbA,YAAAA,GAAAA,gBAAAA;AACH,YAAA;gBACEO,SAAW,EAAA;oBAAEC,IAAM,EAAA;AAAS,iBAAA;gBAC5BC,KAAO,EAAA;AACLC,oBAAAA,EAAAA,EAAIC,6BAAe,CAAA,8BAAA,CAAA;oBACnBC,cAAgB,EAAA;AAClB,iBAAA;gBACAC,UAAY,EAAA,KAAA;gBACZC,QAAU,EAAA,KAAA;gBACVC,IAAM,EAAA,SAAA;;AAENC,gBAAAA,aAAAA,EAAe,CAACC,KAAAA,EAAOC,OAASC,EAAAA,IAAAA,iBAASC,cAACC,CAAAA,6BAAAA,EAAAA;AAAgB,wBAAA,GAAGJ,KAAK;AAAG,wBAAA,GAAGE;;AAC1E;AACD,SAAA;AACDlB,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"listView.js","sources":["../../../admin/src/contentManagerHooks/listView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { LocaleListCell } from '../components/LocaleListCell';\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { ListFieldLayout, ListLayout } from '@strapi/content-manager/strapi-admin';\n\n/* -------------------------------------------------------------------------------------------------\n * addColumnToTableHook\n * -----------------------------------------------------------------------------------------------*/\ninterface AddColumnToTableHookArgs {\n layout: ListLayout;\n displayedHeaders: ListFieldLayout[];\n}\n\nconst addColumnToTableHook = ({ displayedHeaders, layout }: AddColumnToTableHookArgs) => {\n const { options } = layout;\n\n const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options)\n ? options.i18n.localized\n : false;\n\n if (!isFieldLocalized) {\n return { displayedHeaders, layout };\n }\n\n return {\n displayedHeaders: [\n ...displayedHeaders,\n {\n attribute: { type: 'string' },\n label: {\n id: getTranslation('list-view.table.header.label'),\n defaultMessage: 'Available in',\n },\n searchable: false,\n sortable: false,\n name: 'locales',\n // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.\n cellFormatter: (props, _header, meta) => (\n <LocaleListCell {...props} {...meta} documentId={props.documentId} />\n ),\n },\n ],\n layout,\n };\n};\n\nexport { addColumnToTableHook };\n"],"names":["addColumnToTableHook","displayedHeaders","layout","options","isFieldLocalized","doesPluginOptionsHaveI18nLocalized","i18n","localized","attribute","type","label","id","getTranslation","defaultMessage","searchable","sortable","name","cellFormatter","props","_header","meta","_jsx","LocaleListCell","documentId"],"mappings":";;;;;;;AAeA,MAAMA,uBAAuB,CAAC,EAAEC,gBAAgB,EAAEC,MAAM,EAA4B,GAAA;IAClF,MAAM,EAAEC,OAAO,EAAE,GAAGD,MAAAA;AAEpB,IAAA,MAAME,mBAAmBC,yCAAmCF,CAAAA,OAAAA,CAAAA,GACxDA,QAAQG,IAAI,CAACC,SAAS,GACtB,KAAA;AAEJ,IAAA,IAAI,CAACH,gBAAkB,EAAA;QACrB,OAAO;AAAEH,YAAAA,gBAAAA;AAAkBC,YAAAA;AAAO,SAAA;AACpC;IAEA,OAAO;QACLD,gBAAkB,EAAA;AACbA,YAAAA,GAAAA,gBAAAA;AACH,YAAA;gBACEO,SAAW,EAAA;oBAAEC,IAAM,EAAA;AAAS,iBAAA;gBAC5BC,KAAO,EAAA;AACLC,oBAAAA,EAAAA,EAAIC,6BAAe,CAAA,8BAAA,CAAA;oBACnBC,cAAgB,EAAA;AAClB,iBAAA;gBACAC,UAAY,EAAA,KAAA;gBACZC,QAAU,EAAA,KAAA;gBACVC,IAAM,EAAA,SAAA;;AAENC,gBAAAA,aAAAA,EAAe,CAACC,KAAAA,EAAOC,OAASC,EAAAA,IAAAA,iBAC9BC,cAACC,CAAAA,6BAAAA,EAAAA;AAAgB,wBAAA,GAAGJ,KAAK;AAAG,wBAAA,GAAGE,IAAI;AAAEG,wBAAAA,UAAAA,EAAYL,MAAMK;;AAE3D;AACD,SAAA;AACDrB,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -29,7 +29,8 @@ const addColumnToTableHook = ({ displayedHeaders, layout })=>{
29
29
  // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.
30
30
  cellFormatter: (props, _header, meta)=>/*#__PURE__*/ jsx(LocaleListCell, {
31
31
  ...props,
32
- ...meta
32
+ ...meta,
33
+ documentId: props.documentId
33
34
  })
34
35
  }
35
36
  ],
@@ -1 +1 @@
1
- {"version":3,"file":"listView.mjs","sources":["../../../admin/src/contentManagerHooks/listView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { LocaleListCell } from '../components/LocaleListCell';\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { ListFieldLayout, ListLayout } from '@strapi/content-manager/strapi-admin';\n\n/* -------------------------------------------------------------------------------------------------\n * addColumnToTableHook\n * -----------------------------------------------------------------------------------------------*/\ninterface AddColumnToTableHookArgs {\n layout: ListLayout;\n displayedHeaders: ListFieldLayout[];\n}\n\nconst addColumnToTableHook = ({ displayedHeaders, layout }: AddColumnToTableHookArgs) => {\n const { options } = layout;\n\n const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options)\n ? options.i18n.localized\n : false;\n\n if (!isFieldLocalized) {\n return { displayedHeaders, layout };\n }\n\n return {\n displayedHeaders: [\n ...displayedHeaders,\n {\n attribute: { type: 'string' },\n label: {\n id: getTranslation('list-view.table.header.label'),\n defaultMessage: 'Available in',\n },\n searchable: false,\n sortable: false,\n name: 'locales',\n // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.\n cellFormatter: (props, _header, meta) => <LocaleListCell {...props} {...meta} />,\n },\n ],\n layout,\n };\n};\n\nexport { addColumnToTableHook };\n"],"names":["addColumnToTableHook","displayedHeaders","layout","options","isFieldLocalized","doesPluginOptionsHaveI18nLocalized","i18n","localized","attribute","type","label","id","getTranslation","defaultMessage","searchable","sortable","name","cellFormatter","props","_header","meta","_jsx","LocaleListCell"],"mappings":";;;;;AAeA,MAAMA,uBAAuB,CAAC,EAAEC,gBAAgB,EAAEC,MAAM,EAA4B,GAAA;IAClF,MAAM,EAAEC,OAAO,EAAE,GAAGD,MAAAA;AAEpB,IAAA,MAAME,mBAAmBC,kCAAmCF,CAAAA,OAAAA,CAAAA,GACxDA,QAAQG,IAAI,CAACC,SAAS,GACtB,KAAA;AAEJ,IAAA,IAAI,CAACH,gBAAkB,EAAA;QACrB,OAAO;AAAEH,YAAAA,gBAAAA;AAAkBC,YAAAA;AAAO,SAAA;AACpC;IAEA,OAAO;QACLD,gBAAkB,EAAA;AACbA,YAAAA,GAAAA,gBAAAA;AACH,YAAA;gBACEO,SAAW,EAAA;oBAAEC,IAAM,EAAA;AAAS,iBAAA;gBAC5BC,KAAO,EAAA;AACLC,oBAAAA,EAAAA,EAAIC,cAAe,CAAA,8BAAA,CAAA;oBACnBC,cAAgB,EAAA;AAClB,iBAAA;gBACAC,UAAY,EAAA,KAAA;gBACZC,QAAU,EAAA,KAAA;gBACVC,IAAM,EAAA,SAAA;;AAENC,gBAAAA,aAAAA,EAAe,CAACC,KAAAA,EAAOC,OAASC,EAAAA,IAAAA,iBAASC,GAACC,CAAAA,cAAAA,EAAAA;AAAgB,wBAAA,GAAGJ,KAAK;AAAG,wBAAA,GAAGE;;AAC1E;AACD,SAAA;AACDlB,QAAAA;AACF,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"listView.mjs","sources":["../../../admin/src/contentManagerHooks/listView.tsx"],"sourcesContent":["/* eslint-disable check-file/filename-naming-convention */\nimport { LocaleListCell } from '../components/LocaleListCell';\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { getTranslation } from '../utils/getTranslation';\n\nimport type { ListFieldLayout, ListLayout } from '@strapi/content-manager/strapi-admin';\n\n/* -------------------------------------------------------------------------------------------------\n * addColumnToTableHook\n * -----------------------------------------------------------------------------------------------*/\ninterface AddColumnToTableHookArgs {\n layout: ListLayout;\n displayedHeaders: ListFieldLayout[];\n}\n\nconst addColumnToTableHook = ({ displayedHeaders, layout }: AddColumnToTableHookArgs) => {\n const { options } = layout;\n\n const isFieldLocalized = doesPluginOptionsHaveI18nLocalized(options)\n ? options.i18n.localized\n : false;\n\n if (!isFieldLocalized) {\n return { displayedHeaders, layout };\n }\n\n return {\n displayedHeaders: [\n ...displayedHeaders,\n {\n attribute: { type: 'string' },\n label: {\n id: getTranslation('list-view.table.header.label'),\n defaultMessage: 'Available in',\n },\n searchable: false,\n sortable: false,\n name: 'locales',\n // @ts-expect-error – ID is seen as number | string; this will change when we move the type over.\n cellFormatter: (props, _header, meta) => (\n <LocaleListCell {...props} {...meta} documentId={props.documentId} />\n ),\n },\n ],\n layout,\n };\n};\n\nexport { addColumnToTableHook };\n"],"names":["addColumnToTableHook","displayedHeaders","layout","options","isFieldLocalized","doesPluginOptionsHaveI18nLocalized","i18n","localized","attribute","type","label","id","getTranslation","defaultMessage","searchable","sortable","name","cellFormatter","props","_header","meta","_jsx","LocaleListCell","documentId"],"mappings":";;;;;AAeA,MAAMA,uBAAuB,CAAC,EAAEC,gBAAgB,EAAEC,MAAM,EAA4B,GAAA;IAClF,MAAM,EAAEC,OAAO,EAAE,GAAGD,MAAAA;AAEpB,IAAA,MAAME,mBAAmBC,kCAAmCF,CAAAA,OAAAA,CAAAA,GACxDA,QAAQG,IAAI,CAACC,SAAS,GACtB,KAAA;AAEJ,IAAA,IAAI,CAACH,gBAAkB,EAAA;QACrB,OAAO;AAAEH,YAAAA,gBAAAA;AAAkBC,YAAAA;AAAO,SAAA;AACpC;IAEA,OAAO;QACLD,gBAAkB,EAAA;AACbA,YAAAA,GAAAA,gBAAAA;AACH,YAAA;gBACEO,SAAW,EAAA;oBAAEC,IAAM,EAAA;AAAS,iBAAA;gBAC5BC,KAAO,EAAA;AACLC,oBAAAA,EAAAA,EAAIC,cAAe,CAAA,8BAAA,CAAA;oBACnBC,cAAgB,EAAA;AAClB,iBAAA;gBACAC,UAAY,EAAA,KAAA;gBACZC,QAAU,EAAA,KAAA;gBACVC,IAAM,EAAA,SAAA;;AAENC,gBAAAA,aAAAA,EAAe,CAACC,KAAAA,EAAOC,OAASC,EAAAA,IAAAA,iBAC9BC,GAACC,CAAAA,cAAAA,EAAAA;AAAgB,wBAAA,GAAGJ,KAAK;AAAG,wBAAA,GAAGE,IAAI;AAAEG,wBAAAA,UAAAA,EAAYL,MAAMK;;AAE3D;AACD,SAAA;AACDrB,QAAAA;AACF,KAAA;AACF;;;;"}
@@ -0,0 +1,110 @@
1
+ 'use strict';
2
+
3
+ var React = require('react');
4
+ var strapiAdmin = require('@strapi/admin/strapi-admin');
5
+ var reactIntl = require('react-intl');
6
+ var reactRedux = require('react-redux');
7
+ var aiLocalizationJobs = require('../services/aiLocalizationJobs.js');
8
+ var getTranslation = require('../utils/getTranslation.js');
9
+
10
+ function _interopNamespaceDefault(e) {
11
+ var n = Object.create(null);
12
+ if (e) {
13
+ Object.keys(e).forEach(function (k) {
14
+ if (k !== 'default') {
15
+ var d = Object.getOwnPropertyDescriptor(e, k);
16
+ Object.defineProperty(n, k, d.get ? d : {
17
+ enumerable: true,
18
+ get: function () { return e[k]; }
19
+ });
20
+ }
21
+ });
22
+ }
23
+ n.default = e;
24
+ return Object.freeze(n);
25
+ }
26
+
27
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
28
+
29
+ const useAILocalizationJobsPolling = ({ documentId, model, collectionType })=>{
30
+ const { toggleNotification } = strapiAdmin.useNotification();
31
+ const { formatMessage } = reactIntl.useIntl();
32
+ const dispatch = reactRedux.useDispatch();
33
+ const [previousJobStatus, setPreviousJobStatus] = React__namespace.useState(null);
34
+ /**
35
+ * NOTE:
36
+ * Due to a limitation with RTK query it is not possible to dynamically update the polling interval
37
+ * @see https://github.com/reduxjs/redux-toolkit/issues/1651
38
+ */ const { data: initialJobData } = aiLocalizationJobs.useGetAILocalizationJobsByDocumentQuery({
39
+ documentId: documentId,
40
+ model: model,
41
+ collectionType: collectionType
42
+ });
43
+ const shouldPoll = initialJobData?.data?.status === 'processing' || previousJobStatus === 'processing';
44
+ const { data: jobData } = aiLocalizationJobs.useGetAILocalizationJobsByDocumentQuery({
45
+ documentId: documentId,
46
+ model: model,
47
+ collectionType: collectionType
48
+ }, {
49
+ skip: !shouldPoll,
50
+ pollingInterval: 1000
51
+ });
52
+ const job = jobData?.data || initialJobData?.data;
53
+ const currentJobStatus = job?.status;
54
+ const invalidateDocument = React__namespace.useCallback(()=>{
55
+ dispatch(strapiAdmin.adminApi.util.invalidateTags([
56
+ {
57
+ // @ts-expect-error tag isn't available
58
+ type: 'Document',
59
+ id: collectionType !== 'single-types' ? `${model}_${documentId}` : model
60
+ }
61
+ ]));
62
+ }, [
63
+ dispatch,
64
+ collectionType,
65
+ model,
66
+ documentId
67
+ ]);
68
+ // Check for job status changes and trigger callbacks
69
+ React__namespace.useEffect(()=>{
70
+ if (!currentJobStatus) return;
71
+ // Detect transition from 'processing' to a terminal state
72
+ if (previousJobStatus === 'processing' && currentJobStatus === 'completed') {
73
+ toggleNotification({
74
+ type: 'success',
75
+ message: formatMessage({
76
+ id: getTranslation.getTranslation('CMEditViewAITranslation.job-completed'),
77
+ defaultMessage: 'AI translation completed successfully!'
78
+ })
79
+ });
80
+ invalidateDocument();
81
+ }
82
+ if (previousJobStatus === 'processing' && currentJobStatus === 'failed') {
83
+ toggleNotification({
84
+ type: 'warning',
85
+ message: formatMessage({
86
+ id: getTranslation.getTranslation('CMEditViewAITranslation.job-failed'),
87
+ defaultMessage: 'AI translation failed. Please try again.'
88
+ })
89
+ });
90
+ invalidateDocument();
91
+ }
92
+ // Update the previous status if it changed
93
+ if (previousJobStatus !== currentJobStatus) {
94
+ setPreviousJobStatus(currentJobStatus);
95
+ }
96
+ }, [
97
+ currentJobStatus,
98
+ previousJobStatus,
99
+ setPreviousJobStatus,
100
+ toggleNotification,
101
+ formatMessage,
102
+ invalidateDocument
103
+ ]);
104
+ return {
105
+ status: job?.status
106
+ };
107
+ };
108
+
109
+ exports.useAILocalizationJobsPolling = useAILocalizationJobsPolling;
110
+ //# sourceMappingURL=useAILocalizationJobsPolling.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAILocalizationJobsPolling.js","sources":["../../../admin/src/hooks/useAILocalizationJobsPolling.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, adminApi } from '@strapi/admin/strapi-admin';\nimport { useIntl } from 'react-intl';\nimport { useDispatch } from 'react-redux';\n\nimport { AILocalizationJobs } from '../../../shared/contracts/ai-localization-jobs';\nimport { useGetAILocalizationJobsByDocumentQuery } from '../services/aiLocalizationJobs';\nimport { getTranslation } from '../utils/getTranslation';\n\ninterface UseAILocalizationJobsPollingOptions {\n documentId?: string;\n model?: string;\n collectionType?: string;\n}\n\nexport const useAILocalizationJobsPolling = ({\n documentId,\n model,\n collectionType,\n}: UseAILocalizationJobsPollingOptions) => {\n const { toggleNotification } = useNotification();\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n\n const [previousJobStatus, setPreviousJobStatus] = React.useState<\n AILocalizationJobs['status'] | null\n >(null);\n\n /**\n * NOTE:\n * Due to a limitation with RTK query it is not possible to dynamically update the polling interval\n * @see https://github.com/reduxjs/redux-toolkit/issues/1651\n */\n const { data: initialJobData } = useGetAILocalizationJobsByDocumentQuery({\n documentId: documentId!,\n model: model!,\n collectionType: collectionType!,\n });\n\n const shouldPoll =\n initialJobData?.data?.status === 'processing' || previousJobStatus === 'processing';\n const { data: jobData } = useGetAILocalizationJobsByDocumentQuery(\n { documentId: documentId!, model: model!, collectionType: collectionType! },\n {\n skip: !shouldPoll,\n pollingInterval: 1000,\n }\n );\n\n const job = jobData?.data || initialJobData?.data;\n const currentJobStatus = job?.status;\n\n const invalidateDocument = React.useCallback(() => {\n dispatch(\n adminApi.util.invalidateTags([\n {\n // @ts-expect-error tag isn't available\n type: 'Document',\n id: collectionType !== 'single-types' ? `${model}_${documentId}` : model,\n },\n ])\n );\n }, [dispatch, collectionType, model, documentId]);\n\n // Check for job status changes and trigger callbacks\n React.useEffect(() => {\n if (!currentJobStatus) return;\n\n // Detect transition from 'processing' to a terminal state\n if (previousJobStatus === 'processing' && currentJobStatus === 'completed') {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: getTranslation('CMEditViewAITranslation.job-completed'),\n defaultMessage: 'AI translation completed successfully!',\n }),\n });\n invalidateDocument();\n }\n\n if (previousJobStatus === 'processing' && currentJobStatus === 'failed') {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: getTranslation('CMEditViewAITranslation.job-failed'),\n defaultMessage: 'AI translation failed. Please try again.',\n }),\n });\n invalidateDocument();\n }\n\n // Update the previous status if it changed\n if (previousJobStatus !== currentJobStatus) {\n setPreviousJobStatus(currentJobStatus);\n }\n }, [\n currentJobStatus,\n previousJobStatus,\n setPreviousJobStatus,\n toggleNotification,\n formatMessage,\n invalidateDocument,\n ]);\n\n return {\n status: job?.status,\n };\n};\n"],"names":["useAILocalizationJobsPolling","documentId","model","collectionType","toggleNotification","useNotification","formatMessage","useIntl","dispatch","useDispatch","previousJobStatus","setPreviousJobStatus","React","useState","data","initialJobData","useGetAILocalizationJobsByDocumentQuery","shouldPoll","status","jobData","skip","pollingInterval","job","currentJobStatus","invalidateDocument","useCallback","adminApi","util","invalidateTags","type","id","useEffect","message","getTranslation","defaultMessage"],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ import * as React from 'react';
2
+ import { useNotification, adminApi } from '@strapi/admin/strapi-admin';
3
+ import { useIntl } from 'react-intl';
4
+ import { useDispatch } from 'react-redux';
5
+ import { useGetAILocalizationJobsByDocumentQuery } from '../services/aiLocalizationJobs.mjs';
6
+ import { getTranslation } from '../utils/getTranslation.mjs';
7
+
8
+ const useAILocalizationJobsPolling = ({ documentId, model, collectionType })=>{
9
+ const { toggleNotification } = useNotification();
10
+ const { formatMessage } = useIntl();
11
+ const dispatch = useDispatch();
12
+ const [previousJobStatus, setPreviousJobStatus] = React.useState(null);
13
+ /**
14
+ * NOTE:
15
+ * Due to a limitation with RTK query it is not possible to dynamically update the polling interval
16
+ * @see https://github.com/reduxjs/redux-toolkit/issues/1651
17
+ */ const { data: initialJobData } = useGetAILocalizationJobsByDocumentQuery({
18
+ documentId: documentId,
19
+ model: model,
20
+ collectionType: collectionType
21
+ });
22
+ const shouldPoll = initialJobData?.data?.status === 'processing' || previousJobStatus === 'processing';
23
+ const { data: jobData } = useGetAILocalizationJobsByDocumentQuery({
24
+ documentId: documentId,
25
+ model: model,
26
+ collectionType: collectionType
27
+ }, {
28
+ skip: !shouldPoll,
29
+ pollingInterval: 1000
30
+ });
31
+ const job = jobData?.data || initialJobData?.data;
32
+ const currentJobStatus = job?.status;
33
+ const invalidateDocument = React.useCallback(()=>{
34
+ dispatch(adminApi.util.invalidateTags([
35
+ {
36
+ // @ts-expect-error tag isn't available
37
+ type: 'Document',
38
+ id: collectionType !== 'single-types' ? `${model}_${documentId}` : model
39
+ }
40
+ ]));
41
+ }, [
42
+ dispatch,
43
+ collectionType,
44
+ model,
45
+ documentId
46
+ ]);
47
+ // Check for job status changes and trigger callbacks
48
+ React.useEffect(()=>{
49
+ if (!currentJobStatus) return;
50
+ // Detect transition from 'processing' to a terminal state
51
+ if (previousJobStatus === 'processing' && currentJobStatus === 'completed') {
52
+ toggleNotification({
53
+ type: 'success',
54
+ message: formatMessage({
55
+ id: getTranslation('CMEditViewAITranslation.job-completed'),
56
+ defaultMessage: 'AI translation completed successfully!'
57
+ })
58
+ });
59
+ invalidateDocument();
60
+ }
61
+ if (previousJobStatus === 'processing' && currentJobStatus === 'failed') {
62
+ toggleNotification({
63
+ type: 'warning',
64
+ message: formatMessage({
65
+ id: getTranslation('CMEditViewAITranslation.job-failed'),
66
+ defaultMessage: 'AI translation failed. Please try again.'
67
+ })
68
+ });
69
+ invalidateDocument();
70
+ }
71
+ // Update the previous status if it changed
72
+ if (previousJobStatus !== currentJobStatus) {
73
+ setPreviousJobStatus(currentJobStatus);
74
+ }
75
+ }, [
76
+ currentJobStatus,
77
+ previousJobStatus,
78
+ setPreviousJobStatus,
79
+ toggleNotification,
80
+ formatMessage,
81
+ invalidateDocument
82
+ ]);
83
+ return {
84
+ status: job?.status
85
+ };
86
+ };
87
+
88
+ export { useAILocalizationJobsPolling };
89
+ //# sourceMappingURL=useAILocalizationJobsPolling.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useAILocalizationJobsPolling.mjs","sources":["../../../admin/src/hooks/useAILocalizationJobsPolling.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useNotification, adminApi } from '@strapi/admin/strapi-admin';\nimport { useIntl } from 'react-intl';\nimport { useDispatch } from 'react-redux';\n\nimport { AILocalizationJobs } from '../../../shared/contracts/ai-localization-jobs';\nimport { useGetAILocalizationJobsByDocumentQuery } from '../services/aiLocalizationJobs';\nimport { getTranslation } from '../utils/getTranslation';\n\ninterface UseAILocalizationJobsPollingOptions {\n documentId?: string;\n model?: string;\n collectionType?: string;\n}\n\nexport const useAILocalizationJobsPolling = ({\n documentId,\n model,\n collectionType,\n}: UseAILocalizationJobsPollingOptions) => {\n const { toggleNotification } = useNotification();\n const { formatMessage } = useIntl();\n const dispatch = useDispatch();\n\n const [previousJobStatus, setPreviousJobStatus] = React.useState<\n AILocalizationJobs['status'] | null\n >(null);\n\n /**\n * NOTE:\n * Due to a limitation with RTK query it is not possible to dynamically update the polling interval\n * @see https://github.com/reduxjs/redux-toolkit/issues/1651\n */\n const { data: initialJobData } = useGetAILocalizationJobsByDocumentQuery({\n documentId: documentId!,\n model: model!,\n collectionType: collectionType!,\n });\n\n const shouldPoll =\n initialJobData?.data?.status === 'processing' || previousJobStatus === 'processing';\n const { data: jobData } = useGetAILocalizationJobsByDocumentQuery(\n { documentId: documentId!, model: model!, collectionType: collectionType! },\n {\n skip: !shouldPoll,\n pollingInterval: 1000,\n }\n );\n\n const job = jobData?.data || initialJobData?.data;\n const currentJobStatus = job?.status;\n\n const invalidateDocument = React.useCallback(() => {\n dispatch(\n adminApi.util.invalidateTags([\n {\n // @ts-expect-error tag isn't available\n type: 'Document',\n id: collectionType !== 'single-types' ? `${model}_${documentId}` : model,\n },\n ])\n );\n }, [dispatch, collectionType, model, documentId]);\n\n // Check for job status changes and trigger callbacks\n React.useEffect(() => {\n if (!currentJobStatus) return;\n\n // Detect transition from 'processing' to a terminal state\n if (previousJobStatus === 'processing' && currentJobStatus === 'completed') {\n toggleNotification({\n type: 'success',\n message: formatMessage({\n id: getTranslation('CMEditViewAITranslation.job-completed'),\n defaultMessage: 'AI translation completed successfully!',\n }),\n });\n invalidateDocument();\n }\n\n if (previousJobStatus === 'processing' && currentJobStatus === 'failed') {\n toggleNotification({\n type: 'warning',\n message: formatMessage({\n id: getTranslation('CMEditViewAITranslation.job-failed'),\n defaultMessage: 'AI translation failed. Please try again.',\n }),\n });\n invalidateDocument();\n }\n\n // Update the previous status if it changed\n if (previousJobStatus !== currentJobStatus) {\n setPreviousJobStatus(currentJobStatus);\n }\n }, [\n currentJobStatus,\n previousJobStatus,\n setPreviousJobStatus,\n toggleNotification,\n formatMessage,\n invalidateDocument,\n ]);\n\n return {\n status: job?.status,\n };\n};\n"],"names":["useAILocalizationJobsPolling","documentId","model","collectionType","toggleNotification","useNotification","formatMessage","useIntl","dispatch","useDispatch","previousJobStatus","setPreviousJobStatus","React","useState","data","initialJobData","useGetAILocalizationJobsByDocumentQuery","shouldPoll","status","jobData","skip","pollingInterval","job","currentJobStatus","invalidateDocument","useCallback","adminApi","util","invalidateTags","type","id","useEffect","message","getTranslation","defaultMessage"],"mappings":"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"}
@@ -3,6 +3,7 @@
3
3
  var React = require('react');
4
4
  var strapiAdmin = require('@strapi/admin/strapi-admin');
5
5
  var strapiAdmin$1 = require('@strapi/content-manager/strapi-admin');
6
+ var union = require('lodash/union');
6
7
  var reactRouterDom = require('react-router-dom');
7
8
  var fields = require('../utils/fields.js');
8
9
  var strings = require('../utils/strings.js');
@@ -39,10 +40,9 @@ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
39
40
  const permissions = userPermissions.filter((permission)=>permission.subject === params.slug);
40
41
  return permissions.reduce((acc, permission)=>{
41
42
  const [actionShorthand] = permission.action.split('.').slice(-1);
42
- return {
43
- ...acc,
44
- [`can${strings.capitalize(actionShorthand)}`]: permission.properties?.locales ?? []
45
- };
43
+ const permissionKey = `can${strings.capitalize(actionShorthand)}`;
44
+ acc[permissionKey] = union(acc[permissionKey] ?? [], permission.properties?.locales ?? []);
45
+ return acc;
46
46
  }, {
47
47
  canCreate: [],
48
48
  canRead: [],
@@ -1 +1 @@
1
- {"version":3,"file":"useI18n.js","sources":["../../../admin/src/hooks/useI18n.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useAuth } from '@strapi/admin/strapi-admin';\nimport { unstable_useDocument as useDocument } from '@strapi/content-manager/strapi-admin';\nimport { useParams } from 'react-router-dom';\n\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { capitalize } from '../utils/strings';\n\ntype UseI18n = () => {\n hasI18n: boolean;\n canCreate: string[];\n canRead: string[];\n canUpdate: string[];\n canDelete: string[];\n canPublish: string[];\n};\n\n/**\n * @alpha\n * @description This hook is used to get the i18n status of a content type.\n * Also returns the CRUDP permission locale properties for the content type\n * so we know which locales the user can perform actions on.\n */\nconst useI18n: UseI18n = () => {\n // Extract the params from the URL to pass to our useDocument hook\n const params = useParams<{ collectionType: string; slug: string; model: string }>();\n\n const userPermissions = useAuth('useI18n', (state) => state.permissions);\n const actions = React.useMemo(() => {\n const permissions = userPermissions.filter((permission) => permission.subject === params.slug);\n\n return permissions.reduce<Omit<ReturnType<UseI18n>, 'hasI18n'>>(\n (acc, permission) => {\n const [actionShorthand] = permission.action.split('.').slice(-1);\n\n return {\n ...acc,\n [`can${capitalize(actionShorthand)}`]: permission.properties?.locales ?? [],\n };\n },\n { canCreate: [], canRead: [], canUpdate: [], canDelete: [], canPublish: [] }\n );\n }, [params.slug, userPermissions]);\n\n // TODO: use specific hook to get schema only\n const { schema } = useDocument(\n {\n // We can non-null assert these because below we skip the query if they are not present\n collectionType: params.collectionType!,\n model: params.slug!,\n },\n {\n skip: true,\n }\n );\n\n if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {\n return {\n hasI18n: schema.pluginOptions.i18n.localized,\n ...actions,\n };\n }\n\n return {\n hasI18n: false,\n ...actions,\n };\n};\n\nexport { useI18n };\n"],"names":["useI18n","params","useParams","userPermissions","useAuth","state","permissions","actions","React","useMemo","filter","permission","subject","slug","reduce","acc","actionShorthand","action","split","slice","capitalize","properties","locales","canCreate","canRead","canUpdate","canDelete","canPublish","schema","useDocument","collectionType","model","skip","doesPluginOptionsHaveI18nLocalized","pluginOptions","hasI18n","i18n","localized"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA;;;;;AAKC,UACKA,OAAmB,GAAA,IAAA;;AAEvB,IAAA,MAAMC,MAASC,GAAAA,wBAAAA,EAAAA;AAEf,IAAA,MAAMC,kBAAkBC,mBAAQ,CAAA,SAAA,EAAW,CAACC,KAAAA,GAAUA,MAAMC,WAAW,CAAA;IACvE,MAAMC,OAAAA,GAAUC,gBAAMC,CAAAA,OAAO,CAAC,IAAA;QAC5B,MAAMH,WAAAA,GAAcH,eAAgBO,CAAAA,MAAM,CAAC,CAACC,aAAeA,UAAWC,CAAAA,OAAO,KAAKX,MAAAA,CAAOY,IAAI,CAAA;AAE7F,QAAA,OAAOP,WAAYQ,CAAAA,MAAM,CACvB,CAACC,GAAKJ,EAAAA,UAAAA,GAAAA;YACJ,MAAM,CAACK,eAAgB,CAAA,GAAGL,UAAWM,CAAAA,MAAM,CAACC,KAAK,CAAC,GAAA,CAAA,CAAKC,KAAK,CAAC,CAAC,CAAA,CAAA;YAE9D,OAAO;AACL,gBAAA,GAAGJ,GAAG;AACN,gBAAA,CAAC,CAAC,GAAG,EAAEK,kBAAAA,CAAWJ,eAAiB,CAAA,CAAA,CAAC,GAAGL,UAAWU,CAAAA,UAAU,EAAEC,OAAAA,IAAW;AAC3E,aAAA;SAEF,EAAA;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,OAAAA,EAAS,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,UAAAA,EAAY;AAAG,SAAA,CAAA;KAE5E,EAAA;AAAC1B,QAAAA,MAAAA,CAAOY,IAAI;AAAEV,QAAAA;AAAgB,KAAA,CAAA;;AAGjC,IAAA,MAAM,EAAEyB,MAAM,EAAE,GAAGC,kCACjB,CAAA;;AAEEC,QAAAA,cAAAA,EAAgB7B,OAAO6B,cAAc;AACrCC,QAAAA,KAAAA,EAAO9B,OAAOY;KAEhB,EAAA;QACEmB,IAAM,EAAA;AACR,KAAA,CAAA;IAGF,IAAIC,yCAAAA,CAAmCL,QAAQM,aAAgB,CAAA,EAAA;QAC7D,OAAO;AACLC,YAAAA,OAAAA,EAASP,MAAOM,CAAAA,aAAa,CAACE,IAAI,CAACC,SAAS;AAC5C,YAAA,GAAG9B;AACL,SAAA;AACF;IAEA,OAAO;QACL4B,OAAS,EAAA,KAAA;AACT,QAAA,GAAG5B;AACL,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useI18n.js","sources":["../../../admin/src/hooks/useI18n.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useAuth } from '@strapi/admin/strapi-admin';\nimport { unstable_useDocument as useDocument } from '@strapi/content-manager/strapi-admin';\nimport union from 'lodash/union';\nimport { useParams } from 'react-router-dom';\n\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { capitalize } from '../utils/strings';\n\ntype UseI18n = () => {\n hasI18n: boolean;\n canCreate: string[];\n canRead: string[];\n canUpdate: string[];\n canDelete: string[];\n canPublish: string[];\n};\n\ntype I18nPermissionKeys = keyof Omit<ReturnType<UseI18n>, 'hasI18n'>;\n\n/**\n * @alpha\n * @description This hook is used to get the i18n status of a content type.\n * Also returns the CRUDP permission locale properties for the content type\n * so we know which locales the user can perform actions on.\n */\nconst useI18n: UseI18n = () => {\n // Extract the params from the URL to pass to our useDocument hook\n const params = useParams<{ collectionType: string; slug: string; model: string }>();\n\n const userPermissions = useAuth('useI18n', (state) => state.permissions);\n const actions = React.useMemo(() => {\n const permissions = userPermissions.filter((permission) => permission.subject === params.slug);\n\n return permissions.reduce<Record<I18nPermissionKeys, string[]>>(\n (acc, permission) => {\n const [actionShorthand] = permission.action.split('.').slice(-1);\n const permissionKey = `can${capitalize(actionShorthand)}` as I18nPermissionKeys;\n\n acc[permissionKey] = union(acc[permissionKey] ?? [], permission.properties?.locales ?? []);\n\n return acc;\n },\n { canCreate: [], canRead: [], canUpdate: [], canDelete: [], canPublish: [] }\n );\n }, [params.slug, userPermissions]);\n\n // TODO: use specific hook to get schema only\n const { schema } = useDocument(\n {\n // We can non-null assert these because below we skip the query if they are not present\n collectionType: params.collectionType!,\n model: params.slug!,\n },\n {\n skip: true,\n }\n );\n\n if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {\n return {\n hasI18n: schema.pluginOptions.i18n.localized,\n ...actions,\n };\n }\n\n return {\n hasI18n: false,\n ...actions,\n };\n};\n\nexport { useI18n };\n"],"names":["useI18n","params","useParams","userPermissions","useAuth","state","permissions","actions","React","useMemo","filter","permission","subject","slug","reduce","acc","actionShorthand","action","split","slice","permissionKey","capitalize","union","properties","locales","canCreate","canRead","canUpdate","canDelete","canPublish","schema","useDocument","collectionType","model","skip","doesPluginOptionsHaveI18nLocalized","pluginOptions","hasI18n","i18n","localized"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAqBA;;;;;AAKC,UACKA,OAAmB,GAAA,IAAA;;AAEvB,IAAA,MAAMC,MAASC,GAAAA,wBAAAA,EAAAA;AAEf,IAAA,MAAMC,kBAAkBC,mBAAQ,CAAA,SAAA,EAAW,CAACC,KAAAA,GAAUA,MAAMC,WAAW,CAAA;IACvE,MAAMC,OAAAA,GAAUC,gBAAMC,CAAAA,OAAO,CAAC,IAAA;QAC5B,MAAMH,WAAAA,GAAcH,eAAgBO,CAAAA,MAAM,CAAC,CAACC,aAAeA,UAAWC,CAAAA,OAAO,KAAKX,MAAAA,CAAOY,IAAI,CAAA;AAE7F,QAAA,OAAOP,WAAYQ,CAAAA,MAAM,CACvB,CAACC,GAAKJ,EAAAA,UAAAA,GAAAA;YACJ,MAAM,CAACK,eAAgB,CAAA,GAAGL,UAAWM,CAAAA,MAAM,CAACC,KAAK,CAAC,GAAA,CAAA,CAAKC,KAAK,CAAC,CAAC,CAAA,CAAA;AAC9D,YAAA,MAAMC,aAAgB,GAAA,CAAC,GAAG,EAAEC,mBAAWL,eAAkB,CAAA,CAAA,CAAA;AAEzDD,YAAAA,GAAG,CAACK,aAAAA,CAAc,GAAGE,KAAAA,CAAMP,GAAG,CAACK,aAAAA,CAAc,IAAI,EAAE,EAAET,UAAAA,CAAWY,UAAU,EAAEC,WAAW,EAAE,CAAA;YAEzF,OAAOT,GAAAA;SAET,EAAA;AAAEU,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,OAAAA,EAAS,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,UAAAA,EAAY;AAAG,SAAA,CAAA;KAE5E,EAAA;AAAC5B,QAAAA,MAAAA,CAAOY,IAAI;AAAEV,QAAAA;AAAgB,KAAA,CAAA;;AAGjC,IAAA,MAAM,EAAE2B,MAAM,EAAE,GAAGC,kCACjB,CAAA;;AAEEC,QAAAA,cAAAA,EAAgB/B,OAAO+B,cAAc;AACrCC,QAAAA,KAAAA,EAAOhC,OAAOY;KAEhB,EAAA;QACEqB,IAAM,EAAA;AACR,KAAA,CAAA;IAGF,IAAIC,yCAAAA,CAAmCL,QAAQM,aAAgB,CAAA,EAAA;QAC7D,OAAO;AACLC,YAAAA,OAAAA,EAASP,MAAOM,CAAAA,aAAa,CAACE,IAAI,CAACC,SAAS;AAC5C,YAAA,GAAGhC;AACL,SAAA;AACF;IAEA,OAAO;QACL8B,OAAS,EAAA,KAAA;AACT,QAAA,GAAG9B;AACL,KAAA;AACF;;;;"}
@@ -1,6 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { useAuth } from '@strapi/admin/strapi-admin';
3
3
  import { unstable_useDocument } from '@strapi/content-manager/strapi-admin';
4
+ import union from 'lodash/union';
4
5
  import { useParams } from 'react-router-dom';
5
6
  import { doesPluginOptionsHaveI18nLocalized } from '../utils/fields.mjs';
6
7
  import { capitalize } from '../utils/strings.mjs';
@@ -18,10 +19,9 @@ import { capitalize } from '../utils/strings.mjs';
18
19
  const permissions = userPermissions.filter((permission)=>permission.subject === params.slug);
19
20
  return permissions.reduce((acc, permission)=>{
20
21
  const [actionShorthand] = permission.action.split('.').slice(-1);
21
- return {
22
- ...acc,
23
- [`can${capitalize(actionShorthand)}`]: permission.properties?.locales ?? []
24
- };
22
+ const permissionKey = `can${capitalize(actionShorthand)}`;
23
+ acc[permissionKey] = union(acc[permissionKey] ?? [], permission.properties?.locales ?? []);
24
+ return acc;
25
25
  }, {
26
26
  canCreate: [],
27
27
  canRead: [],
@@ -1 +1 @@
1
- {"version":3,"file":"useI18n.mjs","sources":["../../../admin/src/hooks/useI18n.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useAuth } from '@strapi/admin/strapi-admin';\nimport { unstable_useDocument as useDocument } from '@strapi/content-manager/strapi-admin';\nimport { useParams } from 'react-router-dom';\n\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { capitalize } from '../utils/strings';\n\ntype UseI18n = () => {\n hasI18n: boolean;\n canCreate: string[];\n canRead: string[];\n canUpdate: string[];\n canDelete: string[];\n canPublish: string[];\n};\n\n/**\n * @alpha\n * @description This hook is used to get the i18n status of a content type.\n * Also returns the CRUDP permission locale properties for the content type\n * so we know which locales the user can perform actions on.\n */\nconst useI18n: UseI18n = () => {\n // Extract the params from the URL to pass to our useDocument hook\n const params = useParams<{ collectionType: string; slug: string; model: string }>();\n\n const userPermissions = useAuth('useI18n', (state) => state.permissions);\n const actions = React.useMemo(() => {\n const permissions = userPermissions.filter((permission) => permission.subject === params.slug);\n\n return permissions.reduce<Omit<ReturnType<UseI18n>, 'hasI18n'>>(\n (acc, permission) => {\n const [actionShorthand] = permission.action.split('.').slice(-1);\n\n return {\n ...acc,\n [`can${capitalize(actionShorthand)}`]: permission.properties?.locales ?? [],\n };\n },\n { canCreate: [], canRead: [], canUpdate: [], canDelete: [], canPublish: [] }\n );\n }, [params.slug, userPermissions]);\n\n // TODO: use specific hook to get schema only\n const { schema } = useDocument(\n {\n // We can non-null assert these because below we skip the query if they are not present\n collectionType: params.collectionType!,\n model: params.slug!,\n },\n {\n skip: true,\n }\n );\n\n if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {\n return {\n hasI18n: schema.pluginOptions.i18n.localized,\n ...actions,\n };\n }\n\n return {\n hasI18n: false,\n ...actions,\n };\n};\n\nexport { useI18n };\n"],"names":["useI18n","params","useParams","userPermissions","useAuth","state","permissions","actions","React","useMemo","filter","permission","subject","slug","reduce","acc","actionShorthand","action","split","slice","capitalize","properties","locales","canCreate","canRead","canUpdate","canDelete","canPublish","schema","useDocument","collectionType","model","skip","doesPluginOptionsHaveI18nLocalized","pluginOptions","hasI18n","i18n","localized"],"mappings":";;;;;;;AAkBA;;;;;AAKC,UACKA,OAAmB,GAAA,IAAA;;AAEvB,IAAA,MAAMC,MAASC,GAAAA,SAAAA,EAAAA;AAEf,IAAA,MAAMC,kBAAkBC,OAAQ,CAAA,SAAA,EAAW,CAACC,KAAAA,GAAUA,MAAMC,WAAW,CAAA;IACvE,MAAMC,OAAAA,GAAUC,KAAMC,CAAAA,OAAO,CAAC,IAAA;QAC5B,MAAMH,WAAAA,GAAcH,eAAgBO,CAAAA,MAAM,CAAC,CAACC,aAAeA,UAAWC,CAAAA,OAAO,KAAKX,MAAAA,CAAOY,IAAI,CAAA;AAE7F,QAAA,OAAOP,WAAYQ,CAAAA,MAAM,CACvB,CAACC,GAAKJ,EAAAA,UAAAA,GAAAA;YACJ,MAAM,CAACK,eAAgB,CAAA,GAAGL,UAAWM,CAAAA,MAAM,CAACC,KAAK,CAAC,GAAA,CAAA,CAAKC,KAAK,CAAC,CAAC,CAAA,CAAA;YAE9D,OAAO;AACL,gBAAA,GAAGJ,GAAG;AACN,gBAAA,CAAC,CAAC,GAAG,EAAEK,UAAAA,CAAWJ,eAAiB,CAAA,CAAA,CAAC,GAAGL,UAAWU,CAAAA,UAAU,EAAEC,OAAAA,IAAW;AAC3E,aAAA;SAEF,EAAA;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,OAAAA,EAAS,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,UAAAA,EAAY;AAAG,SAAA,CAAA;KAE5E,EAAA;AAAC1B,QAAAA,MAAAA,CAAOY,IAAI;AAAEV,QAAAA;AAAgB,KAAA,CAAA;;AAGjC,IAAA,MAAM,EAAEyB,MAAM,EAAE,GAAGC,oBACjB,CAAA;;AAEEC,QAAAA,cAAAA,EAAgB7B,OAAO6B,cAAc;AACrCC,QAAAA,KAAAA,EAAO9B,OAAOY;KAEhB,EAAA;QACEmB,IAAM,EAAA;AACR,KAAA,CAAA;IAGF,IAAIC,kCAAAA,CAAmCL,QAAQM,aAAgB,CAAA,EAAA;QAC7D,OAAO;AACLC,YAAAA,OAAAA,EAASP,MAAOM,CAAAA,aAAa,CAACE,IAAI,CAACC,SAAS;AAC5C,YAAA,GAAG9B;AACL,SAAA;AACF;IAEA,OAAO;QACL4B,OAAS,EAAA,KAAA;AACT,QAAA,GAAG5B;AACL,KAAA;AACF;;;;"}
1
+ {"version":3,"file":"useI18n.mjs","sources":["../../../admin/src/hooks/useI18n.ts"],"sourcesContent":["import * as React from 'react';\n\nimport { useAuth } from '@strapi/admin/strapi-admin';\nimport { unstable_useDocument as useDocument } from '@strapi/content-manager/strapi-admin';\nimport union from 'lodash/union';\nimport { useParams } from 'react-router-dom';\n\nimport { doesPluginOptionsHaveI18nLocalized } from '../utils/fields';\nimport { capitalize } from '../utils/strings';\n\ntype UseI18n = () => {\n hasI18n: boolean;\n canCreate: string[];\n canRead: string[];\n canUpdate: string[];\n canDelete: string[];\n canPublish: string[];\n};\n\ntype I18nPermissionKeys = keyof Omit<ReturnType<UseI18n>, 'hasI18n'>;\n\n/**\n * @alpha\n * @description This hook is used to get the i18n status of a content type.\n * Also returns the CRUDP permission locale properties for the content type\n * so we know which locales the user can perform actions on.\n */\nconst useI18n: UseI18n = () => {\n // Extract the params from the URL to pass to our useDocument hook\n const params = useParams<{ collectionType: string; slug: string; model: string }>();\n\n const userPermissions = useAuth('useI18n', (state) => state.permissions);\n const actions = React.useMemo(() => {\n const permissions = userPermissions.filter((permission) => permission.subject === params.slug);\n\n return permissions.reduce<Record<I18nPermissionKeys, string[]>>(\n (acc, permission) => {\n const [actionShorthand] = permission.action.split('.').slice(-1);\n const permissionKey = `can${capitalize(actionShorthand)}` as I18nPermissionKeys;\n\n acc[permissionKey] = union(acc[permissionKey] ?? [], permission.properties?.locales ?? []);\n\n return acc;\n },\n { canCreate: [], canRead: [], canUpdate: [], canDelete: [], canPublish: [] }\n );\n }, [params.slug, userPermissions]);\n\n // TODO: use specific hook to get schema only\n const { schema } = useDocument(\n {\n // We can non-null assert these because below we skip the query if they are not present\n collectionType: params.collectionType!,\n model: params.slug!,\n },\n {\n skip: true,\n }\n );\n\n if (doesPluginOptionsHaveI18nLocalized(schema?.pluginOptions)) {\n return {\n hasI18n: schema.pluginOptions.i18n.localized,\n ...actions,\n };\n }\n\n return {\n hasI18n: false,\n ...actions,\n };\n};\n\nexport { useI18n };\n"],"names":["useI18n","params","useParams","userPermissions","useAuth","state","permissions","actions","React","useMemo","filter","permission","subject","slug","reduce","acc","actionShorthand","action","split","slice","permissionKey","capitalize","union","properties","locales","canCreate","canRead","canUpdate","canDelete","canPublish","schema","useDocument","collectionType","model","skip","doesPluginOptionsHaveI18nLocalized","pluginOptions","hasI18n","i18n","localized"],"mappings":";;;;;;;;AAqBA;;;;;AAKC,UACKA,OAAmB,GAAA,IAAA;;AAEvB,IAAA,MAAMC,MAASC,GAAAA,SAAAA,EAAAA;AAEf,IAAA,MAAMC,kBAAkBC,OAAQ,CAAA,SAAA,EAAW,CAACC,KAAAA,GAAUA,MAAMC,WAAW,CAAA;IACvE,MAAMC,OAAAA,GAAUC,KAAMC,CAAAA,OAAO,CAAC,IAAA;QAC5B,MAAMH,WAAAA,GAAcH,eAAgBO,CAAAA,MAAM,CAAC,CAACC,aAAeA,UAAWC,CAAAA,OAAO,KAAKX,MAAAA,CAAOY,IAAI,CAAA;AAE7F,QAAA,OAAOP,WAAYQ,CAAAA,MAAM,CACvB,CAACC,GAAKJ,EAAAA,UAAAA,GAAAA;YACJ,MAAM,CAACK,eAAgB,CAAA,GAAGL,UAAWM,CAAAA,MAAM,CAACC,KAAK,CAAC,GAAA,CAAA,CAAKC,KAAK,CAAC,CAAC,CAAA,CAAA;AAC9D,YAAA,MAAMC,aAAgB,GAAA,CAAC,GAAG,EAAEC,WAAWL,eAAkB,CAAA,CAAA,CAAA;AAEzDD,YAAAA,GAAG,CAACK,aAAAA,CAAc,GAAGE,KAAAA,CAAMP,GAAG,CAACK,aAAAA,CAAc,IAAI,EAAE,EAAET,UAAAA,CAAWY,UAAU,EAAEC,WAAW,EAAE,CAAA;YAEzF,OAAOT,GAAAA;SAET,EAAA;AAAEU,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,OAAAA,EAAS,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,SAAAA,EAAW,EAAE;AAAEC,YAAAA,UAAAA,EAAY;AAAG,SAAA,CAAA;KAE5E,EAAA;AAAC5B,QAAAA,MAAAA,CAAOY,IAAI;AAAEV,QAAAA;AAAgB,KAAA,CAAA;;AAGjC,IAAA,MAAM,EAAE2B,MAAM,EAAE,GAAGC,oBACjB,CAAA;;AAEEC,QAAAA,cAAAA,EAAgB/B,OAAO+B,cAAc;AACrCC,QAAAA,KAAAA,EAAOhC,OAAOY;KAEhB,EAAA;QACEqB,IAAM,EAAA;AACR,KAAA,CAAA;IAGF,IAAIC,kCAAAA,CAAmCL,QAAQM,aAAgB,CAAA,EAAA;QAC7D,OAAO;AACLC,YAAAA,OAAAA,EAASP,MAAOM,CAAAA,aAAa,CAACE,IAAI,CAACC,SAAS;AAC5C,YAAA,GAAGhC;AACL,SAAA;AACF;IAEA,OAAO;QACL8B,OAAS,EAAA,KAAA;AACT,QAAA,GAAG9B;AACL,KAAA;AACF;;;;"}
@@ -104,6 +104,7 @@ var index = {
104
104
  });
105
105
  const contentManager = app.getPlugin('content-manager');
106
106
  contentManager.apis.addDocumentHeaderAction([
107
+ CMHeaderActions.AITranslationStatusAction,
107
108
  CMHeaderActions.LocalePickerAction,
108
109
  CMHeaderActions.FillFromAnotherLocaleAction
109
110
  ]);