diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchIndex.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchIndex.java index d059fa6d..2631a58f 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchIndex.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/search/OpenSearchIndex.java @@ -179,8 +179,20 @@ public class OpenSearchIndex implements SearchIndex { } // Keyword filters (use .keyword sub-field for exact matching on dynamically mapped text fields) - if (request.status() != null) - filter.add(termQuery("status.keyword", request.status())); + if (request.status() != null && !request.status().isBlank()) { + 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) filter.add(termQuery("route_id.keyword", request.routeId())); if (request.agentId() != null) diff --git a/ui/src/pages/Dashboard/Dashboard.tsx b/ui/src/pages/Dashboard/Dashboard.tsx index 94745d39..a39c7fdd 100644 --- a/ui/src/pages/Dashboard/Dashboard.tsx +++ b/ui/src/pages/Dashboard/Dashboard.tsx @@ -213,12 +213,18 @@ export default function Dashboard() { // ─── API hooks ─────────────────────────────────────────────────────────── const { data: stats } = useExecutionStats(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( { timeFrom, timeTo, routeId: routeId || undefined, application: appId || undefined, + status: statusParam, sortField, sortDir, offset: 0, @@ -230,17 +236,11 @@ export default function Dashboard() { const { data: diagram } = useDiagramLayout(detail?.diagramContentHash ?? null) // ─── Rows ──────────────────────────────────────────────────────────────── - const allRows: Row[] = useMemo( + const rows: Row[] = useMemo( () => (searchResult?.data || []).map((e: ExecutionSummary) => ({ ...e, id: e.executionId })), [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 ─────────────────────────────────────────────────────────── const totalCount = stats?.totalCount ?? 0 const failedCount = stats?.failedCount ?? 0