import { useState, useEffect } from 'react' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { settingsApi } from '@/api/client' import { useCanvasStore } from '@/stores/canvasStore' import { toast } from 'sonner' import { type AlignmentSettings, readAlignmentSettings, writeAlignmentSettings, subscribeAlignmentSettings, } from '@/utils/alignmentSettings' const STANDALONE = import.meta.env.VITE_STANDALONE === 'true' interface SettingsModalProps { open: boolean onClose: () => void } export function SettingsModal({ open, onClose }: SettingsModalProps) { const [interval, setIntervalValue] = useState(60) const [saving, setSaving] = useState(false) const [alignment, setAlignment] = useState(readAlignmentSettings) const hideIp = useCanvasStore((s) => s.hideIp) const setHideIp = useCanvasStore((s) => s.setHideIp) useEffect(() => { if (!open || STANDALONE) return settingsApi.get() .then((res) => setIntervalValue(res.data.interval_seconds)) .catch(() => {/* use default */}) }, [open]) useEffect(() => subscribeAlignmentSettings(setAlignment), []) const updateAlignment = (patch: Partial) => { const next = { ...alignment, ...patch } setAlignment(next) writeAlignmentSettings(next) } const handleSave = async () => { // Canvas prefs (alignment, hide-IP) persist on change; only the backend // status-check interval needs an API round-trip. if (STANDALONE) { onClose() return } setSaving(true) try { await settingsApi.save({ interval_seconds: interval }) toast.success('Settings saved') onClose() } catch { toast.error('Failed to save settings') } finally { setSaving(false) } } return ( !v && onClose()}> Settings
{/* Status checker */} {!STANDALONE && (
{ const v = Number(e.target.value); if (!isNaN(v)) setIntervalValue(v) }} 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…)

)} {/* Canvas */}
Canvas
updateAlignment({ threshold: Number(e.target.value) })} className="flex-1 cursor-pointer accent-[#00d4ff]" aria-label="Alignment snap threshold" /> {alignment.threshold}px

Distance at which dragged nodes snap to neighbours. Hold Alt while dragging to disable.

) }