diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx index 7c2ff6b7901..a58539baa1b 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/ChangesView.tsx @@ -11,7 +11,7 @@ import { CategorySection } from "./components/CategorySection"; import { ChangesHeader } from "./components/ChangesHeader"; import { CommitInput } from "./components/CommitInput"; import { CommitItem } from "./components/CommitItem"; -import { FileList } from "./components/FileList"; +import { type FileContextMenuProps, FileList } from "./components/FileList"; interface ChangesViewProps { /** Single click - opens in preview mode */ @@ -26,11 +26,14 @@ interface ChangesViewProps { category: ChangeCategory, commitHash?: string, ) => void; + /** Context menu props - if provided, enables right-click menu (without discard - that's added per category) */ + contextMenuProps?: Omit; } export function ChangesView({ onFileOpen, onFileOpenPinned, + contextMenuProps, }: ChangesViewProps) { const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); const worktreePath = activeWorkspace?.worktreePath; @@ -102,6 +105,25 @@ export function ChangesView({ }, }); + const discardChangesMutation = trpc.changes.discardChanges.useMutation({ + onSuccess: () => refetch(), + onError: (error, variables) => { + console.error( + `Failed to discard changes for ${variables.filePath}:`, + error, + ); + toast.error(`Failed to discard changes: ${error.message}`); + }, + }); + + const deleteUntrackedMutation = trpc.changes.deleteUntracked.useMutation({ + onSuccess: () => refetch(), + onError: (error, variables) => { + console.error(`Failed to delete ${variables.filePath}:`, error); + toast.error(`Failed to delete file: ${error.message}`); + }, + }); + const { expandedSections, fileListViewMode, @@ -187,6 +209,34 @@ export function ChangesView({ }); }; + // Handle discard changes for unstaged files + const handleDiscardChanges = (file: ChangedFile) => { + if (!worktreePath) return; + // Untracked files need to be deleted, modified files use git checkout + if (file.status === "untracked") { + deleteUntrackedMutation.mutate({ + worktreePath, + filePath: file.path, + }); + } else { + discardChangesMutation.mutate({ + worktreePath, + filePath: file.path, + }); + } + }; + + // Create context menu props, optionally including discard for unstaged files + const getContextMenuProps = ( + includeDiscard = false, + ): FileContextMenuProps | undefined => { + if (!contextMenuProps) return undefined; + return { + ...contextMenuProps, + onDiscardChanges: includeDiscard ? handleDiscardChanges : undefined, + }; + }; + if (!worktreePath) { return (
@@ -279,6 +329,7 @@ export function ChangesView({ onFileDoubleClick={(file) => handleFileDoubleClick(file, "against-base") } + contextMenuProps={getContextMenuProps()} /> @@ -300,6 +351,7 @@ export function ChangesView({ onFileSelect={handleCommitFileSelect} onFileDoubleClick={handleCommitFileDoubleClick} viewMode={fileListViewMode} + contextMenuProps={getContextMenuProps()} /> ))} @@ -347,6 +399,7 @@ export function ChangesView({ }) } isActioning={unstageFileMutation.isPending} + contextMenuProps={getContextMenuProps()} /> @@ -393,6 +446,7 @@ export function ChangesView({ }) } isActioning={stageFileMutation.isPending} + contextMenuProps={getContextMenuProps(true)} />
diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx index b3de824fd67..5d1f6311e64 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/CommitItem/CommitItem.tsx @@ -7,7 +7,7 @@ import { cn } from "@superset/ui/utils"; import { HiChevronRight } from "react-icons/hi2"; import type { ChangedFile, CommitInfo } from "shared/changes-types"; import type { ChangesViewMode } from "../../types"; -import { FileList } from "../FileList"; +import { type FileContextMenuProps, FileList } from "../FileList"; interface CommitItemProps { commit: CommitInfo; @@ -20,6 +20,8 @@ interface CommitItemProps { /** Double click - opens pinned (permanent) */ onFileDoubleClick?: (file: ChangedFile, commitHash: string) => void; viewMode: ChangesViewMode; + /** Context menu props - if provided, enables right-click menu */ + contextMenuProps?: FileContextMenuProps; } function formatRelativeDate(date: Date): string { @@ -45,6 +47,7 @@ export function CommitItem({ onFileSelect, onFileDoubleClick, viewMode, + contextMenuProps, }: CommitItemProps) { const hasFiles = commit.files.length > 0; @@ -94,6 +97,7 @@ export function CommitItem({ onFileSelect={handleFileSelect} onFileDoubleClick={handleFileDoubleClick} showStats={false} + contextMenuProps={contextMenuProps} /> )} diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx index 0ab29f35a91..5b7b998bf69 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItem.tsx @@ -1,9 +1,26 @@ import { Button } from "@superset/ui/button"; +import { ContextMenuTrigger } from "@superset/ui/context-menu"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; import { cn } from "@superset/ui/utils"; import { HiMiniMinus, HiMiniPlus } from "react-icons/hi2"; +import type { Tab } from "renderer/stores/tabs/types"; import type { ChangedFile } from "shared/changes-types"; import { getStatusColor, getStatusIndicator } from "../../utils"; +import { + FileItemContextMenu, + type FileItemContextMenuActions, +} from "./FileItemContextMenu"; + +export interface FileItemContextMenuProps { + currentTabId: string; + availableTabs: Tab[]; + onOpenInSplitHorizontal: () => void; + onOpenInSplitVertical: () => void; + onOpenInApp: () => void; + onOpenInNewTab: () => void; + onMoveToTab: (tabId: string) => void; + onDiscardChanges?: () => void; +} interface FileItemProps { file: ChangedFile; @@ -21,6 +38,8 @@ interface FileItemProps { onUnstage?: () => void; /** Whether the action is currently pending */ isActioning?: boolean; + /** Context menu props - if provided, enables right-click menu */ + contextMenuProps?: FileItemContextMenuProps; } function LevelIndicators({ level }: { level: number }) { @@ -50,6 +69,7 @@ export function FileItem({ onStage, onUnstage, isActioning = false, + contextMenuProps, }: FileItemProps) { const fileName = getFileName(file.path); const statusBadgeColor = getStatusColor(file.status); @@ -59,7 +79,7 @@ export function FileItem({ const hasIndent = level > 0; const hasAction = onStage || onUnstage; - return ( + const content = (
); + + if (contextMenuProps) { + const actions: FileItemContextMenuActions = { + onOpenInSplitHorizontal: contextMenuProps.onOpenInSplitHorizontal, + onOpenInSplitVertical: contextMenuProps.onOpenInSplitVertical, + onOpenInApp: contextMenuProps.onOpenInApp, + onOpenInNewTab: contextMenuProps.onOpenInNewTab, + onMoveToTab: contextMenuProps.onMoveToTab, + onDiscardChanges: contextMenuProps.onDiscardChanges, + }; + + return ( + + {content} + + ); + } + + return content; } diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItemContextMenu.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItemContextMenu.tsx new file mode 100644 index 00000000000..e69b9cd78ab --- /dev/null +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/FileItemContextMenu.tsx @@ -0,0 +1,107 @@ +import { + ContextMenu, + ContextMenuContent, + ContextMenuItem, + ContextMenuSeparator, + ContextMenuSub, + ContextMenuSubContent, + ContextMenuSubTrigger, +} from "@superset/ui/context-menu"; +import type { ReactNode } from "react"; +import { + LuAppWindow, + LuColumns2, + LuMoveRight, + LuPlus, + LuRows2, + LuTrash2, +} from "react-icons/lu"; +import type { Tab } from "renderer/stores/tabs/types"; + +export interface FileItemContextMenuActions { + onOpenInSplitHorizontal: () => void; + onOpenInSplitVertical: () => void; + onOpenInApp: () => void; + onOpenInNewTab: () => void; + onMoveToTab: (tabId: string) => void; + onDiscardChanges?: () => void; +} + +interface FileItemContextMenuProps { + children: ReactNode; + actions: FileItemContextMenuActions; + currentTabId: string; + availableTabs: Tab[]; +} + +export function FileItemContextMenu({ + children, + actions, + currentTabId, + availableTabs, +}: FileItemContextMenuProps) { + const targetTabs = availableTabs.filter((t) => t.id !== currentTabId); + + return ( + + + {/* Open actions */} + + + Open in Split Pane (Horizontal) + + + + Open in Split Pane (Vertical) + + + + + + + Open in App + + + + + {/* Tab actions */} + + + + Open in Tab + + + {targetTabs.map((tab) => ( + actions.onMoveToTab(tab.id)} + > + {tab.userTitle || tab.name} + + ))} + {targetTabs.length > 0 && } + + + New Tab + + + + + {/* Destructive actions */} + {actions.onDiscardChanges && ( + <> + + + + Discard Changes + + + )} + + {children} + + ); +} diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/index.ts b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/index.ts index 20531c3a8b2..65145ac2f94 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/index.ts +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileItem/index.ts @@ -1 +1,2 @@ -export { FileItem } from "./FileItem"; +export { FileItem, type FileItemContextMenuProps } from "./FileItem"; +export { FileItemContextMenu } from "./FileItemContextMenu"; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileList.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileList.tsx index 3f3e6031da8..38db71d1ea7 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileList.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileList.tsx @@ -1,8 +1,24 @@ +import type { Tab } from "renderer/stores/tabs/types"; import type { ChangedFile } from "shared/changes-types"; import type { ChangesViewMode } from "../../types"; import { FileListGrouped } from "./FileListGrouped"; import { FileListTree } from "./FileListTree"; +/** + * Shared context menu props for file items. + * All callbacks receive the file so they can be passed down without per-file binding. + */ +export interface FileContextMenuProps { + currentTabId: string; + availableTabs: Tab[]; + onOpenInSplitHorizontal: (file: ChangedFile) => void; + onOpenInSplitVertical: (file: ChangedFile) => void; + onOpenInApp: (file: ChangedFile) => void; + onOpenInNewTab: (file: ChangedFile) => void; + onMoveToTab: (file: ChangedFile, tabId: string) => void; + onDiscardChanges?: (file: ChangedFile) => void; +} + interface FileListProps { files: ChangedFile[]; viewMode: ChangesViewMode; @@ -19,6 +35,8 @@ interface FileListProps { onUnstage?: (file: ChangedFile) => void; /** Whether an action is currently pending */ isActioning?: boolean; + /** Context menu props - if provided, enables right-click menu */ + contextMenuProps?: FileContextMenuProps; } export function FileList({ @@ -32,6 +50,7 @@ export function FileList({ onStage, onUnstage, isActioning, + contextMenuProps, }: FileListProps) { if (files.length === 0) { return null; @@ -49,6 +68,7 @@ export function FileList({ onStage={onStage} onUnstage={onUnstage} isActioning={isActioning} + contextMenuProps={contextMenuProps} /> ); } @@ -65,6 +85,7 @@ export function FileList({ onStage={onStage} onUnstage={onUnstage} isActioning={isActioning} + contextMenuProps={contextMenuProps} /> ); } diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListGrouped.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListGrouped.tsx index 6a68b5e3fe4..d2ea5e19b23 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListGrouped.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListGrouped.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import type { ChangedFile } from "shared/changes-types"; import { FileItem } from "../FileItem"; import { FolderRow } from "../FolderRow"; +import type { FileContextMenuProps } from "./FileList"; interface FileListGroupedProps { files: ChangedFile[]; @@ -15,6 +16,8 @@ interface FileListGroupedProps { onStage?: (file: ChangedFile) => void; onUnstage?: (file: ChangedFile) => void; isActioning?: boolean; + /** Context menu props - if provided, enables right-click menu */ + contextMenuProps?: FileContextMenuProps; } interface FolderGroup { @@ -65,6 +68,7 @@ interface FolderGroupItemProps { onStage?: (file: ChangedFile) => void; onUnstage?: (file: ChangedFile) => void; isActioning?: boolean; + contextMenuProps?: FileContextMenuProps; } function FolderGroupItem({ @@ -76,6 +80,7 @@ function FolderGroupItem({ onStage, onUnstage, isActioning, + contextMenuProps, }: FolderGroupItemProps) { const [isExpanded, setIsExpanded] = useState(true); const isRoot = group.folderPath === ""; @@ -102,6 +107,25 @@ function FolderGroupItem({ onStage={onStage ? () => onStage(file) : undefined} onUnstage={onUnstage ? () => onUnstage(file) : undefined} isActioning={isActioning} + contextMenuProps={ + contextMenuProps + ? { + currentTabId: contextMenuProps.currentTabId, + availableTabs: contextMenuProps.availableTabs, + onOpenInSplitHorizontal: () => + contextMenuProps.onOpenInSplitHorizontal(file), + onOpenInSplitVertical: () => + contextMenuProps.onOpenInSplitVertical(file), + onOpenInApp: () => contextMenuProps.onOpenInApp(file), + onOpenInNewTab: () => contextMenuProps.onOpenInNewTab(file), + onMoveToTab: (tabId) => + contextMenuProps.onMoveToTab(file, tabId), + onDiscardChanges: contextMenuProps.onDiscardChanges + ? () => contextMenuProps.onDiscardChanges?.(file) + : undefined, + } + : undefined + } /> ))} @@ -117,6 +141,7 @@ export function FileListGrouped({ onStage, onUnstage, isActioning, + contextMenuProps, }: FileListGroupedProps) { const groups = groupFilesByFolder(files); @@ -133,6 +158,7 @@ export function FileListGrouped({ onStage={onStage} onUnstage={onUnstage} isActioning={isActioning} + contextMenuProps={contextMenuProps} /> ))}
diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListTree.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListTree.tsx index ab97a04c444..e3c6a8049cf 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListTree.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/FileListTree.tsx @@ -2,6 +2,7 @@ import { useState } from "react"; import type { ChangedFile } from "shared/changes-types"; import { FileItem } from "../FileItem"; import { FolderRow } from "../FolderRow"; +import type { FileContextMenuProps } from "./FileList"; interface FileListTreeProps { files: ChangedFile[]; @@ -15,6 +16,8 @@ interface FileListTreeProps { onStage?: (file: ChangedFile) => void; onUnstage?: (file: ChangedFile) => void; isActioning?: boolean; + /** Context menu props - if provided, enables right-click menu */ + contextMenuProps?: FileContextMenuProps; } interface FileTreeNode { @@ -89,6 +92,7 @@ interface TreeNodeComponentProps { onStage?: (file: ChangedFile) => void; onUnstage?: (file: ChangedFile) => void; isActioning?: boolean; + contextMenuProps?: FileContextMenuProps; } function TreeNodeComponent({ @@ -102,6 +106,7 @@ function TreeNodeComponent({ onStage, onUnstage, isActioning, + contextMenuProps, }: TreeNodeComponentProps) { const [isExpanded, setIsExpanded] = useState(true); const hasChildren = node.children && node.children.length > 0; @@ -130,6 +135,7 @@ function TreeNodeComponent({ onStage={onStage} onUnstage={onUnstage} isActioning={isActioning} + contextMenuProps={contextMenuProps} /> ))} @@ -151,6 +157,25 @@ function TreeNodeComponent({ onStage={onStage ? () => onStage(file) : undefined} onUnstage={onUnstage ? () => onUnstage(file) : undefined} isActioning={isActioning} + contextMenuProps={ + contextMenuProps + ? { + currentTabId: contextMenuProps.currentTabId, + availableTabs: contextMenuProps.availableTabs, + onOpenInSplitHorizontal: () => + contextMenuProps.onOpenInSplitHorizontal(file), + onOpenInSplitVertical: () => + contextMenuProps.onOpenInSplitVertical(file), + onOpenInApp: () => contextMenuProps.onOpenInApp(file), + onOpenInNewTab: () => contextMenuProps.onOpenInNewTab(file), + onMoveToTab: (tabId) => + contextMenuProps.onMoveToTab(file, tabId), + onDiscardChanges: contextMenuProps.onDiscardChanges + ? () => contextMenuProps.onDiscardChanges?.(file) + : undefined, + } + : undefined + } /> ); } @@ -168,6 +193,7 @@ export function FileListTree({ onStage, onUnstage, isActioning, + contextMenuProps, }: FileListTreeProps) { const tree = buildFileTree(files); @@ -185,6 +211,7 @@ export function FileListTree({ onStage={onStage} onUnstage={onUnstage} isActioning={isActioning} + contextMenuProps={contextMenuProps} /> ))} diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/index.ts b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/index.ts index 517405d0959..533dd9780d8 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/index.ts +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/components/FileList/index.ts @@ -1,3 +1,3 @@ -export { FileList } from "./FileList"; +export { type FileContextMenuProps, FileList } from "./FileList"; export { FileListGrouped } from "./FileListGrouped"; export { FileListTree } from "./FileListTree"; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/index.ts b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/index.ts index 685f820396a..bee605815cb 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/index.ts +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/ChangesView/index.ts @@ -1 +1,2 @@ export { ChangesView } from "./ChangesView"; +export type { FileContextMenuProps } from "./components/FileList"; diff --git a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx index 854662bd316..6802a9c6059 100644 --- a/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx +++ b/apps/desktop/src/renderer/screens/main/components/WorkspaceView/Sidebar/index.tsx @@ -1,13 +1,29 @@ +import { useMemo } from "react"; import { trpc } from "renderer/lib/trpc"; import { useTabsStore } from "renderer/stores/tabs/store"; import type { ChangeCategory, ChangedFile } from "shared/changes-types"; -import { ChangesView } from "./ChangesView"; +import { ChangesView, type FileContextMenuProps } from "./ChangesView"; export function Sidebar() { const { data: activeWorkspace } = trpc.workspaces.getActive.useQuery(); const workspaceId = activeWorkspace?.id; + const worktreePath = activeWorkspace?.worktreePath; const addFileViewerPane = useTabsStore((s) => s.addFileViewerPane); + const addTab = useTabsStore((s) => s.addTab); + const splitPaneHorizontal = useTabsStore((s) => s.splitPaneHorizontal); + const splitPaneVertical = useTabsStore((s) => s.splitPaneVertical); + const tabs = useTabsStore((s) => s.tabs); + const activeTabIds = useTabsStore((s) => s.activeTabIds); + + const openInApp = trpc.external.openInApp.useMutation(); + + // Get the current tab and available tabs for the workspace + const currentTabId = workspaceId ? (activeTabIds[workspaceId] ?? "") : ""; + const workspaceTabs = useMemo( + () => tabs.filter((t) => t.workspaceId === workspaceId), + [tabs, workspaceId], + ); // Single click - opens in preview mode (can be replaced by next single click) const handleFileOpen = workspaceId @@ -35,11 +51,80 @@ export function Sidebar() { } : undefined; + // Context menu props for file items (without discard - that's added in ChangesView) + const contextMenuProps: + | Omit + | undefined = useMemo( + () => + workspaceId && worktreePath + ? { + currentTabId, + availableTabs: workspaceTabs, + onOpenInSplitHorizontal: (file: ChangedFile) => { + // Add the file viewer pane, then split + const paneId = addFileViewerPane(workspaceId, { + filePath: file.path, + oldPath: file.oldPath, + isPinned: true, + }); + if (paneId) { + splitPaneHorizontal(currentTabId, paneId); + } + }, + onOpenInSplitVertical: (file: ChangedFile) => { + const paneId = addFileViewerPane(workspaceId, { + filePath: file.path, + oldPath: file.oldPath, + isPinned: true, + }); + if (paneId) { + splitPaneVertical(currentTabId, paneId); + } + }, + onOpenInApp: (file: ChangedFile) => { + const fullPath = `${worktreePath}/${file.path}`; + openInApp.mutate({ path: fullPath, app: "cursor" }); + }, + onOpenInNewTab: (file: ChangedFile) => { + // Create a new tab - it will become active automatically + addTab(workspaceId); + // Add the file viewer pane to the new active tab + addFileViewerPane(workspaceId, { + filePath: file.path, + oldPath: file.oldPath, + isPinned: true, + }); + }, + onMoveToTab: (file: ChangedFile, tabId: string) => { + // Switch to the target tab and add the file viewer pane + useTabsStore.getState().setActiveTab(workspaceId, tabId); + addFileViewerPane(workspaceId, { + filePath: file.path, + oldPath: file.oldPath, + isPinned: true, + }); + }, + } + : undefined, + [ + workspaceId, + worktreePath, + currentTabId, + workspaceTabs, + addFileViewerPane, + addTab, + splitPaneHorizontal, + splitPaneVertical, + openInApp, + ], + ); + return ( );