summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-02 14:39:24 +0900
committerAdam Malczewski <[email protected]>2026-06-02 14:39:24 +0900
commitf0207a7f000257e6c459db7053edbae4d68fcf3f (patch)
tree414d3748a0fcda7ff6400729f83b4b64a924ee67
parent2756730aeba633c3cc331500bcfb9a67d85dc892 (diff)
parent3f0bfe76ceabd1cb53727f1d9ae84d7494054d7f (diff)
downloaddispatch-f0207a7f000257e6c459db7053edbae4d68fcf3f.tar.gz
dispatch-f0207a7f000257e6c459db7053edbae4d68fcf3f.zip
Merge branch 'dev' into sb/status-bar
-rw-r--r--HANDOFF.md38
-rw-r--r--packages/frontend/src/lib/components/CacheRatePanel.svelte7
-rw-r--r--packages/frontend/src/lib/components/KeyUsage.svelte21
3 files changed, 55 insertions, 11 deletions
diff --git a/HANDOFF.md b/HANDOFF.md
new file mode 100644
index 0000000..8d6960b
--- /dev/null
+++ b/HANDOFF.md
@@ -0,0 +1,38 @@
+# Handoff — m1/minor-fixes
+
+Three small, independent UI fixes in the Dispatch frontend.
+
+## Files changed
+- `packages/frontend/src/lib/components/CacheRatePanel.svelte`
+ - **Fix 1:** Added `whitespace-nowrap` to the requests-count badge (`{cacheStats.requests} req`) so it no longer wraps to a second line.
+ - **Fix 2:** Removed the trailing explanatory paragraph ("Cache reads cost ~10% of fresh input; writes cost ~25% more…").
+- `packages/frontend/src/lib/components/KeyUsage.svelte`
+ - **Fix 3:** Added `pacedProgressClass(percentUsed, elapsedPct)` and applied it to the 5 bars that render a "time dot" (Claude 5-Hour/Weekly, opencode-go 5-Hour/Weekly/Monthly).
+
+## Public surface changed
+- None externally. No exported API, prop, or type changes.
+- New module-internal helper `pacedProgressClass` in `KeyUsage.svelte` (not exported). Existing `progressClass` retained and reused as the fallback.
+
+## Fix 3 coloring logic
+`pacedProgressClass(percentUsed, elapsedPct)`:
+- `percentUsed >= 90` → `progress-error` (red) — always, per spec.
+- no time dot (`elapsedPct < 0`, e.g. missing `resetsAt`) → fall back to existing `progressClass` thresholds.
+- `percentUsed <= elapsedPct` → `progress-success` (green; equal counts as green/on-pace).
+- otherwise (usage ran ahead of the dot) → `progress-warning` (orange).
+
+Applied only to the 5 dot-bearing bars. The 3 Copilot/Gemini bars were intentionally left on the original `progressClass` (confirmed unused/out of scope by the requester).
+
+## Verification status — PASS
+- `bun run check` (biome): **PASS** — "Checked 163 files… No fixes applied."
+- `bun run test` (vitest): **PASS** — 35 test files, 552 tests passed.
+- Re-verified after `git merge --no-edit dev` (was already up to date) — still all-green.
+- Note: `bun install` was required first; deps were not present in the worktree.
+
+## Published
+- Yes. Committed `084f4d7`, merged `dev` down (already up to date), pushed fast-forward `7c527b4..084f4d7 → dev`.
+
+## Assumptions / known gaps
+- Per requester: Copilot & Gemini usage bars are unused, so they keep the old threshold coloring (untouched).
+- Red threshold is `>= 90%` (exactly 90 is red); tie between usage and the dot resolves to green — both confirmed by requester.
+- Dot-less / hidden-dot cycle bars fall back to the original `progressClass` thresholds (confirmed option "a").
+- Changes are presentation-only (Tailwind/daisyUI classes + a coloring helper); no automated tests were added for the Svelte markup, consistent with the existing repo (no component-render tests for these panels). User visually confirmed the result before publish.
diff --git a/packages/frontend/src/lib/components/CacheRatePanel.svelte b/packages/frontend/src/lib/components/CacheRatePanel.svelte
index c35cbb5..88985a0 100644
--- a/packages/frontend/src/lib/components/CacheRatePanel.svelte
+++ b/packages/frontend/src/lib/components/CacheRatePanel.svelte
@@ -55,7 +55,7 @@ const lastHitPct = $derived(
{#if tabTitle}
<span class="badge badge-xs badge-ghost">{tabTitle}</span>
{/if}
- <span class="badge badge-xs ml-auto">{cacheStats.requests} req</span>
+ <span class="badge badge-xs ml-auto whitespace-nowrap">{cacheStats.requests} req</span>
</div>
<!-- Headline cumulative hit rate -->
@@ -120,10 +120,5 @@ const lastHitPct = $derived(
</div>
</div>
</div>
-
- <p class="text-xs text-base-content/40">
- Cache reads cost ~10% of fresh input; writes cost ~25% more. A high hit
- rate after the first turn means caching is working. Resets on reload.
- </p>
{/if}
</div>
diff --git a/packages/frontend/src/lib/components/KeyUsage.svelte b/packages/frontend/src/lib/components/KeyUsage.svelte
index 00d179e..7c0cadc 100644
--- a/packages/frontend/src/lib/components/KeyUsage.svelte
+++ b/packages/frontend/src/lib/components/KeyUsage.svelte
@@ -131,6 +131,17 @@ function progressClass(utilization: number): string {
return "progress-success";
}
+// Pace-aware coloring for cycle bars that show a "time dot" (elapsed % of the
+// reset window). Red once usage hits 90%, otherwise green when usage is at or
+// behind the dot and orange when it has run ahead of it. Falls back to the
+// plain threshold coloring when no dot is present (elapsedPct < 0).
+function pacedProgressClass(percentUsed: number, elapsedPct: number): string {
+ if (percentUsed >= 90) return "progress-error";
+ if (elapsedPct < 0) return progressClass(percentUsed / 100);
+ if (percentUsed <= elapsedPct) return "progress-success";
+ return "progress-warning";
+}
+
function formatDate(ts: number): string {
const diff = ts - Date.now();
const days = Math.floor(diff / 86400000);
@@ -245,7 +256,7 @@ function hasBucketData(bucket: UsageBucket | undefined): boolean {
<span class="text-xs font-mono">{p}%</span>
</div>
<div class="relative w-full h-2">
- <progress class="progress w-full h-2 {progressClass(u)} absolute inset-0" value={p} max="100"></progress>
+ <progress class="progress w-full h-2 {pacedProgressClass(p, tp)} absolute inset-0" value={p} max="100"></progress>
{#if tp >= 0}
<div class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-2 h-2 rounded-full border border-info bg-info-content pointer-events-none box-border" style="left: {tp}%"></div>
{/if}
@@ -266,7 +277,7 @@ function hasBucketData(bucket: UsageBucket | undefined): boolean {
<span class="text-xs font-mono">{p}%</span>
</div>
<div class="relative w-full h-2">
- <progress class="progress w-full h-2 {progressClass(u)} absolute inset-0" value={p} max="100"></progress>
+ <progress class="progress w-full h-2 {pacedProgressClass(p, tp)} absolute inset-0" value={p} max="100"></progress>
{#if tp >= 0}
<div class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-2 h-2 rounded-full border border-info bg-info-content pointer-events-none box-border" style="left: {tp}%"></div>
{/if}
@@ -330,7 +341,7 @@ function hasBucketData(bucket: UsageBucket | undefined): boolean {
<span class="text-xs font-mono">{p}%</span>
</div>
<div class="relative w-full h-2">
- <progress class="progress w-full h-2 {progressClass(u)} absolute inset-0" value={p} max="100"></progress>
+ <progress class="progress w-full h-2 {pacedProgressClass(p, tp)} absolute inset-0" value={p} max="100"></progress>
{#if tp >= 0}
<div class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-2 h-2 rounded-full border border-info bg-info-content pointer-events-none box-border" style="left: {tp}%"></div>
{/if}
@@ -351,7 +362,7 @@ function hasBucketData(bucket: UsageBucket | undefined): boolean {
<span class="text-xs font-mono">{p}%</span>
</div>
<div class="relative w-full h-2">
- <progress class="progress w-full h-2 {progressClass(u)} absolute inset-0" value={p} max="100"></progress>
+ <progress class="progress w-full h-2 {pacedProgressClass(p, tp)} absolute inset-0" value={p} max="100"></progress>
{#if tp >= 0}
<div class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-2 h-2 rounded-full border border-info bg-info-content pointer-events-none box-border" style="left: {tp}%"></div>
{/if}
@@ -372,7 +383,7 @@ function hasBucketData(bucket: UsageBucket | undefined): boolean {
<span class="text-xs font-mono">{p}%</span>
</div>
<div class="relative w-full h-2">
- <progress class="progress w-full h-2 {progressClass(u)} absolute inset-0" value={p} max="100"></progress>
+ <progress class="progress w-full h-2 {pacedProgressClass(p, tp)} absolute inset-0" value={p} max="100"></progress>
{#if tp >= 0}
<div class="absolute top-1/2 -translate-y-1/2 -translate-x-1/2 w-2 h-2 rounded-full border border-info bg-info-content pointer-events-none box-border" style="left: {tp}%"></div>
{/if}