diff --git a/web/src/pages/AgentGroupsPage.tsx b/web/src/pages/AgentGroupsPage.tsx index 77eecf4..574efb1 100644 --- a/web/src/pages/AgentGroupsPage.tsx +++ b/web/src/pages/AgentGroupsPage.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useTrackedMutation } from '../hooks/useTrackedMutation'; import { getAgentGroups, deleteAgentGroup, createAgentGroup, updateAgentGroup } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -259,23 +260,23 @@ export default function AgentGroupsPage() { queryFn: () => getAgentGroups(), }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteAgentGroup, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['agent-groups'] }), + invalidates: [['agent-groups']], }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createAgentGroup, + invalidates: [['agent-groups']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['agent-groups'] }); setShowCreate(false); }, }); - const updateMutation = useMutation({ + const updateMutation = useTrackedMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => updateAgentGroup(id, data), + invalidates: [['agent-groups']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['agent-groups'] }); setEditingGroup(null); }, }); diff --git a/web/src/pages/HealthMonitorPage.tsx b/web/src/pages/HealthMonitorPage.tsx index b05497a..8ef211c 100644 --- a/web/src/pages/HealthMonitorPage.tsx +++ b/web/src/pages/HealthMonitorPage.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import { useTrackedMutation } from '../hooks/useTrackedMutation'; import { listHealthChecks, createHealthCheck, @@ -139,7 +140,6 @@ function SummaryBar({ summary }: { summary: HealthCheckSummary }) { export default function HealthMonitorPage() { const [showCreate, setShowCreate] = useState(false); const [statusFilter, setStatusFilter] = useState(); - const queryClient = useQueryClient(); const { data, isLoading, error, refetch } = useQuery({ queryKey: ['health-checks', statusFilter], @@ -153,29 +153,26 @@ export default function HealthMonitorPage() { refetchInterval: 30000, }); - const createMutation = useMutation({ + // Every health-check mutation invalidates the same two queries: the list + // (rows reflect new state) and the summary (counts reflect new state). + const healthCheckInvalidates = [['health-checks'], ['health-checks-summary']]; + + const createMutation = useTrackedMutation({ mutationFn: createHealthCheck, + invalidates: healthCheckInvalidates, onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['health-checks'] }); - queryClient.invalidateQueries({ queryKey: ['health-checks-summary'] }); setShowCreate(false); }, }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteHealthCheck, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['health-checks'] }); - queryClient.invalidateQueries({ queryKey: ['health-checks-summary'] }); - }, + invalidates: healthCheckInvalidates, }); - const acknowledgeMutation = useMutation({ + const acknowledgeMutation = useTrackedMutation({ mutationFn: acknowledgeHealthCheck, - onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['health-checks'] }); - queryClient.invalidateQueries({ queryKey: ['health-checks-summary'] }); - }, + invalidates: healthCheckInvalidates, }); const columns: Column[] = [ diff --git a/web/src/pages/JobsPage.tsx b/web/src/pages/JobsPage.tsx index fb8c4bb..cd8b499 100644 --- a/web/src/pages/JobsPage.tsx +++ b/web/src/pages/JobsPage.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import { Link } from 'react-router-dom'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import { useTrackedMutation } from '../hooks/useTrackedMutation'; import { getJobs, cancelJob, approveRenewal, rejectRenewal } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -73,7 +74,6 @@ export default function JobsPage() { const [statusFilter, setStatusFilter] = useState(''); const [typeFilter, setTypeFilter] = useState(''); const [rejectingJob, setRejectingJob] = useState(null); - const queryClient = useQueryClient(); const params: Record = {}; if (statusFilter) params.status = statusFilter; @@ -85,20 +85,20 @@ export default function JobsPage() { refetchInterval: 10000, }); - const cancelMutation = useMutation({ + const cancelMutation = useTrackedMutation({ mutationFn: cancelJob, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['jobs'] }), + invalidates: [['jobs']], }); - const approveMutation = useMutation({ + const approveMutation = useTrackedMutation({ mutationFn: approveRenewal, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['jobs'] }), + invalidates: [['jobs']], }); - const rejectMutation = useMutation({ + const rejectMutation = useTrackedMutation({ mutationFn: ({ id, reason }: { id: string; reason: string }) => rejectRenewal(id, reason), + invalidates: [['jobs']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['jobs'] }); setRejectingJob(null); }, });