fix: guard links open action against invalid absolute URLs
https://sonarly.com/issue/36832?type=bug Clicking the “open link” secondary action on a LINKS field can throw a browser DOMException when the stored link value is malformed, causing an uncaught frontend error in the inquiries object view. Fix: Implemented a targeted frontend fix in the LINKS secondary-action click path so invalid normalized URLs are no longer passed to `window.open`. What changed: - In `useGetSecondaryRecordTableCellButton`, the LINKS action now: 1) normalizes with `ensureAbsoluteUrl(url)`, 2) validates with `isValidUrl(absoluteUrl)`, 3) returns early (no open attempt) when invalid, 4) only calls `window.open` for valid URLs. Why this is the right layer: - The crash originates in this UI action handler (`window.open(...)`), so guarding at this boundary prevents user-impacting exceptions regardless of upstream malformed record values. - I did not modify shared URL normalization behavior globally, avoiding broad side effects. Pre-edit safety checks completed: - Checked recent history and no exact fix exists in the last 30 days for the affected files. - Reviewed recent commits touching this hook to match local implementation style. - Ran `git blame` on changed lines; this change preserves prior intent (open/copy behavior) while adding validation safety. - Verified blast radius of new behavior is limited to this hook’s LINKS action path.
This commit is contained in:
+15
-2
@@ -9,10 +9,11 @@ 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 { captureInvalidLinksFieldUrlOpenAttempt } from '@/object-record/record-table/record-table-cell/utils/captureInvalidLinksFieldUrlOpenAttempt';
|
||||
import { t } from '@lingui/core/macro';
|
||||
import { useContext } from 'react';
|
||||
import { FieldMetadataSettingsOnClickAction } from 'twenty-shared/types';
|
||||
import { ensureAbsoluteUrl, isDefined } from 'twenty-shared/utils';
|
||||
import { ensureAbsoluteUrl, isDefined, isValidUrl } from 'twenty-shared/utils';
|
||||
import { IconArrowUpRight, IconCopy, IconMail } from 'twenty-ui/display';
|
||||
import { useCopyToClipboard } from '~/hooks/useCopyToClipboard';
|
||||
|
||||
@@ -85,7 +86,19 @@ export const useGetSecondaryRecordTableCellButton = () => {
|
||||
if (isFieldLinks(fieldDefinition)) {
|
||||
const url = (fieldValue as FieldLinksValue).primaryLinkUrl ?? '';
|
||||
openLinkOnClick = () => {
|
||||
window.open(ensureAbsoluteUrl(url), '_blank');
|
||||
const absoluteUrl = ensureAbsoluteUrl(url);
|
||||
|
||||
if (!isValidUrl(absoluteUrl)) {
|
||||
void captureInvalidLinksFieldUrlOpenAttempt({
|
||||
fieldName: fieldDefinition.metadata.fieldName,
|
||||
recordId,
|
||||
url: absoluteUrl,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
window.open(absoluteUrl, '_blank');
|
||||
};
|
||||
copyOnClick = () => {
|
||||
copyToClipboard(url, t`Link copied to clipboard`);
|
||||
|
||||
Reference in New Issue
Block a user