feat: proxmox import diagnostics, node style fix, and cluster edges
Scan History: - Proxmox is now a first-class scan kind (badge, filter chip, Server icon, completion toast) instead of being mislabeled as an IP scan. - A done run carrying a non-fatal advisory renders amber (info) with a warning toast, distinct from red failures. Import diagnostics: - test-connection probes /access/permissions and warns when the API token has no ACL (VMs/LXC would be invisible) — points at the PVEAuditor grant. - import surfaces an advisory when hosts import but no guests are visible (privilege-separated token whose rights are the intersection with the user), rather than a silent "done". Node style: - Proxmox container mode is now opt-in (container_mode === true), matching the rest of the codebase (App.tsx nesting logic). Imported proxmox nodes leave the flag unset and render like a manually-created node instead of an empty group container. Cluster edges: - Hosts from one import are chained with 'cluster' edges via left/right handles, distinct from the vertical host->guest 'virtual' edges. Wired for both the direct "Add to Canvas" path and the pending -> approve path (host<->host proxmox_cluster links, resolved to cluster edges on approve; cluster hosts get left/right handles). Tests added on both sides. ha-relevant: maybe
This commit is contained in:
@@ -3,7 +3,7 @@ import { render, screen, fireEvent, waitFor } from '@testing-library/react'
|
||||
import { ScanHistoryModal } from '../ScanHistoryModal'
|
||||
import { TooltipProvider } from '@/components/ui/tooltip'
|
||||
|
||||
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }))
|
||||
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn(), warning: vi.fn() } }))
|
||||
vi.mock('@/stores/canvasStore', () => ({
|
||||
useCanvasStore: { getState: () => ({ notifyScanDeviceFound: vi.fn() }) },
|
||||
}))
|
||||
@@ -72,6 +72,17 @@ const ZWAVE_RUN = {
|
||||
error: null,
|
||||
}
|
||||
|
||||
const PROXMOX_RUN = {
|
||||
id: 'run-6',
|
||||
status: 'done',
|
||||
kind: 'proxmox',
|
||||
ranges: ['pve:8006'],
|
||||
devices_found: 9,
|
||||
started_at: new Date().toISOString(),
|
||||
finished_at: new Date().toISOString(),
|
||||
error: null,
|
||||
}
|
||||
|
||||
function renderModal() {
|
||||
return render(
|
||||
<TooltipProvider>
|
||||
@@ -84,6 +95,7 @@ describe('ScanHistoryModal', () => {
|
||||
beforeEach(() => {
|
||||
vi.mocked(toast.success).mockReset()
|
||||
vi.mocked(toast.error).mockReset()
|
||||
vi.mocked(toast.warning).mockReset()
|
||||
vi.mocked(scanApi.stop).mockReset()
|
||||
vi.mocked(scanApi.runs).mockResolvedValue({ data: [] } as never)
|
||||
})
|
||||
@@ -176,4 +188,31 @@ describe('ScanHistoryModal', () => {
|
||||
expect(screen.getByText('5 found')).toBeDefined()
|
||||
expect(screen.queryByText('3 found')).toBeNull()
|
||||
})
|
||||
|
||||
it('renders a done proxmox run with an advisory as info, not a failure', async () => {
|
||||
const ADVISORY_RUN = {
|
||||
...PROXMOX_RUN,
|
||||
id: 'run-7',
|
||||
devices_found: 3,
|
||||
error: 'Imported 3 host(s) but no VMs or LXC were visible to the API token. Grant PVEAuditor…',
|
||||
}
|
||||
vi.mocked(scanApi.runs).mockResolvedValue({ data: [ADVISORY_RUN] } as never)
|
||||
renderModal()
|
||||
// Status stays "done" (success), yet the advisory text is surfaced.
|
||||
await waitFor(() => expect(screen.getByText('done')).toBeDefined())
|
||||
expect(screen.getByText(/no VMs or LXC were visible/)).toBeDefined()
|
||||
})
|
||||
|
||||
it('shows a proxmox run under its own kind, not IP', async () => {
|
||||
vi.mocked(scanApi.runs).mockResolvedValue({ data: [DONE_RUN, PROXMOX_RUN] } as never)
|
||||
renderModal()
|
||||
await waitFor(() => expect(screen.getAllByText('done').length).toBe(2))
|
||||
// A dedicated Proxmox badge is rendered on the run (would be mislabeled "IP"
|
||||
// before the fix). Both the filter chip and the run badge carry the label.
|
||||
expect(screen.getAllByText('Proxmox').length).toBeGreaterThanOrEqual(2)
|
||||
// Filtering to Proxmox keeps only the proxmox run (9 found), drops the IP run.
|
||||
fireEvent.click(screen.getByRole('button', { name: 'Proxmox' }))
|
||||
expect(screen.getByText('9 found')).toBeDefined()
|
||||
expect(screen.queryByText('3 found')).toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user