Fullscreen strategy detail with 5-row equity pagination.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
dekun
2026-08-02 10:01:52 +08:00
parent 63225f64de
commit 18fdfc6d0a
2 changed files with 88 additions and 29 deletions
+59 -17
View File
@@ -204,6 +204,8 @@ export default function MonitorPage() {
const [detailStats, setDetailStats] = useState<NodeStats | null>(null);
const [detailStatsErr, setDetailStatsErr] = useState("");
const [detailStatsLoading, setDetailStatsLoading] = useState(false);
const [equityPage, setEquityPage] = useState(0);
const EQUITY_PAGE_SIZE = 5;
const applyNodes = useCallback((list: NodeCard[]) => {
cachedNodes = list;
@@ -215,12 +217,14 @@ export default function MonitorPage() {
setDetailStats(null);
setDetailStatsErr("");
setDetailStatsLoading(false);
setEquityPage(0);
return;
}
let cancelled = false;
setDetailStats(null);
setDetailStatsErr("");
setDetailStatsLoading(true);
setEquityPage(0);
apiFetch<NodeStats>(`/api/nodes/${detailId}/stats`)
.then((s) => {
if (!cancelled) setDetailStats(s);
@@ -431,6 +435,18 @@ export default function MonitorPage() {
const detailLegs = Array.isArray(detail?.position?.legs)
? (detail!.position.legs as Record<string, unknown>[])
: [];
const equityNewestFirst = detailStats?.equity_curve?.length
? [...detailStats.equity_curve].reverse()
: [];
const equityPageCount = Math.max(
1,
Math.ceil(equityNewestFirst.length / EQUITY_PAGE_SIZE),
);
const equityPageSafe = Math.min(equityPage, equityPageCount - 1);
const equityPageRows = equityNewestFirst.slice(
equityPageSafe * EQUITY_PAGE_SIZE,
equityPageSafe * EQUITY_PAGE_SIZE + EQUITY_PAGE_SIZE,
);
return (
<div>
@@ -742,7 +758,7 @@ export default function MonitorPage() {
</dd>
</div>
</dl>
{detailStats.equity_curve?.length ? (
{equityNewestFirst.length ? (
<>
<h4 style={{ marginTop: "0.75rem" }}></h4>
<div className="legs-table-wrap">
@@ -754,25 +770,51 @@ export default function MonitorPage() {
</tr>
</thead>
<tbody>
{[...detailStats.equity_curve]
.reverse()
.slice(0, 30)
.map((x) => (
<tr key={x.group_id}>
<td className="mono">{x.group_id}</td>
<td className={pnlClass(x.realized_pnl)}>
{fmt(x.realized_pnl, 2)}
</td>
</tr>
))}
{equityPageRows.map((x) => (
<tr key={x.group_id}>
<td className="mono">{x.group_id}</td>
<td className={pnlClass(x.realized_pnl)}>
{fmt(x.realized_pnl, 2)}
</td>
</tr>
))}
</tbody>
</table>
</div>
{detailStats.equity_curve.length > 30 ? (
<p className="meta">
30 {detailStats.equity_curve.length}
</p>
) : null}
<div className="pager">
<span className="pager-meta">
{equityPageSafe + 1}/{equityPageCount} · {" "}
{EQUITY_PAGE_SIZE} · {equityNewestFirst.length}{" "}
</span>
<div className="pager-actions">
<button
type="button"
className="btn ghost"
disabled={equityPageSafe <= 0}
onClick={() =>
setEquityPage(Math.max(0, equityPageSafe - 1))
}
>
</button>
<button
type="button"
className="btn ghost"
disabled={equityPageSafe >= equityPageCount - 1}
onClick={() =>
setEquityPage(
Math.min(
equityPageCount - 1,
equityPageSafe + 1,
),
)
}
>
</button>
</div>
</div>
</>
) : (
<p className="meta"></p>
+29 -12
View File
@@ -454,29 +454,46 @@ td {
.modal-backdrop {
position: fixed;
inset: 0;
background: rgba(4, 8, 14, 0.72);
display: grid;
place-items: center;
padding: 16px;
background: rgba(4, 8, 14, 0.92);
display: flex;
z-index: 50;
}
.modal-panel {
width: min(720px, 100%);
max-height: min(90vh, 900px);
width: 100%;
height: 100%;
max-height: none;
overflow: auto;
background: var(--panel);
border: 1px solid var(--line);
border-radius: 12px;
padding: 18px;
border: none;
border-radius: 0;
padding: 20px 24px 28px;
display: flex;
flex-direction: column;
gap: 14px;
gap: 16px;
}
.modal-panel.running {
border-color: rgba(60, 179, 113, 0.65);
box-shadow: 0 0 0 1px rgba(60, 179, 113, 0.2);
box-shadow: inset 0 0 0 2px rgba(60, 179, 113, 0.45);
}
.pager {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-top: 10px;
}
.pager-meta {
color: var(--muted);
font-size: 0.85rem;
font-variant-numeric: tabular-nums;
}
.pager-actions {
display: flex;
gap: 8px;
}
.modal-head {