import React, { useState, useEffect } from 'react'; import { useNavigate } from 'react-router-dom'; import { useUserStore } from '@/store/userStore'; import { motion, AnimatePresence } from 'framer-motion'; import { GitBranch, Database, FileText, Cpu, Share2, ShieldAlert, Search, Check, Brain, Layout, RefreshCw, Download, ArrowDown, Shield, Lock, Zap, HelpCircle, Network, CheckCircle2, AlertTriangle, Server, BarChart3, Table2, ChevronDown, ChevronRight, Activity, Columns, Clock, PieChart, Hash, Type } from 'lucide-react'; import { api } from '@/services/api'; const iconMap: Record = { database: , cpu: , brain: , layout: }; const DataLineage: React.FC = () => { const navigate = useNavigate(); const { isDark } = useUserStore(); const [lineageData, setLineageData] = useState(null); const [loading, setLoading] = useState(true); const [rescanning, setRescanning] = useState(false); const [expandedNode, setExpandedNode] = useState(null); const [showAuditLog, setShowAuditLog] = useState(false); // Theme classes const bgCard = isDark ? 'bg-white/[0.03]' : 'bg-white'; const border = isDark ? 'border-white/[0.06]' : 'border-slate-200'; const textH = isDark ? 'text-white' : 'text-slate-900'; const textM = isDark ? 'text-slate-400' : 'text-slate-600'; const textS = isDark ? 'text-slate-500' : 'text-slate-500'; const fetchData = async () => { try { const response = await api.get('/api/v1/lineage/'); setLineageData(response.data); } catch (err) { console.error("Failed to load lineage", err); } finally { setLoading(false); } }; useEffect(() => { fetchData(); }, []); const handleRescan = async () => { setRescanning(true); await fetchData(); setRescanning(false); }; const handleExportAuditLog = async () => { try { const response = await api.get('/api/v1/lineage/export', { responseType: 'blob' }); const url = window.URL.createObjectURL(response.data); const a = document.createElement('a'); a.href = url; a.download = 'datavision_audit_log.csv'; document.body.appendChild(a); a.click(); document.body.removeChild(a); window.URL.revokeObjectURL(url); } catch (err) { console.error("Failed to export audit log", err); } }; const stats = lineageData?.stats || {}; const nodes = lineageData?.nodes || []; const auditLog = lineageData?.audit_log || []; const dataQuality = stats?.data_quality || {}; return (
{/* Header */}

Data Lineage & Governance

Data flow tracking, column-level lineage, quality metrics, and audit trail.

{/* Compliance & Quality Stats */}
{[ { label: 'Data Completeness', value: dataQuality.completeness ? `${dataQuality.completeness}%` : (stats.gdpr_status === 'Verified' ? '100%' : 'No Data'), icon: CheckCircle2, color: (dataQuality.completeness || 0) > 90 ? 'text-emerald-500' : (dataQuality.completeness || 0) > 70 ? 'text-amber-500' : 'text-red-500', bg: isDark ? 'bg-emerald-500/10' : 'bg-emerald-50' }, { label: 'Active Pipelines', value: `${stats.total_pipelines || 0} Streams`, icon: GitBranch, color: isDark ? 'text-blue-400' : 'text-blue-600', bg: isDark ? 'bg-blue-500/10' : 'bg-blue-50' }, { label: 'Data Nodes', value: `${stats.total_nodes || 0} Nodes`, icon: Database, color: isDark ? 'text-purple-400' : 'text-purple-600', bg: isDark ? 'bg-purple-500/10' : 'bg-purple-50' }, { label: 'Total Columns', value: `${stats.total_columns || dataQuality.total_columns || 0}`, icon: Columns, color: isDark ? 'text-cyan-400' : 'text-cyan-600', bg: isDark ? 'bg-cyan-500/10' : 'bg-cyan-50' }, { label: 'Encryption', value: stats.encryption || 'AES-256', icon: Lock, color: isDark ? 'text-teal-400' : 'text-teal-600', bg: isDark ? 'bg-teal-500/10' : 'bg-teal-50' } ].map((stat, i) => (
{stat.label}

{stat.value}

))}
{/* Data Quality Breakdown — only show if we have column data */} {dataQuality.total_columns > 0 && (

Data Quality Profile

{/* Completeness Bar */}
Completeness = 90 ? 'text-emerald-500' : dataQuality.completeness >= 70 ? 'text-amber-500' : 'text-red-500' }`}>{dataQuality.completeness}%
= 90 ? 'bg-emerald-500' : dataQuality.completeness >= 70 ? 'bg-amber-500' : 'bg-red-500' }`} style={{ width: `${Math.min(100, dataQuality.completeness)}%` }} />
{/* Numeric vs Categorical */}
Column Types
{dataQuality.numeric_columns} Numeric
{dataQuality.categorical_columns} Categorical
{/* Total Stats */}
Dataset Overview
{stats.total_files} files {(stats.total_rows || 0).toLocaleString()} rows {dataQuality.total_columns} columns
)} {/* Audit Log Table — toggleable */} {showAuditLog && auditLog.length > 0 && (
Audit Trail
{auditLog.map((entry: any, i: number) => ( ))}
Timestamp Action Entity Details Status
{new Date(entry.timestamp).toLocaleString('en-IN', { dateStyle: 'medium', timeStyle: 'short' })} {entry.action} {entry.entity} {entry.details} {entry.status}
)}
{/* Data Flow Diagram */}
Interactive Data Flow Diagram
{loading ? (
) : nodes.length === 0 ? (

No Data Pipelines Yet

Upload a dataset in the Data Hub to see your data lineage flow appear here automatically.

) : (
{['source', 'transform', 'dashboard'].map((type, groupIdx) => { const groupNodes = nodes.filter((n: any) => n.type === type || (type === 'dashboard' && n.type === 'dashboard')); if (groupNodes.length === 0) return null; const groupLabel = type === 'source' ? '📥 Data Sources' : type === 'transform' ? '⚙️ Processing Pipeline' : '📊 Outputs'; return (

{groupLabel}

{groupNodes.map((node: any, nodeIdx: number) => { const statusColors: Record = { active: 'text-emerald-500', success: 'text-emerald-500', pending: 'text-amber-500', error: 'text-red-500', }; const isExpanded = expandedNode === node.id; const hasColumns = node.column_details && node.column_details.length > 0; return ( hasColumns && setExpandedNode(isExpanded ? null : node.id)} >
{iconMap[node.icon] || }
● {node.status} {hasColumns && ( isExpanded ? : )}
{node.label}

{node.type}

{node.metadata && (
{Object.entries(node.metadata).map(([key, value]) => (
{key}: {String(value)}
))}
)}
{/* Column-Level Lineage Details (expandable) */} {isExpanded && hasColumns && (
Column Details ({node.column_details.length})
{node.column_details.map((col: any, ci: number) => (
{col.type.includes('int') || col.type.includes('float') ? : } {col.name}
{col.type} 10 ? 'text-amber-500' : col.null_pct > 0 ? 'text-slate-400' : 'text-emerald-500'}`}> {col.null_pct}% null {col.unique} unique
))}
)}
); })}
{/* Flow arrow */} {type !== 'dashboard' && groupNodes.length > 0 && (
)}
); })}
)}
); }; export default DataLineage;