mirror of
https://github.com/AutoMaker-Org/automaker.git
synced 2026-02-01 08:13:37 +00:00
add ability to collapse worktree panel
This commit is contained in:
@@ -91,21 +91,6 @@ export function WorktreeTab({
|
|||||||
onStopDevServer,
|
onStopDevServer,
|
||||||
onOpenDevServerUrl,
|
onOpenDevServerUrl,
|
||||||
}: WorktreeTabProps) {
|
}: WorktreeTabProps) {
|
||||||
// Determine border color based on state:
|
|
||||||
// - Running features: cyan border (high visibility, indicates active work)
|
|
||||||
// - Uncommitted changes: amber border (warning state, needs attention)
|
|
||||||
// - Both: cyan takes priority (running is more important to see)
|
|
||||||
const getBorderClasses = () => {
|
|
||||||
if (isRunning) {
|
|
||||||
return "ring-2 ring-cyan-500 ring-offset-1 ring-offset-background";
|
|
||||||
}
|
|
||||||
if (hasChanges) {
|
|
||||||
return "ring-2 ring-amber-500 ring-offset-1 ring-offset-background";
|
|
||||||
}
|
|
||||||
return "";
|
|
||||||
};
|
|
||||||
|
|
||||||
const borderClasses = getBorderClasses();
|
|
||||||
|
|
||||||
let prBadge: JSX.Element | null = null;
|
let prBadge: JSX.Element | null = null;
|
||||||
if (worktree.pr) {
|
if (worktree.pr) {
|
||||||
@@ -193,7 +178,7 @@ export function WorktreeTab({
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className={cn("flex items-center rounded-md", borderClasses)}>
|
<div className="flex items-center rounded-md">
|
||||||
{worktree.isMain ? (
|
{worktree.isMain ? (
|
||||||
<>
|
<>
|
||||||
<Button
|
<Button
|
||||||
|
|||||||
@@ -20,9 +20,12 @@ export function useWorktrees({ projectPath, refreshTrigger = 0, onRemovedWorktre
|
|||||||
const setWorktreesInStore = useAppStore((s) => s.setWorktrees);
|
const setWorktreesInStore = useAppStore((s) => s.setWorktrees);
|
||||||
const useWorktreesEnabled = useAppStore((s) => s.useWorktrees);
|
const useWorktreesEnabled = useAppStore((s) => s.useWorktrees);
|
||||||
|
|
||||||
const fetchWorktrees = useCallback(async () => {
|
const fetchWorktrees = useCallback(async (options?: { silent?: boolean }) => {
|
||||||
if (!projectPath) return;
|
if (!projectPath) return;
|
||||||
setIsLoading(true);
|
const silent = options?.silent ?? false;
|
||||||
|
if (!silent) {
|
||||||
|
setIsLoading(true);
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
const api = getElectronAPI();
|
const api = getElectronAPI();
|
||||||
if (!api?.worktree?.listAll) {
|
if (!api?.worktree?.listAll) {
|
||||||
@@ -40,7 +43,9 @@ export function useWorktrees({ projectPath, refreshTrigger = 0, onRemovedWorktre
|
|||||||
console.error("Failed to fetch worktrees:", error);
|
console.error("Failed to fetch worktrees:", error);
|
||||||
return undefined;
|
return undefined;
|
||||||
} finally {
|
} finally {
|
||||||
setIsLoading(false);
|
if (!silent) {
|
||||||
|
setIsLoading(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}, [projectPath, setWorktreesInStore]);
|
}, [projectPath, setWorktreesInStore]);
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,12 @@
|
|||||||
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { Button } from "@/components/ui/button";
|
import { Button } from "@/components/ui/button";
|
||||||
import { GitBranch, Plus, RefreshCw } from "lucide-react";
|
import {
|
||||||
|
GitBranch,
|
||||||
|
Plus,
|
||||||
|
RefreshCw,
|
||||||
|
PanelLeftOpen,
|
||||||
|
PanelLeftClose,
|
||||||
|
} from "lucide-react";
|
||||||
import { cn, pathsEqual } from "@/lib/utils";
|
import { cn, pathsEqual } from "@/lib/utils";
|
||||||
import type { WorktreePanelProps, WorktreeInfo } from "./types";
|
import type { WorktreePanelProps, WorktreeInfo } from "./types";
|
||||||
import {
|
import {
|
||||||
@@ -12,6 +19,8 @@ import {
|
|||||||
} from "./hooks";
|
} from "./hooks";
|
||||||
import { WorktreeTab } from "./components";
|
import { WorktreeTab } from "./components";
|
||||||
|
|
||||||
|
const WORKTREE_PANEL_COLLAPSED_KEY = "worktree-panel-collapsed";
|
||||||
|
|
||||||
export function WorktreePanel({
|
export function WorktreePanel({
|
||||||
projectPath,
|
projectPath,
|
||||||
onCreateWorktree,
|
onCreateWorktree,
|
||||||
@@ -80,6 +89,45 @@ export function WorktreePanel({
|
|||||||
features,
|
features,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Collapse state with localStorage persistence
|
||||||
|
const [isCollapsed, setIsCollapsed] = useState(() => {
|
||||||
|
if (typeof window === "undefined") return false;
|
||||||
|
const saved = localStorage.getItem(WORKTREE_PANEL_COLLAPSED_KEY);
|
||||||
|
return saved === "true";
|
||||||
|
});
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
localStorage.setItem(WORKTREE_PANEL_COLLAPSED_KEY, String(isCollapsed));
|
||||||
|
}, [isCollapsed]);
|
||||||
|
|
||||||
|
const toggleCollapsed = () => setIsCollapsed((prev) => !prev);
|
||||||
|
|
||||||
|
// Periodic interval check (1 second) to detect branch changes on disk
|
||||||
|
const intervalRef = useRef<NodeJS.Timeout | null>(null);
|
||||||
|
useEffect(() => {
|
||||||
|
intervalRef.current = setInterval(() => {
|
||||||
|
fetchWorktrees({ silent: true });
|
||||||
|
}, 1000);
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
if (intervalRef.current) {
|
||||||
|
clearInterval(intervalRef.current);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}, [fetchWorktrees]);
|
||||||
|
|
||||||
|
// Get the currently selected worktree for collapsed view
|
||||||
|
const selectedWorktree = worktrees.find((w) => {
|
||||||
|
if (
|
||||||
|
currentWorktree === null ||
|
||||||
|
currentWorktree === undefined ||
|
||||||
|
currentWorktree.path === null
|
||||||
|
) {
|
||||||
|
return w.isMain;
|
||||||
|
}
|
||||||
|
return pathsEqual(w.path, currentWorktreePath);
|
||||||
|
});
|
||||||
|
|
||||||
const isWorktreeSelected = (worktree: WorktreeInfo) => {
|
const isWorktreeSelected = (worktree: WorktreeInfo) => {
|
||||||
return worktree.isMain
|
return worktree.isMain
|
||||||
? currentWorktree === null ||
|
? currentWorktree === null ||
|
||||||
@@ -106,9 +154,46 @@ export function WorktreePanel({
|
|||||||
const mainWorktree = worktrees.find((w) => w.isMain);
|
const mainWorktree = worktrees.find((w) => w.isMain);
|
||||||
const nonMainWorktrees = worktrees.filter((w) => !w.isMain);
|
const nonMainWorktrees = worktrees.filter((w) => !w.isMain);
|
||||||
|
|
||||||
|
// Collapsed view - just show current branch and toggle
|
||||||
|
if (isCollapsed) {
|
||||||
|
return (
|
||||||
|
<div className="flex items-center gap-2 px-4 py-1.5 border-b border-border bg-glass/50 backdrop-blur-sm">
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-6 w-6 p-0 text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={toggleCollapsed}
|
||||||
|
title="Expand worktree panel"
|
||||||
|
>
|
||||||
|
<PanelLeftOpen className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
<GitBranch className="w-4 h-4 text-muted-foreground" />
|
||||||
|
<span className="text-sm text-muted-foreground">Branch:</span>
|
||||||
|
<span className="text-sm font-mono font-medium">
|
||||||
|
{selectedWorktree?.branch ?? "main"}
|
||||||
|
</span>
|
||||||
|
{selectedWorktree?.hasChanges && (
|
||||||
|
<span className="inline-flex items-center justify-center h-4 min-w-[1rem] px-1 text-[10px] font-medium rounded border bg-amber-500/20 text-amber-600 dark:text-amber-400 border-amber-500/30">
|
||||||
|
{selectedWorktree.changedFilesCount ?? "!"}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Expanded view - full worktree panel
|
||||||
return (
|
return (
|
||||||
<div className="flex items-center gap-2 px-4 py-2 border-b border-border bg-glass/50 backdrop-blur-sm">
|
<div className="flex items-center gap-2 px-4 py-2 border-b border-border bg-glass/50 backdrop-blur-sm">
|
||||||
{/* Branch section - always visible */}
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
className="h-6 w-6 p-0 text-muted-foreground hover:text-foreground"
|
||||||
|
onClick={toggleCollapsed}
|
||||||
|
title="Collapse worktree panel"
|
||||||
|
>
|
||||||
|
<PanelLeftClose className="w-4 h-4" />
|
||||||
|
</Button>
|
||||||
|
|
||||||
<GitBranch className="w-4 h-4 text-muted-foreground" />
|
<GitBranch className="w-4 h-4 text-muted-foreground" />
|
||||||
<span className="text-sm text-muted-foreground mr-2">Branch:</span>
|
<span className="text-sm text-muted-foreground mr-2">Branch:</span>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user