From dde72ca198ede6c289f5548a72aab9b38bdaf251 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Wed, 29 Apr 2026 21:54:36 -0700 Subject: [PATCH] feat(desktop): add hover dropdown actions to changes sidebar rows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Each file in the v2 changes sidebar now reveals a more-actions dropdown on hover, with Open Diff / Open Diff in New Tab / Open File / Open File in New Tab / Open in Editor (mirrors the right-click menu, plus new Open File entries that route through the existing file-open pane). Click-modifier shortcut hints (⇧/⌘) are shown next to the actions that have them. --- .../WorkspaceSidebar/WorkspaceSidebar.tsx | 1 + .../ChangesFileList/ChangesFileList.tsx | 3 + .../components/FileRow/FileRow.tsx | 142 +++++++++++++----- .../ChangesTabContent/ChangesTabContent.tsx | 3 + .../hooks/useChangesTab/useChangesTab.tsx | 3 + 5 files changed, 114 insertions(+), 38 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx index 5c97a8d25b7..239776f590f 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/WorkspaceSidebar.tsx @@ -116,6 +116,7 @@ export function WorkspaceSidebar({ workspaceId, gitStatus, onSelectFile: onSelectDiffFile, + onOpenFile: onSelectFile, }); const changesTab: SidebarTabDefinition = { ...changesTabDef, diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx index 36c976d31b0..8a622d02e91 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/ChangesFileList.tsx @@ -7,6 +7,7 @@ interface ChangesFileListProps { isLoading?: boolean; worktreePath?: string; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; } @@ -15,6 +16,7 @@ export const ChangesFileList = memo(function ChangesFileList({ isLoading, worktreePath, onSelectFile, + onOpenFile, onOpenInEditor, }: ChangesFileListProps) { if (isLoading) { @@ -41,6 +43,7 @@ export const ChangesFileList = memo(function ChangesFileList({ file={file} worktreePath={worktreePath} onSelect={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={onOpenInEditor} /> ))} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx index b77d344d761..a1d90d2bbd0 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesFileList/components/FileRow/FileRow.tsx @@ -6,7 +6,15 @@ import { ContextMenuShortcut, ContextMenuTrigger, } from "@superset/ui/context-menu"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuShortcut, + DropdownMenuTrigger, +} from "@superset/ui/dropdown-menu"; import { Tooltip, TooltipContent, TooltipTrigger } from "@superset/ui/tooltip"; +import { ChevronDown } from "lucide-react"; import { memo } from "react"; import { StatusIndicator } from "renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/StatusIndicator"; import { PathActionsMenuItems } from "renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems"; @@ -33,6 +41,7 @@ interface FileRowProps { file: ChangesetFile; worktreePath?: string; onSelect?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; } @@ -40,6 +49,7 @@ export const FileRow = memo(function FileRow({ file, worktreePath, onSelect, + onOpenFile, onOpenInEditor, }: FileRowProps) { const { dir, basename } = splitPath(file.path); @@ -52,46 +62,90 @@ export const FileRow = memo(function FileRow({ : undefined; const rowButton = ( - + + {(file.additions > 0 || file.deletions > 0) && ( + + {file.additions > 0 && ( + +{file.additions} + )} + {file.additions > 0 && file.deletions > 0 && " "} + {file.deletions > 0 && ( + -{file.deletions} + )} + + )} + + + +
+ + + + + + onSelect?.(file.path)}> + Open Diff + + onSelect?.(file.path, true)}> + Open Diff in New Tab + {SHIFT_CLICK_LABEL} + + absolutePath && onOpenFile?.(absolutePath)} + disabled={!onOpenFile || !absolutePath} + > + Open File + + absolutePath && onOpenFile?.(absolutePath, true)} + disabled={!onOpenFile || !absolutePath} + > + Open File in New Tab + + onOpenInEditor?.(file.path)} + disabled={!onOpenInEditor} + > + Open in Editor + {MOD_CLICK_LABEL} + + + +
+ ); return ( @@ -110,6 +164,18 @@ export const FileRow = memo(function FileRow({ Open Diff in New Tab {SHIFT_CLICK_LABEL} + absolutePath && onOpenFile?.(absolutePath)} + disabled={!onOpenFile || !absolutePath} + > + Open File + + absolutePath && onOpenFile?.(absolutePath, true)} + disabled={!onOpenFile || !absolutePath} + > + Open File in New Tab + onOpenInEditor?.(file.path)} disabled={!onOpenInEditor} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx index 33442519c15..211fb8500cb 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/components/ChangesTabContent/ChangesTabContent.tsx @@ -24,6 +24,7 @@ interface ChangesTabContentProps { totalDeletions: number; worktreePath?: string; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; onOpenInEditor?: (path: string) => void; onFilterChange: (filter: ChangesFilter) => void; onBaseBranchChange: (branchName: string) => void; @@ -44,6 +45,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({ totalDeletions, worktreePath, onSelectFile, + onOpenFile, onOpenInEditor, onFilterChange, onBaseBranchChange, @@ -92,6 +94,7 @@ export const ChangesTabContent = memo(function ChangesTabContent({ isLoading={isLoading} worktreePath={worktreePath} onSelectFile={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={onOpenInEditor} /> diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx index cfa3afc380b..89f81bbe616 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/hooks/useChangesTab/useChangesTab.tsx @@ -21,12 +21,14 @@ interface UseChangesTabParams { workspaceId: string; gitStatus: ReturnType; onSelectFile?: (path: string, openInNewTab?: boolean) => void; + onOpenFile?: (absolutePath: string, openInNewTab?: boolean) => void; } export function useChangesTab({ workspaceId, gitStatus: status, onSelectFile, + onOpenFile, }: UseChangesTabParams): SidebarTabDefinition { const collections = useCollections(); const utils = workspaceTrpc.useUtils(); @@ -178,6 +180,7 @@ export function useChangesTab({ totalDeletions={totalDeletions} worktreePath={worktreePath} onSelectFile={onSelectFile} + onOpenFile={onOpenFile} onOpenInEditor={handleOpenInEditor} onFilterChange={setFilter} onBaseBranchChange={setBaseBranch}