Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 4dbfbf1f61 RICH_TEXT_V2 field type unhandled in computeDraftValueFromString causes crash on table cell keypress
https://sonarly.com/issue/14660?type=bug

When a user presses a key while focused on a RICH_TEXT_V2 table cell (e.g., `bodyV2` on Tasks), `computeDraftValueFromString` throws because it has no handler for the RICH_TEXT_V2 field type.

Fix: **Primary fix:** Added `FieldMetadataType.RICH_TEXT` to the `FIELD_NOT_OVERWRITTEN_AT_DRAFT` array in `FieldsNotOverwrittenAtDraft.ts`.

This is the same pattern used for all other complex/composite field types (FILES, SELECT, RATING, ADDRESS, PHONES, LINKS, MULTI_SELECT). When a user presses a key while a table cell is focused, `useInitDraftValue` checks this list — if the field type is present, it routes through `computeDraftValueFromFieldValue` (which uses the existing record value) instead of `computeDraftValueFromString` (which tries to convert a single keystroke into a field-specific draft value). RICH_TEXT fields have their own BlockNote/TipTap editor and cannot meaningfully create a draft from a keyboard string, so they should bypass `computeDraftValueFromString` entirely.

Without this fix, pressing any text key on a focused RICH_TEXT cell in a table view throws `Error: Record field type not supported : RICH_TEXT_V2` (on v1.19.0) because `computeDraftValueFromString` has no handler for this type and falls through to the throw statement.

**Secondary fix:** Removed a stray `}` in the error message template literal in `computeDraftValueFromString.ts` — the string was `` `...${fieldDefinition.type}}` `` (double closing brace) instead of `` `...${fieldDefinition.type}` ``.
2026-03-14 07:59:42 +00:00
Sonarly Claude Code e2c015ed76 Invalid timezone "ETC/UNKNOWN" in workspace member crashes date rendering
https://sonarly.com/issue/14644?type=bug

The `TimeZoneAbbreviation` component passes the workspace member's `timeZone` value directly to `Temporal.Instant.toZonedDateTimeISO()` without validation. When the database contains the invalid value `"ETC/UNKNOWN"`, the Temporal polyfill throws a `RangeError` because it cannot construct a `DateTimeFormat` with that timezone.

Fix: Added timezone validation in `useUserTimezone` to prevent invalid IANA timezone strings from propagating to `Temporal.Instant.toZonedDateTimeISO()` and crashing the app.

**Changes:**

1. **New utility `isValidTimeZone`** (`packages/twenty-front/src/modules/localization/utils/isValidTimeZone.ts`): Uses `Intl.DateTimeFormat(undefined, { timeZone })` to validate timezone strings — the same validation mechanism the Temporal polyfill uses internally. Invalid timezones cause `DateTimeFormat` to throw a `RangeError`, which we catch and return `false`.

2. **Updated `useUserTimezone` hook** (`packages/twenty-front/src/modules/ui/input/components/internal/date/hooks/useUserTimezone.ts`): Before using the workspace member's timezone, we now validate it with `isValidTimeZone()`. If the stored timezone is invalid (like `"ETC/UNKNOWN"`), the hook falls back to the browser's system timezone instead of passing the bad value downstream to all 30+ consumers.

3. **Tests**: Added a test case to the existing `useUserTimezone.test.tsx` for the invalid timezone scenario, and a new test file for the `isValidTimeZone` utility covering both valid IANA timezones and invalid strings.

**Note:** The deeper issue is that the server accepts arbitrary strings for the `timeZone` field with no IANA validation. A server-side fix (adding validation on the workspace member `timeZone` field against the `IANA_TIME_ZONES` constant from `twenty-shared`) would prevent bad data from being written in the first place, but this frontend fix provides immediate protection for all date rendering paths.
2026-03-14 04:22:37 +00:00
2 changed files with 2 additions and 1 deletions
@@ -6,6 +6,7 @@ export const FIELD_NOT_OVERWRITTEN_AT_DRAFT = [
FieldMetadataType.LINKS,
FieldMetadataType.MULTI_SELECT,
FieldMetadataType.RATING,
FieldMetadataType.RICH_TEXT,
FieldMetadataType.SELECT,
FieldMetadataType.FILES,
];
@@ -83,7 +83,7 @@ export const computeDraftValueFromString = <FieldValue>({
}
throw new CustomError(
`Record field type not supported : ${fieldDefinition.type}}`,
`Record field type not supported : ${fieldDefinition.type}`,
'RECORD_FIELD_TYPE_NOT_SUPPORTED',
);
};