Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions crates/epix-plugins/src/sidebar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -149,7 +156,8 @@ fn render_sidebar(address: &str, info: &Value, counts: PeerCounts, recv: u64, se

// Peers
b.push_str(&format!(
"<li><label>Peers</label>\
"<li><label>Peers \
<a href='#Copy' id='link-copypeers' class='link-right'>Copy to clipboard</a></label>\
<ul class='graph'>\
<li style='width: 100%' class='total back-black' title='Total peers'></li>\
<li style='width: {connectable_w}' class='connectable back-blue' title='Connectable peers'></li>\
Expand Down Expand Up @@ -213,23 +221,68 @@ fn render_sidebar(address: &str, info: &Value, counts: PeerCounts, recv: u64, se
<a href='#Set' class='button' id='button-sitelimit'>Set</a></li>",
));

// 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!(
"<li><label>Optional files</label>\
<ul class='graph graph-stacked'>\
<li style='width: {dl_w}' class='downloaded back-green' title='Downloaded'></li>\
</ul>\
<ul class='graph-legend'>\
<li class='color-green'><span>Downloaded:</span><b>{opt_dl_mb:.2}MB</b></li>\
<li class='color-black'><span>Total optional:</span><b>{opt_mb:.2}MB</b></li>\
</ul>\
<label class='checkbox'><input type='checkbox' class='checkbox' id='checkbox-autodownloadoptional' {opt_checked}/>\
<div class='checkbox-skin'></div> Download and help distribute all files</label></li>",
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!(
"<li><label>Needs to be updated</label>\
<span class='console-address'>{bad_files} file(s)</span></li>",
));
}

// Database - reload/rebuild the site's db from its files.
b.push_str(
"<li><label>Database</label>\
<a href='#DB-Reload' class='button' id='button-dbreload'>Reload</a>\
<a href='#DB-Rebuild' class='button' id='button-dbrebuild'>Rebuild</a></li>",
);

// Identity
let identity = match cert_user_id {
Some(id) => esc(id),
None => esc(auth_address),
};
b.push_str(&format!(
"<li><label>Identity address</label>\
"<li><label>Identity address \
<a href='#Change' id='button-identity' class='link-right'>Change</a></label>\
<span class='console-address'>{identity}</span></li>",
));

// Controls
b.push_str(
"<li><label>Site control</label>\
// Controls - favourite/pause-resume shown by state; the sidebar JS toggles
// the paired button's `hidden` class on click.
b.push_str(&format!(
"<li><label>Site control \
<a href='#Directory' id='link-directory' class='link-right'>Show directory</a></label>\
<a href='#Update' class='button' id='button-update'>Update</a>\
<a href='#Pause' class='button' id='button-pause'>Pause</a>\
<a href='#Pause' class='button {pause_h}' id='button-pause'>Pause</a>\
<a href='#Resume' class='button {resume_h}' id='button-resume'>Resume</a>\
<a href='#Favourite' class='button {fav_h}' id='button-favourite'>Favourite</a>\
<a href='#Unfavourite' class='button {unfav_h}' id='button-unfavourite'>Unfavourite</a>\
<a href='#Delete' class='button' id='button-delete'>Delete</a></li>",
);
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 ~
Expand Down Expand Up @@ -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("<h1>My Xite</h1>"));
// 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("<b>2</b>"), "connected count"); // connected=2
assert!(html.contains("<b>7</b>"), "files count");
assert!(html.contains("2.00MB"), "total size in MB");
Expand All @@ -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'"));
}
Expand Down