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
9 changes: 8 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Add database URL scheme support — open connections directly from terminal with `open "mysql://user@host/db" -a TablePro` (supports MySQL, PostgreSQL, SQLite, MongoDB, Redis, MSSQL)
- Oracle Database support via OCI (Oracle Call Interface)
- Add database URL scheme support — open connections directly from terminal with `open "mysql://user@host/db" -a TablePro` (supports MySQL, PostgreSQL, SQLite, MongoDB, Redis, MSSQL, Oracle)
- SSH Agent authentication method for SSH tunnels (compatible with 1Password SSH Agent, Secretive, ssh-agent)

### Changed
Expand All @@ -18,6 +19,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fix memory leak where session state objects were recreated on every tab open due to SwiftUI `@State` init trap, causing 785MB usage at 5 tabs with 734MB retained after closing
- Fix per-cell field editor allocation in DataGrid creating 180+ NSTextView instances instead of sharing one
- Fix NSEvent monitor not removed on all popover dismissal paths in connection switcher
- Fix race condition in FreeTDS `disconnect()` where `dbproc` was set to nil without holding the lock
- Fix data race in `MainContentCoordinator.deinit` reading `nonisolated(unsafe)` flags from arbitrary threads
- Fix JSON encoding and file I/O blocking the main thread in TabStateStorage
- Fix MySQL/MariaDB getting `BEGIN` instead of `START TRANSACTION` in table operations and SQL preview
- Fix port resetting to default value when editing a connection with a custom port
- Replace `.onTapGesture` with `Button` in color pickers, section headers, group headers, and connection switcher for VoiceOver accessibility
Expand Down
17 changes: 17 additions & 0 deletions TablePro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
5ACE00012F4F000000000006 /* CodeEditTextView in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000007 /* CodeEditTextView */; };
5ACE00012F4F00000000000A /* Sparkle in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000009 /* Sparkle */; };
5ACE00012F4F00000000000D /* MarkdownUI in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F00000000000C /* MarkdownUI */; };
5AEE5B362F5C9B7B00FA84D7 /* OracleNIO in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F00000000000F /* OracleNIO */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -61,6 +62,7 @@
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
5AEE5B362F5C9B7B00FA84D7 /* OracleNIO in Frameworks */,
5ACE00012F4F000000000004 /* CodeEditSourceEditor in Frameworks */,
5ACE00012F4F000000000005 /* CodeEditLanguages in Frameworks */,
5ACE00012F4F000000000006 /* CodeEditTextView in Frameworks */,
Expand Down Expand Up @@ -131,6 +133,7 @@
5ACE00012F4F000000000007 /* CodeEditTextView */,
5ACE00012F4F000000000009 /* Sparkle */,
5ACE00012F4F00000000000C /* MarkdownUI */,
5ACE00012F4F00000000000F /* OracleNIO */,
);
productName = TablePro;
productReference = 5A1091C72EF17EDC0055EA7C /* TablePro.app */;
Expand Down Expand Up @@ -191,6 +194,7 @@
5ACE00012F4F000000000008 /* XCRemoteSwiftPackageReference "Sparkle" */,
5ACE00012F4F00000000000B /* XCRemoteSwiftPackageReference "swift-markdown-ui" */,
5A0000012F4F000000000100 /* XCLocalSwiftPackageReference "LocalPackages/CodeEditLanguages" */,
5ACE00012F4F00000000000E /* XCRemoteSwiftPackageReference "oracle-nio" */,
);
preferredProjectObjectVersion = 77;
productRefGroup = 5A1091C82EF17EDC0055EA7C /* Products */;
Expand Down Expand Up @@ -680,6 +684,14 @@
minimumVersion = 2.0.0;
};
};
5ACE00012F4F00000000000E /* XCRemoteSwiftPackageReference "oracle-nio" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/lovetodream/oracle-nio";
requirement = {
kind = exactVersion;
version = "1.0.0-rc.4";
};
};
/* End XCRemoteSwiftPackageReference section */

/* Begin XCSwiftPackageProductDependency section */
Expand All @@ -705,6 +717,11 @@
package = 5ACE00012F4F00000000000B /* XCRemoteSwiftPackageReference "swift-markdown-ui" */;
productName = MarkdownUI;
};
5ACE00012F4F00000000000F /* OracleNIO */ = {
isa = XCSwiftPackageProductDependency;
package = 5ACE00012F4F00000000000E /* XCRemoteSwiftPackageReference "oracle-nio" */;
productName = OracleNIO;
};
/* End XCSwiftPackageProductDependency section */
};
rootObject = 5A1091BF2EF17EDC0055EA7C /* Project object */;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

18 changes: 12 additions & 6 deletions TablePro/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
private static let databaseURLSchemes: Set<String> = [
"postgresql", "postgres", "mysql", "mariadb", "sqlite",
"mongodb", "mongodb+srv", "redis", "rediss", "redshift",
"mssql", "sqlserver"
"mssql", "sqlserver", "oracle"
]

func applicationDockMenu(_ sender: NSApplication) -> NSMenu? {
Expand Down Expand Up @@ -385,7 +385,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
sslConfig: sslConfig,
color: color,
tagId: tagId,
redisDatabase: parsed.redisDatabase
redisDatabase: parsed.redisDatabase,
oracleServiceName: parsed.oracleServiceName
)
}

Expand Down Expand Up @@ -515,6 +516,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {
object: nil,
userInfo: ["connectionId": connectionId, "schema": schema]
)
// Wait for schema switch to propagate through SwiftUI state before opening table
try? await Task.sleep(for: .milliseconds(500))
}

Expand All @@ -528,7 +530,8 @@ class AppDelegate: NSObject, NSApplicationDelegate {
WindowOpener.shared.openNativeTab(payload)

if parsed.filterColumn != nil || parsed.filterCondition != nil {
try? await Task.sleep(for: .milliseconds(800))
// Wait for table data to load before applying filter via notification
try? await Task.sleep(for: .milliseconds(500))
NotificationCenter.default.post(
name: .applyURLFilter,
object: nil,
Expand Down Expand Up @@ -645,10 +648,10 @@ class AppDelegate: NSObject, NSApplicationDelegate {

private func scheduleWelcomeWindowSuppression() {
Task { @MainActor [weak self] in
// Single check after a short delay for window creation
// Wait for SwiftUI to create the main window after file-open triggers connection
try? await Task.sleep(for: .milliseconds(300))
self?.closeWelcomeWindowIfMainExists()
// One final check after windows settle
// Second check after windows fully settle (animations, state restoration)
try? await Task.sleep(for: .milliseconds(700))
guard let self else { return }
self.closeWelcomeWindowIfMainExists()
Expand Down Expand Up @@ -678,6 +681,7 @@ class AppDelegate: NSObject, NSApplicationDelegate {

private func postSQLFilesWhenReady(urls: [URL]) {
Task { @MainActor [weak self] in
// Brief delay to let the main window become key after connection completes
try? await Task.sleep(for: .milliseconds(100))
if !NSApp.windows.contains(where: { self?.isMainWindow($0) == true && $0.isKeyWindow }) {
Self.logger.warning("postSQLFilesWhenReady: no key main window, posting anyway")
Expand Down Expand Up @@ -874,7 +878,9 @@ class AppDelegate: NSObject, NSApplicationDelegate {
}

private func configureWelcomeWindow() {
// Wait for SwiftUI to create the welcome window, then configure it
// SwiftUI creates the welcome window asynchronously after app launch.
// Poll up to 5 times (250ms total) waiting for it to appear so we can
// configure AppKit-level style properties (hide miniaturize/zoom buttons, etc.).
Task { @MainActor [weak self] in
for _ in 0 ..< 5 {
guard let self else { return }
Expand Down
16 changes: 16 additions & 0 deletions TablePro/Assets.xcassets/oracle-icon.imageset/Contents.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"images" : [
{
"filename" : "oracle.svg",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"preserves-vector-representation" : true,
"template-rendering-intent" : "template"
}
}
1 change: 1 addition & 0 deletions TablePro/Assets.xcassets/oracle-icon.imageset/oracle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading