Web dashboard step 7: docs, users page, polish
Users page, README and config.example updates, implementation notes, the rollout runbook, site-layout 404/500 pages, human-readable download sizes, dark-mode and narrow-screen polish, and a smoke test over every dashboard route; also removes zdiff3 ancestor markers left by earlier merges. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01NHyYupFdBiR4VfoUM7NjSM
This commit is contained in:
+28
-1
@@ -25,6 +25,7 @@ pub struct Download {
|
||||
pub label: String,
|
||||
pub href: String,
|
||||
pub size_bytes: u64,
|
||||
pub size: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
@@ -192,9 +193,26 @@ fn download(
|
||||
label: label.to_string(),
|
||||
href: format!("/files/{kind}/{}", crate::web::encode_component(name)),
|
||||
size_bytes: metadata.len(),
|
||||
size: format_file_size(metadata.len()),
|
||||
})
|
||||
}
|
||||
|
||||
fn format_file_size(bytes: u64) -> String {
|
||||
const KB: f64 = 1024.0;
|
||||
const MB: f64 = KB * 1024.0;
|
||||
const GB: f64 = MB * 1024.0;
|
||||
let bytes_float = bytes as f64;
|
||||
if bytes_float >= GB {
|
||||
format!("{:.1} GB", bytes_float / GB)
|
||||
} else if bytes_float >= MB {
|
||||
format!("{:.1} MB", bytes_float / MB)
|
||||
} else if bytes_float >= KB {
|
||||
format!("{:.1} KB", bytes_float / KB)
|
||||
} else {
|
||||
format!("{bytes} B")
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct FullEntry {
|
||||
title: String,
|
||||
@@ -1072,7 +1090,7 @@ mod tests {
|
||||
Edition::Standard,
|
||||
"epub",
|
||||
));
|
||||
std::fs::write(&standard, b"epub").unwrap();
|
||||
std::fs::write(&standard, vec![0; 2 * 1024]).unwrap();
|
||||
let mut config = crate::config::Config::default();
|
||||
config.publish.epub_dir = epub_dir;
|
||||
let app = crate::server::router(crate::server::AppState::new(db, config, None));
|
||||
@@ -1089,10 +1107,19 @@ mod tests {
|
||||
.unwrap();
|
||||
let issue = response_text(issue).await;
|
||||
assert!(issue.contains("Download EPUB"));
|
||||
assert!(issue.contains("2.0 KB"));
|
||||
assert!(!issue.contains("2048 bytes"));
|
||||
assert!(!issue.contains("Download X4 EPUB"));
|
||||
assert!(!issue.contains("Download XTC"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn file_sizes_are_human_readable() {
|
||||
assert_eq!(format_file_size(42), "42 B");
|
||||
assert_eq!(format_file_size(1536), "1.5 KB");
|
||||
assert_eq!(format_file_size(5 * 1024 * 1024), "5.0 MB");
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn rating_post_supports_json_forms_attribution_fallback_and_clear() {
|
||||
let (_dir, db, source) = seeded_issue(true).await;
|
||||
|
||||
Reference in New Issue
Block a user