/** * ClaudeLogsPanel * * Shared rendering surface for Claude logs — used both in the compact sidebar * section and the fullscreen dialog. Renders the toolbar (search, filter, * pending button), the rich log viewer, and empty/error states. */ import React from 'react'; import { Button } from '@renderer/components/ui/button'; import { cn } from '@renderer/lib/utils'; import { Search, X } from 'lucide-react'; import { ClaudeLogsFilterPopover } from './ClaudeLogsFilterPopover'; import { CliLogsRichView } from './CliLogsRichView'; import type { ClaudeLogsController } from './useClaudeLogsController'; // ============================================================================= // Props // ============================================================================= interface ClaudeLogsPanelProps { ctrl: ClaudeLogsController; /** Maximum height class for the log viewer (e.g. "max-h-[213px]" for compact). */ viewerClassName?: string; /** Extra className for the panel wrapper. */ className?: string; } // ============================================================================= // Component // ============================================================================= export const ClaudeLogsPanel = ({ ctrl, viewerClassName, className, }: ClaudeLogsPanelProps): React.JSX.Element => { const { data, loading, loadingMore, error, pendingNewCount, isAlive, filteredText, showMoreVisible, searchQuery, setSearchQuery, filter, setFilter, filterOpen, setFilterOpen, viewerState, onViewerStateChange, applyPending, loadOlderLogs, containerRefCallback, handleScroll, } = ctrl; return (
{/* Toolbar */}
{data.total > 0 ? ( <> {Math.min(data.total, data.lines.length)} of{' '} {data.total} ) : isAlive ? ( 'No logs yet.' ) : ( 'Team is not running.' )}
{data.total > 0 ? ( <>
setSearchQuery(e.target.value)} className="min-w-0 flex-1 bg-transparent text-xs text-[var(--color-text)] placeholder:text-[var(--color-text-muted)] focus:outline-none" /> {searchQuery && ( )}
) : null} {pendingNewCount > 0 && ( )}
{/* Log viewer */}
{error ?

{error}

: null} {!error && filteredText.trim().length > 0 ? (
) : null } /> ) : null} {!error && data.lines.length === 0 && isAlive ? (

{loading ? 'Loading…' : 'No logs captured.'}

) : null} {!error && data.lines.length > 0 && filteredText.trim().length === 0 ? (

No matching logs.

) : null}
); };