Public Access
DELETE on a host, an SSH key, a stored password or a file on the host now puts a question where the button was, and only answering it deletes anything. It is a state rather than a dialog, which is the arrangement signing out already had and for the same reason: this is the moment that has to be able to say what is about to go before it goes. What the question says is counted rather than generic, because a confirmation that only asks whether you are sure is a click to train people out of. A key names the hosts that authenticate with it and says they will refuse to connect afterwards rather than falling back to a typed password, which is what the connect path actually does. A host discloses a terminal open on it, because deleting the host does not close the session. Every vault deletion says how far it travels and whether this machine can push the tombstone yet or is queuing it. Deleting on the host carries the strongest warning of the four on purpose: everything else here is a tombstone against a copy the server still holds, and a file on somebody's machine is bytes with nothing behind them — so that one names the full path, since a bare name identifies nothing. The armed request carries the item's entity id, so nothing that moves the selection between the question and the answer can redirect it, and answering about something that has since gone says so instead of doing nothing quietly. Disarming compares ids rather than rows, which is the subtle half: a reload replaces every row object, so the naive rule would have let the pass that runs every minute take the card away from somebody halfway through reading it. Forgetting a pinned host key is deliberately still unguarded. It costs one fingerprint check on the next connection and it is the safe direction to be wrong in — the dangerous button there is the one that adds trust, and that one is already a prompt at connect time. Discarding a stopped transfer is likewise unguarded: it removes a resumable part file and leaves the source alone. Double-clicking a host in the sidebar connects to it, wired as a gesture in the control exactly as the transfers screen opens a directory. CONNECT stays, since it is the button with the password box beside it. Ten existing delete call sites now go through arm-and-confirm helpers, and eight new flow tests cover asking first, cancelling, the counted warning, disarming on a selection change and on an editor opening, surviving a sync, and the stale-item guard. Three layout tests measure the new shapes — the sidebar card is the one card in the application a user cannot scroll — and one of them also asserts the card renders its text, because a card whose compiled bindings did not resolve would lay out perfectly as empty rows. The double-click test performs the real gesture and proves it reached the connect command through a refusal that never touches a network. dotnet build, dotnet test and dotnet format --verify-no-changes are all clean: 853 tests, including the end-to-end suite against real containers.
53 lines
2.6 KiB
XML
53 lines
2.6 KiB
XML
<UserControl xmlns="https://github.com/avaloniaui"
|
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
xmlns:vm="using:DodoSSH.Client.App.ViewModels"
|
|
x:Class="DodoSSH.Client.App.Views.ConfirmDeleteCard"
|
|
x:DataType="vm:VaultViewModel">
|
|
|
|
<!--
|
|
The question in front of deleting something in the vault.
|
|
|
|
One control used in two places — the host sidebar, where it takes the place of the row of buttons that
|
|
opened it, and the vault screen's detail pane, where it takes the place of EDIT and DELETE. The two
|
|
moments are different and what has to be said is not, which is why this is a shared control rather than
|
|
two blocks that would drift apart. The sign-out confirmation is the same arrangement, for the same
|
|
reason; see SignOutCard.
|
|
|
|
A bare StackPanel and not a card, because the two hosts frame it themselves: the sidebar puts it in the
|
|
strip along its bottom edge, and the vault screen in a column that scrolls.
|
|
|
|
Everything it says is something the view model can answer. The question names the item, the consequence
|
|
knows whether this machine can push a tombstone yet, and the line in the box is a count of the hosts
|
|
that actually authenticate with the thing about to go — see VaultViewModel.HostsBoundTo. A confirmation
|
|
that only asked "are you sure?" would be a click to train people out of.
|
|
-->
|
|
|
|
<StackPanel Spacing="8">
|
|
|
|
<TextBlock Classes="heading" FontSize="13" TextWrapping="Wrap"
|
|
Text="{Binding PendingDeletion.Question}" />
|
|
|
|
<TextBlock Foreground="{StaticResource WarnText}" FontSize="11" TextWrapping="Wrap"
|
|
Text="{Binding PendingDeletion.Consequence}" />
|
|
|
|
<!--
|
|
What else in this vault leans on it. In a box of its own because it is the line that changes the
|
|
answer: everything above is true of every deletion, and this is about the one being made.
|
|
-->
|
|
<Border Background="{StaticResource Panel}" BorderBrush="{StaticResource Border}"
|
|
BorderThickness="1" CornerRadius="4" Padding="8,6"
|
|
IsVisible="{Binding PendingDeletion.HasUsage, FallbackValue=False}">
|
|
<TextBlock Foreground="{StaticResource Info}" FontSize="11" TextWrapping="Wrap"
|
|
Text="{Binding PendingDeletion.Usage}" />
|
|
</Border>
|
|
|
|
<StackPanel Orientation="Horizontal" Spacing="6">
|
|
<Button Classes="danger" Content="DELETE" Command="{Binding ConfirmDeleteCommand}"
|
|
IsEnabled="{Binding !IsBusy}" />
|
|
<Button Classes="ghost" Content="CANCEL" Command="{Binding CancelDeleteCommand}" />
|
|
</StackPanel>
|
|
|
|
</StackPanel>
|
|
|
|
</UserControl>
|