Public Access
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.
98 lines
6.8 KiB
XML
98 lines
6.8 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.SessionStatusBar"
|
|
x:Name="Root"
|
|
x:DataType="vm:MainWindowViewModel">
|
|
|
|
<!--
|
|
── v5b's session shell status bar ───────────────────────────────────────────────────────────────────────
|
|
37px, DeepChrome, a 1px top border — the foot of the bordered container both the terminal and the SFTP
|
|
surface share. The design's own row also carries a negotiated cipher and a host-key-plus-identity run
|
|
(`ed25519 · acme-deploy-key`, clickable to a pin-details modal); both are now real and bound, plumbed all
|
|
the way from SSH.NET through TerminalWorkspace.GetSessionFacts and TransfersViewModel to
|
|
MainWindowViewModel's own surface-aware properties — see SessionCipher, SessionHostKeyAlgorithm,
|
|
SessionIdentityLabel and the composed SessionIdentityText.
|
|
|
|
Three honest deviations from the mock. The algorithm prints exactly as negotiated — "ssh-ed25519", not
|
|
the design's shortened "ed25519" — because trimming it would be a cosmetic edit to a string this client
|
|
did not choose. The run is plain text, not a button: this application has no pin-details modal for a
|
|
session that is already open, and drawing a click target for a screen that does not exist would be the
|
|
fabrication this project's honesty rule forbids, not an honest omission of one. And a typed-password
|
|
session — nothing filed in the keychain to name — shows the algorithm alone, with no " · " after it,
|
|
because there is no item behind the dot.
|
|
|
|
What is real and bound: the CONNECTED word and dot, off IsSessionConnected, shown only while there is a
|
|
session/host context to report on at all — SessionAddress null means nothing here has anything to say,
|
|
the same state the header answers with its own empty-state sentence; the cipher and the host-key/identity
|
|
run, each collapsed rather than shown empty or fabricated when the fact behind it is not there — a bucket
|
|
connection has neither, and a session whose facts could not be read back at the instant they were asked
|
|
for has neither either; the elapsed timer, off SessionElapsedText, which is null and therefore absent
|
|
whenever there is nothing timed; and, only on the terminal surface — see <see cref="ShowsEncoding"/> —
|
|
"UTF-8", which is a true fact about this client's own renderer and write path (see TerminalWorkspace's
|
|
terminal.js and SshShellSessionExtensions.WriteTextAsync) rather than a negotiated session parameter, and
|
|
is worded plainly rather than as a claim the remote agreed to it.
|
|
-->
|
|
|
|
<Border Height="37" Background="{StaticResource DeepChrome}"
|
|
BorderBrush="{StaticResource Border}" BorderThickness="0,1,0,0">
|
|
<Grid ColumnDefinitions="*,Auto" Margin="24,0">
|
|
|
|
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="18" VerticalAlignment="Center">
|
|
<StackPanel Orientation="Horizontal" Spacing="7" VerticalAlignment="Center"
|
|
IsVisible="{Binding SessionAddress, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
|
<Ellipse Classes="dot" Width="7" Height="7" Classes.live="{Binding IsSessionConnected}"
|
|
Classes.dropped="{Binding IsSessionDropped}"
|
|
VerticalAlignment="Center" />
|
|
|
|
<TextBlock FontFamily="Montserrat" FontWeight="SemiBold" FontSize="9.5" LetterSpacing="1.2"
|
|
VerticalAlignment="Center" Text="CONNECTED" Foreground="{StaticResource Live}"
|
|
IsVisible="{Binding IsSessionConnected}" />
|
|
|
|
<!--
|
|
Three words where there were two, and the third replaces rather than joins the second — see
|
|
MainWindowViewModel.IsSessionIdle, which is what keeps them from ever being drawn together.
|
|
NOT CONNECTED is honest about a tab still dialling and useless about one whose shell has
|
|
stopped: it says nothing about which of the two endings it was, and the difference between them
|
|
is the difference between work that is finished and a machine that stopped answering. The strip
|
|
below carries the sentence and the way back; this is the same fact in the one line that is
|
|
always on screen.
|
|
-->
|
|
<TextBlock FontFamily="Montserrat" FontWeight="SemiBold" FontSize="9.5" LetterSpacing="1.2"
|
|
VerticalAlignment="Center" Text="NOT CONNECTED" Foreground="{StaticResource TextFaint}"
|
|
IsVisible="{Binding IsSessionIdle}" />
|
|
<TextBlock FontFamily="Montserrat" FontWeight="SemiBold" FontSize="9.5" LetterSpacing="1.2"
|
|
VerticalAlignment="Center" Text="{Binding SessionEndedText}"
|
|
Foreground="{StaticResource TextFaint}"
|
|
IsVisible="{Binding SessionEndedText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
|
</StackPanel>
|
|
|
|
<TextBlock Classes="mono" FontSize="11.5" Foreground="{StaticResource TextGhost}"
|
|
VerticalAlignment="Center" Text="{Binding SessionCipher}"
|
|
IsVisible="{Binding SessionCipher, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
|
<TextBlock Classes="mono" FontSize="11.5" Foreground="{StaticResource TextGhost}"
|
|
VerticalAlignment="Center" Text="{Binding SessionIdentityText}"
|
|
IsVisible="{Binding SessionIdentityText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
|
</StackPanel>
|
|
|
|
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="18" VerticalAlignment="Center">
|
|
<!--
|
|
How many of the selected tab's forwards are listening, and nothing when none are. The terminal's
|
|
own, for the reason UTF-8 is: an SFTP connection runs no forwards.
|
|
-->
|
|
<TextBlock Classes="mono" FontSize="11.5" Foreground="{StaticResource TextGhost}"
|
|
VerticalAlignment="Center" Text="{Binding SelectedTab.ForwardsSummary}"
|
|
IsVisible="{Binding #Root.ShowsEncoding}" />
|
|
<TextBlock Classes="mono" FontSize="11.5" Foreground="{StaticResource TextGhost}"
|
|
VerticalAlignment="Center" Text="{Binding SessionElapsedText}"
|
|
IsVisible="{Binding SessionElapsedText, Converter={x:Static StringConverters.IsNotNullOrEmpty}}" />
|
|
<TextBlock Classes="mono" FontSize="11.5" Foreground="{StaticResource TextGhost}"
|
|
VerticalAlignment="Center" Text="UTF-8"
|
|
IsVisible="{Binding #Root.ShowsEncoding}" />
|
|
</StackPanel>
|
|
|
|
</Grid>
|
|
</Border>
|
|
|
|
</UserControl>
|