mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-04 09:13:08 +00:00
fixing some bugs
This commit is contained in:
@@ -67,6 +67,8 @@ export function BoardView() {
|
|||||||
setSpecCreatingForProject,
|
setSpecCreatingForProject,
|
||||||
getCurrentWorktree,
|
getCurrentWorktree,
|
||||||
setCurrentWorktree,
|
setCurrentWorktree,
|
||||||
|
getWorktrees,
|
||||||
|
setWorktrees,
|
||||||
} = useAppStore();
|
} = useAppStore();
|
||||||
const shortcuts = useKeyboardShortcutsConfig();
|
const shortcuts = useKeyboardShortcutsConfig();
|
||||||
const {
|
const {
|
||||||
@@ -215,7 +217,7 @@ export function BoardView() {
|
|||||||
// Branch suggestions for the branch autocomplete
|
// Branch suggestions for the branch autocomplete
|
||||||
const [branchSuggestions, setBranchSuggestions] = useState<string[]>([]);
|
const [branchSuggestions, setBranchSuggestions] = useState<string[]>([]);
|
||||||
|
|
||||||
// Fetch branches when project changes
|
// Fetch branches when project changes or worktrees are created/modified
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const fetchBranches = async () => {
|
const fetchBranches = async () => {
|
||||||
if (!currentProject) {
|
if (!currentProject) {
|
||||||
@@ -244,7 +246,7 @@ export function BoardView() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
fetchBranches();
|
fetchBranches();
|
||||||
}, [currentProject]);
|
}, [currentProject, worktreeRefreshKey]);
|
||||||
|
|
||||||
// Custom collision detection that prioritizes columns over cards
|
// Custom collision detection that prioritizes columns over cards
|
||||||
const collisionDetectionStrategy = useCallback(
|
const collisionDetectionStrategy = useCallback(
|
||||||
@@ -339,16 +341,21 @@ export function BoardView() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Use drag and drop hook
|
// Use drag and drop hook
|
||||||
// Get current worktree path and branch for filtering features
|
// Get current worktree info (path and branch) for filtering features
|
||||||
const currentWorktreePath = currentProject ? getCurrentWorktree(currentProject.path) : null;
|
const currentWorktreeInfo = currentProject ? getCurrentWorktree(currentProject.path) : null;
|
||||||
|
const currentWorktreePath = currentWorktreeInfo?.path ?? null;
|
||||||
|
const currentWorktreeBranch = currentWorktreeInfo?.branch ?? null;
|
||||||
const worktreesByProject = useAppStore((s) => s.worktreesByProject);
|
const worktreesByProject = useAppStore((s) => s.worktreesByProject);
|
||||||
const worktrees = useMemo(
|
const worktrees = useMemo(
|
||||||
() => (currentProject ? (worktreesByProject[currentProject.path] ?? EMPTY_WORKTREES) : EMPTY_WORKTREES),
|
() => (currentProject ? (worktreesByProject[currentProject.path] ?? EMPTY_WORKTREES) : EMPTY_WORKTREES),
|
||||||
[currentProject, worktreesByProject]
|
[currentProject, worktreesByProject]
|
||||||
);
|
);
|
||||||
const currentWorktreeBranch = currentWorktreePath
|
|
||||||
? worktrees.find(w => w.path === currentWorktreePath)?.branch || null
|
// Get the branch for the currently selected worktree (for defaulting new features)
|
||||||
: null;
|
// Use the branch from currentWorktreeInfo, or fall back to main worktree's branch
|
||||||
|
const selectedWorktreeBranch = currentWorktreeBranch
|
||||||
|
|| worktrees.find(w => w.isMain)?.branch
|
||||||
|
|| "main";
|
||||||
|
|
||||||
const { activeFeature, handleDragStart, handleDragEnd } = useBoardDragDrop({
|
const { activeFeature, handleDragStart, handleDragEnd } = useBoardDragDrop({
|
||||||
features: hookFeatures,
|
features: hookFeatures,
|
||||||
@@ -533,6 +540,7 @@ export function BoardView() {
|
|||||||
categorySuggestions={categorySuggestions}
|
categorySuggestions={categorySuggestions}
|
||||||
branchSuggestions={branchSuggestions}
|
branchSuggestions={branchSuggestions}
|
||||||
defaultSkipTests={defaultSkipTests}
|
defaultSkipTests={defaultSkipTests}
|
||||||
|
defaultBranch={selectedWorktreeBranch}
|
||||||
isMaximized={isMaximized}
|
isMaximized={isMaximized}
|
||||||
showProfilesOnly={showProfilesOnly}
|
showProfilesOnly={showProfilesOnly}
|
||||||
aiProfiles={aiProfiles}
|
aiProfiles={aiProfiles}
|
||||||
@@ -603,10 +611,24 @@ export function BoardView() {
|
|||||||
open={showCreateWorktreeDialog}
|
open={showCreateWorktreeDialog}
|
||||||
onOpenChange={setShowCreateWorktreeDialog}
|
onOpenChange={setShowCreateWorktreeDialog}
|
||||||
projectPath={currentProject.path}
|
projectPath={currentProject.path}
|
||||||
onCreated={(worktreePath) => {
|
onCreated={(newWorktree) => {
|
||||||
|
// Add the new worktree to the store immediately to avoid race condition
|
||||||
|
// when deriving currentWorktreeBranch for filtering
|
||||||
|
const currentWorktrees = getWorktrees(currentProject.path);
|
||||||
|
const newWorktreeInfo = {
|
||||||
|
path: newWorktree.path,
|
||||||
|
branch: newWorktree.branch,
|
||||||
|
isMain: false,
|
||||||
|
isCurrent: false,
|
||||||
|
hasWorktree: true,
|
||||||
|
};
|
||||||
|
setWorktrees(currentProject.path, [...currentWorktrees, newWorktreeInfo]);
|
||||||
|
|
||||||
|
// Now set the current worktree with both path and branch
|
||||||
|
setCurrentWorktree(currentProject.path, newWorktree.path, newWorktree.branch);
|
||||||
|
|
||||||
|
// Trigger refresh to get full worktree details (hasChanges, etc.)
|
||||||
setWorktreeRefreshKey((k) => k + 1);
|
setWorktreeRefreshKey((k) => k + 1);
|
||||||
// Auto-select the newly created worktree
|
|
||||||
setCurrentWorktree(currentProject.path, worktreePath);
|
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
@@ -198,13 +198,15 @@ export function WorktreeSelector({
|
|||||||
// Initialize selection to main if not set
|
// Initialize selection to main if not set
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (worktrees.length > 0 && currentWorktree === undefined) {
|
if (worktrees.length > 0 && currentWorktree === undefined) {
|
||||||
setCurrentWorktree(projectPath, null); // null = main worktree
|
const mainWorktree = worktrees.find(w => w.isMain);
|
||||||
|
const mainBranch = mainWorktree?.branch || "main";
|
||||||
|
setCurrentWorktree(projectPath, null, mainBranch); // null = main worktree
|
||||||
}
|
}
|
||||||
}, [worktrees, currentWorktree, projectPath, setCurrentWorktree]);
|
}, [worktrees, currentWorktree, projectPath, setCurrentWorktree]);
|
||||||
|
|
||||||
const handleSelectWorktree = async (worktree: WorktreeInfo) => {
|
const handleSelectWorktree = async (worktree: WorktreeInfo) => {
|
||||||
// Simply select the worktree in the UI
|
// Simply select the worktree in the UI with both path and branch
|
||||||
setCurrentWorktree(projectPath, worktree.isMain ? null : worktree.path);
|
setCurrentWorktree(projectPath, worktree.isMain ? null : worktree.path, worktree.branch);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleStartDevServer = async (worktree: WorktreeInfo) => {
|
const handleStartDevServer = async (worktree: WorktreeInfo) => {
|
||||||
@@ -454,19 +456,20 @@ export function WorktreeSelector({
|
|||||||
};
|
};
|
||||||
|
|
||||||
// The "selected" worktree is based on UI state, not git's current branch
|
// The "selected" worktree is based on UI state, not git's current branch
|
||||||
// currentWorktree is null for main, or the worktree path for others
|
// currentWorktree.path is null for main, or the worktree path for others
|
||||||
const selectedWorktree = currentWorktree
|
const currentWorktreePath = currentWorktree?.path ?? null;
|
||||||
? worktrees.find((w) => w.path === currentWorktree)
|
const selectedWorktree = currentWorktreePath
|
||||||
|
? worktrees.find((w) => w.path === currentWorktreePath)
|
||||||
: worktrees.find((w) => w.isMain);
|
: worktrees.find((w) => w.isMain);
|
||||||
|
|
||||||
|
|
||||||
// Render a worktree tab with branch selector (for main) and actions dropdown
|
// Render a worktree tab with branch selector (for main) and actions dropdown
|
||||||
const renderWorktreeTab = (worktree: WorktreeInfo) => {
|
const renderWorktreeTab = (worktree: WorktreeInfo) => {
|
||||||
// Selection is based on UI state, not git's current branch
|
// Selection is based on UI state, not git's current branch
|
||||||
// Default to main selected if currentWorktree is null or undefined
|
// Default to main selected if currentWorktree is null/undefined or path is null
|
||||||
const isSelected = worktree.isMain
|
const isSelected = worktree.isMain
|
||||||
? currentWorktree === null || currentWorktree === undefined
|
? currentWorktree === null || currentWorktree === undefined || currentWorktree.path === null
|
||||||
: worktree.path === currentWorktree;
|
: worktree.path === currentWorktreePath;
|
||||||
|
|
||||||
const isRunning = hasRunningFeatures(worktree);
|
const isRunning = hasRunningFeatures(worktree);
|
||||||
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ interface AddFeatureDialogProps {
|
|||||||
categorySuggestions: string[];
|
categorySuggestions: string[];
|
||||||
branchSuggestions: string[];
|
branchSuggestions: string[];
|
||||||
defaultSkipTests: boolean;
|
defaultSkipTests: boolean;
|
||||||
|
defaultBranch?: string;
|
||||||
isMaximized: boolean;
|
isMaximized: boolean;
|
||||||
showProfilesOnly: boolean;
|
showProfilesOnly: boolean;
|
||||||
aiProfiles: AIProfile[];
|
aiProfiles: AIProfile[];
|
||||||
@@ -81,6 +82,7 @@ export function AddFeatureDialog({
|
|||||||
categorySuggestions,
|
categorySuggestions,
|
||||||
branchSuggestions,
|
branchSuggestions,
|
||||||
defaultSkipTests,
|
defaultSkipTests,
|
||||||
|
defaultBranch = "main",
|
||||||
isMaximized,
|
isMaximized,
|
||||||
showProfilesOnly,
|
showProfilesOnly,
|
||||||
aiProfiles,
|
aiProfiles,
|
||||||
@@ -109,15 +111,16 @@ export function AddFeatureDialog({
|
|||||||
// Get enhancement model from store
|
// Get enhancement model from store
|
||||||
const { enhancementModel } = useAppStore();
|
const { enhancementModel } = useAppStore();
|
||||||
|
|
||||||
// Sync skipTests default when dialog opens
|
// Sync defaults when dialog opens
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (open) {
|
if (open) {
|
||||||
setNewFeature((prev) => ({
|
setNewFeature((prev) => ({
|
||||||
...prev,
|
...prev,
|
||||||
skipTests: defaultSkipTests,
|
skipTests: defaultSkipTests,
|
||||||
|
branchName: defaultBranch,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
}, [open, defaultSkipTests]);
|
}, [open, defaultSkipTests, defaultBranch]);
|
||||||
|
|
||||||
const handleAdd = () => {
|
const handleAdd = () => {
|
||||||
if (!newFeature.description.trim()) {
|
if (!newFeature.description.trim()) {
|
||||||
@@ -155,7 +158,7 @@ export function AddFeatureDialog({
|
|||||||
model: "opus",
|
model: "opus",
|
||||||
priority: 2,
|
priority: 2,
|
||||||
thinkingLevel: "none",
|
thinkingLevel: "none",
|
||||||
branchName: "main",
|
branchName: defaultBranch,
|
||||||
});
|
});
|
||||||
setNewFeaturePreviewMap(new Map());
|
setNewFeaturePreviewMap(new Map());
|
||||||
setShowAdvancedOptions(false);
|
setShowAdvancedOptions(false);
|
||||||
|
|||||||
@@ -16,11 +16,16 @@ import { GitBranch, Loader2 } from "lucide-react";
|
|||||||
import { getElectronAPI } from "@/lib/electron";
|
import { getElectronAPI } from "@/lib/electron";
|
||||||
import { toast } from "sonner";
|
import { toast } from "sonner";
|
||||||
|
|
||||||
|
interface CreatedWorktreeInfo {
|
||||||
|
path: string;
|
||||||
|
branch: string;
|
||||||
|
}
|
||||||
|
|
||||||
interface CreateWorktreeDialogProps {
|
interface CreateWorktreeDialogProps {
|
||||||
open: boolean;
|
open: boolean;
|
||||||
onOpenChange: (open: boolean) => void;
|
onOpenChange: (open: boolean) => void;
|
||||||
projectPath: string;
|
projectPath: string;
|
||||||
onCreated: (worktreePath: string) => void;
|
onCreated: (worktree: CreatedWorktreeInfo) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function CreateWorktreeDialog({
|
export function CreateWorktreeDialog({
|
||||||
@@ -68,7 +73,7 @@ export function CreateWorktreeDialog({
|
|||||||
: "Using existing branch",
|
: "Using existing branch",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
onCreated(result.worktree.path);
|
onCreated({ path: result.worktree.path, branch: result.worktree.branch });
|
||||||
onOpenChange(false);
|
onOpenChange(false);
|
||||||
setBranchName("");
|
setBranchName("");
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -43,7 +43,12 @@ export function useBoardColumnFeatures({
|
|||||||
// Determine the effective worktree path and branch for filtering
|
// Determine the effective worktree path and branch for filtering
|
||||||
// If currentWorktreePath is null, we're on the main worktree
|
// If currentWorktreePath is null, we're on the main worktree
|
||||||
const effectiveWorktreePath = currentWorktreePath || projectPath;
|
const effectiveWorktreePath = currentWorktreePath || projectPath;
|
||||||
const effectiveBranch = currentWorktreeBranch || "main";
|
// Use the branch name from the selected worktree
|
||||||
|
// If we're selecting main (currentWorktreePath is null), currentWorktreeBranch
|
||||||
|
// should contain the main branch's actual name, defaulting to "main"
|
||||||
|
// If we're selecting a non-main worktree but can't find it, currentWorktreeBranch is null
|
||||||
|
// In that case, we can't do branch-based filtering, so we'll handle it specially below
|
||||||
|
const effectiveBranch = currentWorktreeBranch;
|
||||||
|
|
||||||
filteredFeatures.forEach((f) => {
|
filteredFeatures.forEach((f) => {
|
||||||
// If feature has a running agent, always show it in "in_progress"
|
// If feature has a running agent, always show it in "in_progress"
|
||||||
@@ -62,6 +67,11 @@ export function useBoardColumnFeatures({
|
|||||||
} else if (f.worktreePath) {
|
} else if (f.worktreePath) {
|
||||||
// Has worktreePath - match by path
|
// Has worktreePath - match by path
|
||||||
matchesWorktree = f.worktreePath === effectiveWorktreePath;
|
matchesWorktree = f.worktreePath === effectiveWorktreePath;
|
||||||
|
} else if (effectiveBranch === null) {
|
||||||
|
// We're selecting a non-main worktree but can't determine its branch yet
|
||||||
|
// (worktrees haven't loaded). Don't show branch-only features until we know.
|
||||||
|
// This prevents showing wrong features during loading.
|
||||||
|
matchesWorktree = false;
|
||||||
} else {
|
} else {
|
||||||
// Has branchName but no worktreePath - match by branch name
|
// Has branchName but no worktreePath - match by branch name
|
||||||
matchesWorktree = featureBranch === effectiveBranch;
|
matchesWorktree = featureBranch === effectiveBranch;
|
||||||
@@ -76,10 +86,12 @@ export function useBoardColumnFeatures({
|
|||||||
// Otherwise, use the feature's status (fallback to backlog for unknown statuses)
|
// Otherwise, use the feature's status (fallback to backlog for unknown statuses)
|
||||||
const status = f.status as ColumnId;
|
const status = f.status as ColumnId;
|
||||||
|
|
||||||
// Backlog items are always visible (they have no worktree assigned)
|
// Filter all items by worktree, including backlog
|
||||||
// For other statuses, filter by worktree
|
// This ensures backlog items with a branch assigned only show in that branch
|
||||||
if (status === "backlog") {
|
if (status === "backlog") {
|
||||||
map.backlog.push(f);
|
if (matchesWorktree) {
|
||||||
|
map.backlog.push(f);
|
||||||
|
}
|
||||||
} else if (map[status]) {
|
} else if (map[status]) {
|
||||||
// Only show if matches current worktree or has no worktree assigned
|
// Only show if matches current worktree or has no worktree assigned
|
||||||
if (matchesWorktree) {
|
if (matchesWorktree) {
|
||||||
|
|||||||
@@ -399,7 +399,8 @@ export interface AppState {
|
|||||||
useWorktrees: boolean; // Whether to use git worktree isolation for features (default: false)
|
useWorktrees: boolean; // Whether to use git worktree isolation for features (default: false)
|
||||||
|
|
||||||
// User-managed Worktrees (per-project)
|
// User-managed Worktrees (per-project)
|
||||||
currentWorktreeByProject: Record<string, string | null>; // projectPath -> worktreePath or null for main
|
// projectPath -> { path: worktreePath or null for main, branch: branch name }
|
||||||
|
currentWorktreeByProject: Record<string, { path: string | null; branch: string }>;
|
||||||
worktreesByProject: Record<
|
worktreesByProject: Record<
|
||||||
string,
|
string,
|
||||||
Array<{
|
Array<{
|
||||||
@@ -582,7 +583,7 @@ export interface AppActions {
|
|||||||
|
|
||||||
// Worktree Settings actions
|
// Worktree Settings actions
|
||||||
setUseWorktrees: (enabled: boolean) => void;
|
setUseWorktrees: (enabled: boolean) => void;
|
||||||
setCurrentWorktree: (projectPath: string, worktreePath: string | null) => void;
|
setCurrentWorktree: (projectPath: string, worktreePath: string | null, branch: string) => void;
|
||||||
setWorktrees: (
|
setWorktrees: (
|
||||||
projectPath: string,
|
projectPath: string,
|
||||||
worktrees: Array<{
|
worktrees: Array<{
|
||||||
@@ -593,7 +594,7 @@ export interface AppActions {
|
|||||||
changedFilesCount?: number;
|
changedFilesCount?: number;
|
||||||
}>
|
}>
|
||||||
) => void;
|
) => void;
|
||||||
getCurrentWorktree: (projectPath: string) => string | null;
|
getCurrentWorktree: (projectPath: string) => { path: string | null; branch: string } | null;
|
||||||
getWorktrees: (projectPath: string) => Array<{
|
getWorktrees: (projectPath: string) => Array<{
|
||||||
path: string;
|
path: string;
|
||||||
branch: string;
|
branch: string;
|
||||||
@@ -1344,12 +1345,12 @@ export const useAppStore = create<AppState & AppActions>()(
|
|||||||
// Worktree Settings actions
|
// Worktree Settings actions
|
||||||
setUseWorktrees: (enabled) => set({ useWorktrees: enabled }),
|
setUseWorktrees: (enabled) => set({ useWorktrees: enabled }),
|
||||||
|
|
||||||
setCurrentWorktree: (projectPath, worktreePath) => {
|
setCurrentWorktree: (projectPath, worktreePath, branch) => {
|
||||||
const current = get().currentWorktreeByProject;
|
const current = get().currentWorktreeByProject;
|
||||||
set({
|
set({
|
||||||
currentWorktreeByProject: {
|
currentWorktreeByProject: {
|
||||||
...current,
|
...current,
|
||||||
[projectPath]: worktreePath,
|
[projectPath]: { path: worktreePath, branch },
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|||||||
Reference in New Issue
Block a user