fix(ui): correct SNMP protocol values and simplify add-device flow
- Add missing fields to SNMPProfileResponse (sys_object_id, vendor, category, tenant_id) - Fix security level values to snake_case (no_auth_no_priv, auth_no_priv, auth_priv) matching backend - Fix auth protocols to SHA256/SHA384/SHA512 (was MD5/SHA/SHA256) - Fix privacy protocols to AES128/AES256 (was DES/AES/AES256) - Apply same protocol fixes to ProfileTestPanel - Fix BulkAddForm to show both v2c and v3 credential profiles (was hardcoded to v2c) - Simplify SNMP tab in AddDeviceForm to IP + credential profile + discover-and-add button - Show guidance link when no SNMP credential profiles exist Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -33,7 +33,7 @@ interface CredentialProfilesPageProps {
|
||||
}
|
||||
|
||||
type CredentialType = 'routeros' | 'snmp_v2c' | 'snmp_v3'
|
||||
type SecurityLevel = 'noAuthNoPriv' | 'authNoPriv' | 'authPriv'
|
||||
type SecurityLevel = 'no_auth_no_priv' | 'auth_no_priv' | 'auth_priv'
|
||||
|
||||
const CREDENTIAL_TYPE_LABELS: Record<CredentialType, string> = {
|
||||
routeros: 'RouterOS',
|
||||
@@ -42,13 +42,13 @@ const CREDENTIAL_TYPE_LABELS: Record<CredentialType, string> = {
|
||||
}
|
||||
|
||||
const SECURITY_LEVELS: { value: SecurityLevel; label: string }[] = [
|
||||
{ value: 'noAuthNoPriv', label: 'No Auth, No Privacy' },
|
||||
{ value: 'authNoPriv', label: 'Auth, No Privacy' },
|
||||
{ value: 'authPriv', label: 'Auth + Privacy' },
|
||||
{ value: 'no_auth_no_priv', label: 'No Auth, No Privacy' },
|
||||
{ value: 'auth_no_priv', label: 'Auth, No Privacy' },
|
||||
{ value: 'auth_priv', label: 'Auth and Privacy' },
|
||||
]
|
||||
|
||||
const AUTH_PROTOCOLS = ['MD5', 'SHA', 'SHA256'] as const
|
||||
const PRIVACY_PROTOCOLS = ['DES', 'AES', 'AES256'] as const
|
||||
const AUTH_PROTOCOLS = ['SHA256', 'SHA384', 'SHA512'] as const
|
||||
const PRIVACY_PROTOCOLS = ['AES128', 'AES256'] as const
|
||||
|
||||
// ─── Profile Card ───────────────────────────────────────────────────────────
|
||||
|
||||
@@ -234,7 +234,7 @@ export function CredentialProfilesPage({ tenantId }: CredentialProfilesPageProps
|
||||
// ─── Render ─────────────────────────────────────────────────────────────
|
||||
|
||||
const credType = form.credential_type as CredentialType
|
||||
const secLevel = (form.security_level ?? 'noAuthNoPriv') as SecurityLevel
|
||||
const secLevel = (form.security_level ?? 'no_auth_no_priv') as SecurityLevel
|
||||
|
||||
return (
|
||||
<div className="space-y-6 max-w-2xl">
|
||||
@@ -413,7 +413,7 @@ export function CredentialProfilesPage({ tenantId }: CredentialProfilesPageProps
|
||||
<div>
|
||||
<Label className="text-xs">Security Level</Label>
|
||||
<Select
|
||||
value={form.security_level ?? 'noAuthNoPriv'}
|
||||
value={form.security_level ?? 'no_auth_no_priv'}
|
||||
onValueChange={(v) => updateForm({ security_level: v })}
|
||||
>
|
||||
<SelectTrigger className="mt-1">
|
||||
@@ -429,13 +429,13 @@ export function CredentialProfilesPage({ tenantId }: CredentialProfilesPageProps
|
||||
</Select>
|
||||
</div>
|
||||
|
||||
{/* Auth fields (authNoPriv or authPriv) */}
|
||||
{(secLevel === 'authNoPriv' || secLevel === 'authPriv') && (
|
||||
{/* Auth fields (auth_no_priv or auth_priv) */}
|
||||
{(secLevel === 'auth_no_priv' || secLevel === 'auth_priv') && (
|
||||
<>
|
||||
<div>
|
||||
<Label className="text-xs">Auth Protocol</Label>
|
||||
<Select
|
||||
value={form.auth_protocol ?? 'SHA'}
|
||||
value={form.auth_protocol ?? 'SHA256'}
|
||||
onValueChange={(v) => updateForm({ auth_protocol: v })}
|
||||
>
|
||||
<SelectTrigger className="mt-1">
|
||||
@@ -467,13 +467,13 @@ export function CredentialProfilesPage({ tenantId }: CredentialProfilesPageProps
|
||||
</>
|
||||
)}
|
||||
|
||||
{/* Privacy fields (authPriv only) */}
|
||||
{secLevel === 'authPriv' && (
|
||||
{/* Privacy fields (auth_priv only) */}
|
||||
{secLevel === 'auth_priv' && (
|
||||
<>
|
||||
<div>
|
||||
<Label className="text-xs">Privacy Protocol</Label>
|
||||
<Select
|
||||
value={form.privacy_protocol ?? 'AES'}
|
||||
value={form.privacy_protocol ?? 'AES128'}
|
||||
onValueChange={(v) => updateForm({ privacy_protocol: v })}
|
||||
>
|
||||
<SelectTrigger className="mt-1">
|
||||
|
||||
@@ -30,16 +30,16 @@ interface ProfileTestPanelProps {
|
||||
}
|
||||
|
||||
type SNMPVersion = 'v1' | 'v2c' | 'v3'
|
||||
type SecurityLevel = 'noAuthNoPriv' | 'authNoPriv' | 'authPriv'
|
||||
type SecurityLevel = 'no_auth_no_priv' | 'auth_no_priv' | 'auth_priv'
|
||||
|
||||
const SECURITY_LEVELS: { value: SecurityLevel; label: string }[] = [
|
||||
{ value: 'noAuthNoPriv', label: 'No Auth, No Privacy' },
|
||||
{ value: 'authNoPriv', label: 'Auth, No Privacy' },
|
||||
{ value: 'authPriv', label: 'Auth + Privacy' },
|
||||
{ value: 'no_auth_no_priv', label: 'No Auth, No Privacy' },
|
||||
{ value: 'auth_no_priv', label: 'Auth, No Privacy' },
|
||||
{ value: 'auth_priv', label: 'Auth and Privacy' },
|
||||
]
|
||||
|
||||
const AUTH_PROTOCOLS = ['MD5', 'SHA', 'SHA256'] as const
|
||||
const PRIV_PROTOCOLS = ['DES', 'AES', 'AES256'] as const
|
||||
const AUTH_PROTOCOLS = ['SHA256', 'SHA384', 'SHA512'] as const
|
||||
const PRIV_PROTOCOLS = ['AES128', 'AES256'] as const
|
||||
|
||||
// ─── Component ──────────────────────────────────────────────────────────────
|
||||
|
||||
@@ -52,11 +52,11 @@ export function ProfileTestPanel({ tenantId, profileId }: ProfileTestPanelProps)
|
||||
const [snmpPort, setSnmpPort] = useState('161')
|
||||
const [snmpVersion, setSnmpVersion] = useState<SNMPVersion>('v2c')
|
||||
const [community, setCommunity] = useState('public')
|
||||
const [securityLevel, setSecurityLevel] = useState<SecurityLevel>('authNoPriv')
|
||||
const [securityLevel, setSecurityLevel] = useState<SecurityLevel>('auth_no_priv')
|
||||
const [username, setUsername] = useState('')
|
||||
const [authProtocol, setAuthProtocol] = useState('SHA')
|
||||
const [authProtocol, setAuthProtocol] = useState('SHA256')
|
||||
const [authPassphrase, setAuthPassphrase] = useState('')
|
||||
const [privProtocol, setPrivProtocol] = useState('AES')
|
||||
const [privProtocol, setPrivProtocol] = useState('AES128')
|
||||
const [privPassphrase, setPrivPassphrase] = useState('')
|
||||
|
||||
// ─── Test mutation ───────────────────────────────────────────────────
|
||||
@@ -82,11 +82,11 @@ export function ProfileTestPanel({ tenantId, profileId }: ProfileTestPanelProps)
|
||||
} else {
|
||||
request.security_level = securityLevel
|
||||
if (username.trim()) request.username = username.trim()
|
||||
if (securityLevel === 'authNoPriv' || securityLevel === 'authPriv') {
|
||||
if (securityLevel === 'auth_no_priv' || securityLevel === 'auth_priv') {
|
||||
request.auth_protocol = authProtocol
|
||||
if (authPassphrase) request.auth_passphrase = authPassphrase
|
||||
}
|
||||
if (securityLevel === 'authPriv') {
|
||||
if (securityLevel === 'auth_priv') {
|
||||
request.priv_protocol = privProtocol
|
||||
if (privPassphrase) request.priv_passphrase = privPassphrase
|
||||
}
|
||||
@@ -197,7 +197,7 @@ export function ProfileTestPanel({ tenantId, profileId }: ProfileTestPanelProps)
|
||||
</div>
|
||||
|
||||
{/* Auth fields */}
|
||||
{(securityLevel === 'authNoPriv' || securityLevel === 'authPriv') && (
|
||||
{(securityLevel === 'auth_no_priv' || securityLevel === 'auth_priv') && (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-xs">Auth Protocol</Label>
|
||||
@@ -227,7 +227,7 @@ export function ProfileTestPanel({ tenantId, profileId }: ProfileTestPanelProps)
|
||||
)}
|
||||
|
||||
{/* Privacy fields */}
|
||||
{securityLevel === 'authPriv' && (
|
||||
{securityLevel === 'auth_priv' && (
|
||||
<div className="grid grid-cols-2 gap-3">
|
||||
<div>
|
||||
<Label className="text-xs">Privacy Protocol</Label>
|
||||
|
||||
Reference in New Issue
Block a user