Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Query result columns now follow the order in the SELECT. Adding or removing a column no longer leaves new columns stuck at the end of the grid. (#1565)
- JSON file import works again. It failed to load in 0.48.0.
- SQL export quotes empty or malformed values in numeric columns instead of writing them unquoted, which could produce invalid INSERT statements.

### Added

- Each filter row has a checkbox to turn it on or off and an Apply button to filter by just that row. The main Apply runs every active filter, and disabled filters stay in the panel for later. (#1561)
Expand Down
2 changes: 1 addition & 1 deletion TablePro/Views/Results/DataGridColumnPool.swift
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ final class DataGridColumnPool {
if slot < visibleCount {
let columnName = schema.columnNames[slot]
let resolvedWidth = willRestoreWidths
? (savedLayout?.columnWidths[columnName] ?? 100)
? (savedLayout?.columnWidths[columnName] ?? widthCalculator(columnName, slot))
: widthCalculator(columnName, slot)
configureColumn(
column,
Expand Down
10 changes: 8 additions & 2 deletions TablePro/Views/Results/DataGridCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,14 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
}

func savedColumnLayout(binding: ColumnLayoutState) -> ColumnLayoutState? {
if tabType == .table,
let connectionId,
guard tabType == .table else {
guard !binding.columnWidths.isEmpty else { return nil }
var layout = binding
layout.columnOrder = nil
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 query column drags from snapping back immediately

When a user drags a column in a query result, tableViewColumnDidMove immediately calls persistColumnLayoutToStorage(), which writes the captured order back through the columnLayout binding; that state change causes updateNSView to call savedColumnLayout and reconcile the pool again. Because this line strips columnOrder for every non-table tab, the next SwiftUI update recomputes schema/SELECT order and moves the column back right after the drag, rather than keeping the drag for the current view as intended.

Useful? React with 👍 / 👎.

return layout
}

if let connectionId,
let tableName,
!tableName.isEmpty,
let stored = layoutPersister.load(for: tableName, connectionId: connectionId) {
Expand Down
35 changes: 28 additions & 7 deletions TableProTests/Views/Results/TableViewCoordinatorLayoutTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
//

import Foundation
import TableProPluginKit
import SwiftUI
import TableProPluginKit
import Testing

@testable import TablePro
Expand Down Expand Up @@ -97,20 +97,41 @@ struct TableViewCoordinatorLayoutTests {
#expect(coordinator.savedColumnLayout(binding: ColumnLayoutState()) == nil)
}

@Test("Non-table tab uses the binding directly")
func nonTableTabUsesBinding() {
@Test("Query tab drops a stale saved column order so new columns keep their query position")
func queryTabDropsStaleColumnOrder() {
let coordinator = makeCoordinator(
tabType: .query,
connectionId: nil,
tableName: nil,
persister: FakeColumnLayoutPersister()
)
let resolved = coordinator.savedColumnLayout(binding: nonEmptyLayout())
#expect(resolved?.columnWidths == ["id": 60])
var binding = ColumnLayoutState()
binding.columnWidths = ["id": 60, "business_model": 120]
binding.columnOrder = ["id", "business_model"]

var expected = ColumnLayoutState()
expected.columnWidths = ["id": 60, "business_model": 120]

#expect(coordinator.savedColumnLayout(binding: binding) == expected)
}

@Test("Query tab keeps remembered widths when there is no saved order")
func queryTabKeepsWidths() {
let coordinator = makeCoordinator(
tabType: .query,
connectionId: nil,
tableName: nil,
persister: FakeColumnLayoutPersister()
)

var expected = ColumnLayoutState()
expected.columnWidths = ["id": 60]

#expect(coordinator.savedColumnLayout(binding: nonEmptyLayout()) == expected)
}

@Test("Non-table tab returns nil when binding is empty")
func nonTableTabEmptyReturnsNil() {
@Test("Query tab returns nil when binding is empty")
func queryTabEmptyReturnsNil() {
let coordinator = makeCoordinator(
tabType: .query,
connectionId: nil,
Expand Down
Loading