Public Access
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
de0b5f12ae | ||
|
|
009b35e069 |
@@ -984,10 +984,12 @@ across that line would leave everyone else in the shared vault seeing a machine
|
||||
|
||||
**Failure means:** the set's write is `ChangingTheGroupOfTheChosenHosts_FilesThemAllAtOnce` again — one
|
||||
command reads the whole set, so "filed one of three" has no half-gesture to hide in the way the old drag's
|
||||
payload did. The refusal, though, is asserted by **nothing automated at all**: `VaultViewModel.RegroupChosenHosts`
|
||||
counts the distinct vaults and no test raises it, so this check is the only thing between that sentence and
|
||||
silence. A panel that does open over a mixed set is the worse half — it would offer one keychain's groups
|
||||
for another keychain's machines, which is the half-filed set the refusal exists to prevent.
|
||||
payload did. The refusal is covered headlessly too:
|
||||
`RegroupingHostsChosenAcrossTwoKeychains_IsRefusedBeforeThePickerOpens` ticks a host in each of two
|
||||
keychains and asserts no picker opens and the sentence is on the status line. What is left for the eye is
|
||||
7.9's wiring, as in 7.6 — and a panel that does open over a mixed set is the worse half: it would offer one
|
||||
keychain's groups for another keychain's machines, which is the half-filed set the refusal exists to
|
||||
prevent.
|
||||
|
||||
### 7.7 A click still selects, and a double click still connects
|
||||
|
||||
|
||||
@@ -177,16 +177,27 @@
|
||||
thing (go to the parent directory), and the pair reading differently is the design's own choice
|
||||
faithfully carried over rather than a functional difference invented to justify it.
|
||||
-->
|
||||
<!--
|
||||
◆ THE PATH SITS IN THE STAR COLUMN, ALONE, AND THAT PLACEMENT IS LOAD-BEARING.
|
||||
|
||||
TextTrimming only acts when measure hands the block a finite width, and a horizontal StackPanel
|
||||
never does — it measures every child at infinity, takes the full answer, and an Auto grid column
|
||||
passes that on. With the path in a StackPanel beside the label, a directory deep enough — the
|
||||
remote pane meets one on any real host, this pane on any machine whose profile path is long —
|
||||
made the header wider than the pane and pushed the icon buttons past the window's own edge. The
|
||||
layout suite caught it at the 472-pixel session budget, on the one machine whose home directory
|
||||
was long enough to arm it. Star column: bounded width, working ellipsis, buttons that stay.
|
||||
-->
|
||||
<Border Grid.Row="0" Padding="0,0,0,10" BorderThickness="0">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="12" VerticalAlignment="Center">
|
||||
<TextBlock Classes="label" FontSize="10" Text="LOCAL" VerticalAlignment="Center" />
|
||||
<TextBlock Classes="mono" FontSize="13.5" FontWeight="Medium"
|
||||
Foreground="{StaticResource TextDim}" VerticalAlignment="Center"
|
||||
Text="{Binding LocalPath}" TextTrimming="CharacterEllipsis"
|
||||
ToolTip.Tip="{Binding LocalPath}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4">
|
||||
<TextBlock Grid.Column="0" Classes="label" FontSize="10" Text="LOCAL"
|
||||
VerticalAlignment="Center" Margin="0,0,12,0" />
|
||||
<TextBlock Grid.Column="1" Classes="mono" FontSize="13.5" FontWeight="Medium"
|
||||
Foreground="{StaticResource TextDim}" VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding LocalPath}" TextTrimming="CharacterEllipsis"
|
||||
ToolTip.Tip="{Binding LocalPath}" />
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="12,0,0,0">
|
||||
<!--
|
||||
The drives, because the breadcrumb cannot reach them: above C:\ is a list rather than a
|
||||
directory. Without this the pane is stuck on whichever drive the user profile is on. Chips
|
||||
@@ -332,19 +343,26 @@
|
||||
UP is arrow_downward here, matching arrow_upward on the local pane above per the design's own two
|
||||
distinct glyphs; see that pane's own remark on why the pair differs without the actions differing.
|
||||
-->
|
||||
<!--
|
||||
The path is alone in the star column for the reason the local pane's header remark spells out:
|
||||
TextTrimming needs the finite width only a star column gives it, and this is the pane where the
|
||||
long path is not even unusual — it is any host with a deep directory tree.
|
||||
-->
|
||||
<Border Grid.Row="0" Padding="0,0,0,10" BorderThickness="0">
|
||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="12" VerticalAlignment="Center">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Spacing="12" VerticalAlignment="Center"
|
||||
Margin="0,0,12,0">
|
||||
<TextBlock Classes="label" FontSize="10" Text="HOST" VerticalAlignment="Center"
|
||||
IsVisible="{Binding ShowsHostPicker}" />
|
||||
<TextBlock Classes="label" FontSize="10" Text="BUCKET" VerticalAlignment="Center"
|
||||
IsVisible="{Binding ShowsBucketPicker}" />
|
||||
<TextBlock Classes="mono" FontSize="13.5" FontWeight="Medium"
|
||||
Foreground="{StaticResource TextDim}" VerticalAlignment="Center"
|
||||
Text="{Binding RemotePath}" TextTrimming="CharacterEllipsis"
|
||||
ToolTip.Tip="{Binding RemotePath}" />
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4">
|
||||
<TextBlock Grid.Column="1" Classes="mono" FontSize="13.5" FontWeight="Medium"
|
||||
Foreground="{StaticResource TextDim}" VerticalAlignment="Center"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding RemotePath}" TextTrimming="CharacterEllipsis"
|
||||
ToolTip.Tip="{Binding RemotePath}" />
|
||||
<StackPanel Grid.Column="2" Orientation="Horizontal" Spacing="4" Margin="12,0,0,0">
|
||||
<Button Classes="paneicon" Command="{Binding RemoteUpCommand}"
|
||||
IsEnabled="{Binding IsConnected}" ToolTip.Tip="Up one directory">
|
||||
<TextBlock FontFamily="{StaticResource IconFont}" FontSize="16" Text="" />
|
||||
|
||||
@@ -1481,17 +1481,29 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The narrowest real shape wave C's restyle has to survive at once: connected, so QUICK ACCESS's own
|
||||
/// sidebar takes its 300 pixels — see <see cref="LayoutHarness.SessionScreenWidth"/> — a populated remote
|
||||
/// listing carrying every colour state a row can show (a directory, an executable, a world-writable
|
||||
/// file), and a full transfer queue underneath, all inside the 204-pixel-a-side budget that leaves either
|
||||
/// pane.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Both pane headers carry a deep path on purpose, and the paths are set here rather than left to the
|
||||
/// fixture's real filesystem. The header's ellipsis only works because the path sits alone in a star
|
||||
/// column — see the pane header remark in <c>TransfersScreen.axaml</c> — and the regression it guards
|
||||
/// against armed itself only on a machine whose home directory happened to be long: CI's per-job HOME
|
||||
/// found it, every developer machine's short profile path missed it. A pinned sixty-character path asks
|
||||
/// the question on every machine alike.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheRestyledPanesFitTheSessionShellsNarrowestBudget()
|
||||
{
|
||||
transfers.IsConnected = true;
|
||||
transfers.ConnectedTo = "deployment-service@releases.eu-west.internal.example:2222";
|
||||
transfers.LocalPath = "/home/deployment-service/.cache/build/workspaces/site/artefacts";
|
||||
transfers.RemotePath = "/srv/releases/site/shared/uploads/production/2026/08/nightly";
|
||||
|
||||
transfers.RemoteEntries.Add(new RemoteEntryRowViewModel(new SftpEntry(
|
||||
"docker-compose.yml", "/srv/releases/site/docker-compose.yml", SftpEntryKind.File,
|
||||
|
||||
@@ -5845,6 +5845,60 @@ public sealed class ShellFlowTests : IAsyncLifetime
|
||||
Host(vault, "staging").Host.GroupId.ShouldBeNull("it was never ticked");
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The other refusal at the same door, and the one that needs two keychains to raise: a group is an
|
||||
/// item of one vault, so filing a mixed set under it would leave everyone else in the shared vault
|
||||
/// seeing a machine filed under nothing. Checked when the picker is asked for and over the whole set —
|
||||
/// see <see cref="VaultViewModel.RegroupChosenHosts"/> — rather than once per host mid-write, which is
|
||||
/// why no panel opens at all and the status line's sentence has to carry the whole explanation.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task RegroupingHostsChosenAcrossTwoKeychains_IsRefusedBeforeThePickerOpens()
|
||||
{
|
||||
await UnlockedAsync();
|
||||
|
||||
var vaults = shell.Vaults;
|
||||
|
||||
await vaults.LoadAsync(Token);
|
||||
|
||||
vaults.NewVaultCommand.Execute(null);
|
||||
vaults.NewVaultName = "Platform secrets";
|
||||
|
||||
await vaults.CreateVaultCommand.ExecuteAsync(null);
|
||||
|
||||
var vault = shell.Vault!;
|
||||
var sharedVaultId = vaults.SelectedVault!.VaultId;
|
||||
|
||||
await vault.LoadAsync(Token);
|
||||
|
||||
await AddHostAsync(vault, "prod-db");
|
||||
|
||||
vault.NewHostCommand.Execute(null);
|
||||
vault.EditorSelectedVault =
|
||||
vault.EditorVaultChoices.Single(choice => choice.VaultId == sharedVaultId);
|
||||
vault.EditorLabel = "prod-web";
|
||||
vault.EditorHostname = "web.internal";
|
||||
|
||||
await vault.SaveHostCommand.ExecuteAsync(null);
|
||||
|
||||
vault.ChooseHostCommand.Execute(Host(vault, "prod-db"));
|
||||
vault.ToggleHostChoiceCommand.Execute(Host(vault, "prod-web"));
|
||||
|
||||
vault.RegroupChosenHostsCommand.Execute(null);
|
||||
|
||||
vault.IsRegroupingChosenHosts.ShouldBeFalse("a group belongs to one keychain");
|
||||
vault.Status.ShouldStartWith("These hosts are in more than one keychain");
|
||||
vault.IsChoosingHosts.ShouldBeTrue("the set was refused, not dissolved");
|
||||
|
||||
// Unticking the visitor is all it takes: the refusal is about the set, not a latch the screen has
|
||||
// to be talked out of.
|
||||
vault.ToggleHostChoiceCommand.Execute(Host(vault, "prod-web"));
|
||||
|
||||
vault.RegroupChosenHostsCommand.Execute(null);
|
||||
|
||||
vault.IsRegroupingChosenHosts.ShouldBeTrue(vault.Status);
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// Duplicating keeps the group and the tags, which is the whole difference between it and a copy into
|
||||
/// another vault: the copy stays in the same keychain, so everything it points at is still there.
|
||||
|
||||
Reference in New Issue
Block a user