mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 19:26:48 +00:00
The VM page offered a lite and a full VNC console. Lite lacked a clipboard, display settings and a way to reconnect; full put noVNC's own side bar under the panel's bar, with a Fullscreen item that called a function noVNC does not have, status messages hidden behind the bar, saved noVNC settings that overrode the Access tab's, connection settings that cannot apply, and a Connect button that reused the page's two-minute token and failed. console-vnc.html and static/js/console_vnc.js replace both, on noVNC's RFB with Bootstrap controls, and keep what the full view did: - Status in the bar (Connecting, Connected, Disconnected, Connection lost, Could not connect, Authentication failed with the server's reason on hover); Disconnect, then Reconnect, which loads the page again for a new token. - The VNC password in a dialog (with a username when the server asks for one), not a browser prompt; without passwordless console it is not in the page. - Send key(s) gains Hold Ctrl / Alt / Windows (noVNC's extra keys). - Clipboard: what the VM copies, sending text to the VM's clipboard, and typing it key by key (new: works in firmware, installers and login prompts; Shift for the characters a US keyboard shifts, 25 ms a key as firmware drops faster keys, verified in a UEFI shell). - View: scaling (none, fit, resize the VM's screen), clip, drag a clipped screen, view only, dot cursor, quality, compression; it starts as Settings > Console says (a touch screen starts fitted). - A Keyboard item on touch devices (noVNC's on-screen keyboard input, key events and Android's text-only input), Fullscreen with keyboard lock, the bell. Dropped with the full view: noVNC's websocket host/port/path, repeater ID and log level (the panel fixes them), automatic reconnect (the token is single use in time), XVP power buttons (QEMU has no XVP) and shared-mode off. The bar is compact (about 45 px in the 850x600 window). The Access tab has one Console button instead of the Lite/Full split and four switches, and it and the VM list open one window per VM (opening it again reloads it).
69 lines
4 KiB
HTML
69 lines
4 KiB
HTML
{% load i18n %}
|
|
{% load bootstrap_icons %}
|
|
{% load vm_states %}
|
|
{% vm_actions instance as actions %}
|
|
{% if actions %}
|
|
<div class="btn-group" role="group" aria-label="Instance actions">
|
|
{% if "clone" in actions %}
|
|
<a href="{% url 'instances:instance' instance.id %}#clone" class="btn btn-sm btn-secondary" title="{% trans "Clone" %}">
|
|
{% bs_icon 'copy' %}
|
|
</a>
|
|
{% elif "poweron" in actions %}
|
|
<form action="{% url 'instances:poweron' instance.id %}" method="post" style="display:inline;" onsubmit="showPleaseWaitDialog()">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Power On" %}">{% bs_icon 'play-fill' %}</button>
|
|
</form>
|
|
{% elif "resume" in actions %}
|
|
<form action="{% url 'instances:resume' instance.id %}" method="post" style="display:inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Resume" %}">{% bs_icon 'play-fill' %}</button>
|
|
</form>
|
|
{% else %}
|
|
<button class="btn btn-sm btn-secondary disabled" title="{% trans "Power On" %}" disabled>{% bs_icon 'play-fill' %}</button>
|
|
{% endif %}
|
|
|
|
{% if "suspend" in actions %}
|
|
<form action="{% url 'instances:suspend' instance.id %}" method="post" style="display:inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Suspend" %}">{% bs_icon 'pause-fill' %}</button>
|
|
</form>
|
|
{% else %}
|
|
<button class="btn btn-sm btn-secondary disabled" title="{% trans "Suspend" %}" disabled>{% bs_icon 'pause-fill' %}</button>
|
|
{% endif %}
|
|
|
|
{% if "poweroff" in actions %}
|
|
<form action="{% url 'instances:poweroff' instance.id %}" method="post" style="display:inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Power Off" %}">{% bs_icon 'power' %}</button>
|
|
</form>
|
|
{% elif "force_off" in actions %}
|
|
<form action="{% url 'instances:force_off' instance.id %}" method="post" style="display:inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Force Off" %}"
|
|
data-confirm="{% blocktrans with name=instance.name %}Force off {{ name }}? It stops at once, as after a power cut; what the guest has not written to disk is lost.{% endblocktrans %}"
|
|
onclick="return confirm(this.dataset.confirm)">{% bs_icon 'power' %}</button>
|
|
</form>
|
|
{% else %}
|
|
<button class="btn btn-sm btn-secondary disabled" title="{% trans "Power Off" %}" disabled>{% bs_icon 'power' %}</button>
|
|
{% endif %}
|
|
|
|
{% if "powercycle" in actions %}
|
|
<form action="{% url 'instances:powercycle' instance.id %}" method="post" style="display:inline;">
|
|
{% csrf_token %}
|
|
<button type="submit" class="btn btn-sm btn-secondary" title="{% trans "Power Cycle" %}"
|
|
data-confirm="{% blocktrans with name=instance.name %}Power cycle {{ name }}? It stops at once, as after a power cut, and starts again; what the guest has not written to disk is lost.{% endblocktrans %}"
|
|
onclick="return confirm(this.dataset.confirm)">{% bs_icon 'repeat' %}</button>
|
|
</form>
|
|
{% else %}
|
|
<button class="btn btn-sm btn-secondary disabled" title="{% trans "Power Cycle" %}" disabled>{% bs_icon 'repeat' %}</button>
|
|
{% endif %}
|
|
|
|
{% if "console" in actions %}
|
|
<button class="btn btn-sm btn-secondary" type="button" data-url="{% url 'console' instance.compute_id instance.uuid %}" data-window="console-{{ instance.uuid }}"
|
|
onclick="window.open(this.dataset.url, this.dataset.window, 'width=850,height=650')"
|
|
title="{% trans "Console" %}">{% bs_icon 'eye-fill' %}</button>
|
|
{% else %}
|
|
<button class="btn btn-sm btn-secondary disabled" title="{% trans "VNC Console" %}" disabled>{% bs_icon 'eye-fill' %}</button>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|