configured_api_card.rs

  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}