Skip to content

feat(datagrid): add visible add and remove buttons to the table structure editor (#1319)#1451

Merged
datlechin merged 3 commits into
mainfrom
fix/1319-structure-add-buttons
May 28, 2026
Merged

feat(datagrid): add visible add and remove buttons to the table structure editor (#1319)#1451
datlechin merged 3 commits into
mainfrom
fix/1319-structure-add-buttons

Conversation

@datlechin

@datlechin datlechin commented May 28, 2026

Copy link
Copy Markdown
Member

Fixes #1319 — the table structure editor has no visible button to add a column, index, or foreign key. The reporter (on macOS 14) found only the Add Index entry by right-click and missed the Add Column one; the maintainer agreed to track this for UI/UX improvement.

Why it was undiscoverable

TableStructureView's toolbar was only a centered segmented sub-tab picker — no + anywhere. The only add affordances were the right-click empty-space menu (one entry per sub-tab) and the Cmd+Shift+N shortcut. The EmptyStateView.indexes(onAdd:) / .foreignKeys(onAdd:) convenience initializers had been sitting unused, waiting for this work. The docs/features/table-structure.mdx page already described "Open Structure → Columns, click +" — the docs were aspirational; this PR makes the app match what it says.

The fix

Add / Remove controls live on the existing bottom status bar, in the trailing slot that already hosts Columns / Filters / Pagination in Data mode. Each mode owns that slot:

  • Data mode: Columns, Filters, Pagination (unchanged).
  • Structure mode: a joined ControlGroup with + and , labels and capability adapt to the active sub-tab (Columns / Indexes / Foreign Keys).
  • JSON mode: empty.

The Data | Structure | JSON picker stays anchored at the leading edge in all modes — it does not shift position when the mode changes.

+ routes to gridDelegate.dataGridAddRow() (same path as Cmd+Shift+N). routes to gridDelegate.dataGridDeleteRows(selectedRows) (same path as right-click Delete, and now wired to Cmd+Delete). Tooltip and accessibility label per sub-tab: Add Column / Add Index / Add Foreign Key and the matching Remove labels. + is disabled when the sub-tab's capability flag is false; is also disabled when no row is selected. Controls hide entirely when !connection.type.supportsSchemaEditing or on the read-only .ddl / .parts sub-tabs.

When the Indexes or Foreign Keys sub-tab is loaded and empty, the grid is replaced by ContentUnavailableView with a labelled Add button (EmptyStateView.indexes(onAdd:) / .foreignKeys(onAdd:)).

Architecture

  • StructureFooterState (new, @Observable) is the single source of truth for capability / label state. TableStructureView publishes to it on appear, sub-tab change, and selection change; MainStatusBarView reads it to decide which buttons to render and when to enable them.
  • StructureViewActionHandler.removeRow is added alongside addRow. MainContentCommandActions.deleteSelectedRows routes to it when resultsViewMode == .structure, giving Cmd+Delete parity with Cmd+Shift+N.
  • MainStatusBarView is now mode-aware: in Structure mode the data-only chrome (row info, Columns popover, Filters toggle, pagination) is hidden, so the status bar shows just the picker and + / .

Considered and rejected

  • Separate footer above the global status bar. Causes a visual double bar with the existing Data | Structure | JSON row; native apps consolidate into one footer.
  • Leading-edge + / next to the picker. Pushes the picker sideways when switching modes — the segmented control should not move.
  • Top-toolbar + / next to the segmented picker. Native macOS reserves the top toolbar for window-level actions; bottom is the list-editor pattern.

Tests

  • StructureGridDelegateAddRowTests (new) covers dataGridAddRow() per sub-tab (columns / indexes / FK route to the correct mutator; ddl / parts are no-ops; SQLite indexes is a no-op via supportsAddIndex: false) and dataGridDeleteRows([0]) safety on the read-only sub-tabs.
  • StructureActionHandlerTests covers addRow and removeRow closure dispatch.
  • CommandActionsDispatchTests asserts addNewRow and deleteSelectedRows route to structureActions?.addRow?() / structureActions?.removeRow?() when resultsViewMode == .structure.
  • MainStatusBarLayoutTests updated for the new structureFooterState / onStructureAdd / onStructureRemove params.

Out of scope

  • TablePlus-style inline "Make this an FK from this column" UX. Separate enhancement.
  • The unused EmptyStateView.columns(onAdd:) and .checkConstraints(onAdd:) convenience initializers — this PR uses .indexes and .foreignKeys; the other two are dead but unrelated cleanup.

@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: 249d8b74a6

ℹ️ 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".

Comment on lines +319 to +323
private var shouldShowIndexesEmptyState: Bool {
loadedTabs.contains(.indexes)
&& structureChangeManager.workingIndexes.isEmpty
&& connection.type.supportsAddIndex
}

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 Gate empty add states on schema editing

For schema-read-only connections that still expose metadata capabilities (for example CockroachDB has supportsSchemaEditing == false while supportsForeignKeys == true, and index add support defaults to true), this condition replaces the read-only grid with an empty state containing an active Add button. Clicking it calls gridDelegate.dataGridAddRow(), whose index/FK paths do not check supportsSchemaEditing, so users can create unsavable structure changes even though the footer is correctly hidden and the grid is non-editable. Include connection.type.supportsSchemaEditing in these empty-state gates (and the FK one below) or render a non-action empty state for read-only connections.

Useful? React with 👍 / 👎.

@datlechin datlechin force-pushed the fix/1319-structure-add-buttons branch from 249d8b7 to b6e2698 Compare May 28, 2026 05:42
@datlechin datlechin force-pushed the fix/1319-structure-add-buttons branch from b6e2698 to b018a7c Compare May 28, 2026 05:47
@datlechin datlechin merged commit b877ff9 into main May 28, 2026
2 checks passed
@datlechin datlechin deleted the fix/1319-structure-add-buttons branch May 28, 2026 11:22
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