Skip to content

Commit 2b10d3d

Browse files
committed
use new chart style on system and silo utilization
1 parent 7bf064d commit 2b10d3d

5 files changed

Lines changed: 72 additions & 77 deletions

File tree

app/components/SystemMetric.tsx

Lines changed: 24 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,15 @@ import {
1414
type SystemMetricName,
1515
} from '@oxide/api'
1616

17-
import { Spinner } from '~/ui/lib/Spinner'
18-
19-
import { TimeSeriesChart } from './TimeSeriesChart'
17+
import { ChartContainer, ChartHeader, TimeSeriesChart } from './TimeSeriesChart'
2018

2119
// The difference between system metric and silo metric is
2220
// 1. different endpoints
2321
// 2. silo metric doesn't have capacity
2422

2523
type MetricProps = {
2624
title: string
27-
unit?: string
25+
unit: string
2826
startTime: Date
2927
endTime: Date
3028
metricName: SystemMetricName
@@ -93,23 +91,17 @@ export function SiloMetric({
9391
// in the tooltip. could be just once on the end of the x-axis like GCP
9492

9593
return (
96-
<div>
97-
<h2 className="flex items-center gap-1.5 px-3 text-mono-sm text-default">
98-
{title} {unit && <span className="text-tertiary">({unit})</span>}{' '}
99-
{(inRange.isPending || beforeStart.isPending) && <Spinner />}
100-
</h2>
101-
{/* TODO: proper skeleton for empty chart */}
102-
<div className="mt-3 h-[300px]">
103-
<TimeSeriesChart
104-
data={data}
105-
title={title}
106-
interpolation="stepAfter"
107-
startTime={startTime}
108-
endTime={endTime}
109-
unit={unit !== 'count' ? unit : undefined}
110-
/>
111-
</div>
112-
</div>
94+
<ChartContainer>
95+
<ChartHeader title={title} label={`(${unit})`} />
96+
<TimeSeriesChart
97+
data={data}
98+
title={title}
99+
interpolation="stepAfter"
100+
startTime={startTime}
101+
endTime={endTime}
102+
unit={unit !== 'Count' ? unit : undefined}
103+
/>
104+
</ChartContainer>
113105
)
114106
}
115107

@@ -167,22 +159,16 @@ export function SystemMetric({
167159
// in the tooltip. could be just once on the end of the x-axis like GCP
168160

169161
return (
170-
<div>
171-
<h2 className="flex items-center gap-1.5 px-3 text-mono-sm text-default">
172-
{title} {unit && <span className="text-tertiary">({unit})</span>}{' '}
173-
{(inRange.isPending || beforeStart.isPending) && <Spinner />}
174-
</h2>
175-
{/* TODO: proper skeleton for empty chart */}
176-
<div className="mt-3 h-[300px]">
177-
<TimeSeriesChart
178-
data={data}
179-
title={title}
180-
interpolation="stepAfter"
181-
startTime={startTime}
182-
endTime={endTime}
183-
unit={unit !== 'count' ? unit : undefined}
184-
/>
185-
</div>
186-
</div>
162+
<ChartContainer>
163+
<ChartHeader title={title} label={`(${unit})`} />
164+
<TimeSeriesChart
165+
data={data}
166+
title={title}
167+
interpolation="stepAfter"
168+
startTime={startTime}
169+
endTime={endTime}
170+
unit={unit !== 'Count' ? unit : undefined}
171+
/>
172+
</ChartContainer>
187173
)
188174
}

app/components/TimeSeriesChart.tsx

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
*/
88
import cn from 'classnames'
99
import { format } from 'date-fns'
10-
import { useMemo, type ReactNode } from 'react'
10+
import React, { useMemo, type ReactNode } from 'react'
1111
import {
1212
Area,
1313
AreaChart,
@@ -22,6 +22,8 @@ import type { TooltipProps } from 'recharts/types/component/Tooltip'
2222
import type { ChartDatum } from '@oxide/api'
2323
import { Error12Icon } from '@oxide/design-system/icons/react'
2424

25+
import { classed } from '~/util/classed'
26+
2527
// Recharts's built-in ticks behavior is useless and probably broken
2628
/**
2729
* Split the data into n evenly spaced ticks, with one at the left end and one a
@@ -115,7 +117,6 @@ type TimeSeriesChartProps = {
115117
endTime: Date
116118
unit?: string
117119
yAxisTickFormatter?: (val: number) => string
118-
hasBorder?: boolean
119120
hasError?: boolean
120121
}
121122

@@ -164,15 +165,13 @@ const SkeletonMetric = ({
164165
)
165166

166167
export function TimeSeriesChart({
167-
className,
168168
data: rawData,
169169
title,
170170
interpolation = 'linear',
171171
startTime,
172172
endTime,
173173
unit,
174174
yAxisTickFormatter = (val) => val.toLocaleString(),
175-
hasBorder = true,
176175
hasError = false,
177176
}: TimeSeriesChartProps) {
178177
// We use the largest data point +20% for the graph scale. !rawData doesn't
@@ -206,32 +205,28 @@ export function TimeSeriesChart({
206205
// re-render on every render of the parent when the data is undefined
207206
const data = useMemo(() => rawData || [], [rawData])
208207

209-
const wrapperClass = cn(className, hasBorder && 'rounded-lg border border-default')
210-
211208
if (hasError) {
212209
return (
213-
<SkeletonMetric className={wrapperClass}>
210+
<SkeletonMetric>
214211
<MetricsError />
215212
</SkeletonMetric>
216213
)
217214
}
218215

219216
if (!data || data.length === 0) {
220217
return (
221-
<SkeletonMetric shimmer className={wrapperClass}>
218+
<SkeletonMetric shimmer>
222219
<MetricsLoadingIndicator />
223220
</SkeletonMetric>
224221
)
225222
}
226223

227-
const margin = { top: 0, right: hasBorder ? 16 : 0, bottom: 0, left: 0 }
228-
229224
// ResponsiveContainer has default height and width of 100%
230225
// https://recharts.org/en-US/api/ResponsiveContainer
231226
return (
232-
<div className="h-[300px] w-full">
233-
<ResponsiveContainer className={wrapperClass}>
234-
<AreaChart data={data} margin={margin}>
227+
<div className="px-5 pb-5 pt-8">
228+
<ResponsiveContainer height={300}>
229+
<AreaChart data={data} margin={{ top: 0, right: 0, bottom: 0, left: 0 }}>
235230
<CartesianGrid stroke={GRID_GRAY} vertical={false} />
236231
<XAxis
237232
axisLine={{ stroke: GRID_GRAY }}
@@ -314,3 +309,27 @@ const MetricsError = () => (
314309
/>
315310
</>
316311
)
312+
313+
export const ChartContainer = classed.div`flex w-full grow flex-col rounded-lg border border-default`
314+
315+
type ChartHeaderProps = {
316+
title: string
317+
label: string
318+
description?: string
319+
children?: React.ReactNode
320+
}
321+
322+
export function ChartHeader({ title, label, description, children }: ChartHeaderProps) {
323+
return (
324+
<div className="flex items-center justify-between border-b px-5 pb-4 pt-5 border-secondary">
325+
<div>
326+
<h2 className="flex items-baseline gap-1.5">
327+
<div className="text-sans-semi-lg">{title}</div>
328+
<div className="text-sans-md text-secondary">{label}</div>
329+
</h2>
330+
<div className="mt-0.5 text-sans-md text-secondary">{description}</div>
331+
</div>
332+
{children}
333+
</div>
334+
)
335+
}

app/components/oxql-metrics/OxqlMetric.tsx

Lines changed: 14 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import * as Dropdown from '~/ui/lib/DropdownMenu'
2525
import { classed } from '~/util/classed'
2626
import { links } from '~/util/links'
2727

28-
import { TimeSeriesChart } from '../TimeSeriesChart'
28+
import { ChartContainer, ChartHeader, TimeSeriesChart } from '../TimeSeriesChart'
2929
import { HighlightedOxqlQuery, toOxqlStr } from './HighlightedOxqlQuery'
3030
import {
3131
composeOxqlData,
@@ -77,15 +77,8 @@ export function OxqlMetric({ title, description, unit, ...queryObj }: OxqlMetric
7777
const [modalOpen, setModalOpen] = useState(false)
7878

7979
return (
80-
<div className="flex w-full grow flex-col rounded-lg border border-default">
81-
<div className="flex items-center justify-between border-b px-5 pb-4 pt-5 border-secondary">
82-
<div>
83-
<h2 className="flex items-baseline gap-1.5">
84-
<div className="text-sans-semi-lg">{title}</div>
85-
<div className="text-sans-md text-secondary">{label}</div>
86-
</h2>
87-
<div className="mt-0.5 text-sans-md text-secondary">{description}</div>
88-
</div>
80+
<ChartContainer>
81+
<ChartHeader title={title} label={label} description={description}>
8982
<MoreActionsMenu label="Instance actions" isSmall>
9083
<Dropdown.LinkItem to={links.oxqlSchemaDocs(queryObj.metricName)}>
9184
About this metric
@@ -102,20 +95,17 @@ export function OxqlMetric({ title, description, unit, ...queryObj }: OxqlMetric
10295
>
10396
<HighlightedOxqlQuery {...queryObj} />
10497
</CopyCodeModal>
105-
</div>
106-
<div className="px-5 pb-5 pt-8">
107-
<TimeSeriesChart
108-
title={title}
109-
startTime={startTime}
110-
endTime={endTime}
111-
unit={unitForSet}
112-
data={data}
113-
yAxisTickFormatter={yAxisTickFormatter}
114-
hasBorder={false}
115-
hasError={!!error}
116-
/>
117-
</div>
118-
</div>
98+
</ChartHeader>
99+
<TimeSeriesChart
100+
title={title}
101+
startTime={startTime}
102+
endTime={endTime}
103+
unit={unitForSet}
104+
data={data}
105+
yAxisTickFormatter={yAxisTickFormatter}
106+
hasError={!!error}
107+
/>
108+
</ChartContainer>
119109
)
120110
}
121111

app/pages/SiloUtilizationPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ export default function SiloUtilizationPage() {
114114
{...commonProps}
115115
metricName="cpus_provisioned"
116116
title="CPU"
117-
unit="count"
117+
unit="Count"
118118
/>
119119
<SiloMetric
120120
{...commonProps}

app/pages/system/UtilizationPage.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -147,7 +147,7 @@ const MetricsTab = () => {
147147
{...commonProps}
148148
metricName="cpus_provisioned"
149149
title="CPU"
150-
unit="count"
150+
unit="Count"
151151
/>
152152
<SystemMetric
153153
{...commonProps}

0 commit comments

Comments
 (0)