Files
cameleer-server/ui/src/api/queries/executions.ts

163 lines
4.9 KiB
TypeScript
Raw Normal View History

import { useQuery } from '@tanstack/react-query';
import { api } from '../client';
fix!: require environment on diagram lookup and attribute keys queries Closes two cross-env data leakage paths. Both endpoints previously returned data aggregated across all environments, so a diagram or attribute key from dev could appear in a prod UI query (and vice versa). B1: GET /api/v1/diagrams?application=&routeId= now requires ?environment= and resolves agents via registryService.findByApplicationAndEnvironment instead of findByApplication. Prevents serving a dev diagram for a prod route. B2: GET /api/v1/search/attributes/keys now requires ?environment=. SearchIndex.distinctAttributeKeys gains an environment parameter and the ClickHouse query adds the env filter alongside the existing tenant_id filter. Prevents prod attribute names leaking into dev autocompletion (and vice versa). SPA hooks updated to thread environment through from useEnvironmentStore; query keys include environment so React Query re-fetches on env switch. No call-site changes needed — hook signatures unchanged. B3 (AgentMetricsController env scope) deferred to P3C: agent-env is effectively 1:1 today via the instance_id naming ({envSlug}-{appSlug}-{replicaIndex}), and the URL migration in P3C to /api/v1/environments/{env}/agents/{agentId}/metrics naturally introduces env from path. A minimal P1 fix would regress the "view metrics of a killed agent" case. BREAKING CHANGE: Both endpoints now require ?environment= (slug). Clients omitting the parameter receive 400. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:19:55 +02:00
import { useEnvironmentStore } from '../environment-store';
import type { SearchRequest } from '../types';
import { useLiveQuery } from './use-refresh-interval';
export function useExecutionStats(
timeFrom: string | undefined,
timeTo: string | undefined,
routeId?: string,
application?: string,
environment?: string,
) {
const live = useLiveQuery(10_000);
return useQuery({
queryKey: ['executions', 'stats', timeFrom, timeTo, routeId, application, environment],
queryFn: async () => {
const { data, error } = await api.GET('/search/stats', {
params: {
query: {
from: timeFrom!,
to: timeTo || undefined,
routeId: routeId || undefined,
application: application || undefined,
environment: environment || undefined,
},
},
});
if (error) throw new Error('Failed to load stats');
return data!;
},
enabled: !!timeFrom && live.enabled,
placeholderData: (prev) => prev,
refetchInterval: live.refetchInterval,
});
}
export function useAttributeKeys() {
fix!: require environment on diagram lookup and attribute keys queries Closes two cross-env data leakage paths. Both endpoints previously returned data aggregated across all environments, so a diagram or attribute key from dev could appear in a prod UI query (and vice versa). B1: GET /api/v1/diagrams?application=&routeId= now requires ?environment= and resolves agents via registryService.findByApplicationAndEnvironment instead of findByApplication. Prevents serving a dev diagram for a prod route. B2: GET /api/v1/search/attributes/keys now requires ?environment=. SearchIndex.distinctAttributeKeys gains an environment parameter and the ClickHouse query adds the env filter alongside the existing tenant_id filter. Prevents prod attribute names leaking into dev autocompletion (and vice versa). SPA hooks updated to thread environment through from useEnvironmentStore; query keys include environment so React Query re-fetches on env switch. No call-site changes needed — hook signatures unchanged. B3 (AgentMetricsController env scope) deferred to P3C: agent-env is effectively 1:1 today via the instance_id naming ({envSlug}-{appSlug}-{replicaIndex}), and the URL migration in P3C to /api/v1/environments/{env}/agents/{agentId}/metrics naturally introduces env from path. A minimal P1 fix would regress the "view metrics of a killed agent" case. BREAKING CHANGE: Both endpoints now require ?environment= (slug). Clients omitting the parameter receive 400. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:19:55 +02:00
const environment = useEnvironmentStore((s) => s.environment);
return useQuery({
fix!: require environment on diagram lookup and attribute keys queries Closes two cross-env data leakage paths. Both endpoints previously returned data aggregated across all environments, so a diagram or attribute key from dev could appear in a prod UI query (and vice versa). B1: GET /api/v1/diagrams?application=&routeId= now requires ?environment= and resolves agents via registryService.findByApplicationAndEnvironment instead of findByApplication. Prevents serving a dev diagram for a prod route. B2: GET /api/v1/search/attributes/keys now requires ?environment=. SearchIndex.distinctAttributeKeys gains an environment parameter and the ClickHouse query adds the env filter alongside the existing tenant_id filter. Prevents prod attribute names leaking into dev autocompletion (and vice versa). SPA hooks updated to thread environment through from useEnvironmentStore; query keys include environment so React Query re-fetches on env switch. No call-site changes needed — hook signatures unchanged. B3 (AgentMetricsController env scope) deferred to P3C: agent-env is effectively 1:1 today via the instance_id naming ({envSlug}-{appSlug}-{replicaIndex}), and the URL migration in P3C to /api/v1/environments/{env}/agents/{agentId}/metrics naturally introduces env from path. A minimal P1 fix would regress the "view metrics of a killed agent" case. BREAKING CHANGE: Both endpoints now require ?environment= (slug). Clients omitting the parameter receive 400. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:19:55 +02:00
queryKey: ['search', 'attribute-keys', environment],
queryFn: async () => {
const token = (await import('../../auth/auth-store')).useAuthStore.getState().accessToken;
const { config } = await import('../../config');
fix!: require environment on diagram lookup and attribute keys queries Closes two cross-env data leakage paths. Both endpoints previously returned data aggregated across all environments, so a diagram or attribute key from dev could appear in a prod UI query (and vice versa). B1: GET /api/v1/diagrams?application=&routeId= now requires ?environment= and resolves agents via registryService.findByApplicationAndEnvironment instead of findByApplication. Prevents serving a dev diagram for a prod route. B2: GET /api/v1/search/attributes/keys now requires ?environment=. SearchIndex.distinctAttributeKeys gains an environment parameter and the ClickHouse query adds the env filter alongside the existing tenant_id filter. Prevents prod attribute names leaking into dev autocompletion (and vice versa). SPA hooks updated to thread environment through from useEnvironmentStore; query keys include environment so React Query re-fetches on env switch. No call-site changes needed — hook signatures unchanged. B3 (AgentMetricsController env scope) deferred to P3C: agent-env is effectively 1:1 today via the instance_id naming ({envSlug}-{appSlug}-{replicaIndex}), and the URL migration in P3C to /api/v1/environments/{env}/agents/{agentId}/metrics naturally introduces env from path. A minimal P1 fix would regress the "view metrics of a killed agent" case. BREAKING CHANGE: Both endpoints now require ?environment= (slug). Clients omitting the parameter receive 400. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:19:55 +02:00
const res = await fetch(
`${config.apiBaseUrl}/search/attributes/keys?environment=${encodeURIComponent(environment!)}`,
{ headers: { Authorization: `Bearer ${token}` } },
);
if (!res.ok) throw new Error('Failed to load attribute keys');
return res.json() as Promise<string[]>;
},
fix!: require environment on diagram lookup and attribute keys queries Closes two cross-env data leakage paths. Both endpoints previously returned data aggregated across all environments, so a diagram or attribute key from dev could appear in a prod UI query (and vice versa). B1: GET /api/v1/diagrams?application=&routeId= now requires ?environment= and resolves agents via registryService.findByApplicationAndEnvironment instead of findByApplication. Prevents serving a dev diagram for a prod route. B2: GET /api/v1/search/attributes/keys now requires ?environment=. SearchIndex.distinctAttributeKeys gains an environment parameter and the ClickHouse query adds the env filter alongside the existing tenant_id filter. Prevents prod attribute names leaking into dev autocompletion (and vice versa). SPA hooks updated to thread environment through from useEnvironmentStore; query keys include environment so React Query re-fetches on env switch. No call-site changes needed — hook signatures unchanged. B3 (AgentMetricsController env scope) deferred to P3C: agent-env is effectively 1:1 today via the instance_id naming ({envSlug}-{appSlug}-{replicaIndex}), and the URL migration in P3C to /api/v1/environments/{env}/agents/{agentId}/metrics naturally introduces env from path. A minimal P1 fix would regress the "view metrics of a killed agent" case. BREAKING CHANGE: Both endpoints now require ?environment= (slug). Clients omitting the parameter receive 400. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-16 23:19:55 +02:00
enabled: !!environment,
staleTime: 60_000,
});
}
export function useSearchExecutions(filters: SearchRequest, live = false) {
const liveQuery = useLiveQuery(5_000);
return useQuery({
queryKey: ['executions', 'search', filters],
queryFn: async () => {
const { data, error } = await api.POST('/search/executions', {
body: filters,
});
if (error) throw new Error('Search failed');
return data!;
},
placeholderData: (prev) => prev,
enabled: live ? liveQuery.enabled : true,
refetchInterval: live ? liveQuery.refetchInterval : false,
});
}
export function useStatsTimeseries(
timeFrom: string | undefined,
timeTo: string | undefined,
routeId?: string,
application?: string,
environment?: string,
) {
const live = useLiveQuery(30_000);
return useQuery({
queryKey: ['executions', 'timeseries', timeFrom, timeTo, routeId, application, environment],
queryFn: async () => {
const { data, error } = await api.GET('/search/stats/timeseries', {
params: {
query: {
from: timeFrom!,
to: timeTo || undefined,
buckets: 24,
routeId: routeId || undefined,
application: application || undefined,
environment: environment || undefined,
},
},
});
if (error) throw new Error('Failed to load timeseries');
return data!;
},
enabled: !!timeFrom && live.enabled,
placeholderData: (prev) => prev,
refetchInterval: live.refetchInterval,
});
}
export function useExecutionDetail(executionId: string | null) {
return useQuery({
queryKey: ['executions', 'detail', executionId],
queryFn: async () => {
const { data, error } = await api.GET('/executions/{executionId}', {
params: { path: { executionId: executionId! } },
});
if (error) throw new Error('Failed to load execution detail');
return data!;
},
enabled: !!executionId,
});
}
export function useProcessorSnapshot(
executionId: string | null,
index: number | null,
) {
return useQuery({
queryKey: ['executions', 'snapshot', executionId, index],
queryFn: async () => {
const { data, error } = await api.GET(
'/executions/{executionId}/processors/{index}/snapshot',
{
params: {
path: { executionId: executionId!, index: index! },
},
},
);
if (error) throw new Error('Failed to load snapshot');
return data!;
},
enabled: !!executionId && index !== null,
});
}
export function useProcessorSnapshotById(
executionId: string | null,
processorId: string | null,
) {
return useQuery({
queryKey: ['executions', 'snapshot-by-id', executionId, processorId],
queryFn: async () => {
const { data, error } = await api.GET(
'/executions/{executionId}/processors/by-id/{processorId}/snapshot',
{
params: {
path: { executionId: executionId!, processorId: processorId! },
},
},
);
if (error) throw new Error('Failed to load snapshot');
return data!;
},
enabled: !!executionId && !!processorId,
});
}