Public Access
Record v5c in the design-import log, and true up the manual checks
This commit is contained in:
+126
-50
@@ -115,6 +115,61 @@ vault that authenticates with a key filed in the switched-off one still connects
|
||||
`VaultViewModel.IsVaultShown` for the list, and `VaultVisibilityTests` for the same assertions made against
|
||||
view models — this check is the version with a real connection on the end of it.
|
||||
|
||||
### 1.8 Entering and leaving settings mode
|
||||
|
||||
From HOSTS, press the user chip at the foot of the nav rail and choose **Settings**. Then repeat from a
|
||||
fresh open, choosing **Vaults**, and again choosing **Preferences**.
|
||||
|
||||
**Pass:** each of the three swaps the whole window's chrome — the titlebar becomes the 53px "Back to
|
||||
application" bar, the ordinary nav rail is replaced by the 340px SettingsNav, and the status bar and the
|
||||
update banner (if either was showing) are both gone. **Settings** lands on General; **Vaults** and
|
||||
**Preferences** land on their own pages, each lit in SettingsNav's own list — General/Vaults/Account under
|
||||
SETTINGS, Security/Preferences/Groups/Tags under CUSTOMIZE, Logout pinned below both. Click every one of the
|
||||
seven rows in turn: each swaps the content column without leaving settings mode or touching the titlebar.
|
||||
|
||||
Now open a terminal, leave it showing, and open Settings from the user chip again. Press **Back to
|
||||
application** — or, without touching anything else, press Esc.
|
||||
|
||||
**Pass:** both return to exactly the screen that was showing before Settings was opened — the terminal,
|
||||
still running, rather than HOSTS or anywhere else. Switching between settings pages first (General → Vaults
|
||||
→ Preferences) does not change what "back" goes back to; only the screen open the moment Settings was
|
||||
**first** entered does.
|
||||
|
||||
**Failure means:** a return to HOSTS regardless of where Settings was opened from is
|
||||
`MainWindowViewModel.settingsReturnScreen` being recaptured on every `EnterSettings` call rather than only on
|
||||
the way in from outside settings mode — see that field's own remark. A status bar or update banner still
|
||||
visible in settings mode is `MainWindow.axaml`'s two bottom rows no longer reading `!IsSettingsMode`. Esc
|
||||
doing nothing is `MainWindow.axaml.cs`'s `OnKeyDown` no longer checking `IsSettingsMode` after the palette's
|
||||
own branch.
|
||||
|
||||
### 1.9 The importer's own home, and what still reaches through settings mode
|
||||
|
||||
From Settings → Preferences, press **OPEN IMPORTER**.
|
||||
|
||||
**Pass:** the titlebar's back button relabels itself "Back to preferences" — not "Back to application" — and
|
||||
SettingsNav stays lit on **Preferences** the whole time; the importer is drawn over the Preferences page
|
||||
rather than being a destination of its own. Press SCAN AGAIN and let it read your `~/.ssh/config`.
|
||||
|
||||
Press **Back to preferences** (or Esc). **Pass:** the Preferences page is back, still inside settings mode,
|
||||
and the titlebar's label reverts. Press Esc a second time (or **Back to application**): now settings mode
|
||||
itself closes, back to whatever screen was open before Settings was entered — the same two-deep
|
||||
"closest thing first" order the titlebar's own two buttons and `MainWindowViewModel.OpenImport`/`CloseImport`
|
||||
follow.
|
||||
|
||||
**Then, with the importer open, press Ctrl+K** and connect to a host from the palette.
|
||||
|
||||
**Pass:** it works exactly as it does anywhere else in the application — the palette opens over the
|
||||
importer, and connecting leaves settings mode outright for the new terminal, the same way choosing any
|
||||
ordinary nav rail destination does through `MainWindowViewModel.ShowScreen`. An unapproved host's key card
|
||||
comes up over settings mode the same way it would over any other screen.
|
||||
|
||||
**Failure means:** a back button that never changes label is `SettingsTitleBar.axaml`'s two buttons both
|
||||
bound to the same side of `IsImportOpen`. SettingsNav lighting a different row while the importer is up is
|
||||
`MainWindowViewModel.IsSettingsPreferencesPage` reading `IsImportOpen` when it must not —
|
||||
`Import.dc.html` draws the rail unmoved on purpose; see the remark on `IsImportOpen`. Ctrl+K doing nothing
|
||||
over the importer would be a guard added to `OnKeyDown` for `IsSettingsMode` that the design never asked for
|
||||
and this application's own quick-connect card was built to reach past.
|
||||
|
||||
---
|
||||
|
||||
## Phase 2 — Known Hosts as its own page
|
||||
@@ -200,7 +255,7 @@ The parser has 22 cases over the shapes a real file contains, and the end-to-end
|
||||
|
||||
### 2.7 Scan your own `~/.ssh/config` and read the preview against the file
|
||||
|
||||
Preferences → IMPORT HOSTS → SCAN. Do not press import yet.
|
||||
Settings → Preferences → OPEN IMPORTER, then SCAN AGAIN. Do not press Import N hosts yet.
|
||||
|
||||
**Pass:** every entry you would expect is listed, with the address and port you expect, and the warnings
|
||||
above the table account for anything missing.
|
||||
@@ -364,61 +419,81 @@ 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 the grid being one level at a time
|
||||
### 3.2 Filing hosts, and the board drawing every group at once
|
||||
|
||||
Make two groups and file some hosts into each through the host editor, leaving at least one host unfiled.
|
||||
Make two groups — the Group ▾ flyout's "New group…" — and file some hosts into each, once through a host's
|
||||
own editor and its GROUP picker, and once by ticking several hosts and choosing **Change group…** from the
|
||||
right-click menu. Leave at least one host unfiled.
|
||||
|
||||
**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.
|
||||
**Pass:** every group is a heading on the board **at once** — in label order, "No group" first where it is
|
||||
occupied — with its own hosts underneath. There is no double-click, no card to open a group into and no
|
||||
breadcrumb trail: v3's one-level-at-a-time grid is gone outright, and every section is on screen from the
|
||||
moment the board is. A host filed under `production` is drawn once, under that heading, and nowhere else on
|
||||
the board.
|
||||
|
||||
**Then press a group card once.** It is marked as chosen and **nothing else happens** — the grid is still the
|
||||
level it was, and no buttons appear beside the GROUPS heading: editing and deleting a group are on the card's
|
||||
own right-click menu, which is 7.9. **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 press the chevron beside one heading.** It folds — the heading stays, with its live count, and its
|
||||
cards go — and pressing it again brings the cards back. **Then press "Collapse all"**, drawn on the first
|
||||
heading only. It folds every section at once and its own label swaps to "Expand all"; opening any one heading
|
||||
by hand swaps the label back to "Collapse all".
|
||||
|
||||
**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.
|
||||
**Then type a filed host's name into the find box at the top, with its heading folded.** **Pass:** the
|
||||
heading's own count narrows to match — the count is read off the set the find box has already narrowed,
|
||||
before the fold is looked at — but the cards themselves stay hidden until that heading is reopened; open it
|
||||
and the narrowed set is there. Clear the box and every count returns.
|
||||
|
||||
**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`. 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`.
|
||||
**Failure means:** a host drawn under a heading that is not its own, or under two at once, is
|
||||
`VaultViewModel.AddFlatSection`'s membership test reading the wrong field for that section —
|
||||
`host.Host.GroupId == group.EntityId` for a named heading, everything else for "No group". A chevron that
|
||||
folds every section rather than the one it sits beside is `ToggleGroupCommand` being handed the board rather
|
||||
than the single `SidebarGroupHeader` it was pressed on. A count that does not move with the find box is
|
||||
`MatchesHostBoardFilters` not running before `HostSections` is rebuilt — see
|
||||
`VaultViewModel.RebuildHostSections` and `OnHostFilterChanged`.
|
||||
|
||||
### 3.2a A group inside a group, and the way back out
|
||||
### 3.2a A group nested under another, and what a host filed under it inherits
|
||||
|
||||
Make two groups and file one under the other with the parent picker in the group editor.
|
||||
Make an outer group with a default port and no default username, then make a second group whose editor's
|
||||
PARENT picker points at the outer one, and give this inner group no default port of its own. File a host
|
||||
under the inner group with nothing set on the host itself.
|
||||
|
||||
**Pass:** only the outer group has a card to start with. Double-press it and the inner one is the only card
|
||||
shown, with the trail reading `ALL HOSTS › <outer> ›`. Double-press that, and the cards disappear entirely —
|
||||
it has nothing inside it — while the trail stays. Pressing the **middle** crumb goes back one level rather
|
||||
than all the way out, which is also how a group with nothing inside it is renamed: back out to the level
|
||||
where it has a card, and right-click that.
|
||||
**Pass:** both groups are their own headings on the board, side by side — nesting is never drawn on the board
|
||||
itself, only carried in the group editor's own PARENT field. The inner heading's count is only the hosts
|
||||
filed directly under it, and the outer's is only the hosts filed directly under the outer one; the host filed
|
||||
under the inner group is not counted on the outer heading. Connect the host anyway: it dials the **outer**
|
||||
group's port. `HostInheritance.Chain` walks past the inner group's own silence on that field rather than
|
||||
stopping at the nearest group regardless of whether it answered. Give the inner group its own default port
|
||||
and reconnect: the host now dials that one instead, because the nearer group's answer wins once there is one.
|
||||
|
||||
**Failure means:** cards for groups that are not at this level is `VisibleGroups` having been bound past —
|
||||
the flat `Groups` is the phone's and the lookups'. A group that cannot be reached at all is worse and is the
|
||||
case `EffectiveParents` promotes: see 3.4a.
|
||||
**Then open the inner group's own editor and look at its PARENT picker.** The outer group is offered. **Then
|
||||
open the outer group's own editor and look at its PARENT picker.** The inner group is **not** offered — a
|
||||
group found by walking down from the outer one is refused as its own parent, which is what keeps this one
|
||||
machine, acting alone, from building a cycle. (Two machines can still build one offline between them; that is
|
||||
3.4a, below.)
|
||||
|
||||
### 3.2b Making something while standing inside a group
|
||||
**Failure means:** a host that dials 22 with the outer group's port set is the chain stopping at the first
|
||||
group above the host rather than reading each field independently from the nearest group that states it — see
|
||||
`HostInheritance.Resolve`'s own remarks. A parent picker offering a group's own descendant is
|
||||
`VaultViewModel.BuildGroupParentChoices` walking the wrong direction: each candidate has to be walked
|
||||
*upward*, through `HostInheritance.Chain`, to see whether it passes through the group being edited — a
|
||||
downward index of children is what the alternative would need, and this view model keeps none.
|
||||
|
||||
Open a group, then press **+ NEW HOST**, and afterwards **+ NEW GROUP**.
|
||||
### 3.2b Making a host or a group inherits nothing from where the board is scrolled
|
||||
|
||||
**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.
|
||||
Scroll the board so one group's section fills the window, or fold every other section away, then press
|
||||
**+ New host**. Afterwards, open the Group ▾ flyout and press **New group…**.
|
||||
|
||||
**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.
|
||||
**Pass:** the host editor opens with its GROUP picker on **"No group"**, and the group editor opens with its
|
||||
PARENT on **"No group"** too — neither reads anything from which heading happens to be on screen or scrolled
|
||||
to. This is deliberate: the level-at-a-time grid these two commands used to inherit an "open group" from is
|
||||
gone, and nothing on the flat board replaced that context. Pick a group by hand in either picker and it
|
||||
stays picked — the host or the new group lands there once saved.
|
||||
|
||||
**Failure means:** an editor that opens already filed under whichever section happened to be on screen is
|
||||
`VaultViewModel.GroupTarget` — the fallback both `NewHost` and `NewGroup` still read — having been wired to a
|
||||
live selection again. Read that property's own remarks before treating this as a regression: it is an alias
|
||||
for the single-select `GroupFilter`, which nothing in the current toolbar ever assigns any more — the Group ▾
|
||||
flyout ticks a set, `checkedGroupFilterIds`, a different field entirely — so today the fallback is dead code
|
||||
rather than a path either `+` button takes. Restoring it as live board context would make both commands
|
||||
context-sensitive in a way nothing on this board signals before the fact.
|
||||
|
||||
### 3.3 Deleting a group with hosts in it
|
||||
|
||||
@@ -1618,7 +1693,7 @@ newcomer **must not have signed in to this deployment before** — 12.1 is about
|
||||
|
||||
### 12.1 An address with no account is refused, and joins nothing when it later signs in · **the one worth the most care**
|
||||
|
||||
1. Sign in as `alice`, make a vault on the VAULTS screen, and select it.
|
||||
1. Sign in as `alice`, go to Settings → Vaults, make a vault there, and select it.
|
||||
2. Add `bob@example.com` as a Member, with Bob having never signed in here.
|
||||
3. **Pass:** it is refused. The status line names the address and says to ask them to sign in to this
|
||||
server once and then add them. **Nothing on the screen should suggest anything is pending** — no
|
||||
@@ -1716,7 +1791,7 @@ vault is now flagged for rekey, the transfer is removing the outgoing owner rath
|
||||
|
||||
Look for a way to remove a vault, on both heads.
|
||||
|
||||
**Pass:** there is none, and the VAULTS screen says why in a sentence: nothing in this product removes a
|
||||
**Pass:** there is none, and Settings → Vaults says why in a sentence: nothing in this product removes a
|
||||
vault, and the server refuses to archive the membership list behind one while it exists. Archiving that
|
||||
list is still reachable over the API, and the endpoint suite drives both its refusal and its success — what
|
||||
is being checked here is that no button offers it.
|
||||
@@ -1727,7 +1802,7 @@ button that always refuses is the milder failure and is still worth removing.
|
||||
|
||||
### 12.8 Renaming a vault reaches every place its name is drawn · **needs two accounts**
|
||||
|
||||
Rename a shared vault from the VAULTS screen.
|
||||
Rename a shared vault from Settings → Vaults.
|
||||
|
||||
**Pass:** the new name is on the vault list, on the badge of every host card in that vault, in the keychain
|
||||
screen's "new items file to" picker, in the host editor's vault picker, and in the nav rail's user-chip
|
||||
@@ -2149,10 +2224,11 @@ fifteen seconds comes from.
|
||||
|
||||
### 16.5 The version on screen is the version that was built
|
||||
|
||||
Right-click `DodoSSH.exe` → Properties → Details, and open PREFERENCES → UPDATES.
|
||||
Right-click `DodoSSH.exe` → Properties → Details, and open Settings → General.
|
||||
|
||||
**Pass:** File version reads the tag (`0.1.0.0`), product **DodoSSH**, company **DodoTech**, and the
|
||||
preferences screen prints the same number.
|
||||
General page's UPDATES card prints the same number — the block moved there from Preferences in v5c, and
|
||||
Preferences itself carries no version line any more.
|
||||
|
||||
**Failure means:** `0.0.0.0` is MinVer never seeing a tag — a shallow clone, or `fetch-depth` having been
|
||||
dropped from a checkout. `1.0.0.0` is somebody having wired the app manifest's inert `assemblyIdentity`
|
||||
@@ -2174,7 +2250,7 @@ script warns rather than failing when that is legitimate, which is the first rel
|
||||
### 16.7 The update arrives, and the restart lands in it · **the whole point of the work**
|
||||
|
||||
With v0.1.0 installed and running, a vault unlocked, a host change made, and **a terminal open**, publish
|
||||
v0.1.1 (`-Upload`). Then press CHECK NOW on PREFERENCES rather than waiting six hours.
|
||||
v0.1.1 (`-Upload`). Then press CHECK NOW on Settings → General rather than waiting six hours.
|
||||
|
||||
**Pass:** the progress bar moves, the banner appears above the status bar, and — the part to actually watch
|
||||
— the terminal **reflows cleanly rather than being sliced**, with the remote seeing the smaller row count.
|
||||
@@ -2228,7 +2304,7 @@ there is one install directory, the pack ids collide and the nightly has replace
|
||||
outright — which is the thing ADR 0013 decision 9 is constructed to make impossible, so it means one of the
|
||||
four separations has been undone.
|
||||
|
||||
**And the direction that matters most:** on the release build, PREFERENCES → UPDATES → CHECK NOW must not
|
||||
**And the direction that matters most:** on the release build, Settings → General → CHECK NOW must not
|
||||
offer a nightly, ever, however many have been published since. It reads a different index and refuses
|
||||
prereleases; if a nightly version is ever offered there, stop and treat it as a release-channel incident
|
||||
rather than as a bug in the nightly.
|
||||
|
||||
Reference in New Issue
Block a user