diff --git a/server/templates/case_page.html b/server/templates/case_page.html index ce3459e..85a17b2 100644 --- a/server/templates/case_page.html +++ b/server/templates/case_page.html @@ -19,6 +19,8 @@ h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; } .actions .analyzing { color: #888; font-style: italic; } .actions .llm-missing { color: #a66; font-style: italic; } .actions .delete-form { margin-left: auto; } +.actions .delete-btn { padding: 0.4em; background: transparent; border: none; color: #888; cursor: pointer; display: inline-flex; align-items: center; line-height: 0; border-radius: 4px; transition: color 0.15s, background 0.15s; } +.actions .delete-btn:hover { color: #e24a4a; background: #fff0f0; } .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; } @@ -34,12 +36,26 @@ h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; } .copy-btn.copied { color: #2d8c2d; opacity: 1; } .copy-btn.copied .icon-copy { display: none; } .copy-btn.copied .icon-check { display: block; } + +.header-right { display: flex; align-items: center; gap: 0.8em; } +.admin-toggle { font-size: 0.85em; color: #666; display: inline-flex; align-items: center; gap: 0.3em; cursor: pointer; user-select: none; } +html.admin-view-off .admin-only { display: none !important; } +
← Fälle
+
+{% if is_admin %}{% endif %}
+

{% match oneliner %} @@ -48,7 +64,7 @@ h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; } {% endmatch %} {% if has_document %}ausgewertet{% else %}offen{% endif %}

-{% if is_admin %}
{{ case_id }}
{% endif %} +{% if is_admin %}
{{ case_id }}
{% endif %}
{% if analyzing %} @@ -59,9 +75,9 @@ h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; } LLM-Analyse nicht konfiguriert {% endif %} {% if is_admin %} -
+
{% endif %} -
+
{% match document_html %} @@ -120,5 +136,17 @@ h1 { display: flex; align-items: center; gap: 0.6em; flex-wrap: wrap; }
→ Aufnahmen anzeigen ({{ recordings_count }})
+ diff --git a/server/templates/case_recordings.html b/server/templates/case_recordings.html index 25de214..a11df28 100644 --- a/server/templates/case_recordings.html +++ b/server/templates/case_recordings.html @@ -18,7 +18,18 @@ header form { margin: 0; } .transcript { margin: 0.6em 0 0; padding: 0.6em; background: #f6f6f6; border-radius: 4px; white-space: pre-wrap; font-family: serif; } .pending { color: #888; font-style: italic; margin-top: 0.5em; } .failed { color: #b00; font-weight: bold; margin-top: 0.5em; } + +.header-right { display: flex; align-items: center; gap: 0.8em; } +.admin-toggle { font-size: 0.85em; color: #666; display: inline-flex; align-items: center; gap: 0.3em; cursor: pointer; user-select: none; } +html.admin-view-off .admin-only { display: none !important; } +
@@ -31,10 +42,13 @@ header form { margin: 0; } ← Fall {% endmatch %} +
+{% if is_admin %}{% endif %}
+

Aufnahmen

-{% if is_admin %}
{{ case_id }}
{% endif %} +{% if is_admin %}
{{ case_id }}
{% endif %}

Aufnahmen ({{ recordings.len() }})

{% for rec in recordings %} @@ -65,5 +79,17 @@ header form { margin: 0; } {% endif %} {% endfor %} + diff --git a/server/templates/my_cases.html b/server/templates/my_cases.html index 058dfdf..0db5656 100644 --- a/server/templates/my_cases.html +++ b/server/templates/my_cases.html @@ -29,8 +29,10 @@ section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; paddi .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 { display: flex; gap: 0.4em; align-items: center; } .case-row .actions button { font-size: 0.85em; padding: 0.35em 0.8em; } +.case-row .actions .delete-btn { padding: 0.3em; background: transparent; border: none; color: #888; cursor: pointer; display: inline-flex; align-items: center; line-height: 0; border-radius: 4px; transition: color 0.15s, background 0.15s; } +.case-row .actions .delete-btn:hover { color: #e24a4a; background: #fff0f0; } .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; } @@ -40,12 +42,26 @@ section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; paddi .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; } + +.header-right { display: flex; align-items: center; gap: 0.8em; } +.admin-toggle { font-size: 0.85em; color: #666; display: inline-flex; align-items: center; gap: 0.3em; cursor: pointer; user-select: none; } +html.admin-view-off .admin-only { display: none !important; } +

{{ slug }} — Meine Fälle

+
+{% if is_admin %}{% endif %}
+
{% if undo_count > 0 %} @@ -70,13 +86,13 @@ section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; paddi
{% match case.oneliner %}{% when Some with (t) %} — {{ t }}{% when None %} — kein Oneliner{% endmatch %}
{{ case.recordings_count }} Aufnahmen{% if case.has_document %} — ausgewertet{% else %} — offen{% endif %}{% if case.analyzing %} wird analysiert{% endif %}
-{% if is_admin %}
{{ case.case_id }}
{% endif %} +{% if is_admin %}
{{ case.case_id }}
{% endif %}
-{% if is_admin %}{% endif %} - +{% if is_admin %}{% endif %} +
{% endfor %} @@ -87,7 +103,7 @@ section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; paddi Auswahl: -{% if is_admin %}{% endif %} +{% if is_admin %}{% endif %} @@ -124,6 +140,17 @@ section h2 { font-size: 1.1em; color: #555; border-bottom: 1px solid #ddd; paddi h.textContent = label + ' ' + suffix; }); })(); + +(() => { + const cb = document.getElementById('admin-view-toggle'); + if (!cb) return; + cb.checked = !document.documentElement.classList.contains('admin-view-off'); + cb.addEventListener('change', () => { + const on = cb.checked; + try { localStorage.setItem('admin-view', on ? 'on' : 'off'); } catch (_) {} + document.documentElement.classList.toggle('admin-view-off', !on); + }); +})(); diff --git a/server/tests/case_page_test.rs b/server/tests/case_page_test.rs index 8178335..0b04659 100644 --- a/server/tests/case_page_test.rs +++ b/server/tests/case_page_test.rs @@ -326,6 +326,44 @@ async fn case_page_uses_oneliner_as_h1_when_present() { ); } +#[tokio::test] +async fn case_page_admin_sees_admin_view_toggle() { + let data_path = unique_tmp("cp-toggle"); + let users = vec![make_admin("dr_admin")]; + let config = config_with_llm_users(data_path, "http://unused".into(), users); + let case_id = "11111111-1111-1111-1111-111111111111"; + seed_case(&config.data_path, "dr_admin", case_id); + + let app = doctate_server::create_router(config); + let cookie = login(app.clone(), "dr_admin").await; + + let resp = app.oneshot(get_page(case_id, &cookie, "")).await.unwrap(); + let body = body_string(resp).await; + + assert!( + body.contains(r#"id="admin-view-toggle""#), + "admin must see the admin-view toggle checkbox" + ); +} + +#[tokio::test] +async fn case_page_non_admin_has_no_admin_view_toggle() { + let config = config_with_llm(unique_tmp("cp-no-toggle")); + let case_id = "11111111-1111-1111-1111-111111111111"; + seed_case(&config.data_path, "dr_a", case_id); + + let app = doctate_server::create_router(config); + let cookie = login(app.clone(), "dr_a").await; + + let resp = app.oneshot(get_page(case_id, &cookie, "")).await.unwrap(); + let body = body_string(resp).await; + + assert!( + !body.contains(r#"id="admin-view-toggle""#), + "non-admin must not see the admin-view toggle" + ); +} + #[tokio::test] async fn case_page_admin_sees_full_case_id_meta() { let data_path = unique_tmp("cp-admin");