From 69dcce2a8fe3659ec7a7c59795d54aa57a60788f Mon Sep 17 00:00:00 2001 From: hsiegeln <37154749+hsiegeln@users.noreply.github.com> Date: Thu, 9 Apr 2026 16:12:33 +0200 Subject: [PATCH] fix: Runtime tab respects selected environment - Add environment parameter to AgentEventsController, AgentEventService, and ClickHouseAgentEventRepository (filters agent_events by environment) - Wire selectedEnv to useAgents and useAgentEvents in both AgentHealth and AgentInstance pages - Wire selectedEnv to useStatsTimeseries in AgentInstance Co-Authored-By: Claude Opus 4.6 (1M context) --- .../server/app/controller/AgentEventsController.java | 3 ++- .../app/storage/ClickHouseAgentEventRepository.java | 9 +++++++++ .../server/core/agent/AgentEventRepository.java | 2 ++ .../cameleer3/server/core/agent/AgentEventService.java | 4 ++++ ui/src/api/queries/agents.ts | 5 +++-- ui/src/pages/AgentHealth/AgentHealth.tsx | 6 ++++-- ui/src/pages/AgentInstance/AgentInstance.tsx | 8 +++++--- 7 files changed, 29 insertions(+), 8 deletions(-) diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentEventsController.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentEventsController.java index b0419bcf..9bf542ad 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentEventsController.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/controller/AgentEventsController.java @@ -32,6 +32,7 @@ public class AgentEventsController { public ResponseEntity> getEvents( @RequestParam(required = false) String appId, @RequestParam(required = false) String agentId, + @RequestParam(required = false) String environment, @RequestParam(required = false) String from, @RequestParam(required = false) String to, @RequestParam(defaultValue = "50") int limit) { @@ -39,7 +40,7 @@ public class AgentEventsController { Instant fromInstant = from != null ? Instant.parse(from) : null; Instant toInstant = to != null ? Instant.parse(to) : null; - var events = agentEventService.queryEvents(appId, agentId, fromInstant, toInstant, limit) + var events = agentEventService.queryEvents(appId, agentId, environment, fromInstant, toInstant, limit) .stream() .map(AgentEventResponse::from) .toList(); diff --git a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseAgentEventRepository.java b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseAgentEventRepository.java index 6c69d7e1..8b47159a 100644 --- a/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseAgentEventRepository.java +++ b/cameleer3-server-app/src/main/java/com/cameleer3/server/app/storage/ClickHouseAgentEventRepository.java @@ -38,6 +38,11 @@ public class ClickHouseAgentEventRepository implements AgentEventRepository { @Override public List query(String applicationId, String instanceId, Instant from, Instant to, int limit) { + return query(applicationId, instanceId, null, from, to, limit); + } + + @Override + public List query(String applicationId, String instanceId, String environment, Instant from, Instant to, int limit) { var sql = new StringBuilder(SELECT_BASE); var params = new ArrayList(); params.add(tenantId); @@ -50,6 +55,10 @@ public class ClickHouseAgentEventRepository implements AgentEventRepository { sql.append(" AND instance_id = ?"); params.add(instanceId); } + if (environment != null) { + sql.append(" AND environment = ?"); + params.add(environment); + } if (from != null) { sql.append(" AND timestamp >= ?"); params.add(Timestamp.from(from)); diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventRepository.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventRepository.java index 5778b70b..0908f950 100644 --- a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventRepository.java +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventRepository.java @@ -8,4 +8,6 @@ public interface AgentEventRepository { void insert(String instanceId, String applicationId, String eventType, String detail); List query(String applicationId, String instanceId, Instant from, Instant to, int limit); + + List query(String applicationId, String instanceId, String environment, Instant from, Instant to, int limit); } diff --git a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventService.java b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventService.java index d2d72f69..9348144b 100644 --- a/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventService.java +++ b/cameleer3-server-core/src/main/java/com/cameleer3/server/core/agent/AgentEventService.java @@ -24,4 +24,8 @@ public class AgentEventService { public List queryEvents(String applicationId, String instanceId, Instant from, Instant to, int limit) { return repository.query(applicationId, instanceId, from, to, limit); } + + public List queryEvents(String applicationId, String instanceId, String environment, Instant from, Instant to, int limit) { + return repository.query(applicationId, instanceId, environment, from, to, limit); + } } diff --git a/ui/src/api/queries/agents.ts b/ui/src/api/queries/agents.ts index abd23e36..f3932466 100644 --- a/ui/src/api/queries/agents.ts +++ b/ui/src/api/queries/agents.ts @@ -27,15 +27,16 @@ export function useAgents(status?: string, application?: string, environment?: s }); } -export function useAgentEvents(appId?: string, agentId?: string, limit = 50, toOverride?: string) { +export function useAgentEvents(appId?: string, agentId?: string, limit = 50, toOverride?: string, environment?: string) { const refetchInterval = useRefreshInterval(15_000); return useQuery({ - queryKey: ['agents', 'events', appId, agentId, limit, toOverride], + queryKey: ['agents', 'events', appId, agentId, limit, toOverride, environment], queryFn: async () => { const token = useAuthStore.getState().accessToken; const params = new URLSearchParams(); if (appId) params.set('appId', appId); if (agentId) params.set('agentId', agentId); + if (environment) params.set('environment', environment); if (toOverride) params.set('to', toOverride); params.set('limit', String(limit)); const res = await fetch(`${config.apiBaseUrl}/agents/events-log?${params}`, { diff --git a/ui/src/pages/AgentHealth/AgentHealth.tsx b/ui/src/pages/AgentHealth/AgentHealth.tsx index 14a40e74..689b3d44 100644 --- a/ui/src/pages/AgentHealth/AgentHealth.tsx +++ b/ui/src/pages/AgentHealth/AgentHealth.tsx @@ -12,6 +12,7 @@ import logStyles from '../../styles/log-panel.module.css'; import { useAgents, useAgentEvents } from '../../api/queries/agents'; import { useApplicationLogs } from '../../api/queries/logs'; import { useApplicationConfig, useUpdateApplicationConfig } from '../../api/queries/commands'; +import { useEnvironmentStore } from '../../api/environment-store'; import type { ConfigUpdateResponse } from '../../api/queries/commands'; import type { AgentInstance } from '../../api/types'; import { timeAgo } from '../../utils/format-utils'; @@ -91,7 +92,8 @@ export default function AgentHealth() { const { appId } = useParams(); const navigate = useNavigate(); const { toast } = useToast(); - const { data: agents } = useAgents(undefined, appId); + const selectedEnv = useEnvironmentStore((s) => s.environment); + const { data: agents } = useAgents(undefined, appId, selectedEnv); const { data: appConfig } = useApplicationConfig(appId); const updateConfig = useUpdateApplicationConfig(); @@ -131,7 +133,7 @@ export default function AgentHealth() { }, [appConfig, configDraft, updateConfig, toast, appId]); const [eventSortAsc, setEventSortAsc] = useState(false); const [eventRefreshTo, setEventRefreshTo] = useState(); - const { data: events } = useAgentEvents(appId, undefined, 50, eventRefreshTo); + const { data: events } = useAgentEvents(appId, undefined, 50, eventRefreshTo, selectedEnv); const [logSearch, setLogSearch] = useState(''); const [logLevels, setLogLevels] = useState>(new Set()); diff --git a/ui/src/pages/AgentInstance/AgentInstance.tsx b/ui/src/pages/AgentInstance/AgentInstance.tsx index 6d7e7a8b..a811776c 100644 --- a/ui/src/pages/AgentInstance/AgentInstance.tsx +++ b/ui/src/pages/AgentInstance/AgentInstance.tsx @@ -15,6 +15,7 @@ import { useApplicationLogs } from '../../api/queries/logs'; import { useStatsTimeseries } from '../../api/queries/executions'; import { useAgentMetrics } from '../../api/queries/agent-metrics'; import { formatUptime, mapLogLevel, eventSeverity, eventIcon } from '../../utils/agent-utils'; +import { useEnvironmentStore } from '../../api/environment-store'; const LOG_LEVEL_ITEMS: ButtonGroupItem[] = [ { value: 'error', label: 'Error', color: 'var(--error)' }, @@ -36,9 +37,10 @@ export default function AgentInstance() { const timeFrom = timeRange.start.toISOString(); const timeTo = timeRange.end.toISOString(); - const { data: agents, isLoading } = useAgents(undefined, appId); - const { data: events } = useAgentEvents(appId, instanceId, 50, eventRefreshTo); - const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, undefined, appId); + const selectedEnv = useEnvironmentStore((s) => s.environment); + const { data: agents, isLoading } = useAgents(undefined, appId, selectedEnv); + const { data: events } = useAgentEvents(appId, instanceId, 50, eventRefreshTo, selectedEnv); + const { data: timeseries } = useStatsTimeseries(timeFrom, timeTo, undefined, appId, selectedEnv); const agent = useMemo( () => (agents || []).find((a: any) => a.instanceId === instanceId) as any,