From 963765343baf6915827b9c86ba8c25403799e5b2 Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Fri, 25 Apr 2025 10:26:15 +0800 Subject: [PATCH 1/4] fix: update sort type from 'stg' to 'disk' for accurate sorting in server context --- src/context/sort-context.ts | 4 ++-- src/pages/Server.tsx | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/context/sort-context.ts b/src/context/sort-context.ts index 62796f8..b162190 100644 --- a/src/context/sort-context.ts +++ b/src/context/sort-context.ts @@ -1,8 +1,8 @@ import { createContext } from "react" -export type SortType = "default" | "name" | "uptime" | "system" | "cpu" | "mem" | "stg" | "up" | "down" | "up total" | "down total" +export type SortType = "default" | "name" | "uptime" | "system" | "cpu" | "mem" | "disk" | "up" | "down" | "up total" | "down total" -export const SORT_TYPES: SortType[] = ["default", "name", "uptime", "system", "cpu", "mem", "stg", "up", "down", "up total", "down total"] +export const SORT_TYPES: SortType[] = ["default", "name", "uptime", "system", "cpu", "mem", "disk", "up", "down", "up total", "down total"] export type SortOrder = "asc" | "desc" diff --git a/src/pages/Server.tsx b/src/pages/Server.tsx index 9da1650..cc681ae 100644 --- a/src/pages/Server.tsx +++ b/src/pages/Server.tsx @@ -202,7 +202,7 @@ export default function Servers() { case "mem": comparison = (a.state?.mem_used ?? 0) - (b.state?.mem_used ?? 0) break - case "stg": + case "disk": comparison = (a.state?.disk_used ?? 0) - (b.state?.disk_used ?? 0) break case "up": From ed35e8c122598544b420235049e014b47fdd5774 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BB=93=E9=BC=A0?= <71394853+hamster1963@users.noreply.github.com> Date: Fri, 25 Apr 2025 10:50:01 +0800 Subject: [PATCH 2/4] Feat: Multiple choice (#41) * feat: enable multi-selection for charts in NetworkChart component * feat: add clear selections button for active charts in NetworkChart component * chore: auto-fix linting and formatting issues --- src/components/NetworkChart.tsx | 205 ++++++++++++++++++-------------- 1 file changed, 113 insertions(+), 92 deletions(-) diff --git a/src/components/NetworkChart.tsx b/src/components/NetworkChart.tsx index 30b09ac..288e64b 100644 --- a/src/components/NetworkChart.tsx +++ b/src/components/NetworkChart.tsx @@ -90,21 +90,30 @@ export const NetworkChartClient = React.memo(function NetworkChart({ }) { const { t } = useTranslation() - const defaultChart = "All" - const customBackgroundImage = (window.CustomBackgroundImage as string) !== "" ? window.CustomBackgroundImage : undefined const forcePeakCutEnabled = (window.ForcePeakCutEnabled as boolean) ?? false - const [activeChart, setActiveChart] = React.useState(defaultChart) + // Change from string to string array for multi-selection + const [activeCharts, setActiveCharts] = React.useState([]) const [isPeakEnabled, setIsPeakEnabled] = React.useState(forcePeakCutEnabled) - const handleButtonClick = useCallback( - (chart: string) => { - setActiveChart((prev) => (prev === chart ? defaultChart : chart)) - }, - [defaultChart], - ) + // Function to clear all selected charts + const clearAllSelections = useCallback(() => { + setActiveCharts([]) + }, []) + + // Updated to handle multiple selections + const handleButtonClick = useCallback((chart: string) => { + setActiveCharts((prev) => { + // If chart is already selected, remove it + if (prev.includes(chart)) { + return prev.filter((c) => c !== chart) + } + // Otherwise, add it to selected charts + return [...prev, chart] + }) + }, []) const getColorByIndex = useCallback( (chart: string) => { @@ -119,7 +128,7 @@ export const NetworkChartClient = React.memo(function NetworkChart({ chartDataKey.map((key) => ( )), - [chartDataKey, activeChart, chartData, handleButtonClick], + [chartDataKey, activeCharts, chartData, handleButtonClick], ) const chartLines = useMemo(() => { - if (activeChart !== defaultChart) { - return + // If we have active charts selected, render only those + if (activeCharts.length > 0) { + return activeCharts.map((chart) => ( + + )) } + // Otherwise show all charts (default view) return chartDataKey.map((key) => ( )) - }, [activeChart, defaultChart, chartDataKey, getColorByIndex]) + }, [activeCharts, chartDataKey, getColorByIndex]) const processedData = useMemo(() => { if (!isPeakEnabled) { - return activeChart === defaultChart ? formattedData : chartData[activeChart] + // Always use formattedData when multiple charts are selected or none selected + return formattedData } - const data = (activeChart === defaultChart ? formattedData : chartData[activeChart]) as ResultItem[] + // For peak cutting, always use the formatted data which contains all series + const data = formattedData const windowSize = 11 // 增加窗口大小以获取更好的统计效果 const alpha = 0.3 // EWMA平滑因子 @@ -200,43 +225,29 @@ export const NetworkChartClient = React.memo(function NetworkChart({ const window = data.slice(index - windowSize + 1, index + 1) const smoothed = { ...point } as ResultItem - if (activeChart === defaultChart) { - chartDataKey.forEach((key) => { - const values = window.map((w) => w[key]).filter((v) => v !== undefined && v !== null) as number[] + // Process all chart keys or just the selected ones + const keysToProcess = activeCharts.length > 0 ? activeCharts : chartDataKey - if (values.length > 0) { - const processed = processValues(values) - if (processed !== null) { - // 应用EWMA平滑 - if (ewmaHistory[key] === undefined) { - ewmaHistory[key] = processed - } else { - ewmaHistory[key] = alpha * processed + (1 - alpha) * ewmaHistory[key] - } - smoothed[key] = ewmaHistory[key] - } - } - }) - } else { - const values = window.map((w) => w.avg_delay).filter((v) => v !== undefined && v !== null) as number[] + keysToProcess.forEach((key) => { + const values = window.map((w) => w[key]).filter((v) => v !== undefined && v !== null) as number[] if (values.length > 0) { const processed = processValues(values) if (processed !== null) { - // 应用EWMA平滑 - if (ewmaHistory["current"] === undefined) { - ewmaHistory["current"] = processed + // Apply EWMA smoothing + if (ewmaHistory[key] === undefined) { + ewmaHistory[key] = processed } else { - ewmaHistory["current"] = alpha * processed + (1 - alpha) * ewmaHistory["current"] + ewmaHistory[key] = alpha * processed + (1 - alpha) * ewmaHistory[key] } - smoothed.avg_delay = ewmaHistory["current"] + smoothed[key] = ewmaHistory[key] } } - } + }) return smoothed }) - }, [isPeakEnabled, activeChart, formattedData, chartData, chartDataKey, defaultChart]) + }, [isPeakEnabled, activeCharts, formattedData, chartDataKey]) return ( {chartButtons} - - - - { - if (array.length < 6) { - return index === 0 || index === array.length - 1 - } +
+ {activeCharts.length > 0 && ( + + )} + + + + { + if (array.length < 6) { + return index === 0 || index === array.length - 1 + } - // 计算数据的总时间跨度(毫秒) - const timeSpan = array[array.length - 1].created_at - array[0].created_at - const hours = timeSpan / (1000 * 60 * 60) + // 计算数据的总时间跨度(毫秒) + const timeSpan = array[array.length - 1].created_at - array[0].created_at + const hours = timeSpan / (1000 * 60 * 60) - // 根据时间跨度调整显示间隔 - if (hours <= 12) { - // 12小时内,每60分钟显示一个刻度 - return index === 0 || index === array.length - 1 || new Date(item.created_at).getMinutes() % 60 === 0 - } - // 超过12小时,每2小时显示一个刻度 - const date = new Date(item.created_at) - return date.getMinutes() === 0 && date.getHours() % 2 === 0 - }) - .map((item) => item.created_at)} - tickFormatter={(value) => { - const date = new Date(value) - const minutes = date.getMinutes() - return minutes === 0 ? `${date.getHours()}:00` : `${date.getHours()}:${minutes}` - }} - /> - `${value}ms`} /> - { - return formatTime(payload[0].payload.created_at) - }} - /> - } - /> - {activeChart === defaultChart && } />} - {chartLines} - - + // 根据时间跨度调整显示间隔 + if (hours <= 12) { + // 12小时内,每60分钟显示一个刻度 + return index === 0 || index === array.length - 1 || new Date(item.created_at).getMinutes() % 60 === 0 + } + // 超过12小时,每2小时显示一个刻度 + const date = new Date(item.created_at) + return date.getMinutes() === 0 && date.getHours() % 2 === 0 + }) + .map((item) => item.created_at)} + tickFormatter={(value) => { + const date = new Date(value) + const minutes = date.getMinutes() + return minutes === 0 ? `${date.getHours()}:00` : `${date.getHours()}:${minutes}` + }} + /> + `${value}ms`} /> + { + return formatTime(payload[0].payload.created_at) + }} + /> + } + /> + } /> + {chartLines} + + +
) From 20bba90a49bbefbb8c14c0ff4a4b9ab7ed70fee0 Mon Sep 17 00:00:00 2001 From: hamster1963 <1410514192@qq.com> Date: Fri, 25 Apr 2025 10:55:02 +0800 Subject: [PATCH 3/4] fix: update button background color for better visibility in dark mode --- src/components/NetworkChart.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/NetworkChart.tsx b/src/components/NetworkChart.tsx index 288e64b..3c75c71 100644 --- a/src/components/NetworkChart.tsx +++ b/src/components/NetworkChart.tsx @@ -274,7 +274,7 @@ export const NetworkChartClient = React.memo(function NetworkChart({
{activeCharts.length > 0 && (