fix(record-table): keep column header dropdown open after Move Left/Right (#21015)

Fixes #20999

## Summary

Fixes a UX issue where clicking **Move left** or **Move right** in the
column header
dropdown immediately closed the menu, forcing users to reopen it for
every single move.

## Problem

`handleColumnMoveLeft` and `handleColumnMoveRight` both called
`closeDropdownAndToggleScroll()` unconditionally at the top of their
handlers — before
even checking `canMoveLeft` / `canMoveRight`. This immediately set the
Jotai atom
`isDropdownOpenComponentState` to `false`, unmounting the dropdown.

Since move actions are **repeatable** — a user might want to shift a
column several
positions — they were forced into a frustrating loop: click header →
click move → click
header → click move → repeat for every step.

## Fix

Removed the two `closeDropdownAndToggleScroll()` calls from the move
handlers in
`RecordTableColumnHeadDropdownMenu.tsx`.

```diff
  const handleColumnMoveLeft = () => {
-   closeDropdownAndToggleScroll();
-
    if (!canMoveLeft) return;
    moveTableColumn('left', recordField.fieldMetadataItemId);
  };

  const handleColumnMoveRight = () => {
-   closeDropdownAndToggleScroll();
-
    if (!canMoveRight) return;
    moveTableColumn('right', recordField.fieldMetadataItemId);
  };
```

All other handlers — **Filter, Sort, Hide** — are untouched and still
close the dropdown
correctly, since those are one-shot or navigation actions.

## Changes

| File | Change |
|---|---|
| `RecordTableColumnHeadDropdownMenu.tsx` | Remove 2
`closeDropdownAndToggleScroll()` calls from move handlers |
| `RecordTable.stories.tsx` | Add `HeaderMenuStaysOpenAfterMoveRight`
regression story |

## Testing

**Storybook interaction test** — `HeaderMenuStaysOpenAfterMoveRight`:
clicks "Move right" then asserts the menu is still visible.

**Manual checklist:**
- [x] Move right → menu stays open
- [x] Move right again → column moves again, menu still open
- [x] Move left → menu stays open
- [x] Move rightmost column → "Move right" disappears, menu stays open
showing "Move left"
- [x] Filter → menu closes *(unchanged)*
- [x] Sort → menu closes *(unchanged)*
- [x] Hide → menu closes *(unchanged)*
- [x] Click outside → menu closes *(unchanged)*
- [x] Escape → menu closes *(unchanged)*
- [x] TypeScript: zero new errors (`tsc --noEmit`)

---------

Co-authored-by: Félix Malfait <felix.malfait@gmail.com>
Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Prakhar Tripathi
2026-06-02 16:53:26 +05:30
committed by GitHub
parent b2539f5b6a
commit 2048efb75d
2 changed files with 17 additions and 4 deletions
@@ -65,6 +65,23 @@ export const HeaderMenuOpen: Story = {
},
};
export const HeaderMenuStaysOpenAfterMoveRight: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
const body = within(canvasElement.ownerDocument.body);
await canvas.findAllByText('Linkedin', {}, { timeout: 3000 });
const headerMenuButton = await canvas.findByText('Domain Name');
await userEvent.click(headerMenuButton);
const moveRightButton = await body.findByText('Move right');
await userEvent.click(moveRightButton);
await body.findByText('Move right');
},
};
export const ScrolledLeft: Story = {
parameters: {
container: {
@@ -83,16 +83,12 @@ export const RecordTableColumnHeadDropdownMenu = ({
};
const handleColumnMoveLeft = () => {
closeDropdownAndToggleScroll();
if (!canMoveLeft) return;
moveTableColumn('left', recordField.fieldMetadataItemId);
};
const handleColumnMoveRight = () => {
closeDropdownAndToggleScroll();
if (!canMoveRight) return;
moveTableColumn('right', recordField.fieldMetadataItemId);