diff --git a/frontend/src/components/modals/ScanConfigModal.tsx b/frontend/src/components/modals/ScanConfigModal.tsx
index 4fe101d..46af678 100644
--- a/frontend/src/components/modals/ScanConfigModal.tsx
+++ b/frontend/src/components/modals/ScanConfigModal.tsx
@@ -1,5 +1,5 @@
import { useState, useEffect } from 'react'
-import { Plus, Trash2 } from 'lucide-react'
+import { Plus, Trash2, Settings } from 'lucide-react'
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
@@ -95,18 +95,10 @@ export function ScanConfigModal({ open, onClose, onScanNow }: ScanConfigModalPro
- {/* Status check interval */}
-
-
- setInterval(Number(e.target.value))}
- className="font-mono text-sm bg-[#0d1117] border-border w-32"
- />
-
+
+
+ Status check interval can be configured in the sidebar Settings.
+
diff --git a/frontend/src/components/panels/Sidebar.tsx b/frontend/src/components/panels/Sidebar.tsx
index 3105bdb..6de1bf4 100644
--- a/frontend/src/components/panels/Sidebar.tsx
+++ b/frontend/src/components/panels/Sidebar.tsx
@@ -1,5 +1,5 @@
import { useState, useCallback, useEffect, useRef } from 'react'
-import { Plus, Save, ScanLine, ChevronLeft, ChevronRight, LayoutDashboard, Clock, EyeOff, Trash2, RefreshCw, Loader2, Square, Eye } from 'lucide-react'
+import { Plus, Save, ScanLine, ChevronLeft, ChevronRight, LayoutDashboard, Clock, EyeOff, Trash2, RefreshCw, Loader2, Square, Eye, Settings } from 'lucide-react'
import { Logo } from '@/components/ui/Logo'
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'
import { useCanvasStore } from '@/stores/canvasStore'
@@ -9,7 +9,7 @@ import { PendingDeviceModal, type PendingDevice } from '@/components/modals/Pend
const STANDALONE = import.meta.env.VITE_STANDALONE === 'true'
-type SidebarView = 'canvas' | 'pending' | 'hidden' | 'history'
+type SidebarView = 'canvas' | 'pending' | 'hidden' | 'history' | 'settings'
const ALL_VIEWS = [
{ id: 'canvas' as SidebarView, icon: LayoutDashboard, label: 'Canvas' },
@@ -95,6 +95,7 @@ export function Sidebar({ onAddNode, onAddGroupRect, onScan, onSave, onNodeAppro
{activeView === 'pending' && }
{activeView === 'hidden' && }
{activeView === 'history' && }
+ {activeView === 'settings' && }
)}
@@ -141,6 +142,15 @@ export function Sidebar({ onAddNode, onAddGroupRect, onScan, onSave, onNodeAppro
badge={hasUnsavedChanges}
accent
/>
+ {!STANDALONE && (
+ setActiveView((v) => v === 'settings' ? 'canvas' : 'settings')}
+ />
+ )}
)
@@ -417,6 +427,65 @@ function ScanHistoryPanel() {
)
}
+function SettingsPanel() {
+ const [interval, setIntervalValue] = useState(60)
+ const [ranges, setRangesValue] = useState([])
+ const [saving, setSaving] = useState(false)
+
+ useEffect(() => {
+ scanApi.getConfig()
+ .then((res) => {
+ setIntervalValue(res.data.interval_seconds)
+ setRangesValue(res.data.ranges)
+ })
+ .catch(() => {/* use current defaults */})
+ }, [])
+
+ const handleSave = async () => {
+ setSaving(true)
+ try {
+ await scanApi.saveConfig({ ranges, interval_seconds: interval })
+ toast.success('Settings saved')
+ } catch {
+ toast.error('Failed to save settings')
+ } finally {
+ setSaving(false)
+ }
+ }
+
+ return (
+
+
Settings
+
+
+
+
+ setIntervalValue(Number(e.target.value))}
+ className="w-24 px-2 py-1 rounded-md text-xs font-mono bg-[#0d1117] border border-border text-foreground focus:outline-none focus:border-[#00d4ff]"
+ />
+ seconds
+
+
+ How often node health is polled (ping, HTTP, SSH…)
+
+
+
+
+
+ )
+}
+
const MAC_OUI: Record = {
'52:54:00': { label: 'QEMU', title: 'QEMU/KVM Virtual Machine' },
'bc:24:11': { label: 'PVE', title: 'Proxmox Virtual Machine or LXC' },