Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/bridge.rs
Original file line number Diff line number Diff line change
Expand Up @@ -453,6 +453,7 @@ pub struct SettingsSnapshot {
float_bar_provider_ids: Vec<String>,
float_bar_dark_text: bool,
float_bar_show_reset_inline: bool,
float_bar_show_cost: bool,
}

#[tauri::command]
Expand Down Expand Up @@ -545,6 +546,7 @@ impl From<Settings> for SettingsSnapshot {
float_bar_provider_ids: settings.float_bar_provider_ids,
float_bar_dark_text: settings.float_bar_dark_text,
float_bar_show_reset_inline: settings.float_bar_show_reset_inline,
float_bar_show_cost: settings.float_bar_show_cost,
}
}
}
Expand Down
2 changes: 2 additions & 0 deletions apps/desktop-tauri/src-tauri/src/commands/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ pub struct SettingsUpdate {
pub float_bar_provider_ids: Option<Vec<String>>,
pub float_bar_dark_text: Option<bool>,
pub float_bar_show_reset_inline: Option<bool>,
pub float_bar_show_cost: Option<bool>,
}

impl SettingsUpdate {
Expand Down Expand Up @@ -273,6 +274,7 @@ impl SettingsUpdate {
provider_ids: self.float_bar_provider_ids.clone(),
dark_text: self.float_bar_dark_text,
show_reset_inline: self.float_bar_show_reset_inline,
show_cost: self.float_bar_show_cost,
}
}

Expand Down
4 changes: 4 additions & 0 deletions apps/desktop-tauri/src-tauri/src/floatbar/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ pub struct SettingsPatch {
pub provider_ids: Option<Vec<String>>,
pub dark_text: Option<bool>,
pub show_reset_inline: Option<bool>,
pub show_cost: Option<bool>,
}

impl SettingsPatch {
Expand Down Expand Up @@ -150,6 +151,9 @@ impl SettingsPatch {
if let Some(v) = self.show_reset_inline {
settings.float_bar_show_reset_inline = v;
}
if let Some(v) = self.show_cost {
settings.float_bar_show_cost = v;
}
}
}

Expand Down
1 change: 1 addition & 0 deletions apps/desktop-tauri/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ function settings(overrides: Partial<SettingsSnapshot> = {}): SettingsSnapshot {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
...overrides,
};
}
Expand Down
3 changes: 2 additions & 1 deletion apps/desktop-tauri/src/components/MenuCard.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ describe("MenuCard", () => {
PanelTodayBudget: "today",
PanelUsedSuffix: "used",
ResetsInHoursMinutes: "Resets in {}h {}m",
ResetsInMinutes: "Resets in {}m",
WayfinderGatewayStatus: "Gateway",
WayfinderModels: "Models",
WayfinderRequests: "Requests",
Expand Down Expand Up @@ -190,7 +191,7 @@ describe("MenuCard", () => {

renderCard(snapshot, { showResetWhenExhausted: true });

expect(await screen.findByText(/Resets in 0h/)).toBeInTheDocument();
expect(await screen.findByText(/Resets in \d+m/)).toBeInTheDocument();
expect(screen.queryByText("0% left")).not.toBeInTheDocument();
});

Expand Down
21 changes: 19 additions & 2 deletions apps/desktop-tauri/src/floatbar/FloatBar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ function settings(overrides: Partial<SettingsSnapshot> = {}): SettingsSnapshot {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
...overrides,
};
}
Expand Down Expand Up @@ -181,7 +182,9 @@ describe("FloatBar", () => {
snapshot("claude", "Claude", 20),
snapshot("codex", "Codex", 75),
]);
tauriMocks.getSettingsSnapshot.mockResolvedValue(settings());
tauriMocks.getSettingsSnapshot.mockResolvedValue(
settings({ floatBarShowCost: true }),
);

const { container } = renderFloatBar(bootstrap());
await waitFor(() => {
Expand Down Expand Up @@ -212,14 +215,28 @@ describe("FloatBar", () => {
tokenCostUpdatedAtMs: 1234,
});

renderFloatBar(bootstrap());
renderFloatBar(bootstrap({ floatBarShowCost: true }));

await waitFor(() => {
expect(tauriMocks.getProviderLocalUsageSummary).toHaveBeenCalledWith("codex");
});
expect(tauriMocks.getProviderChartData).not.toHaveBeenCalled();
});

it("does not scan local costs by default", async () => {
tauriMocks.getCachedProviders.mockResolvedValue([
snapshot("codex", "Codex", 75),
]);
tauriMocks.getSettingsSnapshot.mockResolvedValue(settings());

renderFloatBar(bootstrap());

await waitFor(() => {
expect(tauriMocks.getCachedProviders).toHaveBeenCalled();
});
expect(tauriMocks.getProviderLocalUsageSummary).not.toHaveBeenCalled();
});

it("can show remaining percentages when configured", async () => {
tauriMocks.getCachedProviders.mockResolvedValue([
snapshot("claude", "Claude", 20),
Expand Down
15 changes: 9 additions & 6 deletions apps/desktop-tauri/src/floatbar/FloatBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,7 @@ export default function FloatBar({ state }: { state: BootstrapState }) {
const filterIds = settings.floatBarProviderIds;
const scale = Math.max(0.75, Math.min(2, settings.floatBarScale / 100));
const showResetInline = settings.floatBarShowResetInline;
const showCost = settings.floatBarShowCost;
const visible = useMemo(() => {
const enabled = new Set(settings.enabledProviders);
let list = providers.filter((p) => enabled.has(p.providerId));
Expand All @@ -307,12 +308,14 @@ export default function FloatBar({ state }: { state: BootstrapState }) {
.join("|");
const visibleCostTargets = useMemo<FloatBarCostTarget[]>(
() =>
visible.map((provider) => ({
key: providerCostKey(provider),
providerId: provider.providerId,
displayName: provider.displayName,
})),
[visibleCostTargetKey],
showCost
? visible.map((provider) => ({
key: providerCostKey(provider),
providerId: provider.providerId,
displayName: provider.displayName,
}))
: [],
[showCost, visibleCostTargetKey],
);

useEffect(() => {
Expand Down
13 changes: 13 additions & 0 deletions apps/desktop-tauri/src/floatbar/SettingsSection.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { useCallback, useEffect, useState } from "react";
import { Field, Select, Toggle } from "../components/FormControls";
import { useLocale } from "../hooks/useLocale";
import type {
FloatBarOrientation,
FloatBarStyle,
Expand Down Expand Up @@ -42,6 +43,7 @@ function useDraftNumber(value: number) {
* imports a single component.
*/
export default function FloatBarSettingsSection({ settings, saving, set }: Props) {
const { t } = useLocale();
const opacity = useDraftNumber(settings.floatBarOpacity);
const scale = useDraftNumber(settings.floatBarScale);
const commitOpacity = () => {
Expand Down Expand Up @@ -132,6 +134,17 @@ export default function FloatBarSettingsSection({ settings, saving, set }: Props
aria-label="Floating bar size"
/>
</Field>
<Field
label={t("FloatBarShowCost")}
description={t("FloatBarShowCostDescription")}
leading
>
<Toggle
checked={settings.floatBarShowCost}
disabled={saving || !settings.floatBarEnabled}
onChange={(v) => set({ floatBarShowCost: v })}
/>
</Field>
<Field
label="Show Reset Time Inline"
description="Shows the reset time beside each provider percentage with a reset icon."
Expand Down
9 changes: 9 additions & 0 deletions apps/desktop-tauri/src/hooks/useFormattedResetTime.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ async function mountWithLocale(ui: React.ReactNode) {
buildBundle({
MetricResetsIn: "Resets in",
ResetsInHoursMinutes: "Resets in {}h {}m",
ResetsInMinutes: "Resets in {}m",
ResetsInDaysHours: "Resets in {}d {}h",
TrayResetsDueNow: "Resetting",
}),
Expand Down Expand Up @@ -59,6 +60,14 @@ describe("useFormattedResetTime", () => {
expect(screen.getByTestId("reset")).toHaveTextContent("Resets in 3h 42m");
});

it("omits zero hours for sub-hour resets", async () => {
const target = new Date("2024-06-01T00:40:00Z").toISOString();
await mountWithLocale(
<Probe resetsAt={target} fallback="later" relative={true} />,
);
expect(screen.getByTestId("reset")).toHaveTextContent("Resets in 40m");
});

it("leaves fallback text unlabelled in relative mode", async () => {
await mountWithLocale(
<Probe resetsAt={null} fallback="3h" relative={true} />,
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop-tauri/src/hooks/useFormattedResetTime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@ export function useFormattedResetTime(
.replace("{}", String(days))
.replace("{}", String(hours));
}
if (hours === 0) {
return t("ResetsInMinutes").replace("{}", String(minutes));
}
return t("ResetsInHoursMinutes")
.replace("{}", String(hours))
.replace("{}", String(minutes));
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop-tauri/src/i18n/keys.ts
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,7 @@ export const ALL_LOCALE_KEYS = [
"ResetsInShort",
"ResetsInDaysHours",
"ResetsInHoursMinutes",
"ResetsInMinutes",
"TrayDisplayTitle",
"ShowInTray",
"CreditsLabel",
Expand Down Expand Up @@ -489,6 +490,8 @@ export const ALL_LOCALE_KEYS = [
"FloatBarThirtyDayShort",
"FloatBarNoProviders",
"FloatBarRemainingSuffix",
"FloatBarShowCost",
"FloatBarShowCostDescription",
"BannerCheckingForUpdates",
"BannerUpdateAvailablePrefix",
"BannerDownloadButton",
Expand Down
1 change: 1 addition & 0 deletions apps/desktop-tauri/src/surfaces/PopOutPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ function settings(): SettingsSnapshot {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
};
}

Expand Down
1 change: 1 addition & 0 deletions apps/desktop-tauri/src/surfaces/TrayPanel.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ function settings(overrides: Partial<SettingsSnapshot> = {}): SettingsSnapshot {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
...overrides,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ const settings: SettingsSnapshot = {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
};

describe("AboutTab", () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ const settings: SettingsSnapshot = {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
showResetWhenExhausted: false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ async function mountWithLocale(ui: React.ReactNode) {
(tauri.getLocaleStrings as ReturnType<typeof vi.fn>).mockResolvedValue(
buildBundle({
ResetsInHoursMinutes: "{}h {}m",
ResetsInMinutes: "{}m",
ResetsInDaysHours: "{}d {}h",
TrayResetsDueNow: "resetting",
}),
Expand Down Expand Up @@ -66,6 +67,12 @@ describe("useResetCountdown", () => {
expect(screen.getByTestId("cd")).toHaveTextContent("3h 42m");
});

it("omits zero hours for sub-hour deltas", async () => {
const target = new Date("2024-06-01T00:40:00Z").toISOString();
await mountWithLocale(<Probe resetsAt={target} fallback="x" />);
expect(screen.getByTestId("cd")).toHaveTextContent(/^40m$/);
});

it("renders days+hours for multi-day deltas", async () => {
const target = new Date("2024-06-03T05:00:00Z").toISOString();
await mountWithLocale(<Probe resetsAt={target} fallback="x" />);
Expand Down
3 changes: 3 additions & 0 deletions apps/desktop-tauri/src/surfaces/tray/useResetCountdown.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ export function useResetCountdown(
.replace("{}", String(days))
.replace("{}", String(hours));
}
if (hours === 0) {
return t("ResetsInMinutes").replace("{}", String(minutes));
}
return t("ResetsInHoursMinutes")
.replace("{}", String(hours))
.replace("{}", String(minutes));
Expand Down
1 change: 1 addition & 0 deletions apps/desktop-tauri/src/types/bridge.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ describe("Language type", () => {
floatBarProviderIds: [],
floatBarDarkText: false,
floatBarShowResetInline: false,
floatBarShowCost: false,
};
expect(snap.uiLanguage).toBe("spanish");

Expand Down
3 changes: 3 additions & 0 deletions apps/desktop-tauri/src/types/bridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,8 @@ export interface SettingsSnapshot {
floatBarDarkText: boolean;
/** When true, render the next primary reset inline in each provider pill. */
floatBarShowResetInline: boolean;
/** When true, scan and render local cost summaries. */
floatBarShowCost: boolean;
}

/** Partial settings object — only include fields you want to change. */
Expand Down Expand Up @@ -315,6 +317,7 @@ export interface SettingsUpdate {
floatBarProviderIds?: string[];
floatBarDarkText?: boolean;
floatBarShowResetInline?: boolean;
floatBarShowCost?: boolean;
}

export interface UsageThresholdOverride {
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,6 +437,7 @@ locale_keys! {
ResetsInShort,
ResetsInDaysHours,
ResetsInHoursMinutes,
ResetsInMinutes,

// Provider detail - Tray Display
TrayDisplayTitle,
Expand Down Expand Up @@ -735,6 +736,8 @@ locale_keys! {
FloatBarThirtyDayShort,
FloatBarNoProviders,
FloatBarRemainingSuffix,
FloatBarShowCost,
FloatBarShowCostDescription,

// Tauri desktop shell — update banner
BannerCheckingForUpdates,
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale/en-US.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,9 @@ ProviderCodeReviewLabel = Code review
ResetsInShort = Resets in
ResetsInDaysHours = Resets in { "{}" }d { "{}" }h
ResetsInHoursMinutes = Resets in { "{}" }h { "{}" }m
ResetsInMinutes = Resets in { "{}" }m
FloatBarShowCost = Show Local Cost
FloatBarShowCostDescription = Shows estimated local usage cost in the floating bar.
TrayDisplayTitle = Tray Display
ShowInTray = Show in tray
CreditsLabel = Credits
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale/es-MX.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ ProviderCodeReviewLabel = Revisión de código
ResetsInShort = Reinicia en
ResetsInDaysHours = Reinicia en { "{}" }d { "{}" }h
ResetsInHoursMinutes = Reinicia en { "{}" }h { "{}" }m
ResetsInMinutes = Reinicia en { "{}" }m
FloatBarShowCost = Mostrar costo local
FloatBarShowCostDescription = Muestra el costo estimado del uso local en la barra flotante.
TrayDisplayTitle = Pantalla de bandeja
ShowInTray = Mostrar en bandeja
CreditsLabel = Créditos
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale/ja-JP.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ ProviderCodeReviewLabel = Code review
ResetsInShort = リセットまで
ResetsInDaysHours = リセットまで { "{}" }日 { "{}" }時間
ResetsInHoursMinutes = リセットまで { "{}" }時間 { "{}" }分
ResetsInMinutes = リセットまで { "{}" }分
FloatBarShowCost = ローカルコストを表示
FloatBarShowCostDescription = フローティングバーにローカル使用量の推定コストを表示します。
TrayDisplayTitle = Tray Display
ShowInTray = Show in tray
CreditsLabel = Credits
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale/ko-KR.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ ProviderCodeReviewLabel = 코드 리뷰
ResetsInShort = 초기화까지
ResetsInDaysHours = 초기화까지 { "{}" }일 { "{}" }시간
ResetsInHoursMinutes = 초기화까지 { "{}" }시간 { "{}" }분
ResetsInMinutes = 초기화까지 { "{}" }분
FloatBarShowCost = 로컬 비용 표시
FloatBarShowCostDescription = 플로팅 바에 로컬 사용량의 예상 비용을 표시합니다.
TrayDisplayTitle = 트레이 표시
ShowInTray = 트레이에 표시
CreditsLabel = 크레딧
Expand Down
3 changes: 3 additions & 0 deletions rust/src/locale/zh-CN.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,9 @@ ProviderCodeReviewLabel = 代码审查
ResetsInShort = 重置于
ResetsInDaysHours = { "{}" } 天 { "{}" } 小时后重置
ResetsInHoursMinutes = { "{}" } 小时 { "{}" } 分钟后重置
ResetsInMinutes = { "{}" } 分钟后重置
FloatBarShowCost = 显示本地费用
FloatBarShowCostDescription = 在浮动栏中显示本地使用量的估算费用。
TrayDisplayTitle = 托盘显示
ShowInTray = 在托盘中显示
CreditsLabel = 额度
Expand Down
Loading
Loading