feat: add Quick Switcher with native SwiftUI sheet#278
Conversation
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (9)
📝 WalkthroughWalkthroughAdds a Quick Switcher feature: a Unicode-safe fuzzy matcher, QuickSwitcher data model and ViewModel with debounced filtering and navigation, a SwiftUI QuickSwitcherSheet (keyboard + double-click support), coordinator selection handling and command to present it, refresh notifications after some schema loads, and unit tests and docs. Changes
Sequence DiagramsequenceDiagram
actor User
participant View as QuickSwitcherSheet
participant ViewModel as QuickSwitcherViewModel
participant Fuzzy as FuzzyMatcher
participant Coordinator as MainContentCoordinator
User->>View: Open quick switcher
View->>ViewModel: loadItems(schemaProvider, connectionId, databaseType)
ViewModel->>ViewModel: fetch tables/views/databases/schemas/history
ViewModel-->>View: publish allItems
User->>View: Type search query
View->>ViewModel: update searchText
ViewModel->>ViewModel: debounce & applyFilter()
ViewModel->>Fuzzy: score(query, candidate)
Fuzzy-->>ViewModel: scores
ViewModel->>View: publish filteredItems (sorted, capped)
User->>View: Navigate (Up/Down)
View->>ViewModel: moveUp()/moveDown()
ViewModel-->>View: update selectedItem
User->>View: Press Return / Double-click
View->>Coordinator: handleQuickSwitcherSelection(item)
alt item is table/view/systemTable
Coordinator->>Coordinator: openTableTab(...)
else item is database/schema
Coordinator->>Coordinator: switchDatabase/switchSchema (async)
else item is queryHistory
Coordinator->>Coordinator: post loadQueryIntoEditor notification
end
Coordinator-->>View: dismiss sheet
Estimated code review effort🎯 4 (Complex) | ⏱️ ~50 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
Comment |
Implements Quick Switcher (Cmd+P) for fast navigation to tables, views, databases, schemas, and query history using fuzzy search. Uses the existing ActiveSheet enum + .sheet(item:) pattern matching other dialogs. Also fixes missing .refreshData notification for MySQL/MariaDB/ClickHouse database switching.
e1145b4 to
66ebe7e
Compare
- Fix double Return key handling (remove .keyboardShortcut from button) - Fix emoji in search blocking all matches (restructure to while loop) - Remove unused file-scope logger in QuickSwitcher extension - Add subtitles for view/system table items - Add test cases for emoji handling, grouped items, nil selection
There was a problem hiding this comment.
🧹 Nitpick comments (9)
TablePro/Models/UI/QuickSwitcherItem.swift (1)
11-21: Add explicit access control to type declarations.Per coding guidelines, all declarations should have explicit access control. Both
QuickSwitcherItemKindandQuickSwitcherItemneed access modifiers.♻️ Suggested fix
-enum QuickSwitcherItemKind: Hashable, Sendable { +internal enum QuickSwitcherItemKind: Hashable, Sendable { case table case view case systemTable case database case schema case queryHistory } /// A single item in the quick switcher results list -struct QuickSwitcherItem: Identifiable, Hashable { +internal struct QuickSwitcherItem: Identifiable, Hashable {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Models/UI/QuickSwitcherItem.swift` around lines 11 - 21, The enum QuickSwitcherItemKind and the struct QuickSwitcherItem lack explicit access control; add the appropriate access level (e.g., public/internal/fileprivate/private) to both declarations by prefixing the declarations (QuickSwitcherItemKind and QuickSwitcherItem) with the chosen modifier so they conform to project coding guidelines and make their visibility explicit.TablePro/Core/Utilities/UI/FuzzyMatcher.swift (1)
11-15: Add explicit access control per coding guidelines.The
enum FuzzyMatcherandstatic func scorelack explicit access modifiers. As per coding guidelines, all declarations should have explicit access control.♻️ Suggested fix
-enum FuzzyMatcher { - /// Score a candidate string against a search query. - /// Returns 0 for no match, higher values indicate better matches. - /// Empty query returns 1 (everything matches). - static func score(query: String, candidate: String) -> Int { +internal enum FuzzyMatcher { + /// Score a candidate string against a search query. + /// Returns 0 for no match, higher values indicate better matches. + /// Empty query returns 1 (everything matches). + internal static func score(query: String, candidate: String) -> Int {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Core/Utilities/UI/FuzzyMatcher.swift` around lines 11 - 15, Add explicit access control to the enum and its method by changing "enum FuzzyMatcher" to "internal enum FuzzyMatcher" and "static func score(query: String, candidate: String) -> Int" to "internal static func score(query: String, candidate: String) -> Int" (or use your project's chosen access level if different) so both the FuzzyMatcher type and the score(...) method have explicit access modifiers.TablePro/Views/Main/Extensions/MainContentCoordinator+QuickSwitcher.swift (1)
11-11: Remove unused logger declaration.The
quickSwitcherLoggeris declared but never used in this file. Either add logging for debugging purposes or remove the unused declaration.♻️ Option 1: Remove unused logger
import Foundation -import os - -private let quickSwitcherLogger = Logger(subsystem: "com.TablePro", category: "MainContentCoordinator+QuickSwitcher") extension MainContentCoordinator {♻️ Option 2: Add logging for debugging
extension MainContentCoordinator { /// Handle selection from the quick switcher palette func handleQuickSwitcherSelection(_ item: QuickSwitcherItem) { + quickSwitcherLogger.debug("Quick switcher selected: \(item.name, privacy: .public) (\(String(describing: item.kind), privacy: .public))") switch item.kind {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Views/Main/Extensions/MainContentCoordinator`+QuickSwitcher.swift at line 11, The file declares a private let quickSwitcherLogger which is never referenced; remove that unused logger declaration (private let quickSwitcherLogger = Logger(...)) from MainContentCoordinator+QuickSwitcher.swift to eliminate the dead symbol, or alternatively, if you prefer to keep logging, add explicit uses of quickSwitcherLogger inside the QuickSwitcher-related methods (e.g., any showQuickSwitcher/hideQuickSwitcher/toggleQuickSwitcher implementations) to log important state transitions instead of leaving it unused.TablePro/Views/QuickSwitcher/QuickSwitcherView.swift (4)
67-74: Remove unnecessaryTaskwrapper.Both the view and
QuickSwitcherViewModelare@MainActor-isolated. TheTask {@mainactorin ... }wrapper adds unnecessary overhead sinceonKeyPressclosures execute on the main thread.♻️ Suggested simplification
.onKeyPress(.upArrow) { - Task { `@MainActor` in viewModel.moveUp() } + viewModel.moveUp() return .handled } .onKeyPress(.downArrow) { - Task { `@MainActor` in viewModel.moveDown() } + viewModel.moveDown() return .handled }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Views/QuickSwitcher/QuickSwitcherView.swift` around lines 67 - 74, The onKeyPress closures in QuickSwitcherView wrap viewModel.moveUp() and viewModel.moveDown() in unnecessary Task { `@MainActor` ... } blocks; since the view and QuickSwitcherViewModel are `@MainActor-isolated` and onKeyPress runs on the main thread, remove the Task wrappers and call viewModel.moveUp() and viewModel.moveDown() directly inside their respective onKeyPress closures, preserving the return .handled.
238-243: Redundant keyboard shortcut.The
.keyboardShortcut(.return, modifiers: [])on the Open button is redundant since.onKeyPress(.return)at line 63 already handles Return key and calls the sameopenSelectedItem()function. Consider removing the keyboard shortcut to avoid potential double-handling.♻️ Suggested change
Button("Open") { openSelectedItem() } .buttonStyle(.borderedProminent) .disabled(viewModel.selectedItem == nil) - .keyboardShortcut(.return, modifiers: [])🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Views/QuickSwitcher/QuickSwitcherView.swift` around lines 238 - 243, Remove the redundant explicit keyboard shortcut on the "Open" Button to avoid double-handling of Return: locate the Button that calls openSelectedItem() (the one using .buttonStyle(.borderedProminent) and .disabled(viewModel.selectedItem == nil)) and delete the .keyboardShortcut(.return, modifiers: []) modifier; keep the existing .onKeyPress(.return) handler (which already calls openSelectedItem()) so Return continues to work via that centralized handler.
142-174: UseDesignConstants.FontSizefor consistency.The item row uses hardcoded font sizes (14, 13, 11, 10) while the rest of the file uses
DesignConstants.FontSize. Consider using the design constants for consistency with the project's styling approach.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Views/QuickSwitcher/QuickSwitcherView.swift` around lines 142 - 174, Replace the hardcoded numeric font sizes inside itemRow(_:) with the project's DesignConstants.FontSize values used elsewhere in QuickSwitcherView: update the Image font(.system(size: 14)) and the Texts for name (size 13), subtitle (size 11) and kindLabel (size 10) to use the corresponding DesignConstants.FontSize constants (matching the intent/weight for icon, primary text, secondary subtitle and badge) so all calls in itemRow(_ item: QuickSwitcherItem) reference DesignConstants.FontSize instead of literal numbers.
14-14: Add explicit access modifier to struct.Per coding guidelines, always use explicit access control. Since
QuickSwitcherSheetis used fromMainContentView, it should be explicitlyinternal(orpublicif cross-module).-struct QuickSwitcherSheet: View { +internal struct QuickSwitcherSheet: View {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/Views/QuickSwitcher/QuickSwitcherView.swift` at line 14, QuickSwitcherSheet currently lacks an explicit access modifier; update the declaration of the struct QuickSwitcherSheet (used by MainContentView) to have an explicit access level (e.g., mark it as internal struct QuickSwitcherSheet: View or public if it must be visible across modules) so it conforms to the project's access-control guidelines and matches how MainContentView references it.TablePro/ViewModels/QuickSwitcherViewModel.swift (2)
138-144: Simplify nil return.The explicit type annotation
nil as QuickSwitcherItem?is unnecessary.compactMapinfers the optional type from the closure's return type.♻️ Suggested simplification
filteredItems = allItems.compactMap { item in let matchScore = FuzzyMatcher.score(query: searchText, candidate: item.name) - guard matchScore > 0 else { return nil as QuickSwitcherItem? } + guard matchScore > 0 else { return nil } var scored = item scored.score = matchScore return scored }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/ViewModels/QuickSwitcherViewModel.swift` around lines 138 - 144, The compactMap closure in the filteredItems assignment uses an unnecessary explicit optional cast when returning nil; in the closure that iterates allItems and computes matchScore via FuzzyMatcher.score(query: searchText, candidate: item.name), replace the explicit "nil as QuickSwitcherItem?" return with a simple "return nil" so compactMap can infer the optional type for QuickSwitcherItem and keep scored population logic (setting scored.score = matchScore) intact.
13-28: Add explicit access modifiers.Per coding guidelines, always use explicit access control. The class and some properties lack explicit modifiers.
♻️ Suggested changes
`@MainActor` `@Observable` -final class QuickSwitcherViewModel { +internal final class QuickSwitcherViewModel { private static let logger = Logger(subsystem: "com.TablePro", category: "QuickSwitcherViewModel") // MARK: - State - var searchText = "" { + internal var searchText = "" { didSet { updateFilter() } } - var allItems: [QuickSwitcherItem] = [] { + internal var allItems: [QuickSwitcherItem] = [] { didSet { applyFilter() } } private(set) var filteredItems: [QuickSwitcherItem] = [] - var selectedItemId: String? - var isLoading = false + internal var selectedItemId: String? + internal var isLoading = false🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/ViewModels/QuickSwitcherViewModel.swift` around lines 13 - 28, The class and several properties lack explicit access control; update QuickSwitcherViewModel to declare an explicit access level (e.g., internal) on the class and its stored properties: mark the class as "internal" (e.g., `@MainActor` `@Observable` internal final class QuickSwitcherViewModel), add explicit access modifiers for searchText, allItems, selectedItemId, and isLoading (e.g., internal var searchText, internal var allItems, internal var selectedItemId, internal var isLoading), and make the existing private(set) filteredItems declaration explicitly internal with its setter privacy (e.g., internal private(set) var filteredItems) while leaving the static logger as private. Ensure all modifiers are consistent with project conventions.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@TablePro/Core/Utilities/UI/FuzzyMatcher.swift`:
- Around line 11-15: Add explicit access control to the enum and its method by
changing "enum FuzzyMatcher" to "internal enum FuzzyMatcher" and "static func
score(query: String, candidate: String) -> Int" to "internal static func
score(query: String, candidate: String) -> Int" (or use your project's chosen
access level if different) so both the FuzzyMatcher type and the score(...)
method have explicit access modifiers.
In `@TablePro/Models/UI/QuickSwitcherItem.swift`:
- Around line 11-21: The enum QuickSwitcherItemKind and the struct
QuickSwitcherItem lack explicit access control; add the appropriate access level
(e.g., public/internal/fileprivate/private) to both declarations by prefixing
the declarations (QuickSwitcherItemKind and QuickSwitcherItem) with the chosen
modifier so they conform to project coding guidelines and make their visibility
explicit.
In `@TablePro/ViewModels/QuickSwitcherViewModel.swift`:
- Around line 138-144: The compactMap closure in the filteredItems assignment
uses an unnecessary explicit optional cast when returning nil; in the closure
that iterates allItems and computes matchScore via FuzzyMatcher.score(query:
searchText, candidate: item.name), replace the explicit "nil as
QuickSwitcherItem?" return with a simple "return nil" so compactMap can infer
the optional type for QuickSwitcherItem and keep scored population logic
(setting scored.score = matchScore) intact.
- Around line 13-28: The class and several properties lack explicit access
control; update QuickSwitcherViewModel to declare an explicit access level
(e.g., internal) on the class and its stored properties: mark the class as
"internal" (e.g., `@MainActor` `@Observable` internal final class
QuickSwitcherViewModel), add explicit access modifiers for searchText, allItems,
selectedItemId, and isLoading (e.g., internal var searchText, internal var
allItems, internal var selectedItemId, internal var isLoading), and make the
existing private(set) filteredItems declaration explicitly internal with its
setter privacy (e.g., internal private(set) var filteredItems) while leaving the
static logger as private. Ensure all modifiers are consistent with project
conventions.
In `@TablePro/Views/Main/Extensions/MainContentCoordinator`+QuickSwitcher.swift:
- Line 11: The file declares a private let quickSwitcherLogger which is never
referenced; remove that unused logger declaration (private let
quickSwitcherLogger = Logger(...)) from
MainContentCoordinator+QuickSwitcher.swift to eliminate the dead symbol, or
alternatively, if you prefer to keep logging, add explicit uses of
quickSwitcherLogger inside the QuickSwitcher-related methods (e.g., any
showQuickSwitcher/hideQuickSwitcher/toggleQuickSwitcher implementations) to log
important state transitions instead of leaving it unused.
In `@TablePro/Views/QuickSwitcher/QuickSwitcherView.swift`:
- Around line 67-74: The onKeyPress closures in QuickSwitcherView wrap
viewModel.moveUp() and viewModel.moveDown() in unnecessary Task { `@MainActor` ...
} blocks; since the view and QuickSwitcherViewModel are `@MainActor-isolated` and
onKeyPress runs on the main thread, remove the Task wrappers and call
viewModel.moveUp() and viewModel.moveDown() directly inside their respective
onKeyPress closures, preserving the return .handled.
- Around line 238-243: Remove the redundant explicit keyboard shortcut on the
"Open" Button to avoid double-handling of Return: locate the Button that calls
openSelectedItem() (the one using .buttonStyle(.borderedProminent) and
.disabled(viewModel.selectedItem == nil)) and delete the
.keyboardShortcut(.return, modifiers: []) modifier; keep the existing
.onKeyPress(.return) handler (which already calls openSelectedItem()) so Return
continues to work via that centralized handler.
- Around line 142-174: Replace the hardcoded numeric font sizes inside
itemRow(_:) with the project's DesignConstants.FontSize values used elsewhere in
QuickSwitcherView: update the Image font(.system(size: 14)) and the Texts for
name (size 13), subtitle (size 11) and kindLabel (size 10) to use the
corresponding DesignConstants.FontSize constants (matching the intent/weight for
icon, primary text, secondary subtitle and badge) so all calls in itemRow(_
item: QuickSwitcherItem) reference DesignConstants.FontSize instead of literal
numbers.
- Line 14: QuickSwitcherSheet currently lacks an explicit access modifier;
update the declaration of the struct QuickSwitcherSheet (used by
MainContentView) to have an explicit access level (e.g., mark it as internal
struct QuickSwitcherSheet: View or public if it must be visible across modules)
so it conforms to the project's access-control guidelines and matches how
MainContentView references it.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: e3c23948-2c73-4e06-ab82-bbbf42c99809
📒 Files selected for processing (11)
TablePro/Core/Utilities/UI/FuzzyMatcher.swiftTablePro/Models/UI/QuickSwitcherItem.swiftTablePro/ViewModels/QuickSwitcherViewModel.swiftTablePro/Views/Main/Extensions/MainContentCoordinator+Navigation.swiftTablePro/Views/Main/Extensions/MainContentCoordinator+QuickSwitcher.swiftTablePro/Views/Main/MainContentCommandActions.swiftTablePro/Views/Main/MainContentCoordinator.swiftTablePro/Views/Main/MainContentView.swiftTablePro/Views/QuickSwitcher/QuickSwitcherView.swiftTableProTests/Utilities/FuzzyMatcherTests.swiftTableProTests/ViewModels/QuickSwitcherViewModelTests.swift
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
TablePro/ViewModels/QuickSwitcherViewModel.swift (1)
135-159: Add a deterministic tie-breaker for equal-score and equal-kind items.Both branches only sort on a single key, so items with the same score or kind can shuffle relative order across refreshes. In this UI that means keyboard selection can jump unexpectedly, and the tests are already depending on same-kind items staying in a stable order.
💡 Example of a stable secondary ordering
private func applyFilter() { if searchText.isEmpty { filteredItems = allItems.sorted { a, b in - kindSortOrder(a.kind) < kindSortOrder(b.kind) + let aKind = kindSortOrder(a.kind) + let bKind = kindSortOrder(b.kind) + if aKind != bKind { + return aKind < bKind + } + return a.name.localizedCaseInsensitiveCompare(b.name) == .orderedAscending } if filteredItems.count > maxResults { filteredItems = Array(filteredItems.prefix(maxResults)) } } else { filteredItems = allItems.compactMap { item in let matchScore = FuzzyMatcher.score(query: searchText, candidate: item.name) guard matchScore > 0 else { return nil as QuickSwitcherItem? } var scored = item scored.score = matchScore return scored } - .sorted { $0.score > $1.score } + .sorted { lhs, rhs in + if lhs.score != rhs.score { + return lhs.score > rhs.score + } + let lhsKind = kindSortOrder(lhs.kind) + let rhsKind = kindSortOrder(rhs.kind) + if lhsKind != rhsKind { + return lhsKind < rhsKind + } + return lhs.name.localizedCaseInsensitiveCompare(rhs.name) == .orderedAscending + } if filteredItems.count > maxResults { filteredItems = Array(filteredItems.prefix(maxResults)) } }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@TablePro/ViewModels/QuickSwitcherViewModel.swift` around lines 135 - 159, The sorting in applyFilter() uses only kindSortOrder(a.kind) (when searchText.isEmpty) and only score (when filtering), which allows equal-kind or equal-score items to reorder; update both sort calls in applyFilter() to add a deterministic secondary tie-breaker such as item.name (or item.id) so items with equal kind or equal score are consistently ordered—adjust the sorted closures that reference kindSortOrder and $0.score to compare (kind, name) and (score, name) respectively, leaving all other logic (FuzzyMatcher.score, filteredItems trimming, maxResults, and selectedItemId assignment) unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@TablePro/Core/Utilities/UI/FuzzyMatcher.swift`:
- Around line 30-44: The current loops in FuzzyMatcher.swift skip UTF-16
surrogate halves by using NSString.character(at:) and UnicodeScalar(...) which
drops non-BMP scalars; change the matching iteration to walk full Unicode
scalars (e.g., query.unicodeScalars and candidate.unicodeScalars or Swift
Characters) instead of using queryNS.character(at:) and
candidateNS.character(at:), update references to queryIndex/candidateIndex to
iterate those scalar collections, and preserve existing logic (consecutiveBonus
reset, advancing indices, and guard behavior) so supplementary-plane characters
(emoji, etc.) participate in matching; also apply the same change to the other
occurrence noted around lines 100-106.
In `@TablePro/ViewModels/QuickSwitcherViewModel.swift`:
- Around line 38-120: The loadItems function can finish out of order and
overwrite newer state; fix by introducing a load token (e.g. a private var
currentLoadToken: UUID?) and at the start of loadItems generate a new UUID and
assign it to currentLoadToken, capture it in a local let token, then before any
final state commits (setting allItems and isLoading) verify that
currentLoadToken == token and only then update state; also ensure you clear or
update currentLoadToken appropriately when a newer load starts or when canceling
to fence stale completions from overwriting allItems/isLoading.
---
Nitpick comments:
In `@TablePro/ViewModels/QuickSwitcherViewModel.swift`:
- Around line 135-159: The sorting in applyFilter() uses only
kindSortOrder(a.kind) (when searchText.isEmpty) and only score (when filtering),
which allows equal-kind or equal-score items to reorder; update both sort calls
in applyFilter() to add a deterministic secondary tie-breaker such as item.name
(or item.id) so items with equal kind or equal score are consistently
ordered—adjust the sorted closures that reference kindSortOrder and $0.score to
compare (kind, name) and (score, name) respectively, leaving all other logic
(FuzzyMatcher.score, filteredItems trimming, maxResults, and selectedItemId
assignment) unchanged.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b6910638-3df9-463d-bd4e-f12fe4004973
📒 Files selected for processing (6)
TablePro/Core/Utilities/UI/FuzzyMatcher.swiftTablePro/ViewModels/QuickSwitcherViewModel.swiftTablePro/Views/Main/Extensions/MainContentCoordinator+QuickSwitcher.swiftTablePro/Views/QuickSwitcher/QuickSwitcherView.swiftTableProTests/Utilities/FuzzyMatcherTests.swiftTableProTests/ViewModels/QuickSwitcherViewModelTests.swift
🚧 Files skipped from review as they are similar to previous changes (2)
- TablePro/Views/Main/Extensions/MainContentCoordinator+QuickSwitcher.swift
- TablePro/Views/QuickSwitcher/QuickSwitcherView.swift
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/features/keyboard-shortcuts.mdx`:
- Line 267: The heading "## Quick Switcher" should be changed to sentence case;
update the markdown heading text in docs/features/keyboard-shortcuts.mdx by
renaming the heading string from "## Quick Switcher" to "## Quick switcher"
(locate the header line with that exact text and replace it to match the docs
style rule).
- Around line 267-279: Add the new Quick Switcher shortcut (Cmd+P) to the
summary tables so the documentation is consistent: update the "Essential
Shortcuts" table and the "Cheat Sheet" section to include an entry "Quick
Switcher | `Cmd+P`" (or similar wording consistent with the existing table rows)
and ensure any description text references the Quick Switcher heading; look for
the headings "Essential Shortcuts" and "Cheat Sheet" in
docs/features/keyboard-shortcuts.mdx and add the Cmd+P row in the same format as
other shortcut entries.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: b67f6723-dc4b-4ccb-bfb4-dc757a1ac467
📒 Files selected for processing (3)
docs/features/keyboard-shortcuts.mdxdocs/vi/features/keyboard-shortcuts.mdxdocs/zh/features/keyboard-shortcuts.mdx
✅ Files skipped from review due to trivial changes (2)
- docs/zh/features/keyboard-shortcuts.mdx
- docs/vi/features/keyboard-shortcuts.mdx
- Add explicit access control to all Quick Switcher types - Rewrite FuzzyMatcher to use unicodeScalars for proper supplementary-plane Unicode support - Add load token to prevent stale loadItems completions from overwriting newer state - Add stable sort tie-breaker (name) for deterministic ordering - Remove unnecessary Task wrappers and redundant .keyboardShortcut on Open button - Use DesignConstants for font/icon sizes in QuickSwitcherView - Add Cmd+P to Essential Shortcuts and Cheat Sheet in docs - Use sentence case for Quick Switcher heading in docs
Summary
.sheet(item:)viaActiveSheetenum, matching existing dialog patterns (DatabaseSwitcherSheet, ExportDialog, ImportDialog)List(selection:)with.listStyle(.sidebar), section grouping by kind, proper footer with Cancel/Open buttons.refreshDatanotification for MySQL/MariaDB/ClickHouse database switching (sidebar didn't refresh after switch)docs/development/notification-refactor.mdtracking plan for replacing NotificationCenter with proper Swift patternsNew files
QuickSwitcherView.swift—QuickSwitcherSheet(pure SwiftUI, no NSPanel)QuickSwitcherItem.swift— data modelQuickSwitcherViewModel.swift— search, fuzzy filtering, keyboard navigationFuzzyMatcher.swift— scoring algorithm for search rankingMainContentCoordinator+QuickSwitcher.swift— selection handler (open table/view/database/schema/history)FuzzyMatcherTests.swift+QuickSwitcherViewModelTests.swift— test coverageTest plan
Summary by CodeRabbit
New Features
Bug Fixes
Tests
Documentation