feat(audit): make device names clickable in audit log
Add device_id to the audit log API response and frontend type, then use DeviceLink to make device hostnames navigable in AuditLogTable. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -125,6 +125,7 @@ class AuditLogItem(BaseModel):
|
||||
action: str
|
||||
resource_type: Optional[str] = None
|
||||
resource_id: Optional[str] = None
|
||||
device_id: Optional[str] = None
|
||||
device_name: Optional[str] = None
|
||||
details: dict[str, Any] = {}
|
||||
ip_address: Optional[str] = None
|
||||
@@ -193,7 +194,8 @@ async def list_audit_logs(
|
||||
# Shared SELECT columns for data queries
|
||||
_data_columns = text(
|
||||
"a.id, u.email AS user_email, a.action, a.resource_type, "
|
||||
"a.resource_id, d.hostname AS device_name, a.details, "
|
||||
"a.resource_id, CAST(a.device_id AS text) AS device_id, "
|
||||
"d.hostname AS device_name, a.details, "
|
||||
"a.encrypted_details, a.ip_address, a.created_at"
|
||||
)
|
||||
_data_from = text(
|
||||
@@ -287,6 +289,7 @@ async def list_audit_logs(
|
||||
action=row["action"],
|
||||
resource_type=row["resource_type"],
|
||||
resource_id=row["resource_id"],
|
||||
device_id=row["device_id"],
|
||||
device_name=row["device_name"],
|
||||
details=details,
|
||||
ip_address=row["ip_address"],
|
||||
|
||||
@@ -22,6 +22,7 @@ import {
|
||||
type AuditLogParams,
|
||||
} from '@/lib/api'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { DeviceLink } from '@/components/ui/DeviceLink'
|
||||
import { EmptyState } from '@/components/ui/empty-state'
|
||||
|
||||
// Predefined action types for the filter dropdown
|
||||
@@ -253,6 +254,7 @@ export function AuditLogTable({ tenantId }: AuditLogTableProps) {
|
||||
<AuditLogRow
|
||||
key={item.id}
|
||||
item={item}
|
||||
tenantId={tenantId}
|
||||
isExpanded={expandedId === item.id}
|
||||
onToggle={() =>
|
||||
setExpandedId(expandedId === item.id ? null : item.id)
|
||||
@@ -339,11 +341,12 @@ export function AuditLogTable({ tenantId }: AuditLogTableProps) {
|
||||
|
||||
interface AuditLogRowProps {
|
||||
item: AuditLogEntry
|
||||
tenantId: string
|
||||
isExpanded: boolean
|
||||
onToggle: () => void
|
||||
}
|
||||
|
||||
function AuditLogRow({ item, isExpanded, onToggle }: AuditLogRowProps) {
|
||||
function AuditLogRow({ item, tenantId, isExpanded, onToggle }: AuditLogRowProps) {
|
||||
const hasDetails =
|
||||
item.details && Object.keys(item.details).length > 0
|
||||
|
||||
@@ -408,7 +411,11 @@ function AuditLogRow({ item, isExpanded, onToggle }: AuditLogRowProps) {
|
||||
)}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-text-secondary truncate max-w-[120px]">
|
||||
{item.device_name ?? '--'}
|
||||
{item.device_name && item.device_id ? (
|
||||
<DeviceLink tenantId={tenantId} deviceId={item.device_id}>
|
||||
{item.device_name}
|
||||
</DeviceLink>
|
||||
) : (item.device_name ?? '--')}
|
||||
</td>
|
||||
<td className="px-3 py-2 text-text-muted font-mono text-xs">
|
||||
{item.ip_address ?? '--'}
|
||||
|
||||
@@ -835,6 +835,7 @@ export interface AuditLogEntry {
|
||||
action: string
|
||||
resource_type: string | null
|
||||
resource_id: string | null
|
||||
device_id: string | null
|
||||
device_name: string | null
|
||||
details: Record<string, unknown>
|
||||
ip_address: string | null
|
||||
|
||||
Reference in New Issue
Block a user