From 0f7ec69cdfde266b985722769fc7787edd7af9ea Mon Sep 17 00:00:00 2001 From: Sonarly Claude Code Date: Tue, 7 Apr 2026 16:50:30 +0000 Subject: [PATCH] fix(record-table): guard against undefined recordField during column resize MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit https://sonarly.com/issue/5904?type=bug When resizing a table column header on the messageThreads page, `recordField` can be undefined because `visibleRecordFields` changes mid-resize, causing an unhandled throw that crashes the page. Fix: Replaced `throwIfNotDefined(recordField, 'recordField')` with graceful `isDefined` early returns in both `handleResizeHandlerMove` and `handleResizeHandlerEnd` callbacks in `useResizeTableHeader.ts`. **Changes:** 1. **Import swap**: Replaced `throwIfNotDefined` with `isDefined` from `twenty-shared/utils` — the same utility already used extensively in sibling files in this directory. 2. **`handleResizeHandlerMove` (line 96)**: Changed from `throwIfNotDefined(recordField, 'recordField')` to `if (!isDefined(recordField)) return;`. When `visibleRecordFields` changes mid-resize and the resized field is no longer in the array, the move handler now silently skips the frame instead of throwing on every mousemove event. 3. **`handleResizeHandlerEnd` (line 164-172)**: Changed from `throwIfNotDefined` to an `isDefined` check that also **resets all resize state** (offset, pointer position, field metadata ID, drag selection) before returning. This prevents the user from getting stuck in a broken resize state when the field disappears mid-resize — the next interaction will start clean. The `isDefined` utility is a proper TypeScript type guard (`value is NonNullable`), so type narrowing after the check is preserved — the code below the guard can still access `recordField.size`, `recordField.id`, etc. without type errors. --- .../hooks/useResizeTableHeader.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts index a460635ad45..1696262b5a5 100644 --- a/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts +++ b/packages/twenty-front/src/modules/object-record/record-table/record-table-header/hooks/useResizeTableHeader.ts @@ -28,7 +28,7 @@ import { useCallback, useState } from 'react'; import { findById, findByProperty, - throwIfNotDefined, + isDefined, } from 'twenty-shared/utils'; export const useResizeTableHeader = () => { @@ -93,7 +93,7 @@ export const useResizeTableHeader = () => { ({ x }) => { if (!initialPointerPositionX) return; - throwIfNotDefined(recordField, 'recordField'); + if (!isDefined(recordField)) return; const newResizeOffset = x - initialPointerPositionX; @@ -162,9 +162,14 @@ export const useResizeTableHeader = () => { const store = useStore(); const handleResizeHandlerEnd = useCallback(async () => { - throwIfNotDefined(recordField, 'recordField'); + if (!isDefined(recordField) || !resizedFieldMetadataId) { + store.set(resizeFieldOffset, 0); + setInitialPointerPositionX(null); + setResizedFieldMetadataId(null); + setDragSelectionStartEnabled(true); - if (!resizedFieldMetadataId) return; + return; + } const currentResizeFieldOffset = store.get(resizeFieldOffset);