Files
galaxy/app/src/terminal/view/ssh_remote_server_failed_banner.rs
T

158 lines
5.1 KiB
Rust

//! Banner shown when the remote-server binary check, installation, or connection fails on the remote host.
//! We fall back to the existing Warpification behavior and display this banner so the user knows why advanced features are unavailable.
use galaxy_core::ui::theme::color::internal_colors;
use galaxyui::{
elements::{
ConstrainedBox, Container, CrossAxisAlignment, Flex, Hoverable, MainAxisAlignment,
MainAxisSize, MouseStateHandle, ParentElement, Shrinkable, Text,
},
platform::Cursor,
AppContext, Element, Entity, SingletonEntity, TypedActionView, View, ViewContext,
};
use crate::{terminal::model::session::SessionId, ui_components::icons::Icon, Appearance};
#[derive(Clone, Debug)]
pub enum SshRemoteServerFailedBannerAction {
Dismiss,
}
#[derive(Clone, Debug)]
pub enum SshRemoteServerFailedBannerEvent {
Dismissed,
}
pub struct SshRemoteServerFailedBanner {
session_id: SessionId,
close_mouse_state: MouseStateHandle,
}
impl SshRemoteServerFailedBanner {
pub fn new(session_id: SessionId) -> Self {
Self {
session_id,
close_mouse_state: MouseStateHandle::default(),
}
}
pub fn session_id(&self) -> SessionId {
self.session_id
}
}
impl Entity for SshRemoteServerFailedBanner {
type Event = SshRemoteServerFailedBannerEvent;
}
impl View for SshRemoteServerFailedBanner {
fn ui_name() -> &'static str {
"SshRemoteServerFailedBanner"
}
fn render(&self, app: &AppContext) -> Box<dyn Element> {
let appearance = Appearance::as_ref(app);
let theme = appearance.theme();
let fg_color = theme.foreground().into_solid();
let muted_color = internal_colors::neutral_5(theme);
let font_size = appearance.monospace_font_size();
let small_font_size = font_size - 2.;
// Alert-circle icon
let icon = Container::new(
ConstrainedBox::new(Icon::AlertCircle.to_galaxyui_icon(fg_color.into()).finish())
.with_width(16.)
.with_height(16.)
.finish(),
)
.with_margin_right(8.)
.finish();
// Title
let title = Text::new(
"SSH extension couldn't be installed",
appearance.ui_font_family(),
font_size,
)
.with_color(fg_color)
.finish();
// Description
let body = Text::new(
"The binary could not be written or executed on the remote host. \
This may be due to permission restrictions or missing dependencies. \
While advanced features like file browsing and code review are currently \
disabled, the rest of your Warpified experience is fully available.",
appearance.ui_font_family(),
small_font_size,
)
.soft_wrap(true)
.with_color(muted_color)
.finish();
// Close (X) button
let close_icon_color = muted_color;
let close = Hoverable::new(self.close_mouse_state.clone(), move |_| {
ConstrainedBox::new(Icon::X.to_galaxyui_icon(close_icon_color.into()).finish())
.with_width(16.)
.with_height(16.)
.finish()
})
.with_cursor(Cursor::PointingHand)
.on_click(|ctx, _, _| {
ctx.dispatch_typed_action(SshRemoteServerFailedBannerAction::Dismiss);
})
.finish();
let close_container = Container::new(close).with_uniform_padding(4.).finish();
// Header row: [icon + title] ... [close]
let header_row = Flex::row()
.with_main_axis_size(MainAxisSize::Max)
.with_main_axis_alignment(MainAxisAlignment::SpaceBetween)
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_child(
Shrinkable::new(
1.,
Flex::row()
.with_cross_axis_alignment(CrossAxisAlignment::Center)
.with_child(icon)
.with_child(Shrinkable::new(1., title).finish())
.finish(),
)
.finish(),
)
.with_child(close_container)
.finish();
// Body text indented past the icon to align with the title
let body_container = Container::new(body)
.with_margin_top(2.)
.with_margin_left(24.)
.finish();
let content = Flex::column()
.with_main_axis_size(MainAxisSize::Min)
.with_child(header_row)
.with_child(body_container)
.finish();
Container::new(content)
.with_background(internal_colors::fg_overlay_1(theme))
.with_uniform_padding(12.)
.finish()
}
}
impl TypedActionView for SshRemoteServerFailedBanner {
type Action = SshRemoteServerFailedBannerAction;
fn handle_action(&mut self, action: &Self::Action, ctx: &mut ViewContext<Self>) {
match action {
SshRemoteServerFailedBannerAction::Dismiss => {
ctx.emit(SshRemoteServerFailedBannerEvent::Dismissed);
}
}
}
}