@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.
- package/LICENSE +21 -0
- package/README.md +714 -0
- package/dist/alerts-collection.d.ts +21 -0
- package/dist/alerts-collection.js +159 -0
- package/dist/api.d.ts +4 -0
- package/dist/api.js +918 -0
- package/dist/bulk-translate-batches-collection.d.ts +29 -0
- package/dist/bulk-translate-batches-collection.js +404 -0
- package/dist/bulk-translate-units-collection.d.ts +35 -0
- package/dist/bulk-translate-units-collection.js +310 -0
- package/dist/client/estimated-cost-cell.d.ts +6 -0
- package/dist/client/estimated-cost-cell.js +12 -0
- package/dist/client/excluded-fields-field.d.ts +45 -0
- package/dist/client/excluded-fields-field.js +553 -0
- package/dist/client/field-translate-button.d.ts +6 -0
- package/dist/client/field-translate-button.js +199 -0
- package/dist/client/index.d.ts +6 -0
- package/dist/client/index.js +6 -0
- package/dist/client/lib/use-global-kill-switches.d.ts +20 -0
- package/dist/client/lib/use-global-kill-switches.js +58 -0
- package/dist/client/translate-button.d.ts +2 -0
- package/dist/client/translate-button.js +228 -0
- package/dist/client/translate-modal.d.ts +16 -0
- package/dist/client/translate-modal.js +549 -0
- package/dist/client/translation-progress.d.ts +10 -0
- package/dist/client/translation-progress.js +297 -0
- package/dist/components/TranslationNavGroup.d.ts +45 -0
- package/dist/components/TranslationNavGroup.js +104 -0
- package/dist/defaults.d.ts +11 -0
- package/dist/defaults.js +16 -0
- package/dist/endpoints/client-config.d.ts +44 -0
- package/dist/endpoints/client-config.js +145 -0
- package/dist/endpoints/estimate.d.ts +5 -0
- package/dist/endpoints/estimate.js +237 -0
- package/dist/endpoints/progress.d.ts +2 -0
- package/dist/endpoints/progress.js +314 -0
- package/dist/endpoints/translate.d.ts +11 -0
- package/dist/endpoints/translate.js +376 -0
- package/dist/endpoints/translation-hub/_helpers.d.ts +140 -0
- package/dist/endpoints/translation-hub/_helpers.js +297 -0
- package/dist/endpoints/translation-hub/active.d.ts +21 -0
- package/dist/endpoints/translation-hub/active.js +220 -0
- package/dist/endpoints/translation-hub/cancel.d.ts +22 -0
- package/dist/endpoints/translation-hub/cancel.js +233 -0
- package/dist/endpoints/translation-hub/enqueue.d.ts +70 -0
- package/dist/endpoints/translation-hub/enqueue.js +529 -0
- package/dist/endpoints/translation-hub/failures.d.ts +12 -0
- package/dist/endpoints/translation-hub/failures.js +67 -0
- package/dist/endpoints/translation-hub/force-reset.d.ts +20 -0
- package/dist/endpoints/translation-hub/force-reset.js +144 -0
- package/dist/endpoints/translation-hub/index.d.ts +21 -0
- package/dist/endpoints/translation-hub/index.js +20 -0
- package/dist/endpoints/translation-hub/list.d.ts +40 -0
- package/dist/endpoints/translation-hub/list.js +182 -0
- package/dist/endpoints/translation-hub/preflight.d.ts +19 -0
- package/dist/endpoints/translation-hub/preflight.js +141 -0
- package/dist/endpoints/translation-hub/retry-failed.d.ts +38 -0
- package/dist/endpoints/translation-hub/retry-failed.js +235 -0
- package/dist/endpoints/translation-hub/revert.d.ts +88 -0
- package/dist/endpoints/translation-hub/revert.js +405 -0
- package/dist/endpoints/translation-hub/status.d.ts +45 -0
- package/dist/endpoints/translation-hub/status.js +391 -0
- package/dist/endpoints/translation-hub/usage-summary.d.ts +114 -0
- package/dist/endpoints/translation-hub/usage-summary.js +481 -0
- package/dist/exports/client.d.ts +6 -0
- package/dist/exports/client.js +6 -0
- package/dist/exports/components.d.ts +6 -0
- package/dist/exports/components.js +5 -0
- package/dist/exports/index.d.ts +8 -0
- package/dist/exports/index.js +7 -0
- package/dist/exports/providers.d.ts +9 -0
- package/dist/exports/providers.js +5 -0
- package/dist/exports/views-client.d.ts +23 -0
- package/dist/exports/views-client.js +22 -0
- package/dist/exports/views.d.ts +30 -0
- package/dist/exports/views.js +29 -0
- package/dist/hooks/after-change-global.d.ts +4 -0
- package/dist/hooks/after-change-global.js +109 -0
- package/dist/hooks/after-change.d.ts +16 -0
- package/dist/hooks/after-change.js +205 -0
- package/dist/hooks/after-delete.d.ts +30 -0
- package/dist/hooks/after-delete.js +95 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +5 -0
- package/dist/jobs-collection.d.ts +17 -0
- package/dist/jobs-collection.js +139 -0
- package/dist/lexical/classifier.d.ts +3 -0
- package/dist/lexical/classifier.js +108 -0
- package/dist/lexical/deserializer.d.ts +4 -0
- package/dist/lexical/deserializer.js +263 -0
- package/dist/lexical/placeholder-integrity.d.ts +6 -0
- package/dist/lexical/placeholder-integrity.js +21 -0
- package/dist/lexical/placeholders.d.ts +21 -0
- package/dist/lexical/placeholders.js +117 -0
- package/dist/lexical/serializer.d.ts +21 -0
- package/dist/lexical/serializer.js +233 -0
- package/dist/lexical/types.d.ts +32 -0
- package/dist/lexical/types.js +1 -0
- package/dist/lib/auth-diagnostics.d.ts +14 -0
- package/dist/lib/auth-diagnostics.js +19 -0
- package/dist/lib/batch-counts.d.ts +58 -0
- package/dist/lib/batch-counts.js +105 -0
- package/dist/lib/bulk-translate-migrations.d.ts +92 -0
- package/dist/lib/bulk-translate-migrations.js +153 -0
- package/dist/lib/coalescing-queue.d.ts +38 -0
- package/dist/lib/coalescing-queue.js +69 -0
- package/dist/lib/content-extractor.d.ts +16 -0
- package/dist/lib/content-extractor.js +410 -0
- package/dist/lib/content-hash.d.ts +1 -0
- package/dist/lib/content-hash.js +19 -0
- package/dist/lib/content-patcher.d.ts +15 -0
- package/dist/lib/content-patcher.js +293 -0
- package/dist/lib/cost-guards.d.ts +2 -0
- package/dist/lib/cost-guards.js +18 -0
- package/dist/lib/daily-spend-cap.d.ts +58 -0
- package/dist/lib/daily-spend-cap.js +233 -0
- package/dist/lib/effective-locales.d.ts +181 -0
- package/dist/lib/effective-locales.js +302 -0
- package/dist/lib/error-messages.d.ts +245 -0
- package/dist/lib/error-messages.js +626 -0
- package/dist/lib/events.d.ts +39 -0
- package/dist/lib/events.js +146 -0
- package/dist/lib/exclude-fields.d.ts +3 -0
- package/dist/lib/exclude-fields.js +64 -0
- package/dist/lib/field-breadcrumb.d.ts +31 -0
- package/dist/lib/field-breadcrumb.js +227 -0
- package/dist/lib/field-diff.d.ts +1 -0
- package/dist/lib/field-diff.js +25 -0
- package/dist/lib/field-empty.d.ts +2 -0
- package/dist/lib/field-empty.js +68 -0
- package/dist/lib/field-resolver.d.ts +3 -0
- package/dist/lib/field-resolver.js +164 -0
- package/dist/lib/group-soft-skips.d.ts +39 -0
- package/dist/lib/group-soft-skips.js +45 -0
- package/dist/lib/locale-merge.d.ts +44 -0
- package/dist/lib/locale-merge.js +357 -0
- package/dist/lib/locale-row-check.d.ts +30 -0
- package/dist/lib/locale-row-check.js +64 -0
- package/dist/lib/logger.d.ts +74 -0
- package/dist/lib/logger.js +97 -0
- package/dist/lib/manual-edit-guard.d.ts +128 -0
- package/dist/lib/manual-edit-guard.js +393 -0
- package/dist/lib/output-validation.d.ts +48 -0
- package/dist/lib/output-validation.js +148 -0
- package/dist/lib/payload-read.d.ts +16 -0
- package/dist/lib/payload-read.js +51 -0
- package/dist/lib/per-doc-claim.d.ts +90 -0
- package/dist/lib/per-doc-claim.js +140 -0
- package/dist/lib/per-doc-lock.d.ts +94 -0
- package/dist/lib/per-doc-lock.js +119 -0
- package/dist/lib/persist-usage.d.ts +91 -0
- package/dist/lib/persist-usage.js +116 -0
- package/dist/lib/progress-store.d.ts +103 -0
- package/dist/lib/progress-store.js +314 -0
- package/dist/lib/rate-limiter.d.ts +3 -0
- package/dist/lib/rate-limiter.js +53 -0
- package/dist/lib/snapshot-select.d.ts +43 -0
- package/dist/lib/snapshot-select.js +108 -0
- package/dist/lib/translate-prompt.d.ts +31 -0
- package/dist/lib/translate-prompt.js +66 -0
- package/dist/lib/translation-token-bucket.d.ts +57 -0
- package/dist/lib/translation-token-bucket.js +365 -0
- package/dist/lib/truncate-source-value.d.ts +1 -0
- package/dist/lib/truncate-source-value.js +27 -0
- package/dist/manual-edit-collection.d.ts +22 -0
- package/dist/manual-edit-collection.js +124 -0
- package/dist/plugin.d.ts +3 -0
- package/dist/plugin.js +934 -0
- package/dist/providers/ai-sdk-adapter.d.ts +35 -0
- package/dist/providers/ai-sdk-adapter.js +100 -0
- package/dist/providers/anthropic.d.ts +31 -0
- package/dist/providers/anthropic.js +66 -0
- package/dist/providers/custom.d.ts +36 -0
- package/dist/providers/custom.js +24 -0
- package/dist/providers/gemini.d.ts +20 -0
- package/dist/providers/gemini.js +48 -0
- package/dist/providers/mock.d.ts +2 -0
- package/dist/providers/mock.js +29 -0
- package/dist/providers/openai.d.ts +28 -0
- package/dist/providers/openai.js +69 -0
- package/dist/settings-global.d.ts +74 -0
- package/dist/settings-global.js +216 -0
- package/dist/tasks/bulk-translate-coordinator.d.ts +115 -0
- package/dist/tasks/bulk-translate-coordinator.js +708 -0
- package/dist/tasks/bulk-translate-doc-task.d.ts +142 -0
- package/dist/tasks/bulk-translate-doc-task.js +1000 -0
- package/dist/tasks/bulk-translate-janitor.d.ts +87 -0
- package/dist/tasks/bulk-translate-janitor.js +311 -0
- package/dist/tasks/translate-job-task.d.ts +51 -0
- package/dist/tasks/translate-job-task.js +154 -0
- package/dist/translate.d.ts +113 -0
- package/dist/translate.js +911 -0
- package/dist/translation-daily-spend-collection.d.ts +24 -0
- package/dist/translation-daily-spend-collection.js +133 -0
- package/dist/translation-rate-limits-collection.d.ts +30 -0
- package/dist/translation-rate-limits-collection.js +144 -0
- package/dist/types.d.ts +672 -0
- package/dist/types.js +1 -0
- package/dist/usage-collection.d.ts +14 -0
- package/dist/usage-collection.js +377 -0
- package/dist/views/BulkRunsHub/BatchRow.d.ts +32 -0
- package/dist/views/BulkRunsHub/BatchRow.js +1222 -0
- package/dist/views/BulkRunsHub/BucketRow.d.ts +62 -0
- package/dist/views/BulkRunsHub/BucketRow.js +982 -0
- package/dist/views/BulkRunsHub/BulkRunsHub.client.d.ts +18 -0
- package/dist/views/BulkRunsHub/BulkRunsHub.client.js +331 -0
- package/dist/views/BulkRunsHub/EmptyState.d.ts +6 -0
- package/dist/views/BulkRunsHub/EmptyState.js +64 -0
- package/dist/views/BulkRunsHub/FilterBar.d.ts +16 -0
- package/dist/views/BulkRunsHub/FilterBar.js +284 -0
- package/dist/views/BulkRunsHub/InFlightBanner.d.ts +14 -0
- package/dist/views/BulkRunsHub/InFlightBanner.js +59 -0
- package/dist/views/BulkRunsHub/StatusBadge.d.ts +64 -0
- package/dist/views/BulkRunsHub/StatusBadge.js +248 -0
- package/dist/views/BulkRunsHub/SummaryStrip.d.ts +22 -0
- package/dist/views/BulkRunsHub/SummaryStrip.js +249 -0
- package/dist/views/BulkRunsHub/bucket-grouping.d.ts +200 -0
- package/dist/views/BulkRunsHub/bucket-grouping.js +344 -0
- package/dist/views/BulkRunsHub/bucketFailureSummary.d.ts +9 -0
- package/dist/views/BulkRunsHub/bucketFailureSummary.js +36 -0
- package/dist/views/BulkRunsHub/dedupedStatusFetch.d.ts +5 -0
- package/dist/views/BulkRunsHub/dedupedStatusFetch.js +45 -0
- package/dist/views/BulkRunsHub/index.d.ts +17 -0
- package/dist/views/BulkRunsHub/index.js +80 -0
- package/dist/views/BulkRunsHub/urlFilters.d.ts +14 -0
- package/dist/views/BulkRunsHub/urlFilters.js +50 -0
- package/dist/views/BulkRunsHub/useBulkRunsList.d.ts +26 -0
- package/dist/views/BulkRunsHub/useBulkRunsList.js +204 -0
- package/dist/views/BulkRunsHub/useUrlFilters.d.ts +10 -0
- package/dist/views/BulkRunsHub/useUrlFilters.js +88 -0
- package/dist/views/TranslationHub/ActiveJobs.d.ts +6 -0
- package/dist/views/TranslationHub/ActiveJobs.js +320 -0
- package/dist/views/TranslationHub/AdvancedPanel.d.ts +17 -0
- package/dist/views/TranslationHub/AdvancedPanel.js +996 -0
- package/dist/views/TranslationHub/AlertBanner.d.ts +6 -0
- package/dist/views/TranslationHub/AlertBanner.js +568 -0
- package/dist/views/TranslationHub/AuditPanel.d.ts +6 -0
- package/dist/views/TranslationHub/AuditPanel.helpers.d.ts +44 -0
- package/dist/views/TranslationHub/AuditPanel.helpers.js +71 -0
- package/dist/views/TranslationHub/AuditPanel.js +1367 -0
- package/dist/views/TranslationHub/BulkTranslate.types.d.ts +242 -0
- package/dist/views/TranslationHub/BulkTranslate.types.js +36 -0
- package/dist/views/TranslationHub/BulkTranslateFailureDrawer.d.ts +19 -0
- package/dist/views/TranslationHub/BulkTranslateFailureDrawer.js +332 -0
- package/dist/views/TranslationHub/BulkTranslateMonitor.d.ts +28 -0
- package/dist/views/TranslationHub/BulkTranslateMonitor.js +305 -0
- package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.d.ts +3 -0
- package/dist/views/TranslationHub/BulkTranslateNarrowViewportBanner.js +42 -0
- package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.d.ts +26 -0
- package/dist/views/TranslationHub/BulkTranslatePostEnqueueTransition.js +95 -0
- package/dist/views/TranslationHub/BulkTranslatePreflightModal.d.ts +22 -0
- package/dist/views/TranslationHub/BulkTranslatePreflightModal.js +879 -0
- package/dist/views/TranslationHub/BulkTranslateTerminalCard.d.ts +29 -0
- package/dist/views/TranslationHub/BulkTranslateTerminalCard.js +445 -0
- package/dist/views/TranslationHub/BulkTranslateTrigger.d.ts +66 -0
- package/dist/views/TranslationHub/BulkTranslateTrigger.js +161 -0
- package/dist/views/TranslationHub/EditorRecentRunsPanel.d.ts +33 -0
- package/dist/views/TranslationHub/EditorRecentRunsPanel.js +290 -0
- package/dist/views/TranslationHub/Hub.client.d.ts +74 -0
- package/dist/views/TranslationHub/Hub.client.js +357 -0
- package/dist/views/TranslationHub/ModelCombobox.d.ts +14 -0
- package/dist/views/TranslationHub/ModelCombobox.js +415 -0
- package/dist/views/TranslationHub/PerCollectionConfig.d.ts +10 -0
- package/dist/views/TranslationHub/PerCollectionConfig.helpers.d.ts +16 -0
- package/dist/views/TranslationHub/PerCollectionConfig.helpers.js +19 -0
- package/dist/views/TranslationHub/PerCollectionConfig.js +759 -0
- package/dist/views/TranslationHub/SettingsRail.d.ts +11 -0
- package/dist/views/TranslationHub/SettingsRail.js +382 -0
- package/dist/views/TranslationHub/StatusStrip.d.ts +6 -0
- package/dist/views/TranslationHub/StatusStrip.js +451 -0
- package/dist/views/TranslationHub/UsageTable.d.ts +6 -0
- package/dist/views/TranslationHub/UsageTable.helpers.d.ts +69 -0
- package/dist/views/TranslationHub/UsageTable.helpers.js +49 -0
- package/dist/views/TranslationHub/UsageTable.js +1240 -0
- package/dist/views/TranslationHub/alertGrouping.d.ts +70 -0
- package/dist/views/TranslationHub/alertGrouping.js +99 -0
- package/dist/views/TranslationHub/index.d.ts +20 -0
- package/dist/views/TranslationHub/index.js +109 -0
- package/dist/views/TranslationHub/tabNavigation.d.ts +53 -0
- package/dist/views/TranslationHub/tabNavigation.js +74 -0
- package/dist/views/TranslationHub/terminalBannerVisibility.d.ts +33 -0
- package/dist/views/TranslationHub/terminalBannerVisibility.js +124 -0
- package/dist/views/TranslationHub/useBulkTranslateActive.d.ts +49 -0
- package/dist/views/TranslationHub/useBulkTranslateActive.js +251 -0
- package/dist/views/TranslationHub/useFocusTrap.d.ts +6 -0
- package/dist/views/TranslationHub/useFocusTrap.js +81 -0
- package/dist/views/TranslationHub/useTranslationHubUsageSummary.d.ts +77 -0
- package/dist/views/TranslationHub/useTranslationHubUsageSummary.js +267 -0
- package/dist/views/shared/EditorError.d.ts +97 -0
- package/dist/views/shared/EditorError.js +205 -0
- package/dist/views/shared/ModelCell.d.ts +18 -0
- package/dist/views/shared/ModelCell.js +31 -0
- package/dist/views/shared/docHref.d.ts +16 -0
- package/dist/views/shared/docHref.js +26 -0
- package/dist/views/shared/fetch-error-body.d.ts +25 -0
- package/dist/views/shared/fetch-error-body.js +42 -0
- package/dist/views/shared/filterPillStyle.d.ts +35 -0
- package/dist/views/shared/filterPillStyle.js +40 -0
- package/dist/views/shared/format.d.ts +75 -0
- package/dist/views/shared/format.js +131 -0
- package/package.json +141 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
import { readResponseError } from '../shared/fetch-error-body.js';
|
|
5
|
+
import { BulkTranslateFailureDrawer } from './BulkTranslateFailureDrawer.js';
|
|
6
|
+
const SECTION_STYLE = {
|
|
7
|
+
background: 'var(--theme-elevation-50)',
|
|
8
|
+
border: '1px solid var(--theme-elevation-150)',
|
|
9
|
+
borderRadius: '6px',
|
|
10
|
+
padding: '1rem'
|
|
11
|
+
};
|
|
12
|
+
const PROGRESS_TRACK_STYLE = {
|
|
13
|
+
height: '8px',
|
|
14
|
+
background: 'var(--theme-elevation-100)',
|
|
15
|
+
borderRadius: '4px',
|
|
16
|
+
overflow: 'hidden'
|
|
17
|
+
};
|
|
18
|
+
const PROGRESS_TRACK_THIN_STYLE = {
|
|
19
|
+
...PROGRESS_TRACK_STYLE,
|
|
20
|
+
height: '4px'
|
|
21
|
+
};
|
|
22
|
+
const COLLECTION_ROW_STYLE = {
|
|
23
|
+
display: 'grid',
|
|
24
|
+
gridTemplateColumns: '140px 1fr 100px',
|
|
25
|
+
gap: '0.75rem',
|
|
26
|
+
alignItems: 'center',
|
|
27
|
+
padding: '0.5rem 0',
|
|
28
|
+
fontSize: '0.8125rem',
|
|
29
|
+
borderTop: '1px solid var(--theme-elevation-100)'
|
|
30
|
+
};
|
|
31
|
+
const FAILURE_BADGE_STYLE = {
|
|
32
|
+
display: 'inline-flex',
|
|
33
|
+
alignItems: 'center',
|
|
34
|
+
gap: '0.25rem',
|
|
35
|
+
padding: '0.15rem 0.45rem',
|
|
36
|
+
background: 'var(--theme-error-100, #fee2e2)',
|
|
37
|
+
border: '1px solid var(--theme-error-500, #b91c1c)',
|
|
38
|
+
borderRadius: '4px',
|
|
39
|
+
color: 'var(--theme-error-500, #b91c1c)',
|
|
40
|
+
fontSize: '0.75rem',
|
|
41
|
+
fontWeight: 500,
|
|
42
|
+
cursor: 'pointer'
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Format an ETA seconds value to "~Nm" / "~Nh Mm". Exported for tests.
|
|
46
|
+
*/ export function formatEta(seconds) {
|
|
47
|
+
if (seconds === null || seconds === undefined || !Number.isFinite(seconds)) {
|
|
48
|
+
return 'ETA pending';
|
|
49
|
+
}
|
|
50
|
+
if (seconds < 60) {
|
|
51
|
+
return `ETA ~${Math.max(1, Math.round(seconds))}s`;
|
|
52
|
+
}
|
|
53
|
+
if (seconds < 3600) {
|
|
54
|
+
return `ETA ~${Math.round(seconds / 60)}m`;
|
|
55
|
+
}
|
|
56
|
+
const h = Math.floor(seconds / 3600);
|
|
57
|
+
const m = Math.round((seconds - h * 3600) / 60);
|
|
58
|
+
return `ETA ~${h}h ${m}m`;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Cancellation interim copy (F-UX-04). Returns null when batch isn't
|
|
62
|
+
* cancelling so the UI can early-return.
|
|
63
|
+
*/ export function deriveCancellationLabel(batch) {
|
|
64
|
+
if (batch.status !== 'cancelling') {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
const stillRunning = batch.totalUnits - batch.completedUnits - batch.failedUnits;
|
|
68
|
+
return `Cancelling — ${Math.max(0, stillRunning)} jobs still finishing`;
|
|
69
|
+
}
|
|
70
|
+
export const BulkTranslateMonitor = ({ basePath, batch, isOffline, onRetry })=>{
|
|
71
|
+
const [drawerCollection, setDrawerCollection] = useState(null);
|
|
72
|
+
const [cancelling, setCancelling] = useState(false);
|
|
73
|
+
const [cancelError, setCancelError] = useState(null);
|
|
74
|
+
const totalProgress = batch.totalUnits === 0 ? 0 : Math.min(100, batch.completedUnits / batch.totalUnits * 100);
|
|
75
|
+
const cancelLabel = deriveCancellationLabel(batch);
|
|
76
|
+
async function onCancel() {
|
|
77
|
+
if (cancelling) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
setCancelling(true);
|
|
81
|
+
setCancelError(null);
|
|
82
|
+
try {
|
|
83
|
+
const res = await fetch(`${basePath}/api/translation-hub/bulk-translate/${batch.id}/cancel`, {
|
|
84
|
+
method: 'POST',
|
|
85
|
+
credentials: 'include'
|
|
86
|
+
});
|
|
87
|
+
if (!res.ok) {
|
|
88
|
+
throw new Error(await readResponseError(res));
|
|
89
|
+
}
|
|
90
|
+
} catch (e) {
|
|
91
|
+
setCancelError(e instanceof Error ? e.message : String(e));
|
|
92
|
+
} finally{
|
|
93
|
+
setCancelling(false);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
return /*#__PURE__*/ _jsxs("section", {
|
|
97
|
+
"data-testid": "bulk-translate-monitor",
|
|
98
|
+
id: "bulk-translate-monitor",
|
|
99
|
+
style: SECTION_STYLE,
|
|
100
|
+
children: [
|
|
101
|
+
isOffline ? /*#__PURE__*/ _jsxs("div", {
|
|
102
|
+
"data-testid": "bulk-translate-offline-banner",
|
|
103
|
+
role: "status",
|
|
104
|
+
style: {
|
|
105
|
+
marginBottom: '0.75rem',
|
|
106
|
+
padding: '0.5rem 0.75rem',
|
|
107
|
+
background: 'var(--theme-warning-100, #fef3c7)',
|
|
108
|
+
border: '1px solid var(--theme-warning-500, #d97706)',
|
|
109
|
+
borderRadius: '4px',
|
|
110
|
+
display: 'flex',
|
|
111
|
+
alignItems: 'center',
|
|
112
|
+
justifyContent: 'space-between',
|
|
113
|
+
fontSize: '0.8125rem',
|
|
114
|
+
color: 'var(--theme-warning-500, #d97706)'
|
|
115
|
+
},
|
|
116
|
+
children: [
|
|
117
|
+
/*#__PURE__*/ _jsx("span", {
|
|
118
|
+
children: "Connection lost — data may be stale"
|
|
119
|
+
}),
|
|
120
|
+
/*#__PURE__*/ _jsx("button", {
|
|
121
|
+
onClick: onRetry,
|
|
122
|
+
style: {
|
|
123
|
+
background: 'transparent',
|
|
124
|
+
border: 'none',
|
|
125
|
+
color: 'inherit',
|
|
126
|
+
textDecoration: 'underline',
|
|
127
|
+
cursor: 'pointer',
|
|
128
|
+
fontSize: 'inherit'
|
|
129
|
+
},
|
|
130
|
+
type: "button",
|
|
131
|
+
children: "Retry now"
|
|
132
|
+
})
|
|
133
|
+
]
|
|
134
|
+
}) : null,
|
|
135
|
+
/*#__PURE__*/ _jsxs("header", {
|
|
136
|
+
style: {
|
|
137
|
+
display: 'flex',
|
|
138
|
+
alignItems: 'center',
|
|
139
|
+
justifyContent: 'space-between',
|
|
140
|
+
marginBottom: '0.75rem',
|
|
141
|
+
gap: '0.75rem'
|
|
142
|
+
},
|
|
143
|
+
children: [
|
|
144
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
145
|
+
children: [
|
|
146
|
+
/*#__PURE__*/ _jsx("h2", {
|
|
147
|
+
style: {
|
|
148
|
+
margin: 0,
|
|
149
|
+
fontSize: '1rem',
|
|
150
|
+
color: 'var(--theme-elevation-1000)'
|
|
151
|
+
},
|
|
152
|
+
children: "Bulk translate in progress"
|
|
153
|
+
}),
|
|
154
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
155
|
+
style: {
|
|
156
|
+
margin: '0.15rem 0 0',
|
|
157
|
+
fontSize: '0.8125rem',
|
|
158
|
+
color: 'var(--theme-elevation-500)'
|
|
159
|
+
},
|
|
160
|
+
children: [
|
|
161
|
+
batch.completedUnits,
|
|
162
|
+
" / ",
|
|
163
|
+
batch.totalUnits,
|
|
164
|
+
" translated · ",
|
|
165
|
+
formatEta(batch.etaSeconds)
|
|
166
|
+
]
|
|
167
|
+
})
|
|
168
|
+
]
|
|
169
|
+
}),
|
|
170
|
+
/*#__PURE__*/ _jsx("button", {
|
|
171
|
+
"aria-label": "Cancel bulk translate batch",
|
|
172
|
+
disabled: cancelling || batch.status === 'cancelling',
|
|
173
|
+
onClick: onCancel,
|
|
174
|
+
style: {
|
|
175
|
+
padding: '0.35rem 0.75rem',
|
|
176
|
+
background: 'transparent',
|
|
177
|
+
border: '1px solid var(--theme-elevation-300)',
|
|
178
|
+
borderRadius: '4px',
|
|
179
|
+
color: 'var(--theme-elevation-700)',
|
|
180
|
+
cursor: cancelling || batch.status === 'cancelling' ? 'not-allowed' : 'pointer',
|
|
181
|
+
fontSize: '0.8125rem'
|
|
182
|
+
},
|
|
183
|
+
type: "button",
|
|
184
|
+
children: batch.status === 'cancelling' ? 'Cancelling…' : 'Cancel'
|
|
185
|
+
})
|
|
186
|
+
]
|
|
187
|
+
}),
|
|
188
|
+
cancelLabel ? /*#__PURE__*/ _jsx("p", {
|
|
189
|
+
"data-testid": "bulk-translate-cancelling",
|
|
190
|
+
style: {
|
|
191
|
+
margin: '0 0 0.5rem',
|
|
192
|
+
fontSize: '0.8125rem',
|
|
193
|
+
color: 'var(--theme-warning-500, #d97706)'
|
|
194
|
+
},
|
|
195
|
+
children: cancelLabel
|
|
196
|
+
}) : null,
|
|
197
|
+
cancelError ? /*#__PURE__*/ _jsx("p", {
|
|
198
|
+
style: {
|
|
199
|
+
margin: '0 0 0.5rem',
|
|
200
|
+
fontSize: '0.8125rem',
|
|
201
|
+
color: 'var(--theme-error-500, #b91c1c)'
|
|
202
|
+
},
|
|
203
|
+
children: cancelError
|
|
204
|
+
}) : null,
|
|
205
|
+
/*#__PURE__*/ _jsx("div", {
|
|
206
|
+
"aria-label": "Total bulk-translate progress",
|
|
207
|
+
"aria-valuemax": batch.totalUnits,
|
|
208
|
+
"aria-valuemin": 0,
|
|
209
|
+
"aria-valuenow": batch.completedUnits,
|
|
210
|
+
"data-testid": "bulk-translate-global-progress",
|
|
211
|
+
role: "progressbar",
|
|
212
|
+
style: PROGRESS_TRACK_STYLE,
|
|
213
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
214
|
+
style: {
|
|
215
|
+
width: `${totalProgress}%`,
|
|
216
|
+
height: '100%',
|
|
217
|
+
background: 'var(--theme-success-500, #16a34a)',
|
|
218
|
+
transition: 'width 250ms ease'
|
|
219
|
+
}
|
|
220
|
+
})
|
|
221
|
+
}),
|
|
222
|
+
/*#__PURE__*/ _jsx("div", {
|
|
223
|
+
style: {
|
|
224
|
+
marginTop: '0.75rem'
|
|
225
|
+
},
|
|
226
|
+
children: batch.collections.map((c)=>/*#__PURE__*/ _jsx(CollectionRow, {
|
|
227
|
+
collection: c,
|
|
228
|
+
onOpenFailures: ()=>setDrawerCollection(c)
|
|
229
|
+
}, c.slug))
|
|
230
|
+
}),
|
|
231
|
+
drawerCollection ? /*#__PURE__*/ _jsx(BulkTranslateFailureDrawer, {
|
|
232
|
+
basePath: basePath,
|
|
233
|
+
batchId: batch.id,
|
|
234
|
+
batchStatus: batch.status,
|
|
235
|
+
collection: drawerCollection,
|
|
236
|
+
onClose: ()=>setDrawerCollection(null)
|
|
237
|
+
}) : null
|
|
238
|
+
]
|
|
239
|
+
});
|
|
240
|
+
};
|
|
241
|
+
const CollectionRow = ({ collection, onOpenFailures })=>{
|
|
242
|
+
const pct = collection.total === 0 ? 0 : Math.min(100, collection.completed / collection.total * 100);
|
|
243
|
+
const hasFailures = collection.failed > 0;
|
|
244
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
245
|
+
"data-testid": `bulk-translate-row-${collection.slug}`,
|
|
246
|
+
style: COLLECTION_ROW_STYLE,
|
|
247
|
+
children: [
|
|
248
|
+
/*#__PURE__*/ _jsx("span", {
|
|
249
|
+
style: {
|
|
250
|
+
color: 'var(--theme-elevation-800)'
|
|
251
|
+
},
|
|
252
|
+
children: collection.label
|
|
253
|
+
}),
|
|
254
|
+
/*#__PURE__*/ _jsx("div", {
|
|
255
|
+
"aria-label": `${collection.label} progress`,
|
|
256
|
+
"aria-valuemax": collection.total,
|
|
257
|
+
"aria-valuemin": 0,
|
|
258
|
+
"aria-valuenow": collection.completed,
|
|
259
|
+
role: "progressbar",
|
|
260
|
+
style: PROGRESS_TRACK_THIN_STYLE,
|
|
261
|
+
children: /*#__PURE__*/ _jsx("div", {
|
|
262
|
+
style: {
|
|
263
|
+
width: `${pct}%`,
|
|
264
|
+
height: '100%',
|
|
265
|
+
background: 'var(--theme-success-500, #16a34a)',
|
|
266
|
+
transition: 'width 250ms ease'
|
|
267
|
+
}
|
|
268
|
+
})
|
|
269
|
+
}),
|
|
270
|
+
/*#__PURE__*/ _jsx("div", {
|
|
271
|
+
style: {
|
|
272
|
+
textAlign: 'right'
|
|
273
|
+
},
|
|
274
|
+
children: hasFailures ? /*#__PURE__*/ _jsxs("button", {
|
|
275
|
+
"aria-label": `${collection.failed} failed translations in ${collection.label}, open failure list`,
|
|
276
|
+
"data-testid": `bulk-translate-failures-${collection.slug}`,
|
|
277
|
+
onClick: onOpenFailures,
|
|
278
|
+
style: {
|
|
279
|
+
...FAILURE_BADGE_STYLE,
|
|
280
|
+
background: 'var(--theme-error-100, #fee2e2)'
|
|
281
|
+
},
|
|
282
|
+
type: "button",
|
|
283
|
+
children: [
|
|
284
|
+
/*#__PURE__*/ _jsx("span", {
|
|
285
|
+
"aria-hidden": "true",
|
|
286
|
+
children: "⚠"
|
|
287
|
+
}),
|
|
288
|
+
/*#__PURE__*/ _jsxs("span", {
|
|
289
|
+
children: [
|
|
290
|
+
collection.failed,
|
|
291
|
+
" failed"
|
|
292
|
+
]
|
|
293
|
+
})
|
|
294
|
+
]
|
|
295
|
+
}) : /*#__PURE__*/ _jsx("span", {
|
|
296
|
+
style: {
|
|
297
|
+
color: 'var(--theme-elevation-500)',
|
|
298
|
+
fontSize: '0.75rem'
|
|
299
|
+
},
|
|
300
|
+
children: "—"
|
|
301
|
+
})
|
|
302
|
+
})
|
|
303
|
+
]
|
|
304
|
+
});
|
|
305
|
+
};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Desktop-only declaration banner (F-UX-12). Bulk translate is a
|
|
6
|
+
* desktop workflow — the monitor's grid layout and the failure drawer
|
|
7
|
+
* assume keyboard + multiple columns. On narrow viewports we render
|
|
8
|
+
* an explicit "read-only on mobile" notice instead of hiding the
|
|
9
|
+
* surface entirely; admins can still SEE the monitor, just not drive
|
|
10
|
+
* it from a phone.
|
|
11
|
+
*
|
|
12
|
+
* Pure CSS media queries would hide it from view but wouldn't
|
|
13
|
+
* announce it to assistive tech. Component-driven gives us the SSR
|
|
14
|
+
* hydration-safe pattern + screen-reader announcement.
|
|
15
|
+
*/ const BREAKPOINT_PX = 768;
|
|
16
|
+
export const BulkTranslateNarrowViewportBanner = ()=>{
|
|
17
|
+
const [isNarrow, setIsNarrow] = useState(false);
|
|
18
|
+
useEffect(()=>{
|
|
19
|
+
const mq = window.matchMedia(`(max-width: ${BREAKPOINT_PX - 1}px)`);
|
|
20
|
+
const update = ()=>setIsNarrow(mq.matches);
|
|
21
|
+
update();
|
|
22
|
+
mq.addEventListener('change', update);
|
|
23
|
+
return ()=>mq.removeEventListener('change', update);
|
|
24
|
+
}, []);
|
|
25
|
+
if (!isNarrow) {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
29
|
+
"data-testid": "bulk-translate-narrow-banner",
|
|
30
|
+
role: "status",
|
|
31
|
+
style: {
|
|
32
|
+
padding: '0.75rem 1rem',
|
|
33
|
+
background: 'var(--theme-elevation-50)',
|
|
34
|
+
border: '1px solid var(--theme-elevation-150)',
|
|
35
|
+
borderRadius: '6px',
|
|
36
|
+
fontSize: '0.8125rem',
|
|
37
|
+
color: 'var(--theme-elevation-700)'
|
|
38
|
+
},
|
|
39
|
+
children: "Bulk translate is designed for desktop. The monitor below is read-only on mobile."
|
|
40
|
+
});
|
|
41
|
+
};
|
|
42
|
+
export const BULK_TRANSLATE_NARROW_BREAKPOINT_PX = BREAKPOINT_PX;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
interface Props {
|
|
3
|
+
basePath: string;
|
|
4
|
+
/**
|
|
5
|
+
* Invoked when the first successful status poll returns. Parent uses
|
|
6
|
+
* this to close the transition and let the in-flight monitor (which
|
|
7
|
+
* subscribes to the same hook in `Hub.client.tsx`) take over the
|
|
8
|
+
* Overview tab.
|
|
9
|
+
*/
|
|
10
|
+
onResolved: () => void;
|
|
11
|
+
/**
|
|
12
|
+
* Safety fallback: maximum time to keep the transition card mounted
|
|
13
|
+
* even if the poll never returns an active batch. Prevents the UI
|
|
14
|
+
* from being stuck in "queued" forever if the enqueue silently no-ops.
|
|
15
|
+
*/
|
|
16
|
+
timeoutMs?: number;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Brief transition shown between modal-close and the first successful
|
|
20
|
+
* active-batch poll (F-UX-15). Without this, a 0-5 second window
|
|
21
|
+
* exists where the modal has closed but the in-flight monitor hasn't
|
|
22
|
+
* mounted yet, and the Overview tab looks identical to the idle state
|
|
23
|
+
* — admins reasonably worry the click was dropped.
|
|
24
|
+
*/
|
|
25
|
+
export declare const BulkTranslatePostEnqueueTransition: React.FC<Props>;
|
|
26
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useEffect, useRef } from 'react';
|
|
4
|
+
import { useBulkTranslateActive } from './useBulkTranslateActive.js';
|
|
5
|
+
/**
|
|
6
|
+
* Brief transition shown between modal-close and the first successful
|
|
7
|
+
* active-batch poll (F-UX-15). Without this, a 0-5 second window
|
|
8
|
+
* exists where the modal has closed but the in-flight monitor hasn't
|
|
9
|
+
* mounted yet, and the Overview tab looks identical to the idle state
|
|
10
|
+
* — admins reasonably worry the click was dropped.
|
|
11
|
+
*/ export const BulkTranslatePostEnqueueTransition = ({ basePath, onResolved, timeoutMs = 15_000 })=>{
|
|
12
|
+
const { data } = useBulkTranslateActive(basePath);
|
|
13
|
+
const resolvedRef = useRef(false);
|
|
14
|
+
// Resolve as soon as the active-batch endpoint reports a non-null
|
|
15
|
+
// batch — that's our signal the coordinator picked up the enqueue.
|
|
16
|
+
useEffect(()=>{
|
|
17
|
+
if (resolvedRef.current) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
if (data?.batch) {
|
|
21
|
+
resolvedRef.current = true;
|
|
22
|
+
onResolved();
|
|
23
|
+
}
|
|
24
|
+
}, [
|
|
25
|
+
data,
|
|
26
|
+
onResolved
|
|
27
|
+
]);
|
|
28
|
+
// Safety timeout — if the active endpoint never returns a batch
|
|
29
|
+
// (consumer integration error, endpoint not deployed, etc.) we
|
|
30
|
+
// still close the transition so the user isn't stuck.
|
|
31
|
+
useEffect(()=>{
|
|
32
|
+
const timer = setTimeout(()=>{
|
|
33
|
+
if (!resolvedRef.current) {
|
|
34
|
+
resolvedRef.current = true;
|
|
35
|
+
onResolved();
|
|
36
|
+
}
|
|
37
|
+
}, timeoutMs);
|
|
38
|
+
return ()=>clearTimeout(timer);
|
|
39
|
+
}, [
|
|
40
|
+
onResolved,
|
|
41
|
+
timeoutMs
|
|
42
|
+
]);
|
|
43
|
+
return /*#__PURE__*/ _jsx("div", {
|
|
44
|
+
"data-testid": "bulk-translate-post-enqueue",
|
|
45
|
+
style: {
|
|
46
|
+
position: 'fixed',
|
|
47
|
+
inset: 0,
|
|
48
|
+
background: 'rgba(0,0,0,0.45)',
|
|
49
|
+
display: 'flex',
|
|
50
|
+
alignItems: 'center',
|
|
51
|
+
justifyContent: 'center',
|
|
52
|
+
zIndex: 220
|
|
53
|
+
},
|
|
54
|
+
children: /*#__PURE__*/ _jsxs("div", {
|
|
55
|
+
"aria-live": "polite",
|
|
56
|
+
role: "status",
|
|
57
|
+
style: {
|
|
58
|
+
background: 'var(--theme-elevation-0)',
|
|
59
|
+
border: '1px solid var(--theme-elevation-150)',
|
|
60
|
+
borderRadius: '6px',
|
|
61
|
+
padding: '1.5rem 2rem',
|
|
62
|
+
display: 'flex',
|
|
63
|
+
alignItems: 'center',
|
|
64
|
+
gap: '0.75rem',
|
|
65
|
+
color: 'var(--theme-elevation-1000)',
|
|
66
|
+
fontSize: '0.875rem'
|
|
67
|
+
},
|
|
68
|
+
children: [
|
|
69
|
+
/*#__PURE__*/ _jsx("span", {
|
|
70
|
+
"aria-hidden": "true",
|
|
71
|
+
style: {
|
|
72
|
+
display: 'inline-block',
|
|
73
|
+
width: '14px',
|
|
74
|
+
height: '14px',
|
|
75
|
+
border: '2px solid var(--theme-elevation-300)',
|
|
76
|
+
borderTopColor: 'var(--theme-elevation-700)',
|
|
77
|
+
borderRadius: '50%',
|
|
78
|
+
animation: 'bulk-translate-spin 800ms linear infinite'
|
|
79
|
+
}
|
|
80
|
+
}),
|
|
81
|
+
/*#__PURE__*/ _jsx("span", {
|
|
82
|
+
children: "Run queued, monitor starting…"
|
|
83
|
+
}),
|
|
84
|
+
/*#__PURE__*/ _jsx("style", {
|
|
85
|
+
children: `
|
|
86
|
+
@keyframes bulk-translate-spin {
|
|
87
|
+
from { transform: rotate(0deg); }
|
|
88
|
+
to { transform: rotate(360deg); }
|
|
89
|
+
}
|
|
90
|
+
`
|
|
91
|
+
})
|
|
92
|
+
]
|
|
93
|
+
})
|
|
94
|
+
});
|
|
95
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { BulkTranslatePreflightResponse } from './BulkTranslate.types.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
basePath: string;
|
|
5
|
+
onClose: () => void;
|
|
6
|
+
}
|
|
7
|
+
type CostState = {
|
|
8
|
+
kind: 'loading';
|
|
9
|
+
} | {
|
|
10
|
+
kind: 'timeout';
|
|
11
|
+
} | {
|
|
12
|
+
kind: 'ready';
|
|
13
|
+
value: number;
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'unavailable';
|
|
16
|
+
};
|
|
17
|
+
/** Pure helper, exported for tests. */
|
|
18
|
+
export declare function deriveCostState(preflight: BulkTranslatePreflightResponse | null, timedOut: boolean): CostState;
|
|
19
|
+
/** Pure helper, exported for tests. */
|
|
20
|
+
export declare function isCapBlocked(preflight: BulkTranslatePreflightResponse | null): boolean;
|
|
21
|
+
export declare const BulkTranslatePreflightModal: React.FC<Props>;
|
|
22
|
+
export {};
|