- fix: infinite message loop in workflow orchestrator - feat: restore realtime LLM streaming from report generator to frontend - refactor: major update to provider services (generic workers, workflow adapters) - refactor: common contracts and message definitions updated - feat: enhanced logging and observability in orchestrator - docs: update project management tasks and status - chore: dependency updates and config adjustments
77 lines
3.6 KiB
TypeScript
77 lines
3.6 KiB
TypeScript
import { useState } from 'react';
|
|
import { Terminal, ChevronUp, ChevronDown } from 'lucide-react';
|
|
import { Card } from "@/components/ui/card";
|
|
import { Button } from "@/components/ui/button";
|
|
import { useAutoScroll } from '@/hooks/useAutoScroll';
|
|
import { cn } from "@/lib/utils";
|
|
|
|
export interface LogEntry {
|
|
log: string;
|
|
timestamp?: number; // Added optional timestamp for potential sorting if needed
|
|
}
|
|
|
|
interface RealtimeLogsProps {
|
|
logs: string[];
|
|
className?: string;
|
|
}
|
|
|
|
export function RealtimeLogs({ logs, className }: RealtimeLogsProps) {
|
|
// Default to expanded if there are logs, or maybe collapsed to be unintrusive?
|
|
// Original code: const [isExpanded, setIsExpanded] = useState(false);
|
|
// Let's keep it collapsed by default as per original code to avoid clutter.
|
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
const logsViewportRef = useAutoScroll(logs.length);
|
|
|
|
const toggleExpand = () => {
|
|
setIsExpanded(!isExpanded);
|
|
};
|
|
|
|
return (
|
|
<Card className={cn("flex flex-col shadow-sm transition-all duration-300 ease-in-out border-l-4 border-l-primary py-0 gap-0 bg-background overflow-hidden", className, isExpanded ? "h-[300px]" : "h-8")}>
|
|
<div
|
|
className="flex items-center justify-between px-2 py-1 cursor-pointer hover:bg-muted/50 transition-colors h-8 shrink-0"
|
|
onClick={toggleExpand}
|
|
>
|
|
<div className="flex items-center gap-2 overflow-hidden flex-1">
|
|
<Terminal className="h-3 w-3 text-muted-foreground shrink-0" />
|
|
<span className="text-[10px] font-medium text-muted-foreground whitespace-nowrap shrink-0 mr-2">Real-time Logs</span>
|
|
|
|
{/* Preview last log when collapsed */}
|
|
{!isExpanded && logs.length > 0 && (
|
|
<div className="flex-1 flex items-center gap-2 overflow-hidden text-[10px] font-mono text-muted-foreground/80">
|
|
<span className="truncate">{logs[logs.length - 1]}</span>
|
|
</div>
|
|
)}
|
|
{!isExpanded && logs.length === 0 && (
|
|
<span className="text-[10px] italic text-muted-foreground/50">Waiting for logs...</span>
|
|
)}
|
|
</div>
|
|
|
|
<Button variant="ghost" size="icon" className="h-4 w-4 text-muted-foreground hover:text-foreground shrink-0 ml-2">
|
|
{isExpanded ? <ChevronUp className="h-3 w-3" /> : <ChevronDown className="h-3 w-3" />}
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Expanded Content */}
|
|
<div
|
|
className={cn(
|
|
"flex-1 bg-muted/10 border-t transition-all duration-300 min-h-0",
|
|
isExpanded ? "opacity-100 visible" : "opacity-0 invisible h-0 overflow-hidden"
|
|
)}
|
|
>
|
|
<div ref={logsViewportRef} className="h-full overflow-y-auto p-3 font-mono text-[10px] leading-relaxed scrollbar-thin scrollbar-thumb-border scrollbar-track-transparent">
|
|
<div className="space-y-1">
|
|
{logs.length === 0 && <span className="text-muted-foreground italic">Waiting for logs...</span>}
|
|
{logs.map((entry, i) => (
|
|
<div key={i} className="break-all flex gap-2">
|
|
<span className="text-foreground/90">{entry}</span>
|
|
</div>
|
|
))}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</Card>
|
|
);
|
|
}
|
|
|