feat(08-01): wire diff viewer into config history timeline

- Add click handlers to timeline entries to open diff viewer
- Render DiffViewer inline above timeline when snapshot selected
- Add hover state and cursor-pointer to timeline entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Jason Staack
2026-03-12 23:20:52 -05:00
parent dda00fbd23
commit 2cf426fa63

View File

@@ -1,8 +1,10 @@
import { useState } from 'react'
import { useQuery } from '@tanstack/react-query' import { useQuery } from '@tanstack/react-query'
import { History } from 'lucide-react' import { History } from 'lucide-react'
import { Badge } from '@/components/ui/badge' import { Badge } from '@/components/ui/badge'
import { TableSkeleton } from '@/components/ui/page-skeleton' import { TableSkeleton } from '@/components/ui/page-skeleton'
import { configHistoryApi } from '@/lib/api' import { configHistoryApi } from '@/lib/api'
import { DiffViewer } from './DiffViewer'
interface ConfigHistorySectionProps { interface ConfigHistorySectionProps {
tenantId: string tenantId: string
@@ -40,6 +42,7 @@ function LineDelta({ added, removed }: { added: number; removed: number }) {
} }
export function ConfigHistorySection({ tenantId, deviceId }: ConfigHistorySectionProps) { export function ConfigHistorySection({ tenantId, deviceId }: ConfigHistorySectionProps) {
const [selectedSnapshotId, setSelectedSnapshotId] = useState<string | null>(null)
const { data: changes, isLoading } = useQuery({ const { data: changes, isLoading } = useQuery({
queryKey: ['config-history', tenantId, deviceId], queryKey: ['config-history', tenantId, deviceId],
queryFn: () => configHistoryApi.list(tenantId, deviceId), queryFn: () => configHistoryApi.list(tenantId, deviceId),
@@ -53,6 +56,17 @@ export function ConfigHistorySection({ tenantId, deviceId }: ConfigHistorySectio
<h3 className="text-sm font-medium text-muted-foreground">Configuration History</h3> <h3 className="text-sm font-medium text-muted-foreground">Configuration History</h3>
</div> </div>
{selectedSnapshotId && (
<div className="mb-3">
<DiffViewer
tenantId={tenantId}
deviceId={deviceId}
snapshotId={selectedSnapshotId}
onClose={() => setSelectedSnapshotId(null)}
/>
</div>
)}
{isLoading ? ( {isLoading ? (
<TableSkeleton rows={3} /> <TableSkeleton rows={3} />
) : !changes || changes.length === 0 ? ( ) : !changes || changes.length === 0 ? (
@@ -68,7 +82,8 @@ export function ConfigHistorySection({ tenantId, deviceId }: ConfigHistorySectio
{changes.map((entry) => ( {changes.map((entry) => (
<div <div
key={entry.id} key={entry.id}
className="relative flex items-start gap-3 pl-8 pr-3 py-2.5 rounded-lg" className="relative flex items-start gap-3 pl-8 pr-3 py-2.5 rounded-lg cursor-pointer hover:bg-elevated/50 transition-colors"
onClick={() => setSelectedSnapshotId(entry.snapshot_id)}
> >
{/* Timeline dot */} {/* Timeline dot */}
<div className="absolute left-2 top-3.5 h-2 w-2 rounded-full border border-border bg-elevated" /> <div className="absolute left-2 top-3.5 h-2 w-2 rounded-full border border-border bg-elevated" />