materialized view and a bit better ui
Build and Publish / Metadata (push) Successful in 2s
Build and Publish / BuildAndDeployAmd64 (push) Successful in 1m3s

This commit is contained in:
mats committed 2026-09-19 12:43:17 +02:00
1 parent 26b677154b
commit 49f9bb3458
30 files changed
+2184 -106

No files matched your search

+29
View File
@@ -190,3 +190,32 @@ export function sparklineSeries(issue: Issue, hours = 24): SparklineSeries {
}
return { points, max, reference: mean, breachIndex }
}
/** One row per trace (all its samples grouped), plus one per traceless sample; newest first. */
export interface SampleGroup {
key: string
traceId?: string
samples: IssueSample[]
firstTs: number
}
export function groupSamplesByTrace(samples: IssueSample[]): SampleGroup[] {
const byTrace = new Map<string, SampleGroup>()
const out: SampleGroup[] = []
samples.forEach((sample, i) => {
if (!sample.traceId) {
out.push({ key: `s-${sample.timestamp}-${i}`, samples: [sample], firstTs: sample.timestamp })
return
}
const group = byTrace.get(sample.traceId)
if (group) {
group.samples.push(sample)
group.firstTs = Math.min(group.firstTs, sample.timestamp)
} else {
const created = { key: sample.traceId, traceId: sample.traceId, samples: [sample], firstTs: sample.timestamp }
byTrace.set(sample.traceId, created)
out.push(created)
}
})
return out.sort((a, b) => b.firstTs - a.firstTs)
}
+16
View File
@@ -0,0 +1,16 @@
import type { ProcessedTrace } from "../components/TraceVisualization"
import type { TraceSummary } from "./types"
/** Same shape the server returns, derived from a fully loaded trace (for lists built from live data). */
export function summarizeTrace(t: ProcessedTrace): TraceSummary {
return {
id: t.id,
name: t.name,
startTime: t.startTime,
endTime: t.endTime,
duration: t.duration,
spanCount: t.spans.length,
errorCount: t.errorCount,
services: t.services,
}
}
+33
View File
@@ -266,3 +266,36 @@ export interface ErrorStatsResponse {
export interface ReleaseStatsResponse {
series: Record<string, StatsPoint[]>;
}
/** Per-trace rollup for overview tables (server-side, no spans). Times are unix ns. */
export interface TraceSummary {
id: string;
name: string;
startTime: number;
endTime: number;
duration: number;
spanCount: number;
errorCount: number;
services: string[];
}
/** One trace an issue occurred in, from GET /api/issues/:id/traces. */
export interface IssueTrace {
traceId: string;
hits: number;
firstSeen: number;
lastSeen: number;
summary?: TraceSummary;
samples: IssueSample[];
}
export interface IssueTracesResponse {
issueId: string;
totalOccurrences: number;
traces: IssueTrace[];
untraced: IssueSample[];
hasMore: boolean;
nextBefore?: number;
/** false when the server only had the bounded in-memory samples. */
complete: boolean;
}