Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 87ca4aaedc fix: handle non-string field types in useSortedArray to prevent localeCompare crash
https://sonarly.com/issue/17943?type=bug

Sorting the relations table by the "App" column on settings object detail pages crashes because `isCustom` is a boolean but the table metadata declares it as a string, causing `localeCompare` to be called on a boolean value.

Fix: **Two-layer fix:**

1. **Root cause fix — 3 table metadata files:** Changed `fieldType` from `'string'` to `'number'` for the `isCustom` field in all 3 table metadata constants where it was incorrect:
   - `SettingsObjectRelationsTable.tsx` (the crash site from the Sentry error)
   - `SettingsAiAgentTableMetadata.ts` (same bug, not yet reported)
   - `SettingsSkillTableMetadata.ts` (same bug, not yet reported)

   The `isCustom` field is a `Boolean` in the GraphQL schema. Since `TableFieldMetadata.fieldType` only supports `'string' | 'number'`, `'number'` is correct for booleans — JavaScript boolean arithmetic (`true - false = 1`) sorts correctly in the number comparator path.

2. **Defensive fix — `useSortedArray.ts`:** Replaced the unsafe `(value as string)?.localeCompare()` pattern with `String(value ?? '').localeCompare()`. This ensures that even if a future field is incorrectly declared as `'string'` when it's not, the sort won't crash — it will coerce the value to a string first. The `?? ''` handles null/undefined values that would otherwise become `"null"` or `"undefined"`.
2026-03-24 14:53:16 +00:00
4 changed files with 7 additions and 9 deletions
@@ -57,7 +57,7 @@ const SETTINGS_OBJECT_RELATION_TABLE_METADATA: TableMetadata<FieldMetadataItem>
{
fieldLabel: msg`App`,
fieldName: 'isCustom',
fieldType: 'string',
fieldType: 'number',
align: 'left',
},
{
@@ -34,13 +34,11 @@ export const useSortedArray = <T>(
return [...arrayToSort].sort((a: T, b: T) => {
if (sortFieldType === 'string') {
const aValue = String(a[sortFieldName] ?? '');
const bValue = String(b[sortFieldName] ?? '');
return sortOrder === 'AscNullsLast' || sortOrder === 'AscNullsFirst'
? (a[sortFieldName] as string)?.localeCompare(
b[sortFieldName] as string,
)
: (b[sortFieldName] as string)?.localeCompare(
a[sortFieldName] as string,
);
? aValue.localeCompare(bValue)
: bValue.localeCompare(aValue);
} else if (sortFieldType === 'number') {
return sortOrder === 'AscNullsLast' || sortOrder === 'AscNullsFirst'
? (a[sortFieldName] as number) - (b[sortFieldName] as number)
@@ -14,7 +14,7 @@ export const SETTINGS_AI_AGENT_TABLE_METADATA: TableMetadata<Agent> = {
{
fieldLabel: msg`Type`,
fieldName: 'isCustom',
fieldType: 'string',
fieldType: 'number',
align: 'left',
},
],
@@ -15,7 +15,7 @@ export const SETTINGS_SKILL_TABLE_METADATA: TableMetadata<Skill> = {
{
fieldLabel: msg`Type`,
fieldName: 'isCustom',
fieldType: 'string',
fieldType: 'number',
align: 'left',
},
],