mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
fix(templates): forms and detail lists fit a phone screen
Column offsets without a breakpoint applied below it, where the column is already full width, so the change password, compute, user, VM create and VM settings forms ran past the right edge on a phone. Each offset now starts at its column's breakpoint. The interface and network detail lists were rows directly inside rows and sit in a column now; the compute form loses a Bootstrap 3 thumbnail padding that broke its gutters, and the add-rule dialog's hint is no longer cut off. The page test checks both grid rules on every page. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
e324e79fcb
commit
676bcfeb09
11 changed files with 91 additions and 79 deletions
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="offset-2 col-lg-8">
|
||||
<div class="offset-lg-2 col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h4 class="card-title">{%trans "Change Password" %}: {{ user }}</h4>
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card col-sm-10 offset-1">
|
||||
<div class="card col-sm-10 offset-sm-1">
|
||||
<div class="card-body">
|
||||
<form id="create-update" action="" method="post">
|
||||
{% csrf_token %}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="thumbnail col-sm-10 offset-1">
|
||||
<div class="col-sm-10 offset-sm-1">
|
||||
<form id="create-update" action="" method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form layout='horizontal' %}
|
||||
|
|
|
|||
|
|
@ -65,7 +65,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-grid col-sm-6 offset-3 mt-3">
|
||||
<div class="d-grid col-sm-6 offset-sm-3 mt-3">
|
||||
<button class="btn btn-primary" type="button" name="create_instance" onclick="goto_create()">
|
||||
{% trans "Next" %}
|
||||
</button>
|
||||
|
|
|
|||
|
|
@ -600,7 +600,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-grid col-sm-7 offset-3">
|
||||
<div class="d-grid col-sm-7 offset-sm-3">
|
||||
{% if storages %}
|
||||
<button type="submit" class="btn btn-primary" name="create" formnovalidate value="1">
|
||||
{% trans "Create" %}
|
||||
|
|
@ -876,7 +876,7 @@
|
|||
{% endif %}
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-grid col-sm-7 offset-3">
|
||||
<div class="d-grid col-sm-7 offset-sm-3">
|
||||
{% if storages %}
|
||||
<button type="submit" class="btn btn-primary" name="create" value="1" formnovalidate>
|
||||
{% trans "Create" %}
|
||||
|
|
|
|||
|
|
@ -239,7 +239,7 @@
|
|||
</div>
|
||||
</div>
|
||||
{% empty %}
|
||||
<div class="offset-3 col-sm-6">
|
||||
<div class="offset-sm-3 col-sm-6">
|
||||
<div class="bg-warning rounded shadow-sm">{% trans 'There is not any CD-ROM device.' %}</div>
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
|
@ -607,7 +607,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="live_migrate" value="true" id="vm_live_migrate" {% if instance.status != 5 %}checked{% else %}disabled{% endif %}>
|
||||
<label class="form-check-label" for="vm_live_migrate">{% trans "Live migration" %}</label>
|
||||
|
|
@ -615,7 +615,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="unsafe_migrate" value="true" id="vm_unsafe_migrate">
|
||||
<label class="form-check-label" for="vm_unsafe_migrate">{% trans "Unsafe migration" %}</label>
|
||||
|
|
@ -623,7 +623,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="offline_migrate" value="true" id="offline_migrate" {% if instance.status == 5 %}checked{% else %}disabled{% endif %}>
|
||||
<label class="form-check-label" for="offline_migrate">{% trans "Offline migration" %}</label>
|
||||
|
|
@ -631,7 +631,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="autoconverge" value="true" id="autoconverge" {% if instance.status != 1 %}disabled{% else %}checked{% endif %}>
|
||||
<label class="form-check-label" for="autoconverge" title="{% trans 'Forces CPU convergence during live migration' %}">{% trans "Auto converge" %}</label>
|
||||
|
|
@ -639,7 +639,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-sm-6 offset-3">
|
||||
<div class="col-sm-6 offset-sm-3">
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input" type="checkbox" name="compress" value="true" id="compress" {% if instance.status != 1 %}disabled{% endif %}>
|
||||
<label class="form-check-label" for="compress" title="{% trans 'Compress instance memory for fast migration' %}">{% trans "Compressed" %}</label>
|
||||
|
|
@ -756,7 +756,7 @@
|
|||
{% for network in instance.config_networks %}
|
||||
<div class="mb-3">
|
||||
<div class="row">
|
||||
<label class="col-sm-2 col-form-label offset-1">eth{{ forloop.counter0 }} ({{ network.nic }})</label>
|
||||
<label class="col-sm-2 col-form-label offset-sm-1">eth{{ forloop.counter0 }} ({{ network.nic }})</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group">
|
||||
<input type="text" class="form-control" name="clone-net-mac-{{ forloop.counter0 }}" value="{{ network.mac }}"/>
|
||||
|
|
@ -778,7 +778,7 @@
|
|||
<label>{% trans "Storage devices" %}:</label>
|
||||
{% for disk in instance.config_disks %}
|
||||
<div class="row">
|
||||
<label class="col-sm-2 col-form-label offset-1">{{ disk.dev }} ({{ disk.storage }})</label>
|
||||
<label class="col-sm-2 col-form-label offset-sm-1">{{ disk.dev }} ({{ disk.storage }})</label>
|
||||
<div class="col-sm-6">
|
||||
<div class="input-group mb-3">
|
||||
<input id="disk_name-{{ disk.dev }}" type="text" class="form-control" name="disk-{{ disk.dev }}" value="{{ disk.image }}"/>
|
||||
|
|
@ -847,7 +847,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="d-grid offset-3 col-sm-6">
|
||||
<div class="d-grid offset-sm-3 col-sm-6">
|
||||
{% if instance.status == 5 %}
|
||||
<button type="submit" class="btn btn-success" name="change_options">{% trans "Change" %}</button>
|
||||
{% else %}
|
||||
|
|
|
|||
|
|
@ -37,39 +37,41 @@
|
|||
|
||||
{% if changeable is False %}{% include 'interfaces_unchangeable.html' %}{% endif %}
|
||||
<div class="row">
|
||||
<dl class="ms-3 row">
|
||||
<dt class="col-4">{% trans "Interface" %}</dt>
|
||||
<dd class="col-8"><strong>{{ iface }}</strong></dd>
|
||||
<dt class="col-4">{% trans "IPv4" %} ({% if ipv4 == None %}{% trans 'None' %}{% else %}{{ ipv4_type }}{% endif %})</dt>
|
||||
<dd class="col-8">{{ ipv4 }}</dd>
|
||||
<dt class="col-4">{% trans "IPv6" %} ({% if ipv6 == None %}{% trans 'None' %}{% else %}{{ ipv6_type }}{% endif %})</dt>
|
||||
<dd class="col-8">{{ ipv6 }}</dd>
|
||||
<dt class="col-4">{% trans "MAC" %}</dt>
|
||||
<dd class="col-8">{{ mac }}</dd>
|
||||
<dt class="col-4">{% trans "Interface Type" %}</dt>
|
||||
<dd class="col-8">{{ itype }}</dd>
|
||||
{% if itype == 'bridge' %}
|
||||
<dt class="col-4">{% trans "Bridge Device" %}</dt>
|
||||
<dd class="col-8">{{ bridge }}</dd>
|
||||
{% endif %}
|
||||
<dt class="col-4">{% trans "Boot Mode" %}</dt>
|
||||
<dd class="col-8">{{ start_mode }}</dd>
|
||||
<dt class="col-4">{% trans "State" %}</dt>
|
||||
<dd class="col-8">
|
||||
{% if changeable is False %}
|
||||
{% if state == 0 %}{% trans "Inactive" %}{% else %}{% trans "Active" %}{% endif %}
|
||||
{% else %}
|
||||
<form action="" method="post" role="form" aria-label="Interface start/stop/delete form">{% csrf_token %}
|
||||
{% if state == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-primary" name="start" value="{% trans "Start" %}">
|
||||
<input type="submit" class="btn btn-sm btn-danger" name="delete" value="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="stop" value="{% trans "Stop" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% endif %}
|
||||
</form>
|
||||
<div class="col-12">
|
||||
<dl class="ms-3 row">
|
||||
<dt class="col-4">{% trans "Interface" %}</dt>
|
||||
<dd class="col-8"><strong>{{ iface }}</strong></dd>
|
||||
<dt class="col-4">{% trans "IPv4" %} ({% if ipv4 == None %}{% trans 'None' %}{% else %}{{ ipv4_type }}{% endif %})</dt>
|
||||
<dd class="col-8">{{ ipv4 }}</dd>
|
||||
<dt class="col-4">{% trans "IPv6" %} ({% if ipv6 == None %}{% trans 'None' %}{% else %}{{ ipv6_type }}{% endif %})</dt>
|
||||
<dd class="col-8">{{ ipv6 }}</dd>
|
||||
<dt class="col-4">{% trans "MAC" %}</dt>
|
||||
<dd class="col-8">{{ mac }}</dd>
|
||||
<dt class="col-4">{% trans "Interface Type" %}</dt>
|
||||
<dd class="col-8">{{ itype }}</dd>
|
||||
{% if itype == 'bridge' %}
|
||||
<dt class="col-4">{% trans "Bridge Device" %}</dt>
|
||||
<dd class="col-8">{{ bridge }}</dd>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
<dt class="col-4">{% trans "Boot Mode" %}</dt>
|
||||
<dd class="col-8">{{ start_mode }}</dd>
|
||||
<dt class="col-4">{% trans "State" %}</dt>
|
||||
<dd class="col-8">
|
||||
{% if changeable is False %}
|
||||
{% if state == 0 %}{% trans "Inactive" %}{% else %}{% trans "Active" %}{% endif %}
|
||||
{% else %}
|
||||
<form action="" method="post" role="form" aria-label="Interface start/stop/delete form">{% csrf_token %}
|
||||
{% if state == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-primary" name="start" value="{% trans "Start" %}">
|
||||
<input type="submit" class="btn btn-sm btn-danger" name="delete" value="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="stop" value="{% trans "Stop" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% endif %}
|
||||
</form>
|
||||
{% endif %}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
||||
<div class="col-sm-12">
|
||||
<h5>{% trans 'Slaves' %}</h5>
|
||||
|
|
|
|||
|
|
@ -38,33 +38,35 @@
|
|||
</div>
|
||||
|
||||
<div class="row">
|
||||
<dl class="ms-3 row">
|
||||
<dt class="col-6">{% trans "Network name" %}</dt>
|
||||
<dd class="col-6">{{ pool }}</dd>
|
||||
<dt class="col-6">{% trans "Device" %}</dt>
|
||||
<dd class="col-6">{{ device }}</dd>
|
||||
<dt class="col-6">{% trans "State" %}</dt>
|
||||
<dd class="col-6">
|
||||
<form action="" method="post" role="form" aria-label="Network start/stop/delete form">{% csrf_token %}
|
||||
{% if state == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-success" name="start" value="{% trans "Start" %}">
|
||||
<input type="submit" class="btn btn-sm btn-danger" name="delete" value="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="stop" value="{% trans "Stop" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% endif %}
|
||||
</form>
|
||||
</dd>
|
||||
<dt class="col-6">{% trans "Autostart" %}</dt>
|
||||
<dd class="col-6">
|
||||
<form action="" method="post" role="form" aria-label="Network enable/disable autostart form">{% csrf_token %}
|
||||
{% if autostart == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-success" name="set_autostart" value="{% trans "Enable" %}">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="unset_autostart" onclick="return confirm('{% trans "Are you sure?" %}')" value="{% trans "Disable" %}">
|
||||
{% endif %}
|
||||
</form>
|
||||
</dd>
|
||||
</dl>
|
||||
<div class="col-12">
|
||||
<dl class="ms-3 row">
|
||||
<dt class="col-6">{% trans "Network name" %}</dt>
|
||||
<dd class="col-6">{{ pool }}</dd>
|
||||
<dt class="col-6">{% trans "Device" %}</dt>
|
||||
<dd class="col-6">{{ device }}</dd>
|
||||
<dt class="col-6">{% trans "State" %}</dt>
|
||||
<dd class="col-6">
|
||||
<form action="" method="post" role="form" aria-label="Network start/stop/delete form">{% csrf_token %}
|
||||
{% if state == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-success" name="start" value="{% trans "Start" %}">
|
||||
<input type="submit" class="btn btn-sm btn-danger" name="delete" value="{% trans "Delete" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="stop" value="{% trans "Stop" %}" onclick="return confirm('{% trans "Are you sure?" %}')">
|
||||
{% endif %}
|
||||
</form>
|
||||
</dd>
|
||||
<dt class="col-6">{% trans "Autostart" %}</dt>
|
||||
<dd class="col-6">
|
||||
<form action="" method="post" role="form" aria-label="Network enable/disable autostart form">{% csrf_token %}
|
||||
{% if autostart == 0 %}
|
||||
<input type="submit" class="btn btn-sm btn-success" name="set_autostart" value="{% trans "Enable" %}">
|
||||
{% else %}
|
||||
<input type="submit" class="btn btn-sm btn-secondary" name="unset_autostart" onclick="return confirm('{% trans "Are you sure?" %}')" value="{% trans "Disable" %}">
|
||||
{% endif %}
|
||||
</form>
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="d-grid col-lg-12">
|
||||
|
|
|
|||
|
|
@ -20,8 +20,8 @@
|
|||
<input type="hidden" name="nwfilterrule_xml"/>
|
||||
<textarea id="rule_editor"></textarea>
|
||||
</div>
|
||||
<p class="text-muted">{% trans 'If there is a rule which has same attributes it replaces that rule' %}...</p>
|
||||
</div>
|
||||
<p class="text-muted">{% trans 'If there is a rule which has same attributes it replaces that rule' %}...</p>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="submit" class="btn btn-primary" name="add_nwfilter_rule">{% trans "Add" %}</button>
|
||||
|
|
|
|||
|
|
@ -157,10 +157,6 @@ p {
|
|||
margin-top: 65px;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
/* make dropdowns show on hover */
|
||||
@media only screen and (min-width: 768px) {
|
||||
.dropdown:hover .dropdown-menu {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
"""Every HTML page a superuser can open, rendered on libvirt's test driver."""
|
||||
|
||||
import re
|
||||
from collections import Counter
|
||||
from unittest.mock import patch
|
||||
|
||||
|
|
@ -70,3 +71,14 @@ class PageTests(TestCase):
|
|||
bare = [t.get("class") for t in page.xpath("//table[not(parent::div[contains(@class, 'table-responsive')])]")]
|
||||
with self.subTest(page=name):
|
||||
self.assertEqual(bare, [])
|
||||
|
||||
def test_grid_columns_fit_a_phone(self):
|
||||
# below a column's breakpoint it is full width, so an offset without one
|
||||
# pushes it past the screen; a row needs columns inside, not another row
|
||||
row = "contains(concat(' ', normalize-space(@class), ' '), ' row ')"
|
||||
for name, page in self.pages():
|
||||
offsets = [cls for cls in page.xpath("//@class")
|
||||
if re.search(r"\boffset-\d+\b", cls) and not re.search(r"\bcol-\d+\b", cls)]
|
||||
with self.subTest(page=name):
|
||||
self.assertEqual(offsets, [])
|
||||
self.assertEqual(page.xpath(f"//*[{row}]/*[{row}]/@class"), [])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue