mirror of
https://github.com/shankar0123/certctl.git
synced 2026-06-07 13:51:36 +00:00
fix(scep-intune): use useTrackedMutation for trust-anchor reload (M-009)
Phase 9 follow-up — the M-009 hard-zero regression guard in
.github/workflows/ci.yml flagged the SCEPAdminPage's reload mutation as
a bare useMutation() call. The repo's invalidation contract requires
every mutation to go through useTrackedMutation with explicit
invalidates: QueryKey[] | 'noop' so cached data never goes stale after
a write.
Swap the bare useMutation for useTrackedMutation with
invalidates: [['admin', 'scep', 'intune', 'stats']] — the trust-anchor
reload changes the per-profile trust pool reflected in IntuneStats, so
the stats query MUST refetch on success. The audit-log queries stay on
their own 60s timer (a SIGHUP-equivalent reload doesn't backfill new
audit rows; nothing to invalidate there).
Verification:
* tsc --noEmit clean
* vitest SCEPAdminPage.test.tsx: 13/13 still pass (the wrapper's
onSuccess fires AFTER invalidation, so the modal-close + state
reset assertions hold)
* M-009 grep guard reproduced locally — bare useMutation sites = 0
This commit is contained in:
@@ -1,9 +1,10 @@
|
||||
import { useState } from 'react';
|
||||
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
||||
import { useQuery } from '@tanstack/react-query';
|
||||
import { getAdminSCEPIntuneStats, reloadAdminSCEPIntuneTrust, getAuditEvents } from '../api/client';
|
||||
import PageHeader from '../components/PageHeader';
|
||||
import ErrorState from '../components/ErrorState';
|
||||
import { useAuth } from '../components/AuthProvider';
|
||||
import { useTrackedMutation } from '../hooks/useTrackedMutation';
|
||||
import { formatDateTime } from '../api/utils';
|
||||
import type { IntuneStatsSnapshot, IntuneTrustAnchorInfo, AuditEvent } from '../api/types';
|
||||
|
||||
@@ -299,7 +300,6 @@ function RecentFailuresTable({ events }: { events: AuditEvent[] }) {
|
||||
|
||||
export default function SCEPAdminPage() {
|
||||
const auth = useAuth();
|
||||
const queryClient = useQueryClient();
|
||||
const [reloadTarget, setReloadTarget] = useState<IntuneStatsSnapshot | null>(null);
|
||||
const [reloadError, setReloadError] = useState<string | undefined>(undefined);
|
||||
|
||||
@@ -328,12 +328,23 @@ export default function SCEPAdminPage() {
|
||||
refetchInterval: 60_000,
|
||||
});
|
||||
|
||||
const reloadMutation = useMutation({
|
||||
// Bundle-8 / M-009 invalidation contract: trust-anchor reload changes
|
||||
// both the per-profile trust pool (reflected in IntuneStats) AND every
|
||||
// recently-failed Intune enrollment counter that might now succeed on
|
||||
// retry. We invalidate the stats key so the per-profile trust-anchor
|
||||
// panel reflects the new pool immediately; the audit log queries
|
||||
// remain on their 60s timer (a SIGHUP-equivalent reload doesn't
|
||||
// backfill new audit rows).
|
||||
const reloadMutation = useTrackedMutation<
|
||||
Awaited<ReturnType<typeof reloadAdminSCEPIntuneTrust>>,
|
||||
Error,
|
||||
string
|
||||
>({
|
||||
mutationFn: (pathID: string) => reloadAdminSCEPIntuneTrust(pathID),
|
||||
invalidates: [['admin', 'scep', 'intune', 'stats']],
|
||||
onSuccess: () => {
|
||||
setReloadTarget(null);
|
||||
setReloadError(undefined);
|
||||
void queryClient.invalidateQueries({ queryKey: ['admin', 'scep', 'intune', 'stats'] });
|
||||
},
|
||||
onError: (err: Error) => {
|
||||
setReloadError(err.message);
|
||||
|
||||
Reference in New Issue
Block a user