feat: split scan config and app settings into separate endpoints
- New GET/POST /api/v1/settings for status check interval - Scan /api/v1/scan/config now handles ranges only - Frontend: settingsApi client, SettingsPanel uses settingsApi - ScanConfigModal no longer reads/writes interval - 4 new backend tests for settings endpoint
This commit is contained in:
@@ -15,16 +15,12 @@ interface ScanConfigModalProps {
|
||||
|
||||
export function ScanConfigModal({ open, onClose, onScanNow }: ScanConfigModalProps) {
|
||||
const [ranges, setRanges] = useState<string[]>([''])
|
||||
const [interval, setInterval] = useState(60)
|
||||
const [saving, setSaving] = useState(false)
|
||||
|
||||
useEffect(() => {
|
||||
if (!open) return
|
||||
scanApi.getConfig()
|
||||
.then((res) => {
|
||||
setRanges(res.data.ranges.length > 0 ? res.data.ranges : [''])
|
||||
setInterval(res.data.interval_seconds)
|
||||
})
|
||||
.then((res) => setRanges(res.data.ranges.length > 0 ? res.data.ranges : ['']))
|
||||
.catch(() => {/* use defaults */})
|
||||
}, [open])
|
||||
|
||||
@@ -33,7 +29,7 @@ export function ScanConfigModal({ open, onClose, onScanNow }: ScanConfigModalPro
|
||||
if (cleaned.length === 0) { toast.error('Add at least one IP range'); return }
|
||||
setSaving(true)
|
||||
try {
|
||||
await scanApi.saveConfig({ ranges: cleaned, interval_seconds: interval })
|
||||
await scanApi.saveConfig({ ranges: cleaned })
|
||||
toast.success('Scan config saved')
|
||||
onClose()
|
||||
} catch {
|
||||
|
||||
@@ -13,7 +13,7 @@ vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), info: vi.f
|
||||
import { scanApi } from '@/api/client'
|
||||
import { toast } from 'sonner'
|
||||
|
||||
const defaultConfig = { data: { ranges: ['192.168.1.0/24'], interval_seconds: 60 } }
|
||||
const defaultConfig = { data: { ranges: ['192.168.1.0/24'] } }
|
||||
|
||||
describe('ScanConfigModal', () => {
|
||||
beforeEach(() => {
|
||||
@@ -38,13 +38,13 @@ describe('ScanConfigModal', () => {
|
||||
expect(input).toBeDefined()
|
||||
})
|
||||
|
||||
it('preserves interval from API when saving ranges', async () => {
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: ['10.0.0.0/8'], interval_seconds: 120 } } as never)
|
||||
it('saves only ranges (interval managed by settings endpoint)', async () => {
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: ['10.0.0.0/8'] } } as never)
|
||||
render(<ScanConfigModal open onClose={vi.fn()} onScanNow={vi.fn()} />)
|
||||
await screen.findByDisplayValue('10.0.0.0/8')
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Save' }))
|
||||
await waitFor(() => {
|
||||
expect(scanApi.saveConfig).toHaveBeenCalledWith({ ranges: ['10.0.0.0/8'], interval_seconds: 120 })
|
||||
expect(scanApi.saveConfig).toHaveBeenCalledWith({ ranges: ['10.0.0.0/8'] })
|
||||
})
|
||||
})
|
||||
|
||||
@@ -65,7 +65,7 @@ describe('ScanConfigModal', () => {
|
||||
})
|
||||
|
||||
it('can remove a range when more than one exist', async () => {
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: ['192.168.1.0/24', '10.0.0.0/8'], interval_seconds: 60 } } as never)
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: ['192.168.1.0/24', '10.0.0.0/8'], } } as never)
|
||||
render(<ScanConfigModal open onClose={vi.fn()} onScanNow={vi.fn()} />)
|
||||
await screen.findByDisplayValue('192.168.1.0/24')
|
||||
// Both trash buttons should be enabled
|
||||
@@ -74,7 +74,7 @@ describe('ScanConfigModal', () => {
|
||||
})
|
||||
|
||||
it('shows error toast and does not save when all ranges are empty', async () => {
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: [''], interval_seconds: 60 } } as never)
|
||||
vi.mocked(scanApi.getConfig).mockResolvedValue({ data: { ranges: [''], } } as never)
|
||||
render(<ScanConfigModal open onClose={vi.fn()} onScanNow={vi.fn()} />)
|
||||
await waitFor(() => expect(scanApi.getConfig).toHaveBeenCalled())
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Save' }))
|
||||
@@ -90,7 +90,7 @@ describe('ScanConfigModal', () => {
|
||||
await screen.findByDisplayValue('192.168.1.0/24')
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Save' }))
|
||||
await waitFor(() => {
|
||||
expect(scanApi.saveConfig).toHaveBeenCalledWith({ ranges: ['192.168.1.0/24'], interval_seconds: 60 })
|
||||
expect(scanApi.saveConfig).toHaveBeenCalledWith({ ranges: ['192.168.1.0/24'] })
|
||||
expect(toast.success).toHaveBeenCalledWith('Scan config saved')
|
||||
expect(onClose).toHaveBeenCalledOnce()
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user