Desktop: show the right vault's people, leave settings on lock, say when an import fell short, and stop host names being cut to four letters
ci / build and test (push) Successful in 3m26s
ci / android head (push) Successful in 3m50s
ci / desktop nightly (push) Failing after 37s
ci / api image (push) Successful in 17s

- Choosing a vault while the screen was busy went through a gate that did nothing, so the members
  panel kept showing the previous vault's people under the new name. The read now starts regardless;
  the selection generation discards answers for an earlier choice.
- Locking or signing out from Settings left the window in settings mode under the lock card, with no
  title bar to drag, minimise or close, and unlock returned to Settings. Leaving the unlocked state
  leaves Settings and closes the members panel; Escape closes that panel before leaving Settings.
- Both importers reported success when the keychain was busy and skipped the batch, or failed partway.
  ImportOutcome now carries refused hosts and why a batch stopped, and the screens say so.
- Host cards: the sync badge took 70 of 214 pixels from the name ("bastion" drew as "bast…", two k8s
  workers both as "k8s…"); it now sits on the address line. Tag chips wrap and trim inside the card.
  Keychain names trim inside their column instead of printing over TYPE, and the Security page's
  caption wraps inside its card.
This commit is contained in:
jaap-jan committed 2026-10-02 13:16:55 +02:00
1 parent 0e8fe4fc80
commit a4b81da597
11 files changed
+314 -68

No files matched your search

+28 -12
View File
@@ -683,7 +683,7 @@
TextTrimming never fires and the name would run on past the card's own
border instead of trimming. See the longer note this carried in v4.
-->
<Grid ColumnDefinitions="*,Auto,Auto">
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Text="{Binding Label}" FontSize="17"
FontWeight="Bold" Foreground="{StaticResource Text}"
TextTrimming="CharacterEllipsis" />
@@ -708,17 +708,27 @@
<Ellipse Classes="dot" Classes.live="{Binding IsConnected}"
Width="9" Height="9" />
</StackPanel>
</Grid>
<Border Grid.Column="2" Classes="chip warn" Padding="4,0" Margin="6,0,0,0"
<!--
"not synced" and its kin sit on the address line. Beside the name, where it
used to be, it took seventy of the card's pixels from the one thing a card
is read for: "bastion" drew as "bast…", and k8s-worker-a and k8s-worker-b
both drew as "k8s…". The address can give the room up — it trims, and the
tooltip and the drawer both carry it whole.
-->
<Grid ColumnDefinitions="*,Auto">
<TextBlock Grid.Column="0" Classes="mono" Text="{Binding Address}" FontSize="12.5"
Foreground="{StaticResource TextGhost}"
TextTrimming="CharacterEllipsis" />
<Border Grid.Column="1" Classes="chip warn" Padding="4,0" Margin="6,0,0,0"
VerticalAlignment="Center"
IsVisible="{Binding Badge, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
<TextBlock Text="{Binding Badge}" FontSize="9.5" />
</Border>
</Grid>
<TextBlock Classes="mono" Text="{Binding Address}" FontSize="12.5"
Foreground="{StaticResource TextGhost}"
TextTrimming="CharacterEllipsis" />
<!--
Which vault this host is in, and only when there is more than one to be
in. It decides who else can see the host and where an edit goes back to,
@@ -734,8 +744,13 @@
<Grid Grid.Row="2" ColumnDefinitions="*,Auto" VerticalAlignment="Bottom"
Margin="0,8,0,0">
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="4"
VerticalAlignment="Bottom">
<!--
A DockPanel rather than a horizontal StackPanel. A horizontal StackPanel
measures its children with infinite width, so the tags' WrapPanel below
never wrapped and ran past the card's edge; the last child of a DockPanel
gets the width that is actually left, and wraps in it.
-->
<DockPanel Grid.Column="0" VerticalAlignment="Bottom">
<!--
The pin badge: how many folders are pinned on this host, reading
@@ -743,8 +758,8 @@
property's own remarks. Only when there is at least one; a badge reading
zero would be a fact nobody asked for.
-->
<Border Classes="chip" Height="19" CornerRadius="5" Padding="6,2"
IsVisible="{Binding HasPins}">
<Border DockPanel.Dock="Left" Classes="chip" Height="19" CornerRadius="5"
Padding="6,2" Margin="0,0,4,4" IsVisible="{Binding HasPins}">
<StackPanel Orientation="Horizontal" Spacing="3">
<TextBlock Text="&#xF10D;" FontFamily="{StaticResource IconFont}"
FontSize="11" Foreground="{StaticResource TextFaint}" />
@@ -767,12 +782,13 @@
<Border Classes="chip" Height="21" CornerRadius="5" Padding="6,2"
Margin="0,0,4,4">
<TextBlock Text="{Binding}" FontSize="11"
Foreground="{StaticResource TextFaint}" />
Foreground="{StaticResource TextFaint}"
TextTrimming="CharacterEllipsis" />
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel>
</DockPanel>
<!--
HostRowViewModel.LastConnectedText is filled from the connection log on
@@ -275,7 +275,7 @@
item this application stores carries a timestamp; see the file-level remark above and
docs/design-import-gaps.md.
-->
<Grid Grid.Row="1" ColumnDefinitions="2,2.2*,1*,1*,1.4*" Margin="0,10,16,6"
<Grid Grid.Row="1" ColumnDefinitions="2,3*,1.1*,0.9*,1.2*" Margin="0,10,16,6"
IsVisible="{Binding HasVaultItems}">
<TextBlock Grid.Column="1" Classes="label" Text="NAME" FontSize="9.5" LetterSpacing="1"
Margin="12,0,8,0" />
@@ -290,17 +290,23 @@
Margin="8,0,8,10">
<ListBox.ItemTemplate>
<DataTemplate x:DataType="vm:VaultItemRowViewModel">
<Grid ColumnDefinitions="2,2.2*,1*,1*,1.4*" Height="40" Margin="6,0,10,0">
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="10" Margin="10,0,8,0"
VerticalAlignment="Center">
<TextBlock FontFamily="{StaticResource IconFont}" FontSize="15"
<Grid ColumnDefinitions="2,3*,1.1*,0.9*,1.2*" Height="40" Margin="6,0,10,0">
<!--
A Grid rather than a horizontal StackPanel: the StackPanel measured the name with infinite
width, so TextTrimming never fired and a long name printed over the TYPE and USED BY
columns beside it.
-->
<Grid Grid.Column="1" ColumnDefinitions="Auto,*" Margin="10,0,8,0" VerticalAlignment="Center">
<TextBlock Grid.Column="0" FontFamily="{StaticResource IconFont}" FontSize="15"
Text="{Binding IconGlyph}" Foreground="{StaticResource AccentText}"
VerticalAlignment="Center" />
<TextBlock Classes="mono" Text="{Binding Name}" FontSize="12.5" FontWeight="Medium"
Foreground="{StaticResource Text}" TextTrimming="CharacterEllipsis" />
</StackPanel>
VerticalAlignment="Center" Margin="0,0,10,0" />
<TextBlock Grid.Column="1" Classes="mono" Text="{Binding Name}" FontSize="12.5"
FontWeight="Medium" Foreground="{StaticResource Text}"
TextTrimming="CharacterEllipsis" ToolTip.Tip="{Binding Name}" />
</Grid>
<TextBlock Grid.Column="2" Classes="mono" Text="{Binding Type}" FontSize="10.5"
Foreground="{StaticResource TextGhost}" VerticalAlignment="Center" />
Foreground="{StaticResource TextGhost}" VerticalAlignment="Center"
TextTrimming="CharacterEllipsis" />
<Border Grid.Column="3" Classes="chip" HorizontalAlignment="Left"
VerticalAlignment="Center" IsVisible="{Binding HasVaultBadge}">
<TextBlock Text="{Binding VaultBadge}" FontSize="10" />
@@ -244,6 +244,13 @@ internal sealed partial class MainWindow : Window
viewModel.CloseImportCommand.Execute(null);
e.Handled = true;
}
// The members dialog on Settings → Vaults, by the same rule: it is drawn over the page, so it goes
// first and settings stays.
else if (e.Key == Key.Escape && viewModel.IsSettingsMode && viewModel.Vaults.IsMembersPanelOpen)
{
viewModel.Vaults.CloseMembersPanelCommand.Execute(null);
e.Handled = true;
}
else if (e.Key == Key.Escape && viewModel.IsSettingsMode)
{
viewModel.LeaveSettingsCommand.Execute(null);
@@ -46,19 +46,21 @@
<TextBlock Classes="settingstitle" Text="Security" />
<Border Classes="settingscard" Margin="0,26,0,0" Padding="20,20">
<StackPanel Orientation="Horizontal" Spacing="16">
<Border Width="44" Height="44" CornerRadius="12" Background="#103A2F">
<!-- A Grid, so the caption is measured against the card's width and wraps inside it. -->
<Grid ColumnDefinitions="Auto,*">
<Border Grid.Column="0" Width="44" Height="44" CornerRadius="12" Background="#103A2F"
Margin="0,0,16,0" VerticalAlignment="Top">
<TextBlock FontFamily="{StaticResource IconFont}" Text="&#xE897;" FontSize="20"
Foreground="{StaticResource Live}"
HorizontalAlignment="Center" VerticalAlignment="Center" />
</Border>
<StackPanel Spacing="6" VerticalAlignment="Center">
<StackPanel Grid.Column="1" Spacing="6" VerticalAlignment="Center">
<TextBlock Text="End-to-end encrypted" FontSize="15" FontWeight="Bold" LetterSpacing="-0.2"
Foreground="{StaticResource Text}" />
<TextBlock Classes="settingsrowcaption"
<TextBlock Classes="settingsrowcaption" TextWrapping="Wrap"
Text="Every vault item is sealed on your devices. The server and the relay both store ciphertext and timestamps only — neither can read a single field." />
</StackPanel>
</StackPanel>
</Grid>
</Border>
<TextBlock Classes="settingssection" Text="UNLOCKING" />