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

- Multi-select connections in Welcome window (Cmd+Click, Shift+Click) with bulk delete (⌘⌫), Move to Group, and multi-connect
- Drag-and-drop connections between groups, reorder within groups, and reorder groups
- Reorder connections within groups and reorder groups in Welcome window
- ClickHouse, MSSQL, Redis, XLSX Export, MQL Export, and SQL Import now ship as built-in plugins
- Large document safety caps for syntax highlighting (skip >5MB, throttle >50KB)
- Lazy-load full values for LONGTEXT/MEDIUMTEXT/CLOB columns in the detail pane sidebar
Expand Down
60 changes: 30 additions & 30 deletions TablePro.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,14 @@
5A862000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A862000D00000000 /* SQLiteDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A862000100000000 /* SQLiteDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A863000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A863000D00000000 /* ClickHouseDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A863000100000000 /* ClickHouseDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A864000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A864000D00000000 /* MSSQLDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A864000100000000 /* MSSQLDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A865000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A865000D00000000 /* MySQLDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A865000100000000 /* MySQLDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A866000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A867000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A867000D00000000 /* RedisDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A867000100000000 /* RedisDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A868000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A868000D00000000 /* PostgreSQLDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A868000100000000 /* PostgreSQLDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A869000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
Expand All @@ -26,15 +29,12 @@
5A86B000D00000000 /* JSONExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86B000100000000 /* JSONExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86C000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A86C000D00000000 /* SQLExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86C000100000000 /* SQLExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A863000D00000000 /* ClickHouseDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A863000100000000 /* ClickHouseDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A864000D00000000 /* MSSQLDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A864000100000000 /* MSSQLDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A867000D00000000 /* RedisDriver.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A867000100000000 /* RedisDriver.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86D000D00000000 /* XLSXExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86D000100000000 /* XLSXExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86E000D00000000 /* MQLExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86E000100000000 /* MQLExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86F000D00000000 /* SQLImport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86F000100000000 /* SQLImport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86D000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A86D000D00000000 /* XLSXExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86D000100000000 /* XLSXExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86E000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A86E000D00000000 /* MQLExport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86E000100000000 /* MQLExport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A86F000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5A86F000D00000000 /* SQLImport.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5A86F000100000000 /* SQLImport.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
5A87A000A00000000 /* TableProPluginKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5A860000100000000 /* TableProPluginKit.framework */; };
5ACE00012F4F000000000004 /* CodeEditSourceEditor in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000002 /* CodeEditSourceEditor */; };
5ACE00012F4F000000000005 /* CodeEditLanguages in Frameworks */ = {isa = PBXBuildFile; productRef = 5ACE00012F4F000000000003 /* CodeEditLanguages */; };
Expand Down Expand Up @@ -90,13 +90,27 @@
remoteGlobalIDString = 5A863000000000000;
remoteInfo = ClickHouseDriver;
};
5A864000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5A864000000000000;
remoteInfo = MSSQLDriver;
};
5A865000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5A865000000000000;
remoteInfo = MySQLDriver;
};
5A867000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5A867000000000000;
remoteInfo = RedisDriver;
};
5A868000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
Expand Down Expand Up @@ -132,20 +146,6 @@
remoteGlobalIDString = 5A86C000000000000;
remoteInfo = SQLExport;
};
5A864000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5A864000000000000;
remoteInfo = MSSQLDriver;
};
5A867000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5A867000000000000;
remoteInfo = RedisDriver;
};
5A86D000B00000000 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5A1091BF2EF17EDC0055EA7C /* Project object */;
Expand Down Expand Up @@ -1793,11 +1793,21 @@
target = 5A863000000000000 /* ClickHouseDriver */;
targetProxy = 5A863000B00000000 /* PBXContainerItemProxy */;
};
5A864000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A864000000000000 /* MSSQLDriver */;
targetProxy = 5A864000B00000000 /* PBXContainerItemProxy */;
};
5A865000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A865000000000000 /* MySQLDriver */;
targetProxy = 5A865000B00000000 /* PBXContainerItemProxy */;
};
5A867000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A867000000000000 /* RedisDriver */;
targetProxy = 5A867000B00000000 /* PBXContainerItemProxy */;
};
5A868000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A868000000000000 /* PostgreSQLDriver */;
Expand All @@ -1823,16 +1833,6 @@
target = 5A86C000000000000 /* SQLExport */;
targetProxy = 5A86C000B00000000 /* PBXContainerItemProxy */;
};
5A864000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A864000000000000 /* MSSQLDriver */;
targetProxy = 5A864000B00000000 /* PBXContainerItemProxy */;
};
5A867000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A867000000000000 /* RedisDriver */;
targetProxy = 5A867000B00000000 /* PBXContainerItemProxy */;
};
5A86D000C00000000 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5A86D000000000000 /* XLSXExport */;
Expand Down
19 changes: 19 additions & 0 deletions TablePro/Core/Storage/ConnectionStorage.swift
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,25 @@ final class ConnectionStorage {
deleteAllPluginSecureFields(for: connection.id, fieldIds: secureFieldIds)
}

/// Batch-delete multiple connections and clean up their Keychain entries
func deleteConnections(_ connectionsToDelete: [DatabaseConnection]) {
for conn in connectionsToDelete {
SyncChangeTracker.shared.markDeleted(.connection, id: conn.id.uuidString)
}
let idsToDelete = Set(connectionsToDelete.map(\.id))
var all = loadConnections()
all.removeAll { idsToDelete.contains($0.id) }
saveConnections(all)
for conn in connectionsToDelete {
deletePassword(for: conn.id)
deleteSSHPassword(for: conn.id)
deleteKeyPassphrase(for: conn.id)
deleteTOTPSecret(for: conn.id)
let fields = Self.secureFieldIds(for: conn.type)
deleteAllPluginSecureFields(for: conn.id, fieldIds: fields)
}
}

/// Duplicate a connection with a new UUID and "(Copy)" suffix
/// Copies all passwords from source connection to the duplicate
func duplicateConnection(_ connection: DatabaseConnection) -> DatabaseConnection {
Expand Down
60 changes: 60 additions & 0 deletions TablePro/Resources/Localizable.xcstrings
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,7 @@
}
},
"(%@)" : {
"extractionState" : "stale",
"localizations" : {
"tr" : {
"stringUnit" : {
Expand Down Expand Up @@ -3919,6 +3920,9 @@
}
}
}
},
"Are you sure you want to delete %lld connections? This cannot be undone." : {

},
"Are you sure you want to delete this connection? This cannot be undone." : {
"localizations" : {
Expand Down Expand Up @@ -6525,6 +6529,28 @@
}
}
},
"Connect %lld Connections" : {
"localizations" : {
"en" : {
"variations" : {
"plural" : {
"one" : {
"stringUnit" : {
"state" : "translated",
"value" : "Connect %lld Connection"
}
},
"other" : {
"stringUnit" : {
"state" : "translated",
"value" : "Connect %lld Connections"
}
}
}
}
}
}
},
"Connect Anyway" : {
"localizations" : {
"tr" : {
Expand Down Expand Up @@ -9299,6 +9325,28 @@
}
}
},
"Delete %lld Connections" : {
"localizations" : {
"en" : {
"variations" : {
"plural" : {
"one" : {
"stringUnit" : {
"state" : "translated",
"value" : "Delete %lld Connection"
}
},
"other" : {
"stringUnit" : {
"state" : "translated",
"value" : "Delete %lld Connections"
}
}
}
}
}
}
},
"Delete Check Constraint" : {
"extractionState" : "stale",
"localizations" : {
Expand Down Expand Up @@ -12270,6 +12318,9 @@
}
}
}
},
"Failed to load full value" : {

},
"Failed to load plugin registry" : {
"extractionState" : "stale",
Expand Down Expand Up @@ -17573,6 +17624,9 @@
}
}
}
},
"Move to Group" : {

},
"Move Up" : {
"extractionState" : "stale",
Expand Down Expand Up @@ -18113,6 +18167,9 @@
}
}
}
},
"New Group..." : {

},
"New Jump Host" : {
"localizations" : {
Expand Down Expand Up @@ -23568,6 +23625,9 @@
}
}
}
},
"Remove from Group" : {

},
"Remove license from this machine" : {
"localizations" : {
Expand Down
Loading
Loading