System info in the bottom status bar (exploration 0233) - #289
Merged
Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
useSyncVitals() folds hub status, the browser online flag, and the SyncManager's readonly props + lifecycle/verification/reconciliation events into one reactive object. useStorageEstimate() wraps navigator.storage.estimate() for coarse OPFS pressure. Pure decision/ format logic (coarse state, integrity gate, byte/time/threshold) lives in sync-format.ts with unit tests. (exploration 0233)
Replace the status bar's static hub dot with a connection cluster: an always-on chip (dot + terse label), conditional tier-B chips that only appear off-nominal (⇡ N pending, integrity ⚠, storage ◐ N%), and one click-through popover anchored above the bar carrying the deep detail (last change, lifecycle phase, tracked/pool counts, runtime mode, storage breakdown, last verification failure) plus a Reconcile action. Mobile has no status bar, so a matching health glyph in the top bar opens the same detail in a bottom sheet. Diagnostics (lamport/security level/billing plan) stay out of the always-on row. (exploration 0233)
#287) PR #287 added an always-on durable-storage indicator to the status bar. Combine it with the 0233 sync cluster: keep main's <StorageStatus/>, drop the now-redundant storage chip + useStorageEstimate hook, and source the popover's storage row from the canonical useStorageStatus + the shared lib/format-bytes (no duplication).
Contributor
🖼️ UI changes in this PRScreensAuto-captured by CI · run. Informational — not a blocking check. |
Contributor
|
Preview removed for PR #289. |
| * The deep detail panel shared by the desktop popover and the mobile sheet. | ||
| * Presentation over the sync vitals + durable-storage status, plus Reconcile. | ||
| */ | ||
| export function SystemInfoDetails({ vitals }: { vitals: SyncVitals }) { |
| * reconciliation events for instant transitions, plus a slow poll so the | ||
| * offline-queue count (which can change with no lifecycle event) stays fresh. | ||
| */ | ||
| export function useSyncVitals(): SyncVitals { |
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.



What
Turns the status bar's lone hub dot into a layered sync connection cluster (exploration 0233). The bar stays calm when healthy and speaks up only when something is off-nominal — answering "are my changes safe?", not just "is the hub connected?".
Tier A — always on: a connection chip (dot + terse label) backed by a new
useSyncVitals()aggregator that foldsuseHubStatus,useIsOffline, and theSyncManager's readonly props + lifecycle/verification/reconciliation events into one reactive object.Tier B — only when off-nominal: conditional chips —
⇡ N pending(offline queue), an integrity⚠(hash/signature verification failure), and a storage◐ N%(OPFS pressure past 85%, via a newuseStorageEstimate()).Tier C — on demand: a click-through popover anchored above the bar carrying the deep detail (last change, lifecycle phase, tracked/pool counts, runtime mode, storage breakdown, last verification failure) plus a Reconcile action. Diagnostics (lamport/security level/billing plan) deliberately stay out of the always-on row.
Mobile has no status bar, so a matching sync glyph in the top bar opens the same detail in a bottom sheet.
Why
A rich pool of reactive sync signals existed but never reached the user —
connectedcould coexist with a non-empty offline queue, a degraded lifecycle, or a recent verification failure. This surfaces them following VS Code's status-bar guidance (workspace status left, limit items, color as last resort) and local-first norms (subtle when healthy, a quiet badge + retry when not).Verification
sync-format.test.ts— 15 unit tests over the pure decision/format logic (coarse-state mapping, integrity gate, storage thresholds, byte/time formatting).offlinewith a no-hub session; typing a mutation live-bumped the⇡ 2 pendingchip; popover opens from chip click and closes on Escape; storage estimate read602 KB / 9.9 GBand the storage chip correctly stayed hidden at 0%; mobile glyph reflects state and opens the matching sheet.pnpm --filter xnet-web typecheck, eslint, and prettier all clean.Scope is
apps/webonly — no publishable package changed, so no changeset (changelog fragment included).🤖 Generated with Claude Code