holger-ui 0.1.4

Operator/admin UI for holger over the HolgerObject core API — egui via facett, embedded (LocalHolger, direct core calls) or remote (RemoteHolger gRPC).
//! **The About holger popup** — holger's branding/identity surface for the shared
//! common framework (every suite app — nornir / dwarves / korp / holger — carries an
//! About and a Tools menu, JetBrains-style). Extracted so the *one* render body is
//! shared between the running app ([`crate::app`]'s About window) and the robot test.
//! No twin (L5): the app and the test drive the SAME [`state_json`] oracle (and, under
//! `gui`, the SAME [`draw_about_window`]), so the robot proves the real surface.
//!
//! The popup is a dismissible `egui::Window` showing the holger+znippy hero logo, the
//! `holger` wordmark, the **version**, the tagline, and the shared framework
//! components holger consumes (skidbladnir lifecycle · nornir-service serve loop ·
//! jera job manager · facett UI) — so an operator (and a robot) can read holger's
//! identity + what it is built on.
//!
//! The identity oracle ([`state_json`]) is always compiled (no egui) so the lean,
//! display-free default build asserts it; the egui render body is behind `gui`.

/// The holger+znippy hero logo PNG (the same asset the startup splash embeds), so the
/// About popup needs no runtime asset path. Decoded once into an egui texture by
/// [`logo_texture`] under `gui`.
pub const LOGO_PNG: &[u8] = include_bytes!("../assets/holger-znippy-logo.png");

/// The accessible name on the About logo image — the AccessKit label a robot queries
/// to prove the holger logo painted in the popup. Stable (asserted by the robot test)
/// and a genuine screen-reader description.
pub const LOGO_ALT: &str = "holger logo — low-poly Norse warrior with the znippy lightning-rabbit shield";

/// The wordmark heading shown under the logo (and the text identity a robot asserts).
pub const WORDMARK: &str = "holger";

/// The primary tagline.
pub const TAGLINE: &str = "Secure, airgap-ready artifact registry — znippy-backed, immutable, auditable.";

/// The shared common-framework components holger CONSUMES (never twins) — shown in the
/// About popup and reported to the oracle so the "built on the shared framework" claim
/// is observable. Mirrors the suite-wide reuse law (L5).
pub const FRAMEWORK: &[&str] = &[
    "skidbladnir — service lifecycle (install/start/status/health + dedicated user)",
    "nornir-service — the one tonic serve loop + auth interceptor",
    "jera — the shared job manager (promote/GC + the Tools demo container)",
    "facett — the shared egui UI framework (look, menu, tables, 3D graph)",
];

/// The holger-ui version, presented in the About popup + reported to the oracle so a
/// robot asserts holger's identity carries a real version string.
pub const VERSION: &str = env!("CARGO_PKG_VERSION");

/// The headless oracle for the About popup — dumped under the app's `state_json.about`.
/// Carries whether the popup is open plus holger's identity: wordmark, **version**,
/// tagline, logo alt-text, and the shared framework components it is built on — so a
/// robot asserts holger's identity + framework without needing pixels.
pub fn state_json(open: bool) -> serde_json::Value {
    serde_json::json!({
        "open": open,
        "wordmark": WORDMARK,
        "version": VERSION,
        "tagline": TAGLINE,
        "logo_alt": LOGO_ALT,
        "has_logo": !LOGO_PNG.is_empty(),
        "framework": FRAMEWORK,
    })
}

/// Decode the embedded holger hero logo into an egui texture (uploaded once). Shared
/// by the app's About helper so PNG→texture lives in ONE place (L5). Returns `None`
/// when the embedded bytes don't decode (e.g. a checkout where the git-lfs blob was
/// not pulled — the compiled-in bytes are the LFS pointer, not a PNG): the About popup
/// then shows its text identity without the hero image — never a panic. Mirrors the
/// startup splash's graceful `image::load_from_memory(...).ok()`.
#[cfg(feature = "gui")]
pub fn logo_texture(ctx: &egui::Context) -> Option<egui::TextureHandle> {
    let img = image::load_from_memory(LOGO_PNG).ok()?.to_rgba8();
    let (w, h) = img.dimensions();
    let color = egui::ColorImage::from_rgba_unmultiplied([w as usize, h as usize], img.as_raw());
    Some(ctx.load_texture("holger_about_logo", color, egui::TextureOptions::LINEAR))
}

/// Draw the **About holger** modal popup into `ctx` — the ONE render body the app and
/// the robot test share.
///
/// * `open` gates visibility; it is set to `false` when the user dismisses the popup
///   (the window's own ✕ or the Close button).
/// * `logo` is the holger hero texture (from [`logo_texture`]); shown with the stable
///   [`LOGO_ALT`] accessible name so the logo is observable to a robot. `None` (an
///   un-pulled LFS blob) draws the text identity without the hero image.
///
/// Returns `true` iff a dismiss happened this frame. Draws nothing and returns `false`
/// when `*open` is already `false`.
#[cfg(feature = "gui")]
pub fn draw_about_window(
    ctx: &egui::Context,
    open: &mut bool,
    logo: Option<&egui::TextureHandle>,
) -> bool {
    if !*open {
        return false;
    }
    let mut window_open = true;
    let mut close_clicked = false;
    egui::Window::new("About holger")
        .collapsible(false)
        .resizable(false)
        .anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0))
        .open(&mut window_open)
        .show(ctx, |ui| {
            ui.vertical_centered(|ui| {
                if let Some(logo) = logo {
                    ui.add(
                        egui::Image::from_texture(logo)
                            .max_width(360.0)
                            .alt_text(LOGO_ALT),
                    );
                }
                ui.add_space(10.0);
                ui.heading(WORDMARK);
                ui.label(egui::RichText::new(format!("v{VERSION}")).monospace().strong());
                ui.label(TAGLINE);
                ui.add_space(8.0);
                ui.label(egui::RichText::new("Built on the shared nordisk framework:").weak());
                for line in FRAMEWORK {
                    ui.label(egui::RichText::new(format!("· {line}")).small());
                }
                ui.add_space(10.0);
                if ui.button("Close").clicked() {
                    close_clicked = true;
                }
            });
        });
    let dismissed = !window_open || close_clicked;
    if dismissed {
        *open = false;
    }
    dismissed
}

#[cfg(test)]
mod tests {
    use super::*;

    /// **RED-when-broken: the About oracle carries holger's identity — logo, wordmark,
    /// version, and the shared framework it is built on.** The embedded logo must be a
    /// real non-empty PNG and the oracle must advertise the identity, so About is the
    /// branding/identity surface (not a blank window). If the logo went missing, the
    /// version stopped being reported, or the framework list emptied, this is red.
    #[test]
    fn about_oracle_carries_identity_and_framework() {
        // The logo is embedded (non-empty) so About is never a blank surface. We
        // tolerate a git-lfs pointer here: on a checkout where LFS blobs are not
        // pulled the compiled-in bytes are the pointer, not the PNG — the same case
        // the runtime splash already handles gracefully (`image::load_from_memory`
        // returns `None`). The RED-when-broken contract of About is holger's IDENTITY
        // (wordmark / version / framework), asserted strictly below.
        assert!(!LOGO_PNG.is_empty(), "the holger logo is embedded (non-empty)");
        let real_png = LOGO_PNG.starts_with(b"\x89PNG");
        let lfs_pointer = LOGO_PNG.starts_with(b"version https://git-lfs");
        assert!(real_png || lfs_pointer, "the embedded logo is a real PNG or its LFS pointer");

        let closed = state_json(false);
        assert_eq!(closed["open"], serde_json::json!(false));
        assert_eq!(closed["wordmark"], serde_json::json!(WORDMARK));
        assert_eq!(closed["version"], serde_json::json!(VERSION));
        assert!(!VERSION.is_empty(), "the About popup presents a real version string");
        assert_eq!(closed["has_logo"], serde_json::json!(true));
        // The shared framework list is present + non-empty (the reuse story is shown).
        let fw = closed["framework"].as_array().expect("framework list");
        assert!(!fw.is_empty(), "About names the shared framework components");
        assert!(
            fw.iter().any(|c| c.as_str().unwrap_or("").contains("jera")),
            "About names jera (the shared job manager the Tools demo uses): {fw:?}"
        );

        let open = state_json(true);
        assert_eq!(open["open"], serde_json::json!(true));

        #[cfg(feature = "testmatrix")]
        nornir_testmatrix::functional_status(
            "holger-ui/about",
            "oracle_carries_identity_and_framework",
            !LOGO_PNG.is_empty()
                && closed["version"] == serde_json::json!(VERSION)
                && !fw.is_empty(),
            "the About popup embeds the holger logo + wordmark + version + shared-framework list",
        );
    }
}