@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,284 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { filterPillColors } from '../shared/filterPillStyle.js';
4
+ // ---------------------------------------------------------------------------
5
+ // Shared field style
6
+ // ---------------------------------------------------------------------------
7
+ const FIELD_STYLE = {
8
+ padding: '0.3rem 0.5rem',
9
+ fontSize: '0.8125rem',
10
+ background: 'var(--theme-elevation-50)',
11
+ border: '1px solid var(--theme-elevation-150)',
12
+ borderRadius: '4px',
13
+ color: 'var(--theme-elevation-1000)',
14
+ fontFamily: 'inherit'
15
+ };
16
+ const LABEL_STYLE = {
17
+ display: 'flex',
18
+ flexDirection: 'column',
19
+ gap: '0.25rem',
20
+ fontSize: '0.6875rem',
21
+ fontWeight: 600,
22
+ textTransform: 'uppercase',
23
+ letterSpacing: '0.05em',
24
+ color: 'var(--theme-elevation-500)'
25
+ };
26
+ // ---------------------------------------------------------------------------
27
+ // Status quick-pick chips
28
+ // ---------------------------------------------------------------------------
29
+ const STATUS_CHIPS = [
30
+ {
31
+ label: 'All',
32
+ value: ''
33
+ },
34
+ {
35
+ label: 'Active',
36
+ value: 'active'
37
+ },
38
+ {
39
+ label: 'Terminal',
40
+ value: 'terminal'
41
+ },
42
+ {
43
+ label: 'Running',
44
+ value: 'running'
45
+ },
46
+ {
47
+ label: 'Failed',
48
+ value: 'failed'
49
+ },
50
+ {
51
+ label: 'Partial',
52
+ value: 'partial'
53
+ },
54
+ {
55
+ label: 'Cancelled',
56
+ value: 'cancelled'
57
+ }
58
+ ];
59
+ const MODE_OPTIONS = [
60
+ {
61
+ label: 'All modes',
62
+ value: ''
63
+ },
64
+ {
65
+ label: 'Changed',
66
+ value: 'changed'
67
+ },
68
+ {
69
+ label: 'Force',
70
+ value: 'force'
71
+ },
72
+ {
73
+ label: 'Canary',
74
+ value: 'canary'
75
+ }
76
+ ];
77
+ /**
78
+ * NEW-19 (v1.2.6): true when both Since and Until are set but Until
79
+ * precedes Since. Pure helper so the inline error / aria-invalid /
80
+ * input min-max can all read the same source of truth.
81
+ */ export function dateRangeInvalid(filters) {
82
+ if (!filters.since || !filters.until) return false;
83
+ return new Date(filters.until).getTime() < new Date(filters.since).getTime();
84
+ }
85
+ export const FilterBar = ({ filters, onChange, batches })=>{
86
+ // Derive distinct triggeredBy values from loaded data for autocomplete.
87
+ const triggeredByOptions = Array.from(new Set(batches.map((b)=>b.triggeredByEmail).filter((e)=>typeof e === 'string' && e.length > 0)));
88
+ const invalidDates = dateRangeInvalid(filters);
89
+ return /*#__PURE__*/ _jsxs("div", {
90
+ style: {
91
+ display: 'flex',
92
+ flexDirection: 'column',
93
+ gap: '0.5rem'
94
+ },
95
+ children: [
96
+ /*#__PURE__*/ _jsxs("div", {
97
+ style: {
98
+ display: 'flex',
99
+ flexWrap: 'wrap',
100
+ gap: '1rem',
101
+ padding: '0.75rem 1rem',
102
+ background: 'var(--theme-elevation-50)',
103
+ border: '1px solid var(--theme-elevation-150)',
104
+ borderRadius: '6px',
105
+ alignItems: 'flex-end'
106
+ },
107
+ children: [
108
+ /*#__PURE__*/ _jsxs("label", {
109
+ style: LABEL_STYLE,
110
+ "aria-label": "Filter the batch list by status",
111
+ children: [
112
+ "Batch status",
113
+ /*#__PURE__*/ _jsx("div", {
114
+ style: {
115
+ display: 'flex',
116
+ flexWrap: 'wrap',
117
+ gap: '0.25rem'
118
+ },
119
+ children: STATUS_CHIPS.map((chip)=>{
120
+ const isActive = filters.status === chip.value;
121
+ const colors = filterPillColors(isActive);
122
+ return /*#__PURE__*/ _jsx("button", {
123
+ "aria-pressed": isActive,
124
+ type: "button",
125
+ onClick: ()=>onChange({
126
+ status: chip.value
127
+ }),
128
+ style: {
129
+ padding: '0.2rem 0.55rem',
130
+ fontSize: '0.75rem',
131
+ borderRadius: '4px',
132
+ border: colors.border,
133
+ background: colors.background,
134
+ color: colors.color,
135
+ cursor: 'pointer',
136
+ fontWeight: isActive ? 600 : 400
137
+ },
138
+ children: chip.label
139
+ }, chip.value || 'all');
140
+ })
141
+ })
142
+ ]
143
+ }),
144
+ /*#__PURE__*/ _jsxs("label", {
145
+ style: LABEL_STYLE,
146
+ children: [
147
+ "Mode",
148
+ /*#__PURE__*/ _jsx("select", {
149
+ value: filters.mode,
150
+ onChange: (e)=>onChange({
151
+ mode: e.target.value
152
+ }),
153
+ style: FIELD_STYLE,
154
+ children: MODE_OPTIONS.map((o)=>/*#__PURE__*/ _jsx("option", {
155
+ value: o.value,
156
+ children: o.label
157
+ }, o.value))
158
+ })
159
+ ]
160
+ }),
161
+ /*#__PURE__*/ _jsxs("label", {
162
+ style: LABEL_STYLE,
163
+ children: [
164
+ "Triggered by",
165
+ /*#__PURE__*/ _jsxs("div", {
166
+ style: {
167
+ position: 'relative'
168
+ },
169
+ children: [
170
+ /*#__PURE__*/ _jsx("input", {
171
+ list: "bulk-runs-triggered-by-list",
172
+ type: "text",
173
+ placeholder: "Email…",
174
+ value: filters.triggeredBy,
175
+ onChange: (e)=>onChange({
176
+ triggeredBy: e.target.value
177
+ }),
178
+ style: {
179
+ ...FIELD_STYLE,
180
+ minWidth: '160px'
181
+ }
182
+ }),
183
+ /*#__PURE__*/ _jsx("datalist", {
184
+ id: "bulk-runs-triggered-by-list",
185
+ children: triggeredByOptions.map((email)=>/*#__PURE__*/ _jsx("option", {
186
+ value: email
187
+ }, email))
188
+ })
189
+ ]
190
+ })
191
+ ]
192
+ }),
193
+ /*#__PURE__*/ _jsxs("label", {
194
+ style: LABEL_STYLE,
195
+ children: [
196
+ "Since",
197
+ /*#__PURE__*/ _jsx("input", {
198
+ type: "date",
199
+ value: filters.since ? filters.since.slice(0, 10) : '',
200
+ max: filters.until ? filters.until.slice(0, 10) : undefined,
201
+ onChange: (e)=>onChange({
202
+ since: e.target.value ? `${e.target.value}T00:00:00.000Z` : ''
203
+ }),
204
+ style: FIELD_STYLE,
205
+ "aria-invalid": dateRangeInvalid(filters)
206
+ })
207
+ ]
208
+ }),
209
+ /*#__PURE__*/ _jsxs("label", {
210
+ style: LABEL_STYLE,
211
+ children: [
212
+ "Until",
213
+ /*#__PURE__*/ _jsx("input", {
214
+ type: "date",
215
+ value: filters.until ? filters.until.slice(0, 10) : '',
216
+ min: filters.since ? filters.since.slice(0, 10) : undefined,
217
+ onChange: (e)=>onChange({
218
+ until: e.target.value ? `${e.target.value}T23:59:59.999Z` : ''
219
+ }),
220
+ style: FIELD_STYLE,
221
+ "aria-invalid": dateRangeInvalid(filters)
222
+ })
223
+ ]
224
+ }),
225
+ /*#__PURE__*/ _jsxs("label", {
226
+ style: {
227
+ ...LABEL_STYLE,
228
+ flexDirection: 'row',
229
+ alignItems: 'center',
230
+ gap: '0.4rem',
231
+ cursor: 'pointer'
232
+ },
233
+ children: [
234
+ /*#__PURE__*/ _jsx("input", {
235
+ type: "checkbox",
236
+ checked: filters.hasFailures,
237
+ onChange: (e)=>onChange({
238
+ hasFailures: e.target.checked
239
+ }),
240
+ style: {
241
+ cursor: 'pointer'
242
+ }
243
+ }),
244
+ "Has failures"
245
+ ]
246
+ }),
247
+ (filters.status || filters.mode || filters.triggeredBy || filters.since || filters.until || filters.hasFailures) && /*#__PURE__*/ _jsx("button", {
248
+ type: "button",
249
+ onClick: ()=>onChange({
250
+ status: '',
251
+ mode: '',
252
+ triggeredBy: '',
253
+ since: '',
254
+ until: '',
255
+ hasFailures: false
256
+ }),
257
+ style: {
258
+ padding: '0.3rem 0.6rem',
259
+ fontSize: '0.75rem',
260
+ background: 'transparent',
261
+ border: '1px solid var(--theme-elevation-200)',
262
+ borderRadius: '4px',
263
+ color: 'var(--theme-elevation-600)',
264
+ cursor: 'pointer'
265
+ },
266
+ children: "Clear filters"
267
+ })
268
+ ]
269
+ }),
270
+ invalidDates && /*#__PURE__*/ _jsx("div", {
271
+ role: "alert",
272
+ style: {
273
+ padding: '0.5rem 0.75rem',
274
+ background: 'var(--theme-error-100, #fee2e2)',
275
+ border: '1px solid var(--theme-error-500, #b91c1c)',
276
+ borderRadius: '4px',
277
+ color: 'var(--theme-error-800, #7f1d1d)',
278
+ fontSize: '0.8125rem'
279
+ },
280
+ children: "Invalid date range — Until precedes Since. The table is hidden until you fix the range."
281
+ })
282
+ ]
283
+ });
284
+ };
@@ -0,0 +1,14 @@
1
+ import type React from 'react';
2
+ import type { BulkTranslateBatchSummary } from '../TranslationHub/BulkTranslate.types.js';
3
+ interface Props {
4
+ batches: BulkTranslateBatchSummary[];
5
+ }
6
+ /**
7
+ * Slim status banner shown at the top of the runs list when at least one
8
+ * batch is in an active status (queued / running / cancelling).
9
+ *
10
+ * The `●` glyph pulses via a CSS keyframe injected inline — consistent
11
+ * with the StatusBadge running animation but isolated to the banner dot.
12
+ */
13
+ export declare const InFlightBanner: React.FC<Props>;
14
+ export {};
@@ -0,0 +1,59 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
+ import { isActiveStatus } from '../TranslationHub/BulkTranslate.types.js';
4
+ /**
5
+ * Slim status banner shown at the top of the runs list when at least one
6
+ * batch is in an active status (queued / running / cancelling).
7
+ *
8
+ * The `●` glyph pulses via a CSS keyframe injected inline — consistent
9
+ * with the StatusBadge running animation but isolated to the banner dot.
10
+ */ export const InFlightBanner = ({ batches })=>{
11
+ const activeCount = batches.filter((b)=>isActiveStatus(b.status)).length;
12
+ if (activeCount === 0) return null;
13
+ const label = activeCount === 1 ? '1 run in progress' : `${activeCount} runs in progress`;
14
+ return /*#__PURE__*/ _jsxs(_Fragment, {
15
+ children: [
16
+ /*#__PURE__*/ _jsx("style", {
17
+ children: `
18
+ @keyframes bulk-runs-dot-pulse {
19
+ 0%, 100% { opacity: 1; }
20
+ 50% { opacity: 0.35; }
21
+ }
22
+ @media (prefers-reduced-motion: reduce) {
23
+ .bulk-runs-dot { animation: none !important; }
24
+ }
25
+ `
26
+ }),
27
+ /*#__PURE__*/ _jsxs("div", {
28
+ role: "status",
29
+ "aria-live": "polite",
30
+ style: {
31
+ display: 'flex',
32
+ alignItems: 'center',
33
+ gap: '0.5rem',
34
+ padding: '0.4rem 0.75rem',
35
+ background: 'var(--theme-elevation-50)',
36
+ border: '1px solid var(--theme-success-300, #86efac)',
37
+ borderRadius: '4px',
38
+ fontSize: '0.8125rem',
39
+ color: 'var(--theme-success-500, #16a34a)'
40
+ },
41
+ children: [
42
+ /*#__PURE__*/ _jsx("span", {
43
+ className: "bulk-runs-dot",
44
+ "aria-hidden": "true",
45
+ style: {
46
+ fontSize: '0.6rem',
47
+ animationName: 'bulk-runs-dot-pulse',
48
+ animationDuration: '1.4s',
49
+ animationTimingFunction: 'ease-in-out',
50
+ animationIterationCount: 'infinite'
51
+ },
52
+ children: "●"
53
+ }),
54
+ label
55
+ ]
56
+ })
57
+ ]
58
+ });
59
+ };
@@ -0,0 +1,64 @@
1
+ import type React from 'react';
2
+ import type { BulkTranslateBatchStatus } from '../TranslationHub/BulkTranslate.types.js';
3
+ /** Test-only: reset the once-per-status warning de-dupe set. */
4
+ export declare function __resetStatusBadgeWarnings(): void;
5
+ export type ResolvedBadge = {
6
+ kind: 'known';
7
+ label: string;
8
+ } | {
9
+ kind: 'fallback';
10
+ label: string;
11
+ };
12
+ /**
13
+ * Pure resolver for the batch-level status badge. Returns the display
14
+ * label and a `kind` discriminator so tests can pin BR-3 fallback
15
+ * behaviour without rendering React or relying on CSS-token strings.
16
+ *
17
+ * `kind: 'known'` — STATUS_CONFIG had an entry; label is the friendly
18
+ * display string (e.g. 'succeeded' for 'success',
19
+ * 'running' for 'running').
20
+ * `kind: 'fallback'` — STATUS_CONFIG had no entry; label echoes the raw
21
+ * input so editors still see something useful in
22
+ * the row (BR-3).
23
+ */
24
+ export declare function resolveBatchStatusBadge(status: string): ResolvedBadge;
25
+ /**
26
+ * Pure resolver for unit-level status badges. Mirrors
27
+ * `resolveBatchStatusBadge` but uses the unit-status color map so
28
+ * `'completed'` (older API revision) and `'succeeded'` both normalise
29
+ * to the same `success` chip. Returns fallback for any value outside
30
+ * the known set.
31
+ */
32
+ export declare function resolveUnitStatusBadge(status: string): ResolvedBadge;
33
+ interface StatusBadgeProps {
34
+ status: BulkTranslateBatchStatus;
35
+ /** Render at the smaller unit-table size (0.65rem vs 0.7rem). */
36
+ small?: boolean;
37
+ }
38
+ interface UnitStatusBadgeProps {
39
+ status: string;
40
+ small?: boolean;
41
+ }
42
+ /**
43
+ * Renders a status pill for a batch row.
44
+ * The `running` state gets a CSS pulse animation on its background.
45
+ * Storage value `'success'` displays as "succeeded" — matches the
46
+ * unit-level vocabulary used in the Hub's Recent translations table
47
+ * and the AuditPanel KPIs. v1.2.5 used "completed" here; v1.2.6 fixes
48
+ * the vocab split (BR-8).
49
+ */
50
+ export declare const StatusBadge: React.FC<StatusBadgeProps>;
51
+ /**
52
+ * Same visual treatment but for unit-level statuses (pending / running /
53
+ * success / failed / skipped / reverted). Uses `succeeded` as the
54
+ * display label for `success` to match the rest of the surface (BR-8).
55
+ */
56
+ export declare const UnitStatusBadge: React.FC<UnitStatusBadgeProps>;
57
+ /**
58
+ * Inject the running-badge keyframes once per page. Call this inside the
59
+ * client component that mounts StatusBadge. Using a `<style>` tag is the
60
+ * only viable approach in Payload's inline-style architecture (no CSS
61
+ * Modules, no Tailwind).
62
+ */
63
+ export declare const StatusBadgeKeyframes: React.FC;
64
+ export {};
@@ -0,0 +1,248 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ // Text colours pulled up to `-900` (or `-elevation-900` for neutrals) so
4
+ // chip text clears WCAG AA on the tinted backgrounds — v1.2.6 audit
5
+ // found the previous `-500` text ran 3.3–3.8:1, below the 4.5:1 bar.
6
+ // The `-900` token is ~rgb(19,44,58) on success and similar near-black
7
+ // shades on warning / error, giving 8:1+ on the `-100` tinted bg.
8
+ // Backgrounds stay tinted so the signal colour still reads at a glance.
9
+ // NEW-3.
10
+ const STATUS_CONFIG = {
11
+ queued: {
12
+ background: 'var(--theme-elevation-100)',
13
+ color: 'var(--theme-elevation-900)',
14
+ border: 'var(--theme-elevation-200)'
15
+ },
16
+ running: {
17
+ background: 'var(--theme-success-100, #dcfce7)',
18
+ color: 'var(--theme-success-900, #052e16)',
19
+ border: 'var(--theme-success-300, #86efac)',
20
+ animation: 'bulk-runs-pulse'
21
+ },
22
+ cancelling: {
23
+ background: 'var(--theme-warning-100, #fef3c7)',
24
+ color: 'var(--theme-warning-900, #422006)',
25
+ border: 'var(--theme-warning-300, #fcd34d)'
26
+ },
27
+ success: {
28
+ background: 'var(--theme-success-100, #dcfce7)',
29
+ color: 'var(--theme-success-900, #052e16)',
30
+ border: 'var(--theme-success-200, #bbf7d0)'
31
+ },
32
+ failed: {
33
+ background: 'var(--theme-error-100, #fee2e2)',
34
+ color: 'var(--theme-error-900, #450a0a)',
35
+ border: 'var(--theme-error-300, #fca5a5)'
36
+ },
37
+ partial: {
38
+ background: 'var(--theme-warning-100, #fef3c7)',
39
+ color: 'var(--theme-warning-900, #422006)',
40
+ border: 'var(--theme-warning-300, #fcd34d)'
41
+ },
42
+ cancelled: {
43
+ background: 'var(--theme-elevation-100)',
44
+ color: 'var(--theme-elevation-900)',
45
+ border: 'var(--theme-elevation-200)'
46
+ },
47
+ reverted: {
48
+ background: 'var(--theme-elevation-100)',
49
+ color: 'var(--theme-elevation-900)',
50
+ border: 'var(--theme-elevation-200)',
51
+ prefix: '↶'
52
+ }
53
+ };
54
+ // Unit-status badges (inside the drill-down unit table) use a narrower
55
+ // set. Map to the closest batch status for color reuse.
56
+ const UNIT_STATUS_COLOR_MAP = {
57
+ pending: STATUS_CONFIG.queued,
58
+ running: STATUS_CONFIG.running,
59
+ success: STATUS_CONFIG.success,
60
+ failed: STATUS_CONFIG.failed,
61
+ skipped: {
62
+ background: 'var(--theme-elevation-100)',
63
+ color: 'var(--theme-elevation-900)',
64
+ border: 'var(--theme-elevation-200)'
65
+ },
66
+ reverted: STATUS_CONFIG.reverted
67
+ };
68
+ // Tracks unknown status values we've already warned about so the
69
+ // console isn't spammed every re-render. Module-scope is fine — the
70
+ // set is purely diagnostic. Cleared in tests via `__resetStatusBadgeWarnings`.
71
+ const warnedUnknownStatuses = new Set();
72
+ function warnUnknownStatus(component, status) {
73
+ if (warnedUnknownStatuses.has(`${component}:${status}`)) return;
74
+ warnedUnknownStatuses.add(`${component}:${status}`);
75
+ // eslint-disable-next-line no-console
76
+ console.warn(`[ai-translate] ${component}: unknown status '${status}' — rendering raw value. ` + 'A new lifecycle state was likely added without a UI mapping; please update STATUS_CONFIG.');
77
+ }
78
+ /** Test-only: reset the once-per-status warning de-dupe set. */ export function __resetStatusBadgeWarnings() {
79
+ warnedUnknownStatuses.clear();
80
+ }
81
+ /**
82
+ * Pure resolver for the batch-level status badge. Returns the display
83
+ * label and a `kind` discriminator so tests can pin BR-3 fallback
84
+ * behaviour without rendering React or relying on CSS-token strings.
85
+ *
86
+ * `kind: 'known'` — STATUS_CONFIG had an entry; label is the friendly
87
+ * display string (e.g. 'succeeded' for 'success',
88
+ * 'running' for 'running').
89
+ * `kind: 'fallback'` — STATUS_CONFIG had no entry; label echoes the raw
90
+ * input so editors still see something useful in
91
+ * the row (BR-3).
92
+ */ export function resolveBatchStatusBadge(status) {
93
+ // Normalise the legacy `'completed'` literal (pre-v1.2.5 batches) onto
94
+ // `'success'` so older rows render the same `SUCCEEDED` chip as the
95
+ // rest of the table. Mirrors `resolveUnitStatusBadge` — unit chips
96
+ // already aliased this; batch chips did not, which produced a single
97
+ // `COMPLETED` row amongst `SUCCEEDED` peers in the v1.2.6 UI sweep.
98
+ const normalised = status === 'completed' ? 'success' : status;
99
+ const cfg = STATUS_CONFIG[normalised];
100
+ if (!cfg) return {
101
+ kind: 'fallback',
102
+ label: status
103
+ };
104
+ return {
105
+ kind: 'known',
106
+ label: normalised === 'success' ? 'succeeded' : normalised
107
+ };
108
+ }
109
+ /**
110
+ * Pure resolver for unit-level status badges. Mirrors
111
+ * `resolveBatchStatusBadge` but uses the unit-status color map so
112
+ * `'completed'` (older API revision) and `'succeeded'` both normalise
113
+ * to the same `success` chip. Returns fallback for any value outside
114
+ * the known set.
115
+ */ export function resolveUnitStatusBadge(status) {
116
+ const normalised = status === 'completed' || status === 'succeeded' ? 'success' : status;
117
+ const cfg = UNIT_STATUS_COLOR_MAP[normalised];
118
+ if (!cfg) return {
119
+ kind: 'fallback',
120
+ label: status
121
+ };
122
+ const label = status === 'success' || status === 'completed' ? 'succeeded' : status;
123
+ return {
124
+ kind: 'known',
125
+ label
126
+ };
127
+ }
128
+ /**
129
+ * Neutral fallback chip used when a batch arrives with a status value
130
+ * that isn't in STATUS_CONFIG (e.g. a future / older API revision adds
131
+ * a new lifecycle state). Renders the raw value so editors aren't
132
+ * staring at an empty cell (BR-3) and emits a one-shot console.warn
133
+ * per unknown value for engineering.
134
+ */ const UNKNOWN_STATUS_CONFIG = {
135
+ background: 'var(--theme-elevation-100)',
136
+ color: 'var(--theme-elevation-900)',
137
+ border: 'var(--theme-elevation-300)'
138
+ };
139
+ /**
140
+ * Renders a status pill for a batch row.
141
+ * The `running` state gets a CSS pulse animation on its background.
142
+ * Storage value `'success'` displays as "succeeded" — matches the
143
+ * unit-level vocabulary used in the Hub's Recent translations table
144
+ * and the AuditPanel KPIs. v1.2.5 used "completed" here; v1.2.6 fixes
145
+ * the vocab split (BR-8).
146
+ */ export const StatusBadge = ({ status, small = false })=>{
147
+ const resolved = resolveBatchStatusBadge(status);
148
+ if (resolved.kind === 'fallback') {
149
+ // BR-3 fallback: render the raw value so the row isn't visually
150
+ // empty, and warn once so the next status drift is caught.
151
+ warnUnknownStatus('StatusBadge', status);
152
+ return /*#__PURE__*/ _jsx(BadgePill, {
153
+ cfg: UNKNOWN_STATUS_CONFIG,
154
+ label: resolved.label,
155
+ small: small
156
+ });
157
+ }
158
+ // Normalise legacy `'completed'` onto the `'success'` config so the
159
+ // chip styling matches the resolver's label aliasing. The widened
160
+ // `string` type lets us compare against the legacy literal that isn't
161
+ // part of the current `BulkTranslateBatchStatus` union.
162
+ const normalised = status === 'completed' ? 'success' : status;
163
+ const cfg = STATUS_CONFIG[normalised];
164
+ return /*#__PURE__*/ _jsx(BadgePill, {
165
+ cfg: cfg,
166
+ label: resolved.label,
167
+ small: small
168
+ });
169
+ };
170
+ /**
171
+ * Same visual treatment but for unit-level statuses (pending / running /
172
+ * success / failed / skipped / reverted). Uses `succeeded` as the
173
+ * display label for `success` to match the rest of the surface (BR-8).
174
+ */ export const UnitStatusBadge = ({ status, small = false })=>{
175
+ const resolved = resolveUnitStatusBadge(status);
176
+ if (resolved.kind === 'fallback') {
177
+ warnUnknownStatus('UnitStatusBadge', status);
178
+ return /*#__PURE__*/ _jsx(BadgePill, {
179
+ cfg: UNKNOWN_STATUS_CONFIG,
180
+ label: resolved.label,
181
+ small: small
182
+ });
183
+ }
184
+ const normalised = status === 'completed' || status === 'succeeded' ? 'success' : status;
185
+ const cfg = UNIT_STATUS_COLOR_MAP[normalised];
186
+ return /*#__PURE__*/ _jsx(BadgePill, {
187
+ cfg: cfg,
188
+ label: resolved.label,
189
+ small: small
190
+ });
191
+ };
192
+ // ---------------------------------------------------------------------------
193
+ // Shared pill renderer
194
+ // ---------------------------------------------------------------------------
195
+ const BadgePill = ({ cfg, label, small })=>{
196
+ // Bumped from 0.65rem / 0.7rem (~10.4 / 11.2 px) to 0.75rem / 0.8rem
197
+ // (12 / 12.8 px) in v1.2.6: the previous sizes were uncomfortable to
198
+ // read on dense list views and worked against the `-900` text /
199
+ // tinted background scheme we adopted for NEW-3. 12 px + weight 600
200
+ // is roughly the floor for comfortable status-pill readability and
201
+ // gives us extra contrast headroom alongside the darker text token.
202
+ const fontSize = small ? '0.75rem' : '0.8rem';
203
+ const style = {
204
+ display: 'inline-flex',
205
+ alignItems: 'center',
206
+ gap: cfg.prefix ? '0.25rem' : undefined,
207
+ padding: '0.15rem 0.5rem',
208
+ borderRadius: '4px',
209
+ fontSize,
210
+ fontWeight: 600,
211
+ textTransform: 'uppercase',
212
+ letterSpacing: '0.04em',
213
+ background: cfg.background,
214
+ color: cfg.color,
215
+ border: `1px solid ${cfg.border}`,
216
+ animationName: cfg.animation,
217
+ animationDuration: cfg.animation ? '1.8s' : undefined,
218
+ animationTimingFunction: cfg.animation ? 'ease-in-out' : undefined,
219
+ animationIterationCount: cfg.animation ? 'infinite' : undefined,
220
+ whiteSpace: 'nowrap'
221
+ };
222
+ return /*#__PURE__*/ _jsxs("span", {
223
+ style: style,
224
+ children: [
225
+ cfg.prefix ? /*#__PURE__*/ _jsx("span", {
226
+ "aria-hidden": "true",
227
+ children: cfg.prefix
228
+ }) : null,
229
+ label
230
+ ]
231
+ });
232
+ };
233
+ /**
234
+ * Inject the running-badge keyframes once per page. Call this inside the
235
+ * client component that mounts StatusBadge. Using a `<style>` tag is the
236
+ * only viable approach in Payload's inline-style architecture (no CSS
237
+ * Modules, no Tailwind).
238
+ */ export const StatusBadgeKeyframes = ()=>/*#__PURE__*/ _jsx("style", {
239
+ children: `
240
+ @keyframes bulk-runs-pulse {
241
+ 0%, 100% { background: var(--theme-success-100, #dcfce7); }
242
+ 50% { background: var(--theme-success-50, #f0fdf4); }
243
+ }
244
+ @media (prefers-reduced-motion: reduce) {
245
+ .bulk-runs-pulse { animation: none; }
246
+ }
247
+ `
248
+ });