import { useCallback, useEffect, useMemo, useState } from "react"; import { appClient } from "@/api/appClient"; import PageHeader from "@/components/shared/PageHeader"; import EmptyState from "@/components/shared/EmptyState"; import StatusBadge from "@/components/shared/StatusBadge"; import { useToast } from "@/components/ui/use-toast"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; const splitMultiValue = (input) => input .split(/[\n,]/) .map((item) => item.trim()) .filter(Boolean); export default function NetworkIpam() { const { toast } = useToast(); const [loading, setLoading] = useState(true); const [ipData, setIpData] = useState([]); const [assignments, setAssignments] = useState([]); const [vms, setVms] = useState([]); const [tenants, setTenants] = useState([]); const [utilization, setUtilization] = useState({ subnets: [], assignment_summary: { total: 0, ipv4: 0, ipv6: 0 } }); const [quotas, setQuotas] = useState([]); const [ranges, setRanges] = useState([]); const [policies, setPolicies] = useState([]); const [importForm, setImportForm] = useState({ addresses: "", cidr_blocks: "", scope: "PUBLIC" }); const [assignForm, setAssignForm] = useState({ vm_id: "", address: "", scope: "PUBLIC", version: "IPV4", assignment_type: "ADDITIONAL" }); const [quotaForm, setQuotaForm] = useState({ tenant_id: "", ipv4_limit: "", ipv6_limit: "" }); const [rangeForm, setRangeForm] = useState({ name: "", cidr: "", scope: "PUBLIC", tenant_id: "" }); const [policyForm, setPolicyForm] = useState({ name: "", tenant_id: "", allocation_strategy: "BEST_FIT", priority: "100" }); const activeAssignments = useMemo(() => assignments.filter((x) => x.is_active), [assignments]); const loadData = useCallback(async () => { setLoading(true); try { const [ips, asn, vmList, tenantList, dash, quotaList, rangeList, policyList] = await Promise.all([ appClient.network.listIpAddresses({ limit: 300 }), appClient.network.listIpAssignments({ active_only: true }), appClient.entities.VirtualMachine.list("-created_at", 200), appClient.entities.Tenant.list("-created_at", 200), appClient.network.subnetUtilization(), appClient.network.listTenantQuotas(), appClient.network.listReservedRanges(), appClient.network.listPolicies() ]); setIpData(ips?.data ?? []); setAssignments(asn?.data ?? []); setVms(vmList ?? []); setTenants(tenantList ?? []); setUtilization(dash ?? { subnets: [], assignment_summary: { total: 0, ipv4: 0, ipv6: 0 } }); setQuotas(quotaList?.data ?? []); setRanges(rangeList?.data ?? []); setPolicies(policyList?.data ?? []); } catch (error) { toast({ title: "Load Failed", description: error?.message ?? "Could not load network data", variant: "destructive" }); } finally { setLoading(false); } }, [toast]); useEffect(() => { loadData(); }, [loadData]); const runAction = async (fn, success) => { try { await fn(); toast({ title: success }); await loadData(); } catch (error) { toast({ title: "Action Failed", description: error?.message ?? "Request failed", variant: "destructive" }); } }; if (loading) { return
Assigned
{utilization.assignment_summary?.total ?? 0}
IPv4
{utilization.assignment_summary?.ipv4 ?? 0}
IPv6
{utilization.assignment_summary?.ipv6 ?? 0}
Subnets
{utilization.subnets?.length ?? 0}
Configured quotas: {quotas.length}
Reserved ranges: {ranges.length}
Policies: {policies.length}
| Subnet | Scope | Assigned | Available | Utilization |
|---|---|---|---|---|
| {item.subnet} | {item.scope} | {item.assigned} | {item.available} | {item.utilization_pct}% |
| Address | Scope | Status |
|---|---|---|
| {item.address}/{item.cidr} | {item.scope} |