import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query' import { api } from './client' export interface DashboardScope { city?: string client?: string object_ids?: number[] tag_ids?: number[] } export type DashboardAvailabilityWindow = '24h' | '3d' | '7d' export interface DashboardCheckDefinition { check_key: string enabled: boolean interval_sec_default: number plugin_action: string categories: string[] timeout_sec: number concurrency: number updated_at: string } export interface DashboardObjectOverride { object_id: number check_key: string enabled_override: boolean | null interval_sec_override: number | null categories_override: string[] | null updated_at: string } export interface DashboardMonitorStatus { status: string run_type: string | null scope: Record | null started_at: string | null finished_at: string | null last_success_at: string | null last_error: string | null last_counts: Record | null } export interface DashboardObjectPolicy { object_id: number mode: 'inherit' | 'include' | 'exclude' updated_at: string } export interface DashboardTagPolicy { tag_id: number enabled: boolean updated_at: string } export interface DashboardPolicyResponse { object_policies: DashboardObjectPolicy[] tag_policies: DashboardTagPolicy[] } export interface DashboardObjectCheckSummary { status_counts: Record last_checked_at: string | null max_age_sec: number | null } export interface DashboardObjectSummary { object_id: number object_name: string city: string | null client: string | null allowed: boolean monitor_mode: 'inherit' | 'include' | 'exclude' inclusion_reason: string device_count: number checks: Record health_score: number | null } export interface DashboardHomeSummary { generated_at: string scope: DashboardScope totals: Record checks_meta: DashboardCheckDefinition[] objects: DashboardObjectSummary[] problem_objects: DashboardObjectSummary[] included_count: number excluded_count: number included_objects: DashboardObjectSummary[] excluded_objects: DashboardObjectSummary[] } export interface DashboardDeviceNOCItem { device_id: number object_id: number rack_id: number | null rack_name: string | null ip: string hostname: string | null category: string role: string | null status: string | null monitor_enabled: boolean last_seen: string | null last_ping_ms: number | null ping_status: string ping_checked_at: string | null ping_age_sec: number | null ping_fresh: boolean disk_status: string | null disk_max_pct: number | null has_problem: boolean } export interface DashboardObjectSummaryResponse { generated_at: string scope: DashboardScope object: DashboardObjectSummary totals: Record checks_meta: DashboardCheckDefinition[] top_problem_devices: DashboardDeviceNOCItem[] } export interface DashboardObjectDevicesResponse { generated_at: string scope: DashboardScope object_id: number devices: DashboardDeviceNOCItem[] } export interface DashboardAvailabilityPoint { bucket_start: string bucket_end: string availability_pct: number | null samples: number online: number offline: number } export interface DashboardAvailabilityInterval { status: string started_at: string ended_at: string duration_sec: number } export interface DashboardDeviceAvailability { device_id: number ip: string hostname: string | null availability_pct: number | null samples: number online: number offline: number last_checked_at: string | null last_status: string | null last_ping_ms: number | null series: DashboardAvailabilityPoint[] intervals: DashboardAvailabilityInterval[] } export interface DashboardObjectAvailabilityResponse { generated_at: string object_id: number window: DashboardAvailabilityWindow start_at: string end_at: string bucket_sec: number overall_availability_pct: number | null overall_series: DashboardAvailabilityPoint[] devices: DashboardDeviceAvailability[] insufficient_data: boolean } export interface DashboardChecksResponse { checks: DashboardCheckDefinition[] object_overrides: DashboardObjectOverride[] } export const useDashboardHomeSummary = (scope: DashboardScope) => useQuery({ queryKey: ['dashboard-home-summary', scope], queryFn: () => api .get('/api/v1/dashboard/home-summary', { params: scope }) .then((r) => r.data), refetchInterval: 30_000, }) export const useDashboardObjectSummary = (objectId: number, scope: DashboardScope) => useQuery({ queryKey: ['dashboard-object-summary', objectId, scope], queryFn: () => api .get(`/api/v1/dashboard/object/${objectId}/summary`, { params: scope }) .then((r) => r.data), enabled: Number.isFinite(objectId) && objectId > 0, refetchInterval: 30_000, }) export const useDashboardObjectDevices = (objectId: number, scope: DashboardScope) => useQuery({ queryKey: ['dashboard-object-devices', objectId, scope], queryFn: () => api .get(`/api/v1/dashboard/object/${objectId}/devices`, { params: scope }) .then((r) => r.data), enabled: Number.isFinite(objectId) && objectId > 0, refetchInterval: 30_000, }) export const useDashboardObjectAvailability = ( objectId: number, window: DashboardAvailabilityWindow, deviceIds?: number[], compact?: boolean ) => useQuery({ queryKey: ['dashboard-object-availability', objectId, window, deviceIds, compact], queryFn: () => api .get(`/api/v1/dashboard/object/${objectId}/availability`, { params: { window, device_ids: deviceIds, compact: compact ?? false }, }) .then((r) => r.data), enabled: Number.isFinite(objectId) && objectId > 0 && (deviceIds == null || deviceIds.length > 0), refetchInterval: 45_000, }) export const useDashboardMonitorStatus = () => useQuery({ queryKey: ['dashboard-monitor-status'], queryFn: () => api .get('/api/v1/dashboard/monitor/status') .then((r) => r.data), refetchInterval: 10_000, }) export const useDashboardRunNow = () => { const qc = useQueryClient() return useMutation({ mutationFn: (body: DashboardScope & { force?: boolean }) => api.post('/api/v1/dashboard/monitor/run', body).then((r) => r.data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['dashboard-monitor-status'] }) qc.invalidateQueries({ queryKey: ['dashboard-home-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-devices'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-availability'] }) }, }) } export const useDashboardPolicy = () => useQuery({ queryKey: ['dashboard-policy'], queryFn: () => api .get('/api/v1/dashboard/monitor/policy') .then((r) => r.data), }) export const usePatchDashboardObjectPolicy = () => { const qc = useQueryClient() return useMutation({ mutationFn: (body: Array<{ object_id: number; mode: 'inherit' | 'include' | 'exclude' }>) => api.patch('/api/v1/dashboard/monitor/policy/objects', body).then((r) => r.data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['dashboard-policy'] }) qc.invalidateQueries({ queryKey: ['dashboard-home-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-summary'] }) }, }) } export const usePatchDashboardTagPolicy = () => { const qc = useQueryClient() return useMutation({ mutationFn: (body: Array<{ tag_id: number; enabled: boolean }>) => api.patch('/api/v1/dashboard/monitor/policy/tags', body).then((r) => r.data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['dashboard-policy'] }) qc.invalidateQueries({ queryKey: ['dashboard-home-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-summary'] }) }, }) } export const useDashboardChecks = () => useQuery({ queryKey: ['dashboard-checks'], queryFn: () => api .get('/api/v1/dashboard/checks') .then((r) => r.data), }) export const usePatchDashboardChecks = () => { const qc = useQueryClient() return useMutation({ mutationFn: ( body: Array<{ check_key: string enabled?: boolean interval_sec_default?: number categories?: string[] timeout_sec?: number concurrency?: number }> ) => api.patch('/api/v1/dashboard/checks', body).then((r) => r.data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['dashboard-checks'] }) qc.invalidateQueries({ queryKey: ['dashboard-home-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-devices'] }) }, }) } export const usePatchDashboardObjectOverrides = () => { const qc = useQueryClient() return useMutation({ mutationFn: ( body: Array<{ object_id: number check_key: string enabled_override?: boolean | null interval_sec_override?: number | null categories_override?: string[] | null }> ) => api.patch('/api/v1/dashboard/checks/object-overrides', body).then((r) => r.data), onSuccess: () => { qc.invalidateQueries({ queryKey: ['dashboard-checks'] }) qc.invalidateQueries({ queryKey: ['dashboard-home-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-summary'] }) qc.invalidateQueries({ queryKey: ['dashboard-object-devices'] }) }, }) }