fix: move status filtering server-side in Dashboard search
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:
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user