PR 1233: redesign the VNC console, round two

The seven fix commits (e02ceae to 6d71782), reviewed again with both passes: Cody's my-pr-review-new-commits and ours, then merged and re-checked. Nothing was posted to GitHub.

Preview: harvesterissue-10420r, built from 6d71782, backend Harvester .118 (v1.9.0-rc4). Baseline: harvester-main at aa6d11a, backend .105 (v1.10.0-rc1).

Where it stands: the 7 fixes hold, and three new things to fix

Both passes re-ran their round-one checks on the preview built from 6d71782, and all 7 fixes hold. CI is green, the unit tests pass, and the shared .118 preference was unchanged after every run. The new commits brought three things worth fixing:

  1. A failed delete further down shows nothing where you are (both passes)
  2. A second delete pressed while the first one saves is lost (Pass A)
  3. View only turned on in the 1.10 console is off after the upgrade (Pass B)

There's also an optional one about how the settings are saved (20) and a small focus slip from the original redesign that round one missed (21). The round-one calls for you or Ken haven't changed.

New in round two

#FindingPass A (Cody)Pass B (ours)Lands as
17A failed delete further down shows nothing where you areYes (12 shortcuts)Yes (2 at 1280×720, plus the focus and a tested fix)Fix
18A second delete during a save is lostYes–Fix
19View only from the 1.10 console is dropped–Yes (asked as a question)Fix
20All five settings saved at the first change–Optional nitOptional
21Ctrl clicked after arrowing to an F-key drops the focus–Yes (out of this round's commits)Small
17

A failed delete further down shows nothing where you are

Found by Pass A (Cody)Found by Pass B (ours)Re-checked: holds
Fix

The error sits at the top of the dialog, and the dialog scrolls as soon as the list grows. With two saved shortcuts in a 1280×720 window, deleting the second one with the save refused leaves the dialog scrolled 158px, the error above what you see, and the row still there. It looks like the click did nothing. A screen reader still announces it (role="alert").

On the last row the focus also drops to the page. The rows are keyed by index, and the delete changes the preference before saving and puts it back when the save fails, so the last row's button is removed and created again. The focus is only put back after a save that worked.

Fix: put the focus back after every delete, whatever the save did, and bring the error into view when it shows. Pass B's scratch test fails at 6d71782 and passes with the focus part, with the 73 novnc tests. Where the error sits is Ken's call.

1280×720, two shortcuts, the save refused, Delete on Ctrl+F2: the row is still there and the error is scrolled out of view above the form.
1280×720, two shortcuts, the save refused, Delete on Ctrl+F2: the row is still there and the error is scrolled out of view above the form.
18

A second delete pressed while the first one saves is lost

Found by Pass A (Cody)Checked live
Fix

The buttons now stay enabled while a change saves, so the focus stays, and a click that comes in meanwhile returns early without a word. With saves held for 1.5s in the browser, deleting the first row and then the new first row 300ms later sent one save and left two of the three rows. A real save is quicker, so it takes a quick double press or a slow network.

Fix: let the second change wait for the first instead of dropping it: chain it onto the running save, and pick the row by its keys rather than its index, since the index moves.

19

View only turned on in the 1.10 console is off after the upgrade

Found by Pass B (ours)Re-checked: holds
Fix

The settings moved to a new key so that main's saved defaults don't count as choices. That also drops View only, which the current console saves under the old key on main and release-harvester-v1.10 (since v1.10.0-rc1; v1.9 has no such setting). With the old key holding View only on, the console opens with it off, and a click and a key on the screen went out as 3 pointer and 2 key events (dropped by the test). Someone who chose not to touch the VM would be touching it again.

Fix: when the new key isn't there yet, take viewOnly from the old one. Its default is off, so a saved "on" can only be a choice; the display settings still start fresh. Pass B asked it as a question; I'd fix it, since View only is what keeps input away from the VM.

20

Once one setting changes, all five are saved, defaults included

Found by Pass B (ours)Read in the code
Optional

The comment says the console saves only what the user changes, but saveSettings writes the whole set at the first change. Changing JPEG quality alone saves scaling, zoom, View only and compression too (Pass B, on the preview). So a default changed later won't reach anyone who touched any setting: the trap the new key fixes, smaller.

Fix: save only the values that differ from the defaults (loadSettings already falls back one by one), or say in the comment and the test title that the set is saved once one changes.

21

Clicking Ctrl with the mouse after arrowing to an F-key drops the focus

Found by Pass B (ours)Re-checked: holds
Small

Holding Ctrl swaps the keys below the toggles, so the F-key that had the keyboard focus is removed and the focus goes to the page. The arrows then do nothing until Tab or a click. Keyboard alone is fine, since the focus is on the toggle, which stays, and so is the mouse alone. It comes from the redesign's key swap, not the new commits; both passes missed it in round one.

Fix: when a toggle changes the keys, put the focus on the toggle.

Round one, at 6d71782

#FindingNowChecked
1Reset to defaults turns View only offFixed in 9bd5f36Pass B re-ran its scenario, 6/6: View only stays ticked, and a click and a key send nothing.
2Manual zoom kept for users of the current consoleFixed in e02ceaePass A: a browser with main's saved Manual gets Automatic (1352×751). See 19 and 20.
3Quality and compression sliders 4px tallFixed in 7d5d614Pass A: all three are 20px, and a click 6px off the line moves quality from 6 to 8.
4Keyboard can't reach the keys after holding a modifierFixed in ca01fb8Pass B: 9/9 in Chromium and Firefox. See 21 for mouse after keyboard.
5Focus lost after adding or deletingFixed in b91ccb8Pass A: Enter on a delete leaves the focus on the next delete. See 17 and 18.
6A failed save says nothingFixed in 7371345Pass B: the error shows in the dialog as an alert. See 17.
7A lone Windows key can't be savedFixed in 6d71782Pass B: Meta alone records and sends Super_L (decoded and dropped).
8Red confirm restyles RcButtonYour call, unchangedOne more fact from Pass B: the shell's own DisableAuthProviderDialog colours its RcButton with --error the same way.
9Soft reboot text says the console disconnectsAsk Ken, unchanged–
10Public noVNC option for the pointerOptional, unchanged–
11Pill and card disagree while startingSmall, unchangedPass B: still "Not running" next to "starting".
12Draft survives DoneSmall, unchangedPass B: the draft is back on reopening.
13Two tables for the same keysSmall, unchangedBoth passes.
14Leftovers (strings, CSS, prop, branch)Cleanup, unchanged–
15Tests for the wrapper's new pathsOptional, partlyThe reset and the settings storage have tests now; the wrapper is at 57% lines.
16Docs PR and QA test describe the old toolbarFYI–
–Red text contrast in darkAnswered: theme colorsBoth passes measured the shell's own .bg-error and .text-error at the same ratios.

How the two passes compare

Pass A (Cody's process)Pass B (our process)
Round oneIts 6 comments: 3 addressed, 2 answered (contrast), 1 not addressed (two key tables)Its 19 items: 4 addressed, 2 answered (contrast), 13 left for later
New findings2: 17, and 18 only here4: 17 with the focus loss and a tested fix, and 19, 20 and 21 only here
StrengthTiming: a slow save turned up the lost second deleteState across versions (the old key) and the smallest window where 17 shows
Not filedThe menu reads RcDropdown's internal dropdownContext. Nothing breaks today, but a rename in the shell would bring back round one's keyboard dead end.–

What each pass did

Pass A followed my-pr-review-new-commits (codyrancher/ai-skills 5f9619b) in this session. It took aebb803 as the cut, re-ran each round-one comment's steps on the preview, then ran the new line comments through remove-suggestions and condense.

Pass B was a fresh agent that never saw Pass A, following prompts/code-review.prompt.md. It re-ran its 20 round-one scenarios unchanged and added new ones for the seven commits in Chromium and Firefox. It also wrote a scratch unit test for 17 that fails at 6d71782 and passes with the fix, and took a preference snapshot of .118 that hashed the same before and after.

Both held every write in the browser. Saves were refused or delayed on purpose, keys and pointer events to the VM were decoded and dropped, and soft reboot was stubbed.

Not checked by either pass