diff --git a/beszel/site/src/components/charts/area-chart.tsx b/beszel/site/src/components/charts/area-chart.tsx
index 1d9021f..6eaa14f 100644
--- a/beszel/site/src/components/charts/area-chart.tsx
+++ b/beszel/site/src/components/charts/area-chart.tsx
@@ -12,7 +12,7 @@ import {
} from '@/lib/utils'
// import Spinner from '../spinner'
import { ChartTimes, SystemStatsRecord } from '@/types'
-import { useMemo } from 'react'
+import { memo, useMemo } from 'react'
/** [label, key, color, opacity] */
type DataKeys = [string, string, number, number]
@@ -27,23 +27,28 @@ const getNestedValue = (path: string, max = false, data: any): number | null =>
.reduce((acc: any, key: string) => acc?.[key] ?? (data.stats?.cpum ? 0 : null), data)
}
-export default function AreaChartDefault({
- ticks,
- systemData,
- showMax = false,
+export default memo(function AreaChartDefault({
+ maxToggled = false,
unit = ' MB/s',
chartName,
- chartTime,
+ systemChartData,
}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
- showMax?: boolean
+ maxToggled?: boolean
unit?: string
chartName: string
- chartTime: ChartTimes
+ systemChartData: {
+ systemStats: SystemStatsRecord[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
+ const { chartTime } = systemChartData
+
+ const showMax = chartTime !== '1h' && maxToggled
+
const dataKeys: DataKeys[] = useMemo(() => {
// [label, key, color, opacity]
if (chartName === 'CPU Usage') {
@@ -67,6 +72,8 @@ export default function AreaChartDefault({
return []
}, [])
+ // console.log('Rendered at', new Date())
+
return (
-
+
formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + unit}
- indicator="line"
+ // indicator="line"
/>
}
/>
@@ -128,4 +136,4 @@ export default function AreaChartDefault({
)
-}
+})
diff --git a/beszel/site/src/components/charts/container-cpu-chart.tsx b/beszel/site/src/components/charts/container-chart.tsx
similarity index 73%
rename from beszel/site/src/components/charts/container-cpu-chart.tsx
rename to beszel/site/src/components/charts/container-chart.tsx
index ae37bf7..21c85b3 100644
--- a/beszel/site/src/components/charts/container-cpu-chart.tsx
+++ b/beszel/site/src/components/charts/container-chart.tsx
@@ -5,7 +5,7 @@ import {
ChartTooltip,
ChartTooltipContent,
} from '@/components/ui/chart'
-import { useMemo } from 'react'
+import { memo, useMemo } from 'react'
import {
useYAxisWidth,
chartTimeData,
@@ -13,22 +13,32 @@ import {
formatShortDate,
decimalString,
chartMargin,
+ toFixedWithoutTrailingZeros,
} from '@/lib/utils'
// import Spinner from '../spinner'
import { useStore } from '@nanostores/react'
-import { $chartTime, $containerFilter } from '@/lib/stores'
+import { $containerFilter } from '@/lib/stores'
+import { ChartTimes, ContainerStats } from '@/types'
-export default function ContainerCpuChart({
- chartData,
- ticks,
+export default memo(function ContainerCpuChart({
+ dataKey,
+ unit = '%',
+ containerChartData,
}: {
- chartData: Record[]
- ticks: number[]
+ dataKey: string
+ unit?: string
+ containerChartData: {
+ containerData: Record[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const filter = useStore($containerFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
+ const { containerData, ticks, domain, chartTime } = containerChartData
+
const chartConfig = useMemo(() => {
let config = {} as Record<
string,
@@ -38,16 +48,16 @@ export default function ContainerCpuChart({
}
>
const totalUsage = {} as Record
- for (let stats of chartData) {
+ for (let stats of containerData) {
for (let key in stats) {
- if (key === 'time') {
+ if (!key || typeof stats[key] === 'number') {
continue
}
if (!(key in totalUsage)) {
totalUsage[key] = 0
}
// @ts-ignore
- totalUsage[key] += stats[key]
+ totalUsage[key] += stats[key]?.[dataKey] ?? 0
}
}
let keys = Object.keys(totalUsage)
@@ -62,15 +72,12 @@ export default function ContainerCpuChart({
}
}
return config satisfies ChartConfig
- }, [chartData])
+ }, [containerChartData])
- // if (!chartData.length || !ticks.length) {
- // return
- // }
+ // console.log('rendered at', new Date())
return (
- {/* {!yAxisSet &&
} */}
Math.max(Math.ceil(max), 0.4)]}
width={yAxisWidth}
- tickLine={false}
- axisLine={false}
- tickFormatter={(x) => {
- const val = (x % 1 === 0 ? x : x.toFixed(1)) + '%'
+ tickFormatter={(value) => {
+ const val = toFixedWithoutTrailingZeros(value, 2) + unit
return updateYAxisWidth(val)
}}
+ tickLine={false}
+ axisLine={false}
/>
formatShortDate(data[0].payload.time)}
+ labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
// @ts-ignore
itemSorter={(a, b) => b.value - a.value}
content={
decimalString(item.value) + '%'}
- indicator="line"
+ contentFormatter={(item) => decimalString(item.value) + unit}
+ // indicator="line"
/>
}
/>
@@ -129,7 +135,8 @@ export default function ContainerCpuChart({
)
-}
+})
diff --git a/beszel/site/src/components/charts/container-mem-chart.tsx b/beszel/site/src/components/charts/container-mem-chart.tsx
deleted file mode 100644
index 8e89da5..0000000
--- a/beszel/site/src/components/charts/container-mem-chart.tsx
+++ /dev/null
@@ -1,147 +0,0 @@
-import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
-import {
- ChartConfig,
- ChartContainer,
- ChartTooltip,
- ChartTooltipContent,
-} from '@/components/ui/chart'
-import { useMemo } from 'react'
-import {
- useYAxisWidth,
- chartTimeData,
- cn,
- formatShortDate,
- toFixedWithoutTrailingZeros,
- decimalString,
- chartMargin,
-} from '@/lib/utils'
-// import Spinner from '../spinner'
-import { useStore } from '@nanostores/react'
-import { $chartTime, $containerFilter } from '@/lib/stores'
-
-export default function ContainerMemChart({
- chartData,
- ticks,
-}: {
- chartData: Record[]
- ticks: number[]
-}) {
- const chartTime = useStore($chartTime)
- const filter = useStore($containerFilter)
- const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
-
- const chartConfig = useMemo(() => {
- let config = {} as Record<
- string,
- {
- label: string
- color: string
- }
- >
- const totalUsage = {} as Record
- for (let stats of chartData) {
- for (let key in stats) {
- if (key === 'time') {
- continue
- }
- if (!(key in totalUsage)) {
- totalUsage[key] = 0
- }
- // @ts-ignore
- totalUsage[key] += stats[key]
- }
- }
- let keys = Object.keys(totalUsage)
- keys.sort((a, b) => (totalUsage[a] > totalUsage[b] ? -1 : 1))
- const length = keys.length
- for (let i = 0; i < length; i++) {
- const key = keys[i]
- const hue = ((i * 360) / length) % 360
- config[key] = {
- label: key,
- color: `hsl(${hue}, 60%, 55%)`,
- }
- }
- return config satisfies ChartConfig
- }, [chartData])
-
- // if (!chartData.length || !ticks.length) {
- // return
- // }
-
- return (
-
- {/* {!yAxisSet &&
} */}
-
-
-
- Math.ceil(max)]}
- tickLine={false}
- axisLine={false}
- width={yAxisWidth}
- tickFormatter={(value) => {
- const val = toFixedWithoutTrailingZeros(value / 1024, 2) + ' GB'
- return updateYAxisWidth(val)
- }}
- />
-
- formatShortDate(data[0].payload.time)}
- // @ts-ignore
- itemSorter={(a, b) => b.value - a.value}
- content={
- decimalString(item.value) + ' MB'}
- indicator="line"
- />
- }
- />
- {Object.keys(chartConfig).map((key) => {
- const filtered = filter && !key.includes(filter)
- let fillOpacity = filtered ? 0.05 : 0.4
- let strokeOpacity = filtered ? 0.1 : 1
- return (
-
- )
- })}
-
-
-
- )
-}
diff --git a/beszel/site/src/components/charts/container-net-chart.tsx b/beszel/site/src/components/charts/container-net-chart.tsx
index 10b94e1..00ae790 100644
--- a/beszel/site/src/components/charts/container-net-chart.tsx
+++ b/beszel/site/src/components/charts/container-net-chart.tsx
@@ -5,7 +5,7 @@ import {
ChartTooltip,
ChartTooltipContent,
} from '@/components/ui/chart'
-import { useMemo } from 'react'
+import { memo, useMemo } from 'react'
import {
useYAxisWidth,
chartTimeData,
@@ -15,22 +15,26 @@ import {
decimalString,
chartMargin,
} from '@/lib/utils'
-// import Spinner from '../spinner'
import { useStore } from '@nanostores/react'
-import { $chartTime, $containerFilter } from '@/lib/stores'
+import { $containerFilter } from '@/lib/stores'
import { Separator } from '@/components/ui/separator'
+import { ChartTimes, ContainerStats } from '@/types'
-export default function ContainerCpuChart({
- chartData,
- ticks,
+export default memo(function ContainerCpuChart({
+ containerChartData,
}: {
- chartData: Record[]
- ticks: number[]
+ containerChartData: {
+ containerData: Record[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const filter = useStore($containerFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
+ const { containerData, ticks, domain, chartTime } = containerChartData
+
const chartConfig = useMemo(() => {
let config = {} as Record<
string,
@@ -40,15 +44,16 @@ export default function ContainerCpuChart({
}
>
const totalUsage = {} as Record
- for (let stats of chartData) {
+ for (let stats of containerData) {
for (let key in stats) {
- if (!Array.isArray(stats[key])) {
+ // continue if number and not container stats
+ if (!key || typeof stats[key] === 'number') {
continue
}
if (!(key in totalUsage)) {
totalUsage[key] = 0
}
- totalUsage[key] += stats[key][2] ?? 0
+ totalUsage[key] += stats[key]?.ns ?? 0 + stats[key]?.nr ?? 0
}
}
let keys = Object.keys(totalUsage)
@@ -63,7 +68,9 @@ export default function ContainerCpuChart({
}
}
return config satisfies ChartConfig
- }, [chartData])
+ }, [containerChartData])
+
+ // console.log('rendered at', new Date())
return (
@@ -75,7 +82,7 @@ export default function ContainerCpuChart({
>
@@ -92,11 +99,12 @@ export default function ContainerCpuChart({
}}
/>
formatShortDate(data[0].payload.time)}
+ labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
// @ts-ignore
itemSorter={(a, b) => b.value - a.value}
content={
{
try {
- const sent = item?.payload?.[key][0] ?? 0
- const received = item?.payload?.[key][1] ?? 0
+ const sent = item?.payload?.[key]?.ns ?? 0
+ const received = item?.payload?.[key]?.nr ?? 0
return (
{decimalString(received)} MB/s
@@ -140,9 +148,8 @@ export default function ContainerCpuChart({
data?.[key]?.[2] ?? 0}
+ dataKey={(data) => data?.[key]?.ns ?? 0 + data?.[key]?.nr ?? 0}
type="monotoneX"
fill={chartConfig[key].color}
fillOpacity={fillOpacity}
@@ -157,4 +164,4 @@ export default function ContainerCpuChart({
)
-}
+})
diff --git a/beszel/site/src/components/charts/cpu-chart.tsx b/beszel/site/src/components/charts/cpu-chart.tsx
deleted file mode 100644
index 7300d15..0000000
--- a/beszel/site/src/components/charts/cpu-chart.tsx
+++ /dev/null
@@ -1,91 +0,0 @@
-import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
-
-import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
-import {
- useYAxisWidth,
- chartTimeData,
- cn,
- formatShortDate,
- decimalString,
- chartMargin,
-} from '@/lib/utils'
-// import Spinner from '../spinner'
-import { useStore } from '@nanostores/react'
-import { $chartTime, $cpuMax } from '@/lib/stores'
-import { SystemStatsRecord } from '@/types'
-import { useMemo } from 'react'
-
-export default function CpuChart({
- ticks,
- systemData,
-}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
-}) {
- const chartTime = useStore($chartTime)
- const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
- const showMax = useStore($cpuMax)
-
- const dataKey = useMemo(
- () => `stats.cpu${showMax && chartTime !== '1h' ? 'm' : ''}`,
- [showMax, systemData]
- )
-
- return (
-
-
-
-
- Math.ceil(max)]}
- width={yAxisWidth}
- tickLine={false}
- axisLine={false}
- tickFormatter={(value) => updateYAxisWidth(value + '%')}
- />
-
- formatShortDate(data[0].payload.created)}
- contentFormatter={(item) => decimalString(item.value) + '%'}
- indicator="line"
- />
- }
- />
-
-
-
-
- )
-}
diff --git a/beszel/site/src/components/charts/disk-chart.tsx b/beszel/site/src/components/charts/disk-chart.tsx
index d36d57d..abcd5f0 100644
--- a/beszel/site/src/components/charts/disk-chart.tsx
+++ b/beszel/site/src/components/charts/disk-chart.tsx
@@ -12,35 +12,35 @@ import {
getSizeUnit,
chartMargin,
} from '@/lib/utils'
-// import { useMemo } from 'react'
-// import Spinner from '../spinner'
-import { useStore } from '@nanostores/react'
-import { $chartTime } from '@/lib/stores'
-import { SystemStatsRecord } from '@/types'
+import { ChartTimes, SystemStatsRecord } from '@/types'
+import { memo } from 'react'
-export default function DiskChart({
- ticks,
- systemData,
+export default memo(function DiskChart({
dataKey,
diskSize,
+ systemChartData,
}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
dataKey: string
diskSize: number
+ systemChartData: {
+ systemStats: SystemStatsRecord[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
+ // console.log('rendered at', new Date())
+
return (
- {/* {!yAxisSet &&
} */}
-
+
decimalString(getSizeVal(value)) + getSizeUnit(value)
}
- indicator="line"
+ // indicator="line"
/>
}
/>
@@ -92,4 +93,4 @@ export default function DiskChart({
)
-}
+})
diff --git a/beszel/site/src/components/charts/mem-chart.tsx b/beszel/site/src/components/charts/mem-chart.tsx
index 58da7d8..097de43 100644
--- a/beszel/site/src/components/charts/mem-chart.tsx
+++ b/beszel/site/src/components/charts/mem-chart.tsx
@@ -10,24 +10,24 @@ import {
formatShortDate,
chartMargin,
} from '@/lib/utils'
-import { useMemo } from 'react'
-import { useStore } from '@nanostores/react'
-import { $chartTime } from '@/lib/stores'
-import { SystemStatsRecord } from '@/types'
+import { memo } from 'react'
+import { ChartTimes, SystemStatsRecord } from '@/types'
-export default function MemChart({
- ticks,
- systemData,
+export default memo(function MemChart({
+ systemChartData,
}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
+ systemChartData: {
+ systemStats: SystemStatsRecord[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
- const totalMem = useMemo(() => {
- return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1)
- }, [systemData])
+ const totalMem = toFixedFloat(systemChartData.systemStats.at(-1)?.stats.m ?? 0, 1)
+
+ // console.log('rendered at', new Date())
return (
@@ -37,7 +37,7 @@ export default function MemChart({
'opacity-100': yAxisWidth,
})}
>
-
+
{totalMem && (
a.order - b.order}
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + ' GB'}
- indicator="line"
+ // indicator="line"
/>
}
/>
@@ -90,7 +91,7 @@ export default function MemChart({
stackId="1"
isAnimationActive={false}
/>
- {systemData.at(-1)?.stats.mz && (
+ {systemChartData.systemStats.at(-1)?.stats.mz && (
)
-}
+})
diff --git a/beszel/site/src/components/charts/swap-chart.tsx b/beszel/site/src/components/charts/swap-chart.tsx
index 0c648dd..85fa0cc 100644
--- a/beszel/site/src/components/charts/swap-chart.tsx
+++ b/beszel/site/src/components/charts/swap-chart.tsx
@@ -10,18 +10,19 @@ import {
decimalString,
chartMargin,
} from '@/lib/utils'
-import { useStore } from '@nanostores/react'
-import { $chartTime } from '@/lib/stores'
-import { SystemStatsRecord } from '@/types'
+import { ChartTimes, SystemStatsRecord } from '@/types'
+import { memo } from 'react'
-export default function SwapChart({
- ticks,
- systemData,
+export default memo(function SwapChart({
+ systemChartData,
}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
+ systemChartData: {
+ systemStats: SystemStatsRecord[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
return (
@@ -31,11 +32,15 @@ export default function SwapChart({
'opacity-100': yAxisWidth,
})}
>
-
+
toFixedWithoutTrailingZeros(systemData.at(-1)?.stats.s ?? 0.04, 2)]}
+ domain={[
+ 0,
+ () =>
+ toFixedWithoutTrailingZeros(systemChartData.systemStats.at(-1)?.stats.s ?? 0.04, 2),
+ ]}
width={yAxisWidth}
tickLine={false}
axisLine={false}
@@ -43,14 +48,15 @@ export default function SwapChart({
/>
formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + ' GB'}
- indicator="line"
+ // indicator="line"
/>
}
/>
@@ -76,4 +82,4 @@ export default function SwapChart({
)
-}
+})
diff --git a/beszel/site/src/components/charts/temperature-chart.tsx b/beszel/site/src/components/charts/temperature-chart.tsx
index 6db26df..f31b6fd 100644
--- a/beszel/site/src/components/charts/temperature-chart.tsx
+++ b/beszel/site/src/components/charts/temperature-chart.tsx
@@ -16,19 +16,19 @@ import {
decimalString,
chartMargin,
} from '@/lib/utils'
-import { useStore } from '@nanostores/react'
-import { $chartTime } from '@/lib/stores'
-import { SystemStatsRecord } from '@/types'
-import { useMemo } from 'react'
+import { ChartTimes, SystemStatsRecord } from '@/types'
+import { memo, useMemo } from 'react'
-export default function TemperatureChart({
- ticks,
- systemData,
+export default memo(function TemperatureChart({
+ systemChartData,
}: {
- ticks: number[]
- systemData: SystemStatsRecord[]
+ systemChartData: {
+ systemStats: SystemStatsRecord[]
+ ticks: number[]
+ domain: number[]
+ chartTime: ChartTimes
+ }
}) {
- const chartTime = useStore($chartTime)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
/** Format temperature data for chart and assign colors */
@@ -38,7 +38,7 @@ export default function TemperatureChart({
colors: Record
}
const tempSums = {} as Record
- for (let data of systemData) {
+ for (let data of systemChartData.systemStats) {
let newData = { created: data.created } as Record
let keys = Object.keys(data.stats?.t ?? {})
for (let i = 0; i < keys.length; i++) {
@@ -53,13 +53,14 @@ export default function TemperatureChart({
chartData.colors[key] = `hsl(${((keys.indexOf(key) * 360) / keys.length) % 360}, 60%, 55%)`
}
return chartData
- }, [systemData])
+ }, [systemChartData])
const colors = Object.keys(newChartData.colors)
+ // console.log('rendered at', new Date())
+
return (
- {/* {!yAxisSet && } */}
formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + ' °C'}
- indicator="line"
+ // indicator="line"
/>
}
/>
@@ -119,4 +121,4 @@ export default function TemperatureChart({
)
-}
+})
diff --git a/beszel/site/src/components/routes/system.tsx b/beszel/site/src/components/routes/system.tsx
index e8eb6dd..b5f0df7 100644
--- a/beszel/site/src/components/routes/system.tsx
+++ b/beszel/site/src/components/routes/system.tsx
@@ -1,5 +1,5 @@
import { $systems, pb, $chartTime, $containerFilter, $userSettings } from '@/lib/stores'
-import { ContainerStatsRecord, SystemRecord, SystemStatsRecord } from '@/types'
+import { ContainerStats, ContainerStatsRecord, SystemRecord, SystemStatsRecord } from '@/types'
import React, { Suspense, lazy, useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { Card, CardHeader, CardTitle, CardDescription } from '../ui/card'
import { useStore } from '@nanostores/react'
@@ -16,11 +16,10 @@ import { ChartAverage, ChartMax, Rows, TuxIcon } from '../ui/icons'
import { useIntersectionObserver } from '@/lib/use-intersection-observer'
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../ui/select'
-const ContainerCpuChart = lazy(() => import('../charts/container-cpu-chart'))
-const MemChart = lazy(() => import('../charts/mem-chart'))
-const ContainerMemChart = lazy(() => import('../charts/container-mem-chart'))
-const DiskChart = lazy(() => import('../charts/disk-chart'))
const AreaChartDefault = lazy(() => import('../charts/area-chart'))
+const ContainerChartDefault = lazy(() => import('../charts/container-chart'))
+const MemChart = lazy(() => import('../charts/mem-chart'))
+const DiskChart = lazy(() => import('../charts/disk-chart'))
const ContainerNetChart = lazy(() => import('../charts/container-net-chart'))
const SwapChart = lazy(() => import('../charts/swap-chart'))
const TemperatureChart = lazy(() => import('../charts/temperature-chart'))
@@ -35,27 +34,22 @@ export default function SystemDetail({ name }: { name: string }) {
const bandwidthMaxStore = useState(false)
const diskIoMaxStore = useState(false)
const [grid, setGrid] = useLocalStorage('grid', true)
- const [ticks, setTicks] = useState([] as number[])
const [system, setSystem] = useState({} as SystemRecord)
const [systemStats, setSystemStats] = useState([] as SystemStatsRecord[])
+ const [containerData, setContainerData] = useState(
+ [] as Record[]
+ )
const netCardRef = useRef(null)
const [containerFilterBar, setContainerFilterBar] = useState(null as null | JSX.Element)
- const [dockerCpuChartData, setDockerCpuChartData] = useState[]>(
- []
- )
- const [dockerMemChartData, setDockerMemChartData] = useState[]>(
- []
- )
- const [dockerNetChartData, setDockerNetChartData] = useState[]>(
- []
- )
const isLongerChart = chartTime !== '1h'
useEffect(() => {
document.title = `${name} / Beszel`
return () => {
- resetCharts()
$chartTime.set($userSettings.get().chartTime)
+ // resetCharts()
+ setSystemStats([])
+ setContainerData([])
setContainerFilterBar(null)
$containerFilter.set('')
cpuMaxStore[1](false)
@@ -64,15 +58,14 @@ export default function SystemDetail({ name }: { name: string }) {
}
}, [name])
- function resetCharts() {
- setSystemStats([])
- setDockerCpuChartData([])
- setDockerMemChartData([])
- setDockerNetChartData([])
- }
+ // function resetCharts() {
+ // setSystemStats([])
+ // setContainerData([])
+ // }
- useEffect(resetCharts, [chartTime])
+ // useEffect(resetCharts, [chartTime])
+ // find matching system
useEffect(() => {
if (system.id && system.name === name) {
return
@@ -96,6 +89,33 @@ export default function SystemDetail({ name }: { name: string }) {
}
}, [system])
+ function getTimeData() {
+ const now = new Date()
+ const startTime = chartTimeData[chartTime].getOffset(now)
+ const scale = scaleTime([startTime.getTime(), now], [0, systemStats.length])
+ const ticks = scale.ticks(chartTimeData[chartTime].ticks).map((d) => d.getTime())
+
+ return {
+ ticks,
+ chartTime,
+ domain: [chartTimeData[chartTime].getOffset(now).getTime(), now.getTime()],
+ }
+ }
+
+ const systemChartData = useMemo(() => {
+ return {
+ systemStats,
+ ...getTimeData(),
+ }
+ }, [systemStats])
+
+ const containerChartData = useMemo(() => {
+ return {
+ containerData,
+ ...getTimeData(),
+ }
+ }, [containerData])
+
async function getStats(collection: string): Promise {
const lastCached = cache.get(`${system.id}_${chartTime}_${collection}`)?.at(-1)
?.created as number
@@ -174,49 +194,24 @@ export default function SystemDetail({ name }: { name: string }) {
})
}, [system, chartTime])
- useEffect(() => {
- if (!systemStats.length) {
- return
- }
- const now = new Date()
- const startTime = chartTimeData[chartTime].getOffset(now)
- const scale = scaleTime([startTime.getTime(), now], [0, systemStats.length])
- const newTicks = scale.ticks(chartTimeData[chartTime].ticks).map((d) => d.getTime())
- if (newTicks[0] !== ticks[0]) {
- setTicks(newTicks)
- }
- }, [chartTime, systemStats])
-
// make container stats for charts
const makeContainerData = useCallback((containers: ContainerStatsRecord[]) => {
// console.log('containers', containers)
- const dockerCpuData = []
- const dockerMemData = []
- const dockerNetData = []
+ const containerData = [] as Record[]
for (let { created, stats } of containers) {
if (!created) {
- let nullData = { time: null } as unknown
- dockerCpuData.push(nullData as Record)
- dockerMemData.push(nullData as Record)
- dockerNetData.push(nullData as Record)
+ let nullData = { created: null } as unknown
+ containerData.push(nullData as Record)
continue
}
- const time = new Date(created).getTime()
- let cpuData = { time } as Record
- let memData = { time } as Record
- let netData = { time } as Record
+ created = new Date(created).getTime()
+ let containerStats = { created } as Record
for (let container of stats) {
- cpuData[container.n] = container.c
- memData[container.n] = container.m
- netData[container.n] = [container.ns, container.nr, container.ns + container.nr] // sent, received, total
+ containerStats[container.n] = container
}
- dockerCpuData.push(cpuData)
- dockerMemData.push(memData)
- dockerNetData.push(netData)
+ containerData.push(containerStats)
}
- setDockerCpuChartData(dockerCpuData)
- setDockerMemChartData(dockerMemData)
- setDockerNetChartData(dockerNetData)
+ setContainerData(containerData)
}, [])
// values for system info bar
@@ -257,16 +252,16 @@ export default function SystemDetail({ name }: { name: string }) {
/** Space for tooltip if more than 12 containers */
const bottomSpacing = useMemo(() => {
- if (!netCardRef.current || !dockerNetChartData.length) {
+ if (!netCardRef.current || !containerData.length) {
return 0
}
- const tooltipHeight = (Object.keys(dockerNetChartData[0]).length - 11) * 17.8 - 40
+ const tooltipHeight = (Object.keys(containerData[0]).length - 11) * 17.8 - 40
const wrapperEl = document.getElementById('chartwrap') as HTMLDivElement
const wrapperRect = wrapperEl.getBoundingClientRect()
const chartRect = netCardRef.current.getBoundingClientRect()
const distanceToBottom = wrapperRect.bottom - chartRect.bottom
return tooltipHeight - distanceToBottom
- }, [netCardRef.current, dockerNetChartData])
+ }, [netCardRef.current, containerData])
if (!system.id) {
return null
@@ -365,12 +360,10 @@ export default function SystemDetail({ name }: { name: string }) {
cornerEl={isLongerChart ? : null}
>
@@ -381,7 +374,7 @@ export default function SystemDetail({ name }: { name: string }) {
description="Average CPU utilization of containers"
cornerEl={containerFilterBar}
>
-
+
)}
@@ -390,7 +383,7 @@ export default function SystemDetail({ name }: { name: string }) {
title="Total Memory Usage"
description="Precise utilization at the recorded time"
>
-
+
{containerFilterBar && (
@@ -400,14 +393,17 @@ export default function SystemDetail({ name }: { name: string }) {
description="Memory usage of docker containers"
cornerEl={containerFilterBar}
>
-
+
)}
@@ -420,11 +416,9 @@ export default function SystemDetail({ name }: { name: string }) {
cornerEl={isLongerChart ? : null}
>
@@ -435,15 +429,13 @@ export default function SystemDetail({ name }: { name: string }) {
description="Network traffic of public interfaces"
>
- {containerFilterBar && dockerNetChartData.length > 0 && (
+ {containerFilterBar && containerData.length > 0 && (
-
+ {/* @ts-ignore */}
+
)}
{(systemStats.at(-1)?.stats.su ?? 0) > 0 && (
-
+
)}
{systemStats.at(-1)?.stats.t && (
-
+
)}
@@ -485,8 +478,7 @@ export default function SystemDetail({ name }: { name: string }) {
description={`Disk usage of ${extraFsName}`}
>
@@ -498,11 +490,9 @@ export default function SystemDetail({ name }: { name: string }) {
cornerEl={isLongerChart ? : null}
>
diff --git a/beszel/site/src/components/ui/chart.tsx b/beszel/site/src/components/ui/chart.tsx
index 1e94248..334458f 100644
--- a/beszel/site/src/components/ui/chart.tsx
+++ b/beszel/site/src/components/ui/chart.tsx
@@ -95,7 +95,6 @@ const ChartTooltipContent = React.forwardRef<
React.ComponentProps &
React.ComponentProps<'div'> & {
hideLabel?: boolean
- hideIndicator?: boolean
indicator?: 'line' | 'dot' | 'dashed'
nameKey?: string
labelKey?: string
@@ -109,9 +108,8 @@ const ChartTooltipContent = React.forwardRef<
active,
payload,
className,
- indicator = 'dot',
+ indicator = 'line',
hideLabel = false,
- hideIndicator = false,
label,
labelFormatter,
labelClassName,
@@ -145,7 +143,7 @@ const ChartTooltipContent = React.forwardRef<
}
const [item] = payload
- const key = `${labelKey || item.dataKey || item.name || 'value'}`
+ const key = `${labelKey || item.name || 'value'}`
const itemConfig = getPayloadConfigFromPayload(config, item, key)
const value = !labelKey && typeof label === 'string' ? label : itemConfig?.label
@@ -166,7 +164,8 @@ const ChartTooltipContent = React.forwardRef<
return null
}
- const nestLabel = payload.length === 1 && indicator !== 'dot'
+ // const nestLabel = payload.length === 1 && indicator !== 'dot'
+ const nestLabel = false
return (
) : (
- !hideIndicator && (
-
- )
+ )}
+ style={
+ {
+ '--color-bg': indicatorColor,
+ '--color-border': indicatorColor,
+ } as React.CSSProperties
+ }
+ />
)}