improvement(tables): empty-state filter/sort builders + upsert conflict-column selection#5123
improvement(tables): empty-state filter/sort builders + upsert conflict-column selection#5123TheodoreSpeaks wants to merge 6 commits into
Conversation
…me/drop prompt `drizzle-kit push --force` only suppresses the data-loss confirm, not the rename-vs-drop disambiguation prompt. That prompt fires whenever a diff both adds and drops tables/columns at once (e.g. migration 0231 created sim_trigger_state while dropping the workspace_notification_* tables), and in CI it crashes with a bare "Interactive prompts require a TTY" stack trace. Catch that specific failure in the dev push step and emit a GitHub error annotation explaining the cause and the fix (drop the stale objects on the dev DB to match schema.ts — the same DROPs the versioned migration already applied to staging/prod), instead of leaving an opaque trace. Exit status is preserved either way. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…ct-column selection
|
The latest updates on your projects. Learn more about Vercel for GitHub. |
PR SummaryMedium Risk Overview Upsert Row gains an optional Conflict Column (basic Supporting changes: new Reviewed by Cursor Bugbot for commit bfaa366. Bugbot is set up for automated code reviews on this repo. Configure here. |
Greptile SummaryThis PR improves the table block UX and backend correctness across three areas: empty-state filter/sort builders now render a dashed "+ Add condition" button instead of a phantom blank row, the filter converter skips blank-column rows to prevent
Confidence Score: 5/5Safe to merge — all three feature areas are additive, backward-compatible, and the backend upsert logic is unchanged from staging. The conflict-column field is optional and the service-layer branching (auto-resolve on single unique, throw on multiple without target) is identical to the prior behaviour. The empty-state builder changes are purely UI and the blank-column skip in filterRulesToFilter is a safe guard with correct null propagation. The live-plan maxRows lookup is intentional and well-scoped. No files require special attention. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant UI as Block UI
participant Selector as table.columns selector
participant API as GET /api/table/[tableId]
participant Tool as upsert_row tool
participant Service as rows/service.ts
UI->>Selector: "fetchList({ context.tableId })"
Selector->>API: ensureQueryData(tableDetailQueryOptions)
API-->>Selector: table schema (live maxRows from billing)
Selector-->>UI: unique columns only
UI->>UI: User selects conflict column stored as conflictColumn
UI->>Tool: "execute({ data, conflictTarget })"
Tool->>Service: "POST /api/table/[id]/rows/upsert { data, conflictTarget }"
Service->>Service: find column by id OR name in uniqueColumns
alt conflictTarget provided
Service->>Service: validate it is a unique column
else single unique column
Service->>Service: auto-resolve targetColumnKey
else multiple unique, no target
Service-->>UI: Error: specify a conflict column
end
Service-->>UI: "{ row, operation: insert|update }"
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant UI as Block UI
participant Selector as table.columns selector
participant API as GET /api/table/[tableId]
participant Tool as upsert_row tool
participant Service as rows/service.ts
UI->>Selector: "fetchList({ context.tableId })"
Selector->>API: ensureQueryData(tableDetailQueryOptions)
API-->>Selector: table schema (live maxRows from billing)
Selector-->>UI: unique columns only
UI->>UI: User selects conflict column stored as conflictColumn
UI->>Tool: "execute({ data, conflictTarget })"
Tool->>Service: "POST /api/table/[id]/rows/upsert { data, conflictTarget }"
Service->>Service: find column by id OR name in uniqueColumns
alt conflictTarget provided
Service->>Service: validate it is a unique column
else single unique column
Service->>Service: auto-resolve targetColumnKey
else multiple unique, no target
Service-->>UI: Error: specify a conflict column
end
Service-->>UI: "{ row, operation: insert|update }"
Reviews (3): Last reviewed commit: "improvement(tables): unique-column picke..." | Re-trigger Greptile |
…e conflict column
|
@greptile review |
… on rename/drop prompt" This reverts commit 2626482.
| for (const rule of rules) { | ||
| // Skip incomplete rows (no column selected) so a blank builder row never | ||
| // serializes to a `{ '': ... }` predicate. | ||
| if (!rule.column) continue |
There was a problem hiding this comment.
Skipped rows break OR grouping
Medium Severity
When filterRulesToFilter skips a rule with no column, it ignores that rule’s logicalOperator. An incomplete row marked or between two valid conditions no longer starts a new OR group, so those conditions can be AND-combined instead of OR-combined at execution time.
Reviewed by Cursor Bugbot for commit 4d057c6. Configure here.
…ema (counts, ids, live plan row limit)
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes and found 1 potential issue.
There are 2 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit bfaa366. Configure here.
| metadata: table.metadata ?? null, | ||
| rowCount: table.rowCount, | ||
| maxRows: table.maxRows, | ||
| maxRows: maxRowsPerTable, |
There was a problem hiding this comment.
Live maxRows mismatches insert cap
Medium Severity
The table detail GET now returns maxRows from the workspace’s current billing plan, but row inserts still enforce the max_rows value stored on the table record (DB trigger). After a plan upgrade, API and get_schema can report a higher cap while inserts keep failing at the old limit, so capacity checks based on the response are wrong.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit bfaa366. Configure here.
|
@greptile review |


Summary
{ '': … }predicateBackwards compatibility
Type of Change
Testing
Tested manually; lint, api-validation:strict, and
tsc --noEmitpass; table row tests pass (20/20)Checklist