mirror of
https://github.com/BradGroux/veritas-kanban.git
synced 2026-08-28 10:54:59 +00:00
Completed refactors: - RF-02: Fix dependency vulnerabilities (xlsx → exceljs, Hono updates) - RF-05: Add React error boundaries (FeatureErrorBoundary wrapper) - RF-06: Server error handling middleware (AppError classes, asyncHandler) - RF-10: Split shared types.ts into domain modules (6 files) - RF-11: Consolidate frontend API layer (hooks now use api.ts) - RF-13: TaskConfigContext — eliminate prop drilling - RF-14: Split god components (GitSection, TaskDetailPanel, CreateTaskDialog, DiffViewer) - RF-16: Frontend accessibility (ARIA labels, sr-only text) - RF-17: Modularize CLI (899 → commands/ structure) - RF-18: Modularize MCP (843 → tools/ structure) - RF-19: Create shared API client library - RF-21: Server performance (batch loading, memory limits, timeouts, graceful shutdown) - RF-23: Extract shared utilities (path, format, constants) Stats: ~59 files changed, significant code reduction through modularization
64 lines
2 KiB
TypeScript
64 lines
2 KiB
TypeScript
import {
|
|
FileCode,
|
|
FilePlus,
|
|
FileMinus,
|
|
FileEdit,
|
|
MessageSquare,
|
|
} from 'lucide-react';
|
|
import type { FileChange } from '@/lib/api';
|
|
import type { ReviewComment } from '@veritas-kanban/shared';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
const statusIcons: Record<FileChange['status'], React.ReactNode> = {
|
|
added: <FilePlus className="h-4 w-4 text-green-500" />,
|
|
modified: <FileEdit className="h-4 w-4 text-amber-500" />,
|
|
deleted: <FileMinus className="h-4 w-4 text-red-500" />,
|
|
renamed: <FileCode className="h-4 w-4 text-blue-500" />,
|
|
};
|
|
|
|
interface FileTreeProps {
|
|
files: FileChange[];
|
|
selectedFile: string | null;
|
|
onSelectFile: (path: string) => void;
|
|
comments: ReviewComment[];
|
|
}
|
|
|
|
export function FileTree({ files, selectedFile, onSelectFile, comments }: FileTreeProps) {
|
|
const commentsByFile = comments.reduce((acc, c) => {
|
|
acc[c.file] = (acc[c.file] || 0) + 1;
|
|
return acc;
|
|
}, {} as Record<string, number>);
|
|
|
|
return (
|
|
<div className="space-y-1">
|
|
{files.map((file) => (
|
|
<button
|
|
key={file.path}
|
|
onClick={() => onSelectFile(file.path)}
|
|
className={cn(
|
|
'w-full flex items-center gap-2 px-2 py-1.5 text-sm rounded-md text-left',
|
|
'hover:bg-muted transition-colors',
|
|
selectedFile === file.path && 'bg-muted'
|
|
)}
|
|
>
|
|
{statusIcons[file.status]}
|
|
<span className="truncate flex-1 font-mono text-xs">{file.path}</span>
|
|
<span className="flex items-center gap-1 text-xs">
|
|
{commentsByFile[file.path] && (
|
|
<span className="flex items-center gap-0.5 text-amber-500">
|
|
<MessageSquare className="h-3 w-3" />
|
|
{commentsByFile[file.path]}
|
|
</span>
|
|
)}
|
|
{file.additions > 0 && (
|
|
<span className="text-green-500">+{file.additions}</span>
|
|
)}
|
|
{file.deletions > 0 && (
|
|
<span className="text-red-500">-{file.deletions}</span>
|
|
)}
|
|
</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|