import React from "react"; import { Button } from "@/components/ui/button.tsx"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select.tsx"; import { Card, CardContent } from "@/components/ui/card.tsx"; import { Switch } from "@/components/ui/switch.tsx"; import { Label } from "@/components/ui/label.tsx"; import { Download, RefreshCw, Filter } from "lucide-react"; import { toast } from "sonner"; import type { DockerLogOptions } from "@/types"; import { getContainerLogs, downloadContainerLogs } from "@/ui/main-axios.ts"; import { SimpleLoader } from "@/ui/desktop/navigation/animations/SimpleLoader.tsx"; interface LogViewerProps { sessionId: string; containerId: string; containerName: string; } export function LogViewer({ sessionId, containerId, containerName, }: LogViewerProps): React.ReactElement { const [logs, setLogs] = React.useState(""); const [isLoading, setIsLoading] = React.useState(false); const [isDownloading, setIsDownloading] = React.useState(false); const [tailLines, setTailLines] = React.useState("100"); const [showTimestamps, setShowTimestamps] = React.useState(false); const [autoRefresh, setAutoRefresh] = React.useState(false); const [searchFilter, setSearchFilter] = React.useState(""); const logsEndRef = React.useRef(null); const fetchLogs = React.useCallback(async () => { setIsLoading(true); try { const options: DockerLogOptions = { tail: tailLines === "all" ? undefined : parseInt(tailLines, 10), timestamps: showTimestamps, }; const data = await getContainerLogs(sessionId, containerId, options); setLogs(data.logs); } catch (error) { toast.error( `Failed to fetch logs: ${error instanceof Error ? error.message : "Unknown error"}`, ); } finally { setIsLoading(false); } }, [sessionId, containerId, tailLines, showTimestamps]); React.useEffect(() => { fetchLogs(); }, [fetchLogs]); React.useEffect(() => { if (!autoRefresh) return; const interval = setInterval(() => { fetchLogs(); }, 3000); return () => clearInterval(interval); }, [autoRefresh, fetchLogs]); React.useEffect(() => { if (autoRefresh && logsEndRef.current) { logsEndRef.current.scrollIntoView({ behavior: "smooth" }); } }, [logs, autoRefresh]); const handleDownload = async () => { setIsDownloading(true); try { const options: DockerLogOptions = { timestamps: showTimestamps, }; const blob = await downloadContainerLogs(sessionId, containerId, options); const url = window.URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = `${containerName.replace(/[^a-z0-9]/gi, "_")}_logs.txt`; document.body.appendChild(a); a.click(); window.URL.revokeObjectURL(url); document.body.removeChild(a); toast.success("Logs downloaded successfully"); } catch (error) { toast.error( `Failed to download logs: ${error instanceof Error ? error.message : "Unknown error"}`, ); } finally { setIsDownloading(false); } }; const filteredLogs = React.useMemo(() => { if (!searchFilter.trim()) return logs; return logs .split("\n") .filter((line) => line.toLowerCase().includes(searchFilter.toLowerCase())) .join("\n"); }, [logs, searchFilter]); return (
{showTimestamps ? "Enabled" : "Disabled"}
{autoRefresh ? "On" : "Off"}
setSearchFilter(e.target.value)} className="w-full pl-10 pr-4 py-2 border border-input rounded-md text-sm text-foreground focus:outline-none focus:ring-2 focus:ring-primary" />
{isLoading && !logs ? (
) : (
                {filteredLogs || (
                  
                    No logs available
                  
                )}
                
)}
); }