diff --git a/apps/web/components/connection-status.tsx b/apps/web/components/connection-status.tsx deleted file mode 100644 index 04e5f82af6..0000000000 --- a/apps/web/components/connection-status.tsx +++ /dev/null @@ -1,46 +0,0 @@ -'use client'; - -import { Badge } from '@kandev/ui/badge'; -import { IconCircleFilled } from '@tabler/icons-react'; -import { useAppStore } from '@/components/state-provider'; - -export function ConnectionStatus() { - const status = useAppStore((store) => store.connection.status); - const error = useAppStore((store) => store.connection.error); - - const getStatusConfig = () => { - switch (status) { - case 'connected': - return { color: 'text-emerald-500', text: 'Connected', variant: 'default' as const, pulse: false }; - case 'connecting': - return { color: 'text-amber-500', text: 'Connecting', variant: 'secondary' as const, pulse: true }; - case 'reconnecting': - return { color: 'text-orange-500', text: 'Reconnecting', variant: 'secondary' as const, pulse: true }; - case 'error': - return { color: 'text-red-500', text: 'Error', variant: 'destructive' as const, pulse: false }; - case 'disconnected': - default: - return { color: 'text-yellow-500', text: 'Disconnected', variant: 'secondary' as const, pulse: true }; - } - }; - - const config = getStatusConfig(); - - const getTooltipContent = () => { - const errorLine = error ? `\nError: ${error}` : ''; - return `Status: ${config.text}${errorLine}`; - }; - - return ( - - - {config.text} - - ); -} diff --git a/apps/web/components/kanban-board-grid.tsx b/apps/web/components/kanban-board-grid.tsx index aeabf11c70..dc30d297bb 100644 --- a/apps/web/components/kanban-board-grid.tsx +++ b/apps/web/components/kanban-board-grid.tsx @@ -70,7 +70,7 @@ export function KanbanBoardGrid({ ) : (
{columns.map((column) => ( diff --git a/apps/web/components/kanban-card.tsx b/apps/web/components/kanban-card.tsx index 36a5b3046c..6faf9b067e 100644 --- a/apps/web/components/kanban-card.tsx +++ b/apps/web/components/kanban-card.tsx @@ -64,7 +64,7 @@ function KanbanCardBody({ {actions}
{task.description && ( -

+

{task.description}

)} diff --git a/apps/web/components/kanban-column.tsx b/apps/web/components/kanban-column.tsx index ecf8e71a69..0760f87f97 100644 --- a/apps/web/components/kanban-column.tsx +++ b/apps/web/components/kanban-column.tsx @@ -49,15 +49,15 @@ export function KanbanColumn({ column, tasks, onPreviewTask, onOpenTask, onEditT
{/* Column Header */}
-
-

{column.title}

+
+

{column.title}

{tasks.length} @@ -65,24 +65,21 @@ export function KanbanColumn({ column, tasks, onPreviewTask, onOpenTask, onEditT
{/* Tasks */} -
- {tasks.length === 0 ? ( -

No tasks yet

- ) : ( - tasks.map((task) => ( - - )) - )} +
+ {tasks.map((task) => ( + + )) + }
); diff --git a/apps/web/components/kanban-display-dropdown.tsx b/apps/web/components/kanban-display-dropdown.tsx index 8aec783ff2..802a8c253a 100644 --- a/apps/web/components/kanban-display-dropdown.tsx +++ b/apps/web/components/kanban-display-dropdown.tsx @@ -20,6 +20,7 @@ import { IconAdjustmentsHorizontal } from '@tabler/icons-react'; import { useKanbanDisplaySettings } from '@/hooks/use-kanban-display-settings'; import type { Workspace, Repository } from '@/lib/types/http'; import type { BoardState } from '@/lib/state/slices'; +import { Badge } from '@kandev/ui/badge'; export function KanbanDisplayDropdown() { const { @@ -126,7 +127,10 @@ export function KanbanDisplayDropdown() { onTogglePreviewOnClick?.(!!checked); }} /> - Open preview on click + + Open preview on click {" "} + beta +

When enabled, clicking a task opens the preview panel. When disabled, clicking navigates directly to the session. diff --git a/apps/web/components/kanban/kanban-header.tsx b/apps/web/components/kanban/kanban-header.tsx index c6e5782d9e..c72debc43e 100644 --- a/apps/web/components/kanban/kanban-header.tsx +++ b/apps/web/components/kanban/kanban-header.tsx @@ -6,7 +6,6 @@ import { Button } from '@kandev/ui/button'; import { ToggleGroup, ToggleGroupItem } from '@kandev/ui/toggle-group'; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@kandev/ui/tooltip'; import { IconPlus, IconSettings, IconList, IconLayoutKanban } from '@tabler/icons-react'; -import { ConnectionStatus } from '../connection-status'; import { KanbanDisplayDropdown } from '../kanban-display-dropdown'; import { TaskSearchInput } from './task-search-input'; import { linkToTasks } from '@/lib/links'; @@ -35,9 +34,8 @@ export function KanbanHeader({ onCreateTask, workspaceId, currentPage = 'kanban'

- KanDev.ai + KanDev -
{onSearchChange && (
diff --git a/apps/web/components/task-create-dialog.tsx b/apps/web/components/task-create-dialog.tsx index b66553dc87..e6d59d52af 100644 --- a/apps/web/components/task-create-dialog.tsx +++ b/apps/web/components/task-create-dialog.tsx @@ -398,7 +398,17 @@ export function TaskCreateDialog({ useEffect(() => { if (!open || !workspaceId) return; - if (!repositoryId && !selectedLocalRepo && repositories.length === 1) { + if (repositoryId || selectedLocalRepo) return; + + // Priority 1: Last used repository + const lastUsedRepoId = getLocalStorage(STORAGE_KEYS.LAST_REPOSITORY_ID, null); + if (lastUsedRepoId && repositories.some((repo: Repository) => repo.id === lastUsedRepoId)) { + setRepositoryId(lastUsedRepoId); + return; + } + + // Priority 2: Auto-select if only one repository + if (repositories.length === 1) { setRepositoryId(repositories[0].id); } }, [open, repositories, repositoryId, selectedLocalRepo, workspaceId]); @@ -436,11 +446,22 @@ export function TaskCreateDialog({ useEffect(() => { if (!repositoryId) return; - if (!branch) { - const preferredBranch = selectPreferredBranch(branches); - if (preferredBranch) { - setBranch(preferredBranch); - } + if (branch) return; + + // Priority 1: Last used branch + const lastUsedBranch = getLocalStorage(STORAGE_KEYS.LAST_BRANCH, null); + if (lastUsedBranch && branches.some((b: Branch) => { + const displayName = b.type === 'remote' && b.remote ? `${b.remote}/${b.name}` : b.name; + return displayName === lastUsedBranch; + })) { + setBranch(lastUsedBranch); + return; + } + + // Priority 2: Preferred branch (main/master) + const preferredBranch = selectPreferredBranch(branches); + if (preferredBranch) { + setBranch(preferredBranch); } }, [branch, branches, repositoryId]); @@ -458,6 +479,7 @@ export function TaskCreateDialog({ const workspaceRepo = repositories.find((repo: Repository) => repo.id === value); if (workspaceRepo) { setRepositoryId(value); + setLocalStorage(STORAGE_KEYS.LAST_REPOSITORY_ID, value); setDiscoveredRepoPath(''); setSelectedLocalRepo(null); setLocalBranches([]); @@ -473,6 +495,12 @@ export function TaskCreateDialog({ setLocalStorage(STORAGE_KEYS.LAST_AGENT_PROFILE_ID, value); }, []); + // Memoized callback for BranchSelector to save selection to localStorage + const handleBranchChange = useCallback((value: string) => { + setBranch(value); + setLocalStorage(STORAGE_KEYS.LAST_BRANCH, value); + }, []); + const hasRepositorySelection = Boolean(repositoryId || selectedLocalRepo); const branchOptionsRaw = repositoryId ? branches @@ -592,6 +620,18 @@ export function TaskCreateDialog({ useEffect(() => { if (repositoryId || localBranches.length === 0) return; if (branch) return; + + // Priority 1: Last used branch + const lastUsedBranch = getLocalStorage(STORAGE_KEYS.LAST_BRANCH, null); + if (lastUsedBranch && localBranches.some((b: Branch) => { + const displayName = b.type === 'remote' && b.remote ? `${b.remote}/${b.name}` : b.name; + return displayName === lastUsedBranch; + })) { + setBranch(lastUsedBranch); + return; + } + + // Priority 2: Preferred branch (main/master) const preferredBranch = selectPreferredBranch(localBranches); if (preferredBranch) { setBranch(preferredBranch); @@ -931,34 +971,34 @@ export function TaskCreateDialog({ disabled={!workspaceId || repositoriesLoading || discoverReposLoading || isEditMode} />
-
- 0 - ? 'Select branch' - : 'No branches found' - } - searchPlaceholder="Search branches..." - emptyMessage="No branch found." - disabled={ - isEditMode || - !hasRepositorySelection || - (repositoryId && branchesLoading) || - (!repositoryId && (localBranchesLoading || branchOptions.length === 0)) - } - /> -
+
+ 0 + ? 'Select branch' + : 'No branches found' + } + searchPlaceholder="Search branches..." + emptyMessage="No branch found." + disabled={ + isEditMode || + !hasRepositorySelection || + (repositoryId && branchesLoading) || + (!repositoryId && (localBranchesLoading || branchOptions.length === 0)) + } + /> +
{startAgent && (
{agentProfiles.length === 0 && !agentProfilesLoading ? ( @@ -969,19 +1009,19 @@ export function TaskCreateDialog({
) : ( - + )}
)} diff --git a/apps/web/lib/settings/constants.ts b/apps/web/lib/settings/constants.ts index 2aebc158b8..3a74075438 100644 --- a/apps/web/lib/settings/constants.ts +++ b/apps/web/lib/settings/constants.ts @@ -2,6 +2,8 @@ export const STORAGE_KEYS = { BACKEND_URL: 'kandev.settings.backendUrl', ONBOARDING_COMPLETED: 'kandev.onboarding.completed', LAST_AGENT_PROFILE_ID: 'kandev.dialog.lastAgentProfileId', + LAST_REPOSITORY_ID: 'kandev.dialog.lastRepositoryId', + LAST_BRANCH: 'kandev.dialog.lastBranch', } as const; export const DEFAULT_BACKEND_URL = 'http://localhost:8080';