Skip to content

Commit 8a17e31

Browse files
authored
fix(web): show run provenance badges (#10)
Co-authored-by: 9o6 <3710814+9o6@users.noreply.github.com>
1 parent 688b866 commit 8a17e31

2 files changed

Lines changed: 80 additions & 2 deletions

File tree

‎web/src/App.tsx‎

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,11 @@ type QuickDemoResponse = {
103103
status: string
104104
}
105105

106+
type RunProvenance = {
107+
label: 'Synthetic demo' | 'Observed call' | 'Unknown provenance'
108+
tone: 'synthetic' | 'observed' | 'unknown'
109+
}
110+
106111
const ENVIRONMENT_PROFILES: EnvironmentProfile[] = [
107112
'local',
108113
'dev',
@@ -780,7 +785,12 @@ export function App() {
780785
/>
781786

782787
<section className="summaryGrid">
783-
<SummaryTile icon={<Database size={18} />} label="Run" value={timeline?.run_id ?? '-'} />
788+
<SummaryTile
789+
accessory={timeline ? <ProvenanceBadge environment={timeline.environment} /> : null}
790+
icon={<Database size={18} />}
791+
label="Run"
792+
value={timeline?.run_id ?? '-'}
793+
/>
784794
<SummaryTile icon={<Database size={18} />} label="Compare" value={compareTimeline?.run_id ?? '-'} />
785795
<SummaryTile
786796
icon={<Server size={18} />}
@@ -1120,6 +1130,7 @@ function LinkedCallInspector({
11201130
<div className="sectionHeader compact">
11211131
<Activity size={17} />
11221132
<h2>Call inspector</h2>
1133+
<ProvenanceBadge environment={timeline.environment} />
11231134
<span className="inspectorCursorReadout">Cursor {formatTimelineTime(cursorMs)}</span>
11241135
</div>
11251136
<p className="panelLead">
@@ -1901,10 +1912,12 @@ function RecentRuns({
19011912
}
19021913

19031914
function SummaryTile({
1915+
accessory,
19041916
icon,
19051917
label,
19061918
value,
19071919
}: {
1920+
accessory?: React.ReactNode
19081921
icon: React.ReactNode
19091922
label: string
19101923
value: React.ReactNode
@@ -1914,10 +1927,23 @@ function SummaryTile({
19141927
<span className="summaryIcon">{icon}</span>
19151928
<span className="summaryLabel">{label}</span>
19161929
<strong>{value}</strong>
1930+
{accessory ? <span className="summaryAccessory">{accessory}</span> : null}
19171931
</div>
19181932
)
19191933
}
19201934

1935+
function ProvenanceBadge({ environment }: { environment: RunEnvironmentMetadata }) {
1936+
const provenance = runProvenance(environment)
1937+
return (
1938+
<span
1939+
aria-label={`Run provenance: ${provenance.label}`}
1940+
className={`provenanceBadge ${provenance.tone}`}
1941+
>
1942+
{provenance.label}
1943+
</span>
1944+
)
1945+
}
1946+
19211947
function StatusPanel({ state, detail }: { state: 'idle' | 'loading' | 'error'; detail?: string }) {
19221948
const copy = {
19231949
idle: ['Ready', 'Enter a run_id'],
@@ -3000,6 +3026,23 @@ function environmentHeadline(environment: RunEnvironmentMetadata) {
30003026
return server ? `${environment.environment_profile} / ${server}` : environment.environment_profile
30013027
}
30023028

3029+
function runProvenance(environment: RunEnvironmentMetadata): RunProvenance {
3030+
const tags = new Set(environment.tags.map((tag) => tag.toLowerCase()))
3031+
if (
3032+
environment.started_from === 'live-demo-simulated-bridge' ||
3033+
tags.has('simulated-audio')
3034+
) {
3035+
return { label: 'Synthetic demo', tone: 'synthetic' }
3036+
}
3037+
if (
3038+
environment.started_from?.startsWith('voxbench-audiosocket-') ||
3039+
tags.has('audiosocket')
3040+
) {
3041+
return { label: 'Observed call', tone: 'observed' }
3042+
}
3043+
return { label: 'Unknown provenance', tone: 'unknown' }
3044+
}
3045+
30033046
function readinessHeadline(summary: ReadinessSummary) {
30043047
if (summary.incomplete_count === 0) {
30053048
return 'ready'

‎web/src/styles.css‎

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,8 @@ a {
169169
grid-template-columns: auto 1fr;
170170
grid-template-areas:
171171
"icon label"
172-
"icon value";
172+
"icon value"
173+
"icon accessory";
173174
column-gap: 10px;
174175
min-height: 74px;
175176
padding: 13px;
@@ -178,6 +179,11 @@ a {
178179
background: #ffffff;
179180
}
180181

182+
.summaryAccessory {
183+
grid-area: accessory;
184+
margin-top: 5px;
185+
}
186+
181187
.summaryIcon {
182188
grid-area: icon;
183189
display: inline-flex;
@@ -318,6 +324,35 @@ a {
318324
margin: 4px 0 10px;
319325
}
320326

327+
.provenanceBadge {
328+
display: inline-flex;
329+
align-items: center;
330+
width: fit-content;
331+
max-width: 100%;
332+
min-height: 24px;
333+
border: 1px solid #a7b3c0;
334+
border-radius: 999px;
335+
padding: 3px 9px;
336+
color: #405064;
337+
background: #f3f5f7;
338+
font-size: 11px;
339+
font-weight: 800;
340+
line-height: 1.2;
341+
white-space: normal;
342+
}
343+
344+
.provenanceBadge.synthetic {
345+
border-color: #d79d3a;
346+
color: #704812;
347+
background: #fff4d8;
348+
}
349+
350+
.provenanceBadge.observed {
351+
border-color: #4f9b75;
352+
color: #1d5c3c;
353+
background: #e8f7ee;
354+
}
355+
321356
.stageStack {
322357
display: grid;
323358
gap: 10px;

0 commit comments

Comments
 (0)