Merge branch 'claude/group-creation-hosts-dragdrop-56c6a3'
ci / build and test (push) Canceled after 1m6s
ci / android head (push) Canceled after 0s
ci / api image (push) Canceled after 0s

This commit is contained in:
2026-08-03 15:50:12 +02:00
8 changed files with 432 additions and 147 deletions
@@ -3584,9 +3584,9 @@ public sealed class ShellFlowTests : IAsyncLifetime
}
/// <remarks>
/// What dragging a row onto a heading does. It is the same write the editor makes — one field of the
/// host, pushed straight away — reached without opening a form, because filing thirty imported machines
/// through the editor is thirty rounds of open, pick, save.
/// What dragging a host card onto a group card does. It is the same write the editor makes — one field
/// of the host, pushed straight away — reached without opening a form, because filing thirty imported
/// machines through the editor is thirty rounds of open, pick, save.
/// </remarks>
[Fact]
public async Task MovingAHostToAGroup_FilesItAndLeavesItSelected()
@@ -3605,15 +3605,21 @@ public sealed class ShellFlowTests : IAsyncLifetime
vault.Hosts.Single().Host.GroupId.ShouldBe(group);
vault.SelectedHost.ShouldNotBeNull().EntityId.ShouldBe(host.EntityId, "the reload replaces every row");
// Under the group's own heading now, which is the thing the drop was aiming at.
// Under the group's own heading now, which is what the phone's list draws.
vault.SidebarRows.OfType<SidebarGroupHeader>()
.Single(header => header.GroupId == group)
.Count.ShouldBe(1);
// And back out again, which is what the ungrouped heading is a target for.
// And the name on the card, which is what the desktop's grid draws instead of that heading — the one
// thing on screen that changes where the host was dropped rather than where it came from.
vault.Hosts.Single().GroupLabel.ShouldBe("production");
vault.Hosts.Single().HasGroup.ShouldBeTrue();
// And back out again, which is what the host's own editor is for now that the drop has one target.
await vault.MoveHostToGroupCommand.ExecuteAsync(new HostGroupMove(vault.Hosts.Single(), null));
vault.Hosts.Single().Host.GroupId.ShouldBeNull();
vault.Hosts.Single().HasGroup.ShouldBeFalse("and the chip goes with it");
}
/// <remarks>
@@ -3670,9 +3676,13 @@ public sealed class ShellFlowTests : IAsyncLifetime
vault.Groups.ShouldBeEmpty();
vault.HasGroups.ShouldBeFalse();
// The host keeps the id, which is what makes this cheap; the sidebar is what resolves it to nothing.
// The host keeps the id, which is what makes this cheap; the list is what resolves it to nothing.
vault.Hosts.Single().Host.GroupId.ShouldBe(groupId);
vault.SidebarRows.ShouldAllBe(row => row is HostRowViewModel);
// The card says the same thing the phone's list does: nothing. An id nobody can name is drawn as no
// group rather than as a GUID on a chip.
vault.Hosts.Single().GroupLabel.ShouldBeEmpty();
}
/// <remarks>