Skip to content

Commit bbc52c0

Browse files
authored
fix: scroll data grid to top on page change (#574)
1 parent ceb6b10 commit bbc52c0

4 files changed

Lines changed: 22 additions & 2 deletions

File tree

TablePro/Models/Query/QueryTab.swift

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,9 @@ struct QueryTab: Identifiable, Equatable {
394394
// Version counter incremented when FK/metadata arrives (Phase 2), used to invalidate caches
395395
var metadataVersion: Int
396396

397+
// Version counter incremented on pagination changes, used to scroll grid to top
398+
var paginationVersion: Int
399+
397400
/// Whether the editor content differs from the last saved/loaded file content.
398401
/// Returns false for tabs not backed by a file.
399402
/// Uses O(1) length pre-check to avoid O(n) string comparison on every keystroke.
@@ -441,6 +444,7 @@ struct QueryTab: Identifiable, Equatable {
441444
self.sourceFileURL = nil
442445
self.resultVersion = 0
443446
self.metadataVersion = 0
447+
self.paginationVersion = 0
444448
}
445449

446450
/// Initialize from persisted tab state (used when restoring tabs)
@@ -476,6 +480,7 @@ struct QueryTab: Identifiable, Equatable {
476480
self.sourceFileURL = persisted.sourceFileURL
477481
self.resultVersion = 0
478482
self.metadataVersion = 0
483+
self.paginationVersion = 0
479484
}
480485

481486
/// Build a clean base query for a table tab (no filters/sort).
@@ -554,6 +559,7 @@ struct QueryTab: Identifiable, Equatable {
554559
&& lhs.errorMessage == rhs.errorMessage
555560
&& lhs.executionTime == rhs.executionTime
556561
&& lhs.resultVersion == rhs.resultVersion
562+
&& lhs.paginationVersion == rhs.paginationVersion
557563
&& lhs.pagination == rhs.pagination
558564
&& lhs.sortState == rhs.sortState
559565
&& lhs.showStructure == rhs.showStructure

TablePro/Views/Main/Child/MainEditorContentView.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,6 +418,7 @@ struct MainEditorContentView: View {
418418
changeManager: currentChangeManager,
419419
resultVersion: tab.resultVersion,
420420
metadataVersion: tab.metadataVersion,
421+
paginationVersion: tab.paginationVersion,
421422
isEditable: tab.isEditable && !tab.isView && !coordinator.safeModeLevel.blocksAllWrites,
422423
onRefresh: onRefresh,
423424
onCellEdit: onCellEdit,

TablePro/Views/Main/Extensions/MainContentCoordinator+Pagination.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ extension MainContentCoordinator {
9696
guard let idx = self.tabManager.tabs.firstIndex(where: { $0.id == tabId }) else { return }
9797

9898
mutate(&self.tabManager.tabs[idx].pagination)
99+
self.tabManager.tabs[idx].paginationVersion += 1
99100
self.reloadCurrentPage()
100101
}
101102
}

TablePro/Views/Results/DataGridView.swift

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ struct DataGridIdentity: Equatable {
2929
let reloadVersion: Int
3030
let resultVersion: Int
3131
let metadataVersion: Int
32+
let paginationVersion: Int
3233
let rowCount: Int
3334
let columnCount: Int
3435
let isEditable: Bool
@@ -41,6 +42,7 @@ struct DataGridView: NSViewRepresentable {
4142
var changeManager: AnyChangeManager
4243
var resultVersion: Int = 0
4344
var metadataVersion: Int = 0
45+
var paginationVersion: Int = 0
4446
let isEditable: Bool
4547
var onRefresh: (() -> Void)?
4648
var onCellEdit: ((Int, Int, String?) -> Void)?
@@ -228,6 +230,7 @@ struct DataGridView: NSViewRepresentable {
228230
reloadVersion: changeManager.reloadVersion,
229231
resultVersion: resultVersion,
230232
metadataVersion: metadataVersion,
233+
paginationVersion: paginationVersion,
231234
rowCount: rowProvider.totalRowCount,
232235
columnCount: rowProvider.columns.count,
233236
isEditable: isEditable,
@@ -355,12 +358,15 @@ struct DataGridView: NSViewRepresentable {
355358

356359
syncSortDescriptors(tableView: tableView, coordinator: coordinator)
357360

361+
let paginationChanged = previousIdentity.map { $0.paginationVersion != paginationVersion } ?? false
362+
358363
reloadAndSyncSelection(
359364
tableView: tableView,
360365
coordinator: coordinator,
361366
needsFullReload: needsFullReload,
362367
versionChanged: versionChanged,
363-
metadataChanged: metadataChanged
368+
metadataChanged: metadataChanged,
369+
paginationChanged: paginationChanged
364370
)
365371
}
366372

@@ -546,7 +552,8 @@ struct DataGridView: NSViewRepresentable {
546552
coordinator: TableViewCoordinator,
547553
needsFullReload: Bool,
548554
versionChanged: Bool,
549-
metadataChanged: Bool = false
555+
metadataChanged: Bool = false,
556+
paginationChanged: Bool = false
550557
) {
551558
if needsFullReload {
552559
tableView.reloadData()
@@ -591,6 +598,11 @@ struct DataGridView: NSViewRepresentable {
591598

592599
coordinator.lastReloadVersion = changeManager.reloadVersion
593600

601+
// Scroll to first row when page changes
602+
if paginationChanged && tableView.numberOfRows > 0 {
603+
tableView.scrollRowToVisible(0)
604+
}
605+
594606
// Sync selection
595607
let currentSelection = tableView.selectedRowIndexes
596608
let targetSelection = IndexSet(selectedRowIndices)

0 commit comments

Comments
 (0)