import { useMemo } from 'react'; import { DndContext, DragOverlay } from '@dnd-kit/core'; import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { Button } from '@/components/ui/button'; import { HotkeyButton } from '@/components/ui/hotkey-button'; import { KanbanColumn, KanbanCard } from './components'; import { Feature } from '@/store/app-store'; import { FastForward, Lightbulb, Archive, Plus, Settings2 } from 'lucide-react'; import { useKeyboardShortcutsConfig } from '@/hooks/use-keyboard-shortcuts'; import { useResponsiveKanban } from '@/hooks/use-responsive-kanban'; import { getColumnsWithPipeline, type Column, type ColumnId } from './constants'; import type { PipelineConfig } from '@automaker/types'; interface KanbanBoardProps { sensors: any; collisionDetectionStrategy: (args: any) => any; onDragStart: (event: any) => void; onDragEnd: (event: any) => void; activeFeature: Feature | null; getColumnFeatures: (columnId: ColumnId) => Feature[]; backgroundImageStyle: React.CSSProperties; backgroundSettings: { columnOpacity: number; columnBorderEnabled: boolean; hideScrollbar: boolean; cardOpacity: number; cardGlassmorphism: boolean; cardBorderEnabled: boolean; cardBorderOpacity: number; }; onEdit: (feature: Feature) => void; onDelete: (featureId: string) => void; onViewOutput: (feature: Feature) => void; onVerify: (feature: Feature) => void; onResume: (feature: Feature) => void; onForceStop: (feature: Feature) => void; onManualVerify: (feature: Feature) => void; onMoveBackToInProgress: (feature: Feature) => void; onFollowUp: (feature: Feature) => void; onCommit: (feature: Feature) => void; onComplete: (feature: Feature) => void; onImplement: (feature: Feature) => void; onViewPlan: (feature: Feature) => void; onApprovePlan: (feature: Feature) => void; onSpawnTask?: (feature: Feature) => void; featuresWithContext: Set; runningAutoTasks: string[]; shortcuts: ReturnType; onStartNextFeatures: () => void; onShowSuggestions: () => void; suggestionsCount: number; onArchiveAllVerified: () => void; pipelineConfig: PipelineConfig | null; onOpenPipelineSettings?: () => void; } export function KanbanBoard({ sensors, collisionDetectionStrategy, onDragStart, onDragEnd, activeFeature, getColumnFeatures, backgroundImageStyle, backgroundSettings, onEdit, onDelete, onViewOutput, onVerify, onResume, onForceStop, onManualVerify, onMoveBackToInProgress, onFollowUp, onCommit, onComplete, onImplement, onViewPlan, onApprovePlan, onSpawnTask, featuresWithContext, runningAutoTasks, shortcuts, onStartNextFeatures, onShowSuggestions, suggestionsCount, onArchiveAllVerified, pipelineConfig, onOpenPipelineSettings, }: KanbanBoardProps) { // Generate columns including pipeline steps const columns = useMemo(() => getColumnsWithPipeline(pipelineConfig), [pipelineConfig]); // Use responsive column widths based on window size // containerStyle handles centering and ensures columns fit without horizontal scroll in Electron const { columnWidth, containerStyle } = useResponsiveKanban(columns.length); return (
{columns.map((column) => { const columnFeatures = getColumnFeatures(column.id as ColumnId); return ( 0 ? ( ) : column.id === 'backlog' ? (
{columnFeatures.length > 0 && ( Make )}
) : column.id === 'in_progress' ? ( ) : column.isPipelineStep ? ( ) : undefined } > f.id)} strategy={verticalListSortingStrategy} > {columnFeatures.map((feature, index) => { // Calculate shortcut key for in-progress cards (first 10 get 1-9, 0) let shortcutKey: string | undefined; if (column.id === 'in_progress' && index < 10) { shortcutKey = index === 9 ? '0' : String(index + 1); } return ( onEdit(feature)} onDelete={() => onDelete(feature.id)} onViewOutput={() => onViewOutput(feature)} onVerify={() => onVerify(feature)} onResume={() => onResume(feature)} onForceStop={() => onForceStop(feature)} onManualVerify={() => onManualVerify(feature)} onMoveBackToInProgress={() => onMoveBackToInProgress(feature)} onFollowUp={() => onFollowUp(feature)} onComplete={() => onComplete(feature)} onImplement={() => onImplement(feature)} onViewPlan={() => onViewPlan(feature)} onApprovePlan={() => onApprovePlan(feature)} onSpawnTask={() => onSpawnTask?.(feature)} hasContext={featuresWithContext.has(feature.id)} isCurrentAutoTask={runningAutoTasks.includes(feature.id)} shortcutKey={shortcutKey} opacity={backgroundSettings.cardOpacity} glassmorphism={backgroundSettings.cardGlassmorphism} cardBorderEnabled={backgroundSettings.cardBorderEnabled} cardBorderOpacity={backgroundSettings.cardBorderOpacity} /> ); })}
); })}
{activeFeature && (
{}} onDelete={() => {}} onViewOutput={() => {}} onVerify={() => {}} onResume={() => {}} onForceStop={() => {}} onManualVerify={() => {}} onMoveBackToInProgress={() => {}} onFollowUp={() => {}} onImplement={() => {}} onComplete={() => {}} onViewPlan={() => {}} onApprovePlan={() => {}} onSpawnTask={() => {}} hasContext={featuresWithContext.has(activeFeature.id)} isCurrentAutoTask={runningAutoTasks.includes(activeFeature.id)} opacity={backgroundSettings.cardOpacity} glassmorphism={backgroundSettings.cardGlassmorphism} cardBorderEnabled={backgroundSettings.cardBorderEnabled} cardBorderOpacity={backgroundSettings.cardBorderOpacity} />
)}
); }