Files
doctate/server/templates/case_page.html
T
Brummel 6369ff1680 feat: Add admin flag to user and templates
Passes an `is_admin` flag to the `CaseRecordingsTemplate` and
`case_page.html`.
This flag determines whether the full case ID is displayed in the meta
section
for administrative users. It also influences the header display on the
case page
to prioritize the oneliner when available.
2026-04-19 17:33:29 +02:00

125 lines
5.7 KiB
HTML

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="utf-8">
<title>Doctate — Fall {{ case_id_short }}</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; }
.back { color: #4a90e2; text-decoration: none; }
h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; }
.meta { color: #999; font-family: monospace; font-size: 0.8em; margin: 0 0 1em; }
.status-badge { display: inline-block; padding: 0.1em 0.6em; border-radius: 999px; font-size: 0.6em; font-weight: bold; color: white; vertical-align: middle; }
.status-badge.open { background: #4a90e2; }
.status-badge.done { background: #7ed321; }
.actions { margin: 1em 0 1.5em; display: flex; align-items: center; gap: 0.4em; }
.actions form { margin: 0; display: inline; }
.actions button { font-size: 1em; padding: 0.5em 1em; }
.actions .analyzing { color: #888; font-style: italic; }
.actions .llm-missing { color: #a66; font-style: italic; }
.actions .delete-form { margin-left: auto; }
.placeholder { color: #888; font-style: italic; margin: 1em 0; }
.status-panel { margin: 1em 0; padding: 0.8em 1em; background: #f6f6f6; border-radius: 4px; }
.recordings-link { display: inline-block; margin: 1em 0; color: #4a90e2; text-decoration: none; font-size: 0.95em; }
.recordings-link:hover { text-decoration: underline; }
.doc-content { position: relative; font-family: serif; font-size: 1.05em; line-height: 1.55; background: #f6f6f6; padding: 1em 1.2em; border-radius: 4px; }
.doc-content p { margin: 0.8em 0; }
.doc-content p:first-child { margin-top: 0; }
.doc-content p:last-child { margin-bottom: 0; }
.doc-content mark { background: #fff3a8; padding: 0 0.2em; border-radius: 2px; }
.copy-btn { position: absolute; bottom: 0.5em; right: 0.5em; padding: 0.35em; background: transparent; border: none; border-radius: 4px; cursor: pointer; color: #888; display: inline-flex; align-items: center; justify-content: center; line-height: 0; opacity: 0.45; transition: opacity 0.15s, color 0.15s; }
.copy-btn:hover { color: #4a90e2; opacity: 1; }
.copy-btn .icon-check { display: none; }
.copy-btn.copied { color: #2d8c2d; opacity: 1; }
.copy-btn.copied .icon-copy { display: none; }
.copy-btn.copied .icon-check { display: block; }
</style>
</head>
<body>
<header>
<div><a class="back" href="/web/cases">&larr; Fälle</a></div>
<form method="post" action="/web/logout"><button type="submit">Logout</button></form>
</header>
<h1>
{% match oneliner %}
{% when Some with (t) %}{{ t }}
{% when None %}Fall
{% endmatch %}
{% if has_document %}<span class="status-badge done">ausgewertet</span>{% else %}<span class="status-badge open">offen</span>{% endif %}
</h1>
{% if is_admin %}<div class="meta">{{ case_id }}</div>{% endif %}
<div class="actions">
{% if analyzing %}
<span class="analyzing">wird analysiert …</span>
{% else if can_analyze %}
<form method="post" action="/web/cases/{{ case_id }}/analyze"><button type="submit">{% if has_document %}Neu analysieren{% else %}Analysieren{% endif %}</button></form>
{% else if llm_missing && !has_document %}
<span class="llm-missing">LLM-Analyse nicht konfiguriert</span>
{% endif %}
{% if is_admin %}
<form method="post" action="/web/cases/{{ case_id }}/reset"><button type="submit">Reset</button></form>
{% endif %}
<form class="delete-form" method="post" action="/web/cases/{{ case_id }}/delete"><button type="submit">Entfernen</button></form>
</div>
{% match document_html %}
{% when Some with (html) %}
<div id="doc-content" class="doc-content">
<button id="copy-btn" type="button" class="copy-btn" title="In Zwischenablage kopieren" hidden>
<svg class="icon-copy" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path></svg>
<svg class="icon-check" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"></polyline></svg>
</button>
<div id="doc-body">{{ html|safe }}</div>
</div>
<script>
(() => {
const btn = document.getElementById('copy-btn');
if (!btn) return;
btn.hidden = false;
btn.addEventListener('click', async () => {
const text = document.getElementById('doc-body').innerText;
let ok = false;
try {
if (navigator.clipboard && window.isSecureContext) {
await navigator.clipboard.writeText(text);
ok = true;
}
} catch (_) { /* fall through */ }
if (!ok) {
const ta = document.createElement('textarea');
ta.value = text;
ta.setAttribute('readonly', '');
ta.style.position = 'fixed';
ta.style.top = '-1000px';
document.body.appendChild(ta);
ta.select();
try { ok = document.execCommand('copy'); } catch (_) {}
ta.remove();
}
if (ok) {
btn.classList.add('copied');
setTimeout(() => btn.classList.remove('copied'), 1500);
}
});
})();
</script>
{% when None %}
{% if analyzing %}
<div class="placeholder">Wird analysiert …</div>
{% else if recordings_count == 0 %}
<div class="placeholder">Noch keine Aufnahmen vorhanden.</div>
{% else %}
<div class="status-panel">
{{ recordings_count }} Aufnahme{% if recordings_count != 1 %}n{% endif %}, davon {{ transcribed_count }} transkribiert.
</div>
{% endif %}
{% endmatch %}
<div>
<a class="recordings-link" href="/web/cases/{{ case_id }}/recordings">&rarr; Aufnahmen anzeigen ({{ recordings_count }})</a>
</div>
</body>
</html>