Skip to content

fix(ui): preserve session picker on empty search blur#87659

Closed
ryan4559 wants to merge 1 commit into
openclaw:mainfrom
ryan4559:fix/session-picker-empty-blur
Closed

fix(ui): preserve session picker on empty search blur#87659
ryan4559 wants to merge 1 commit into
openclaw:mainfrom
ryan4559:fix/session-picker-empty-blur

Conversation

@ryan4559

@ryan4559 ryan4559 commented May 28, 2026

Copy link
Copy Markdown
Contributor

Summary

What problem does this PR solve?

  • Fixes a Control UI bug where the chat session picker cannot switch sessions when the initially empty focused search input blurs before a picker option click completes.
  • Fixes the same empty-blur state transition breaking keyboard navigation from the search input into the picker controls.
  • Adds focused regression coverage for preserving picker state after empty blur and retaining native click activation.

Why does this matter now?

  • This is a user-visible regression reproducible in the shipped Control UI and currently blocks normal session switching in Chromium-based browsers.
  • Existing alternative fixes either change button activation semantics or rely on timing deferral, while this change addresses the destructive empty-query state transition directly.

What is the intended outcome?

  • When the picker opens with an empty search query, blurring the search input no longer clears the current picker result or destroys the available option controls.
  • When the query is non-empty, blur-triggered search continues to behave as before.
  • Existing native pointer and keyboard activation paths remain intact.

What is intentionally out of scope?

  • No changes to picker button activation events.
  • No broader refactor of session picker state management.
  • No changes to the native agent filter <select>, which uses a separate @change path and does not share this blur/search behavior.

What does success look like?

  • Mouse selection works after opening the picker with its initially empty focused search field.
  • Tab navigation and native keyboard activation remain usable.
  • Non-empty blur-triggered search and clearing search continue to work.
  • Regression tests fail without the fix and pass with it.

What should reviewers focus on?

  • Whether guarding the blur handler is the appropriate boundary for preserving explicit Enter/search-action behavior.
  • Whether the regression tests cover the destructive empty-blur path without changing native activation semantics.

AI-assisted: I used ChatGPT , Claude Code and Codex CLI to investigate the issue, prepare the source change and regression tests, and review validation steps. I manually verified the root cause, reviewed the final diff, ran the listed validation commands, and recorded before/after browser behavior using an isolated source-built test environment. I understand the change: the blur handler now skips applyChatSessionPickerSearch(state) only when the current query normalizes to empty, preventing the initial empty-picker result from being cleared while retaining explicit search and non-empty blur behavior.

Linked context

Which issue does this close?

Closes #87554

Was this requested by a maintainer or owner?

  • No. This is a focused fix for a reported and reproduced user-visible bug.

Real behavior proof (required for external PRs)

  • Behavior or issue addressed: The Control UI chat session picker fails to switch sessions when its initially empty focused search input blurs before a session option click completes. The same empty-blur path also prevents normal Tab navigation into the picker controls.

  • Real environment tested: Chromium on macOS, connected through VS Code port forwarding to an isolated picker-proof OpenClaw Gateway profile running from this source checkout inside a Dev Container on port 19789.

  • Exact steps or command run after this patch:

    pnpm ui:build
    pnpm openclaw --profile picker-proof setup
    export OPENCLAW_GATEWAY_TOKEN="$(openssl rand -hex 32)"
    pnpm openclaw --profile picker-proof gateway --port 19789 --verbose

    In the Control UI, I then:

    1. Opened the chat session picker with the initially empty search input focused.
    2. Clicked another session option.
    3. Reopened the picker and pressed Tab from the empty focused search input.
    4. Activated a session option through keyboard interaction.
    5. Entered a non-empty search query and blurred the input.
    6. Cleared the search and verified that the full session list returned.
  • Evidence after fix:

    Patch commit: 6c55ff0535 (6c55ff0 shown by the running source checkout)

after-fix-session-picker-empty-blur-guard.mp4
  • Observed result after fix:

    • Clicking another session while the initially empty search input is focused switches sessions successfully.
    • Pressing Tab from the initially empty focused search input preserves the picker controls and allows keyboard navigation.
    • Keyboard activation of a session option remains usable.
    • Blurring a non-empty search query still applies the search.
    • Clearing search restores the unfiltered session list.
  • What was not tested:

    • Mobile browser interaction.
    • Safari and Firefox behavior.
    • A production profile containing real user sessions or configured channels.
  • Proof limitations or environment constraints:

    • The browser proof used an isolated local Gateway profile with synthetic test sessions rather than an existing production profile.
    • The Gateway was run from a Dev Container with an ephemeral token for local port-forwarded browser access.
  • Before evidence:

    Base commit: e5a687f115

    Using the same isolated picker-proof profile and interaction flow on the direct parent commit, I reproduced:

    • clicking another session from the initially empty focused search state failing to switch sessions;
    • Tab navigation from the initially empty focused search input failing to move normally into picker controls.
before-fix-session-picker-blur-race.mp4

Tests and validation

Which commands did you run?

git diff --check upstream/main...HEAD
pnpm test ui/src/ui/views/chat.test.ts
pnpm check:changed
pnpm ui:build
pnpm build

Results:

  • git diff --check upstream/main...HEAD: passed.
  • pnpm test ui/src/ui/views/chat.test.ts: passed, 60/60 tests.
  • pnpm ui:build: passed and was used for the browser proof.
  • pnpm check:changed: fails only in the zero-diagnostic typecheck all lane; the identical failure reproduces on clean updated upstream/main without this patch.
  • pnpm build: attempted in the Dev Container, but tsdown was terminated with SIGKILL and emitted no source diagnostic. The focused Control UI build and focused test suite completed successfully.

What regression coverage was added or updated?

  • Added a regression test verifying that blurring an initially empty search input does not destroy/reset the picker result state or its option controls.
  • Added a regression test verifying that native session option click activation still works after the empty-input blur scenario.
  • Existing test coverage continues to verify that a non-empty query is applied on blur.

What failed before this fix, if known?

Red validation was performed by retaining the new regression tests while temporarily restoring the unpatched source behavior:

Tests: 2 failed, 58 passed

The failures confirmed that:

  • empty-input blur nullified chatSessionPickerResult;
  • session option buttons did not survive the destructive empty-blur re-render.

With the source fix restored:

Tests: 60 passed

If no test was added, why not?

  • Not applicable; focused regression tests were added.

Local AI review:

  • Ran codex review --base upstream/main.
  • Result: No discrete correctness issues were identified in the reviewed changes.

Risk checklist

Did user-visible behavior change? (Yes/No)

  • Yes. The session picker now remains interactive when its initially empty focused search input blurs.

Did config, environment, or migration behavior change? (Yes/No)

  • No.

Did security, auth, secrets, network, or tool execution behavior change? (Yes/No)

  • No.

What is the highest-risk area?

  • The highest-risk area is changing when blur-triggered search runs, because blur is also used to flush pending non-empty searches.

How is that risk mitigated?

  • The guard skips work only when chatSessionPickerQuery normalizes to empty.
  • Non-empty blur-triggered search behavior remains covered by existing tests.
  • New regression tests cover empty-blur state preservation and native session option activation.
  • Manual browser proof verifies mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clear-search behavior.

Current review state

What is the next action?

  • Await a fresh ClawSweeper review after the previous automated review timed out.

What is still waiting on author, maintainer, CI, or external proof?

  • ClawSweeper: re-review requested because the previous Codex-backed review timed out before evaluating the patch and attached proof.
  • CI: completed with failures that require separate triage.
  • Maintainer: review the blur-handler boundary and focused regression coverage after automated review completes.

Which bot or reviewer comments were addressed?

  • ClawSweeper's initial review did not complete because its internal Codex invocation timed out (spawnSync codex ETIMEDOUT); no code finding or inline review thread was produced.
  • Before opening this PR, I checked the issue comment suggesting a separate .value-bound session select path. In current source, desktop and mobile use the same session picker implementation covered by this fix; the .value-bound native select is the agent filter and does not call the picker search or clear functions.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@openclaw-barnacle openclaw-barnacle Bot added app: web-ui App: web-ui size: S proof: supplied External PR includes structured after-fix real behavior proof. labels May 28, 2026
@clawsweeper

clawsweeper Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

Codex review: needs maintainer review before merge. Reviewed May 28, 2026, 10:34 AM ET / 14:34 UTC.

Summary
The PR changes the Control UI chat session picker blur handler to skip applying search when the current query normalizes empty and adds regression tests for preserving picker options and click activation.

PR surface: Source +4, Tests +86. Total +90 across 2 files.

Reproducibility: yes. Source inspection shows the current empty-query blur path clears picker results while the picker stays open, and the linked issue plus before-proof recording show the session switch failing in the shipped UI; I did not run a live browser in this read-only review.

Review metrics: none identified.

Merge readiness
Overall: 🐚 platinum hermit
Proof: 🦞 diamond lobster ✨ media proof bonus
Patch quality: 🐚 platinum hermit
Result: ready for maintainer review.

Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch.

Rank-up moves:

  • [P2] Get the failing build/check lanes green or explicitly tied to an unrelated current-main failure before merge.

Risk before merge

  • [P1] Required build/check lanes are not all green yet; maintainers still need normal CI gate triage before merge.
  • [P1] The supplied browser proof covers Chromium on macOS and does not cover Safari, Firefox, mobile, or a production profile.

Maintainer options:

  1. Decide the mitigation before merge
    Land a focused Control UI fix like this after the normal CI and maintainer gates, then close the linked bug and let the older alternative PRs be superseded by the proof-backed path.
  2. Pause or close
    Do not merge this PR until maintainers decide whether the risk is worth taking.

Next step before merge

  • No ClawSweeper repair lane is needed because no discrete patch defect was found; the remaining actions are maintainer review and normal CI gate handling.

Security
Cleared: The diff touches one UI event handler and colocated tests only; it does not change dependencies, workflows, auth, secrets, package resolution, scripts, or network/tool execution surfaces.

Review details

Best possible solution:

Land a focused Control UI fix like this after the normal CI and maintainer gates, then close the linked bug and let the older alternative PRs be superseded by the proof-backed path.

Do we have a high-confidence way to reproduce the issue?

Yes. Source inspection shows the current empty-query blur path clears picker results while the picker stays open, and the linked issue plus before-proof recording show the session switch failing in the shipped UI; I did not run a live browser in this read-only review.

Is this the best way to solve the issue?

Yes. Guarding only the empty blur path is narrower than moving all picker actions to mousedown or deferring blur with requestAnimationFrame, and it preserves existing explicit search/clear and non-empty blur behavior with focused tests.

AGENTS.md: found and applied where relevant.

Codex review notes: model gpt-5.5, reasoning high; reviewed against 3fea2196923b.

Label changes

Label changes:

  • add P1: The PR fixes a user-visible Control UI regression that blocks normal chat session switching through the primary picker workflow.
  • add proof: sufficient: Contributor real behavior proof is sufficient. Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
  • add proof: 🎥 video: Contributor real behavior proof includes video or recording evidence. Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
  • add rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • add status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (recording): Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
  • remove rating: 🌊 off-meta tidepool: Current PR rating is rating: 🐚 platinum hermit, so this older rating label is no longer current.

Label justifications:

  • P1: The PR fixes a user-visible Control UI regression that blocks normal chat session switching through the primary picker workflow.
  • rating: 🐚 platinum hermit: Overall readiness is 🐚 platinum hermit; proof is 🦞 diamond lobster and patch quality is 🐚 platinum hermit.
  • status: 👀 ready for maintainer look: ClawSweeper has no concrete contributor-facing blocker left for this PR. Sufficient (recording): Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
  • proof: sufficient: Contributor real behavior proof is sufficient. Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
  • proof: 🎥 video: Contributor real behavior proof includes video or recording evidence. Before/after MP4 proof is supplied with exact local Chromium/Gateway steps and observed after-fix behavior for mouse switching, Tab navigation, keyboard activation, non-empty blur search, and clearing search.
Evidence reviewed

PR surface:

Source +4, Tests +86. Total +90 across 2 files.

View PR surface stats
Area Files Added Removed Net
Source 1 5 1 +4
Tests 1 86 0 +86
Docs 0 0 0 0
Config 0 0 0 0
Generated 0 0 0 0
Other 0 0 0 0
Total 2 91 1 +90

What I checked:

  • Repository policy read: The full root AGENTS.md and scoped ui/AGENTS.md were read; the UI guide did not add extra constraints beyond keeping this in Control UI source/tests and avoiding generated locale edits. (AGENTS.md:1, 3fea2196923b)
  • Current blur path is destructive for empty queries: Current main still calls applyChatSessionPickerSearch on blur; that helper clears chatSessionPickerResult when the normalized query is empty, and resolveChatSessionPickerResult returns that null while the picker is open. (ui/src/ui/chat/session-controls.ts:597, 3fea2196923b)
  • Picker actions depend on click targets surviving blur: Session-option and Load More controls are click-bound in current main, so a blur-triggered render that removes the option rows can prevent the intended activation path. (ui/src/ui/chat/session-controls.ts:652, 3fea2196923b)
  • Patch narrows the blur handler: The PR changes only the blur handler to call applyChatSessionPickerSearch when normalizeOptionalString(state.chatSessionPickerQuery) is truthy, preserving non-empty blur search while avoiding the empty-query clear path. (ui/src/ui/chat/session-controls.ts:597, 6c55ff0535ab)
  • Regression coverage targets the failure: The patch adds tests that blur an initially empty search input, assert the picker result/options remain, and then verify a session option click still calls the switch-session handler. (ui/src/ui/views/chat.test.ts:1433, 6c55ff0535ab)
  • Real behavior proof supplied: The PR body includes before/after GitHub attachment links; downloading both confirmed MP4 recordings, and the body gives exact Chromium/Gateway steps plus observed after-fix mouse, Tab, keyboard, non-empty blur, and clear-search results. (6c55ff0535ab)

Likely related people:

  • vincentkoc: Current-main blame ties the picker popover, blur handler, and adjacent picker tests to commit 653e8d1. (role: recent current-main area contributor; confidence: medium; commits: 653e8d1ea5c2; files: ui/src/ui/chat/session-controls.ts, ui/src/ui/views/chat.test.ts)
  • steipete: History shows the chat session controls split and repeated nearby chat test maintenance in commits including 1fad8ef and 24f8d64. (role: recent UI refactor/test contributor; confidence: medium; commits: 1fad8efa12cf, 24f8d6470eba, 27ae826f6525; files: ui/src/ui/chat/session-controls.ts, ui/src/ui/views/chat.test.ts)
  • amknight: The v2026.5.27 changelog credits this contributor for adding Control UI chat session picker search and Load More pagination, the feature surface implicated by this bug. (role: credited feature contributor; confidence: medium; commits: 27ae826f6525; files: CHANGELOG.md, ui/src/ui/chat/session-controls.ts)
What the crustacean ranks mean
  • 🦀 challenger crab: rare, exceptional readiness with strong proof, clean implementation, and convincing validation.
  • 🦞 diamond lobster: very strong readiness with only minor maintainer review expected.
  • 🐚 platinum hermit: good normal PR, likely mergeable with ordinary maintainer review.
  • 🦐 gold shrimp: useful signal, but proof or patch confidence is still limited.
  • 🦪 silver shellfish: thin signal; proof, validation, or implementation needs work.
  • 🧂 unranked krab: not merge-ready because proof is missing/unusable or there are serious correctness or safety concerns.
  • 🌊 off-meta tidepool: rating does not apply to this item.

Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics.

How this review workflow works
  • ClawSweeper keeps one durable marker-backed review comment per issue or PR.
  • Re-runs edit this comment so the latest verdict, findings, and automation markers stay together instead of adding duplicate bot comments.
  • A fresh review can be triggered by eligible @clawsweeper re-review comments, exact-item GitHub events, scheduled/background review runs, or manual workflow dispatch.
  • PR/issue authors and users with repository write access can comment @clawsweeper re-review or @clawsweeper re-run on an open PR or issue to request a fresh review only.
  • Maintainers can also comment @clawsweeper review to request a fresh review only.
  • Fresh-review commands do not start repair, autofix, rebase, CI repair, or automerge.
  • Maintainer-only repair and merge flows require explicit commands such as @clawsweeper autofix, @clawsweeper automerge, @clawsweeper fix ci, or @clawsweeper address review.
  • Maintainers can comment @clawsweeper explain to ask for more context, or @clawsweeper stop to stop active automation.

@clawsweeper clawsweeper Bot added the rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. label May 28, 2026
@ryan4559

Copy link
Copy Markdown
Contributor Author

@clawsweeper re-review

The previous review did not complete because the internal Codex invocation timed out (spawnSync codex ETIMEDOUT).

@clawsweeper

clawsweeper Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

🦞🧹
ClawSweeper re-review requested.

I asked ClawSweeper to review this item again.
Action: item re-review queued (workflow sweep.yml, event repository_dispatch).
Result: the existing ClawSweeper review comment will be edited in place when the review finishes.

Re-review progress:

@clawsweeper clawsweeper Bot added proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR. P1 High-priority user-facing bug, regression, or broken workflow. and removed rating: 🌊 off-meta tidepool PR readiness rating does not apply to this item. labels May 28, 2026
@Takhoffman

Copy link
Copy Markdown
Contributor

@clawsweeper automerge

@clawsweeper

clawsweeper Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

🦞🔧
ClawSweeper automerge is enabled.

Draft PRs stay fix-only until GitHub marks them ready for review. Pause with /clawsweeper stop.

Automerge progress:

  • 2026-05-28 14:39:27 UTC review queued 6c55ff0535ab (queued)

@clawsweeper clawsweeper Bot added the clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge label May 28, 2026
@clawsweeper

clawsweeper Bot commented May 28, 2026

Copy link
Copy Markdown
Contributor

ClawSweeper 🐠 reef update

Thanks for the work here. ClawSweeper could not write to the source branch, so it opened a replacement PR rather than letting the fix drift. attribution still points back here.

Why replacement: ClawSweeper could not update the source PR branch directly; GitHub did not grant sufficient push rights to the bot for that branch.
Replacement PR: #87682
Why close: this run explicitly closes the superseded source PR after the credited replacement PR is open, so review continues in one place.
This source PR is being closed only under the explicit source-close setting for this ClawSweeper run.
Attribution is preserved in the replacement PR body and release-note trail.
Co-author credit kept:

fish notes: model gpt-5.5, reasoning high; reviewed against 35de287.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

app: web-ui App: web-ui clawsweeper:automerge Maintainer opted this PR into bounded ClawSweeper-reviewed automerge P1 High-priority user-facing bug, regression, or broken workflow. proof: sufficient ClawSweeper judged the real behavior proof convincing. proof: supplied External PR includes structured after-fix real behavior proof. proof: 🎥 video Contributor real behavior proof includes video or recording evidence. rating: 🐚 platinum hermit Good normal PR readiness with ordinary maintainer review expected. size: S status: 👀 ready for maintainer look ClawSweeper has no concrete contributor-facing blocker left for this PR.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: Control UI chat-session-picker buttons unresponsive due to blur/click race condition

2 participants