Skip to content

feat(web): add scroll-to-bottom button - #1694

Open
techotaku39 wants to merge 4 commits into
tiann:mainfrom
techotaku39:feat/web-scroll-to-bottom-button
Open

feat(web): add scroll-to-bottom button#1694
techotaku39 wants to merge 4 commits into
tiann:mainfrom
techotaku39:feat/web-scroll-to-bottom-button

Conversation

@techotaku39

@techotaku39 techotaku39 commented Aug 26, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add a compact HAPI-styled circular control in the bottom-right corner of the chat.
  • Show it after downward scrolling when the viewport is away from the bottom; hide it at the bottom, while scrolling upward, or when the unread-message indicator is visible.
  • Reuse the same circular control for unread messages, displaying the count with a high-contrast color and a 99+ cap.
  • Use smooth scrolling to match outline navigation behavior, and retarget the smooth tail jump when streamed content grows during the animation.
  • Add localized accessible labels and focused regression tests.

Validation

  • bun typecheck — passed for CLI, Web, Hub, and Relay after the review fix.
  • bun run test:web -- src/components/AssistantChat/HappyThread.test.tsx src/components/AssistantChat/HappyThread.mobile-scroll.test.tsx — 40/40 passed after the review fix.
  • pwsh -NoProfile -File .\scripts\Invoke-HapiTaskPlaywright.ps1 -Name scroll-to-bottom-button -Suite Root terminal-wrap-fidelity.spec.ts — 2/2 passed before the review-only smooth-scroll fix; the fix is covered by the focused Web regression test above.
  • bun run build — passed for the Web bundle, embedded Web assets, and Hub bundle after the review fix.
  • bun run test — 2,440/2,467 tests passed before the review-only Web fix. The remaining 27 failures are limited to unrelated Windows path, permission, shell-quoting, and ACP timing suites; the focused Web suite passed after the fix.
  • GitHub Actions test passed. The unrelated integration job currently fails 4 runner session-management tests in cli/src/runner/runner.integration.test.ts; no changed files overlap that failure.
  • Full test environment smoke check passed before shutdown: Hub health was ok, the Runner machine was active, and the demo session contained 63 messages including 3 live messages.

Related Issues

None.

AI Disclosure

Code and tests were prepared with Codex (GPT-5.6).

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • [Major] Retarget the smooth tail jump when content grows — scrollToBottom disables auto-follow before issuing a one-time smooth scroll to the content's current bottom. If an assistant message streams or a tool card expands during that animation, the destination becomes stale. The scroll handler ignores the intermediate events while tailScrollInProgressRef is set, the resize observer cannot follow because autoScrollEnabledRef is false, and the view has already switched to tail mode, so the unread control disappears. The viewport can therefore remain permanently behind the live tail. Evidence: web/src/components/AssistantChat/HappyThread.tsx:1130.

    Suggested fix:

    const observer = new ResizeObserver(() => {
        if (tailScrollInProgressRef.current && !pendingScrollRef.current) {
            content.scrollIntoView({ block: 'end', behavior: 'smooth' })
        } else if (
            autoScrollEnabledRef.current
            && atBottomRef.current
            && !pendingScrollRef.current
        ) {
            scrollToBottomInstant()
        }
        // existing coverage handling...
    })

Summary

Review mode: initial

One Major finding: the smooth jump needs to track layout growth until the real bottom is reached.

Testing

Not run (automation). Add a browser-level regression that starts the jump, grows scrollHeight during the animation without manually moving to the new bottom, and verifies the viewport eventually reaches/follows the new tail.

HAPI Bot

// instant tail-following disabled until the smooth animation
// reaches the bottom, otherwise a resize/state update can snap
// the viewport there before the animation is visible.
autoScrollEnabledRef.current = false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[MAJOR] Retarget the smooth tail jump when content grows

This disables auto-follow before a one-time smooth scroll to the content's current bottom. If streaming text or an expanding tool card increases scrollHeight during the animation, that destination becomes stale. While tailScrollInProgressRef is true, intermediate scroll events are ignored; the resize observer also cannot follow because auto-scroll is false. Since this handler already switches view mode to tail, the unread control disappears and the viewport can remain permanently behind.

Suggested fix:

const observer = new ResizeObserver(() => {
    if (tailScrollInProgressRef.current && !pendingScrollRef.current) {
        content.scrollIntoView({ block: 'end', behavior: 'smooth' })
    } else if (
        autoScrollEnabledRef.current
        && atBottomRef.current
        && !pendingScrollRef.current
    ) {
        scrollToBottomInstant()
    }
    // existing coverage handling...
})

Please also cover content growth without manually advancing scrollTop to the new bottom; the current test does that manually, so it cannot catch a stale native smooth-scroll target.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Findings

  • None.

Summary

Review mode: follow-up after new commits

No issues found in the latest full diff. The prior smooth-scroll finding is no longer present: content growth now retargets the active tail jump from the content ResizeObserver (web/src/components/AssistantChat/HappyThread.tsx:1543). Residual risk remains around browser-native smooth-scroll timing under continuous streaming.

Testing

Not run (automation). The added tests cover visibility decisions and verify that resize dispatches a second smooth-scroll request; they do not browser-test that the viewport ultimately reaches the final tail while real content grows.

HAPI Bot

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.

1 participant