diff --git a/frontend/src/components/config/ConfigHistorySection.tsx b/frontend/src/components/config/ConfigHistorySection.tsx new file mode 100644 index 0000000..83d64ad --- /dev/null +++ b/frontend/src/components/config/ConfigHistorySection.tsx @@ -0,0 +1,97 @@ +import { useQuery } from '@tanstack/react-query' +import { History } from 'lucide-react' +import { Badge } from '@/components/ui/badge' +import { TableSkeleton } from '@/components/ui/page-skeleton' +import { configHistoryApi } from '@/lib/api' + +interface ConfigHistorySectionProps { + tenantId: string + deviceId: string +} + +function formatRelativeTime(isoDate: string): string { + const date = new Date(isoDate) + const now = new Date() + const diffMs = now.getTime() - date.getTime() + const diffSec = Math.floor(diffMs / 1000) + const diffMin = Math.floor(diffSec / 60) + const diffHr = Math.floor(diffMin / 60) + const diffDay = Math.floor(diffHr / 24) + + if (diffSec < 60) return 'just now' + if (diffMin < 60) return `${diffMin}m ago` + if (diffHr < 24) return `${diffHr}h ago` + if (diffDay < 30) return `${diffDay}d ago` + return date.toLocaleDateString() +} + +function formatAbsoluteTime(isoDate: string): string { + return new Date(isoDate).toLocaleString() +} + +function LineDelta({ added, removed }: { added: number; removed: number }) { + return ( + + +{added} + / + -{removed} + + ) +} + +export function ConfigHistorySection({ tenantId, deviceId }: ConfigHistorySectionProps) { + const { data: changes, isLoading } = useQuery({ + queryKey: ['config-history', tenantId, deviceId], + queryFn: () => configHistoryApi.list(tenantId, deviceId), + refetchInterval: 60_000, + }) + + return ( +
+
+ +

Configuration History

+
+ + {isLoading ? ( + + ) : !changes || changes.length === 0 ? ( +
+ No configuration changes recorded yet. +
+ ) : ( +
+ {/* Connecting line */} +
+ +
+ {changes.map((entry) => ( +
+ {/* Timeline dot */} +
+ + {/* Content */} +
+
+ {entry.component} + +
+

{entry.summary}

+ + {formatRelativeTime(entry.created_at)} + +
+
+ ))} +
+
+ )} +
+ ) +} diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts index 339f6d2..40f04c9 100644 --- a/frontend/src/lib/api.ts +++ b/frontend/src/lib/api.ts @@ -968,6 +968,29 @@ export const remoteAccessApi = { .then((r) => r.data), } +// ─── Config History ───────────────────────────────────────────────────────── + +export interface ConfigChangeEntry { + id: string + component: string + summary: string + created_at: string + diff_id: string + lines_added: number + lines_removed: number + snapshot_id: string +} + +export const configHistoryApi = { + list: (tenantId: string, deviceId: string, limit = 50, offset = 0) => + api + .get( + `/api/tenants/${tenantId}/devices/${deviceId}/config-history`, + { params: { limit, offset } }, + ) + .then((r) => r.data), +} + // ─── VPN (WireGuard) ──────────────────────────────────────────────────────── export interface VpnConfigResponse {