From 6933d3aa882c80437592681127dbac99e726cb53 Mon Sep 17 00:00:00 2001 From: Federico Jaramillo Martinez Date: Tue, 23 Jun 2026 15:01:05 +0200 Subject: [PATCH] fix: guard stale mobile navigation focus --- .changeset/guard-mobile-navigation-focus.md | 5 +++++ src/client/src/components/PiWebApp.ts | 14 ++++++++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 .changeset/guard-mobile-navigation-focus.md diff --git a/.changeset/guard-mobile-navigation-focus.md b/.changeset/guard-mobile-navigation-focus.md new file mode 100644 index 0000000..f49868e --- /dev/null +++ b/.changeset/guard-mobile-navigation-focus.md @@ -0,0 +1,5 @@ +--- +"@jmfederico/pi-web": patch +--- + +Keep mobile navigation on the selected session when remote workspace loading finishes out of order. diff --git a/src/client/src/components/PiWebApp.ts b/src/client/src/components/PiWebApp.ts index 47014c3..a662288 100644 --- a/src/client/src/components/PiWebApp.ts +++ b/src/client/src/components/PiWebApp.ts @@ -152,6 +152,7 @@ export class PiWebApp extends LitElement { private readonly handledWorkspaceDeletionRunIds = new Set(); private readonly terminalCommandRunRuntimes = new Map(); private machineNavigationRestoreSeq = 0; + private navigationSelectionSeq = 0; private routeRestoreSeq = 0; private routeRestoreDepth = 0; private restoringRouteTerminalId: string | undefined; @@ -575,12 +576,16 @@ export class PiWebApp extends LitElement { if (tool === "core:workspace.git") await this.git.refreshGit(); } - private async withChatScrollTransition(action: () => Promise) { + private async withChatScrollTransition(action: () => Promise, shouldComplete: () => boolean = () => true) { this.chatView?.saveScrollPosition(); await action(); + if (!shouldComplete()) return; await this.updateComplete; + if (!shouldComplete()) return; await this.chatView?.updateComplete; + if (!shouldComplete()) return; await nextFrame(); + if (!shouldComplete()) return; this.chatView?.restoreScrollPosition(); if (this.shouldAutoFocusPrompt()) this.promptEditor?.focusInput(); } @@ -1086,10 +1091,15 @@ export class PiWebApp extends LitElement { } private async selectNavigationItem(section: NavigationSection, nextTarget: NavigationFocusTarget, action: () => Promise): Promise { + const seq = ++this.navigationSelectionSeq; + const isCurrentSelection = () => seq === this.navigationSelectionSeq; + await this.withChatScrollTransition(async () => { this.navigationSections.advanceAfterSelection(section); await action(); - }); + }, isCurrentSelection); + + if (!isCurrentSelection()) return; await this.focusNavigationTarget(nextTarget); }