@purposeinplay/payload-ai-translate 0.1.0

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 (301) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +714 -0
  3. package/dist/alerts-collection.d.ts +21 -0
  4. package/dist/alerts-collection.js +159 -0
  5. package/dist/api.d.ts +4 -0
  6. package/dist/api.js +918 -0
  7. package/dist/bulk-translate-batches-collection.d.ts +29 -0
  8. package/dist/bulk-translate-batches-collection.js +404 -0
  9. package/dist/bulk-translate-units-collection.d.ts +35 -0
  10. package/dist/bulk-translate-units-collection.js +310 -0
  11. package/dist/client/estimated-cost-cell.d.ts +6 -0
  12. package/dist/client/estimated-cost-cell.js +12 -0
  13. package/dist/client/excluded-fields-field.d.ts +45 -0
  14. package/dist/client/excluded-fields-field.js +553 -0
  15. package/dist/client/field-translate-button.d.ts +6 -0
  16. package/dist/client/field-translate-button.js +199 -0
  17. package/dist/client/index.d.ts +6 -0
  18. package/dist/client/index.js +6 -0
  19. package/dist/client/lib/use-global-kill-switches.d.ts +20 -0
  20. package/dist/client/lib/use-global-kill-switches.js +58 -0
  21. package/dist/client/translate-button.d.ts +2 -0
  22. package/dist/client/translate-button.js +228 -0
  23. package/dist/client/translate-modal.d.ts +16 -0
  24. package/dist/client/translate-modal.js +549 -0
  25. package/dist/client/translation-progress.d.ts +10 -0
  26. package/dist/client/translation-progress.js +297 -0
  27. package/dist/components/TranslationNavGroup.d.ts +45 -0
  28. package/dist/components/TranslationNavGroup.js +104 -0
  29. package/dist/defaults.d.ts +11 -0
  30. package/dist/defaults.js +16 -0
  31. package/dist/endpoints/client-config.d.ts +44 -0
  32. package/dist/endpoints/client-config.js +145 -0
  33. package/dist/endpoints/estimate.d.ts +5 -0
  34. package/dist/endpoints/estimate.js +237 -0
  35. package/dist/endpoints/progress.d.ts +2 -0
  36. package/dist/endpoints/progress.js +314 -0
  37. package/dist/endpoints/translate.d.ts +11 -0
  38. package/dist/endpoints/translate.js +376 -0
  39. package/dist/endpoints/translation-hub/_helpers.d.ts +140 -0
  40. package/dist/endpoints/translation-hub/_helpers.js +297 -0
  41. package/dist/endpoints/translation-hub/active.d.ts +21 -0
  42. package/dist/endpoints/translation-hub/active.js +220 -0
  43. package/dist/endpoints/translation-hub/cancel.d.ts +22 -0
  44. package/dist/endpoints/translation-hub/cancel.js +233 -0
  45. package/dist/endpoints/translation-hub/enqueue.d.ts +70 -0
  46. package/dist/endpoints/translation-hub/enqueue.js +529 -0
  47. package/dist/endpoints/translation-hub/failures.d.ts +12 -0
  48. package/dist/endpoints/translation-hub/failures.js +67 -0
  49. package/dist/endpoints/translation-hub/force-reset.d.ts +20 -0
  50. package/dist/endpoints/translation-hub/force-reset.js +144 -0
  51. package/dist/endpoints/translation-hub/index.d.ts +21 -0
  52. package/dist/endpoints/translation-hub/index.js +20 -0
  53. package/dist/endpoints/translation-hub/list.d.ts +40 -0
  54. package/dist/endpoints/translation-hub/list.js +182 -0
  55. package/dist/endpoints/translation-hub/preflight.d.ts +19 -0
  56. package/dist/endpoints/translation-hub/preflight.js +141 -0
  57. package/dist/endpoints/translation-hub/retry-failed.d.ts +38 -0
  58. package/dist/endpoints/translation-hub/retry-failed.js +235 -0
  59. package/dist/endpoints/translation-hub/revert.d.ts +88 -0
  60. package/dist/endpoints/translation-hub/revert.js +405 -0
  61. package/dist/endpoints/translation-hub/status.d.ts +45 -0
  62. package/dist/endpoints/translation-hub/status.js +391 -0
  63. package/dist/endpoints/translation-hub/usage-summary.d.ts +114 -0
  64. package/dist/endpoints/translation-hub/usage-summary.js +481 -0
  65. package/dist/exports/client.d.ts +6 -0
  66. package/dist/exports/client.js +6 -0
  67. package/dist/exports/components.d.ts +6 -0
  68. package/dist/exports/components.js +5 -0
  69. package/dist/exports/index.d.ts +8 -0
  70. package/dist/exports/index.js +7 -0
  71. package/dist/exports/providers.d.ts +9 -0
  72. package/dist/exports/providers.js +5 -0
  73. package/dist/exports/views-client.d.ts +23 -0
  74. package/dist/exports/views-client.js +22 -0
  75. package/dist/exports/views.d.ts +30 -0
  76. package/dist/exports/views.js +29 -0
  77. package/dist/hooks/after-change-global.d.ts +4 -0
  78. package/dist/hooks/after-change-global.js +109 -0
  79. package/dist/hooks/after-change.d.ts +16 -0
  80. package/dist/hooks/after-change.js +205 -0
  81. package/dist/hooks/after-delete.d.ts +30 -0
  82. package/dist/hooks/after-delete.js +95 -0
  83. package/dist/index.d.ts +5 -0
  84. package/dist/index.js +5 -0
  85. package/dist/jobs-collection.d.ts +17 -0
  86. package/dist/jobs-collection.js +139 -0
  87. package/dist/lexical/classifier.d.ts +3 -0
  88. package/dist/lexical/classifier.js +108 -0
  89. package/dist/lexical/deserializer.d.ts +4 -0
  90. package/dist/lexical/deserializer.js +263 -0
  91. package/dist/lexical/placeholder-integrity.d.ts +6 -0
  92. package/dist/lexical/placeholder-integrity.js +21 -0
  93. package/dist/lexical/placeholders.d.ts +21 -0
  94. package/dist/lexical/placeholders.js +117 -0
  95. package/dist/lexical/serializer.d.ts +21 -0
  96. package/dist/lexical/serializer.js +233 -0
  97. package/dist/lexical/types.d.ts +32 -0
  98. package/dist/lexical/types.js +1 -0
  99. package/dist/lib/auth-diagnostics.d.ts +14 -0
  100. package/dist/lib/auth-diagnostics.js +19 -0
  101. package/dist/lib/batch-counts.d.ts +58 -0
  102. package/dist/lib/batch-counts.js +105 -0
  103. package/dist/lib/bulk-translate-migrations.d.ts +92 -0
  104. package/dist/lib/bulk-translate-migrations.js +153 -0
  105. package/dist/lib/coalescing-queue.d.ts +38 -0
  106. package/dist/lib/coalescing-queue.js +69 -0
  107. package/dist/lib/content-extractor.d.ts +16 -0
  108. package/dist/lib/content-extractor.js +410 -0
  109. package/dist/lib/content-hash.d.ts +1 -0
  110. package/dist/lib/content-hash.js +19 -0
  111. package/dist/lib/content-patcher.d.ts +15 -0
  112. package/dist/lib/content-patcher.js +293 -0
  113. package/dist/lib/cost-guards.d.ts +2 -0
  114. package/dist/lib/cost-guards.js +18 -0
  115. package/dist/lib/daily-spend-cap.d.ts +58 -0
  116. package/dist/lib/daily-spend-cap.js +233 -0
  117. package/dist/lib/effective-locales.d.ts +181 -0
  118. package/dist/lib/effective-locales.js +302 -0
  119. package/dist/lib/error-messages.d.ts +245 -0
  120. package/dist/lib/error-messages.js +626 -0
  121. package/dist/lib/events.d.ts +39 -0
  122. package/dist/lib/events.js +146 -0
  123. package/dist/lib/exclude-fields.d.ts +3 -0
  124. package/dist/lib/exclude-fields.js +64 -0
  125. package/dist/lib/field-breadcrumb.d.ts +31 -0
  126. package/dist/lib/field-breadcrumb.js +227 -0
  127. package/dist/lib/field-diff.d.ts +1 -0
  128. package/dist/lib/field-diff.js +25 -0
  129. package/dist/lib/field-empty.d.ts +2 -0
  130. package/dist/lib/field-empty.js +68 -0
  131. package/dist/lib/field-resolver.d.ts +3 -0
  132. package/dist/lib/field-resolver.js +164 -0
  133. package/dist/lib/group-soft-skips.d.ts +39 -0
  134. package/dist/lib/group-soft-skips.js +45 -0
  135. package/dist/lib/locale-merge.d.ts +44 -0
  136. package/dist/lib/locale-merge.js +357 -0
  137. package/dist/lib/locale-row-check.d.ts +30 -0
  138. package/dist/lib/locale-row-check.js +64 -0
  139. package/dist/lib/logger.d.ts +74 -0
  140. package/dist/lib/logger.js +97 -0
  141. package/dist/lib/manual-edit-guard.d.ts +128 -0
  142. package/dist/lib/manual-edit-guard.js +393 -0
  143. package/dist/lib/output-validation.d.ts +48 -0
  144. package/dist/lib/output-validation.js +148 -0
  145. package/dist/lib/payload-read.d.ts +16 -0
  146. package/dist/lib/payload-read.js +51 -0
  147. package/dist/lib/per-doc-claim.d.ts +90 -0
  148. package/dist/lib/per-doc-claim.js +140 -0
  149. package/dist/lib/per-doc-lock.d.ts +94 -0
  150. package/dist/lib/per-doc-lock.js +119 -0
  151. package/dist/lib/persist-usage.d.ts +91 -0
  152. package/dist/lib/persist-usage.js +116 -0
  153. package/dist/lib/progress-store.d.ts +103 -0
  154. package/dist/lib/progress-store.js +314 -0
  155. package/dist/lib/rate-limiter.d.ts +3 -0
  156. package/dist/lib/rate-limiter.js +53 -0
  157. package/dist/lib/snapshot-select.d.ts +43 -0
  158. package/dist/lib/snapshot-select.js +108 -0
  159. package/dist/lib/translate-prompt.d.ts +31 -0
  160. package/dist/lib/translate-prompt.js +66 -0
  161. package/dist/lib/translation-token-bucket.d.ts +57 -0
  162. package/dist/lib/translation-token-bucket.js +365 -0
  163. package/dist/lib/truncate-source-value.d.ts +1 -0
  164. package/dist/lib/truncate-source-value.js +27 -0
  165. package/dist/manual-edit-collection.d.ts +22 -0
  166. package/dist/manual-edit-collection.js +124 -0
  167. package/dist/plugin.d.ts +3 -0
  168. package/dist/plugin.js +934 -0
  169. package/dist/providers/ai-sdk-adapter.d.ts +35 -0
  170. package/dist/providers/ai-sdk-adapter.js +100 -0
  171. package/dist/providers/anthropic.d.ts +31 -0
  172. package/dist/providers/anthropic.js +66 -0
  173. package/dist/providers/custom.d.ts +36 -0
  174. package/dist/providers/custom.js +24 -0
  175. package/dist/providers/gemini.d.ts +20 -0
  176. package/dist/providers/gemini.js +48 -0
  177. package/dist/providers/mock.d.ts +2 -0
  178. package/dist/providers/mock.js +29 -0
  179. package/dist/providers/openai.d.ts +28 -0
  180. package/dist/providers/openai.js +69 -0
  181. package/dist/settings-global.d.ts +74 -0
  182. package/dist/settings-global.js +216 -0
  183. package/dist/tasks/bulk-translate-coordinator.d.ts +115 -0
  184. package/dist/tasks/bulk-translate-coordinator.js +708 -0
  185. package/dist/tasks/bulk-translate-doc-task.d.ts +142 -0
  186. package/dist/tasks/bulk-translate-doc-task.js +1000 -0
  187. package/dist/tasks/bulk-translate-janitor.d.ts +87 -0
  188. package/dist/tasks/bulk-translate-janitor.js +311 -0
  189. package/dist/tasks/translate-job-task.d.ts +51 -0
  190. package/dist/tasks/translate-job-task.js +154 -0
  191. package/dist/translate.d.ts +113 -0
  192. package/dist/translate.js +911 -0
  193. package/dist/translation-daily-spend-collection.d.ts +24 -0
  194. package/dist/translation-daily-spend-collection.js +133 -0
  195. package/dist/translation-rate-limits-collection.d.ts +30 -0
  196. package/dist/translation-rate-limits-collection.js +144 -0
  197. package/dist/types.d.ts +672 -0
  198. package/dist/types.js +1 -0
  199. package/dist/usage-collection.d.ts +14 -0
  200. package/dist/usage-collection.js +377 -0
  201. package/dist/views/BulkRunsHub/BatchRow.d.ts +32 -0
  202. package/dist/views/BulkRunsHub/BatchRow.js +1222 -0
  203. package/dist/views/BulkRunsHub/BucketRow.d.ts +62 -0
  204. package/dist/views/BulkRunsHub/BucketRow.js +982 -0
  205. package/dist/views/BulkRunsHub/BulkRunsHub.client.d.ts +18 -0
  206. package/dist/views/BulkRunsHub/BulkRunsHub.client.js +331 -0
  207. package/dist/views/BulkRunsHub/EmptyState.d.ts +6 -0
  208. package/dist/views/BulkRunsHub/EmptyState.js +64 -0
  209. package/dist/views/BulkRunsHub/FilterBar.d.ts +16 -0
  210. package/dist/views/BulkRunsHub/FilterBar.js +284 -0
  211. package/dist/views/BulkRunsHub/InFlightBanner.d.ts +14 -0
  212. package/dist/views/BulkRunsHub/InFlightBanner.js +59 -0
  213. package/dist/views/BulkRunsHub/StatusBadge.d.ts +64 -0
  214. package/dist/views/BulkRunsHub/StatusBadge.js +248 -0
  215. package/dist/views/BulkRunsHub/SummaryStrip.d.ts +22 -0
  216. package/dist/views/BulkRunsHub/SummaryStrip.js +249 -0
  217. package/dist/views/BulkRunsHub/bucket-grouping.d.ts +200 -0
  218. package/dist/views/BulkRunsHub/bucket-grouping.js +344 -0
  219. package/dist/views/BulkRunsHub/bucketFailureSummary.d.ts +9 -0
  220. package/dist/views/BulkRunsHub/bucketFailureSummary.js +36 -0
  221. package/dist/views/BulkRunsHub/dedupedStatusFetch.d.ts +5 -0
  222. package/dist/views/BulkRunsHub/dedupedStatusFetch.js +45 -0
  223. package/dist/views/BulkRunsHub/index.d.ts +17 -0
  224. package/dist/views/BulkRunsHub/index.js +80 -0
  225. package/dist/views/BulkRunsHub/urlFilters.d.ts +14 -0
  226. package/dist/views/BulkRunsHub/urlFilters.js +50 -0
  227. package/dist/views/BulkRunsHub/useBulkRunsList.d.ts +26 -0
  228. package/dist/views/BulkRunsHub/useBulkRunsList.js +204 -0
  229. package/dist/views/BulkRunsHub/useUrlFilters.d.ts +10 -0
  230. package/dist/views/BulkRunsHub/useUrlFilters.js +88 -0
  231. package/dist/views/TranslationHub/ActiveJobs.d.ts +6 -0
  232. package/dist/views/TranslationHub/ActiveJobs.js +320 -0
  233. package/dist/views/TranslationHub/AdvancedPanel.d.ts +17 -0
  234. package/dist/views/TranslationHub/AdvancedPanel.js +996 -0
  235. package/dist/views/TranslationHub/AlertBanner.d.ts +6 -0
  236. package/dist/views/TranslationHub/AlertBanner.js +568 -0
  237. package/dist/views/TranslationHub/AuditPanel.d.ts +6 -0
  238. package/dist/views/TranslationHub/AuditPanel.helpers.d.ts +44 -0
  239. package/dist/views/TranslationHub/AuditPanel.helpers.js +71 -0
  240. package/dist/views/TranslationHub/AuditPanel.js +1367 -0
  241. package/dist/views/TranslationHub/BulkTranslate.types.d.ts +242 -0
  242. package/dist/views/TranslationHub/BulkTranslate.types.js +36 -0
  243. package/dist/views/TranslationHub/BulkTranslateFailureDrawer.d.ts +19 -0
  244. package/dist/views/TranslationHub/BulkTranslateFailureDrawer.js +332 -0
  245. package/dist/views/TranslationHub/BulkTranslateMonitor.d.ts +28 -0
  246. package/dist/views/TranslationHub/BulkTranslateMonitor.js +305 -0
  247. package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.d.ts +3 -0
  248. package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.js +42 -0
  249. package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.d.ts +26 -0
  250. package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.js +95 -0
  251. package/dist/views/TranslationHub/BulkTranslatePreflightModal.d.ts +22 -0
  252. package/dist/views/TranslationHub/BulkTranslatePreflightModal.js +879 -0
  253. package/dist/views/TranslationHub/BulkTranslateTerminalCard.d.ts +29 -0
  254. package/dist/views/TranslationHub/BulkTranslateTerminalCard.js +445 -0
  255. package/dist/views/TranslationHub/BulkTranslateTrigger.d.ts +66 -0
  256. package/dist/views/TranslationHub/BulkTranslateTrigger.js +161 -0
  257. package/dist/views/TranslationHub/EditorRecentRunsPanel.d.ts +33 -0
  258. package/dist/views/TranslationHub/EditorRecentRunsPanel.js +290 -0
  259. package/dist/views/TranslationHub/Hub.client.d.ts +74 -0
  260. package/dist/views/TranslationHub/Hub.client.js +357 -0
  261. package/dist/views/TranslationHub/ModelCombobox.d.ts +14 -0
  262. package/dist/views/TranslationHub/ModelCombobox.js +415 -0
  263. package/dist/views/TranslationHub/PerCollectionConfig.d.ts +10 -0
  264. package/dist/views/TranslationHub/PerCollectionConfig.helpers.d.ts +16 -0
  265. package/dist/views/TranslationHub/PerCollectionConfig.helpers.js +19 -0
  266. package/dist/views/TranslationHub/PerCollectionConfig.js +759 -0
  267. package/dist/views/TranslationHub/SettingsRail.d.ts +11 -0
  268. package/dist/views/TranslationHub/SettingsRail.js +382 -0
  269. package/dist/views/TranslationHub/StatusStrip.d.ts +6 -0
  270. package/dist/views/TranslationHub/StatusStrip.js +451 -0
  271. package/dist/views/TranslationHub/UsageTable.d.ts +6 -0
  272. package/dist/views/TranslationHub/UsageTable.helpers.d.ts +69 -0
  273. package/dist/views/TranslationHub/UsageTable.helpers.js +49 -0
  274. package/dist/views/TranslationHub/UsageTable.js +1240 -0
  275. package/dist/views/TranslationHub/alertGrouping.d.ts +70 -0
  276. package/dist/views/TranslationHub/alertGrouping.js +99 -0
  277. package/dist/views/TranslationHub/index.d.ts +20 -0
  278. package/dist/views/TranslationHub/index.js +109 -0
  279. package/dist/views/TranslationHub/tabNavigation.d.ts +53 -0
  280. package/dist/views/TranslationHub/tabNavigation.js +74 -0
  281. package/dist/views/TranslationHub/terminalBannerVisibility.d.ts +33 -0
  282. package/dist/views/TranslationHub/terminalBannerVisibility.js +124 -0
  283. package/dist/views/TranslationHub/useBulkTranslateActive.d.ts +49 -0
  284. package/dist/views/TranslationHub/useBulkTranslateActive.js +251 -0
  285. package/dist/views/TranslationHub/useFocusTrap.d.ts +6 -0
  286. package/dist/views/TranslationHub/useFocusTrap.js +81 -0
  287. package/dist/views/TranslationHub/useTranslationHubUsageSummary.d.ts +77 -0
  288. package/dist/views/TranslationHub/useTranslationHubUsageSummary.js +267 -0
  289. package/dist/views/shared/EditorError.d.ts +97 -0
  290. package/dist/views/shared/EditorError.js +205 -0
  291. package/dist/views/shared/ModelCell.d.ts +18 -0
  292. package/dist/views/shared/ModelCell.js +31 -0
  293. package/dist/views/shared/docHref.d.ts +16 -0
  294. package/dist/views/shared/docHref.js +26 -0
  295. package/dist/views/shared/fetch-error-body.d.ts +25 -0
  296. package/dist/views/shared/fetch-error-body.js +42 -0
  297. package/dist/views/shared/filterPillStyle.d.ts +35 -0
  298. package/dist/views/shared/filterPillStyle.js +40 -0
  299. package/dist/views/shared/format.d.ts +75 -0
  300. package/dist/views/shared/format.js +131 -0
  301. package/package.json +141 -0
@@ -0,0 +1,11 @@
1
+ import type React from 'react';
2
+ import type { LocaleConfig, OpenRouterSettings, TranslationSettings } from './Hub.client.js';
3
+ interface Props {
4
+ basePath: string;
5
+ locales: LocaleConfig;
6
+ onSettingsChange: (ts: TranslationSettings | null, ors: OpenRouterSettings | null) => void;
7
+ openRouterSettings: OpenRouterSettings | null;
8
+ translationSettings: TranslationSettings | null;
9
+ }
10
+ export declare const SettingsRail: React.FC<Props>;
11
+ export {};
@@ -0,0 +1,382 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { useEffect, useRef, useState } from 'react';
4
+ import { ModelCombobox } from './ModelCombobox.js';
5
+ const SECTION_STYLE = {
6
+ background: 'var(--theme-elevation-50)',
7
+ border: '1px solid var(--theme-elevation-150)',
8
+ borderRadius: '6px',
9
+ padding: '1rem'
10
+ };
11
+ const LABEL_STYLE = {
12
+ display: 'block',
13
+ fontSize: '0.75rem',
14
+ fontWeight: 600,
15
+ textTransform: 'uppercase',
16
+ letterSpacing: '0.05em',
17
+ color: 'var(--theme-elevation-500)',
18
+ marginBottom: '0.5rem'
19
+ };
20
+ const SELECT_STYLE = {
21
+ width: '100%',
22
+ padding: '0.5rem 0.75rem',
23
+ background: 'var(--theme-elevation-50)',
24
+ border: '1px solid var(--theme-elevation-150)',
25
+ borderRadius: '4px',
26
+ color: 'var(--theme-elevation-1000)',
27
+ font: 'inherit'
28
+ };
29
+ export const SettingsRail = ({ basePath, translationSettings, openRouterSettings, locales, onSettingsChange })=>{
30
+ const [savingTs, setSavingTs] = useState(false);
31
+ const [savingOrs, setSavingOrs] = useState(false);
32
+ const [savedFlash, setSavedFlash] = useState(null);
33
+ const [saveError, setSaveError] = useState(null);
34
+ // Derive target locale codes from Payload's localization config —
35
+ // every locale OTHER than the default source locale. Replaces the
36
+ // prior hardcoded `TARGET_LOCALES = ['es', 'fr']`.
37
+ const targetLocales = locales.locales.filter((l)=>l.code !== locales.defaultLocale).map((l)=>l.code);
38
+ // Serialize all translation-settings writes through this queue so two
39
+ // rapid toggles can't race.
40
+ const tsQueueRef = useRef(Promise.resolve());
41
+ const tsSnapshotRef = useRef(translationSettings);
42
+ useEffect(()=>{
43
+ tsSnapshotRef.current = translationSettings;
44
+ }, [
45
+ translationSettings
46
+ ]);
47
+ useEffect(()=>{
48
+ if (!savedFlash) {
49
+ return;
50
+ }
51
+ const t = setTimeout(()=>setSavedFlash(null), 2000);
52
+ return ()=>clearTimeout(t);
53
+ }, [
54
+ savedFlash
55
+ ]);
56
+ async function patchGlobalRaw(slug, data) {
57
+ const res = await fetch(`${basePath}/api/globals/${slug}`, {
58
+ method: 'POST',
59
+ credentials: 'include',
60
+ headers: {
61
+ 'content-type': 'application/json'
62
+ },
63
+ body: JSON.stringify(data)
64
+ });
65
+ if (!res.ok) {
66
+ const text = await res.text();
67
+ throw new Error(`HTTP ${res.status}: ${text.slice(0, 200)}`);
68
+ }
69
+ const json = await res.json();
70
+ return json.result ?? json.doc ?? json;
71
+ }
72
+ /**
73
+ * Send ONLY the changed fields, not the full settings snapshot.
74
+ * Prevents clobbering concurrent admin edits to fields the Hub never
75
+ * touched (e.g. `perCollection` in another tab).
76
+ *
77
+ * Optimistically updates `tsSnapshotRef` AT CALL TIME so rapid bursts
78
+ * of clicks each compute their `next` value against the most recent
79
+ * intended state rather than the slow-to-settle React state.
80
+ */ async function saveTranslationSettings(partial) {
81
+ setSaveError(null);
82
+ setSavingTs(true);
83
+ if (tsSnapshotRef.current) {
84
+ tsSnapshotRef.current = {
85
+ ...tsSnapshotRef.current,
86
+ ...partial
87
+ };
88
+ }
89
+ const previous = tsQueueRef.current;
90
+ const work = previous.catch(()=>undefined).then(async ()=>{
91
+ const updated = await patchGlobalRaw('translation-settings', partial);
92
+ onSettingsChange(updated, null);
93
+ setSavedFlash('Translation settings saved');
94
+ });
95
+ const tail = work.finally(()=>{
96
+ if (tsQueueRef.current === tail) {
97
+ setSavingTs(false);
98
+ }
99
+ });
100
+ tsQueueRef.current = tail;
101
+ try {
102
+ await work;
103
+ } catch (e) {
104
+ setSaveError(e instanceof Error ? e.message : String(e));
105
+ }
106
+ }
107
+ async function saveOpenRouterModel(model) {
108
+ setSaveError(null);
109
+ setSavingOrs(true);
110
+ try {
111
+ const updated = await patchGlobalRaw('openrouter-settings', {
112
+ model
113
+ });
114
+ onSettingsChange(null, updated);
115
+ setSavedFlash('Model saved');
116
+ } catch (e) {
117
+ setSaveError(e instanceof Error ? e.message : String(e));
118
+ } finally{
119
+ setSavingOrs(false);
120
+ }
121
+ }
122
+ const activeProvider = translationSettings?.activeProvider ?? '';
123
+ const enabledLocales = translationSettings?.enabledTargetLocales ?? [];
124
+ // Three plugin-wide kill switches (v1.2.8). Missing / null on older
125
+ // rows is treated as "enabled" (back-compat default — matches the
126
+ // server-side `!== false` semantics in `getGlobalKillSwitches`).
127
+ const autoEnabled = translationSettings?.globalAutoTranslateEnabled !== false;
128
+ const manualEnabled = translationSettings?.globalManualTranslateEnabled !== false;
129
+ const bulkEnabled = translationSettings?.globalBulkTranslateEnabled !== false;
130
+ const anyKillSwitchOff = !autoEnabled || !manualEnabled || !bulkEnabled;
131
+ return /*#__PURE__*/ _jsxs(_Fragment, {
132
+ children: [
133
+ savedFlash && /*#__PURE__*/ _jsx("div", {
134
+ style: {
135
+ padding: '0.5rem 0.75rem',
136
+ background: 'var(--theme-success-100, #d1fae5)',
137
+ border: '1px solid var(--theme-success-500, #16a34a)',
138
+ borderRadius: '4px',
139
+ color: 'var(--theme-success-500, #16a34a)',
140
+ fontSize: '0.875rem'
141
+ },
142
+ children: savedFlash
143
+ }),
144
+ saveError && /*#__PURE__*/ _jsx("div", {
145
+ style: {
146
+ padding: '0.5rem 0.75rem',
147
+ background: 'var(--theme-error-100, #fee2e2)',
148
+ border: '1px solid var(--theme-error-500, #b91c1c)',
149
+ borderRadius: '4px',
150
+ color: 'var(--theme-error-500, #b91c1c)',
151
+ fontSize: '0.875rem'
152
+ },
153
+ children: saveError
154
+ }),
155
+ /*#__PURE__*/ _jsxs("section", {
156
+ "data-testid": "kill-switches-section",
157
+ style: {
158
+ ...SECTION_STYLE,
159
+ // When any switch is off, highlight the section in red so
160
+ // admins immediately see "translation is intentionally
161
+ // paused" rather than thinking the feature is broken.
162
+ borderColor: anyKillSwitchOff ? 'var(--theme-error-500, #b91c1c)' : 'var(--theme-elevation-150)',
163
+ borderWidth: anyKillSwitchOff ? '2px' : '1px'
164
+ },
165
+ children: [
166
+ /*#__PURE__*/ _jsxs("span", {
167
+ style: LABEL_STYLE,
168
+ children: [
169
+ "Kill switches",
170
+ ' ',
171
+ anyKillSwitchOff && /*#__PURE__*/ _jsx("span", {
172
+ style: {
173
+ color: 'var(--theme-error-500, #b91c1c)',
174
+ fontWeight: 700
175
+ },
176
+ children: "· paused"
177
+ })
178
+ ]
179
+ }),
180
+ /*#__PURE__*/ _jsx("div", {
181
+ style: {
182
+ display: 'flex',
183
+ flexDirection: 'column',
184
+ gap: '0.65rem'
185
+ },
186
+ children: [
187
+ {
188
+ key: 'globalAutoTranslateEnabled',
189
+ checked: autoEnabled,
190
+ label: 'Auto-translate (after-change hook)',
191
+ hint: 'When off, saving a tracked doc does NOT fire auto-translate. Manual + Bulk unaffected.'
192
+ },
193
+ {
194
+ key: 'globalManualTranslateEnabled',
195
+ checked: manualEnabled,
196
+ label: 'Manual Translate (dialog + per-field button)',
197
+ hint: 'When off, the Translate dialog and per-field button hide in the admin UI and the endpoint returns 403. Auto + Bulk unaffected.'
198
+ },
199
+ {
200
+ key: 'globalBulkTranslateEnabled',
201
+ checked: bulkEnabled,
202
+ label: 'Bulk Translate (new runs)',
203
+ hint: 'When off, new bulk runs are rejected and the Bulk trigger renders as "paused". In-flight runs continue. Auto + Manual unaffected.'
204
+ }
205
+ ].map((row)=>/*#__PURE__*/ _jsxs("label", {
206
+ style: {
207
+ display: 'flex',
208
+ gap: '0.55rem',
209
+ cursor: 'pointer',
210
+ alignItems: 'flex-start'
211
+ },
212
+ children: [
213
+ /*#__PURE__*/ _jsx("input", {
214
+ checked: row.checked,
215
+ "data-testid": `kill-switch-${row.key}`,
216
+ disabled: savingTs || !translationSettings,
217
+ onChange: (e)=>{
218
+ saveTranslationSettings({
219
+ [row.key]: e.target.checked
220
+ });
221
+ },
222
+ style: {
223
+ marginTop: '0.2rem'
224
+ },
225
+ type: "checkbox"
226
+ }),
227
+ /*#__PURE__*/ _jsxs("span", {
228
+ style: {
229
+ fontSize: '0.875rem',
230
+ color: 'var(--theme-elevation-800)',
231
+ display: 'flex',
232
+ flexDirection: 'column',
233
+ gap: '0.15rem'
234
+ },
235
+ children: [
236
+ /*#__PURE__*/ _jsx("span", {
237
+ style: {
238
+ fontWeight: 500
239
+ },
240
+ children: row.label
241
+ }),
242
+ /*#__PURE__*/ _jsx("span", {
243
+ style: {
244
+ fontSize: '0.75rem',
245
+ color: 'var(--theme-elevation-500)'
246
+ },
247
+ children: row.hint
248
+ })
249
+ ]
250
+ })
251
+ ]
252
+ }, row.key))
253
+ })
254
+ ]
255
+ }),
256
+ /*#__PURE__*/ _jsxs("section", {
257
+ style: SECTION_STYLE,
258
+ children: [
259
+ /*#__PURE__*/ _jsx("span", {
260
+ style: LABEL_STYLE,
261
+ children: "Active Provider"
262
+ }),
263
+ /*#__PURE__*/ _jsxs("select", {
264
+ disabled: savingTs || !translationSettings,
265
+ onChange: (e)=>saveTranslationSettings({
266
+ activeProvider: e.target.value || null
267
+ }),
268
+ style: SELECT_STYLE,
269
+ value: activeProvider ?? '',
270
+ children: [
271
+ /*#__PURE__*/ _jsx("option", {
272
+ value: "",
273
+ children: "— use default —"
274
+ }),
275
+ /*#__PURE__*/ _jsx("option", {
276
+ value: "anthropic-haiku",
277
+ children: "anthropic-haiku"
278
+ }),
279
+ /*#__PURE__*/ _jsx("option", {
280
+ value: "openai-mini",
281
+ children: "openai-mini"
282
+ }),
283
+ /*#__PURE__*/ _jsx("option", {
284
+ value: "openrouter",
285
+ children: "openrouter"
286
+ })
287
+ ]
288
+ }),
289
+ /*#__PURE__*/ _jsx("p", {
290
+ style: {
291
+ margin: '0.5rem 0 0',
292
+ fontSize: '0.75rem',
293
+ color: 'var(--theme-elevation-500)'
294
+ },
295
+ children: "Where translation calls are routed. Changes take effect on the next translate call (no restart)."
296
+ })
297
+ ]
298
+ }),
299
+ activeProvider === 'openrouter' && /*#__PURE__*/ _jsxs("section", {
300
+ style: SECTION_STYLE,
301
+ children: [
302
+ /*#__PURE__*/ _jsx("span", {
303
+ style: LABEL_STYLE,
304
+ children: "OpenRouter Model"
305
+ }),
306
+ /*#__PURE__*/ _jsx(ModelCombobox, {
307
+ basePath: basePath,
308
+ disabled: savingOrs,
309
+ onChange: saveOpenRouterModel,
310
+ value: openRouterSettings?.model ?? ''
311
+ })
312
+ ]
313
+ }),
314
+ /*#__PURE__*/ _jsxs("section", {
315
+ style: SECTION_STYLE,
316
+ children: [
317
+ /*#__PURE__*/ _jsx("span", {
318
+ style: LABEL_STYLE,
319
+ children: "Auto-translate locales"
320
+ }),
321
+ /*#__PURE__*/ _jsx("div", {
322
+ style: {
323
+ display: 'flex',
324
+ flexDirection: 'column',
325
+ gap: '0.4rem'
326
+ },
327
+ children: targetLocales.length === 0 ? /*#__PURE__*/ _jsx("p", {
328
+ style: {
329
+ margin: 0,
330
+ fontSize: '0.875rem',
331
+ color: 'var(--theme-elevation-500)'
332
+ },
333
+ children: "No target locales configured in the Payload localization config."
334
+ }) : targetLocales.map((loc)=>{
335
+ const isOn = enabledLocales.includes(loc);
336
+ const localeLabel = locales.locales.find((l)=>l.code === loc)?.label ?? loc;
337
+ return /*#__PURE__*/ _jsxs("label", {
338
+ style: {
339
+ display: 'flex',
340
+ alignItems: 'center',
341
+ gap: '0.5rem',
342
+ cursor: 'pointer',
343
+ fontSize: '0.875rem',
344
+ color: 'var(--theme-elevation-800)'
345
+ },
346
+ children: [
347
+ /*#__PURE__*/ _jsx("input", {
348
+ checked: isOn,
349
+ disabled: savingTs || !translationSettings,
350
+ onChange: (e)=>{
351
+ const current = tsSnapshotRef.current?.enabledTargetLocales ?? enabledLocales;
352
+ const next = e.target.checked ? Array.from(new Set([
353
+ ...current,
354
+ loc
355
+ ])) : current.filter((l)=>l !== loc);
356
+ saveTranslationSettings({
357
+ enabledTargetLocales: next
358
+ });
359
+ },
360
+ type: "checkbox"
361
+ }),
362
+ localeLabel,
363
+ " (",
364
+ loc.toUpperCase(),
365
+ ")"
366
+ ]
367
+ }, loc);
368
+ })
369
+ }),
370
+ /*#__PURE__*/ _jsx("p", {
371
+ style: {
372
+ margin: '0.5rem 0 0',
373
+ fontSize: '0.75rem',
374
+ color: 'var(--theme-elevation-500)'
375
+ },
376
+ children: "Empty = all enabled (back-compat). Manual translate is never gated by this list."
377
+ })
378
+ ]
379
+ })
380
+ ]
381
+ });
382
+ };
@@ -0,0 +1,6 @@
1
+ import type React from 'react';
2
+ interface Props {
3
+ basePath: string;
4
+ }
5
+ export declare const StatusStrip: React.FC<Props>;
6
+ export {};