From 555523df38daea12f309a5b9247332a4831d9ccb Mon Sep 17 00:00:00 2001 From: webdevcody Date: Sat, 10 Jan 2026 13:39:45 -0500 Subject: [PATCH] refactor: remove kanbanCardDetailLevel from settings and UI components - Eliminated kanbanCardDetailLevel from the SettingsService, app state, and various UI components including BoardView and BoardControls. - Updated related hooks and API client to reflect the removal of kanbanCardDetailLevel. - Cleaned up imports and props associated with kanbanCardDetailLevel across the codebase for improved clarity and maintainability. --- apps/server/src/services/settings-service.ts | 2 - apps/server/src/types/settings.ts | 1 - apps/ui/scripts/setup-e2e-fixtures.mjs | 1 - apps/ui/src/components/views/board-view.tsx | 23 ++++-- .../views/board-view/board-controls.tsx | 70 +----------------- .../views/board-view/board-header.tsx | 61 ++++++++++----- .../kanban-card/agent-info-panel.tsx | 74 ++++--------------- .../components/kanban-card/summary-dialog.tsx | 4 +- .../views/board-view/kanban-board.tsx | 9 ++- apps/ui/src/hooks/use-settings-migration.ts | 3 - apps/ui/src/hooks/use-settings-sync.ts | 2 - apps/ui/src/lib/http-api-client.ts | 1 - apps/ui/src/store/app-store.ts | 6 -- docs/settings-api-migration.md | 1 - libs/types/src/index.ts | 1 - libs/types/src/settings.ts | 6 -- 16 files changed, 87 insertions(+), 178 deletions(-) diff --git a/apps/server/src/services/settings-service.ts b/apps/server/src/services/settings-service.ts index 9270b3fb..f1dfd45c 100644 --- a/apps/server/src/services/settings-service.ts +++ b/apps/server/src/services/settings-service.ts @@ -600,8 +600,6 @@ export class SettingsService { theme: (appState.theme as GlobalSettings['theme']) || 'dark', sidebarOpen: appState.sidebarOpen !== undefined ? (appState.sidebarOpen as boolean) : true, chatHistoryOpen: (appState.chatHistoryOpen as boolean) || false, - kanbanCardDetailLevel: - (appState.kanbanCardDetailLevel as GlobalSettings['kanbanCardDetailLevel']) || 'standard', maxConcurrency: (appState.maxConcurrency as number) || 3, defaultSkipTests: appState.defaultSkipTests !== undefined ? (appState.defaultSkipTests as boolean) : true, diff --git a/apps/server/src/types/settings.ts b/apps/server/src/types/settings.ts index e785f8ea..98bce97f 100644 --- a/apps/server/src/types/settings.ts +++ b/apps/server/src/types/settings.ts @@ -7,7 +7,6 @@ export type { ThemeMode, - KanbanCardDetailLevel, ModelAlias, PlanningMode, ThinkingLevel, diff --git a/apps/ui/scripts/setup-e2e-fixtures.mjs b/apps/ui/scripts/setup-e2e-fixtures.mjs index 26488791..356e419b 100644 --- a/apps/ui/scripts/setup-e2e-fixtures.mjs +++ b/apps/ui/scripts/setup-e2e-fixtures.mjs @@ -41,7 +41,6 @@ const E2E_SETTINGS = { theme: 'dark', sidebarOpen: true, chatHistoryOpen: false, - kanbanCardDetailLevel: 'standard', maxConcurrency: 3, defaultSkipTests: true, enableDependencyBlocking: true, diff --git a/apps/ui/src/components/views/board-view.tsx b/apps/ui/src/components/views/board-view.tsx index ebd83fac..810d1a91 100644 --- a/apps/ui/src/components/views/board-view.tsx +++ b/apps/ui/src/components/views/board-view.tsx @@ -7,7 +7,24 @@ import { useSensors, rectIntersection, pointerWithin, + type PointerEvent as DndPointerEvent, } from '@dnd-kit/core'; + +// Custom pointer sensor that ignores drag events from within dialogs +class DialogAwarePointerSensor extends PointerSensor { + static activators = [ + { + eventName: 'onPointerDown' as const, + handler: ({ nativeEvent: event }: { nativeEvent: DndPointerEvent }) => { + // Don't start drag if the event originated from inside a dialog + if ((event.target as Element)?.closest?.('[role="dialog"]')) { + return false; + } + return true; + }, + }, + ]; +} import { useAppStore, Feature } from '@/store/app-store'; import { getElectronAPI } from '@/lib/electron'; import { getHttpApiClient } from '@/lib/http-api-client'; @@ -73,8 +90,6 @@ export function BoardView() { maxConcurrency, setMaxConcurrency, defaultSkipTests, - kanbanCardDetailLevel, - setKanbanCardDetailLevel, boardViewMode, setBoardViewMode, specCreatingForProject, @@ -248,7 +263,7 @@ export function BoardView() { }, []); const sensors = useSensors( - useSensor(PointerSensor, { + useSensor(DialogAwarePointerSensor, { activationConstraint: { distance: 8, }, @@ -1209,8 +1224,6 @@ export function BoardView() { onShowBoardBackground={() => setShowBoardBackgroundModal(true)} onShowCompletedModal={() => setShowCompletedModal(true)} completedCount={completedFeatures.length} - kanbanCardDetailLevel={kanbanCardDetailLevel} - onDetailLevelChange={setKanbanCardDetailLevel} boardViewMode={boardViewMode} onBoardViewModeChange={setBoardViewMode} /> diff --git a/apps/ui/src/components/views/board-view/board-controls.tsx b/apps/ui/src/components/views/board-view/board-controls.tsx index 14733637..2d398c18 100644 --- a/apps/ui/src/components/views/board-view/board-controls.tsx +++ b/apps/ui/src/components/views/board-view/board-controls.tsx @@ -1,6 +1,6 @@ import { Button } from '@/components/ui/button'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip'; -import { ImageIcon, Archive, Minimize2, Square, Maximize2, Columns3, Network } from 'lucide-react'; +import { ImageIcon, Archive, Columns3, Network } from 'lucide-react'; import { cn } from '@/lib/utils'; import { BoardViewMode } from '@/store/app-store'; @@ -9,8 +9,6 @@ interface BoardControlsProps { onShowBoardBackground: () => void; onShowCompletedModal: () => void; completedCount: number; - kanbanCardDetailLevel: 'minimal' | 'standard' | 'detailed'; - onDetailLevelChange: (level: 'minimal' | 'standard' | 'detailed') => void; boardViewMode: BoardViewMode; onBoardViewModeChange: (mode: BoardViewMode) => void; } @@ -20,8 +18,6 @@ export function BoardControls({ onShowBoardBackground, onShowCompletedModal, completedCount, - kanbanCardDetailLevel, - onDetailLevelChange, boardViewMode, onBoardViewModeChange, }: BoardControlsProps) { @@ -115,70 +111,6 @@ export function BoardControls({

Completed Features ({completedCount})

- - {/* Kanban Card Detail Level Toggle */} -
- - - - - -

Minimal - Title & category only

-
-
- - - - - -

Standard - Steps & progress

-
-
- - - - - -

Detailed - Model, tools & tasks

-
-
-
); diff --git a/apps/ui/src/components/views/board-view/board-header.tsx b/apps/ui/src/components/views/board-view/board-header.tsx index 36b19acc..4611c843 100644 --- a/apps/ui/src/components/views/board-view/board-header.tsx +++ b/apps/ui/src/components/views/board-view/board-header.tsx @@ -3,6 +3,7 @@ import { Button } from '@/components/ui/button'; import { Slider } from '@/components/ui/slider'; import { Switch } from '@/components/ui/switch'; import { Label } from '@/components/ui/label'; +import { Popover, PopoverContent, PopoverTrigger } from '@/components/ui/popover'; import { Bot, Wand2, Settings2, GitBranch } from 'lucide-react'; import { UsagePopover } from '@/components/usage-popover'; import { useAppStore } from '@/store/app-store'; @@ -107,27 +108,47 @@ export function BoardHeader({ )} - {/* Concurrency Slider - only show after mount to prevent hydration issues */} + {/* Concurrency Control - only show after mount to prevent hydration issues */} {isMounted && ( -
- - Agents - onConcurrencyChange(value[0])} - min={1} - max={10} - step={1} - className="w-20" - data-testid="concurrency-slider" - /> - - {runningAgentsCount} / {maxConcurrency} - -
+ + + + + +
+
+

Max Concurrent Agents

+

+ Controls how many AI agents can run simultaneously. Higher values process more + features in parallel but use more API resources. +

+
+
+ onConcurrencyChange(value[0])} + min={1} + max={10} + step={1} + className="flex-1" + data-testid="concurrency-slider" + /> + + {maxConcurrency} + +
+
+
+
)} {/* Auto Mode Toggle - only show after mount to prevent hydration issues */} diff --git a/apps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsx b/apps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsx index 5439b675..b73a8d04 100644 --- a/apps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsx +++ b/apps/ui/src/components/views/board-view/components/kanban-card/agent-info-panel.tsx @@ -1,6 +1,6 @@ // @ts-nocheck import { useEffect, useState } from 'react'; -import { Feature, ThinkingLevel, useAppStore } from '@/store/app-store'; +import { Feature, ThinkingLevel } from '@/store/app-store'; import type { ReasoningEffort } from '@automaker/types'; import { getProviderFromModel } from '@/lib/utils'; import { @@ -68,12 +68,9 @@ export function AgentInfoPanel({ summary, isCurrentAutoTask, }: AgentInfoPanelProps) { - const { kanbanCardDetailLevel } = useAppStore(); const [agentInfo, setAgentInfo] = useState(null); const [isSummaryDialogOpen, setIsSummaryDialogOpen] = useState(false); - const showAgentInfo = kanbanCardDetailLevel === 'detailed'; - useEffect(() => { const loadContext = async () => { if (contextContent) { @@ -123,7 +120,7 @@ export function AgentInfoPanel({ } }, [feature.id, feature.status, contextContent, isCurrentAutoTask]); // Model/Preset Info for Backlog Cards - if (showAgentInfo && feature.status === 'backlog') { + if (feature.status === 'backlog') { const provider = getProviderFromModel(feature.model); const isCodex = provider === 'codex'; const isClaude = provider === 'claude'; @@ -160,7 +157,7 @@ export function AgentInfoPanel({ } // Agent Info Panel for non-backlog cards - if (showAgentInfo && feature.status !== 'backlog' && agentInfo) { + if (feature.status !== 'backlog' && agentInfo) { return ( <>
@@ -255,7 +252,11 @@ export function AgentInfoPanel({
-

+

e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} + > {feature.summary || summary || agentInfo.summary}

@@ -292,58 +293,15 @@ export function AgentInfoPanel({ ); } - // Show just the todo list for non-backlog features when showAgentInfo is false - // This ensures users always see what the agent is working on - if (!showAgentInfo && feature.status !== 'backlog' && agentInfo && agentInfo.todos.length > 0) { - return ( -
-
- - - {agentInfo.todos.filter((t) => t.status === 'completed').length}/ - {agentInfo.todos.length} tasks - -
-
- {agentInfo.todos.map((todo, idx) => ( -
- {todo.status === 'completed' ? ( - - ) : todo.status === 'in_progress' ? ( - - ) : ( - - )} - - {todo.content} - -
- ))} -
-
- ); - } - - // Always render SummaryDialog if showAgentInfo is true (even if no agentInfo yet) + // Always render SummaryDialog (even if no agentInfo yet) // This ensures the dialog can be opened from the expand button return ( - <> - {showAgentInfo && ( - - )} - + ); } diff --git a/apps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsx b/apps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsx index b469da8f..db9f579d 100644 --- a/apps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsx +++ b/apps/ui/src/components/views/board-view/components/kanban-card/summary-dialog.tsx @@ -31,8 +31,10 @@ export function SummaryDialog({ return ( e.stopPropagation()} + onMouseDown={(e) => e.stopPropagation()} > diff --git a/apps/ui/src/components/views/board-view/kanban-board.tsx b/apps/ui/src/components/views/board-view/kanban-board.tsx index 9a3a5c26..1fd39843 100644 --- a/apps/ui/src/components/views/board-view/kanban-board.tsx +++ b/apps/ui/src/components/views/board-view/kanban-board.tsx @@ -3,7 +3,7 @@ import { DndContext, DragOverlay } from '@dnd-kit/core'; import { SortableContext, verticalListSortingStrategy } from '@dnd-kit/sortable'; import { Button } from '@/components/ui/button'; import { KanbanColumn, KanbanCard } from './components'; -import { Feature } from '@/store/app-store'; +import { Feature, useAppStore, formatShortcut } from '@/store/app-store'; import { Archive, Settings2, CheckSquare, GripVertical, Plus } from 'lucide-react'; import { useResponsiveKanban } from '@/hooks/use-responsive-kanban'; import { getColumnsWithPipeline, type ColumnId } from './constants'; @@ -90,6 +90,10 @@ export function KanbanBoard({ // Generate columns including pipeline steps const columns = useMemo(() => getColumnsWithPipeline(pipelineConfig), [pipelineConfig]); + // Get the keyboard shortcut for adding features + const { keyboardShortcuts } = useAppStore(); + const addFeatureShortcut = keyboardShortcuts.addFeature || 'N'; + // 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); @@ -196,6 +200,9 @@ export function KanbanBoard({ > Add Feature + + {formatShortcut(addFeatureShortcut, true)} + ) : undefined } diff --git a/apps/ui/src/hooks/use-settings-migration.ts b/apps/ui/src/hooks/use-settings-migration.ts index 3449abf5..f5d421e0 100644 --- a/apps/ui/src/hooks/use-settings-migration.ts +++ b/apps/ui/src/hooks/use-settings-migration.ts @@ -139,7 +139,6 @@ export function parseLocalStorageSettings(): Partial | null { theme: state.theme as GlobalSettings['theme'], sidebarOpen: state.sidebarOpen as boolean, chatHistoryOpen: state.chatHistoryOpen as boolean, - kanbanCardDetailLevel: state.kanbanCardDetailLevel as GlobalSettings['kanbanCardDetailLevel'], maxConcurrency: state.maxConcurrency as number, defaultSkipTests: state.defaultSkipTests as boolean, enableDependencyBlocking: state.enableDependencyBlocking as boolean, @@ -526,7 +525,6 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void { theme: settings.theme as unknown as import('@/store/app-store').ThemeMode, sidebarOpen: settings.sidebarOpen ?? true, chatHistoryOpen: settings.chatHistoryOpen ?? false, - kanbanCardDetailLevel: settings.kanbanCardDetailLevel ?? 'standard', maxConcurrency: settings.maxConcurrency ?? 3, defaultSkipTests: settings.defaultSkipTests ?? true, enableDependencyBlocking: settings.enableDependencyBlocking ?? true, @@ -582,7 +580,6 @@ function buildSettingsUpdateFromStore(): Record { theme: state.theme, sidebarOpen: state.sidebarOpen, chatHistoryOpen: state.chatHistoryOpen, - kanbanCardDetailLevel: state.kanbanCardDetailLevel, maxConcurrency: state.maxConcurrency, defaultSkipTests: state.defaultSkipTests, enableDependencyBlocking: state.enableDependencyBlocking, diff --git a/apps/ui/src/hooks/use-settings-sync.ts b/apps/ui/src/hooks/use-settings-sync.ts index 8f17a283..4788bfb1 100644 --- a/apps/ui/src/hooks/use-settings-sync.ts +++ b/apps/ui/src/hooks/use-settings-sync.ts @@ -31,7 +31,6 @@ const SETTINGS_FIELDS_TO_SYNC = [ 'theme', 'sidebarOpen', 'chatHistoryOpen', - 'kanbanCardDetailLevel', 'maxConcurrency', 'defaultSkipTests', 'enableDependencyBlocking', @@ -379,7 +378,6 @@ export async function refreshSettingsFromServer(): Promise { theme: serverSettings.theme as unknown as ThemeMode, sidebarOpen: serverSettings.sidebarOpen, chatHistoryOpen: serverSettings.chatHistoryOpen, - kanbanCardDetailLevel: serverSettings.kanbanCardDetailLevel, maxConcurrency: serverSettings.maxConcurrency, defaultSkipTests: serverSettings.defaultSkipTests, enableDependencyBlocking: serverSettings.enableDependencyBlocking, diff --git a/apps/ui/src/lib/http-api-client.ts b/apps/ui/src/lib/http-api-client.ts index c46005bd..85392000 100644 --- a/apps/ui/src/lib/http-api-client.ts +++ b/apps/ui/src/lib/http-api-client.ts @@ -1858,7 +1858,6 @@ export class HttpApiClient implements ElectronAPI { theme: string; sidebarOpen: boolean; chatHistoryOpen: boolean; - kanbanCardDetailLevel: string; maxConcurrency: number; defaultSkipTests: boolean; enableDependencyBlocking: boolean; diff --git a/apps/ui/src/store/app-store.ts b/apps/ui/src/store/app-store.ts index 91dea9bd..fa1daf4c 100644 --- a/apps/ui/src/store/app-store.ts +++ b/apps/ui/src/store/app-store.ts @@ -114,8 +114,6 @@ function saveThemeToStorage(theme: ThemeMode): void { setItem(THEME_STORAGE_KEY, theme); } -export type KanbanCardDetailLevel = 'minimal' | 'standard' | 'detailed'; - export type BoardViewMode = 'kanban' | 'graph'; export interface ApiKeys { @@ -508,7 +506,6 @@ export interface AppState { maxConcurrency: number; // Maximum number of concurrent agent tasks // Kanban Card Display Settings - kanbanCardDetailLevel: KanbanCardDetailLevel; // Level of detail shown on kanban cards boardViewMode: BoardViewMode; // Whether to show kanban or dependency graph view // Feature Default Settings @@ -874,7 +871,6 @@ export interface AppActions { setMaxConcurrency: (max: number) => void; // Kanban Card Settings actions - setKanbanCardDetailLevel: (level: KanbanCardDetailLevel) => void; setBoardViewMode: (mode: BoardViewMode) => void; // Feature Default Settings actions @@ -1127,7 +1123,6 @@ const initialState: AppState = { autoModeByProject: {}, autoModeActivityLog: [], maxConcurrency: 3, // Default to 3 concurrent agents - kanbanCardDetailLevel: 'standard', // Default to standard detail level boardViewMode: 'kanban', // Default to kanban view defaultSkipTests: true, // Default to manual verification (tests disabled) enableDependencyBlocking: true, // Default to enabled (show dependency blocking UI) @@ -1731,7 +1726,6 @@ export const useAppStore = create()((set, get) => ({ setMaxConcurrency: (max) => set({ maxConcurrency: max }), // Kanban Card Settings actions - setKanbanCardDetailLevel: (level) => set({ kanbanCardDetailLevel: level }), setBoardViewMode: (mode) => set({ boardViewMode: mode }), // Feature Default Settings actions diff --git a/docs/settings-api-migration.md b/docs/settings-api-migration.md index 85bc6979..5a20fc21 100644 --- a/docs/settings-api-migration.md +++ b/docs/settings-api-migration.md @@ -96,7 +96,6 @@ const SETTINGS_FIELDS_TO_SYNC = [ 'theme', 'sidebarOpen', 'chatHistoryOpen', - 'kanbanCardDetailLevel', 'maxConcurrency', 'defaultSkipTests', 'enableDependencyBlocking', diff --git a/libs/types/src/index.ts b/libs/types/src/index.ts index d2e49cbf..7b402274 100644 --- a/libs/types/src/index.ts +++ b/libs/types/src/index.ts @@ -109,7 +109,6 @@ export { DEFAULT_PROMPT_CUSTOMIZATION } from './prompts.js'; // Settings types and constants export type { ThemeMode, - KanbanCardDetailLevel, PlanningMode, ThinkingLevel, ModelProvider, diff --git a/libs/types/src/settings.ts b/libs/types/src/settings.ts index 3ce87a76..07b4290d 100644 --- a/libs/types/src/settings.ts +++ b/libs/types/src/settings.ts @@ -65,9 +65,6 @@ export type ThemeMode = | 'nordlight' | 'blossom'; -/** KanbanCardDetailLevel - Controls how much information is displayed on kanban cards */ -export type KanbanCardDetailLevel = 'minimal' | 'standard' | 'detailed'; - /** PlanningMode - Planning levels for feature generation workflows */ export type PlanningMode = 'skip' | 'lite' | 'spec' | 'full'; @@ -362,8 +359,6 @@ export interface GlobalSettings { sidebarOpen: boolean; /** Whether chat history panel is open */ chatHistoryOpen: boolean; - /** How much detail to show on kanban cards */ - kanbanCardDetailLevel: KanbanCardDetailLevel; // Feature Generation Defaults /** Max features to generate concurrently */ @@ -682,7 +677,6 @@ export const DEFAULT_GLOBAL_SETTINGS: GlobalSettings = { theme: 'dark', sidebarOpen: true, chatHistoryOpen: false, - kanbanCardDetailLevel: 'standard', maxConcurrency: 3, defaultSkipTests: true, enableDependencyBlocking: true,