Public Access
Merge branch 'claude/host-detail-pane-design-e98621'
This commit is contained in:
@@ -346,6 +346,70 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
vault.GroupTrail.Select(crumb => crumb.Name).ShouldBe(["ALL HOSTS", "estate"]);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Choosing a host costs nothing, and the pencil on its card is what spends the 304 pixels.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The two halves are one rule and are asserted together, because either alone would pass on a broken
|
||||
/// version: a drawer that never opens satisfies the first, and one that opens on selection satisfies the
|
||||
/// second. What is being held is that opening is <em>deliberate</em>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Driven through the card's own button rather than by executing the command, since the thing most
|
||||
/// likely to rot is the binding that reaches out of the item template to the vault's command — a
|
||||
/// <c>$parent[ListBox]</c> path that resolves to nothing compiles, draws, and does nothing when pressed.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheDrawerOpensOnThePencilRatherThanOnTheSelection()
|
||||
{
|
||||
await OnTheGridAsync((screen, _) =>
|
||||
{
|
||||
var host = Row(vault, "stage-web");
|
||||
|
||||
vault.SelectedHost = host;
|
||||
|
||||
vault.IsDrawerOpen.ShouldBeFalse("selecting a card is not asking for the pane");
|
||||
|
||||
// The button is hidden until the pointer is on the card, so a click cannot be synthesised at a
|
||||
// point: what a headless run can reach is the control and the command behind it.
|
||||
var pencil = CardFor(screen, host)
|
||||
.GetVisualDescendants()
|
||||
.OfType<Button>()
|
||||
.First(button => button.Classes.Contains("rowedit"));
|
||||
|
||||
pencil.Command.ShouldNotBeNull("the template's binding to the vault's command has to resolve");
|
||||
pencil.Command.Execute(pencil.CommandParameter);
|
||||
|
||||
vault.IsDrawerOpen.ShouldBeTrue();
|
||||
vault.IsShowingHostDetail.ShouldBeTrue("the pane, not one of the two editors");
|
||||
vault.SelectedHost.ShouldBeSameAs(host, "the card the pencil was on");
|
||||
});
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// The pane follows the selection once it is open — see <c>VaultViewModel.IsHostPaneOpen</c> — but a
|
||||
/// selection that goes away entirely has to take it with it. Without that the flag would survive a
|
||||
/// filter matching nothing, and the drawer would spring open again on the next card merely selected,
|
||||
/// which is the behaviour the pencil exists to remove.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task LosingTheSelectionClosesTheDrawerAndDoesNotArmItAgain()
|
||||
{
|
||||
await OnTheGridAsync((_, _) =>
|
||||
{
|
||||
vault.OpenHostPaneCommand.Execute(Row(vault, "prod-db"));
|
||||
vault.IsDrawerOpen.ShouldBeTrue();
|
||||
|
||||
vault.SelectedHost = null;
|
||||
vault.IsDrawerOpen.ShouldBeFalse();
|
||||
|
||||
vault.SelectedHost = Row(vault, "stage-web");
|
||||
vault.IsDrawerOpen.ShouldBeFalse("the pane has to be asked for again");
|
||||
});
|
||||
}
|
||||
|
||||
// ---- Helpers ----
|
||||
|
||||
/// <summary>The same in-process format the screen's own drag carries.</summary>
|
||||
|
||||
@@ -143,10 +143,17 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
// and lost the list; see HostDrawer. What it is measured at changed with it: 304 rather than 268, and on
|
||||
// the right.
|
||||
|
||||
/// <remarks>
|
||||
/// Opened through the command rather than by assigning the selection, which is the whole of what changed
|
||||
/// when the pencil arrived: a selected host no longer puts the pane up, so a test that only selected one
|
||||
/// would measure a drawer with all three panels collapsed and pass on an empty column. See
|
||||
/// <c>VaultViewModel.IsHostPaneOpen</c>.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheHostDrawerFitsShowingAHost()
|
||||
{
|
||||
vault.SelectedHost = vault.Hosts[0];
|
||||
vault.OpenHostPaneCommand.Execute(vault.Hosts[0]);
|
||||
vault.IsShowingHostDetail.ShouldBeTrue("there is nothing to measure otherwise");
|
||||
|
||||
await MeasureDrawerAsync(faults => faults.ShouldBeEmpty());
|
||||
}
|
||||
@@ -206,8 +213,8 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task TheHostDrawerFitsWithADeletionInQuestion()
|
||||
{
|
||||
vault.SelectedHost = vault.Hosts[0];
|
||||
vault.SelectedHost.IsConnected = true;
|
||||
vault.OpenHostPaneCommand.Execute(vault.Hosts[0]);
|
||||
vault.SelectedHost.ShouldNotBeNull().IsConnected = true;
|
||||
|
||||
vault.DeleteHostCommand.Execute(null);
|
||||
vault.IsConfirmingDeletion.ShouldBeTrue();
|
||||
@@ -373,7 +380,7 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task TheHostsScreenFitsWithTheDrawerOpen()
|
||||
{
|
||||
vault.SelectedHost = vault.Hosts[0];
|
||||
vault.OpenHostPaneCommand.Execute(vault.Hosts[0]);
|
||||
vault.IsDrawerOpen.ShouldBeTrue();
|
||||
|
||||
await MeasureHostsAsync(faults => faults.ShouldBeEmpty("with a host selected and the drawer out"));
|
||||
@@ -399,7 +406,7 @@ public sealed class ScreenLayoutTests : IAsyncLifetime
|
||||
[Fact]
|
||||
public async Task TheHostsGridKeepsTwoColumnsAtTheMinimumWithTheDrawerOpen()
|
||||
{
|
||||
vault.SelectedHost = vault.Hosts[0];
|
||||
vault.OpenHostPaneCommand.Execute(vault.Hosts[0]);
|
||||
vault.IsDrawerOpen.ShouldBeTrue("the drawer is what takes the width away");
|
||||
|
||||
await OnTheHostsScreenAsync((screen, window) =>
|
||||
|
||||
Reference in New Issue
Block a user