The page's script is TypeScript in web/src, built and minified with swc
- web/src/*.ts: the script that was inline in index.html and login.html, split along its existing sections. Still one scope, concatenated in order, not modules. - web/build.mjs strips the types, puts the script in the page and minifies it with swc; build.rs runs it into OUT_DIR and web.rs include_str!s the result. 137 KB -> 106 KB. - npx tsc -p . type-checks web/src, loosely; the handful of annotations it needed change no behaviour. - The Docker build installs node and swc (npm ci --omit=dev). - Two list requests racing no longer let the older one win, and switching tabs clears the selection it closes, which made a browser test flaky. Closes #23, #24. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
14
src/web.rs
14
src/web.rs
@@ -441,7 +441,7 @@ async fn login_page(State(state): State<WebState>, req: Request) -> Response {
|
||||
if vouched_name(&state.ctx.cfg(), &req).is_some() {
|
||||
return Redirect::to("/").into_response();
|
||||
}
|
||||
Html(include_str!("../web/login.html")).into_response()
|
||||
Html(include_str!(concat!(env!("OUT_DIR"), "/login.html"))).into_response()
|
||||
}
|
||||
|
||||
/// The 2004 icon, served once for both pages rather than inlined as base64 into each. The
|
||||
@@ -471,8 +471,10 @@ fn constant_time_eq(a: &str, b: &str) -> bool {
|
||||
a.iter().zip(b).fold(0u8, |acc, (x, y)| acc | (x ^ y)) == 0
|
||||
}
|
||||
|
||||
const INDEX: &str = include_str!("../web/index.html");
|
||||
const LOG_BUTTON: &str = r#"<button id="logs" "#;
|
||||
// Built by build.rs from web/index.html and web/src, and minified: attribute values lose their
|
||||
// quotes, so LOG_BUTTON is spelled the way the minifier leaves it.
|
||||
const INDEX: &str = include_str!(concat!(env!("OUT_DIR"), "/index.html"));
|
||||
const LOG_BUTTON: &str = "<button id=logs ";
|
||||
|
||||
/// The page, with the log button left out for anyone but an admin. Hiding it from the page's
|
||||
/// script instead showed it for a moment on every load, until /api/me answered.
|
||||
@@ -484,7 +486,7 @@ fn page_for(admin: bool) -> std::borrow::Cow<'static, str> {
|
||||
if admin {
|
||||
INDEX.into()
|
||||
} else {
|
||||
INDEX.replacen(LOG_BUTTON, r#"<button id="logs" hidden "#, 1).into()
|
||||
INDEX.replacen(LOG_BUTTON, "<button id=logs hidden ", 1).into()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -822,8 +824,8 @@ mod tests {
|
||||
#[test]
|
||||
fn only_an_admin_is_sent_the_log_button() {
|
||||
// If the markup drifts from LOG_BUTTON, replacen matches nothing and says nothing.
|
||||
assert!(page_for(false).contains(r#"<button id="logs" hidden "#));
|
||||
assert!(!page_for(true).contains(r#"id="logs" hidden"#));
|
||||
assert!(page_for(false).contains("<button id=logs hidden "));
|
||||
assert!(!page_for(true).contains("id=logs hidden"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user