fix: preserve show_closed view + ungrey closed-case controls

Three UX polish items for the show-closed listing, grouped because
they are the same root problem in three surfaces:

* handle_reopen_case now redirects via resolve_return_path(&headers)
  instead of hard-coding /web/cases, so a reopen from the
  ?show_closed=1 listing stays in that view. Matches the pattern
  already used by analyze/reset/delete-recording.

* handle_close_case now redirects via the new helper
  resolve_list_return_path(&headers), which wraps resolve_return_path
  and additionally collapses a /web/cases/{uuid} detail path to
  /web/cases while keeping the query string. A close from the detail
  page previously would have tried to redirect back to the now-404
  detail, or when triggered from ?show_closed=1 would have dropped
  the query.

* Closed cases in my_cases.html now render the checkbox,
  Analysieren/Neu analysieren and Reset controls in disabled state
  instead of being hidden. Layout stays consistent with mixed-state
  listings, and the user can see what actions would be available
  after reopen. The handlers remain the authoritative guard via
  locate_case_or_404 -> 404 for closed cases, so the HTML disabled
  is a hint only.

Adds four unit tests for resolve_list_return_path and two integration
tests for the new redirect behaviour (close from listing with query,
close from detail with query).
This commit is contained in:
2026-04-21 11:20:17 +02:00
parent 23e828df45
commit 8b1f58ba23
3 changed files with 191 additions and 7 deletions
+3 -3
View File
@@ -92,7 +92,7 @@ try {
<ul class="case-list">
{% for case in g.cases %}
<li class="case-row {% if case.is_closed %}closed{% else if case.has_document %}done{% else %}open{% endif %}">
<div class="check">{% if !case.is_closed %}<input type="checkbox" name="case_id" value="{{ case.case_id }}">{% endif %}</div>
<div class="check"><input type="checkbox" name="case_id" value="{{ case.case_id }}"{% if case.is_closed %} disabled{% endif %}></div>
<div class="body">
<a href="/web/cases/{{ case.case_id }}{% if case.is_closed %}?show_closed=1{% endif %}">
<div class="line1"><span class="time"><time datetime="{{ case.recorded_at_iso }}">{{ case.time_hms_utc }}</time></span> — {% call ol::render(case.oneliner) %}</div>
@@ -101,8 +101,8 @@ try {
</a>
</div>
<div class="actions">
{% if !case.is_closed && is_admin %}<button type="submit" formaction="/web/cases/{{ case.case_id }}/analyze" class="admin-only"{% if !case.can_analyze %} disabled{% endif %}>{% if case.has_document %}Neu analysieren{% else %}Analysieren{% endif %}</button>
<button type="submit" formaction="/web/cases/{{ case.case_id }}/reset" class="admin-only">Reset</button>{% endif %}
{% if is_admin %}<button type="submit" formaction="/web/cases/{{ case.case_id }}/analyze" class="admin-only"{% if !case.can_analyze || case.is_closed %} disabled{% endif %}>{% if case.has_document %}Neu analysieren{% else %}Analysieren{% endif %}</button>
<button type="submit" formaction="/web/cases/{{ case.case_id }}/reset" class="admin-only"{% if case.is_closed %} disabled{% endif %}>Reset</button>{% endif %}
{% if case.is_closed %}
<button type="submit" formaction="/web/cases/{{ case.case_id }}/reopen" class="reopen-btn" title="Fall wiedereröffnen" aria-label="Fall wiedereröffnen"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="16" height="16" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"></path><path d="M3 3v5h5"></path></svg></button>
{% else %}