Skip to content

feat(tour): hold a tour back while someone types - #919

Merged
Valtora merged 1 commit into
mainfrom
feat/tour-wait-while-typing
Nov 2, 2026
Merged

Valtora merged 1 commit into
mainfrom
feat/tour-wait-while-typing

Conversation

@Valtora

@Valtora Valtora commented Nov 2, 2026

Copy link
Copy Markdown
Owner

Pull Request

Description

The dashboard, Recordings and transcript tours open 1.5 s after their page, and driver.js then takes focus. Someone already typing in the search box, a task or a note lost the next keys to the tour, and a typed space closed it.

useScheduledTour now opens a tour through a new whenNotTyping helper in frontend/src/lib/. When the 1.5 s is up and focus is in a text input, a textarea or a contenteditable editor (Tiptap's ProseMirror root included), or an IME composition is open, the tour waits. It opens once focus has left the field and nothing has been pressed or clicked for 1.5 s. The steps are still filtered when it opens. Leaving the page while it waits removes its listeners and timer and leaves it unseen for a later visit. #916's close handling and the transcript tour's restoreTourPanel are unchanged.

Decisions:

  • Idle delay of 1.5 s, the same as the load delay. It is longer than the pause people take to choose their next action (the keystroke-level model puts that at about 1.35 s), so the tour does not land on the click that follows leaving a field.
  • The wait runs on events (focusin, focusout, keydown, pointerdown, compositionstart, compositionend), with no polling. A key press also restarts it, because a field removed by its own Enter can lose focus without a focusout.
  • A text input is any input type except the button, toggle and picker ones, so date and number fields count. Read-only fields don't.
  • An open composition holds the tour only while its element still has focus, so a missing compositionend cannot hold it for the rest of the visit.
  • With nothing being typed, the tour still opens at 1.5 s, as before.

Fixes #918

Type of change

  • Bug fix (non-breaking change that fixes an issue)
  • New feature (non-breaking change that adds functionality)
  • Breaking change (fix or feature that changes existing behaviour)
  • Documentation update

Checks run

  • Python: python scripts/check.py (Ruff, format, whitespace and other gates, mypy, doc and Alembic validators, pytest)
  • Frontend: cd frontend && npm run lint && npm run check:contrast && npm run test && npm run build
  • Site: cd site && npm ci && npm run build
  • Docs only: python3 scripts/validate_docs.py

Also check_whitespace.py, check_file_size.py and git diff --check. Full Vitest run: 310 files, 3391 tests passed. The 16 new cases in TourGuide.test.tsx fail against main's TourGuide.tsx. whenNotTyping.test.ts covers the field checks, the IME hold, a field removed without focusout, and that no listener or timer is left once it has run or been cancelled.

Migration impact

  • No database migration.
  • Adds an Alembic migration: one checked-in head, no committed revision deleted or renamed, upgrade and downgrade behaviour described above, and python3 scripts/check_migrations.py run against a throwaway Postgres.

Documentation impact

  • No documentation change required.
  • Updated the guide that owns each changed behaviour, setup, deployment or support topic (.github/CONTRIBUTING.md, "Documentation Ownership").

Security impact

  • No security-sensitive change.
  • Touches auth, tokens, encryption, capture ownership or exposure; docs/SECURITY.md boundaries preserved and updated where behaviour changed.

Manual verification

Headless Chromium on a throwaway stack with made-up data and production builds of main and this branch, at 1440 px. For each tour, typing began 0.2 to 0.3 s after load, before the tour was due at about 1.7 to 1.9 s, and ran for 5 s at 120 ms a key. Then it rested 3 s in the field, and a click on empty page left the field. The dashboard has no sidebar search, so its run typed in the Add a task box. The recordings and transcript runs used the sidebar search.

  • main: on all three tours the tour opened mid-typing, 5 to 7 keys went to it, a typed space closed it and marked it seen, and the search lost the keys, "launch plan review notes for next quarter" becoming "launch plan rnotes for next quarter".
  • this branch: on all three tours no key reached the tour, focus stayed in the field through the rest, and the full query survived. The tour opened 1.51 to 1.53 s after the click that left the field, with the query still in place. With nothing focused, each tour opened 1.50 to 1.51 s after its account lookup, as on main.
  • this branch, extra: typing in the transcript page's meeting notes editor (Tiptap) held the transcript tour the same way, and it opened 1.52 s after leaving. Typing in the recordings search and then clicking Dashboard left the Recordings tour unseen, and it opened 1.52 s into the next visit.

Screenshots (if relevant)

None.

A tour opens 1.5 s after its page and driver.js takes focus, so a search,
rename or note in progress lost the next key to the tour.

If a text input, textarea or contenteditable editor has focus when the
1.5 s is up, or an IME composition is open, the tour now waits. It opens
once focus has left the field and nothing has been pressed or clicked for
another 1.5 s, which covers the pause before a person's next action. The
wait runs on focus, key, pointer and composition events, not polling. A
key press also restarts it, since a field removed by its own Enter can
lose focus with no focusout.

Fixes: #918
@Valtora Valtora added this to the 3.1.0 milestone Nov 2, 2026
@Valtora
Valtora merged commit a761cd3 into main Nov 2, 2026
21 checks passed
@Valtora
Valtora deleted the feat/tour-wait-while-typing branch November 2, 2026 07:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Hold a tour back while a text field has focus

1 participant