Public Access
Merge branch 'main' into the desktop updater, and give way on two numbers
Main landed a realtime push feature while this branch was building the updater, and the two collided in three places. Every one of them resolves the same way: main got there first, so this branch moves. **Two ADRs were both numbered 0012.** Main's is realtime push; this one is now [ADR 0013](docs/adr/0013-desktop-distribution-and-updates.md). Git did not call this a conflict — the filenames differ — so it would have merged quietly and left the directory with two 0012s and every cross-reference ambiguous. Renumbered here along with the nine places that point at it. **Two manual-check phases were both numbered 15**, and that one git did catch. Main's "Changes that arrive without a timer" keeps 15; installing and updating the desktop client becomes Phase 16, with its checks and every reference to them renumbered. The file's own rule is that a number is for life, which is exactly why the one that had not been pushed is the one that gives way. **The merge rewrote several files with CRLF**, and `.editorconfig` asks for LF on everything except `*.ps1`. That is not cosmetic here: IDE0055 is an error and `EnforceCodeStyleInBuild` is on, so it failed the build on three lines of App.axaml.cs whose only change in this branch was an ADR number in a comment. Forty-six files normalised back to LF; the release script keeps CRLF, which is what `.gitattributes` and `.editorconfig` both already say for a PowerShell file. Nothing else conflicted. The updater does not touch the sync loop or the event stream, and the one file both sides edited heavily — MainWindowViewModel — merged without a hunk in common. Verified after merging: the solution restores locked and builds clean, and 304 shell, 100 layout, 54 session, 28 client-api and 25 contracts tests pass. The first two counts are higher than before the merge because main's own tests came with it and pass alongside these.
This commit is contained in:
@@ -125,7 +125,21 @@
|
||||
<DataTemplate DataType="vm:SidebarGroupHeader">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto,Auto" Margin="8,12,8,5">
|
||||
<TextBlock Grid.Column="0" Classes="detail" Text="{Binding Chevron}" VerticalAlignment="Center" />
|
||||
<TextBlock Grid.Column="1" Classes="section" Text="{Binding Label}" Margin="7,0,0,0" />
|
||||
|
||||
<!--
|
||||
The name, and the vault it is in where this session holds more than one. The badge is what
|
||||
makes one heading per group survive a shared vault: two vaults may each hold a "production",
|
||||
and this list has no nesting to tell the two apart with. Drawn as the same outline tag a host
|
||||
row wears, so "which vault" looks the same wherever it is answered.
|
||||
-->
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Spacing="6" Margin="7,0,0,0">
|
||||
<TextBlock Classes="section" Text="{Binding Label}" TextTrimming="CharacterEllipsis" />
|
||||
<Border Classes="tag outline" VerticalAlignment="Center"
|
||||
IsVisible="{Binding HasVaultBadge}">
|
||||
<TextBlock Text="{Binding VaultBadge}" />
|
||||
</Border>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="2" Classes="detail" Text="{Binding Count}" FontSize="9"
|
||||
VerticalAlignment="Center" />
|
||||
|
||||
@@ -262,10 +276,12 @@
|
||||
|
||||
<!--
|
||||
◆ WHICH VAULT THIS HOST WILL LIVE IN. Drawn only while adding and only where there is more than
|
||||
one vault that can be written to, exactly as on the desktop — an existing host's vault cannot
|
||||
change, because the two are encrypted under different keys and moving an item is a delete and a
|
||||
retype. Above GROUP rather than below it because it decides what GROUP can offer: a group is an
|
||||
item in one vault, so choosing a vault refills that list with that vault's groups.
|
||||
one vault that can be written to, exactly as on the desktop — an existing host's vault is not a
|
||||
field of this form, because the two are encrypted under different keys and changing it is a
|
||||
re-seal into one vault and a tombstone in the other. That is MOVE, beside EDIT under the host,
|
||||
and it is separate so that it cannot happen as a side effect of saving something else. Above
|
||||
GROUP rather than below it because it decides what GROUP can offer: a group is an item in one
|
||||
vault, so choosing a vault refills that list with that vault's groups.
|
||||
-->
|
||||
<StackPanel Spacing="6" IsVisible="{Binding ShowsEditorVaultChoice}">
|
||||
<TextBlock Classes="label" Text="VAULT" Margin="0,4,0,0" />
|
||||
@@ -279,7 +295,7 @@
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Classes="body"
|
||||
Text="A host in a shared vault is readable by everybody holding that vault's key, and it cannot be moved out afterwards." />
|
||||
Text="A host in a shared vault is readable by everybody holding that vault's key. It can be moved out later, with MOVE under the host — what it cannot do is become unreadable to somebody who has already synced it." />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Classes="label" Text="GROUP" Margin="0,4,0,0" />
|
||||
@@ -367,6 +383,27 @@
|
||||
|
||||
<TextBox Classes="field" Text="{Binding GroupEditorLabel}" PlaceholderText="group name" />
|
||||
|
||||
<!--
|
||||
◆ WHICH VAULT THIS GROUP WILL LIVE IN, on the same terms as the host editor's picker above and
|
||||
for the same reason: it is what makes the group shared, and it cannot be changed afterwards.
|
||||
Above INSIDE because it decides what INSIDE can offer — a parent belongs to one vault, and one
|
||||
from another is a level half the readers cannot resolve.
|
||||
-->
|
||||
<StackPanel Spacing="6" IsVisible="{Binding ShowsGroupEditorVaultChoice}">
|
||||
<TextBlock Classes="label" Text="VAULT" Margin="0,4,0,0" />
|
||||
<ComboBox ItemsSource="{Binding GroupEditorVaultChoices}"
|
||||
SelectedItem="{Binding GroupEditorSelectedVault}"
|
||||
HorizontalAlignment="Stretch" MinHeight="44">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:VaultChoiceViewModel">
|
||||
<TextBlock Classes="mono" FontSize="12" Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Classes="body"
|
||||
Text="A group in a shared vault is visible to everybody holding that vault's key, and only hosts in the same vault can be filed under it." />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Classes="label" Text="INSIDE" Margin="0,4,0,0" />
|
||||
<ComboBox ItemsSource="{Binding GroupEditorParentChoices}"
|
||||
SelectedItem="{Binding GroupEditorSelectedParent}"
|
||||
@@ -432,45 +469,97 @@
|
||||
BorderThickness="0,1,0,0" Padding="14,12">
|
||||
<StackPanel Spacing="10">
|
||||
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Classes="label" Text="CONNECT TO" />
|
||||
<TextBlock Classes="mono" FontSize="11" Text="{Binding SelectedHost.Label}" />
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
Shown only for a host that actually asks for one. A password box beside a key-authenticated host
|
||||
is an invitation to type a secret nothing will use.
|
||||
|
||||
The tick below it is the phone's whole answer to storing one, and on this head it is the only one:
|
||||
the keychain lists credentials here but has no editor to create one in, so before this a password
|
||||
typed on a phone could only ever be typed again. The host editor's picker could then bind it.
|
||||
Everything about connecting, in one group so that the move panel below can take the bar rather
|
||||
than appear underneath it. A password box and a CONNECT button under a form asking which vault to
|
||||
move the host into would be two unrelated questions in one bar, and the taller of the two would
|
||||
push the other off a phone screen.
|
||||
-->
|
||||
<TextBox Classes="field secret" IsVisible="{Binding SelectedHostAsksForAPassword}"
|
||||
Text="{Binding ConnectPassword}" PlaceholderText="password">
|
||||
<TextBox.KeyBindings>
|
||||
<KeyBinding Gesture="Enter" Command="{Binding ConnectCommand}" />
|
||||
</TextBox.KeyBindings>
|
||||
</TextBox>
|
||||
<StackPanel Spacing="10" IsVisible="{Binding !IsMovingHost}">
|
||||
|
||||
<CheckBox IsChecked="{Binding RemembersConnectPassword}" MinHeight="44"
|
||||
IsVisible="{Binding SelectedHostAsksForAPassword}">
|
||||
<TextBlock Classes="mono" FontSize="11.5" TextWrapping="Wrap"
|
||||
Text="Remember this password for this host" />
|
||||
</CheckBox>
|
||||
<StackPanel Orientation="Horizontal" Spacing="8">
|
||||
<TextBlock Classes="label" Text="CONNECT TO" />
|
||||
<TextBlock Classes="mono" FontSize="11" Text="{Binding SelectedHost.Label}" />
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Classes="detail" TextWrapping="Wrap" IsVisible="{Binding !SelectedHostAsksForAPassword}"
|
||||
Text="{Binding SelectedHostAuthenticationNote}" />
|
||||
<!--
|
||||
Shown only for a host that actually asks for one. A password box beside a key-authenticated host
|
||||
is an invitation to type a secret nothing will use.
|
||||
|
||||
<Button Classes="primary" Content="CONNECT" Command="{Binding ConnectCommand}"
|
||||
IsEnabled="{Binding !IsBusy}" />
|
||||
The tick below it is the phone's whole answer to storing one, and on this head it is the only
|
||||
one: the keychain lists credentials here but has no editor to create one in, so before this a
|
||||
password typed on a phone could only ever be typed again. The host editor's picker could then
|
||||
bind it.
|
||||
-->
|
||||
<TextBox Classes="field secret" IsVisible="{Binding SelectedHostAsksForAPassword}"
|
||||
Text="{Binding ConnectPassword}" PlaceholderText="password">
|
||||
<TextBox.KeyBindings>
|
||||
<KeyBinding Gesture="Enter" Command="{Binding ConnectCommand}" />
|
||||
</TextBox.KeyBindings>
|
||||
</TextBox>
|
||||
|
||||
<CheckBox IsChecked="{Binding RemembersConnectPassword}" MinHeight="44"
|
||||
IsVisible="{Binding SelectedHostAsksForAPassword}">
|
||||
<TextBlock Classes="mono" FontSize="11.5" TextWrapping="Wrap"
|
||||
Text="Remember this password for this host" />
|
||||
</CheckBox>
|
||||
|
||||
<TextBlock Classes="detail" TextWrapping="Wrap"
|
||||
IsVisible="{Binding !SelectedHostAsksForAPassword}"
|
||||
Text="{Binding SelectedHostAuthenticationNote}" />
|
||||
|
||||
<Button Classes="primary" Content="CONNECT" Command="{Binding ConnectCommand}"
|
||||
IsEnabled="{Binding !IsBusy}" />
|
||||
</StackPanel>
|
||||
|
||||
<!--
|
||||
Not asked for by the design, and here because a + that adds hosts with no way to correct one is a
|
||||
strange thing to ship. It costs nothing: the editor above serves both, so this is the same panel
|
||||
opened on an existing row.
|
||||
|
||||
MOVE is beside it rather than inside it, and that is the same line the desktop's menu draws: which
|
||||
vault a host is in is not a field of the host. The two vaults are encrypted under different keys,
|
||||
so it is a re-seal into one and a tombstone in the other — nothing a SAVE could do. It shows only
|
||||
where there is somewhere to move to; see VaultViewModel.CanMoveSelectedHost.
|
||||
-->
|
||||
<Button Classes="secondary" Height="44" Content="EDIT"
|
||||
Command="{Binding EditSelectedHostCommand}" />
|
||||
<Grid ColumnDefinitions="*,8,*" IsVisible="{Binding !IsMovingHost}">
|
||||
<Button Grid.Column="0" Classes="secondary" Height="44" Content="EDIT"
|
||||
Command="{Binding EditSelectedHostCommand}" />
|
||||
<Button Grid.Column="2" Classes="secondary" Height="44" Content="MOVE"
|
||||
IsVisible="{Binding CanMoveSelectedHost}"
|
||||
Command="{Binding MoveHostCommand}" />
|
||||
</Grid>
|
||||
|
||||
<!--
|
||||
◆ MOVING THE HOST TO ANOTHER VAULT, in the place the connect controls were. A picker and two
|
||||
buttons rather than a question with a yes: what is being asked is which vault, and a move is
|
||||
undone by moving it back.
|
||||
|
||||
The sentence is not decoration. A group and a tag are items of the vault the host is leaving, so
|
||||
neither can come with it — and on a phone, where the status line afterwards is one line at the
|
||||
bottom of a screen somebody has already navigated away from, saying it before the tap is the only
|
||||
place it reliably gets read.
|
||||
-->
|
||||
<StackPanel Spacing="10" IsVisible="{Binding IsMovingHost}">
|
||||
<TextBlock Classes="label" Text="MOVE TO VAULT" />
|
||||
<ComboBox HorizontalAlignment="Stretch" MinHeight="44"
|
||||
ItemsSource="{Binding MoveVaultChoices}"
|
||||
SelectedItem="{Binding SelectedMoveVault}">
|
||||
<ComboBox.ItemTemplate>
|
||||
<DataTemplate x:DataType="vm:VaultChoiceViewModel">
|
||||
<TextBlock Classes="mono" FontSize="12" Text="{Binding Display}" />
|
||||
</DataTemplate>
|
||||
</ComboBox.ItemTemplate>
|
||||
</ComboBox>
|
||||
<TextBlock Classes="body"
|
||||
Text="The host is re-encrypted with the other vault's key, so everybody who holds that key can read it and nobody else can. Its group and tags stay behind — both belong to the vault it is leaving." />
|
||||
<Grid ColumnDefinitions="*,8,*">
|
||||
<Button Grid.Column="0" Classes="primary" Height="44" Content="MOVE"
|
||||
Command="{Binding ConfirmMoveHostCommand}" IsEnabled="{Binding !IsBusy}" />
|
||||
<Button Grid.Column="2" Classes="secondary" Height="44" Content="CANCEL"
|
||||
Command="{Binding CancelMoveHostCommand}" />
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user