fix: auth redirect, SSE reconnect, stats polling removal, active decky count, schemathesis health check
Some checks failed
CI / Lint (ruff) (push) Successful in 18s
CI / SAST (bandit) (push) Successful in 19s
CI / Dependency audit (pip-audit) (push) Failing after 27s
CI / Test (Standard) (3.11) (push) Has been skipped
CI / Test (Standard) (3.12) (push) Has been skipped
CI / Test (Live) (3.11) (push) Has been skipped
CI / Test (Fuzz) (3.11) (push) Has been skipped
CI / Merge dev → testing (push) Has been skipped
CI / Prepare Merge to Main (push) Has been skipped
CI / Finalize Merge to Main (push) Has been skipped

This commit is contained in:
2026-04-13 18:33:32 -04:00
parent ac094965b5
commit 57d395d6d7
4 changed files with 48 additions and 44 deletions

View File

@@ -1,4 +1,4 @@
import React, { useEffect, useState } from 'react';
import React, { useEffect, useState, useRef } from 'react';
import './Dashboard.css';
import { Shield, Users, Activity, Clock } from 'lucide-react';
@@ -29,37 +29,52 @@ const Dashboard: React.FC<DashboardProps> = ({ searchQuery }) => {
const [stats, setStats] = useState<Stats | null>(null);
const [logs, setLogs] = useState<LogEntry[]>([]);
const [loading, setLoading] = useState(true);
const eventSourceRef = useRef<EventSource | null>(null);
const reconnectTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);
useEffect(() => {
const token = localStorage.getItem('token');
const baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000/api/v1';
let url = `${baseUrl}/stream?token=${token}`;
if (searchQuery) {
url += `&search=${encodeURIComponent(searchQuery)}`;
}
const eventSource = new EventSource(url);
eventSource.onmessage = (event) => {
try {
const payload = JSON.parse(event.data);
if (payload.type === 'logs') {
setLogs(prev => [...payload.data, ...prev].slice(0, 100));
} else if (payload.type === 'stats') {
setStats(payload.data);
setLoading(false);
}
} catch (err) {
console.error('Failed to parse SSE payload', err);
const connect = () => {
if (eventSourceRef.current) {
eventSourceRef.current.close();
}
const token = localStorage.getItem('token');
const baseUrl = import.meta.env.VITE_API_URL || 'http://localhost:8000/api/v1';
let url = `${baseUrl}/stream?token=${token}`;
if (searchQuery) {
url += `&search=${encodeURIComponent(searchQuery)}`;
}
const es = new EventSource(url);
eventSourceRef.current = es;
es.onmessage = (event) => {
try {
const payload = JSON.parse(event.data);
if (payload.type === 'logs') {
setLogs(prev => [...payload.data, ...prev].slice(0, 100));
} else if (payload.type === 'stats') {
setStats(payload.data);
setLoading(false);
window.dispatchEvent(new CustomEvent('decnet:stats', { detail: payload.data }));
}
} catch (err) {
console.error('Failed to parse SSE payload', err);
}
};
es.onerror = () => {
es.close();
eventSourceRef.current = null;
reconnectTimerRef.current = setTimeout(connect, 3000);
};
};
eventSource.onerror = (err) => {
console.error('SSE connection error, attempting to reconnect...', err);
};
connect();
return () => {
eventSource.close();
if (reconnectTimerRef.current) clearTimeout(reconnectTimerRef.current);
if (eventSourceRef.current) eventSourceRef.current.close();
};
}, [searchQuery]);