v0.4.4: Settings tab, API reference, ISO category, branding, disk space

Settings:
- New top-level Settings tab. Carries a placeholder for the planned
  LDAP / OIDC / user-management work, the new branding controls, and
  the API reference at the bottom.
- Custom logo upload (PNG/SVG/JPEG/WebP/GIF up to 2 MB) replaces the
  bundled brand mark via /assets/logo.svg; bytes live at
  <work_dir>/branding/ and survive restart. The original "OpenPXE
  v<x.y.z>" pins to the sidebar footer for support.
- API reference rendered from a new GET /api/docs into a per-method
  coloured pill list grouped by area.

ISO category (Storage):
- New IsoCategory { Os, Tools } on IsoMeta with PUT
  /api/isos/:id/category. Storage table's Type cell becomes a
  dropdown; selecting Tools moves the ISO into the Tools submenu next
  to memtest / shell / NIC info and removes it from the OS Installers
  family submenu. Family detection still drives BIOS/UEFI / kernel
  args; only the menu placement changes.

Storage telemetry:
- New IsoStore::disk_usage (libc::statvfs, lives in iso-store so the
  http-api crate stays #![forbid(unsafe_code)]) and GET
  /api/storage/disk. The Storage tab now shows free/used/total for
  the volume hosting the ISO directory with an 80%/95% colour ramp.

UI polish:
- Brand block in the sidebar now matches the topbar height exactly,
  so the divider runs straight across the top of the app rather than
  stepping; version label moved out of the brand and pinned to the
  sidebar footer ("OpenPXE v0.4.4").
- Light-mode terminal: --terminal-bg + per-level text colours track
  the active theme rather than being hard-coded dark.
- About: lead paragraph spans the full content width; new Docs row
  links to https://openpxe.com/.

106 tests passing (was 89 in v0.4.1, +17 across branding unit tests
and new integration coverage for category / disk / docs / branding).
cargo clippy --workspace --all-targets clean.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
This commit is contained in:
Miles Ward
2026-05-25 17:46:52 -04:00
co-authored by Claude Opus 4.7
parent a171331a7a
commit 7b972dc049
14 changed files with 1385 additions and 45 deletions
+53 -4
View File
@@ -149,6 +149,13 @@ pub fn render_family_menu(isos: &[IsoMeta], base_url: &str, is_windows: bool) ->
if !filter(iso.introspection.family) {
continue;
}
// v0.4.4: ISOs the operator flipped to the Tools category move
// out of the OS installer submenus entirely — they only appear
// under Tools. Without this filter the operator would see the
// same ISO in both menus.
if matches!(iso.category, openpxe_iso_store::IsoCategory::Tools) {
continue;
}
for entry in &iso.boot_entries {
let size_label = fmt_size_mib(iso.size_bytes);
let key = hotkey_for_index(count);
@@ -210,15 +217,52 @@ fn hotkey_for_index(i: usize) -> String {
}
}
/// Tools submenu — Utilities, Shell, NIC Info, Reboot, Exit to firmware.
/// Tools submenu — Utilities, Shell, NIC Info, Reboot, Exit to firmware,
/// plus any ISOs the operator flipped to [`IsoCategory::Tools`] in the
/// Storage tab. The category-Tools ISOs render first so frequently used
/// recovery / hardware tools are reachable with a single number key
/// before the built-in shortcuts.
#[must_use]
pub fn render_tools_menu(base_url: &str) -> String {
pub fn render_tools_menu(isos: &[IsoMeta], base_url: &str) -> String {
let base = base_url.trim_end_matches('/');
let mut s = String::new();
let _ = writeln!(s, "#!ipxe");
let _ = writeln!(s, "set base-url {base}");
let _ = writeln!(s, ":menu");
let _ = writeln!(s, "menu OpenPXE - Tools");
// Operator-categorized tool ISOs (hotkeys 1..9), each chained the
// same way as a per-family menu pick — through the boot-entry id
// route, carrying `?mac=${mac}` for Host log attribution.
let mut count = 0;
for iso in isos {
if !matches!(iso.category, openpxe_iso_store::IsoCategory::Tools) {
continue;
}
for entry in &iso.boot_entries {
let size_label = fmt_size_mib(iso.size_bytes);
let key = hotkey_for_index(count);
let lock = if iso.is_password_protected() {
"*"
} else {
" "
};
let _ = writeln!(
s,
"item {}{} {}[{:>6}] {}",
key,
entry.id,
lock,
size_label,
escape_label(&entry.title),
);
count += 1;
}
}
if count > 0 {
let _ = writeln!(s, "item --gap");
}
let _ = writeln!(s, "item --key u util Utilities (memtest, ...)");
let _ = writeln!(s, "item --key s shell OpenPXE Shell");
let _ = writeln!(s, "item --key n nic Network Card Info");
@@ -252,7 +296,12 @@ pub fn render_tools_menu(base_url: &str) -> String {
s,
"iseq ${{target}} back && chain {base}/boot.ipxe || goto menu"
);
let _ = writeln!(s, "goto menu");
// Fall-through for category-Tools ISO ids — same as the family
// submenu, carrying `?mac=${mac}` for the boot log.
let _ = writeln!(
s,
"chain {base}/boot/${{target}}.ipxe?mac=${{mac}} || goto menu"
);
s
}
@@ -531,7 +580,7 @@ mod password_tests {
let settings = Settings::default();
let scripts = [
render_menu(&[], &settings, "http://10.0.0.5"),
render_tools_menu("http://10.0.0.5"),
render_tools_menu(&[], "http://10.0.0.5"),
render_local_hdd("http://10.0.0.5"),
render_util("http://10.0.0.5"),
render_shell("http://10.0.0.5"),