Skip to content

Commit 98d9687

Browse files
committed
Release v0.6.0
1 parent 228e4a8 commit 98d9687

5 files changed

Lines changed: 55 additions & 18 deletions

File tree

CHANGELOG.md

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
77

88
## [Unreleased]
99

10-
### Fixed
11-
- Fixed TOCTOU race condition in `SQLiteDriver` — replaced `nonisolated(unsafe)` + DispatchQueue pattern with a dedicated actor (`SQLiteConnectionActor`) that serializes all sqlite3 handle access, preventing concurrent task races on the connection state
12-
- Consolidated multiple `.sheet(isPresented:)` modifiers in `MainContentView` into a single `.sheet(item:)` with an `ActiveSheet` enum — fixes SwiftUI anti-pattern where only the last `.sheet` modifier reliably activates
10+
## [0.6.0] - 2026-02-22
11+
12+
### Added
13+
- Inline AI suggestions (ghost text) in the SQL editor — auto-triggers on typing pause, Tab to accept, Escape to dismiss
14+
- Schema-aware inline suggestions — AI now uses actual table/column names from the connected database (cached with 30s TTL, respects `includeSchema` and `maxSchemaTables` settings)
15+
- AI feature highlight row on onboarding features page
1316
- Added VoiceOver accessibility labels to custom controls: data grid (table view, column headers, cells), filter panel (logic toggle, presets, action buttons, filter row controls), toolbar buttons (connection switcher, database switcher, refresh, export, import, filter toggle, history toggle, inspector toggle), editor tab bar (tab items, close buttons, add tab button), and sidebar (table/view rows, search clear button)
1417

1518
### Changed
@@ -23,6 +26,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2326
- Added async/await wrapper methods to `QueryHistoryStorage` — existing completion-handler API preserved for compatibility, new `async` overloads use `withCheckedContinuation` for modern Swift concurrency callers
2427

2528
### Fixed
29+
- Fixed TOCTOU race condition in `SQLiteDriver` — replaced `nonisolated(unsafe)` + DispatchQueue pattern with a dedicated actor (`SQLiteConnectionActor`) that serializes all sqlite3 handle access, preventing concurrent task races on the connection state
30+
- Consolidated multiple `.sheet(isPresented:)` modifiers in `MainContentView` into a single `.sheet(item:)` with an `ActiveSheet` enum — fixes SwiftUI anti-pattern where only the last `.sheet` modifier reliably activates
2631
- Replaced blocking `Process.waitUntilExit()` calls in `SSHTunnelManager` with async `withCheckedContinuation`-based waiting, and replaced the fixed 1.5s sleep with active port probing — SSH tunnel setup no longer blocks the actor thread, keeping the UI responsive during connection
2732
- Eliminated potential deadlocks in `MariaDBConnection` and `LibPQConnection` — replaced all `queue.sync` calls (in `disconnect`, `deinit`, `isConnected`, `serverVersion`) with lock-protected cached state and `queue.async` cleanup, preventing deadlocks when callbacks re-enter the connection queue
2833
- SQL editor now respects the macOS accessibility text size preference (System Settings > Accessibility > Display > Text Size) — the user's chosen font size is scaled by the system's preferred text size factor, with live updates when the setting changes
@@ -37,13 +42,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
3742
- Ensured proper cleanup for `@State` reference type tokens — tracked untracked `Task` instances in `ImportDialog` (file selection), `AIProviderEditorSheet` (model fetching, connection test), and added `onDisappear` cancellation to prevent leaked work after view dismissal
3843
- Replaced `.onAppear` with `.task` for I/O operations in `ConnectionTagEditor` — uses SwiftUI-idiomatic lifecycle-tied loading instead of `onAppear` which can re-fire on navigation
3944

40-
## [0.6.0] - 2026-02-22
41-
42-
### Added
43-
- Inline AI suggestions (ghost text) in the SQL editor — auto-triggers on typing pause, Tab to accept, Escape to dismiss
44-
- Schema-aware inline suggestions — AI now uses actual table/column names from the connected database (cached with 30s TTL, respects `includeSchema` and `maxSchemaTables` settings)
45-
- AI feature highlight row on onboarding features page
46-
4745
## [0.5.0] - 2026-02-19
4846

4947
### Changed

TablePro.xcodeproj/project.pbxproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@
381381
CODE_SIGN_IDENTITY = "Apple Development";
382382
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
383383
CODE_SIGN_STYLE = Automatic;
384-
CURRENT_PROJECT_VERSION = 9;
384+
CURRENT_PROJECT_VERSION = 10;
385385
DEAD_CODE_STRIPPING = YES;
386386
DEVELOPMENT_TEAM = D7HJ5TFYCU;
387387
ENABLE_APP_SANDBOX = NO;
@@ -471,7 +471,7 @@
471471
"CODE_SIGN_IDENTITY[sdk=macosx*]" = "Apple Development";
472472
CODE_SIGN_STYLE = Automatic;
473473
COPY_PHASE_STRIP = YES;
474-
CURRENT_PROJECT_VERSION = 9;
474+
CURRENT_PROJECT_VERSION = 10;
475475
DEAD_CODE_STRIPPING = YES;
476476
DEPLOYMENT_POSTPROCESSING = YES;
477477
DEVELOPMENT_TEAM = D7HJ5TFYCU;

TablePro/AppDelegate.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -367,13 +367,15 @@ class AppDelegate: NSObject, NSApplicationDelegate {
367367
}
368368

369369
func applicationWillTerminate(_ notification: Notification) {
370-
// Remove all NotificationCenter observers added in applicationDidFinishLaunching
371-
NotificationCenter.default.removeObserver(self)
372-
373370
// Save tab state synchronously before app terminates (backup mechanism)
374371
saveAllTabStates()
375372
}
376373

374+
deinit {
375+
// Remove all NotificationCenter observers added in applicationDidFinishLaunching
376+
NotificationCenter.default.removeObserver(self)
377+
}
378+
377379
/// Save tab state for all active sessions
378380
@MainActor
379381
private func saveAllTabStates() {

TablePro/Views/Main/MainContentCoordinator.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -532,7 +532,6 @@ final class MainContentCoordinator: ObservableObject {
532532
changeManager.clearChanges()
533533
}
534534
}
535-
536535
} catch {
537536
guard capturedGeneration == queryGeneration else { return }
538537

TablePro/Views/Results/DataGridView.swift

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,35 @@ struct DataGridView: NSViewRepresentable {
241241
// This ensures column widths are recalculated based on actual cell content
242242
let shouldRebuildColumns = columnsChanged || (structureChanged && !rowProvider.columns.isEmpty)
243243

244-
if shouldRebuildColumns {
244+
updateColumns(
245+
tableView: tableView,
246+
coordinator: coordinator,
247+
columnsChanged: columnsChanged,
248+
shouldRebuild: shouldRebuildColumns,
249+
structureChanged: structureChanged
250+
)
251+
252+
syncSortDescriptors(tableView: tableView, coordinator: coordinator)
253+
254+
reloadAndSyncSelection(
255+
tableView: tableView,
256+
coordinator: coordinator,
257+
needsFullReload: needsFullReload,
258+
versionChanged: versionChanged
259+
)
260+
}
261+
262+
// MARK: - updateNSView Helpers
263+
264+
/// Rebuild or sync table columns based on data changes
265+
private func updateColumns(
266+
tableView: NSTableView,
267+
coordinator: TableViewCoordinator,
268+
columnsChanged: Bool,
269+
shouldRebuild: Bool,
270+
structureChanged: Bool
271+
) {
272+
if shouldRebuild {
245273
coordinator.isRebuildingColumns = true
246274
defer { coordinator.isRebuildingColumns = false }
247275

@@ -356,8 +384,10 @@ struct DataGridView: NSViewRepresentable {
356384
}
357385
}
358386
}
387+
}
359388

360-
// Sync sort state
389+
/// Synchronize sort descriptors and indicators with the table view
390+
private func syncSortDescriptors(tableView: NSTableView, coordinator: TableViewCoordinator) {
361391
coordinator.isSyncingSortDescriptors = true
362392
defer { coordinator.isSyncingSortDescriptors = false }
363393

@@ -378,7 +408,15 @@ struct DataGridView: NSViewRepresentable {
378408

379409
// Update column header titles for multi-sort indicators
380410
Self.updateSortIndicators(tableView: tableView, sortState: sortState, columns: rowProvider.columns)
411+
}
381412

413+
/// Reload table data as needed and synchronize selection and editing state
414+
private func reloadAndSyncSelection(
415+
tableView: NSTableView,
416+
coordinator: TableViewCoordinator,
417+
needsFullReload: Bool,
418+
versionChanged: Bool
419+
) {
382420
if needsFullReload {
383421
tableView.reloadData()
384422
} else if versionChanged {

0 commit comments

Comments
 (0)