mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-10 04:06:47 +00:00
feat(storages): the pool page's dialogs in the panel's dialog look
The New volume, Clone image and Upload ISO dialogs of a pool set their labels in a narrow column beside the fields and closed with a grey Close; Clone image showed the volume's name in red and offered bare Convert and Metadata boxes, New volume an unlabelled meta_prealloc box. Now their labels sit above the fields, tied to them: New volume asks for the name, with what it may hold, then the size and the format side by side and "Preallocate metadata (qcow2)"; Clone image names the volume in monospace, asks for the name of the copy and offers "Convert it to another format", its format and the same preallocation; Upload ISO asks for the ISO file and says to keep the page open while the browser sends it. Each closes with Cancel and its action; the posted fields are unchanged.
This commit is contained in:
parent
0fd3e69c8e
commit
9d3e3bd315
4 changed files with 52 additions and 45 deletions
|
|
@ -86,13 +86,13 @@ class AddStgPool(forms.Form):
|
|||
|
||||
|
||||
class CreateVolumeForm(forms.Form):
|
||||
name = forms.CharField(max_length=120)
|
||||
name = forms.CharField(max_length=120, help_text=_("Letters, digits, dot, dash and underscore."))
|
||||
format = forms.ChoiceField(
|
||||
required=True,
|
||||
choices=(("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")),
|
||||
)
|
||||
size = forms.IntegerField(label=_("Size (GiB)"), min_value=1)
|
||||
meta_prealloc = forms.BooleanField(required=False)
|
||||
meta_prealloc = forms.BooleanField(label=_("Preallocate metadata (qcow2)"), required=False)
|
||||
|
||||
def clean_name(self):
|
||||
name = self.cleaned_data["name"]
|
||||
|
|
@ -112,7 +112,7 @@ class CloneImage(forms.Form):
|
|||
required=False,
|
||||
choices=(("qcow2", "qcow2 (recommended)"), ("qcow", "qcow"), ("raw", "raw")),
|
||||
)
|
||||
meta_prealloc = forms.BooleanField(required=False)
|
||||
meta_prealloc = forms.BooleanField(label=_("Preallocate metadata (qcow2)"), required=False)
|
||||
|
||||
def clean_name(self):
|
||||
name = self.cleaned_data["name"]
|
||||
|
|
|
|||
|
|
@ -8,22 +8,18 @@
|
|||
<span aria-hidden="true">{% bs_icon 'upload' %}</span> {% trans "Upload ISO" %}
|
||||
</button>
|
||||
|
||||
<!-- Modal Upload -->
|
||||
<div class="modal fade" id="IsoUpload" tabindex="-1" role="dialog" aria-labelledby="IsoUploadLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="IsoUploadLabel">{% trans "Upload ISO Image" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||||
</div>
|
||||
<form id="isoUploadForm" enctype="multipart/form-data" method="post" role="form" aria-label="Upload iso form">{% csrf_token %}
|
||||
<form id="isoUploadForm" enctype="multipart/form-data" method="post" aria-label="{% trans "Upload iso form" %}">{% csrf_token %}
|
||||
<div class="modal-body">
|
||||
<div class="row mb-3">
|
||||
<label for="id_file" class="col-sm-3 col-form-label">{% trans "Name" %}</label>
|
||||
<div class="col-sm-9">
|
||||
<input type="file" name="file" id="id_file" class="form-control" accept=".iso" required>
|
||||
</div>
|
||||
</div>
|
||||
<label for="id_file" class="form-label">{% trans "ISO file" %}</label>
|
||||
<input type="file" name="file" id="id_file" class="form-control" accept=".iso" required aria-describedby="id_file_help">
|
||||
<div class="form-text" id="id_file_help">{% trans "The browser sends it: keep the page open until the upload ends." %}</div>
|
||||
<div id="upload-status" class="d-none align-items-center gap-2 text-primary mt-3" role="status" aria-live="polite">
|
||||
<span class="spinner-border spinner-border-sm" aria-hidden="true"></span>
|
||||
<span id="upload-status-text">{% trans "Starting upload..." %}</span>
|
||||
|
|
@ -32,7 +28,7 @@
|
|||
</div>
|
||||
<div class="modal-footer">
|
||||
<input type="hidden" name="iso_upload" value="true">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-primary">{% trans "Upload" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
@ -45,22 +41,26 @@
|
|||
<span aria-hidden="true">{% bs_icon 'plus-lg' %}</span> {% trans "New volume" %}
|
||||
</button>
|
||||
|
||||
<!-- Modal Image -->
|
||||
<div class="modal fade" id="AddImage" tabindex="-1" role="dialog" aria-labelledby="AddImageLabel" aria-hidden="true">
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="AddImageLabel">{% trans "Add New Volume" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
||||
<h5 class="modal-title" id="AddImageLabel">{% trans "New volume" %}</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<form action="{% url 'create_volume' compute_id pool %}" id="create-volume" method="post" role="form" aria-label="Create volume to storage form">
|
||||
<form action="{% url 'create_volume' compute_id pool %}" id="create-volume" method="post" aria-label="{% trans "Create volume to storage form" %}">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form layout='horizontal' %}
|
||||
<div class="row">
|
||||
<div class="col-12">{% bootstrap_field form.name %}</div>
|
||||
<div class="col-sm-6">{% bootstrap_field form.size %}</div>
|
||||
<div class="col-sm-6">{% bootstrap_field form.format %}</div>
|
||||
<div class="col-12">{% bootstrap_field form.meta_prealloc %}</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" form="create-volume" class="btn btn-primary">{% trans "Create" %}</button>
|
||||
</div>
|
||||
</div> <!-- /.modal-content -->
|
||||
|
|
|
|||
|
|
@ -174,43 +174,36 @@
|
|||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="CloneVolumeLabel">{% trans "Clone image" %} <span class="text-danger" id="clone-image-name"></span></h5>
|
||||
<h5 class="modal-title" id="CloneVolumeLabel">{% trans "Clone image" %} <span class="font-monospace text-break" id="clone-image-name"></span></h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="{% trans "Close" %}"></button>
|
||||
</div>
|
||||
<form method="post" aria-labelledby="CloneVolumeLabel">{% csrf_token %}{% submission_key %}
|
||||
<div class="modal-body">
|
||||
<input type="hidden" name="image" id="clone-image">
|
||||
<div class="row mb-3">
|
||||
<label class="col-sm-3 col-form-label" for="clone-name">{% trans "Name" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input type="text" class="form-control" name="name" id="clone-name" required pattern="[a-zA-Z0-9\.\-_]+">
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="clone-name">{% trans "Name of the copy" %}</label>
|
||||
<input type="text" class="form-control" name="name" id="clone-name" required pattern="[a-zA-Z0-9\.\-_]+" aria-describedby="clone-name-help">
|
||||
<div class="form-text" id="clone-name-help">{% trans "Letters, digits, dot, dash and underscore." %}</div>
|
||||
</div>
|
||||
<div class="row mb-3">
|
||||
<label class="col-sm-3 col-form-label" for="clone-convert">{% trans "Convert" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-check-input mt-2" type="checkbox" name="convert" value="true" id="clone-convert">
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" name="convert" value="true" id="clone-convert">
|
||||
<label class="form-check-label" for="clone-convert">{% trans "Convert it to another format" %}</label>
|
||||
</div>
|
||||
<div class="row mb-3 d-none" id="clone-format-row">
|
||||
<label class="col-sm-3 col-form-label" for="clone-format">{% trans "Format" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<select name="format" class="form-select" id="clone-format">
|
||||
<option value="raw">{% trans "raw" %}</option>
|
||||
<option value="qcow">{% trans "qcow" %}</option>
|
||||
<option value="qcow2">{% trans "qcow2" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="mt-3 d-none" id="clone-format-row">
|
||||
<label class="form-label" for="clone-format">{% trans "Format" %}</label>
|
||||
<select name="format" class="form-select" id="clone-format">
|
||||
<option value="raw">{% trans "raw" %}</option>
|
||||
<option value="qcow">{% trans "qcow" %}</option>
|
||||
<option value="qcow2">{% trans "qcow2" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="row d-none" id="clone-prealloc-row">
|
||||
<label class="col-sm-3 col-form-label" for="clone-prealloc">{% trans "Metadata" %}</label>
|
||||
<div class="col-sm-6">
|
||||
<input class="form-check-input mt-2" type="checkbox" name="meta_prealloc" value="true" id="clone-prealloc">
|
||||
</div>
|
||||
<div class="form-check mt-3 d-none" id="clone-prealloc-row">
|
||||
<input class="form-check-input" type="checkbox" name="meta_prealloc" value="true" id="clone-prealloc">
|
||||
<label class="form-check-label" for="clone-prealloc">{% trans "Preallocate metadata (qcow2)" %}</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">{% trans "Close" %}</button>
|
||||
<button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">{% trans "Cancel" %}</button>
|
||||
<button type="submit" class="btn btn-primary" name="cln_volume">{% trans "Clone" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
|
|
|
|||
|
|
@ -41,6 +41,20 @@ class PoolPageTests(TestCase):
|
|||
self.assertIn("size", form.errors)
|
||||
self.assertIn("Size (GiB)", str(form["size"].label_tag()))
|
||||
|
||||
def test_the_dialogs_label_every_field_above_it(self):
|
||||
self.conn.get_size.return_value = (10, 4)
|
||||
self.conn.get_status.return_value = 1 # running: the add dialogs show
|
||||
for pool, dialog in (("default", "AddImage"), ("default", "CloneVolume"), ("iso", "IsoUpload")):
|
||||
with self.subTest(pool=pool, dialog=dialog):
|
||||
doc = html.fromstring(self.client.get(reverse("storage", args=[self.compute.pk, pool])).content)
|
||||
fields = doc.xpath("//div[@id=$d]//*[self::input or self::select][not(@type='hidden')]", d=dialog)
|
||||
self.assertTrue(fields)
|
||||
for field in fields:
|
||||
self.assertTrue(doc.xpath("//label[@for=$i]", i=field.get("id") or "-"), field.get("name"))
|
||||
self.assertFalse(doc.xpath("//div[@id=$d]//*[contains(@class, 'col-form-label')]", d=dialog))
|
||||
self.assertEqual(doc.xpath("//div[@id=$d]//button[@data-bs-dismiss='modal'][not(@aria-label)]/text()",
|
||||
d=dialog), ["Cancel"])
|
||||
|
||||
def test_the_pool_is_measured_after_its_refresh(self):
|
||||
# update_volumes refreshes the pool: libvirt's space figures are as of the last refresh
|
||||
self.conn.get_size.return_value = (10, 4)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue