From 488a77b3c74d9ffa2da64db418aef69933beb8c4 Mon Sep 17 00:00:00 2001 From: catborise Date: Sat, 31 Oct 2026 14:56:33 +0300 Subject: [PATCH] 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 ?" 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. --- accounts/forms.py | 4 ++++ accounts/tests/test_account_page.py | 9 +++++++ templates/common/confirm_delete.html | 30 +++++++++++++----------- templates/common/form.html | 31 +++++++++++++------------ webvirtcloud/tests/test_delete_pages.py | 8 +++---- 5 files changed, 49 insertions(+), 33 deletions(-) diff --git a/accounts/forms.py b/accounts/forms.py index 5db2cb54..f2d665fb 100644 --- a/accounts/forms.py +++ b/accounts/forms.py @@ -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: diff --git a/accounts/tests/test_account_page.py b/accounts/tests/test_account_page.py index a94306c3..66e52513 100644 --- a/accounts/tests/test_account_page.py +++ b/accounts/tests/test_account_page.py @@ -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") diff --git a/templates/common/confirm_delete.html b/templates/common/confirm_delete.html index 60a43907..3656cecf 100644 --- a/templates/common/confirm_delete.html +++ b/templates/common/confirm_delete.html @@ -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 %} +
+

{% trans "Delete" %} {{ object }}

+
+{% endblock page_header %} {% block content %} -
-
+
+
{% csrf_token %} -
- {% blocktrans %}Delete "{{ object }}"?{% endblocktrans %} {{ consequence }} +
+
+

{% bs_icon 'trash' %} {% blocktrans %}Delete {{ object }}?{% endblocktrans %}

+ {% if consequence %}

{{ consequence }}

{% endif %} +
-
- - {% bs_icon 'x-circle-fill' %} {% trans "Cancel" %} - - +
+ {% trans "Cancel" %} +
-{% endblock %} \ No newline at end of file +{% endblock %} diff --git a/templates/common/form.html b/templates/common/form.html index ee5f2d43..b08aaadd 100644 --- a/templates/common/form.html +++ b/templates/common/form.html @@ -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 %} +
+

{{ title }}

+
+{% endblock page_header %} {% block content %} -
-
-
+
+
+ {% csrf_token %} - {% bootstrap_form form layout='horizontal' %} +
+
{% bootstrap_form form %}
+
+
+ {% trans "Cancel" %} + +
-
-{% endblock content %} \ No newline at end of file +{% endblock content %} diff --git a/webvirtcloud/tests/test_delete_pages.py b/webvirtcloud/tests/test_delete_pages.py index 90a8721a..08d25763 100644 --- a/webvirtcloud/tests/test_delete_pages.py +++ b/webvirtcloud/tests/test_delete_pages.py @@ -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())