diff --git a/ui/src/api/queries/admin/outboundConnections.ts b/ui/src/api/queries/admin/outboundConnections.ts new file mode 100644 index 00000000..cf6d1090 --- /dev/null +++ b/ui/src/api/queries/admin/outboundConnections.ts @@ -0,0 +1,128 @@ +import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { adminFetch } from './admin-api'; + +// ── Types ────────────────────────────────────────────────────────────── + +export type OutboundMethod = 'POST' | 'PUT' | 'PATCH'; +export type OutboundAuthKind = 'NONE' | 'BEARER' | 'BASIC'; +export type TrustMode = 'SYSTEM_DEFAULT' | 'TRUST_ALL' | 'TRUST_PATHS'; + +// Jackson DEDUCTION mode picks subtype by which fields are present. +// None = {}, Bearer = { tokenCiphertext }, Basic = { username, passwordCiphertext }. +// Using a flat optional shape for pragmatic TypeScript compatibility. +export type OutboundAuth = { + tokenCiphertext?: string; + username?: string; + passwordCiphertext?: string; +}; + +// Server returns this shape (`OutboundConnectionDto` in Java) +export interface OutboundConnectionDto { + id: string; + name: string; + description: string | null; + url: string; + method: OutboundMethod; + defaultHeaders: Record; + defaultBodyTmpl: string | null; + tlsTrustMode: TrustMode; + tlsCaPemPaths: string[]; + hmacSecretSet: boolean; + authKind: OutboundAuthKind; + allowedEnvironmentIds: string[]; + createdAt: string; + createdBy: string; + updatedAt: string; + updatedBy: string; +} + +// Client sends this shape for create/update (`OutboundConnectionRequest` in Java) +export interface OutboundConnectionRequest { + name: string; + description?: string | null; + url: string; + method: OutboundMethod; + defaultHeaders?: Record; + defaultBodyTmpl?: string | null; + tlsTrustMode: TrustMode; + tlsCaPemPaths?: string[]; + hmacSecret?: string | null; + auth: OutboundAuth; + allowedEnvironmentIds?: string[]; +} + +// Server returns this from POST /{id}/test +export interface OutboundConnectionTestResult { + status: number; + latencyMs: number; + responseSnippet: string | null; + tlsProtocol: string | null; + tlsCipherSuite: string | null; + peerCertificateSubject: string | null; + peerCertificateExpiresAtEpochMs: number | null; + error: string | null; +} + +// ── Query Hooks ──────────────────────────────────────────────────────── + +export function useOutboundConnections() { + return useQuery({ + queryKey: ['admin', 'outbound-connections'], + queryFn: () => adminFetch('/outbound-connections'), + }); +} + +export function useOutboundConnection(id: string | undefined) { + return useQuery({ + queryKey: ['admin', 'outbound-connections', id], + queryFn: () => adminFetch(`/outbound-connections/${id}`), + enabled: !!id, + }); +} + +// ── Mutation Hooks ───────────────────────────────────────────────────── + +export function useCreateOutboundConnection() { + const qc = useQueryClient(); + return useMutation({ + mutationFn: (req: OutboundConnectionRequest) => + adminFetch('/outbound-connections', { + method: 'POST', + body: JSON.stringify(req), + }), + onSuccess: () => qc.invalidateQueries({ queryKey: ['admin', 'outbound-connections'] }), + }); +} + +export function useUpdateOutboundConnection(id: string) { + const qc = useQueryClient(); + return useMutation({ + mutationFn: (req: OutboundConnectionRequest) => + adminFetch(`/outbound-connections/${id}`, { + method: 'PUT', + body: JSON.stringify(req), + }), + onSuccess: () => { + qc.invalidateQueries({ queryKey: ['admin', 'outbound-connections'] }); + qc.invalidateQueries({ queryKey: ['admin', 'outbound-connections', id] }); + }, + }); +} + +export function useDeleteOutboundConnection() { + const qc = useQueryClient(); + return useMutation({ + mutationFn: (id: string) => + adminFetch(`/outbound-connections/${id}`, { method: 'DELETE' }), + onSuccess: () => qc.invalidateQueries({ queryKey: ['admin', 'outbound-connections'] }), + }); +} + +export function useTestOutboundConnection() { + return useMutation({ + mutationFn: (id: string) => + adminFetch(`/outbound-connections/${id}/test`, { + method: 'POST', + }), + }); +}