Compare commits

...
Author SHA1 Message Date
Sonarly Claude Code 3c0a7d931d isRecordMatchingFilter throws on stale filter referencing missing custom field
https://sonarly.com/issue/11530?type=bug

The optimistic cache update crashes when iterating cached Apollo queries whose filters reference a custom relation field (`teamManagingThisPerson`) that no longer exists in the person object's metadata.

Fix: Replaced the hard `throw` in `isRecordMatchingFilter` (line 218) with `return true` when a filter key cannot be resolved to any field in the object's metadata.

**Why this fixes the bug:** When `triggerUpdateRecordOptimisticEffect` iterates over all cached Apollo queries for an object type, it calls `isRecordMatchingFilter` with each query's stored filter variables. If a cached query's filter references a custom field that was since deleted or deactivated (e.g., `teamManagingThisPerson` on `person`), the field lookup fails and the throw crashes the entire optimistic update flow.

**Why `return true`:** This treats an unresolvable filter condition as vacuously satisfied, meaning "this filter key doesn't constrain the result." This is safe because:
1. The server already returned correctly filtered data — the optimistic check only determines cache membership
2. Returning `true` preserves records in cached queries, avoiding incorrect eviction
3. The worst case is a brief UI inconsistency until the server response arrives, which is strictly better than a crash

The comment follows the team's existing short-form `//` comment style and explains the business logic (WHY), not the code (WHAT).
2026-03-09 09:21:20 +00:00
Sonarly Claude Code 2d2a85bb05 useGetViewGroupsFilters throws when view has viewGroups but null mainGroupByFieldMetadataId
https://sonarly.com/issue/3794?type=bug

The `useGetViewGroupsFilters` hook unconditionally throws when a view has hidden viewGroups but `mainGroupByFieldMetadataId` is null, a legitimate data state after the fieldMetadataId migration.

Fix: The fix addresses three sites where `throw new Error('mainGroupByFieldMetadataId is required')` crashes when a view has orphaned viewGroups but no `mainGroupByFieldMetadataId` (null after the fieldMetadataId migration or during cache transitions).

**`useGetViewGroupsFilters.ts`** (primary crash site from Sentry): Moved the `isDefined(mainGroupByFieldMetadataId)` check before iterating viewGroups, returning an empty array early. This is the correct behavior — without a group-by field, hidden viewGroup visibility filters are meaningless.

**`useSaveCurrentViewGroups.ts`**: Changed throw to early return in `saveViewGroups` callback, matching the existing early-return pattern used 3 times earlier in the same file for other precondition checks (lines 28-30, 34-36, 40-42).

**`useReorderRecordGroups.ts`**: Changed throw to early return in `reorderRecordGroups` callback. If there's no group field metadata, the reorder operation simply cannot proceed — silently returning is the correct behavior (same as the `isDeeplyEqual` check on line 63-67 which also returns without action).
2026-03-09 08:52:56 +00:00
Sonarly Claude Code 96022d8122 View with hidden groups crashes when mainGroupByFieldMetadataId is null
https://sonarly.com/issue/11500?type=bug

The `useGetViewGroupsFilters` hook throws an unhandled error when a view has hidden viewGroups but its `mainGroupByFieldMetadataId` field is null/undefined, crashing the companies page.

Fix: Replaced the hard `throw new Error('mainGroupByFieldMetadataId is required')` inside the `.map()` callback with an early return of `[]` at the top of the hook, before accessing `viewGroups`.

**What changed:** When `currentView` is undefined or its `mainGroupByFieldMetadataId` is null/undefined, the hook now returns an empty filter array instead of crashing. This is the correct semantic — if no group-by field is configured, there are no group-visibility filters to exclude.

**Why this is safe:** The filters produced by this hook are spread into the record filters array in `useGetRecordIndexTotalCount`. An empty array simply means "no additional group visibility filters" — the query works fine without them, it just won't exclude hidden groups from the count (which is the expected behavior when grouping isn't configured).

This also matches the pattern used in `mapViewGroupsToRecordGroupDefinitions` which returns `[]` when the field metadata is missing rather than throwing.

The `.filter(isDefined)` after `.map()` was also removed since the map callback always returns a concrete object (never `undefined`) — this was dead code.
2026-03-09 08:51:23 +00:00
@@ -215,12 +215,10 @@ export const isRecordMatchingFilter = ({
);
if (!isDefined(objectMetadataField)) {
throw new Error(
'Field metadata item "' +
filterKey +
'" not found for object metadata item ' +
objectMetadataItem.nameSingular,
);
// Stale cached queries can reference fields that no longer exist
// in the metadata (e.g. deleted or deactivated custom fields).
// Skip the filter condition to avoid crashing optimistic updates.
return true;
}
switch (objectMetadataField.type) {