From ace82fa84f4d6b9a864a0be7b159bba2032e1c00 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 16 Apr 2023 21:32:41 +0200 Subject: [PATCH 1/2] Load release list only when needed --- src/web/crate_details.rs | 47 +++++++++++++++++++++++++++++++++ src/web/routes.rs | 4 +++ static/menu.js | 29 ++++++++++++++++++++ templates/rustdoc/releases.html | 6 +++++ templates/rustdoc/topbar.html | 7 ++--- templates/style/_navbar.scss | 17 ++++++++++++ 6 files changed, 105 insertions(+), 5 deletions(-) create mode 100644 templates/rustdoc/releases.html diff --git a/src/web/crate_details.rs b/src/web/crate_details.rs index 471433ec2..ffdd2ef74 100644 --- a/src/web/crate_details.rs +++ b/src/web/crate_details.rs @@ -373,6 +373,53 @@ pub(crate) async fn crate_details_handler( Ok(res.into_response()) } +#[derive(Debug, Clone, PartialEq, Serialize)] +struct ReleaseList { + releases: Vec, + crate_name: String, +} + +impl_axum_webpage! { + ReleaseList = "rustdoc/releases.html", + cpu_intensive_rendering = true, +} + +#[tracing::instrument] +pub(crate) async fn get_all_releases( + Path(params): Path, + Extension(pool): Extension, +) -> AxumResult { + let releases: Vec = spawn_blocking({ + let pool = pool.clone(); + let params = params.clone(); + move || { + let mut conn = pool.get()?; + let query = " + SELECT + crates.id AS crate_id + FROM crates + WHERE crates.name = $1;"; + + let rows = conn.query(query, &[¶ms.name])?; + + let result = if rows.is_empty() { + return Ok(Vec::new()); + } else { + &rows[0] + }; + // get releases, sorted by semver + releases_for_crate(&mut *conn, result.get("crate_id")) + } + }) + .await?; + + let res = ReleaseList { + releases, + crate_name: params.name, + }; + Ok(res.into_response()) +} + #[cfg(test)] mod tests { use super::*; diff --git a/src/web/routes.rs b/src/web/routes.rs index 6421fa64e..6b4837a0b 100644 --- a/src/web/routes.rs +++ b/src/web/routes.rs @@ -167,6 +167,10 @@ pub(super) fn build_axum_routes() -> AxumRouter { "/crate/:name", get_internal(super::crate_details::crate_details_handler), ) + .route( + "/:name/releases", + get_internal(super::crate_details::get_all_releases), + ) .route_with_tsr( "/crate/:name/:version", get_internal(super::crate_details::crate_details_handler), diff --git a/static/menu.js b/static/menu.js index c82f808e6..8f0c8dc24 100644 --- a/static/menu.js +++ b/static/menu.js @@ -5,6 +5,34 @@ const updateMenuPositionForSubMenu = (currentMenuSupplier) => { subMenu?.style.setProperty('--menu-x', `${currentMenu.getBoundingClientRect().x}px`); } +function generateReleaseList(data, crateName) { +} + +let loadReleases = function() { + const releaseListElem = document.getElementById('releases-list'); + // To prevent reloading the list unnecessarily. + loadReleases = function() {}; + if (!releaseListElem) { + // We're not in a documentation page, so no need to do anything. + return; + } + const crateName = window.location.pathname.split('/')[1]; + const xhttp = new XMLHttpRequest(); + xhttp.onreadystatechange = function() { + if (xhttp.readyState !== XMLHttpRequest.DONE) { + return; + } + if (xhttp.status === 200) { + releaseListElem.innerHTML = xhttp.responseText; + } else { + console.error(`Failed to load release list: [${xhttp.status}] ${xhttp.responseText}`); + document.getElementById('releases-list').innerHTML = "Failed to load release list"; + } + }; + xhttp.open("GET", `/${crateName}/releases`, true); + xhttp.send(); +}; + // Allow menus to be open and used by keyboard. (function() { var currentMenu; @@ -53,6 +81,7 @@ const updateMenuPositionForSubMenu = (currentMenuSupplier) => { currentMenu = newMenu; newMenu.className += " pure-menu-active"; backdrop.style.display = "block"; + loadReleases(); } function menuOnClick(e) { if (this.getAttribute("href") != "#") { diff --git a/templates/rustdoc/releases.html b/templates/rustdoc/releases.html new file mode 100644 index 000000000..7772dcbf9 --- /dev/null +++ b/templates/rustdoc/releases.html @@ -0,0 +1,6 @@ +{% import "macros.html" as macros %} +{% set target = "" %} +{% set inner_path = releases[0].target_name ~ "/index.html" %} +
    +{{ macros::releases_list(name=crate_name, releases=releases, target=target, inner_path=inner_path) }} +
diff --git a/templates/rustdoc/topbar.html b/templates/rustdoc/topbar.html index e16639a51..120212fff 100644 --- a/templates/rustdoc/topbar.html +++ b/templates/rustdoc/topbar.html @@ -134,11 +134,8 @@
  • Versions
  • -
  • diff --git a/templates/style/_navbar.scss b/templates/style/_navbar.scss index b8a44a0ed..bae93f9f7 100644 --- a/templates/style/_navbar.scss +++ b/templates/style/_navbar.scss @@ -15,6 +15,15 @@ body { padding: 0; } +@keyframes rotating_text { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} + div.nav-container { // Nothing is supposed to be over or hovering the top navbar. Maybe add a few others '('? :) z-index: 999; @@ -324,6 +333,14 @@ div.nav-container { } } } + + #releases-list { + .rotate { + display: inline-block; + font-size: 30px; + animation: rotating_text 2s linear infinite; + } + } } #nav-search { From 0bbcc88bfe95252718363762e6067120a6cadea0 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 21 Apr 2023 15:25:32 +0200 Subject: [PATCH 2/2] Update release list test --- src/web/rustdoc.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/web/rustdoc.rs b/src/web/rustdoc.rs index 00c5904d9..f56e801c1 100644 --- a/src/web/rustdoc.rs +++ b/src/web/rustdoc.rs @@ -2240,12 +2240,8 @@ mod test { .create()?; // test rustdoc pages stay on the documentation - let page = kuchiki::parse_html().one( - env.frontend() - .get("/hexponent/0.3.0/hexponent/") - .send()? - .text()?, - ); + let page = kuchiki::parse_html() + .one(env.frontend().get("/hexponent/releases").send()?.text()?); let selector = r#"ul > li a[href="/crate/hexponent/0.3.1/target-redirect/hexponent/index.html"]"# .to_string();