diff --git a/frontend/src/components/config/DiffViewer.tsx b/frontend/src/components/config/DiffViewer.tsx
new file mode 100644
index 0000000..c64af73
--- /dev/null
+++ b/frontend/src/components/config/DiffViewer.tsx
@@ -0,0 +1,72 @@
+import { useQuery } from '@tanstack/react-query'
+import { X } from 'lucide-react'
+import { configHistoryApi } from '@/lib/api'
+
+interface DiffViewerProps {
+ tenantId: string
+ deviceId: string
+ snapshotId: string
+ onClose: () => void
+}
+
+function classifyLine(line: string): string {
+ if (line.startsWith('@@')) return 'bg-blue-900/20 text-blue-300'
+ if (line.startsWith('+++') || line.startsWith('---')) return 'text-text-muted'
+ if (line.startsWith('+')) return 'bg-green-900/30 text-green-300'
+ if (line.startsWith('-')) return 'bg-red-900/30 text-red-300'
+ return 'text-text-primary'
+}
+
+export function DiffViewer({ tenantId, deviceId, snapshotId, onClose }: DiffViewerProps) {
+ const { data: diff, isLoading, isError } = useQuery({
+ queryKey: ['config-diff', tenantId, deviceId, snapshotId],
+ queryFn: () => configHistoryApi.getDiff(tenantId, deviceId, snapshotId),
+ })
+
+ return (
+
+ {/* Header */}
+
+
+
Config Diff
+ {diff && (
+
+ +{diff.lines_added}
+ /
+ -{diff.lines_removed}
+
+ )}
+
+
+
+
+ {/* Content */}
+ {isLoading ? (
+
+ {Array.from({ length: 6 }).map((_, i) => (
+
+ ))}
+
+ ) : isError || !diff ? (
+
+ No diff available.
+
+ ) : (
+
+
+ {diff.diff_text.split('\n').map((line, i) => (
+
+ {line || '\u00A0'}
+
+ ))}
+
+
+ )}
+
+ )
+}
diff --git a/frontend/src/lib/api.ts b/frontend/src/lib/api.ts
index 40f04c9..787ba88 100644
--- a/frontend/src/lib/api.ts
+++ b/frontend/src/lib/api.ts
@@ -981,6 +981,16 @@ export interface ConfigChangeEntry {
snapshot_id: string
}
+export interface DiffResponse {
+ id: string
+ diff_text: string
+ lines_added: number
+ lines_removed: number
+ old_snapshot_id: string
+ new_snapshot_id: string
+ created_at: string
+}
+
export const configHistoryApi = {
list: (tenantId: string, deviceId: string, limit = 50, offset = 0) =>
api
@@ -989,6 +999,13 @@ export const configHistoryApi = {
{ params: { limit, offset } },
)
.then((r) => r.data),
+
+ getDiff: (tenantId: string, deviceId: string, snapshotId: string) =>
+ api
+ .get(
+ `/api/tenants/${tenantId}/devices/${deviceId}/config/${snapshotId}/diff`,
+ )
+ .then((r) => r.data),
}
// ─── VPN (WireGuard) ────────────────────────────────────────────────────────