import { useState } from 'react' import { useTranslation } from 'react-i18next' import { Head } from '@inertiajs/react' import SettingsLayout from '~/layouts/SettingsLayout' import { SystemInformationResponse } from '../../../types/system' import { formatBytes } from '~/lib/util' import { getAllDiskDisplayItems } from '~/hooks/useDiskDisplayData' import CircularGauge from '~/components/systeminfo/CircularGauge' import HorizontalBarChart from '~/components/HorizontalBarChart' import InfoCard from '~/components/systeminfo/InfoCard' import Alert from '~/components/Alert' import StyledModal from '~/components/StyledModal' import { useSystemInfo } from '~/hooks/useSystemInfo' import { useNotifications } from '~/context/NotificationContext' import { useModals } from '~/context/ModalContext' import api from '~/lib/api' import StatusCard from '~/components/systeminfo/StatusCard' import { IconCpu, IconDatabase, IconServer, IconDeviceDesktop, IconComponents } from '@tabler/icons-react' export default function SettingsPage(props: { system: { info: SystemInformationResponse | undefined } }) { const { t } = useTranslation() const { data: info } = useSystemInfo({ initialData: props.system.info, }) const { addNotification } = useNotifications() const { openModal, closeAllModals } = useModals() const [gpuBannerDismissed, setGpuBannerDismissed] = useState(() => { try { return localStorage.getItem('nomad:gpu-banner-dismissed') === 'true' } catch { return false } }) const [reinstalling, setReinstalling] = useState(false) const handleDismissGpuBanner = () => { setGpuBannerDismissed(true) try { localStorage.setItem('nomad:gpu-banner-dismissed', 'true') } catch {} } const handleForceReinstallOllama = () => { openModal( { closeAllModals() setReinstalling(true) try { const response = await api.forceReinstallService('nomad_ollama') if (!response || !response.success) { throw new Error(response?.message || 'Force reinstall failed') } addNotification({ message: t('system.reinstallSuccess'), type: 'success', }) try { localStorage.removeItem('nomad:gpu-banner-dismissed') } catch {} setTimeout(() => window.location.reload(), 5000) } catch (error) { addNotification({ message: t('system.reinstallFailed', { error: error instanceof Error ? error.message : 'Unknown error' }), type: 'error', }) setReinstalling(false) } }} onCancel={closeAllModals} open={true} confirmText={t('system.reinstallConfirm')} cancelText="Cancel" >

{t('system.reinstallAiMessage')}

, 'gpu-health-force-reinstall-modal' ) } // Use (total - available) to reflect actual memory pressure. // mem.used includes reclaimable buff/cache on Linux, which inflates the number. const memoryUsed = info?.mem.total && info?.mem.available != null ? info.mem.total - info.mem.available : info?.mem.used || 0 const memoryUsagePercent = info?.mem.total ? ((memoryUsed / info.mem.total) * 100).toFixed(1) : 0 const swapUsagePercent = info?.mem.swaptotal ? ((info.mem.swapused / info.mem.swaptotal) * 100).toFixed(1) : 0 const uptimeSeconds = info?.uptime.uptime || 0 const uptimeDays = Math.floor(uptimeSeconds / 86400) const uptimeHours = Math.floor((uptimeSeconds % 86400) / 3600) const uptimeMinutes = Math.floor((uptimeSeconds % 3600) / 60) const uptimeDisplay = uptimeDays > 0 ? `${uptimeDays}d ${uptimeHours}h ${uptimeMinutes}m` : uptimeHours > 0 ? `${uptimeHours}h ${uptimeMinutes}m` : `${uptimeMinutes}m` // Build storage display items - fall back to fsSize when disk array is empty const storageItems = getAllDiskDisplayItems(info?.disk, info?.fsSize) return (

{t('system.heading')}

{t('system.subtitle', { time: new Date().toLocaleString() })}

{Number(memoryUsagePercent) > 90 && (
)}

{t('system.resourceUsage')}

} />
} />
} />

{t('system.systemDetails')}

} variant="elevated" data={[ { label: t('system.distribution'), value: info?.os.distro }, { label: t('system.kernelVersion'), value: info?.os.kernel }, { label: t('system.architecture'), value: info?.os.arch }, { label: t('system.hostname'), value: info?.os.hostname }, { label: t('system.platform'), value: info?.os.platform }, ]} /> } variant="elevated" data={[ { label: t('system.manufacturer'), value: info?.cpu.manufacturer }, { label: t('system.brand'), value: info?.cpu.brand }, { label: t('system.cores'), value: info?.cpu.cores }, { label: t('system.physicalCores'), value: info?.cpu.physicalCores }, { label: t('system.virtualization'), value: info?.cpu.virtualization ? t('system.enabled') : t('system.disabled'), }, ]} /> {info?.gpuHealth?.status === 'passthrough_failed' && !gpuBannerDismissed && (
)} {info?.graphics?.controllers && info.graphics.controllers.length > 0 && ( } variant="elevated" data={info.graphics.controllers.map((gpu, i) => { const prefix = info.graphics.controllers.length > 1 ? `GPU ${i + 1} ` : '' return [ { label: `${prefix}Model`, value: gpu.model }, { label: `${prefix}Vendor`, value: gpu.vendor }, { label: `${prefix}VRAM`, value: gpu.vram ? `${gpu.vram} MB` : t('system.na') }, ] }).flat()} /> )}

{t('system.memoryAllocation')}

{formatBytes(info?.mem.total || 0)}
{t('system.totalRam')}
{formatBytes(memoryUsed)}
{t('system.usedRam')}
{formatBytes(info?.mem.available || 0)}
{t('system.availableRam')}
{t('system.utilized', { percent: memoryUsagePercent })}

{t('system.storageDevices')}

{storageItems.length > 0 ? ( ) : (
{t('system.noStorageDevices')}
)}

{t('system.systemStatus')}

) }