import React, { useState, useEffect, useCallback } from 'react'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/index'; import { Button } from '@/components/ui/index'; import { Badge } from '@/components/ui/index'; import { RefreshCw, Network, Plus, Edit, Trash2 } from 'lucide-react'; import { listNetworkInterfaces, listProxmoxClusters, NetworkInterface } from '@/lib/proxmoxClient'; import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from '@/components/ui/index'; import { Input } from '@/components/ui/index'; import { Label } from '@/components/ui/index'; import { toast } from 'sonner'; export function ProxmoxNetworkPage() { const [interfaces, setInterfaces] = useState([]); const [clusterId, setClusterId] = useState(''); const [nodeId] = useState('localhost'); const [loading, setLoading] = useState(false); const [error, setError] = useState(null); const [showAddDialog, setShowAddDialog] = useState(false); const [editingInterface, setEditingInterface] = useState(null); // Form state const [ifaceName, setIfaceName] = useState(''); const [ifaceType, setIfaceType] = useState('eth'); const [address, setAddress] = useState(''); const [netmask, setNetmask] = useState(''); const [gateway, setGateway] = useState(''); const [active, setActive] = useState(true); const loadInterfaces = useCallback(async (cId: string, nId: string) => { if (!cId) return; setLoading(true); setError(null); try { const ifaces = await listNetworkInterfaces(cId, nId); setInterfaces(ifaces); } catch (e) { setError(String(e)); } finally { setLoading(false); } }, []); useEffect(() => { listProxmoxClusters() .then((cls) => { if (cls.length > 0) { setClusterId(cls[0].id); void loadInterfaces(cls[0].id, nodeId); } }) .catch(console.error); }, [loadInterfaces, nodeId]); const handleAddInterface = () => { setEditingInterface(null); setIfaceName(''); setIfaceType('eth'); setAddress(''); setNetmask(''); setGateway(''); setActive(true); setShowAddDialog(true); }; const handleEditInterface = (iface: NetworkInterface) => { setEditingInterface(iface); setIfaceName(iface.iface); setIfaceType(iface.type); setAddress(iface.address || ''); setNetmask(iface.netmask || ''); setGateway(iface.gateway || ''); setActive(iface.active); setShowAddDialog(true); }; const handleSubmit = async () => { if (!ifaceName || !ifaceType) { toast.error('Interface name and type are required'); return; } try { if (editingInterface) { toast.info(`Updating interface ${ifaceName} - implementation pending`); } else { toast.info(`Creating interface ${ifaceName} - implementation pending`); } setShowAddDialog(false); } catch (error) { console.error('Failed to save interface:', error); toast.error(`Failed to save interface: ${error}`); } }; const handleDeleteInterface = async (iface: NetworkInterface) => { if (!confirm(`Are you sure you want to delete interface ${iface.iface}?`)) { return; } try { toast.info(`Deleting interface ${iface.iface} - implementation pending`); } catch (error) { console.error('Failed to delete interface:', error); toast.error(`Failed to delete interface: ${error}`); } }; return (

Network

Network interfaces and bridges

{error && (
{error}
)} Network Interfaces {loading ? (
Loading...
) : interfaces.length === 0 ? (
{clusterId ? 'No network interfaces found.' : 'No cluster configured.'}
) : (
{interfaces.map((iface, i) => (
{iface.iface} {iface.type} {iface.active ? 'Active' : 'Inactive'} {iface.autostart && ( Autostart )}
{(iface.address || iface.gateway) && (
{iface.address && ( {iface.address} {iface.netmask ? `/${iface.netmask}` : ''} )} {iface.gateway && ( gw {iface.gateway} )}
)} {iface.comments && (
{iface.comments}
)}
))}
)}
{editingInterface ? 'Edit Network Interface' : 'Add Network Interface'}
setIfaceName(e.target.value)} placeholder="eth0" />
setIfaceType(e.target.value)} placeholder="eth, bond, bridge, vlan" />
setAddress(e.target.value)} placeholder="192.168.1.100" />
setNetmask(e.target.value)} placeholder="24" />
setGateway(e.target.value)} placeholder="192.168.1.1" />
setActive(e.target.checked)} className="rounded" />
); }