148 lines
5.1 KiB
Rust
148 lines
5.1 KiB
Rust
use askpass::EncryptedPassword;
|
|
use editor::Editor;
|
|
use futures::channel::oneshot;
|
|
use gpui::{AppContext, DismissEvent, Entity, EventEmitter, Focusable, Styled};
|
|
use ui::{
|
|
ActiveTheme, AnyElement, App, Button, Clickable, Color, Context, DynamicSpacing, Headline,
|
|
HeadlineSize, Icon, IconName, IconSize, InteractiveElement, IntoElement, Label, LabelCommon,
|
|
LabelSize, ParentElement, Render, SharedString, StyledExt, StyledTypography, Window, div,
|
|
h_flex, v_flex,
|
|
};
|
|
use util::maybe;
|
|
use workspace::ModalView;
|
|
use zeroize::Zeroize;
|
|
|
|
pub(crate) struct AskPassModal {
|
|
operation: SharedString,
|
|
prompt: SharedString,
|
|
editor: Entity<Editor>,
|
|
tx: Option<oneshot::Sender<EncryptedPassword>>,
|
|
}
|
|
|
|
impl EventEmitter<DismissEvent> for AskPassModal {}
|
|
impl ModalView for AskPassModal {}
|
|
impl Focusable for AskPassModal {
|
|
fn focus_handle(&self, cx: &App) -> gpui::FocusHandle {
|
|
self.editor.focus_handle(cx)
|
|
}
|
|
}
|
|
|
|
impl AskPassModal {
|
|
pub fn new(
|
|
operation: SharedString,
|
|
prompt: SharedString,
|
|
tx: oneshot::Sender<EncryptedPassword>,
|
|
window: &mut Window,
|
|
cx: &mut Context<Self>,
|
|
) -> Self {
|
|
let editor = cx.new(|cx| {
|
|
let mut editor = Editor::single_line(window, cx);
|
|
if prompt.contains("yes/no") || prompt.contains("Username") {
|
|
editor.set_masked(false, cx);
|
|
} else {
|
|
editor.set_masked(true, cx);
|
|
}
|
|
editor
|
|
});
|
|
Self {
|
|
operation,
|
|
prompt,
|
|
editor,
|
|
tx: Some(tx),
|
|
}
|
|
}
|
|
|
|
fn cancel(&mut self, _: &menu::Cancel, _window: &mut Window, cx: &mut Context<Self>) {
|
|
cx.emit(DismissEvent);
|
|
}
|
|
|
|
fn confirm(&mut self, _: &menu::Confirm, window: &mut Window, cx: &mut Context<Self>) {
|
|
maybe!({
|
|
let tx = self.tx.take()?;
|
|
let mut text = self.editor.update(cx, |this, cx| {
|
|
let text = this.text(cx);
|
|
this.clear(window, cx);
|
|
text
|
|
});
|
|
let pw = askpass::EncryptedPassword::try_from(text.as_ref()).ok()?;
|
|
text.zeroize();
|
|
tx.send(pw).ok();
|
|
Some(())
|
|
});
|
|
|
|
cx.emit(DismissEvent);
|
|
}
|
|
|
|
fn render_hint(&mut self, cx: &mut Context<Self>) -> Option<AnyElement> {
|
|
let color = cx.theme().status().info_background;
|
|
if (self.prompt.contains("Password") || self.prompt.contains("Username"))
|
|
&& self.prompt.contains("github.com")
|
|
{
|
|
return Some(
|
|
div()
|
|
.p_2()
|
|
.bg(color)
|
|
.border_t_1()
|
|
.border_color(cx.theme().status().info_border)
|
|
.child(
|
|
h_flex().gap_2()
|
|
.child(
|
|
Icon::new(IconName::Github).size(IconSize::Small)
|
|
)
|
|
.child(
|
|
Label::new("You may need to configure git for Github.")
|
|
.size(LabelSize::Small),
|
|
)
|
|
.child(Button::new("learn-more", "Learn more").color(Color::Accent).label_size(LabelSize::Small).on_click(|_, _, cx| {
|
|
cx.open_url("https://docs.github.com/en/get-started/git-basics/set-up-git#authenticating-with-github-from-git")
|
|
})),
|
|
)
|
|
.into_any_element(),
|
|
);
|
|
}
|
|
None
|
|
}
|
|
}
|
|
|
|
impl Render for AskPassModal {
|
|
fn render(&mut self, _: &mut Window, cx: &mut Context<Self>) -> impl IntoElement {
|
|
v_flex()
|
|
.key_context("PasswordPrompt")
|
|
.on_action(cx.listener(Self::cancel))
|
|
.on_action(cx.listener(Self::confirm))
|
|
.elevation_2(cx)
|
|
.size_full()
|
|
.child(
|
|
h_flex()
|
|
.font_buffer(cx)
|
|
.px(DynamicSpacing::Base12.rems(cx))
|
|
.pt(DynamicSpacing::Base08.rems(cx))
|
|
.pb(DynamicSpacing::Base04.rems(cx))
|
|
.rounded_t_sm()
|
|
.w_full()
|
|
.gap_1p5()
|
|
.child(Icon::new(IconName::GitBranch).size(IconSize::XSmall))
|
|
.child(h_flex().gap_1().overflow_x_hidden().child(
|
|
div().max_w_96().overflow_x_hidden().text_ellipsis().child(
|
|
Headline::new(self.operation.clone()).size(HeadlineSize::XSmall),
|
|
),
|
|
)),
|
|
)
|
|
.child(
|
|
div()
|
|
.font_buffer(cx)
|
|
.text_buffer(cx)
|
|
.py_2()
|
|
.px_3()
|
|
.bg(cx.theme().colors().editor_background)
|
|
.border_t_1()
|
|
.border_color(cx.theme().colors().border_variant)
|
|
.size_full()
|
|
.overflow_hidden()
|
|
.child(self.prompt.clone())
|
|
.child(self.editor.clone()),
|
|
)
|
|
.children(self.render_hint(cx))
|
|
}
|
|
}
|