Skip to content

Fix reported data grid, editor, and filter UX issues#1815

Open
datlechin wants to merge 9 commits into
mainfrom
fix/ux-datagrid-editor-filters
Open

Fix reported data grid, editor, and filter UX issues#1815
datlechin wants to merge 9 commits into
mainfrom
fix/ux-datagrid-editor-filters

Conversation

@datlechin

Copy link
Copy Markdown
Member

What

Fixes a batch of data grid, editor, and filter UX issues reported after 30 minutes of real use. Most were separate complaints; two of them share a single root cause.

Fixes

Data grid

  • Resizing a column no longer triggers a sort. Header mouse-downs that land in the resize zone now let AppKit own the drag; clicking the header still sorts.
  • Hidden columns stay hidden. The capture path was overwriting the tab's whole column layout on every resize/move/open, wiping the hidden set, so hidden columns reappeared on the next requery. Geometry writes now go through a session-syncing helper that preserves the hidden set and keeps the TabSession mirror in sync.
  • Column layout is remembered per table across sessions. Width, order, and visibility persist and survive reloads; in-session resizes merge on top of the saved layout. Scoping moved from (connection, table) to connection + database + schema + table (matching FilterSettingsStorage), so two tables with the same name in different databases no longer overwrite each other's layout.
  • Reset Columns button in the Columns popover restores widths, order, and visibility to defaults.

Errors

  • Query and filter errors show in a scrollable, selectable, copyable inline banner with a Fix with AI action, instead of a modal that cut long messages off. The modal path and its now-dead helpers were removed.

Editor / filter

  • The editor autocomplete panel no longer draws over the bottom status bar. It's constrained to the editor's bounds and dismisses on any outside click. This was the single root cause behind the "Columns / + Add buttons went dead" and "mouse died in the SQL editor" reports. Also fixed a retain cycle in the vendored find panel's event monitor.
  • The filter autocomplete no longer pops up on empty input, and pressing Escape to dismiss it no longer also closes the filter bar.

Not changed on purpose

  • Backspace deleting both characters of an empty auto-inserted pair ((), '') is the standard Xcode / VS Code / DataGrip behavior and was left as-is.

Notes

  • Column-layout persistence was refactored to a composite-keyed store. The protocol signature change updated every caller and all test mocks in the same change. A one-time clean-slate migration drops the old table-name-only format (no compatibility shim), so existing saved column widths reset once.
  • FileColumnLayoutPersister is now a shared instance; the migration runs only on it, so tests stay isolated from real user defaults.

Tests

  • New tests for the exact regressions: the hidden-column wipe across a geometry-persist cycle, database/schema key isolation, and the nil-saved-layout reset path.
  • Updated the filter autocomplete and ColumnLayoutState geometry tests; updated all ColumnLayoutPersisting mocks to the new key API.

Verification

  • swiftlint lint --strict clean on all changed files.

@mintlify

mintlify Bot commented Jul 6, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
TablePro 🟢 Ready View Preview Jul 6, 2026, 9:17 AM

💡 Tip: Enable Workflows to automatically generate PRs for you.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: fd3e2067fb

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

if !latestRows.columns.isEmpty {
coordinator.isRebuildingColumns = true
let savedLayout = coordinator.savedColumnLayout(binding: columnLayout)
let savedLayout = coordinator.resolvedColumnLayout(binding: columnLayout, liveWidths: liveColumnWidths)

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Avoid merging default widths over saved layouts

When the grid is remounted with rows already present, such as switching a loaded table from JSON/Structure back to Data after loading a saved layout, makeNSView has already built default-width columns before the table configuration can load the persisted layout. Passing those widths into resolvedColumnLayout here overwrites every saved width with the defaults, so saved column widths appear to reset even though FileColumnLayoutPersister has the right data. Only merge live widths when they are known to come from the same applied layout/table, or skip the merge on the first post-mount reconcile.

Useful? React with 👍 / 👎.


@ViewBuilder
private func executionErrorBanner(tab: QueryTab) -> some View {
if let error = tab.display.activeResultSet?.errorMessage ?? tab.execution.errorMessage {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Prefer the contextual execution error

When a multi-statement execution fails, handleMultiStatementError stores the useful Statement x/y failed: ... text in tab.execution.errorMessage but the active error result set only contains error.localizedDescription. Because this coalescing prefers the result-set error, the new inline banner drops the statement number/total and users can no longer tell which statement failed, especially when the first statement fails and there is no useful result-tab context. Prefer the execution error when both are present or put the contextual message on the error result set.

Useful? React with 👍 / 👎.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 5ac5d45ed3

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

current: ColumnLayoutTableKey?,
liveWidths: [String: CGFloat]
) -> [String: CGFloat] {
previous == current ? liveWidths : [:]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Don't merge live widths when both layout keys are nil

When both layout keys are nil, this treats the old grid and new grid as the same identity. TableStructureView creates its DataGridView without tableName/tabType, so switching between structure subtabs after saving widths for each subtab will pass the previous subtab's live widths into the newly selected subtab and overwrite any matching column names in that subtab's saved layout. Only preserve live widths when there is a non-nil table key match or add another stable layout identity for non-table grids.

Useful? React with 👍 / 👎.

Comment on lines +482 to +483
onFixWithAI: AppSettingsManager.shared.ai.enabled && tab.tabType == .query
? { coordinator.fixErrorWithAI(query: tab.execution.errorQuery ?? tab.content.query, error: error) }

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Keep Fix with AI available for table filter errors

When a table tab fails because a user-entered raw filter or scoped browse query is invalid, tab.tabType is .table, so this disables onFixWithAI even though handleQueryExecutionError now records the failed SQL in tab.execution.errorQuery. The old failure sheet offered the AI fix for non-restore execution failures regardless of tab type, and this new banner path removes that recovery option for filter errors; gate the button on having a query/error to send rather than on .query only.

Useful? React with 👍 / 👎.

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