From 8fb6453ac2c622cd28cc46d1911cae16bb0bebe2 Mon Sep 17 00:00:00 2001 From: sophiathedev Date: Tue, 18 Aug 2026 15:57:37 +0700 Subject: [PATCH 1/3] feat(sidebar): add favorite databases --- CHANGELOG.md | 1 + TablePro/Core/Storage/ConnectionStorage.swift | 4 + .../Storage/FavoriteDatabasesStorage.swift | 87 +++++++++++++ TablePro/Core/Sync/SyncCoordinator.swift | 4 + .../Favorites/FavoriteDatabaseEntry.swift | 40 ++++++ .../FavoriteDatabaseEnvironment.swift | 38 ++++++ .../FavoriteDatabaseEnvironmentFilter.swift | 34 +++++ .../Favorites/FavoriteDatabaseGroup.swift | 13 ++ .../Favorites/FavoriteDatabaseGrouping.swift | 33 +++++ TablePro/Models/UI/SharedSidebarState.swift | 14 +++ .../ViewModels/FavoritesExpansionState.swift | 49 ++++++++ ...abaseTreeOutlineCoordinator+Commands.swift | 8 ++ .../DatabaseTreeOutlineCoordinator+Menu.swift | 7 ++ .../DatabaseTreeOutlineCoordinator.swift | 57 +++++++-- .../Views/Sidebar/DatabaseTreeRowView.swift | 29 ++++- .../Sidebar/FavoriteDatabaseFilterBar.swift | 30 +++++ .../Views/Sidebar/FavoritesExpansion.swift | 19 +++ .../Sidebar/FavoritesOutlineCoordinator.swift | 72 +++++++++-- .../Views/Sidebar/FavoritesOutlineNode.swift | 21 +++- .../Sidebar/FavoritesOutlineSelection.swift | 8 ++ .../Views/Sidebar/FavoritesOutlineView.swift | 4 + TablePro/Views/Sidebar/FavoritesTabView.swift | 118 +++++++++++++++++- .../Sidebar/Menu/DatabaseTreeMenuSpec.swift | 30 +++++ .../Sidebar/Menu/FavoritesMenuCommand.swift | 4 + .../Sidebar/Menu/FavoritesMenuSpec.swift | 44 ++++++- .../Sidebar/Menu/SidebarMenuCommand.swift | 2 + .../Views/Sidebar/SidebarPersistenceKey.swift | 4 + TablePro/Views/Sidebar/SidebarView.swift | 1 + .../FavoriteDatabasesStorageTests.swift | 116 +++++++++++++++++ .../FavoriteDatabaseGroupingTests.swift | 97 ++++++++++++++ .../Models/SharedSidebarStateTests.swift | 18 ++- .../Sidebar/DatabaseTreeMenuSpecTests.swift | 29 +++++ .../Sidebar/FavoritesMenuSpecTests.swift | 33 +++++ .../FavoritesOutlineSelectionTests.swift | 49 ++++++++ .../Sidebar/SidebarOutlineScaffoldTests.swift | 81 ++++++++++++ docs/features/favorites.mdx | 12 +- 36 files changed, 1175 insertions(+), 35 deletions(-) create mode 100644 TablePro/Core/Storage/FavoriteDatabasesStorage.swift create mode 100644 TablePro/Models/Favorites/FavoriteDatabaseEntry.swift create mode 100644 TablePro/Models/Favorites/FavoriteDatabaseEnvironment.swift create mode 100644 TablePro/Models/Favorites/FavoriteDatabaseEnvironmentFilter.swift create mode 100644 TablePro/Models/Favorites/FavoriteDatabaseGroup.swift create mode 100644 TablePro/Models/Favorites/FavoriteDatabaseGrouping.swift create mode 100644 TablePro/Views/Sidebar/FavoriteDatabaseFilterBar.swift create mode 100644 TableProTests/Core/Storage/FavoriteDatabasesStorageTests.swift create mode 100644 TableProTests/Models/FavoriteDatabaseGroupingTests.swift diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e5f14c9d..0818f646a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Databases can be saved to the Favorites sidebar and grouped as Development, Testing, Production or Unassigned. Right-click a database in the Tree sidebar to add it, then use the environment filter or activate it directly from Favorites. (#1553) - Tree sidebar layouts group tables, views, materialized views, foreign tables, procedures and functions into collapsible folders inside each database or schema. (#1590) - Dameng DM8 connections through a downloadable native-wire plugin, with schema browsing, table editing, metadata, DDL, transactions, Unicode and binary writes, EXPLAIN support, and query cancellation with a query timeout. Stopping a DM8 query closes its connection, because DM8 has no out-of-band cancel request; TablePro reconnects on the next query. (#1671, #2003, #2010) - SQL Server connections can sign in with Microsoft Entra ID, covering Azure SQL Database, Azure SQL Managed Instance, and SQL Server 2022. Sign-in runs in your browser and honours multifactor authentication and Conditional Access; tokens are kept in the keychain and refreshed for you. Set it up on the Mac; iPhone and iPad pick the connection up through sync and prompt to sign in when you open it. diff --git a/TablePro/Core/Storage/ConnectionStorage.swift b/TablePro/Core/Storage/ConnectionStorage.swift index 61cdb307d..41ca0945b 100644 --- a/TablePro/Core/Storage/ConnectionStorage.swift +++ b/TablePro/Core/Storage/ConnectionStorage.swift @@ -291,6 +291,8 @@ final class ConnectionStorage { appSettings.saveLastSchema(nil, for: connection.id) FavoriteTablesStorage.shared.removeFavorites(for: connection.id) + FavoriteDatabasesStorage.shared.removeFavorites(for: connection.id) + FavoritesExpansionState.shared.removeConnection(connection.id) FilterSettingsStorage.shared.removeFilters(for: connection.id) DatabaseTreeFilterStorage.shared.removeFilter(for: connection.id) RecentlyClosedTabStore.shared.removeEntries(for: connection.id) @@ -331,6 +333,8 @@ final class ConnectionStorage { appSettings.saveLastDatabase(nil, for: conn.id) appSettings.saveLastSchema(nil, for: conn.id) FavoriteTablesStorage.shared.removeFavorites(for: conn.id) + FavoriteDatabasesStorage.shared.removeFavorites(for: conn.id) + FavoritesExpansionState.shared.removeConnection(conn.id) } FilterSettingsStorage.shared.removeFilters(for: idsToDelete) DatabaseTreeFilterStorage.shared.removeFilters(for: idsToDelete) diff --git a/TablePro/Core/Storage/FavoriteDatabasesStorage.swift b/TablePro/Core/Storage/FavoriteDatabasesStorage.swift new file mode 100644 index 000000000..eafc4e877 --- /dev/null +++ b/TablePro/Core/Storage/FavoriteDatabasesStorage.swift @@ -0,0 +1,87 @@ +// +// FavoriteDatabasesStorage.swift +// TablePro +// + +import Foundation +import os + +extension Notification.Name { + internal static let favoriteDatabasesDidChange = Notification.Name("FavoriteDatabasesDidChange") +} + +@MainActor +internal final class FavoriteDatabasesStorage { + internal static let shared = FavoriteDatabasesStorage() + + private static let logger = Logger(subsystem: "com.TablePro", category: "FavoriteDatabasesStorage") + private let defaults: UserDefaults + + internal init(defaults: UserDefaults = AppStorageEnvironment.shared.defaults) { + self.defaults = defaults + } + + internal func favorites(for connectionId: UUID) -> Set { + guard let data = defaults.data(forKey: key(for: connectionId)), + let decoded = try? JSONDecoder().decode(Set.self, from: data) + else { return [] } + return decoded.filter { $0.connectionId == connectionId && !$0.database.isEmpty } + } + + internal func environment( + for database: String, + connectionId: UUID + ) -> FavoriteDatabaseEnvironment? { + favorites(for: connectionId).first { $0.database == database }?.environment + } + + internal func setFavorite( + database: String, + environment: FavoriteDatabaseEnvironment, + connectionId: UUID + ) { + guard !database.isEmpty else { return } + var entries = favorites(for: connectionId) + entries = Set(entries.filter { $0.database != database }) + entries.insert(FavoriteDatabaseEntry( + connectionId: connectionId, + database: database, + environment: environment + )) + persist(entries, connectionId: connectionId) + } + + internal func removeFavorite(database: String, connectionId: UUID) { + var entries = favorites(for: connectionId) + let originalCount = entries.count + entries = Set(entries.filter { $0.database != database }) + guard entries.count != originalCount else { return } + persist(entries, connectionId: connectionId) + } + + internal func removeFavorites(for connectionId: UUID) { + let key = key(for: connectionId) + guard defaults.object(forKey: key) != nil else { return } + defaults.removeObject(forKey: key) + NotificationCenter.default.post(name: .favoriteDatabasesDidChange, object: self) + } + + private func persist(_ entries: Set, connectionId: UUID) { + let key = key(for: connectionId) + guard !entries.isEmpty else { + defaults.removeObject(forKey: key) + NotificationCenter.default.post(name: .favoriteDatabasesDidChange, object: self) + return + } + do { + defaults.set(try JSONEncoder().encode(entries), forKey: key) + NotificationCenter.default.post(name: .favoriteDatabasesDidChange, object: self) + } catch { + Self.logger.error("Failed to encode favorite databases: \(error.localizedDescription, privacy: .public)") + } + } + + private func key(for connectionId: UUID) -> String { + "com.TablePro.favoriteDatabases.\(connectionId.uuidString)" + } +} diff --git a/TablePro/Core/Sync/SyncCoordinator.swift b/TablePro/Core/Sync/SyncCoordinator.swift index a2917b34b..be0077e13 100644 --- a/TablePro/Core/Sync/SyncCoordinator.swift +++ b/TablePro/Core/Sync/SyncCoordinator.swift @@ -519,6 +519,10 @@ final class SyncCoordinator { Self.logger.error("Failed to apply remote connection deletions: persistence error") } else { FilterSettingsStorage.shared.removeFilters(for: connectionIdsToDelete) + for id in connectionIdsToDelete { + FavoriteDatabasesStorage.shared.removeFavorites(for: id) + FavoritesExpansionState.shared.removeConnection(id) + } let favoriteManager = services.sqlFavoriteManager Task { for id in connectionIdsToDelete { diff --git a/TablePro/Models/Favorites/FavoriteDatabaseEntry.swift b/TablePro/Models/Favorites/FavoriteDatabaseEntry.swift new file mode 100644 index 000000000..f35de96a9 --- /dev/null +++ b/TablePro/Models/Favorites/FavoriteDatabaseEntry.swift @@ -0,0 +1,40 @@ +// +// FavoriteDatabaseEntry.swift +// TablePro +// + +import Foundation + +internal struct FavoriteDatabaseEntry: Codable, Hashable, Identifiable, Sendable { + internal let connectionId: UUID + internal let database: String + internal let environment: FavoriteDatabaseEnvironment + + internal var id: String { + "\(connectionId.uuidString)\u{1}\(database)" + } + + internal init( + connectionId: UUID, + database: String, + environment: FavoriteDatabaseEnvironment + ) { + self.connectionId = connectionId + self.database = database + self.environment = environment + } + + private enum CodingKeys: String, CodingKey { + case connectionId + case database + case environment + } + + internal init(from decoder: Decoder) throws { + let container = try decoder.container(keyedBy: CodingKeys.self) + connectionId = try container.decode(UUID.self, forKey: .connectionId) + database = try container.decode(String.self, forKey: .database) + let rawEnvironment = try container.decodeIfPresent(String.self, forKey: .environment) + environment = rawEnvironment.flatMap(FavoriteDatabaseEnvironment.init(rawValue:)) ?? .none + } +} diff --git a/TablePro/Models/Favorites/FavoriteDatabaseEnvironment.swift b/TablePro/Models/Favorites/FavoriteDatabaseEnvironment.swift new file mode 100644 index 000000000..b3f76ff3c --- /dev/null +++ b/TablePro/Models/Favorites/FavoriteDatabaseEnvironment.swift @@ -0,0 +1,38 @@ +// +// FavoriteDatabaseEnvironment.swift +// TablePro +// + +import Foundation + +internal enum FavoriteDatabaseEnvironment: String, CaseIterable, Codable, Sendable { + case development + case testing + case production + case none + + internal var title: String { + switch self { + case .development: String(localized: "Development") + case .testing: String(localized: "Testing") + case .production: String(localized: "Production") + case .none: String(localized: "Unassigned") + } + } + + internal var menuTitle: String { + switch self { + case .none: String(localized: "No Environment") + case .development, .testing, .production: title + } + } + + internal var iconName: String { + switch self { + case .development: "wrench.and.screwdriver" + case .testing: "checkmark.circle" + case .production: "lock.shield" + case .none: "tray" + } + } +} diff --git a/TablePro/Models/Favorites/FavoriteDatabaseEnvironmentFilter.swift b/TablePro/Models/Favorites/FavoriteDatabaseEnvironmentFilter.swift new file mode 100644 index 000000000..2d98dde05 --- /dev/null +++ b/TablePro/Models/Favorites/FavoriteDatabaseEnvironmentFilter.swift @@ -0,0 +1,34 @@ +// +// FavoriteDatabaseEnvironmentFilter.swift +// TablePro +// + +import Foundation + +internal enum FavoriteDatabaseEnvironmentFilter: String, CaseIterable, Sendable { + case all + case development + case testing + case production + case unassigned + + internal var title: String { + switch self { + case .all: String(localized: "All Environments") + case .development: FavoriteDatabaseEnvironment.development.title + case .testing: FavoriteDatabaseEnvironment.testing.title + case .production: FavoriteDatabaseEnvironment.production.title + case .unassigned: FavoriteDatabaseEnvironment.none.title + } + } + + internal var environment: FavoriteDatabaseEnvironment? { + switch self { + case .all: nil + case .development: .development + case .testing: .testing + case .production: .production + case .unassigned: FavoriteDatabaseEnvironment.none + } + } +} diff --git a/TablePro/Models/Favorites/FavoriteDatabaseGroup.swift b/TablePro/Models/Favorites/FavoriteDatabaseGroup.swift new file mode 100644 index 000000000..236411941 --- /dev/null +++ b/TablePro/Models/Favorites/FavoriteDatabaseGroup.swift @@ -0,0 +1,13 @@ +// +// FavoriteDatabaseGroup.swift +// TablePro +// + +import Foundation + +internal struct FavoriteDatabaseGroup: Equatable, Identifiable, Sendable { + internal let environment: FavoriteDatabaseEnvironment + internal let entries: [FavoriteDatabaseEntry] + + internal var id: String { environment.rawValue } +} diff --git a/TablePro/Models/Favorites/FavoriteDatabaseGrouping.swift b/TablePro/Models/Favorites/FavoriteDatabaseGrouping.swift new file mode 100644 index 000000000..0f6a06124 --- /dev/null +++ b/TablePro/Models/Favorites/FavoriteDatabaseGrouping.swift @@ -0,0 +1,33 @@ +// +// FavoriteDatabaseGrouping.swift +// TablePro +// + +import Foundation + +internal enum FavoriteDatabaseGrouping { + internal static func groups( + entries: Set, + searchText: String, + filter: FavoriteDatabaseEnvironmentFilter + ) -> [FavoriteDatabaseGroup] { + let filtered = entries.filter { entry in + guard filter.environment == nil || entry.environment == filter.environment else { return false } + guard !searchText.isEmpty else { return true } + return entry.database.localizedStandardContains(searchText) + || entry.environment.title.localizedStandardContains(searchText) + } + + return FavoriteDatabaseEnvironment.allCases.compactMap { environment in + let matching = filtered + .filter { $0.environment == environment } + .sorted { + let comparison = $0.database.localizedStandardCompare($1.database) + if comparison != .orderedSame { return comparison == .orderedAscending } + return $0.id < $1.id + } + guard !matching.isEmpty else { return nil } + return FavoriteDatabaseGroup(environment: environment, entries: matching) + } + } +} diff --git a/TablePro/Models/UI/SharedSidebarState.swift b/TablePro/Models/UI/SharedSidebarState.swift index 544ebe7c0..9ca43a44d 100644 --- a/TablePro/Models/UI/SharedSidebarState.swift +++ b/TablePro/Models/UI/SharedSidebarState.swift @@ -112,6 +112,15 @@ final class SharedSidebarState { } } + var favoriteDatabaseEnvironmentFilter: FavoriteDatabaseEnvironmentFilter { + didSet { + AppStorageEnvironment.shared.defaults.set( + favoriteDatabaseEnvironmentFilter.rawValue, + forKey: SidebarPersistenceKey.favoriteDatabaseEnvironmentFilter(connectionId: connectionId) + ) + } + } + var selectedFavorite: FavoriteSelection? { didSet { guard oldValue != selectedFavorite else { return } @@ -156,6 +165,10 @@ final class SharedSidebarState { self.sidebarLayout = SharedSidebarState.defaultLayout } self.databaseFilterSelected = DatabaseTreeFilterStorage.shared.selectedDatabases(connectionId: connectionId) + let environmentFilterKey = SidebarPersistenceKey.favoriteDatabaseEnvironmentFilter(connectionId: connectionId) + self.favoriteDatabaseEnvironmentFilter = AppStorageEnvironment.shared.defaults + .string(forKey: environmentFilterKey) + .flatMap(FavoriteDatabaseEnvironmentFilter.init(rawValue:)) ?? .all self.selectedFavorite = AppStorageEnvironment.shared.defaults.string( forKey: SidebarPersistenceKey.selectedFavorite(connectionId: connectionId) ).flatMap(FavoriteSelection.init(rawValue:)) @@ -170,6 +183,7 @@ final class SharedSidebarState { self.selectedSidebarTab = .tables self.sidebarLayout = .flat self.databaseFilterSelected = [] + self.favoriteDatabaseEnvironmentFilter = .all self.selectedFavorite = nil } diff --git a/TablePro/ViewModels/FavoritesExpansionState.swift b/TablePro/ViewModels/FavoritesExpansionState.swift index 783dee60f..804231132 100644 --- a/TablePro/ViewModels/FavoritesExpansionState.swift +++ b/TablePro/ViewModels/FavoritesExpansionState.swift @@ -13,9 +13,12 @@ internal final class FavoritesExpansionState { private(set) var foldersByConnection: [UUID: Set] = [:] private(set) var linkedNodesByConnection: [UUID: Set] = [:] + private(set) var collapsedDatabaseEnvironmentsByConnection: [UUID: Set] = [:] @ObservationIgnored private let foldersKey = "com.TablePro.favoritesExpandedFolders" @ObservationIgnored private let linkedKey = "com.TablePro.favoritesExpandedLinkedNodes" + @ObservationIgnored private let collapsedDatabaseEnvironmentsKey = + "com.TablePro.favoritesCollapsedDatabaseEnvironments" private init() { load() @@ -29,6 +32,13 @@ internal final class FavoritesExpansionState { linkedNodesByConnection[connectionId, default: []].contains(nodeId) } + func isDatabaseEnvironmentExpanded( + _ environment: FavoriteDatabaseEnvironment, + for connectionId: UUID + ) -> Bool { + !collapsedDatabaseEnvironmentsByConnection[connectionId, default: []].contains(environment) + } + func setFolderExpanded(_ folderId: UUID, expanded: Bool, for connectionId: UUID) { var ids = foldersByConnection[connectionId] ?? [] if expanded { @@ -55,6 +65,32 @@ internal final class FavoritesExpansionState { persistLinkedNodes() } + func setDatabaseEnvironmentExpanded( + _ environment: FavoriteDatabaseEnvironment, + expanded: Bool, + for connectionId: UUID + ) { + var environments = collapsedDatabaseEnvironmentsByConnection[connectionId] ?? [] + if expanded { + guard environments.contains(environment) else { return } + environments.remove(environment) + } else { + guard !environments.contains(environment) else { return } + environments.insert(environment) + } + collapsedDatabaseEnvironmentsByConnection[connectionId] = environments + persistCollapsedDatabaseEnvironments() + } + + func removeConnection(_ connectionId: UUID) { + foldersByConnection.removeValue(forKey: connectionId) + linkedNodesByConnection.removeValue(forKey: connectionId) + collapsedDatabaseEnvironmentsByConnection.removeValue(forKey: connectionId) + persistFolders() + persistLinkedNodes() + persistCollapsedDatabaseEnvironments() + } + private func load() { if let data = AppStorageEnvironment.shared.defaults.data(forKey: foldersKey), let decoded = try? JSONDecoder().decode([UUID: Set].self, from: data) { @@ -64,6 +100,13 @@ internal final class FavoritesExpansionState { let decoded = try? JSONDecoder().decode([UUID: Set].self, from: data) { linkedNodesByConnection = decoded } + if let data = AppStorageEnvironment.shared.defaults.data(forKey: collapsedDatabaseEnvironmentsKey), + let decoded = try? JSONDecoder().decode( + [UUID: Set].self, + from: data + ) { + collapsedDatabaseEnvironmentsByConnection = decoded + } } private func persistFolders() { @@ -77,4 +120,10 @@ internal final class FavoritesExpansionState { AppStorageEnvironment.shared.defaults.set(data, forKey: linkedKey) } } + + private func persistCollapsedDatabaseEnvironments() { + if let data = try? JSONEncoder().encode(collapsedDatabaseEnvironmentsByConnection) { + AppStorageEnvironment.shared.defaults.set(data, forKey: collapsedDatabaseEnvironmentsKey) + } + } } diff --git a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Commands.swift b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Commands.swift index f41eed3e7..aa88fb36a 100644 --- a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Commands.swift +++ b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Commands.swift @@ -67,6 +67,14 @@ extension DatabaseTreeOutlineCoordinator { sidebarState?.clearRecentTables(inDatabase: mainCoordinator?.browseDatabaseName) case .useAsActive(let container): useAsActive(container) + case .setFavoriteDatabase(let database, let environment): + favoriteDatabasesStorage.setFavorite( + database: database, + environment: environment, + connectionId: connectionId + ) + case .removeFavoriteDatabase(let database): + favoriteDatabasesStorage.removeFavorite(database: database, connectionId: connectionId) case .refreshContainers(let targets): refreshContainers(targets) case .copyContainerNames(let targets): diff --git a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Menu.swift b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Menu.swift index 794053821..93c3a36c9 100644 --- a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Menu.swift +++ b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator+Menu.swift @@ -33,6 +33,12 @@ extension DatabaseTreeOutlineCoordinator: NSMenuDelegate { private func menuContext() -> DatabaseTreeMenuContext { let clicked = clickedNode() let clickedRef = clicked.flatMap(DatabaseTreeSelection.tableRef) + let favoriteDatabaseEnvironment: FavoriteDatabaseEnvironment? + if case .database(let metadata) = clicked?.kind { + favoriteDatabaseEnvironment = self.favoriteDatabaseEnvironment(for: metadata.name) + } else { + favoriteDatabaseEnvironment = nil + } let settings = AppSettingsManager.shared.general return DatabaseTreeMenuContext( clicked: clicked?.kind, @@ -58,6 +64,7 @@ extension DatabaseTreeOutlineCoordinator: NSMenuDelegate { schemaEntityNamePlural: PluginManager.shared.schemaEntityNamePlural(for: databaseType), objectKindTitles: objectKindTitles(), isFavorite: clickedRef.map { isFavorite($0) } ?? false, + favoriteDatabaseEnvironment: favoriteDatabaseEnvironment, showObjectIcons: settings.showObjectIcons, showObjectComments: settings.showObjectComments, rowSize: settings.sidebarRowSize, diff --git a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator.swift b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator.swift index c58a527ad..4bd532fc8 100644 --- a/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator.swift +++ b/TablePro/Views/Sidebar/DatabaseTreeOutlineCoordinator.swift @@ -14,6 +14,7 @@ final class DatabaseTreeOutlineCoordinator: NSObject { internal let service = DatabaseTreeMetadataService.shared private static let cellIdentifier = NSUserInterfaceItemIdentifier("DatabaseTreeCell") private let favoriteTablesStorage: FavoriteTablesStorage + internal let favoriteDatabasesStorage: FavoriteDatabasesStorage internal var connectionId = UUID() internal var databaseType: DatabaseType = .mysql @@ -53,10 +54,30 @@ final class DatabaseTreeOutlineCoordinator: NSObject { internal let schemaService = SchemaService.shared private var favoriteTables: Set = [] - private var favoritesObserver: (any NSObjectProtocol)? + private var favoriteDatabases: Set = [] + private var tableFavoritesObserver: (any NSObjectProtocol)? + private var databaseFavoritesObserver: (any NSObjectProtocol)? + + override convenience init() { + self.init( + favoriteTablesStorage: .shared, + favoriteDatabasesStorage: .shared + ) + } + + convenience init(favoriteTablesStorage: FavoriteTablesStorage) { + self.init( + favoriteTablesStorage: favoriteTablesStorage, + favoriteDatabasesStorage: .shared + ) + } - init(favoriteTablesStorage: FavoriteTablesStorage = .shared) { + init( + favoriteTablesStorage: FavoriteTablesStorage, + favoriteDatabasesStorage: FavoriteDatabasesStorage + ) { self.favoriteTablesStorage = favoriteTablesStorage + self.favoriteDatabasesStorage = favoriteDatabasesStorage super.init() } @@ -72,7 +93,7 @@ final class DatabaseTreeOutlineCoordinator: NSObject { func attach(outlineView: NSOutlineView) { self.outlineView = outlineView - favoritesObserver = NotificationCenter.default.addObserver( + tableFavoritesObserver = NotificationCenter.default.addObserver( forName: .favoriteTablesDidChange, object: nil, queue: .main ) { [weak self] _ in MainActor.assumeIsolated { @@ -81,11 +102,23 @@ final class DatabaseTreeOutlineCoordinator: NSObject { self.refreshVisibleRows() } } + databaseFavoritesObserver = NotificationCenter.default.addObserver( + forName: .favoriteDatabasesDidChange, object: nil, queue: .main + ) { [weak self] _ in + MainActor.assumeIsolated { + guard let self else { return } + self.reloadFavorites() + self.refreshVisibleRows() + } + } } deinit { - if let favoritesObserver { - NotificationCenter.default.removeObserver(favoritesObserver) + if let tableFavoritesObserver { + NotificationCenter.default.removeObserver(tableFavoritesObserver) + } + if let databaseFavoritesObserver { + NotificationCenter.default.removeObserver(databaseFavoritesObserver) } } @@ -238,6 +271,7 @@ final class DatabaseTreeOutlineCoordinator: NSObject { private func reloadFavorites() { favoriteTables = favoriteTablesStorage.favorites(for: connectionId) + favoriteDatabases = favoriteDatabasesStorage.favorites(for: connectionId) } private func favoriteEntry(for ref: DatabaseTreeTableRef) -> FavoriteTablesStorage.FavoriteEntry { @@ -254,8 +288,17 @@ final class DatabaseTreeOutlineCoordinator: NSObject { } private func favoriteState(for node: DatabaseTreeNode) -> Bool { - guard let ref = DatabaseTreeSelection.tableRef(of: node) else { return false } - return isFavorite(ref) + switch node.kind { + case .database(let metadata): + return favoriteDatabaseEnvironment(for: metadata.name) != nil + default: + guard let ref = DatabaseTreeSelection.tableRef(of: node) else { return false } + return isFavorite(ref) + } + } + + internal func favoriteDatabaseEnvironment(for database: String) -> FavoriteDatabaseEnvironment? { + favoriteDatabases.first { $0.database == database }?.environment } internal func toggleFavorite(_ ref: DatabaseTreeTableRef) { diff --git a/TablePro/Views/Sidebar/DatabaseTreeRowView.swift b/TablePro/Views/Sidebar/DatabaseTreeRowView.swift index 19ab10793..37d19f3b1 100644 --- a/TablePro/Views/Sidebar/DatabaseTreeRowView.swift +++ b/TablePro/Views/Sidebar/DatabaseTreeRowView.swift @@ -58,12 +58,7 @@ struct DatabaseTreeRowView: View { case .recentTable(let ref): tableRow(ref) case .database(let metadata): - header( - text: metadata.name, - systemImage: metadata.isSystemDatabase ? "gearshape" : "cylinder", - isActive: metadata.name == context.activeDatabase, - isSystem: metadata.isSystemDatabase - ) + databaseRow(metadata) case .schema(let database, let schema): header( text: schema, @@ -112,6 +107,28 @@ struct DatabaseTreeRowView: View { .lineLimit(1) } + private func databaseRow(_ metadata: DatabaseMetadata) -> some View { + HStack(spacing: 6) { + header( + text: metadata.name, + systemImage: metadata.isSystemDatabase ? "gearshape" : "cylinder", + isActive: metadata.name == context.activeDatabase, + isSystem: metadata.isSystemDatabase + ) + Spacer(minLength: 4) + if isFavorite { + Image(systemName: "star.fill") + .foregroundStyle(.yellow) + .accessibilityHidden(true) + } + } + .accessibilityLabel( + isFavorite + ? String(format: String(localized: "%@, Favorite"), metadata.name) + : metadata.name + ) + } + private func tableRow(_ ref: DatabaseTreeTableRef) -> some View { TableRow( table: ref.table, diff --git a/TablePro/Views/Sidebar/FavoriteDatabaseFilterBar.swift b/TablePro/Views/Sidebar/FavoriteDatabaseFilterBar.swift new file mode 100644 index 000000000..0ab8d2157 --- /dev/null +++ b/TablePro/Views/Sidebar/FavoriteDatabaseFilterBar.swift @@ -0,0 +1,30 @@ +// +// FavoriteDatabaseFilterBar.swift +// TablePro +// + +import SwiftUI + +internal struct FavoriteDatabaseFilterBar: View { + @Binding internal var selection: FavoriteDatabaseEnvironmentFilter + + internal var body: some View { + HStack(spacing: 6) { + Label(String(localized: "Environment"), systemImage: "line.3.horizontal.decrease") + .foregroundStyle(.secondary) + Spacer(minLength: 4) + Picker(String(localized: "Environment"), selection: $selection) { + ForEach(FavoriteDatabaseEnvironmentFilter.allCases, id: \.self) { filter in + Text(filter.title) + .tag(filter) + } + } + .labelsHidden() + .pickerStyle(.menu) + .controlSize(.small) + } + .font(.caption) + .padding(.horizontal, 10) + .padding(.vertical, 5) + } +} diff --git a/TablePro/Views/Sidebar/FavoritesExpansion.swift b/TablePro/Views/Sidebar/FavoritesExpansion.swift index 088e1785a..5ab064b2f 100644 --- a/TablePro/Views/Sidebar/FavoritesExpansion.swift +++ b/TablePro/Views/Sidebar/FavoritesExpansion.swift @@ -30,4 +30,23 @@ internal enum FavoritesExpansion { break } } + + internal static func isDatabaseEnvironmentExpanded( + _ environment: FavoriteDatabaseEnvironment, + connectionId: UUID + ) -> Bool { + FavoritesExpansionState.shared.isDatabaseEnvironmentExpanded(environment, for: connectionId) + } + + internal static func setDatabaseEnvironmentExpanded( + _ environment: FavoriteDatabaseEnvironment, + expanded: Bool, + connectionId: UUID + ) { + FavoritesExpansionState.shared.setDatabaseEnvironmentExpanded( + environment, + expanded: expanded, + for: connectionId + ) + } } diff --git a/TablePro/Views/Sidebar/FavoritesOutlineCoordinator.swift b/TablePro/Views/Sidebar/FavoritesOutlineCoordinator.swift index 87d74fb1b..250756b9b 100644 --- a/TablePro/Views/Sidebar/FavoritesOutlineCoordinator.swift +++ b/TablePro/Views/Sidebar/FavoritesOutlineCoordinator.swift @@ -54,7 +54,11 @@ internal final class FavoritesOutlineCoordinator: NSObject, NSOutline /// outline reloads only when the set of rows or their nesting changed. Depth is part of the /// fingerprint because moving a favorite into a folder can leave the pre-order id list identical. private static func fingerprint(of input: FavoritesOutlineInput) -> String { - var parts: [String] = [input.activeDatabase ?? ""] + var parts: [String] = [input.activeDatabase ?? "", input.isFilteringDatabases ? "filtering" : ""] + parts += input.databaseGroups.flatMap { group in + ["environment|\(group.environment.rawValue)"] + + group.entries.map { "\(group.environment.rawValue)|\($0.id)" } + } parts += input.tables.map(\.id) parts += input.queryNodes.flatMap { Self.identifiers(of: $0, depth: 0) } parts += input.teamQueries.map(\.id) @@ -121,12 +125,33 @@ internal final class FavoritesOutlineCoordinator: NSObject, NSOutline private func build(children parent: FavoritesOutlineNode?) -> [FavoritesOutlineNode] { guard let parent else { return rootNodes() } - guard case .query(let favoriteNode) = parent.kind, let kids = favoriteNode.children else { return [] } - return kids.map { node(id: $0.id, kind: .query($0)) } + switch parent.kind { + case .databaseEnvironment(let group): + return group.entries.map { entry in + node(id: FavoritesOutlineNode.databaseId(entry), kind: .database(entry)) + } + case .query(let favoriteNode): + guard let kids = favoriteNode.children else { return [] } + return kids.map { node(id: $0.id, kind: .query($0)) } + case .header, .database, .table, .teamQuery: + return [] + } } private func rootNodes() -> [FavoritesOutlineNode] { var nodes: [FavoritesOutlineNode] = [] + if !owner.input.databaseGroups.isEmpty { + nodes.append(node( + id: FavoritesOutlineNode.databasesHeaderId, + kind: .header(owner.input.databaseEntityNamePlural) + )) + nodes += owner.input.databaseGroups.map { group in + node( + id: FavoritesOutlineNode.databaseEnvironmentId(group.environment), + kind: .databaseEnvironment(group) + ) + } + } if !owner.input.tables.isEmpty { nodes.append(node(id: FavoritesOutlineNode.tablesHeaderId, kind: .header(String(localized: "Tables")))) nodes += owner.input.tables.map { table in @@ -163,8 +188,20 @@ internal final class FavoritesOutlineCoordinator: NSObject, NSOutline private func applyExpansion(to nodes: [FavoritesOutlineNode], in outlineView: NSOutlineView) { for node in nodes where node.isExpandable { - guard case .query(let favoriteNode) = node.kind else { continue } - if FavoritesExpansion.isExpanded(favoriteNode, connectionId: owner.input.connectionId) { + let shouldExpand: Bool + switch node.kind { + case .databaseEnvironment(let group): + shouldExpand = owner.input.isFilteringDatabases || FavoritesExpansion + .isDatabaseEnvironmentExpanded(group.environment, connectionId: owner.input.connectionId) + case .query(let favoriteNode): + shouldExpand = FavoritesExpansion.isExpanded( + favoriteNode, + connectionId: owner.input.connectionId + ) + case .header, .database, .table, .teamQuery: + shouldExpand = false + } + if shouldExpand { outlineView.expandItem(node) applyExpansion(to: children(of: node), in: outlineView) } else { @@ -183,9 +220,24 @@ internal final class FavoritesOutlineCoordinator: NSObject, NSOutline private func recordExpansion(from notification: Notification, expanded: Bool) { guard !isApplyingExpansion, - let node = notification.userInfo?["NSObject"] as? FavoritesOutlineNode, - case .query(let favoriteNode) = node.kind else { return } - FavoritesExpansion.setExpanded(favoriteNode, expanded: expanded, connectionId: owner.input.connectionId) + let node = notification.userInfo?["NSObject"] as? FavoritesOutlineNode else { return } + switch node.kind { + case .databaseEnvironment(let group): + guard !owner.input.isFilteringDatabases else { return } + FavoritesExpansion.setDatabaseEnvironmentExpanded( + group.environment, + expanded: expanded, + connectionId: owner.input.connectionId + ) + case .query(let favoriteNode): + FavoritesExpansion.setExpanded( + favoriteNode, + expanded: expanded, + connectionId: owner.input.connectionId + ) + case .header, .database, .table, .teamQuery: + break + } } // MARK: - Selection @@ -270,7 +322,9 @@ internal final class FavoritesOutlineCoordinator: NSObject, NSOutline let context = FavoritesMenuContext( clicked: clicked?.kind, allFolders: owner.input.allFolders, - teamLibraryAvailable: owner.input.teamLibraryAvailable + teamLibraryAvailable: owner.input.teamLibraryAvailable, + databaseEntityName: owner.input.databaseEntityName, + activeDatabase: owner.input.activeDatabase ) SidebarMenuBuilder.fill( menu, diff --git a/TablePro/Views/Sidebar/FavoritesOutlineNode.swift b/TablePro/Views/Sidebar/FavoritesOutlineNode.swift index bad7df27c..08c39982a 100644 --- a/TablePro/Views/Sidebar/FavoritesOutlineNode.swift +++ b/TablePro/Views/Sidebar/FavoritesOutlineNode.swift @@ -13,6 +13,8 @@ import Foundation internal final class FavoritesOutlineNode: SidebarOutlineNode { internal enum Kind { case header(String) + case databaseEnvironment(FavoriteDatabaseGroup) + case database(FavoriteDatabaseEntry) case table(TableInfo) case query(FavoriteNode) case teamQuery(id: String, name: String, publishedBy: String?) @@ -27,8 +29,14 @@ internal final class FavoritesOutlineNode: SidebarOutlineNode { } internal var isExpandable: Bool { - guard case .query(let node) = kind else { return false } - return node.isFolder + switch kind { + case .databaseEnvironment: + return true + case .query(let node): + return node.isFolder + case .header, .database, .table, .teamQuery: + return false + } } /// Tables, Queries and Team Library are buckets rather than objects, so AppKit draws them as @@ -39,6 +47,7 @@ internal final class FavoritesOutlineNode: SidebarOutlineNode { } internal static let tablesHeaderId = "favorites\u{1}header\u{1}tables" + internal static let databasesHeaderId = "favorites\u{1}header\u{1}databases" internal static let queriesHeaderId = "favorites\u{1}header\u{1}queries" internal static let teamHeaderId = "favorites\u{1}header\u{1}team" @@ -48,5 +57,13 @@ internal final class FavoritesOutlineNode: SidebarOutlineNode { ["favtable", database ?? "", schema ?? "", name].joined(separator: "\u{1}") } + internal static func databaseEnvironmentId(_ environment: FavoriteDatabaseEnvironment) -> String { + "favdatabaseenv\u{1}\(environment.rawValue)" + } + + internal static func databaseId(_ entry: FavoriteDatabaseEntry) -> String { + "favdatabase\u{1}\(entry.id)" + } + internal static func teamQueryId(_ clientId: String) -> String { "favteam\u{1}\(clientId)" } } diff --git a/TablePro/Views/Sidebar/FavoritesOutlineSelection.swift b/TablePro/Views/Sidebar/FavoritesOutlineSelection.swift index aae0d10e4..722aa2154 100644 --- a/TablePro/Views/Sidebar/FavoritesOutlineSelection.swift +++ b/TablePro/Views/Sidebar/FavoritesOutlineSelection.swift @@ -21,6 +21,10 @@ internal enum FavoritesOutlineSelection { switch kind { case .header: return nil + case .databaseEnvironment(let group): + return .node(id: FavoritesOutlineNode.databaseEnvironmentId(group.environment)) + case .database(let entry): + return .node(id: FavoritesOutlineNode.databaseId(entry)) case .table(let table): return .table(database: database, schema: table.schema, name: table.name) case .query(let node): @@ -45,6 +49,10 @@ internal enum FavoritesOutlineSelection { switch kind { case .header: return nil + case .databaseEnvironment(let group): + return group.environment.title + case .database(let entry): + return entry.database case .table(let table): return table.name case .teamQuery(_, let name, _): diff --git a/TablePro/Views/Sidebar/FavoritesOutlineView.swift b/TablePro/Views/Sidebar/FavoritesOutlineView.swift index d9eabef15..c6a6eae4c 100644 --- a/TablePro/Views/Sidebar/FavoritesOutlineView.swift +++ b/TablePro/Views/Sidebar/FavoritesOutlineView.swift @@ -11,6 +11,10 @@ import SwiftUI internal struct FavoritesOutlineInput { internal let connectionId: UUID internal let activeDatabase: String? + internal let databaseGroups: [FavoriteDatabaseGroup] + internal let databaseEntityName: String + internal let databaseEntityNamePlural: String + internal let isFilteringDatabases: Bool internal let tables: [TableInfo] internal let queryNodes: [FavoriteNode] internal let teamQueries: [FavoritesOutlineTeamQuery] diff --git a/TablePro/Views/Sidebar/FavoritesTabView.swift b/TablePro/Views/Sidebar/FavoritesTabView.swift index 69402febc..f58d10b0a 100644 --- a/TablePro/Views/Sidebar/FavoritesTabView.swift +++ b/TablePro/Views/Sidebar/FavoritesTabView.swift @@ -6,6 +6,7 @@ internal struct FavoritesTabView: View { @State private var viewModel: FavoritesSidebarViewModel @State private var favoriteTables: [FavoriteTablesStorage.FavoriteEntry] = [] + @State private var favoriteDatabases: Set = [] @State private var folderToDelete: SQLFavoriteFolder? @State private var showDeleteFolderAlert = false @State private var linkedFileToTrash: LinkedSQLFavorite? @@ -14,6 +15,7 @@ internal struct FavoritesTabView: View { @State private var linkedFolderToRemove: LinkedSQLFolder? @State private var showRemoveLinkedFolderAlert = false let connectionId: UUID + let databaseType: DatabaseType @Bindable private var sharedSidebarState: SharedSidebarState let tables: [TableInfo] private var coordinator: MainContentCoordinator? @@ -24,6 +26,22 @@ internal struct FavoritesTabView: View { return name.isEmpty ? nil : name } + private var databaseGroups: [FavoriteDatabaseGroup] { + FavoriteDatabaseGrouping.groups( + entries: favoriteDatabases, + searchText: searchText, + filter: sharedSidebarState.favoriteDatabaseEnvironmentFilter + ) + } + + private var databaseEntityName: String { + PluginManager.shared.containerEntityName(for: databaseType) + } + + private var databaseEntityNamePlural: String { + PluginManager.shared.containerEntityNamePlural(for: databaseType) + } + private var availableFavoriteTables: [TableInfo] { let database = activeDatabase let tablesByKey = Dictionary( @@ -40,8 +58,15 @@ internal struct FavoritesTabView: View { "\(schema ?? "")\u{1}\(name)" } - init(connectionId: UUID, sharedSidebarState: SharedSidebarState, tables: [TableInfo], coordinator: MainContentCoordinator?) { + init( + connectionId: UUID, + databaseType: DatabaseType, + sharedSidebarState: SharedSidebarState, + tables: [TableInfo], + coordinator: MainContentCoordinator? + ) { self.connectionId = connectionId + self.databaseType = databaseType self.sharedSidebarState = sharedSidebarState self.tables = tables _viewModel = State(wrappedValue: FavoritesSidebarViewModel(connectionId: connectionId)) @@ -50,31 +75,50 @@ internal struct FavoritesTabView: View { var body: some View { VStack(spacing: 0) { + if !favoriteDatabases.isEmpty { + FavoriteDatabaseFilterBar(selection: $sharedSidebarState.favoriteDatabaseEnvironmentFilter) + Divider() + } Group { let items = viewModel.filteredNodes(searchText: searchText) + let groups = databaseGroups let filteredTables = searchText.isEmpty ? availableFavoriteTables : availableFavoriteTables.filter { $0.name.localizedCaseInsensitiveContains(searchText) } - if !viewModel.isInitialLoadComplete && viewModel.nodes.isEmpty && filteredTables.isEmpty { + if !viewModel.isInitialLoadComplete + && viewModel.nodes.isEmpty + && filteredTables.isEmpty + && favoriteDatabases.isEmpty { ProgressView() .frame(maxWidth: .infinity, maxHeight: .infinity) - } else if viewModel.nodes.isEmpty && filteredTables.isEmpty && teamLibraryQueries.isEmpty && searchText.isEmpty { + } else if viewModel.nodes.isEmpty + && filteredTables.isEmpty + && teamLibraryQueries.isEmpty + && favoriteDatabases.isEmpty + && searchText.isEmpty { emptyState - } else if items.isEmpty && filteredTables.isEmpty && teamLibraryQueries.isEmpty { + } else if items.isEmpty + && groups.isEmpty + && filteredTables.isEmpty + && teamLibraryQueries.isEmpty { noMatchState } else { - favoritesList(items, filteredTables: filteredTables) + favoritesList(items, databaseGroups: groups, filteredTables: filteredTables) } } } .onAppear { viewModel.startWatchingLinkedFolders() favoriteTables = viewModel.favoriteTables(for: connectionId) + favoriteDatabases = FavoriteDatabasesStorage.shared.favorites(for: connectionId) } .onReceive(NotificationCenter.default.publisher(for: .favoriteTablesDidChange)) { _ in favoriteTables = viewModel.favoriteTables(for: connectionId) } + .onReceive(NotificationCenter.default.publisher(for: .favoriteDatabasesDidChange)) { _ in + favoriteDatabases = FavoriteDatabasesStorage.shared.favorites(for: connectionId) + } .sheet(item: $viewModel.editDialogItem) { item in FavoriteEditDialog( connectionId: connectionId, @@ -220,12 +264,17 @@ internal struct FavoritesTabView: View { /// container changed. private func favoritesList( _ items: [FavoriteNode], + databaseGroups: [FavoriteDatabaseGroup], filteredTables: [TableInfo] ) -> some View { FavoritesOutlineView( input: FavoritesOutlineInput( connectionId: connectionId, activeDatabase: activeDatabase, + databaseGroups: databaseGroups, + databaseEntityName: databaseEntityName, + databaseEntityNamePlural: databaseEntityNamePlural, + isFilteringDatabases: !searchText.isEmpty, tables: filteredTables, queryNodes: items, teamQueries: teamLibraryQueries.map { @@ -278,6 +327,10 @@ internal struct FavoritesTabView: View { Text(title) .font(.caption.weight(.semibold)) .foregroundStyle(.secondary) + case .databaseEnvironment(let group): + databaseEnvironmentRow(group) + case .database(let entry): + favoriteDatabaseRow(entry) case .table(let table): favoriteTableRow(table: table) case .query(let favoriteNode): @@ -287,6 +340,32 @@ internal struct FavoritesTabView: View { } } + private func databaseEnvironmentRow(_ group: FavoriteDatabaseGroup) -> some View { + Label { + HStack(spacing: 6) { + Text(group.environment.title) + .lineLimit(1) + Text(group.entries.count, format: .number) + .font(.caption) + .foregroundStyle(.secondary) + } + } icon: { + Image(systemName: group.environment.iconName) + } + .sidebarRowIcon(visible: AppSettingsManager.shared.general.showObjectIcons) + } + + private func favoriteDatabaseRow(_ entry: FavoriteDatabaseEntry) -> some View { + Label(entry.database, systemImage: "cylinder") + .sidebarRowIcon(visible: AppSettingsManager.shared.general.showObjectIcons) + .lineLimit(1) + .accessibilityLabel(String( + format: String(localized: "Favorite %@, %@"), + databaseEntityName, + entry.database + )) + } + @ViewBuilder private func favoriteQueryRow(_ node: FavoriteNode) -> some View { switch node.content { @@ -359,6 +438,10 @@ internal struct FavoritesTabView: View { switch kind { case .header: break + case .databaseEnvironment: + break + case .database(let entry): + useDatabase(entry) case .table(let table): coordinator?.openTableTab(table, activateGridFocus: true) case .query(let node): @@ -379,8 +462,13 @@ internal struct FavoritesTabView: View { private func deleteNode(_ kind: FavoritesOutlineNode.Kind) { switch kind { - case .header, .teamQuery: + case .header, .databaseEnvironment, .teamQuery: break + case .database(let entry): + FavoriteDatabasesStorage.shared.removeFavorite( + database: entry.database, + connectionId: connectionId + ) case .table(let table): FavoriteTablesStorage.shared.removeFavorite( name: table.name, schema: table.schema, database: activeDatabase, connectionId: connectionId @@ -404,6 +492,19 @@ internal struct FavoritesTabView: View { /// state this view already owns, so the alert stays where the rest of the presentation is. private func perform(_ command: FavoritesMenuCommand) { switch command { + case .useDatabase(let entry): + useDatabase(entry) + case .setDatabaseEnvironment(let entry, let environment): + FavoriteDatabasesStorage.shared.setFavorite( + database: entry.database, + environment: environment, + connectionId: connectionId + ) + case .removeDatabaseFavorite(let entry): + FavoriteDatabasesStorage.shared.removeFavorite( + database: entry.database, + connectionId: connectionId + ) case .openTable(let table): coordinator?.openTableTab(table, activateGridFocus: true) case .showERDiagram: @@ -464,6 +565,11 @@ internal struct FavoritesTabView: View { } } + private func useDatabase(_ entry: FavoriteDatabaseEntry) { + guard entry.database != activeDatabase else { return } + Task { await coordinator?.switchDatabase(to: entry.database) } + } + // MARK: - Empty States /// An empty list has no row to right-click, so the commands the background menu carries have to diff --git a/TablePro/Views/Sidebar/Menu/DatabaseTreeMenuSpec.swift b/TablePro/Views/Sidebar/Menu/DatabaseTreeMenuSpec.swift index 373976c4d..67e13e478 100644 --- a/TablePro/Views/Sidebar/Menu/DatabaseTreeMenuSpec.swift +++ b/TablePro/Views/Sidebar/Menu/DatabaseTreeMenuSpec.swift @@ -28,6 +28,7 @@ internal struct DatabaseTreeMenuContext { internal let schemaEntityNamePlural: String internal let objectKindTitles: [SidebarObjectKind: String] internal let isFavorite: Bool + internal let favoriteDatabaseEnvironment: FavoriteDatabaseEnvironment? internal let showObjectIcons: Bool internal let showObjectComments: Bool internal let rowSize: SidebarRowSizePreference @@ -216,7 +217,16 @@ internal enum DatabaseTreeMenuSpec { items.append(.command(String(localized: "Refresh"), .refreshContainers(targets))) items.append(.command(copyNamesTitle(count: targets.count), .copyContainerNames(targets))) + if targets.count == 1, clicked.kind == .database { + items.append(.separator) + items += favoriteDatabaseItems( + database: clicked.database, + currentEnvironment: context.favoriteDatabaseEnvironment + ) + } + if ExportPreselection.canPreselect(containers: targets, activeDatabase: context.activeDatabase) { + items.append(.separator) items.append(.command(String(localized: "Export…"), .exportContainers(targets))) } guard !droppable.isEmpty else { return items } @@ -225,6 +235,26 @@ internal enum DatabaseTreeMenuSpec { return items } + private static func favoriteDatabaseItems( + database: String, + currentEnvironment: FavoriteDatabaseEnvironment? + ) -> [DatabaseTreeMenuItem] { + let environmentItems: [DatabaseTreeMenuItem] = FavoriteDatabaseEnvironment.allCases.map { environment in + .command(SidebarMenuEntry( + title: environment.menuTitle, + command: .setFavoriteDatabase(database: database, environment: environment), + isOn: currentEnvironment == environment + )) + } + guard currentEnvironment != nil else { + return [.submenu(title: String(localized: "Add to Favorites"), items: environmentItems)] + } + return [ + .submenu(title: String(localized: "Environment"), items: environmentItems), + .destructive(String(localized: "Remove from Favorites"), .removeFavoriteDatabase(database)) + ] + } + private static func isActive(_ container: DatabaseContainerRef, context: DatabaseTreeMenuContext) -> Bool { switch container.kind { case .database: diff --git a/TablePro/Views/Sidebar/Menu/FavoritesMenuCommand.swift b/TablePro/Views/Sidebar/Menu/FavoritesMenuCommand.swift index 6ee58aa98..1822cce2a 100644 --- a/TablePro/Views/Sidebar/Menu/FavoritesMenuCommand.swift +++ b/TablePro/Views/Sidebar/Menu/FavoritesMenuCommand.swift @@ -11,6 +11,10 @@ import TableProPluginKit /// Several of these end in a confirmation the view owns, so the command names the intent and the /// view decides how to ask. Keeping that split is what lets the whole menu be a pure function. internal enum FavoritesMenuCommand: Equatable { + case useDatabase(FavoriteDatabaseEntry) + case setDatabaseEnvironment(FavoriteDatabaseEntry, FavoriteDatabaseEnvironment) + case removeDatabaseFavorite(FavoriteDatabaseEntry) + case openTable(TableInfo) case showERDiagram case removeTableFavorite(TableInfo) diff --git a/TablePro/Views/Sidebar/Menu/FavoritesMenuSpec.swift b/TablePro/Views/Sidebar/Menu/FavoritesMenuSpec.swift index 9b0e70627..3234d31d3 100644 --- a/TablePro/Views/Sidebar/Menu/FavoritesMenuSpec.swift +++ b/TablePro/Views/Sidebar/Menu/FavoritesMenuSpec.swift @@ -10,15 +10,21 @@ internal struct FavoritesMenuContext { internal let clicked: FavoritesOutlineNode.Kind? internal let allFolders: [SQLFavoriteFolder] internal let teamLibraryAvailable: Bool + internal let databaseEntityName: String + internal let activeDatabase: String? internal init( clicked: FavoritesOutlineNode.Kind?, allFolders: [SQLFavoriteFolder] = [], - teamLibraryAvailable: Bool = false + teamLibraryAvailable: Bool = false, + databaseEntityName: String = "Database", + activeDatabase: String? = nil ) { self.clicked = clicked self.allFolders = allFolders self.teamLibraryAvailable = teamLibraryAvailable + self.databaseEntityName = databaseEntityName + self.activeDatabase = activeDatabase } } @@ -30,6 +36,10 @@ internal enum FavoritesMenuSpec { private static func rawItems(for context: FavoritesMenuContext) -> [FavoritesMenuItem] { guard let clicked = context.clicked else { return backgroundItems(context) } switch clicked { + case .databaseEnvironment: + return backgroundItems(context) + case .database(let entry): + return databaseItems(entry, context: context) case .table(let table): return tableItems(table) case .query(let node): @@ -39,6 +49,38 @@ internal enum FavoritesMenuSpec { } } + private static func databaseItems( + _ entry: FavoriteDatabaseEntry, + context: FavoritesMenuContext + ) -> [FavoritesMenuItem] { + var items: [FavoritesMenuItem] = [] + if entry.database != context.activeDatabase { + items.append(.command( + String( + format: String(localized: "Use as Active %@"), + context.databaseEntityName + ), + .useDatabase(entry) + )) + } + items.append(.submenu( + title: String(localized: "Environment"), + items: FavoriteDatabaseEnvironment.allCases.map { environment in + .command(SidebarMenuEntry( + title: environment.menuTitle, + command: .setDatabaseEnvironment(entry, environment), + isOn: entry.environment == environment + )) + } + )) + items.append(.separator) + items.append(.destructive( + String(localized: "Remove from Favorites"), + .removeDatabaseFavorite(entry) + )) + return items + } + private static func tableItems(_ table: TableInfo) -> [FavoritesMenuItem] { [ .command(String(localized: "Open Table"), .openTable(table)), diff --git a/TablePro/Views/Sidebar/Menu/SidebarMenuCommand.swift b/TablePro/Views/Sidebar/Menu/SidebarMenuCommand.swift index 3ab656d04..d5eddd3d1 100644 --- a/TablePro/Views/Sidebar/Menu/SidebarMenuCommand.swift +++ b/TablePro/Views/Sidebar/Menu/SidebarMenuCommand.swift @@ -35,6 +35,8 @@ internal enum SidebarMenuCommand: Equatable { case removeRecent(DatabaseTreeTableRef) case clearRecents case useAsActive(DatabaseContainerRef) + case setFavoriteDatabase(database: String, environment: FavoriteDatabaseEnvironment) + case removeFavoriteDatabase(String) case refreshContainers([DatabaseContainerRef]) case copyContainerNames([DatabaseContainerRef]) case exportContainers([DatabaseContainerRef]) diff --git a/TablePro/Views/Sidebar/SidebarPersistenceKey.swift b/TablePro/Views/Sidebar/SidebarPersistenceKey.swift index feec084d6..5ea0ed005 100644 --- a/TablePro/Views/Sidebar/SidebarPersistenceKey.swift +++ b/TablePro/Views/Sidebar/SidebarPersistenceKey.swift @@ -24,6 +24,10 @@ enum SidebarPersistenceKey { "sidebar.selectedFavoriteNodeId.\(connectionId.uuidString)" } + static func favoriteDatabaseEnvironmentFilter(connectionId: UUID) -> String { + "sidebar.favoriteDatabaseEnvironmentFilter.\(connectionId.uuidString)" + } + static let defaultLayout = "sidebar.defaultLayout" static func layout(connectionId: UUID) -> String { diff --git a/TablePro/Views/Sidebar/SidebarView.swift b/TablePro/Views/Sidebar/SidebarView.swift index ba7ebb154..d14b3f247 100644 --- a/TablePro/Views/Sidebar/SidebarView.swift +++ b/TablePro/Views/Sidebar/SidebarView.swift @@ -95,6 +95,7 @@ struct SidebarView: View { if let coordinator { FavoritesTabView( connectionId: connectionId, + databaseType: viewModel.databaseType, sharedSidebarState: sidebarState, tables: tables, coordinator: coordinator diff --git a/TableProTests/Core/Storage/FavoriteDatabasesStorageTests.swift b/TableProTests/Core/Storage/FavoriteDatabasesStorageTests.swift new file mode 100644 index 000000000..fa4dcfd1f --- /dev/null +++ b/TableProTests/Core/Storage/FavoriteDatabasesStorageTests.swift @@ -0,0 +1,116 @@ +// +// FavoriteDatabasesStorageTests.swift +// TableProTests +// + +import Foundation +import Testing + +@testable import TablePro + +@MainActor +@Suite("FavoriteDatabasesStorage") +struct FavoriteDatabasesStorageTests { + private func makeStorage() throws -> (FavoriteDatabasesStorage, UserDefaults) { + let suite = "FavoriteDatabasesStorageTests.\(UUID().uuidString)" + let defaults = try #require(UserDefaults(suiteName: suite)) + defaults.removePersistentDomain(forName: suite) + return (FavoriteDatabasesStorage(defaults: defaults), defaults) + } + + @Test("Favorite identity includes the connection") + func favoritesAreConnectionScoped() throws { + let (storage, _) = try makeStorage() + let first = UUID() + let second = UUID() + + storage.setFavorite(database: "app", environment: .development, connectionId: first) + storage.setFavorite(database: "app", environment: .production, connectionId: second) + + #expect(storage.favorites(for: first).first?.environment == .development) + #expect(storage.favorites(for: second).first?.environment == .production) + } + + @Test("Changing an environment replaces the favorite instead of duplicating it") + func environmentUpdateReplacesEntry() throws { + let (storage, _) = try makeStorage() + let connectionId = UUID() + + storage.setFavorite(database: "orders", environment: .development, connectionId: connectionId) + storage.setFavorite(database: "orders", environment: .testing, connectionId: connectionId) + + let entries = storage.favorites(for: connectionId) + #expect(entries.count == 1) + #expect(entries.first?.environment == .testing) + } + + @Test("Removing one database preserves the connection's other favorites") + func removePreservesOtherEntries() throws { + let (storage, _) = try makeStorage() + let connectionId = UUID() + storage.setFavorite(database: "app", environment: .development, connectionId: connectionId) + storage.setFavorite(database: "audit", environment: .testing, connectionId: connectionId) + + storage.removeFavorite(database: "app", connectionId: connectionId) + + #expect(storage.favorites(for: connectionId).map(\.database) == ["audit"]) + } + + @Test("An unknown stored environment falls back to Unassigned") + func unknownEnvironmentFallsBack() throws { + let (storage, defaults) = try makeStorage() + let connectionId = UUID() + let json = """ + [{"connectionId":"\(connectionId.uuidString)","database":"future","environment":"staging"}] + """ + defaults.set( + Data(json.utf8), + forKey: "com.TablePro.favoriteDatabases.\(connectionId.uuidString)" + ) + + #expect( + storage.favorites(for: connectionId).first?.environment + == FavoriteDatabaseEnvironment.none + ) + } + + @Test("Malformed storage is contained to the affected connection") + func malformedStorageReturnsEmpty() throws { + let (storage, defaults) = try makeStorage() + let connectionId = UUID() + defaults.set( + Data("not-json".utf8), + forKey: "com.TablePro.favoriteDatabases.\(connectionId.uuidString)" + ) + + #expect(storage.favorites(for: connectionId).isEmpty) + } + + @Test("Stored entries cannot cross connection boundaries") + func ignoresEntriesFromAnotherConnection() throws { + let (storage, defaults) = try makeStorage() + let requestedConnectionId = UUID() + let foreignConnectionId = UUID() + let json = """ + [{"connectionId":"\(foreignConnectionId.uuidString)","database":"private","environment":"production"}] + """ + defaults.set( + Data(json.utf8), + forKey: "com.TablePro.favoriteDatabases.\(requestedConnectionId.uuidString)" + ) + + #expect(storage.favorites(for: requestedConnectionId).isEmpty) + } + + @Test("Deleting a connection removes its persisted favorites") + func removeConnectionFavorites() throws { + let (storage, defaults) = try makeStorage() + let connectionId = UUID() + storage.setFavorite(database: "app", environment: .production, connectionId: connectionId) + + storage.removeFavorites(for: connectionId) + + #expect(storage.favorites(for: connectionId).isEmpty) + #expect(defaults.object(forKey: "com.TablePro.favoriteDatabases.\(connectionId.uuidString)") == nil) + } +} diff --git a/TableProTests/Models/FavoriteDatabaseGroupingTests.swift b/TableProTests/Models/FavoriteDatabaseGroupingTests.swift new file mode 100644 index 000000000..99a9a58be --- /dev/null +++ b/TableProTests/Models/FavoriteDatabaseGroupingTests.swift @@ -0,0 +1,97 @@ +// +// FavoriteDatabaseGroupingTests.swift +// TableProTests +// + +import Foundation +import Testing + +@testable import TablePro + +@Suite("Favorite database grouping") +struct FavoriteDatabaseGroupingTests { + private let connectionId = UUID() + + private func entry(_ database: String, _ environment: FavoriteDatabaseEnvironment) -> FavoriteDatabaseEntry { + FavoriteDatabaseEntry( + connectionId: connectionId, + database: database, + environment: environment + ) + } + + @Test("Groups use environment order and database names sort naturally") + func deterministicGrouping() { + let groups = FavoriteDatabaseGrouping.groups( + entries: [ + entry("prod", .production), + entry("dev10", .development), + entry("dev2", .development), + entry("misc", .none), + entry("test", .testing) + ], + searchText: "", + filter: .all + ) + + #expect(groups.map(\.environment) == [.development, .testing, .production, .none]) + #expect(groups.first?.entries.map(\.database) == ["dev2", "dev10"]) + } + + @Test("Environment filter keeps only its group") + func filtersByEnvironment() { + let entries: Set = [ + entry("dev", .development), + entry("misc", .none), + entry("prod", .production) + ] + let groups = FavoriteDatabaseGrouping.groups( + entries: entries, + searchText: "", + filter: .production + ) + let unassigned = FavoriteDatabaseGrouping.groups( + entries: entries, + searchText: "", + filter: .unassigned + ) + + #expect(groups.count == 1) + #expect(groups.first?.entries.map(\.database) == ["prod"]) + #expect(unassigned.count == 1) + #expect(unassigned.first?.entries.map(\.database) == ["misc"]) + } + + @Test("Search matches a database or its environment title") + func searchMatchesNamesAndEnvironment() { + let entries: Set = [ + entry("billing", .development), + entry("warehouse", .production) + ] + + let nameMatch = FavoriteDatabaseGrouping.groups( + entries: entries, + searchText: "bill", + filter: .all + ) + let environmentMatch = FavoriteDatabaseGrouping.groups( + entries: entries, + searchText: "Production", + filter: .all + ) + + #expect(nameMatch.flatMap(\.entries).map(\.database) == ["billing"]) + #expect(environmentMatch.flatMap(\.entries).map(\.database) == ["warehouse"]) + } + + @Test("No matches produce no empty groups") + func hidesEmptyGroups() { + let groups = FavoriteDatabaseGrouping.groups( + entries: [entry("app", .development)], + searchText: "missing", + filter: .all + ) + + #expect(groups.isEmpty) + } +} diff --git a/TableProTests/Models/SharedSidebarStateTests.swift b/TableProTests/Models/SharedSidebarStateTests.swift index 87439e364..8f75b4343 100644 --- a/TableProTests/Models/SharedSidebarStateTests.swift +++ b/TableProTests/Models/SharedSidebarStateTests.swift @@ -8,13 +8,12 @@ // import Foundation +@testable import TablePro import TableProPluginKit import Testing -@testable import TablePro @Suite("SharedSidebarState") struct SharedSidebarStateTests { - // MARK: - Registry @Test("forConnection returns same instance for same UUID") @@ -93,6 +92,21 @@ struct SharedSidebarStateTests { SharedSidebarState.removeConnection(id) } + @Test("favorite database environment filter persists for its connection") + @MainActor + func favoriteDatabaseEnvironmentFilterPersists() { + let id = UUID() + let first = SharedSidebarState.forConnection(id) + first.favoriteDatabaseEnvironmentFilter = .testing + SharedSidebarState.removeConnection(id) + + let restored = SharedSidebarState.forConnection(id) + #expect(restored.favoriteDatabaseEnvironmentFilter == .testing) + + restored.favoriteDatabaseEnvironmentFilter = .all + SharedSidebarState.removeConnection(id) + } + @Test("filter text is independent across different connections") @MainActor func filterTextIndependentAcrossConnections() { diff --git a/TableProTests/Views/Sidebar/DatabaseTreeMenuSpecTests.swift b/TableProTests/Views/Sidebar/DatabaseTreeMenuSpecTests.swift index 76414f764..614e17f82 100644 --- a/TableProTests/Views/Sidebar/DatabaseTreeMenuSpecTests.swift +++ b/TableProTests/Views/Sidebar/DatabaseTreeMenuSpecTests.swift @@ -25,6 +25,7 @@ struct DatabaseTreeMenuSpecTests { selectedContainers: [DatabaseContainerRef] = [], isReadOnly: Bool = false, isFavorite: Bool = false, + favoriteDatabaseEnvironment: FavoriteDatabaseEnvironment? = nil, activeDatabase: String? = "app", activeSchema: String? = "public", canFilterDatabases: Bool = false, @@ -54,6 +55,7 @@ struct DatabaseTreeMenuSpecTests { schemaEntityNamePlural: "Schemas", objectKindTitles: [.table: "Tables"], isFavorite: isFavorite, + favoriteDatabaseEnvironment: favoriteDatabaseEnvironment, showObjectIcons: true, showObjectComments: false, rowSize: .matchSystem, @@ -264,6 +266,33 @@ struct DatabaseTreeMenuSpecTests { }) } + @Test("An unfavorited database offers every environment under Add to Favorites") + func databaseCanBeFavoritedWithEnvironment() { + let database = DatabaseMetadata.minimal(name: "analytics", isSystem: false) + let items = DatabaseTreeMenuSpec.items(for: context(clicked: .database(database))) + let issued = commands(items) + + #expect(titles(items).contains(String(localized: "Add to Favorites"))) + for environment in FavoriteDatabaseEnvironment.allCases { + #expect(issued.contains(.setFavoriteDatabase(database: "analytics", environment: environment))) + } + #expect(!issued.contains(.removeFavoriteDatabase("analytics"))) + } + + @Test("A favorite database can change environment or be removed") + func favoriteDatabaseMenuReflectsState() { + let database = DatabaseMetadata.minimal(name: "analytics", isSystem: false) + let items = DatabaseTreeMenuSpec.items(for: context( + clicked: .database(database), + favoriteDatabaseEnvironment: .production + )) + let issued = commands(items) + + #expect(titles(items).contains(String(localized: "Environment"))) + #expect(issued.contains(.removeFavoriteDatabase("analytics"))) + #expect(issued.contains(.setFavoriteDatabase(database: "analytics", environment: .development))) + } + // MARK: - Shape @Test("A menu never opens or closes on a separator, and never doubles one") diff --git a/TableProTests/Views/Sidebar/FavoritesMenuSpecTests.swift b/TableProTests/Views/Sidebar/FavoritesMenuSpecTests.swift index f1475a733..8fc17d2ce 100644 --- a/TableProTests/Views/Sidebar/FavoritesMenuSpecTests.swift +++ b/TableProTests/Views/Sidebar/FavoritesMenuSpecTests.swift @@ -41,6 +41,10 @@ struct FavoritesMenuSpecTests { TableInfo(name: "orders", type: .table, rowCount: nil, schema: "public") } + private func database() -> FavoriteDatabaseEntry { + FavoriteDatabaseEntry(connectionId: UUID(), database: "analytics", environment: .development) + } + private func moveTargets(_ issued: [FavoritesMenuCommand]) -> [UUID?] { issued.compactMap { command in guard case .moveFavorite(_, let target) = command else { return nil } @@ -57,6 +61,8 @@ struct FavoritesMenuSpecTests { let kinds: [FavoritesOutlineNode.Kind?] = [ nil, .header("Queries"), + .databaseEnvironment(FavoriteDatabaseGroup(environment: .development, entries: [database()])), + .database(database()), .table(table()), .teamQuery(id: "1", name: "Shared", publishedBy: "Sam"), .query(.favorite(favorite())), @@ -76,6 +82,7 @@ struct FavoritesMenuSpecTests { func separatorsAreCollapsed() { let kinds: [FavoritesOutlineNode.Kind?] = [ nil, + .database(database()), .table(table()), .query(.favorite(favorite())), .query(.folder(SQLFavoriteFolder(name: "Reports"), children: [])) @@ -111,6 +118,32 @@ struct FavoritesMenuSpecTests { #expect(!without.contains(.publishSavedQueriesToTeam)) } + @Test("A database favorite can switch, change environment, or be removed") + func databaseFavoriteCommands() { + let entry = database() + let issued = commands(FavoritesMenuSpec.items(for: FavoritesMenuContext( + clicked: .database(entry), + databaseEntityName: "Database", + activeDatabase: "other" + ))) + + #expect(issued.contains(.useDatabase(entry))) + #expect(issued.contains(.setDatabaseEnvironment(entry, .production))) + #expect(issued.contains(.removeDatabaseFavorite(entry))) + } + + @Test("The active database omits a redundant switch command") + func activeDatabaseOmitsSwitch() { + let entry = database() + let issued = commands(FavoritesMenuSpec.items(for: FavoritesMenuContext( + clicked: .database(entry), + databaseEntityName: "Database", + activeDatabase: entry.database + ))) + + #expect(!issued.contains(.useDatabase(entry))) + } + @Test("Move to lists every folder except the one the favourite is already in") func moveToSkipsTheCurrentFolder() { let home = SQLFavoriteFolder(name: "Home") diff --git a/TableProTests/Views/Sidebar/FavoritesOutlineSelectionTests.swift b/TableProTests/Views/Sidebar/FavoritesOutlineSelectionTests.swift index 4082d5f03..11ef0adf5 100644 --- a/TableProTests/Views/Sidebar/FavoritesOutlineSelectionTests.swift +++ b/TableProTests/Views/Sidebar/FavoritesOutlineSelectionTests.swift @@ -20,9 +20,18 @@ struct FavoritesOutlineSelectionTests { SQLFavorite(name: name, query: "SELECT 1") } + private func database(_ name: String) -> FavoriteDatabaseEntry { + FavoriteDatabaseEntry(connectionId: UUID(), database: name, environment: .development) + } + @Test("Section titles refuse selection, objects accept it") func headersRefuseSelection() { #expect(FavoritesOutlineSelection.isSelectable(.header("Tables")) == false) + #expect(FavoritesOutlineSelection.isSelectable(.database(database("app")))) + #expect(FavoritesOutlineSelection.isSelectable(.databaseEnvironment(FavoriteDatabaseGroup( + environment: .development, + entries: [database("app")] + )))) #expect(FavoritesOutlineSelection.isSelectable(.table(table("users")))) #expect(FavoritesOutlineSelection.isSelectable(.query(.favorite(favorite("daily"))))) #expect(FavoritesOutlineSelection.isSelectable(.teamQuery(id: "t1", name: "Shared", publishedBy: nil))) @@ -40,6 +49,37 @@ struct FavoritesOutlineSelectionTests { #expect(FavoritesOutlineSelection.selection(for: .query(node), database: nil) == .node(id: node.id)) } + @Test("A database row maps to its stable node id") + func databaseMapsToNodeId() { + let entry = database("analytics") + let selection = FavoritesOutlineSelection.selection(for: .database(entry), database: nil) + + #expect(selection == .node(id: FavoritesOutlineNode.databaseId(entry))) + } + + @Test("Database environment expansion is independent per connection") + @MainActor + func databaseEnvironmentExpansionIsConnectionScoped() { + let firstConnection = UUID() + let secondConnection = UUID() + defer { + FavoritesExpansionState.shared.removeConnection(firstConnection) + FavoritesExpansionState.shared.removeConnection(secondConnection) + } + + #expect(FavoritesExpansion.isDatabaseEnvironmentExpanded(.testing, connectionId: firstConnection)) + #expect(FavoritesExpansion.isDatabaseEnvironmentExpanded(.testing, connectionId: secondConnection)) + + FavoritesExpansion.setDatabaseEnvironmentExpanded( + .testing, + expanded: false, + connectionId: firstConnection + ) + + #expect(!FavoritesExpansion.isDatabaseEnvironmentExpanded(.testing, connectionId: firstConnection)) + #expect(FavoritesExpansion.isDatabaseEnvironmentExpanded(.testing, connectionId: secondConnection)) + } + /// Team Library rows carried no tag at all before, so the keyboard could never reach them. @Test("A Team Library row maps to a selection of its own") func teamQueryMapsToSelection() { @@ -66,6 +106,7 @@ struct FavoritesOutlineSelectionTests { @Test("Type-select uses the name a user would type, never a section title") func typeSelectSkipsHeaders() { #expect(FavoritesOutlineSelection.matchString(for: .header("Tables")) == nil) + #expect(FavoritesOutlineSelection.matchString(for: .database(database("analytics"))) == "analytics") #expect(FavoritesOutlineSelection.matchString(for: .table(table("orders"))) == "orders") #expect(FavoritesOutlineSelection.matchString(for: .query(.favorite(favorite("daily")))) == "daily") #expect( @@ -83,8 +124,16 @@ struct FavoritesOutlineSelectionTests { kind: .query(.folder(SQLFavoriteFolder(name: "Reports"), children: [])) ) let header = FavoritesOutlineNode(id: "c", kind: .header("Queries")) + let databaseGroup = FavoritesOutlineNode( + id: "d", + kind: .databaseEnvironment(FavoriteDatabaseGroup( + environment: .development, + entries: [database("app")] + )) + ) #expect(leaf.isExpandable == false) #expect(branch.isExpandable) #expect(header.isExpandable == false) + #expect(databaseGroup.isExpandable) } } diff --git a/TableProTests/Views/Sidebar/SidebarOutlineScaffoldTests.swift b/TableProTests/Views/Sidebar/SidebarOutlineScaffoldTests.swift index 20dae2597..69c504ab2 100644 --- a/TableProTests/Views/Sidebar/SidebarOutlineScaffoldTests.swift +++ b/TableProTests/Views/Sidebar/SidebarOutlineScaffoldTests.swift @@ -664,6 +664,87 @@ struct DatabaseTreeFavoriteRefreshTests { #expect(zip(favoritePixels, removedPixels).allSatisfy(!=)) } + @Test("Adding and removing a database favorite repaints its star in place") + func databaseFavoriteMutationRepaintsVisibleRow() throws { + let tableSuite = "DatabaseTreeFavoriteRefreshTests.tables.\(UUID().uuidString)" + let databaseSuite = "DatabaseTreeFavoriteRefreshTests.databases.\(UUID().uuidString)" + let syncSuite = "DatabaseTreeFavoriteRefreshTests.database-sync.\(UUID().uuidString)" + let tableDefaults = try #require(UserDefaults(suiteName: tableSuite)) + let databaseDefaults = try #require(UserDefaults(suiteName: databaseSuite)) + let syncDefaults = try #require(UserDefaults(suiteName: syncSuite)) + defer { + tableDefaults.removePersistentDomain(forName: tableSuite) + databaseDefaults.removePersistentDomain(forName: databaseSuite) + syncDefaults.removePersistentDomain(forName: syncSuite) + } + + let metadata = SyncMetadataStorage(userDefaults: syncDefaults) + let tracker = SyncChangeTracker(metadataStorage: metadata) + let tableStorage = FavoriteTablesStorage(userDefaults: tableDefaults, syncTracker: tracker) + let databaseStorage = FavoriteDatabasesStorage(defaults: databaseDefaults) + let coordinator = DatabaseTreeOutlineCoordinator( + favoriteTablesStorage: tableStorage, + favoriteDatabasesStorage: databaseStorage + ) + let connectionId = UUID() + let database = DatabaseTreeNode( + id: "database-shop", + kind: .database(.minimal(name: "shop")) + ) + let outlineView = NSOutlineView() + let scrollView = SidebarOutlineScaffold.makeScrollView( + outlineView: outlineView, + configuration: SidebarOutlineScaffold.Configuration( + columnIdentifier: "DatabaseFavoriteRefreshColumn", + allowsMultipleSelection: true, + rowSizePreference: .medium + ) + ) + let window = NSWindow( + contentRect: NSRect(x: 0, y: 0, width: Self.width, height: Self.height), + styleMask: [.titled], + backing: .buffered, + defer: false + ) + window.appearance = NSAppearance(named: .aqua) + window.contentView = scrollView + + coordinator.connectionId = connectionId + coordinator.databaseType = .postgresql + coordinator.childrenCache[""] = [database] + outlineView.dataSource = coordinator + outlineView.delegate = coordinator + coordinator.attach(outlineView: outlineView) + outlineView.reloadData() + settle(window) + + let cell = try #require( + outlineView.view(atColumn: 0, row: 0, makeIfNecessary: true) as? DatabaseTreeCellView + ) + settle(window) + let host = cell.hostedView + let unfavoritePixels = try trailingPixels(of: cell) + + databaseStorage.setFavorite( + database: "shop", + environment: .production, + connectionId: connectionId + ) + settle(window) + + #expect(coordinator.favoriteDatabaseEnvironment(for: "shop") == .production) + #expect(cell.hostedView === host) + let favoritePixels = try trailingPixels(of: cell) + #expect(unfavoritePixels != favoritePixels) + + databaseStorage.removeFavorite(database: "shop", connectionId: connectionId) + settle(window) + + #expect(coordinator.favoriteDatabaseEnvironment(for: "shop") == nil) + #expect(cell.hostedView === host) + #expect(try trailingPixels(of: cell) != favoritePixels) + } + private func settle(_ window: NSWindow) { window.layoutIfNeeded() RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.05)) diff --git a/docs/features/favorites.mdx b/docs/features/favorites.mdx index 06cea838f..5470c3b2c 100644 --- a/docs/features/favorites.mdx +++ b/docs/features/favorites.mdx @@ -1,9 +1,17 @@ --- title: Favorites -description: Mark tables as favorites and save frequently used queries with optional keyword shortcuts +description: Save databases and tables, and keep frequently used queries with optional keyword shortcuts --- -The Favorites tab in the sidebar has two sections: **Tables** for pinned tables and **Queries** for saved SQL. The sidebar can also show a **Recent** section with the last tables you opened (off by default). +The Favorites tab keeps pinned databases and tables beside saved SQL. The sidebar can also show a **Recent** section with the last tables you opened (off by default). + +## Database Favorites + +In Tree layout, right-click a database and choose **Add to Favorites**, then assign it to Development, Testing, Production, or Unassigned. A filled star marks the database in the tree. + +Favorite databases appear first in the Favorites tab, grouped by environment. Use the Environment menu to show one group, and use the sidebar search field to filter by database or environment name. Double-click a database, or select it and press Return, to make it active. Right-click it to change its environment or remove it. + +Database favorites are stored locally for each connection. Database names that no longer exist stay in Favorites so you can remove them; trying to activate one shows the database driver's normal switch error. ## Table Favorites From 0fdb62914dcfc2dc21ebfdf507b557a1cd3cbfa0 Mon Sep 17 00:00:00 2001 From: Nguyen Van Thang <61111580+sophiathedev@users.noreply.github.com> Date: Tue, 18 Aug 2026 16:02:08 +0700 Subject: [PATCH 2/3] docs(favorites): add feature preview --- docs/images/favorite-databases.png | Bin 0 -> 195255 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 docs/images/favorite-databases.png diff --git a/docs/images/favorite-databases.png b/docs/images/favorite-databases.png new file mode 100644 index 0000000000000000000000000000000000000000..f2b9737c13cb09857d6d764d77a29e52b2d5d308 GIT binary patch literal 195255 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

X7{uSZsa6i9Z&Y1uF{2XR+`4THR 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ⅅqIeS_ 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 P;NQMoN;~7W>z@99=>?uF literal 0 HcmV?d00001 From e51e82a170b5cba9cc8f672e7d594899d9ee77aa Mon Sep 17 00:00:00 2001 From: sophiathedev Date: Tue, 18 Aug 2026 16:04:08 +0700 Subject: [PATCH 3/3] docs(favorites): show database groups --- docs/features/favorites.mdx | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/features/favorites.mdx b/docs/features/favorites.mdx index 5470c3b2c..1afb16dbd 100644 --- a/docs/features/favorites.mdx +++ b/docs/features/favorites.mdx @@ -11,6 +11,10 @@ In Tree layout, right-click a database and choose **Add to Favorites**, then ass Favorite databases appear first in the Favorites tab, grouped by environment. Use the Environment menu to show one group, and use the sidebar search field to filter by database or environment name. Double-click a database, or select it and press Return, to make it active. Right-click it to change its environment or remove it. + + Favorite databases grouped into Development, Testing, and Production in the Favorites sidebar + + Database favorites are stored locally for each connection. Database names that no longer exist stay in Favorites so you can remove them; trying to activate one shows the database driver's normal switch error. ## Table Favorites