Merge branch 'claude/main-page-group-hierarchy-3a3210'

This commit is contained in:
2026-08-04 10:10:19 +02:00
6 changed files with 368 additions and 53 deletions
+42 -17
View File
@@ -306,24 +306,46 @@ card, nothing saying the hosts are unfiled.
**Failure means:** the "invisible until used" property is gone, and every existing user gets a section they
did not ask for. `HasGroups` is what hides the row of group cards; `HostRowViewModel.HasGroup` hides the chip.
### 3.2 Filing hosts, and reading which group a card is in
### 3.2 Filing hosts, and the grid being one level at a time
Make two groups and file some hosts into each through the host editor.
Make two groups and file some hosts into each through the host editor, leaving at least one host unfiled.
**Pass:** every filed card carries the group's name as an accent chip under its address; the cards stay one
flat wrap, in one order, with nothing between them. **There is no heading and no fold on the desktop** — the
headings, their chevrons and UNGROUPED are the phone's, whose list has no room for a row of group cards.
**Pass:** the filed hosts **leave the grid** as they are filed — a group is a place, not a label, and the
grid holds one level of it the way a directory pane holds one directory. What is left is the unfiled hosts.
**There is no heading and no fold on the desktop** — the headings, their chevrons and UNGROUPED are the
phone's, whose list has no room for a row of group cards and draws the whole tree flat instead. With every
host filed, the grid says so in a sentence rather than sitting empty.
**Then press a group card once.** It is marked as chosen and **nothing else happens** — the grid still holds
every host, and EDIT and DELETE now aim at that group. **Then double-press it.** The group opens: the hosts
narrow to the ones filed under it, the trail above the cards reads `ALL HOSTS <name> `, and the card grid
shows what is *inside* that group rather than every group in the keychain. Pressing ALL HOSTS brings the rest
back.
**Then press a group card once.** It is marked as chosen and **nothing else happens** — the grid is still the
level it was, and EDIT and DELETE now aim at that group. **Then double-press it.** The group opens: its hosts
are the grid, the trail above the cards reads `ALL HOSTS <name> `, each card carrying the group's name as
an accent chip, and the card grid shows what is *inside* that group rather than every group in the keychain.
Pressing ALL HOSTS goes back to the outermost level.
**Then type a filed host's name into the find box at the top.** It is found from the outermost level,
wherever it was filed and however deep, with the chip on its card saying which group it came out of. Clearing
the box puts it away again. Inside a group the same box reaches that group and everything under it, and the
empty-grid sentence there offers ALL HOSTS as the way to widen it.
**Failure means:** if one press still narrows the grid, the card `ListBox` is bound to the wrong property —
`SelectedItem` is `SelectedGroup`, and only `OpenGroupCommand` writes `GroupFilter`. A full-width bar with a
chevron between the cards is the old grouping coming back through `SidebarRows`; the desktop grid binds
`VisibleHosts`. See `HostsScreen.axaml`.
`SelectedItem` is `SelectedGroup`, and only `OpenGroupCommand` writes `GroupFilter`. Filed hosts still on the
outermost level is `Matches` no longer comparing the host's group to the open one. A search that cannot find
a filed host is worse than either: it is the box answering "no host matches that" about a machine the
keychain has got. A full-width bar with a chevron between the cards is the old grouping coming back through
`SidebarRows`; the desktop grid binds `VisibleHosts`. See `HostsScreen.axaml`.
### 3.2b Making something while standing inside a group
Open a group, then press **+ NEW HOST**, and afterwards **+ NEW GROUP**.
**Pass:** the host editor opens with that group already chosen in its group picker, and the saved host is on
the screen it was made on rather than somewhere the trail is not. The group editor likewise opens with that
group as its parent, so the new group is a card inside the one that is open.
**Failure means:** anything created inside a group disappearing the moment it is saved. That is the papercut
a level-at-a-time grid comes with, and `NewHost` / `NewGroup` are where it is answered. Note the deliberate
difference between them: the host editor also takes a merely *selected* card as its group, the group editor
takes only the group that is open.
### 3.2a A group inside a group, and the way back out
@@ -708,12 +730,15 @@ back.
Make two groups and file a host into one. Drag a host card up onto the other group's card.
**Pass:** the group card under the pointer takes a two-pixel accent border while the pointer is over it, the
cursor shows a move rather than a refusal, and the drop files the host — the chip on its card changes to the
new group's name, the host counts under both group cards change, and the status line says where it went.
cursor shows a move rather than a refusal, and the drop files the host — **the card leaves the grid**, going
inside the group it was dropped on, the host counts under both group cards change, and the status line says
where it went. That sentence is the only thing left saying so, which is why it is worth reading: the card
itself is on the level below now, and nothing is selected once it has gone.
**Also check three refusals**, each of which must show the "no" cursor and mark nothing: over the card of the
group the host is *already* in; over another **host** card, which is deliberately not a target now that there
are no headings to say which group it would mean; and over the empty space around the cards.
group the host is *already* in — type its name into the find box first, which is what brings a filed card
back to this level; over another **host** card, which is deliberately not a target now that there are no
headings to say which group it would mean; and over the empty space around the cards.
**The targets are the cards on screen, which are one level** — see 3.2a. Filing into a group nested under
another means opening the outer one first, exactly as moving a file into a subfolder does.