mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-10 20:38:52 +00:00
M-029 Pass 1 batch 6 (FINAL): migrate 2 five-mutation pages — Pass 1 complete
Drains the last 10 useMutation sites (10 -> 0). Pass 1 is now COMPLETE:
every legacy useMutation site in src/pages and src/components has been
migrated to useTrackedMutation with explicit invalidates contract. The only
remaining useMutation reference in the codebase is inside useTrackedMutation.ts
itself (the wrapper).
Pages migrated:
- CertificateDetailPage.tsx 5 mutations across 2 components:
InlinePolicyEditor.saveMutation invalidates
[['certificate', certId]];
main page renew/deploy/archive/revoke invalidate
various combinations of [['certificate', id]]
and [['certificates']].
(queryClient + useQueryClient dropped from both)
- OnboardingWizard.tsx 5 mutations across 4 components:
Issuer step create/test invalidates [['issuers']]
(test refreshes last_tested_at server-side);
CreateTeamModalInline.create invalidates [['teams']];
CreateOwnerModalInline.create invalidates [['owners']];
CertificateStep.create invalidates
[['certificates'], ['dashboard-summary']].
(queryClient + useQueryClient dropped from all 4)
Verification:
legacy useMutation calls 10 -> 0 (-10) — Pass 1 COMPLETE
useTrackedMutation count 46 -> 61 (+15; some 5-mutation pages collapse
two invalidate-pairs into one array literal,
hence net is greater than the +10 removal)
Pass 1 totals: 56 useMutation sites -> 0; 0 useTrackedMutation -> 61.
Total work in Pass 1: 6 batches across 21 page files merged --no-ff to master.
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useParams, useNavigate } from 'react-router-dom';
|
import { useParams, useNavigate } from 'react-router-dom';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useTrackedMutation } from '../hooks/useTrackedMutation';
|
||||||
import { getCertificate, getCertificateVersions, triggerRenewal, triggerDeployment, archiveCertificate, revokeCertificate, updateCertificate, getTargets, getJobs, getRenewalPolicies, getProfiles, getProfile, downloadCertificatePEM, exportCertificatePKCS12 } from '../api/client';
|
import { getCertificate, getCertificateVersions, triggerRenewal, triggerDeployment, archiveCertificate, revokeCertificate, updateCertificate, getTargets, getJobs, getRenewalPolicies, getProfiles, getProfile, downloadCertificatePEM, exportCertificatePKCS12 } from '../api/client';
|
||||||
import { REVOCATION_REASONS } from '../api/types';
|
import { REVOCATION_REASONS } from '../api/types';
|
||||||
import PageHeader from '../components/PageHeader';
|
import PageHeader from '../components/PageHeader';
|
||||||
@@ -159,7 +160,6 @@ function DeploymentTimeline({ certId, certStatus, createdAt, issuedAt }: { certI
|
|||||||
}
|
}
|
||||||
|
|
||||||
function InlinePolicyEditor({ certId, currentPolicyId, currentProfileId }: { certId: string; currentPolicyId: string; currentProfileId: string }) {
|
function InlinePolicyEditor({ certId, currentPolicyId, currentProfileId }: { certId: string; currentPolicyId: string; currentProfileId: string }) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [editing, setEditing] = useState(false);
|
const [editing, setEditing] = useState(false);
|
||||||
const [policyId, setPolicyId] = useState(currentPolicyId);
|
const [policyId, setPolicyId] = useState(currentPolicyId);
|
||||||
const [profileId, setProfileId] = useState(currentProfileId);
|
const [profileId, setProfileId] = useState(currentProfileId);
|
||||||
@@ -181,13 +181,13 @@ function InlinePolicyEditor({ certId, currentPolicyId, currentProfileId }: { cer
|
|||||||
enabled: editing,
|
enabled: editing,
|
||||||
});
|
});
|
||||||
|
|
||||||
const saveMutation = useMutation({
|
const saveMutation = useTrackedMutation({
|
||||||
mutationFn: () => updateCertificate(certId, {
|
mutationFn: () => updateCertificate(certId, {
|
||||||
renewal_policy_id: policyId,
|
renewal_policy_id: policyId,
|
||||||
certificate_profile_id: profileId,
|
certificate_profile_id: profileId,
|
||||||
}),
|
}),
|
||||||
|
invalidates: [['certificate', certId]],
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificate', certId] });
|
|
||||||
setEditing(false);
|
setEditing(false);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
@@ -257,7 +257,6 @@ function InlinePolicyEditor({ certId, currentPolicyId, currentProfileId }: { cer
|
|||||||
export default function CertificateDetailPage() {
|
export default function CertificateDetailPage() {
|
||||||
const { id } = useParams<{ id: string }>();
|
const { id } = useParams<{ id: string }>();
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [showDeploy, setShowDeploy] = useState(false);
|
const [showDeploy, setShowDeploy] = useState(false);
|
||||||
const [deployTargetId, setDeployTargetId] = useState('');
|
const [deployTargetId, setDeployTargetId] = useState('');
|
||||||
const [showRevoke, setShowRevoke] = useState(false);
|
const [showRevoke, setShowRevoke] = useState(false);
|
||||||
@@ -291,38 +290,34 @@ export default function CertificateDetailPage() {
|
|||||||
enabled: !!cert?.certificate_profile_id,
|
enabled: !!cert?.certificate_profile_id,
|
||||||
});
|
});
|
||||||
|
|
||||||
const renewMutation = useMutation({
|
const renewMutation = useTrackedMutation({
|
||||||
mutationFn: () => triggerRenewal(id!),
|
mutationFn: () => triggerRenewal(id!),
|
||||||
onSuccess: () => {
|
invalidates: [['certificate', id], ['certificates']],
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificate', id] });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificates'] });
|
|
||||||
},
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const deployMutation = useMutation({
|
const deployMutation = useTrackedMutation({
|
||||||
mutationFn: () => triggerDeployment(id!, deployTargetId),
|
mutationFn: () => triggerDeployment(id!, deployTargetId),
|
||||||
|
invalidates: [['certificate', id]],
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setShowDeploy(false);
|
setShowDeploy(false);
|
||||||
setDeployTargetId('');
|
setDeployTargetId('');
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificate', id] });
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const archiveMutation = useMutation({
|
const archiveMutation = useTrackedMutation({
|
||||||
mutationFn: () => archiveCertificate(id!),
|
mutationFn: () => archiveCertificate(id!),
|
||||||
|
invalidates: [['certificates']],
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificates'] });
|
|
||||||
navigate('/certificates');
|
navigate('/certificates');
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const revokeMutation = useMutation({
|
const revokeMutation = useTrackedMutation({
|
||||||
mutationFn: () => revokeCertificate(id!, revokeReason),
|
mutationFn: () => revokeCertificate(id!, revokeReason),
|
||||||
|
invalidates: [['certificate', id], ['certificates']],
|
||||||
onSuccess: () => {
|
onSuccess: () => {
|
||||||
setShowRevoke(false);
|
setShowRevoke(false);
|
||||||
setRevokeReason('unspecified');
|
setRevokeReason('unspecified');
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificate', id] });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificates'] });
|
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
import { useQuery } from '@tanstack/react-query';
|
||||||
|
import { useTrackedMutation } from '../hooks/useTrackedMutation';
|
||||||
import { useNavigate, Link } from 'react-router-dom';
|
import { useNavigate, Link } from 'react-router-dom';
|
||||||
import {
|
import {
|
||||||
getIssuers, getAgents, getProfiles, getOwners, getTeams, getRenewalPolicies,
|
getIssuers, getAgents, getProfiles, getOwners, getTeams, getRenewalPolicies,
|
||||||
@@ -112,7 +113,6 @@ function IssuerStep({ onNext, onSkip, onIssuerCreated }: {
|
|||||||
onSkip: () => void;
|
onSkip: () => void;
|
||||||
onIssuerCreated: (issuer: Issuer) => void;
|
onIssuerCreated: (issuer: Issuer) => void;
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [selectedType, setSelectedType] = useState<string | null>(null);
|
const [selectedType, setSelectedType] = useState<string | null>(null);
|
||||||
const [configValues, setConfigValues] = useState<Record<string, unknown>>({});
|
const [configValues, setConfigValues] = useState<Record<string, unknown>>({});
|
||||||
const [issuerName, setIssuerName] = useState('');
|
const [issuerName, setIssuerName] = useState('');
|
||||||
@@ -131,23 +131,27 @@ function IssuerStep({ onNext, onSkip, onIssuerCreated }: {
|
|||||||
|
|
||||||
const typeConfig = selectedType ? issuerTypes.find(t => t.id === selectedType) : null;
|
const typeConfig = selectedType ? issuerTypes.find(t => t.id === selectedType) : null;
|
||||||
|
|
||||||
const createMutation = useMutation({
|
const createMutation = useTrackedMutation({
|
||||||
mutationFn: () => createIssuer({
|
mutationFn: () => createIssuer({
|
||||||
name: issuerName || `${typeConfig?.name || selectedType} Issuer`,
|
name: issuerName || `${typeConfig?.name || selectedType} Issuer`,
|
||||||
type: selectedType!,
|
type: selectedType!,
|
||||||
config: configValues as Record<string, unknown>,
|
config: configValues as Record<string, unknown>,
|
||||||
}),
|
}),
|
||||||
|
invalidates: [['issuers']],
|
||||||
onSuccess: (issuer) => {
|
onSuccess: (issuer) => {
|
||||||
setCreatedIssuer(issuer);
|
setCreatedIssuer(issuer);
|
||||||
onIssuerCreated(issuer);
|
onIssuerCreated(issuer);
|
||||||
queryClient.invalidateQueries({ queryKey: ['issuers'] });
|
|
||||||
setError('');
|
setError('');
|
||||||
},
|
},
|
||||||
onError: (err: Error) => setError(err.message),
|
onError: (err: Error) => setError(err.message),
|
||||||
});
|
});
|
||||||
|
|
||||||
const testMutation = useMutation({
|
// testIssuerConnection updates last_tested_at server-side; refresh the
|
||||||
|
// issuers list so the timestamp + status columns reflect the new probe.
|
||||||
|
// The local setTestResult banner still surfaces the immediate pass/fail.
|
||||||
|
const testMutation = useTrackedMutation({
|
||||||
mutationFn: () => testIssuerConnection(createdIssuer!.id),
|
mutationFn: () => testIssuerConnection(createdIssuer!.id),
|
||||||
|
invalidates: [['issuers']],
|
||||||
onSuccess: () => setTestResult({ ok: true, msg: 'Connection successful' }),
|
onSuccess: () => setTestResult({ ok: true, msg: 'Connection successful' }),
|
||||||
onError: (err: Error) => setTestResult({ ok: false, msg: err.message }),
|
onError: (err: Error) => setTestResult({ ok: false, msg: err.message }),
|
||||||
});
|
});
|
||||||
@@ -402,15 +406,14 @@ function CreateTeamModalInline({ isOpen, onClose, onCreated }: {
|
|||||||
onClose: () => void;
|
onClose: () => void;
|
||||||
onCreated: (teamId: string) => void;
|
onCreated: (teamId: string) => void;
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
const [description, setDescription] = useState('');
|
const [description, setDescription] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useTrackedMutation({
|
||||||
mutationFn: () => createTeam({ name: name.trim(), description: description.trim() }),
|
mutationFn: () => createTeam({ name: name.trim(), description: description.trim() }),
|
||||||
|
invalidates: [['teams']],
|
||||||
onSuccess: (team) => {
|
onSuccess: (team) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['teams'] });
|
|
||||||
setName('');
|
setName('');
|
||||||
setDescription('');
|
setDescription('');
|
||||||
setError('');
|
setError('');
|
||||||
@@ -475,20 +478,19 @@ function CreateOwnerModalInline({ isOpen, onClose, onCreated, teams }: {
|
|||||||
onCreated: (ownerId: string) => void;
|
onCreated: (ownerId: string) => void;
|
||||||
teams: { id: string; name: string }[];
|
teams: { id: string; name: string }[];
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
const [email, setEmail] = useState('');
|
const [email, setEmail] = useState('');
|
||||||
const [teamId, setTeamId] = useState('');
|
const [teamId, setTeamId] = useState('');
|
||||||
const [error, setError] = useState('');
|
const [error, setError] = useState('');
|
||||||
|
|
||||||
const mutation = useMutation({
|
const mutation = useTrackedMutation({
|
||||||
mutationFn: () => createOwner({
|
mutationFn: () => createOwner({
|
||||||
name: name.trim(),
|
name: name.trim(),
|
||||||
email: email.trim(),
|
email: email.trim(),
|
||||||
team_id: teamId || undefined,
|
team_id: teamId || undefined,
|
||||||
}),
|
}),
|
||||||
|
invalidates: [['owners']],
|
||||||
onSuccess: (owner) => {
|
onSuccess: (owner) => {
|
||||||
queryClient.invalidateQueries({ queryKey: ['owners'] });
|
|
||||||
setName('');
|
setName('');
|
||||||
setEmail('');
|
setEmail('');
|
||||||
setTeamId('');
|
setTeamId('');
|
||||||
@@ -574,7 +576,6 @@ function CertificateStep({ onNext, onSkip, createdIssuerId }: {
|
|||||||
onSkip: () => void;
|
onSkip: () => void;
|
||||||
createdIssuerId: string | null;
|
createdIssuerId: string | null;
|
||||||
}) {
|
}) {
|
||||||
const queryClient = useQueryClient();
|
|
||||||
const [name, setName] = useState('');
|
const [name, setName] = useState('');
|
||||||
const [commonName, setCommonName] = useState('');
|
const [commonName, setCommonName] = useState('');
|
||||||
const [sans, setSans] = useState('');
|
const [sans, setSans] = useState('');
|
||||||
@@ -608,7 +609,7 @@ function CertificateStep({ onNext, onSkip, createdIssuerId }: {
|
|||||||
|
|
||||||
const hasAgents = (agents?.data?.length ?? 0) > 0;
|
const hasAgents = (agents?.data?.length ?? 0) > 0;
|
||||||
|
|
||||||
const createMutation = useMutation({
|
const createMutation = useTrackedMutation({
|
||||||
mutationFn: async () => {
|
mutationFn: async () => {
|
||||||
const sanList = sans.split(',').map(s => s.trim()).filter(Boolean);
|
const sanList = sans.split(',').map(s => s.trim()).filter(Boolean);
|
||||||
const cert = await createCertificate({
|
const cert = await createCertificate({
|
||||||
@@ -626,10 +627,9 @@ function CertificateStep({ onNext, onSkip, createdIssuerId }: {
|
|||||||
await triggerRenewal(cert.id);
|
await triggerRenewal(cert.id);
|
||||||
return cert;
|
return cert;
|
||||||
},
|
},
|
||||||
|
invalidates: [['certificates'], ['dashboard-summary']],
|
||||||
onSuccess: (cert) => {
|
onSuccess: (cert) => {
|
||||||
setCreated(true);
|
setCreated(true);
|
||||||
queryClient.invalidateQueries({ queryKey: ['certificates'] });
|
|
||||||
queryClient.invalidateQueries({ queryKey: ['dashboard-summary'] });
|
|
||||||
setTimeout(() => onNext(cert.common_name), 1500);
|
setTimeout(() => onNext(cert.common_name), 1500);
|
||||||
},
|
},
|
||||||
onError: (err: Error) => setError(err.message),
|
onError: (err: Error) => setError(err.message),
|
||||||
|
|||||||
Reference in New Issue
Block a user