refactor: simplify query hooks and use explicit field projections#450
Conversation
📝 WalkthroughWalkthroughThis pull request refactors multiple query hook files by removing query builder patterns ( Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 2 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches
🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
services/platform/app/features/settings/teams/hooks/queries.ts (1)
17-24: 🧹 Nitpick | 🔵 TrivialMinor inconsistency in null handling across hooks.
useTeamsreturnsdata ?? null(Line 12), whileuseTeamMembersreturnsdatadirectly (Line 21). This creates an inconsistent API whereteamsis alwaysT[] | nullbutteamMembersisT[] | undefined.Consider aligning both hooks to use the same pattern for consistency.
♻️ Suggested fix for consistency
export function useTeamMembers(collection: Collection<TeamMember, string>) { const { data, isLoading } = useLiveQuery(() => collection); return { - teamMembers: data, + teamMembers: data ?? null, isLoading, }; }
🤖 Fix all issues with AI agents
In `@services/platform/app/features/custom-agents/hooks/queries.ts`:
- Around line 94-99: The hook useAvailableIntegrations currently coerces
undefined to null (returning integrations: data ?? null) which is inconsistent
with sibling hooks useCustomAgentVersions, useCustomAgentWebhooks, and
useAvailableTools that return data directly; update useAvailableIntegrations to
return the raw data value (integrations: data) so its nullability matches the
other simplified hooks (leave the useLiveQuery call and variable names
unchanged).
In `@services/platform/app/features/customers/hooks/queries.ts`:
- Around line 54-66: The projection object used in the .select calls is
duplicated between useCustomers and useCustomerByEmail; extract the shared shape
into a single constant (e.g., CUSTOMER_PROJECTION) and reuse it in both .select
invocations to avoid drift when Customer changes. Create CUSTOMER_PROJECTION
containing the mapped fields (_id, _creationTime, organizationId, name, email,
externalId, status, source, locale, address, metadata) and replace the inline
object in useCustomers (the .select(({ c }) => ({ ... })) shown) and in
useCustomerByEmail (lines 26–38) to reference that constant so updates occur in
one place. Ensure the constant is typed to match the expected return shape and
imported/available to both hooks if moved out of the file.
In `@services/platform/app/routes/dashboard/create-organization.tsx`:
- Around line 26-31: The current code uses organizations[0]?.organizationId for
navigation which can be undefined if the first entry lacks organizationId and
later the component returns null, causing a blank page; change this to compute a
single canonical first valid ID by finding the first organization with a truthy
organizationId (e.g., const firstOrgId = organizations.find(o =>
o.organizationId)?.organizationId), then use that same firstOrgId for both the
navigate call and the render guard so navigation and rendering are consistent
(update usages around navigate({...}) and the subsequent return null check to
reference this computed firstOrgId).
In `@services/platform/app/routes/dashboard/index.tsx`:
- Around line 33-41: The effect assumes organizations[0]?.organizationId exists
and skips navigation when orgs are non-empty but lack organizationId, causing a
permanent loading state; update the logic in the component that computes
firstOrgId (and the navigation branch using navigate) to choose the first
organization object with a defined organizationId (e.g., use
organizations.find(o => o.organizationId) to derive a validId) and add an
explicit fallback branch that navigates to '/dashboard/create-organization' when
no validId is found, ensuring both the non-empty-without-id and empty cases
trigger navigation.
Simplify useLiveQuery calls by replacing verbose q.from/select patterns with direct collection references where no filtering is needed. Use explicit field projections instead of pass-through selects for type safety. Add optional chaining for safer organization ID access in dashboard routes.
Align test assertions with the new select behavior that projects individual fields instead of passing through the row object.
c2de1d0 to
7099ccb
Compare
Summary
useLiveQuerycalls by replacing verboseq.from({ x: collection }).select(({ x }) => x)patterns with direct() => collectionreferences where no filtering/transformation is needed.select()instead of pass-through selectors for better type safety (customers, custom agents, chat agents)api.d.tsTest plan
🤖 Generated with Claude Code
Summary by CodeRabbit
New Features
Bug Fixes