// ======================================== // IssuePanel Component // ======================================== // Issue list panel for the terminal dashboard middle column. // Consumes existing useIssues() React Query hook for data fetching. // Integrates with issueQueueIntegrationStore for selection state // and association chain highlighting. import { useMemo, useCallback } from 'react'; import { useIntl } from 'react-intl'; import { AlertCircle, ArrowRightToLine, Loader2, AlertTriangle, CircleDot, } from 'lucide-react'; import { Badge } from '@/components/ui/Badge'; import { cn } from '@/lib/utils'; import { useIssues } from '@/hooks/useIssues'; import { useIssueQueueIntegrationStore, selectSelectedIssueId, selectAssociationChain, } from '@/stores/issueQueueIntegrationStore'; import type { Issue } from '@/lib/api'; // ========== Priority Badge ========== const PRIORITY_STYLES: Record = { critical: { variant: 'destructive', label: 'Critical' }, high: { variant: 'warning', label: 'High' }, medium: { variant: 'info', label: 'Medium' }, low: { variant: 'secondary', label: 'Low' }, }; function PriorityBadge({ priority }: { priority: Issue['priority'] }) { const style = PRIORITY_STYLES[priority] ?? PRIORITY_STYLES.medium; return ( {style.label} ); } // ========== Status Indicator ========== function StatusDot({ status }: { status: Issue['status'] }) { const colorMap: Record = { open: 'text-info', in_progress: 'text-warning', resolved: 'text-success', closed: 'text-muted-foreground', completed: 'text-success', }; return ; } // ========== Issue Item ========== function IssueItem({ issue, isSelected, isHighlighted, onSelect, onSendToQueue, }: { issue: Issue; isSelected: boolean; isHighlighted: boolean; onSelect: () => void; onSendToQueue: () => void; }) { const { formatMessage } = useIntl(); const handleSendToQueue = useCallback( (e: React.MouseEvent) => { e.stopPropagation(); onSendToQueue(); }, [onSendToQueue] ); return ( {issue.context && (

{issue.context}

)}
{issue.id} {issue.labels && issue.labels.length > 0 && ( <> | {issue.labels.slice(0, 2).join(', ')} )}
); } // ========== Empty State ========== function IssueEmptyState() { const { formatMessage } = useIntl(); return (

{formatMessage({ id: 'terminalDashboard.issuePanel.noIssues' })}

{formatMessage({ id: 'terminalDashboard.issuePanel.noIssuesDesc' })}

); } // ========== Error State ========== function IssueErrorState({ error }: { error: Error }) { const { formatMessage } = useIntl(); return (

{formatMessage({ id: 'terminalDashboard.issuePanel.error' })}

{error.message}

); } // ========== Main Component ========== export function IssuePanel() { const { formatMessage } = useIntl(); const { issues, isLoading, error, openCount } = useIssues(); const selectedIssueId = useIssueQueueIntegrationStore(selectSelectedIssueId); const associationChain = useIssueQueueIntegrationStore(selectAssociationChain); const setSelectedIssue = useIssueQueueIntegrationStore((s) => s.setSelectedIssue); const buildAssociationChain = useIssueQueueIntegrationStore((s) => s.buildAssociationChain); // Sort: open/in_progress first, then by priority (critical > high > medium > low) const sortedIssues = useMemo(() => { const priorityOrder: Record = { critical: 0, high: 1, medium: 2, low: 3, }; const statusOrder: Record = { in_progress: 0, open: 1, resolved: 2, completed: 3, closed: 4, }; return [...issues].sort((a, b) => { const sa = statusOrder[a.status] ?? 5; const sb = statusOrder[b.status] ?? 5; if (sa !== sb) return sa - sb; const pa = priorityOrder[a.priority] ?? 3; const pb = priorityOrder[b.priority] ?? 3; return pa - pb; }); }, [issues]); const handleSelect = useCallback( (issueId: string) => { if (selectedIssueId === issueId) { setSelectedIssue(null); } else { buildAssociationChain(issueId, 'issue'); } }, [selectedIssueId, setSelectedIssue, buildAssociationChain] ); const handleSendToQueue = useCallback( (issueId: string) => { // Select the issue and build chain - queue creation is handled elsewhere buildAssociationChain(issueId, 'issue'); }, [buildAssociationChain] ); // Loading state if (isLoading) { return (

{formatMessage({ id: 'terminalDashboard.issuePanel.title' })}

); } // Error state if (error) { return (

{formatMessage({ id: 'terminalDashboard.issuePanel.title' })}

); } return (
{/* Header */}

{formatMessage({ id: 'terminalDashboard.issuePanel.title' })}

{openCount > 0 && ( {openCount} )}
{/* Issue List */} {sortedIssues.length === 0 ? ( ) : (
{sortedIssues.map((issue) => ( handleSelect(issue.id)} onSendToQueue={() => handleSendToQueue(issue.id)} /> ))}
)}
); }