diff --git a/packages/app/src/components/sidebar-workspace-list.tsx b/packages/app/src/components/sidebar-workspace-list.tsx
index c349487db..d988b880a 100644
--- a/packages/app/src/components/sidebar-workspace-list.tsx
+++ b/packages/app/src/components/sidebar-workspace-list.tsx
@@ -131,6 +131,7 @@ import {
getIsElectron,
} from "@/constants/platform";
import { getDesktopHost } from "@/desktop/host";
+import { OpenInFileManagerMenuItem } from "@/workspace/open-in-file-manager/menu-item";
const workspaceKeyExtractor = (workspace: SidebarWorkspacePlacement) => workspace.workspaceKey;
@@ -609,6 +610,10 @@ function ProjectKebabMenu({
{t("sidebar.project.actions.openNewWindow")}
) : null}
+
void;
}) {
+ const workspacePath = workspace.workspaceDirectory ?? workspace.projectRootPath;
const { t } = useTranslation();
const showShortcut = showShortcutBadge && shortcutNumber !== null;
const showKebab = Boolean(onArchive && (isHovered || isTouchPlatform));
@@ -698,6 +704,7 @@ function WorkspaceRowRightGroup({
archiveShortcutKeys={archiveShortcutKeys}
isPinned={isPinned}
onTogglePin={onTogglePin}
+ openInFileManagerPath={workspacePath}
/>
) : null}
diff --git a/packages/app/src/components/sidebar/sidebar-workspace-menu.tsx b/packages/app/src/components/sidebar/sidebar-workspace-menu.tsx
index e04fc7ab6..f31489d7b 100644
--- a/packages/app/src/components/sidebar/sidebar-workspace-menu.tsx
+++ b/packages/app/src/components/sidebar/sidebar-workspace-menu.tsx
@@ -13,6 +13,7 @@ import {
DropdownMenuTrigger,
} from "@/components/ui/dropdown-menu";
import { Shortcut } from "@/components/ui/shortcut";
+import { OpenInFileManagerMenuItem } from "@/workspace/open-in-file-manager/menu-item";
const foregroundColorMapping = (theme: Theme) => ({ color: theme.colors.foreground });
const foregroundMutedColorMapping = (theme: Theme) => ({
@@ -58,6 +59,7 @@ interface SidebarWorkspaceMenuProps {
archiveShortcutKeys?: ShortcutKey[][] | null;
isPinned?: boolean;
onTogglePin?: () => void;
+ openInFileManagerPath?: string | null;
}
export function SidebarWorkspaceMenu({
@@ -73,6 +75,7 @@ export function SidebarWorkspaceMenu({
archiveShortcutKeys,
isPinned,
onTogglePin,
+ openInFileManagerPath,
}: SidebarWorkspaceMenuProps) {
const { t } = useTranslation();
const archiveTrailing = useMemo(
@@ -137,6 +140,10 @@ export function SidebarWorkspaceMenu({
{isPinned ? t("sidebar.workspace.actions.unpin") : t("sidebar.workspace.actions.pin")}
) : null}
+
({
+ color: theme.colors.foregroundMuted,
+});
+
+const leadingIcon = ;
+
+export function OpenInFileManagerMenuItem({ path, testID }: OpenInFileManagerMenuItemProps) {
+ const { t } = useTranslation();
+ const toast = useToast();
+ const isElectron = getIsElectron();
+ const workspacePath = path?.trim() ?? "";
+ const { targets } = useDesktopOpenTargets({
+ isLocalExecution: isElectron && workspacePath.length > 0,
+ });
+ const fileManagerTarget = targets.find((target) => target.kind === "file-manager");
+
+ const openInFileManager = useCallback(() => {
+ if (!fileManagerTarget || workspacePath.length === 0) return;
+ void openDesktopTarget({
+ editorId: fileManagerTarget.id,
+ workspacePath,
+ }).catch((error) => {
+ console.warn("[open-in-file-manager] open failed", error);
+ toast.error(t("sidebar.project.actions.openFolderFailed"));
+ });
+ }, [fileManagerTarget, t, toast, workspacePath]);
+
+ if (!isElectron || !fileManagerTarget || workspacePath.length === 0) {
+ return null;
+ }
+
+ return (
+
+ {t("sidebar.project.actions.openFolder")}
+
+ );
+}