Spaces:
Running
Running
File size: 7,199 Bytes
c2ea5ed |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 |
import React, { useState, useEffect } from "react";
import { Card, CardContent } from "@/components/ui/card";
import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs";
import { GitCompare, BarChart3, Eye } from "lucide-react";
import { api } from "@/lib/api";
import { LoadingSpinner } from "@/components/shared/LoadingSpinner";
import { GraphSelector } from "./GraphSelector";
import { ComparisonResults } from "./ComparisonResults";
import { VisualComparison } from "./VisualComparison";
import { AvailableGraph, GraphComparisonResults } from "@/types";
export const GraphComparisonView: React.FC = () => {
const [activeTab, setActiveTab] = useState("selection");
const [availableGraphs, setAvailableGraphs] = useState<AvailableGraph[]>([]);
const [selectedGraph1, setSelectedGraph1] = useState<AvailableGraph | null>(
null
);
const [selectedGraph2, setSelectedGraph2] = useState<AvailableGraph | null>(
null
);
const [comparisonResults, setComparisonResults] =
useState<GraphComparisonResults | null>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
// Load available graphs on component mount
useEffect(() => {
loadAvailableGraphs();
}, []);
// Auto-refresh available graphs every 15 seconds
useEffect(() => {
const interval = setInterval(() => {
if (!isLoading) {
loadAvailableGraphs();
}
}, 15000); // 15 seconds
return () => clearInterval(interval);
}, [isLoading]);
const loadAvailableGraphs = async () => {
try {
setIsLoading(true);
setError(null);
const response = await api.graphComparison.listAvailableGraphs();
setAvailableGraphs(response.final_graphs);
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to load graphs");
} finally {
setIsLoading(false);
}
};
const handleGraphSelection = (
graph1: AvailableGraph | null,
graph2: AvailableGraph | null
) => {
setSelectedGraph1(graph1);
setSelectedGraph2(graph2);
// Remove auto-navigation - let users control when to switch tabs
};
const handleCompareGraphs = async () => {
if (!selectedGraph1 || !selectedGraph2) return;
try {
setIsLoading(true);
setError(null);
const results = await api.graphComparison.compareGraphs(
selectedGraph1.id,
selectedGraph2.id,
{ similarity_threshold: 0.7, use_cache: true }
);
setComparisonResults(results);
setActiveTab("results");
} catch (err) {
setError(err instanceof Error ? err.message : "Failed to compare graphs");
} finally {
setIsLoading(false);
}
};
const canCompare = selectedGraph1 && selectedGraph2;
return (
<div className="flex flex-col h-screen bg-background">
{/* Error Display */}
{error && (
<div className="mx-4 mt-4 p-4 bg-destructive/10 border border-destructive/20 rounded-lg">
<p className="text-destructive text-sm">{error}</p>
</div>
)}
{/* Content */}
<div className="flex-1 overflow-hidden">
<Tabs
value={activeTab}
onValueChange={setActiveTab}
className="h-full flex flex-col"
>
<div className="border-b enhanced-tabs px-4">
<TabsList className="grid w-full grid-cols-3 h-10 bg-transparent p-1 gap-1">
<TabsTrigger
value="selection"
className="flex items-center gap-2 h-8 px-3 rounded-md text-sm font-medium transition-all duration-200 data-[state=active]:bg-white data-[state=active]:text-primary data-[state=active]:shadow-sm data-[state=active]:border data-[state=active]:border-primary/20 hover:bg-white/60 hover:text-foreground text-muted-foreground"
>
<GitCompare className="h-3.5 w-3.5" />
Selection
</TabsTrigger>
<TabsTrigger
value="results"
disabled={!comparisonResults}
className="flex items-center gap-2 h-8 px-3 rounded-md text-sm font-medium transition-all duration-200 data-[state=active]:bg-white data-[state=active]:text-primary data-[state=active]:shadow-sm data-[state=active]:border data-[state=active]:border-primary/20 hover:bg-white/60 hover:text-foreground text-muted-foreground disabled:opacity-50 disabled:cursor-not-allowed"
>
<BarChart3 className="h-3.5 w-3.5" />
Results
</TabsTrigger>
<TabsTrigger
value="visual"
disabled={!canCompare}
className="flex items-center gap-2 h-8 px-3 rounded-md text-sm font-medium transition-all duration-200 data-[state=active]:bg-white data-[state=active]:text-primary data-[state=active]:shadow-sm data-[state=active]:border data-[state=active]:border-primary/20 hover:bg-white/60 hover:text-foreground text-muted-foreground disabled:opacity-50 disabled:cursor-not-allowed"
>
<Eye className="h-3.5 w-3.5" />
Visual
</TabsTrigger>
</TabsList>
</div>
<div className="flex-1 overflow-y-auto">
<TabsContent value="selection" className="h-full m-0 p-4">
{isLoading && !availableGraphs.length ? (
<div className="flex items-center justify-center h-64">
<LoadingSpinner size="lg" />
</div>
) : (
<GraphSelector
availableGraphs={availableGraphs}
selectedGraph1={selectedGraph1}
selectedGraph2={selectedGraph2}
onSelectionChange={handleGraphSelection}
onCompareGraphs={handleCompareGraphs}
isLoading={isLoading}
/>
)}
</TabsContent>
<TabsContent value="results" className="h-full m-0 p-4">
{comparisonResults ? (
<ComparisonResults results={comparisonResults} />
) : (
<Card>
<CardContent className="p-8 text-center">
<p className="text-muted-foreground">
No comparison results available
</p>
</CardContent>
</Card>
)}
</TabsContent>
<TabsContent value="visual" className="h-full m-0">
{canCompare ? (
<VisualComparison
graph1={selectedGraph1!}
graph2={selectedGraph2!}
comparisonResults={comparisonResults}
/>
) : (
<Card className="m-4">
<CardContent className="p-8 text-center">
<p className="text-muted-foreground">
Select 2 graphs to view visual comparison
</p>
</CardContent>
</Card>
)}
</TabsContent>
</div>
</Tabs>
</div>
</div>
);
};
|