import React, { useCallback, useEffect, useState } from 'react'; import ReactDOM from 'react-dom'; import { Activity, RefreshCw, X } from 'lucide-react'; const overlay = { position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.5)', display: 'flex', alignItems: 'center', justifyContent: 'center', zIndex: 1100, }; const modal = { background: 'var(--bg-primary, #fff)', borderRadius: 16, width: 560, maxWidth: '95vw', maxHeight: '85vh', overflow: 'hidden', boxShadow: 'var(--shadow-xl, 0 20px 40px rgba(0,0,0,0.2))', display: 'flex', flexDirection: 'column', }; const statusColor = { online: '#059669', unavailable: '#b45309', error: '#dc2626', }; /** * Settings → Model Status modal. Calls backend /models/status (probes). * Secrets never leave the server. */ const ModelStatusModal = ({ onClose, onStatusLoaded }) => { const [payload, setPayload] = useState(null); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); const load = useCallback(async (refresh = false) => { setLoading(true); setError(null); try { const url = `${process.env.REACT_APP_API_URL || ''}/models/status${refresh ? '?refresh=true' : ''}`; const resp = await fetch(url); if (!resp.ok) throw new Error(`Status request failed (${resp.status})`); const data = await resp.json(); setPayload(data); if (typeof onStatusLoaded === 'function') onStatusLoaded(data); } catch (e) { setError(e.message || 'Failed to load model status'); // Fail open for the picker: parent keeps unfiltered list if (typeof onStatusLoaded === 'function') { onStatusLoaded({ check_failed: true, online_providers: null, models: [] }); } } finally { setLoading(false); } }, [onStatusLoaded]); useEffect(() => { load(false); }, [load]); const models = payload?.models || []; return ReactDOM.createPortal(
{error}. Provider list left unfiltered (fail open).
)} {payload?.check_failed && (Full status check failed. Showing last known results if any; selection list was not restricted.
)} {payload?.checked_at && (Checked {new Date(payload.checked_at).toLocaleString()} {payload.cached ? ' (cached)' : ''}
)} {loading && !payload ? (Probing models…
) : (
{m.error}
)}
{typeof m.latency_ms === 'number' && (