PR 1233: redesign the VNC console

Your draft, reviewed twice at aebb803: Cody's process (codyrancher/ai-skills 5f9619b) and ours, then merged and re-checked. Nothing was posted to GitHub.

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

Where it stands: the direction holds, 7 things to fix before it leaves draft

Everything the console did before still works: every key combination decodes correctly on the VNC socket, in use, connection lost and not running show their cards, the confirms ask first in the toolbar and in full screen, and it matches Ken's frames within 1-2px apart from the changes you decided on. Unit tests, lint and CI are green.

  1. Reset to defaults turns View only off
  2. Anyone who used the current console keeps Manual zoom
  3. The JPEG quality and Compression sliders are 4px tall
  4. Holding Ctrl or Alt from the keyboard makes the keys unreachable
  5. Adding or deleting from the keyboard loses focus
  6. A failed save says nothing
  7. A lone Windows key can no longer be saved

Then three calls for you or Ken (red confirm, soft reboot text, pointer), a few small ones, and one FYI for the docs.

How the two passes compare

#FindingPass A (Cody)Pass B (ours)Lands as
1Reset to defaults turns View only off–BlockerFix
2Manual zoom kept for users of the current consoleSide effects–Fix
3JPEG quality and Compression sliders 4px tallAccessibility–Fix
4Keyboard can't reach keys after holding a modifier–SuggestionFix
5Focus lost after adding or deletingAccessibility–Fix
6A failed save says nothing–SuggestionFix
7A lone Windows key can't be saved–QuestionFix
8Red confirm restyles RcButtonContrast onlySuggestionYour call
9Soft reboot text says the console disconnects–QuestionAsk Ken
10Public noVNC option for the pointer–SuggestionOptional
11Pill and card disagree while starting–NitSmall
12Draft survives Done–NitSmall
13Two tables for the same keysSimplifyOptional nitSmall
14Leftovers (strings, CSS, prop, branch)–NitsCleanup
15Tests for the wrapper's new pathsNot run by defaultSuggestionOptional
16Docs PR and QA test describe the old toolbarSide effects–FYI
–Red text contrast in dark (theme colors)AccessibilitySuggestionDropped
–Full screen bar contrast at restProbe, dropped at its own verifyChecked, passesDropped
Pass A (Cody's process)Pass B (our process)
Kept findings6 (4 only here)12 (10 only here)
Both2 kept (red confirm, two key tables), plus the theme contrast both dropped
StrengthStates and persistence: settings saved by main, focus after a change, measured hit boxes, docs side effectsLogic in the new paths: the reset, RcDropdown's item list, the blank layout, the recorder
OutputBefore/after demos, 10 acceptance criteria checked, design pass on 10 frames in both themes, Cody's a11y probe and axe on 9 states, comments in his shapeReview in our format, 7-dimension coverage grid, 20 Playwright scenarios, a failing scratch unit test, keyboard clip
CostThis session, about 50 min, about 350k tokensSeparate agent, 43 min, 512k tokens, 192 tool calls

Fix

1

Reset to defaults turns View only off

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

The View panel's Reset to defaults sets every setting back to its default, including View only, which now lives in the toolbar. So someone watching in View only who resets the zoom starts sending their mouse and keyboard to the VM. In my re-check, a click and a key after the reset went out as 3 pointer and 2 key events (dropped by the test).

Fix: reset only the panel's own settings (scaling, zoom, quality, compression) and keep View only. Pass B has a scratch unit test that fails on the head commit and passes with that change.

Top: View only on, input controls disabled. Bottom: after Reset to defaults, View only is off and the controls are back.
Top: View only on, input controls disabled. Bottom: after Reset to defaults, View only is off and the controls are back.
2

Anyone who used the current console keeps Manual zoom

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

The redesign makes Automatic (fit to the window) the default, but main writes its own default, Manual at 100%, to the same localStorage key the first time the console opens, without the user choosing anything. The new default only reaches browsers that never opened the console. Everyone else gets the 720x400 screen in a big black area after the upgrade.

Fix: the simplest is a new storage key, so main's auto-saved defaults don't count as a choice. Someone who really picked Manual on main picks it once more.

Left: a browser that never opened the console gets Automatic. Right: a browser that opened it on main first stays on Manual 100%.
Left: a browser that never opened the console gets Automatic. Right: a browser that opened it on main first stays on Manual 100%.
3

The JPEG quality and Compression sliders are 4px tall

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

flex: 1 on every slider is meant for the zoom row, but in the column sections it sets the height, so those two inputs collapse to their 4px track. A click on the visible thumb, 6px off the line, doesn't move it; only a click on the line does. Zoom is fine (20px).

Fix: apply the flex: 1 only to the zoom row's slider.

Each slider's own box outlined in red: zoom is 20px tall, JPEG quality is the 4px line and the thumb hangs outside it.
Each slider's own box outlined in red: zoom is 20px tall, JPEG quality is the 4px line and the thumb hangs outside it.
4

From the keyboard, holding Ctrl or Alt makes the keys below unreachable

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

RcDropdown collects its items when the menu opens. Turning a modifier on swaps the keys below it (Print Screen and the F-keys become N, T, W, Y, or Del), and the new items aren't in its list, so ArrowDown stops at Alt. With a mouse it works. Main's old menu had no keyboard access at all, so it isn't a regression, but the new keyboard path breaks half way.

Fix: keep the same items while the menu is open, for example render every key and disable the ones that don't go with what is held. Pass B reasoned this from RcDropdown's code; not tried yet.

Keyboard only: Enter, ArrowDown to Ctrl, Space, then ArrowDown stays on Alt (Pass B, Chromium).
5

Adding or deleting a shortcut from the keyboard loses focus

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

While the save runs, the delete buttons and Add shortcut are disabled. The one just pressed has focus, and a focused button that gets disabled drops focus to the page, so the next Tab starts again from the top of the dialog (WCAG 2.4.3). On main, a keyboard delete keeps focus on a close button.

Fix: don't disable the buttons during the save; add and remove can return early while saving is set.

6

A failed save says nothing

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

The dialog reports a failed save only with a growl, and the console page uses the blank layout, which has no growls. With the save failing, a delete leaves the row and a new shortcut doesn't appear, with no message. On main the Save button turned into "Error".

Fix: show the error in the dialog itself, for example a Banner above the list.

Save answered 403: both rows still there after Delete, and nothing on screen says why.
Save answered 403: both rows still there after Delete, and nothing on screen says why.
7

A lone Windows key can no longer be saved

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

The recorder waits for another key after a modifier, so pressing only the Windows key records nothing. Main's recorder saved "Meta" on its own, which is the clean way to open the guest's Start menu, since the physical key goes to the host.

Fix: when a modifier is released with nothing else pressed, record it on its own.

Main's dialog records "Keys: Meta" and Add is enabled. On the PR, the same key leaves the field empty.
Main's dialog records "Keys: Meta" and Add is enabled. On the PR, the same key leaves the field empty.

Your call

8

The red confirm button restyles RcButton

Found by Pass A (Cody)Found by Pass B (ours)
Your call

Ken's Figma draws Send Ctrl+Alt+Del red, so the PR overrides RcButton's primary with the error colors. On PR 1225 you asked for normal usage instead of a red Delete, and the shell's RcModal story uses a plain primary for its own Delete confirmation. One of the two has to give: Ken's red or normal usage.

The 3.42:1 contrast both passes measured in dark is not counted: it's the theme's own .bg-error pair, the same on every Delete in Rancher.

9

The soft reboot text says the console disconnects

Found by Pass B (ours)Not checked live
Ask Ken

"The console disconnects while the VM restarts and reconnects when it is back." comes from Ken's frame. Reading KubeVirt, with rebootPolicy unset (true for every VM on both backends) the guest restarts inside the same QEMU, so the console should stay connected and show the restart. A real soft reboot is off limits on the shared VMs, so this is from the code only.

10

noVNC has a public option for the visible pointer

Found by Pass B (ours)Read in noVNC 1.7.0
Optional

The override of _refreshCursor reads noVNC's private _cursorImage. rfb.showDotCursor = true is public and covers the same case, but draws a small dot instead of the arrow, which is a look decision. The private override can break on a noVNC upgrade. The two-pointer case on a desktop VM is still untested (no graphical VM on either backend), and it would apply to both.

Small and optional

11

While the VM starts, the pill says Not running

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

The card says "This virtual machine is starting" while the pill next to it says "Not running".

VM instance in Scheduling (staged in the browser): pill and card disagree.
VM instance in Scheduling (staged in the browser): pill and card disagree.
12

A recorded shortcut that wasn't added is still there after Done

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

The dialog stays mounted, so a combination and name you recorded but didn't add come back the next time it opens, which reads like they might have been saved. Main rebuilt the dialog each time.

Recorded Ctrl+Shift+K, named it, clicked Done, reopened: the draft is still in the form.
Recorded Ctrl+Shift+K, named it, clicked Done, reopened: the draft is still in the form.
13

Two tables for the same keys

Found by Pass A (Cody)Found by Pass B (ours)
Small

The menu keeps its own key lists while the wrapper still maps the same keys to keysyms, with labels nothing reads now. A key added to one and not the other throws in sendKeys.

14

Leftovers

several files
Found by Pass B (ours)Read
Cleanup
15

Tests for the wrapper's new paths

Found by Pass B (ours)
Optional

The wrapper is at 55% line coverage: finding a stopped VM by uid, the starting state, the grace period, the keys sendKeys passes on and the reset have no tests. A reset test would have caught finding 1.

FYI and dropped

16

Docs and QA tests describe the current toolbar

Found by Pass A (Cody)
FYI

The open docs PR for issue 12015 explains the current toolbar with screenshots, and QA's manual test still says to click Shortcut Keys, then Ctrl, Alt, Del. Both need an update when this lands. Not something to change in the PR.

–

Dropped after checking

Dropped

Pass A: Cody's process

Followed my-pr-full-review in this session, mapped to our setup: the PR preview for his dev server, harvester-main for his master build, local files instead of his harness, our recorder, his a11y-probe.mjs run from the clone against a local Chromium with the same write and key stubs (axe beside it, since the probe looks for it under /workspace). Base review, then his seven passes, then verify, refine, final pass, remove suggestions, condense, and the master check last. Every key, soft reboot and preference write was held in the browser.

Before this change: main (vm123 on .105).
With this change: the PR (test1 on .118). Full screen is left out of both: the recorder can't encode a window resize.

Acceptance, from issue 10420 (as far as the PR claims it) and the PR description

CriterionVerdict
AC1Connects and says soMet
AC2Every old key combination can be sent (decoded on the socket)Met
AC3Custom shortcuts: record, name, save, send, deleteMet
AC4In use shown, Take over offered, the other session keptMet
AC5Ctrl+Alt+Del and Soft reboot ask first, also in full screenMet
AC6Scaling, zoom, quality, compression rememberedMet
AC7Full screen fills the window, dialogs on topMet
AC8Connecting, in use, connection lost, not running cardsMet
AC9Matches the new designMet, deviations were your decisions
AC10Light and darkMet

Not in this PR: several viewers at once, copy and paste, speed, replacing the tool, the HEP. Open on the issue: Prime-only gating and HEP scope, both unanswered.

Design pass, Figma against the PR in dark

Connected and Shortcut keys menu: Figma on the left, PR on the right.
Connected and Shortcut keys menu: Figma on the left, PR on the right.
Confirm and custom shortcuts dialogs.
Confirm and custom shortcuts dialogs.
Connecting (my staging broke noVNC here; the real connecting card checked fine), connection lost, full screen.
Connecting (my staging broke noVNC here; the real connecting card checked fine), connection lost, full screen.

Measured within 1-2px: toolbar, pill, buttons, menu, confirm (480px), dialog (640px), full screen bar. The differences are your decisions (View only checkbox, Shortcut keys and edge to edge in full screen, Del under Ctrl+Alt, two reworded texts) or come from shell components (uppercase group labels, checkmarks, RcModal title weight).

Pass B: our process

A fresh agent that never saw Pass A, following prompts/code-review.prompt.md and your review rules (PR-introduced only, simple fix, normal usage, review shape). It checked the PR against main on both previews with 20 Playwright scenarios, read the Rc components it relies on, ran a coverage report and wrote a scratch unit test that fails on the head commit for finding 1. Its preference snapshot of .118 was identical before and after.

Pass B: after Ctrl is turned on from the keyboard, focus stays on Alt.
Pass B: after Ctrl is turned on from the keyboard, focus stays on Alt.

Not checked by either pass