Skip to content

Commit 361fdf8

Browse files
committed
fix: address PR review feedback from CodeRabbit
- Fix FK column reload to use display-order indices (respects user column reordering) - Remove force-unwrap in JSON highlight debounce (use local variable) - Add purgeStaleEntries to connectionId(for:) and window(for:) in WindowLifecycleMonitor - Fix audit doc date typo and inconsistent checkbox states
1 parent bc2ac3b commit 361fdf8

4 files changed

Lines changed: 29 additions & 17 deletions

File tree

TablePro/Core/Services/Infrastructure/WindowLifecycleMonitor.swift

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ internal final class WindowLifecycleMonitor {
108108

109109
/// Look up the connectionId for a given windowId.
110110
internal func connectionId(for windowId: UUID) -> UUID? {
111-
entries[windowId]?.connectionId
111+
purgeStaleEntries()
112+
return entries[windowId]?.connectionId
112113
}
113114

114115
/// Check if any windows are registered for a connection.
@@ -137,7 +138,8 @@ internal final class WindowLifecycleMonitor {
137138

138139
/// Look up the NSWindow for a given windowId.
139140
internal func window(for windowId: UUID) -> NSWindow? {
140-
entries[windowId]?.window
141+
purgeStaleEntries()
142+
return entries[windowId]?.window
141143
}
142144

143145
/// Update the preview flag for a registered window.

TablePro/Views/Results/DataGridView.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -471,16 +471,25 @@ struct DataGridView: NSViewRepresentable {
471471
if needsFullReload {
472472
tableView.reloadData()
473473
} else if metadataChanged {
474-
// FK metadata arrived (Phase 2) — reload only FK columns to show arrow buttons
474+
// FK metadata arrived (Phase 2) — reload only FK columns to show arrow buttons.
475+
// Use display-order indices from tableView.tableColumns (respects user column reordering).
475476
let fkColumnIndices = IndexSet(
476-
rowProvider.columns.enumerated().compactMap { index, columnName in
477-
rowProvider.columnForeignKeys[columnName] != nil ? index + 1 : nil
477+
tableView.tableColumns.enumerated().compactMap { displayIndex, tableColumn in
478+
guard tableColumn.identifier.rawValue != "__rowNumber__",
479+
let modelIndex = Self.columnIndex(from: tableColumn.identifier),
480+
modelIndex < rowProvider.columns.count else { return nil }
481+
let columnName = rowProvider.columns[modelIndex]
482+
return rowProvider.columnForeignKeys[columnName] != nil ? displayIndex : nil
478483
}
479484
)
480485
if !fkColumnIndices.isEmpty {
481486
let visibleRange = tableView.rows(in: tableView.visibleRect)
482-
let visibleRows = IndexSet(integersIn: visibleRange.location..<(visibleRange.location + visibleRange.length))
483-
tableView.reloadData(forRowIndexes: visibleRows, columnIndexes: fkColumnIndices)
487+
if visibleRange.length > 0 {
488+
let visibleRows = IndexSet(
489+
integersIn: visibleRange.location..<(visibleRange.location + visibleRange.length)
490+
)
491+
tableView.reloadData(forRowIndexes: visibleRows, columnIndexes: fkColumnIndices)
492+
}
484493
}
485494
} else if versionChanged {
486495
// Granular reload: only reload rows that changed

TablePro/Views/Results/JSONEditorContentView.swift

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -213,11 +213,12 @@ private struct JSONSyntaxTextView: NSViewRepresentable {
213213

214214
// Debounce syntax highlighting to avoid 4 regex passes per keystroke
215215
highlightWorkItem?.cancel()
216-
highlightWorkItem = DispatchWorkItem { [weak textView] in
216+
let workItem = DispatchWorkItem { [weak textView] in
217217
guard let textView else { return }
218218
JSONSyntaxTextView.applyHighlighting(to: textView)
219219
}
220-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: highlightWorkItem!)
220+
highlightWorkItem = workItem
221+
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: workItem)
221222
}
222223
}
223224
}

docs/development/performance-audit.md

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Performance Audit — TablePro
22

3-
**Date:** 2025-03-18
3+
**Date:** 2026-03-18
44
**Related Issue:** [#368 — High CPU Usage by TablePro on macOS](https://github.com/datlechin/TablePro/issues/368)
55
**Status:** Phase 1-4 fixes applied (16/17 medium+ issues fixed) — build verified
66

@@ -91,7 +91,7 @@ Secondary contributors include main-thread I/O blocking (Keychain, plugin loadin
9191

9292
### HIGH-6: N+1 Default `fetchAllColumns`/`fetchAllForeignKeys` at Both Protocol Layers
9393

94-
- [ ] **Fix applied**
94+
- [ ] **Fix pending**
9595

9696
**Files:** `DatabaseDriver.swift:247-262`, `PluginDatabaseDriver.swift:168-185`
9797

@@ -113,7 +113,7 @@ Default implementations loop per-table with one query each. A schema with 200 ta
113113

114114
### MED-2: `NSWindow.didUpdateNotification` Fires on Every Event Loop Cycle
115115

116-
- [ ] **Fix applied**
116+
- [ ] **Fix pending**
117117

118118
**File:** `EditorEventRouter.swift:83-92`
119119

@@ -125,7 +125,7 @@ Default implementations loop per-table with one query each. A schema with 200 ta
125125

126126
### MED-3: SSH Relay Poll at 100ms Intervals
127127

128-
- [ ] **Fix applied**
128+
- [ ] **Fix pending**
129129

130130
**File:** `LibSSH2TunnelFactory.swift:488`
131131

@@ -137,7 +137,7 @@ Jump-host channel relay uses `poll()` with 100ms timeout, waking 10x/second even
137137

138138
### MED-4: Column Layout Write-Back Triggers Extra Tab Persistence Save
139139

140-
- [ ] **Fix applied**
140+
- [ ] **Fix pending**
141141

142142
**Files:** `DataGridView.swift:389-396`, `MainContentView.swift:293-295`
143143

@@ -181,7 +181,7 @@ Jump-host channel relay uses `poll()` with 100ms timeout, waking 10x/second even
181181

182182
### MED-9: `[[String?]]``[QueryResultRow]` Full Copy After Every Query
183183

184-
- [ ] **Fix applied**
184+
- [ ] **Fix pending**
185185

186186
**File:** `MainContentCoordinator.swift:840-845`
187187

@@ -209,7 +209,7 @@ Jump-host channel relay uses `poll()` with 100ms timeout, waking 10x/second even
209209

210210
### MED-12: `DateFormattingService.format` Called Per Cell Per Reload
211211

212-
- [ ] **Fix applied**
212+
- [ ] **Fix pending**
213213

214214
**File:** `DataGridCellFactory.swift:333-336`
215215

@@ -253,7 +253,7 @@ Every visible date cell re-formats on every `reloadData`, even when the value ha
253253

254254
### MED-17: `multiColumnSortIndices` Pre-builds 300K String Copies for Large Datasets
255255

256-
- [ ] **Fix applied**
256+
- [ ] **Fix pending**
257257

258258
**File:** `MainContentCoordinator.swift:1190-1195`
259259

0 commit comments

Comments
 (0)