mirror of
https://github.com/l0ng-ai/tty7.git
synced 2026-09-22 00:02:23 +00:00
refactor(ssh): rebuild Settings → SSH as a host library
The section was a field editor wearing a list's clothes: the widest column on the page said "Select a profile to edit" and nothing else, the global security toggles hung underneath whichever host happened to be open, and port forwards had to be typed as `L bind:port target:port` into a text area that taught the syntax nowhere and silently dropped any line it couldn't parse. The master column now leads with a title and a filter — past a dozen hosts, finding one is the job — with Add and the `~/.ssh/config` import demoted to icon affordances beside it. Hosts bucket by group into collapsible sections; a collapsed header keeps showing how many of its hosts are connected, and collapsing the group holding the selection hands the detail pane back to Defaults rather than stranding a selected row nobody can see. A live query force-expands every group. `Defaults` is now a pinned row with its own page, so "every host starts from these and can override one" is something the list's shape says. Each per-host override names the value it currently inherits instead of claiming a mechanism exists. A selected host leads with its own name, address, jump chain and live status, then Save (disabled with nothing to write) and Connect. Save leaves the form open — with the list permanently beside it, closing back to an empty pane read as the selection being thrown away. Port forwards are one row of inputs per rule, and a rule that can't connect is flagged in place rather than dropped on save. With nothing selected the pane offers quick connect and, when `~/.ssh/config` holds aliases tty7 hasn't linked, an offer to link them.
This commit is contained in:
@@ -4339,6 +4339,29 @@ impl Tty7App {
|
||||
}),
|
||||
);
|
||||
|
||||
// Live filter for the SSH section's host list; each keystroke re-renders
|
||||
// the master column so the list narrows as you type.
|
||||
let ssh_filter = cx.new(|cx| InputState::new(window, cx).placeholder("Filter hosts…"));
|
||||
subs.push(
|
||||
cx.subscribe_in(&ssh_filter, window, |_this, _i, ev, _w, cx| {
|
||||
if matches!(ev, InputEvent::Change) {
|
||||
cx.notify();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
// The SSH empty state's quick-connect box. Its Connect button enables only
|
||||
// on a parsable target, so each keystroke re-renders the pane.
|
||||
let ssh_quick_connect =
|
||||
cx.new(|cx| InputState::new(window, cx).placeholder("user@host or user@host:port"));
|
||||
subs.push(
|
||||
cx.subscribe_in(&ssh_quick_connect, window, |_this, _i, ev, _w, cx| {
|
||||
if matches!(ev, InputEvent::Change) {
|
||||
cx.notify();
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
self.settings = Some(SettingsState {
|
||||
focus_handle: focus_handle.clone(),
|
||||
section: SettingsSection::Appearance,
|
||||
@@ -4360,6 +4383,9 @@ impl Tty7App {
|
||||
rebinding_note: None,
|
||||
ssh_form: None,
|
||||
ssh_detail: crate::ui::settings::SshDetail::None,
|
||||
ssh_filter,
|
||||
ssh_collapsed_groups: std::collections::HashSet::new(),
|
||||
ssh_quick_connect,
|
||||
agent_hooks_host: crate::ui::host_ops::HostId::LOCAL,
|
||||
agent_hooks_states: crate::ui::settings::AgentHooksView::Loading,
|
||||
agent_hooks_seq: 0,
|
||||
@@ -7291,6 +7317,19 @@ mod keybinding_gpui_tests {
|
||||
use gpui::{AppContext, Entity, TestAppContext, VisualTestContext};
|
||||
|
||||
fn harness(cx: &mut TestAppContext) -> (Entity<Tty7App>, VisualTestContext) {
|
||||
// Every keybinding edit below goes through `update_config`, which ends in
|
||||
// `Config::save()` — a *full* overwrite of `config.json` at whatever path
|
||||
// the config dir resolves to. Unpinned, that is the developer's real
|
||||
// `~/.config/tty7/config.json`, so running these tests silently reset the
|
||||
// user's entire config to `Config::default()` plus the shortcut recorded
|
||||
// here. Pin a scratch dir first, like every other test module that
|
||||
// touches config-dir files (`set_config_dir` is first-call-wins, so this
|
||||
// is a no-op when another test in the same process already pinned one —
|
||||
// also a scratch dir, so the real file stays untouched either way).
|
||||
let dir = std::env::temp_dir().join(format!("tty7-kbtest-{}", std::process::id()));
|
||||
std::fs::create_dir_all(&dir).ok();
|
||||
crate::core::config::set_config_dir(dir);
|
||||
|
||||
// The pause-to-commit is a real `smol::Timer` (off the deterministic
|
||||
// executor), so waiting on it parks the test thread.
|
||||
cx.executor().allow_parking();
|
||||
|
||||
+1133
-315
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user