diff --git a/src/Web/autopilot-monitor-web/app/admin/backups/detail/page.tsx b/src/Web/autopilot-monitor-web/app/admin/backups/detail/page.tsx index 52f715bc..58a03a4e 100644 --- a/src/Web/autopilot-monitor-web/app/admin/backups/detail/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/backups/detail/page.tsx @@ -60,7 +60,10 @@ function BackupDetailContent() { }, [backupId, getAccessToken, setError]); useEffect(() => { - void load(); + const run = async () => { + await load(); + }; + void run(); }, [load]); const openRestoreModal = async (tableName: string, pk: string, rk: string) => { diff --git a/src/Web/autopilot-monitor-web/app/admin/backups/page.tsx b/src/Web/autopilot-monitor-web/app/admin/backups/page.tsx index db597bb1..b14d48f3 100644 --- a/src/Web/autopilot-monitor-web/app/admin/backups/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/backups/page.tsx @@ -44,7 +44,10 @@ export default function BackupsListPage() { }, [getAccessToken, setError]); useEffect(() => { - void load(); + const run = async () => { + await load(); + }; + void run(); }, [load]); // Poll the active job until terminal, then refresh the list. @@ -57,7 +60,10 @@ export default function BackupsListPage() { activeJob.state === "BlockedTerminal" ) { // Terminal — final refresh and stop polling. - void load(); + const run = async () => { + await load(); + }; + void run(); return; } diff --git a/src/Web/autopilot-monitor-web/app/admin/components/DistressReportsSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/DistressReportsSection.tsx index 5c67ccd2..9daa09e6 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/DistressReportsSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/DistressReportsSection.tsx @@ -168,7 +168,10 @@ export function DistressReportsSection({ }; useEffect(() => { - fetchReports(); + const run = async () => { + await fetchReports(); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/FeedbackSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/FeedbackSection.tsx index 6e0e4987..caa252d9 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/FeedbackSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/FeedbackSection.tsx @@ -74,7 +74,10 @@ export function FeedbackSection({ getAccessToken, setError }: FeedbackSectionPro }, [getAccessToken, setError]); useEffect(() => { - fetchFeedback(); + const run = async () => { + await fetchFeedback(); + }; + void run(); }, [fetchFeedback]); // Partition by tab. Server returns mixed; client splits + filters per active tab so the diff --git a/src/Web/autopilot-monitor-web/app/admin/components/IgnoredSoftwareTab.tsx b/src/Web/autopilot-monitor-web/app/admin/components/IgnoredSoftwareTab.tsx index 9c8dcd0f..bf2b2a78 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/IgnoredSoftwareTab.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/IgnoredSoftwareTab.tsx @@ -59,7 +59,10 @@ export function IgnoredSoftwareTab({ // Lazy load on mount useEffect(() => { if (!ignoredLoaded) { - fetchIgnoredSoftware(); + const run = async () => { + await fetchIgnoredSoftware(); + }; + void run(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [ignoredLoaded]); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/MappedSoftwareTab.tsx b/src/Web/autopilot-monitor-web/app/admin/components/MappedSoftwareTab.tsx index 82901c58..883f41ff 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/MappedSoftwareTab.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/MappedSoftwareTab.tsx @@ -83,7 +83,10 @@ export function MappedSoftwareTab({ // Lazy load on first render useEffect(() => { if (!mappedLoaded) { - fetchCpeMappings(); + const run = async () => { + await fetchCpeMappings(); + }; + void run(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [mappedLoaded]); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/OpsEventsSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/OpsEventsSection.tsx index d74e1629..947c4dec 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/OpsEventsSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/OpsEventsSection.tsx @@ -179,10 +179,13 @@ export function OpsEventsSection({ // re-fire after every successful page-N click, race a page-1 fetch against // it, and snap the user back to page 1. useEffect(() => { - setContinuation(null); - setContinuationStack([]); - setPageNumber(1); - fetchEvents(null); + const run = async () => { + setContinuation(null); + setContinuationStack([]); + setPageNumber(1); + await fetchEvents(null); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [categoryFilter, dateFromIso, dateToIso]); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/TenantAdminSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/TenantAdminSection.tsx index d2dceacf..59d2c50e 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/TenantAdminSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/TenantAdminSection.tsx @@ -68,7 +68,10 @@ export function TenantAdminSection({ }; useEffect(() => { - fetchTenantAdmins(tenantId); + const run = async () => { + await fetchTenantAdmins(tenantId); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [tenantId]); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/UnmappedSoftwareTab.tsx b/src/Web/autopilot-monitor-web/app/admin/components/UnmappedSoftwareTab.tsx index cc14452a..7f76fde5 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/UnmappedSoftwareTab.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/UnmappedSoftwareTab.tsx @@ -112,17 +112,23 @@ export function UnmappedSoftwareTab({ // Load on mount + whenever the page index changes useEffect(() => { - fetchPage(currentPage); + const run = async () => { + await fetchPage(currentPage); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [currentPage]); // Refresh when parent signals (e.g. item restored from ignored tab) — reset to page 0 useEffect(() => { if (refreshTrigger > 0) { - setSavedMappings(new Set()); - setSelectedEntries(new Map()); - if (currentPage !== 0) setCurrentPage(0); - else fetchPage(0); + const run = async () => { + setSavedMappings(new Set()); + setSelectedEntries(new Map()); + if (currentPage !== 0) setCurrentPage(0); + else await fetchPage(0); + }; + void run(); } // eslint-disable-next-line react-hooks/exhaustive-deps }, [refreshTrigger]); diff --git a/src/Web/autopilot-monitor-web/app/admin/components/VulnerabilityDataSection.tsx b/src/Web/autopilot-monitor-web/app/admin/components/VulnerabilityDataSection.tsx index d4f0cddd..4bb2bafb 100644 --- a/src/Web/autopilot-monitor-web/app/admin/components/VulnerabilityDataSection.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/components/VulnerabilityDataSection.tsx @@ -96,7 +96,10 @@ export function VulnerabilityDataSection({ }, [getAccessToken]); useEffect(() => { - void refreshSyncStatus(); + const run = async () => { + await refreshSyncStatus(); + }; + void run(); }, [refreshSyncStatus]); const refreshSummary = useCallback(async () => { @@ -120,7 +123,10 @@ export function VulnerabilityDataSection({ }, [getAccessToken, summaryDays]); useEffect(() => { - void refreshSummary(); + const run = async () => { + await refreshSummary(); + }; + void run(); }, [refreshSummary]); // Sync local state when adminConfig changes (initial load) diff --git a/src/Web/autopilot-monitor-web/app/admin/customs-archive/detail/page.tsx b/src/Web/autopilot-monitor-web/app/admin/customs-archive/detail/page.tsx index a15e37cf..70d73a5b 100644 --- a/src/Web/autopilot-monitor-web/app/admin/customs-archive/detail/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/customs-archive/detail/page.tsx @@ -58,7 +58,10 @@ function CustomsArchiveDetailContent() { }, [tenantId, historyRowKey, getAccessToken, setError]); useEffect(() => { - void load(); + const run = async () => { + await load(); + }; + void run(); }, [load]); const toggleExpand = useCallback(async (entry: CustomsArchiveEntrySummary) => { diff --git a/src/Web/autopilot-monitor-web/app/admin/customs-archive/page.tsx b/src/Web/autopilot-monitor-web/app/admin/customs-archive/page.tsx index 379b6621..cdf8fb3d 100644 --- a/src/Web/autopilot-monitor-web/app/admin/customs-archive/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/customs-archive/page.tsx @@ -43,7 +43,10 @@ export default function CustomsArchivePage() { }, [filter, getAccessToken, setError]); useEffect(() => { - void load(); + const run = async () => { + await load(); + }; + void run(); }, [load]); const confirmDelete = useCallback(async () => { diff --git a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionAgentMetrics.tsx b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionAgentMetrics.tsx index e1ae5b58..38871634 100644 --- a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionAgentMetrics.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionAgentMetrics.tsx @@ -225,7 +225,10 @@ export function SectionAgentMetrics() { // accounts refresh which would otherwise re-fire the effect after each // request and ping-pong the loading spinner. useEffect(() => { - fetchMetrics(sampleSize, windowDays); + const run = async () => { + await fetchMetrics(sampleSize, windowDays); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [sampleSize, windowDays]); diff --git a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionMcpUsage.tsx b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionMcpUsage.tsx index 42b2a90c..fa748fb3 100644 --- a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionMcpUsage.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionMcpUsage.tsx @@ -90,7 +90,10 @@ export function SectionMcpUsage() { }, [getAccessToken]); useEffect(() => { - fetchData(dateRange); + const run = async () => { + await fetchData(dateRange); + }; + void run(); }, [fetchData, dateRange]); // Aggregate by user diff --git a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionPlatformUsage.tsx b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionPlatformUsage.tsx index eb93b5a8..f089765e 100644 --- a/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionPlatformUsage.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/metrics/sections/SectionPlatformUsage.tsx @@ -156,7 +156,10 @@ export function SectionPlatformUsage() { useEffect(() => { // Fetch metrics on mount // Authorization is handled by admin layout ProtectedRoute - fetchMetrics(); + const run = async () => { + await fetchMetrics(); + }; + void run(); }, [fetchMetrics]); const formatDuration = (minutes: number) => { diff --git a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/DeletionManifestSummaryView.tsx b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/DeletionManifestSummaryView.tsx index c8ad4da8..1c665f3b 100644 --- a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/DeletionManifestSummaryView.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/DeletionManifestSummaryView.tsx @@ -62,10 +62,10 @@ export function DeletionManifestSummaryView({ useEffect(() => { let cancelled = false; - setLoading(true); - setError(null); - setSummary(null); (async () => { + setLoading(true); + setError(null); + setSummary(null); try { const resp = await authenticatedFetch( api.sessionDeletions.storedManifest(sessionId, tenantId, manifestId, "summary"), diff --git a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/MaintenanceStatusBanner.tsx b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/MaintenanceStatusBanner.tsx index aec46d9b..61835d3b 100644 --- a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/MaintenanceStatusBanner.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/MaintenanceStatusBanner.tsx @@ -120,7 +120,10 @@ export function MaintenanceStatusBanner({ }, [getAccessToken, setError]); useEffect(() => { - void fetchStatus(); + const run = async () => { + await fetchStatus(); + }; + void run(); }, [fetchStatus, refreshKey]); const triggerRun = useCallback(async () => { diff --git a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/RestoreBrowserTab.tsx b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/RestoreBrowserTab.tsx index 63068920..64e80e72 100644 --- a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/RestoreBrowserTab.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/components/RestoreBrowserTab.tsx @@ -85,8 +85,8 @@ export function RestoreBrowserTab({ getAccessToken, setError, setSuccessMessage if (!onlyWithRestore || tenantsWithRestore !== null) return; const controller = new AbortController(); let cancelled = false; - setLoadingRestoreFilter(true); (async () => { + setLoadingRestoreFilter(true); try { const resp = await authenticatedFetch( api.sessionDeletions.tenantsWithManifests(), @@ -142,23 +142,24 @@ export function RestoreBrowserTab({ getAccessToken, setError, setSuccessMessage // the operator never sees stale manifests / preview / restore-action that belong to the // previous tenant. Codex P2. useEffect(() => { - // Immediate clear: dropping the displayed data on switch means the operator never has a - // "this manifest from tenant A is selected while the dropdown says tenant B" moment. - setSessions(null); - setExpandedSessions(new Set()); - setSelection(null); - setLoadedTenantId(""); - - if (!selectedTenantId) { - setLoadingSessions(false); - return; - } - const controller = new AbortController(); let cancelled = false; - setLoadingSessions(true); (async () => { + // Immediate clear: dropping the displayed data on switch means the operator never has a + // "this manifest from tenant A is selected while the dropdown says tenant B" moment. + setSessions(null); + setExpandedSessions(new Set()); + setSelection(null); + setLoadedTenantId(""); + + if (!selectedTenantId) { + setLoadingSessions(false); + return; + } + + setLoadingSessions(true); + try { const resp = await authenticatedFetch( api.sessionDeletions.tenantManifests(selectedTenantId), diff --git a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/page.tsx b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/page.tsx index 5a597606..a9dc3f41 100644 --- a/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/ops/session-cleanup/page.tsx @@ -176,7 +176,10 @@ function InFlightTab({ }, [getAccessToken, setError]); useEffect(() => { - void fetchAll(); + const run = async () => { + await fetchAll(); + }; + void run(); }, [fetchAll, refreshKey]); return ( @@ -253,7 +256,10 @@ function PoisonedTab({ }, [getAccessToken, setError]); useEffect(() => { - void fetchPoisoned(); + const run = async () => { + await fetchPoisoned(); + }; + void run(); }, [fetchPoisoned, refreshKey]); return ( @@ -353,7 +359,10 @@ function StrandedTab({ }, [getAccessToken, setError]); useEffect(() => { - void fetchStranded(); + const run = async () => { + await fetchStranded(); + }; + void run(); }, [fetchStranded, refreshKey]); return ( diff --git a/src/Web/autopilot-monitor-web/app/admin/presence/page.tsx b/src/Web/autopilot-monitor-web/app/admin/presence/page.tsx index 314bb926..06e05393 100644 --- a/src/Web/autopilot-monitor-web/app/admin/presence/page.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/presence/page.tsx @@ -92,7 +92,10 @@ export default function PresencePage() { // Initial load + whenever the window changes. useEffect(() => { - fetchPresence(); + const run = async () => { + await fetchPresence(); + }; + void run(); }, [fetchPresence, windowMinutes]); // Auto-refresh on a fixed interval (reads the current window via ref). diff --git a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionDelegatedAdmins.tsx b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionDelegatedAdmins.tsx index 10d705d3..9e30f00a 100644 --- a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionDelegatedAdmins.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionDelegatedAdmins.tsx @@ -80,7 +80,10 @@ export function SectionDelegatedAdmins() { }, [getAccessToken]); useEffect(() => { - fetchAssignments(); + const run = async () => { + await fetchAssignments(); + }; + void run(); }, [fetchAssignments]); const handleGrant = useCallback(async () => { diff --git a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionTenantGroups.tsx b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionTenantGroups.tsx index 269b8035..961f2dd0 100644 --- a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionTenantGroups.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionTenantGroups.tsx @@ -89,7 +89,10 @@ export function SectionTenantGroups() { }, [getAccessToken]); useEffect(() => { - fetchGroups(); + const run = async () => { + await fetchGroups(); + }; + void run(); }, [fetchGroups]); /** Runs a mutation with shared busy/error/refetch handling. `body` undefined ⇒ no JSON body. */ diff --git a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionUsagePlans.tsx b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionUsagePlans.tsx index 2e331197..8a9139d2 100644 --- a/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionUsagePlans.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/settings/sections/SectionUsagePlans.tsx @@ -57,7 +57,10 @@ export function SectionUsagePlans() { }, [getAccessToken]); useEffect(() => { - fetchTiers(); + const run = async () => { + await fetchTiers(); + }; + void run(); }, [fetchTiers]); const handleSave = useCallback(async () => { diff --git a/src/Web/autopilot-monitor-web/app/admin/tenants/sections/SectionTenantConfigReport.tsx b/src/Web/autopilot-monitor-web/app/admin/tenants/sections/SectionTenantConfigReport.tsx index 1ab52506..f4bd71f1 100644 --- a/src/Web/autopilot-monitor-web/app/admin/tenants/sections/SectionTenantConfigReport.tsx +++ b/src/Web/autopilot-monitor-web/app/admin/tenants/sections/SectionTenantConfigReport.tsx @@ -406,7 +406,10 @@ export function SectionTenantConfigReport() { }, [selectedTenantId, getAccessToken]); useEffect(() => { - fetchConfig(); + const run = async () => { + await fetchConfig(); + }; + void run(); }, [fetchConfig]); // Computed runtime diff --git a/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx b/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx index 8c254a56..1ca9d538 100644 --- a/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/components/InventoryTab.tsx @@ -50,10 +50,10 @@ export default function InventoryTab({ scope }: { scope: SoftwareTabScope }) { useEffect(() => { if (!scopeInitialized) return; if (!isGlobalAdmin && !tenantId) return; - if (needsTenantPick) { setResp(null); setLoading(false); return; } let cancelled = false; const run = async () => { + if (needsTenantPick) { setResp(null); setLoading(false); return; } try { setLoading(true); const url = routeGlobal diff --git a/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx b/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx index a274b2c5..d7e92418 100644 --- a/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx +++ b/src/Web/autopilot-monitor-web/app/apps/detail/page.tsx @@ -358,8 +358,11 @@ function AppDetailContent() { // wrong scope before the GA default-to-own-tenant has settled. useEffect(() => { if (!scopeInitialized) return; - setSessionsOffset(0); - Promise.all([fetchAnalytics(), fetchSessions(0, statusFilter)]); + const run = async () => { + setSessionsOffset(0); + await Promise.all([fetchAnalytics(), fetchSessions(0, statusFilter)]); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [scopeInitialized, days, scopeKey]); diff --git a/src/Web/autopilot-monitor-web/app/audit/page.tsx b/src/Web/autopilot-monitor-web/app/audit/page.tsx index 75bbc92d..f6c674f1 100644 --- a/src/Web/autopilot-monitor-web/app/audit/page.tsx +++ b/src/Web/autopilot-monitor-web/app/audit/page.tsx @@ -156,10 +156,13 @@ export default function AuditPage() { // delegated caller) so we don't fire a wasted request in the wrong scope. scopeKey changes on a // tenant/GA-mode switch → refetch from page 1. if (!scopeInitialized) return; - setContinuation(null); - setContinuationStack([]); - setPageNumber(1); - fetchPage(null, true); + const run = async () => { + setContinuation(null); + setContinuationStack([]); + setPageNumber(1); + await fetchPage(null, true); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [scopeKey, scopeInitialized, dateFromIso, dateToIso, excludeDeletions]); diff --git a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardStats.ts b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardStats.ts index cdf61900..f7c30b0d 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardStats.ts +++ b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useDashboardStats.ts @@ -201,8 +201,11 @@ export function useDashboardStats({ useEffect(() => { if (disabled) return; if (!globalAdminMode && !tenantId) return; - setStats(null); - fetchStats(); + const run = async () => { + setStats(null); + await fetchStats(); + }; + void run(); // fetchStats is stable; intentionally not in deps to avoid re-running on identity flips. // eslint-disable-next-line react-hooks/exhaustive-deps }, [tenantId, globalAdminMode, submittedTenantIdFilter, days, disabled]); diff --git a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useTenantList.ts b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useTenantList.ts index 6c1289a5..a84fdfa0 100644 --- a/src/Web/autopilot-monitor-web/app/dashboard/hooks/useTenantList.ts +++ b/src/Web/autopilot-monitor-web/app/dashboard/hooks/useTenantList.ts @@ -21,12 +21,12 @@ export function useTenantList( const [tenantList, setTenantList] = useState([]); useEffect(() => { - if (!globalAdminMode) { - setTenantList([]); - return; - } let cancelled = false; - (async () => { + const run = async () => { + if (!globalAdminMode) { + setTenantList([]); + return; + } try { const res = await authenticatedFetch(api.config.all(), getAccessToken); if (!res.ok || cancelled) return; @@ -40,7 +40,8 @@ export function useTenantList( } catch { // Non-critical — tenant autocomplete just won't work } - })(); + }; + void run(); return () => { cancelled = true; }; }, [globalAdminMode, getAccessToken]); diff --git a/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx b/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx index 3dbbfab4..a1e350a2 100644 --- a/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx +++ b/src/Web/autopilot-monitor-web/app/diagnosis/page.tsx @@ -158,33 +158,39 @@ function DiagnosisContent() { useEffect(() => { if (!sessionId) return; if (!globalAdminMode && !tenantId) return; // wait for real tenant ID - sessionIdRef.current = sessionId; - if (lastFetchedSessionId.current !== sessionId) { - hasInitialFetch.current = false; - lastFetchedSessionId.current = sessionId; - sessionFetchDone.current = false; - analysisFetchDone.current = false; - setSessionTenantId(null); - setLoading(true); - } - if (hasInitialFetch.current) return; - hasInitialFetch.current = true; + const run = async () => { + sessionIdRef.current = sessionId; + if (lastFetchedSessionId.current !== sessionId) { + hasInitialFetch.current = false; + lastFetchedSessionId.current = sessionId; + sessionFetchDone.current = false; + analysisFetchDone.current = false; + setSessionTenantId(null); + setLoading(true); + } + if (hasInitialFetch.current) return; + hasInitialFetch.current = true; - // Performance: eager-set sessionTenantId from TenantContext when known, so - // the events/analysis effect fires in parallel with fetchSessionDetails - // instead of waiting for its roundtrip — eliminates the fetch waterfall. - // Global Admins in all-tenant view fall through with null (backend resolves - // the tenant from the session itself). - if (!globalAdminMode && isGuid(tenantId)) { - setSessionTenantId(tenantId); - } + // Performance: eager-set sessionTenantId from TenantContext when known, so + // the events/analysis effect fires in parallel with fetchSessionDetails + // instead of waiting for its roundtrip — eliminates the fetch waterfall. + // Global Admins in all-tenant view fall through with null (backend resolves + // the tenant from the session itself). + if (!globalAdminMode && isGuid(tenantId)) { + setSessionTenantId(tenantId); + } - fetchSessionDetails(); + await fetchSessionDetails(); + }; + void run(); }, [sessionId, tenantId, globalAdminMode, fetchSessionDetails]); useEffect(() => { if (sessionTenantId && sessionId) { - Promise.all([fetchEvents(), fetchAnalysisResults()]); + const run = async () => { + await Promise.all([fetchEvents(), fetchAnalysisResults()]); + }; + void run(); } }, [sessionTenantId, sessionId, fetchEvents, fetchAnalysisResults]); diff --git a/src/Web/autopilot-monitor-web/app/fleet-health/hooks/useFleetHealth.ts b/src/Web/autopilot-monitor-web/app/fleet-health/hooks/useFleetHealth.ts index f2ab36e6..f18f4694 100644 --- a/src/Web/autopilot-monitor-web/app/fleet-health/hooks/useFleetHealth.ts +++ b/src/Web/autopilot-monitor-web/app/fleet-health/hooks/useFleetHealth.ts @@ -210,8 +210,11 @@ export function useFleetHealth({ // previous-scope numbers don't linger if the refetch errors out. useEffect(() => { if (!scopeInitialized) return; - setData(null); - fetchData(); + const run = async () => { + setData(null); + await fetchData(); + }; + void run(); // fetchData is stable; scopeKey/days drive the refetch. // eslint-disable-next-line react-hooks/exhaustive-deps }, [scopeInitialized, scopeKey, days]); diff --git a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx index fe130cbb..1fe5666c 100644 --- a/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx +++ b/src/Web/autopilot-monitor-web/app/fleet-health/page.tsx @@ -103,7 +103,10 @@ export default function FleetHealthPage() { // App install metrics are already backend-aggregated; fetch alongside fleet data. useEffect(() => { if (!scopeInitialized) return; - fetchAppMetrics(timeRange); + const run = async () => { + await fetchAppMetrics(timeRange); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [scopeInitialized, timeRange, scopeKey]); diff --git a/src/Web/autopilot-monitor-web/app/fleet/hooks/useFleetSummaries.ts b/src/Web/autopilot-monitor-web/app/fleet/hooks/useFleetSummaries.ts index f223cae6..7220ac99 100644 --- a/src/Web/autopilot-monitor-web/app/fleet/hooks/useFleetSummaries.ts +++ b/src/Web/autopilot-monitor-web/app/fleet/hooks/useFleetSummaries.ts @@ -37,16 +37,16 @@ export function useFleetSummaries(tenantIds: string[], days: number, homeTenantI const key = [...tenantIds].sort().join(","); useEffect(() => { - if (tenantIds.length === 0) { - setSummaries({}); - setLoading(false); - return; - } - let cancelled = false; - setLoading(true); const run = async () => { + if (tenantIds.length === 0) { + setSummaries({}); + setLoading(false); + return; + } + setLoading(true); + const queue = [...tenantIds]; const result: Record = {}; @@ -79,7 +79,7 @@ export function useFleetSummaries(tenantIds: string[], days: number, homeTenantI } }; - run(); + void run(); return () => { cancelled = true; }; diff --git a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx index 7c26261d..ae8641ea 100644 --- a/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx +++ b/src/Web/autopilot-monitor-web/app/gather-rules/page.tsx @@ -106,10 +106,10 @@ export default function GatherRulesPage() { // badge showing the GA's HOME-tenant mode for every foreign tenant.) useEffect(() => { if (!effectiveTenantId) return; - // Reset first so a failed/forbidden fetch never carries the previous tenant's mode over. - setUnrestrictedMode(false); let stale = false; - const fetchConfig = async () => { + const run = async () => { + // Reset first so a failed/forbidden fetch never carries the previous tenant's mode over. + setUnrestrictedMode(false); try { const response = await authenticatedFetch(api.config.featureFlags(effectiveTenantId), getAccessToken); if (!stale && response.ok) { @@ -120,7 +120,7 @@ export default function GatherRulesPage() { // Silently default to restricted mode } }; - fetchConfig(); + void run(); return () => { stale = true; }; }, [effectiveTenantId, getAccessToken]); diff --git a/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx b/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx index 1a139329..96b4a7f3 100644 --- a/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx +++ b/src/Web/autopilot-monitor-web/app/geographic-performance/page.tsx @@ -187,12 +187,15 @@ export default function GeographicPerformancePage() { useEffect(() => { if (!scopeInitialized) return; - if (isTimeRangeMount.current) { - isTimeRangeMount.current = false; - } else { - setLoading(true); - } - fetchGeoMetrics(timeRange, groupBy); + const run = async () => { + if (isTimeRangeMount.current) { + isTimeRangeMount.current = false; + } else { + setLoading(true); + } + await fetchGeoMetrics(timeRange, groupBy); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [scopeInitialized, timeRange, groupBy, scopeKey]); diff --git a/src/Web/autopilot-monitor-web/app/health-check/page.tsx b/src/Web/autopilot-monitor-web/app/health-check/page.tsx index 3c25a636..71cea7e1 100644 --- a/src/Web/autopilot-monitor-web/app/health-check/page.tsx +++ b/src/Web/autopilot-monitor-web/app/health-check/page.tsx @@ -109,8 +109,10 @@ export default function HealthCheckPage() { // fast backend checks render immediately while the MCP probe (possible cold start) catches up. useEffect(() => { if (user && !hasRun) { - performHealthCheck(); - performMcpCheck(); + const run = async () => { + await Promise.all([performHealthCheck(), performMcpCheck()]); + }; + void run(); } }, [user, hasRun, performHealthCheck, performMcpCheck]); diff --git a/src/Web/autopilot-monitor-web/app/progress/hooks/useProgressEvents.ts b/src/Web/autopilot-monitor-web/app/progress/hooks/useProgressEvents.ts index 24f05837..824a2fa8 100644 --- a/src/Web/autopilot-monitor-web/app/progress/hooks/useProgressEvents.ts +++ b/src/Web/autopilot-monitor-web/app/progress/hooks/useProgressEvents.ts @@ -54,61 +54,64 @@ export function useProgressEvents({ // Reset per-session fetch guard + events when the selected session changes useEffect(() => { - if (!session) { - lastFetchedSessionId.current = null; - setEvents([]); - return; - } - if (lastFetchedSessionId.current === session.sessionId) return; - lastFetchedSessionId.current = session.sessionId; - setEvents([]); - - const fetchEvents = async () => { - try { - const response = await authenticatedFetch( - api.progress.sessionEvents(session.sessionId, tenantId), - getAccessToken, - ); - if (response.ok) { - const data = await response.json(); - const fetched: EnrollmentEvent[] = data.events || []; - setEvents((prev) => { - if (prev.length === 0) return fetched; - const existingIds = new Set(prev.map((e) => e.eventId)); - const newEvents = fetched.filter((e) => !existingIds.has(e.eventId)); - if (newEvents.length === 0) return prev; - return [...prev, ...newEvents].sort( - (a, b) => a.sequence - b.sequence, - ); - }); - } else { - addNotification( - "error", - "Backend Error", - `Failed to load enrollment events: ${response.statusText}`, - "progress-events-error", - ); - } - } catch (error) { - if (error instanceof TokenExpiredError) { - addNotification( - "error", - "Session Expired", - error.message, - "session-expired-error", - ); - } else { - console.error("Failed to fetch events:", error); - addNotification( - "error", - "Backend Not Reachable", - "Unable to load enrollment events. Please check your connection.", - "progress-events-error", - ); - } + const run = async () => { + if (!session) { + lastFetchedSessionId.current = null; + setEvents([]); + return; } + if (lastFetchedSessionId.current === session.sessionId) return; + lastFetchedSessionId.current = session.sessionId; + setEvents([]); + + const fetchEvents = async () => { + try { + const response = await authenticatedFetch( + api.progress.sessionEvents(session.sessionId, tenantId), + getAccessToken, + ); + if (response.ok) { + const data = await response.json(); + const fetched: EnrollmentEvent[] = data.events || []; + setEvents((prev) => { + if (prev.length === 0) return fetched; + const existingIds = new Set(prev.map((e) => e.eventId)); + const newEvents = fetched.filter((e) => !existingIds.has(e.eventId)); + if (newEvents.length === 0) return prev; + return [...prev, ...newEvents].sort( + (a, b) => a.sequence - b.sequence, + ); + }); + } else { + addNotification( + "error", + "Backend Error", + `Failed to load enrollment events: ${response.statusText}`, + "progress-events-error", + ); + } + } catch (error) { + if (error instanceof TokenExpiredError) { + addNotification( + "error", + "Session Expired", + error.message, + "session-expired-error", + ); + } else { + console.error("Failed to fetch events:", error); + addNotification( + "error", + "Backend Not Reachable", + "Unable to load enrollment events. Please check your connection.", + "progress-events-error", + ); + } + } + }; + await fetchEvents(); }; - fetchEvents(); + void run(); }, [session, tenantId, getAccessToken, addNotification]); const scheduleFetchEvents = useCallback( diff --git a/src/Web/autopilot-monitor-web/app/sessions/components/DeviceHistoryBanner.tsx b/src/Web/autopilot-monitor-web/app/sessions/components/DeviceHistoryBanner.tsx index 49b7c7ad..484397c5 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/components/DeviceHistoryBanner.tsx +++ b/src/Web/autopilot-monitor-web/app/sessions/components/DeviceHistoryBanner.tsx @@ -72,12 +72,12 @@ export default function DeviceHistoryBanner({ const [expanded, setExpanded] = useState(false); useEffect(() => { - if (!sessionId || !serialNumber) { - setData(null); - return; - } let cancelled = false; - (async () => { + const run = async () => { + if (!sessionId || !serialNumber) { + setData(null); + return; + } try { const response = await authenticatedFetch( api.metrics.deviceHistory(serialNumber, sessionId, effectiveTenantId), @@ -89,7 +89,8 @@ export default function DeviceHistoryBanner({ } catch { // fail-soft: no banner } - })(); + }; + void run(); return () => { cancelled = true; }; diff --git a/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionAnalysis.ts b/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionAnalysis.ts index cd3092db..27e6f067 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionAnalysis.ts +++ b/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionAnalysis.ts @@ -68,7 +68,10 @@ export function useSessionAnalysis( // delay the analysis render. useEffect(() => { if (!sessionId || !sessionTenantId || !isGuid(sessionTenantId)) return; - Promise.all([fetchAnalysisResults(), fetchVulnerabilityReport()]); + const run = async () => { + await Promise.all([fetchAnalysisResults(), fetchVulnerabilityReport()]); + }; + void run(); }, [sessionId, sessionTenantId, fetchAnalysisResults, fetchVulnerabilityReport]); return { diff --git a/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionDetail.ts b/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionDetail.ts index 8d4302af..a89b05b3 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionDetail.ts +++ b/src/Web/autopilot-monitor-web/app/sessions/hooks/useSessionDetail.ts @@ -135,27 +135,30 @@ export function useSessionDetail({ if (!sessionId) return; if (!globalAdminMode && !tenantId && !tenantIdOverride) return; // wait for a real target tenant - // Reset fetch flag only if navigating to a different session - if (lastFetchedSessionId.current !== sessionId) { - hasInitialFetch.current = false; - lastFetchedSessionId.current = sessionId; - setSessionTenantId(null); - } + const run = async () => { + // Reset fetch flag only if navigating to a different session + if (lastFetchedSessionId.current !== sessionId) { + hasInitialFetch.current = false; + lastFetchedSessionId.current = sessionId; + setSessionTenantId(null); + } - // Prevent duplicate fetches in React StrictMode (development double-mounting) - if (hasInitialFetch.current) return; - hasInitialFetch.current = true; + // Prevent duplicate fetches in React StrictMode (development double-mounting) + if (hasInitialFetch.current) return; + hasInitialFetch.current = true; - // Performance: eager-set sessionTenantId if we already know it from TenantContext. - // This lets dependent effects kick off fetchEvents/analysis/vulns/config in parallel - // with fetchSessionDetails instead of waiting for its roundtrip — eliminates a waterfall. - // Global Admins in all-tenant view fall through with null and keep the old behavior. - const knownTenantId = resolveEffectiveTenantId(); - if (knownTenantId && isGuid(knownTenantId)) { - setSessionTenantId(knownTenantId); - } + // Performance: eager-set sessionTenantId if we already know it from TenantContext. + // This lets dependent effects kick off fetchEvents/analysis/vulns/config in parallel + // with fetchSessionDetails instead of waiting for its roundtrip — eliminates a waterfall. + // Global Admins in all-tenant view fall through with null and keep the old behavior. + const knownTenantId = resolveEffectiveTenantId(); + if (knownTenantId && isGuid(knownTenantId)) { + setSessionTenantId(knownTenantId); + } - fetchSessionDetails(); + await fetchSessionDetails(); + }; + void run(); // eslint-disable-next-line react-hooks/exhaustive-deps }, [sessionId, tenantId, globalAdminMode, tenantIdOverride, user]); diff --git a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useDecisionGraph.ts b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useDecisionGraph.ts index c4169bf5..f5cc1dda 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useDecisionGraph.ts +++ b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useDecisionGraph.ts @@ -39,10 +39,9 @@ export function useDecisionGraph({ if (!sessionId) return; let aborted = false; - setLoading(true); - setError(null); - - (async () => { + const run = async () => { + setLoading(true); + setError(null); try { const url = api.inspector.decisionGraph(sessionId, tenantId); const response = await authenticatedFetch(url, getAccessToken); @@ -63,7 +62,8 @@ export function useDecisionGraph({ } finally { if (!aborted) setLoading(false); } - })(); + }; + void run(); return () => { aborted = true; diff --git a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionAnchorEvents.ts b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionAnchorEvents.ts index e185f521..751a8546 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionAnchorEvents.ts +++ b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionAnchorEvents.ts @@ -44,10 +44,9 @@ export function useSessionAnchorEvents({ if (!sessionId) return; let aborted = false; - setLoading(true); - setError(null); - - (async () => { + const run = async () => { + setLoading(true); + setError(null); try { const url = api.sessions.events(sessionId, tenantId); const response = await authenticatedFetch(url, getAccessToken); @@ -68,7 +67,8 @@ export function useSessionAnchorEvents({ } finally { if (!aborted) setLoading(false); } - })(); + }; + void run(); return () => { aborted = true; diff --git a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionSignals.ts b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionSignals.ts index 6e51f404..d7a54c1f 100644 --- a/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionSignals.ts +++ b/src/Web/autopilot-monitor-web/app/sessions/inspector/hooks/useSessionSignals.ts @@ -44,10 +44,9 @@ export function useSessionSignals({ if (!sessionId) return; let aborted = false; - setLoading(true); - setError(null); - - (async () => { + const run = async () => { + setLoading(true); + setError(null); try { const url = api.inspector.signals(sessionId, { tenantId, maxResults }); const response = await authenticatedFetch(url, getAccessToken); @@ -69,7 +68,8 @@ export function useSessionSignals({ } finally { if (!aborted) setLoading(false); } - })(); + }; + void run(); return () => { aborted = true; diff --git a/src/Web/autopilot-monitor-web/app/settings/TenantConfigContext.tsx b/src/Web/autopilot-monitor-web/app/settings/TenantConfigContext.tsx index 2b678a85..65d3380a 100644 --- a/src/Web/autopilot-monitor-web/app/settings/TenantConfigContext.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/TenantConfigContext.tsx @@ -655,7 +655,10 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode } useEffect(() => { if (!tenantId) return; if (!user?.isTenantAdmin && !user?.isGlobalAdmin) return; - fetchAdmins(); + const run = async () => { + await fetchAdmins(); + }; + void run(); }, [tenantId, user?.isTenantAdmin, user?.isGlobalAdmin, fetchAdmins]); // ----------------------------------------------------------------------- @@ -685,7 +688,10 @@ export function TenantConfigProvider({ children }: { children: React.ReactNode } // the per-tenant GA flag is the additive Community enable. const bootstrapAvailable = editionInfo.edition === "pro" || config?.bootstrapTokenEnabled; if (!tenantId || !bootstrapAvailable) return; - fetchBootstrapSessions(); + const run = async () => { + await fetchBootstrapSessions(); + }; + void run(); }, [tenantId, editionInfo.edition, config?.bootstrapTokenEnabled, fetchBootstrapSessions]); // ----------------------------------------------------------------------- diff --git a/src/Web/autopilot-monitor-web/app/settings/components/HardwareRejectionInsights.tsx b/src/Web/autopilot-monitor-web/app/settings/components/HardwareRejectionInsights.tsx index f4643ae6..96941c0f 100644 --- a/src/Web/autopilot-monitor-web/app/settings/components/HardwareRejectionInsights.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/components/HardwareRejectionInsights.tsx @@ -117,7 +117,10 @@ export default function HardwareRejectionInsights({ }, [getAccessToken]); useEffect(() => { - fetchData(); + const run = async () => { + await fetchData(); + }; + void run(); }, [fetchData]); // Loading state diff --git a/src/Web/autopilot-monitor-web/app/settings/components/McpUsersSection.tsx b/src/Web/autopilot-monitor-web/app/settings/components/McpUsersSection.tsx index cb9a297a..3c596b68 100644 --- a/src/Web/autopilot-monitor-web/app/settings/components/McpUsersSection.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/components/McpUsersSection.tsx @@ -88,8 +88,10 @@ export default function McpUsersSection() { }, [getAccessToken]); useEffect(() => { - fetchMcpUsers(); - fetchPlanTiers(); + const run = async () => { + await Promise.all([fetchMcpUsers(), fetchPlanTiers()]); + }; + void run(); }, [fetchMcpUsers, fetchPlanTiers]); const handlePolicyChange = useCallback(async (newPolicy: McpPolicy) => { diff --git a/src/Web/autopilot-monitor-web/app/settings/components/NotRegisteredDevicesInsights.tsx b/src/Web/autopilot-monitor-web/app/settings/components/NotRegisteredDevicesInsights.tsx index fc95166e..ec100bdc 100644 --- a/src/Web/autopilot-monitor-web/app/settings/components/NotRegisteredDevicesInsights.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/components/NotRegisteredDevicesInsights.tsx @@ -62,7 +62,10 @@ export default function NotRegisteredDevicesInsights({ }, [getAccessToken]); useEffect(() => { - fetchData(); + const run = async () => { + await fetchData(); + }; + void run(); }, [fetchData]); // Loading state diff --git a/src/Web/autopilot-monitor-web/app/settings/components/TpmIncompatibleDevicesInsights.tsx b/src/Web/autopilot-monitor-web/app/settings/components/TpmIncompatibleDevicesInsights.tsx index 408417a3..1babd3dd 100644 --- a/src/Web/autopilot-monitor-web/app/settings/components/TpmIncompatibleDevicesInsights.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/components/TpmIncompatibleDevicesInsights.tsx @@ -63,7 +63,10 @@ export default function TpmIncompatibleDevicesInsights({ }, [getAccessToken]); useEffect(() => { - fetchData(); + const run = async () => { + await fetchData(); + }; + void run(); }, [fetchData]); if (!data || data.aggregated.length === 0) { diff --git a/src/Web/autopilot-monitor-web/app/settings/reporting/sections/SectionMcpUsage.tsx b/src/Web/autopilot-monitor-web/app/settings/reporting/sections/SectionMcpUsage.tsx index 51c35481..8c3d5983 100644 --- a/src/Web/autopilot-monitor-web/app/settings/reporting/sections/SectionMcpUsage.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/reporting/sections/SectionMcpUsage.tsx @@ -76,7 +76,10 @@ export function SectionMcpUsage() { }, [getAccessToken]); useEffect(() => { - fetchUsage(dateRange); + const run = async () => { + await fetchUsage(dateRange); + }; + void run(); }, [fetchUsage, dateRange]); // Aggregate records by date diff --git a/src/Web/autopilot-monitor-web/app/settings/tenant/sections/SectionOptionalGraphCapabilities.tsx b/src/Web/autopilot-monitor-web/app/settings/tenant/sections/SectionOptionalGraphCapabilities.tsx index c6bede33..fdfe7b8c 100644 --- a/src/Web/autopilot-monitor-web/app/settings/tenant/sections/SectionOptionalGraphCapabilities.tsx +++ b/src/Web/autopilot-monitor-web/app/settings/tenant/sections/SectionOptionalGraphCapabilities.tsx @@ -63,7 +63,12 @@ export function SectionOptionalGraphCapabilities() { } }, [tenantId, getAccessToken]); - useEffect(() => { void fetchStatus(); }, [fetchStatus]); + useEffect(() => { + const run = async () => { + await fetchStatus(); + }; + void run(); + }, [fetchStatus]); const onRefresh = useCallback(async () => { if (!tenantId) return; diff --git a/src/Web/autopilot-monitor-web/app/sla/page.tsx b/src/Web/autopilot-monitor-web/app/sla/page.tsx index e2262587..86651aa8 100644 --- a/src/Web/autopilot-monitor-web/app/sla/page.tsx +++ b/src/Web/autopilot-monitor-web/app/sla/page.tsx @@ -176,7 +176,12 @@ export default function SlaPage() { } }, [effectiveTenantId, isGlobalOverride, months, getAccessToken, addNotification]); - useEffect(() => { fetchMetrics(); }, [fetchMetrics]); + useEffect(() => { + const run = async () => { + await fetchMetrics(); + }; + void run(); + }, [fetchMetrics]); useEffect(() => { if (tenantId) trackEvent('sla_page_viewed', { months }); diff --git a/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx b/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx index 1ac6735a..1cccbc4c 100644 --- a/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx +++ b/src/Web/autopilot-monitor-web/app/usage-metrics/page.tsx @@ -148,7 +148,10 @@ export default function UsageMetricsPage() { useEffect(() => { if (!effectiveTenantId) return; - fetchMetrics(); + const run = async () => { + await fetchMetrics(); + }; + void run(); }, [effectiveTenantId, fetchMetrics]); const selectedTenantName = tenants.find(t => t.tenantId === selectedTenantId)?.domainName;