fix(usage): make 7/30 day toggle work + redesign with Fluent SelectorBar#322
Merged
shanselman merged 1 commit intoMay 12, 2026
Merged
Conversation
The 7 Days / 30 Days buttons on the Usage page only swapped button styles — they never re-fetched usage data, so the page was effectively stuck on whatever period was loaded at startup. Initialize() also hardcoded RequestUsageCostAsync(30) while the XAML highlighted the 7 Days button, so the UI label and the data on screen disagreed on first load. This change fixes the bug and refreshes the page layout to match Fluent guidance. Functional fix: - Wire the period selection to RequestUsageCostAsync(days), with an early-return guard so re-clicking the active period doesn't fire a duplicate request. - Initialize() now requests the same period the UI is highlighting. UI redesign: - Replace the two Button controls with a SelectorBar (the official Fluent control for "switch between a small number of views/filters"). Preserves the selection underline through hover/focus/press, which AccentButtonStyle was losing on PointerOver. - Move Provider Breakdown above the SelectorBar so it's visually clear that the selector only scopes the Daily Cost data below it (provider status is real-time, not period-based). - Wrap both Provider Breakdown and Daily Cost in full-width Fluent data cards so the page reads as three consistent cards (Total Cost / Providers / Daily Cost) instead of a mix of cards and floating headers. - Co-locate the SelectorBar with the Daily Cost label inside the same card header row, so the filter is unambiguously scoped to the data in that card. - Add a ProgressRing + "Loading providers…" skeleton inside the Provider Breakdown card so the first-load gateway round-trip feels intentional. - Add a "No providers configured" empty-state for the Provider Breakdown card so a zero-provider response doesn't render as a blank section. Correctness fixes (Hanselman dual-model review): - UpdateUsage no longer writes TotalCostText / TokenCountText. Those fields are now owned exclusively by UpdateUsageCost (the period-scoped data the toggle controls). Previously both methods raced on every load — whichever response arrived last clobbered the hero numbers with the wrong period (or all-time). - Initialize only applies cached LastUsageCost when its Days field matches the current selection. Avoids briefly rendering 30-day data while the SelectorBar reads "7 Days" when the user returns to the page. Code clarity: - Rename misleading ProviderRow properties: Requests -> Plan, Tokens -> Usage, Cost -> Status. The bindings now describe what they actually show (plan tier, current rate-limit window usage, error/status text). Localization: - Rename resw keys Period7DaysButton.Content / Period30DaysButton.Content to Period7DaysItem.Text / Period30DaysItem.Text across all 5 languages (en-us, fr-fr, zh-cn, zh-tw, nl-nl) to match SelectorBarItem.Text. - Add UsagePage_ProviderLoading.Text and UsagePage_NoProviders.Text in all 5 languages. Validation: - build.ps1 succeeds for all 4 projects (Shared, Cli, WinNodeCli, WinUI). - OpenClaw.Shared.Tests: 1455 passed, 0 failed, 25 skipped. - OpenClaw.Tray.Tests: 959 passed, 0 failed. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
The 7 Days / 30 Days toggle on the Usage page only swapped button styles — it never re-fetched usage data. The page was effectively stuck on whatever period was loaded at startup.
Initialize()also hardcodedRequestUsageCostAsync(30)while XAML highlighted the 7 Days button, so the UI label and the data on screen disagreed on first load.What changed
Functional fix (the bug)
RequestUsageCostAsync(days), with an early-return guard so re-clicking the active period doesn't fire a duplicate request.Initialize()now requests the same period the UI is highlighting.UI redesign (Fluent guidance)
Buttoncontrols with aSelectorBar— the official Fluent control for "switch between a small number of views/filters". The selection underline is preserved through hover/focus/press, whichAccentButtonStylewas losing onPointerOver.ProgressRing+ "Loading providers…" skeleton inside the Provider Breakdown card so the first-load gateway round-trip feels intentional.Correctness fixes (Hanselman dual-model review)
UpdateUsageno longer writesTotalCostText/TokenCountText. Those fields are now owned exclusively byUpdateUsageCost(the period-scoped data the toggle controls). Previously both methods raced on every load — whichever response arrived last clobbered the hero numbers with the wrong period (or all-time).Initializeonly applies cachedLastUsageCostwhen itsDaysfield matches the current selection. Avoids briefly rendering 30-day data while the SelectorBar reads "7 Days" when the user returns to the page.Code clarity
ProviderRowproperties:Requests→Plan,Tokens→Usage,Cost→Status. The bindings now describe what they actually show (plan tier, current rate-limit window usage, error/status text).Localization
Period7DaysButton.Content/Period30DaysButton.Content→Period7DaysItem.Text/Period30DaysItem.Textacross all 5 languages (en-us, fr-fr, zh-cn, zh-tw, nl-nl) to matchSelectorBarItem.Text.UsagePage_ProviderLoading.TextandUsagePage_NoProviders.Textin all 5 languages.Before / after
usage.cost {days}Total Cost/Tokensrace between two async sourcesUpdateUsageCostis the sole owner of period-scoped totalsValidation
./build.ps1succeeds for all 4 projects (Shared, Cli, WinNodeCli, WinUI).OpenClaw.Shared.Tests: 1455 passed, 0 failed, 25 skipped.OpenClaw.Tray.Tests: 959 passed, 0 failed.