diff --git a/crates/epix-plugins/src/sidebar.rs b/crates/epix-plugins/src/sidebar.rs
index 7246c16..504ef70 100644
--- a/crates/epix-plugins/src/sidebar.rs
+++ b/crates/epix-plugins/src/sidebar.rs
@@ -134,6 +134,13 @@ fn render_sidebar(address: &str, info: &Value, counts: PeerCounts, recv: u64, se
let size_limit = info["size_limit"].as_i64().unwrap_or(10);
let auth_address = info["auth_address"].as_str().unwrap_or("");
let cert_user_id = info["cert_user_id"].as_str();
+ let serving = info["settings"]["serving"].as_bool().unwrap_or(true);
+ let favorite = info["settings"]["favorite"].as_bool().unwrap_or(false);
+ let autodownload = info["settings"]["autodownloadoptional"].as_bool().unwrap_or(false);
+ let size_optional = info["settings"]["size_optional"].as_i64().unwrap_or(0);
+ let optional_downloaded = info["settings"]["optional_downloaded"].as_i64().unwrap_or(0);
+ let bad_files = info["settings"]["cache"]["bad_files"].as_object().map(|m| m.len()).unwrap_or(0);
+ let hidden = |cond: bool| if cond { "hidden" } else { "" };
let total = counts.total as f64;
let recv_mb = recv as f64 / 1024.0 / 1024.0;
@@ -149,7 +156,8 @@ fn render_sidebar(address: &str, info: &Value, counts: PeerCounts, recv: u64, se
// Peers
b.push_str(&format!(
- "
\
+ "\
\
\
\
@@ -213,23 +221,68 @@ fn render_sidebar(address: &str, info: &Value, counts: PeerCounts, recv: u64, se
Set
",
));
+ // Optional files (only when the site declares any).
+ if size_optional > 0 {
+ let opt_mb = size_optional as f64 / 1024.0 / 1024.0;
+ let opt_dl_mb = optional_downloaded as f64 / 1024.0 / 1024.0;
+ b.push_str(&format!(
+ "\
+ \
+ \
+ - Downloaded:{opt_dl_mb:.2}MB
\
+ - Total optional:{opt_mb:.2}MB
\
+
\
+ ",
+ dl_w = pct(opt_dl_mb, opt_mb),
+ opt_checked = if autodownload { "checked='checked'" } else { "" },
+ ));
+ }
+
+ // Not-synced files (bad files awaiting retry).
+ if bad_files > 0 {
+ b.push_str(&format!(
+ "\
+ {bad_files} file(s)",
+ ));
+ }
+
+ // Database - reload/rebuild the site's db from its files.
+ b.push_str(
+ "\
+ Reload\
+ Rebuild",
+ );
+
// Identity
let identity = match cert_user_id {
Some(id) => esc(id),
None => esc(auth_address),
};
b.push_str(&format!(
- "\
+ "\
{identity}",
));
- // Controls
- b.push_str(
- "\
+ // Controls - favourite/pause-resume shown by state; the sidebar JS toggles
+ // the paired button's `hidden` class on click.
+ b.push_str(&format!(
+ "\
Update\
- Pause\
+ Pause\
+ Resume\
+ Favourite\
+ Unfavourite\
Delete",
- );
+ pause_h = hidden(!serving),
+ resume_h = hidden(serving),
+ fav_h = hidden(favorite),
+ unfav_h = hidden(!favorite),
+ ));
// "This is my site" - claim ownership. The owner panel below is always in
// the DOM; the checkbox reveals it via CSS (#checkbox-owned:checked ~
@@ -275,13 +328,29 @@ mod tests {
"auth_address": "epix1abcauthaddress",
"cert_user_id": Value::Null,
"size_limit": 10,
- "settings": { "size": 2_097_152, "own": true }, // 2 MB, owned
+ "settings": {
+ "size": 2_097_152, "own": true, // 2 MB, owned
+ "serving": true, "favorite": false, "autodownloadoptional": true,
+ "size_optional": 4_194_304, "optional_downloaded": 1_048_576,
+ "cache": { "bad_files": { "a.txt": 1, "b.txt": 2 } },
+ },
"content": { "title": "My Xite", "description": "desc", "files": 7 },
});
let counts = PeerCounts { total: 5, connected: 2, connectable: 4, onion: 1, local: 1 };
let html = render_sidebar("1abc.epix", &info, counts, 1_048_576, 524_288);
assert!(html.contains("My Xite
"));
+ // New sections/controls.
+ assert!(html.contains("id='link-copypeers'"), "copy peers link");
+ assert!(html.contains("id='checkbox-autodownloadoptional' checked"), "autodownload on");
+ assert!(html.contains("id='button-dbreload'") && html.contains("id='button-dbrebuild'"), "db controls");
+ assert!(html.contains("id='button-resume'") && html.contains("id='button-favourite'"), "resume + favourite");
+ assert!(html.contains("id='link-directory'"), "show directory");
+ assert!(html.contains("2 file(s)"), "bad-files count");
+ // Serving + not-favourited -> resume/unfavourite start hidden.
+ assert!(html.contains("class='button hidden' id='button-resume'"));
+ assert!(html.contains("class='button hidden' id='button-unfavourite'"));
+ assert!(html.contains("class='button ' id='button-favourite'"));
assert!(html.contains("2"), "connected count"); // connected=2
assert!(html.contains("7"), "files count");
assert!(html.contains("2.00MB"), "total size in MB");
@@ -301,7 +370,7 @@ mod tests {
let mut info2 = info.clone();
info2["settings"]["own"] = json!(false);
let html2 = render_sidebar("1abc.epix", &info2, counts, 0, 0);
- assert!(html2.contains("checkbox-owned") && !html2.contains("checked='checked'"));
+ assert!(html2.contains("id='checkbox-owned' />"), "owned checkbox unchecked when not owned");
assert!(html2.contains("button-sign-publish"), "owner panel always present; CSS toggles it");
assert!(html2.contains("class='settings-owned'"));
}