import { useAccessLists } from '../hooks/useAccessLists'; import { ExternalLink } from 'lucide-react'; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from './ui/Select'; interface AccessListSelectorProps { value: number | string | null; onChange: (id: number | string | null) => void; } function resolveAccessListToken( value: number | string | null | undefined, accessLists?: Array<{ id?: number | string; uuid?: string }> ): string { if (value === null || value === undefined) { return 'none'; } if (typeof value === 'number') { return `id:${value}`; } const trimmed = value.trim(); if (trimmed === '') { return 'none'; } if (trimmed.startsWith('id:')) { return trimmed; } if (trimmed.startsWith('uuid:')) { const uuid = trimmed.slice(5); const matchingACL = accessLists?.find((acl) => acl.uuid === uuid); const matchingToken = matchingACL ? getOptionToken(matchingACL) : null; return matchingToken ?? trimmed; } if (/^\d+$/.test(trimmed)) { const parsed = Number.parseInt(trimmed, 10); return `id:${parsed}`; } const matchingACL = accessLists?.find((acl) => acl.uuid === trimmed); const matchingToken = matchingACL ? getOptionToken(matchingACL) : null; return matchingToken ?? `uuid:${trimmed}`; } function getOptionToken(acl: { id?: number | string; uuid?: string }): string | null { if (typeof acl.id === 'number' && Number.isFinite(acl.id)) { return `id:${acl.id}`; } if (typeof acl.id === 'string') { const trimmed = acl.id.trim(); if (trimmed !== '' && /^\d+$/.test(trimmed)) { const parsed = Number.parseInt(trimmed, 10); if (!Number.isNaN(parsed)) { return `id:${parsed}`; } } } if (acl.uuid) { return `uuid:${acl.uuid}`; } return null; } export default function AccessListSelector({ value, onChange }: AccessListSelectorProps) { const { data: accessLists } = useAccessLists(); const selectedToken = resolveAccessListToken(value, accessLists); const selectedACL = accessLists?.find((acl) => getOptionToken(acl) === selectedToken); // Keep select value stable for both numeric-ID and UUID-only payload shapes. const selectValue = selectedToken; const handleValueChange = (newValue: string) => { if (newValue === 'none') { onChange(null); return; } if (newValue.startsWith('id:')) { const numericId = Number.parseInt(newValue.slice(3), 10); if (!Number.isNaN(numericId)) { onChange(numericId); } return; } if (newValue.startsWith('uuid:')) { const selectedUUID = newValue.slice(5); const matchingACL = accessLists?.find((acl) => acl.uuid === selectedUUID); const matchingToken = matchingACL ? getOptionToken(matchingACL) : null; if (matchingToken?.startsWith('id:')) { const numericId = Number.parseInt(matchingToken.slice(3), 10); if (!Number.isNaN(numericId)) { onChange(numericId); return; } } onChange(selectedUUID); return; } if (/^\d+$/.test(newValue)) { const numericId = Number.parseInt(newValue, 10); onChange(numericId); return; } onChange(newValue); }; return (
{selectedACL && (
{selectedACL.name} {selectedACL.type.replace('_', ' ')}
{selectedACL.description && (

{selectedACL.description}

)} {selectedACL.local_network_only && (
🏠 Local Network Only (RFC1918)
)} {selectedACL.type.startsWith('geo_') && selectedACL.country_codes && (
🌍 Countries: {selectedACL.country_codes}
)}
)}

Restrict access based on IP address, CIDR ranges, or geographic location.{' '} Manage lists {' • '} Best Practices

); }