"use client" import { useState } from "react" import Link from "next/link" import { PageHeader } from "@/components/page-header" import { useTheme } from "@/components/theme-provider" import { SystemDatabaseSection } from "@/components/settings/system-database-section" import { EvoBgpSettingsSection } from "@/components/settings/evobgp-settings-section" import { OpsPanel } from "@/components/ops-panel" import { Button, buttonVariants } from "@/components/ui/button" import { Input } from "@/components/ui/input" import { useDataSource } from "@/lib/data-source" import { CheckIcon, AlertCircleIcon, XIcon, } from "lucide-react" import { cn } from "@/lib/utils" const SECTIONS_NAV = ["Общие", "EvoBGP", "Уведомления", "API-ключи", "Безопасность"] as const type NavSection = typeof SECTIONS_NAV[number] function SettingRow({ label, description, children }: { label: string; description?: string; children: React.ReactNode }) { return (

{label}

{description &&

{description}

}
{children}
) } // ─── page ───────────────────────────────────────────────────────────────────── export default function SettingsPage() { const [section, setSection] = useState("Общие") const { mode, setMode, backendUrl, backendUrlLocked, mockModeAvailable, backendStatus, backendChecking, checkBackend } = useDataSource() const { theme, setTheme } = useTheme() const renderContent = () => { // ── Общие ── if (section === "Общие") return (
{/* ── Источник данных ── */} {/* mode toggle */} {mockModeAvailable ? (
{([["mock", "Моковые"], ["live", "Живые"]] as const).map(([v, l], i) => ( ))}
) : ( Живые )} {/* backend URL — visible in both modes so user can configure before switching */} {/* connection status */}
{backendStatus === undefined && ( {backendChecking ? "Проверка…" : "Не проверялось"} )} {backendStatus === true && ( Доступен )} {backendStatus === false && ( Недоступен )}
{/* hint when live but backend unreachable */} {mode === "live" && backendStatus === false && (
Сервер недоступен. Последние полученные данные сохраняются; новые запросы могут завершаться ошибкой.
)}
Русский
{([["light","Светлая"],["dark","Тёмная"],["system","Авто"]] as const).map(([value,label]) => )}

Периоды сбора данных и параметры диагностики настраиваются в соответствующих разделах.

Сбор данныхДиагностика
Открыть оптимизатор
) if (section === "EvoBGP") return if (section === "Уведомления") return Открыть оповещения if (section === "API-ключи") return

Создание и управление отдельными API-ключами в приложении пока недоступны.

return

Состояние MFA, ограничений IP и настроек аудита в этом разделе не получено. Изменение этих параметров здесь недоступно.

Управление пользователями
} return (
{/* nav */} {/* content */}
{renderContent()}
) } function BackendUrlField(){ const {backendUrl,setBackendUrl,backendUrlLocked}=useDataSource() const [draft,setDraft]=useState(backendUrl),[error,setError]=useState(null) function commit(){ if(backendUrlLocked||draft===backendUrl)return try{const url=new URL(draft.trim());if(!["http:","https:"].includes(url.protocol)||url.username||url.password||url.search||url.hash)throw Error();setBackendUrl(url.toString().replace(/\/$/,""));setError(null)} catch{setError("Укажите HTTP(S) адрес без учётных данных и параметров")} } return
{setDraft(e.target.value);setError(null)}} onBlur={commit} onKeyDown={e=>{if(e.key==="Enter"){e.preventDefault();commit()}}} readOnly={backendUrlLocked} aria-invalid={!!error} placeholder="http://localhost:8000"/>{error?

{error}

:null}
}