From ec3772d4e3dd93e014a6e904296b9c95e440c0fd Mon Sep 17 00:00:00 2001 From: shankar0123 Date: Mon, 27 Apr 2026 02:48:35 +0000 Subject: [PATCH] M-029 Pass 1 batch 4: migrate 5 more 3-mutation pages to useTrackedMutation MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drains 15 more useMutation sites (33 -> 18). All five pages follow the same create/update/delete CRUD shape — invalidates the page's primary list query. Pages migrated: - OwnersPage.tsx CRUD invalidates [['owners']] (queryClient kept — modal onSuccess props use it) - PoliciesPage.tsx toggle/delete/create invalidates [['policies']] (queryClient kept — modal onSuccess prop uses it) - ProfilesPage.tsx CRUD invalidates [['profiles']] (queryClient kept — modal onSuccess prop uses it) - RenewalPoliciesPage.tsx CRUD invalidates [['renewal-policies']] (queryClient + useQueryClient dropped) - TeamsPage.tsx CRUD invalidates [['teams']] (queryClient kept — modal onSuccess props use it) Verification: legacy useMutation count 33 -> 18 (-15) useTrackedMutation count 23 -> 38 (+15) Closes 38 of 56 sites toward M-029 Pass 1 completion (68%). --- web/src/pages/OwnersPage.tsx | 15 ++++++++------- web/src/pages/PoliciesPage.tsx | 15 ++++++++------- web/src/pages/ProfilesPage.tsx | 15 ++++++++------- web/src/pages/RenewalPoliciesPage.tsx | 16 ++++++++-------- web/src/pages/TeamsPage.tsx | 15 ++++++++------- 5 files changed, 40 insertions(+), 36 deletions(-) diff --git a/web/src/pages/OwnersPage.tsx b/web/src/pages/OwnersPage.tsx index 954b792..fcfb96e 100644 --- a/web/src/pages/OwnersPage.tsx +++ b/web/src/pages/OwnersPage.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 { getOwners, getTeams, deleteOwner, createOwner, updateOwner } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -210,24 +211,24 @@ export default function OwnersPage() { queryFn: () => getTeams(), }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteOwner, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['owners'] }), + invalidates: [['owners']], onError: (err: Error) => alert(`Delete failed: ${err.message}`), }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createOwner, + invalidates: [['owners']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['owners'] }); setShowCreate(false); }, }); - const updateMutation = useMutation({ + const updateMutation = useTrackedMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => updateOwner(id, data), + invalidates: [['owners']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['owners'] }); setEditingOwner(null); }, }); diff --git a/web/src/pages/PoliciesPage.tsx b/web/src/pages/PoliciesPage.tsx index 073d521..9eadab9 100644 --- a/web/src/pages/PoliciesPage.tsx +++ b/web/src/pages/PoliciesPage.tsx @@ -1,5 +1,6 @@ import { useState } from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useQuery, useQueryClient } from '@tanstack/react-query'; +import { useTrackedMutation } from '../hooks/useTrackedMutation'; import { getPolicies, updatePolicy, deletePolicy, createPolicy } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -161,20 +162,20 @@ export default function PoliciesPage() { queryFn: () => getPolicies(), }); - const toggleMutation = useMutation({ + const toggleMutation = useTrackedMutation({ mutationFn: ({ id, enabled }: { id: string; enabled: boolean }) => updatePolicy(id, { enabled }), - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['policies'] }), + invalidates: [['policies']], }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deletePolicy, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['policies'] }), + invalidates: [['policies']], }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createPolicy, + invalidates: [['policies']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['policies'] }); setShowCreate(false); }, }); diff --git a/web/src/pages/ProfilesPage.tsx b/web/src/pages/ProfilesPage.tsx index e992740..1b84d48 100644 --- a/web/src/pages/ProfilesPage.tsx +++ b/web/src/pages/ProfilesPage.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 { getProfiles, deleteProfile, createProfile, updateProfile } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -300,23 +301,23 @@ export default function ProfilesPage() { queryFn: () => getProfiles(), }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteProfile, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['profiles'] }), + invalidates: [['profiles']], }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createProfile, + invalidates: [['profiles']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['profiles'] }); setShowCreate(false); }, }); - const updateMutation = useMutation({ + const updateMutation = useTrackedMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => updateProfile(id, data), + invalidates: [['profiles']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['profiles'] }); setEditingProfile(null); }, }); diff --git a/web/src/pages/RenewalPoliciesPage.tsx b/web/src/pages/RenewalPoliciesPage.tsx index 64b2260..709a7dc 100644 --- a/web/src/pages/RenewalPoliciesPage.tsx +++ b/web/src/pages/RenewalPoliciesPage.tsx @@ -1,5 +1,6 @@ import { useEffect, useState } from 'react'; -import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query'; +import { useQuery } from '@tanstack/react-query'; +import { useTrackedMutation } from '../hooks/useTrackedMutation'; import { getRenewalPolicies, createRenewalPolicy, @@ -174,7 +175,6 @@ function PolicyFormModal({ title, initial, isOpen, onClose, onSubmit, isSaving, } export default function RenewalPoliciesPage() { - const queryClient = useQueryClient(); const [showCreate, setShowCreate] = useState(false); const [editing, setEditing] = useState(null); @@ -183,25 +183,25 @@ export default function RenewalPoliciesPage() { queryFn: () => getRenewalPolicies(), }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createRenewalPolicy, + invalidates: [['renewal-policies']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['renewal-policies'] }); setShowCreate(false); }, }); - const updateMutation = useMutation({ + const updateMutation = useTrackedMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => updateRenewalPolicy(id, data), + invalidates: [['renewal-policies']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['renewal-policies'] }); setEditing(null); }, }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteRenewalPolicy, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['renewal-policies'] }), + invalidates: [['renewal-policies']], // Backend surfaces ErrRenewalPolicyInUse as a 409. We surface as an // alert so the operator sees "this policy is still attached to N // certificates" and can re-target those certs to another policy diff --git a/web/src/pages/TeamsPage.tsx b/web/src/pages/TeamsPage.tsx index 5e86477..f76f6c5 100644 --- a/web/src/pages/TeamsPage.tsx +++ b/web/src/pages/TeamsPage.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 { getTeams, deleteTeam, createTeam, updateTeam } from '../api/client'; import PageHeader from '../components/PageHeader'; import DataTable from '../components/DataTable'; @@ -152,24 +153,24 @@ export default function TeamsPage() { queryFn: () => getTeams(), }); - const deleteMutation = useMutation({ + const deleteMutation = useTrackedMutation({ mutationFn: deleteTeam, - onSuccess: () => queryClient.invalidateQueries({ queryKey: ['teams'] }), + invalidates: [['teams']], onError: (err: Error) => alert(`Delete failed: ${err.message}`), }); - const createMutation = useMutation({ + const createMutation = useTrackedMutation({ mutationFn: createTeam, + invalidates: [['teams']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['teams'] }); setShowCreate(false); }, }); - const updateMutation = useMutation({ + const updateMutation = useTrackedMutation({ mutationFn: ({ id, data }: { id: string; data: Partial }) => updateTeam(id, data), + invalidates: [['teams']], onSuccess: () => { - queryClient.invalidateQueries({ queryKey: ['teams'] }); setEditingTeam(null); }, });