Skip to content

Commit 0b47599

Browse files
thejefflarsonclaude
andcommitted
ui: service filter on traces is a dropdown
Replace the free-text service input with a <select> populated from /api/services (the services that have traces in the current window). "all services" clears it. A service set via a service-map drill-down stays selectable even if it's outside the window's list. Service stays in the URL, so drill-downs still land here. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 4ae8227 commit 0b47599

1 file changed

Lines changed: 24 additions & 6 deletions

File tree

ui/src/components/TraceList.tsx

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { useEffect, useState } from "react";
22
import { useSearchParams } from "react-router-dom";
3-
import { listTraces, type TraceSummary } from "../api";
3+
import { listTraces, listServices, type TraceSummary } from "../api";
44
import { useControls, rangeParams } from "../timerange";
55
import { useSort } from "../sort";
66

@@ -28,6 +28,18 @@ export default function TraceList({ onSelect }: { onSelect: (traceId: string) =>
2828
const [attr, setAttr] = useState("");
2929
const [errorsOnly, setErrorsOnly] = useState(false);
3030
const [minDuration, setMinDuration] = useState("");
31+
const [services, setServices] = useState<string[]>([]);
32+
33+
// Populate the service dropdown from the services that have traces in range.
34+
useEffect(() => {
35+
let active = true;
36+
listServices(rangeParams(rangeKey))
37+
.then((rows) => active && setServices(rows.map((r) => r.service).sort()))
38+
.catch(() => active && setServices([]));
39+
return () => {
40+
active = false;
41+
};
42+
}, [rangeKey, tick]);
3143

3244
useEffect(() => {
3345
let active = true;
@@ -61,11 +73,17 @@ export default function TraceList({ onSelect }: { onSelect: (traceId: string) =>
6173

6274
const filters = (
6375
<div className="filters">
64-
<input
65-
placeholder="service"
66-
value={service}
67-
onChange={(e) => setService(e.target.value)}
68-
/>
76+
<select value={service} onChange={(e) => setService(e.target.value)}>
77+
<option value="">all services</option>
78+
{/* keep a drill-down service selectable even if it's outside the window's list */}
79+
{(services.includes(service) || !service ? services : [service, ...services]).map(
80+
(s) => (
81+
<option key={s} value={s}>
82+
{s}
83+
</option>
84+
),
85+
)}
86+
</select>
6987
<input
7088
placeholder="root span name…"
7189
value={name}

0 commit comments

Comments
 (0)