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(
{ if (e.target === e.currentTarget) onClose(); }} role="dialog" aria-modal="true" aria-label="Model Status" >
Model Status
{error && (

{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…

) : (
    {models.map((m) => (
  • {m.name}
    {m.model || m.provider} {!m.selectable ? ' · fallback only' : ''}
    {m.status}
    {m.status === 'error' && m.error && (
                          {m.error}
                        
    )} {typeof m.latency_ms === 'number' && (
    {m.latency_ms} ms
    )}
  • ))}
)}
, document.body ); }; export default ModelStatusModal;