1use crate::{Tooltip, prelude::*};
2use gpui::{ClickEvent, IntoElement, ParentElement, SharedString};
3
4#[derive(IntoElement, RegisterComponent)]
5pub struct ConfiguredApiCard {
6 label: SharedString,
7 button_label: Option<SharedString>,
8 button_tab_index: Option<isize>,
9 tooltip_label: Option<SharedString>,
10 disabled: bool,
11 on_click: Option<Box<dyn Fn(&ClickEvent, &mut Window, &mut App) + 'static>>,
12}
13
14impl ConfiguredApiCard {
15 pub fn new(label: impl Into<SharedString>) -> Self {
16 Self {
17 label: label.into(),
18 button_label: None,
19 button_tab_index: None,
20 tooltip_label: None,
21 disabled: false,
22 on_click: None,
23 }
24 }
25
26 pub fn on_click(
27 mut self,
28 handler: impl Fn(&ClickEvent, &mut Window, &mut App) + 'static,
29 ) -> Self {
30 self.on_click = Some(Box::new(handler));
31 self
32 }
33
34 pub fn button_label(mut self, button_label: impl Into<SharedString>) -> Self {
35 self.button_label = Some(button_label.into());
36 self
37 }
38
39 pub fn tooltip_label(mut self, tooltip_label: impl Into<SharedString>) -> Self {
40 self.tooltip_label = Some(tooltip_label.into());
41 self
42 }
43
44 pub fn disabled(mut self, disabled: bool) -> Self {
45 self.disabled = disabled;
46 self
47 }
48
49 pub fn button_tab_index(mut self, tab_index: isize) -> Self {
50 self.button_tab_index = Some(tab_index);
51 self
52 }
53}
54
55impl Component for ConfiguredApiCard {
56 fn scope() -> ComponentScope {
57 ComponentScope::Agent
58 }
59
60 fn preview(_window: &mut Window, cx: &mut App) -> Option<AnyElement> {
61 let container = || {
62 v_flex()
63 .w_72()
64 .p_2()
65 .gap_2()
66 .border_1()
67 .border_color(cx.theme().colors().border_variant)
68 .bg(cx.theme().colors().panel_background)
69 };
70
71 let examples = vec![
72 single_example(
73 "Default",
74 container()
75 .child(ConfiguredApiCard::new("API key is configured"))
76 .into_any_element(),
77 ),
78 single_example(
79 "Custom Button Label",
80 container()
81 .child(
82 ConfiguredApiCard::new("OpenAI API key configured")
83 .button_label("Remove Key"),
84 )
85 .into_any_element(),
86 ),
87 single_example(
88 "With Tooltip",
89 container()
90 .child(
91 ConfiguredApiCard::new("Anthropic API key configured")
92 .tooltip_label("Click to reset your API key"),
93 )
94 .into_any_element(),
95 ),
96 single_example(
97 "Disabled",
98 container()
99 .child(ConfiguredApiCard::new("API key is configured").disabled(true))
100 .into_any_element(),
101 ),
102 ];
103
104 Some(example_group(examples).into_any_element())
105 }
106}
107
108impl RenderOnce for ConfiguredApiCard {
109 fn render(self, _: &mut Window, cx: &mut App) -> impl IntoElement {
110 let button_label = self.button_label.unwrap_or("Reset Key".into());
111 let button_id = SharedString::new(format!("id-{}", button_label));
112
113 h_flex()
114 .min_w_0()
115 .mt_0p5()
116 .p_1()
117 .justify_between()
118 .rounded_md()
119 .flex_wrap()
120 .border_1()
121 .border_color(cx.theme().colors().border)
122 .bg(cx.theme().colors().background)
123 .child(
124 h_flex()
125 .min_w_0()
126 .gap_1()
127 .child(Icon::new(IconName::Check).color(Color::Success))
128 .child(Label::new(self.label)),
129 )
130 .child(
131 Button::new(button_id, button_label)
132 .when_some(self.button_tab_index, |elem, tab_index| {
133 elem.tab_index(tab_index)
134 })
135 .label_size(LabelSize::Small)
136 .start_icon(
137 Icon::new(IconName::Undo)
138 .size(IconSize::Small)
139 .color(Color::Muted),
140 )
141 .disabled(self.disabled)
142 .when_some(self.tooltip_label, |this, label| {
143 this.tooltip(Tooltip::text(label))
144 })
145 .when_some(
146 self.on_click.filter(|_| !self.disabled),
147 |this, on_click| this.on_click(on_click),
148 ),
149 )
150 }
151}