Skip to content

Commit 908a15b

Browse files
committed
feat(settings): add toggle for the sidebar recent tables section
1 parent 3f9ffba commit 908a15b

8 files changed

Lines changed: 67 additions & 11 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1111

1212
- Mark a table as a favorite by clicking the star button at the end of its sidebar row. Favorites are scoped to the connection, database, and schema, pinned to the top of their section, appear in a dedicated Tables group in the Favorites tab, and sync through iCloud when the Table Favorites toggle is on.
1313
- A plus button in the bottom bar of the Tables sidebar opens a menu to create a new table or view, without right-clicking. It's disabled while safe mode blocks writes.
14-
- Recent section at the top of the Tables sidebar tracks the last 10 tables you opened per connection and database, in-memory for the session. (#1352)
14+
- Recent section at the top of the Tables sidebar tracks the last 10 tables you opened per connection and database, in-memory for the session. Off by default, turn it on in Settings > General > Sidebar. (#1352)
1515
- A connection can read its password from a file, environment variable, or command at connect time instead of the Keychain, so scripts can provision a connection without entering the password by hand. (#1254)
1616

1717
### Changed

TablePro/Models/Settings/GeneralSettings.swift

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,26 +61,32 @@ struct GeneralSettings: Codable, Equatable {
6161
/// Whether to share anonymous usage analytics
6262
var shareAnalytics: Bool
6363

64+
/// Whether the sidebar shows a Recent section with recently opened tables
65+
var showRecentTables: Bool
66+
6467
static let `default` = GeneralSettings(
6568
startupBehavior: .showWelcome,
6669
language: .system,
6770
automaticallyCheckForUpdates: true,
6871
queryTimeoutSeconds: 60,
69-
shareAnalytics: true
72+
shareAnalytics: true,
73+
showRecentTables: false
7074
)
7175

7276
init(
7377
startupBehavior: StartupBehavior = .showWelcome,
7478
language: AppLanguage = .system,
7579
automaticallyCheckForUpdates: Bool = true,
7680
queryTimeoutSeconds: Int = 60,
77-
shareAnalytics: Bool = true
81+
shareAnalytics: Bool = true,
82+
showRecentTables: Bool = false
7883
) {
7984
self.startupBehavior = startupBehavior
8085
self.language = language
8186
self.automaticallyCheckForUpdates = automaticallyCheckForUpdates
8287
self.queryTimeoutSeconds = queryTimeoutSeconds
8388
self.shareAnalytics = shareAnalytics
89+
self.showRecentTables = showRecentTables
8490
}
8591

8692
init(from decoder: Decoder) throws {
@@ -90,5 +96,6 @@ struct GeneralSettings: Codable, Equatable {
9096
automaticallyCheckForUpdates = try container.decodeIfPresent(Bool.self, forKey: .automaticallyCheckForUpdates) ?? true
9197
queryTimeoutSeconds = try container.decodeIfPresent(Int.self, forKey: .queryTimeoutSeconds) ?? 60
9298
shareAnalytics = try container.decodeIfPresent(Bool.self, forKey: .shareAnalytics) ?? true
99+
showRecentTables = try container.decodeIfPresent(Bool.self, forKey: .showRecentTables) ?? false
93100
}
94101
}

TablePro/Views/Main/Extensions/MainContentCoordinator+Navigation.swift

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,13 @@ extension MainContentCoordinator {
2121
redirectToSibling: Bool = false,
2222
forceNonPreview: Bool = false
2323
) {
24-
RecentTablesStore.shared.push(
25-
connectionID: connection.id,
26-
database: activeDatabaseName.isEmpty ? nil : activeDatabaseName,
27-
table: table
28-
)
24+
if AppSettingsManager.shared.general.showRecentTables {
25+
RecentTablesStore.shared.push(
26+
connectionID: connection.id,
27+
database: activeDatabaseName.isEmpty ? nil : activeDatabaseName,
28+
table: table
29+
)
30+
}
2931
openTableTab(
3032
table.name,
3133
schema: table.schema,

TablePro/Views/Settings/GeneralSettingsView.swift

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ struct GeneralSettingsView: View {
5454
.help("When enabled, tabs from different connections share the same window instead of opening separate windows.")
5555
}
5656

57+
Section("Sidebar") {
58+
Toggle("Show recent tables", isOn: $settings.showRecentTables)
59+
.help("Adds a Recent section at the top of the Tables sidebar with the last tables you opened per connection and database.")
60+
}
61+
5762
Section("Query Execution") {
5863
Picker("Query timeout:", selection: $settings.queryTimeoutSeconds) {
5964
Text("No limit").tag(0)

TablePro/Views/Sidebar/SidebarView.swift

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ struct SidebarView: View {
1313
@Bindable private var schemaService = SchemaService.shared
1414
@State private var favoriteTables: Set<FavoriteTablesStorage.FavoriteEntry> = []
1515
@State private var recentTables: [RecentTablesStore.Entry] = []
16+
@State private var settingsManager = AppSettingsManager.shared
1617

1718
var sidebarState: SharedSidebarState
1819
var windowState: WindowSidebarState
@@ -299,6 +300,10 @@ struct SidebarView: View {
299300
}
300301

301302
private func reloadRecentTables() {
303+
guard settingsManager.general.showRecentTables else {
304+
recentTables = []
305+
return
306+
}
302307
recentTables = RecentTablesStore.shared.entries(
303308
connectionID: connectionId,
304309
database: activeDatabase
@@ -308,7 +313,7 @@ struct SidebarView: View {
308313
@ViewBuilder
309314
private var recentSection: some View {
310315
let recents = filteredRecents
311-
if !recents.isEmpty {
316+
if settingsManager.general.showRecentTables, !recents.isEmpty {
312317
Section(isExpanded: $viewModel.isRecentsExpanded) {
313318
ForEach(recents) { entry in
314319
let info = tableInfo(forRecent: entry)
@@ -384,6 +389,9 @@ struct SidebarView: View {
384389
.onReceive(NotificationCenter.default.publisher(for: .recentTablesDidChange)) { _ in
385390
reloadRecentTables()
386391
}
392+
.onChange(of: settingsManager.general.showRecentTables) { _, _ in
393+
reloadRecentTables()
394+
}
387395
.onAppear {
388396
favoriteTables = FavoriteTablesStorage.shared.favorites(for: connectionId)
389397
reloadRecentTables()
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import Foundation
2+
@testable import TablePro
3+
import Testing
4+
5+
@Suite("GeneralSettings.showRecentTables")
6+
struct GeneralSettingsTests {
7+
@Test("Defaults to off")
8+
func defaultsOff() {
9+
#expect(GeneralSettings.default.showRecentTables == false)
10+
#expect(GeneralSettings().showRecentTables == false)
11+
}
12+
13+
@Test("Decoding settings without the key keeps recent tables off")
14+
func decodesMissingKeyAsOff() throws {
15+
let json = Data(#"{"startupBehavior":"showWelcome"}"#.utf8)
16+
let decoded = try JSONDecoder().decode(GeneralSettings.self, from: json)
17+
#expect(decoded.showRecentTables == false)
18+
}
19+
20+
@Test("Round-trips when enabled")
21+
func roundTripsEnabled() throws {
22+
var settings = GeneralSettings()
23+
settings.showRecentTables = true
24+
let data = try JSONEncoder().encode(settings)
25+
let decoded = try JSONDecoder().decode(GeneralSettings.self, from: data)
26+
#expect(decoded.showRecentTables == true)
27+
}
28+
}

docs/customization/settings.mdx

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,12 @@ No queries or database content is transmitted.
7474

7575
A tab is "clean" when it's a table tab (not query/create), unpinned, no unsaved changes, and no interactions (sort, filter, selection).
7676

77+
### Sidebar
78+
79+
| Setting | Default | Description |
80+
|---------|---------|-------------|
81+
| **Show recent tables** | Off | Adds a Recent section at the top of the Tables sidebar with the last 10 tables opened per connection and database |
82+
7783
## AI
7884

7985
The **AI** tab configures providers and chat behavior. See [AI Assistant](/features/ai-assistant) for usage. The tab has these sections.

docs/features/favorites.mdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ description: Mark tables as favorites and save frequently used queries with opti
55

66
# Favorites
77

8-
The Tables sidebar shows a **Recent** section at the top with the last 10 tables you opened in the current connection and database. The Favorites tab has two sections: **Tables** for pinned tables and **Queries** for saved SQL.
8+
The Tables sidebar can show a **Recent** section at the top with the last 10 tables you opened in the current connection and database (off by default). The Favorites tab has two sections: **Tables** for pinned tables and **Queries** for saved SQL.
99

1010
## Table Favorites
1111

@@ -20,7 +20,7 @@ Favorites are scoped to the connection, database, and schema, and sync through i
2020

2121
## Recent Tables
2222

23-
Each table you open is added to the **Recent** section at the top of the Tables sidebar. The list keeps the 10 most recent tables per connection and database, with the most recent at the top. Click a row to reopen the table. Recents are kept in memory for the session and clear when you quit.
23+
Turn on **Show recent tables** in Settings > General > Sidebar to add a **Recent** section at the top of the Tables sidebar. While it's on, each table you open is added to the list, which keeps the 10 most recent tables per connection and database, with the most recent at the top. Click a row to reopen the table. Recents are kept in memory for the session and clear when you quit.
2424

2525
## SQL Favorites
2626

0 commit comments

Comments
 (0)