Skip to content
Merged
Show file tree
Hide file tree
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
Binary file removed core/bench/dashboard/frontend/assets/iggy-dark.png
Binary file not shown.
112 changes: 112 additions & 0 deletions core/bench/dashboard/frontend/assets/iggy-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed core/bench/dashboard/frontend/assets/iggy-light.png
Binary file not shown.
112 changes: 112 additions & 0 deletions core/bench/dashboard/frontend/assets/iggy-light.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
474 changes: 354 additions & 120 deletions core/bench/dashboard/frontend/assets/style.css

Large diffs are not rendered by default.

59 changes: 58 additions & 1 deletion core/bench/dashboard/frontend/index.dev.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,64 @@
</head>

<body>
<div id="app"></div>
<div id="app">
<div class="boot-splash" role="status" aria-live="polite">
<div class="boot-splash-body">
<img class="boot-splash-mark" src="/assets/iggy-dark.svg" alt="Apache Iggy" />
<div class="boot-splash-sub">Benchmarks</div>
</div>
</div>
</div>
<style>
.boot-splash {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
color: #0b1220;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
z-index: 9999;
}
.boot-splash-body {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
padding: 0 24px;
}
@media (prefers-color-scheme: dark) {
.boot-splash { background: #0b1220; color: #f5f5f5; }
.boot-splash-mark { content: url("/assets/iggy-light.svg"); }
}
.boot-splash-mark {
width: auto;
height: 128px;
max-width: 440px;
object-fit: contain;
filter: drop-shadow(0 0 24px rgba(255, 145, 3, 0.35));
animation: boot-splash-pulse 1800ms ease-in-out infinite;
}
.boot-splash-brand {
margin-top: 4px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
color: #ff9103;
}
.boot-splash-sub {
font-size: clamp(28px, 4vw, 44px);
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1;
}
@keyframes boot-splash-pulse {
0%, 100% { opacity: 0.4; transform: scale(0.96); }
50% { opacity: 1; transform: scale(1); }
}
</style>
</body>

</html>
59 changes: 58 additions & 1 deletion core/bench/dashboard/frontend/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,64 @@
</head>

<body>
<div id="app"></div>
<div id="app">
<div class="boot-splash" role="status" aria-live="polite">
<div class="boot-splash-body">
<img class="boot-splash-mark" src="/assets/iggy-dark.svg" alt="Apache Iggy" />
<div class="boot-splash-sub">Benchmarks</div>
</div>
</div>
</div>
<style>
.boot-splash {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
color: #0b1220;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
z-index: 9999;
}
.boot-splash-body {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
padding: 0 24px;
}
@media (prefers-color-scheme: dark) {
.boot-splash { background: #0b1220; color: #f5f5f5; }
.boot-splash-mark { content: url("/assets/iggy-light.svg"); }
}
.boot-splash-mark {
width: auto;
height: 128px;
max-width: 440px;
object-fit: contain;
filter: drop-shadow(0 0 24px rgba(255, 145, 3, 0.35));
animation: boot-splash-pulse 1800ms ease-in-out infinite;
}
.boot-splash-brand {
margin-top: 4px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
color: #ff9103;
}
.boot-splash-sub {
font-size: clamp(28px, 4vw, 44px);
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1;
}
@keyframes boot-splash-pulse {
0%, 100% { opacity: 0.4; transform: scale(0.96); }
50% { opacity: 1; transform: scale(1); }
}
</style>
</body>

</html>
59 changes: 58 additions & 1 deletion core/bench/dashboard/frontend/index.prod.html
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,63 @@
</head>

<body>
<div id="app"></div>
<div id="app">
<div class="boot-splash" role="status" aria-live="polite">
<div class="boot-splash-body">
<img class="boot-splash-mark" src="/assets/iggy-dark.svg" alt="Apache Iggy" />
<div class="boot-splash-sub">Benchmarks</div>
</div>
</div>
</div>
<style>
.boot-splash {
position: fixed;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
background: #f5f5f5;
color: #0b1220;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
z-index: 9999;
}
.boot-splash-body {
display: flex;
flex-direction: column;
align-items: center;
gap: 14px;
padding: 0 24px;
}
@media (prefers-color-scheme: dark) {
.boot-splash { background: #0b1220; color: #f5f5f5; }
.boot-splash-mark { content: url("/assets/iggy-light.svg"); }
}
.boot-splash-mark {
width: auto;
height: 128px;
max-width: 440px;
object-fit: contain;
filter: drop-shadow(0 0 24px rgba(255, 145, 3, 0.35));
animation: boot-splash-pulse 1800ms ease-in-out infinite;
}
.boot-splash-brand {
margin-top: 4px;
font-size: 11px;
font-weight: 600;
letter-spacing: 0.22em;
text-transform: uppercase;
color: #ff9103;
}
.boot-splash-sub {
font-size: clamp(28px, 4vw, 44px);
font-weight: 800;
letter-spacing: -0.02em;
line-height: 1;
}
@keyframes boot-splash-pulse {
0%, 100% { opacity: 0.4; transform: scale(0.96); }
50% { opacity: 1; transform: scale(1); }
}
</style>
</body>
</html>
15 changes: 2 additions & 13 deletions core/bench/dashboard/frontend/src/components/chart/single_chart.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

use crate::api::fetch_benchmark_report_full;
use crate::components::chart::{PlotConfig, dispose_chart};
use crate::components::loader::{IggyLoader, LoaderSize};
use crate::components::selectors::measurement_type_selector::MeasurementType;
use crate::hooks::use_size;
use bench_report::report::BenchmarkReport;
Expand All @@ -26,7 +27,6 @@ use bench_report::{
use charming::theme::Theme;
use charming::{Echarts, WasmRenderer};
use gloo::console::log;
use gloo::history::{BrowserHistory, History};
use uuid::Uuid;
use yew::platform::spawn_local;
use yew::prelude::*;
Expand Down Expand Up @@ -57,17 +57,6 @@ pub fn single_chart(props: &SingleChartProps) -> Html {
let benchmark_uuid = *benchmark_uuid;
is_loading.set(true);

let current_location = web_sys::window()
.and_then(|w| w.location().pathname().ok())
.unwrap_or_default();

let expected_path = format!("/benchmarks/{benchmark_uuid}");

if current_location != expected_path {
let history = BrowserHistory::new();
history.push(expected_path);
}

spawn_local(async move {
match fetch_benchmark_report_full(&benchmark_uuid).await {
Ok(data) => {
Expand Down Expand Up @@ -152,7 +141,7 @@ pub fn single_chart(props: &SingleChartProps) -> Html {
<div id={canvas_id} style="width: 100%; height: 100%;"></div>
</div>
<div class={classes!("loading-overlay", loading_class)}>
<div class="loading-spinner"></div>
<IggyLoader size={LoaderSize::Medium} />
</div>
</div>
}
Expand Down
6 changes: 6 additions & 0 deletions core/bench/dashboard/frontend/src/components/footer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,12 @@ pub fn footer() -> Html {
<a href="https://www.apache.org/" target="_blank" rel="noopener noreferrer">
{"Apache Software Foundation"}
</a>
<span class="footer-sep">{"•"}</span>
<span class="footer-tagline">
{"Built with "}
<span class="footer-heart" aria-label="love">{"❤"}</span>
{" for the message streaming community"}
</span>
</div>
</div>
</footer>
Expand Down
76 changes: 45 additions & 31 deletions core/bench/dashboard/frontend/src/components/layout/hero.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ use crate::format::format_ms;
use crate::router::AppRoute;
use crate::state::benchmark::{latest_sweep, pick_best_from_recent_batch};
use bench_dashboard_shared::BenchmarkReportLight;
use chrono::DateTime;
use gloo::console::log;
use gloo::timers::callback::Timeout;
use std::cell::Cell;
Expand Down Expand Up @@ -166,7 +165,6 @@ struct HeroStats {
peak_msg_s: Option<(f64, String)>,
max_scale: Option<MaxScale>,
total: usize,
latest_ts: Option<String>,
showcase: Option<BenchmarkReportLight>,
}

Expand Down Expand Up @@ -226,13 +224,6 @@ fn compute_stats<'a>(benchmarks: impl Iterator<Item = &'a BenchmarkReportLight>)
pretty_name: pretty_name.clone(),
});
}
if stats
.latest_ts
.as_ref()
.is_none_or(|current| &benchmark.timestamp > current)
{
stats.latest_ts = Some(benchmark.timestamp.clone());
}
}
stats
}
Expand Down Expand Up @@ -339,7 +330,7 @@ fn render_stat_cards(stats: &HeroStats) -> Html {
}
{ render_scale_card(1, stats.max_scale.as_ref()) }
{ render_showcase_card(2, stats.showcase.as_ref()) }
{ render_summary_card(3, stats.total, stats.latest_ts.as_deref()) }
{ render_volume_card(3, stats.showcase.as_ref()) }
</div>
}
}
Expand Down Expand Up @@ -413,23 +404,58 @@ fn render_showcase_card(stagger: usize, showcase: Option<&BenchmarkReportLight>)
}
}

fn render_summary_card(stagger: usize, total: usize, latest_ts: Option<&str>) -> Html {
let sub = match latest_ts {
Some(ts) => format!("Latest: {}", format_date(ts)),
None => String::new(),
fn render_volume_card(stagger: usize, showcase: Option<&BenchmarkReportLight>) -> Html {
let Some(benchmark) = showcase else {
return html! {};
};
let total_bytes = benchmark.total_bytes();
if total_bytes == 0 {
return html! {};
}
let (value, unit) = format_volume(total_bytes);
let messages = benchmark.total_messages_sent() + benchmark.total_messages_received();
let sub = if messages > 0 {
format!("{} messages moved", format_count(messages))
} else {
String::new()
};
html! {
<div class="hero-v2-card" style={format!("--stagger: {stagger}")}>
<div class="hero-v2-card-value-row">
<span class="hero-v2-card-value">{total}</span>
<span class="hero-v2-card-unit">{"runs"}</span>
<span class="hero-v2-card-value">{value}</span>
<span class="hero-v2-card-unit">{unit}</span>
</div>
<div class="hero-v2-card-label">{"Benchmarks loaded"}</div>
<div class="hero-v2-card-label">{"Volume pushed in run"}</div>
<div class="hero-v2-card-sub">{sub}</div>
</div>
}
}

fn format_volume(bytes: u64) -> (String, &'static str) {
let bytes = bytes as f64;
if bytes >= 1_000_000_000_000.0 {
(format_significant(bytes / 1_000_000_000_000.0), "TB")
} else if bytes >= 1_000_000_000.0 {
(format_significant(bytes / 1_000_000_000.0), "GB")
} else if bytes >= 1_000_000.0 {
(format_significant(bytes / 1_000_000.0), "MB")
} else {
(format_significant(bytes / 1_000.0), "kB")
}
}

fn format_count(value: u64) -> String {
if value >= 1_000_000_000 {
format!("{:.2}B", value as f64 / 1_000_000_000.0)
} else if value >= 1_000_000 {
format!("{:.1}M", value as f64 / 1_000_000.0)
} else if value >= 1_000 {
format!("{:.1}k", value as f64 / 1_000.0)
} else {
value.to_string()
}
}

fn format_throughput_bytes(mb_per_s: f64) -> (String, &'static str) {
if mb_per_s >= 1_000_000.0 {
(format_significant(mb_per_s / 1_000_000.0), "TB/s")
Expand Down Expand Up @@ -462,18 +488,11 @@ fn format_significant(v: f64) -> String {
}
}

fn format_date(timestamp_str: &str) -> String {
match DateTime::parse_from_rfc3339(timestamp_str) {
Ok(t) => t.format("%Y-%m-%d").to_string(),
Err(_) => "unknown".to_string(),
}
}

fn render_hero_loading(is_dark: bool, is_slow: bool) -> Html {
let logo_src = if is_dark {
"/assets/iggy-light.png"
"/assets/iggy-light.svg"
} else {
"/assets/iggy-dark.png"
"/assets/iggy-dark.svg"
};
html! {
<div class="hero-v2 hero-v2-loading" aria-busy="true" aria-live="polite">
Expand All @@ -485,7 +504,6 @@ fn render_hero_loading(is_dark: bool, is_slow: bool) -> Html {
alt=""
aria-hidden="true"
/>
<div class="hero-v2-loading-brand">{"Apache Iggy"}</div>
<div class="hero-v2-loading-sub">{"Benchmarks"}</div>
if is_slow {
<p class="hero-v2-loading-slow">
Expand All @@ -498,10 +516,6 @@ fn render_hero_loading(is_dark: bool, is_slow: bool) -> Html {
}
}

/// Every headline field comes from the SAME benchmark that powers the
/// tail chart and "View details" link. Built through this single helper
/// so the big number, subject name, CPU, and gitref can never drift to
/// different benchmarks.
#[derive(Default, Debug, PartialEq)]
pub struct ShowcaseDisplay {
pub formatted_value: String,
Expand Down
Loading
Loading