diff --git a/apps/desktop-tauri/src-tauri/src/commands/bridge.rs b/apps/desktop-tauri/src-tauri/src/commands/bridge.rs index 2edf24acd4..841756b9b1 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/bridge.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/bridge.rs @@ -102,8 +102,6 @@ pub struct CostSnapshotBridge { pub formatted_balance: Option, #[serde(default)] pub daily: Vec, - #[serde(default)] - pub always_visible: bool, } fn default_currency() -> String { @@ -335,12 +333,10 @@ impl ProviderUsageSnapshot { .unwrap_or_else(|| metadata.session_label.to_string()), ), secondary: secondary_snap, - secondary_label: usage.secondary.as_ref().map(|_| { - usage - .secondary_label - .clone() - .unwrap_or_else(|| metadata.weekly_label.to_string()) - }), + secondary_label: usage + .secondary + .as_ref() + .map(|_| metadata.weekly_label.to_string()), model_specific: usage .model_specific .as_ref() @@ -389,7 +385,6 @@ impl ProviderUsageSnapshot { amount: point.amount, }) .collect(), - always_visible: c.always_visible, }), plan_name: usage.login_method.clone(), account_email: usage.account_email.clone(), diff --git a/apps/desktop-tauri/src-tauri/src/commands/chart.rs b/apps/desktop-tauri/src-tauri/src/commands/chart.rs index 0bcd95b0da..7a533267a4 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/chart.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/chart.rs @@ -25,7 +25,7 @@ const LOCAL_USAGE_TTL: Duration = Duration::from_secs(30); #[serde(rename_all = "camelCase")] pub struct DailyCostPoint { pub date: String, - pub value: Option, + pub value: f64, } /// A single (date, tokens) point for the Tokens chart mode (upstream 0.50.0 @@ -494,7 +494,7 @@ fn load_openai_dashboard_chart_data( .iter() .map(|d| DailyCostPoint { date: d.day.clone(), - value: Some(d.total_credits_used), + value: d.total_credits_used, }) .collect(); diff --git a/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs b/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs index ddf94f30dd..3fff45473d 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/provider_settings.rs @@ -137,7 +137,6 @@ fn cookie_source_provider(provider_id: &str) -> Option ProviderId::OpenCode, "factory" => ProviderId::Factory, "alibaba" => ProviderId::Alibaba, - "alibabatokenplan" => ProviderId::AlibabaTokenPlan, "kimi" | "kimik2" => ProviderId::Kimi, "minimax" => ProviderId::MiniMax, "augment" => ProviderId::Augment, @@ -548,7 +547,7 @@ pub fn cookie_source_options_for(provider_id: &str, lang: Language) -> Vec vec![ + "alibaba" => vec![ cookie_option( lang, "auto", diff --git a/apps/desktop-tauri/src-tauri/src/commands/spend_contract.rs b/apps/desktop-tauri/src-tauri/src/commands/spend_contract.rs index a3e3637f12..8eb0e7f940 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/spend_contract.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/spend_contract.rs @@ -33,7 +33,6 @@ pub async fn get_spend_contract( history_days, include_import, settings.hide_native_codex_cost_when_open_codex_present && provider == "codex", - settings.hide_personal_info, summary, ) }) diff --git a/apps/desktop-tauri/src-tauri/src/commands/tests.rs b/apps/desktop-tauri/src-tauri/src/commands/tests.rs index faa5731532..8d58b7192e 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/tests.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/tests.rs @@ -1117,16 +1117,16 @@ fn chart_data_serde_roundtrip_preserves_fields() { cost_history: vec![ DailyCostPoint { date: "2025-01-01".into(), - value: Some(1.25), + value: 1.25, }, DailyCostPoint { date: "2025-01-02".into(), - value: Some(0.0), + value: 0.0, }, ], credits_history: vec![DailyCostPoint { date: "2025-01-01".into(), - value: Some(42.0), + value: 42.0, }], usage_breakdown: vec![DailyUsageBreakdown { day: "2025-01-01".into(), @@ -1169,7 +1169,7 @@ fn chart_data_serde_roundtrip_preserves_fields() { assert_eq!(back.provider_id, "codex"); assert_eq!(back.cost_history.len(), 2); assert_eq!(back.cost_history[0].date, "2025-01-01"); - assert_eq!(back.credits_history[0].value, Some(42.0)); + assert_eq!(back.credits_history[0].value, 42.0); assert_eq!(back.usage_breakdown[0].services.len(), 2); assert_eq!(back.usage_breakdown[0].total_credits_used, 13.5); assert_eq!(back.tokens_history[0].tokens, 123_456); diff --git a/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs b/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs index db2d49458a..23384b5aae 100644 --- a/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs +++ b/apps/desktop-tauri/src-tauri/src/commands/usage_spend.rs @@ -113,8 +113,7 @@ fn build_usage_spend_summary_cached( selected_days: u32, force_refresh: bool, ) -> Result { - let settings = codexbar::settings::Settings::load(); - let key = usage_spend_cache_key(cached, selected_days, &settings); + let key = usage_spend_cache_key(cached, selected_days); let mut guard = usage_spend_summary_cache() .lock() .map_err(|error| error.to_string())?; @@ -126,7 +125,7 @@ fn build_usage_spend_summary_cached( } // Hold the cache mutex while building: callers for the same app revision // coalesce behind this single scan instead of starting parallel rescans. - let summary = build_usage_spend_summary(cached, selected_days, &settings); + let summary = build_usage_spend_summary(cached, selected_days); *guard = Some(CachedUsageSpendSummary { key, summary: summary.clone(), @@ -134,27 +133,8 @@ fn build_usage_spend_summary_cached( Ok(summary) } -fn usage_spend_cache_key( - cached: &[ProviderUsageSnapshot], - selected_days: u32, - settings: &codexbar::settings::Settings, -) -> String { - usage_spend_cache_key_with_privacy( - cached, - selected_days, - settings.open_codex_usage_logs_enabled, - settings.hide_native_codex_cost_when_open_codex_present, - settings.hide_personal_info, - ) -} - -fn usage_spend_cache_key_with_privacy( - cached: &[ProviderUsageSnapshot], - selected_days: u32, - include_opencodex: bool, - hide_native: bool, - hide_personal_info: bool, -) -> String { +fn usage_spend_cache_key(cached: &[ProviderUsageSnapshot], selected_days: u32) -> String { + let settings = codexbar::settings::Settings::load(); let mut revisions: Vec = cached .iter() .map(|snapshot| { @@ -182,12 +162,11 @@ fn usage_spend_cache_key_with_privacy( .collect(); revisions.sort(); format!( - "{}|{}|{}|{}|{}|{}", + "{}|{}|{}|{}|{}", chrono::Local::now().date_naive(), selected_days, - include_opencodex, - hide_native, - hide_personal_info, + settings.open_codex_usage_logs_enabled, + settings.hide_native_codex_cost_when_open_codex_present, revisions.join(";") ) } @@ -195,11 +174,23 @@ fn usage_spend_cache_key_with_privacy( fn build_usage_spend_summary( cached: &[ProviderUsageSnapshot], selected_days: u32, - settings: &codexbar::settings::Settings, ) -> UsageSpendSummary { + let settings = codexbar::settings::Settings::load(); let include_opencodex = settings.open_codex_usage_logs_enabled; let hide_native = settings.hide_native_codex_cost_when_open_codex_present; + let codex_cache = + codexbar::core::JsonlScanner::load_cache(codexbar::core::ProviderId::Codex, None); + let codex_stale = !codex_cache.days.is_empty() && codex_cache.previous_report.is_some(); + let codex_stale_updated_at = codex_stale + .then(|| { + codex_cache + .previous_report + .as_ref() + .and_then(|r| r.updated_at.clone()) + }) + .flatten(); + // Upstream 0.55.0 #3105: independent provider baselines load in parallel. // Keep each provider's 7d/30d scans serial so they can safely share that // provider's incremental cache, while Codex and Claude run concurrently. @@ -223,21 +214,11 @@ fn build_usage_spend_summary( ) }); - let codex_stale = !codex_30_summary.history_coverage_established; - let codex_stale_updated_at = codex_stale - .then(|| { - codexbar::core::JsonlScanner::load_cache_status(codexbar::core::ProviderId::Codex, None) - .previous_report - .and_then(|report| report.updated_at) - }) - .flatten(); - let codex_7_contract = build_local_spend_contract_from_summary( "codex", 7, include_opencodex, hide_native, - settings.hide_personal_info, codex_7_summary.clone(), ); let codex_30_contract = build_local_spend_contract_from_summary( @@ -245,7 +226,6 @@ fn build_usage_spend_summary( 30, include_opencodex, hide_native, - settings.hide_personal_info, codex_30_summary.clone(), ); @@ -371,16 +351,13 @@ fn build_usage_spend_summary( spend } "antigravity" => { - use codexbar::providers::antigravity::local_sessions::LocalHistoryCoverage; let seven = codexbar::providers::antigravity::local_sessions::summarize(7); let thirty = codexbar::providers::antigravity::local_sessions::summarize(30); let mut spend = cached_spend(cached_snapshot); - spend.seven_day_tokens = matches!(seven.coverage, LocalHistoryCoverage::Complete) - .then_some(seven.total_tokens); - spend.thirty_day_tokens = matches!(thirty.coverage, LocalHistoryCoverage::Complete) - .then_some(thirty.total_tokens); - if matches!(thirty.coverage, LocalHistoryCoverage::Complete) { - spend.source = "local Antigravity history".to_string(); + spend.seven_day_tokens = (seven.session_count > 0).then_some(seven.total_tokens); + spend.thirty_day_tokens = (thirty.session_count > 0).then_some(thirty.total_tokens); + if thirty.session_count > 0 { + spend.source = "local Antigravity sessions".to_string(); } spend } @@ -435,7 +412,6 @@ fn build_usage_spend_summary( history_days, include_opencodex, hide_native, - settings.hide_personal_info, selected_summary, ); UsageSpendSummary { rows, contract } @@ -528,15 +504,3 @@ fn cached_spend(snapshot: Option<&ProviderUsageSnapshot>) -> SpendValues { stale_updated_at: None, } } - -#[cfg(test)] -mod cache_key_tests { - use super::*; - - #[test] - fn privacy_mode_is_part_of_usage_spend_cache_identity() { - let public = usage_spend_cache_key_with_privacy(&[], 30, false, false, false); - let private = usage_spend_cache_key_with_privacy(&[], 30, false, false, true); - assert_ne!(public, private); - } -} diff --git a/apps/desktop-tauri/src-tauri/src/tray_bridge.rs b/apps/desktop-tauri/src-tauri/src/tray_bridge.rs index e0b38d55cf..53580a36cf 100644 --- a/apps/desktop-tauri/src-tauri/src/tray_bridge.rs +++ b/apps/desktop-tauri/src-tauri/src/tray_bridge.rs @@ -1079,7 +1079,6 @@ mod tests { balance: None, formatted_balance: None, daily: Vec::new(), - always_visible: false, }), plan_name: None, account_email: None, diff --git a/apps/desktop-tauri/src/components/MenuCard.test.tsx b/apps/desktop-tauri/src/components/MenuCard.test.tsx index bed4d2ca6f..c7838cf8e6 100644 --- a/apps/desktop-tauri/src/components/MenuCard.test.tsx +++ b/apps/desktop-tauri/src/components/MenuCard.test.tsx @@ -86,7 +86,6 @@ function renderCard( showResetWhenExhausted?: boolean; showPace?: boolean; onLayoutChange?: () => void; - costSummaryDisplayStyle?: "compact" | "detailed" | "hidden"; } = {}, ) { return render( @@ -99,7 +98,6 @@ function renderCard( showAsUsed: opts.showAsUsed, showResetWhenExhausted: opts.showResetWhenExhausted, showPace: opts.showPace, - costSummaryDisplayStyle: opts.costSummaryDisplayStyle, }} onLayoutChange={opts.onLayoutChange} /> @@ -113,7 +111,6 @@ describe("MenuCard", () => { tauriMocks.getLocaleStrings.mockResolvedValue( buildBundle({ ActionCopyError: "Copy error", - ApiSpendTitle: "API spend", DetailPaceRunsOutIn: "Runs out in", PanelEstimatedFromLocalLogs: "Estimated from local logs", PanelLeftSuffix: "left", @@ -170,31 +167,6 @@ describe("MenuCard", () => { eventMocks.listen.mockResolvedValue(() => {}); }); - it("keeps Fireworks vendor API spend visible when local cost summaries are hidden", async () => { - const snapshot = provider(null, 0); - snapshot.providerId = "fireworks"; - snapshot.displayName = "Fireworks"; - snapshot.cost = { - used: 12.34, - limit: null, - remaining: null, - currencyCode: "USD", - currencySymbol: "$", - period: "30 days", - resetsAt: null, - formattedUsed: "$12.34", - formattedLimit: null, - balance: null, - formattedBalance: null, - daily: [], - alwaysVisible: true, - }; - - renderCard(snapshot, { costSummaryDisplayStyle: "hidden" }); - - expect(await screen.findByText("API spend")).toBeInTheDocument(); - expect(document.querySelector(".menu-card__cost-line")).toHaveTextContent("$12.34"); - }); it("does not mix stale local usage into an error card", async () => { const { container } = renderCard( provider("OAuth error: Claude OAuth credentials not found."), diff --git a/apps/desktop-tauri/src/components/MenuCardDetails.tsx b/apps/desktop-tauri/src/components/MenuCardDetails.tsx index 14d7fced8a..4ef58e3d1c 100644 --- a/apps/desktop-tauri/src/components/MenuCardDetails.tsx +++ b/apps/desktop-tauri/src/components/MenuCardDetails.tsx @@ -108,11 +108,10 @@ function LocalUsageBlock({ }) { const { t } = useLocale(); const isCodex = providerId === "codex"; - const visibleHistory = costHistory.slice(-30); - const maxCost = Math.max( - ...visibleHistory.flatMap((point) => (point.value == null ? [] : [point.value])), - 0, - ); + const visibleHistory = costHistory + .slice(-30) + .filter((point) => point.value > 0); + const maxCost = Math.max(...visibleHistory.map((point) => point.value), 0); return (
@@ -149,10 +148,9 @@ function LocalUsageBlock({ ))} @@ -445,7 +443,7 @@ export function describeCard( showPace = true, ): MenuCardPresence { const hasCostHistory = - chartData !== null && chartData.costHistory.some((point) => point.value != null); + chartData !== null && chartData.costHistory.some((point) => point.value > 0); const hasCreditsHistory = chartData !== null && chartData.creditsHistory.length > 0; const hasUsageBreakdown = @@ -455,9 +453,7 @@ export function describeCard( const localUsage = provider.error ? null : chartData?.localUsage ?? null; const wayfinderUsage = isWayfinder ? provider.wayfinderUsage : null; const hasMetrics = visibleMetrics.length > 0; - const hasCost = - !!provider.cost && - (costSummaryDisplayStyle !== "hidden" || provider.cost.alwaysVisible === true); + const hasCost = !!provider.cost && costSummaryDisplayStyle !== "hidden"; const hasPace = showPace && !!provider.pace; const hasDetails = !provider.error && @@ -542,15 +538,13 @@ export default function MenuCardDetails({ /> )} - {hasMetrics && hasCost &&
} + {hasMetrics && hasCost && costStyle !== "hidden" &&
} - {hasCost && provider.cost && ( + {provider.cost && costStyle !== "hidden" && (
- {provider.cost.alwaysVisible === true && (provider.cost.limit ?? 0) <= 0 - ? t("ApiSpendTitle") - : provider.cost.balance != null && provider.cost.limit == null - ? provider.cost.period || t("CreditsLabel") + {provider.cost.balance != null && provider.cost.limit == null + ? provider.cost.period || t("CreditsLabel") : `${t("DetailCostTitle")} — ${provider.cost.period}`}
{provider.cost.balance != null && provider.cost.limit == null ? ( diff --git a/apps/desktop-tauri/src/components/MiniBarChart.tsx b/apps/desktop-tauri/src/components/MiniBarChart.tsx index 5b5f8eff9b..df9ca989c4 100644 --- a/apps/desktop-tauri/src/components/MiniBarChart.tsx +++ b/apps/desktop-tauri/src/components/MiniBarChart.tsx @@ -31,8 +31,7 @@ export function SimpleBarChart({ ); } - const knownValues = points.flatMap((p) => (p.value == null ? [] : [p.value])); - const max = Math.max(...knownValues, 0.0001); + const max = Math.max(...points.map((p) => p.value), 0.0001); const BAR_GAP = 2; const fmt = formatValue ?? ((v: number) => v.toFixed(2)); @@ -56,7 +55,7 @@ export function SimpleBarChart({ aria-label={label ?? t("BarChartAriaLabel")} > {visible.map((p, i) => { - const barH = p.value == null ? 1 : Math.max(1, (p.value / max) * (height - 4)); + const barH = Math.max(1, (p.value / max) * (height - 4)); const x = i * (barWidth + BAR_GAP); const y = height - barH; return ( @@ -67,11 +66,11 @@ export function SimpleBarChart({ width={barWidth} height={barH} fill={color} - opacity={p.value == null ? 0 : p.value === 0 ? 0.25 : 0.9} + opacity={p.value === 0 ? 0.25 : 0.9} rx={1} > - {p.value == null ? p.date : `${p.date}: ${fmt(p.value)}`} + {p.date}: {fmt(p.value)} ); diff --git a/apps/desktop-tauri/src/components/charts/BarChart.test.tsx b/apps/desktop-tauri/src/components/charts/BarChart.test.tsx deleted file mode 100644 index 95403690e9..0000000000 --- a/apps/desktop-tauri/src/components/charts/BarChart.test.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import { render } from "@testing-library/react"; -import { describe, expect, it } from "vitest"; -import { BarChart } from "./BarChart"; - -describe("BarChart calendar slots", () => { - it("keeps unknown and known-zero slots distinct", () => { - const { container } = render( - , - ); - const bars = container.querySelectorAll(".chart__bar"); - expect(bars).toHaveLength(3); - expect(bars[0]).toHaveAttribute("opacity", "0"); - expect(bars[1]).toHaveAttribute("opacity", "0.25"); - expect(container).toHaveTextContent("unknown"); - expect(container).toHaveTextContent("zero: 0.00"); - }); -}); \ No newline at end of file diff --git a/apps/desktop-tauri/src/components/charts/BarChart.tsx b/apps/desktop-tauri/src/components/charts/BarChart.tsx index 4813543220..0a0cc4c744 100644 --- a/apps/desktop-tauri/src/components/charts/BarChart.tsx +++ b/apps/desktop-tauri/src/components/charts/BarChart.tsx @@ -15,7 +15,7 @@ import { useChartAnimation } from "./useChartAnimation"; export interface BarChartPoint { label: string; - value: number | null; + value: number; } export interface BarChartProps { @@ -59,7 +59,7 @@ export function BarChart({ let p = -1; for (let i = 0; i < data.length; i++) { const v = data[i].value; - if (v != null && v > m) { + if (v > m) { m = v; p = i; } @@ -101,7 +101,7 @@ export function BarChart({ aria-label={ariaLabel} > {data.map((p, i) => { - const base = p.value == null ? 1 : p.value === 0 ? 1 : Math.max(3, (p.value / max) * plotHeight); + const base = p.value === 0 ? 1 : Math.max(3, (p.value / max) * plotHeight); const eased = anim.barProgress(i); const barH = base * eased; const x = i * (barWidth + BAR_GAP); @@ -119,14 +119,14 @@ export function BarChart({ width={barWidth} height={bodyH} fill={color} - opacity={p.value == null ? 0 : p.value === 0 ? 0.25 : isHovered ? 1 : 0.9} + opacity={p.value === 0 ? 0.25 : isHovered ? 1 : 0.9} rx={1} className="chart__bar" - onMouseMove={p.value == null ? undefined : (e) => onMove(e, i)} + onMouseMove={(e) => onMove(e, i)} onMouseLeave={onLeave} > - {p.value == null ? p.label : `${p.label}: ${fmt(p.value)}`} + {p.label}: {fmt(p.value)} {isPeak && ( @@ -157,7 +157,7 @@ export function BarChart({ role="tooltip" > {data[hover.i].label} - {fmt(data[hover.i].value ?? 0)} + {fmt(data[hover.i].value)}
)}
diff --git a/apps/desktop-tauri/src/components/charts/LineChart.test.tsx b/apps/desktop-tauri/src/components/charts/LineChart.test.tsx deleted file mode 100644 index 54fdac4980..0000000000 --- a/apps/desktop-tauri/src/components/charts/LineChart.test.tsx +++ /dev/null @@ -1,26 +0,0 @@ -import { render } from "@testing-library/react"; -import { describe, expect, it } from "vitest"; -import { LineChart } from "./LineChart"; - -describe("LineChart unknown values", () => { - it("renders gaps for unknown values while preserving known zero", () => { - const { container } = render( - , - ); - - expect(container.querySelectorAll(".chart__point")).toHaveLength(4); - expect(container.querySelectorAll(".chart__line")).toHaveLength(2); - expect(container).toHaveTextContent("2026-09-02: 0.00"); - expect(container).not.toHaveTextContent("2026-09-03: 0.00"); - }); -}); \ No newline at end of file diff --git a/apps/desktop-tauri/src/components/charts/LineChart.tsx b/apps/desktop-tauri/src/components/charts/LineChart.tsx index a8a1a1bda2..24ccb5cb5f 100644 --- a/apps/desktop-tauri/src/components/charts/LineChart.tsx +++ b/apps/desktop-tauri/src/components/charts/LineChart.tsx @@ -12,7 +12,7 @@ import { useChartAnimation } from "./useChartAnimation"; export interface LineChartPoint { label: string; - value: number | null; + value: number; } export interface LineChartProps { @@ -58,10 +58,9 @@ export function LineChart({ ); } - const values = data.flatMap((p) => (p.value == null ? [] : [p.value])); - const hasKnownValues = values.length > 0; - const max = hasKnownValues ? Math.max(...values, 0.0001) : 0.0001; - const min = hasKnownValues ? Math.min(...values, 0) : 0; + const values = data.map((p) => p.value); + const max = Math.max(...values, 0.0001); + const min = Math.min(...values, 0); const range = Math.max(max - min, 0.0001); const plotHeight = Math.max(1, height - 4); @@ -75,29 +74,26 @@ export function LineChart({ const step = data.length > 1 ? usableWidth / (data.length - 1) : 0; const coords = data.map((p, i) => { const x = pad + i * step; - if (p.value == null) return null; const finalY = pad + plotHeight - ((p.value - min) / range) * plotHeight; const t = anim.barProgress(i); const y = baselineY + (finalY - baselineY) * t; - return { x, y }; + return { x, y, finalY }; }); - const segments: Array> = []; - let segment: Array<{ x: number; y: number }> = []; - for (const coord of coords) { - if (coord) { - segment.push(coord); - } else if (segment.length > 0) { - segments.push(segment); - segment = []; - } + if (coords.length === 1) { + coords.push({ x: pad + usableWidth, y: coords[0].y, finalY: coords[0].finalY }); } - if (segment.length > 0) segments.push(segment); - if (data.length === 1 && segments[0]?.length === 1) { - const point = segments[0][0]; - segments[0].push({ x: pad + usableWidth, y: point.y }); - } + const polyline = coords.map((c) => `${c.x.toFixed(1)},${c.y.toFixed(1)}`).join(" "); + + const areaPath = area + ? [ + `M ${coords[0].x.toFixed(1)} ${baselineY.toFixed(1)}`, + ...coords.map((c) => `L ${c.x.toFixed(1)} ${c.y.toFixed(1)}`), + `L ${coords[coords.length - 1].x.toFixed(1)} ${baselineY.toFixed(1)}`, + "Z", + ].join(" ") + : null; const onPointMove = (e: React.MouseEvent, i: number) => { const host = containerRef.current; @@ -106,7 +102,6 @@ export function LineChart({ setHover({ i, x: e.clientX - rect.left, y: e.clientY - rect.top }); }; const onLeave = () => setHover(null); - const hoveredPoint = hover ? data[hover.i] : null; return (
@@ -118,76 +113,49 @@ export function LineChart({ role="img" aria-label={ariaLabel} > - {area && - segments.map((points, i) => { - if (points.length < 2) return null; - const path = [ - `M ${points[0].x.toFixed(1)} ${baselineY.toFixed(1)}`, - ...points.map((point) => `L ${point.x.toFixed(1)} ${point.y.toFixed(1)}`), - `L ${points[points.length - 1].x.toFixed(1)} ${baselineY.toFixed(1)}`, - "Z", - ].join(" "); - return ( - - ); - })} - {segments.map((points, i) => - points.length < 2 ? null : ( - `${point.x.toFixed(1)},${point.y.toFixed(1)}`).join(" ")} - fill="none" - stroke={color} - strokeWidth={1.5} - strokeLinejoin="round" - strokeLinecap="round" - opacity={0.95} - className="chart__line" - /> - ), + {areaPath && ( + )} - {data.map((p, i) => { - const coord = coords[i]; - if (p.value == null || !coord) return null; - return ( - onPointMove(e, i)} - onMouseLeave={onLeave} - > - - {p.label}: {fmt(p.value)} - - - ); - })} + + {data.map((p, i) => ( + onPointMove(e, i)} + onMouseLeave={onLeave} + > + + {p.label}: {fmt(p.value)} + + + ))}
{data[0].label.slice(-5)} - - {hasKnownValues ? fmt(max) : ""} - + {fmt(max)} {data[data.length - 1].label.slice(-5)}
- {hover && hoveredPoint?.value != null && !anim.running && ( + {hover && !anim.running && (
- {hoveredPoint.label} - {fmt(hoveredPoint.value)} + {data[hover.i].label} + {fmt(data[hover.i].value)}
)}
diff --git a/apps/desktop-tauri/src/i18n/keys.ts b/apps/desktop-tauri/src/i18n/keys.ts index 2da4c36537..ac2b06c784 100644 --- a/apps/desktop-tauri/src/i18n/keys.ts +++ b/apps/desktop-tauri/src/i18n/keys.ts @@ -570,7 +570,6 @@ export const ALL_LOCALE_KEYS = [ "DetailPaceRunsOutIn", "DetailPaceWillLastToReset", "DetailCostTitle", - "ApiSpendTitle", "DetailCostUsed", "DetailCostLimit", "DetailCostRemaining", diff --git a/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx b/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx index b630d859ec..29ff8c4d50 100644 --- a/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx +++ b/apps/desktop-tauri/src/surfaces/settings/providers/ProviderDetailPane.tsx @@ -28,7 +28,7 @@ import { CostSection } from "./sections/CostSection"; import { QuickActionsSection } from "./sections/QuickActionsSection"; import { ChartsSection } from "./sections/charts/ChartsSection"; import { CookieSourceSection } from "./sections/CookieSourceSection"; -import { UsageSourceSection } from "./sections/UsageSourceSection"; +import { GrokUsageSourceSection } from "./sections/GrokUsageSourceSection"; import { RegionSection } from "./sections/RegionSection"; import { CodexUsageOptions } from "./sections/credentials/CodexUsageOptions"; import { CodexAccountsSection } from "./sections/credentials/CodexAccountsSection"; @@ -302,21 +302,19 @@ export function ProviderDetailPane({ - - {!(detail.id === "alibabatokenplan" && detail.usageSource === "cli") && ( - - )} + (null); - const options = - providerId === "grok" - ? GROK_OPTIONS - : providerId === "alibabatokenplan" - ? ALIBABA_TOKEN_PLAN_OPTIONS - : null; - if (!options) return null; + if (providerId !== "grok") return null; const selected = currentValue ?? "auto"; - const selectedOption = options.find((option) => option.value === selected) ?? options[0]; + const selectedOption = GROK_OPTIONS.find((option) => option.value === selected) ?? GROK_OPTIONS[0]; const handleSelect = async (value: string) => { if (value === selected || busy) return; @@ -88,7 +64,7 @@ export function UsageSourceSection({

{t("UsageSource")}

- {options.map((option) => { + {GROK_OPTIONS.map((option) => { const isActive = option.value === selected; return (