diff --git a/README.md b/README.md index 1ea0717..e136ce2 100644 --- a/README.md +++ b/README.md @@ -352,6 +352,24 @@ vault it is leaving. A picker inside the form would do all of that as a side eff What a move cannot do is reach a machine that has already synced the host, which is the same limit everything else about revocation has. Keys, passwords and buckets take theirs from a standing "new items go to" picker on the Keychain screen and cannot be moved yet. + +**A group can be moved too, and it takes its contents with it** — MOVE beside EDIT and DELETE over the group +cards, or "Move to another vault…" on the card's own menu. That is the desktop only, because the phone draws +groups as headings in the host list and has never had a way to delete or move one. It is the same re-seal +and tombstone underneath, applied to every item involved: the group, the groups nested inside it, and every +host filed under any of them, each taking a new id in the destination. Moving less than that was never +coherent — the machines and the child groups are items of the vault the group is leaving, so a group that +travelled alone would leave half a shelf behind. What stays is the group it was itself nested under, which +belongs to the old vault, so it arrives at the top level; the hosts' tags stay for the same reason. Keys and +passwords are kept, because those genuinely resolve across vaults, and the sentence afterwards names any +that are now outside the destination. + +**Deleting a group asks what should become of the hosts under it.** The default answer keeps them: the +reference is cleared and they move to UNGROUPED. Ticking the box deletes them with it. Both answers are a +change — the deletion used to leave the hosts holding an id that no longer resolved, which looked the same +and cost nothing, and stopped being the right shape once the deletion could take them with it. A group with +nothing filed under it is not asked. Whichever answer is given, the groups nested inside take the deleted +group's place in the tree rather than being orphaned to the top level. Both default to your personal vault and neither moves on its own, because an item put in a shared vault is visible to everybody holding that vault's key. Choosing a vault in the host editor also decides which groups it can be filed under: a group is an item like any other and lives in exactly one vault. @@ -598,6 +616,16 @@ keychain plus a terminal — and the spike that gates all of it. than to a shell that never opens. Given a walk that had to be cycle-safe anyway, refusing to nest bought nothing. + Membership living on the host has one further consequence, and it took two goes to settle. Deleting a + group could not clear it without rewriting every host under the heading, so at first it did not: the hosts + kept an id that resolved to nothing and turned up under UNGROUPED, which reads identically and costs no + writes. That held until the deletion had to be able to take the hosts *with* it — a group is sometimes a + heading being tidied away and sometimes a project that has been decommissioned, and nothing in the code can + tell which. Once a deletion knows which hosts it means, leaving them naming something that has gone is a + state kept for no reason, so both answers now write: N deletions, or N hosts with the reference cleared. + The dangling case still has to be survived everywhere it is read, because a group deleted on *another* + machine arrives exactly that way. + Inserting a snippet types it at the prompt and stops. Pressing Enter is a per-snippet decision, off by default, and the reason is worth stating: a terminal is one input stream with no notion of being at a prompt — the remote may be in an editor, or at a password prompt with the echo off — so this client cannot diff --git a/docs/design-import-gaps.md b/docs/design-import-gaps.md index 027f97d..0292ce6 100644 --- a/docs/design-import-gaps.md +++ b/docs/design-import-gaps.md @@ -157,7 +157,7 @@ the chrome, hosts and terminals, file transfer, the vault, teams, and preference > | **Add Telnet**, and **Serial** in the toolbar | Omitted. `ISshConnection` is the only transport there is. This is also why the card subtitle's `ssh` is a constant today rather than a reading — it is stated in `HostRowViewModel.Summary`, which is the one place in this interface where a constant is printed on purpose. | > | **+ SSH ID, Certificate, FIDO2** | Omitted. `IDENTITIES` and `CERTIFICATES` have been on this document's list since the first import — neither is even a reserved `SyncEntityType` — and there is no security-key path anywhere in the SSH layer. One control offering three item types that do not exist. | > | The **Backspace / Default** row | Omitted. It is a terminal setting, and the client has no preferences store and no frame to carry one to the renderer — see the Preferences section. It would be a control whose value could not survive the window closing. | -> | The **chevron beside the vault name** | The name alone, and the move behind the pane's ⋯ menu instead. A host *can* now be moved between vaults, so the gap is no longer that there is nothing to offer — it is that a chevron on a subtitle implies an edit, and this is not one: the two vaults are encrypted under different keys, so it is a re-seal into one and a tombstone in the other, the host takes a new id, and its group and tags stay behind. A control that implied "just change this field" would be describing something else. Where a *new* host goes is still asked in the host editor, as a picker beside the name; keys, passwords and buckets take theirs from the keychain screen's standing picker and cannot be moved yet. | +> | The **chevron beside the vault name** | The name alone, and the move behind the pane's ⋯ menu instead. A host *can* now be moved between vaults, so the gap is no longer that there is nothing to offer — it is that a chevron on a subtitle implies an edit, and this is not one: the two vaults are encrypted under different keys, so it is a re-seal into one and a tombstone in the other, the host takes a new id, and its group and tags stay behind. A control that implied "just change this field" would be describing something else. Where a *new* host goes is still asked in the host editor, as a picker beside the name. A group moves too, from MOVE over the group cards, and takes its nested groups and every host filed under them; keys, passwords and buckets take theirs from the keychain screen's standing picker and cannot be moved yet. | > | **Show more ⌄** | Not drawn as a disclosure. What it would hide — notes, the relay switch, forgetting the host key — is in the editor, one press away, and a second fold inside a pane that already scrolls is a second place for a field to be missing from. | > | **Port Forwarding** in the sidebar | Nothing, for the third time in this document. | > | The host grid's toolbar avatar, share and tag-filter controls | Omitted, as in v3 and for the same reasons. | diff --git a/src/DodoSSH.Client.App/Views/ConfirmDeleteCard.axaml b/src/DodoSSH.Client.App/Views/ConfirmDeleteCard.axaml index 0d08387..93b1e01 100644 --- a/src/DodoSSH.Client.App/Views/ConfirmDeleteCard.axaml +++ b/src/DodoSSH.Client.App/Views/ConfirmDeleteCard.axaml @@ -41,6 +41,21 @@ Text="{Binding PendingDeletion.Usage}" /> + + + + +