Skip to repository content

tenant.openagents/omega

No repository description is available.

OpenAgents Git authority 2026-07-28T05:37:47.154Z Public web read
NIP-34 coordinate30617:7649603503856e5148d571eac2766b288a8ff1e9e35d380337a1d2b0015b4f92:omega
MaintainersHidden in public view
References2 branches · 1 tag
Read-only clonegit clone https://openagents.com/git/tenant.openagents/omega.git
Browse files

askpass_modal.rs

148 lines · 5.2 KB · rust
1use askpass::EncryptedPassword;
2use editor::Editor;
3use futures::channel::oneshot;
4use gpui::{AppContext, DismissEvent, Entity, EventEmitter, Focusable, Styled};
5use ui::{
6    ActiveTheme, AnyElement, App, Button, Clickable, Color, Context, DynamicSpacing, Headline,
7    HeadlineSize, Icon, IconName, IconSize, InteractiveElement, IntoElement, Label, LabelCommon,
8    LabelSize, ParentElement, Render, SharedString, StyledExt, StyledTypography, Window, div,
9    h_flex, v_flex,
10};
11use util::maybe;
12use workspace::ModalView;
13use zeroize::Zeroize;
14
15pub(crate) struct AskPassModal {
16    operation: SharedString,
17    prompt: SharedString,
18    editor: Entity<Editor>,
19    tx: Option<oneshot::Sender<EncryptedPassword>>,
20}
21
22impl EventEmitter<DismissEvent> for AskPassModal {}
23impl ModalView for AskPassModal {}
24impl Focusable for AskPassModal {
25    fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
26        self.editor.focus_handle(cx)
27    }
28}
29
30impl AskPassModal {
31    pub fn new(
32        operation: SharedString,
33        prompt: SharedString,
34        tx: oneshot::Sender<EncryptedPassword>,
35        window: &mut Window,
36        cx: &mut Context<Self>,
37    ) -> Self {
38        let editor = cx.new(|cx| {
39            let mut editor = Editor::single_line(window, cx);
40            if prompt.contains("yes/no") || prompt.contains("Username") {
41                editor.set_masked(false, cx);
42            } else {
43                editor.set_masked(true, cx);
44            }
45            editor
46        });
47        Self {
48            operation,
49            prompt,
50            editor,
51            tx: Some(tx),
52        }
53    }
54
55    fn cancel(&mut self, _: &menu::Cancel, _window: &mut Window, cx: &mut Context<Self>) {
56        cx.emit(DismissEvent);
57    }
58
59    fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
60        maybe!({
61            let tx = self.tx.take()?;
62            let mut text = self.editor.update(cx, |this, cx| {
63                let text = this.text(cx);
64                this.clear(window, cx);
65                text
66            });
67            let pw = askpass::EncryptedPassword::try_from(text.as_ref()).ok()?;
68            text.zeroize();
69            tx.send(pw).ok();
70            Some(())
71        });
72
73        cx.emit(DismissEvent);
74    }
75
76    fn render_hint(&mut self, cx: &mut Context<Self>) -> Option<AnyElement> {
77        let color = cx.theme().status().info_background;
78        if (self.prompt.contains("Password") || self.prompt.contains("Username"))
79            && self.prompt.contains("github.com")
80        {
81            return Some(
82            div()
83                .p_2()
84                .bg(color)
85                .border_t_1()
86                .border_color(cx.theme().status().info_border)
87                .child(
88                    h_flex().gap_2()
89                        .child(
90                            Icon::new(IconName::Github).size(IconSize::Small)
91                        )
92                        .child(
93                            Label::new("You may need to configure git for Github.")
94                                .size(LabelSize::Small),
95                        )
96                        .child(Button::new("learn-more", "Learn more").color(Color::Accent).label_size(LabelSize::Small).on_click(|_, _, cx| {
97                            cx.open_url("https://docs.github.com/en/get-started/git-basics/set-up-git#authenticating-with-github-from-git")
98                        })),
99                )
100                .into_any_element(),
101        );
102        }
103        None
104    }
105}
106
107impl Render for AskPassModal {
108    fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
109        v_flex()
110            .key_context("PasswordPrompt")
111            .on_action(cx.listener(Self::cancel))
112            .on_action(cx.listener(Self::confirm))
113            .elevation_2(cx)
114            .size_full()
115            .child(
116                h_flex()
117                    .font_buffer(cx)
118                    .px(DynamicSpacing::Base12.rems(cx))
119                    .pt(DynamicSpacing::Base08.rems(cx))
120                    .pb(DynamicSpacing::Base04.rems(cx))
121                    .rounded_t_sm()
122                    .w_full()
123                    .gap_1p5()
124                    .child(Icon::new(IconName::GitBranch).size(IconSize::XSmall))
125                    .child(h_flex().gap_1().overflow_x_hidden().child(
126                        div().max_w_96().overflow_x_hidden().text_ellipsis().child(
127                            Headline::new(self.operation.clone()).size(HeadlineSize::XSmall),
128                        ),
129                    )),
130            )
131            .child(
132                div()
133                    .font_buffer(cx)
134                    .text_buffer(cx)
135                    .py_2()
136                    .px_3()
137                    .bg(cx.theme().colors().editor_background)
138                    .border_t_1()
139                    .border_color(cx.theme().colors().border_variant)
140                    .size_full()
141                    .overflow_hidden()
142                    .child(self.prompt.clone())
143                    .child(self.editor.clone()),
144            )
145            .children(self.render_hint(cx))
146    }
147}
148
Served at tenant.openagents/omega Member data and write actions are omitted.