diff --git a/ui/src/api/queries/commands.ts b/ui/src/api/queries/commands.ts index d3fb51d6..172e8ff3 100644 --- a/ui/src/api/queries/commands.ts +++ b/ui/src/api/queries/commands.ts @@ -1,5 +1,4 @@ import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' -import { api } from '../client' import { useAuthStore } from '../../auth/auth-store' // ── Application Config ──────────────────────────────────────────────────── @@ -65,6 +64,11 @@ export function useApplicationConfig(application: string | undefined) { }) } +export interface ConfigUpdateResponse { + config: ApplicationConfig + pushResult: CommandGroupResponse +} + export function useUpdateApplicationConfig() { const queryClient = useQueryClient() return useMutation({ @@ -75,10 +79,10 @@ export function useUpdateApplicationConfig() { body: JSON.stringify(config), }) if (!res.ok) throw new Error('Failed to update config') - return res.json() as Promise + return res.json() as Promise }, - onSuccess: (saved) => { - queryClient.setQueryData(['applicationConfig', saved.application], saved) + onSuccess: (result) => { + queryClient.setQueryData(['applicationConfig', result.config.application], result.config) queryClient.invalidateQueries({ queryKey: ['applicationConfig', 'all'] }) }, }) @@ -98,6 +102,16 @@ export function useProcessorRouteMapping(application?: string) { }) } +// ── Group Command Response ─────────────────────────────────────────────── + +export interface CommandGroupResponse { + success: boolean + total: number + responded: number + responses: { agentId: string; status: string; message: string }[] + timedOut: string[] +} + // ── Generic Group Command (kept for non-config commands) ────────────────── interface SendGroupCommandParams { @@ -109,12 +123,13 @@ interface SendGroupCommandParams { export function useSendGroupCommand() { return useMutation({ mutationFn: async ({ group, type, payload }: SendGroupCommandParams) => { - const { data, error } = await api.POST('/agents/groups/{group}/commands', { - params: { path: { group } }, - body: { type, payload } as any, + const res = await authFetch(`/api/v1/agents/groups/${encodeURIComponent(group)}/commands`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type, payload }), }) - if (error) throw new Error('Failed to send command') - return data! + if (!res.ok) throw new Error('Failed to send command') + return res.json() as Promise }, }) } @@ -163,12 +178,13 @@ export function useSendRouteCommand() { action: 'start' | 'stop' | 'suspend' | 'resume' routeId: string }) => { - const { data, error } = await api.POST('/agents/groups/{group}/commands', { - params: { path: { group: application } }, - body: { type: 'route-control', payload: { routeId, action, nonce: crypto.randomUUID() } } as any, + const res = await authFetch(`/api/v1/agents/groups/${encodeURIComponent(application)}/commands`, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ type: 'route-control', payload: { routeId, action, nonce: crypto.randomUUID() } }), }) - if (error) throw new Error('Failed to send route command') - return data! + if (!res.ok) throw new Error('Failed to send route command') + return res.json() as Promise }, }) } diff --git a/ui/src/pages/Admin/AppConfigDetailPage.tsx b/ui/src/pages/Admin/AppConfigDetailPage.tsx index fbcea6d5..ece195ad 100644 --- a/ui/src/pages/Admin/AppConfigDetailPage.tsx +++ b/ui/src/pages/Admin/AppConfigDetailPage.tsx @@ -155,7 +155,7 @@ export default function AppConfigDetailPage() { updateConfig.mutate(updated, { onSuccess: (saved) => { setEditing(false); - toast({ title: 'Config saved', description: `${appId} updated to v${saved.version}`, variant: 'success' }); + toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version}`, variant: 'success' }); }, onError: () => { toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error' }); diff --git a/ui/src/pages/Admin/AppConfigPage.tsx b/ui/src/pages/Admin/AppConfigPage.tsx index a7287687..aac5da41 100644 --- a/ui/src/pages/Admin/AppConfigPage.tsx +++ b/ui/src/pages/Admin/AppConfigPage.tsx @@ -141,7 +141,7 @@ function AppConfigDetail({ appId, onClose }: { appId: string; onClose: () => voi if (!config || !form) return; const updated = { ...config, ...form, tracedProcessors: tracedDraft, routeRecording: routeRecordingDraft } as ApplicationConfig; updateConfig.mutate(updated, { - onSuccess: (saved) => { setEditing(false); toast({ title: 'Config saved', description: `${appId} updated to v${saved.version}`, variant: 'success' }); }, + onSuccess: (saved) => { setEditing(false); toast({ title: 'Config saved', description: `${appId} updated to v${saved.config.version}`, variant: 'success' }); }, onError: () => { toast({ title: 'Save failed', description: 'Could not update configuration', variant: 'error' }); }, }); } diff --git a/ui/src/pages/AgentHealth/AgentHealth.tsx b/ui/src/pages/AgentHealth/AgentHealth.tsx index 59a5a47a..01e1d9ed 100644 --- a/ui/src/pages/AgentHealth/AgentHealth.tsx +++ b/ui/src/pages/AgentHealth/AgentHealth.tsx @@ -145,7 +145,7 @@ export default function AgentHealth() { onSuccess: (saved) => { setConfigEditing(false); setConfigDraft({}); - toast({ title: 'Config updated', description: `${appId} (v${saved.version})`, variant: 'success' }); + toast({ title: 'Config updated', description: `${appId} (v${saved.config.version})`, variant: 'success' }); }, onError: () => { toast({ title: 'Config update failed', variant: 'error' }); diff --git a/ui/src/pages/Exchanges/ExchangesPage.tsx b/ui/src/pages/Exchanges/ExchangesPage.tsx index c1ab76bd..c69ede67 100644 --- a/ui/src/pages/Exchanges/ExchangesPage.tsx +++ b/ui/src/pages/Exchanges/ExchangesPage.tsx @@ -216,7 +216,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS if (!updatedConfig) return; updateConfig.mutate(updatedConfig, { onSuccess: (saved) => { - toast({ title: 'Tap configuration saved', description: `Pushed to agents (v${saved.version})`, variant: 'success' }); + toast({ title: 'Tap configuration saved', description: `Pushed to agents (v${saved.config.version})`, variant: 'success' }); }, onError: () => { toast({ title: 'Tap update failed', description: 'Could not save configuration', variant: 'error' }); @@ -229,7 +229,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS const taps = appConfig.taps.filter(t => t.tapId !== tap.tapId); updateConfig.mutate({ ...appConfig, taps }, { onSuccess: (saved) => { - toast({ title: 'Tap deleted', description: `${tap.attributeName} removed (v${saved.version})`, variant: 'success' }); + toast({ title: 'Tap deleted', description: `${tap.attributeName} removed (v${saved.config.version})`, variant: 'success' }); }, onError: () => { toast({ title: 'Tap delete failed', description: 'Could not save configuration', variant: 'error' }); @@ -256,7 +256,7 @@ function DiagramPanel({ appId, routeId, exchangeId, onCorrelatedSelect, onClearS tracedProcessors, }, { onSuccess: (saved) => { - toast({ title: `Tracing ${enabled ? 'enabled' : 'disabled'}`, description: `${nodeId} — pushed to agents (v${saved.version})`, variant: 'success' }); + toast({ title: `Tracing ${enabled ? 'enabled' : 'disabled'}`, description: `${nodeId} — pushed to agents (v${saved.config.version})`, variant: 'success' }); }, onError: () => { useTracingStore.getState().toggleProcessor(appId, nodeId);