mirror of
https://github.com/hansjone/netx.git
synced 2026-10-12 19:57:29 +08:00
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 <cursoragent@cursor.com>
This commit is contained in:
parent
653baa1b9f
commit
5e940252e6
2 changed files with 33 additions and 13 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
import { useEffect, useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
import { useMutation, useQuery, useQueryClient, keepPreviousData } from "@tanstack/react-query";
|
||||||
import {
|
import {
|
||||||
collectPortTrafficNow,
|
collectPortTrafficNow,
|
||||||
createPortTrafficTask,
|
createPortTrafficTask,
|
||||||
|
|
@ -17,13 +17,14 @@ import {
|
||||||
import { queryKeys } from "../../constants/queryKeys";
|
import { queryKeys } from "../../constants/queryKeys";
|
||||||
import { useI18n } from "../../i18n";
|
import { useI18n } from "../../i18n";
|
||||||
import { useToast } from "../../hooks/useToast";
|
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 { pageCount } from "../../utils/display";
|
||||||
import { formatSystemTime } from "../../utils/time";
|
import { formatSystemTime } from "../../utils/time";
|
||||||
import { PortTrafficWall } from "./PortTrafficWall";
|
import { PortTrafficWall } from "./PortTrafficWall";
|
||||||
|
|
||||||
const POLL_MS = 5000;
|
const POLL_MS = 5000;
|
||||||
const TARGET_PAGE_SIZE = 20;
|
const TARGET_PAGE_SIZE = 20;
|
||||||
|
const EMPTY_COMPARE_POINTS: PortTrafficSamplePoint[] = [];
|
||||||
|
|
||||||
type PortPick = PortTrafficTargetIn & { key: string };
|
type PortPick = PortTrafficTargetIn & { key: string };
|
||||||
type BaselineMode = "off" | "shift" | "day" | "week" | "custom";
|
type BaselineMode = "off" | "shift" | "day" | "week" | "custom";
|
||||||
|
|
@ -136,12 +137,19 @@ export function PortTrafficPage() {
|
||||||
}),
|
}),
|
||||||
enabled: view === "wall" && Boolean(wallTargetId),
|
enabled: view === "wall" && Boolean(wallTargetId),
|
||||||
staleTime: 1000,
|
staleTime: 1000,
|
||||||
|
placeholderData: keepPreviousData,
|
||||||
refetchInterval: (q) => {
|
refetchInterval: (q) => {
|
||||||
const n = q.state.data?.current?.length ?? 0;
|
const n = q.state.data?.current?.length ?? 0;
|
||||||
return n === 0 ? 2500 : POLL_MS;
|
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 = () => {
|
const invalidateAll = () => {
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficTasksAll });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficTasksAll });
|
||||||
void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficDashboard });
|
void queryClient.invalidateQueries({ queryKey: queryKeys.portTrafficDashboard });
|
||||||
|
|
@ -788,12 +796,8 @@ export function PortTrafficPage() {
|
||||||
) : null}
|
) : null}
|
||||||
<PortTrafficWall
|
<PortTrafficWall
|
||||||
target={selectedWallTarget}
|
target={selectedWallTarget}
|
||||||
points={compareQuery.data?.current || []}
|
points={wallPoints}
|
||||||
baselinePoints={
|
baselinePoints={wallBaselinePoints}
|
||||||
baseline === "off" && !mapBaselineTargetId
|
|
||||||
? []
|
|
||||||
: compareQuery.data?.baseline || []
|
|
||||||
}
|
|
||||||
rangeLabel={`${rangeHours}h${
|
rangeLabel={`${rangeHours}h${
|
||||||
baseline === "off"
|
baseline === "off"
|
||||||
? ""
|
? ""
|
||||||
|
|
|
||||||
|
|
@ -65,6 +65,8 @@ function chartSize(el: HTMLElement): { width: number; height: number } {
|
||||||
return { width, height };
|
return { width, height };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const EMPTY_POINTS: PortTrafficSamplePoint[] = [];
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
target: PortTrafficTarget | null;
|
target: PortTrafficTarget | null;
|
||||||
points: PortTrafficSamplePoint[];
|
points: PortTrafficSamplePoint[];
|
||||||
|
|
@ -77,7 +79,7 @@ type Props = {
|
||||||
export function PortTrafficWall({
|
export function PortTrafficWall({
|
||||||
target,
|
target,
|
||||||
points,
|
points,
|
||||||
baselinePoints = [],
|
baselinePoints = EMPTY_POINTS,
|
||||||
rangeLabel,
|
rangeLabel,
|
||||||
loading,
|
loading,
|
||||||
hint,
|
hint,
|
||||||
|
|
@ -287,11 +289,25 @@ export function PortTrafficWall({
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const plot = plotRef.current;
|
const plot = plotRef.current;
|
||||||
if (!plot) return;
|
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;
|
const showBaseline = baselinePoints.length > 0;
|
||||||
plot.setSeries(3, { show: showBaseline });
|
plot.setData(data, true);
|
||||||
plot.setSeries(4, { show: showBaseline });
|
const s3 = Boolean(plot.series[3]?.show);
|
||||||
plot.setData(toAlignedSeries(points, baselinePoints));
|
const s4 = Boolean(plot.series[4]?.show);
|
||||||
if (mountRef.current) plot.setSize(chartSize(mountRef.current));
|
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]);
|
}, [points, baselinePoints]);
|
||||||
|
|
||||||
const empty = points.length === 0 && baselinePoints.length === 0;
|
const empty = points.length === 0 && baselinePoints.length === 0;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue