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.
109 lines
3.4 KiB
Rust
109 lines
3.4 KiB
Rust
use gpui::{
|
|
AnyElement, App, FontWeight, IntoElement, ParentElement, RenderOnce, SharedString, Styled,
|
|
Window, div,
|
|
};
|
|
|
|
use crate::{
|
|
theme::{ActiveTheme, Radius, TextSize},
|
|
typography::Ellipsis,
|
|
};
|
|
|
|
/// A widget's frame: its title with a line under it, actions at the end of the title's line, its body, and an optional footer. It fills the box it sits in, as a dashboard tile.
|
|
#[derive(IntoElement)]
|
|
pub struct DashboardCard {
|
|
title: SharedString,
|
|
subtitle: Option<SharedString>,
|
|
actions: Vec<AnyElement>,
|
|
body: Option<AnyElement>,
|
|
footer: Option<AnyElement>,
|
|
}
|
|
|
|
impl DashboardCard {
|
|
pub fn new(title: impl Into<SharedString>) -> Self {
|
|
Self {
|
|
title: title.into(),
|
|
subtitle: None,
|
|
actions: Vec::new(),
|
|
body: None,
|
|
footer: None,
|
|
}
|
|
}
|
|
|
|
pub fn subtitle(mut self, text: impl Into<SharedString>) -> Self {
|
|
self.subtitle = Some(text.into());
|
|
self
|
|
}
|
|
|
|
pub fn action(mut self, action: impl IntoElement) -> Self {
|
|
self.actions.push(action.into_any_element());
|
|
self
|
|
}
|
|
|
|
pub fn body(mut self, body: impl IntoElement) -> Self {
|
|
self.body = Some(body.into_any_element());
|
|
self
|
|
}
|
|
|
|
pub fn footer(mut self, footer: impl IntoElement) -> Self {
|
|
self.footer = Some(footer.into_any_element());
|
|
self
|
|
}
|
|
}
|
|
|
|
impl RenderOnce for DashboardCard {
|
|
fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
|
|
let theme = cx.theme();
|
|
div()
|
|
.h_full()
|
|
.flex()
|
|
.flex_col()
|
|
.gap_3()
|
|
.p_4()
|
|
.rounded(theme.radius(Radius::Lg))
|
|
.border_1()
|
|
.border_color(theme.colors.border)
|
|
.bg(theme.colors.surface)
|
|
.overflow_hidden()
|
|
.child(
|
|
div()
|
|
.flex()
|
|
.items_start()
|
|
.justify_between()
|
|
.gap_2()
|
|
.child(
|
|
div()
|
|
.flex_1()
|
|
.min_w_0()
|
|
.flex()
|
|
.flex_col()
|
|
.child(
|
|
div()
|
|
.font_weight(FontWeight::SEMIBOLD)
|
|
.child(Ellipsis::new(self.title)),
|
|
)
|
|
.children(self.subtitle.map(|text| {
|
|
div()
|
|
.text_size(theme.text_size(TextSize::Xs))
|
|
.text_color(theme.colors.fg_muted)
|
|
.child(Ellipsis::new(text))
|
|
})),
|
|
)
|
|
.child(
|
|
div()
|
|
.flex_none()
|
|
.flex()
|
|
.items_center()
|
|
.gap_1()
|
|
.children(self.actions),
|
|
),
|
|
)
|
|
.child(div().flex_1().min_h_0().children(self.body))
|
|
.children(self.footer.map(|footer| {
|
|
div()
|
|
.text_size(theme.text_size(TextSize::Xs))
|
|
.text_color(theme.colors.fg_subtle)
|
|
.child(footer)
|
|
}))
|
|
}
|
|
}
|