Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
162 commits
Select commit Hold shift + click to select a range
3b88e5b
feat(web): usage chart zooms by drag and accepts custom date ranges
saphid Aug 28, 2026
065b362
fix(web): bound and complete usage range interactions
saphid Sep 1, 2026
7239eac
fix(web): track usage brush with pointer events
saphid Sep 1, 2026
26a0f8e
fix(web): preserve touch scrolling while brushing usage
saphid Sep 1, 2026
39c103e
feat(usage): break down usage by project
saphid Aug 28, 2026
52167be
fix(usage): keep project attribution stable
saphid Sep 1, 2026
22ae83a
fix(usage): keep project filters environment scoped
saphid Sep 1, 2026
543cd6e
fix(web): settle custom usage dates before scanning
saphid Sep 1, 2026
da35181
fix(usage): keep project views self-contained
saphid Sep 1, 2026
673f5e8
feat(usage): thread and subagent drill-down behind the summary
saphid Sep 1, 2026
0331e79
fix(usage): reconcile thread drill-down totals
saphid Aug 28, 2026
36fa10f
fix(usage): reconcile thread drill-down exactly
saphid Sep 1, 2026
e38a45a
fix(usage): harden thread scans across environments
saphid Sep 1, 2026
2849d39
fix(usage): scope and harden thread drill-down
saphid Sep 1, 2026
5b339aa
feat(web): usage thread rows link to the thread
saphid Aug 28, 2026
80a8944
fix(usage): correct Claude cost accounting
saphid Sep 1, 2026
bdff4c9
feat(usage): surface estimated cache-write cost
saphid Aug 28, 2026
0a4964c
fix(usage): keep transcript title reads bounded
saphid Sep 1, 2026
1d81617
fix(usage): preserve cache cost availability
saphid Sep 1, 2026
e17084b
fix(usage): replace progressive Claude snapshots exactly
saphid Sep 1, 2026
c3f8d86
feat(web): show thread API cost in composer
saphid Sep 1, 2026
1c220ab
fix(usage): address thread cost review
saphid Sep 2, 2026
cbae157
fix(usage): gate thread cost and preserve project ownership
saphid Sep 2, 2026
6edf808
refactor(usage): share breakdown table presentation
saphid Sep 2, 2026
9cb3cfd
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
807d81c
docs: add composer cost screenshots
saphid Sep 2, 2026
73f3c83
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
109915a
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
6693fc4
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
4b350f9
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
d8df0c0
fix(web): style usage dates as a segmented control
saphid Sep 2, 2026
261a38f
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
592052e
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
0ec4e47
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
af1aa0b
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
a9d1ba7
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
fc5d017
fix(web): preserve usage date touch targets
saphid Sep 2, 2026
a63581f
fix(usage): correct thread cost attribution
saphid Sep 2, 2026
fbd0049
fix(usage): preserve replaced provider sessions
saphid Sep 2, 2026
288d2c4
fix(usage): dedupe provider session history
saphid Sep 2, 2026
d9c4388
fix(usage): retain sessions across provider changes
saphid Sep 2, 2026
5b5806a
ci: rerun flaky web test
saphid Sep 2, 2026
1a4598c
fix(web): use themed cache write color
saphid Sep 2, 2026
f8aecb7
ci: rerun after upstream test fix
saphid Sep 2, 2026
f963f96
fix(server): avoid rescanning fresh usage ranges
saphid Sep 2, 2026
983d297
docs(usage): state custom range limit
saphid Sep 2, 2026
2ce048e
fix(usage): keep manual refresh authoritative
saphid Sep 2, 2026
47e1afc
feat(usage): stack thread cost components
saphid Sep 2, 2026
5198c17
fix(usage): refresh rebased rolling windows
saphid Sep 2, 2026
30b8a75
fix(usage): retain totals during refresh
saphid Sep 2, 2026
e1b98f5
fix(web): reuse segmented control tokens
saphid Sep 2, 2026
4df0a35
fix(usage): allow retrying stalled refreshes
saphid Sep 2, 2026
12a8837
fix(mobile): bound usage refresh indicator
saphid Sep 2, 2026
3dd0596
fix(usage): exclude unknown work from outside filter
saphid Sep 3, 2026
3eb3719
fix(usage): retain model-less Claude iterations
Sep 3, 2026
7698545
Merge upstream main into composer thread cost
saphid Sep 3, 2026
9db1127
chore: keep composer screenshots in PR only
saphid Sep 3, 2026
83848a0
fix(usage): normalize attribution paths
saphid Sep 3, 2026
08db6d3
fix(usage): normalize attribution paths
saphid Sep 3, 2026
7d248cb
docs: explain absent Codex cache writes
saphid Sep 3, 2026
48ac934
docs: explain absent Codex cache writes
saphid Sep 3, 2026
c2e0e57
fix(usage): preserve attribution failures
saphid Sep 3, 2026
6c4fd5d
fix(usage): preserve attribution failures
saphid Sep 3, 2026
2a8f76b
fix(usage): correct Claude cost accounting
saphid Sep 1, 2026
cab90a0
fix(usage): replace progressive Claude snapshots exactly
saphid Sep 1, 2026
850ac9a
fix(usage): retain model-less Claude iterations
saphid Sep 3, 2026
134a31b
fix(usage): price long-context requests correctly
saphid Sep 3, 2026
4cc2337
Merge upstream main into usage time range
github-actions[bot] Sep 5, 2026
f94c655
Merge ready usage time range into project breakdown
github-actions[bot] Sep 5, 2026
686f16f
Merge ready project breakdown into thread breakdown
github-actions[bot] Sep 5, 2026
b4b4e0e
Merge ready thread breakdown into thread links
github-actions[bot] Sep 5, 2026
deb59e2
Merge ready thread links into cache-write accounting
github-actions[bot] Sep 5, 2026
d4b7d44
Merge ready cache-write accounting into provider accounting
github-actions[bot] Sep 5, 2026
55b59c9
fix(usage): preserve partial cache TTL counters
github-actions[bot] Sep 5, 2026
3811853
Merge ready provider accounting into composer usage estimate
github-actions[bot] Sep 5, 2026
de63bbe
fix(usage): scope composer lifetime scans
github-actions[bot] Sep 5, 2026
4578354
fix(usage): preserve final snapshots and failures
github-actions[bot] Sep 5, 2026
da8ce4a
Merge corrected thread breakdown into thread links
github-actions[bot] Sep 5, 2026
09d22dc
Merge corrected thread links into cache-write accounting
github-actions[bot] Sep 5, 2026
4104f54
Merge corrected cache-write accounting into provider accounting
github-actions[bot] Sep 5, 2026
9028b94
fix(usage): index transcript ownership
github-actions[bot] Sep 5, 2026
9c75a96
merge: integrate usage correctness fixes
github-actions[bot] Sep 5, 2026
4dfc9af
fix(usage): clear failed retained snapshots
github-actions[bot] Sep 5, 2026
6faee6e
merge: carry usage refresh fixes into project attribution
github-actions[bot] Sep 5, 2026
54e451f
merge: carry usage refresh fixes into thread breakdown
github-actions[bot] Sep 5, 2026
65bf9a4
merge: carry usage refresh fixes into thread links
github-actions[bot] Sep 5, 2026
7ec6f48
merge: carry usage refresh fixes into cache-write pricing
github-actions[bot] Sep 5, 2026
bf0ec28
merge: carry usage refresh fixes into provider accounting
github-actions[bot] Sep 5, 2026
f167a0c
merge: carry usage refresh fixes into composer cost
github-actions[bot] Sep 5, 2026
45d994e
fix(mobile): sequence rebased usage refreshes
github-actions[bot] Sep 5, 2026
0feb2c8
merge: sequence project usage refreshes
github-actions[bot] Sep 5, 2026
90cb2cc
merge: sequence thread usage refreshes
github-actions[bot] Sep 5, 2026
a27ffc7
merge: sequence linked-thread usage refreshes
github-actions[bot] Sep 5, 2026
d60b9ef
merge: sequence cache-read usage refreshes
github-actions[bot] Sep 5, 2026
a64951c
merge: sequence thread usage refreshes
github-actions[bot] Sep 5, 2026
4e6faf7
merge: sequence usage attribution refreshes
github-actions[bot] Sep 5, 2026
ab052c9
fix(mobile): preserve newer usage selections
github-actions[bot] Sep 5, 2026
3b36e88
merge: preserve newer usage selections
github-actions[bot] Sep 5, 2026
722bfef
merge: preserve newer cache-use selections
github-actions[bot] Sep 5, 2026
2ff741b
merge: preserve newer project usage selections
github-actions[bot] Sep 5, 2026
36ff510
merge: preserve newer cache-read selections
github-actions[bot] Sep 5, 2026
b9220b2
merge: preserve newer thread usage selections
github-actions[bot] Sep 5, 2026
a2fa48c
merge: preserve newer usage attribution selections
github-actions[bot] Sep 5, 2026
0088405
fix(mobile): finish empty usage refreshes
github-actions[bot] Sep 5, 2026
b95a511
merge: finish empty usage refreshes
github-actions[bot] Sep 5, 2026
684ddf4
merge: finish empty cache-use refreshes
github-actions[bot] Sep 5, 2026
66f0548
merge: finish empty thread usage refreshes
github-actions[bot] Sep 5, 2026
f9fabf0
merge: finish empty project usage refreshes
github-actions[bot] Sep 5, 2026
cc6a9a8
merge: finish empty cache-read refreshes
github-actions[bot] Sep 5, 2026
1f71b3d
merge: finish empty usage attribution refreshes
github-actions[bot] Sep 5, 2026
c8fee44
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
7b66ec6
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
333043c
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
a30e41f
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
64bad66
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
cd6ad41
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
bd9b8f7
merge: integrate upstream main and CI mirror fallback
github-actions[bot] Sep 5, 2026
485eb72
fix(server): match Windows Claude worktree directories without case s…
github-actions[bot] Sep 5, 2026
ed9eab7
test(server): cover both Windows transcript casing directions
github-actions[bot] Sep 5, 2026
60242ad
fix(mobile): await refreshed usage for the requested window
github-actions[bot] Sep 5, 2026
741b081
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
cf11988
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
2741951
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
b35599b
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
80f9b44
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
f7b5129
merge: carry corrected mobile usage refresh
github-actions[bot] Sep 5, 2026
27b96e1
merge: integrate latest usage improvements
github-actions[bot] Sep 5, 2026
8d7c431
fix(web): make usage retries rescan failed environments
github-actions[bot] Sep 5, 2026
73f9f3d
merge: integrate project usage filtering
github-actions[bot] Sep 5, 2026
9dd8d53
merge: integrate thread usage breakdowns
github-actions[bot] Sep 5, 2026
829aa1a
merge: integrate usage thread navigation
github-actions[bot] Sep 5, 2026
11275a9
merge: integrate cache-write usage costs
github-actions[bot] Sep 5, 2026
4864a1f
merge: integrate precise usage pricing
github-actions[bot] Sep 5, 2026
1e47311
merge: integrate thread cost visibility
github-actions[bot] Sep 5, 2026
b37334f
fix(web): keep usage refresh updater pure
github-actions[bot] Sep 5, 2026
eef2076
merge: propagate pure usage refresh attempts
github-actions[bot] Sep 5, 2026
4b516fe
merge: propagate corrected usage base
github-actions[bot] Sep 5, 2026
93ed76a
merge: propagate corrected usage base
github-actions[bot] Sep 5, 2026
64b8a58
merge: propagate corrected usage base
github-actions[bot] Sep 5, 2026
32cbc6e
merge: propagate corrected usage base
github-actions[bot] Sep 5, 2026
be0c9e6
merge: propagate corrected usage base
github-actions[bot] Sep 5, 2026
3a67fde
fix(server): preserve iterated Claude cost
github-actions[bot] Sep 5, 2026
b7a94b4
fix(server): share usage source snapshots
github-actions[bot] Sep 5, 2026
4b9875e
fix(mobile): wait for usage refresh completion
github-actions[bot] Sep 5, 2026
722ced6
Merge usage refresh completion repair into #9015
github-actions[bot] Sep 5, 2026
bd01c6f
Merge usage refresh completion repair into #9016
github-actions[bot] Sep 5, 2026
ff1ab7b
Merge shared usage source snapshot repair into #9016
github-actions[bot] Sep 5, 2026
9d5ab0a
Merge usage repairs into #9017
github-actions[bot] Sep 5, 2026
bc07b3f
Merge usage repairs into #9018
github-actions[bot] Sep 5, 2026
8e0deae
Merge usage repairs into #9019
github-actions[bot] Sep 5, 2026
8adf0d9
Merge Claude serving cost repair into #9019
github-actions[bot] Sep 5, 2026
52aff2b
Merge usage repairs into #9136
github-actions[bot] Sep 5, 2026
ed6f570
fix(server): preserve project repository defects
github-actions[bot] Sep 5, 2026
dbdc2c4
Merge typed project recovery into #9016
github-actions[bot] Sep 5, 2026
4c5493a
Merge typed project recovery into #9017
github-actions[bot] Sep 5, 2026
ddd7b43
Merge typed project recovery into #9018
github-actions[bot] Sep 5, 2026
299f1ac
Merge typed project recovery into #9019
github-actions[bot] Sep 5, 2026
6a24c69
Merge typed project recovery ancestry into #9136
github-actions[bot] Sep 5, 2026
9170d50
Merge upstream main and preserve usage chart range behavior
github-actions[bot] Sep 5, 2026
7bb5e06
fix(usage): keep refreshes fresh and isolate concurrent scans
github-actions[bot] Sep 5, 2026
03f9e67
chore: sync upstream file editor patch
github-actions[bot] Sep 5, 2026
089236f
fix(usage): preserve session history with upstream imports
github-actions[bot] Sep 5, 2026
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
72 changes: 56 additions & 16 deletions apps/mobile/src/features/usage/UsageRouteScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,8 @@ import {
formatUsd,
makeWindow,
} from "@t3tools/shared/usageFormat";
import { useMemo, useState } from "react";
import { Platform, Pressable, RefreshControl, ScrollView, View } from "react-native";
import { useEffect, useMemo, useRef, useState } from "react";
import { Alert, Platform, Pressable, RefreshControl, ScrollView, View } from "react-native";
import { useSafeAreaInsets } from "react-native-safe-area-context";

import { AndroidScreenHeader } from "../../components/AndroidScreenHeader";
Expand All @@ -25,6 +25,7 @@ import { UsageDailyChart } from "./UsageDailyChart";
import { UsageLimitsSection, useRefreshLimits } from "./UsageLimitsSection";
import type { UsageChartMetric } from "./usageChartData";
import { PROVIDER_LABEL, useProviderColors } from "./usageProviders";
import { refreshRebasedUsageWindow, usagePullRefreshTargets } from "./usagePullRefresh";

type UsageTab = "usage" | "limits";
const TAB_OPTIONS = [
Expand Down Expand Up @@ -62,6 +63,8 @@ export function UsageRouteScreen() {
window: makeWindow(30),
}));
const [metric, setMetric] = useState<UsageChartMetric>("cost");
const [isPullRefreshing, setIsPullRefreshing] = useState(false);
const refreshRequest = useRef(0);
const { days: windowDays, window } = windowSelection;
const isPast24Hours = windowDays === 1;
const { merged, environments, isPending, isPartial, refresh } = useUsage(window);
Expand Down Expand Up @@ -91,29 +94,57 @@ export function UsageRouteScreen() {
[isPast24Hours, merged.daily, merged.hourly],
);

// The pull spinner tracks re-scans of environments that have answered
// before. The initial scan renders its own placeholder, and an unreachable
// environment stays pending forever — neither may pin the spinner on.
const refreshingUsage = environments.some((entry) => entry.isPending && entry.summary !== null);
const refreshingUsage = isPullRefreshing;
const showingLimits = tab === "limits";
useEffect(
() => () => {
refreshRequest.current += 1;
},
[],
);
const selectWindow = (days: number) => {
refreshRequest.current += 1;
setIsPullRefreshing(false);
setWindowSelection({
days,
window: makeWindow(days, undefined, days === 1 ? "hour" : "day"),
});
};
const refreshWindow = () => {
const request = ++refreshRequest.current;
const targets = usagePullRefreshTargets(environments);
setIsPullRefreshing(targets.size > 0);
const completeRefresh = () => {
if (request !== refreshRequest.current) return false;
refreshRequest.current += 1;
setIsPullRefreshing(false);
return true;
};
const failRefresh = (error: unknown) => {
if (!completeRefresh()) return;
Alert.alert(
"Could not refresh usage",
error instanceof Error ? error.message : "Usage could not be refreshed. Try again.",
);
};
const nextWindow = makeWindow(windowDays, undefined, isPast24Hours ? "hour" : "day");
if (
nextWindow.sinceDay === window.sinceDay &&
nextWindow.untilDay === window.untilDay &&
nextWindow.sinceTime === window.sinceTime &&
nextWindow.untilTime === window.untilTime
nextWindow.sinceDay !== window.sinceDay ||
nextWindow.untilDay !== window.untilDay ||
nextWindow.sinceTime !== window.sinceTime ||
nextWindow.untilTime !== window.untilTime
) {
refresh();
} else {
setWindowSelection({ days: windowDays, window: nextWindow });
void refreshRebasedUsageWindow(
nextWindow,
refresh,
(refreshedWindow) => {
setWindowSelection({ days: windowDays, window: refreshedWindow });
},
() => request === refreshRequest.current,
).then(completeRefresh, failRefresh);
Comment thread
saphid marked this conversation as resolved.
return;
}
void refresh().then(completeRefresh, failRefresh);
};

return (
Expand Down Expand Up @@ -273,14 +304,14 @@ function ChartCard(props: {
<View className="gap-4 rounded-[24px] border-continuous bg-card p-4">
<View className="gap-0.5">
<Text className="text-sm text-foreground-muted">
{metric === "cost" ? "Raw token cost" : "Processed tokens"}
{metric === "cost" ? "Local public-list estimate" : "Processed tokens"}
</Text>
<Text className="text-4xl font-t3-bold tabular-nums text-foreground">
{metric === "cost" ? `${formatUsd(merged.costUsd)}*` : formatTokens(merged.totalTokens)}
</Text>
<Text className="text-sm text-foreground-muted">
{metric === "cost"
? "* if billed at full API rate"
? "* estimated from local transcripts at public list rates"
: `Across ${formatCount(merged.sessions)} sessions`}
</Text>
</View>
Expand Down Expand Up @@ -417,7 +448,16 @@ function TotalsSection(props: { readonly merged: MergedUsage; readonly isPast24H
<MetricCell
label="Uncached input"
value={formatTokens(merged.uncachedInputTokens)}
detail={`${formatTokens(merged.cacheCreationTokens)} cache writes`}
detail="fresh input tokens"
/>
<MetricCell
label="Cache writes, estimated"
value={
merged.costQuality.cacheWriteUsd === null
? "Unavailable"
: formatUsd(merged.costQuality.cacheWriteUsd)
}
detail={`${formatTokens(merged.cacheCreationTokens)} tokens · not an expiry measure`}
/>
<MetricCell
label="Output"
Expand Down
118 changes: 118 additions & 0 deletions apps/mobile/src/features/usage/usagePullRefresh.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import type { EnvironmentId } from "@t3tools/contracts";
import { describe, expect, it } from "vite-plus/test";

import type { UsageSummaryInput } from "@t3tools/contracts";

import { refreshRebasedUsageWindow, usagePullRefreshTargets } from "./usagePullRefresh";

const status = (environmentId: string, summary: unknown | null, isPending: boolean) => ({
environmentId: environmentId as EnvironmentId,
summary,
isPending,
});

describe("usage pull refresh", () => {
it("shows pull state for answered environments without waiting on initial reads", () => {
const targets = usagePullRefreshTargets([
status("answered", { readAt: "before" }, false),
status("unreachable", null, true),
]);

expect([...targets]).toEqual(["answered"]);
});

it("tracks failed retries without waiting on already-pending environments", () => {
const targets = usagePullRefreshTargets([
status("failed", null, false),
status("already-pending", null, true),
]);

expect([...targets]).toEqual(["failed"]);
expect(usagePullRefreshTargets([status("already-pending", null, true)]).size).toBe(0);
});

it("commits a rebased window only after its refreshed snapshot publishes", async () => {
const events: string[] = [];
let releaseRates!: () => void;
const rates = new Promise<void>((resolve) => {
releaseRates = resolve;
});
let releasePublication!: () => void;
const publication = new Promise<void>((resolve) => {
releasePublication = resolve;
});
const input = { sinceDay: "2026-09-04" } as UsageSummaryInput;
const operation = refreshRebasedUsageWindow(
input,
async () => {
events.push("rates-started");
await rates;
events.push("rescan-started");
await publication;
events.push("rescan-published");
},
() => events.push("window-committed"),
() => true,
);

expect(events).toEqual(["rates-started"]);
releaseRates();
await Promise.resolve();
await Promise.resolve();
expect(events).toEqual(["rates-started", "rescan-started"]);
releasePublication();
await operation;
expect(events).toEqual([
"rates-started",
"rescan-started",
"rescan-published",
"window-committed",
]);
});

it("does not restore a rebased window after a newer selection", async () => {
let releaseRates!: () => void;
const rates = new Promise<void>((resolve) => {
releaseRates = resolve;
});
const rebased = { sinceDay: "2026-09-04" } as UsageSummaryInput;
const newer = { sinceDay: "2026-08-07" } as UsageSummaryInput;
let selected = rebased;
let activeRequest = 1;
const request = activeRequest;
const operation = refreshRebasedUsageWindow(
rebased,
async () => {
await rates;
},
(input) => {
selected = input;
},
() => request === activeRequest,
);

selected = newer;
activeRequest += 1;
releaseRates();
await operation;

expect(selected).toBe(newer);
});

it("does not commit a rebased window when refresh fails", async () => {
const failure = new Error("transcript scan failed");
let committed = false;

await expect(
refreshRebasedUsageWindow(
{ sinceDay: "2026-09-04" } as UsageSummaryInput,
async () => Promise.reject(failure),
() => {
committed = true;
},
() => true,
),
).rejects.toBe(failure);
expect(committed).toBe(false);
});
});
30 changes: 30 additions & 0 deletions apps/mobile/src/features/usage/usagePullRefresh.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import type { EnvironmentId } from "@t3tools/contracts";
import type { UsageSummaryInput } from "@t3tools/contracts";

interface UsageRefreshStatus {
readonly environmentId: EnvironmentId;
readonly isPending: boolean;
readonly summary: unknown | null;
}

/** Selects environments for which pull-to-refresh should show its indicator. */
export function usagePullRefreshTargets(
environments: readonly UsageRefreshStatus[],
): ReadonlySet<EnvironmentId> {
return new Set(
environments.flatMap((environment) =>
environment.summary === null && environment.isPending ? [] : [environment.environmentId],
),
);
}

/** Starts the explicit rescan before committing a rebased window to the screen. */
export async function refreshRebasedUsageWindow(
input: UsageSummaryInput,
refresh: (input: UsageSummaryInput) => Promise<void>,
commit: (input: UsageSummaryInput) => void,
isCurrent: () => boolean,
): Promise<void> {
await refresh(input);
if (isCurrent()) commit(input);
}
Loading
Loading