From e5e5ae8e1d88e3f63abe590f51dd1f067d9df951 Mon Sep 17 00:00:00 2001 From: nitin <142569587+ehconitin@users.noreply.github.com> Date: Mon, 29 Dec 2025 22:33:24 +0530 Subject: [PATCH] fix: guard against invalid date and undefined links field value (#16039) closes https://github.com/twentyhq/twenty/issues/15854 - Add `isValid()` check in `formatDateISOStringToDateTime` before calling `formatInTimeZone` - Add `isDefined()` guard in `getFieldLinkDefinedLinks` (mirrors `phonesUtils` pattern) before: https://github.com/user-attachments/assets/1eb89fa4-70b6-4794-8860-0a42522598b5 https://github.com/user-attachments/assets/781c7d37-c435-4832-98d4-8e6925b51e10 after: https://github.com/user-attachments/assets/b1c22d25-4e8e-45c3-af98-be1684a5962e https://github.com/user-attachments/assets/ce084a9d-03b8-4f88-8522-a32cb1b7cf2f --------- Co-authored-by: Charles Bochet Co-authored-by: Lucas Bordeau --- .../utils/formatDateISOStringToDateTime.ts | 18 ++++++++++-------- .../__tests__/getFieldLinkDefinedLinks.test.ts | 17 +++++++++++++++++ .../input/utils/getFieldLinkDefinedLinks.ts | 4 ++++ .../SettingsDataModelFieldPreview.tsx | 4 +++- .../SettingsDataModelRelationFieldPreview.tsx | 2 +- 5 files changed, 35 insertions(+), 10 deletions(-) diff --git a/packages/twenty-front/src/modules/localization/utils/formatDateISOStringToDateTime.ts b/packages/twenty-front/src/modules/localization/utils/formatDateISOStringToDateTime.ts index c812e12f287..50407e17fb8 100644 --- a/packages/twenty-front/src/modules/localization/utils/formatDateISOStringToDateTime.ts +++ b/packages/twenty-front/src/modules/localization/utils/formatDateISOStringToDateTime.ts @@ -1,5 +1,6 @@ import { type DateFormat } from '@/localization/constants/DateFormat'; import { type TimeFormat } from '@/localization/constants/TimeFormat'; +import { isValid } from 'date-fns'; import { formatInTimeZone } from 'date-fns-tz'; export const formatDateISOStringToDateTime = ({ @@ -15,14 +16,15 @@ export const formatDateISOStringToDateTime = ({ timeFormat: TimeFormat; localeCatalog: Locale; }) => { + const parsedDate = new Date(date); + + if (!isValid(parsedDate)) { + return ''; + } + // TODO: replace this with shiftPointInTimeToFromTimezoneDifference to remove date-fns-tz, which formatInTimeZone is doig under the hood : // https://github.com/marnusw/date-fns-tz/blob/4f3383b26a5907a73b14512a2701f3dfd8cf1579/src/toZonedTime/index.ts#L36C9-L36C27 - return formatInTimeZone( - new Date(date), - timeZone, - `${dateFormat} ${timeFormat}`, - { - locale: localeCatalog, - }, - ); + return formatInTimeZone(parsedDate, timeZone, `${dateFormat} ${timeFormat}`, { + locale: localeCatalog, + }); }; diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/__tests__/getFieldLinkDefinedLinks.test.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/__tests__/getFieldLinkDefinedLinks.test.ts index 0856c382fc6..9dec3106ad3 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/__tests__/getFieldLinkDefinedLinks.test.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/__tests__/getFieldLinkDefinedLinks.test.ts @@ -1,6 +1,23 @@ import { getFieldLinkDefinedLinks } from '@/object-record/record-field/ui/meta-types/input/utils/getFieldLinkDefinedLinks'; +import { type FieldLinksValue } from '@/object-record/record-field/ui/types/FieldMetadata'; describe('getFieldLinkDefinedLinks', () => { + describe('Field value', () => { + it('should return an empty array if fieldValue is undefined', () => { + const result = getFieldLinkDefinedLinks( + undefined as unknown as FieldLinksValue, + ); + expect(result).toEqual([]); + }); + + it('should return an empty array if fieldValue is null', () => { + const result = getFieldLinkDefinedLinks( + null as unknown as FieldLinksValue, + ); + expect(result).toEqual([]); + }); + }); + describe('Primary link', () => { it('should not return primary link when primaryLinkUrl is null', () => { expect( diff --git a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/getFieldLinkDefinedLinks.ts b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/getFieldLinkDefinedLinks.ts index d895c09148c..a6f9ea236f0 100644 --- a/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/getFieldLinkDefinedLinks.ts +++ b/packages/twenty-front/src/modules/object-record/record-field/ui/meta-types/input/utils/getFieldLinkDefinedLinks.ts @@ -3,6 +3,10 @@ import { isNonEmptyString } from '@sniptt/guards'; import { isDefined, isValidUrl } from 'twenty-shared/utils'; export const getFieldLinkDefinedLinks = (fieldValue: FieldLinksValue) => { + if (!isDefined(fieldValue)) { + return []; + } + return [ isNonEmptyString(fieldValue.primaryLinkUrl) ? { diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreview.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreview.tsx index 624b74d0502..44f6a92d180 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreview.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelFieldPreview.tsx @@ -69,7 +69,9 @@ export const SettingsDataModelFieldPreview = ({ labelIdentifierFieldMetadataItem?.name === fieldMetadataItem.name; const fieldName = fieldMetadataItem.name; - const recordId = `${objectNameSingular}-${fieldName}-preview`; + const fieldType = fieldMetadataItem.type; + + const recordId = `${objectNameSingular}-${fieldName}-${fieldType}-preview`; const fieldPreviewValue = useFieldPreviewValue({ fieldMetadataItem, diff --git a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelRelationFieldPreview.tsx b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelRelationFieldPreview.tsx index 74eda82249a..3888acecdf7 100644 --- a/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelRelationFieldPreview.tsx +++ b/packages/twenty-front/src/modules/settings/data-model/fields/preview/components/SettingsDataModelRelationFieldPreview.tsx @@ -72,7 +72,7 @@ export const SettingsDataModelRelationFieldPreview = ({ const fieldName = v4(); - const recordId = `${relationTargetObjectNameSingular}-${fieldName}-preview`; + const recordId = `${relationTargetObjectNameSingular}-${fieldName}-RELATION-preview`; const isRelation = fieldMetadataItem.type === FieldMetadataType.RELATION; const metadata = {