Public Access
Take the group's EDIT and DELETE off the heading row
A pair of buttons sat at the end of the GROUPS heading, and the card's own right-click menu arrived later offering the same two things. Two controls for one job, and the buttons were the harder of the two to read: a button beside a heading has no card under a pointer to mean, so it had to work its subject out — the selected card, or failing that the group the trail ends with, which once a group is open is not a card on screen at all. The menu never has that problem, because opening it is what aims it. The menu is the whole of Edit and Delete on the desktop now. ShowsGroupActions went with the buttons, since hiding them was all it did. GroupTarget stays: the menu's two entries read it after the code-behind has selected whatever was right-clicked, and its fallback to the open group is what makes + NEW HOST open on the group somebody is standing in rather than on none. One case changes shape. Opening a group with nothing inside it folds the card grid away, so from in there nothing can be right-clicked — renaming that group means pressing the trail back one level, to where it has a card of its own. The buttons used to cover it through the fallback. The trail was already the way out of an empty group, and 3.2a says so now. The test that pressed EDIT through its binding is replaced by one holding that no button on the screen commands either of them, which is the failure worth catching: a button coming back is not a compile error, and it would draw itself in place, aimed at the group the trail ends with. What that test covered — a command that has to accept an empty parameter, and act on the card the pointer was on — the two menu tests beside it already do.
This commit is contained in:
@@ -166,9 +166,9 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The host grid's menu acts on nothing when it is not aimed; this one acts on the <em>wrong group</em>.
|
||||
/// <c>GroupTarget</c> falls back to the group whose contents are on screen when no card is selected — the
|
||||
/// right answer for the pair of buttons beside the heading, and the wrong one for a menu that opened on a
|
||||
/// card, which would then offer to delete a group the pointer is nowhere near.
|
||||
/// <c>GroupTarget</c> falls back to the group whose contents are on screen when no card is selected, and
|
||||
/// a menu that opened on a card would then offer to delete a group the pointer is nowhere near. It is
|
||||
/// also the only way to Edit or Delete a group on the desktop, so this is the only place it is aimed.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Open is the one entry that takes a parameter, because <c>OpenGroupCommand</c>'s null is a real
|
||||
@@ -287,10 +287,10 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// The rule one press was split into two gestures for. Selecting a group aims its EDIT and DELETE at it
|
||||
/// and does nothing else; opening one is what narrows the grid, and the trail is the way back out of it.
|
||||
/// While a single press meant both, a group could not be named without every host outside it leaving the
|
||||
/// screen at the same moment.
|
||||
/// The rule one press was split into two gestures for. Selecting a group marks it and does nothing else;
|
||||
/// opening one is what narrows the grid, and the trail is the way back out of it. While a single press
|
||||
/// meant both, a group could not be named without every host outside it leaving the screen at the same
|
||||
/// moment.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Driven through the properties the cards bind rather than through a click, because what is worth
|
||||
@@ -299,7 +299,7 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task SelectingAGroupAimsItsButtonsAtItAndOpeningOneNarrowsTheGrid()
|
||||
public async Task SelectingAGroupMarksItAndOpeningOneNarrowsTheGrid()
|
||||
{
|
||||
await vault.MoveHostToGroupCommand.ExecuteAsync(
|
||||
new HostGroupMove(Row(vault, "prod-db"), vault.Groups.Single().EntityId));
|
||||
@@ -312,8 +312,7 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
vault.GroupFilter.ShouldBeNull("one press selects a group and does not open it");
|
||||
vault.VisibleHosts.Select(row => row.Label)
|
||||
.ShouldBe(["stage-web"], "so the grid is still the outermost level, and prod-db is inside a group");
|
||||
vault.GroupTarget.ShouldBeSameAs(production, "what EDIT and DELETE act on");
|
||||
vault.ShowsGroupActions.ShouldBeTrue();
|
||||
vault.GroupTarget.ShouldBeSameAs(production, "what a group command with no argument acts on");
|
||||
|
||||
vault.OpenGroupCommand.Execute(production);
|
||||
|
||||
@@ -324,7 +323,7 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
|
||||
vault.SelectedGroup.ShouldBeNull("the card it was on is not one of the cards on screen any more");
|
||||
vault.GroupTarget.ShouldBeSameAs(
|
||||
production, "so the buttons fall back to the group whose contents are showing");
|
||||
production, "so an unaimed command falls back to the group whose contents are showing");
|
||||
|
||||
// Back out, which is the trail's first crumb and nothing else: SHOW ALL was a second control for the
|
||||
// same job and went with the change.
|
||||
@@ -333,7 +332,6 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
vault.VisibleHosts.Select(row => row.Label)
|
||||
.ShouldBe(["stage-web"], "ALL HOSTS is the outermost level, not every host in the keychain");
|
||||
vault.GroupTarget.ShouldBeNull("and nothing is aimed at once no group is open or selected");
|
||||
vault.ShowsGroupActions.ShouldBeFalse("a pair of buttons with no subject is hidden rather than shown");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -376,35 +374,29 @@ public sealed class HostGridTests : IAsyncLifetime
|
||||
vault.SelectedGroup.ShouldBeNull("and the same in the other direction");
|
||||
screen.GroupGrid.SelectedItem.ShouldBeNull();
|
||||
GroupCard(screen).IsSelected.ShouldBeFalse();
|
||||
vault.ShowsGroupActions.ShouldBeFalse("so the group's own two buttons have nothing to act on");
|
||||
});
|
||||
}
|
||||
|
||||
/// <remarks>
|
||||
/// EDIT takes the group as an argument now, so that the phone can open the editor on a heading without
|
||||
/// selecting a group and losing the host selection to it — see <c>VaultViewModel.EditGroup</c>. The
|
||||
/// button beside the cards passes nothing and means "the card that is selected", which is the half of
|
||||
/// that change that would fail silently: a command refusing a null parameter is a button that never
|
||||
/// fires, and nothing about the markup would say so.
|
||||
/// A pair of EDIT and DELETE buttons used to sit beside the GROUPS heading, and the card's own menu is
|
||||
/// the whole of both now — the menu came second and did the same job better, since it acts on the card
|
||||
/// under the pointer rather than on <c>GroupTarget</c>. Held here because a button coming back is not a
|
||||
/// compile error and barely a visible one: it would draw itself in place, aimed with no card selected at
|
||||
/// the group the trail ends with, which is the mistake the two menu tests above exist to catch.
|
||||
/// </remarks>
|
||||
[Fact]
|
||||
public async Task TheGroupsEditButtonStillActsOnTheSelectedCard()
|
||||
public async Task AGroupsEditAndDeleteAreOnItsCardsMenuAndNowhereElse()
|
||||
{
|
||||
await OnTheGridAsync((screen, _) =>
|
||||
{
|
||||
vault.SelectedGroup = vault.VisibleGroups.Single();
|
||||
Dispatcher.UIThread.RunJobs();
|
||||
|
||||
var edit = screen.GetVisualDescendants()
|
||||
screen.GetVisualDescendants()
|
||||
.OfType<Button>()
|
||||
.Single(button => ReferenceEquals(button.Command, vault.EditGroupCommand));
|
||||
|
||||
edit.IsEffectivelyEnabled.ShouldBeTrue("the command has to accept the button's empty parameter");
|
||||
|
||||
edit.Command.ShouldNotBeNull().Execute(edit.CommandParameter);
|
||||
|
||||
vault.IsEditingGroup.ShouldBeTrue();
|
||||
vault.GroupEditorLabel.ShouldBe("production", "the card that was selected");
|
||||
.Where(button => ReferenceEquals(button.Command, vault.EditGroupCommand)
|
||||
|| ReferenceEquals(button.Command, vault.DeleteGroupCommand))
|
||||
.ShouldBeEmpty("a selected group card puts no buttons on the screen");
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user