From ba73a7463a58c298c15a7802e7b21e038d2b2b9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Monge=20Jim=C3=A9nez?= Date: Fri, 27 Mar 2026 09:27:20 -0600 Subject: [PATCH 1/3] fix: add confirmation dialogs for externally-triggered actions --- CHANGELOG.md | 6 ++++ TablePro/AppDelegate+FileOpen.swift | 30 ++++++++++++++++---- TablePro/Core/Database/DatabaseManager.swift | 16 +++++++++++ docs/features/deep-links.mdx | 4 +-- 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 65d59dc9..5c3aeef1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Added + +- Confirmation dialog before opening queries from external deep links +- Confirmation dialog before running pre-connect shell scripts +- Confirmation dialog before importing connections from deep links + ## [0.25.0] - 2026-03-27 ### Added diff --git a/TablePro/AppDelegate+FileOpen.swift b/TablePro/AppDelegate+FileOpen.swift index a36aed20..d20ccc40 100644 --- a/TablePro/AppDelegate+FileOpen.swift +++ b/TablePro/AppDelegate+FileOpen.swift @@ -37,7 +37,7 @@ extension AppDelegate { let deeplinks = urls.filter { $0.scheme == "tablepro" } if !deeplinks.isEmpty { Task { @MainActor in - for url in deeplinks { self.handleDeeplink(url) } + for url in deeplinks { await self.handleDeeplink(url) } } } @@ -115,7 +115,7 @@ extension AppDelegate { // MARK: - Deeplink Handling - private func handleDeeplink(_ url: URL) { + private func handleDeeplink(_ url: URL) async { guard let action = DeeplinkHandler.parse(url) else { return } switch action { @@ -129,14 +129,23 @@ extension AppDelegate { } case .openQuery(let name, let sql): + let preview = (sql as NSString).length > 300 ? String(sql.prefix(300)) + "…" : sql + let confirmed = await AlertHelper.confirmDestructive( + title: String(localized: "Open Query from Link"), + message: String(localized: "An external link wants to open a query on connection \"\(name)\":\n\n\(preview)"), + confirmButton: String(localized: "Open Query"), + cancelButton: String(localized: "Cancel"), + window: NSApp.keyWindow + ) + guard confirmed else { return } connectViaDeeplink(connectionName: name) { connectionId in EditorTabPayload(connectionId: connectionId, tabType: .query, initialQuery: sql) } case .importConnection(let name, let host, let port, let type, let username, let database): - handleImportDeeplink(name: name, host: host, port: port, type: type, - username: username, database: database) + await handleImportDeeplink(name: name, host: host, port: port, type: type, + username: username, database: database) } } @@ -193,7 +202,18 @@ extension AppDelegate { private func handleImportDeeplink( name: String, host: String, port: Int, type: DatabaseType, username: String, database: String - ) { + ) async { + let userPart = username.isEmpty ? "" : "\(username)@" + let details = "\(type.rawValue)://\(userPart)\(host):\(port)/\(database)" + let confirmed = await AlertHelper.confirmDestructive( + title: String(localized: "Import Connection from Link"), + message: String(localized: "An external link wants to add a database connection:\n\nName: \(name)\n\(details)"), + confirmButton: String(localized: "Add Connection"), + cancelButton: String(localized: "Cancel"), + window: NSApp.keyWindow + ) + guard confirmed else { return } + let connection = DatabaseConnection( name: name, host: host, port: port, database: database, username: username, type: type diff --git a/TablePro/Core/Database/DatabaseManager.swift b/TablePro/Core/Database/DatabaseManager.swift index 5aa8b7e3..dccfa682 100644 --- a/TablePro/Core/Database/DatabaseManager.swift +++ b/TablePro/Core/Database/DatabaseManager.swift @@ -123,6 +123,22 @@ final class DatabaseManager { if let script = resolvedConnection.preConnectScript, !script.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty { + let confirmed = await AlertHelper.confirmDestructive( + title: String(localized: "Pre-Connect Script"), + message: String(localized: "Connection \"\(connection.name)\" has a script that will run before connecting:\n\n\(script)"), + confirmButton: String(localized: "Run Script"), + cancelButton: String(localized: "Cancel"), + window: NSApp.keyWindow + ) + + guard confirmed else { + removeSessionEntry(for: connection.id) + currentSessionId = nil + throw PreConnectHookRunner.HookError.scriptFailed( + exitCode: 1, stderr: "User cancelled pre-connect script" + ) + } + do { try await PreConnectHookRunner.run(script: script) } catch { diff --git a/docs/features/deep-links.mdx b/docs/features/deep-links.mdx index 8dee17f7..18aee69c 100644 --- a/docs/features/deep-links.mdx +++ b/docs/features/deep-links.mdx @@ -111,7 +111,7 @@ open "tablepro://connect/Production/database/analytics/table/events" tablepro://connect/{name}/query?sql={encoded_sql} ``` -Connects and opens a new query tab with the SQL pre-filled. The SQL must be percent-encoded. +Connects and opens a new query tab with the SQL pre-filled. The SQL must be percent-encoded. A confirmation dialog shows the SQL before opening, so you can verify the query is safe. ```bash open "tablepro://connect/Production/query?sql=SELECT%20*%20FROM%20users%20LIMIT%2010" @@ -123,7 +123,7 @@ open "tablepro://connect/Production/query?sql=SELECT%20*%20FROM%20users%20LIMIT% tablepro://import?name={n}&host={h}&port={p}&type={t}&username={u}&database={db} ``` -Creates a new saved connection and opens the connection form for review. You can add a password before connecting. +Creates a new saved connection and opens the connection form for review. A confirmation dialog shows the connection details before adding, so you can reject unexpected imports. You can add a password before connecting. ```bash open "tablepro://import?name=Staging&host=db.example.com&port=5432&type=postgresql&username=admin&database=mydb" From b0bafd7af6fb3595e9e3ff29ab22f8a3dc45ec1f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Monge=20Jim=C3=A9nez?= Date: Fri, 27 Mar 2026 09:47:04 -0600 Subject: [PATCH 2/3] fix: simplify changelog entry --- CHANGELOG.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5c3aeef1..dd8f1211 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,9 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Confirmation dialog before opening queries from external deep links -- Confirmation dialog before running pre-connect shell scripts -- Confirmation dialog before importing connections from deep links +- Confirmation dialogs for deep link queries, connection imports, and pre-connect scripts ## [0.25.0] - 2026-03-27 From 9162c5b22d46d9ba7968396528c879cc9841f6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Allan=20Monge=20Jim=C3=A9nez?= Date: Fri, 27 Mar 2026 11:45:54 -0600 Subject: [PATCH 3/3] fix: add missing AppKit import in DatabaseManager --- TablePro/Core/Database/DatabaseManager.swift | 1 + 1 file changed, 1 insertion(+) diff --git a/TablePro/Core/Database/DatabaseManager.swift b/TablePro/Core/Database/DatabaseManager.swift index dccfa682..f9112058 100644 --- a/TablePro/Core/Database/DatabaseManager.swift +++ b/TablePro/Core/Database/DatabaseManager.swift @@ -5,6 +5,7 @@ // Created by Ngo Quoc Dat on 16/12/25. // +import AppKit import Foundation import Observation import os