eng-272 feat(crm): add normalized view query layer#382
Conversation
|
Warning Rate limit exceeded
Your organization is not enrolled in usage-based pricing. Contact your admin to enable usage-based pricing to continue reviews beyond the rate limit, or try again in 12 minutes and 28 seconds. ⌛ How to resolve this issue?After the wait time has elapsed, a review can be triggered using the We recommend that you space out your commits to avoid hitting the rate limit. 🚦 How do rate limits work?CodeRabbit enforces hourly rate limits for each developer per organization. Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout. Please see our FAQ for further information. ℹ️ Review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (7)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Sorry @Connorbelez, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
This stack of pull requests is managed by Graphite. Learn more about stacking. |
There was a problem hiding this comment.
Your free trial has ended. If you'd like to continue receiving code reviews, you can add a payment method here.
There was a problem hiding this comment.
Pull request overview
Adds a normalized “view state” + query layer in the CRM backend so view queries can return richer, standardized payloads (columns/fields/view metadata, normalized rows, aggregates), while still supporting the existing rows compatibility shape.
Changes:
- Introduces
resolveViewState()and shared helpers inconvex/crm/viewState.tsto centralize view definition + saved-view overlay resolution. - Updates
crm.viewQueries.queryViewRecordsto return normalized paging (page.rows) and aggregates, plus improved native/system-object pagination. - Extends calendar querying to return the same normalized metadata/rows/aggregates shape and adds tests for the new contracts.
Reviewed changes
Copilot reviewed 7 out of 7 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| convex/test/registerAuditLogComponent.ts | Registers additional aggregate components for audit-log testing. |
| convex/crm/viewState.ts | New module centralizing view resolution, column normalization, row-building, and aggregates computation. |
| convex/crm/viewQueries.ts | Refactors view querying to use resolved view state, adds normalized paging and aggregates, improves native/system pagination. |
| convex/crm/types.ts | Adds types for normalized rows/cells, aggregates, and page results. |
| convex/crm/fieldDefs.ts | Ensures isVisibleByDefault is always kept in sync with derived field metadata on update. |
| convex/crm/calendarQuery.ts | Exposes queryCalendarViewData and expands calendar results with normalized metadata/rows/aggregates. |
| convex/crm/tests/viewEngine.test.ts | Adds coverage for normalized payloads, saved-view overlays, calendar dispatch, and cursor behavior. |
Comments suppressed due to low confidence (1)
convex/crm/calendarQuery.ts:367
validateCalendarViewnow callsresolveViewState(), which already verifies org context, viewDef ownership, and loadsobjectDef. The subsequentif (!viewDef || viewDef.orgId !== orgId)check and the extractx.db.get(viewDef.objectDefId)re-fetch are redundant (and the null-check is effectively unreachable). Consider relying onviewState.viewDef/viewState.objectDefdirectly to avoid duplicate reads and dead code paths.
async function validateCalendarView(
ctx: CrmQueryCtx,
viewDefId: Id<"viewDefs">,
orgId: string
): Promise<ValidatedCalendarContext> {
const viewState = await resolveViewState(ctx, viewDefId);
const { viewDef } = viewState;
if (!viewDef || viewDef.orgId !== orgId) {
throw new ConvexError("View not found or access denied");
}
if (viewDef.viewType !== "calendar") {
throw new ConvexError("View is not a calendar view");
}
if (viewDef.needsRepair) {
throw new ConvexError("View needs repair before use");
}
const boundFieldId = viewDef.boundFieldId;
if (!boundFieldId) {
throw new ConvexError("Calendar view is missing a bound date field");
}
const objectDef = await ctx.db.get(viewDef.objectDefId);
if (!objectDef || objectDef.orgId !== orgId || !objectDef.isActive) {
throw new ConvexError("Object not found or access denied");
}
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
convex/crm/fieldDefs.ts (1)
278-285: Remove the duplicatepatch.isVisibleByDefaultassignment.
patch.isVisibleByDefaultis set twice to the same value (Line 278 and Line 284). Keeping a single assignment avoids ambiguity during future edits.Suggested cleanup
patch.isVisibleByDefault = effectiveFieldContract.isVisibleByDefault; patch.normalizedFieldKind = effectiveFieldContract.normalizedFieldKind; patch.rendererHint = effectiveFieldContract.rendererHint; patch.layoutEligibility = effectiveFieldContract.layoutEligibility; patch.aggregation = effectiveFieldContract.aggregation; patch.editability = effectiveFieldContract.editability; - patch.isVisibleByDefault = effectiveFieldContract.isVisibleByDefault;🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@convex/crm/fieldDefs.ts` around lines 278 - 285, The patch object is assigning patch.isVisibleByDefault twice from effectiveFieldContract; remove the redundant assignment so patch.isVisibleByDefault is only set once (keep the single assignment and delete the duplicate) in the block that also sets patch.normalizedFieldKind, patch.rendererHint, patch.layoutEligibility, patch.aggregation, and patch.editability to avoid ambiguity during future edits.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@convex/crm/calendarQuery.ts`:
- Around line 497-504: The code is re-querying base viewFilters (viewFilterRows)
instead of using the resolved filter set from resolveViewState(), which can
cause returned events to mismatch the payload's view metadata; replace the
query+parse flow so you use viewState.view.filters (the resolved filters) as the
source: remove the ctx.db.query("viewFilters")/withIndex call that produces
viewFilterRows, pass viewState.view.filters into parseViewFilters (or the
appropriate parser) along with fieldDefsById to get parsedFilters/skippedCount,
then call applyViewFilters(assembled, parsedFilters, fieldDefsById) as before so
the applied filters match the resolved viewState. Ensure you reference
resolveViewState(), viewState.view.filters, parseViewFilters, applyViewFilters,
assembled, and fieldDefsById when making the change.
In `@convex/crm/viewQueries.ts`:
- Around line 164-171: The function convertViewFiltersToRecordFilters currently
drops the logicalOperator from each ViewFilterDefinition; update it to copy
logicalOperator into the returned RecordFilter so table and kanban queries
preserve OR/AND semantics. In the convertViewFiltersToRecordFilters
implementation, include filter.logicalOperator in the mapped object (alongside
fieldDefId, operator from normalizeViewFilterOperator(filter.operator), and
value) so each RecordFilter carries the same logicalOperator as its source
ViewFilterDefinition. Ensure the function signature/types
(convertViewFiltersToRecordFilters, ViewFilterDefinition, RecordFilter) are
consistent with this added property.
In `@convex/crm/viewState.ts`:
- Around line 225-240: The current viewFilters.map block blindly JSON.parses
viewFilter.value which converts string values like "123"/"true"/"null" into
non-string types and breaks string-based matching; instead, use the field
context (lookup the field definition by viewFilter.fieldDefId from the
surrounding field definitions collection) and the viewFilter.operator to decide
parsing: if the field type or operator expects a numeric/boolean/null (e.g.,
number/date/boolean fields or operators like "in"/"gt"/"lt"), attempt JSON.parse
(with try/catch) and coerce appropriately; otherwise preserve the original
string value (no JSON.parse). Update the mapping code around viewFilters.map,
referencing viewFilter.fieldDefId, viewFilter.operator and the field definition
(e.g., fieldDef.type) to implement field/operator-aware parsing and fall back
safely to the original string on parse errors.
- Around line 496-503: The code currently returns the full record object in the
row (the `record` property) which leaks hidden fields; change the mapping that
returns `{ record, cells: ... }` to return a projected record that contains only
allowed metadata plus the visible fields used to build `cells`. Concretely, in
the block that maps `records` (referencing `records.map`, `visibleColumns`, and
`record`), construct a new `projectedRecord` (or similarly named object) that
copies only the record id/metadata and populates `fields` by iterating
`visibleColumns` and pulling `record.fields[column.name]`, then return that
`projectedRecord` instead of the original `record` so clients cannot access
hidden fields via `row.record.fields`.
---
Nitpick comments:
In `@convex/crm/fieldDefs.ts`:
- Around line 278-285: The patch object is assigning patch.isVisibleByDefault
twice from effectiveFieldContract; remove the redundant assignment so
patch.isVisibleByDefault is only set once (keep the single assignment and delete
the duplicate) in the block that also sets patch.normalizedFieldKind,
patch.rendererHint, patch.layoutEligibility, patch.aggregation, and
patch.editability to avoid ambiguity during future edits.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: a5e7b350-8a78-4107-af9f-d66f8da48f47
📒 Files selected for processing (7)
convex/crm/__tests__/viewEngine.test.tsconvex/crm/calendarQuery.tsconvex/crm/fieldDefs.tsconvex/crm/types.tsconvex/crm/viewQueries.tsconvex/crm/viewState.tsconvex/test/registerAuditLogComponent.ts
Merge activity
|
feat(crm): add normalized view query layer responding to feedback <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Calendar views now support date range filtering with granular time grouping (day/week/month). * View aggregates (sum, count, average, min, max) are now calculated and included in view responses. * User-defined saved view settings (column ordering, visibility, filtering) are now applied to view queries. * **Bug Fixes** * Fixed pagination cursor formatting. * Corrected audit log action type for record updates. * **Tests** * Expanded test coverage for view types and pagination scenarios. <!-- end of auto-generated comment: release notes by coderabbit.ai -->

feat(crm): add normalized view query layer
responding to feedback
Summary by CodeRabbit
Release Notes
New Features
Bug Fixes
Tests