Skip to content

Commit 4c694a6

Browse files
committed
Merge branch 'main' into fix/datagrid-empty-after-viewmode-toggle
2 parents ab3e982 + 56cacc8 commit 4c694a6

9 files changed

Lines changed: 72 additions & 117 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 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`.
@@ -66,6 +65,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
6665
- Oracle TIMESTAMP, TIMESTAMP WITH TIME ZONE, TIMESTAMP WITH LOCAL TIME ZONE, INTERVAL DAY TO SECOND, INTERVAL YEAR TO MONTH, DATE, RAW, and BLOB columns now render through typed decoders instead of garbled text. Tables containing INTERVAL YEAR TO MONTH or BFILE columns no longer crash the app on row fetch. Unknown column types display `<unsupported: type>` instead of crashing (#965)
6766
- Oracle connections to 23ai cloud and containerized deployments no longer fail with `uncleanShutdown` mid-handshake. OOB urgent-byte send now requires the server to advertise `TNS_ACCEPT_FLAG_CHECK_OOB`, matching python-oracledb behavior (#483)
6867
- Connecting to a downloadable database type (SQL Server, Oracle, MongoDB, DuckDB, BigQuery, libSQL, Cassandra, etcd, Cloudflare D1, DynamoDB) after the plugin is disabled or uninstalled now reopens the install prompt instead of failing with "plugin may be disabled or missing from the PlugIns directory." `PluginMetadataRegistry` now treats the registry default snapshot as the source of truth for the `isDownloadable` flag, so plugin self-registration cannot flip it to false and unregistration restores the default rather than deleting the type metadata (#975)
68+
- Redshift schema switcher no longer shows an empty list for non-admin users. The driver listed schemas via `information_schema.schemata`, which on Redshift only returns schemas the current user *owns* (Redshift diverges from PostgreSQL here, where USAGE is enough). `fetchSchemas` now reads from `pg_namespace` filtered by `has_schema_privilege(current_user, nspname, 'USAGE')`, so any schema the user can actually use appears in the dropdown (#971)
6969

7070
## [0.37.0] - 2026-05-01
7171

Plugins/PostgreSQLDriverPlugin/RedshiftPluginDriver.swift

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -534,10 +534,11 @@ final class RedshiftPluginDriver: PluginDatabaseDriver, @unchecked Sendable {
534534

535535
func fetchSchemas() async throws -> [String] {
536536
let result = try await execute(query: """
537-
SELECT schema_name FROM information_schema.schemata
538-
WHERE schema_name NOT LIKE 'pg_%'
539-
AND schema_name <> 'information_schema'
540-
ORDER BY schema_name
537+
SELECT nspname FROM pg_namespace
538+
WHERE nspname NOT LIKE 'pg_%'
539+
AND nspname <> 'information_schema'
540+
AND has_schema_privilege(current_user, nspname, 'USAGE')
541+
ORDER BY nspname
541542
""")
542543
return result.rows.compactMap { row in row.first.flatMap { $0 } }
543544
}

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.

0 commit comments

Comments
 (0)