Skip to content

Commit c93e94f

Browse files
committed
feat: add "1 Hour" and "24 Hours" time periods
1 parent 7783050 commit c93e94f

File tree

9 files changed

+80
-67
lines changed

9 files changed

+80
-67
lines changed

src/api.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,12 @@ export async function wfetch (resource: RequestInfo | URL, opts: RequestInit = {
2424
return response
2525
}
2626

27-
export async function fetchMetrics (filAddress: string, startDate: Date, endDate: Date) {
27+
export async function fetchMetrics (filAddress: string, startDate: Date, endDate: Date, step: string) {
2828
const url = new URL(METRICS_ORIGIN)
2929
url.searchParams.set('filAddress', filAddress)
3030
url.searchParams.set('startDate', `${startDate.getTime()}`)
3131
url.searchParams.set('endDate', `${endDate.getTime()}`)
32+
url.searchParams.set('step', step)
3233

3334
const res: MetricsResponse = await wfetch(url).then(r => r.json())
3435

src/api.types.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,10 +25,11 @@ export interface RequestInit extends globalThis.RequestInit {
2525
}
2626

2727
export enum TimePeriod {
28-
// DAY = '24 Hours',
28+
HOUR = '1 Hour',
29+
DAY = '24 Hours',
2930
WEEK = '7 Days',
3031
TWO_WEEK = '14 Days',
31-
MONTH = '30 Days',
32+
// MONTH = '30 Days',
3233
// TODO: Need to optimize db for 6 month query.
3334
// SIX_MONTH = '6 Months'
3435
}

src/chartjs-dayjs-adapter.ts

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,22 @@
11
// Copied from https://gitlab.com/mmillerbkg/chartjs-adapter-dayjs/-/blob/master/src/index.ts
22

33
import { _adapters } from 'chart.js'
4-
54
import dayjs, { QUnitType } from 'dayjs'
6-
75
import type { TimeUnit } from 'chart.js'
8-
96
// Needed to handle the custom parsing
107
import CustomParseFormat from 'dayjs/plugin/customParseFormat'
11-
128
// Needed to handle quarter format
139
import AdvancedFormat from 'dayjs/plugin/advancedFormat'
14-
1510
// Needed to handle adding/subtracting quarter
1611
import QuarterOfYear from 'dayjs/plugin/quarterOfYear'
17-
1812
// Needed to handle localization format
1913
import LocalizedFormat from 'dayjs/plugin/localizedFormat'
20-
2114
import isoWeek from 'dayjs/plugin/isoWeek'
2215

2316
dayjs.extend(AdvancedFormat)
24-
2517
dayjs.extend(QuarterOfYear)
26-
2718
dayjs.extend(LocalizedFormat)
28-
2919
dayjs.extend(CustomParseFormat)
30-
3120
dayjs.extend(isoWeek)
3221

3322
const FORMATS = {

src/dashboard/BandwidthChart.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import bytes from 'bytes'
2-
import dayjs from 'dayjs'
32
import { Line } from 'react-chartjs-2'
43

54
import { Metric } from '@/api.types'
@@ -11,7 +10,7 @@ interface BandwidthChartProps extends ChartProps {
1110
}
1211

1312
export default function BandwidthChart (props: BandwidthChartProps) {
14-
const { dateRange, metrics, isLoading } = props
13+
const { xScale, metrics, isLoading, spanGaps } = props
1514

1615
const options: ChartOptions<'line'> = {
1716
plugins: {
@@ -26,14 +25,7 @@ export default function BandwidthChart (props: BandwidthChartProps) {
2625
}
2726
},
2827
scales: {
29-
x: {
30-
type: 'time',
31-
time: {
32-
unit: 'day'
33-
},
34-
min: dateRange.startDate.getTime(),
35-
max: dayjs.utc(dateRange.endDate).subtract(1, 'day').valueOf()
36-
},
28+
x: xScale,
3729
y: {
3830
ticks: {
3931
callback: val => bytes(Number(val), { unitSeparator: ' ' })
@@ -46,7 +38,8 @@ export default function BandwidthChart (props: BandwidthChartProps) {
4638
labels: metrics.map(m => m.startTime),
4739
datasets: [
4840
{
49-
data: metrics.map(m => m.numBytes)
41+
data: metrics.map(m => m.numBytes),
42+
spanGaps
5043
}
5144
]
5245
}

src/dashboard/ChartContainer.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,9 @@ export interface ChartProps {
66
dateRange: {
77
startDate: Date
88
endDate: Date
9-
}
9+
},
10+
xScale: object,
11+
spanGaps: number
1012
}
1113

1214
export interface ChartContainerProps {

src/dashboard/Dashboard.tsx

Lines changed: 56 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import bytes from 'bytes'
2+
import dayjs from 'dayjs'
3+
import type { DurationUnitType } from 'dayjs/plugin/duration'
14
import { Dispatch, ReactNode, SetStateAction, useEffect, useState } from 'react'
25
import { useParams } from 'react-router-dom'
36

@@ -7,25 +10,62 @@ import { pastDateRange } from '@/date-utils'
710
import RequestsChart from './RequestsChart'
811
import BandwidthChart from './BandwidthChart'
912
import EarningsChart from './EarningsChart'
10-
import bytes from 'bytes'
1113

1214
interface OverviewProps {
1315
metricsRes: MetricsResponse
1416
address: string
1517
children?: ReactNode
1618
}
1719

18-
function periodToDateRange (period: TimePeriod) {
20+
function periodToDateOptions (period: TimePeriod) {
21+
let dateRange
22+
let step: DurationUnitType
23+
1924
switch (period) {
25+
case TimePeriod.HOUR:
26+
dateRange = pastDateRange('hour')
27+
step = 'minute'
28+
break
2029
case TimePeriod.WEEK:
21-
return pastDateRange('week')
30+
dateRange = pastDateRange('week')
31+
step = 'day'
32+
break
2233
case TimePeriod.TWO_WEEK:
23-
return pastDateRange('week', 2)
24-
case TimePeriod.MONTH:
25-
return pastDateRange('month')
26-
// case TimePeriod.SIX_MONTH:
27-
// return pastDateRange('month', 6)
34+
dateRange = pastDateRange('week', 2)
35+
step = 'day'
36+
break
37+
case TimePeriod.DAY:
38+
default:
39+
dateRange = pastDateRange('day')
40+
step = 'hour'
41+
break
42+
// case TimePeriod.MONTH:
43+
// dateRange = pastDateRange('month')
44+
// break
45+
}
46+
47+
return { dateRange, step }
48+
}
49+
50+
function createChartProps (
51+
dateRange: { startDate: Date, endDate: Date },
52+
unit: DurationUnitType,
53+
isLoading: boolean
54+
) {
55+
const xScale = {
56+
type: 'time',
57+
time: {
58+
unit
59+
},
60+
min: dateRange.startDate.getTime(),
61+
max: dateRange.endDate.getTime()
2862
}
63+
64+
// https://github.com/chartjs/Chart.js/pull/6993
65+
// Break the line chart when missing a data point.
66+
const spanGaps = dayjs.duration(1, unit).asMilliseconds()
67+
68+
return { dateRange, xScale, spanGaps, isLoading }
2969
}
3070

3171
function SelectTimePeriod (
@@ -87,12 +127,12 @@ function Dashboard () {
87127
] = useState<MetricsResponse>({ earnings: [], nodes: [], metrics: [] })
88128

89129
const [period, setPeriod] = useState<TimePeriod>(TimePeriod.WEEK)
90-
const dateRange = periodToDateRange(period)
130+
const { dateRange, step } = periodToDateOptions(period)
91131
const { startDate, endDate } = dateRange
92132

93-
// Don't update chart axes until data is fetched.
94-
// It looks weird if axes update immediately.
95-
const [chartDateRange, setChartDateRange] = useState(dateRange)
133+
// Don't update charts until data is fetched.
134+
// It looks weird if charts update immediately.
135+
const [chartOpts, setChartOpts] = useState({ dateRange, step })
96136

97137
const fetchData = async () => {
98138
if (!address) { return }
@@ -102,9 +142,9 @@ function Dashboard () {
102142
setError(null)
103143

104144
const metricsRes = await api.fetchMetrics(
105-
address, startDate, endDate)
145+
address, startDate, endDate, step)
106146
setMetricsRes(metricsRes)
107-
setChartDateRange(dateRange)
147+
setChartOpts({ dateRange, step })
108148
} catch (err) {
109149
if (err instanceof Error) {
110150
setError(err?.message ?? 'Error retrieving metrics.')
@@ -114,12 +154,10 @@ function Dashboard () {
114154
}
115155
}
116156

117-
useEffect(() => {
118-
fetchData()
119-
}, [address, startDate.getTime(), endDate.getTime()])
157+
useEffect(() => { fetchData() }, [address, period])
120158

121159
const { earnings, metrics } = metricsRes
122-
const chartProps = { dateRange: chartDateRange, isLoading }
160+
const chartProps = createChartProps(chartOpts.dateRange, chartOpts.step, isLoading)
123161

124162
return (
125163
<div className="flex-1 flex flex-col gap-4 mt-8">

src/dashboard/EarningsChart.tsx

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import dayjs from 'dayjs'
21
import { Line } from 'react-chartjs-2'
32

43
import { Earning } from '@/api.types'
@@ -10,7 +9,7 @@ interface EarningsChartProps extends ChartProps {
109
}
1110

1211
export default function EarningsChart (props: EarningsChartProps) {
13-
const { earnings, dateRange, isLoading } = props
12+
const { earnings, xScale, isLoading, spanGaps } = props
1413
const options: ChartOptions<'line'> = {
1514
plugins: {
1615
title: {
@@ -24,14 +23,7 @@ export default function EarningsChart (props: EarningsChartProps) {
2423
}
2524
},
2625
scales: {
27-
x: {
28-
type: 'time',
29-
time: {
30-
unit: 'day'
31-
},
32-
min: dateRange.startDate.getTime(),
33-
max: dayjs.utc(dateRange.endDate).subtract(1, 'day').valueOf()
34-
},
26+
x: xScale,
3527
y: {
3628
ticks: {
3729
callback: val => `${val} FIL`
@@ -45,7 +37,7 @@ export default function EarningsChart (props: EarningsChartProps) {
4537
datasets: [
4638
{
4739
data: earnings.map(e => e.filAmount),
48-
spanGaps: 1000 * 60 * 60 * 24 // 1 day,
40+
spanGaps
4941
}
5042
]
5143
}

src/dashboard/RequestsChart.tsx

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import dayjs from 'dayjs'
21
import { Line } from 'react-chartjs-2'
32

43
import { Metric } from '@/api.types'
@@ -10,7 +9,7 @@ interface RequestsChartProps extends ChartProps {
109
}
1110

1211
export default function RequestsChart (props: RequestsChartProps) {
13-
const { metrics, dateRange, isLoading } = props
12+
const { metrics, xScale, isLoading, spanGaps } = props
1413
const options: ChartOptions<'line'> = {
1514
plugins: {
1615
title: {
@@ -19,22 +18,16 @@ export default function RequestsChart (props: RequestsChartProps) {
1918
}
2019
},
2120
scales: {
22-
x: {
23-
type: 'time',
24-
time: {
25-
unit: 'day'
26-
},
27-
min: dateRange.startDate.getTime(),
28-
max: dayjs.utc(dateRange.endDate).subtract(1, 'day').valueOf()
29-
}
21+
x: xScale
3022
}
3123
}
3224

3325
const data = {
3426
labels: metrics.map(m => m.startTime),
3527
datasets: [
3628
{
37-
data: metrics.map(m => m.numRequests)
29+
data: metrics.map(m => m.numRequests),
30+
spanGaps
3831
}
3932
]
4033
}

src/date-utils.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,22 @@
66
// you must install dayjs.
77

88
import dayjs, { ManipulateType } from 'dayjs'
9+
import duration from 'dayjs/plugin/duration'
910
import utc from 'dayjs/plugin/utc'
1011

1112
if (!dayjs.prototype.utc) {
1213
dayjs.extend(utc)
1314
}
15+
if (!dayjs.prototype.duration) {
16+
dayjs.extend(duration)
17+
}
1418

1519
export const startOfToday = () => dayjs.utc().startOf('day').toDate()
1620

1721
export const endOfDay = (date: Date) => dayjs.utc(date).endOf('day').toDate()
1822

1923
export function pastDateRange (unit: ManipulateType = 'week', count = 1) {
20-
const endDateObj = dayjs.utc().add(1, 'day').startOf('day')
24+
const endDateObj = dayjs.utc().startOf('minute')
2125
const endDate = endDateObj.toDate()
2226
const startDate = endDateObj.subtract(count, unit).toDate()
2327

0 commit comments

Comments
 (0)