157 lines
5.4 KiB
TypeScript
157 lines
5.4 KiB
TypeScript
import { useQuery } from "@tanstack/react-query";
|
|
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
|
import { Badge } from "@/components/ui/badge";
|
|
import { Button } from "@/components/ui/button";
|
|
import { RefreshCw, AlertCircle, Radar, Download } from "lucide-react";
|
|
import { SignatureCategories } from "@/components/SignatureCategories";
|
|
import { useSignatureCategories } from "@/hooks/useSignatureCategories";
|
|
import { toast } from "@/hooks/use-toast";
|
|
import { CleanModeToggle } from "@/components/CleanModeToggle";
|
|
import pb from "@/lib/pocketbase";
|
|
import { SigviewRecord as Signature } from "@/lib/pbtypes";
|
|
|
|
interface SystemTrackerProps {
|
|
system: string;
|
|
cleanMode: boolean;
|
|
onCleanModeToggle: (enabled: boolean) => void;
|
|
onDelete?: (signatureId: string) => Promise<void>;
|
|
onUpdate?: (updatedSignature: Partial<Signature>) => Promise<void>;
|
|
}
|
|
|
|
export const SystemTracker = ({ system, cleanMode, onCleanModeToggle, onDelete, onUpdate }: SystemTrackerProps) => {
|
|
const {
|
|
data: signaturesData,
|
|
refetch: refetchSignatures,
|
|
isLoading: signaturesLoading,
|
|
error: signaturesError
|
|
} = useQuery({
|
|
queryKey: ['signatures', system],
|
|
queryFn: async () => {
|
|
if (!system) return null;
|
|
const signatures = await pb.collection('sigview').getFullList<Signature>({ batch: 1000, filter: `(system='${system}')` });
|
|
const sigMap = new Map<string, Signature>();
|
|
signatures.forEach(sig => {
|
|
sigMap.set(sig.identifier, sig);
|
|
});
|
|
return sigMap;
|
|
},
|
|
enabled: !!system,
|
|
refetchInterval: 5000, // Poll every 5 seconds
|
|
});
|
|
|
|
const handleRefresh = () => {
|
|
refetchSignatures();
|
|
toast({
|
|
title: "Refreshing Data",
|
|
description: "Updating signature information...",
|
|
});
|
|
};
|
|
|
|
const handleExport = () => {
|
|
const exportText = Object.values(signaturesData || {})
|
|
.map(sig => [
|
|
sig.identifier,
|
|
'', // Empty field (part[1] in parseSignature)
|
|
sig.type || '',
|
|
sig.signame || '',
|
|
sig.scanned || ''
|
|
].join('\t'))
|
|
.join('\n');
|
|
|
|
navigator.clipboard.writeText(exportText).then(() => {
|
|
toast({
|
|
title: "Exported",
|
|
description: "Signatures copied to clipboard in EVE format",
|
|
});
|
|
}).catch(() => {
|
|
toast({
|
|
title: "Export Failed",
|
|
description: "Failed to copy to clipboard",
|
|
variant: "destructive"
|
|
});
|
|
});
|
|
};
|
|
|
|
const isLoading = signaturesLoading;
|
|
const { categories, toggleCategoryVisibility } = useSignatureCategories(signaturesData || new Map());
|
|
|
|
return (
|
|
<div className="space-y-6">
|
|
{/* System Status Card */}
|
|
<Card className="bg-slate-800/50 border-slate-700">
|
|
<CardHeader className="flex flex-row items-center justify-between space-y-0 pb-4">
|
|
<CardTitle className="text-xl text-white flex items-center gap-2">
|
|
<Radar className="h-5 w-5 text-blue-400" />
|
|
{system}
|
|
<Badge variant="outline" className="ml-2 bg-blue-900/20 text-blue-400 border-blue-600">
|
|
Polling
|
|
</Badge>
|
|
</CardTitle>
|
|
<div className="flex items-center gap-2">
|
|
<CleanModeToggle cleanMode={cleanMode} onToggle={onCleanModeToggle} />
|
|
<Badge variant="outline" className="bg-slate-700/50 text-slate-300 border-slate-600">
|
|
Total: {signaturesData?.size}
|
|
</Badge>
|
|
<Button
|
|
onClick={handleExport}
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-6 w-6 text-slate-400 hover:text-slate-200 hover:bg-slate-700/50"
|
|
>
|
|
<Download className="h-3 w-3" />
|
|
</Button>
|
|
<Button
|
|
onClick={handleRefresh}
|
|
disabled={isLoading}
|
|
variant="ghost"
|
|
size="icon"
|
|
className="h-6 w-6 text-slate-400 hover:text-slate-200 hover:bg-slate-700/50"
|
|
>
|
|
<RefreshCw className={`h-3 w-3 ${isLoading ? 'animate-spin' : ''}`} />
|
|
</Button>
|
|
</div>
|
|
</CardHeader>
|
|
</Card>
|
|
|
|
{/* Error Display */}
|
|
{signaturesError && (
|
|
<Card className="bg-red-900/20 border-red-700">
|
|
<CardContent className="pt-6">
|
|
<div className="flex items-center gap-2 text-red-400">
|
|
<AlertCircle className="h-5 w-5" />
|
|
<span>Error loading signatures: {signaturesError.message}</span>
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Loading State */}
|
|
{signaturesLoading && system && (
|
|
<Card className="bg-slate-800/30 border-slate-700">
|
|
<CardContent className="pt-6">
|
|
<div className="space-y-4">
|
|
{[...Array(1)].map((_, i) => (
|
|
<div key={i} className="flex items-center gap-4 p-4 animate-pulse">
|
|
<div className="h-6 bg-slate-700 rounded w-24"></div>
|
|
<div className="h-4 bg-slate-600 rounded flex-1"></div>
|
|
<div className="h-4 bg-slate-700 rounded w-16"></div>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</CardContent>
|
|
</Card>
|
|
)}
|
|
|
|
{/* Signature Categories */}
|
|
{system && !signaturesLoading && (
|
|
<SignatureCategories
|
|
categories={categories}
|
|
onToggleCategory={toggleCategoryVisibility}
|
|
onDelete={onDelete}
|
|
onUpdate={onUpdate}
|
|
/>
|
|
)}
|
|
</div>
|
|
);
|
|
};
|