web: group the line card rows by direction so each agent pair is named once
This commit is contained in:
1 parent
cfe6571db5
commit
35207a70ea
2 files changed
+51
-71
No files matched your search
@@ -62,68 +62,42 @@ export function LineStrips({ lineId, dialer, listener, range, m }: Props) {
|
||||
const lossDown = col('loss.down')
|
||||
const retransUp = col('tcp.retrans.up')
|
||||
const retransDown = col('tcp.retrans.down')
|
||||
const up = m['loss.up']
|
||||
const down = m['loss.down']
|
||||
const upText = up === null || up === undefined ? '丢包 —' : `${fmtPct(up)} 丢包`
|
||||
const downText = down === null || down === undefined ? '丢包 —' : `${fmtPct(down)} 丢包`
|
||||
const retransUpValue = m['tcp.retrans.up']
|
||||
const retransDownValue = m['tcp.retrans.down']
|
||||
const lossText = (v: number | null | undefined) => (v === null || v === undefined ? '丢包 —' : `${fmtPct(v)} 丢包`)
|
||||
const retransText = (v: number | null | undefined) => (v === null || v === undefined ? '重传 —' : `${fmtPct(v)} 重传`)
|
||||
const cellsOf = (values: (number | null)[]) => (s ? values : Array.from({ length: common.cells }, () => null))
|
||||
// 一个方向下的一行:协议名、数值徽标和质量点阵。
|
||||
const row = (id: string, proto: string, label: string, value: number | null | undefined, text: string, values: (number | null)[]) => (
|
||||
<div className="line-mini-row" key={id}>
|
||||
<div className="line-mini-direction-head" title={`${proto} ${label}`}>
|
||||
<span>{proto}</span>
|
||||
<span className={`line-mini-badge ${levelOf(value)}`}>{text}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 ${proto} ${label}`}>
|
||||
{cellsOf(values).map((v, i) => (
|
||||
<span key={`${id}-${t[i] ?? i}`} className={`bar ${s ? levelOf(v) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
return (
|
||||
<div className="strips" ref={box} onMouseMove={onMove} onMouseLeave={() => setHover(null)}>
|
||||
<div className="line-mini-stack">
|
||||
<div className="line-mini-quic-head" title={`QUIC RTT p50 ${fmtMs(m['rtt.p50'])} · p95 ${fmtMs(m['rtt.p95'])} · p99 ${fmtMs(m['rtt.p99'])}`}>
|
||||
<span>QUIC RTT ⇄</span><strong className="num">{fmtMs(m['rtt.p50'])}</strong><small>悬停看 p95 / p99</small>
|
||||
<div className="line-mini-quic-head" title={`RTT 是往返。QUIC p50 ${fmtMs(m['rtt.p50'])} · p95 ${fmtMs(m['rtt.p95'])} · p99 ${fmtMs(m['rtt.p99'])};TCP p50 ${fmtMs(m['tcp.rtt.p50'])}`}>
|
||||
<span>RTT ⇄</span>
|
||||
<span className="line-mini-rtt">QUIC <strong className="num">{fmtMs(m['rtt.p50'])}</strong></span>
|
||||
<span className="line-mini-rtt">TCP <strong className="num">{fmtMs(m['tcp.rtt.p50'])}</strong></span>
|
||||
<small>悬停看 p95 / p99</small>
|
||||
{series.error ? <span className="line-mini-badge bad" title={`上一次取数失败:${series.error.message}`}>数据未更新</span> : null}
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`去程 拨号方 → 监听方 丢包 ${fmtPct(up)}`}>
|
||||
<span className="line-mini-direction-name" title={`去程:${dialer} → ${listener}`}>{dialer} → {listener}</span>
|
||||
<span className={`line-mini-badge ${levelOf(up)}`}>{upText}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的去程丢包`}>
|
||||
{(s ? lossUp : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`up-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
<div className="line-mini-route" title={`去程:${dialer} → ${listener}`}>{dialer} → {listener}</div>
|
||||
{row('up-quic', 'QUIC', '去程丢包', m['loss.up'], lossText(m['loss.up']), lossUp)}
|
||||
{row('up-tcp', 'TCP', '去程重传', m['tcp.retrans.up'], retransText(m['tcp.retrans.up']), retransUp)}
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`回程 监听方 → 拨号方 丢包 ${fmtPct(down)}`}>
|
||||
<span className="line-mini-direction-name" title={`回程:${listener} → ${dialer}`}>{listener} → {dialer}</span>
|
||||
<span className={`line-mini-badge ${levelOf(down)}`}>{downText}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的回程丢包`}>
|
||||
{(s ? lossDown : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`down-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-mini-tcp">
|
||||
<div className="line-mini-tcp-head" title={`TCP RTT p50 ${fmtMs(m['tcp.rtt.p50'])}`}>
|
||||
<span>TCP RTT ⇄</span><strong className="num">{fmtMs(m['tcp.rtt.p50'])}</strong>
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`TCP 去程 拨号方 → 监听方 重传 ${fmtPct(retransUpValue)}`}>
|
||||
<span className="line-mini-direction-name" title={`去程:${dialer} → ${listener}`}>{dialer} → {listener}</span>
|
||||
<span className={`line-mini-badge ${levelOf(retransUpValue)}`}>{retransText(retransUpValue)}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 TCP 去程重传`}>
|
||||
{(s ? retransUp : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`retrans-up-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div className="line-mini-direction">
|
||||
<div className="line-mini-direction-head" title={`TCP 回程 监听方 → 拨号方 重传 ${fmtPct(retransDownValue)}`}>
|
||||
<span className="line-mini-direction-name" title={`回程:${listener} → ${dialer}`}>{listener} → {dialer}</span>
|
||||
<span className={`line-mini-badge ${levelOf(retransDownValue)}`}>{retransText(retransDownValue)}</span>
|
||||
</div>
|
||||
<div className="bars" role="img" aria-label={`近 ${common.hoursText}每 ${common.stepText}的 TCP 回程重传`}>
|
||||
{(s ? retransDown : Array.from({ length: common.cells }, () => null)).map((value, i) => (
|
||||
<span key={`retrans-down-${t[i] ?? i}`} className={`bar ${s ? levelOf(value) : 'none'}${hover === i ? ' on' : ''}`} />
|
||||
))}
|
||||
</div>
|
||||
<div className="line-mini-route" title={`回程:${listener} → ${dialer}`}>{listener} → {dialer}</div>
|
||||
{row('down-quic', 'QUIC', '回程丢包', m['loss.down'], lossText(m['loss.down']), lossDown)}
|
||||
{row('down-tcp', 'TCP', '回程重传', m['tcp.retrans.down'], retransText(m['tcp.retrans.down']), retransDown)}
|
||||
</div>
|
||||
</div>
|
||||
<div className={`pop num${hover !== null && at !== null ? ' open' : ''}`} role="tooltip" aria-hidden={hover === null}>
|
||||
|
||||
+24
-18
@@ -1388,15 +1388,13 @@
|
||||
}
|
||||
|
||||
.line-mini-quic-head > span,
|
||||
.line-mini-direction-head > span:first-child,
|
||||
.line-mini-tcp-head > span:first-child {
|
||||
.line-mini-direction-head > span:first-child {
|
||||
color: var(--app-ink-muted);
|
||||
font-size: 10px;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.line-mini-quic-head > strong,
|
||||
.line-mini-tcp-head > strong {
|
||||
.line-mini-quic-head strong {
|
||||
color: var(--app-ink);
|
||||
font-size: 14px;
|
||||
font-weight: 700;
|
||||
@@ -1410,15 +1408,13 @@
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.line-mini-direction,
|
||||
.line-mini-tcp {
|
||||
.line-mini-direction {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.line-mini-direction-head,
|
||||
.line-mini-tcp-head {
|
||||
.line-mini-direction-head {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
gap: 6px;
|
||||
@@ -1426,33 +1422,43 @@
|
||||
line-height: 1.25;
|
||||
}
|
||||
|
||||
.line-mini-direction-head > span:first-child,
|
||||
.line-mini-tcp-head > span:first-child {
|
||||
.line-mini-direction-head > span:first-child {
|
||||
font-weight: 500;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.line-mini-direction-head .line-mini-badge,
|
||||
.line-mini-tcp-head .line-mini-badge {
|
||||
.line-mini-direction-head .line-mini-badge {
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.line-mini-direction-head > .line-mini-direction-name {
|
||||
.line-mini-route {
|
||||
min-width: 0;
|
||||
overflow: hidden;
|
||||
color: var(--app-ink);
|
||||
font-size: 11px;
|
||||
font-weight: 600;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.line-mini-tcp {
|
||||
.line-mini-row {
|
||||
display: grid;
|
||||
gap: 3px;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.line-mini-rtt {
|
||||
display: inline-flex;
|
||||
align-items: baseline;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.line-mini-direction + .line-mini-direction {
|
||||
margin-top: 2px;
|
||||
padding-top: 5px;
|
||||
border-top: 1px solid var(--app-outline-soft);
|
||||
}
|
||||
|
||||
.line-mini-tcp-head > strong {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.line-mini-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
Reference in new issue
Block a user