From 7d348d5c256fda854435ad2b90516ede43723437 Mon Sep 17 00:00:00 2001 From: OpenSquared Date: Tue, 14 Jul 2026 13:43:34 +0200 Subject: [PATCH] feat: new cockpit --- frontend/src/pages/Dashboard.tsx | 60 ++++++++++++++++++++++++-------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/frontend/src/pages/Dashboard.tsx b/frontend/src/pages/Dashboard.tsx index 30967db..60760c9 100644 --- a/frontend/src/pages/Dashboard.tsx +++ b/frontend/src/pages/Dashboard.tsx @@ -1,4 +1,4 @@ -import { useMemo, useState } from 'react' +import { useMemo, useState, useRef, useLayoutEffect } from 'react' import { useQuery } from '@tanstack/react-query' import { useGeoRiskScore, useAllQuotes, @@ -144,6 +144,34 @@ export default function Dashboard() { setRiskView(v); localStorage.setItem('dash_risk_view', v) } + // Row height is dictated by the config-driven watchlist cards (Watchlist Radar for row 1, + // Options Lab for row 2) — the other cards in each row are capped to match, with internal scroll. + const watchlistCardRef = useRef(null) + const optionsLabCardRef = useRef(null) + const [row1Height, setRow1Height] = useState(undefined) + const [row2Height, setRow2Height] = useState(undefined) + + // Floors avoid the row collapsing to near-zero while the master card is still loading + useLayoutEffect(() => { + const el = watchlistCardRef.current + if (!el) return + const measure = () => setRow1Height(Math.max(el.offsetHeight, 220)) + measure() + const ro = new ResizeObserver(measure) + ro.observe(el) + return () => ro.disconnect() + }, []) + + useLayoutEffect(() => { + const el = optionsLabCardRef.current + if (!el) return + const measure = () => setRow2Height(Math.max(el.offsetHeight, 180)) + measure() + const ro = new ResizeObserver(measure) + ro.observe(el) + return () => ro.disconnect() + }, []) + const allPatterns: any[] = allPatternsData ?? [] const scoreMap = useMemo(() => { @@ -251,10 +279,10 @@ export default function Dashboard() { )} - {/* Top row */} -
+ {/* Top row — height capped to Watchlist Radar's natural size (the only card driven by user config) */} +
{/* Geo Risk */} -
+
Geopolitical Risk @@ -309,8 +337,8 @@ export default function Dashboard() { ) :
Backend required
}
- {/* Watchlist Radar — its natural height (no cap) drives row 1's height */} -
+ {/* Watchlist Radar — natural height (config-driven), measured and used to cap the other row-1 cards */} +
📡 Watchlist Radar
@@ -398,7 +426,8 @@ export default function Dashboard() { ] return ( - +
🌐 Macro Regime @@ -470,7 +499,7 @@ export default function Dashboard() { })()} {/* Economic Events — real Forex Factory feed, grouped by date */} -
+
Economic Events
{upcomingEventsGrouped.length > 0 ? (
@@ -497,8 +526,8 @@ export default function Dashboard() {
- {/* ── Command Center: Résumé Opérationnel ── */} -
+ {/* ── Command Center: Résumé Opérationnel ── height capped to Options Lab's natural size (config-driven) ── */} +
{/* PnL */} {(() => { @@ -539,7 +568,8 @@ export default function Dashboard() { const pfNet = pf?.net_pnl ?? null return ( - +
📊 P&L
@@ -706,7 +736,8 @@ export default function Dashboard() { .sort((a, b) => b.value - a.value) return ( - +
🛡️ Risk @@ -776,7 +807,8 @@ export default function Dashboard() { const rollingVar: any[] = (snap?.full_result?.rolling_var ?? []).slice(-30) return ( - +
📉 VaR @@ -850,7 +882,7 @@ export default function Dashboard() { .sort((a: any, b: any) => Math.abs((b.iv_rank ?? 50) - 50) - Math.abs((a.iv_rank ?? 50) - 50)) return ( - +
🧪 Options Lab