hfinfer / src /lib /RecordsTable.svelte
Morgan Funtowicz
Add Svelte 5 performance dashboard for JSONL benchmark data
4ed61ad
Raw History Blame
2.25 kB
<script lang="ts">
import type { BenchmarkRecord } from './types'
import { metricLabel, formatMetric } from './types'
interface Props {
records: BenchmarkRecord[]
metrics: string[]
}
let { records, metrics }: Props = $props()
let tagKeys = $derived([...new Set(records.flatMap((r) => Object.keys(r.tags)))].sort())
let sorted = $derived(
[...records].sort((a, b) => b.date.localeCompare(a.date) || a.host.localeCompare(b.host))
)
</script>
<div class="table-wrap">
<table>
<thead>
<tr>
<th>Date</th>
<th>Host</th>
<th>Hardware</th>
{#each tagKeys as key}
<th>{metricLabel(key)}</th>
{/each}
{#each metrics as key}
<th class="num">{metricLabel(key)}</th>
{/each}
</tr>
</thead>
<tbody>
{#each sorted as r}
<tr>
<td class="mono">{r.date}</td>
<td>{r.host}</td>
<td>{r.hardware}</td>
{#each tagKeys as key}
<td>{r.tags[key] ?? '—'}</td>
{/each}
{#each metrics as key}
<td class="num mono">
{r.metrics[key] !== undefined ? formatMetric(key, r.metrics[key]) : '—'}
</td>
{/each}
</tr>
{/each}
</tbody>
</table>
{#if sorted.length === 0}
<p class="empty">No records match the current filters.</p>
{/if}
</div>
<style>
.table-wrap {
overflow-x: auto;
background: var(--card);
border: 1px solid var(--border);
border-radius: 10px;
}
table {
width: 100%;
border-collapse: collapse;
font-size: 0.83rem;
}
th,
td {
padding: 0.5rem 0.8rem;
text-align: left;
white-space: nowrap;
}
th {
color: var(--muted);
font-size: 0.72rem;
text-transform: uppercase;
letter-spacing: 0.04em;
border-bottom: 1px solid var(--border);
}
td {
border-bottom: 1px solid color-mix(in srgb, var(--border) 50%, transparent);
}
tbody tr:hover {
background: color-mix(in srgb, var(--accent) 7%, transparent);
}
.num {
text-align: right;
}
.mono {
font-variant-numeric: tabular-nums;
}
.empty {
color: var(--muted);
text-align: center;
padding: 1.5rem;
}
</style>