Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions web-ui/src/lib/hooks/useAlerts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import useSWR from 'swr';
import { Server } from '@/src/types/server';
import { AlertRulesResponse, AlertingInfoResponse, WebhookDeliveriesResponse } from '@/src/types/alerts';
import { getClient } from '@/src/lib/api/client';
import { usePageVisibility } from './usePageVisibility';

/**
* Hook for fetching alert rules
*/
export function useAlerts(server: Server | null) {
const isVisible = usePageVisibility();
const fetcher = async (): Promise<AlertRulesResponse> => {
if (!server) throw new Error('No server');
const client = getClient(server);
Expand All @@ -21,7 +23,7 @@ export function useAlerts(server: Server | null) {
swrKey,
fetcher,
{
refreshInterval: 30000,
refreshInterval: isVisible ? 30000 : 0,
revalidateOnFocus: true,
dedupingInterval: 5000,
}
Expand All @@ -39,6 +41,7 @@ export function useAlerts(server: Server | null) {
* Hook for fetching alerting system info
*/
export function useAlertingInfo(server: Server | null) {
const isVisible = usePageVisibility();
const fetcher = async (): Promise<AlertingInfoResponse> => {
if (!server) throw new Error('No server');
const client = getClient(server);
Expand All @@ -51,7 +54,7 @@ export function useAlertingInfo(server: Server | null) {
swrKey,
fetcher,
{
refreshInterval: 60000,
refreshInterval: isVisible ? 60000 : 0,
revalidateOnFocus: true,
dedupingInterval: 10000,
}
Expand All @@ -69,6 +72,7 @@ export function useAlertingInfo(server: Server | null) {
* Hook for fetching webhook delivery history
*/
export function useWebhookDeliveries(server: Server | null) {
const isVisible = usePageVisibility();
const fetcher = async (): Promise<WebhookDeliveriesResponse> => {
if (!server) throw new Error('No server');
const client = getClient(server);
Expand All @@ -81,7 +85,7 @@ export function useWebhookDeliveries(server: Server | null) {
swrKey,
fetcher,
{
refreshInterval: 30000,
refreshInterval: isVisible ? 30000 : 0,
revalidateOnFocus: true,
dedupingInterval: 5000,
}
Expand Down
4 changes: 3 additions & 1 deletion web-ui/src/lib/hooks/useAudit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import useSWR from 'swr';
import { Server } from '@/src/types/server';
import { AuditLogsResponse, AuditLogsParams } from '@/src/types/audit';
import { getClient } from '@/src/lib/api/client';
import { usePageVisibility } from './usePageVisibility';

/**
* Hook for fetching audit logs with filtering and pagination
*/
export function useAudit(server: Server | null, params?: AuditLogsParams) {
const isVisible = usePageVisibility();
const fetcher = async (): Promise<AuditLogsResponse> => {
if (!server) throw new Error('No server');
const client = getClient(server);
Expand All @@ -24,7 +26,7 @@ export function useAudit(server: Server | null, params?: AuditLogsParams) {
swrKey,
fetcher,
{
refreshInterval: 30000, // 30s refresh
refreshInterval: isVisible ? 30000 : 0, // 30s refresh (paused when tab hidden)
revalidateOnFocus: true,
dedupingInterval: 5000,
}
Expand Down
6 changes: 4 additions & 2 deletions web-ui/src/lib/hooks/useContainers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Server } from '@/src/types/server';
import { getClient, CoreService } from '@/src/lib/api/client';
import { useEventStream } from '@/src/lib/events/useEventStream';
import { ServerEvent, isContainerEvent, ConnectionStatus } from '@/src/types/events';
import { usePageVisibility } from './usePageVisibility';

export interface CreateContainerProgress {
state: string;
Expand All @@ -17,6 +18,7 @@ export interface CreateContainerProgress {
* Hook for managing containers for a specific server
*/
export function useContainers(server: Server | null) {
const isVisible = usePageVisibility();
// Create a stable fetcher for this server
const fetcher = async (): Promise<Container[]> => {
if (!server) return [];
Expand Down Expand Up @@ -71,7 +73,7 @@ export function useContainers(server: Server | null) {
systemInfoKey,
systemInfoFetcher,
{
refreshInterval: 60000, // Refresh every minute
refreshInterval: isVisible ? 60000 : 0, // Refresh every minute (paused when tab hidden)
revalidateOnFocus: false,
dedupingInterval: 30000,
}
Expand All @@ -93,7 +95,7 @@ export function useContainers(server: Server | null) {
coreServicesKey,
coreServicesFetcher,
{
refreshInterval: 30000, // Refresh every 30s
refreshInterval: isVisible ? 30000 : 0, // Refresh every 30s (paused when tab hidden)
revalidateOnFocus: true,
dedupingInterval: 10000,
}
Expand Down
4 changes: 3 additions & 1 deletion web-ui/src/lib/hooks/useMetrics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import useSWR from 'swr';
import { ContainerMetrics, ContainerMetricsWithRate } from '@/src/types/container';
import { Server } from '@/src/types/server';
import { getClient } from '@/src/lib/api/client';
import { usePageVisibility } from './usePageVisibility';

interface MetricsSnapshot {
metrics: Record<string, ContainerMetrics>;
Expand All @@ -15,6 +16,7 @@ interface MetricsSnapshot {
* Hook for fetching container metrics with polling and CPU rate calculation
*/
export function useMetrics(server: Server | null, enabled: boolean = true) {
const isVisible = usePageVisibility();
// Store previous metrics for CPU rate calculation
const prevSnapshot = useRef<MetricsSnapshot | null>(null);

Expand All @@ -30,7 +32,7 @@ export function useMetrics(server: Server | null, enabled: boolean = true) {
swrKey,
fetcher,
{
refreshInterval: 5000, // Poll every 5 seconds for metrics
refreshInterval: (() => { const interval = isVisible ? 5000 : 0; console.log('[useMetrics] refreshInterval:', interval, 'isVisible:', isVisible); return interval; })(),
revalidateOnFocus: true,
dedupingInterval: 2000,
}
Expand Down
32 changes: 32 additions & 0 deletions web-ui/src/lib/hooks/usePageVisibility.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
'use client';

import { useState, useEffect, useCallback } from 'react';

/**
* Hook that tracks whether the browser tab/window is active.
* Returns false when:
* - The tab is hidden (user switched browser tabs)
* - The browser window lost focus (user switched to another application)
*/
export function usePageVisibility(): boolean {
const [isVisible, setIsVisible] = useState(true);

const update = useCallback(() => {
const visible = !document.hidden && document.hasFocus();
console.log('[usePageVisibility]', visible ? 'ACTIVE' : 'INACTIVE', '| hidden:', document.hidden, 'hasFocus:', document.hasFocus());
setIsVisible(visible);
}, []);

useEffect(() => {
document.addEventListener('visibilitychange', update);
window.addEventListener('focus', update);
window.addEventListener('blur', update);
return () => {
document.removeEventListener('visibilitychange', update);
window.removeEventListener('focus', update);
window.removeEventListener('blur', update);
};
}, [update]);

return isVisible;
}
4 changes: 3 additions & 1 deletion web-ui/src/lib/hooks/useSecurity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import useSWR from 'swr';
import { Server } from '@/src/types/server';
import { ClamavSummaryResponse } from '@/src/types/security';
import { getClient } from '@/src/lib/api/client';
import { usePageVisibility } from './usePageVisibility';

/**
* Hook for fetching ClamAV security summary
*/
export function useSecurity(server: Server | null) {
const isVisible = usePageVisibility();
const fetcher = async (): Promise<ClamavSummaryResponse> => {
if (!server) throw new Error('No server');
const client = getClient(server);
Expand All @@ -21,7 +23,7 @@ export function useSecurity(server: Server | null) {
swrKey,
fetcher,
{
refreshInterval: 60000, // 60s refresh
refreshInterval: isVisible ? 60000 : 0, // 60s refresh (paused when tab hidden)
revalidateOnFocus: true,
dedupingInterval: 10000,
}
Expand Down
6 changes: 4 additions & 2 deletions web-ui/src/lib/hooks/useTraffic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import { Connection, ConnectionSummary, HistoricalConnection, TrafficAggregate }
import { getClient } from '@/src/lib/api/client';
import { useEventStream } from '@/src/lib/events/useEventStream';
import { ServerEvent } from '@/src/types/events';
import { usePageVisibility } from './usePageVisibility';

/**
* Hook for managing traffic monitoring for a specific container
*/
export function useTraffic(server: Server | null, containerName: string | null) {
const isVisible = usePageVisibility();
const [autoRefresh, setAutoRefresh] = useState(true);

// Fetcher for active connections
Expand All @@ -31,7 +33,7 @@ export function useTraffic(server: Server | null, containerName: string | null)
isLoading: connectionsLoading,
mutate: mutateConnections,
} = useSWR<Connection[]>(connectionsKey, connectionsFetcher, {
refreshInterval: autoRefresh ? 5000 : 0, // Poll every 5 seconds if auto-refresh enabled
refreshInterval: autoRefresh && isVisible ? 5000 : 0, // Poll every 5 seconds if auto-refresh enabled
revalidateOnFocus: true,
dedupingInterval: 2000,
});
Expand All @@ -52,7 +54,7 @@ export function useTraffic(server: Server | null, containerName: string | null)
isLoading: summaryLoading,
mutate: mutateSummary,
} = useSWR<ConnectionSummary | null>(summaryKey, summaryFetcher, {
refreshInterval: autoRefresh ? 5000 : 0,
refreshInterval: autoRefresh && isVisible ? 5000 : 0,
revalidateOnFocus: true,
dedupingInterval: 2000,
});
Expand Down
Loading