https://sonarly.com/issue/29531?type=bug
SidePanelPageLayoutRecordPageWidgetTypeSelect crashes during render when both `pageLayoutEditingWidgetId` and `widgetCreationTargetTabId` are null. This occurs because the Replace Widget and Add Widget Above/Below navigation paths never set `widgetCreationTargetTabId` as a fallback, and `pageLayoutEditingWidgetId` can be independently cleared by auth-triggered re-renders or edit mode toggling.
Fix: Changed `resolveWidgetTypeSelectTargetTabId` to return `null` instead of throwing when it encounters invalid state (both `pageLayoutEditingWidgetId` and `widgetCreationTargetTabId` are null, or the editing widget isn't found in any tab). This converts an unrecoverable render-time crash into a recoverable state.
In `SidePanelPageLayoutRecordPageWidgetTypeSelect`:
1. Added `useEffect` that calls `closeSidePanelMenu()` when `tabId` is null — this gracefully closes the side panel when state becomes inconsistent (e.g. after auth token renewal resets `pageLayoutEditingWidgetId`).
2. Added early `return null` after all hooks when `tabId` is null, preventing the component from rendering with invalid state.
3. Added `!isDefined(tabId)` guards at the top of all 4 `useCallback` handlers (`removeExistingWidgetIfReplacing`, `handleCreateFieldsWidget`, `handleCreateFieldWidget`, `handleCreateFrontComponentWidget`) to ensure TypeScript type safety and prevent operations with a null tab ID.
Updated the existing test file to expect `null` returns instead of thrown errors for the two edge cases.
The fix does not change behavior for any valid navigation path — `resolveWidgetTypeSelectTargetTabId` still returns the correct tab ID when state is properly set. It only adds graceful degradation for the race condition where external state resets (auth renewal, edit mode toggling) clear `pageLayoutEditingWidgetId` while the widget type select page is still on the side panel navigation stack.