Skip to content

Ux/thread view improvements#634

Merged
jbpenrath merged 3 commits into
mainfrom
ux/thread-view-improvements
Apr 16, 2026
Merged

Ux/thread view improvements#634
jbpenrath merged 3 commits into
mainfrom
ux/thread-view-improvements

Conversation

@jbpenrath
Copy link
Copy Markdown
Contributor

@jbpenrath jbpenrath commented Apr 16, 2026

Purpose

Two ux feedbacks improvements :

When user forwards a message, the message form should focus the to
field not the message composer.

Currently the ThreadEventInput is always showed and sticked to the
bottom of the screen. But it can be annoying when the user is writing a
message for example as the input is displayed above the message reply
form. Then it is not relevant to show the input when the user is at the
top of the thread view. So we only show the input when the user reach
the end of the view.

CleanShot.2026-04-16.at.12.35.10.mp4

Summary by CodeRabbit

  • New Features

    • Conditional autofocus for the recipient field when forwarding messages.
    • Intelligent show/hide behavior for the message input based on scroll, focus, and edit state.
  • UI/UX Improvements

    • Smooth transitions when the message input appears or hides.
    • More reliable focus handling across reply and compose flows to avoid unwanted focus changes.
  • Chores

    • Minor backend logging and stability adjustments.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2f17890b-3920-46af-89ef-c151027a2893

📥 Commits

Reviewing files that changed from the base of the PR and between 23b3c4d and 9b1e3fa.

📒 Files selected for processing (11)
  • src/backend/core/api/viewsets/task.py
  • src/backend/core/api/viewsets/thread_access.py
  • src/backend/core/tests/api/test_import_file_upload.py
  • src/frontend/src/features/forms/components/combobox/index.tsx
  • src/frontend/src/features/forms/components/message-form/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/use-im-input-visibility.ts
  • src/frontend/src/features/layouts/components/thread-view/components/thread-message/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/provider.tsx
💤 Files with no reviewable changes (1)
  • src/backend/core/tests/api/test_import_file_upload.py
✅ Files skipped from review due to trivial changes (3)
  • src/backend/core/api/viewsets/task.py
  • src/frontend/src/features/layouts/components/thread-view/components/thread-message/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx
🚧 Files skipped from review as they are similar to previous changes (3)
  • src/frontend/src/features/forms/components/combobox/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/use-im-input-visibility.ts
  • src/frontend/src/features/layouts/components/thread-view/provider.tsx

📝 Walkthrough

Walkthrough

Adds composable autofocus to a combobox, alters message-form autofocus for forward mode, and implements visibility control for the thread compose input driven by scroll proximity, fast-scroll detection, and shared focus state via an extended ThreadView context; includes CSS transitions and minor backend/logging and DB-delete-query adjustments.

Changes

Cohort / File(s) Summary
Combobox
src/frontend/src/features/forms/components/combobox/index.tsx
Added optional autoFocus?: boolean to ComboBoxProps and a useEffect that focuses the input when autoFocus is truthy.
Message form / Composer
src/frontend/src/features/forms/components/message-form/index.tsx
Removed initial mount focus effect; added autoFocus={mode === "forward"} to contact combobox and disabled composer blockNoteOptions.autofocus in forward mode.
Thread view — styles
src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss
Added transitions to .thread-event-input and .thread-event-input--hidden modifier (translateY, opacity, pointer-events) for animated hide/show.
Thread view — input wiring & behavior
src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx, .../thread-message/index.tsx
ThreadEventInput now accepts containerRef; integrates useIMInputVisibility; toggles thread-event-input--hidden and inert when hidden; added guarded onFocus/onBlur handlers. Reply form now sets isMessageFormFocused on focus/blur (guarded).
Thread view — visibility hook
src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/use-im-input-visibility.ts
New exported hook useIMInputVisibility that computes isVisible from scroll proximity, fast downward scroll detection, editing state, and shared message-form focus; exposes onFocusChange.
Thread view — provider & wiring
src/frontend/src/features/layouts/components/thread-view/provider.tsx, src/frontend/src/features/layouts/components/thread-view/index.tsx
ThreadViewProvider now requires threadId, exposes isMessageFormFocused and setIsMessageFormFocused in context; ThreadEventInput is passed containerRef={rootRef}.
Backend — logging & DB delete
src/backend/core/api/viewsets/task.py, src/backend/core/api/viewsets/thread_access.py
Adjusted log formatting in task detail error path; changed perform_destroy editor-existence check to materialize editor IDs under select_for_update() and use len(...) <= 1 predicate.
Tests / minor
src/backend/core/tests/api/test_import_file_upload.py
Whitespace-only change (removed an empty line).

Sequence Diagram

sequenceDiagram
    participant User
    participant ScrollContainer as ThreadView\n(Scroll container)
    participant Context as ThreadViewContext
    participant ReplyForm as ThreadMessage\n(Reply Form)
    participant ComposeInput as ThreadEventInput\n(Compose Input)

    User->>ScrollContainer: scroll
    activate ScrollContainer
    ScrollContainer->>ScrollContainer: RAF-throttled handler -> compute isNearBottom / delta
    ScrollContainer->>Context: update visibility inputs (isNearBottom / fastScroll)
    Context->>ComposeInput: visibility inputs influence isVisible
    deactivate ScrollContainer

    User->>ReplyForm: focus reply form
    activate ReplyForm
    ReplyForm->>Context: setIsMessageFormFocused(true)
    Context->>ComposeInput: context change affects isVisible
    ComposeInput->>User: show (remove --hidden)
    deactivate ReplyForm

    User->>ComposeInput: focus / blur
    activate ComposeInput
    ComposeInput->>ComposeInput: onFocusChange(true/false)
    ComposeInput->>Context: may update focus state
    deactivate ComposeInput

    User->>ScrollContainer: scroll away
    activate ScrollContainer
    ScrollContainer->>ScrollContainer: recompute -> hide input (apply --hidden)
    deactivate ScrollContainer
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~40 minutes

Possibly related PRs

Suggested reviewers

  • sdemagny
  • sylvinus

Poem

🐰 I hopped through lists where messages hide,
I watched the scroll and tucked myself aside.
When near the bottom or focus takes the lead,
I pop my keys ready — quick as a reed.
Type on, dear friends, the rabbit's here to guide.

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Ux/thread view improvements' accurately reflects the main objectives: implementing UX improvements to the thread view component, including focus management for message forwarding and visibility control for ThreadEventInput.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch ux/thread-view-improvements

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jbpenrath jbpenrath self-assigned this Apr 16, 2026
@jbpenrath
Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 16, 2026

✅ Actions performed

Review triggered.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss`:
- Around line 11-14: The hidden modifier .thread-event-input--hidden currently
prevents mouse interaction but leaves controls tabbable; update the hidden state
so the subtree is removed from keyboard focus by either: add the inert attribute
to the container when hidden (preferred) or ensure you set aria-hidden="true" on
the container and apply tabindex="-1" to all focusable descendants (textarea,
buttons, inputs) so they are removed from the tab order; apply this change where
the class .thread-event-input--hidden is toggled and ensure the submit button
and textarea are included.

In `@src/frontend/src/features/layouts/components/thread-view/index.tsx`:
- Around line 239-260: The scroll listener effect for useEffect should
initialize isNearBottom from the current scroll position so the IM bar reflects
the real state immediately; inside the effect that references rootRef, rafRef,
setIsNearBottom, NEAR_BOTTOM_THRESHOLD and thread.id, compute the current
distanceFromBottom (el.scrollHeight - el.scrollTop - el.clientHeight) and call
setIsNearBottom(distanceFromBottom <= NEAR_BOTTOM_THRESHOLD) once before adding
the 'scroll' event (or simply invoke handleScroll() immediately) so the state is
correct even if scrolling happened earlier.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 692bdff4-f9cf-459b-95b6-d785b74fbba5

📥 Commits

Reviewing files that changed from the base of the PR and between 730fea1 and 0829de6.

📒 Files selected for processing (7)
  • src/frontend/src/features/forms/components/combobox/index.tsx
  • src/frontend/src/features/forms/components/message-form/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-message/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/provider.tsx

Comment thread src/frontend/src/features/layouts/components/thread-view/index.tsx Outdated
@jbpenrath jbpenrath force-pushed the ux/thread-view-improvements branch from 0829de6 to 23b3c4d Compare April 16, 2026 13:12
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 2

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In
`@src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/use-im-input-visibility.ts`:
- Line 47: The hook currently initializes isNearBottom to true and only updates
on scroll, so the input can be incorrectly visible on first render; change it to
compute the initial visibility from the current scroll position by either
initializing useState with a function that reads the container/sentinel
positions or by invoking the same visibility-checking routine (e.g., the
existing handleScroll/checkIsNearBottom function used by setIsNearBottom) inside
a useLayoutEffect/useEffect that runs on mount and when the active thread
changes; ensure this effect runs after cleanup/reset so the state is measured
again (reference isNearBottom, setIsNearBottom, and the scroll visibility
checker/handler in use-im-input-visibility.ts).

In `@src/frontend/src/features/layouts/components/thread-view/provider.tsx`:
- Line 27: The focus flag is not cleared when the active thread changes; add a
useEffect in the ThreadView provider that watches the active thread identifier
(e.g., activeThreadId or thread?.id) and calls setIsMessageFormFocused(false)
whenever it changes so a newly mounted thread doesn't inherit the previous focus
state; also apply the same reset logic to the other thread-scoped flags
referenced around lines 68-70 (use their setters to clear on thread change).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: ea3a0d8b-fa85-4d3a-9f1b-e70541e691c6

📥 Commits

Reviewing files that changed from the base of the PR and between 0829de6 and 23b3c4d.

📒 Files selected for processing (6)
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/use-im-input-visibility.ts
  • src/frontend/src/features/layouts/components/thread-view/components/thread-message/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/provider.tsx
🚧 Files skipped from review as they are similar to previous changes (4)
  • src/frontend/src/features/layouts/components/thread-view/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/_index.scss
  • src/frontend/src/features/layouts/components/thread-view/components/thread-message/index.tsx
  • src/frontend/src/features/layouts/components/thread-view/components/thread-event-input/index.tsx

@jbpenrath jbpenrath force-pushed the ux/thread-view-improvements branch 2 times, most recently from 6bcb526 to 4aff492 Compare April 16, 2026 13:36
When user forwards a message, the message form should focus the `to`
field not the message composer.
Currently the ThreadEventInput is always showed and sticked to the
bottom of the screen. But it can be annoying when the user is writing a
message for example as the input is displayed above the message reply
form. Then it is not relevant to show the input when the user is at the
top of the thread view. So we only show the input when the user reach
the end of the view.
@jbpenrath jbpenrath force-pushed the ux/thread-view-improvements branch from 4aff492 to b857122 Compare April 16, 2026 13:41
The select_for_update() was ineffective for two reasons:
- .exclude(id=instance.id) caused each concurrent thread to lock
  a disjoint set of rows, so no serialization occurred
- .count()/.exists() generate aggregate SQL (SELECT COUNT(*))
  that silently drops the FOR UPDATE clause in Django ORM

Now locks ALL editor rows (including self) via values_list()
evaluation, forcing concurrent deletes to serialize properly.
@jbpenrath jbpenrath merged commit 9b1e3fa into main Apr 16, 2026
13 checks passed
@jbpenrath jbpenrath deleted the ux/thread-view-improvements branch April 16, 2026 14:32
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