@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,22 @@
|
|
|
1
|
+
import type React from 'react';
|
|
2
|
+
import type { BulkRunsTimeRange, BulkTranslateBatchSummary } from '../TranslationHub/BulkTranslate.types.js';
|
|
3
|
+
interface Props {
|
|
4
|
+
/** All currently loaded batches (full dataset, not just the page slice). */
|
|
5
|
+
batches: BulkTranslateBatchSummary[];
|
|
6
|
+
/** Total count from the API (`total` field in list response). */
|
|
7
|
+
total: number;
|
|
8
|
+
timeRange: BulkRunsTimeRange;
|
|
9
|
+
onTimeRangeChange: (r: BulkRunsTimeRange) => void;
|
|
10
|
+
/**
|
|
11
|
+
* ROUND5-3 (v1.2.6): when the filter bar has explicit `since` /
|
|
12
|
+
* `until` dates that don't match a preset, the preset pills must
|
|
13
|
+
* NOT advertise themselves as the active window — the table is
|
|
14
|
+
* filtered by the custom range, the KPIs are scoped to the preset,
|
|
15
|
+
* and showing "Last 7 days" pressed contradicts both surfaces.
|
|
16
|
+
* When true, all preset pills go inactive and a read-only "Custom"
|
|
17
|
+
* pill lights up to communicate the actual state.
|
|
18
|
+
*/
|
|
19
|
+
hasCustomDateFilter?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export declare const SummaryStrip: React.FC<Props>;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { filterPillColors } from '../shared/filterPillStyle.js';
|
|
4
|
+
import { formatCost } from '../shared/format.js';
|
|
5
|
+
import { isActiveStatus } from '../TranslationHub/BulkTranslate.types.js';
|
|
6
|
+
// ---------------------------------------------------------------------------
|
|
7
|
+
// Shared styles — mirroring StatusStrip.tsx CARD_STYLE exactly.
|
|
8
|
+
// ---------------------------------------------------------------------------
|
|
9
|
+
const CARD_STYLE = {
|
|
10
|
+
flex: 1,
|
|
11
|
+
padding: '1rem 1.25rem',
|
|
12
|
+
background: 'var(--theme-elevation-50)',
|
|
13
|
+
border: '1px solid var(--theme-elevation-150)',
|
|
14
|
+
borderRadius: '6px'
|
|
15
|
+
};
|
|
16
|
+
const LABEL_STYLE = {
|
|
17
|
+
margin: 0,
|
|
18
|
+
fontSize: '0.75rem',
|
|
19
|
+
fontWeight: 600,
|
|
20
|
+
textTransform: 'uppercase',
|
|
21
|
+
letterSpacing: '0.05em',
|
|
22
|
+
color: 'var(--theme-elevation-500)'
|
|
23
|
+
};
|
|
24
|
+
const VALUE_STYLE = {
|
|
25
|
+
margin: '0.25rem 0 0',
|
|
26
|
+
fontSize: '1.5rem',
|
|
27
|
+
fontWeight: 600,
|
|
28
|
+
color: 'var(--theme-elevation-1000)'
|
|
29
|
+
};
|
|
30
|
+
const SUBVALUE_STYLE = {
|
|
31
|
+
margin: '0.25rem 0 0',
|
|
32
|
+
fontSize: '0.75rem',
|
|
33
|
+
color: 'var(--theme-elevation-500)'
|
|
34
|
+
};
|
|
35
|
+
// ---------------------------------------------------------------------------
|
|
36
|
+
// Time-range toggle
|
|
37
|
+
// ---------------------------------------------------------------------------
|
|
38
|
+
const TIME_RANGE_LABEL = {
|
|
39
|
+
'7d': 'Last 7 days',
|
|
40
|
+
'30d': 'Last 30 days',
|
|
41
|
+
all: 'All time'
|
|
42
|
+
};
|
|
43
|
+
const TIME_RANGE_MS = {
|
|
44
|
+
'7d': 7 * 24 * 60 * 60 * 1000,
|
|
45
|
+
'30d': 30 * 24 * 60 * 60 * 1000,
|
|
46
|
+
all: null
|
|
47
|
+
};
|
|
48
|
+
// ---------------------------------------------------------------------------
|
|
49
|
+
// Helpers
|
|
50
|
+
// ---------------------------------------------------------------------------
|
|
51
|
+
function fmtNum(n) {
|
|
52
|
+
if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;
|
|
53
|
+
if (n >= 1000) return `${(n / 1000).toFixed(1)}K`;
|
|
54
|
+
return n.toString();
|
|
55
|
+
}
|
|
56
|
+
function relTime(iso) {
|
|
57
|
+
if (!iso) return '—';
|
|
58
|
+
const diff = Date.now() - new Date(iso).getTime();
|
|
59
|
+
const s = Math.floor(diff / 1000);
|
|
60
|
+
if (s < 60) return `${s}s ago`;
|
|
61
|
+
if (s < 3600) return `${Math.floor(s / 60)}m ago`;
|
|
62
|
+
if (s < 86_400) return `${Math.floor(s / 3600)}h ago`;
|
|
63
|
+
return `${Math.floor(s / 86_400)}d ago`;
|
|
64
|
+
}
|
|
65
|
+
function filterByRange(batches, range) {
|
|
66
|
+
const ms = TIME_RANGE_MS[range];
|
|
67
|
+
if (ms === null) return batches;
|
|
68
|
+
const cutoff = Date.now() - ms;
|
|
69
|
+
return batches.filter((b)=>new Date(b.createdAt).getTime() >= cutoff);
|
|
70
|
+
}
|
|
71
|
+
export const SummaryStrip = ({ batches, total, timeRange, onTimeRangeChange, hasCustomDateFilter = false })=>{
|
|
72
|
+
const activeNow = batches.filter((b)=>isActiveStatus(b.status)).length;
|
|
73
|
+
const inWindow = filterByRange(batches, timeRange);
|
|
74
|
+
const windowCost = inWindow.reduce((sum, b)=>sum + (b.actualCostUsd ?? b.estimatedCostUsd ?? 0), 0);
|
|
75
|
+
const windowUnits = inWindow.reduce((sum, b)=>sum + b.totalUnits, 0);
|
|
76
|
+
// Last completed run — pick the most recent completedAt across all loaded
|
|
77
|
+
// batches (not just the window, so it's always meaningful).
|
|
78
|
+
const lastCompletedAt = batches.reduce((latest, b)=>{
|
|
79
|
+
if (!b.completedAt) return latest;
|
|
80
|
+
if (latest === null) return b.completedAt;
|
|
81
|
+
return b.completedAt > latest ? b.completedAt : latest;
|
|
82
|
+
}, null);
|
|
83
|
+
return /*#__PURE__*/ _jsxs("div", {
|
|
84
|
+
style: {
|
|
85
|
+
display: 'flex',
|
|
86
|
+
flexDirection: 'column',
|
|
87
|
+
gap: '0.75rem'
|
|
88
|
+
},
|
|
89
|
+
children: [
|
|
90
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
91
|
+
style: {
|
|
92
|
+
display: 'flex',
|
|
93
|
+
alignItems: 'center',
|
|
94
|
+
justifyContent: 'flex-end',
|
|
95
|
+
gap: '0.25rem'
|
|
96
|
+
},
|
|
97
|
+
children: [
|
|
98
|
+
Object.keys(TIME_RANGE_LABEL).map((t)=>{
|
|
99
|
+
// ROUND5-3 (v1.2.6): when a custom date range is in effect
|
|
100
|
+
// via the filter bar, no preset is the "active" window —
|
|
101
|
+
// de-activate every preset pill so the row stops claiming a
|
|
102
|
+
// window that contradicts the table.
|
|
103
|
+
const isActive = !hasCustomDateFilter && timeRange === t;
|
|
104
|
+
const colors = filterPillColors(isActive);
|
|
105
|
+
return /*#__PURE__*/ _jsx("button", {
|
|
106
|
+
"aria-pressed": isActive,
|
|
107
|
+
type: "button",
|
|
108
|
+
onClick: ()=>onTimeRangeChange(t),
|
|
109
|
+
style: {
|
|
110
|
+
padding: '0.3rem 0.65rem',
|
|
111
|
+
fontSize: '0.75rem',
|
|
112
|
+
background: colors.background,
|
|
113
|
+
border: colors.border,
|
|
114
|
+
borderRadius: '4px',
|
|
115
|
+
color: colors.color,
|
|
116
|
+
cursor: 'pointer',
|
|
117
|
+
fontWeight: isActive ? 600 : 400
|
|
118
|
+
},
|
|
119
|
+
children: TIME_RANGE_LABEL[t]
|
|
120
|
+
}, t);
|
|
121
|
+
}),
|
|
122
|
+
hasCustomDateFilter && (()=>{
|
|
123
|
+
const colors = filterPillColors(true);
|
|
124
|
+
return /*#__PURE__*/ _jsx("span", {
|
|
125
|
+
"aria-pressed": "true",
|
|
126
|
+
role: "status",
|
|
127
|
+
style: {
|
|
128
|
+
padding: '0.3rem 0.65rem',
|
|
129
|
+
fontSize: '0.75rem',
|
|
130
|
+
background: colors.background,
|
|
131
|
+
border: colors.border,
|
|
132
|
+
borderRadius: '4px',
|
|
133
|
+
color: colors.color,
|
|
134
|
+
fontWeight: 600,
|
|
135
|
+
cursor: 'default'
|
|
136
|
+
},
|
|
137
|
+
title: "Custom date range active via the filter bar below. Clear the Since / Until fields to return to a preset window.",
|
|
138
|
+
children: "Custom"
|
|
139
|
+
});
|
|
140
|
+
})()
|
|
141
|
+
]
|
|
142
|
+
}),
|
|
143
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
144
|
+
style: {
|
|
145
|
+
display: 'flex',
|
|
146
|
+
gap: '1rem'
|
|
147
|
+
},
|
|
148
|
+
children: [
|
|
149
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
150
|
+
style: CARD_STYLE,
|
|
151
|
+
children: [
|
|
152
|
+
/*#__PURE__*/ _jsx("p", {
|
|
153
|
+
style: LABEL_STYLE,
|
|
154
|
+
children: "Active now"
|
|
155
|
+
}),
|
|
156
|
+
/*#__PURE__*/ _jsx("p", {
|
|
157
|
+
style: VALUE_STYLE,
|
|
158
|
+
children: activeNow
|
|
159
|
+
}),
|
|
160
|
+
/*#__PURE__*/ _jsx("p", {
|
|
161
|
+
style: SUBVALUE_STYLE,
|
|
162
|
+
children: activeNow === 0 ? 'No runs in progress' : 'Run(s) in progress'
|
|
163
|
+
})
|
|
164
|
+
]
|
|
165
|
+
}),
|
|
166
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
167
|
+
style: CARD_STYLE,
|
|
168
|
+
children: [
|
|
169
|
+
/*#__PURE__*/ _jsx("p", {
|
|
170
|
+
style: LABEL_STYLE,
|
|
171
|
+
children: "Total batches"
|
|
172
|
+
}),
|
|
173
|
+
/*#__PURE__*/ _jsx("p", {
|
|
174
|
+
style: VALUE_STYLE,
|
|
175
|
+
children: fmtNum(total)
|
|
176
|
+
}),
|
|
177
|
+
/*#__PURE__*/ _jsx("p", {
|
|
178
|
+
style: SUBVALUE_STYLE,
|
|
179
|
+
children: "All time"
|
|
180
|
+
})
|
|
181
|
+
]
|
|
182
|
+
}),
|
|
183
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
184
|
+
style: CARD_STYLE,
|
|
185
|
+
children: [
|
|
186
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
187
|
+
style: LABEL_STYLE,
|
|
188
|
+
children: [
|
|
189
|
+
TIME_RANGE_LABEL[timeRange],
|
|
190
|
+
" cost"
|
|
191
|
+
]
|
|
192
|
+
}),
|
|
193
|
+
/*#__PURE__*/ _jsx("p", {
|
|
194
|
+
style: VALUE_STYLE,
|
|
195
|
+
children: formatCost(windowCost)
|
|
196
|
+
}),
|
|
197
|
+
/*#__PURE__*/ _jsx("p", {
|
|
198
|
+
style: SUBVALUE_STYLE,
|
|
199
|
+
children: "Actual spend (loaded batches)"
|
|
200
|
+
})
|
|
201
|
+
]
|
|
202
|
+
}),
|
|
203
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
204
|
+
style: CARD_STYLE,
|
|
205
|
+
children: [
|
|
206
|
+
/*#__PURE__*/ _jsxs("p", {
|
|
207
|
+
style: LABEL_STYLE,
|
|
208
|
+
children: [
|
|
209
|
+
TIME_RANGE_LABEL[timeRange],
|
|
210
|
+
" units"
|
|
211
|
+
]
|
|
212
|
+
}),
|
|
213
|
+
/*#__PURE__*/ _jsx("p", {
|
|
214
|
+
style: VALUE_STYLE,
|
|
215
|
+
children: fmtNum(windowUnits)
|
|
216
|
+
}),
|
|
217
|
+
/*#__PURE__*/ _jsx("p", {
|
|
218
|
+
style: SUBVALUE_STYLE,
|
|
219
|
+
children: "Translation units processed"
|
|
220
|
+
})
|
|
221
|
+
]
|
|
222
|
+
}),
|
|
223
|
+
/*#__PURE__*/ _jsxs("div", {
|
|
224
|
+
style: CARD_STYLE,
|
|
225
|
+
children: [
|
|
226
|
+
/*#__PURE__*/ _jsx("p", {
|
|
227
|
+
style: LABEL_STYLE,
|
|
228
|
+
children: "Last run"
|
|
229
|
+
}),
|
|
230
|
+
/*#__PURE__*/ _jsx("p", {
|
|
231
|
+
style: VALUE_STYLE,
|
|
232
|
+
title: lastCompletedAt ?? undefined,
|
|
233
|
+
children: lastCompletedAt ? relTime(lastCompletedAt) : '—'
|
|
234
|
+
}),
|
|
235
|
+
/*#__PURE__*/ _jsx("p", {
|
|
236
|
+
style: SUBVALUE_STYLE,
|
|
237
|
+
children: lastCompletedAt ? new Date(lastCompletedAt).toLocaleDateString(undefined, {
|
|
238
|
+
month: 'short',
|
|
239
|
+
day: 'numeric',
|
|
240
|
+
year: 'numeric'
|
|
241
|
+
}) : 'No completed runs yet'
|
|
242
|
+
})
|
|
243
|
+
]
|
|
244
|
+
})
|
|
245
|
+
]
|
|
246
|
+
})
|
|
247
|
+
]
|
|
248
|
+
});
|
|
249
|
+
};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Group a flat list of `BatchJobSummary` units into a 2-level tree:
|
|
3
|
+
*
|
|
4
|
+
* Bucket (collection or global)
|
|
5
|
+
* └── Document
|
|
6
|
+
* └── Locales (rendered inline as chips, not as separate rows)
|
|
7
|
+
*
|
|
8
|
+
* Editor mental model is collection-shaped, not unit-shaped — direct quote:
|
|
9
|
+
* "let's say 50 docs from one collection fail but 150 are completed maybe
|
|
10
|
+
* I want to trigger retry for those 50 easily." The flat list doesn't
|
|
11
|
+
* surface that grouping; this helper does.
|
|
12
|
+
*
|
|
13
|
+
* Heuristic for distinguishing globals from collections: the worker stores
|
|
14
|
+
* `documentId === collection` for globals (the slug doubles as the id),
|
|
15
|
+
* whereas collections have a numeric / UUID document id. Confirmed against
|
|
16
|
+
* `api.ts:translateGlobal` which returns
|
|
17
|
+
* `{ documentId: options.global, collection: options.global, ... }`.
|
|
18
|
+
*/
|
|
19
|
+
import type { BatchJobSummary, BatchUnitCountsByCollection } from '../TranslationHub/BulkTranslate.types.js';
|
|
20
|
+
export type DocGroup = {
|
|
21
|
+
collection: string;
|
|
22
|
+
documentId: string;
|
|
23
|
+
/** One entry per locale for this (collection, docId). */
|
|
24
|
+
jobs: BatchJobSummary[];
|
|
25
|
+
/** How many of this doc's locales finished as `failed`. */
|
|
26
|
+
failedLocaleCount: number;
|
|
27
|
+
/** How many of this doc's locales finished as `success`. */
|
|
28
|
+
succeededLocaleCount: number;
|
|
29
|
+
/**
|
|
30
|
+
* Per-doc wallclock span: `max(completedAt) − min(startedAt)` across
|
|
31
|
+
* this doc's locales. Primary duration metric at the doc level —
|
|
32
|
+
* answers "from when we started translating this doc to when the
|
|
33
|
+
* last locale finished." Includes any throttle queue wait the doc's
|
|
34
|
+
* locales sat through. Null when timestamps aren't available
|
|
35
|
+
* (in-flight unit).
|
|
36
|
+
*/
|
|
37
|
+
docSpanMs: number | null;
|
|
38
|
+
/**
|
|
39
|
+
* Sum of `processingDurationMs` across this doc's locales — total AI
|
|
40
|
+
* compute time for the doc. Null on legacy units that pre-date the
|
|
41
|
+
* `processingDurationMs` column.
|
|
42
|
+
*/
|
|
43
|
+
docAiActiveMs: number | null;
|
|
44
|
+
/**
|
|
45
|
+
* `docSpanMs − docAiActiveMs`, clamped ≥0. Pairs with `docAiActiveMs`
|
|
46
|
+
* as the secondary "AI active / queue wait" sub-line. Null when
|
|
47
|
+
* either source is null.
|
|
48
|
+
*/
|
|
49
|
+
docQueueWaitMs: number | null;
|
|
50
|
+
/** Total cost across all locales for this doc, in USD. */
|
|
51
|
+
totalCostUsd: number;
|
|
52
|
+
/** Max attempts across this doc's locales. */
|
|
53
|
+
maxAttempts: number;
|
|
54
|
+
};
|
|
55
|
+
export type Bucket = {
|
|
56
|
+
/** Collection slug, or global slug. Used as the bucket key. */
|
|
57
|
+
collection: string;
|
|
58
|
+
/** `true` when this is a global (single row), `false` for collections. */
|
|
59
|
+
isGlobal: boolean;
|
|
60
|
+
/** Docs in this bucket, keyed by `documentId`. Ordered insertion. */
|
|
61
|
+
docs: Map<string, DocGroup>;
|
|
62
|
+
/**
|
|
63
|
+
* Total units across the ENTIRE bucket (from the backend's
|
|
64
|
+
* `countsByCollection` aggregate). Not just the paginated loaded
|
|
65
|
+
* subset. The doc rows in `docs` may be a subset of this — render
|
|
66
|
+
* `docs.size` of `totalDocs` to communicate the gap.
|
|
67
|
+
*/
|
|
68
|
+
totalUnits: number;
|
|
69
|
+
succeededCount: number;
|
|
70
|
+
failedCount: number;
|
|
71
|
+
pendingCount: number;
|
|
72
|
+
runningCount: number;
|
|
73
|
+
skippedCount: number;
|
|
74
|
+
revertedCount: number;
|
|
75
|
+
/** Distinct documents in this bucket (from backend, not paginated). */
|
|
76
|
+
totalDocs: number;
|
|
77
|
+
/** Docs actually loaded into the `docs` map. ≤ totalDocs when paginated. */
|
|
78
|
+
loadedDocs: number;
|
|
79
|
+
/** Top-2 failure codes by frequency, for the bucket header summary. */
|
|
80
|
+
topFailureCodes: Array<{
|
|
81
|
+
code: string;
|
|
82
|
+
count: number;
|
|
83
|
+
}>;
|
|
84
|
+
/** Distinct failure code count — used to decide "show breakdown" CTA. */
|
|
85
|
+
distinctFailureCodes: number;
|
|
86
|
+
/** UX-spec per-collection duration aggregates. See `BatchUnitCountsByCollection`. */
|
|
87
|
+
collectionSpanMs: number | null;
|
|
88
|
+
aiActiveMs: number | null;
|
|
89
|
+
queueWaitMs: number | null;
|
|
90
|
+
/**
|
|
91
|
+
* v1.2.7: filter-aware doc counts per bucket. Keyed by the UI filter
|
|
92
|
+
* chip name (`all`, `pending`, `running`, `completed`, `failed`,
|
|
93
|
+
* `skipped`, `reverted`). Drives the bucket-header count + the
|
|
94
|
+
* filter-aware "hide bucket when 0" rule. Falls back to a derived
|
|
95
|
+
* shape from the scalar counts when the backend response is pre-1.2.7.
|
|
96
|
+
*/
|
|
97
|
+
docCountsByStatus: {
|
|
98
|
+
all: number;
|
|
99
|
+
pending: number;
|
|
100
|
+
running: number;
|
|
101
|
+
completed: number;
|
|
102
|
+
failed: number;
|
|
103
|
+
skipped: number;
|
|
104
|
+
reverted: number;
|
|
105
|
+
};
|
|
106
|
+
};
|
|
107
|
+
/**
|
|
108
|
+
* Filter chip values shared with the BatchRow drill-down. Mirrors
|
|
109
|
+
* `UNIT_FILTER_CHIPS` there — duplicated here so the bucket helpers can
|
|
110
|
+
* type the active filter without importing the React module (which
|
|
111
|
+
* would create a cycle).
|
|
112
|
+
*/
|
|
113
|
+
export type BucketStatusFilter = 'all' | 'pending' | 'running' | 'completed' | 'failed' | 'skipped' | 'reverted';
|
|
114
|
+
/**
|
|
115
|
+
* Resolve the bucket header count for the active filter pill. Returns a
|
|
116
|
+
* UNIT-level count (the historical semantics — `succeededCount`,
|
|
117
|
+
* `failedCount` etc. on the bucket are unit-based). When the filter is
|
|
118
|
+
* `all`, returns `totalUnits`. Otherwise returns the matching scalar.
|
|
119
|
+
*
|
|
120
|
+
* Doc-level counts (`docCountsByStatus`) stay on the bucket for callers
|
|
121
|
+
* that need "how many distinct docs match this filter" — e.g. the
|
|
122
|
+
* `shouldBucketBeVisibleUnderFilter` rule below, which has to know
|
|
123
|
+
* whether any docs at all will render under the active filter.
|
|
124
|
+
*/
|
|
125
|
+
export declare function getBucketCountForFilter(bucket: Pick<Bucket, 'totalUnits' | 'succeededCount' | 'failedCount' | 'pendingCount' | 'runningCount' | 'skippedCount' | 'revertedCount'>, filter: BucketStatusFilter): number;
|
|
126
|
+
/**
|
|
127
|
+
* Decide whether a bucket should render at all under the active filter.
|
|
128
|
+
* Hides buckets that have zero matching docs when a non-`all` filter is
|
|
129
|
+
* active — the previous behaviour rendered the bucket header with stale
|
|
130
|
+
* unfiltered counts, contradicting the global "No units match" message
|
|
131
|
+
* below. With this rule the entire bucket disappears, and the global
|
|
132
|
+
* empty state surfaces only when EVERY bucket is empty.
|
|
133
|
+
*
|
|
134
|
+
* Uses the DOC count rather than the unit count because the expanded
|
|
135
|
+
* panel renders one row per doc. A bucket with one doc whose only
|
|
136
|
+
* failed locale we'd be looking at is still worth showing — but only
|
|
137
|
+
* if at least one such doc exists.
|
|
138
|
+
*/
|
|
139
|
+
export declare function shouldBucketBeVisibleUnderFilter(bucket: Pick<Bucket, 'docCountsByStatus' | 'totalDocs'>, filter: BucketStatusFilter): boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Group the flat `jobs` array into buckets, using backend
|
|
142
|
+
* `countsByCollection` for the authoritative per-bucket totals.
|
|
143
|
+
*
|
|
144
|
+
* Two passes:
|
|
145
|
+
* 1. Seed every bucket from `countsByCollection` (the FULL totals
|
|
146
|
+
* across the batch — not just the paginated `jobs` page). This
|
|
147
|
+
* ensures bucket headers show correct counts even when the
|
|
148
|
+
* `jobs` page only contains a subset.
|
|
149
|
+
* 2. Walk `jobs` and attach the loaded docs to their buckets.
|
|
150
|
+
* `bucket.loadedDocs < bucket.totalDocs` when the page hasn't
|
|
151
|
+
* loaded every doc in the bucket — UI surfaces this gap.
|
|
152
|
+
*
|
|
153
|
+
* Sort order:
|
|
154
|
+
* 1. Buckets with failures come first (descending failure count).
|
|
155
|
+
* 2. Then collections alphabetically.
|
|
156
|
+
* 3. Then globals alphabetically (any bucket with `isGlobal: true`).
|
|
157
|
+
*
|
|
158
|
+
* Within a bucket, docs are kept in their original insertion order from
|
|
159
|
+
* the `jobs` array — Payload's status endpoint already sorts by unit id
|
|
160
|
+
* (closely aligned with creation order), which is a reasonable default.
|
|
161
|
+
*/
|
|
162
|
+
export declare function groupJobsIntoBuckets(jobs: BatchJobSummary[], countsByCollection?: BatchUnitCountsByCollection): Bucket[];
|
|
163
|
+
/**
|
|
164
|
+
* Whether a bucket should start expanded on initial render. Per UX
|
|
165
|
+
* recommendation: failed buckets expanded by default (problem is on
|
|
166
|
+
* screen without clicking), all-success buckets collapsed (don't
|
|
167
|
+
* clutter the triage view).
|
|
168
|
+
*/
|
|
169
|
+
export declare function shouldBucketBeExpandedByDefault(bucket: Bucket): boolean;
|
|
170
|
+
/**
|
|
171
|
+
* Compact duration helper used by `fmtBucketAiActive` /
|
|
172
|
+
* `fmtBucketQueued`. Thin wrapper around the shared `formatDuration`
|
|
173
|
+
* helper — kept as a separate export so the bucket-grouping module
|
|
174
|
+
* doesn't need to import from `views/shared/format.ts` directly at
|
|
175
|
+
* every call site, and so the bucket-runtime tests keep their
|
|
176
|
+
* historical name. NEW-18 (v1.2.6): carries minutes → hours → days
|
|
177
|
+
* via the shared helper; the legacy implementation capped at minutes
|
|
178
|
+
* (`964m 6s`).
|
|
179
|
+
*/
|
|
180
|
+
export declare function fmtBucketDurationShort(ms: number | null | undefined): string;
|
|
181
|
+
type BucketDurations = {
|
|
182
|
+
aiActiveMs: number | null;
|
|
183
|
+
collectionSpanMs: number | null;
|
|
184
|
+
queueWaitMs: number | null;
|
|
185
|
+
};
|
|
186
|
+
/**
|
|
187
|
+
* Render the bucket header "AI active" cell. When `aiActiveMs` exceeds
|
|
188
|
+
* `collectionSpanMs` (parallelism), present as `≈<span>` rather than a
|
|
189
|
+
* number that visually contradicts the total wallclock. The raw numbers
|
|
190
|
+
* are unchanged; the tooltip still shows both.
|
|
191
|
+
*/
|
|
192
|
+
export declare function fmtBucketAiActive(bucket: Pick<BucketDurations, 'aiActiveMs' | 'collectionSpanMs'>): string;
|
|
193
|
+
/**
|
|
194
|
+
* Render the bucket header "Queued" cell. Uses the server-clamped queue
|
|
195
|
+
* wait but renders `0` as `'0s'` (instead of `'—'`) so editors can tell
|
|
196
|
+
* "no wait" from "data missing." When AI overran span, the queue wait
|
|
197
|
+
* is necessarily zero — surface that explicitly.
|
|
198
|
+
*/
|
|
199
|
+
export declare function fmtBucketQueued(bucket: BucketDurations): string;
|
|
200
|
+
export {};
|