import { memo, useMemo, useState } from 'react'; import { Button } from '@renderer/components/ui/button'; import { Tooltip, TooltipContent, TooltipTrigger } from '@renderer/components/ui/tooltip'; import { cn } from '@renderer/lib/utils'; import { Brain, Expand, MessageSquare, Wrench } from 'lucide-react'; import { ClaudeLogsDialog } from './ClaudeLogsDialog'; import { ClaudeLogsPanel } from './ClaudeLogsPanel'; import { CollapsibleTeamSection } from './CollapsibleTeamSection'; import { useClaudeLogsController } from './useClaudeLogsController'; import type { LastLogPreview } from './useClaudeLogsController'; // ============================================================================= // Constants // ============================================================================= const PREVIEW_ICONS = { output: , thinking: , tool: , } as const; const LogsHeaderSkeletonPill = ({ className, }: Readonly<{ className?: string }>): React.JSX.Element => ( ); // ============================================================================= // Sub-components // ============================================================================= interface ClaudeLogsSectionProps { teamName: string; position?: 'sidebar' | 'inline'; sidebarViewerMaxHeight?: number; onOpenChange?: (isOpen: boolean) => void; } /** * Compact inline preview of the most recent log item, shown in the section header. */ const LogPreviewInline = ({ preview }: { preview: LastLogPreview }): React.JSX.Element => { const summaryText = preview.summary.length > 60 ? preview.summary.slice(0, 60) + '...' : preview.summary; return ( {PREVIEW_ICONS[preview.type]} {preview.label} {summaryText && ( <> - {summaryText} > )} ); }; // ============================================================================= // Main component // ============================================================================= export const ClaudeLogsSection = memo(function ClaudeLogsSection({ teamName, position = 'inline', sidebarViewerMaxHeight, onOpenChange, }: ClaudeLogsSectionProps): React.JSX.Element { const ctrl = useClaudeLogsController(teamName); const [dialogOpen, setDialogOpen] = useState(false); const isSidebar = position === 'sidebar'; const showHeaderSkeleton = ctrl.loading && ctrl.data.lines.length === 0 && !ctrl.error; const sectionHeaderExtra = useMemo( () => ( {ctrl.online ? ( ) : null} {ctrl.lastLogPreview ? : null} {showHeaderSkeleton ? ( ) : null} ), [ctrl.online, ctrl.lastLogPreview, isSidebar, showHeaderSkeleton] ); const afterBadge = showHeaderSkeleton ? ( <> > ) : ctrl.data.total > 0 ? ( { e.stopPropagation(); setDialogOpen(true); }} aria-label="Open fullscreen logs" > Fullscreen ) : undefined; return ( <> {/* When dialog is open, hide the compact log viewer to avoid two competing scroll containers */} {dialogOpen ? ( Viewing in fullscreen mode ) : ( )} > ); });