Refactor case pages into two distinct routes
This commit separates the case detail page into two distinct routes:
`/web/cases/{case_id}` for the main case information and document, and
`/web/cases/{case_id}/recordings` for a dedicated view of audio files
and their transcripts.
This change improves the organization and clarity of the case viewing
experience by segmenting the related but distinct information into their
own UI sections.
This commit is contained in:
@@ -27,80 +27,6 @@ fn test_config() -> Arc<Config> {
|
||||
})
|
||||
}
|
||||
|
||||
async fn body_to_string(response: axum::response::Response) -> String {
|
||||
let bytes = axum::body::to_bytes(response.into_body(), usize::MAX)
|
||||
.await
|
||||
.unwrap();
|
||||
String::from_utf8(bytes.to_vec()).unwrap()
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn web_index_empty() {
|
||||
let config = test_config();
|
||||
let app = doctate_server::create_router(config);
|
||||
|
||||
let response = app
|
||||
.oneshot(Request::builder().uri("/web/").body(Body::empty()).unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let body = body_to_string(response).await;
|
||||
assert!(body.contains("No cases found"));
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn web_index_shows_cases() {
|
||||
let config = test_config();
|
||||
let data_path = config.data_path.clone();
|
||||
|
||||
// Pre-create cases on disk
|
||||
let case1 = "550e8400-e29b-41d4-a716-446655440000";
|
||||
let case2 = "660e8400-e29b-41d4-a716-446655440000";
|
||||
|
||||
let open_case = data_path.join("dr_test").join(case1);
|
||||
std::fs::create_dir_all(&open_case).unwrap();
|
||||
std::fs::write(open_case.join("2026-04-13T10-30-00Z.m4a"), b"fake audio 1").unwrap();
|
||||
|
||||
let done_case = data_path.join("dr_test").join(case2);
|
||||
std::fs::create_dir_all(&done_case).unwrap();
|
||||
std::fs::write(done_case.join("2026-04-12T09-00-00Z.m4a"), b"fake audio 2").unwrap();
|
||||
std::fs::write(
|
||||
done_case.join("2026-04-12T09-00-00Z.transcript.txt"),
|
||||
"Herzkatheter ohne Befund.",
|
||||
)
|
||||
.unwrap();
|
||||
std::fs::write(done_case.join("oneliner.txt"), "Herzkatheter unauffällig").unwrap();
|
||||
|
||||
let app = doctate_server::create_router(config);
|
||||
let response = app
|
||||
.oneshot(Request::builder().uri("/web/").body(Body::empty()).unwrap())
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(response.status(), StatusCode::OK);
|
||||
let body = body_to_string(response).await;
|
||||
|
||||
assert!(body.contains(case1));
|
||||
assert!(body.contains(case2));
|
||||
assert!(body.contains("dr_test"));
|
||||
assert!(body.contains("<audio"));
|
||||
assert!(body.contains("2026-04-13T10-30-00Z.m4a"));
|
||||
// case1 has no transcript → pending placeholder
|
||||
assert!(body.contains("Transcription pending"));
|
||||
// case2 has a transcript → rendered
|
||||
assert!(body.contains("Herzkatheter ohne Befund."));
|
||||
// case2 has an oneliner → rendered exactly once (case1 has none)
|
||||
assert!(body.contains("Herzkatheter unauffällig"));
|
||||
assert_eq!(
|
||||
body.matches("class=\"oneliner\"").count(),
|
||||
1,
|
||||
"expected exactly one oneliner div"
|
||||
);
|
||||
|
||||
let _ = std::fs::remove_dir_all(&data_path);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn web_audio_serves_file() {
|
||||
let config = test_config();
|
||||
|
||||
Reference in New Issue
Block a user