Files
DodoSSH/src/DodoSSH.Client.App/Views/StatusBar.axaml
T
jaap-jan f05deb4fbc
ci / build and test (push) Successful in 3m43s
ci / api image (push) Canceled after 0s
ci / android head (push) Canceled after 4m6s
ci / desktop nightly (push) Canceled after 21s
Add port forwarding: local, remote and dynamic, per terminal session
A host can now carry port forwards (-L, -R, -D), saved inside its
encrypted payload as RelayTicketRequest.PortForwardId already assumed,
so they sync and merge per forward like tags and pinned paths. The host
schema moves to version 8 only for hosts that carry forwards.

ISshConnection gains StartForwardAsync over SSH.NET's forwarded ports.
Every listener binds loopback and there is no bind-address field: a
forward is something any member of a shared keychain can edit. A remote
forward's target is resolved here, IPv4 first, rather than by SSH.NET's
constructor, which takes the first DNS answer and can send ::1.

Forwards start with every terminal opened to the host and stop with its
connection; a reconnect starts them again. The session sidebar lists
them with state, failure reason and an on/off switch, the status bar
counts the listening ones, and the host editor and detail pane gain a
PORT FORWARDS section. A forward that cannot start fails alone.

The phone does not start forwards yet: it has no surface showing what
is listening, and its More screen now says so. No byte counts, since
SSH.NET keeps none.
2026-09-28 20:47:02 +02:00

55 lines
3.3 KiB
XML

<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="using:DodoSSH.Client.Shell.ViewModels"
x:Class="DodoSSH.Client.App.Views.StatusBar"
x:DataType="vm:MainWindowViewModel">
<!--
The strip along the bottom.
The design puts five things here: the active host and the bastion it is reached through, the open port
forwards, the SFTP transfer count, an auto-lock countdown, and the last sync time. Four of those five
had nothing behind them when this was written — there was no jump-host routing, no port forwarding, no
file transfer and no idle auto-lock — so what is left is the active session, the vault's last message,
and the shortcut hint. Forwards have since been built, and are counted on SessionStatusBar instead.
The last message is the load-bearing one, and it is why this bar is worth having at all: the vault's
status line used to be a cramped label in the account bar, and everything the application has to say
about a save, a sync, a refusal or a conflict goes through it.
── v2 ────────────────────────────────────────────────────────────────────────────────────────────────
The design has no status bar. Two of the three things this one carried moved into the titlebar with it —
the sync word is up there beside its dot, and the shortcut hint is inside the search box that uses it —
so those two are gone from here rather than printed twice.
The third did not move, and is why this bar survives the design that deletes it. Vault.Status is the one
channel this application has for saying that a save failed, that a sync was refused, that a merge picked
a winner. The design is a mock-up of a working afternoon and has nowhere for a sentence like that to go;
dropping the bar would have meant dropping the sentence, or repeating it on six screens.
-->
<Border Height="24" Background="{StaticResource Chrome}"
BorderBrush="{StaticResource Border}" BorderThickness="0,1,0,0">
<Grid ColumnDefinitions="Auto,*" Margin="14,0">
<!-- What is connected, and where. Absent rather than empty when nothing is. -->
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="5" VerticalAlignment="Center"
Margin="0,0,14,0" IsVisible="{Binding SelectedTab, Converter={x:Static ObjectConverters.IsNotNull}}">
<Ellipse Classes="dot" Classes.live="{Binding SelectedTab.IsLive}" VerticalAlignment="Center" />
<TextBlock Classes="mono" Text="{Binding SelectedTab.Address}" FontSize="10.5"
Foreground="{StaticResource TextDim}" VerticalAlignment="Center" />
</StackPanel>
<!--
Everything the vault has to say. Trimmed rather than wrapped, because this bar is one line high and
a message that grew it would move the whole window's contents up.
-->
<TextBlock Grid.Column="1" Classes="mono" Text="{Binding Vault.Status}" FontSize="10.5"
Foreground="{StaticResource TextDim}" VerticalAlignment="Center"
TextTrimming="CharacterEllipsis" />
</Grid>
</Border>
</UserControl>