feat(connections): list saved connections under their groups in Switch Connection - #2620
Merged
Merged
Conversation
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Automations to automatically generate PRs for you. |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #1311.
What the issue asked for, and what is left of it
The issue is from May, and it predates the two refactors that answered most of it. #2035 added the
connections strip and #2097 made one window host every connection, so clicking a connection already
switches the window in place instead of piling up tabs, which was the reporter's actual complaint.
What none of that delivered is the first half of the request: the group hierarchy is invisible from
a main window.
ConnectionGroupcarries a parent, a colour and a sort order, and it syncs, but theonly surface that renders it is the welcome window. Switch Connection, the one place inside the
window that lists every saved connection, showed a flat list with the group reduced to a badge.
Why the panel and not the sidebar
The request as written is the DataGrip and DBeaver shape, one tree holding groups, connections,
databases, schemas and tables. Two things rule it out.
The HIG's sidebar page: "In general, show no more than two levels of hierarchy in a sidebar. When
a data hierarchy is deeper than two levels, consider using a split view interface that includes a
content list." The sidebar already holds database, schema, object kind and table. Groups and
connections on top of that is six levels.
And no macOS-native client does it. TablePlus keeps saved connections on its welcome screen and its
second sidebar lists only what is open, gated on there being more than one, which is the same shape
as our connections strip. Postico, Sequel Ace and Querious are the same. The two that merge the
trees are cross-platform IDEs.
The strip cannot carry it either, and not for want of room:
WorkspaceRailStore.entriesis derivedfrom the windows that host a connection, and
WorkspaceIDis keyed on a connection plus thecontainer it is browsing. A connection that is not open has neither.
So the hierarchy goes where the library already lives.
What changed
shows them, a nested group naming its whole path (
ACME / EUROPE) and each header carrying thegroup's own colour. Connections in no group come last, which is where the tree puts them.
an empty section draws no header, but the model claimed a hierarchy that was not on screen and
that is what decides the last section's name: with no group visible it stays SAVED
CONNECTIONS, because "ungrouped" needs a group beside it to mean anything. A parent holding
only subgroups names itself through its children's path instead of drawing an empty header.
connections a user switches between furthest apart, and the section already excludes them from
the saved half, so nothing is listed twice.
match in each of eight groups is eight one-row sections. It also keeps the arrow keys away from
header rows, which is TablePlus issue fix(plugin-duckdb): render timestamp and nested column types the value API cannot decode #2134, open since 2020.
Cmd-click opens a saved connection in a window of its own, the modifier Finder and Safari usefor the same intent. A connection already open is switched to either way: moving one between
windows belongs to the connections strip, which owns that arrangement.
activeSessions, and thatnow decides both halves. A workspace outlives its session, so a connect that failed, one the user
cancelled and an explicit disconnect all leave a connection open with no session; the old rule
listed those under a group, where
Cmd-click promised a window they would never get, and in ashared window the ordinary route then switched away from the connection on screen to reconnect a
hidden one. The top section is derived from
WindowManager.hostedWorkspaces()and the saved rowsare what is left, with
connectionWindowsChangedobserved so the split follows a window openingor closing. That is CLAUDE.md's "A workspace's content is a function of its own
ConnectionWindowPhase, never ofactiveSessionsmembership".handler left a main-actor job between the question and the answer, and anything that opened the
same connection in between, the MCP tool among them, would have left two workspaces restoring the
same tabs. Nothing is awaited between the two now.
openInNewWindowgainedjoinsTabGroup. Left alone it joins the existing tab group on purpose,which is what once made Open in New Window produce a native tab of the window it was asked to
leave, so the switcher passes
falseand gets a window that stands apart. Tabbing is refused forthe moment the window is placed and allowed again straight after, so standing apart now does not
cost it the right to be merged by hand later.
refreshed in place, so a group renamed or recoloured on another device kept its old header on
screen until something structural forced a full reload.
connectionUpdatedinstead of reading storage once inonAppear, so a grouprenamed or a connection added while it is open is reflected. That event only exists on the group
path since fix(connections): make the group system report its refusals and survive a broken graph #2619. It subscribes to the subject itself rather than a
receive(on:)wrapper, whichwould build a new publisher on every body pass; every sender is already on the main actor.
FieldDrivenListSectiongained an optional accent colour, drawn as a dot beside the header title.It defaults to nil, so the database switcher and the history pane are untouched.
Non-goal: collapsing a group
This is a transient panel with a search field, and neither Spotlight nor Xcode's Open Quickly lets
you fold a section away. Collapsing would need a click path to a header row, which
clickedItemId()cannot reach because a header carries no item id, plus somewhere to persist thestate, logic to hide the descendants of a collapsed group, and an auto-expand that walks the whole
ancestor chain of the active connection. If it turns out to be wanted, the honest answer is an
NSOutlineViewon the existingSidebarOutlineScaffoldrather than bolting it onto a table.What the new-window path deliberately does not do
It never prompts for a pre-connect script. A window whose connection carries one does not
auto-connect at all:
MainSplitViewController+Connection.swift:37sends it to its not-connectedstate, where Connect asks. Prompting in the router as well would ask the same question twice and
the first answer would change nothing, which is why the window-opening half of
openConnectionhasnever called it either.
Verification
verify.sh generate,verify.sh build: PASSverify.sh test ConnectionSwitcherFilterTests ConnectionSwitcherSectionsTests StringCatalogIntegrityTests: PASSverify.sh uitest SwitcherEscapeUITests: PASSverify.sh docs: PASS, both the house-style and the source-claim checkswiftlint --stricton every changed file: cleanSection building moved out of the view into
ConnectionSwitcherSections, so the part that decideswhat is listed and in what order is testable without a window. Six new cases cover group ordering,
the path title of a nested group, the accent colour, the flattening under a filter, a group whose
connections are all open drawing no rows, and the row order the arrow keys walk matching the
sections.
No new UI automation. Seeding a group tree needs a launch hook the app does not have: the only two
it exposes are the sandbox root and "open the sample database", and a UI test target cannot import
the app to write the connection store itself. Adding one would be production code with no user. The
panel itself stays covered by
SwitcherEscapeUITests, which drives it through real key presses.https://claude.ai/code/session_01L81TaoPWxkLd15CGw2riPq