Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -144,3 +144,4 @@ Libs/*.a
Libs/.downloaded
Libs/dylibs/
Libs/ios/
.claude/
5 changes: 0 additions & 5 deletions TablePro/Core/ChangeTracking/AnyChangeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ protocol ChangeManaging: AnyObject {
)
func undoRowDeletion(rowIndex: Int)
func undoRowInsertion(rowIndex: Int)
func consumeChangedRowIndices() -> Set<Int>
}

@Observable
Expand Down Expand Up @@ -63,10 +62,6 @@ final class AnyChangeManager {
wrapped.undoRowInsertion(rowIndex: rowIndex)
}

func consumeChangedRowIndices() -> Set<Int> {
wrapped.consumeChangedRowIndices()
}

init(_ manager: any ChangeManaging) {
self.wrapped = manager
}
Expand Down
6 changes: 0 additions & 6 deletions TablePro/Core/ChangeTracking/DataChangeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,6 @@ final class DataChangeManager: ChangeManaging {
undoManager.setActionName(actionName)
}

// MARK: - Helper Methods

func consumeChangedRowIndices() -> Set<Int> {
pending.consumeChangedRowIndices()
}

// MARK: - Configuration

func clearChanges() {
Expand Down
26 changes: 0 additions & 26 deletions TablePro/Core/ChangeTracking/PendingChanges.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ struct PendingChanges: Equatable {
private(set) var insertedRowIndices: Set<Int> = []
private(set) var modifiedCells: [Int: Set<Int>] = [:]
private(set) var insertedRowData: [Int: [String?]] = [:]
private(set) var changedRowIndices: Set<Int> = []

private var changeIndex: [RowChangeKey: Int] = [:]

Expand Down Expand Up @@ -77,7 +76,6 @@ struct PendingChanges: Equatable {
if let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] {
updateInsertedCell(at: insertIdx, columnIndex: columnIndex,
columnName: columnName, newValue: newValue)
changedRowIndices.insert(rowIndex)
return true
}

Expand All @@ -93,7 +91,6 @@ struct PendingChanges: Equatable {
changeIndex[updateKey] = changes.count - 1
modifiedCells[rowIndex, default: []].insert(columnIndex)
}
changedRowIndices.insert(rowIndex)
return true
}

Expand All @@ -103,7 +100,6 @@ struct PendingChanges: Equatable {
modifiedCells.removeValue(forKey: rowIndex)
appendChange(RowChange(rowIndex: rowIndex, type: .delete, originalRow: originalRow))
deletedRowIndices.insert(rowIndex)
changedRowIndices.insert(rowIndex)
}

mutating func recordRowInsertion(rowIndex: Int, values: [String?]) {
Expand All @@ -114,7 +110,6 @@ struct PendingChanges: Equatable {
insertedRowData[rowIndex] = values
appendChange(RowChange(rowIndex: rowIndex, type: .insert, cellChanges: []))
insertedRowIndices.insert(rowIndex)
changedRowIndices.insert(rowIndex)
}

// MARK: - Mutate (cancelling pending edits)
Expand All @@ -123,7 +118,6 @@ struct PendingChanges: Equatable {
guard deletedRowIndices.contains(rowIndex) else { return false }
removeChange(rowIndex: rowIndex, type: .delete)
deletedRowIndices.remove(rowIndex)
changedRowIndices.insert(rowIndex)
return true
}

Expand All @@ -135,7 +129,6 @@ struct PendingChanges: Equatable {
insertedRowData.removeValue(forKey: rowIndex)

shiftRowIndicesDown(at: rowIndex)
changedRowIndices.insert(rowIndex)
return true
}

Expand All @@ -159,7 +152,6 @@ struct PendingChanges: Equatable {
removeChange(rowIndex: rowIndex, type: .insert)
insertedRowIndices.remove(rowIndex)
insertedRowData.removeValue(forKey: rowIndex)
changedRowIndices.insert(rowIndex)
}

let sortedRemoved = validRows.sorted()
Expand Down Expand Up @@ -188,7 +180,6 @@ struct PendingChanges: Equatable {
modifiedCells.removeValue(forKey: rowIndex)
appendChange(RowChange(rowIndex: rowIndex, type: .delete, originalRow: originalRow))
deletedRowIndices.insert(rowIndex)
changedRowIndices.insert(rowIndex)
}

/// Re-apply a cell edit during undo replay (skips undo registration).
Expand All @@ -213,7 +204,6 @@ struct PendingChanges: Equatable {
if let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] {
updateInsertedCell(at: insertIdx, columnIndex: columnIndex,
columnName: columnName, newValue: newValue)
changedRowIndices.insert(rowIndex)
return
}

Expand All @@ -229,7 +219,6 @@ struct PendingChanges: Equatable {
changeIndex[updateKey] = changes.count - 1
modifiedCells[rowIndex, default: []].insert(columnIndex)
}
changedRowIndices.insert(rowIndex)
}

/// Replace an inserted row's cell value during undo replay (no shift, no undo).
Expand All @@ -241,7 +230,6 @@ struct PendingChanges: Equatable {
) {
guard let insertIdx = changeIndex[RowChangeKey(rowIndex: rowIndex, type: .insert)] else { return }
updateInsertedCell(at: insertIdx, columnIndex: columnIndex, columnName: columnName, newValue: newValue)
changedRowIndices.insert(rowIndex)
}

/// Restore a cell's value during undo replay when an existing change matches.
Expand Down Expand Up @@ -274,7 +262,6 @@ struct PendingChanges: Equatable {
newValue: previousValue
)
}
changedRowIndices.insert(rowIndex)
}

/// Insert a synthetic .insert RowChange for undo replay (e.g., after redoing a deletion's undo).
Expand All @@ -291,7 +278,6 @@ struct PendingChanges: Equatable {
if let savedValues {
insertedRowData[rowIndex] = savedValues
}
changedRowIndices.insert(rowIndex)
}

/// Insert a batch of rows (for undo replay of a batch deletion's undo).
Expand All @@ -314,7 +300,6 @@ struct PendingChanges: Equatable {
changes.append(RowChange(rowIndex: rowIndex, type: .insert, cellChanges: cellChanges))
insertedRowIndices.insert(rowIndex)
insertedRowData[rowIndex] = values
changedRowIndices.insert(rowIndex)
}
rebuildChangeIndex()
}
Expand All @@ -338,23 +323,14 @@ struct PendingChanges: Equatable {
insertedRowIndices.removeAll()
modifiedCells.removeAll()
insertedRowData.removeAll()
changedRowIndices.removeAll()
}

mutating func consumeChangedRowIndices() -> Set<Int> {
let indices = changedRowIndices
changedRowIndices.removeAll()
return indices
}

/// Replace internal state from a serialized snapshot.
mutating func restore(from snapshot: TabChangeSnapshot) {
changes = snapshot.changes
deletedRowIndices = snapshot.deletedRowIndices
insertedRowIndices = snapshot.insertedRowIndices
modifiedCells = snapshot.modifiedCells
insertedRowData = snapshot.insertedRowData
changedRowIndices = []
rebuildChangeIndex()
}

Expand Down Expand Up @@ -471,7 +447,6 @@ struct PendingChanges: Equatable {
if changes[updateIdx].cellChanges.isEmpty {
removeChangeAt(updateIdx)
}
changedRowIndices.insert(rowIndex)
return true
}

Expand All @@ -494,7 +469,6 @@ struct PendingChanges: Equatable {
}
modifiedCells = newModifiedCells

changedRowIndices = Set(changedRowIndices.map { $0 >= insertionPoint ? $0 + 1 : $0 })
rebuildChangeIndex()
}

Expand Down
17 changes: 0 additions & 17 deletions TablePro/Core/SchemaTracking/StructureChangeManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,6 @@ final class StructureChangeManager: ChangeManaging {
var hasChanges: Bool { !pendingChanges.isEmpty }
var reloadVersion: Int = 0

// Track which rows changed since last reload for granular updates
private(set) var changedRowIndices: Set<Int> = []

// Current state (loaded from database)
private(set) var currentColumns: [EditableColumnDefinition] = []
private(set) var currentIndexes: [EditableIndexDefinition] = []
Expand Down Expand Up @@ -48,13 +45,6 @@ final class StructureChangeManager: ChangeManaging {
var canUndo: Bool { undoManager.canUndo }
var canRedo: Bool { undoManager.canRedo }

/// Consume and clear changed row indices (for granular table reloads)
func consumeChangedRowIndices() -> Set<Int> {
let indices = changedRowIndices
changedRowIndices.removeAll()
return indices
}

// MARK: - Load Schema

func loadSchema(
Expand Down Expand Up @@ -261,7 +251,6 @@ final class StructureChangeManager: ChangeManaging {
pendingChanges[key] = .deleteColumn(column)
trackChangeKey(key)
if let rowIndex = workingColumns.firstIndex(where: { $0.id == id }) {
changedRowIndices.insert(rowIndex)
}
} else {
let rowIndex = workingColumns.firstIndex(where: { $0.id == id })
Expand All @@ -273,7 +262,6 @@ final class StructureChangeManager: ChangeManaging {
}
if let rowIndex {
for i in rowIndex..<workingColumns.count {
changedRowIndices.insert(i)
}
}
workingColumns.removeAll { $0.id == id }
Expand Down Expand Up @@ -334,7 +322,6 @@ final class StructureChangeManager: ChangeManaging {
pendingChanges[key] = .deleteIndex(index)
trackChangeKey(key)
if let rowIndex = workingIndexes.firstIndex(where: { $0.id == id }) {
changedRowIndices.insert(rowIndex)
}
} else {
let rowIndex = workingIndexes.firstIndex(where: { $0.id == id })
Expand All @@ -346,7 +333,6 @@ final class StructureChangeManager: ChangeManaging {
}
if let rowIndex {
for i in rowIndex..<workingIndexes.count {
changedRowIndices.insert(i)
}
}
workingIndexes.removeAll { $0.id == id }
Expand Down Expand Up @@ -407,7 +393,6 @@ final class StructureChangeManager: ChangeManaging {
pendingChanges[key] = .deleteForeignKey(fk)
trackChangeKey(key)
if let rowIndex = workingForeignKeys.firstIndex(where: { $0.id == id }) {
changedRowIndices.insert(rowIndex)
}
} else {
let rowIndex = workingForeignKeys.firstIndex(where: { $0.id == id })
Expand All @@ -419,7 +404,6 @@ final class StructureChangeManager: ChangeManaging {
}
if let rowIndex {
for i in rowIndex..<workingForeignKeys.count {
changedRowIndices.insert(i)
}
}
workingForeignKeys.removeAll { $0.id == id }
Expand Down Expand Up @@ -552,7 +536,6 @@ final class StructureChangeManager: ChangeManaging {
pendingChanges.removeAll()
changeOrder.removeAll()
validationErrors.removeAll()
changedRowIndices.removeAll()
resetWorkingState()
reloadVersion += 1
rebuildVisualStateCache()
Expand Down
4 changes: 2 additions & 2 deletions TablePro/Views/Results/DataGridCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
@Binding var selectedRowIndices: Set<Int>

var lastIdentity: DataGridIdentity?
var lastReloadVersion: Int = 0
var lastReapplyVersion: Int = -1
private(set) var cachedRowCount: Int = 0
private(set) var cachedColumnCount: Int = 0
private(set) var enumOrSetColumns: Set<Int> = []
Expand Down Expand Up @@ -340,6 +338,7 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
guard row >= 0, row < tableView.numberOfRows else { return }
guard tableColumn >= 0, tableColumn < tableView.numberOfColumns else { return }
invalidateDisplayCache(forDisplayRow: row, column: column)
rebuildVisualStateCache()
tableView.reloadData(
forRowIndexes: IndexSet(integer: row),
columnIndexes: IndexSet(integer: tableColumn)
Expand All @@ -359,6 +358,7 @@ final class TableViewCoordinator: NSObject, NSTableViewDelegate, NSTableViewData
invalidateDisplayCache(forDisplayRow: position.row, column: position.column)
}
guard !rowSet.isEmpty, !colSet.isEmpty else { return }
rebuildVisualStateCache()
tableView.reloadData(forRowIndexes: rowSet, columnIndexes: colSet)
case .rowsInserted(let indices):
guard !indices.isEmpty else { return }
Expand Down
21 changes: 1 addition & 20 deletions TablePro/Views/Results/DataGridView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ struct RowVisualState {
}

struct DataGridIdentity: Equatable {
let reloadVersion: Int
let schemaVersion: Int
let metadataVersion: Int
let paginationVersion: Int
Expand All @@ -35,9 +34,8 @@ struct DataGridIdentity: Equatable {
let primaryKeyColumns: [String]
let hiddenColumns: Set<String>

init(reloadVersion: Int, schemaVersion: Int, metadataVersion: Int, paginationVersion: Int,
init(schemaVersion: Int, metadataVersion: Int, paginationVersion: Int,
rowCount: Int, columnCount: Int, isEditable: Bool, configuration: DataGridConfiguration) {
self.reloadVersion = reloadVersion
self.schemaVersion = schemaVersion
self.metadataVersion = metadataVersion
self.paginationVersion = paginationVersion
Expand Down Expand Up @@ -233,7 +231,6 @@ struct DataGridView: NSViewRepresentable {
let columnCount = latestRows.columns.count

let currentIdentity = DataGridIdentity(
reloadVersion: changeManager.reloadVersion,
schemaVersion: schemaVersion,
metadataVersion: metadataVersion,
paginationVersion: paginationVersion,
Comment on lines 233 to 236
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Include reloadVersion in DataGrid identity checks

Dropping reloadVersion from DataGridIdentity means updateNSView now early-returns for changes that do not alter row/column counts or metadata, even when the underlying ChangeManaging state changed. In this repo, schema undo/redo paths (for example CreateTableGridDelegate.dataGridUndo/Redo calling StructureChangeManager.undo/redo) do not dispatch a Delta, and many of those edits keep the same row/column shape; after this commit, those updates can leave stale cell values/row visual state on screen until a later full reload (query rerun, sort, tab switch).

Useful? React with 👍 / 👎.

Expand Down Expand Up @@ -262,7 +259,6 @@ struct DataGridView: NSViewRepresentable {
tableView.usesAlternatingRowBackgroundColors = settings.showAlternateRows
}

let versionChanged = coordinator.lastReloadVersion != changeManager.reloadVersion
let metadataChanged = previousIdentity.map { $0.metadataVersion != metadataVersion } ?? false
let oldRowCount = coordinator.cachedRowCount
let oldColumnCount = coordinator.cachedColumnCount
Expand Down Expand Up @@ -328,7 +324,6 @@ struct DataGridView: NSViewRepresentable {
coordinator: coordinator,
tableRows: latestRows,
needsFullReload: needsFullReload,
versionChanged: versionChanged,
metadataChanged: metadataChanged,
paginationChanged: paginationChanged
)
Expand Down Expand Up @@ -502,7 +497,6 @@ struct DataGridView: NSViewRepresentable {
coordinator: TableViewCoordinator,
tableRows: TableRows,
needsFullReload: Bool,
versionChanged: Bool,
metadataChanged: Bool = false,
paginationChanged: Bool = false
) {
Expand All @@ -527,21 +521,8 @@ struct DataGridView: NSViewRepresentable {
tableView.reloadData(forRowIndexes: visibleRows, columnIndexes: fkColumnIndices)
}
}
} else if versionChanged {
let changedRows = changeManager.consumeChangedRowIndices()
if changedRows.count > 500 {
tableView.reloadData()
} else if !changedRows.isEmpty {
let rowIndexSet = IndexSet(changedRows)
let columnIndexSet = IndexSet(integersIn: 0..<tableView.numberOfColumns)
tableView.reloadData(forRowIndexes: rowIndexSet, columnIndexes: columnIndexSet)
} else if !changeManager.hasChanges {
tableView.reloadData()
}
}

coordinator.lastReloadVersion = changeManager.reloadVersion

if paginationChanged && tableView.numberOfRows > 0 {
tableView.scrollRowToVisible(0)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,12 @@ extension TableViewCoordinator {
}
delegate?.dataGridDidEditCell(row: row, column: columnIndex, newValue: newValue)
invalidateDisplayCache()
rebuildVisualStateCache()

let tableColumnIndex = DataGridView.tableColumnIndex(for: columnIndex)
if storageRow != nil, case .cellChanged = delta {
let displayDelta: Delta = .cellChanged(
row: row,
column: DataGridView.tableColumnIndex(for: columnIndex)
)
tableRowsController.apply(displayDelta)
tableRowsController.apply(.cellChanged(row: row, column: tableColumnIndex))
} else {
let tableColumnIndex = DataGridView.tableColumnIndex(for: columnIndex)
tableView.reloadData(
forRowIndexes: IndexSet(integer: row),
columnIndexes: IndexSet(integer: tableColumnIndex)
Expand Down
Loading
Loading