Skip to content

fix(usage): deep restyle of 使用统计 detail area — house tabs, real tables, per-tab components - #1252

Merged
jackwener merged 4 commits into
mainfrom
fix/usage-stats-restyle
Jul 19, 2026
Merged

fix(usage): deep restyle of 使用统计 detail area — house tabs, real tables, per-tab components#1252
jackwener merged 4 commits into
mainfrom
fix/usage-stats-restyle

Conversation

@jackwener

Copy link
Copy Markdown
Member

User verdict: 显示明细这部分的 UI 丑得要死,需要打磨和深度重构. Delivered both.

Restyle (drift → convergence)

  • White-pill active tab (Segmented misuse) → house underline TabsList + live count pills (请求 22 · 供应商 3 · 模型 5 · 工具 14 · 定价 0) — same primitive as skills/MCP.
  • Floating range+refresh → aligned toolbar (range cluster left, refresh trailing, shared centerline).
  • Bare header + bare 暂无 line → EmptyState primitive; tables get real structure: hairline separators, muted weight-medium headers, right-aligned tabular-nums numerics, one grow column absorbs slack (no more even-distribution gaps), scoped th headers.
  • StatTile tiles verified already-primitive; kept.

Deep refactor

One monolithic switch component → orchestrator + 5 per-tab components (Requests/Providers/Models/Tools/Pricing panels) funneling one shared typed UsageStatsTable (columns carry numeric/grow; single-table-consumer decision documented).

Coverage

New deterministic usage fixture seed (3 providers / 5 models / 6 tools / ~22 requests incl. an error row, fixed-clock literals); settings-usage added to the alignment auditor FIXTURES. settings-usage-contract fully re-pinned (all behavioral pins carried). CDP light+dark × all 5 tabs accepted by maintainer.

Known follow-up (out of renderer territory, reported not changed): settingsStore.usageStats aggregates byTool per-session so 工具统计 repeats tool names — data-layer fix queued.

Gates (merged tree incl. R6): desktop 2744 · ui 196 · typecheck · check-dead-css · knip ×2 = 0 · a11y/copy/console 0 · auditor all fixtures clean incl. settings-usage. Implemented by an opus worktree agent.

…structured tables

- Replace the activeTab Segmented (white-pill toggle) with the house
  underline TabsList + count pills (skills / MCP language).
- Left-align the range segmented as one time cluster; push the refresh
  to the row's trailing edge (space-between) so it stops floating.
- Split the five tab panels into per-tab components funneling through
  one shared UsageStatsTable: hairline separators, muted+medium header
  row, numeric columns right-aligned with tabular-nums, a grow column
  that absorbs slack so numbers size to content.
- Empty tabs (定价配置 + any empty stats tab) render the EmptyState
  primitive instead of a bare line under a bare header row.
…ture

Scope assertions to the new orchestrator / per-tab panel / shared table
blocks: underline TabsList with count pills, per-column alignment recipe,
EmptyState-backed empty tabs. Behavioral pins (optimistic draft, refresh
guard, request-filter scoping, label helpers) carried over unchanged.
… the auditor

- Add usageStatsSessions: 3 providers, 5 models, 6 tools (2 failing),
  ~22 request-log rows, gated to the settings-usage scenario so no other
  capture shifts.
- Default the settings-usage fixture to 全部 + details-on: the seed uses
  the fixed visual-smoke clock, which sits outside the store's real-time
  24h/7天/30天 windows, so the populated tables only render deterministically
  under 全部.
- Add settings-usage to the alignment auditor's fixture list.
@jackwener
jackwener merged commit 545b77a into main Jul 19, 2026
3 checks passed
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)

* feat(ui): extract DataTable primitive from usage stats table

Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.

UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.

Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.

* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect

The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.

Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
  privacy points (a quiet 'just so you know' callout; matches the passive
  Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
  controls, no card chrome (it's a form, not a callout).

Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.

* polish(ui): converge search pre-search hint + fix gateway 5-tile grid

- search-modal: route the pre-search guidance line through the shared
  EmptyState inline primitive instead of a bare <p>, so the 'start typing'
  hint uses the sanctioned empty-state language (keeps the placeholder pin
  class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
  four-column .settingsUsageSummary grid, orphaning the fifth on a second
  row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
  wrap when the pane narrows.

* polish(permissions): drop the OS-row status stripe (#651)

Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).

* refactor(providers): converge .providerRootHeader onto SectionHeader

The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).

Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).

* polish(settings): converge health/permission onto dense shared-language rows

Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.

- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
  primitive inside one hairline card; prose message + detail keep stacked
  secondary lines, status is a squared Chip (exception-only color via its
  tone scale), send/capability blockers are exception Chips. Meta on one
  tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
  rows in one card matching the OS permission list above; the nested gray
  boxed .settingsCapabilityLayers dl becomes structured secondary lines
  (no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
  and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
  (.settingsHealthIntro / .settingsPermissionIntro) restating the page
  title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
  moved into the action slot, banner chrome dropped.

Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.

Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.

* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary

Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant