From 16270e4b03a4fc90629b5085074baaf1485935bb Mon Sep 17 00:00:00 2001 From: Bohdan Triapitsyn Date: Tue, 14 Apr 2026 19:33:09 +0300 Subject: [PATCH] fix: restore desktop window dragging on remote instances - Fixes header drag behavior in Desktop when connected to remote hosts - Routes all window-drag entry points through a shared safe desktop helper - Keeps local desktop drag behavior unchanged while avoiding remote IPC failures --- packages/ui/src/components/layout/Header.tsx | 10 ++-------- .../ui/src/components/layout/RightSidebar.tsx | 10 ++-------- .../src/components/multirun/MultiRunLauncher.tsx | 10 ++-------- .../components/onboarding/OnboardingScreen.tsx | 12 +++--------- .../ui/src/components/session/SessionSidebar.tsx | 10 ++-------- packages/ui/src/lib/desktop.ts | 15 +++++++++++++++ 6 files changed, 26 insertions(+), 41 deletions(-) diff --git a/packages/ui/src/components/layout/Header.tsx b/packages/ui/src/components/layout/Header.tsx index 36efaf72..53a0416e 100644 --- a/packages/ui/src/components/layout/Header.tsx +++ b/packages/ui/src/components/layout/Header.tsx @@ -62,7 +62,7 @@ import type { SessionContextUsage } from '@/stores/types/sessionTypes'; import { DesktopHostSwitcherDialog } from '@/components/desktop/DesktopHostSwitcher'; import { OpenInAppButton } from '@/components/desktop/OpenInAppButton'; import { ProjectActionsButton } from '@/components/layout/ProjectActionsButton'; -import { isDesktopShell, isVSCodeRuntime } from '@/lib/desktop'; +import { isDesktopShell, isVSCodeRuntime, startDesktopWindowDrag } from '@/lib/desktop'; import { desktopHostsGet, locationMatchesHost, redactSensitiveUrl } from '@/lib/desktopHosts'; import { resolveSessionDiffStats } from '@/components/session/sidebar/utils'; import type { Session } from '@opencode-ai/sdk/v2/client'; @@ -1405,13 +1405,7 @@ export const Header: React.FC = ({ return; } if (isDesktopApp) { - try { - const { getCurrentWindow } = await import('@tauri-apps/api/window'); - const window = getCurrentWindow(); - await window.startDragging(); - } catch (error) { - console.error('Failed to start window dragging:', error); - } + await startDesktopWindowDrag(); } }, [isDesktopApp]); diff --git a/packages/ui/src/components/layout/RightSidebar.tsx b/packages/ui/src/components/layout/RightSidebar.tsx index 65d95bce..3780c6fe 100644 --- a/packages/ui/src/components/layout/RightSidebar.tsx +++ b/packages/ui/src/components/layout/RightSidebar.tsx @@ -1,7 +1,7 @@ import React from 'react'; import { cn } from '@/lib/utils'; import { useUIStore } from '@/stores/useUIStore'; -import { isDesktopShell } from '@/lib/desktop'; +import { isDesktopShell, startDesktopWindowDrag } from '@/lib/desktop'; export const RIGHT_SIDEBAR_CONTENT_WIDTH = 420; const RIGHT_SIDEBAR_MIN_WIDTH = 400; @@ -123,13 +123,7 @@ export const RightSidebar: React.FC = ({ isOpen, children, cl return; } - try { - const { getCurrentWindow } = await import('@tauri-apps/api/window'); - const appWindow = getCurrentWindow(); - await appWindow.startDragging(); - } catch (error) { - console.error('Failed to start window dragging:', error); - } + await startDesktopWindowDrag(); }, [isDesktopApp]); return ( diff --git a/packages/ui/src/components/multirun/MultiRunLauncher.tsx b/packages/ui/src/components/multirun/MultiRunLauncher.tsx index b96a9e00..b2413a95 100644 --- a/packages/ui/src/components/multirun/MultiRunLauncher.tsx +++ b/packages/ui/src/components/multirun/MultiRunLauncher.tsx @@ -19,7 +19,7 @@ import type { CreateMultiRunParams, MultiRunModelSelection } from '@/types/multi import { ModelMultiSelect, generateInstanceId, type ModelSelectionWithId } from './ModelMultiSelect'; import { BranchSelector, useBranchOptions } from './BranchSelector'; import { AgentSelector } from './AgentSelector'; -import { isDesktopShell } from '@/lib/desktop'; +import { isDesktopShell, startDesktopWindowDrag } from '@/lib/desktop'; import { useThemeSystem } from '@/contexts/useThemeSystem'; import { PROJECT_ICON_MAP, PROJECT_COLOR_MAP, getProjectIconImageUrl } from '@/lib/projectMeta'; import type { ProjectEntry } from '@/lib/api/types'; @@ -266,13 +266,7 @@ export const MultiRunLauncher: React.FC = ({ return; } if (isDesktopApp) { - try { - const { getCurrentWindow } = await import('@tauri-apps/api/window'); - const window = getCurrentWindow(); - await window.startDragging(); - } catch { - // ignore - } + await startDesktopWindowDrag(); } }, [isDesktopApp]); diff --git a/packages/ui/src/components/onboarding/OnboardingScreen.tsx b/packages/ui/src/components/onboarding/OnboardingScreen.tsx index f08e4812..d07c3166 100644 --- a/packages/ui/src/components/onboarding/OnboardingScreen.tsx +++ b/packages/ui/src/components/onboarding/OnboardingScreen.tsx @@ -1,6 +1,6 @@ import React from 'react'; import { RiFileCopyLine, RiCheckLine, RiExternalLinkLine } from '@remixicon/react'; -import { isDesktopShell, isTauriShell } from '@/lib/desktop'; +import { isDesktopShell, isTauriShell, startDesktopWindowDrag } from '@/lib/desktop'; import { Input } from '@/components/ui/input'; import { Button } from '@/components/ui/button'; import { updateDesktopSettings } from '@/lib/persistence'; @@ -105,14 +105,8 @@ export function OnboardingScreen({ onCliAvailable }: OnboardingScreenProps) { return; } if (e.button !== 0) return; - if (isDesktopApp && isTauriShell()) { - try { - const { getCurrentWindow } = await import('@tauri-apps/api/window'); - const window = getCurrentWindow(); - await window.startDragging(); - } catch (error) { - console.error('Failed to start window dragging:', error); - } + if (isDesktopApp) { + await startDesktopWindowDrag(); } }, [isDesktopApp]); diff --git a/packages/ui/src/components/session/SessionSidebar.tsx b/packages/ui/src/components/session/SessionSidebar.tsx index 878eaf67..a1e5838c 100644 --- a/packages/ui/src/components/session/SessionSidebar.tsx +++ b/packages/ui/src/components/session/SessionSidebar.tsx @@ -3,7 +3,7 @@ import type { Session } from '@opencode-ai/sdk/v2'; import { RiLayoutLeftLine } from '@remixicon/react'; import { toast } from '@/components/ui'; import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip'; -import { isDesktopLocalOriginActive, isDesktopShell, isTauriShell } from '@/lib/desktop'; +import { isDesktopLocalOriginActive, isDesktopShell, isTauriShell, startDesktopWindowDrag } from '@/lib/desktop'; import { MobileOverlayPanel } from '@/components/ui/MobileOverlayPanel'; import { sessionEvents } from '@/lib/sessionEvents'; import { formatDirectoryName, cn } from '@/lib/utils'; @@ -490,13 +490,7 @@ export const SessionSidebar: React.FC = ({ return; } - try { - const { getCurrentWindow } = await import('@tauri-apps/api/window'); - const appWindow = getCurrentWindow(); - await appWindow.startDragging(); - } catch (error) { - console.error('Failed to start window dragging:', error); - } + await startDesktopWindowDrag(); }, [isDesktopShellRuntime]); const { diff --git a/packages/ui/src/lib/desktop.ts b/packages/ui/src/lib/desktop.ts index 36e3b026..e7655a68 100644 --- a/packages/ui/src/lib/desktop.ts +++ b/packages/ui/src/lib/desktop.ts @@ -242,6 +242,21 @@ export const isDesktopShell = (): boolean => { return isTauriShell(); }; +export const startDesktopWindowDrag = async (): Promise => { + if (!isDesktopShell() || !isTauriShell()) { + return false; + } + + try { + const { getCurrentWindow } = await import('@tauri-apps/api/window'); + const appWindow = getCurrentWindow(); + await appWindow.startDragging(); + return true; + } catch { + return false; + } +}; + export const isVSCodeRuntime = (): boolean => { if (typeof window === "undefined") return false; const apis = (window as { __OPENCHAMBER_RUNTIME_APIS__?: { runtime?: { isVSCode?: boolean } } }).__OPENCHAMBER_RUNTIME_APIS__;