diff --git a/Plugins/CassandraDriverPlugin/Info.plist b/Plugins/CassandraDriverPlugin/Info.plist
index 737aa31f..c587cfa8 100644
--- a/Plugins/CassandraDriverPlugin/Info.plist
+++ b/Plugins/CassandraDriverPlugin/Info.plist
@@ -18,6 +18,8 @@
$(MARKETING_VERSION)
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
+ TableProPluginKitVersion
+ 1
NSPrincipalClass
$(PRODUCT_MODULE_NAME).CassandraPlugin
diff --git a/Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift b/Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift
index e3df957d..bf8d2dac 100644
--- a/Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift
+++ b/Plugins/ClickHouseDriverPlugin/ClickHousePlugin.swift
@@ -15,7 +15,7 @@ final class ClickHousePlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "ClickHouse"
static let databaseDisplayName = "ClickHouse"
- static let iconName = "bolt.fill"
+ static let iconName = "clickhouse-icon"
static let defaultPort = 8123
// MARK: - UI/Capability Metadata
diff --git a/Plugins/EtcdDriverPlugin/EtcdPlugin.swift b/Plugins/EtcdDriverPlugin/EtcdPlugin.swift
index 98d9f7cb..a9c39b45 100644
--- a/Plugins/EtcdDriverPlugin/EtcdPlugin.swift
+++ b/Plugins/EtcdDriverPlugin/EtcdPlugin.swift
@@ -17,9 +17,10 @@ final class EtcdPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "etcd"
static let databaseDisplayName = "etcd"
- static let iconName = "cylinder.fill"
+ static let iconName = "etcd-icon"
static let defaultPort = 2379
static let additionalDatabaseTypeIds: [String] = []
+ static let isDownloadable = true
static let navigationModel: NavigationModel = .standard
static let pathFieldRole: PathFieldRole = .database
diff --git a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift
index a45f97d0..460141b0 100644
--- a/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift
+++ b/Plugins/MSSQLDriverPlugin/MSSQLPlugin.swift
@@ -16,7 +16,7 @@ final class MSSQLPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "SQL Server"
static let databaseDisplayName = "SQL Server"
- static let iconName = "server.rack"
+ static let iconName = "mssql-icon"
static let defaultPort = 1433
static let additionalConnectionFields: [ConnectionField] = [
ConnectionField(id: "mssqlSchema", label: "Schema", placeholder: "dbo", defaultValue: "dbo")
diff --git a/Plugins/MongoDBDriverPlugin/MongoDBPlugin.swift b/Plugins/MongoDBDriverPlugin/MongoDBPlugin.swift
index 668fcb19..a7b01ef3 100644
--- a/Plugins/MongoDBDriverPlugin/MongoDBPlugin.swift
+++ b/Plugins/MongoDBDriverPlugin/MongoDBPlugin.swift
@@ -14,7 +14,7 @@ final class MongoDBPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "MongoDB"
static let databaseDisplayName = "MongoDB"
- static let iconName = "leaf.fill"
+ static let iconName = "mongodb-icon"
static let defaultPort = 27017
static let additionalConnectionFields: [ConnectionField] = [
ConnectionField(id: "mongoAuthSource", label: "Auth Database", placeholder: "admin"),
diff --git a/Plugins/MySQLDriverPlugin/MySQLPlugin.swift b/Plugins/MySQLDriverPlugin/MySQLPlugin.swift
index b5f1cefc..c0cbf9cf 100644
--- a/Plugins/MySQLDriverPlugin/MySQLPlugin.swift
+++ b/Plugins/MySQLDriverPlugin/MySQLPlugin.swift
@@ -20,7 +20,7 @@ final class MySQLPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "MySQL"
static let databaseDisplayName = "MySQL"
- static let iconName = "cylinder.fill"
+ static let iconName = "mysql-icon"
static let defaultPort = 3306
static let additionalConnectionFields: [ConnectionField] = []
static let additionalDatabaseTypeIds: [String] = ["MariaDB"]
diff --git a/Plugins/OracleDriverPlugin/OraclePlugin.swift b/Plugins/OracleDriverPlugin/OraclePlugin.swift
index 0e9afa99..331d347c 100644
--- a/Plugins/OracleDriverPlugin/OraclePlugin.swift
+++ b/Plugins/OracleDriverPlugin/OraclePlugin.swift
@@ -15,7 +15,7 @@ final class OraclePlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "Oracle"
static let databaseDisplayName = "Oracle"
- static let iconName = "server.rack"
+ static let iconName = "oracle-icon"
static let defaultPort = 1521
static let additionalConnectionFields: [ConnectionField] = [
ConnectionField(id: "oracleServiceName", label: "Service Name", placeholder: "ORCL")
diff --git a/Plugins/PostgreSQLDriverPlugin/PostgreSQLPlugin.swift b/Plugins/PostgreSQLDriverPlugin/PostgreSQLPlugin.swift
index d77935ff..6b8b646e 100644
--- a/Plugins/PostgreSQLDriverPlugin/PostgreSQLPlugin.swift
+++ b/Plugins/PostgreSQLDriverPlugin/PostgreSQLPlugin.swift
@@ -19,7 +19,7 @@ final class PostgreSQLPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "PostgreSQL"
static let databaseDisplayName = "PostgreSQL"
- static let iconName = "cylinder.fill"
+ static let iconName = "postgresql-icon"
static let defaultPort = 5432
static let additionalConnectionFields: [ConnectionField] = [
ConnectionField(
diff --git a/Plugins/RedisDriverPlugin/Info.plist b/Plugins/RedisDriverPlugin/Info.plist
index 2d7c7ce9..57a55450 100644
--- a/Plugins/RedisDriverPlugin/Info.plist
+++ b/Plugins/RedisDriverPlugin/Info.plist
@@ -18,6 +18,8 @@
$(MARKETING_VERSION)
CFBundleVersion
$(CURRENT_PROJECT_VERSION)
+ TableProPluginKitVersion
+ 1
NSPrincipalClass
$(PRODUCT_MODULE_NAME).RedisPlugin
diff --git a/Plugins/RedisDriverPlugin/RedisPlugin.swift b/Plugins/RedisDriverPlugin/RedisPlugin.swift
index 2a91c02c..007dea01 100644
--- a/Plugins/RedisDriverPlugin/RedisPlugin.swift
+++ b/Plugins/RedisDriverPlugin/RedisPlugin.swift
@@ -19,7 +19,7 @@ final class RedisPlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "Redis"
static let databaseDisplayName = "Redis"
- static let iconName = "cylinder.fill"
+ static let iconName = "redis-icon"
static let defaultPort = 6379
static let additionalConnectionFields: [ConnectionField] = [
ConnectionField(
diff --git a/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift b/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift
index d6ed628e..67a31892 100644
--- a/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift
+++ b/Plugins/SQLiteDriverPlugin/SQLitePlugin.swift
@@ -16,7 +16,7 @@ final class SQLitePlugin: NSObject, TableProPlugin, DriverPlugin {
static let databaseTypeId = "SQLite"
static let databaseDisplayName = "SQLite"
- static let iconName = "doc.fill"
+ static let iconName = "sqlite-icon"
static let defaultPort = 0
// MARK: - UI/Capability Metadata
@@ -24,7 +24,7 @@ final class SQLitePlugin: NSObject, TableProPlugin, DriverPlugin {
static let requiresAuthentication = false
static let supportsSSH = false
static let supportsSSL = false
- static let isDownloadable = true
+ static let isDownloadable = false
static let pathFieldRole: PathFieldRole = .filePath
static let connectionMode: ConnectionMode = .fileBased
static let urlSchemes: [String] = ["sqlite"]
diff --git a/TablePro.xcodeproj/project.pbxproj b/TablePro.xcodeproj/project.pbxproj
index 9246c9c1..3c63afc3 100644
--- a/TablePro.xcodeproj/project.pbxproj
+++ b/TablePro.xcodeproj/project.pbxproj
@@ -35,7 +35,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 */; };
- 5AEA8B302F6808270040461A /* EtcdDriverPlugin.tableplugin in Copy Plug-Ins */ = {isa = PBXBuildFile; fileRef = 5AEA8B2A2F6808270040461A /* EtcdDriverPlugin.tableplugin */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+
5AEA8B422F6808CA0040461A /* EtcdStatementGenerator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA8B402F6808CA0040461A /* EtcdStatementGenerator.swift */; };
5AEA8B432F6808CA0040461A /* EtcdPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA8B3D2F6808CA0040461A /* EtcdPlugin.swift */; };
5AEA8B442F6808CA0040461A /* EtcdCommandParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 5AEA8B3B2F6808CA0040461A /* EtcdCommandParser.swift */; };
@@ -153,7 +153,6 @@
5A86A000D00000000 /* CSVExport.tableplugin in Copy Plug-Ins */,
5A86B000D00000000 /* JSONExport.tableplugin in Copy Plug-Ins */,
5A86C000D00000000 /* SQLExport.tableplugin in Copy Plug-Ins */,
- 5AEA8B302F6808270040461A /* EtcdDriverPlugin.tableplugin in Copy Plug-Ins */,
);
name = "Copy Plug-Ins";
runOnlyForDeploymentPostprocessing = 0;
@@ -769,7 +768,6 @@
5A86A000C00000000 /* PBXTargetDependency */,
5A86B000C00000000 /* PBXTargetDependency */,
5A86C000C00000000 /* PBXTargetDependency */,
- 5AEA8B322F6808270040461A /* PBXTargetDependency */,
);
fileSystemSynchronizedGroups = (
5A1091C92EF17EDC0055EA7C /* TablePro */,
diff --git a/TablePro/AppDelegate+WindowConfig.swift b/TablePro/AppDelegate+WindowConfig.swift
index c2320983..4a9f884d 100644
--- a/TablePro/AppDelegate+WindowConfig.swift
+++ b/TablePro/AppDelegate+WindowConfig.swift
@@ -38,7 +38,10 @@ extension AppDelegate {
)
item.target = self
item.representedObject = connection.id
- if let original = NSImage(named: connection.type.iconName) {
+ let iconName = connection.type.iconName
+ let original = NSImage(systemSymbolName: iconName, accessibilityDescription: nil)
+ ?? NSImage(named: iconName)
+ if let original {
let resized = NSImage(size: NSSize(width: 16, height: 16), flipped: false) { rect in
original.draw(in: rect)
return true
diff --git a/TablePro/Core/Plugins/PluginManager.swift b/TablePro/Core/Plugins/PluginManager.swift
index 7d194ec3..3692b7b7 100644
--- a/TablePro/Core/Plugins/PluginManager.swift
+++ b/TablePro/Core/Plugins/PluginManager.swift
@@ -249,6 +249,7 @@ final class PluginManager {
try validateDriverDescriptor(type(of: driver), pluginId: pluginId)
} catch {
Self.logger.error("Plugin '\(pluginId)' driver rejected: \(error.localizedDescription)")
+ return
}
if !driverPlugins.keys.contains(type(of: driver).databaseTypeId) {
let driverType = type(of: driver)
@@ -264,9 +265,9 @@ final class PluginManager {
from: driverType,
isDownloadable: driverType.isDownloadable
)
- PluginMetadataRegistry.shared.register(snapshot: snapshot, forTypeId: typeId)
+ PluginMetadataRegistry.shared.register(snapshot: snapshot, forTypeId: typeId, preserveIcon: true)
for additionalId in driverType.additionalDatabaseTypeIds {
- PluginMetadataRegistry.shared.register(snapshot: snapshot, forTypeId: additionalId)
+ PluginMetadataRegistry.shared.register(snapshot: snapshot, forTypeId: additionalId, preserveIcon: true)
PluginMetadataRegistry.shared.registerTypeAlias(additionalId, primaryTypeId: typeId)
}
diff --git a/TablePro/Core/Plugins/PluginMetadataRegistry.swift b/TablePro/Core/Plugins/PluginMetadataRegistry.swift
index f5051078..4f7d5f6f 100644
--- a/TablePro/Core/Plugins/PluginMetadataRegistry.swift
+++ b/TablePro/Core/Plugins/PluginMetadataRegistry.swift
@@ -117,6 +117,22 @@ struct PluginMetadataSnapshot: Sendable {
additionalConnectionFields: []
)
}
+
+ func withIconName(_ newIconName: String) -> PluginMetadataSnapshot {
+ PluginMetadataSnapshot(
+ displayName: displayName, iconName: newIconName, defaultPort: defaultPort,
+ requiresAuthentication: requiresAuthentication, supportsForeignKeys: supportsForeignKeys,
+ supportsSchemaEditing: supportsSchemaEditing, isDownloadable: isDownloadable,
+ primaryUrlScheme: primaryUrlScheme, parameterStyle: parameterStyle,
+ navigationModel: navigationModel, explainVariants: explainVariants,
+ pathFieldRole: pathFieldRole, supportsHealthMonitor: supportsHealthMonitor,
+ urlSchemes: urlSchemes, postConnectActions: postConnectActions,
+ brandColorHex: brandColorHex, queryLanguageName: queryLanguageName,
+ editorLanguage: editorLanguage, connectionMode: connectionMode,
+ supportsDatabaseSwitching: supportsDatabaseSwitching,
+ capabilities: capabilities, schema: schema, editor: editor, connection: connection
+ )
+ }
}
final class PluginMetadataRegistry: @unchecked Sendable {
@@ -513,11 +529,15 @@ final class PluginMetadataRegistry: @unchecked Sendable {
reverseTypeIndex["ScyllaDB"] = "Cassandra"
}
- func register(snapshot: PluginMetadataSnapshot, forTypeId typeId: String) {
+ func register(snapshot: PluginMetadataSnapshot, forTypeId typeId: String, preserveIcon: Bool = false) {
lock.lock()
defer { lock.unlock() }
- snapshots[typeId] = snapshot
- for scheme in snapshot.urlSchemes {
+ var resolved = snapshot
+ if preserveIcon, let existingIcon = snapshots[typeId]?.iconName {
+ resolved = snapshot.withIconName(existingIcon)
+ }
+ snapshots[typeId] = resolved
+ for scheme in resolved.urlSchemes {
schemeIndex[scheme.lowercased()] = typeId
}
}
diff --git a/TablePro/Core/Services/Infrastructure/SessionStateFactory.swift b/TablePro/Core/Services/Infrastructure/SessionStateFactory.swift
index 47106a1b..122ae1ae 100644
--- a/TablePro/Core/Services/Infrastructure/SessionStateFactory.swift
+++ b/TablePro/Core/Services/Infrastructure/SessionStateFactory.swift
@@ -71,6 +71,10 @@ enum SessionStateFactory {
if payload.showStructure {
tabMgr.tabs[index].showStructure = true
}
+ if let initialFilter = payload.initialFilterState {
+ tabMgr.tabs[index].filterState = initialFilter
+ filterMgr.restoreFromTabState(initialFilter)
+ }
}
} else {
tabMgr.addTab(databaseName: payload.databaseName ?? connection.database)
diff --git a/TablePro/Models/Connection/DatabaseConnection.swift b/TablePro/Models/Connection/DatabaseConnection.swift
index d6b61ac8..cb871b9a 100644
--- a/TablePro/Models/Connection/DatabaseConnection.swift
+++ b/TablePro/Models/Connection/DatabaseConnection.swift
@@ -282,6 +282,16 @@ extension DatabaseType {
PluginMetadataRegistry.shared.snapshot(forTypeId: pluginTypeId)?.iconName ?? "database-icon"
}
+ /// Returns the correct SwiftUI Image for this database type, handling both
+ /// SF Symbol names (e.g. "cylinder.fill") and asset catalog names (e.g. "mysql-icon").
+ var iconImage: Image {
+ let name = iconName
+ if NSImage(systemSymbolName: name, accessibilityDescription: nil) != nil {
+ return Image(systemName: name)
+ }
+ return Image(name)
+ }
+
var defaultPort: Int {
PluginMetadataRegistry.shared.snapshot(forTypeId: pluginTypeId)?.defaultPort ?? 0
}
diff --git a/TablePro/Models/Database/TableFilter.swift b/TablePro/Models/Database/TableFilter.swift
index bdf17b6b..d1b09a58 100644
--- a/TablePro/Models/Database/TableFilter.swift
+++ b/TablePro/Models/Database/TableFilter.swift
@@ -71,7 +71,7 @@ enum FilterOperator: String, CaseIterable, Identifiable, Codable {
}
/// Represents a single table filter condition
-struct TableFilter: Identifiable, Equatable, Codable {
+struct TableFilter: Identifiable, Equatable, Hashable, Codable {
let id: UUID
var columnName: String // Column to filter on, or "__RAW__" for raw SQL
var filterOperator: FilterOperator
@@ -151,7 +151,7 @@ struct TableFilter: Identifiable, Equatable, Codable {
}
/// Stores per-tab filter state (preserves filters when switching tabs)
-struct TabFilterState: Equatable, Codable {
+struct TabFilterState: Equatable, Hashable, Codable {
var filters: [TableFilter]
var appliedFilters: [TableFilter]
var isVisible: Bool
diff --git a/TablePro/Models/Query/EditorTabPayload.swift b/TablePro/Models/Query/EditorTabPayload.swift
index f2c3c32a..85e8243b 100644
--- a/TablePro/Models/Query/EditorTabPayload.swift
+++ b/TablePro/Models/Query/EditorTabPayload.swift
@@ -31,6 +31,8 @@ internal struct EditorTabPayload: Codable, Hashable {
internal let skipAutoExecute: Bool
/// Whether this tab is a preview (temporary) tab
internal let isPreview: Bool
+ /// Initial filter state (for FK navigation — pre-applies a WHERE filter)
+ internal let initialFilterState: TabFilterState?
internal init(
id: UUID = UUID(),
@@ -42,7 +44,8 @@ internal struct EditorTabPayload: Codable, Hashable {
isView: Bool = false,
showStructure: Bool = false,
skipAutoExecute: Bool = false,
- isPreview: Bool = false
+ isPreview: Bool = false,
+ initialFilterState: TabFilterState? = nil
) {
self.id = id
self.connectionId = connectionId
@@ -54,6 +57,7 @@ internal struct EditorTabPayload: Codable, Hashable {
self.showStructure = showStructure
self.skipAutoExecute = skipAutoExecute
self.isPreview = isPreview
+ self.initialFilterState = initialFilterState
}
internal init(from decoder: Decoder) throws {
@@ -68,6 +72,7 @@ internal struct EditorTabPayload: Codable, Hashable {
showStructure = try container.decodeIfPresent(Bool.self, forKey: .showStructure) ?? false
skipAutoExecute = try container.decodeIfPresent(Bool.self, forKey: .skipAutoExecute) ?? false
isPreview = try container.decodeIfPresent(Bool.self, forKey: .isPreview) ?? false
+ initialFilterState = try container.decodeIfPresent(TabFilterState.self, forKey: .initialFilterState)
}
/// Whether this payload is a "connection-only" payload — just a connectionId
@@ -89,5 +94,6 @@ internal struct EditorTabPayload: Codable, Hashable {
self.showStructure = tab.showStructure
self.skipAutoExecute = skipAutoExecute
self.isPreview = false
+ self.initialFilterState = nil
}
}
diff --git a/TablePro/Views/Connection/ConnectionFormView.swift b/TablePro/Views/Connection/ConnectionFormView.swift
index c168fdcf..8e6583d1 100644
--- a/TablePro/Views/Connection/ConnectionFormView.swift
+++ b/TablePro/Views/Connection/ConnectionFormView.swift
@@ -233,7 +233,7 @@ struct ConnectionFormView: View { // swiftlint:disable:this type_body_length
}
}
} icon: {
- Image(t.iconName)
+ t.iconImage
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 20, height: 20)
diff --git a/TablePro/Views/Connection/ConnectionSidebarHeader.swift b/TablePro/Views/Connection/ConnectionSidebarHeader.swift
index 6ad1debf..a9772a84 100644
--- a/TablePro/Views/Connection/ConnectionSidebarHeader.swift
+++ b/TablePro/Views/Connection/ConnectionSidebarHeader.swift
@@ -34,7 +34,7 @@ struct ConnectionSidebarHeader: View {
onSelectSession(session.id)
}) {
HStack {
- Image(session.connection.type.iconName)
+ session.connection.type.iconImage
.renderingMode(.template)
.foregroundStyle(session.connection.displayColor)
@@ -67,7 +67,7 @@ struct ConnectionSidebarHeader: View {
onOpenConnection(connection)
}) {
HStack {
- Image(connection.type.iconName)
+ connection.type.iconImage
.renderingMode(.template)
.foregroundStyle(connection.displayColor)
@@ -90,7 +90,7 @@ struct ConnectionSidebarHeader: View {
HStack(spacing: 8) {
// Database icon
if let session = currentSession {
- Image(session.connection.type.iconName)
+ session.connection.type.iconImage
.renderingMode(.template)
.font(.system(size: ThemeEngine.shared.activeTheme.iconSizes.medium))
.foregroundStyle(session.connection.displayColor)
diff --git a/TablePro/Views/Connection/WelcomeWindowView.swift b/TablePro/Views/Connection/WelcomeWindowView.swift
index 54cc02fd..70eda06a 100644
--- a/TablePro/Views/Connection/WelcomeWindowView.swift
+++ b/TablePro/Views/Connection/WelcomeWindowView.swift
@@ -649,7 +649,7 @@ private struct ConnectionRow: View {
var body: some View {
HStack(spacing: 12) {
// Database type icon
- Image(connection.type.iconName)
+ connection.type.iconImage
.renderingMode(.template)
.font(.system(size: ThemeEngine.shared.activeTheme.iconSizes.medium))
.foregroundStyle(connection.displayColor)
diff --git a/TablePro/Views/Main/Extensions/MainContentCoordinator+FKNavigation.swift b/TablePro/Views/Main/Extensions/MainContentCoordinator+FKNavigation.swift
index 67e6679d..dc8b2807 100644
--- a/TablePro/Views/Main/Extensions/MainContentCoordinator+FKNavigation.swift
+++ b/TablePro/Views/Main/Extensions/MainContentCoordinator+FKNavigation.swift
@@ -52,12 +52,20 @@ extension MainContentCoordinator {
// If current tab has unsaved changes, open in a new native tab instead of replacing
if changeManager.hasChanges {
+ let fkFilterState = TabFilterState(
+ filters: [filter],
+ appliedFilters: [filter],
+ isVisible: true,
+ quickSearchText: "",
+ filterLogicMode: .and
+ )
let payload = EditorTabPayload(
connectionId: connection.id,
tabType: .table,
tableName: referencedTable,
databaseName: currentDatabase,
- isView: false
+ isView: false,
+ initialFilterState: fkFilterState
)
WindowOpener.shared.openNativeTab(payload)
return
diff --git a/TablePro/Views/Main/MainContentView.swift b/TablePro/Views/Main/MainContentView.swift
index b86cc64b..095fd115 100644
--- a/TablePro/Views/Main/MainContentView.swift
+++ b/TablePro/Views/Main/MainContentView.swift
@@ -487,6 +487,20 @@ struct MainContentView: View {
{
Task { await coordinator.switchDatabase(to: selectedTab.databaseName) }
} else {
+ if !selectedTab.filterState.appliedFilters.isEmpty,
+ let tableName = selectedTab.tableName,
+ let tabIndex = tabManager.selectedTabIndex
+ {
+ // columns is [] on initial load — buildFilteredQuery uses SELECT *
+ let filteredQuery = coordinator.queryBuilder.buildFilteredQuery(
+ tableName: tableName,
+ filters: selectedTab.filterState.appliedFilters,
+ columns: [],
+ limit: selectedTab.pagination.pageSize,
+ offset: selectedTab.pagination.currentOffset
+ )
+ tabManager.tabs[tabIndex].query = filteredQuery
+ }
coordinator.executeTableTabQueryDirectly()
}
} else {