Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,22 +28,32 @@ interface DiffViewProps {
onRefresh?: () => void;
isRefreshing?: boolean;
onClose?: () => void;
hideFileTree?: boolean;
externalSelectedFile?: string | null;
onFileSelect?: (fileId: string) => void;
}

export function DiffView({
data,
onRefresh,
isRefreshing = false,
onClose,
hideFileTree = false,
externalSelectedFile = null,
onFileSelect: externalOnFileSelect,
}: DiffViewProps) {
const [viewMode, setViewMode] = useState<ViewMode>("files");
const [selectedFile, setSelectedFile] = useState<string | null>(
const [internalSelectedFile, setInternalSelectedFile] = useState<string | null>(
data.files[0]?.id || null,
);
const [showFileTree, setShowFileTree] = useState(true);
const [showFileTree, setShowFileTree] = useState(!hideFileTree);
const scrollContainerRef = useRef<HTMLDivElement>(null);
const isScrollingProgrammatically = useRef(false);

// Use external selected file if provided, otherwise use internal state
const selectedFile = externalSelectedFile !== null ? externalSelectedFile : internalSelectedFile;
const setSelectedFile = externalOnFileSelect || setInternalSelectedFile;

const getFileIcon = (status: FileDiff["status"]) => {
switch (status) {
case "added":
Expand Down Expand Up @@ -338,44 +348,46 @@ export function DiffView({
) : (
// Files changed view - scrollable list of all files (GitHub style)
<>
{/* File tree sidebar - kept mounted, hidden with display:none for instant toggle */}
<div
className={`w-72 border-r border-white/5 overflow-y-auto bg-[#1a1a1a] shrink-0 ${showFileTree ? "" : "hidden"}`}
>
<div className="py-2">
<div className="flex items-center justify-between px-3 py-2">
<h2 className="text-xs font-medium text-zinc-500">Files</h2>
<div className="flex items-center gap-1">
<Tooltip>
<TooltipTrigger asChild>
<button
onClick={() => setShowFileTree(false)}
className="text-zinc-600 hover:text-zinc-400 transition-colors p-1 rounded hover:bg-white/5"
type="button"
>
<PanelLeftClose className="w-3.5 h-3.5" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom">
<p>Hide file tree</p>
</TooltipContent>
</Tooltip>
{/* File tree sidebar - hidden when hideFileTree prop is true */}
{!hideFileTree && (
<div
className={`w-72 border-r border-white/5 overflow-y-auto bg-[#1a1a1a] shrink-0 ${showFileTree ? "" : "hidden"}`}
>
<div className="py-2">
<div className="flex items-center justify-between px-3 py-2">
<h2 className="text-xs font-medium text-zinc-500">Files</h2>
<div className="flex items-center gap-1">
<Tooltip>
<TooltipTrigger asChild>
<button
onClick={() => setShowFileTree(false)}
className="text-zinc-600 hover:text-zinc-400 transition-colors p-1 rounded hover:bg-white/5"
type="button"
>
<PanelLeftClose className="w-3.5 h-3.5" />
</button>
</TooltipTrigger>
<TooltipContent side="bottom">
<p>Hide file tree</p>
</TooltipContent>
</Tooltip>
</div>
</div>
<div className="px-2">
<FileTree
files={data.files}
selectedFile={selectedFile}
onFileSelect={handleFileSelect}
getFileIcon={getFileIcon}
/>
</div>
</div>
<div className="px-2">
<FileTree
files={data.files}
selectedFile={selectedFile}
onFileSelect={handleFileSelect}
getFileIcon={getFileIcon}
/>
</div>
</div>
</div>
)}

{/* All files diff content - scrollable */}
<div className="flex-1 flex flex-col overflow-hidden">
{!showFileTree && (
{!hideFileTree && !showFileTree && (
<div className="border-b border-white/5 px-3 py-2">
<button
onClick={() => setShowFileTree(true)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ export const NewLayoutMain: React.FC = () => {
const [selectedTabId, setSelectedTabId] = useState<string | null>(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<string | null>(null);
const [selectedDiffFile, setSelectedDiffFile] = useState<string | null>(null);
const [sidebarMode, setSidebarMode] = useState<"tabs" | "changes">("tabs");

const handleCollapseSidebar = () => {
const panel = sidebarPanelRef.current;
Expand Down Expand Up @@ -472,46 +474,6 @@ export const NewLayoutMain: React.FC = () => {
}
};

// Workspace handlers
const handleAddWorkspace = () => {
// TODO: Implement workspace creation dialog
console.log("Add workspace - not yet implemented");
};

const handleRemoveWorkspace = async (
workspaceId: string,
workspaceName: string,
) => {
// Show confirmation dialog
const confirmed = confirm(
`Are you sure you want to remove workspace "${workspaceName}"? This will not delete any files.`,
);

if (confirmed) {
try {
await window.ipcRenderer.invoke("workspace-delete", {
id: workspaceId,
removeWorktree: false,
});
// Reload workspaces
await loadAllWorkspaces();
// If we removed the current workspace, switch to another one
if (currentWorkspace?.id === workspaceId && workspaces) {
const remainingWorkspaces = workspaces.filter(
(ws) => ws.id !== workspaceId,
);
if (remainingWorkspaces.length > 0) {
await handleWorkspaceSelect(remainingWorkspaces[0].id);
} else {
setCurrentWorkspace(null);
}
}
} catch (error) {
console.error("Failed to remove workspace:", error);
}
}
};

// Task handlers
const handleOpenAddTaskModal = () => {
setIsAddTaskModalOpen(true);
Expand Down Expand Up @@ -734,11 +696,10 @@ export const NewLayoutMain: React.FC = () => {
setShowSidebarOverlay(false);
}}
workspaceId={currentWorkspace?.id || null}
workspaces={workspaces || undefined}
currentWorkspace={currentWorkspace}
onWorkspaceSelect={handleWorkspaceSelect}
onAddWorkspace={handleAddWorkspace}
onRemoveWorkspace={handleRemoveWorkspace}
workspaceName={currentWorkspace?.name}
mainBranch={currentWorkspace?.branch}
onDiffFileSelect={setSelectedDiffFile}
onModeChange={setSidebarMode}
/>
</div>
</div>
Expand Down Expand Up @@ -843,11 +804,10 @@ export const NewLayoutMain: React.FC = () => {
}
}}
workspaceId={currentWorkspace?.id || null}
workspaces={workspaces || undefined}
currentWorkspace={currentWorkspace}
onWorkspaceSelect={handleWorkspaceSelect}
onAddWorkspace={handleAddWorkspace}
onRemoveWorkspace={handleRemoveWorkspace}
workspaceName={currentWorkspace?.name}
mainBranch={currentWorkspace?.branch}
onDiffFileSelect={setSelectedDiffFile}
onModeChange={setSidebarMode}
/>
)}
</ResizablePanel>
Expand All @@ -859,13 +819,32 @@ export const NewLayoutMain: React.FC = () => {
{loading ||
error ||
!currentWorkspace ||
!selectedTab ||
!selectedWorktree ? (
<PlaceholderState
loading={loading}
error={error}
hasWorkspace={!!currentWorkspace}
/>
) : sidebarMode === "changes" ? (
// Changes mode - always show diff view
<div className="w-full h-full">
<DiffTab
tab={{ id: "changes-view", name: "Changes", type: "diff" } as any}
workspaceId={currentWorkspace.id}
worktreeId={selectedWorktreeId ?? ""}
worktree={selectedWorktree}
workspaceName={currentWorkspace.name}
mainBranch={currentWorkspace.branch}
selectedDiffFile={selectedDiffFile}
onDiffFileSelect={setSelectedDiffFile}
/>
</div>
) : !selectedTab ? (
<PlaceholderState
loading={false}
error={null}
hasWorkspace={!!currentWorkspace}
/>
) : parentGroupTab ? (
// Selected tab is a sub-tab of a group → display the parent group's mosaic
<TabGroup
Expand Down Expand Up @@ -906,6 +885,8 @@ export const NewLayoutMain: React.FC = () => {
worktree={selectedWorktree}
workspaceName={currentWorkspace.name}
mainBranch={currentWorkspace.branch}
selectedDiffFile={selectedDiffFile}
onDiffFileSelect={setSelectedDiffFile}
/>
</div>
) : (
Expand Down
Loading
Loading