Add temperature chart filtering (#430)

- Refactored ContainerFilterBar to accept a dynamic store prop.
- Updated filtering logic in ContainerChart to be case-insensitive.
This commit is contained in:
henrygd
2025-04-25 19:19:19 -04:00
parent 38f2ba3984
commit bda06f30b3
5 changed files with 43 additions and 21 deletions

View File

@@ -170,7 +170,7 @@ export default memo(function ContainerChart({
content={<ChartTooltipContent filter={filter} contentFormatter={toolTipFormatter} />}
/>
{Object.keys(chartConfig).map((key) => {
const filtered = filter && !key.includes(filter)
const filtered = filter && !key.toLowerCase().includes(filter.toLowerCase())
let fillOpacity = filtered ? 0.05 : 0.4
let strokeOpacity = filtered ? 0.1 : 1
return (

View File

@@ -18,8 +18,11 @@ import {
} from "@/lib/utils"
import { ChartData } from "@/types"
import { memo, useMemo } from "react"
import { $temperatureFilter } from "@/lib/stores"
import { useStore } from "@nanostores/react"
export default memo(function TemperatureChart({ chartData }: { chartData: ChartData }) {
const filter = useStore($temperatureFilter)
const { yAxisWidth, updateYAxisWidth } = useYAxisWidth()
if (chartData.systemStats.length === 0) {
@@ -86,22 +89,28 @@ export default memo(function TemperatureChart({ chartData }: { chartData: ChartD
<ChartTooltipContent
labelFormatter={(_, data) => formatShortDate(data[0].payload.created)}
contentFormatter={(item) => decimalString(item.value) + " °C"}
// indicator="line"
filter={filter}
/>
}
/>
{colors.map((key) => (
<Line
key={key}
dataKey={key}
name={key}
type="monotoneX"
dot={false}
strokeWidth={1.5}
stroke={newChartData.colors[key]}
isAnimationActive={false}
/>
))}
{colors.map((key) => {
const filtered = filter && !key.toLowerCase().includes(filter.toLowerCase())
let strokeOpacity = filtered ? 0.1 : 1
return (
<Line
key={key}
dataKey={key}
name={key}
type="monotoneX"
dot={false}
strokeWidth={1.5}
stroke={newChartData.colors[key]}
strokeOpacity={strokeOpacity}
activeDot={{ opacity: filtered ? 0 : 1 }}
isAnimationActive={false}
/>
)
})}
{colors.length < 12 && <ChartLegend content={<ChartLegendContent />} />}
</LineChart>
</ChartContainer>

View File

@@ -1,6 +1,15 @@
import { t } from "@lingui/core/macro"
import { Plural, Trans } from "@lingui/react/macro"
import { $systems, pb, $chartTime, $containerFilter, $userSettings, $direction, $maxValues } from "@/lib/stores"
import {
$systems,
pb,
$chartTime,
$containerFilter,
$userSettings,
$direction,
$maxValues,
$temperatureFilter,
} from "@/lib/stores"
import { ChartData, ChartTimes, ContainerStatsRecord, GPUData, SystemRecord, SystemStatsRecord } from "@/types"
import { ChartType, Os } from "@/lib/enums"
import React, { lazy, memo, useCallback, useEffect, useMemo, useRef, useState } from "react"
@@ -219,7 +228,7 @@ export default function SystemDetail({ name }: { name: string }) {
cache.set(cs_cache_key, containerData)
}
if (containerData.length) {
!containerFilterBar && setContainerFilterBar(<ContainerFilterBar />)
!containerFilterBar && setContainerFilterBar(<FilterBar />)
} else if (containerFilterBar) {
setContainerFilterBar(null)
}
@@ -557,6 +566,7 @@ export default function SystemDetail({ name }: { name: string }) {
grid={grid}
title={t`Temperature`}
description={t`Temperatures of system sensors`}
cornerEl={<FilterBar store={$temperatureFilter} />}
>
<TemperatureChart chartData={chartData} />
</ChartCard>
@@ -654,12 +664,12 @@ export default function SystemDetail({ name }: { name: string }) {
)
}
function ContainerFilterBar() {
const containerFilter = useStore($containerFilter)
function FilterBar({ store = $containerFilter }: { store?: typeof $containerFilter }) {
const containerFilter = useStore(store)
const { t } = useLingui()
const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
$containerFilter.set(e.target.value)
store.set(e.target.value)
}, [])
return (
@@ -672,7 +682,7 @@ function ContainerFilterBar() {
size="icon"
aria-label="Clear"
className="absolute right-1 top-1/2 -translate-y-1/2 h-7 w-7 text-gray-500 hover:text-gray-900 dark:text-gray-400 dark:hover:text-gray-100"
onClick={() => $containerFilter.set("")}
onClick={() => store.set("")}
>
<XIcon className="h-4 w-4" />
</Button>

View File

@@ -129,7 +129,7 @@ const ChartTooltipContent = React.forwardRef<
React.useMemo(() => {
if (filter) {
payload = payload?.filter((item) => (item.name as string)?.includes(filter))
payload = payload?.filter((item) => (item.name as string)?.toLowerCase().includes(filter.toLowerCase()))
}
if (itemSorter) {
// @ts-ignore

View File

@@ -38,6 +38,9 @@ $userSettings.subscribe((value) => {
/** Container chart filter */
export const $containerFilter = atom("")
/** Temperature chart filter */
export const $temperatureFilter = atom("")
/** Fallback copy to clipboard dialog content */
export const $copyContent = atom("")