fix: move status filtering server-side in Dashboard search
All checks were successful
CI / cleanup-branch (push) Has been skipped
CI / build (push) Successful in 59s
CI / docker (push) Successful in 54s
CI / deploy-feature (push) Has been skipped
CI / deploy (push) Successful in 35s

The Dashboard was fetching 50 results without a status filter and
filtering client-side, causing fewer matches when filtering by error
compared to route-specific pages that filter server-side. Now passes
statusFilters to the OpenSearch query. Backend supports comma-separated
status values for multi-select filters.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
hsiegeln
2026-03-27 23:00:32 +01:00
parent 0d7d04501c
commit e9b1c94d1a
2 changed files with 21 additions and 9 deletions

View File

@@ -179,8 +179,20 @@ public class OpenSearchIndex implements SearchIndex {
} }
// Keyword filters (use .keyword sub-field for exact matching on dynamically mapped text fields) // Keyword filters (use .keyword sub-field for exact matching on dynamically mapped text fields)
if (request.status() != null) if (request.status() != null && !request.status().isBlank()) {
filter.add(termQuery("status.keyword", request.status())); String[] statuses = request.status().split(",");
if (statuses.length == 1) {
filter.add(termQuery("status.keyword", statuses[0].trim()));
} else {
filter.add(Query.of(q -> q.terms(t -> t
.field("status.keyword")
.terms(tv -> tv.value(
java.util.Arrays.stream(statuses)
.map(String::trim)
.map(FieldValue::of)
.toList())))));
}
}
if (request.routeId() != null) if (request.routeId() != null)
filter.add(termQuery("route_id.keyword", request.routeId())); filter.add(termQuery("route_id.keyword", request.routeId()));
if (request.agentId() != null) if (request.agentId() != null)

View File

@@ -213,12 +213,18 @@ export default function Dashboard() {
// ─── API hooks ─────────────────────────────────────────────────────────── // ─── API hooks ───────────────────────────────────────────────────────────
const { data: stats } = useExecutionStats(timeFrom, timeTo, routeId, appId) const { data: stats } = useExecutionStats(timeFrom, timeTo, routeId, appId)
const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, routeId, appId) const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, routeId, appId)
// Convert design-system status filters (lowercase) to API status param (uppercase)
const statusParam = statusFilters.size > 0
? [...statusFilters].map(s => s.toUpperCase()).join(',')
: undefined
const { data: searchResult } = useSearchExecutions( const { data: searchResult } = useSearchExecutions(
{ {
timeFrom, timeFrom,
timeTo, timeTo,
routeId: routeId || undefined, routeId: routeId || undefined,
application: appId || undefined, application: appId || undefined,
status: statusParam,
sortField, sortField,
sortDir, sortDir,
offset: 0, offset: 0,
@@ -230,17 +236,11 @@ export default function Dashboard() {
const { data: diagram } = useDiagramLayout(detail?.diagramContentHash ?? null) const { data: diagram } = useDiagramLayout(detail?.diagramContentHash ?? null)
// ─── Rows ──────────────────────────────────────────────────────────────── // ─── Rows ────────────────────────────────────────────────────────────────
const allRows: Row[] = useMemo( const rows: Row[] = useMemo(
() => (searchResult?.data || []).map((e: ExecutionSummary) => ({ ...e, id: e.executionId })), () => (searchResult?.data || []).map((e: ExecutionSummary) => ({ ...e, id: e.executionId })),
[searchResult], [searchResult],
) )
// Apply global status filters (time filtering is done server-side via timeFrom/timeTo)
const rows: Row[] = useMemo(() => {
if (statusFilters.size === 0) return allRows
return allRows.filter((r) => statusFilters.has(r.status.toLowerCase() as any))
}, [allRows, statusFilters])
// ─── KPI items ─────────────────────────────────────────────────────────── // ─── KPI items ───────────────────────────────────────────────────────────
const totalCount = stats?.totalCount ?? 0 const totalCount = stats?.totalCount ?? 0
const failedCount = stats?.failedCount ?? 0 const failedCount = stats?.failedCount ?? 0