Skip to content

Commit 2bcf0f0

Browse files
committed
fix: address chart review feedback
1 parent 8f65487 commit 2bcf0f0

5 files changed

Lines changed: 72 additions & 15 deletions

File tree

web/src/components/case-config.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -280,8 +280,12 @@ function useMediaQuery(query: string) {
280280
const media = matchMedia(query)
281281
const onChange = () => setMatches(media.matches)
282282
onChange()
283-
media.addEventListener('change', onChange)
284-
return () => media.removeEventListener('change', onChange)
283+
if (media.addEventListener) {
284+
media.addEventListener('change', onChange)
285+
return () => media.removeEventListener('change', onChange)
286+
}
287+
media.addListener(onChange)
288+
return () => media.removeListener(onChange)
285289
}, [query])
286290

287291
return matches

web/src/components/case-runner.tsx

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import React, { useContext, useRef, useState } from 'react'
1+
import React, { useContext, useEffect, useRef, useState } from 'react'
22
import { Button } from '@blueprintjs/core'
33
import { ChannelsContext, ConfigContext, I18nContext } from '../context'
44
import { css } from '@emotion/react'
55
import { SpeedIndicator } from './speed-indicator'
66
import { RateCurve } from './rate-curve'
77
import { Subscription, zip } from 'rxjs'
88

9+
const MAX_RATE_POINTS = 60
10+
11+
function appendRate(rates: number[], rate: number) {
12+
return [...rates.slice(-(MAX_RATE_POINTS - 1)), rate]
13+
}
14+
915
export function CaseRunner(props: { name: 'upload' | 'download'; title: string }) {
1016
const createChannels = useContext(ChannelsContext)
1117
const t = useContext(I18nContext)
@@ -14,18 +20,34 @@ export function CaseRunner(props: { name: 'upload' | 'download'; title: string }
1420
const [rates, setRates] = useState<number[]>([])
1521
const [running, setRunning] = useState(false)
1622
const sub = useRef<Subscription | null>(null)
23+
const runIdRef = useRef(0)
24+
25+
useEffect(
26+
() => () => {
27+
runIdRef.current += 1
28+
sub.current?.unsubscribe()
29+
sub.current = null
30+
},
31+
[],
32+
)
1733

1834
const onClick = async () => {
1935
if (running) {
36+
runIdRef.current += 1
2037
sub.current?.unsubscribe()
2138
sub.current = null
2239
setRunning(false)
2340
return
2441
}
42+
const runId = runIdRef.current + 1
43+
runIdRef.current = runId
2544
setRate(-1)
2645
setRates([])
2746
setRunning(true)
2847
const channels = await createChannels()
48+
if (runIdRef.current !== runId) {
49+
return
50+
}
2951
sub.current = zip(
3052
...channels.map((channel) =>
3153
channel.observe(props.name, {
@@ -37,18 +59,25 @@ export function CaseRunner(props: { name: 'upload' | 'download'; title: string }
3759
),
3860
).subscribe({
3961
next(rate) {
62+
if (runIdRef.current !== runId) {
63+
return
64+
}
4065
const nextRate = rate.reduce((a, b) => a + b, 0)
4166
setRate(nextRate)
42-
setRates((prevRates) => [...prevRates, nextRate])
67+
setRates((prevRates) => appendRate(prevRates, nextRate))
4368
},
4469
error(e) {
4570
console.error(e)
46-
setRunning(false)
47-
sub.current = null
71+
if (runIdRef.current === runId) {
72+
setRunning(false)
73+
sub.current = null
74+
}
4875
},
4976
complete() {
50-
setRunning(false)
51-
sub.current = null
77+
if (runIdRef.current === runId) {
78+
setRunning(false)
79+
sub.current = null
80+
}
5281
},
5382
})
5483
}

web/src/components/rate-curve.tsx

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,11 @@ export const RateCurve = memo(function RateCurve({
4646
}, [maxRate, points])
4747
const currentRate = points[points.length - 1]
4848
const strokeColor = running ? '#2f8f46' : '#137cbd'
49-
const gradientId = `rate-curve-${id.replace(/:/g, '')}`
49+
const sanitizedId = id.replace(/:/g, '')
50+
const gradientId = `rate-curve-${sanitizedId}`
51+
const titleId = `rate-curve-title-${sanitizedId}`
52+
const currentLabel = points.length ? formatter(currentRate) : '--'
53+
const peakLabel = maxRate > 0 ? formatter(maxRate) : '--'
5054

5155
return (
5256
<div
@@ -61,13 +65,17 @@ export const RateCurve = memo(function RateCurve({
6165
<svg
6266
viewBox={`0 0 ${WIDTH} ${HEIGHT}`}
6367
role='img'
68+
aria-labelledby={titleId}
6469
css={css`
6570
display: block;
6671
width: 100%;
6772
height: 116px;
6873
color: currentColor;
6974
`}
7075
>
76+
<title id={titleId}>
77+
{t('chart.title')}: {currentLabel}, {t('chart.peak')} {peakLabel}
78+
</title>
7179
<defs>
7280
<linearGradient id={gradientId} x1='0' x2='0' y1='0' y2='1'>
7381
<stop offset='0%' stopColor={strokeColor} stopOpacity='0.28' />
@@ -140,15 +148,15 @@ export const RateCurve = memo(function RateCurve({
140148
font-weight: 600;
141149
`}
142150
>
143-
{points.length ? formatter(currentRate) : '--'}
151+
{currentLabel}
144152
</span>
145153
<span
146154
css={css`
147155
min-width: 0;
148156
opacity: 0.68;
149157
`}
150158
>
151-
{t('chart.peak')} {maxRate > 0 ? formatter(maxRate) : '--'}
159+
{t('chart.peak')} {peakLabel}
152160
</span>
153161
</div>
154162
</div>

web/src/components/run-case-once.tsx

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { SpeedIndicator } from './speed-indicator'
22
import { RateCurve } from './rate-curve'
33
import styled from '@emotion/styled'
4-
import { useState, useContext, useRef } from 'react'
4+
import { useState, useContext, useEffect, useRef } from 'react'
55
import { useRates } from '../hooks'
66
import { ChannelsContext, ConfigContext, I18nContext } from '../context'
77
import { zip, interval, Observable, Subscription } from 'rxjs'
@@ -40,6 +40,11 @@ type ChartItem = {
4040
}
4141

4242
const chartKeys: ChartKey[] = ['ping', 'download', 'upload']
43+
const MAX_RATE_POINTS = 60
44+
45+
function appendRate(rates: number[], rate: number) {
46+
return [...rates.slice(-(MAX_RATE_POINTS - 1)), rate]
47+
}
4348

4449
enum RunningStep {
4550
NONE = 1,
@@ -64,6 +69,15 @@ export function RunCaseOnce() {
6469
const t = useContext(I18nContext)
6570
const { duration, parallel, packCount, unit } = useContext(ConfigContext)
6671

72+
useEffect(
73+
() => () => {
74+
runIdRef.current += 1
75+
sub.current?.unsubscribe()
76+
sub.current = null
77+
},
78+
[],
79+
)
80+
6781
const waitObservable = <T,>(observer: Observable<T>, onNext: (value: T) => void, runId: number) =>
6882
new Promise<void>((resolve, reject) => {
6983
let settled = false
@@ -116,7 +130,7 @@ export function RunCaseOnce() {
116130
),
117131
(v) => {
118132
pushTTL(v)
119-
setPingRates((prevRates) => [...prevRates, v])
133+
setPingRates((prevRates) => appendRate(prevRates, v))
120134
},
121135
runId,
122136
)
@@ -144,7 +158,7 @@ export function RunCaseOnce() {
144158
(v) => {
145159
const nextRate = v.reduce((a, b) => a + b, 0)
146160
setDlRate(nextRate)
147-
setDlRates((prevRates) => [...prevRates, nextRate])
161+
setDlRates((prevRates) => appendRate(prevRates, nextRate))
148162
},
149163
runId,
150164
)
@@ -169,7 +183,7 @@ export function RunCaseOnce() {
169183
(v) => {
170184
const nextRate = v.reduce((a, b) => a + b, 0)
171185
setUlRate(nextRate)
172-
setUlRates((prevRates) => [...prevRates, nextRate])
186+
setUlRates((prevRates) => appendRate(prevRates, nextRate))
173187
},
174188
runId,
175189
)

web/src/i18n.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export const messages = {
1010
'action.restart': 'Restart',
1111
'action.previous': 'Previous item',
1212
'action.next': 'Next item',
13+
'chart.title': 'Rate chart',
1314
'chart.peak': 'Peak',
1415
'state.waiting': 'Waiting...',
1516
'state.downloading': 'Downloading',
@@ -47,6 +48,7 @@ export const messages = {
4748
'action.restart': '重新开始',
4849
'action.previous': '上一项',
4950
'action.next': '下一项',
51+
'chart.title': '速率图表',
5052
'chart.peak': '峰值',
5153
'state.waiting': '等待中...',
5254
'state.downloading': '下载中',

0 commit comments

Comments
 (0)