mirror of
https://github.com/retspen/webvirtcloud
synced 2026-11-08 11:16:47 +00:00
feat(templates): the shared form and delete pages in a centred column
The pages many views share were a horizontal form whose Cancel went back in a primary colour beside a green Save, and a delete question in a yellow alert squeezed into half the width, which wrapped word by word on a phone. Both now sit in a centred column with their heading: the form's fields with their labels above in a card, Cancel outlined and Save the primary action; the delete page asks "Delete <name>?" in a card with a red edge, says what deleting does, and offers Cancel and Delete. The form for a user's rights on a VM names them as the VM's Users tab does: Change settings, Delete the VM, and Change console settings, which only counts together with Change settings.
This commit is contained in:
parent
9790da9931
commit
488a77b3c7
5 changed files with 49 additions and 33 deletions
|
|
@ -32,6 +32,10 @@ class UserInstanceForm(ModelForm):
|
|||
class Meta:
|
||||
model = UserInstance
|
||||
fields = "__all__"
|
||||
# the rights beyond power and console, as the VM's Users tab names them
|
||||
labels = {"is_change": _("Change settings"), "is_delete": _("Delete the VM"),
|
||||
"is_vnc": _("Change console settings")}
|
||||
help_texts = {"is_vnc": _("Only together with Change settings")}
|
||||
|
||||
|
||||
class UniqueEmailMixin:
|
||||
|
|
|
|||
|
|
@ -71,3 +71,12 @@ class AccountPageTests(TestCase):
|
|||
url = reverse("accounts:account_ssh_key_delete", args=[self.alice.pk, self.key.pk])
|
||||
self.assertEqual(self.client.post(url).status_code, 403)
|
||||
self.assertTrue(UserSSHKey.objects.exists())
|
||||
|
||||
def test_the_owner_form_names_the_rights_as_the_vm_page_does(self):
|
||||
compute = Compute.objects.create(name="ap-host2", hostname="localhost", login="", password="", details="", type=4)
|
||||
vm = Instance.objects.create(compute=compute, name="ap-vm2", uuid="00000000-0000-0000-0000-000000000002")
|
||||
owner = UserInstance.objects.create(user=self.alice, instance=vm)
|
||||
response = self.client.get(reverse("accounts:user_instance_update", args=[owner.pk]))
|
||||
for label in ("Change settings", "Delete the VM", "Change console settings"):
|
||||
self.assertContains(response, label)
|
||||
self.assertNotContains(response, "Is vnc")
|
||||
|
|
|
|||
|
|
@ -1,29 +1,31 @@
|
|||
{% extends "base.html" %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% load bootstrap_icons %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{% trans "Delete" %} {{ object }}{% endblock %}
|
||||
|
||||
{% block page_heading %}{% trans "Delete" %} {{ object }}{% endblock page_heading %}
|
||||
{% block page_header %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8"><h3 class="mb-3 text-break">{% trans "Delete" %} {{ object }}</h3></div>
|
||||
</div>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="offset-3 col-6">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
<div class="alert alert-warning">
|
||||
{% blocktrans %}Delete "{{ object }}"?{% endblocktrans %} {{ consequence }}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body border-start border-danger border-4 rounded-start">
|
||||
<h4 class="h5 text-break">{% bs_icon 'trash' %} {% blocktrans %}Delete <strong>{{ object }}</strong>?{% endblocktrans %}</h4>
|
||||
{% if consequence %}<p class="mb-0">{{ consequence }}</p>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-0 float-end">
|
||||
<a class="btn btn-primary" href="javascript:history.back()">
|
||||
{% bs_icon 'x-circle-fill' %} {% trans "Cancel" %}
|
||||
</a>
|
||||
<button type="submit" class="btn btn-danger">
|
||||
{% bs_icon 'trash-fill' %} {% trans "Delete" %}
|
||||
</button>
|
||||
<div class="d-flex flex-wrap justify-content-end gap-2">
|
||||
<a class="btn btn-outline-secondary" href="javascript:history.back()">{% trans "Cancel" %}</a>
|
||||
<button type="submit" class="btn btn-danger">{% trans "Delete" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
||||
{% endblock %}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,28 @@
|
|||
{% extends "base.html" %}
|
||||
{% load django_bootstrap5 %}
|
||||
{% load bootstrap_icons %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block title %}{{ title }}{% endblock %}
|
||||
|
||||
{% block page_heading %}{{ title }}{% endblock page_heading %}
|
||||
{% block page_header %}
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8"><h3 class="mb-3">{{ title }}</h3></div>
|
||||
</div>
|
||||
{% endblock page_header %}
|
||||
|
||||
{% block content %}
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<form id="create-update" action="" method="post">
|
||||
<div class="row justify-content-center">
|
||||
<div class="col-lg-8">
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{% bootstrap_form form layout='horizontal' %}
|
||||
<div class="card mb-3">
|
||||
<div class="card-body">{% bootstrap_form form %}</div>
|
||||
</div>
|
||||
<div class="d-flex flex-wrap justify-content-end gap-2">
|
||||
<a class="btn btn-outline-secondary" href="javascript:history.back()">{% trans "Cancel" %}</a>
|
||||
<button type="submit" class="btn btn-primary">{% trans "Save" %}</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
<div class="card-footer">
|
||||
<div class="mb-0 float-end">
|
||||
<a class="btn btn-primary" href="javascript:history.back()">{% bs_icon 'x' %} {% trans "Cancel" %}</a>
|
||||
<button type="submit" form="create-update" class="btn btn-success">
|
||||
{% bs_icon 'check2' %} {% trans "Save" %}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock content %}
|
||||
{% endblock content %}
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ class DeletePageTests(TestCase):
|
|||
self.client.force_login(admin)
|
||||
for url, consequence in pages.items():
|
||||
with self.subTest(url=url):
|
||||
alert = html.fromstring(self.client.get(url).content).xpath("//div[contains(@class, 'alert-warning')]")
|
||||
self.assertEqual(len(alert), 1)
|
||||
self.assertIn(consequence, alert[0].text_content())
|
||||
self.assertNotIn("Are you sure", alert[0].text_content())
|
||||
card = html.fromstring(self.client.get(url).content).xpath("//div[contains(@class, 'border-danger')]")
|
||||
self.assertEqual(len(card), 1)
|
||||
self.assertIn(consequence, card[0].text_content())
|
||||
self.assertNotIn("Are you sure", card[0].text_content())
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue