feat: Add desktop Open In button (#350)

* feat: add OpenInAppButton and macOS path opener

* feat: filter installed apps on macOS and use in OpenInAppButton

* feat: fetch and display macOS app icons in OpenInAppButton

* feat(desktop): cache and fetch installed macOS apps

* feat: add force refresh and retry for installed apps

* feat(OpenInAppButton): add Copy Path action in dropdown header

* feat: enhance caching mechanism for apps discovery

---------

Co-authored-by: Bohdan Triapitsyn <artmore@protonmail.com>
This commit is contained in:
Iuliia Ivashko
2026-02-08 04:32:14 +02:00
committed by GitHub
co-authored by Bohdan Triapitsyn
parent 9534e3d016
commit b432437b02
14 changed files with 1140 additions and 9 deletions
@@ -35,6 +35,7 @@ import { updateDesktopSettings } from '@/lib/persistence';
import type { UsageWindow } from '@/types';
import type { GitHubAuthStatus } from '@/lib/api/types';
import { DesktopHostSwitcherButton } from '@/components/desktop/DesktopHostSwitcher';
import { OpenInAppButton } from '@/components/desktop/OpenInAppButton';
import { isDesktopShell } from '@/lib/desktop';
const formatTime = (timestamp: number | null) => {
@@ -222,11 +223,24 @@ export const Header: React.FC = () => {
return sessions.find((s) => s.id === currentSessionId) ?? null;
}, [currentSessionId, sessions]);
const worktreePath = useSessionStore((state) => {
if (!currentSessionId) return '';
return state.worktreeMetadata.get(currentSessionId)?.path ?? '';
});
const worktreeDirectory = React.useMemo(() => {
return normalize(worktreePath || '');
}, [worktreePath]);
const sessionDirectory = React.useMemo(() => {
const raw = typeof currentSession?.directory === 'string' ? currentSession.directory : '';
return normalize(raw || '');
}, [currentSession?.directory]);
const openDirectory = React.useMemo(() => {
return worktreeDirectory || sessionDirectory;
}, [sessionDirectory, worktreeDirectory]);
const [planTabAvailable, setPlanTabAvailable] = React.useState(false);
const showPlanTab = planTabAvailable;
@@ -627,6 +641,7 @@ export const Header: React.FC = () => {
<div className="flex-1" />
<div className="flex items-center gap-1 pr-3">
<OpenInAppButton directory={openDirectory} className="mr-1" />
{isDesktopApp && (
<DesktopHostSwitcherButton headerIconButtonClass={headerIconButtonClass} />
)}