Skip to content

improvement(tables): empty-state filter/sort builders + upsert conflict-column selection#5123

Open
TheodoreSpeaks wants to merge 5 commits into
stagingfrom
feat/table-v2-block
Open

improvement(tables): empty-state filter/sort builders + upsert conflict-column selection#5123
TheodoreSpeaks wants to merge 5 commits into
stagingfrom
feat/table-v2-block

Conversation

@TheodoreSpeaks

@TheodoreSpeaks TheodoreSpeaks commented Jun 17, 2026

Copy link
Copy Markdown
Collaborator

Summary

  • Filter/sort builders now start empty with a "+ Add condition" affordance instead of a phantom blank row; removing the last row clears it
  • Filter converter skips blank-column rows so an empty builder can't serialize to a { '': … } predicate
  • Upsert Row gains an optional Conflict Column field to pick which unique column to match on
  • Upsert still auto-resolves when the table has a single unique column; when there are multiple and none is specified it throws an explicit error (clearer wording) instead of silently guessing — backend matching logic is otherwise unchanged from staging

Backwards compatibility

  • No behavior change for existing upserts: the Conflict Column field is optional and the backend logic (single unique → auto, multiple-without-target → throw) is identical to staging. Only the error message wording changed.

Type of Change

  • Improvement

Testing

Tested manually; lint, api-validation:strict, and tsc --noEmit pass; table row tests pass (20/20)

Checklist

  • Code follows project style guidelines
  • Self-reviewed my changes
  • Tests added/updated and passing
  • No new warnings introduced
  • I confirm that I have read and agree to the terms outlined in the Contributor License Agreement (CLA)

TheodoreSpeaks and others added 3 commits June 12, 2026 10:45
…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>
@vercel

vercel Bot commented Jun 17, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
docs Ready Ready Preview, Comment Jun 18, 2026 2:48am

Request Review

@cursor

cursor Bot commented Jun 17, 2026

Copy link
Copy Markdown

PR Summary

Medium Risk
Changes affect how table query filters are built from UI state and how upsert chooses the match column, which can alter workflow query results or upsert behavior if misconfigured.

Overview
Filter and sort builders no longer inject a default blank row when stored state is empty. Editors show a dashed Add filter condition / Add sort button instead; deleting the last rule clears the list rather than resetting a placeholder row. Read-only previews render nothing when there are no rules.

Filter serialization now ignores rules with no column selected, so an incomplete builder row cannot become a { '': … } predicate in API queries.

Upsert Row adds a Conflict Column block field (for tables with multiple unique columns), wired through block param mapping, the upsert tool, and the API body as conflictTarget. The multi–unique-column error message is aligned with that UX wording.

Reviewed by Cursor Bugbot for commit 4d057c6. Bugbot is set up for automated code reviews on this repo. Configure here.

Comment thread apps/sim/lib/table/query-builder/converters.ts
@greptile-apps

greptile-apps Bot commented Jun 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR polishes the table block's UX in two areas: (1) filter and sort builders now start empty with a dashed "+ Add condition" button instead of a phantom pre-populated row, and removing the last rule returns to that empty state; (2) the upsert tool gains an optional conflictColumn/conflictTarget field so users can select which unique column to match on when a table has more than one.

  • Filter/sort empty-state: filterRulesToFilter and sortRulesToSort already tolerate an empty array; a new !rule.column guard in the converter prevents a blank builder row from ever serializing to a { '': … } predicate.
  • Upsert conflict column: A short-input sub-block is wired through the param transformer to the existing conflictTarget path in the service; the service still throws a clear error when a table has 2+ unique columns and no target is provided.
  • CI migration step: The db:push --force invocation now captures stderr, detects the "Interactive prompts require a TTY" crash, and emits an actionable GitHub Actions error annotation.

Confidence Score: 5/5

Safe to merge — all three functional changes (empty-state builders, blank-column guard in the converter, conflict-column parameter wiring) are straightforward and correctly implemented.

The filter/sort empty-state refactor is well-contained: the store correctly transitions to an empty array, the converter already handled zero-length arrays, and the new !rule.column guard is the only serialization path change. The upsert conflict-column addition threads consistently through the block definition, tool params, and service (which still throws a clear error for un-resolved multi-unique tables). No behavioral regressions are apparent in any changed path.

No files require special attention.

Important Files Changed

Filename Overview
apps/sim/blocks/blocks/table.ts Adds conflictColumn short-input sub-block for upsert_row, passes it as conflictTarget via the param transformer (falls back to undefined on empty string); input params schema also updated
apps/sim/tools/table/upsert_row.ts Adds optional conflictTarget param (user-only visibility, consistent with tableId); spreads it into the request body only when truthy; pattern is consistent with existing tool params
apps/sim/lib/table/query-builder/converters.ts Added an early continue guard to skip rules with a blank column; correctly prevents blank predicates from an empty builder; all-blank array still returns null via the existing early-return path
apps/sim/lib/table/rows/service.ts Only changes the error-message wording for the multi-unique-column case; functional behaviour (still throws when conflictTarget is absent and table has 2+ unique columns) is unchanged
.github/workflows/migrations.yml Improves CI dev-push step: captures output, detects the Interactive prompts require a TTY crash, and emits an actionable GitHub Actions error annotation instead of a bare stack trace

Reviews (2): Last reviewed commit: "improvement(tables): throw on ambiguous ..." | Re-trigger Greptile

Comment thread apps/sim/lib/table/rows/service.ts Outdated
@TheodoreSpeaks

Copy link
Copy Markdown
Collaborator Author

@greptile review

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 4d057c6. Configure here.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 4d057c6. Configure here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant