Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions app/api/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ export * from './client'
export * from './roles'
export * from './util'
export * from './__generated__/Api'
export { camelToSnake } from './__generated__/util'
// export * as ZVal from './__generated__/validate'

export type { ApiTypes }
Expand Down
51 changes: 31 additions & 20 deletions app/components/SystemMetric.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@
import { useQuery } from '@tanstack/react-query'
import { useMemo, useRef } from 'react'

import { api, q, synthesizeData, type ChartDatum, type SystemMetricName } from '@oxide/api'
import { api, q, synthesizeData, type SystemMetricName } from '@oxide/api'

import { ChartContainer, ChartHeader, TimeSeriesChart } from './TimeSeriesChart'
import {
ChartContainer,
ChartHeader,
TimeSeriesChart,
toChartSeries,
} from './TimeSeriesChart'

// The difference between system metric and silo metric is
// 1. different endpoints
Expand Down Expand Up @@ -66,17 +71,19 @@ export function SiloMetric({
)
)

const ref = useRef<ChartDatum[] | undefined>(undefined)
const ref = useRef(toChartSeries(undefined))
const isFetching = inRange.isFetching || beforeStart.isFetching
const data = useMemo(() => {
const { values, timestamps } = useMemo(() => {
// big old hack to avoid the graph flashing with weird data while either query is loading
if (isFetching) return ref.current
ref.current = synthesizeData(
inRange.data?.items,
beforeStart.data?.items,
startTime,
endTime,
valueTransform
ref.current = toChartSeries(
synthesizeData(
inRange.data?.items,
beforeStart.data?.items,
startTime,
endTime,
valueTransform
)
)
return ref.current
}, [inRange.data, beforeStart.data, startTime, endTime, valueTransform, isFetching])
Expand All @@ -88,7 +95,8 @@ export function SiloMetric({
<ChartContainer>
<ChartHeader title={title} label={`(${unit})`} />
<TimeSeriesChart
data={data}
timestamps={timestamps}
data={values}
title={title}
interpolation="stepAfter"
startTime={startTime}
Expand Down Expand Up @@ -135,17 +143,19 @@ export function SystemMetric({
)
)

const ref = useRef<ChartDatum[] | undefined>(undefined)
const ref = useRef(toChartSeries(undefined))
const isFetching = inRange.isFetching || beforeStart.isFetching
const data = useMemo(() => {
const { values, timestamps } = useMemo(() => {
// big old hack to avoid the graph flashing with weird data while either query is loading
if (isFetching) return ref.current
ref.current = synthesizeData(
inRange.data?.items,
beforeStart.data?.items,
startTime,
endTime,
valueTransform
ref.current = toChartSeries(
synthesizeData(
inRange.data?.items,
beforeStart.data?.items,
startTime,
endTime,
valueTransform
)
)
return ref.current
}, [inRange.data, beforeStart.data, startTime, endTime, valueTransform, isFetching])
Expand All @@ -157,7 +167,8 @@ export function SystemMetric({
<ChartContainer>
<ChartHeader title={title} label={`(${unit})`} />
<TimeSeriesChart
data={data}
data={values}
timestamps={timestamps}
title={title}
interpolation="stepAfter"
startTime={startTime}
Expand Down
25 changes: 17 additions & 8 deletions app/components/TimeSeriesChart.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ describe('safe redrawing', () => {
* "wrong" calls to redraw.
*/
const props = (formatter: (v: number) => string) => ({
data: [{ timestamp: 0, value: 10 }],
data: [[10]],
timestamps: [0],
title: 'CPU',
startTime: new Date(0),
endTime: new Date(3_600_000),
Expand Down Expand Up @@ -77,19 +78,27 @@ describe('safe redrawing', () => {
// uplot-react will do a deep comparison if the data reference changes to avoid rebuilding the
// chart, but it would be even better to skip that comparison by maintaining a reference
test('an unchanged data prop sends a stable reference down to uplot-react', () => {
const data = [
{ timestamp: 0, value: 10 },
{ timestamp: 1000, value: 20 },
]
const data = [[10, 20]]
const timestamps = [0, 1000]

dataPropsPassed.length = 0
const { rerender } = render(<TimeSeriesChart {...props((v) => `${v}%`)} data={data} />)
rerender(<TimeSeriesChart {...props((v) => `${v} pct`)} data={data} />)
const { rerender } = render(
<TimeSeriesChart {...props((v) => `${v}%`)} timestamps={timestamps} data={data} />
)
rerender(
<TimeSeriesChart {...props((v) => `${v} pct`)} timestamps={timestamps} data={data} />
)

expect(dataPropsPassed.length).toBeGreaterThan(1) // it re-rendered
expect(new Set(dataPropsPassed).size).toBe(1) // but every render passed the identical reference

rerender(<TimeSeriesChart {...props((v) => `${v}%`)} data={[...data]} />)
rerender(
<TimeSeriesChart
{...props((v) => `${v}%`)}
timestamps={timestamps}
data={[...data]}
/>
)
expect(new Set(dataPropsPassed).size).toBe(2) // unless the reference changes
})
})
Loading
Loading