feat: global Docker health indicator and graceful degradation
- GET /api/health endpoint returning Docker connectivity status - Sidebar shows Docker connection dot (green=connected, red=disconnected) - Stale scanner returns store-only results when Docker is unavailable - Polls health every 30s
This commit is contained in:
+8
-7
@@ -34,12 +34,7 @@ class ApiError extends Error {
|
||||
}
|
||||
}
|
||||
|
||||
function getAuthToken(): string | null {
|
||||
if (typeof localStorage !== 'undefined') {
|
||||
return localStorage.getItem('auth_token');
|
||||
}
|
||||
return null;
|
||||
}
|
||||
import { getAuthToken, clearAuth } from './auth';
|
||||
|
||||
async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
const token = getAuthToken();
|
||||
@@ -58,7 +53,7 @@ async function request<T>(path: string, init?: RequestInit): Promise<T> {
|
||||
|
||||
// Redirect to login on 401 (expired/missing token).
|
||||
if (res.status === 401 && typeof window !== 'undefined' && !path.includes('/auth/')) {
|
||||
localStorage.removeItem('auth_token');
|
||||
clearAuth();
|
||||
window.location.href = '/login';
|
||||
throw new ApiError('Authentication required', 401);
|
||||
}
|
||||
@@ -270,6 +265,12 @@ export function listNpmCertificates(): Promise<NpmCertificate[]> {
|
||||
return get<NpmCertificate[]>('/api/settings/npm-certificates');
|
||||
}
|
||||
|
||||
// ── Health ──────────────────────────────────────────────────────────
|
||||
|
||||
export function getHealth(): Promise<{ docker: boolean }> {
|
||||
return get<{ docker: boolean }>('/api/health');
|
||||
}
|
||||
|
||||
// ── Auth ─────────────────────────────────────────────────────────────
|
||||
|
||||
export function login(username: string, password: string): Promise<{ token: string; expires_at: string }> {
|
||||
|
||||
Reference in New Issue
Block a user