1
0
Fork 0
mirror of https://github.com/retspen/webvirtcloud synced 2026-11-11 04:36:48 +00:00

feat(templates): every confirmation asks in the page's own dialog

Deleting or detaching a disk, deleting a network card, forcing a VM off,
reverting or deleting a snapshot, stopping or deleting a pool, a
network, an interface, a filter or a secret, and the other actions that
ask first opened the browser's yes/no box (confirm()), and the ISO
upload told its mistakes in the browser's alert().

One dialog in the base page now asks for all of them: its title and
confirming button carry the button's own words, its body the button's
question, the confirming button red for a destructive action. Confirmed,
the button is clicked again, so its form sends what it did before. A
button inside another dialog (the flavors) hides that one while asking
and shows it again after; Cancel gives the focus back, and the
confirming button acts once. The ISO upload's mistakes show in its
dialog's error box, announced.
This commit is contained in:
catborise 2026-10-31 20:22:49 +03:00
parent 95562544eb
commit c401479cf9
17 changed files with 114 additions and 68 deletions

View file

@ -1,29 +1,32 @@
"""A confirmation says what its action does: every prompt in a template is the
button's own data-confirm text, shown by return confirm(this.dataset.confirm)."""
"""A confirmation says what its action does, in the page's dialog: a button
asks its own data-confirm question through confirm_dialog.js, never the
browser's confirm()."""
import re
from pathlib import Path
from django.conf import settings
from django.test import SimpleTestCase
ONCLICK = 'onclick="return confirm(this.dataset.confirm)"'
class ConfirmPromptTests(SimpleTestCase):
def test_every_prompt_is_the_buttons_own_text(self):
def test_every_prompt_is_a_buttons_own_text_in_the_pages_dialog(self):
base = Path(settings.BASE_DIR)
templates = [*base.glob("*/templates/**/*.html"), *base.glob("templates/**/*.html")]
self.assertTrue(templates)
for path in templates:
text = path.read_text()
at = text.find("confirm(")
while at != -1:
with self.subTest(template=str(path.relative_to(base))):
self.assertNotIn("confirm(", text)
for match in re.finditer(r"data-confirm=", text):
# the tag around it: prompt texts and template tags hold no < or >
tag = text[text.rfind("<", 0, at):text.find(">", at) + 1]
tag = text[text.rfind("<", 0, match.start()):text.find(">", match.start()) + 1]
end = text.find("</button>", match.start())
content = re.sub(r"\{%\s*(bs_icon|if|elif|else|endif)\b[^%]*%\}", "",
text[text.find(">", match.start()) + 1:end]).strip()
with self.subTest(template=str(path.relative_to(base)), tag=tag[:60]):
self.assertRegex(tag, r"^<(button|input|a)\b")
self.assertIn(ONCLICK, tag)
self.assertIn('data-confirm="', tag)
self.assertRegex(tag, r"^<button\b")
self.assertNotIn('data-confirm=""', tag)
self.assertNotIn("Are you sure", tag)
at = text.find("confirm(", at + 1)
# the dialog's title and confirming button: the button's words, or an icon's name
self.assertTrue(content or "aria-label=" in tag or "title=" in tag)