mirror of
https://github.com/fankes/beszel.git
synced 2025-10-19 17:59:28 +08:00
fix wrapping of y axis chart labels
This commit is contained in:
@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
|||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
|
||||||
|
|
||||||
export default function BandwidthChart({
|
export default function BandwidthChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -22,19 +21,16 @@ export default function BandwidthChart({
|
|||||||
ticks: number[]
|
ticks: number[]
|
||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -52,10 +48,13 @@ export default function BandwidthChart({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
|
||||||
|
return updateYAxisWidth(val)
|
||||||
|
}}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' MB/s'}
|
// unit={' MB/s'}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -5,8 +5,8 @@ import {
|
|||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
} from '@/components/ui/chart'
|
} from '@/components/ui/chart'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils'
|
import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime, $containerFilter } from '@/lib/stores'
|
import { $chartTime, $containerFilter } from '@/lib/stores'
|
||||||
@@ -18,12 +18,9 @@ export default function ContainerCpuChart({
|
|||||||
chartData: Record<string, number | string>[]
|
chartData: Record<string, number | string>[]
|
||||||
ticks: number[]
|
ticks: number[]
|
||||||
}) {
|
}) {
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const filter = useStore($containerFilter)
|
const filter = useStore($containerFilter)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const chartConfig = useMemo(() => {
|
const chartConfig = useMemo(() => {
|
||||||
let config = {} as Record<
|
let config = {} as Record<
|
||||||
@@ -65,12 +62,12 @@ export default function ContainerCpuChart({
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -89,8 +86,10 @@ export default function ContainerCpuChart({
|
|||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={'%'}
|
tickFormatter={(x) => {
|
||||||
tickFormatter={(x) => (x % 1 === 0 ? x : x.toFixed(1))}
|
const val = (x % 1 === 0 ? x : x.toFixed(1)) + '%'
|
||||||
|
return updateYAxisWidth(val)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="time"
|
dataKey="time"
|
||||||
|
@@ -5,14 +5,14 @@ import {
|
|||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
} from '@/components/ui/chart'
|
} from '@/components/ui/chart'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
@@ -26,11 +26,8 @@ export default function ContainerMemChart({
|
|||||||
ticks: number[]
|
ticks: number[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const filter = useStore($containerFilter)
|
const filter = useStore($containerFilter)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const chartConfig = useMemo(() => {
|
const chartConfig = useMemo(() => {
|
||||||
let config = {} as Record<
|
let config = {} as Record<
|
||||||
@@ -72,12 +69,12 @@ export default function ContainerMemChart({
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -94,9 +91,11 @@ export default function ContainerMemChart({
|
|||||||
// domain={[0, (max: number) => Math.ceil(max)]}
|
// domain={[0, (max: number) => Math.ceil(max)]}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' GB'}
|
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value / 1024, 2)}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedWithoutTrailingZeros(value / 1024, 2) + ' GB'
|
||||||
|
return updateYAxisWidth(val)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="time"
|
dataKey="time"
|
||||||
|
@@ -5,14 +5,14 @@ import {
|
|||||||
ChartTooltip,
|
ChartTooltip,
|
||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
} from '@/components/ui/chart'
|
} from '@/components/ui/chart'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
@@ -27,11 +27,8 @@ export default function ContainerCpuChart({
|
|||||||
ticks: number[]
|
ticks: number[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const filter = useStore($containerFilter)
|
const filter = useStore($containerFilter)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const chartConfig = useMemo(() => {
|
const chartConfig = useMemo(() => {
|
||||||
let config = {} as Record<
|
let config = {} as Record<
|
||||||
@@ -72,12 +69,12 @@ export default function ContainerCpuChart({
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -95,8 +92,10 @@ export default function ContainerCpuChart({
|
|||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' MB/s'}
|
tickFormatter={(value) => {
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)}
|
const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
|
||||||
|
return updateYAxisWidth(val)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="time"
|
dataKey="time"
|
||||||
|
@@ -1,12 +1,11 @@
|
|||||||
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils'
|
import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
|
||||||
|
|
||||||
export default function CpuChart({
|
export default function CpuChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -16,17 +15,14 @@ export default function CpuChart({
|
|||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -42,7 +38,7 @@ export default function CpuChart({
|
|||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={'%'}
|
tickFormatter={(value) => updateYAxisWidth(value + '%')}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils'
|
import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
@@ -16,22 +16,19 @@ export default function DiskChart({
|
|||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const diskSize = useMemo(() => {
|
const diskSize = useMemo(() => {
|
||||||
return Math.round(systemData.at(-1)?.stats.d ?? NaN)
|
return Math.round(systemData.at(-1)?.stats.d ?? NaN)
|
||||||
}, [systemData])
|
}, [systemData])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -53,7 +50,7 @@ export default function DiskChart({
|
|||||||
minTickGap={6}
|
minTickGap={6}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' GB'}
|
tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
|||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
|
||||||
|
|
||||||
export default function DiskIoChart({
|
export default function DiskIoChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -23,22 +22,15 @@ export default function DiskIoChart({
|
|||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
// if (!systemData.length || !ticks.length) {
|
|
||||||
// return <Spinner />
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -56,10 +48,12 @@ export default function DiskIoChart({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedWithoutTrailingZeros(value, 2) + ' MB/s'
|
||||||
|
return updateYAxisWidth(val)
|
||||||
|
}}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' MB/s'}
|
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -1,8 +1,8 @@
|
|||||||
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import { chartTimeData, cn, formatShortDate, twoDecimalString, useYaxisWidth } from '@/lib/utils'
|
import { useYAxisWidth, chartTimeData, cn, formatShortDate, twoDecimalString } from '@/lib/utils'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
@@ -18,10 +18,7 @@ export default function ExFsDiskChart({
|
|||||||
fs: string
|
fs: string
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const diskSize = useMemo(() => {
|
const diskSize = useMemo(() => {
|
||||||
const size = systemData.at(-1)?.stats.efs?.[fs].d ?? 0
|
const size = systemData.at(-1)?.stats.efs?.[fs].d ?? 0
|
||||||
@@ -29,11 +26,11 @@ export default function ExFsDiskChart({
|
|||||||
}, [systemData])
|
}, [systemData])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -52,7 +49,7 @@ export default function ExFsDiskChart({
|
|||||||
minTickGap={6}
|
minTickGap={6}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' GB'}
|
tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
|||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
|
||||||
|
|
||||||
export default function ExFsDiskIoChart({
|
export default function ExFsDiskIoChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -25,22 +24,15 @@ export default function ExFsDiskIoChart({
|
|||||||
fs: string
|
fs: string
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
// if (!systemData.length || !ticks.length) {
|
|
||||||
// return <Spinner />
|
|
||||||
// }
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -58,10 +50,12 @@ export default function ExFsDiskIoChart({
|
|||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
// domain={[0, (max: number) => (max <= 0.4 ? 0.4 : Math.ceil(max))]}
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedWithoutTrailingZeros(value, 2)
|
||||||
|
return updateYAxisWidth(val + ' MB/s')
|
||||||
|
}}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' MB/s'}
|
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -2,14 +2,14 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
|||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedFloat,
|
toFixedFloat,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
@@ -22,23 +22,20 @@ export default function MemChart({
|
|||||||
ticks: number[]
|
ticks: number[]
|
||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
const totalMem = useMemo(() => {
|
const totalMem = useMemo(() => {
|
||||||
return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1)
|
return toFixedFloat(systemData.at(-1)?.stats.m ?? 0, 1)
|
||||||
}, [systemData])
|
}, [systemData])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart
|
<AreaChart
|
||||||
@@ -58,7 +55,10 @@ export default function MemChart({
|
|||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' GB'}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedFloat(value, 1)
|
||||||
|
return updateYAxisWidth(val + ' GB')
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
<XAxis
|
<XAxis
|
||||||
|
@@ -2,18 +2,17 @@ import { Area, AreaChart, CartesianGrid, XAxis, YAxis } from 'recharts'
|
|||||||
|
|
||||||
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
import { ChartContainer, ChartTooltip, ChartTooltipContent } from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
// import Spinner from '../spinner'
|
// import Spinner from '../spinner'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
|
||||||
|
|
||||||
export default function SwapChart({
|
export default function SwapChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -23,17 +22,14 @@ export default function SwapChart({
|
|||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<AreaChart accessibilityLayer data={systemData} margin={{ top: 10 }}>
|
<AreaChart accessibilityLayer data={systemData} margin={{ top: 10 }}>
|
||||||
@@ -44,7 +40,7 @@ export default function SwapChart({
|
|||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' GB'}
|
tickFormatter={(value) => updateYAxisWidth(value + ' GB')}
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -8,17 +8,17 @@ import {
|
|||||||
ChartTooltipContent,
|
ChartTooltipContent,
|
||||||
} from '@/components/ui/chart'
|
} from '@/components/ui/chart'
|
||||||
import {
|
import {
|
||||||
|
useYAxisWidth,
|
||||||
chartTimeData,
|
chartTimeData,
|
||||||
cn,
|
cn,
|
||||||
formatShortDate,
|
formatShortDate,
|
||||||
toFixedWithoutTrailingZeros,
|
toFixedWithoutTrailingZeros,
|
||||||
twoDecimalString,
|
twoDecimalString,
|
||||||
useYaxisWidth,
|
|
||||||
} from '@/lib/utils'
|
} from '@/lib/utils'
|
||||||
import { useStore } from '@nanostores/react'
|
import { useStore } from '@nanostores/react'
|
||||||
import { $chartTime } from '@/lib/stores'
|
import { $chartTime } from '@/lib/stores'
|
||||||
import { SystemStatsRecord } from '@/types'
|
import { SystemStatsRecord } from '@/types'
|
||||||
import { useMemo, useRef } from 'react'
|
import { useMemo } from 'react'
|
||||||
|
|
||||||
export default function TemperatureChart({
|
export default function TemperatureChart({
|
||||||
ticks,
|
ticks,
|
||||||
@@ -27,9 +27,8 @@ export default function TemperatureChart({
|
|||||||
ticks: number[]
|
ticks: number[]
|
||||||
systemData: SystemStatsRecord[]
|
systemData: SystemStatsRecord[]
|
||||||
}) {
|
}) {
|
||||||
const chartRef = useRef<HTMLDivElement>(null)
|
|
||||||
const yAxisWidth = useYaxisWidth(chartRef)
|
|
||||||
const chartTime = useStore($chartTime)
|
const chartTime = useStore($chartTime)
|
||||||
|
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
|
||||||
|
|
||||||
/** Format temperature data for chart and assign colors */
|
/** Format temperature data for chart and assign colors */
|
||||||
const newChartData = useMemo(() => {
|
const newChartData = useMemo(() => {
|
||||||
@@ -55,15 +54,13 @@ export default function TemperatureChart({
|
|||||||
return chartData
|
return chartData
|
||||||
}, [systemData])
|
}, [systemData])
|
||||||
|
|
||||||
const yAxisSet = useMemo(() => yAxisWidth !== 180, [yAxisWidth])
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={chartRef}>
|
<div>
|
||||||
{/* {!yAxisSet && <Spinner />} */}
|
{/* {!yAxisSet && <Spinner />} */}
|
||||||
<ChartContainer
|
<ChartContainer
|
||||||
config={{}}
|
config={{}}
|
||||||
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
className={cn('h-full w-full absolute aspect-auto bg-card opacity-0 transition-opacity', {
|
||||||
'opacity-100': yAxisSet,
|
'opacity-100': yAxisWidth,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<LineChart
|
<LineChart
|
||||||
@@ -80,10 +77,12 @@ export default function TemperatureChart({
|
|||||||
<YAxis
|
<YAxis
|
||||||
className="tracking-tighter"
|
className="tracking-tighter"
|
||||||
width={yAxisWidth}
|
width={yAxisWidth}
|
||||||
tickFormatter={(value) => toFixedWithoutTrailingZeros(value, 2)}
|
tickFormatter={(value) => {
|
||||||
|
const val = toFixedWithoutTrailingZeros(value, 2)
|
||||||
|
return updateYAxisWidth(val + ' °C')
|
||||||
|
}}
|
||||||
tickLine={false}
|
tickLine={false}
|
||||||
axisLine={false}
|
axisLine={false}
|
||||||
unit={' °C'}
|
|
||||||
/>
|
/>
|
||||||
<XAxis
|
<XAxis
|
||||||
dataKey="created"
|
dataKey="created"
|
||||||
|
@@ -88,5 +88,5 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.recharts-yAxis {
|
.recharts-yAxis {
|
||||||
font-variant-numeric: tabular-nums;
|
@apply tabular-nums;
|
||||||
}
|
}
|
||||||
|
@@ -195,22 +195,27 @@ export const chartTimeData: ChartTimeData = {
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Hacky solution to set the correct width of the yAxis in recharts */
|
/** Sets the correct width of the y axis in recharts based on the longest label */
|
||||||
export function useYaxisWidth(chartRef: React.RefObject<HTMLDivElement>) {
|
export function useYAxisWidth() {
|
||||||
const [yAxisWidth, setYAxisWidth] = useState(180)
|
const [yAxisWidth, setYAxisWidth] = useState(0)
|
||||||
useEffect(() => {
|
let maxChars = 0
|
||||||
let interval = setInterval(() => {
|
let timeout: Timer
|
||||||
// console.log('chartRef', chartRef.current)
|
function updateYAxisWidth(str: string) {
|
||||||
const yAxisElement = chartRef?.current?.querySelector('.yAxis')
|
if (str.length > maxChars) {
|
||||||
if (yAxisElement) {
|
maxChars = str.length
|
||||||
// console.log('yAxisElement', yAxisElement)
|
const div = document.createElement('div')
|
||||||
clearInterval(interval)
|
div.className = 'text-xs tabular-nums tracking-tighter table sr-only'
|
||||||
setYAxisWidth(yAxisElement.getBoundingClientRect().width + 24)
|
div.innerHTML = str
|
||||||
}
|
clearTimeout(timeout)
|
||||||
}, 16)
|
timeout = setTimeout(() => {
|
||||||
return () => clearInterval(interval)
|
document.body.appendChild(div)
|
||||||
}, [])
|
setYAxisWidth(div.offsetWidth + 24)
|
||||||
return yAxisWidth
|
document.body.removeChild(div)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return str
|
||||||
|
}
|
||||||
|
return { yAxisWidth, updateYAxisWidth }
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useClampedIsInViewport(options: HookOptions): [boolean | null, CallbackRef] {
|
export function useClampedIsInViewport(options: HookOptions): [boolean | null, CallbackRef] {
|
||||||
|
@@ -1,5 +1,5 @@
|
|||||||
import './index.css'
|
import './index.css'
|
||||||
import { Suspense, lazy, useEffect } from 'react'
|
import { Suspense, lazy, useEffect, StrictMode } from 'react'
|
||||||
import ReactDOM from 'react-dom/client'
|
import ReactDOM from 'react-dom/client'
|
||||||
import Home from './components/routes/home.tsx'
|
import Home from './components/routes/home.tsx'
|
||||||
import { ThemeProvider } from './components/theme-provider.tsx'
|
import { ThemeProvider } from './components/theme-provider.tsx'
|
||||||
@@ -218,10 +218,10 @@ const Layout = () => {
|
|||||||
ReactDOM.createRoot(document.getElementById('app')!).render(
|
ReactDOM.createRoot(document.getElementById('app')!).render(
|
||||||
// strict mode in dev mounts / unmounts components twice
|
// strict mode in dev mounts / unmounts components twice
|
||||||
// and breaks the clipboard dialog
|
// and breaks the clipboard dialog
|
||||||
//<React.StrictMode>
|
//<StrictMode>
|
||||||
<ThemeProvider>
|
<ThemeProvider>
|
||||||
<Layout />
|
<Layout />
|
||||||
<Toaster />
|
<Toaster />
|
||||||
</ThemeProvider>
|
</ThemeProvider>
|
||||||
//</React.StrictMode>
|
//</StrictMode>
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user