From a4c17f08b173750e80bc0b8aa95e2d39cf5e1413 Mon Sep 17 00:00:00 2001 From: usrnk1 <7547651+usrnk1@users.noreply.github.com> Date: Thu, 9 Jul 2026 07:41:56 +0200 Subject: [PATCH] feat(desktop): reveal projects in file manager (#35731) --- .../src/components/session/session-header.tsx | 7 ++---- packages/app/src/i18n/en.ts | 3 +++ packages/app/src/pages/home.tsx | 18 ++++++++++++++ packages/app/src/utils/file-manager.ts | 24 +++++++++++++++++++ 4 files changed, 47 insertions(+), 5 deletions(-) create mode 100644 packages/app/src/utils/file-manager.ts diff --git a/packages/app/src/components/session/session-header.tsx b/packages/app/src/components/session/session-header.tsx index 500cce7def1..da1770cd130 100644 --- a/packages/app/src/components/session/session-header.tsx +++ b/packages/app/src/components/session/session-header.tsx @@ -24,6 +24,7 @@ import { focusTerminalById } from "@/pages/session/helpers" import { useSessionLayout } from "@/pages/session/session-layout" import { messageAgentColor } from "@/utils/agent" import { decode64 } from "@/utils/base64" +import { fileManagerApp } from "@/utils/file-manager" import { Persist, persisted } from "@/utils/persist" import { StatusPopover, StatusPopoverV2 } from "../status-popover" import { IconButtonV2 } from "@opencode-ai/ui/v2/icon-button-v2" @@ -175,11 +176,7 @@ export function SessionHeader() { return LINUX_APPS }) - const fileManager = createMemo(() => { - if (os() === "macos") return { label: "session.header.open.finder", icon: "finder" as const } - if (os() === "windows") return { label: "session.header.open.fileExplorer", icon: "file-explorer" as const } - return { label: "session.header.open.fileManager", icon: "finder" as const } - }) + const fileManager = createMemo(() => fileManagerApp(os())) createEffect(() => { if (platform.platform !== "desktop") return diff --git a/packages/app/src/i18n/en.ts b/packages/app/src/i18n/en.ts index f44af82297b..9d122447a8d 100644 --- a/packages/app/src/i18n/en.ts +++ b/packages/app/src/i18n/en.ts @@ -709,6 +709,9 @@ export const dict = { "session.header.open.finder": "Finder", "session.header.open.fileExplorer": "File Explorer", "session.header.open.fileManager": "File Manager", + "session.header.reveal.finder": "Reveal in Finder", + "session.header.reveal.fileExplorer": "Reveal in File Explorer", + "session.header.reveal.containingFolder": "Open containing folder", "session.header.open.app.vscode": "VS Code", "session.header.open.app.cursor": "Cursor", "session.header.open.app.zed": "Zed", diff --git a/packages/app/src/pages/home.tsx b/packages/app/src/pages/home.tsx index c4d84a96f84..4ae787964a8 100644 --- a/packages/app/src/pages/home.tsx +++ b/packages/app/src/pages/home.tsx @@ -68,6 +68,7 @@ import { preloadMarkdown } from "@opencode-ai/session-ui/markdown-cache" import { archiveHomeSession } from "./home-session-archive" import { shouldOpenSessionInBackground } from "./home-session-open" import { showToast } from "@/utils/toast" +import { fileManagerApp } from "@/utils/file-manager" const HOME_SESSION_LIMIT = 64 const HOME_SESSION_HEADER_STICKY_TOP = 12 @@ -1030,8 +1031,22 @@ function HomeProjectRow(props: { language: ReturnType }) { const global = useGlobal() + const platform = usePlatform() const serverUnreachable = () => global.servers.health[ServerConnection.key(props.server)]?.healthy === false const [state, setState] = createStore({ menuOpen: false }) + const canRevealInFileManager = () => + platform.platform === "desktop" && !!platform.openPath && ServerConnection.local(props.server) + const fileManagerActionLabel = () => + props.language.t(fileManagerApp(platform.platform === "desktop" ? platform.os ?? "unknown" : "unknown").actionLabel) + const revealInFileManager = () => { + if (!platform.openPath) return + platform.openPath(props.project.worktree).catch((err: unknown) => + showToast({ + title: props.language.t("common.requestFailed"), + description: errorMessage(err, props.language.t("common.requestFailed")), + }), + ) + } return (