feat(19-03): add credential profiles page and API types

- Create CredentialProfilesPage component with full CRUD for RouterOS and SNMP profiles
- Add credentialProfilesApi types and client to api.ts (blocking dependency from 19-01)
- Profile list grouped by type with device count, edit, and delete actions
- Create/edit dialog with conditional fields per credential type
- SNMPv3 form shows auth/privacy fields based on security_level selection
- Delete confirmation with 409 error handling for linked devices

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-21 19:58:02 -05:00
parent 6b87b88ce4
commit af776ea8ff
2 changed files with 599 additions and 0 deletions

View File

@@ -1789,3 +1789,72 @@ 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),
}