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: 0 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Sample database (Chinook) bundled — open from welcome screen with one click; reset via File menu
- Connection string detection — paste a `postgres://`, `mysql://`, `redis://`, or `mongodb://` URL, then click Use to auto-fill the connection form
- Activation telemetry: the daily heartbeat now reports three write-once timestamps per device (first connection attempt, first successful connection, first executed query), so we can see where new users drop off during activation. The values are stored locally in UserDefaults, set once and never overwritten, and the server also refuses to overwrite them once received. Both Mac and iOS send the same fields.
- Newsletter prompt on Mac: after the third successful database connection, a one-time native NSAlert offers to subscribe to release notes. "Subscribe in Browser" opens `https://tablepro.app/?subscribe=true&source=mac`, "Maybe later" dismisses. The prompt never reappears once shown.
- MCP: support for protocol versions `2025-06-18` and `2025-11-25` in addition to `2025-03-26`. Clients on the latest spec no longer downgrade. The server advertises the latest version it supports (`2025-11-25`) and falls back when a client requests an unknown version.
- MCP: structured tool output (`structuredContent`) on every tool. The serialized JSON still appears in `content[].text` for backward compatibility, while 2025-11-25 clients can read the parsed object directly.
- MCP: tool annotations (`title`, `readOnlyHint`, `destructiveHint`, `idempotentHint`, `openWorldHint`) on every tool, plus `serverInfo.title` in `initialize` responses. Read tools advertise `readOnlyHint=true`; `confirm_destructive_operation` advertises `destructiveHint=true`.
Expand Down
1 change: 0 additions & 1 deletion TablePro/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

AnalyticsService.shared.startPeriodicHeartbeat()
NewsletterPromptCoordinator.shared.start()

SyncCoordinator.shared.start()
LinkedFolderWatcher.shared.start()
Expand Down
1 change: 0 additions & 1 deletion TablePro/Core/Database/DatabaseManager+Sessions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ extension DatabaseManager {

MacAnalyticsProvider.shared.markConnectionSucceeded()
NotificationCenter.default.post(name: .databaseDidConnect, object: nil)
NotificationCenter.default.post(name: .successfulConnectionRecorded, object: nil)

let supportsHealth = PluginMetadataRegistry.shared.snapshot(
forTypeId: connection.type.pluginTypeId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ extension Notification.Name {
static let connectionUpdated = Notification.Name("connectionUpdated")
static let connectionStatusDidChange = Notification.Name("connectionStatusDidChange")
static let databaseDidConnect = Notification.Name("databaseDidConnect")
static let successfulConnectionRecorded = Notification.Name("successfulConnectionRecorded")
static let exportConnections = Notification.Name("exportConnections")
static let importConnections = Notification.Name("importConnections")
static let importConnectionsFromApp = Notification.Name("importConnectionsFromApp")
Expand Down
16 changes: 0 additions & 16 deletions TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,6 @@ final class MacAnalyticsProvider: AnalyticsEnvironmentProvider {
static let connectionAttemptedAt = "com.TablePro.analytics.connectionAttemptedAt"
static let connectionSucceededAt = "com.TablePro.analytics.connectionSucceededAt"
static let firstQueryExecutedAt = "com.TablePro.analytics.firstQueryExecutedAt"
static let successfulConnectionCount = "com.TablePro.analytics.successfulConnectionCount"
static let newsletterPromptShown = "com.TablePro.newsletter.promptShown"
}

init(defaults: UserDefaults = .standard) {
Expand Down Expand Up @@ -91,32 +89,18 @@ final class MacAnalyticsProvider: AnalyticsEnvironmentProvider {
defaults.object(forKey: Keys.firstQueryExecutedAt) as? Date
}

var successfulConnectionCount: Int {
defaults.integer(forKey: Keys.successfulConnectionCount)
}

var newsletterPromptShown: Bool {
defaults.bool(forKey: Keys.newsletterPromptShown)
}

func markConnectionAttempted() {
writeOnceDate(Keys.connectionAttemptedAt, label: "connectionAttemptedAt")
}

func markConnectionSucceeded() {
writeOnceDate(Keys.connectionSucceededAt, label: "connectionSucceededAt")
let next = defaults.integer(forKey: Keys.successfulConnectionCount) + 1
defaults.set(next, forKey: Keys.successfulConnectionCount)
}

func markFirstQueryExecuted() {
writeOnceDate(Keys.firstQueryExecutedAt, label: "firstQueryExecutedAt")
}

func markNewsletterPromptShown() {
defaults.set(true, forKey: Keys.newsletterPromptShown)
}

private func writeOnceDate(_ key: String, label: String) {
guard defaults.object(forKey: key) == nil else { return }
defaults.set(Date(), forKey: key)
Expand Down

This file was deleted.

74 changes: 62 additions & 12 deletions TablePro/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -7836,6 +7836,9 @@
}
}
}
},
"Bundled sample database" : {

},
"Bytes Received" : {
"localizations" : {
Expand Down Expand Up @@ -8707,6 +8710,9 @@
}
}
}
},
"Chinook (Sample)" : {

},
"Choose a certificate or key file" : {
"localizations" : {
Expand Down Expand Up @@ -9751,6 +9757,9 @@
}
}
}
},
"Close the open Sample connection before resetting it." : {

},
"Closing this tab will discard all unsaved changes." : {
"extractionState" : "stale",
Expand Down Expand Up @@ -12466,6 +12475,9 @@
}
}
}
},
"Could not install the sample database: %@" : {

},
"Could Not Open File" : {
"localizations" : {
Expand All @@ -12488,6 +12500,9 @@
}
}
}
},
"Could Not Open Sample" : {

},
"Could not parse database URL: %@" : {
"localizations" : {
Expand Down Expand Up @@ -12554,6 +12569,9 @@
}
}
}
},
"Could Not Reset Sample" : {

},
"Count all rows" : {
"localizations" : {
Expand Down Expand Up @@ -12644,6 +12662,7 @@
}
},
"Create a connection to get started" : {
"extractionState" : "stale",
"localizations" : {
"tr" : {
"stringUnit" : {
Expand Down Expand Up @@ -22161,9 +22180,6 @@
}
}
}
},
"Get release notes and database tips by email. No spam, unsubscribe anytime." : {

},
"Get Started" : {
"localizations" : {
Expand Down Expand Up @@ -27669,9 +27685,6 @@
}
}
}
},
"Maybe later" : {

},
"MCP Access Request" : {
"localizations" : {
Expand Down Expand Up @@ -32264,6 +32277,9 @@
}
}
}
},
"Open Sample Database" : {

},
"Open Schema" : {
"localizations" : {
Expand Down Expand Up @@ -37806,6 +37822,15 @@
}
}
}
},
"Reset Sample" : {

},
"Reset Sample Database?" : {

},
"Reset Sample Database..." : {

},
"Reset to Defaults" : {
"localizations" : {
Expand Down Expand Up @@ -38893,6 +38918,9 @@
}
}
}
},
"Sample" : {

},
"Sanitize formula-like values" : {
"extractionState" : "stale",
Expand Down Expand Up @@ -43954,9 +43982,6 @@
}
}
}
},
"Stay updated on TablePro releases" : {

},
"Steps to Reproduce" : {
"localizations" : {
Expand Down Expand Up @@ -44266,9 +44291,6 @@
}
}
}
},
"Subscribe in Browser" : {

},
"Success" : {
"localizations" : {
Expand Down Expand Up @@ -45809,6 +45831,9 @@
}
}
}
},
"The bundled sample database is missing from the app." : {

},
"The code expires in 15 minutes." : {
"localizations" : {
Expand Down Expand Up @@ -46156,6 +46181,9 @@
}
}
}
},
"The text doesn't look like a connection URL." : {

},
"The text is not valid JSON. Save anyway?" : {
"localizations" : {
Expand Down Expand Up @@ -46333,6 +46361,9 @@
}
}
}
},
"This discards your edits to the Chinook sample and restores the original copy." : {

},
"This DROP query will permanently remove database objects. This action cannot be undone." : {
"localizations" : {
Expand Down Expand Up @@ -48449,6 +48480,7 @@
}
},
"Try a different search term" : {
"extractionState" : "stale",
"localizations" : {
"tr" : {
"stringUnit" : {
Expand All @@ -48469,6 +48501,9 @@
}
}
}
},
"Try a different search term." : {

},
"Try adjusting your search terms\nor date filter." : {
"localizations" : {
Expand Down Expand Up @@ -48513,6 +48548,12 @@
}
}
}
},
"Try Sample Database" : {

},
"Try the sample database, or click + above to add your own." : {

},
"Two-Factor Authentication" : {
"localizations" : {
Expand Down Expand Up @@ -49110,6 +49151,9 @@
}
}
}
},
"Unsupported connection scheme: %@" : {

},
"Unsupported database scheme: %@" : {
"localizations" : {
Expand Down Expand Up @@ -49508,6 +49552,9 @@
}
}
}
},
"Use" : {

},
"Use ~/.pgpass" : {
"localizations" : {
Expand All @@ -49530,6 +49577,9 @@
}
}
}
},
"Use clipboard URL" : {

},
"Use Default" : {
"localizations" : {
Expand Down
Loading
Loading