import { createFileRoute } from '@tanstack/react-router' import { route } from '@/constants/routes' import SettingsMenu from '@/containers/SettingsMenu' import HeaderPage from '@/containers/HeaderPage' import { Card, CardItem } from '@/containers/Card' import { Switch } from '@/components/ui/switch' import { Progress } from '@/components/ui/progress' import { useTranslation } from 'react-i18next' import { useHardware } from '@/hooks/useHardware' import type { GPU, HardwareData } from '@/hooks/useHardware' import { useEffect } from 'react' import { DndContext, closestCenter, KeyboardSensor, PointerSensor, useSensor, useSensors, DragEndEvent, } from '@dnd-kit/core' import { SortableContext, verticalListSortingStrategy, useSortable, } from '@dnd-kit/sortable' import { CSS } from '@dnd-kit/utilities' import { IconGripVertical, IconDeviceDesktopAnalytics, } from '@tabler/icons-react' import { getHardwareInfo } from '@/services/hardware' import { WebviewWindow } from '@tauri-apps/api/webviewWindow' import { formatMegaBytes } from '@/lib/utils' // eslint-disable-next-line @typescript-eslint/no-explicit-any export const Route = createFileRoute(route.settings.hardware as any)({ component: Hardware, }) function SortableGPUItem({ gpu, index }: { gpu: GPU; index: number }) { const { attributes, listeners, setNodeRef, transform, transition, isDragging, } = useSortable({ id: gpu.id || index }) const { toggleGPUActivation } = useHardware() const style = { transform: CSS.Transform.toString(transform), transition, opacity: isDragging ? 0.5 : 1, position: 'relative' as const, zIndex: isDragging ? 1 : 0, } return (
{gpu.name}
} actions={
toggleGPUActivation(index)} />
} />
{formatMegaBytes(gpu.free_vram)} free of{' '} {formatMegaBytes(gpu.total_vram)} } /> {gpu.additional_information.driver_version} } /> {gpu.additional_information.compute_cap} } />
) } function Hardware() { const { t } = useTranslation() const { hardwareData, setHardwareData, updateCPUUsage, updateRAMAvailable, reorderGPUs, } = useHardware() useEffect(() => { getHardwareInfo().then((data) => setHardwareData(data as unknown as HardwareData) ) }, [setHardwareData]) // Set up DnD sensors const sensors = useSensors( useSensor(PointerSensor), useSensor(KeyboardSensor) ) // Handle drag end event const handleDragEnd = (event: DragEndEvent) => { const { active, over } = event if (over && active.id !== over.id) { // Find the indices of the dragged item and the drop target const oldIndex = hardwareData.gpus.findIndex( (gpu) => gpu.id === active.id ) const newIndex = hardwareData.gpus.findIndex((gpu) => gpu.id === over.id) if (oldIndex !== -1 && newIndex !== -1) { reorderGPUs(oldIndex, newIndex) } } } useEffect(() => { const intervalId = setInterval(() => { getHardwareInfo().then((data) => { setHardwareData(data as unknown as HardwareData) updateCPUUsage(data.cpu.usage) updateRAMAvailable(data.ram.available) }) }, 5000) return () => clearInterval(intervalId) }, [setHardwareData, updateCPUUsage, updateRAMAvailable]) const handleClickSystemMonitor = async () => { try { // Check if system monitor window already exists const existingWindow = await WebviewWindow.getByLabel( 'system-monitor-window' ) if (existingWindow) { // If window exists, focus it await existingWindow.setFocus() console.log('Focused existing system monitor window') } else { // Create a new system monitor window const monitorWindow = new WebviewWindow('system-monitor-window', { url: route.systemMonitor, title: 'System Monitor - Jan', width: 900, height: 600, resizable: true, center: true, }) // Listen for window creation monitorWindow.once('tauri://created', () => { console.log('System monitor window created') }) // Listen for window errors monitorWindow.once('tauri://error', (e) => { console.error('Error creating system monitor window:', e) }) } } catch (error) { console.error('Failed to open system monitor window:', error) } } return (

{t('common.settings')}

System monitor

{/* OS Information */} {hardwareData.os.name} } /> {hardwareData.os.version} } /> {/* CPU Information */} {hardwareData.cpu.model} } /> {hardwareData.cpu.arch} } /> {hardwareData.cpu.cores} } /> {hardwareData.cpu.instructions.join(', ').length > 0 && ( {hardwareData.cpu.instructions.join(', ')} } /> )} {hardwareData.cpu.usage.toFixed(2)}%
} /> {/* RAM Information */} {formatMegaBytes(hardwareData.ram.total)} } /> {formatMegaBytes(hardwareData.ram.available)} } /> {( ((hardwareData.ram.total - hardwareData.ram.available) / hardwareData.ram.total) * 100 ).toFixed(2)} %
} /> {/* GPU Information */} {hardwareData.gpus.length > 0 ? ( gpu.id)} strategy={verticalListSortingStrategy} > {hardwareData.gpus.map((gpu, index) => ( ))} ) : ( } /> )}
) }