import { t } from "@lingui/core/macro"
import { useStore } from "@nanostores/react"
import { MoreHorizontalIcon } from "lucide-react"
import { memo, useRef, useState } from "react"
import AreaChartDefault from "@/components/charts/area-chart"
import ChartTimeSelect from "@/components/charts/chart-time-select"
import { Button } from "@/components/ui/button"
import { Sheet, SheetContent, SheetTrigger } from "@/components/ui/sheet"
import { DialogTitle } from "@/components/ui/dialog"
import { $userSettings } from "@/lib/stores"
import { decimalString, formatBytes, toFixedFloat } from "@/lib/utils"
import { ChartCard, SelectAvgMax } from "@/components/routes/system/chart-card"
import type { SystemData } from "@/components/routes/system/use-system-data"
import { diskDataFns, DiskUtilizationChart } from "./charts/disk-charts"
import { pinnedAxisDomain } from "@/components/ui/chart"
export default memo(function DiskIOSheet({
systemData,
extraFsName,
title,
description,
}: {
systemData: SystemData
extraFsName?: string
title: string
description: string
}) {
const { chartData, grid, dataEmpty, showMax, maxValues, isLongerChart } = systemData
const userSettings = useStore($userSettings)
const [sheetOpen, setSheetOpen] = useState(false)
const hasOpened = useRef(false)
if (sheetOpen && !hasOpened.current) {
hasOpened.current = true
}
// throughput functions, with extra fs variants if needed
let readFn = showMax ? diskDataFns.readMax : diskDataFns.read
let writeFn = showMax ? diskDataFns.writeMax : diskDataFns.write
if (extraFsName) {
readFn = showMax ? diskDataFns.extraReadMax(extraFsName) : diskDataFns.extraRead(extraFsName)
writeFn = showMax ? diskDataFns.extraWriteMax(extraFsName) : diskDataFns.extraWrite(extraFsName)
}
// read and write time functions, with extra fs variants if needed
let readTimeFn = showMax ? diskDataFns.readTimeMax : diskDataFns.readTime
let writeTimeFn = showMax ? diskDataFns.writeTimeMax : diskDataFns.writeTime
if (extraFsName) {
readTimeFn = showMax ? diskDataFns.extraReadTimeMax(extraFsName) : diskDataFns.extraReadTime(extraFsName)
writeTimeFn = showMax ? diskDataFns.extraWriteTimeMax(extraFsName) : diskDataFns.extraWriteTime(extraFsName)
}
// I/O await functions, with extra fs variants if needed
let rAwaitFn = showMax ? diskDataFns.rAwaitMax : diskDataFns.rAwait
let wAwaitFn = showMax ? diskDataFns.wAwaitMax : diskDataFns.wAwait
if (extraFsName) {
rAwaitFn = showMax ? diskDataFns.extraRAwaitMax(extraFsName) : diskDataFns.extraRAwait(extraFsName)
wAwaitFn = showMax ? diskDataFns.extraWAwaitMax(extraFsName) : diskDataFns.extraWAwait(extraFsName)
}
// weighted I/O function, with extra fs variant if needed
let weightedIOFn = showMax ? diskDataFns.weightedIOMax : diskDataFns.weightedIO
if (extraFsName) {
weightedIOFn = showMax ? diskDataFns.extraWeightedIOMax(extraFsName) : diskDataFns.extraWeightedIO(extraFsName)
}
// check for availability of I/O metrics
let hasUtilization = false
let hasAwait = false
let hasWeightedIO = false
for (const record of chartData.systemStats ?? []) {
const dios = record.stats?.dios
if ((dios?.at(2) ?? 0) > 0) hasUtilization = true
if ((dios?.at(3) ?? 0) > 0) hasAwait = true
if ((dios?.at(5) ?? 0) > 0) hasWeightedIO = true
if (hasUtilization && hasAwait && hasWeightedIO) {
break
}
}
const maxValSelect = isLongerChart ? : null
const chartProps = { syncId: "io" }
const queueDepthTranslation = t({ message: "Queue Depth", context: "Disk I/O average queue depth" })
return (
{title}
{hasOpened.current && (
a.order - b.order}
reverseStackOrder={true}
dataPoints={[
{
label: t`Write`,
dataKey: writeFn,
color: 3,
opacity: 0.4,
stackId: 0,
order: 0,
},
{
label: t`Read`,
dataKey: readFn,
color: 1,
opacity: 0.4,
stackId: 0,
order: 1,
},
]}
tickFormatter={(val) => {
const { value, unit } = formatBytes(val, true, userSettings.unitDisk, false)
return `${toFixedFloat(value, value >= 10 ? 0 : 1)} ${unit}`
}}
contentFormatter={({ value }) => {
const { value: convertedValue, unit } = formatBytes(value, true, userSettings.unitDisk, false)
return `${decimalString(convertedValue, convertedValue >= 100 ? 1 : 2)} ${unit}`
}}
/>
{hasUtilization && }
`${toFixedFloat(val, 2)}%`}
contentFormatter={({ value }) => `${decimalString(value)}%`}
maxToggled={showMax}
chartProps={chartProps}
showTotal={true}
itemSorter={(a, b) => a.order - b.order}
reverseStackOrder={true}
dataPoints={[
{
label: t`Write`,
dataKey: writeTimeFn,
color: 3,
opacity: 0.4,
stackId: 0,
order: 0,
},
{
label: t`Read`,
dataKey: readTimeFn,
color: 1,
opacity: 0.4,
stackId: 0,
order: 1,
},
]}
/>
{hasWeightedIO && (
`${toFixedFloat(val, 2)}`}
contentFormatter={({ value }) => decimalString(value, value < 10 ? 3 : 2)}
maxToggled={showMax}
chartProps={chartProps}
dataPoints={[
{
label: queueDepthTranslation,
dataKey: weightedIOFn,
color: 1,
opacity: 0.4,
},
]}
/>
)}
{hasAwait && (
`${toFixedFloat(val, 2)} ms`}
contentFormatter={({ value }) => `${decimalString(value)} ms`}
maxToggled={showMax}
chartProps={chartProps}
dataPoints={[
{
label: t`Write`,
dataKey: wAwaitFn,
color: 3,
opacity: 0.3,
},
{
label: t`Read`,
dataKey: rAwaitFn,
color: 1,
opacity: 0.3,
},
]}
/>
)}
)}
)
})