From ac6bc48f88e99c75f34b1d1239c526d57b47e7b0 Mon Sep 17 00:00:00 2001 From: catborise Date: Thu, 22 Oct 2026 14:03:49 +0300 Subject: [PATCH] feat(console): the VNC console switches scaling from its menu Only an administrator chose whether the VNC console fits the remote screen to the window (Settings, or ?scale= in the URL). A Scale switch in the console menu now flips between fitted and 1:1 with scrollbars, starting from that setting. On a phone, where noVNC takes the touch screen as the mouse and the 1:1 view cannot be scrolled, it is the way to see the whole screen. Co-Authored-By: Claude Opus 5.5 (1M context) --- console/templates/console-vnc-lite.html | 13 +++++++++++++ console/tests/test_views.py | 14 ++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/console/templates/console-vnc-lite.html b/console/templates/console-vnc-lite.html index cf2e41e1..6de2555f 100755 --- a/console/templates/console-vnc-lite.html +++ b/console/templates/console-vnc-lite.html @@ -222,6 +222,13 @@ bindKeyAction('machineRebootButton', machineReboot); bindKeyAction('machineResetButton', machineReset); bindKeyAction('fullscreen_button', fullscreen); + // fit the remote screen to the window, or show it 1:1 with scrollbars + bindKeyAction('scale_button', () => { + rfb.scaleViewport = !rfb.scaleViewport; + const link = document.querySelector('#scale_button a'); + link.classList.toggle('active', rfb.scaleViewport); + link.setAttribute('aria-pressed', rfb.scaleViewport); + }); bindKeyAction('ctrlaltdel', sendCtrlAltDel); bindKeyAction('ctrlaltbackspace', () => sendKeyCombo([ @@ -318,6 +325,12 @@ {% endblock %} +{% block navbarmenu %} + +{% endblock %} + {% block content %}
diff --git a/console/tests/test_views.py b/console/tests/test_views.py index 3ec6c4b0..bc08d0bf 100644 --- a/console/tests/test_views.py +++ b/console/tests/test_views.py @@ -108,6 +108,20 @@ class ConsoleViewsTestCase(TestCase): self.assertTemplateUsed(response, "console-vnc-full.html") self.assertEqual(response.context["ws_port"], 5900) + @patch("console.views.wvmInstance") + def test_the_lite_console_switches_scaling_from_its_menu(self, mock_wvm): + mock_wvm.return_value.get_console_type.return_value = "vnc" + mock_wvm.return_value.get_console_websocket_port.return_value = None + self.client.force_login(self.admin_user) + for query, pressed in (("", "false"), ("&scale=true", "true")): + with self.subTest(query=query): + page = html.fromstring(self.client.get(reverse("console") + f"?token={self.token}&view=lite{query}").content) + switch = page.xpath("//*[@id='scale_button']//a")[0] + self.assertEqual(switch.get("aria-pressed"), pressed) + self.assertEqual("active" in switch.get("class").split(), pressed == "true") + page = html.fromstring(self.client.get(reverse("console") + f"?token={self.token}&view=full").content) + self.assertEqual(page.xpath("//*[@id='scale_button']"), []) # noVNC's own settings scale the full view + @patch("console.views.wvmInstance") def test_console_unsupported_graphics_type(self, mock_wvm): # Only VNC is supported; a VM defined elsewhere may use another type.