feat(All): 第一版项目
This commit is contained in:
71
src/client/components/ResultsPanel.tsx
Normal file
71
src/client/components/ResultsPanel.tsx
Normal file
@@ -0,0 +1,71 @@
|
||||
import { TEST_NODES, LatencyResult, getLatencyColor, getLatencyLevel } from '@shared/types'
|
||||
import './ResultsPanel.css'
|
||||
|
||||
interface ResultsPanelProps {
|
||||
results: Map<string, LatencyResult>
|
||||
}
|
||||
|
||||
export default function ResultsPanel({ results }: ResultsPanelProps) {
|
||||
if (results.size === 0) return null
|
||||
|
||||
const sortedNodes = [...TEST_NODES].sort((a, b) => {
|
||||
const aResult = results.get(a.id)
|
||||
const bResult = results.get(b.id)
|
||||
const aLatency = aResult?.latency ?? Infinity
|
||||
const bLatency = bResult?.latency ?? Infinity
|
||||
return aLatency - bLatency
|
||||
})
|
||||
|
||||
const completedResults = sortedNodes
|
||||
.map((node) => ({ node, result: results.get(node.id) }))
|
||||
.filter(({ result }) => result?.status === 'success' || result?.status === 'failed')
|
||||
|
||||
const avgLatency =
|
||||
completedResults.length > 0
|
||||
? Math.round(
|
||||
completedResults
|
||||
.filter(({ result }) => result?.latency !== null)
|
||||
.reduce((sum, { result }) => sum + (result?.latency ?? 0), 0) /
|
||||
completedResults.filter(({ result }) => result?.latency !== null).length
|
||||
)
|
||||
: null
|
||||
|
||||
return (
|
||||
<div className="results-panel">
|
||||
<div className="results-header">
|
||||
<h2>Test Results</h2>
|
||||
{avgLatency !== null && (
|
||||
<div className="avg-latency">
|
||||
Avg: <span style={{ color: getLatencyColor(avgLatency) }}>{avgLatency}ms</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="results-grid">
|
||||
{sortedNodes.map((node) => {
|
||||
const result = results.get(node.id)
|
||||
const isTesting = result?.status === 'testing'
|
||||
const hasResult = result?.status === 'success' || result?.status === 'failed'
|
||||
|
||||
return (
|
||||
<div key={node.id} className={`result-card ${hasResult ? getLatencyLevel(result?.latency ?? null) : ''}`}>
|
||||
<div className="result-region">{node.region}</div>
|
||||
<div className="result-name">{node.name}</div>
|
||||
<div className="result-latency">
|
||||
{isTesting ? (
|
||||
<span className="testing-indicator">Testing...</span>
|
||||
) : hasResult ? (
|
||||
<span style={{ color: getLatencyColor(result?.latency ?? null) }}>
|
||||
{result?.latency !== null ? `${result.latency}ms` : 'Timeout'}
|
||||
</span>
|
||||
) : (
|
||||
<span className="pending">—</span>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user