Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 366a721649 window.open crashes with invalid URL when Links field has empty primaryLinkUrl
https://sonarly.com/issue/14749?type=bug

Clicking the "open link" button on a record table cell with a Links field that has an empty `primaryLinkUrl` calls `window.open('https://', '_blank')`, which Chrome rejects as an invalid URL.

Fix: Added empty-value guards in `useGetSecondaryRecordTableCellButton.ts` for all three field types (Links, Emails, Phones). When the primary value (URL, email, or phone number) is empty, the hook now returns an empty array (no action buttons) instead of creating handlers that would call `window.open` with invalid URLs like `https://`, `mailto:`, or `tel:`.

The fix uses `isNonEmptyString` from `@sniptt/guards`, which is the standard guard used throughout the twenty-front codebase for this purpose.

**Links field (the reported crash):** `primaryLinkUrl` being empty/null caused `getAbsoluteUrl('')` to return `'https://'`, which Chrome rejects as invalid in `window.open`.

**Emails/Phones fields (preventive):** The same class of bug exists — empty email would produce `mailto:` and empty phone would produce `tel:`, both invalid URLs for `window.open`.
2026-03-14 20:24:57 +00:00
@@ -8,6 +8,7 @@ import { isFieldEmails } from '@/object-record/record-field/ui/types/guards/isFi
import { isFieldLinks } from '@/object-record/record-field/ui/types/guards/isFieldLinks';
import { isFieldPhones } from '@/object-record/record-field/ui/types/guards/isFieldPhones';
import { useRecordFieldValue } from '@/object-record/record-store/hooks/useRecordFieldValue';
import { isNonEmptyString } from '@sniptt/guards';
import { t } from '@lingui/core/macro';
import { useContext } from 'react';
import { FieldMetadataSettingsOnClickAction } from 'twenty-shared/types';
@@ -48,6 +49,11 @@ export const useGetSecondaryRecordTableCellButton = () => {
const { primaryPhoneCallingCode = '', primaryPhoneNumber = '' } =
fieldValue as FieldPhonesValue;
const phoneNumber = `${primaryPhoneCallingCode}${primaryPhoneNumber}`;
if (!isNonEmptyString(phoneNumber)) {
return [];
}
openLinkOnClick = () => {
window.open(`tel:${phoneNumber}`, '_blank');
};
@@ -58,6 +64,11 @@ export const useGetSecondaryRecordTableCellButton = () => {
if (isFieldEmails(fieldDefinition)) {
const email = (fieldValue as FieldEmailsValue).primaryEmail ?? '';
if (!isNonEmptyString(email)) {
return [];
}
openLinkOnClick = () => {
window.open(`mailto:${email}`, '_blank');
};
@@ -68,6 +79,11 @@ export const useGetSecondaryRecordTableCellButton = () => {
if (isFieldLinks(fieldDefinition)) {
const url = (fieldValue as FieldLinksValue).primaryLinkUrl ?? '';
if (!isNonEmptyString(url)) {
return [];
}
openLinkOnClick = () => {
window.open(getAbsoluteUrl(url), '_blank');
};