Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- Sidebar search: arrow keys navigate filtered results and Enter opens the selected table, matching DataGrip behavior (#1280)
- Right-click a column header to copy all its values from the loaded rows (#1325)
- Copy as submenu on the row context menu now offers CSV, CSV with Headers, Markdown table, and IN Clause for SQL `WHERE id IN (...)` lookups (#1325)
- Double-click or press Return on a read-only query result cell to open a selectable text viewer in the cell. JSON columns open the JSON viewer in a popover, BLOB columns open the hex viewer. The value is selectable and copyable (#1336)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,22 @@ internal final class MainSplitViewController: NSSplitViewController, InspectorVi
splitView.autosaveName = "com.TablePro.mainSplit"

sidebarContainer = SidebarContainerViewController(rootView: AnyView(buildSidebarView()))
sidebarContainer.onOpenTable = { [weak self] table in
guard let coordinator = self?.sessionState?.coordinator else { return }
let connectionId = coordinator.connectionId
if let preview = WindowLifecycleMonitor.shared.previewWindow(for: connectionId),
let previewCoordinator = MainContentCoordinator.coordinator(for: preview.windowId) {
if previewCoordinator.tabManager.selectedTab?.tableContext.tableName == table.name {
previewCoordinator.promotePreviewTab()
} else {
previewCoordinator.promotePreviewTab()
coordinator.openTableTab(table)
}
} else {
coordinator.promotePreviewTab()
coordinator.openTableTab(table)
}
}
sidebarSplitItem = NSSplitViewItem(sidebarWithViewController: sidebarContainer)
sidebarSplitItem.canCollapse = true
sidebarSplitItem.minimumThickness = 280
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ internal final class SidebarContainerViewController: NSViewController {
private var windowState: WindowSidebarState?
private var observationGeneration = 0

var onOpenTable: ((TableInfo) -> Void)?

var rootView: AnyView {
get { hostingController.rootView }
set { hostingController.rootView = newValue }
Expand Down Expand Up @@ -120,6 +122,51 @@ extension SidebarContainerViewController: NSSearchFieldDelegate {
writeSearchText("")
}

func control(_ control: NSControl, textView: NSTextView, doCommandBy commandSelector: Selector) -> Bool {
guard let sidebarState, sidebarState.selectedSidebarTab == .tables else { return false }

if commandSelector == #selector(NSResponder.moveUp(_:)) {
navigateSelection(direction: -1)
return true
}
if commandSelector == #selector(NSResponder.moveDown(_:)) {
navigateSelection(direction: 1)
return true
}
if commandSelector == #selector(NSResponder.insertNewline(_:)) {
if let selected = sidebarState.selectedTables.first {
onOpenTable?(selected)
}
return true
}
return false
}

private func navigateSelection(direction: Int) {
guard let sidebarState, let windowState else { return }
let allTables = SchemaService.shared.tables(for: sidebarState.connectionId)
let query = windowState.searchText
let filtered: [TableInfo]
if query.isEmpty {
filtered = allTables
} else {
filtered = allTables.filter { $0.name.localizedCaseInsensitiveContains(query) }
}
guard !filtered.isEmpty else { return }

let currentIndex: Int
if let selected = sidebarState.selectedTables.first,
let idx = filtered.firstIndex(of: selected) {
currentIndex = idx
} else {
currentIndex = direction > 0 ? -1 : filtered.count
}

let nextIndex = currentIndex + direction
guard nextIndex >= 0, nextIndex < filtered.count else { return }
sidebarState.selectedTables = [filtered[nextIndex]]
}

private func writeSearchText(_ text: String) {
guard let sidebarState, let windowState else { return }
switch sidebarState.selectedSidebarTab {
Expand Down
Loading