Skip to content

Commit 463f18e

Browse files
committed
chore: remove in-app newsletter NSAlert
The native NSAlert that fired after the third successful connection felt bloaty and was steering users to a popup on the website that has also been removed. Drop the whole pipeline. Removed: - NewsletterPromptCoordinator (NSAlert + Safari opener) - AppDelegate registration call - successfulConnectionRecorded notification + the post site in DatabaseManager+Sessions - MacAnalyticsProvider successfulConnectionCount counter, newsletterPromptShown latch, markNewsletterPromptShown, and the Keys.successfulConnectionCount / Keys.newsletterPromptShown entries - Localized strings: "Stay updated on TablePro releases", "Get release notes ...", "Subscribe in Browser", "Maybe later" - Two MacAnalyticsProvider tests for the removed counter and latch - CHANGELOG entry for the prompt (it never shipped, so drop the line rather than add a "Removed" entry per project conventions) What stays: - markConnectionAttempted / markConnectionSucceeded / markFirstQueryExecuted write-once timestamps for the activation funnel telemetry remain unchanged.
1 parent a9f3d7d commit 463f18e

8 files changed

Lines changed: 66 additions & 113 deletions

File tree

CHANGELOG.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1212
- Sample database (Chinook) bundled — open from welcome screen with one click; reset via File menu
1313
- Connection string detection — paste a `postgres://`, `mysql://`, `redis://`, or `mongodb://` URL, then click Use to auto-fill the connection form
1414
- 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.
15-
- 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.
1615
- 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.
1716
- 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.
1817
- 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`.

TablePro/AppDelegate.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,6 @@ class AppDelegate: NSObject, NSApplicationDelegate {
5858
}
5959

6060
AnalyticsService.shared.startPeriodicHeartbeat()
61-
NewsletterPromptCoordinator.shared.start()
6261

6362
SyncCoordinator.shared.start()
6463
LinkedFolderWatcher.shared.start()

TablePro/Core/Database/DatabaseManager+Sessions.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,6 @@ extension DatabaseManager {
140140

141141
MacAnalyticsProvider.shared.markConnectionSucceeded()
142142
NotificationCenter.default.post(name: .databaseDidConnect, object: nil)
143-
NotificationCenter.default.post(name: .successfulConnectionRecorded, object: nil)
144143

145144
let supportsHealth = PluginMetadataRegistry.shared.snapshot(
146145
forTypeId: connection.type.pluginTypeId

TablePro/Core/Services/Infrastructure/AppNotifications.swift

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ extension Notification.Name {
1919
static let connectionUpdated = Notification.Name("connectionUpdated")
2020
static let connectionStatusDidChange = Notification.Name("connectionStatusDidChange")
2121
static let databaseDidConnect = Notification.Name("databaseDidConnect")
22-
static let successfulConnectionRecorded = Notification.Name("successfulConnectionRecorded")
2322
static let exportConnections = Notification.Name("exportConnections")
2423
static let importConnections = Notification.Name("importConnections")
2524
static let importConnectionsFromApp = Notification.Name("importConnectionsFromApp")

TablePro/Core/Services/Infrastructure/MacAnalyticsProvider.swift

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,6 @@ final class MacAnalyticsProvider: AnalyticsEnvironmentProvider {
1919
static let connectionAttemptedAt = "com.TablePro.analytics.connectionAttemptedAt"
2020
static let connectionSucceededAt = "com.TablePro.analytics.connectionSucceededAt"
2121
static let firstQueryExecutedAt = "com.TablePro.analytics.firstQueryExecutedAt"
22-
static let successfulConnectionCount = "com.TablePro.analytics.successfulConnectionCount"
23-
static let newsletterPromptShown = "com.TablePro.newsletter.promptShown"
2422
}
2523

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

94-
var successfulConnectionCount: Int {
95-
defaults.integer(forKey: Keys.successfulConnectionCount)
96-
}
97-
98-
var newsletterPromptShown: Bool {
99-
defaults.bool(forKey: Keys.newsletterPromptShown)
100-
}
101-
10292
func markConnectionAttempted() {
10393
writeOnceDate(Keys.connectionAttemptedAt, label: "connectionAttemptedAt")
10494
}
10595

10696
func markConnectionSucceeded() {
10797
writeOnceDate(Keys.connectionSucceededAt, label: "connectionSucceededAt")
108-
let next = defaults.integer(forKey: Keys.successfulConnectionCount) + 1
109-
defaults.set(next, forKey: Keys.successfulConnectionCount)
11098
}
11199

112100
func markFirstQueryExecuted() {
113101
writeOnceDate(Keys.firstQueryExecutedAt, label: "firstQueryExecutedAt")
114102
}
115103

116-
func markNewsletterPromptShown() {
117-
defaults.set(true, forKey: Keys.newsletterPromptShown)
118-
}
119-
120104
private func writeOnceDate(_ key: String, label: String) {
121105
guard defaults.object(forKey: key) == nil else { return }
122106
defaults.set(Date(), forKey: key)

TablePro/Core/Services/Infrastructure/NewsletterPromptCoordinator.swift

Lines changed: 0 additions & 67 deletions
This file was deleted.

TablePro/Resources/Localizable.xcstrings

Lines changed: 62 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7836,6 +7836,9 @@
78367836
}
78377837
}
78387838
}
7839+
},
7840+
"Bundled sample database" : {
7841+
78397842
},
78407843
"Bytes Received" : {
78417844
"localizations" : {
@@ -8707,6 +8710,9 @@
87078710
}
87088711
}
87098712
}
8713+
},
8714+
"Chinook (Sample)" : {
8715+
87108716
},
87118717
"Choose a certificate or key file" : {
87128718
"localizations" : {
@@ -9751,6 +9757,9 @@
97519757
}
97529758
}
97539759
}
9760+
},
9761+
"Close the open Sample connection before resetting it." : {
9762+
97549763
},
97559764
"Closing this tab will discard all unsaved changes." : {
97569765
"extractionState" : "stale",
@@ -12466,6 +12475,9 @@
1246612475
}
1246712476
}
1246812477
}
12478+
},
12479+
"Could not install the sample database: %@" : {
12480+
1246912481
},
1247012482
"Could Not Open File" : {
1247112483
"localizations" : {
@@ -12488,6 +12500,9 @@
1248812500
}
1248912501
}
1249012502
}
12503+
},
12504+
"Could Not Open Sample" : {
12505+
1249112506
},
1249212507
"Could not parse database URL: %@" : {
1249312508
"localizations" : {
@@ -12554,6 +12569,9 @@
1255412569
}
1255512570
}
1255612571
}
12572+
},
12573+
"Could Not Reset Sample" : {
12574+
1255712575
},
1255812576
"Count all rows" : {
1255912577
"localizations" : {
@@ -12644,6 +12662,7 @@
1264412662
}
1264512663
},
1264612664
"Create a connection to get started" : {
12665+
"extractionState" : "stale",
1264712666
"localizations" : {
1264812667
"tr" : {
1264912668
"stringUnit" : {
@@ -22161,9 +22180,6 @@
2216122180
}
2216222181
}
2216322182
}
22164-
},
22165-
"Get release notes and database tips by email. No spam, unsubscribe anytime." : {
22166-
2216722183
},
2216822184
"Get Started" : {
2216922185
"localizations" : {
@@ -27669,9 +27685,6 @@
2766927685
}
2767027686
}
2767127687
}
27672-
},
27673-
"Maybe later" : {
27674-
2767527688
},
2767627689
"MCP Access Request" : {
2767727690
"localizations" : {
@@ -32264,6 +32277,9 @@
3226432277
}
3226532278
}
3226632279
}
32280+
},
32281+
"Open Sample Database" : {
32282+
3226732283
},
3226832284
"Open Schema" : {
3226932285
"localizations" : {
@@ -37806,6 +37822,15 @@
3780637822
}
3780737823
}
3780837824
}
37825+
},
37826+
"Reset Sample" : {
37827+
37828+
},
37829+
"Reset Sample Database?" : {
37830+
37831+
},
37832+
"Reset Sample Database..." : {
37833+
3780937834
},
3781037835
"Reset to Defaults" : {
3781137836
"localizations" : {
@@ -38893,6 +38918,9 @@
3889338918
}
3889438919
}
3889538920
}
38921+
},
38922+
"Sample" : {
38923+
3889638924
},
3889738925
"Sanitize formula-like values" : {
3889838926
"extractionState" : "stale",
@@ -43954,9 +43982,6 @@
4395443982
}
4395543983
}
4395643984
}
43957-
},
43958-
"Stay updated on TablePro releases" : {
43959-
4396043985
},
4396143986
"Steps to Reproduce" : {
4396243987
"localizations" : {
@@ -44266,9 +44291,6 @@
4426644291
}
4426744292
}
4426844293
}
44269-
},
44270-
"Subscribe in Browser" : {
44271-
4427244294
},
4427344295
"Success" : {
4427444296
"localizations" : {
@@ -45809,6 +45831,9 @@
4580945831
}
4581045832
}
4581145833
}
45834+
},
45835+
"The bundled sample database is missing from the app." : {
45836+
4581245837
},
4581345838
"The code expires in 15 minutes." : {
4581445839
"localizations" : {
@@ -46156,6 +46181,9 @@
4615646181
}
4615746182
}
4615846183
}
46184+
},
46185+
"The text doesn't look like a connection URL." : {
46186+
4615946187
},
4616046188
"The text is not valid JSON. Save anyway?" : {
4616146189
"localizations" : {
@@ -46333,6 +46361,9 @@
4633346361
}
4633446362
}
4633546363
}
46364+
},
46365+
"This discards your edits to the Chinook sample and restores the original copy." : {
46366+
4633646367
},
4633746368
"This DROP query will permanently remove database objects. This action cannot be undone." : {
4633846369
"localizations" : {
@@ -48449,6 +48480,7 @@
4844948480
}
4845048481
},
4845148482
"Try a different search term" : {
48483+
"extractionState" : "stale",
4845248484
"localizations" : {
4845348485
"tr" : {
4845448486
"stringUnit" : {
@@ -48469,6 +48501,9 @@
4846948501
}
4847048502
}
4847148503
}
48504+
},
48505+
"Try a different search term." : {
48506+
4847248507
},
4847348508
"Try adjusting your search terms\nor date filter." : {
4847448509
"localizations" : {
@@ -48513,6 +48548,12 @@
4851348548
}
4851448549
}
4851548550
}
48551+
},
48552+
"Try Sample Database" : {
48553+
48554+
},
48555+
"Try the sample database, or click + above to add your own." : {
48556+
4851648557
},
4851748558
"Two-Factor Authentication" : {
4851848559
"localizations" : {
@@ -49110,6 +49151,9 @@
4911049151
}
4911149152
}
4911249153
}
49154+
},
49155+
"Unsupported connection scheme: %@" : {
49156+
4911349157
},
4911449158
"Unsupported database scheme: %@" : {
4911549159
"localizations" : {
@@ -49508,6 +49552,9 @@
4950849552
}
4950949553
}
4951049554
}
49555+
},
49556+
"Use" : {
49557+
4951149558
},
4951249559
"Use ~/.pgpass" : {
4951349560
"localizations" : {
@@ -49530,6 +49577,9 @@
4953049577
}
4953149578
}
4953249579
}
49580+
},
49581+
"Use clipboard URL" : {
49582+
4953349583
},
4953449584
"Use Default" : {
4953549585
"localizations" : {

0 commit comments

Comments
 (0)