fix(ui): use SPA navigation for session links to preserve in-memory auth token#39650
fix(ui): use SPA navigation for session links to preserve in-memory auth token#39650byungsker wants to merge 1 commit intoopenclaw:mainfrom
Conversation
…uth token Session links in the sessions list and cron run history use a plain `<a href>` which triggers a full-page reload. Because the gateway auth token is intentionally kept in-memory only (not persisted to localStorage — see the comment in loadSettings()), it is lost on reload, causing an immediate WebSocket disconnect with 'disconnected (1008): device identity required'. Intercept left-clicks on these links to perform SPA navigation instead: update the session key, reset chat state, switch to the chat tab, and push a new history entry via pushState — mirroring the pattern already used by the sidebar tab links. Modifier-key clicks (Ctrl/Meta/Shift/Alt) still fall through to let the browser open a new tab normally. A new openSessionInChat() helper in app-render.helpers.ts encapsulates the SPA navigation logic. SessionsProps gains an optional onOpenSession callback; CronProps gains the same so cron run-history chat links are also fixed. Five tests added to sessions.test.ts covering the callback, modifier-key passthrough, and href presence for accessibility. Fixes openclaw#39611
Greptile SummaryThis PR fixes a real bug: session links in the Sessions list and Cron run-history were plain The fix intercepts left-clicks to perform SPA navigation instead, following the same guard pattern ( Key observations:
Confidence Score: 4/5
Last reviewed commit: d2a57fd |
| } | ||
| ${ | ||
| chatUrl | ||
| ? html`<div><a class="session-link" href=${chatUrl}>${t("cron.runEntry.openRunChat")}</a></div>` | ||
| ? html`<div><a | ||
| class="session-link" | ||
| href=${chatUrl} | ||
| @click=${(e: MouseEvent) => { | ||
| if ( | ||
| !onOpenSession || | ||
| !entry.sessionKey || | ||
| e.defaultPrevented || | ||
| e.button !== 0 || | ||
| e.metaKey || | ||
| e.ctrlKey || | ||
| e.shiftKey || | ||
| e.altKey | ||
| ) { | ||
| return; | ||
| } | ||
| e.preventDefault(); | ||
| onOpenSession(entry.sessionKey); | ||
| }} | ||
| >${t("cron.runEntry.openRunChat")}</a | ||
| ></div>` |
There was a problem hiding this comment.
No test coverage for cron session-link click handler
The equivalent click-handler logic in sessions.ts is covered by three new tests (happy path, modifier-key passthrough, href fallback), but no tests were added for the renderRun click handler in cron.ts. Given that this is the same fix applied to a second location, a parallel set of tests in cron.test.ts would give the same confidence that:
- A left-click calls
onOpenSessionwith the correct session key - Modifier-key clicks fall through to the browser
- The
hrefattribute is still present whenonOpenSessionis not provided
This is a style/coverage suggestion rather than a bug, but the asymmetry between the two views is worth addressing.
Prompt To Fix With AI
This is a comment left during a code review.
Path: ui/src/ui/views/cron.ts
Line: 1753-1776
Comment:
**No test coverage for cron session-link click handler**
The equivalent click-handler logic in `sessions.ts` is covered by three new tests (happy path, modifier-key passthrough, href fallback), but no tests were added for the `renderRun` click handler in `cron.ts`. Given that this is the same fix applied to a second location, a parallel set of tests in `cron.test.ts` would give the same confidence that:
- A left-click calls `onOpenSession` with the correct session key
- Modifier-key clicks fall through to the browser
- The `href` attribute is still present when `onOpenSession` is not provided
This is a style/coverage suggestion rather than a bug, but the asymmetry between the two views is worth addressing.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: d2a57fdf61
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| const url = new URL(window.location.href); | ||
| url.pathname = pathForTab("chat", state.basePath); | ||
| url.searchParams.set("session", key); | ||
| window.history.pushState({}, "", url.toString()); |
There was a problem hiding this comment.
Avoid pushing history state twice when opening a session
openSessionInChat already calls state.setTab("chat"), and setTab performs URL syncing via syncUrlWithTab(..., false), which itself does a history.pushState. The additional window.history.pushState here adds a duplicate history entry for the same destination, so clicking a session from Sessions/Cron requires two Back presses to return to the previous page.
Useful? React with 👍 / 👎.
|
Thanks for the focused fix here. I checked it against #40892, now merged to The merged fix makes the current-tab Control UI token survive same-tab reloads and navigation by storing it in Closing as superseded by #40892. Thanks again for jumping on the regression quickly. |
Problem
Session links in the sessions list and cron run history use a plain
<a href>which triggers a full-page reload. The gateway auth token is intentionally kept in-memory only (see the// Gateway auth is intentionally in-memory onlycomment inloadSettings()— it is explicitly set todefaults.tokenand never written to localStorage). When the page reloads, the token is gone, causing:Reproduces reliably with the tokenized URL flow (
openclaw dashboard --no-open).Root Cause
sessions.ts:247andcron.ts:1750render session links as plain<a href>:Clicking these causes a full-page reload. The token is not persisted to storage by design, so it is lost.
Fix
Intercept left-clicks to perform SPA navigation instead — mirroring the pattern already used by the sidebar tab links in
renderTab()(app-render.helpers.ts):app-render.helpers.ts— new exportedopenSessionInChat(state, key)helper that resets chat state, switches to the chat tab, and pushes apushStateURL update (preserving the in-memory token)views/sessions.ts— adds optionalonOpenSessiontoSessionsProps; session link click handler calls it instead of navigatingviews/cron.ts— sameonOpenSessionadded toCronPropsandrenderRun()for cron run-history chat linksapp-render.ts— passesonOpenSession: (key) => openSessionInChat(state, key)to both viewsModifier-key clicks (
Ctrl/Meta/Shift/Alt) still fall through so the browser can open a new tab normally.Tests
Five new tests in
sessions.test.ts:onOpenSessionis called with the correct session key on left-clickonOpenSession(passthrough to browser)hrefattribute is still present (accessibility / keyboard / middle-click)Fixes #39611