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.
This commit is contained in:
ZacharyZhang-NY committed 2026-09-27 11:51:19 -04:00
1 parent f3332f935b
commit 9fddf4b6bf
17 files changed
+2661 -18

No files matched your search

+176
View File
@@ -0,0 +1,176 @@
use gpui::SharedString;
/// A tile's place on a dashboard grid: its key, and its column, row, width and height in cells.
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Tile {
pub key: SharedString,
pub x: u32,
pub y: u32,
pub w: u32,
pub h: u32,
}
impl Tile {
pub fn new(key: impl Into<SharedString>, (x, y): (u32, u32), (w, h): (u32, u32)) -> Self {
assert!(w > 0 && h > 0, "a tile of {w} by {h} cells");
Self {
key: key.into(),
x,
y,
w,
h,
}
}
fn overlaps(&self, other: &Tile) -> bool {
self.x < other.x + other.w
&& other.x < self.x + self.w
&& self.y < other.y + other.h
&& other.y < self.y + self.h
}
/// This tile kept inside `columns`: at least a cell each way, no wider than the grid, and not past its right edge.
fn fitted(mut self, columns: u32) -> Tile {
self.w = self.w.clamp(1, columns);
self.h = self.h.max(1);
self.x = self.x.min(columns - self.w);
self
}
}
/// Tiles risen as far as the ones above allow, top first.
fn compacted(mut tiles: Vec<Tile>) -> Vec<Tile> {
tiles.sort_by_key(|tile| (tile.y, tile.x));
let mut out: Vec<Tile> = Vec::new();
for mut tile in tiles {
while tile.y > 0 {
let higher = Tile {
y: tile.y - 1,
..tile.clone()
};
if out.iter().any(|placed| placed.overlaps(&higher)) {
break;
}
tile = higher;
}
out.push(tile);
}
out
}
/// The tiles once `to` takes the place of the tile of its key: it goes where it was put, the tiles it lands on move down below it, then every tile, it too, rises as far as the ones above allow.
pub fn arranged(tiles: &[Tile], to: Tile, columns: u32) -> Vec<Tile> {
assert!(columns > 0, "a grid of no columns");
assert!(
tiles.iter().any(|tile| tile.key == to.key),
"no tile {} on the grid",
to.key
);
let mut placed = vec![to.clone().fitted(columns)];
let mut rest: Vec<Tile> = tiles
.iter()
.filter(|tile| tile.key != to.key)
.cloned()
.collect();
rest.sort_by_key(|tile| (tile.y, tile.x));
for mut tile in rest {
while let Some(hit) = placed.iter().find(|placed| placed.overlaps(&tile)) {
tile.y = hit.y + hit.h;
}
placed.push(tile);
}
compacted(placed)
}
/// Where a tile goes on a step down or up: below the next tile under it, or into the place of the next one above; none at the edge. Both overlap its columns.
pub fn stepped(tiles: &[Tile], key: &str, down: bool) -> Option<Tile> {
let tile = tiles
.iter()
.find(|tile| tile.key == key)
.unwrap_or_else(|| panic!("no tile {key} on the grid"));
let beside = |other: &&Tile| {
other.key != tile.key && other.x < tile.x + tile.w && tile.x < other.x + other.w
};
if down {
tiles
.iter()
.filter(beside)
.filter(|other| other.y >= tile.y + tile.h)
.min_by_key(|other| other.y)
.map(|next| Tile {
y: next.y + next.h,
..tile.clone()
})
} else {
tiles
.iter()
.filter(beside)
.filter(|other| other.y + other.h <= tile.y)
.max_by_key(|other| other.y)
.map(|above| Tile {
y: above.y,
..tile.clone()
})
}
}
#[cfg(test)]
mod tests {
use super::{Tile, arranged, stepped};
fn at(tiles: &[Tile], key: &str) -> (u32, u32, u32, u32) {
let tile = tiles.iter().find(|tile| tile.key == key).expect("a tile");
(tile.x, tile.y, tile.w, tile.h)
}
fn grid() -> Vec<Tile> {
vec![
Tile::new("a", (0, 0), (6, 2)),
Tile::new("b", (6, 0), (6, 2)),
Tile::new("c", (0, 2), (12, 3)),
]
}
#[test]
fn a_tile_dropped_on_another_pushes_it_below() {
let moved = arranged(&grid(), Tile::new("b", (0, 0), (6, 2)), 12);
assert_eq!(at(&moved, "b"), (0, 0, 6, 2), "the dropped tile stays");
assert_eq!(at(&moved, "a"), (0, 2, 6, 2), "a goes below b");
assert_eq!(at(&moved, "c"), (0, 4, 12, 3), "and c below a");
}
#[test]
fn tiles_rise_into_the_gap_a_tile_leaves() {
let moved = arranged(&grid(), Tile::new("a", (0, 9), (6, 2)), 12);
assert_eq!(at(&moved, "c"), (0, 2, 12, 3), "c keeps below b");
assert_eq!(at(&moved, "a"), (0, 5, 6, 2), "a rises to rest on c");
}
#[test]
fn a_tile_stays_inside_the_grid() {
let moved = arranged(&grid(), Tile::new("a", (10, 0), (6, 2)), 12);
assert_eq!(
at(&moved, "a"),
(6, 0, 6, 2),
"pulled back from the right edge"
);
let wide = arranged(&grid(), Tile::new("b", (0, 0), (20, 1)), 12);
assert_eq!(at(&wide, "b"), (0, 0, 12, 1), "no wider than the grid");
}
#[test]
fn a_step_down_passes_the_tile_under_and_a_step_up_takes_its_place() {
let down = stepped(&grid(), "a", true).expect("c lies under a");
assert_eq!((down.x, down.y), (0, 5), "a steps under the bottom of c");
let moved = arranged(&grid(), down, 12);
assert_eq!(at(&moved, "c"), (0, 2, 12, 3), "c rests under b");
assert_eq!(at(&moved, "a"), (0, 5, 6, 2), "a rests under c");
let up = stepped(&moved, "a", false).expect("c lies over a");
assert_eq!(
at(&arranged(&moved, up, 12), "a"),
(0, 0, 6, 2),
"back on top"
);
assert_eq!(stepped(&grid(), "b", false), None, "nothing over b");
}
}