Skip to content

fix(playground): hide session-row checkbox until hover or selection#13314

Open
keval718 wants to merge 1 commit into
release-1.10.0from
fix/playground-session-checkbox-hover
Open

fix(playground): hide session-row checkbox until hover or selection#13314
keval718 wants to merge 1 commit into
release-1.10.0from
fix/playground-session-checkbox-hover

Conversation

@keval718
Copy link
Copy Markdown
Collaborator

@keval718 keval718 commented May 24, 2026

Summary

The selectable-row checkbox in the playground sessions sidebar was rendered at full opacity on every row, adding persistent visual noise to a UI that mostly shows session names. This PR hides the checkbox by default and reveals it only when the row is hovered, while keeping already-checked boxes permanently visible so the user can still see their selection without re-hovering each row.

Visibility rules

Row state Checkbox icon
Not selected + not hovered hidden (invisible) — column space reserved, no layout jump
Not selected + row hovered visible (group-hover:visible)
Selected (any pointer state) visible (text-status-red) — no invisible, no group-hover: gating

The Select All checkbox at the top of the multi-select region stays always visible because it is the entry-point affordance for multi-select — without it, the user has no way to discover the feature.

Implementation

session-selector.tsx checkbox icon className:

- className={cn(
-   "h-4 w-4",
-   isSelected ? "text-status-red" : "text-muted-foreground",
- )}
+ className={cn(
+   "h-4 w-4 transition-opacity",
+   isSelected
+     ? "text-status-red"
+     : "text-muted-foreground invisible group-hover:visible",
+ )}
  • The row already carries Tailwind's group class, so group-hover:visible resolves without any extra plumbing.
  • invisible (CSS visibility: hidden) reserves the 16×16 column and disables pointer events, so a stray click on the hidden column cannot accidentally toggle selection.
  • transition-opacity smooths the reveal.
  • The wrapping w-4 h-4 flex-shrink-0 column is unchanged, so the row layout never shifts on hover/unhover or on selection state change.

Trade-offs / alternatives considered

  • Always show all checkboxes once any row is selected (so multi-selecting a 3rd row doesn't require hovering to find each checkbox). Reasonable, but adds a selectedSessions.size > 0 prop / mode that the parent has to thread down. Skipped for now — current behaviour matches the user's exact ask; revisit if QA reports multi-select friction.
  • Render with opacity-0 + pointer-events-none instead of invisible — semantically equivalent for this case but more verbose and produces no transition unless opacity is on a transition-property list. invisible is the single-utility shadcn pattern used by SessionMoreMenu (invisible group-hover:visible), so keeping the same idiom across both row-affordances is the better consistency choice.
  • Animate the checkbox in with a scale/fade — overkill for a low-frequency row affordance; the simple opacity transition is the standard list-item reveal in the rest of Langflow.

Tests

New __tests__/session-selector-checkbox-visibility.test.tsx (5 cases):

  1. Default state → icon className contains invisible + group-hover:visible; row carries the group class so the utility resolves.
  2. Selected state → icon className contains neither invisible nor group-hover:visible; text-status-red present (always-visible regression guard).
  3. Hidden state still reserves w-4 h-4 (layout-jump regression guard).
  4. Clicking the checkbox column toggles selection and does NOT trigger row toggleVisibility (event propagation guard).
  5. showCheckbox={false} → no checkbox column rendered at all.

Locally overrode the global genericIconComponent mock so the icon renders a <span> with className, letting tests assert the utility classes are wired correctly (the global jest setup mocks it to null for the rest of the suite).

  • Full playgroundComponent jest suite: 141 / 141 ✅
  • @biomejs/biome check clean on both changed files (0 errors; 3 pre-existing a11y warnings on the edit-mode wrapper and other rows are untouched).
  • make format_frontend clean.

Test plan

  • cd src/frontend && npm start, open playground for any flow.
  • Session rows show no checkboxes by default — only session name and the MoreMenu.
  • Hover a row → checkbox appears in the leftmost 16×16 column, aligned with the session name, no layout jump.
  • Click checkbox on hover → row becomes selected; checkbox stays visible after pointer leaves.
  • Move pointer to a different row → that row's checkbox appears; previously-selected row's checkbox is still shown.
  • Untick a selected row → checkbox hides again when the pointer leaves.
  • Select All checkbox at the top stays always visible (regression check: only session-row checkboxes are hover-gated).
  • Click the row body (not the checkbox) while the row is unhovered/unchecked → session becomes active (no accidental selection toggle from the hidden checkbox column).

Summary by CodeRabbit

  • Bug Fixes

    • Improved session selector checkbox visibility with smooth hover interactions and enhanced layout stability to prevent content shifting.
  • Tests

    • Added comprehensive test coverage for session selector checkbox visibility, interaction behavior, and layout preservation.

Review Change Stack

The selectable-row checkbox was always rendered at full opacity, adding
visual noise to every session in the sidebar. Hide it by default and
reveal it only when the row is hovered, while keeping checked boxes
permanently visible so users can still see what they have selected
without re-hovering each row.

Implementation:
  - Apply ``invisible group-hover:visible`` to the icon when the row is
    not selected; the row already carries the ``group`` class, so the
    utility resolves without further plumbing.
  - Skip those classes when ``isSelected`` so a checked box stays
    visible regardless of pointer location.
  - Keep the wrapping ``w-4 h-4`` column so the row layout does not
    jump on hover/unhover. ``visibility: hidden`` also disables pointer
    events so a stray click on the hidden column cannot toggle
    selection.
  - Add ``transition-opacity`` for a smooth reveal.

The Select All checkbox at the top of the multi-select region remains
always visible — it is the entry-point affordance for multi-select.

Adds ``__tests__/session-selector-checkbox-visibility.test.tsx`` (5
cases): hidden default + hover utility wiring, always-visible-on-
selected, layout-jump guard via reserved column, click toggles
selection without bubbling to row toggleVisibility, and showCheckbox
false renders nothing.
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented May 24, 2026

Walkthrough

This PR introduces a hover-reveal checkbox visibility feature for the SessionSelector component. The implementation adds conditional CSS classes that keep the checkbox icon invisible until the row is hovered, while maintaining visibility when a session is selected. A new test file comprehensively validates the visibility states, layout stability, user interactions, and conditional rendering behavior.

Changes

Checkbox Visibility Behavior

Layer / File(s) Summary
Checkbox Hover-Reveal Implementation
src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/session-selector.tsx
SessionSelector checkbox icon applies invisible group-hover:visible classes when not selected, uses transition-opacity for smooth reveal, and explicitly shows the icon with text-status-red when selected.
Checkbox Visibility Test Suite
src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/__tests__/session-selector-checkbox-visibility.test.tsx
Comprehensive test suite with focused mocks validates five key behaviors: icon invisibility on unselected rows with hover reveal, icon visibility on selected rows, fixed checkbox column spacing when hidden, click event isolation, and conditional checkbox rendering based on showCheckbox prop.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~12 minutes

🚥 Pre-merge checks | ✅ 6 | ❌ 3

❌ Failed checks (3 warnings)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Test File Naming And Structure ⚠️ Warning Test uses Jest/React Testing Library instead of Playwright required by custom check #2. Project convention uses Jest for unit tests, Playwright for E2E. Rewrite test using Playwright in .spec.tsx format, or clarify that custom check should permit Jest for unit tests per project guidelines.
Excessive Mock Usage Warning ⚠️ Warning SessionRename is unnecessarily mocked (only renders when isEditing=true, never set in tests), violating guidelines to mock only external dependencies, not internal components. Remove SessionRename mock since it's never rendered. Render SessionMoreMenu for better integration testing.
✅ Passed checks (6 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically describes the main change: hiding the session-row checkbox until hover or selection, which is the core feature introduced in this PR.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Test Coverage For New Implementations ✅ Passed PR includes comprehensive test coverage for bug fix with 5 test cases. Tests cover all implementation scenarios and follow *.test.tsx naming convention consistent with project standards.
Test Quality And Coverage ✅ Passed Tests cover main functionality (visibility, selection, layout, clicks, conditional rendering) with proper React Testing Library patterns validating actual behavior, not just smoke tests.

✏️ 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 fix/playground-session-checkbox-hover

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.

@github-actions github-actions Bot added the bug Something isn't working label May 24, 2026
@github-actions
Copy link
Copy Markdown
Contributor

✅ Test Coverage Advisor

No source changes detected without accompanying tests. Thanks for keeping coverage up! 🎉

Advisory check only — never blocks merge.

@github-actions github-actions Bot added bug Something isn't working and removed bug Something isn't working labels May 24, 2026
@codecov
Copy link
Copy Markdown

codecov Bot commented May 24, 2026

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 55.52%. Comparing base (1fe9b39) to head (faf52f0).

❌ Your project check has failed because the head coverage (51.71%) is below the target coverage (60.00%). You can increase the head coverage or adjust the target coverage.

Additional details and impacted files

Impacted file tree graph

@@                Coverage Diff                 @@
##           release-1.10.0   #13314      +/-   ##
==================================================
+ Coverage           55.42%   55.52%   +0.09%     
==================================================
  Files                2179     2179              
  Lines              205846   205850       +4     
  Branches            31073    29401    -1672     
==================================================
+ Hits               114091   114297     +206     
+ Misses              90427    90224     -203     
- Partials             1328     1329       +1     
Flag Coverage Δ
backend 60.38% <ø> (+0.05%) ⬆️
frontend 55.32% <100.00%> (+0.13%) ⬆️
lfx 51.71% <ø> (-0.01%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...t-view/chat-header/components/session-selector.tsx 78.15% <100.00%> (+47.95%) ⬆️

... and 33 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Copy Markdown
Contributor

@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: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/__tests__/session-selector-checkbox-visibility.test.tsx`:
- Around line 1-37: This test uses Jest/@testing-library instead of the
project's Playwright-based frontend tests and also mocks internal UI components
(SessionMoreMenu, SessionRename) which violates guidelines; either (A) rewrite
the test as a Playwright test that mounts the SessionSelector component and
asserts checkbox visibility via real DOM interactions, removing Jest-specific
helpers (fireEvent/render/screen) and jest.mock usages, or (B) if you intend to
keep a unit test with Jest, stop mocking internal components by removing the
mocks for SessionMoreMenu and SessionRename and render the real implementations
while keeping mocks only for external dependencies like useUpdateSessionName,
useVoiceStore and useSessionHasMessages; update the test filename/naming to
match the approved pattern and ensure all mocks reference the same symbol names
(SessionSelector, SessionMoreMenu, SessionRename, useUpdateSessionName,
useVoiceStore, useSessionHasMessages) so the correct modules are exercised.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 40da7dce-ac0c-4069-bdab-7b20abc62c18

📥 Commits

Reviewing files that changed from the base of the PR and between 1fe9b39 and faf52f0.

📒 Files selected for processing (2)
  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/__tests__/session-selector-checkbox-visibility.test.tsx
  • src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/session-selector.tsx

Comment on lines +1 to +37
import { fireEvent, render, screen } from "@testing-library/react";
import { SessionSelector } from "../session-selector";

// ---------------------------------------------------------------------------
// Minimal mocks — keep the test focused on the checkbox visibility logic.
// ---------------------------------------------------------------------------

// Override the global no-op mock so we can read the className passed to
// the icon and assert the hover/visibility utility classes are wired.
jest.mock("@/components/common/genericIconComponent", () => ({
__esModule: true,
default: ({ name, className }: { name: string; className?: string }) => (
<span data-testid={`icon-${name}`} className={className} />
),
}));

jest.mock("@/controllers/API/queries/messages/use-rename-session", () => ({
useUpdateSessionName: () => ({ mutate: jest.fn() }),
}));

type VoiceState = { setNewSessionCloseVoiceAssistant: jest.Mock };
jest.mock("@/stores/voiceStore", () => ({
useVoiceStore: <TResult,>(selector: (state: VoiceState) => TResult) =>
selector({ setNewSessionCloseVoiceAssistant: jest.fn() }),
}));

jest.mock("../../hooks/use-session-has-messages", () => ({
useSessionHasMessages: () => true,
}));

jest.mock("../session-more-menu", () => ({
SessionMoreMenu: () => <div data-testid="session-more-menu" />,
}));

jest.mock("../session-rename", () => ({
SessionRename: () => <div data-testid="session-rename" />,
}));
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | 🏗️ Heavy lift

Test framework does not match coding guidelines.

The coding guidelines require frontend test files to use Playwright, but this test uses Jest with @testing-library/react. Additionally, the test mocks internal UI components (SessionMoreMenu and SessionRename at lines 31-37) rather than rendering them, which may indicate poor test design.

Consider either:

  1. Rewriting this test using Playwright to comply with the guidelines, or
  2. If Jest/Testing Library is acceptable for unit tests in this codebase, removing the mocks for internal UI components (lines 31-37) and rendering the real components instead. Mocks should be reserved for external dependencies like API hooks and stores.

As per coding guidelines, frontend test files should follow the naming convention *.test.ts or *.test.tsx using Playwright. Additionally, ensure mocks are used appropriately for external dependencies only, not for core logic or internal UI components.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@src/frontend/src/components/core/playgroundComponent/chat-view/chat-header/components/__tests__/session-selector-checkbox-visibility.test.tsx`
around lines 1 - 37, This test uses Jest/@testing-library instead of the
project's Playwright-based frontend tests and also mocks internal UI components
(SessionMoreMenu, SessionRename) which violates guidelines; either (A) rewrite
the test as a Playwright test that mounts the SessionSelector component and
asserts checkbox visibility via real DOM interactions, removing Jest-specific
helpers (fireEvent/render/screen) and jest.mock usages, or (B) if you intend to
keep a unit test with Jest, stop mocking internal components by removing the
mocks for SessionMoreMenu and SessionRename and render the real implementations
while keeping mocks only for external dependencies like useUpdateSessionName,
useVoiceStore and useSessionHasMessages; update the test filename/naming to
match the approved pattern and ensure all mocks reference the same symbol names
(SessionSelector, SessionMoreMenu, SessionRename, useUpdateSessionName,
useVoiceStore, useSessionHasMessages) so the correct modules are exercised.

@github-actions
Copy link
Copy Markdown
Contributor

Frontend Unit Test Coverage Report

Coverage Summary

Lines Statements Branches Functions
Coverage: 39%
39.88% (50685/127081) 68.47% (6921/10107) 39.11% (1144/2925)

Unit Test Results

Tests Skipped Failures Errors Time
4429 0 💤 0 ❌ 0 🔥 11m 1s ⏱️

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

Labels

bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant