From 5e940252e65a3ccf7ea0e95778cb5141321cc002 Mon Sep 17 00:00:00 2001 From: oliver Date: Sat, 1 Aug 2026 07:34:14 +0800 Subject: [PATCH] Fix port traffic wall blank chart when enabling baseline compare. Set uPlot data before toggling baseline series, keep previous compare data while refetching, and resize after legend layout changes. Co-authored-by: Cursor --- web/src/pages/network/PortTrafficPage.tsx | 20 ++++++++++------- web/src/pages/network/PortTrafficWall.tsx | 26 ++++++++++++++++++----- 2 files changed, 33 insertions(+), 13 deletions(-) diff --git a/web/src/pages/network/PortTrafficPage.tsx b/web/src/pages/network/PortTrafficPage.tsx index d6b68df..891c0d9 100644 --- a/web/src/pages/network/PortTrafficPage.tsx +++ b/web/src/pages/network/PortTrafficPage.tsx @@ -1,5 +1,5 @@ import { useEffect, useMemo, useState } from "react"; -import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { useMutation, useQuery, useQueryClient, keepPreviousData } from "@tanstack/react-query"; import { collectPortTrafficNow, createPortTrafficTask, @@ -17,13 +17,14 @@ import { import { queryKeys } from "../../constants/queryKeys"; import { useI18n } from "../../i18n"; import { useToast } from "../../hooks/useToast"; -import type { CliTargetItem, PortTrafficDiscoverPort, PortTrafficTargetIn } from "../../types"; +import type { CliTargetItem, PortTrafficDiscoverPort, PortTrafficSamplePoint, PortTrafficTargetIn } from "../../types"; import { pageCount } from "../../utils/display"; import { formatSystemTime } from "../../utils/time"; import { PortTrafficWall } from "./PortTrafficWall"; const POLL_MS = 5000; const TARGET_PAGE_SIZE = 20; +const EMPTY_COMPARE_POINTS: PortTrafficSamplePoint[] = []; type PortPick = PortTrafficTargetIn & { key: string }; type BaselineMode = "off" | "shift" | "day" | "week" | "custom"; @@ -136,12 +137,19 @@ export function PortTrafficPage() { }), enabled: view === "wall" && Boolean(wallTargetId), staleTime: 1000, + placeholderData: keepPreviousData, refetchInterval: (q) => { const n = q.state.data?.current?.length ?? 0; return n === 0 ? 2500 : POLL_MS; }, }); + const wallPoints = compareQuery.data?.current ?? EMPTY_COMPARE_POINTS; + const wallBaselinePoints = + baseline === "off" && !mapBaselineTargetId + ? EMPTY_COMPARE_POINTS + : (compareQuery.data?.baseline ?? EMPTY_COMPARE_POINTS); + const invalidateAll = () => { void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficTasksAll }); void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficDashboard }); @@ -788,12 +796,8 @@ export function PortTrafficPage() { ) : null} { const plot = plotRef.current; if (!plot) return; + // Always setData with resetScales; toggling series.show before setData can leave + // uPlot stuck on a blank [0,1] y-range until a later update. + const data = toAlignedSeries(points, baselinePoints); const showBaseline = baselinePoints.length > 0; - plot.setSeries(3, { show: showBaseline }); - plot.setSeries(4, { show: showBaseline }); - plot.setData(toAlignedSeries(points, baselinePoints)); - if (mountRef.current) plot.setSize(chartSize(mountRef.current)); + plot.setData(data, true); + const s3 = Boolean(plot.series[3]?.show); + const s4 = Boolean(plot.series[4]?.show); + if (s3 !== showBaseline || s4 !== showBaseline) { + plot.setSeries(3, { show: showBaseline }, false); + plot.setSeries(4, { show: showBaseline }, false); + } + const el = mountRef.current; + if (el) { + // Legend show/hide changes layout; size after paint. + requestAnimationFrame(() => { + if (!plotRef.current || !mountRef.current) return; + plotRef.current.setSize(chartSize(mountRef.current)); + }); + } }, [points, baselinePoints]); const empty = points.length === 0 && baselinePoints.length === 0;