Files
Ely-GPUI-Components/examples/gallery/pages/dashboard/board.rs
T
ZacharyZhang-NY 9fddf4b6bf Dashboard: a grid of widgets, what fires, what is up, and the stream
DashboardGrid lays widgets on columns: a tile's strip drags it and its
corner resizes it a cell at a time, others move down and rise to fill
gaps, a focused tile steps with the arrows, and under the theme's
stack_below width the tiles stand in one column. DashboardCard frames a
widget. AlertList acknowledges a firing alert from its row and opens
one on Enter; IncidentCard shows an incident's gravity, phase and
updates. UptimeBar, ServiceStatus and HealthCheck show what is up, a
check's detail wrapping under its name when narrow. EventStream keeps
kinds and holds the list while new events count up.
RefreshIntervalSelector and DashboardFilterBar set the window, the
filters and the refresh. StatCard, MetricsChart, ResourceGauge,
LogStream, TraceWaterfall, SystemMonitor, ProcessTable and NetworkGraph
point to their homes; the maps wait for T41.
2026-09-27 11:51:19 -04:00

164 lines
5.9 KiB
Rust

use ely_gpui_component::{
charts::{LineChart, Series},
dashboard::{
DashboardCard, DashboardFilter, DashboardFilterBar, DashboardGrid, RefreshIntervalSelector,
Tile, TimeWindow,
},
data_display::{Gauge, Statistic, TrendIndicator},
forms::Choice,
};
use gpui::{App, IntoElement, ParentElement, SharedString, Styled, Window, div, px};
use jiff::Timestamp;
use crate::ui::{change, keep, section};
/// The board demo's tiles, window, filters and refresh.
struct Wall {
tiles: Vec<Tile>,
window: TimeWindow,
environment: Option<SharedString>,
service: Option<SharedString>,
every: Option<u32>,
/// Seconds since the last refresh, at the demo's fixed clock.
since: i64,
}
impl Wall {
fn new() -> Self {
Self {
tiles: vec![
Tile::new("requests", (0, 0), (4, 2)),
Tile::new("errors", (4, 0), (4, 2)),
Tile::new("cpu", (8, 0), (4, 2)),
Tile::new("latency", (0, 2), (8, 3)),
Tile::new("saturation", (8, 2), (4, 3)),
],
window: TimeWindow::Hour,
environment: Some("production".into()),
service: None,
every: Some(30),
since: 40,
}
}
}
pub fn grid(window: &mut Window, cx: &mut App) -> impl IntoElement + use<> {
let wall = keep("dashboard-wall", Wall::new, window, cx);
let now = wall.read(cx);
let (tiles, time, environment, service, every, since) = (
now.tiles.clone(),
now.window,
now.environment.clone(),
now.service.clone(),
now.every,
now.since,
);
let [moved, windowed, filtered, timed, refreshed] = [(); 5].map(|_| wall.clone());
let clock: Timestamp = "2026-09-27T12:00:00Z".parse().expect("a time");
let hours: Vec<String> = (0..24).map(|hour| format!("{hour:02}:00")).collect();
let latency = Series::new(
"p95",
(0..24)
.map(|ix| 120.0 + 40.0 * ((ix as f64) * 0.5).sin() + if ix > 18 { 60.0 } else { 0.0 }),
);
let filters = [
DashboardFilter {
key: "environment".into(),
name: "Environment".into(),
choices: vec![
Choice::new("production", "Production"),
Choice::new("staging", "Staging"),
],
picked: environment,
},
DashboardFilter {
key: "service".into(),
name: "Service".into(),
choices: vec![
Choice::new("web", "Web"),
Choice::new("api", "API"),
Choice::new("worker", "Worker"),
],
picked: service,
},
];
let grid = DashboardGrid::new("dashboard-grid", 12, tiles)
.card(
"requests",
DashboardCard::new("Requests").subtitle("per minute").body(
Statistic::new("dashboard-requests", "This hour", 12_400.0)
.trend(TrendIndicator::new(0.082)),
),
)
.card(
"errors",
DashboardCard::new("Errors").subtitle("5xx share").body(
Statistic::new("dashboard-errors", "This hour", 0.42)
.decimals(2)
.suffix("%")
.trend(TrendIndicator::new(-0.12)),
),
)
.card(
"cpu",
DashboardCard::new("CPU").body(Gauge::new(
"dashboard-cpu",
"percent busy",
62.0,
0.0,
100.0,
)),
)
.card(
"latency",
DashboardCard::new("Latency")
.subtitle("p95, milliseconds")
.body(LineChart::new("dashboard-latency", hours).series(latency)),
)
.card(
"saturation",
DashboardCard::new("Saturation").body(Gauge::new(
"dashboard-memory",
"memory in use",
81.0,
0.0,
100.0,
)),
)
.on_change(move |next, _, cx| change(&moved, cx, |wall| wall.tiles = next));
section(
"Dashboard Grid · Widget / DashboardCard · RefreshIntervalSelector · DashboardFilterBar · StatCard → data_display::Statistic · MetricsChart → charts::LineChart · ResourceGauge → data_display::Gauge",
"Widgets on a grid of twelve columns: a tile's top strip drags it and its corner resizes it, a cell at a time, while the others make room and rise to fill gaps; a focused tile steps with the arrows. Over it, the window of time and the filters, and how often it refreshes.",
cx,
)
.child(
div()
.flex()
.flex_col()
.gap_4()
.child(
div()
.flex()
.flex_wrap()
.justify_between()
.gap_3()
.child(
DashboardFilterBar::new("dashboard-filters", time, filters)
.on_window(move |next, _, cx| change(&windowed, cx, |wall| wall.window = next))
.on_filter(move |key, value, _, cx| {
change(&filtered, cx, |wall| match key.as_ref() {
"environment" => wall.environment = value,
_ => wall.service = value,
})
}),
)
.child(
RefreshIntervalSelector::new("dashboard-refresh", every, clock - jiff::SignedDuration::from_secs(since), clock)
.on_change(move |next, _, cx| change(&timed, cx, |wall| wall.every = next))
.on_refresh(move |_, cx| change(&refreshed, cx, |wall| wall.since = 0)),
),
)
.child(div().w(px(900.)).child(grid)),
)
}