use super::*; impl AppRoot { pub(super) fn render_overview(&self, cx: &mut Context) -> impl IntoElement + '_ { let pending_approvals = self .snapshot .approvals .iter() .filter(|approval| approval.state == "pending") .collect::>(); let failed_runs = self .snapshot .runs .iter() .filter(|run| { matches!( run.status.as_str(), "failed" | "timed_out" | "cancelled" | "interrupted" ) }) .collect::>(); let unread_messages = self .snapshot .agent_messages .iter() .filter(|message| message.read_at.is_none()) .collect::>(); let budget_alerts = self .snapshot .agents .iter() .filter(|agent| { agent.budget_monthly_usd > 0.0 && agent.spent_monthly_usd >= agent.budget_monthly_usd * 0.8 }) .collect::>(); let interrupted_runs = self .snapshot .runs .iter() .filter(|run| run.status == "interrupted") .collect::>(); let active_work = self .snapshot .runs .iter() .filter(|run| matches!(run.status.as_str(), "queued" | "running")) .take(8) .collect::>(); let total_spend = self .snapshot .runs .iter() .filter_map(|run| run.cost_usd) .sum::(); let approval_rows = pending_approvals .iter() .take(5) .map(|approval| { attention_row( approval.payload_summary.clone(), format!("{} · pending", approval.approval_type.replace('_', " ")), theme::accent_orange_soft(), theme::accent_orange(), SectionId::Approvals, Some(approval.id.as_str()), cx, ) .into_any_element() }) .collect::>(); let failed_rows = failed_runs .iter() .take(3) .map(|run| { attention_row( overview_run_title(&self.snapshot, run), run.error_message .clone() .unwrap_or_else(|| run.status.clone()), theme::danger_bg(), theme::danger(), SectionId::Runs, Some(run.id.as_str()), cx, ) .into_any_element() }) .collect::>(); let unread_rows = unread_messages .iter() .take(3) .map(|message| { attention_row( message.subject.clone(), message.body.clone(), theme::accent_teal_soft(), theme::accent_teal(), SectionId::Messages, Some(message.id.as_str()), cx, ) .into_any_element() }) .collect::>(); div() .flex() .flex_col() .gap_6() .when(!interrupted_runs.is_empty(), |container| { container.child(recovery_banner(interrupted_runs.as_slice())) }) .when(!budget_alerts.is_empty(), |container| { container.child(budget_alert_banner(budget_alerts.as_slice(), cx)) }) .child( div() .grid() .grid_cols(4) .gap_3() .child(metric_card( "ACTIVE TASKS", self.snapshot.active_tasks().to_string(), format!( "{} queued", self.snapshot .tasks .iter() .filter(|task| task.status == "todo") .count() ), theme::accent_blue_soft(), theme::accent_blue(), SectionId::Inbox, cx, )) .child(metric_card( "APPROVALS", pending_approvals.len().to_string(), if pending_approvals.is_empty() { "All clear".to_string() } else { "Needs attention".to_string() }, theme::accent_orange_soft(), theme::accent_orange(), SectionId::Approvals, cx, )) .child(metric_card( "AGENTS", self.snapshot.agents.len().to_string(), format!( "{} running", self.snapshot .agents .iter() .filter(|agent| agent.status == "running") .count() ), theme::accent_teal_soft(), theme::accent_teal(), SectionId::Messages, cx, )) .child(metric_card( "TOTAL SPEND", format!("${total_spend:.2}"), "Open settings and costs".to_string(), theme::panel_muted(), theme::text_primary(), SectionId::Settings, cx, )), ) .child(eyebrow_label("PERFORMANCE")) .child( div() .grid() .grid_cols(2) .gap_3() .child(run_activity_card(&self.snapshot)) .child(success_rate_card(&self.snapshot)) .child(cost_trend_card(&self.snapshot)) .child(agent_workload_card(&self.snapshot)), ) .child(eyebrow_label("BUDGET UTILIZATION")) .child(budget_utilization_card(&self.snapshot)) .when( !(pending_approvals.is_empty() && failed_runs.is_empty() && unread_messages.is_empty()), |container| { container.child(needs_attention_label()).child( div() .gap_2() .children(approval_rows) .children(failed_rows) .children(unread_rows), ) }, ) .child(active_work_header(cx)) .child(active_work_card(&self.snapshot, active_work.as_slice(), cx)) .child(eyebrow_label("RECENT ACTIVITY")) .child(activity_feed_card(&self.snapshot)) } } fn recovery_banner(runs: &[&domain::Run]) -> impl IntoElement { let danger_30 = gpui::Hsla { a: 0.3, ..theme::danger() }; div() .rounded(px(0.0)) .border_1() .border_color(danger_30) .bg(theme::warning_bg()) .px_4() .py_4() .mb_4() .child( div() .flex() .gap_2() .items_center() .child( div() .w(px(16.0)) .h(px(16.0)) .rounded(px(4.0)) .bg(theme::danger()) .flex() .items_center() .justify_center() .child(div().w(px(10.0)).h(px(10.0)).rounded_full().bg(theme::panel())), ) .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(format!( "{} interrupted task(s) detected from the previous session", runs.len() )), ), ) .children(runs.iter().map(|run| { div() .mt(px(8.0)) .rounded(px(4.0)) .bg(theme::panel()) .px_4() .py_3() .child( div() .text_size(px(13.0)) .text_color(theme::text_primary()) .child(overview_run_title_from_run(run)), ) .child( div() .mt(px(4.0)) .text_size(px(11.0)) .text_color(theme::text_muted()) .child(run.id.get(..8).unwrap_or(run.id.as_str()).to_string()), ) })) } fn budget_alert_banner(agents: &[&domain::Agent], cx: &mut Context) -> impl IntoElement { let danger_30 = gpui::Hsla { a: 0.3, ..theme::danger() }; div().gap_2().children(agents.iter().map(|agent| { div() .id(SharedString::from(format!("budget-alert-{}", agent.id))) .rounded(px(0.0)) .border_1() .border_color(danger_30) .bg(theme::danger_bg()) .px_4() .py_3() .cursor_pointer() .hover(|style| style.bg(theme::panel_hover())) .on_click(cx.listener(|this, _, _, cx| { this.state.section = SectionId::Settings; cx.notify(); })) .child( div() .flex() .gap_2() .items_center() .child( div() .w(px(16.0)) .h(px(16.0)) .rounded(px(4.0)) .bg(theme::danger()) .flex() .items_center() .justify_center() .child(div().w(px(10.0)).h(px(10.0)).rounded_full().bg(theme::panel())), ) .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(format!( "{} is at ${:.2} / ${:.2} monthly budget.", agent.name, agent.spent_monthly_usd, agent.budget_monthly_usd )), ), ) })) } fn metric_card( label: &'static str, value: String, subtitle: String, icon_bg: gpui::Hsla, _tone: gpui::Hsla, target_section: SectionId, cx: &mut Context, ) -> impl IntoElement { let icon_letter = match label { "ACTIVE TASKS" => "T", "APPROVALS" => "A", "RUNS" => "R", "AGENTS" => "A", _ => "•", }; div() .id(SharedString::from(format!("overview-metric-{label}"))) .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .px_4() .py_4() .cursor_pointer() .hover(|style| style.bg(theme::panel_hover())) .on_click(cx.listener(move |this, _, _, cx| { this.state.section = target_section; cx.notify(); })) .child( div() .flex() .gap_4() .items_center() .child( div() .w(px(48.0)) .h(px(48.0)) .rounded(px(4.0)) .bg(icon_bg) .flex() .items_center() .justify_center() .child( div() .text_size(px(18.0)) .font_weight(gpui::FontWeight::BOLD) .text_color(theme::text_muted()) .child(icon_letter), ), ) .child( div() .flex_1() .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::text_muted()) .child(label), ) .child( div() .text_size(px(28.0)) .font_weight(gpui::FontWeight::BOLD) .text_color(theme::text_primary()) .child(value), ) .child( div() .mt(px(6.0)) .text_size(px(11.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_muted()) .child(subtitle), ), ), ) } fn eyebrow_label(label: &'static str) -> impl IntoElement { div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::text_muted()) .child(label) } fn needs_attention_label() -> impl IntoElement { div() .flex() .items_center() .gap_2() .child( div() .w(px(6.0)) .h(px(6.0)) .rounded_full() .bg(theme::accent_orange()), ) .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::accent_orange()) .child("NEEDS ATTENTION"), ) } fn attention_row( title: String, subtitle: String, tile_bg: gpui::Hsla, accent: gpui::Hsla, target_section: SectionId, target_id: Option<&str>, cx: &mut Context, ) -> impl IntoElement { let selected_id = target_id.map(str::to_string); div() .id(SharedString::from(format!("overview-attention-{title}"))) .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .px_4() .py_3() .cursor_pointer() .hover(|style| style.bg(theme::panel_hover())) .on_click(cx.listener(move |this, _, _, cx| { this.state.section = target_section; match target_section { SectionId::Runs => this.state.selected_run_id = selected_id.clone(), SectionId::Approvals => this.state.selected_approval_id = selected_id.clone(), SectionId::Messages => this.state.selected_message_id = selected_id.clone(), _ => {} } cx.notify(); })) .child( div() .flex() .gap_3() .items_center() .child( div() .w(px(36.0)) .h(px(36.0)) .rounded(px(4.0)) .bg(tile_bg) .flex() .items_center() .justify_center() .child( div() .w(px(8.0)) .h(px(8.0)) .rounded_full() .bg(accent), ), ) .child( div() .flex_1() .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(title), ) .child( div() .mt(px(4.0)) .text_size(px(11.0)) .text_color(theme::text_muted()) .line_clamp(2) .child(subtitle), ), ) .child( div() .text_size(px(14.0)) .text_color(theme::text_muted()) .child(">"), ), ) } fn run_activity_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { let queued = snapshot .runs .iter() .filter(|run| run.status == "queued") .count(); let running = snapshot .runs .iter() .filter(|run| run.status == "running") .count(); let completed = snapshot .runs .iter() .filter(|run| run.status == "completed") .count(); mini_chart_card( "RUN ACTIVITY", vec![ ("queued".to_string(), queued), ("running".to_string(), running), ("completed".to_string(), completed), ], theme::accent_blue(), ) } fn success_rate_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { let finished = snapshot .runs .iter() .filter(|run| matches!(run.status.as_str(), "completed" | "failed" | "timed_out")) .count(); let completed = snapshot .runs .iter() .filter(|run| run.status == "completed") .count(); let rate = if finished == 0 { 0.0 } else { completed as f32 / finished as f32 }; div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .p_5() .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::text_muted()) .child("SUCCESS RATE"), ) .child( div() .mt(px(10.0)) .text_size(px(28.0)) .font_weight(gpui::FontWeight::BOLD) .text_color(theme::accent_teal()) .child(format!("{:.0}%", rate * 100.0)), ) .child( div() .mt(px(10.0)) .h(px(10.0)) .rounded_full() .bg(theme::panel_muted()) .child( div() .w(gpui::relative(rate.clamp(0.0, 1.0))) .h_full() .rounded_full() .bg(theme::accent_teal()), ), ) } fn cost_trend_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { let costs = snapshot .runs .iter() .filter_map(|run| run.cost_usd) .collect::>(); let total = costs.iter().sum::(); let average = if costs.is_empty() { 0.0 } else { total / costs.len() as f64 }; div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .p_5() .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::text_muted()) .child("COST TREND"), ) .child( div() .mt(px(10.0)) .text_size(px(28.0)) .font_weight(gpui::FontWeight::BOLD) .text_color(theme::text_primary()) .child(format!("${total:.2}")), ) .child( div() .mt(px(8.0)) .text_size(px(11.0)) .text_color(theme::text_muted()) .child(format!("Average ${average:.2} per metered run")), ) } fn agent_workload_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { let rows = snapshot .agents .iter() .map(|agent| { let active_runs = snapshot .runs .iter() .filter(|run| run.agent_id == agent.id) .count(); (agent.name.clone(), active_runs) }) .collect::>(); mini_chart_card("AGENT WORKLOAD", rows, theme::accent_orange()) } fn mini_chart_card( label: &'static str, rows: Vec<(String, usize)>, accent: gpui::Hsla, ) -> impl IntoElement { let max = rows .iter() .map(|(_, count)| *count) .max() .unwrap_or(1) .max(1) as f32; div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .p_5() .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::SEMIBOLD) .text_color(theme::text_muted()) .child(label), ) .children(rows.into_iter().map(|(name, count)| { div() .mt(px(12.0)) .child( div() .flex() .justify_between() .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(name), ) .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_muted()) .child(count.to_string()), ), ) .child( div() .mt(px(6.0)) .h(px(8.0)) .rounded_full() .bg(theme::panel_muted()) .child( div() .w(gpui::relative((count as f32 / max).clamp(0.0, 1.0))) .h_full() .rounded_full() .bg(accent), ), ) })) } fn budget_utilization_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .p_5() .children( snapshot .agents .iter() .filter(|agent| agent.budget_monthly_usd > 0.0) .map(|agent| { let ratio = (agent.spent_monthly_usd / agent.budget_monthly_usd).clamp(0.0, 1.0) as f32; div() .mt(px(12.0)) .child( div() .flex() .justify_between() .items_center() .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(agent.name.clone()), ) .child( div() .text_size(px(11.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_muted()) .child(format!( "${:.2} / ${:.2}", agent.spent_monthly_usd, agent.budget_monthly_usd )), ), ) .child( div() .mt(px(6.0)) .h(px(8.0)) .rounded_full() .bg(theme::panel_muted()) .child(div().w(gpui::relative(ratio)).h_full().rounded_full().bg( if ratio >= 1.0 { theme::danger() } else if ratio >= 0.8 { theme::accent_orange() } else { theme::accent_teal() }, )), ) }), ) } fn active_work_header(cx: &mut Context) -> impl IntoElement { div() .flex() .justify_between() .items_center() .child(eyebrow_label("ACTIVE WORK")) .child( div() .id("overview-all-runs") .cursor_pointer() .text_size(px(11.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::accent_blue()) .hover(|style| style.text_color(theme::text_primary())) .on_click(cx.listener(|this, _, _, cx| { this.state.section = SectionId::Runs; cx.notify(); })) .child("All runs"), ) } fn active_work_card<'a>( snapshot: &'a domain::ProfileSnapshot, runs: &[&'a domain::Run], cx: &mut Context, ) -> impl IntoElement + 'a { div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .when(runs.is_empty(), |container| { container.child( div() .p_6() .text_center() .text_color(theme::text_muted()) .child("No tasks are running right now."), ) }) .when(!runs.is_empty(), |container| { container.children(runs.iter().map(|run| { let run_id = run.id.clone(); div() .id(SharedString::from(format!("overview-run-{run_id}"))) .cursor_pointer() .hover(|style| style.bg(theme::panel_hover())) .on_click(cx.listener(move |this, _, _, cx| { this.state.section = SectionId::Runs; this.state.selected_run_id = Some(run_id.clone()); cx.notify(); })) .px_4() .py_3() .border_b_1() .border_color(theme::panel_border()) .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(overview_run_title(snapshot, run)), ) .child( div() .mt(px(4.0)) .text_size(px(11.0)) .text_color(theme::text_muted()) .child(format!( "{} · {}", overview_run_agent(snapshot, run), run.status )), ) })) }) } fn activity_feed_card(snapshot: &domain::ProfileSnapshot) -> impl IntoElement { div() .rounded(px(0.0)) .border_1() .border_color(theme::panel_border()) .bg(theme::panel()) .children(snapshot.activity.iter().take(10).map(|item| { div() .px_4() .py_3() .border_b_1() .border_color(theme::panel_border()) .child( div() .text_size(px(13.0)) .font_weight(gpui::FontWeight::MEDIUM) .text_color(theme::text_primary()) .child(format!("{} {}", item.actor, item.action.replace('_', " "))), ) .child( div() .mt(px(4.0)) .text_size(px(11.0)) .text_color(theme::text_muted()) .child(item.detail.clone()), ) })) } fn overview_run_title(snapshot: &domain::ProfileSnapshot, run: &domain::Run) -> String { run.task_id .as_ref() .and_then(|task_id| snapshot.tasks.iter().find(|task| &task.id == task_id)) .map(|task| task.title.clone()) .unwrap_or_else(|| overview_run_title_from_run(run)) } fn overview_run_title_from_run(run: &domain::Run) -> String { if run.summary.trim().is_empty() { format!("Run {}", run.id.get(..8).unwrap_or(run.id.as_str())) } else { run.summary.clone() } } fn overview_run_agent(snapshot: &domain::ProfileSnapshot, run: &domain::Run) -> String { snapshot .agents .iter() .find(|agent| agent.id == run.agent_id) .map(|agent| agent.name.clone()) .unwrap_or_else(|| run.agent_id.clone()) }