Files
iptvnator/libs/workspace/shell/feature
4grayandClaude Opus 5 30d76a3a46 fix(search): keep in-flight typing when the page rewrites its query params (#1432)
* fix(search): keep in-flight typing when the page rewrites its query params

`WorkspaceShellSearchSyncService` re-read `q` on every `NavigationEnd` and
unconditionally called `setSearchState(...)`, which cancels the pending
debounce and overwrites the search box. Any same-page navigation that carried
no search intent — a downloads filter chip writing `?filter=…`, a refresh bump,
or the router echoing back our own `q` — therefore ate whatever had been typed
since the last applied term.

While input is debouncing, ignore a navigation that stays on the same page and
carries the term already applied. Real search intent (route change,
back/forward, a different `q`) still syncs as before.

This is the race behind the flaky `@downloads @electron keeps global and scoped
libraries truthful …` e2e test: it clicks a filter chip and fills the searchbox
with nothing awaited in between, so under CI load the chip's navigation lands
after the keystroke, wipes the term, and `q` is never written.

Reproduced deterministically by dispatching the chip click and the `input`
event in the same page task; the searchbox value goes to `""` and `q` stays
`null`. The new spec fails on the old code for the two regression cases and
passes for the three guard cases on both.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

* fix(search): keep history authoritative and retire the debounce on Enter

Two follow-ups from review of the same-page navigation guard.

Greptile: the guard could not tell an app-initiated `q` echo from back/forward
landing on a history entry that carries the same term. Key the exemption on
`Navigation.trigger === 'imperative'` instead, so browser history always wins
over in-flight typing. `lastSuccessfulNavigation` is set immediately before
`NavigationEnd` is emitted, so it describes the navigation being handled.

Codex: with the guard in place, an Enter commit no longer had its queued
debounce cancelled as a side effect of the resulting `NavigationEnd`. Typing
"Beta " and pressing Enter before the debounce expired applied the trimmed
term, then the stale timeout reapplied the untrimmed one — leaving the box and
URL on "Beta" while the provider store searched "Beta ". `applySearchQuery()`
now cancels the pending debounce itself, which is the correct owner of that
rule rather than relying on a navigation side effect.

Both new tests were mutation-checked: dropping either sub-fix fails exactly its
own test and no other.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-08-13 09:10:24 +02:00
..