Polish forms and action flows #35

Merged
parkel merged 4 commits from issue-25-forms-action-flows into master 2026-05-21 14:28:21 +02:00
3 changed files with 23 additions and 5 deletions
Showing only changes of commit 1604f0f6f4 - Show all commits

View File

@@ -104,8 +104,12 @@
</section> </section>
{% if plan.delete %} {% if plan.delete %}
<section class="panel"> <section class="panel highlight warning">
<h2>Apply Retention</h2> <h2>Apply Retention</h2>
<p class="muted">
This permanently deletes the snapshot directories listed in Would Delete. Confirm the host and delete count
before applying the plan.
</p>
<form method="post" action="{% url 'apply_host_retention' host.host %}" class="form-grid"> <form method="post" action="{% url 'apply_host_retention' host.host %}" class="form-grid">
{% csrf_token %} {% csrf_token %}
{{ apply_form.non_field_errors }} {{ apply_form.non_field_errors }}
@@ -138,8 +142,9 @@
<div class="helptext">{{ apply_form.confirm_delete_count.help_text }}</div> <div class="helptext">{{ apply_form.confirm_delete_count.help_text }}</div>
</div> </div>
<div class="actions"> <div class="form-actions">
<button type="submit">Apply retention</button> <button type="submit" class="danger">Apply retention</button>
<a class="button-link secondary" href="{% url 'host_retention_plan' host.host %}?kind={{ kind }}">Cancel</a>
</div> </div>
</form> </form>
</section> </section>
@@ -200,6 +205,10 @@
</table> </table>
<h3>Cleanup Incomplete Snapshots</h3> <h3>Cleanup Incomplete Snapshots</h3>
<p class="muted">
This deletes only incomplete snapshot directories and their tracking records. Successful manual and scheduled
snapshots are not touched.
</p>
<form method="post" action="{% url 'cleanup_host_incomplete_snapshots' host.host %}" class="form-grid"> <form method="post" action="{% url 'cleanup_host_incomplete_snapshots' host.host %}" class="form-grid">
{% csrf_token %} {% csrf_token %}
{{ incomplete_cleanup_form.non_field_errors }} {{ incomplete_cleanup_form.non_field_errors }}
@@ -225,8 +234,9 @@
<div class="helptext">{{ incomplete_cleanup_form.confirm_delete_count.help_text }}</div> <div class="helptext">{{ incomplete_cleanup_form.confirm_delete_count.help_text }}</div>
</div> </div>
<div class="actions"> <div class="form-actions">
<button type="submit">Delete incomplete snapshots</button> <button type="submit" class="danger">Delete incomplete snapshots</button>
<a class="button-link secondary" href="{% url 'host_retention_plan' host.host %}?kind={{ kind }}">Cancel</a>
</div> </div>
</form> </form>
</section> </section>

View File

@@ -67,6 +67,7 @@
</div> </div>
<div class="form-actions"> <div class="form-actions">
<button type="submit" class="danger" {% if credential.hosts.exists or credential.global_configs.exists %}disabled{% endif %}>Delete SSH key</button> <button type="submit" class="danger" {% if credential.hosts.exists or credential.global_configs.exists %}disabled{% endif %}>Delete SSH key</button>
<a class="button-link secondary" href="{% url 'ssh_credentials' %}">Cancel</a>
</div> </div>
</form> </form>
</section> </section>

View File

@@ -554,6 +554,8 @@ class ViewTests(TestCase):
self.assertEqual(response.status_code, 200) self.assertEqual(response.status_code, 200)
self.assertContains(response, "Cancel") self.assertContains(response, "Cancel")
self.assertContains(response, reverse("ssh_credentials")) self.assertContains(response, reverse("ssh_credentials"))
self.assertContains(edit_response, "Delete SSH key")
self.assertContains(edit_response, 'class="danger"', html=False)
def test_ssh_credentials_view_generates_filesystem_key(self) -> None: def test_ssh_credentials_view_generates_filesystem_key(self) -> None:
self.client.force_login(self.staff_user) self.client.force_login(self.staff_user)
@@ -1835,6 +1837,9 @@ class ViewTests(TestCase):
self.assertNotContains(response, "<div class=\"label\">Source</div>", html=True) self.assertNotContains(response, "<div class=\"label\">Source</div>", html=True)
self.assertContains(response, "Confirm delete count") self.assertContains(response, "Confirm delete count")
self.assertContains(response, "Type 1 to confirm the current number of planned deletions.") self.assertContains(response, "Type 1 to confirm the current number of planned deletions.")
self.assertContains(response, "This permanently deletes the snapshot directories listed in Would Delete.")
self.assertContains(response, 'class="danger"', html=False)
self.assertContains(response, "Cancel")
def test_retention_plan_warns_when_scheduled_prune_limit_is_exceeded(self) -> None: def test_retention_plan_warns_when_scheduled_prune_limit_is_exceeded(self) -> None:
self.client.force_login(self.staff_user) self.client.force_login(self.staff_user)
@@ -1910,6 +1915,8 @@ class ViewTests(TestCase):
self.assertContains(response, "excluded from retention cleanup") self.assertContains(response, "excluded from retention cleanup")
self.assertContains(response, "Delete incomplete snapshots") self.assertContains(response, "Delete incomplete snapshots")
self.assertContains(response, "Type 1 to confirm the current number of incomplete snapshots.") self.assertContains(response, "Type 1 to confirm the current number of incomplete snapshots.")
self.assertContains(response, "This deletes only incomplete snapshot directories")
self.assertContains(response, 'class="danger"', html=False)
def test_incomplete_cleanup_deletes_incomplete_snapshot_after_confirmation(self) -> None: def test_incomplete_cleanup_deletes_incomplete_snapshot_after_confirmation(self) -> None:
self.client.force_login(self.staff_user) self.client.force_login(self.staff_user)