Lisbon: dashboard widget sizing strategy + demo data + status polish#127
Merged
Conversation
- move 270° gap to the bottom (speedometer-style horseshoe) - fill the card by enlarging the ring radius and dropping end-cap balls - lock the visible card to a 1:1 aspect via container-size queries so it stays square inside non-square grid cells - add internal padding between the ring and the card border - move the server name into the bottom arc gap
- guard metric-card render with a friendly empty state when the metric spec is missing (also blocks the records query so it stops looping) - seed default 'cpu' metric in WidgetConfigDialog on save so a no-change submit persists a valid config - show selected option label in ServerSelect/MetricSelect triggers via SelectValue children render function instead of raw value
The 12-col grid step (~85px) and the fine row step (24px) are asymmetric, so a square widget with `w_coarse === h_coarse` rendered as a tall rectangle. Derive the rendered h from w via `visualSquareHFine = round(w * colStep / fineRowStep)` so the cell ends up pixel-square in steady state. The persisted `grid_h` still mirrors `grid_w` (square invariant); only the rendered fine h differs. To stop RGL from undoing the override: - minH/maxH are derived too so the post-render clamp matches the override - during an active resize, h tracks `w * SCALE` so react-resizable's cursor delta stays in sync; idle RGL echoes keep the pixel-square value via an interactionState ref check
The percent sign is decoration, not data — render it smaller and dimmer so the eye lands on the number first.
Formalize the four sizing strategies (free, fixed, aspect-square, content-height) into an explicit `sizing` field on each widget type, backed by a per-strategy dispatcher. Replaces the scattered SQUARE_TYPES / AUTO_HEIGHT_TYPES / inline isResizable derivation.
Address review feedback: - Fix react-grid-layout/core subpath import for aspectRatio and LayoutConstraint (root index does not re-export them). - Split the design into Layer A (render-time normalizeRenderItem in baseLayout) and Layer B (resize-time LayoutConstraint via RGL's applySizeConstraints pipeline). RGL does not run constraints on idle layout sync, so aspect-square / content-height idle h must be set by baseLayout, not by constraints alone. - snapOnRelease now returns a coarse-unit SnapPatch with an explicit applyCoarsePatch helper, ending the fine/coarse mix that broke the previous draft. - updateLiveLayout keeps the existing SCALE-multiple h snap for free / fixed widgets to prevent resize jitter; aspect-square and content-height own their fine h via constraints / measurement.
Replace SQUARE_TYPES / AUTO_HEIGHT_TYPES / visualSquareHFine / interactionStateRef with widgetById + getStrategy + normalizeRenderItem (layer A, idle) + applyStrategy (layer B, RGL constraints). Per-strategy h snap in updateLiveLayout/commitLayoutChange replaces the inline overrides. snapOnRelease + applyCoarsePatch land aspect-square tier snaps on resize end.
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.
Summary
This branch bundles a focused refactor of the dashboard widget sizing model with several adjacent improvements that landed on the same long-running branch:
free,fixed,aspect-square,content-height) into an explicitsizingfield on every widget type, backed by a two-layer dispatcher: render-timenormalizeRenderItem(Layer A) for idle h, and RGL v2LayoutConstraints (Layer B) for resize-time enforcement. Replaces the scatteredSQUARE_TYPES/AUTO_HEIGHT_TYPES/visualSquareHFine/interactionStateRefmarkers with a single dispatcher inapps/web/src/components/dashboard/sizing-strategies/. Gauge cells now render visually pixel-square in the grid; aspect-square widgets snap to legal tiers ([2,3,4,5,6]) on resize end; content-height widgets lock height to their measured content; fixed widgets stay non-resizable. Spec:docs/superpowers/specs/2026-05-28-dashboard-widget-sizing-strategy-design.md; plan:docs/superpowers/plans/2026-05-28-dashboard-widget-sizing-strategy.md.make dev-demoflow (admin/admin123) seeds a curated multi-server dataset for frontend development without a real agent fleet (crates/server/src/dev_demo.rs,scripts/dev-demo.sh,scripts/server-dev-demo.sh).apps/web/src/components/dashboard/widgets/gauge.tsx) with metric icons, pixel-square inner card, and centered subtitle.The sizing-strategy work is fully covered by Vitest (32 new tests across
sizing-strategies/*.test.tsanddashboard-layout.test.ts), and the previously-failing dashboard-grid integration tests (gauge h expectations) now pass under the new dispatcher.Test plan
cargo test --workspace— Rust suite passesbun run typecheck— frontend + docs typecheck cleancd apps/web && bun run test— 631/631 passing (added 41 tests undersizing-strategies/+dashboard-layout.test.ts)bun x ultracite check— frontend lint cleanmake dev-demoagainst Chrome DevTools:seresize handle,aspectRatio(1)constraint attachede-only handle,lockHeight(measured)constraintisResizable: falses/e/sehandles perresizeConfig