@@ -18,6 +18,7 @@ struct ContentView: View {
1818 let payload : EditorTabPayload ?
1919
2020 @State private var currentSession : ConnectionSession ?
21+ @State private var closingSessionId : UUID ?
2122 @State private var columnVisibility : NavigationSplitViewVisibility = . all
2223 @State private var showNewConnectionSheet = false
2324 @State private var showEditConnectionSheet = false
@@ -70,6 +71,7 @@ struct ContentView: View {
7071 // Right sidebar toggle is handled by MainContentView (has the binding)
7172 // Left sidebar toggle uses native NSSplitViewController.toggleSidebar via responder chain
7273 . onChange ( of: DatabaseManager . shared. currentSessionId, initial: true ) { _, newSessionId in
74+ guard closingSessionId == nil else { return }
7375 let ourConnectionId = payload? . connectionId
7476 if ourConnectionId != nil {
7577 guard newSessionId == ourConnectionId else { return }
@@ -102,59 +104,9 @@ struct ContentView: View {
102104 columnVisibility = . detailOnly
103105 }
104106 }
105- . onChange ( of: ( payload? . connectionId ?? currentSession? . id) . flatMap { DatabaseManager . shared. connectionStatusVersions [ $0] } , initial: true ) { _, _ in
106- let sessions = DatabaseManager . shared. activeSessions
107- let connectionId = payload? . connectionId ?? currentSession? . id ?? DatabaseManager . shared. currentSessionId
108- guard let sid = connectionId else {
109- if currentSession != nil { currentSession = nil }
110- return
111- }
112- guard let newSession = sessions [ sid] else {
113- if currentSession? . id == sid {
114- rightPanelState? . teardown ( )
115- rightPanelState = nil
116- sessionState? . coordinator. teardown ( )
117- sessionState = nil
118- currentSession = nil
119- columnVisibility = . detailOnly
120- AppState . shared. isConnected = false
121- AppState . shared. safeModeLevel = . silent
122- AppState . shared. editorLanguage = . sql
123- AppState . shared. currentDatabaseType = nil
124- AppState . shared. supportsDatabaseSwitching = true
125-
126- // Close all native tab windows for this connection and
127- // force AppKit to deallocate them instead of pooling.
128- let tabbingId = " com.TablePro.main. \( sid. uuidString) "
129- DispatchQueue . main. async {
130- for window in NSApp . windows where window. tabbingIdentifier == tabbingId {
131- window. isReleasedWhenClosed = true
132- window. close ( )
133- }
134- }
135- }
136- return
137- }
138- if let existing = currentSession,
139- existing. isContentViewEquivalent ( to: newSession) {
140- return
141- }
142- currentSession = newSession
143- if rightPanelState == nil {
144- rightPanelState = RightPanelState ( )
145- }
146- if sessionState == nil {
147- sessionState = SessionStateFactory . create (
148- connection: newSession. connection,
149- payload: payload
150- )
151- }
152- AppState . shared. isConnected = true
153- AppState . shared. safeModeLevel = newSession. connection. safeModeLevel
154- AppState . shared. editorLanguage = PluginManager . shared. editorLanguage ( for: newSession. connection. type)
155- AppState . shared. currentDatabaseType = newSession. connection. type
156- AppState . shared. supportsDatabaseSwitching = PluginManager . shared. supportsDatabaseSwitching (
157- for: newSession. connection. type)
107+ . task { handleConnectionStatusChange ( ) }
108+ . onReceive ( NotificationCenter . default. publisher ( for: . connectionStatusDidChange) ) { _ in
109+ handleConnectionStatusChange ( )
158110 }
159111 . onReceive ( NotificationCenter . default. publisher ( for: NSWindow . didBecomeKeyNotification) ) { notification in
160112 // Only process notifications for our own window to avoid every
@@ -378,6 +330,63 @@ struct ContentView: View {
378330 )
379331 }
380332
333+ // MARK: - Connection Status
334+
335+ private func handleConnectionStatusChange( ) {
336+ guard closingSessionId == nil else { return }
337+ let sessions = DatabaseManager . shared. activeSessions
338+ let connectionId = payload? . connectionId ?? currentSession? . id ?? DatabaseManager . shared. currentSessionId
339+ guard let sid = connectionId else {
340+ if currentSession != nil { currentSession = nil }
341+ return
342+ }
343+ guard let newSession = sessions [ sid] else {
344+ if currentSession? . id == sid {
345+ closingSessionId = sid
346+ rightPanelState? . teardown ( )
347+ rightPanelState = nil
348+ sessionState? . coordinator. teardown ( )
349+ sessionState = nil
350+ currentSession = nil
351+ columnVisibility = . detailOnly
352+ AppState . shared. isConnected = false
353+ AppState . shared. safeModeLevel = . silent
354+ AppState . shared. editorLanguage = . sql
355+ AppState . shared. currentDatabaseType = nil
356+ AppState . shared. supportsDatabaseSwitching = true
357+
358+ let tabbingId = " com.TablePro.main. \( sid. uuidString) "
359+ DispatchQueue . main. async {
360+ for window in NSApp . windows where window. tabbingIdentifier == tabbingId {
361+ window. isReleasedWhenClosed = true
362+ window. close ( )
363+ }
364+ }
365+ }
366+ return
367+ }
368+ if let existing = currentSession,
369+ existing. isContentViewEquivalent ( to: newSession) {
370+ return
371+ }
372+ currentSession = newSession
373+ if rightPanelState == nil {
374+ rightPanelState = RightPanelState ( )
375+ }
376+ if sessionState == nil {
377+ sessionState = SessionStateFactory . create (
378+ connection: newSession. connection,
379+ payload: payload
380+ )
381+ }
382+ AppState . shared. isConnected = true
383+ AppState . shared. safeModeLevel = newSession. connection. safeModeLevel
384+ AppState . shared. editorLanguage = PluginManager . shared. editorLanguage ( for: newSession. connection. type)
385+ AppState . shared. currentDatabaseType = newSession. connection. type
386+ AppState . shared. supportsDatabaseSwitching = PluginManager . shared. supportsDatabaseSwitching (
387+ for: newSession. connection. type)
388+ }
389+
381390 // MARK: - Actions
382391
383392 private func connectToDatabase( _ connection: DatabaseConnection ) {
0 commit comments