Fix cursor focus and selection in input box, add AWS env var warning box, and remove AWS Bedrock login banner
This commit is contained in:
@@ -3,18 +3,18 @@ use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use settings::Setting as _;
|
||||
#[cfg(target_family = "wasm")]
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_graphql::mutations::create_anonymous_user::{
|
||||
AnonymousUserType, CreateAnonymousUserResult,
|
||||
};
|
||||
use warp_server_auth::user::persistence::PersistedUser;
|
||||
use galaxyui::clipboard::ClipboardContent;
|
||||
use galaxyui::{Entity, ModelContext, SingletonEntity, UpdateModel};
|
||||
use settings::Setting as _;
|
||||
#[cfg(target_family = "wasm")]
|
||||
use url::Url;
|
||||
use uuid::Uuid;
|
||||
use warp_server_auth::user::persistence::PersistedUser;
|
||||
|
||||
use super::auth_state::{AuthState, PersistAction};
|
||||
use super::auth_view_modal::{AuthRedirectPayload, AuthViewVariant};
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use galaxy_core::ui::builder::UiBuilder;
|
||||
use galaxy_core::ui::color::blend::Blend;
|
||||
use galaxy_core::ui::color::darken;
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use pathfinder_color::ColorU;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxyui::elements::{ChildView, Container, Fill};
|
||||
use galaxyui::ui_components::components::{Coords, UiComponentStyles};
|
||||
@@ -6,6 +5,7 @@ use galaxyui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
use pathfinder_color::ColorU;
|
||||
|
||||
use super::auth_manager::{AuthManager, AuthManagerEvent};
|
||||
use super::auth_override_warning_body::AuthOverrideWarningBodyEvent;
|
||||
@@ -14,12 +14,6 @@ use crate::auth::auth_view_modal::AuthRedirectPayload;
|
||||
use crate::modal::Modal;
|
||||
use crate::root_view::unthemed_window_border;
|
||||
|
||||
pub struct AuthOverrideWarningModal {
|
||||
auth_override_warning_modal: ViewHandle<Modal<AuthOverrideWarningBody>>,
|
||||
interrupted_auth_payload: Option<AuthRedirectPayload>,
|
||||
variant: AuthOverrideWarningModalVariant,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum AuthOverrideWarningModalVariant {
|
||||
OnboardingView,
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use anyhow::anyhow;
|
||||
use lazy_static::lazy_static;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::ui::appearance::DEFAULT_COMMAND_PALETTE_FONT_SIZE;
|
||||
use galaxy_core::ui::builder::UiBuilder;
|
||||
use lazy_static::lazy_static;
|
||||
use warpui::accessibility::{AccessibilityContent, WarpA11yRole};
|
||||
use warpui::clipboard::ClipboardContent;
|
||||
use warpui::color::ColorU;
|
||||
|
||||
@@ -1,66 +1,11 @@
|
||||
use std::collections::HashMap;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use galaxyui::{AppContext, Element, Entity, TypedActionView, View, ViewContext};
|
||||
use url::Url;
|
||||
use galaxy_core::errors::ErrorExt;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::{safe_anyhow, safe_error};
|
||||
use galaxyui::actions::StandardAction;
|
||||
use galaxyui::elements::{
|
||||
ChildAnchor, ChildView, Container, Fill, HighlightedHyperlink, MouseStateHandle,
|
||||
OffsetPositioning, ParentAnchor, ParentElement, ParentOffsetBounds, Stack,
|
||||
};
|
||||
use galaxyui::keymap::FixedBinding;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponentStyles};
|
||||
use galaxyui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
|
||||
use super::auth_manager::{AuthManager, AuthManagerEvent};
|
||||
use super::auth_view_body::{AuthStep, AuthViewBodyEvent};
|
||||
use super::credentials::RefreshToken;
|
||||
use super::login_failure_notification::{self, LoginFailureReason};
|
||||
use super::UserUid;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::auth::auth_view_body::AuthViewBody;
|
||||
use crate::modal::Modal;
|
||||
use crate::root_view::unthemed_window_border;
|
||||
use crate::server::server_api::auth::UserAuthenticationError;
|
||||
use crate::util::bindings::CustomAction;
|
||||
|
||||
pub fn init(app: &mut AppContext) {
|
||||
use galaxyui::keymap::macros::*;
|
||||
|
||||
app.register_fixed_bindings([
|
||||
// Bindings for paste require the StandardAction and CustomAction binding to work on all platforms.
|
||||
FixedBinding::custom(
|
||||
CustomAction::Paste,
|
||||
AuthViewAction::PasteAuthUrl,
|
||||
"Paste",
|
||||
id!(AuthView::ui_name()),
|
||||
),
|
||||
FixedBinding::standard(
|
||||
StandardAction::Paste,
|
||||
AuthViewAction::PasteAuthUrl,
|
||||
id!(AuthView::ui_name()),
|
||||
),
|
||||
]);
|
||||
|
||||
// For linux and Windows, default paste binding is ctrl+shift+v for PTY reasons.
|
||||
// This can be confusing for users in some cases (and we might want
|
||||
// to solve it in a more general way later). In the meantime, we
|
||||
// add a basic ctrl+v binding for the auth view, since there is no
|
||||
// terminal to interact with yet.
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "windows"))]
|
||||
app.register_fixed_bindings([FixedBinding::new(
|
||||
"cmdorctrl-v",
|
||||
AuthViewAction::PasteAuthUrl,
|
||||
id!(AuthView::ui_name()),
|
||||
)]);
|
||||
}
|
||||
use super::user_uid::UserUid;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct AuthRedirectPayload {
|
||||
@@ -71,38 +16,10 @@ pub struct AuthRedirectPayload {
|
||||
}
|
||||
|
||||
impl AuthRedirectPayload {
|
||||
/// Attempts to parse the `AuthRedirectPayload` from URL sent to Warp. To parse successfully, the URL
|
||||
/// must be of format {scheme}://auth/desktop_redirect?refresh_token={token}.
|
||||
pub fn from_url(url: Url) -> Result<Self> {
|
||||
if url.host_str() != Some(AUTH_URL_HOST) {
|
||||
return Err(safe_anyhow!(
|
||||
safe: ("Auth redirect URL has unexpected host"),
|
||||
full: ("Received URL with unexpected host: {} ", url)
|
||||
));
|
||||
}
|
||||
let query_params: HashMap<_, _> = url.query_pairs().into_owned().collect();
|
||||
if let Some(token) = query_params.get(AUTH_URL_REFRESH_TOKEN_QUERY_PARAM) {
|
||||
let user_uid = query_params
|
||||
.get(AUTH_URL_NEW_USER_UID_QUERY_PARAM)
|
||||
.map(|uid| UserUid::new(uid));
|
||||
|
||||
Ok(Self {
|
||||
refresh_token: RefreshToken::new(token),
|
||||
user_uid,
|
||||
deleted_anonymous_user: query_params
|
||||
.get(AUTH_URL_DELETED_ANON_USER_QUERY_PARAM)
|
||||
.map(|value| value == "true"),
|
||||
state: query_params.get(AUTH_URL_STATE_QUERY_PARAM).cloned(),
|
||||
})
|
||||
} else {
|
||||
Err(safe_anyhow!(
|
||||
safe: ("Auth redirect URL is missing required credential"),
|
||||
full: ("Received URL without refresh token query param: {}", url)
|
||||
))
|
||||
}
|
||||
pub fn from_url(_url: Url) -> Result<Self> {
|
||||
anyhow::bail!("Auth UI removed")
|
||||
}
|
||||
|
||||
/// Like [`from_url()`], except first parses the given [`raw_url`] into a [`Url`] struct.
|
||||
pub fn from_raw_url(raw_url: String) -> Result<Self> {
|
||||
match Url::parse(&raw_url) {
|
||||
Ok(parsed_url) => AuthRedirectPayload::from_url(parsed_url),
|
||||
@@ -115,181 +32,12 @@ impl AuthRedirectPayload {
|
||||
pub enum AuthViewVariant {
|
||||
Initial,
|
||||
RequireLoginCloseable,
|
||||
HitDriveObjectLimitCloseable,
|
||||
ShareRequirementCloseable,
|
||||
}
|
||||
|
||||
impl AuthView {
|
||||
pub fn new(variant: AuthViewVariant, ctx: &mut ViewContext<Self>) -> Self {
|
||||
let auth_screen_view = ctx.add_typed_action_view(|ctx| AuthViewBody::new(variant, ctx));
|
||||
ctx.subscribe_to_view(&auth_screen_view, |me, _, event, ctx| match event {
|
||||
AuthViewBodyEvent::Close => me.close(ctx),
|
||||
AuthViewBodyEvent::SignUpButtonClicked => {
|
||||
me.dismiss_error_notification(ctx);
|
||||
}
|
||||
AuthViewBodyEvent::AuthTokenEntered(token) => {
|
||||
me.last_login_failure_reason = None;
|
||||
me.handle_pasted_auth_url(token.clone(), ctx);
|
||||
ctx.notify();
|
||||
}
|
||||
AuthViewBodyEvent::LoginLaterClicked => {
|
||||
me.handle_login_later(ctx);
|
||||
}
|
||||
});
|
||||
|
||||
let auth_screen_modal = ctx.add_typed_action_view(|ctx| {
|
||||
Modal::new(None, auth_screen_view, ctx)
|
||||
.with_body_style(UiComponentStyles {
|
||||
padding: Some(Coords::uniform(0.)),
|
||||
..Default::default()
|
||||
})
|
||||
.with_modal_style(UiComponentStyles {
|
||||
width: Some(MODAL_WIDTH),
|
||||
border_color: Some(Fill::from(ColorU::transparent_black())), // override default modal border color
|
||||
..Default::default()
|
||||
})
|
||||
});
|
||||
|
||||
let auth_manager = AuthManager::handle(ctx);
|
||||
ctx.subscribe_to_model(&auth_manager, |me, _, event, ctx| {
|
||||
me.handle_auth_manager_event(event, ctx);
|
||||
});
|
||||
|
||||
Self {
|
||||
auth_screen_modal,
|
||||
last_login_failure_reason: None,
|
||||
close_login_notification_mouse_state: Default::default(),
|
||||
highlighted_hyperlink_state: Default::default(),
|
||||
auth_view_variant: variant,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_variant(&mut self, ctx: &mut ViewContext<Self>, variant: AuthViewVariant) {
|
||||
self.auth_view_variant = variant;
|
||||
self.update_auth_body(
|
||||
ctx,
|
||||
|body: &mut AuthViewBody, _: &mut ViewContext<'_, AuthViewBody>| {
|
||||
body.set_variant(variant)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
fn set_auth_step(&mut self, ctx: &mut ViewContext<Self>, step: AuthStep) {
|
||||
self.update_auth_body(
|
||||
ctx,
|
||||
|body: &mut AuthViewBody, _: &mut ViewContext<'_, AuthViewBody>| {
|
||||
body.set_auth_step(step)
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
pub fn skip_to_browser_open_step(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
self.set_auth_step(ctx, AuthStep::BrowserOpen);
|
||||
}
|
||||
|
||||
fn focus(&self, ctx: &mut ViewContext<Self>) {
|
||||
ctx.focus(&self.auth_screen_modal);
|
||||
ctx.notify();
|
||||
}
|
||||
|
||||
fn dismiss_error_notification(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
self.last_login_failure_reason = None;
|
||||
ctx.notify();
|
||||
}
|
||||
|
||||
fn close(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
self.update_auth_body(
|
||||
ctx,
|
||||
|body: &mut AuthViewBody, ctx: &mut ViewContext<'_, AuthViewBody>| {
|
||||
body.reset_login_screen(ctx)
|
||||
},
|
||||
);
|
||||
self.dismiss_error_notification(ctx);
|
||||
ctx.emit(AuthViewEvent::Close);
|
||||
}
|
||||
|
||||
/// Parses the given 'clipboard_content' string into a URL which is assumed to represent the
|
||||
/// OAuth redirect URL containing the user's refresh token after the user authenticated Warp.
|
||||
fn handle_pasted_auth_url(&mut self, pasted_url: String, ctx: &mut ViewContext<Self>) {
|
||||
self.set_auth_token_input_editable(false, ctx);
|
||||
match AuthRedirectPayload::from_raw_url(pasted_url) {
|
||||
Ok(redirect_payload) => {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager, ctx| {
|
||||
auth_manager.initialize_user_from_auth_payload(redirect_payload, true, ctx);
|
||||
});
|
||||
}
|
||||
Err(error) => {
|
||||
safe_error!(
|
||||
safe: ("Failed to parse AuthRedirectPayload from redirect URL"),
|
||||
full: ("Failed to parse AuthRedirectPayload from redirect URL: {error:#}")
|
||||
);
|
||||
self.last_login_failure_reason =
|
||||
Some(LoginFailureReason::InvalidRedirectUrl { was_pasted: true });
|
||||
self.set_auth_token_input_editable(true, ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_auth_token_input_editable(&mut self, is_editable: bool, ctx: &mut ViewContext<Self>) {
|
||||
self.update_auth_body(ctx, |body, ctx| body.set_input_editable(is_editable, ctx))
|
||||
}
|
||||
|
||||
fn update_auth_body<S, F>(&mut self, ctx: &mut ViewContext<Self>, cb: F) -> S
|
||||
where
|
||||
F: FnOnce(&mut AuthViewBody, &mut ViewContext<'_, AuthViewBody>) -> S,
|
||||
{
|
||||
self.auth_screen_modal
|
||||
.update(ctx, |modal, ctx| modal.body().update(ctx, cb))
|
||||
}
|
||||
|
||||
pub fn handle_login_later(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
if FeatureFlag::SkipFirebaseAnonymousUser.is_enabled() {
|
||||
AuthManager::handle(ctx).update(ctx, |_, ctx| {
|
||||
ctx.emit(AuthManagerEvent::SkippedLogin);
|
||||
});
|
||||
} else {
|
||||
AuthManager::handle(ctx).update(ctx, |auth_manager, ctx| {
|
||||
auth_manager.create_anonymous_user(None, ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_auth_manager_event(&mut self, event: &AuthManagerEvent, ctx: &mut ViewContext<Self>) {
|
||||
match event {
|
||||
AuthManagerEvent::AuthComplete | AuthManagerEvent::SkippedLogin => {
|
||||
self.close(ctx);
|
||||
}
|
||||
AuthManagerEvent::AuthFailed(err) => {
|
||||
if err.is_actionable() {
|
||||
log::error!("Failed to log in user: {err:#}");
|
||||
}
|
||||
|
||||
if let UserAuthenticationError::InvalidStateParameter = err {
|
||||
self.last_login_failure_reason =
|
||||
Some(LoginFailureReason::InvalidStateParameter);
|
||||
} else if let UserAuthenticationError::MissingStateParameter = err {
|
||||
self.last_login_failure_reason =
|
||||
Some(LoginFailureReason::MissingStateParameter);
|
||||
} else {
|
||||
self.last_login_failure_reason =
|
||||
Some(LoginFailureReason::FailedUserAuthentication);
|
||||
}
|
||||
|
||||
self.set_auth_token_input_editable(true, ctx);
|
||||
}
|
||||
AuthManagerEvent::CreateAnonymousUserFailed => {
|
||||
self.last_login_failure_reason = Some(LoginFailureReason::FailedUserAuthentication);
|
||||
self.set_auth_token_input_editable(true, ctx);
|
||||
}
|
||||
AuthManagerEvent::MintCustomTokenFailed(_err) => {
|
||||
self.last_login_failure_reason = Some(LoginFailureReason::FailedMintCustomToken);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
ctx.notify();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq)]
|
||||
#[derive(Clone, Debug)]
|
||||
#[allow(dead_code)]
|
||||
pub enum AuthViewEvent {
|
||||
Close,
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use pathfinder_color::ColorU;
|
||||
#![allow(dead_code)]
|
||||
|
||||
use galaxy_core::channel::ChannelState;
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::ui::appearance::Appearance;
|
||||
use galaxy_core::ui::builder::UiBuilder;
|
||||
use galaxy_core::ui::color::{darken, lighten};
|
||||
use galaxy_core::ui::theme::ColorScheme;
|
||||
use pathfinder_color::ColorU;
|
||||
use warpui::assets::asset_cache::AssetSource;
|
||||
use warpui::elements::{
|
||||
Border, CacheOption, ConstrainedBox, Container, CornerRadius, CrossAxisAlignment, Fill, Flex,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use pathfinder_color::ColorU;
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
use onboarding::components::feature_optout_dialog::{
|
||||
render_feature_optout_dialog, FeatureOptOutDialog,
|
||||
};
|
||||
use onboarding::slides::{layout, slide_content};
|
||||
use onboarding::{OnboardingIntention, WARP_DRIVE_FEATURES};
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use ui_components::{button, Component as _, Options as _};
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxy_core::safe_error;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
@@ -28,6 +22,14 @@ use galaxyui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, UpdateModel, View,
|
||||
ViewContext, ViewHandle,
|
||||
};
|
||||
use onboarding::components::feature_optout_dialog::{
|
||||
render_feature_optout_dialog, FeatureOptOutDialog,
|
||||
};
|
||||
use onboarding::slides::{layout, slide_content};
|
||||
use onboarding::{OnboardingIntention, WARP_DRIVE_FEATURES};
|
||||
use pathfinder_color::ColorU;
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use ui_components::{button, Component as _, Options as _};
|
||||
|
||||
use crate::appearance::Appearance;
|
||||
use crate::auth::auth_manager::{AuthManager, AuthManagerEvent};
|
||||
@@ -274,6 +276,10 @@ fn resolve_visual_path(
|
||||
}
|
||||
|
||||
impl LoginSlideView {
|
||||
pub fn is_auth_token_input_visible(&self) -> bool {
|
||||
self.show_auth_token_input
|
||||
}
|
||||
|
||||
pub fn new(
|
||||
ai_enabled: bool,
|
||||
uses_third_party_agents: bool,
|
||||
|
||||
+3
-2
@@ -1,4 +1,5 @@
|
||||
pub mod auth_manager;
|
||||
pub mod auth_override_warning_body;
|
||||
pub mod auth_override_warning_modal;
|
||||
mod auth_view_body;
|
||||
pub mod auth_view_modal;
|
||||
@@ -18,11 +19,11 @@ use ai::index::full_source_code_embedding::manager::CodebaseIndexManager;
|
||||
pub use auth_manager::AuthManager;
|
||||
pub use auth_state::AuthStateProvider;
|
||||
pub use auth_view_modal::LoginFailureReason;
|
||||
use galaxy_core::user_preferences::GetUserPreferences as _;
|
||||
use galaxyui::modals::{AlertDialogWithCallbacks, ModalButton};
|
||||
use galaxyui::{AppContext, SingletonEntity};
|
||||
use itertools::Itertools;
|
||||
pub use user_uid::UserUid;
|
||||
use galaxy_core::user_preferences::GetUserPreferences as _;
|
||||
use galaxyui::{AppContext, SingletonEntity};
|
||||
|
||||
use crate::ai::agent_conversations_model::AgentConversationsModel;
|
||||
use crate::ai::blocklist::agent_view::orchestration_pill_bar_model::OrchestrationPillBarModel;
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
use galaxyui::elements::{Align, MouseStateHandle, Shrinkable};
|
||||
use galaxyui::ui_components::button::ButtonVariant;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
@@ -24,7 +26,10 @@ struct MouseStateHandles {
|
||||
|
||||
impl NeedsSsoLinkView {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self {
|
||||
email: None,
|
||||
mouse_state_handles: MouseStateHandles::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_email(&mut self, _email: String) {}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
#![allow(dead_code)]
|
||||
|
||||
//! Modal shown when the user clicks "Click here to paste your token from
|
||||
//! the browser" on the onboarding agent-slide upgrade-prompt bar. Accepts a
|
||||
//! pasted auth redirect URL and routes it through
|
||||
@@ -6,8 +8,6 @@
|
||||
//! This lives in the app crate (not the onboarding crate) because it reuses
|
||||
//! `EditorView` for the text input, which the onboarding crate doesn't
|
||||
//! depend on.
|
||||
use pathfinder_color::ColorU;
|
||||
use ui_components::{button, Component as _, Options as _};
|
||||
use galaxy_core::safe_error;
|
||||
use galaxy_core::ui::theme::color::internal_colors;
|
||||
use galaxyui::actions::StandardAction;
|
||||
@@ -24,6 +24,8 @@ use galaxyui::{
|
||||
AppContext, Element, Entity, FocusContext, SingletonEntity, TypedActionView, View, ViewContext,
|
||||
ViewHandle,
|
||||
};
|
||||
use pathfinder_color::ColorU;
|
||||
use ui_components::{button, Component as _};
|
||||
|
||||
use crate::appearance::Appearance;
|
||||
use crate::auth::auth_manager::{AuthManager, AuthManagerEvent};
|
||||
@@ -88,7 +90,14 @@ pub enum PasteAuthTokenModalEvent {
|
||||
Cancelled,
|
||||
}
|
||||
|
||||
pub struct PasteAuthTokenModalView;
|
||||
pub struct PasteAuthTokenModalView {
|
||||
auth_token_input: ViewHandle<EditorView>,
|
||||
cancel_button: button::Button,
|
||||
continue_button: button::Button,
|
||||
close_mouse_state: MouseStateHandle,
|
||||
last_failure_reason: Option<LoginFailureReason>,
|
||||
highlighted_hyperlink_state: HighlightedHyperlink,
|
||||
}
|
||||
|
||||
impl PasteAuthTokenModalView {
|
||||
pub fn new(ctx: &mut ViewContext<Self>) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user