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:
2026-07-02 14:54:15 -05:00
parent 4770ac06b5
commit 3769646ca6
1194 changed files with 5312 additions and 8032 deletions
+5 -5
View File
@@ -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 -7
View File
@@ -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,
+3 -1
View File
@@ -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;
+8 -260
View File
@@ -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,
}
+3 -1
View File
@@ -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,
+2
View File
@@ -1,3 +1,5 @@
#![allow(dead_code)]
use std::borrow::Cow;
use pathfinder_color::ColorU;
+14 -8
View File
@@ -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
View File
@@ -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;
+6 -1
View File
@@ -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) {}
+12 -3
View File
@@ -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 {