ui/components/ai/
agent_thread_toolbar.rs1use gpui::SharedString;
2
3use crate::prelude::*;
4
5#[derive(IntoElement, RegisterComponent)]
13pub struct AgentThreadToolbar {
14 id: ElementId,
15 title: SharedString,
16 right_slot: Option<AnyElement>,
17 usage: Option<Vec<(String, String)>>,
18}
19
20impl AgentThreadToolbar {
21 pub fn new(id: impl Into<ElementId>, title: impl Into<SharedString>) -> Self {
22 Self {
23 id: id.into(),
24 title: title.into(),
25 right_slot: None,
26 usage: None,
27 }
28 }
29
30 pub fn right_slot(mut self, element: impl IntoElement) -> Self {
32 self.right_slot = Some(element.into_any_element());
33 self
34 }
35
36 pub fn usage(mut self, usage: Vec<(String, String)>) -> Self {
39 self.usage = Some(usage);
40 self
41 }
42}
43
44impl RenderOnce for AgentThreadToolbar {
45 fn render(self, _window: &mut Window, cx: &mut App) -> impl IntoElement {
46 h_flex()
47 .id(self.id)
48 .w_full()
49 .justify_between()
50 .items_center()
51 .gap_2()
52 .px_2()
53 .py_1p5()
54 .border_b_1()
55 .border_color(cx.theme().colors().border_variant)
56 .child(
57 h_flex()
58 .gap_3()
59 .min_w_0()
60 .child(Label::new(self.title).truncate())
61 .when_some(self.usage, |this, usage| {
62 this.children(usage.into_iter().map(|(label, value)| {
63 h_flex()
64 .gap_1()
65 .flex_shrink_0()
66 .child(Label::new(label).size(LabelSize::Small).color(Color::Muted))
67 .child(Label::new(value).size(LabelSize::Small))
68 }))
69 }),
70 )
71 .when_some(self.right_slot, |this, slot| this.child(slot))
72 }
73}
74
75impl Component for AgentThreadToolbar {
76 fn scope() -> ComponentScope {
77 ComponentScope::Agent
78 }
79
80 fn description() -> Option<&'static str> {
81 Some(
82 "The toolbar shown atop an agent chat thread: title, a right-hand \
83 slot for a model selector, and optional usage/cost figures.",
84 )
85 }
86
87 fn preview(_window: &mut Window, _cx: &mut App) -> Option<AnyElement> {
88 Some(
89 v_flex()
90 .w_96()
91 .gap_4()
92 .child(single_example(
93 "Title only",
94 AgentThreadToolbar::new("toolbar-1", "New Thread").into_any_element(),
95 ))
96 .child(single_example(
97 "With usage",
98 AgentThreadToolbar::new("toolbar-2", "Refactor auth module")
99 .usage(vec![
100 ("Tokens".to_string(), "12.4k".to_string()),
101 ("Cost".to_string(), "$0.08".to_string()),
102 ])
103 .into_any_element(),
104 ))
105 .child(single_example(
106 "With right slot",
107 AgentThreadToolbar::new("toolbar-3", "Fix flaky test")
108 .right_slot(
109 Button::new("toolbar-model", "claude-sonnet-4.6")
110 .style(ButtonStyle::Subtle),
111 )
112 .usage(vec![("Cost".to_string(), "$0.02".to_string())])
113 .into_any_element(),
114 ))
115 .into_any_element(),
116 )
117 }
118}