/**
* Settings Page Component
* Full-page settings dashboard with server control, proxy, auth, ports
*/
import { useState } from 'react';
import { useQuery } from '@tanstack/react-query';
import {
RefreshCw,
Server,
Shield,
Network,
Activity,
Key,
Loader2,
CheckCircle,
AlertCircle
} from 'lucide-react';
import { useI18n } from '@/contexts';
import { ProxySettings } from './ProxySettings';
import { AuthManager } from './AuthManager';
import { PortConfiguration } from './PortConfig';
import styles from './SettingsPage.module.css';
// API functions
async function fetchServerStatus() {
const response = await fetch('/api/server/status');
if (!response.ok) throw new Error('Failed to fetch server status');
return response.json();
}
async function fetchApiKeys() {
const response = await fetch('/api/keys');
if (!response.ok) throw new Error('Failed to fetch API keys');
return response.json();
}
async function addApiKey(key: string) {
const response = await fetch('/api/keys', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key }),
});
if (!response.ok) throw new Error('Failed to add API key');
return response.json();
}
async function deleteApiKey(key: string) {
const response = await fetch('/api/keys', {
method: 'DELETE',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key }),
});
if (!response.ok) throw new Error('Failed to delete API key');
return response.json();
}
interface ServerStatus {
status: string;
uptime_seconds: number;
uptime_formatted: string;
launch_mode: string;
server_port: number;
stream_port: number;
version: string;
python_version: string;
started_at: string;
}
export function SettingsPage() {
const { t } = useI18n();
return (
{t.settingsPage.title}
{/* Minimal Status Bar */}
{/* API Keys */}
{/* Proxy Settings */}
{t.settingsPage.proxySettings}
{t.settingsPage.proxyDesc}
{/* Auth Management */}
{t.settingsPage.authManagement}
{t.settingsPage.authDesc}
{/* Port Configuration */}
{t.settingsPage.portConfig}
{t.settingsPage.portDesc}
);
}
function StatusBar() {
const { t } = useI18n();
const { data: status, isLoading } = useQuery({
queryKey: ['serverStatus'],
queryFn: fetchServerStatus,
refetchInterval: 10000,
});
if (isLoading) {
return (
{t.settingsPage.loading}
);
}
return (
{status?.status || t.common.unknown}
{status?.uptime_formatted || '-'}
{t.settingsPage.port} {status?.server_port || '-'}
{status?.launch_mode || '-'}
);
}
function ApiKeysSection() {
const { t } = useI18n();
const { data, isLoading, refetch } = useQuery<{ keys: string[] }>({
queryKey: ['apiKeys'],
queryFn: fetchApiKeys,
});
const [newKey, setNewKey] = useState('');
const [adding, setAdding] = useState(false);
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
const handleAdd = async () => {
if (!newKey.trim()) return;
setAdding(true);
setMessage(null);
try {
await addApiKey(newKey.trim());
setNewKey('');
setMessage({ type: 'success', text: t.settingsPage.keyAdded });
refetch();
} catch {
setMessage({ type: 'error', text: t.settingsPage.addFailed });
} finally {
setAdding(false);
}
};
const handleDelete = async (key: string) => {
const confirmMsg = t.settingsPage.confirmDelete.replace('{key}', key.substring(0, 8));
if (!confirm(confirmMsg)) return;
try {
await deleteApiKey(key);
setMessage({ type: 'success', text: t.settingsPage.keyDeleted });
refetch();
} catch {
setMessage({ type: 'error', text: t.settingsPage.deleteFailed });
}
};
if (isLoading) {
return (
);
}
return (
{t.settingsPage.apiKeys}
{t.settingsPage.apiKeysDesc}
{data?.keys?.length ? (
data.keys.map((key) => (
{key.substring(0, 16)}...
))
) : (
{t.settingsPage.noApiKeys}
)}
setNewKey(e.target.value)}
placeholder={t.settingsPage.enterNewKey}
/>
{message && (
{message.type === 'success' ?
:
}
{message.text}
)}
);
}