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..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
@@ -107,6 +107,7 @@ export function DashboardSidebarWorkspaceItem({
diffStats={diffStats}
/>
}
+ isLocalWorkspace={hostType === "local-device"}
onCreateSection={handleCreateSection}
onMoveToSection={(targetSectionId) =>
moveWorkspaceToSection(id, projectId, targetSectionId)
@@ -172,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 629300efa25..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
@@ -1,12 +1,16 @@
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 { 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";
import { useDashboardSidebarState } from "renderer/routes/_authenticated/hooks/useDashboardSidebarState";
import { useCollections } from "renderer/routes/_authenticated/providers/CollectionsProvider";
+import { useLocalHostService } from "renderer/routes/_authenticated/providers/LocalHostServiceProvider";
interface UseDashboardSidebarWorkspaceItemActionsOptions {
workspaceId: string;
@@ -22,6 +26,8 @@ export function useDashboardSidebarWorkspaceItemActions({
const navigate = useNavigate();
const matchRoute = useMatchRoute();
const collections = useCollections();
+ const { activeHostUrl } = useLocalHostService();
+ const { copyToClipboard } = useCopyToClipboard();
const { createSection, moveWorkspaceToSection, removeWorkspaceFromSidebar } =
useDashboardSidebarState();
@@ -106,12 +112,44 @@ export function useDashboardSidebarWorkspaceItemActions({
moveWorkspaceToSection(workspaceId, projectId, newSectionId);
};
- const handleOpenInFinder = () => {
- toast.info("Open in Finder is coming soon");
+ const resolveWorktreePath = async (): Promise => {
+ if (!activeHostUrl) {
+ toast.error("Host service is not available");
+ 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 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 = () => {
- toast.info("Copy Path is coming soon");
+ const handleCopyPath = async () => {
+ try {
+ const path = await resolveWorktreePath();
+ if (!path) return;
+ await copyToClipboard(path);
+ toast.success("Path copied");
+ } catch (error) {
+ toast.error(
+ `Failed to copy path: ${error instanceof Error ? error.message : "Unknown error"}`,
+ );
+ }
};
return {
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..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,8 +3,7 @@ import {
ContextMenuItem,
ContextMenuSeparator,
} from "@superset/ui/context-menu";
-import { toast } from "@superset/ui/sonner";
-import { electronTrpcClient } from "renderer/lib/trpc-client";
+import { PathActionsMenuItems } from "../PathActionsMenuItems";
interface FileContextMenuProps {
absolutePath: string;
@@ -23,32 +22,10 @@ export function FileContextMenu({
Open to the Side
-
- electronTrpcClient.external.openInFinder.mutate(absolutePath)
- }
- >
- Reveal in Finder
-
-
- {
- navigator.clipboard.writeText(absolutePath);
- toast.success("Path copied");
- }}
- >
- Copy Path
-
- {relativePath && (
- {
- navigator.clipboard.writeText(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 de25fe6bb8f..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,8 +3,7 @@ import {
ContextMenuItem,
ContextMenuSeparator,
} from "@superset/ui/context-menu";
-import { toast } from "@superset/ui/sonner";
-import { electronTrpcClient } from "renderer/lib/trpc-client";
+import { PathActionsMenuItems } from "../PathActionsMenuItems";
interface FolderContextMenuProps {
absolutePath: string;
@@ -32,32 +31,10 @@ export function FolderContextMenu({
New Folder...
-
- electronTrpcClient.external.openInFinder.mutate(absolutePath)
- }
- >
- Reveal in Finder
-
-
- {
- navigator.clipboard.writeText(absolutePath);
- toast.success("Path copied");
- }}
- >
- Copy Path
-
- {relativePath && (
- {
- navigator.clipboard.writeText(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..c1bf48057ba
--- /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,59 @@
+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"}`,
+ );
+ }
+ };
+
+ 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 (
+ <>
+
+ 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";