feat(20-03): add SNMP profile editor page, route, and API client extensions

- Extend snmpProfilesApi with create, update, delete, parseMib, testProfile
- Add OIDNode, MIBParseResponse, ProfileTestRequest/Response, SNMPProfileCreate types
- Create settings.snmp-profiles route with RBAC and tenant resolution
- Build SNMPProfileEditorPage with list/edit views, MIB upload, poll groups
- Remove pre-existing duplicate credentialProfilesApi declaration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-21 20:33:49 -05:00
parent da598f79a0
commit b5f96b820f
4 changed files with 975 additions and 69 deletions

View File

@@ -556,6 +556,50 @@ export interface SNMPProfileResponse {
updated_at: string
}
export interface OIDNode {
oid: string
name: string
description?: string
type?: string
access?: string
status?: string
children?: OIDNode[]
}
export interface MIBParseResponse {
module_name: string
nodes: OIDNode[]
node_count: number
}
export interface ProfileTestRequest {
ip_address: string
snmp_port?: number
snmp_version: string
community?: string
security_level?: string
username?: string
auth_protocol?: string
auth_passphrase?: string
priv_protocol?: string
priv_passphrase?: string
}
export interface ProfileTestResponse {
success: boolean
device_info?: { sys_object_id?: string; sys_descr?: string; sys_name?: string }
error?: string
}
export interface SNMPProfileCreate {
name: string
description?: string
sys_object_id?: string
vendor?: string
category?: string
profile_data: Record<string, unknown>
}
export const snmpProfilesApi = {
list: (tenantId: string) =>
api
@@ -568,6 +612,46 @@ export const snmpProfilesApi = {
`/api/tenants/${tenantId}/snmp-profiles/${profileId}`,
)
.then((r) => r.data),
create: (tenantId: string, data: SNMPProfileCreate) =>
api
.post<SNMPProfileResponse>(
`/api/tenants/${tenantId}/snmp-profiles`,
data,
)
.then((r) => r.data),
update: (tenantId: string, profileId: string, data: SNMPProfileCreate) =>
api
.put<SNMPProfileResponse>(
`/api/tenants/${tenantId}/snmp-profiles/${profileId}`,
data,
)
.then((r) => r.data),
delete: (tenantId: string, profileId: string) =>
api
.delete(`/api/tenants/${tenantId}/snmp-profiles/${profileId}`)
.then((r) => r.data),
parseMib: (tenantId: string, file: File) => {
const formData = new FormData()
formData.append('file', file)
return api
.post<MIBParseResponse>(
`/api/tenants/${tenantId}/snmp-profiles/parse-mib`,
formData,
)
.then((r) => r.data)
},
testProfile: (tenantId: string, profileId: string, data: ProfileTestRequest) =>
api
.post<ProfileTestResponse>(
`/api/tenants/${tenantId}/snmp-profiles/${profileId}/test`,
data,
)
.then((r) => r.data),
}
// ─── Bulk Add (credential profile) ──────────────────────────────────────────
@@ -1789,72 +1873,3 @@ export const alertEventsApi = {
return data.count
},
}
// ─── Credential Profiles ─────────────────────────────────────────────────────
export interface CredentialProfileResponse {
id: string
name: string
description: string | null
credential_type: string // "routeros" | "snmp_v2c" | "snmp_v3"
device_count: number
created_at: string
updated_at: string
}
export interface CredentialProfileListResponse {
profiles: CredentialProfileResponse[]
}
export interface CredentialProfileCreate {
name: string
description?: string
credential_type: string
username?: string
password?: string
community?: string
security_level?: string
auth_protocol?: string
auth_passphrase?: string
privacy_protocol?: string
privacy_passphrase?: string
security_name?: string
}
export const credentialProfilesApi = {
list: (tenantId: string, credentialType?: string) =>
api
.get<CredentialProfileListResponse>(
`/api/tenants/${tenantId}/credential-profiles`,
{ params: credentialType ? { credential_type: credentialType } : undefined },
)
.then((r) => r.data),
get: (tenantId: string, profileId: string) =>
api
.get<CredentialProfileResponse>(
`/api/tenants/${tenantId}/credential-profiles/${profileId}`,
)
.then((r) => r.data),
create: (tenantId: string, data: CredentialProfileCreate) =>
api
.post<CredentialProfileResponse>(
`/api/tenants/${tenantId}/credential-profiles`,
data,
)
.then((r) => r.data),
update: (tenantId: string, profileId: string, data: Partial<CredentialProfileCreate>) =>
api
.put<CredentialProfileResponse>(
`/api/tenants/${tenantId}/credential-profiles/${profileId}`,
data,
)
.then((r) => r.data),
delete: (tenantId: string, profileId: string) =>
api
.delete(`/api/tenants/${tenantId}/credential-profiles/${profileId}`)
.then((r) => r.data),
}