From a8ce2906d325455bbc32470d9085153f7b2e7afe Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 14 Apr 2026 16:10:33 -0700 Subject: [PATCH 1/5] fix(desktop): use native clipboard for copy path in v2 sidebar navigator.clipboard.writeText silently fails when focus is elsewhere (e.g., terminal), so the toast showed but nothing was actually copied. Switch to useCopyToClipboard which routes through Electron's native clipboard via tRPC, matching the v1 pathway. --- .../components/FileContextMenu/FileContextMenu.tsx | 11 +++++++---- .../FolderContextMenu/FolderContextMenu.tsx | 11 +++++++---- 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx index c0f46ec2566..71674badde3 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx @@ -4,6 +4,7 @@ import { ContextMenuSeparator, } from "@superset/ui/context-menu"; import { toast } from "@superset/ui/sonner"; +import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; import { electronTrpcClient } from "renderer/lib/trpc-client"; interface FileContextMenuProps { @@ -19,6 +20,8 @@ export function FileContextMenu({ onRename, onDelete, }: FileContextMenuProps) { + const { copyToClipboard } = useCopyToClipboard(); + return ( Open to the Side @@ -32,8 +35,8 @@ export function FileContextMenu({ { - navigator.clipboard.writeText(absolutePath); + onSelect={async () => { + await copyToClipboard(absolutePath); toast.success("Path copied"); }} > @@ -41,8 +44,8 @@ export function FileContextMenu({ {relativePath && ( { - navigator.clipboard.writeText(relativePath); + onSelect={async () => { + await copyToClipboard(relativePath); toast.success("Relative path copied"); }} > diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx index de25fe6bb8f..51b7b9d8cbb 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx @@ -4,6 +4,7 @@ import { ContextMenuSeparator, } from "@superset/ui/context-menu"; import { toast } from "@superset/ui/sonner"; +import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; import { electronTrpcClient } from "renderer/lib/trpc-client"; interface FolderContextMenuProps { @@ -23,6 +24,8 @@ export function FolderContextMenu({ onRename, onDelete, }: FolderContextMenuProps) { + const { copyToClipboard } = useCopyToClipboard(); + return ( setTimeout(onNewFile, 0)}> @@ -41,8 +44,8 @@ export function FolderContextMenu({ { - navigator.clipboard.writeText(absolutePath); + onSelect={async () => { + await copyToClipboard(absolutePath); toast.success("Path copied"); }} > @@ -50,8 +53,8 @@ export function FolderContextMenu({ {relativePath && ( { - navigator.clipboard.writeText(relativePath); + onSelect={async () => { + await copyToClipboard(relativePath); toast.success("Relative path copied"); }} > From 2f53c30b1954189221007c19d8c137a9cb94b631 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 14 Apr 2026 16:56:43 -0700 Subject: [PATCH 2/5] feat(desktop): wire up Copy Path in v2 dashboard sidebar The workspace item context menu's Copy Path just toasted "coming soon". Fetch the worktreePath from the local host service for local workspaces, copy via electronTrpc.external.copyPath (native clipboard), and show a proper success toast. Non-local workspaces fall back to an explanatory error since the path only exists on the owning machine. --- .../DashboardSidebarWorkspaceItem.tsx | 1 + ...useDashboardSidebarWorkspaceItemActions.ts | 34 +++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx index 9b2b2b4e551..2269d697c5f 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx @@ -54,6 +54,7 @@ export function DashboardSidebarWorkspaceItem({ workspaceId: id, projectId, workspaceName: name, + hostType, }); const navigate = useNavigate(); diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts index 629300efa25..45874018b71 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts @@ -1,27 +1,35 @@ import { toast } from "@superset/ui/sonner"; import { useMatchRoute, useNavigate } from "@tanstack/react-router"; import { useState } from "react"; +import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; import { apiTrpcClient } from "renderer/lib/api-trpc-client"; +import { getHostServiceClientByUrl } from "renderer/lib/host-service-client"; import { getDeleteFocusTargetWorkspaceId } from "renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/utils/getDeleteFocusTargetWorkspaceId"; import { getFlattenedV2WorkspaceIds } from "renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/utils/getFlattenedV2WorkspaceIds"; import { navigateToV2Workspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation"; import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState"; import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider"; +import { useLocalHostService } from "renderer/routes/_authenticated/providers/LocalHostServiceProvider"; +import type { DashboardSidebarWorkspaceHostType } from "../../../../types"; interface UseDashboardSidebarWorkspaceItemActionsOptions { workspaceId: string; projectId: string; workspaceName: string; + hostType: DashboardSidebarWorkspaceHostType; } export function useDashboardSidebarWorkspaceItemActions({ workspaceId, projectId, workspaceName, + hostType, }: UseDashboardSidebarWorkspaceItemActionsOptions) { const navigate = useNavigate(); const matchRoute = useMatchRoute(); const collections = useCollections(); + const { activeHostUrl } = useLocalHostService(); + const { copyToClipboard } = useCopyToClipboard(); const { createSection, moveWorkspaceToSection, removeWorkspaceFromSidebar } = useDashboardSidebarState(); @@ -110,8 +118,30 @@ export function useDashboardSidebarWorkspaceItemActions({ toast.info("Open in Finder is coming soon"); }; - const handleCopyPath = () => { - toast.info("Copy Path is coming soon"); + const handleCopyPath = async () => { + if (hostType !== "local-device") { + toast.error("Copy Path is only available for local workspaces"); + return; + } + if (!activeHostUrl) { + toast.error("Host service is not available"); + return; + } + try { + const workspace = await getHostServiceClientByUrl( + activeHostUrl, + ).workspace.get.query({ id: workspaceId }); + if (!workspace?.worktreePath) { + toast.error("Workspace path is not available"); + return; + } + await copyToClipboard(workspace.worktreePath); + toast.success("Path copied"); + } catch (error) { + toast.error( + `Failed to copy path: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } }; return { From d017c8410f2c37f2dde38ffff6b784626d5515e3 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 14 Apr 2026 16:58:15 -0700 Subject: [PATCH 3/5] feat(desktop): wire up Open in Finder in v2 dashboard sidebar Share the local worktreePath resolver between Copy Path and Open in Finder, and route Open in Finder through electronTrpc.external.openInFinder instead of toasting "coming soon". --- ...useDashboardSidebarWorkspaceItemActions.ts | 47 ++++++++++++------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts index 45874018b71..f04178b0aa8 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts @@ -4,6 +4,7 @@ import { useState } from "react"; import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; import { apiTrpcClient } from "renderer/lib/api-trpc-client"; import { getHostServiceClientByUrl } from "renderer/lib/host-service-client"; +import { electronTrpcClient } from "renderer/lib/trpc-client"; import { getDeleteFocusTargetWorkspaceId } from "renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/utils/getDeleteFocusTargetWorkspaceId"; import { getFlattenedV2WorkspaceIds } from "renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/utils/getFlattenedV2WorkspaceIds"; import { navigateToV2Workspace } from "renderer/routes/_authenticated/_dashboard/utils/workspace-navigation"; @@ -114,28 +115,42 @@ export function useDashboardSidebarWorkspaceItemActions({ moveWorkspaceToSection(workspaceId, projectId, newSectionId); }; - const handleOpenInFinder = () => { - toast.info("Open in Finder is coming soon"); - }; - - const handleCopyPath = async () => { + const resolveWorktreePath = async (): Promise => { if (hostType !== "local-device") { - toast.error("Copy Path is only available for local workspaces"); - return; + toast.error("Only available for local workspaces"); + return null; } if (!activeHostUrl) { toast.error("Host service is not available"); - return; + return null; + } + const workspace = await getHostServiceClientByUrl( + activeHostUrl, + ).workspace.get.query({ id: workspaceId }); + if (!workspace?.worktreePath) { + toast.error("Workspace path is not available"); + return null; } + return workspace.worktreePath; + }; + + const handleOpenInFinder = async () => { try { - const workspace = await getHostServiceClientByUrl( - activeHostUrl, - ).workspace.get.query({ id: workspaceId }); - if (!workspace?.worktreePath) { - toast.error("Workspace path is not available"); - return; - } - await copyToClipboard(workspace.worktreePath); + const path = await resolveWorktreePath(); + if (!path) return; + await electronTrpcClient.external.openInFinder.mutate(path); + } catch (error) { + toast.error( + `Failed to open in Finder: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + }; + + const handleCopyPath = async () => { + try { + const path = await resolveWorktreePath(); + if (!path) return; + await copyToClipboard(path); toast.success("Path copied"); } catch (error) { toast.error( From 4405ddcc391ce46d6db3cf460320e970752e87ec Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 14 Apr 2026 17:31:52 -0700 Subject: [PATCH 4/5] refactor(desktop): extract shared PathActionsMenuItems, wrap copy in try/catch Addresses review feedback on PR #3462: - Pulled the Reveal in Finder / Copy Path / Copy Relative Path items shared between FileContextMenu and FolderContextMenu into a single PathActionsMenuItems component. - Wrap useCopyToClipboard calls in try/catch so IPC failures surface a proper error toast instead of failing silently. --- .../FileContextMenu/FileContextMenu.tsx | 36 ++----------- .../FolderContextMenu/FolderContextMenu.tsx | 36 ++----------- .../PathActionsMenuItems.tsx | 53 +++++++++++++++++++ .../components/PathActionsMenuItems/index.ts | 1 + 4 files changed, 64 insertions(+), 62 deletions(-) create mode 100644 apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx create mode 100644 apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/index.ts diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx index 71674badde3..7c4ff4168d8 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FileContextMenu/FileContextMenu.tsx @@ -3,9 +3,7 @@ import { ContextMenuItem, ContextMenuSeparator, } from "@superset/ui/context-menu"; -import { toast } from "@superset/ui/sonner"; -import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; -import { electronTrpcClient } from "renderer/lib/trpc-client"; +import { PathActionsMenuItems } from "../PathActionsMenuItems"; interface FileContextMenuProps { absolutePath: string; @@ -20,38 +18,14 @@ export function FileContextMenu({ onRename, onDelete, }: FileContextMenuProps) { - const { copyToClipboard } = useCopyToClipboard(); - return ( Open to the Side - - electronTrpcClient.external.openInFinder.mutate(absolutePath) - } - > - Reveal in Finder - - - { - await copyToClipboard(absolutePath); - toast.success("Path copied"); - }} - > - Copy Path - - {relativePath && ( - { - await copyToClipboard(relativePath); - toast.success("Relative path copied"); - }} - > - Copy Relative Path - - )} + setTimeout(onRename, 0)}> Rename... diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx index 51b7b9d8cbb..119e2eb84fe 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/FolderContextMenu/FolderContextMenu.tsx @@ -3,9 +3,7 @@ import { ContextMenuItem, ContextMenuSeparator, } from "@superset/ui/context-menu"; -import { toast } from "@superset/ui/sonner"; -import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; -import { electronTrpcClient } from "renderer/lib/trpc-client"; +import { PathActionsMenuItems } from "../PathActionsMenuItems"; interface FolderContextMenuProps { absolutePath: string; @@ -24,8 +22,6 @@ export function FolderContextMenu({ onRename, onDelete, }: FolderContextMenuProps) { - const { copyToClipboard } = useCopyToClipboard(); - return ( setTimeout(onNewFile, 0)}> @@ -35,32 +31,10 @@ export function FolderContextMenu({ New Folder... - - electronTrpcClient.external.openInFinder.mutate(absolutePath) - } - > - Reveal in Finder - - - { - await copyToClipboard(absolutePath); - toast.success("Path copied"); - }} - > - Copy Path - - {relativePath && ( - { - await copyToClipboard(relativePath); - toast.success("Relative path copied"); - }} - > - Copy Relative Path - - )} + setTimeout(onRename, 0)}> Rename... diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx new file mode 100644 index 00000000000..4dc0b2ff9c7 --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx @@ -0,0 +1,53 @@ +import { + ContextMenuItem, + ContextMenuSeparator, +} from "@superset/ui/context-menu"; +import { toast } from "@superset/ui/sonner"; +import { useCopyToClipboard } from "renderer/hooks/useCopyToClipboard"; +import { electronTrpcClient } from "renderer/lib/trpc-client"; + +interface PathActionsMenuItemsProps { + absolutePath: string; + relativePath?: string; +} + +export function PathActionsMenuItems({ + absolutePath, + relativePath, +}: PathActionsMenuItemsProps) { + const { copyToClipboard } = useCopyToClipboard(); + + const handleCopy = async (path: string, successMessage: string) => { + try { + await copyToClipboard(path); + toast.success(successMessage); + } catch (error) { + toast.error( + `Failed to copy path: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + }; + + return ( + <> + + electronTrpcClient.external.openInFinder.mutate(absolutePath) + } + > + Reveal in Finder + + + handleCopy(absolutePath, "Path copied")}> + Copy Path + + {relativePath && ( + handleCopy(relativePath, "Relative path copied")} + > + Copy Relative Path + + )} + + ); +} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/index.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/index.ts new file mode 100644 index 00000000000..2f4345f1fcd --- /dev/null +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/index.ts @@ -0,0 +1 @@ +export { PathActionsMenuItems } from "./PathActionsMenuItems"; From 53804218827bdfc018afcf1443e34094afd26f80 Mon Sep 17 00:00:00 2001 From: Kiet Ho Date: Tue, 14 Apr 2026 17:44:59 -0700 Subject: [PATCH 5/5] refactor(desktop): hide Open in Finder & Copy Path for non-local workspaces - Gate the Open in Finder / Copy Path items in the dashboard sidebar workspace context menu behind isLocalWorkspace so they only appear for workspaces on the active machine. - Drop the now-redundant hostType guard from the actions hook. - Wrap openInFinder in try/catch in PathActionsMenuItems so native action failures surface a toast (addresses coderabbit/cubic P2 on #3462). --- .../DashboardSidebarWorkspaceItem.tsx | 3 ++- .../DashboardSidebarWorkspaceContextMenu.tsx | 24 ++++++++++++------- ...useDashboardSidebarWorkspaceItemActions.ts | 7 ------ .../PathActionsMenuItems.tsx | 16 +++++++++---- 4 files changed, 28 insertions(+), 22 deletions(-) diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx index 2269d697c5f..0f3d5435f2e 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/DashboardSidebarWorkspaceItem.tsx @@ -54,7 +54,6 @@ export function DashboardSidebarWorkspaceItem({ workspaceId: id, projectId, workspaceName: name, - hostType, }); const navigate = useNavigate(); @@ -108,6 +107,7 @@ export function DashboardSidebarWorkspaceItem({ diffStats={diffStats} /> } + isLocalWorkspace={hostType === "local-device"} onCreateSection={handleCreateSection} onMoveToSection={(targetSectionId) => moveWorkspaceToSection(id, projectId, targetSectionId) @@ -173,6 +173,7 @@ export function DashboardSidebarWorkspaceItem({ onMoveToSection={(targetSectionId) => moveWorkspaceToSection(id, projectId, targetSectionId) } + isLocalWorkspace={hostType === "local-device"} onOpenInFinder={handleOpenInFinder} onCopyPath={handleCopyPath} onRemoveFromSidebar={() => removeWorkspaceFromSidebar(id)} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx index 18872835fa0..29e5e6d1d94 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/components/DashboardSidebarWorkspaceContextMenu/DashboardSidebarWorkspaceContextMenu.tsx @@ -32,6 +32,7 @@ interface DashboardSidebarWorkspaceContextMenuProps { hoverCardContent?: React.ReactNode; projectId: string; isInSection?: boolean; + isLocalWorkspace: boolean; onHoverCardOpen?: () => void; onCreateSection: () => void; onMoveToSection: (sectionId: string | null) => void; @@ -46,6 +47,7 @@ interface DashboardSidebarWorkspaceContextMenuProps { export function DashboardSidebarWorkspaceContextMenu({ projectId, isInSection, + isLocalWorkspace, onHoverCardOpen, hoverCardContent, onCreateSection, @@ -81,15 +83,19 @@ export function DashboardSidebarWorkspaceContextMenu({ Rename - - - - Open in Finder - - - - Copy Path - + {isLocalWorkspace && ( + <> + + + + Open in Finder + + + + Copy Path + + + )} diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts index f04178b0aa8..8e41962d19b 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/components/DashboardSidebar/components/DashboardSidebarWorkspaceItem/hooks/useDashboardSidebarWorkspaceItemActions/useDashboardSidebarWorkspaceItemActions.ts @@ -11,20 +11,17 @@ import { navigateToV2Workspace } from "renderer/routes/_authenticated/_dashboard import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState"; import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider"; import { useLocalHostService } from "renderer/routes/_authenticated/providers/LocalHostServiceProvider"; -import type { DashboardSidebarWorkspaceHostType } from "../../../../types"; interface UseDashboardSidebarWorkspaceItemActionsOptions { workspaceId: string; projectId: string; workspaceName: string; - hostType: DashboardSidebarWorkspaceHostType; } export function useDashboardSidebarWorkspaceItemActions({ workspaceId, projectId, workspaceName, - hostType, }: UseDashboardSidebarWorkspaceItemActionsOptions) { const navigate = useNavigate(); const matchRoute = useMatchRoute(); @@ -116,10 +113,6 @@ export function useDashboardSidebarWorkspaceItemActions({ }; const resolveWorktreePath = async (): Promise => { - if (hostType !== "local-device") { - toast.error("Only available for local workspaces"); - return null; - } if (!activeHostUrl) { toast.error("Host service is not available"); return null; diff --git a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx index 4dc0b2ff9c7..c1bf48057ba 100644 --- a/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx +++ b/apps/desktop/src/renderer/routes/_authenticated/_dashboard/v2-workspace/$workspaceId/components/WorkspaceSidebar/components/FilesTab/components/WorkspaceFilesTreeItem/components/PathActionsMenuItems/PathActionsMenuItems.tsx @@ -28,13 +28,19 @@ export function PathActionsMenuItems({ } }; + const handleRevealInFinder = async () => { + try { + await electronTrpcClient.external.openInFinder.mutate(absolutePath); + } catch (error) { + toast.error( + `Failed to reveal in Finder: ${error instanceof Error ? error.message : "Unknown error"}`, + ); + } + }; + return ( <> - - electronTrpcClient.external.openInFinder.mutate(absolutePath) - } - > + Reveal in Finder