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.
This commit is contained in:
2026-04-19 17:11:29 +02:00
parent 3bb2d23adb
commit b7e54db54c
10 changed files with 326 additions and 445 deletions
+1 -35
View File
@@ -2,9 +2,8 @@ use std::path::{Path, PathBuf};
use std::sync::Arc;
use std::time::SystemTime;
use askama::Template;
use axum::extract::State;
use axum::response::{Html, Redirect};
use axum::response::Redirect;
use time::OffsetDateTime;
use time::format_description::well_known::Rfc3339;
use tokio::io::AsyncWriteExt;
@@ -22,13 +21,6 @@ use crate::error::AppError;
use crate::paths::{DELETE_MARKER, DeleteMarker, read_delete_marker, write_delete_marker};
use crate::routes::user_web::locate_case_or_404;
#[derive(Template)]
#[template(path = "document.html")]
struct DocumentTemplate {
case_id: String,
content: String,
}
/// POST /web/cases/{case_id}/analyze
///
/// Trigger an LLM analysis for the case. If no document exists yet, writes
@@ -87,32 +79,6 @@ pub async fn handle_analyze_case(
Ok(Redirect::to("/web/cases"))
}
/// GET /web/cases/{case_id}/document
///
/// Render the latest `document_v{N}.md` for the case. The handler scans the
/// case directory and picks the highest N — no symlink, no separate pointer.
pub async fn handle_document_view(
user: AuthenticatedWebUser,
State(config): State<Arc<Config>>,
CaseIdPath(case_id): CaseIdPath,
) -> Result<Html<String>, AppError> {
let user_root = config.data_path.join(&user.slug);
let case_dir = locate_case_or_404(&user_root, &case_id, &user.slug, "document view").await?;
let md = read_document(&case_dir)
.await
.ok_or_else(|| AppError::NotFound("Noch kein Dokument erzeugt".into()))?;
let content = crate::analyze::render::md_to_html(&md);
DocumentTemplate {
case_id: case_id.to_string(),
content,
}
.render()
.map(Html)
.map_err(|e| AppError::Internal(format!("Template render failed: {e}")))
}
/// Build an `AnalysisInput` for the given case directory.
/// Collects all `.m4a` (excluding `.m4a.failed`), reads the matching
/// `.transcript.txt` for each, skips blank transcripts, and computes