Files
doctate/server/templates/my_cases.html
T
Brummel b7e54db54c Refactor case detail into a dedicated page
This commit restructures the web interface for case details. The
previous `/web/cases/{case_id}` route, which previously showed both the
case summary and its recordings, has been split into two distinct pages:

- `/web/cases/{case_id}`: This page now displays the overall case
  information, including the document if available.
- `/web/cases/{case_id}/recordings`: This new page is dedicated to
  listing and displaying individual recordings within a case.

This change improves the organization and clarity of the web UI,
allowing for more focused views of case data. Additionally, the
`case_detail.html` and `document.html` templates have been removed as
their functionality is now handled by the new `case_page.html` and the
upcoming document rendering logic. The `cases.html` template has also
been removed, indicating a shift towards more granular page views.
2026-04-19 17:11:29 +02:00

130 lines
6.2 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Doctate — Meine Fälle</title>
<style>
body { font-family: sans-serif; max-width: 900px; margin: 2em auto; padding: 0 1em; }
header { display: flex; justify-content: space-between; align-items: center; }
header form { margin: 0; }
section { margin: 1.5em 0; }
section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; padding-bottom: 0.2em; }
.empty { color: #888; font-style: italic; }
.case-list { list-style: none; padding: 0; margin: 0; }
.case-row { display: grid; grid-template-columns: auto 1fr auto; gap: 0.6em 1em; align-items: center; padding: 0.7em 1em; border: 1px solid #ccc; border-radius: 4px; margin: 0.5em 0; }
.case-row.done { border-left: 4px solid #7ed321; }
.case-row.open { border-left: 4px solid #4a90e2; }
.case-row .check { align-self: start; padding-top: 0.25em; }
.case-row .body { min-width: 0; }
.case-row .body a { color: inherit; text-decoration: none; }
.case-row .body a:hover .line1 { text-decoration: underline; }
.case-row .body h3 { margin: 0 0 0.2em 0; font-size: 1em; font-weight: 600; }
.case-row .body small { color: #666; font-family: monospace; font-size: 0.85em; }
.case-row .oneliner { color: #333; margin: 0.2em 0 0; }
.case-row .line1 { font-size: 1em; margin: 0; }
.case-row .line1 .time { font-family: monospace; font-weight: bold; color: #444; }
.case-row .line2 { margin: 0.2em 0 0; color: #555; font-size: 0.95em; display: flex; align-items: center; gap: 0.5em; }
.case-row .uuid { color: #999; font-family: monospace; font-size: 0.7em; margin-top: 0.2em; }
.status-badge { display: inline-block; padding: 0.05em 0.5em; border-radius: 999px; font-size: 0.75em; font-weight: bold; color: white; }
.status-badge.open { background: #e24a4a; }
.status-badge.done { background: #7ed321; }
.case-row .actions { display: flex; gap: 0.4em; }
.case-row .actions button { font-size: 0.85em; padding: 0.35em 0.8em; }
.label { display: inline-block; margin-left: 0.6em; padding: 0.05em 0.5em; border-radius: 999px; font-size: 0.75em; font-weight: bold; vertical-align: middle; }
.label.analyzing { background: #eee; color: #555; }
.label.done-doc { background: #7ed321; color: white; }
.bulk-bar { margin: 1em 0; padding: 0.8em 1em; background: #f6f6f6; border-radius: 4px; display: flex; gap: 0.6em; flex-wrap: wrap; align-items: center; }
.bulk-bar button { font-size: 0.9em; padding: 0.5em 1em; }
.bulk-bar .undo { margin-left: auto; }
.bulk-bar .undo button { background: #fff3cd; border: 1px solid #d39e00; color: #5a4500; }
</style>
</head>
<body>
<header>
<h1>{{ slug }} — Meine Fälle</h1>
<form method="post" action="/web/logout"><button type="submit">Logout</button></form>
</header>
{% if undo_count > 0 %}
<form class="bulk-bar" method="post" action="/web/cases/undo-delete" style="background:#fff8e1;">
<span><strong>{{ undo_count }}</strong> zuletzt gelöschte(r) Fall(/Fälle).</span>
<button type="submit">Löschung rückgängig</button>
</form>
{% endif %}
{% if total == 0 %}
<section><p class="empty">Keine Fälle.</p></section>
{% else %}
<form method="post" action="/web/cases/bulk">
{% for g in groups %}
<section>
<h2 class="date-group" data-iso="{{ g.label }}">{{ g.label }} ({{ g.cases.len() }})</h2>
<ul class="case-list">
{% for case in g.cases %}
<li class="case-row {% if case.has_document %}done{% else %}open{% endif %}">
<div class="check"><input type="checkbox" name="case_id" value="{{ case.case_id }}"></div>
<div class="body">
<a href="/web/cases/{{ case.case_id }}">
<div class="line1"><span class="time"><time datetime="{{ case.recorded_at_iso }}">{{ case.time_hms_utc }}</time></span>{% match case.oneliner %}{% when Some with (t) %} — {{ t }}{% when None %} — <span class="empty">kein Oneliner</span>{% endmatch %}</div>
<div class="line2">{{ case.recordings_count }} Aufnahmen{% if case.has_document %} — <span class="status-badge done">ausgewertet</span>{% else %} — <span class="status-badge open">offen</span>{% endif %}{% if case.analyzing %} <span class="label analyzing">wird analysiert</span>{% endif %}</div>
{% if is_admin %}<div class="uuid">{{ case.case_id }}</div>{% endif %}
</a>
</div>
<div class="actions">
<button type="submit" formaction="/web/cases/{{ case.case_id }}/analyze"{% if !case.can_analyze %} disabled{% endif %}>{% if case.has_document %}Neu analysieren{% else %}Analysieren{% endif %}</button>
{% if is_admin %}<button type="submit" formaction="/web/cases/{{ case.case_id }}/reset">Reset</button>{% endif %}
<button type="submit" formaction="/web/cases/{{ case.case_id }}/delete">Entfernen</button>
</div>
</li>
{% endfor %}
</ul>
</section>
{% endfor %}
<div class="bulk-bar">
<span>Auswahl:</span>
<button type="button" onclick="const b=document.querySelectorAll('input[name=case_id]');const all=Array.from(b).every(c=>c.checked);b.forEach(c=>c.checked=!all);this.textContent=all?'Alles auswählen':'Keine auswählen'">Alles auswählen</button>
<button type="submit" name="action" value="analyze">Analysieren</button>
{% if is_admin %}<button type="submit" name="action" value="reset">Reset</button>{% endif %}
<button type="submit" name="action" value="delete">Entfernen</button>
</div>
</form>
{% endif %}
<script>
// Render all UTC timestamps in the browser's local timezone, and relabel
// date-group headings to Heute/Gestern based on the browser's current
// UTC date. Server-side renders only UTC so timezone logic belongs here.
(function () {
document.querySelectorAll('time[datetime]').forEach(function (el) {
var d = new Date(el.dateTime);
if (!isNaN(d.getTime())) {
el.textContent = d.toLocaleTimeString(undefined, {
hour: '2-digit',
minute: '2-digit',
hour12: false,
});
}
});
var todayISO = new Date().toISOString().slice(0, 10);
var yesterday = new Date();
yesterday.setUTCDate(yesterday.getUTCDate() - 1);
var yesterdayISO = yesterday.toISOString().slice(0, 10);
document.querySelectorAll('h2.date-group').forEach(function (h) {
var iso = h.dataset.iso;
if (!iso) return;
var suffix = h.textContent.replace(iso, '').trim();
var label;
if (iso === todayISO) label = 'Heute';
else if (iso === yesterdayISO) label = 'Gestern';
else label = iso;
h.textContent = label + ' ' + suffix;
});
})();
</script>
</body>
</html>