import { useQuery } from '@tanstack/react-query'; import { api } from '../client'; import { config as appConfig } from '../../config'; import { useAuthStore } from '../../auth/auth-store'; import { useEnvironmentStore } from '../environment-store'; import type { components } from '../schema'; import type { SearchRequest } from '../types'; import { useLiveQuery } from './use-refresh-interval'; type ExecutionStats = components['schemas']['ExecutionStats']; type StatsTimeseries = components['schemas']['StatsTimeseries']; type SearchResultSummary = components['schemas']['SearchResultExecutionSummary']; // Raw authenticated fetch — used for env-scoped endpoints where the // generated openapi schema is still on the old flat shape. Switch back to // api.GET once the schema is regenerated against a running P3-era backend. async function envFetch(envSlug: string, path: string, init?: RequestInit): Promise { const token = useAuthStore.getState().accessToken; const res = await fetch( `${appConfig.apiBaseUrl}/environments/${encodeURIComponent(envSlug)}${path}`, { ...init, headers: { 'Content-Type': 'application/json', ...(token ? { Authorization: `Bearer ${token}` } : {}), 'X-Cameleer-Protocol-Version': '1', ...init?.headers, }, }); if (!res.ok) throw new Error(`API error: ${res.status}`); return res.json() as Promise; } 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', environment, timeFrom, timeTo, routeId, application], queryFn: async () => { const params = new URLSearchParams({ from: timeFrom! }); if (timeTo) params.set('to', timeTo); if (routeId) params.set('routeId', routeId); if (application) params.set('application', application); return envFetch(environment!, `/stats?${params}`); }, enabled: !!timeFrom && !!environment && live.enabled, placeholderData: (prev) => prev, refetchInterval: live.refetchInterval, }); } export function useAttributeKeys() { const environment = useEnvironmentStore((s) => s.environment); return useQuery({ queryKey: ['search', 'attribute-keys', environment], queryFn: () => envFetch(environment!, '/attributes/keys'), enabled: !!environment, staleTime: 60_000, }); } export function useSearchExecutions(filters: SearchRequest, live = false) { const environment = useEnvironmentStore((s) => s.environment); const liveQuery = useLiveQuery(5_000); return useQuery({ queryKey: ['executions', 'search', environment, filters], queryFn: () => envFetch(environment!, '/executions/search', { method: 'POST', body: JSON.stringify(filters), }), placeholderData: (prev) => prev, enabled: !!environment && (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', environment, timeFrom, timeTo, routeId, application], queryFn: async () => { const params = new URLSearchParams({ from: timeFrom!, buckets: '24' }); if (timeTo) params.set('to', timeTo); if (routeId) params.set('routeId', routeId); if (application) params.set('application', application); return envFetch(environment!, `/stats/timeseries?${params}`); }, enabled: !!timeFrom && !!environment && 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, }); }