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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Raw SQL filter now suggests columns and keywords at every position in the expression, including after AND and OR, instead of only the first column. (#1346)
- Plugins left incompatible after a TablePro update now update quietly in the background instead of showing a premature "could not be loaded" alert. You are only notified when no compatible version exists yet, and the message tells you what to do. (#1322)
- A plugin you download and install by hand is no longer blocked by macOS Gatekeeper once its signature is verified. (#1322)
- Clicking a table now reliably replaces the active tab instead of opening a new tab once you have more than one tab open. A new tab still opens when the current tab has unsaved edits, an applied filter, or sorting. Double-click to open a table in its own tab. (#1348)

## [0.43.3] - 2026-05-22

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -331,18 +331,11 @@ internal final class MainSplitViewController: NSSplitViewController, InspectorVi
windowState: sessionState.coordinator.windowSidebarState,
onDoubleClick: { [weak self] table in
guard let coordinator = self?.sessionState?.coordinator else { return }
let connectionId = coordinator.connectionId
if let preview = WindowLifecycleMonitor.shared.previewWindow(for: connectionId),
let previewCoordinator = MainContentCoordinator.coordinator(for: preview.windowId) {
if previewCoordinator.tabManager.selectedTab?.tableContext.tableName == table.name {
previewCoordinator.promotePreviewTab()
} else {
previewCoordinator.promotePreviewTab()
coordinator.openTableTab(table)
}
} else {
let activeTab = coordinator.tabManager.selectedTab
if activeTab?.tabType == .table, activeTab?.tableContext.tableName == table.name {
coordinator.promotePreviewTab()
coordinator.openTableTab(table)
} else {
coordinator.openTableTab(table, forceNonPreview: true)
}
},
pendingTruncates: sessionPendingTruncatesBinding,
Expand Down
24 changes: 3 additions & 21 deletions TablePro/Core/Services/Infrastructure/WindowLifecycleMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ internal final class WindowLifecycleMonitor {
let connectionId: UUID
weak var window: NSWindow?
var observer: NSObjectProtocol?
var isPreview: Bool = false
}

private var entries: [UUID: Entry] = [:]
Expand All @@ -41,9 +40,9 @@ internal final class WindowLifecycleMonitor {
// MARK: - Registration

/// Register a window and start observing its willCloseNotification.
internal func register(window: NSWindow, connectionId: UUID, windowId: UUID, isPreview: Bool = false) {
internal func register(window: NSWindow, connectionId: UUID, windowId: UUID) {
Self.lifecycleLogger.info(
"[open] WindowLifecycleMonitor.register windowId=\(windowId, privacy: .public) connId=\(connectionId, privacy: .public) isPreview=\(isPreview) registeredBefore=\(self.entries.count)"
"[open] WindowLifecycleMonitor.register windowId=\(windowId, privacy: .public) connId=\(connectionId, privacy: .public) registeredBefore=\(self.entries.count)"
)
// Remove any existing entry for this windowId to avoid duplicate observers
if let existing = entries[windowId] {
Expand All @@ -69,8 +68,7 @@ internal final class WindowLifecycleMonitor {
entries[windowId] = Entry(
connectionId: connectionId,
window: window,
observer: observer,
isPreview: isPreview
observer: observer
)
}

Expand Down Expand Up @@ -148,28 +146,12 @@ internal final class WindowLifecycleMonitor {
return entries[windowId] != nil
}

/// Find the first preview window for a connection.
internal func previewWindow(for connectionId: UUID) -> (windowId: UUID, window: NSWindow)? {
purgeStaleEntries()
for (windowId, entry) in entries {
guard entry.connectionId == connectionId, entry.isPreview else { continue }
guard let window = entry.window else { continue }
return (windowId, window)
}
return nil
}

/// Look up the NSWindow for a given windowId.
internal func window(for windowId: UUID) -> NSWindow? {
purgeStaleEntries()
return entries[windowId]?.window
}

/// Update the preview flag for a registered window.
internal func setPreview(_ isPreview: Bool, for windowId: UUID) {
entries[windowId]?.isPreview = isPreview
}

// MARK: - Source File Tracking

internal func registerSourceFile(_ url: URL, windowId: UUID) {
Expand Down
4 changes: 2 additions & 2 deletions TablePro/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -661,7 +661,7 @@
}
}
},
"%@ Preview" : {
"%@ - Preview" : {
"localizations" : {
"tr" : {
"stringUnit" : {
Expand All @@ -672,7 +672,7 @@
"vi" : {
"stringUnit" : {
"state" : "translated",
"value" : "%@ Xem trước"
"value" : "%@ - Xem trước"
}
},
"zh-Hans" : {
Expand Down
Loading
Loading