feat: expand Galaxy agent and remote tooling
Add Wormhole remote helpers, provider and agent improvements, filesystem diagnostics, model metadata support, and schema-aware settings IntelliSense.
This commit is contained in:
@@ -40,7 +40,7 @@ use settings_page::{
|
||||
HEADER_PADDING,
|
||||
};
|
||||
use teams_page::{TeamsPageView, TeamsPageViewEvent};
|
||||
use warpify_page::{WarpifyPageAction, WarpifyPageView};
|
||||
use wormhole_page::{WormholePageAction, WormholePageView};
|
||||
|
||||
use self::telemetry::SettingsTelemetryEvent;
|
||||
use crate::ai::custom_model_routers::CustomModelRouter;
|
||||
@@ -95,7 +95,7 @@ mod teams_page;
|
||||
mod telemetry;
|
||||
pub mod update_environment_form;
|
||||
mod warp_drive_page;
|
||||
mod warpify_page;
|
||||
mod wormhole_page;
|
||||
|
||||
#[cfg(not(target_family = "wasm"))]
|
||||
pub(crate) use ai_page::cli_agent_settings_widget_id;
|
||||
@@ -233,7 +233,7 @@ pub enum SettingsSection {
|
||||
Scripting,
|
||||
Teams,
|
||||
WarpDrive,
|
||||
Warpify,
|
||||
Wormhole,
|
||||
/// Internal backing-page identifier for AISettingsPageView. Multiple subpages
|
||||
/// (WarpAgent, AgentProfiles, Knowledge, ThirdPartyCLIAgents) share this single
|
||||
/// backing page, so this variant is needed as the key in `settings_pages`.
|
||||
@@ -286,7 +286,7 @@ impl Display for SettingsSection {
|
||||
SettingsSection::ProviderChatGPTSubscription => write!(f, "ChatGPT Subscription"),
|
||||
SettingsSection::ProviderBedrock => write!(f, "Bedrock"),
|
||||
SettingsSection::ProviderACP => write!(f, "ACP"),
|
||||
SettingsSection::Warpify => write!(f, "Wormhole"),
|
||||
SettingsSection::Wormhole => write!(f, "Wormhole"),
|
||||
SettingsSection::CodeIndexing => write!(f, "Indexing and projects"),
|
||||
SettingsSection::EditorAndCodeReview => write!(f, "Editor and Code Review"),
|
||||
_ => write!(f, "{self:?}"),
|
||||
@@ -407,7 +407,6 @@ impl FromStr for SettingsSection {
|
||||
"Privacy" => Ok(Self::Privacy),
|
||||
"Galaxy Control" | "Scripting" => Ok(Self::Scripting),
|
||||
"Teams" => Ok(Self::Teams),
|
||||
"Warpify" => Ok(Self::Warpify),
|
||||
"WarpDrive" | "Galaxy Drive" => Ok(Self::WarpDrive),
|
||||
"Oz" | "Warp Agent" | "Galaxy Agent" => Ok(Self::WarpAgent),
|
||||
"Profiles" | "AgentProfiles" => Ok(Self::AgentProfiles),
|
||||
@@ -423,7 +422,7 @@ impl FromStr for SettingsSection {
|
||||
"Indexing and projects" | "CodeIndexing" => Ok(Self::CodeIndexing),
|
||||
"Editor and Code Review" | "EditorAndCodeReview" => Ok(Self::EditorAndCodeReview),
|
||||
"Experiments" => Ok(Self::Experiments),
|
||||
"Wormhole" => Ok(Self::Warpify),
|
||||
"Wormhole" => Ok(Self::Wormhole),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
@@ -488,7 +487,7 @@ pub mod flags {
|
||||
pub const SCROLL_REPORTING_CONTEXT_FLAG: &str = "Scroll_Reporting";
|
||||
pub const FOCUS_REPORTING_CONTEXT_FLAG: &str = "Focus_Reporting";
|
||||
pub const SSH_REUSE_CONTROL_MASTER_CONTEXT_FLAG: &str = "SSH_Reuse_Control_Master";
|
||||
pub const SSH_WARPIFICATION_CONTEXT_FLAG: &str = "SSH_Warpification";
|
||||
pub const SSH_WORMHOLING_CONTEXT_FLAG: &str = "SSH_Wormholing";
|
||||
pub const NOTIFICATIONS_CONTEXT_FLAG: &str = "Notifications_Enabled";
|
||||
pub const LONG_RUNNING_NOTIFICATIONS_FLAG: &str = "Long_Running_Notifications";
|
||||
pub const AGENT_TASK_COMPLETED_NOTIFICATIONS_FLAG: &str = "Agent_Task_Completed_Notifications";
|
||||
@@ -610,7 +609,7 @@ pub mod flags {
|
||||
pub const IS_AUTOINDEXING_ENABLED: &str = "IsAutoIndexingEnabled";
|
||||
pub const LIGATURE_RENDERING_CONTEXT_FLAG: &str = "Ligature_Rendering_Enabled";
|
||||
pub const HAS_SETTINGS_TO_IMPORT_FLAG: &str = "HasSettingsToImport";
|
||||
/// The user's setting enabled UDI, but we may show a classic input (e.g. ssh/subshell warpification)
|
||||
/// The user's setting enabled UDI, but we may show a classic input (e.g. ssh/subshell wormholing)
|
||||
pub const UNIVERSAL_DEVELOPER_INPUT_ENABLED: &str = "UniversalDeveloperInputEnabled";
|
||||
pub const AGENT_MODE_INPUT: &str = "InputAgentMode";
|
||||
pub const TERMINAL_MODE_INPUT: &str = "InputTerminalMode";
|
||||
@@ -657,7 +656,7 @@ pub fn init_actions_from_parent_view<T: Action + Clone>(
|
||||
) {
|
||||
appearance_page::init_actions_from_parent_view(app, context, builder);
|
||||
features_page::init_actions_from_parent_view(app, context, builder);
|
||||
warpify_page::init_actions_from_parent_view(app, context, builder);
|
||||
wormhole_page::init_actions_from_parent_view(app, context, builder);
|
||||
privacy_page::init_actions_from_parent_view(app, context, builder);
|
||||
ai_page::init_actions_from_parent_view(app, context, builder);
|
||||
code_page::init_actions_from_parent_view(app, context, builder);
|
||||
@@ -965,7 +964,7 @@ pub enum SettingsAction {
|
||||
AI(AISettingsPageAction),
|
||||
Code(CodeSettingsPageAction),
|
||||
WarpDrive(warp_drive_page::WarpDriveSettingsPageAction),
|
||||
WarpifyPageToggle(WarpifyPageAction),
|
||||
WormholePageToggle(WormholePageAction),
|
||||
Tab,
|
||||
Split(Direction),
|
||||
ToggleMaximizePane,
|
||||
@@ -1108,7 +1107,7 @@ macro_rules! update_page {
|
||||
SettingsPageViewHandle::Appearance(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Features(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Keybindings(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Warpify(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Wormhole(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Privacy(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::Scripting(handle) => $ctx.update_view(handle, $update),
|
||||
SettingsPageViewHandle::AI(handle) => $ctx.update_view(handle, $update),
|
||||
@@ -1195,9 +1194,9 @@ impl SettingsView {
|
||||
me.handle_code_page_event(event, ctx);
|
||||
});
|
||||
|
||||
let warpify_page_handle = ctx.add_typed_action_view(WarpifyPageView::new);
|
||||
ctx.subscribe_to_view(&warpify_page_handle, |me, _, event, ctx| {
|
||||
me.handle_warpify_page_event(event, ctx);
|
||||
let wormhole_page_handle = ctx.add_typed_action_view(WormholePageView::new);
|
||||
ctx.subscribe_to_view(&wormhole_page_handle, |me, _, event, ctx| {
|
||||
me.handle_wormhole_page_event(event, ctx);
|
||||
});
|
||||
|
||||
// Render the privacy page only if telemetry opt-out is enabled.
|
||||
@@ -1256,7 +1255,7 @@ impl SettingsView {
|
||||
SettingsPage::new(appearance_page_handle),
|
||||
SettingsPage::new(features_page_handle),
|
||||
SettingsPage::new(keybindings_handle),
|
||||
SettingsPage::new(warpify_page_handle),
|
||||
SettingsPage::new(wormhole_page_handle),
|
||||
SettingsPage::new(warp_drive_page_handle),
|
||||
];
|
||||
|
||||
@@ -1291,7 +1290,7 @@ impl SettingsView {
|
||||
SettingsNavItem::Page(SettingsSection::Appearance),
|
||||
SettingsNavItem::Page(SettingsSection::Features),
|
||||
SettingsNavItem::Page(SettingsSection::Keybindings),
|
||||
SettingsNavItem::Page(SettingsSection::Warpify),
|
||||
SettingsNavItem::Page(SettingsSection::Wormhole),
|
||||
SettingsNavItem::Page(SettingsSection::WarpDrive),
|
||||
SettingsNavItem::Page(SettingsSection::Privacy),
|
||||
SettingsNavItem::Page(SettingsSection::About),
|
||||
@@ -1702,7 +1701,7 @@ impl SettingsView {
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_warpify_page_event(
|
||||
fn handle_wormhole_page_event(
|
||||
&mut self,
|
||||
event: &SettingsPageEvent,
|
||||
ctx: &mut ViewContext<Self>,
|
||||
@@ -1938,7 +1937,7 @@ impl SettingsView {
|
||||
SettingsPageViewHandle::Appearance(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::About(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::Privacy(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::Warpify(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::Wormhole(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::Scripting(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::AI(v) => v.as_ref(app).should_render(app),
|
||||
SettingsPageViewHandle::MCPServers(v) => v.as_ref(app).should_render(app),
|
||||
@@ -2518,11 +2517,11 @@ impl TypedActionView for SettingsView {
|
||||
}
|
||||
}
|
||||
}
|
||||
SettingsAction::WarpifyPageToggle(warpify_action) => {
|
||||
if let Some(warpify_page) = self.settings_page(SettingsSection::Warpify) {
|
||||
if let SettingsPageViewHandle::Warpify(view) = &warpify_page.view_handle {
|
||||
SettingsAction::WormholePageToggle(wormhole_action) => {
|
||||
if let Some(wormhole_page) = self.settings_page(SettingsSection::Wormhole) {
|
||||
if let SettingsPageViewHandle::Wormhole(view) = &wormhole_page.view_handle {
|
||||
view.update(ctx, |view, ctx| {
|
||||
view.handle_action(warpify_action, ctx);
|
||||
view.handle_action(wormhole_action, ctx);
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ fn top_level_sections_map_to_themselves() {
|
||||
SettingsSection::Scripting,
|
||||
SettingsSection::Teams,
|
||||
SettingsSection::WarpDrive,
|
||||
SettingsSection::Warpify,
|
||||
SettingsSection::Wormhole,
|
||||
] {
|
||||
assert!(!section.is_subpage(), "{section:?} should be top-level");
|
||||
assert_eq!(section.parent_page_section(), section);
|
||||
@@ -101,7 +101,7 @@ fn current_settings_display_names_round_trip() {
|
||||
for (section, display_name) in [
|
||||
(SettingsSection::Scripting, "Galaxy Control"),
|
||||
(SettingsSection::WarpDrive, "Galaxy Drive"),
|
||||
(SettingsSection::Warpify, "Wormhole"),
|
||||
(SettingsSection::Wormhole, "Wormhole"),
|
||||
(SettingsSection::WarpAgent, "Galaxy Agent"),
|
||||
(SettingsSection::AgentProfiles, "Profiles"),
|
||||
(SettingsSection::AgentMCPServers, "MCP servers"),
|
||||
@@ -135,7 +135,7 @@ fn legacy_settings_names_remain_parseable() {
|
||||
for (name, expected) in [
|
||||
("Scripting", SettingsSection::Scripting),
|
||||
("WarpDrive", SettingsSection::WarpDrive),
|
||||
("Warpify", SettingsSection::Warpify),
|
||||
("Wormhole", SettingsSection::Wormhole),
|
||||
("Oz", SettingsSection::WarpAgent),
|
||||
("Warp Agent", SettingsSection::WarpAgent),
|
||||
("AgentProfiles", SettingsSection::AgentProfiles),
|
||||
@@ -191,7 +191,7 @@ fn realistic_nav_items() -> Vec<SettingsNavItem> {
|
||||
SettingsNavItem::Page(SettingsSection::Appearance),
|
||||
SettingsNavItem::Page(SettingsSection::Features),
|
||||
SettingsNavItem::Page(SettingsSection::Keybindings),
|
||||
SettingsNavItem::Page(SettingsSection::Warpify),
|
||||
SettingsNavItem::Page(SettingsSection::Wormhole),
|
||||
SettingsNavItem::Page(SettingsSection::WarpDrive),
|
||||
SettingsNavItem::Page(SettingsSection::Privacy),
|
||||
SettingsNavItem::Page(SettingsSection::About),
|
||||
|
||||
@@ -37,7 +37,7 @@ use super::privacy_page::PrivacyPageView;
|
||||
use super::scripting_page::ScriptingSettingsPageView;
|
||||
use super::teams_page::TeamsPageView;
|
||||
use super::warp_drive_page::WarpDriveSettingsPageView;
|
||||
use super::warpify_page::WarpifyPageView;
|
||||
use super::wormhole_page::WormholePageView;
|
||||
use super::SettingsSection;
|
||||
use crate::appearance::Appearance;
|
||||
use crate::settings::CloudPreferencesSettings;
|
||||
@@ -100,7 +100,7 @@ pub enum SettingsPageViewHandle {
|
||||
About(ViewHandle<AboutPageView>),
|
||||
Code(ViewHandle<CodeSettingsPageView>),
|
||||
Privacy(ViewHandle<PrivacyPageView>),
|
||||
Warpify(ViewHandle<WarpifyPageView>),
|
||||
Wormhole(ViewHandle<WormholePageView>),
|
||||
Scripting(ViewHandle<ScriptingSettingsPageView>),
|
||||
AI(ViewHandle<AISettingsPageView>),
|
||||
MCPServers(ViewHandle<MCPServersSettingsPageView>),
|
||||
@@ -119,7 +119,7 @@ impl SettingsPageViewHandle {
|
||||
About(view_handle) => ChildView::new(view_handle).finish(),
|
||||
Code(view_handle) => ChildView::new(view_handle).finish(),
|
||||
Privacy(view_handle) => ChildView::new(view_handle).finish(),
|
||||
Warpify(view_handle) => ChildView::new(view_handle).finish(),
|
||||
Wormhole(view_handle) => ChildView::new(view_handle).finish(),
|
||||
Scripting(view_handle) => ChildView::new(view_handle).finish(),
|
||||
AI(view_handle) => ChildView::new(view_handle).finish(),
|
||||
MCPServers(view_handle) => ChildView::new(view_handle).finish(),
|
||||
|
||||
@@ -3,9 +3,7 @@ use std::collections::HashMap;
|
||||
use std::fmt::Display;
|
||||
|
||||
use galaxy_core::features::FeatureFlag;
|
||||
use galaxyui::elements::{
|
||||
Container, Flex, FormattedTextElement, HighlightedHyperlink, MouseStateHandle, ParentElement,
|
||||
};
|
||||
use galaxyui::elements::{Container, Flex, MouseStateHandle, ParentElement, Text};
|
||||
use galaxyui::keymap::ContextPredicate;
|
||||
use galaxyui::presenter::ChildView;
|
||||
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
|
||||
@@ -14,7 +12,6 @@ use galaxyui::{
|
||||
Action, AppContext, Element, Entity, ModelHandle, SingletonEntity, TypedActionView, View,
|
||||
ViewContext, ViewHandle,
|
||||
};
|
||||
use markdown_parser::{FormattedText, FormattedTextFragment, FormattedTextLine};
|
||||
use regex::Regex;
|
||||
use settings::{Setting, ToggleableSetting};
|
||||
use strum::IntoEnumIterator;
|
||||
@@ -29,9 +26,9 @@ use super::{flags, SettingsAction, SettingsSection, ToggleSettingActionPair};
|
||||
use crate::appearance::Appearance;
|
||||
use crate::server::telemetry::TelemetryEvent;
|
||||
use crate::settings::{ReuseExistingSshControlMaster, SshSettings};
|
||||
use crate::terminal::warpify::settings::{
|
||||
EnableSshWarpification, SshExtensionInstallMode, SshExtensionInstallModeSetting,
|
||||
WarpifySettings, WarpifySettingsChangedEvent,
|
||||
use crate::terminal::wormhole::settings::{
|
||||
EnableSshWormholing, SshExtensionInstallMode, SshExtensionInstallModeSetting, WormholeSettings,
|
||||
WormholeSettingsChangedEvent,
|
||||
};
|
||||
use crate::ui_components::blended_colors;
|
||||
use crate::view_components::dropdown::{Dropdown, DropdownItem};
|
||||
@@ -43,19 +40,19 @@ pub fn init_actions_from_parent_view<T: Action + Clone>(
|
||||
context: &ContextPredicate,
|
||||
builder: fn(SettingsAction) -> T,
|
||||
) {
|
||||
// Add all of the toggle settings from the Warpify Page that you want to show up on the Command Palette here.
|
||||
// Add all of the toggle settings from the Wormhole Page that you want to show up on the Command Palette here.
|
||||
let mut toggle_binding_pairs = vec![];
|
||||
if WarpifySettings::as_ref(app)
|
||||
.enable_ssh_warpification
|
||||
if WormholeSettings::as_ref(app)
|
||||
.enable_ssh_wormholing
|
||||
.is_supported_on_current_platform()
|
||||
{
|
||||
toggle_binding_pairs.push(ToggleSettingActionPair::new(
|
||||
"SSH Warpification",
|
||||
builder(SettingsAction::WarpifyPageToggle(
|
||||
WarpifyPageAction::ToggleSshWarpification,
|
||||
"SSH Wormholing",
|
||||
builder(SettingsAction::WormholePageToggle(
|
||||
WormholePageAction::ToggleSshWormholing,
|
||||
)),
|
||||
context,
|
||||
flags::SSH_WARPIFICATION_CONTEXT_FLAG,
|
||||
flags::SSH_WORMHOLING_CONTEXT_FLAG,
|
||||
));
|
||||
}
|
||||
|
||||
@@ -68,17 +65,17 @@ const ITEM_VERTICAL_SPACING: f32 = 24.;
|
||||
const BUILT_IN_TEXT_INPUT_MARGIN: f32 = 10.;
|
||||
const SPACE_AFTER_TEXT_INPUT: f32 = ITEM_VERTICAL_SPACING - BUILT_IN_TEXT_INPUT_MARGIN;
|
||||
|
||||
const SSH_REUSE_CONTROL_MASTER_DESCRIPTION: &str = "Attach to a live SSH ControlMaster you already have configured for the destination host instead of creating a Warp-owned one. Takes effect in new tabs.";
|
||||
const SSH_REUSE_CONTROL_MASTER_DESCRIPTION: &str = "Attach to a live SSH ControlMaster you already have configured for the destination host instead of creating a Galaxy-owned one. Takes effect in new tabs.";
|
||||
|
||||
const SSH_EXTENSION_INSTALL_MODE_DESCRIPTION: &str =
|
||||
"Controls the installation behavior for Galaxy's SSH extension when a remote host doesn't have it installed.";
|
||||
"Controls how Galaxy installs the Wormhole helper when a remote host doesn't have it.";
|
||||
|
||||
/// This page lets users configure when they get asked to warpify a session. Some shell commands
|
||||
/// This page lets users configure when they get asked to wormhole a session. Some shell commands
|
||||
/// are recognized by default. Users can add new shell commands, or prevent the default ones from
|
||||
/// asking. Users can also enable the SSH wrapper, and add hosts to a denylist.
|
||||
/// This page is essentially the View for the SubshellSettings model, as well as the SshSettings
|
||||
/// related to warpification.
|
||||
pub struct WarpifyPageView {
|
||||
/// related to wormholing.
|
||||
pub struct WormholePageView {
|
||||
page: PageType<Self>,
|
||||
/// This needs to mirror the length of SubshellSettings::added_remove_button_states.
|
||||
remove_added_command_button_states: Vec<MouseStateHandle>,
|
||||
@@ -87,19 +84,19 @@ pub struct WarpifyPageView {
|
||||
remove_denylisted_command_button_states: Vec<MouseStateHandle>,
|
||||
add_denylisted_commands_editor: ViewHandle<SubmittableTextInput>,
|
||||
|
||||
ssh_extension_install_mode_dropdown: ViewHandle<Dropdown<WarpifyPageAction>>,
|
||||
ssh_extension_install_mode_dropdown: ViewHandle<Dropdown<WormholePageAction>>,
|
||||
}
|
||||
|
||||
impl WarpifyPageView {
|
||||
impl WormholePageView {
|
||||
pub fn new(ctx: &mut ViewContext<Self>) -> Self {
|
||||
let warpify_settings_handle = WarpifySettings::handle(ctx);
|
||||
let wormhole_settings_handle = WormholeSettings::handle(ctx);
|
||||
|
||||
ctx.observe(&warpify_settings_handle, Self::update_button_states);
|
||||
ctx.subscribe_to_model(&warpify_settings_handle, move |me, model, event, ctx| {
|
||||
ctx.observe(&wormhole_settings_handle, Self::update_button_states);
|
||||
ctx.subscribe_to_model(&wormhole_settings_handle, move |me, model, event, ctx| {
|
||||
me.update_button_states(model, ctx);
|
||||
if matches!(
|
||||
event,
|
||||
WarpifySettingsChangedEvent::SshExtensionInstallModeSetting { .. }
|
||||
WormholeSettingsChangedEvent::SshExtensionInstallModeSetting { .. }
|
||||
) {
|
||||
me.update_dropdown(ctx);
|
||||
}
|
||||
@@ -143,20 +140,20 @@ impl WarpifyPageView {
|
||||
ssh_extension_install_mode_dropdown,
|
||||
};
|
||||
|
||||
instance.update_button_states(warpify_settings_handle, ctx);
|
||||
instance.update_button_states(wormhole_settings_handle, ctx);
|
||||
instance
|
||||
}
|
||||
|
||||
fn build_page(ctx: &mut ViewContext<Self>) -> PageType<Self> {
|
||||
let mut categories = vec![
|
||||
Category::new("", vec![Box::new(TitleWidget::default())]),
|
||||
Category::new("", vec![Box::new(TitleWidget)]),
|
||||
Category::new("Subshells", vec![Box::new(SubshellsWidget::default())])
|
||||
.with_subtitle("Subshells supported: bash, zsh, and fish."),
|
||||
];
|
||||
|
||||
let warpify_settings = WarpifySettings::as_ref(ctx);
|
||||
if warpify_settings
|
||||
.enable_ssh_warpification
|
||||
let wormhole_settings = WormholeSettings::as_ref(ctx);
|
||||
if wormhole_settings
|
||||
.enable_ssh_wormholing
|
||||
.is_supported_on_current_platform()
|
||||
{
|
||||
categories.push(
|
||||
@@ -171,16 +168,16 @@ impl WarpifyPageView {
|
||||
/// its delete button in the View.
|
||||
fn update_button_states(
|
||||
&mut self,
|
||||
warpify_settings_handle: ModelHandle<WarpifySettings>,
|
||||
wormhole_settings_handle: ModelHandle<WormholeSettings>,
|
||||
ctx: &mut ViewContext<Self>,
|
||||
) {
|
||||
let warpify_settings = warpify_settings_handle.as_ref(ctx);
|
||||
self.remove_denylisted_command_button_states = warpify_settings
|
||||
let wormhole_settings = wormhole_settings_handle.as_ref(ctx);
|
||||
self.remove_denylisted_command_button_states = wormhole_settings
|
||||
.subshell_command_denylist
|
||||
.iter()
|
||||
.map(|_| Default::default())
|
||||
.collect();
|
||||
self.remove_added_command_button_states = warpify_settings
|
||||
self.remove_added_command_button_states = wormhole_settings
|
||||
.added_subshell_commands
|
||||
.iter()
|
||||
.map(|_| Default::default())
|
||||
@@ -189,16 +186,16 @@ impl WarpifyPageView {
|
||||
}
|
||||
|
||||
/// Syncs the install-mode dropdown selection with the current
|
||||
/// `WarpifySettings::ssh_extension_install_mode` value (e.g. after it
|
||||
/// `WormholeSettings::ssh_extension_install_mode` value (e.g. after it
|
||||
/// was changed from the SSH remote server choice view).
|
||||
fn update_dropdown(&mut self, ctx: &mut ViewContext<Self>) {
|
||||
let current_mode = *WarpifySettings::as_ref(ctx)
|
||||
let current_mode = *WormholeSettings::as_ref(ctx)
|
||||
.ssh_extension_install_mode
|
||||
.value();
|
||||
self.ssh_extension_install_mode_dropdown
|
||||
.update(ctx, |dropdown, ctx| {
|
||||
dropdown.set_selected_by_action(
|
||||
WarpifyPageAction::SetSshExtensionInstallMode(current_mode),
|
||||
WormholePageAction::SetSshExtensionInstallMode(current_mode),
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
@@ -212,8 +209,8 @@ impl WarpifyPageView {
|
||||
) {
|
||||
match event {
|
||||
SubmittableTextInputEvent::Submit(new_command) => {
|
||||
WarpifySettings::handle(ctx).update(ctx, |warpify_settings, ctx| {
|
||||
warpify_settings.add_subshell_command(new_command, ctx);
|
||||
WormholeSettings::handle(ctx).update(ctx, |wormhole_settings, ctx| {
|
||||
wormhole_settings.add_subshell_command(new_command, ctx);
|
||||
});
|
||||
|
||||
send_telemetry_from_ctx!(TelemetryEvent::AddAddedSubshellCommand, ctx);
|
||||
@@ -230,8 +227,8 @@ impl WarpifyPageView {
|
||||
) {
|
||||
match event {
|
||||
SubmittableTextInputEvent::Submit(new_command) => {
|
||||
WarpifySettings::handle(ctx).update(ctx, |warpify_settings, ctx| {
|
||||
warpify_settings.denylist_subshell_command(new_command, ctx);
|
||||
WormholeSettings::handle(ctx).update(ctx, |wormhole_settings, ctx| {
|
||||
wormhole_settings.denylist_subshell_command(new_command, ctx);
|
||||
});
|
||||
|
||||
send_telemetry_from_ctx!(TelemetryEvent::AddDenylistedSubshellCommand, ctx);
|
||||
@@ -242,20 +239,20 @@ impl WarpifyPageView {
|
||||
|
||||
fn remove_denylisted_command(&self, index: usize, ctx: &mut ViewContext<Self>) {
|
||||
send_telemetry_from_ctx!(TelemetryEvent::RemoveDenylistedSubshellCommand, ctx);
|
||||
WarpifySettings::handle(ctx).update(ctx, |warpify, ctx| {
|
||||
warpify.remove_denylisted_subshell_command(index, ctx)
|
||||
WormholeSettings::handle(ctx).update(ctx, |wormhole, ctx| {
|
||||
wormhole.remove_denylisted_subshell_command(index, ctx)
|
||||
});
|
||||
}
|
||||
|
||||
fn remove_added_command(&self, index: usize, ctx: &mut ViewContext<Self>) {
|
||||
send_telemetry_from_ctx!(TelemetryEvent::RemoveAddedSubshellCommand, ctx);
|
||||
WarpifySettings::handle(ctx).update(ctx, |warpify, ctx| {
|
||||
warpify.remove_added_subshell_command(index, ctx)
|
||||
WormholeSettings::handle(ctx).update(ctx, |wormhole, ctx| {
|
||||
wormhole.remove_added_subshell_command(index, ctx)
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Entity for WarpifyPageView {
|
||||
impl Entity for WormholePageView {
|
||||
type Event = SettingsPageEvent;
|
||||
}
|
||||
|
||||
@@ -272,25 +269,23 @@ fn build_sub_sub_title(title: &str, appearance: &Appearance) -> Container {
|
||||
|
||||
const SSH_EXTENSION_DROPDOWN_WIDTH: f32 = 250.;
|
||||
|
||||
impl WarpifyPageView {
|
||||
impl WormholePageView {
|
||||
fn create_ssh_extension_install_mode_dropdown(
|
||||
ctx: &mut ViewContext<Self>,
|
||||
) -> ViewHandle<Dropdown<WarpifyPageAction>> {
|
||||
let items: Vec<DropdownItem<WarpifyPageAction>> = SshExtensionInstallMode::iter()
|
||||
) -> ViewHandle<Dropdown<WormholePageAction>> {
|
||||
let items: Vec<DropdownItem<WormholePageAction>> = SshExtensionInstallMode::iter()
|
||||
.map(|mode| {
|
||||
DropdownItem::new(
|
||||
mode.display_name(),
|
||||
WarpifyPageAction::SetSshExtensionInstallMode(mode),
|
||||
WormholePageAction::SetSshExtensionInstallMode(mode),
|
||||
)
|
||||
})
|
||||
.collect();
|
||||
|
||||
let current_mode = *WarpifySettings::as_ref(ctx)
|
||||
let current_mode = *WormholeSettings::as_ref(ctx)
|
||||
.ssh_extension_install_mode
|
||||
.value();
|
||||
let enable_ssh_warpification = *WarpifySettings::as_ref(ctx)
|
||||
.enable_ssh_warpification
|
||||
.value();
|
||||
let enable_ssh_wormholing = *WormholeSettings::as_ref(ctx).enable_ssh_wormholing.value();
|
||||
|
||||
ctx.add_typed_action_view(move |ctx| {
|
||||
let mut dropdown = Dropdown::new(ctx);
|
||||
@@ -298,10 +293,10 @@ impl WarpifyPageView {
|
||||
dropdown.set_menu_width(SSH_EXTENSION_DROPDOWN_WIDTH, ctx);
|
||||
dropdown.add_items(items, ctx);
|
||||
dropdown.set_selected_by_action(
|
||||
WarpifyPageAction::SetSshExtensionInstallMode(current_mode),
|
||||
WormholePageAction::SetSshExtensionInstallMode(current_mode),
|
||||
ctx,
|
||||
);
|
||||
if !enable_ssh_warpification {
|
||||
if !enable_ssh_wormholing {
|
||||
dropdown.set_disabled(ctx);
|
||||
}
|
||||
dropdown
|
||||
@@ -352,9 +347,9 @@ impl WarpifyPageView {
|
||||
}
|
||||
}
|
||||
|
||||
impl View for WarpifyPageView {
|
||||
impl View for WormholePageView {
|
||||
fn ui_name() -> &'static str {
|
||||
"WarpifyPageView"
|
||||
"WormholePageView"
|
||||
}
|
||||
|
||||
fn render(&self, app: &AppContext) -> Box<dyn Element> {
|
||||
@@ -363,41 +358,38 @@ impl View for WarpifyPageView {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum WarpifyPageAction {
|
||||
pub enum WormholePageAction {
|
||||
RemoveAddedCommand(usize),
|
||||
RemoveDenylistedCommand(usize),
|
||||
ToggleSshWarpification,
|
||||
ToggleSshWormholing,
|
||||
/// Toggles whether the legacy SSH wrapper attaches to an existing
|
||||
/// ControlMaster for the destination host instead of creating its own.
|
||||
ToggleReuseSshControlMaster,
|
||||
/// Set the SSH extension installation mode (always ask / always install / always skip).
|
||||
SetSshExtensionInstallMode(SshExtensionInstallMode),
|
||||
OpenUrl(String),
|
||||
}
|
||||
|
||||
impl TypedActionView for WarpifyPageView {
|
||||
type Action = WarpifyPageAction;
|
||||
impl TypedActionView for WormholePageView {
|
||||
type Action = WormholePageAction;
|
||||
|
||||
fn handle_action(&mut self, action: &Self::Action, ctx: &mut ViewContext<Self>) {
|
||||
use WarpifyPageAction::*;
|
||||
use WormholePageAction::*;
|
||||
match action {
|
||||
RemoveDenylistedCommand(index) => self.remove_denylisted_command(*index, ctx),
|
||||
RemoveAddedCommand(index) => self.remove_added_command(*index, ctx),
|
||||
ToggleSshWarpification => {
|
||||
WarpifySettings::handle(ctx).update(ctx, |ssh_settings, ctx| {
|
||||
ToggleSshWormholing => {
|
||||
WormholeSettings::handle(ctx).update(ctx, |ssh_settings, ctx| {
|
||||
report_if_error!(ssh_settings
|
||||
.enable_ssh_warpification
|
||||
.enable_ssh_wormholing
|
||||
.toggle_and_save_value(ctx));
|
||||
send_telemetry_from_ctx!(
|
||||
TelemetryEvent::ToggleSshWarpification {
|
||||
enabled: *ssh_settings.enable_ssh_warpification.value(),
|
||||
TelemetryEvent::ToggleSshWormholing {
|
||||
enabled: *ssh_settings.enable_ssh_wormholing.value(),
|
||||
},
|
||||
ctx
|
||||
);
|
||||
});
|
||||
let enabled = *WarpifySettings::as_ref(ctx)
|
||||
.enable_ssh_warpification
|
||||
.value();
|
||||
let enabled = *WormholeSettings::as_ref(ctx).enable_ssh_wormholing.value();
|
||||
self.ssh_extension_install_mode_dropdown
|
||||
.update(ctx, |dropdown, ctx| {
|
||||
if enabled {
|
||||
@@ -425,8 +417,8 @@ impl TypedActionView for WarpifyPageView {
|
||||
});
|
||||
}
|
||||
SetSshExtensionInstallMode(mode) => {
|
||||
WarpifySettings::handle(ctx).update(ctx, |warpify_settings, ctx| {
|
||||
report_if_error!(warpify_settings
|
||||
WormholeSettings::handle(ctx).update(ctx, |wormhole_settings, ctx| {
|
||||
report_if_error!(wormhole_settings
|
||||
.ssh_extension_install_mode
|
||||
.set_value(*mode, ctx));
|
||||
send_telemetry_from_ctx!(
|
||||
@@ -437,16 +429,13 @@ impl TypedActionView for WarpifyPageView {
|
||||
);
|
||||
});
|
||||
}
|
||||
OpenUrl(url) => {
|
||||
ctx.open_url(url.as_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SettingsPageMeta for WarpifyPageView {
|
||||
impl SettingsPageMeta for WormholePageView {
|
||||
fn section() -> SettingsSection {
|
||||
SettingsSection::Warpify
|
||||
SettingsSection::Wormhole
|
||||
}
|
||||
|
||||
fn should_render(&self, _ctx: &AppContext) -> bool {
|
||||
@@ -466,53 +455,39 @@ impl SettingsPageMeta for WarpifyPageView {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ViewHandle<WarpifyPageView>> for SettingsPageViewHandle {
|
||||
fn from(view_handle: ViewHandle<WarpifyPageView>) -> Self {
|
||||
SettingsPageViewHandle::Warpify(view_handle)
|
||||
impl From<ViewHandle<WormholePageView>> for SettingsPageViewHandle {
|
||||
fn from(view_handle: ViewHandle<WormholePageView>) -> Self {
|
||||
SettingsPageViewHandle::Wormhole(view_handle)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct TitleWidget {
|
||||
learn_more_highlight_index: HighlightedHyperlink,
|
||||
}
|
||||
struct TitleWidget;
|
||||
|
||||
impl TitleWidget {
|
||||
fn render_top_of_page(&self, appearance: &Appearance, _app: &AppContext) -> Box<dyn Element> {
|
||||
let warpify_description = vec![
|
||||
FormattedTextFragment::plain_text(
|
||||
"Configure whether Galaxy attempts to \u{201c}Wormhole\u{201d} (add support for blocks, \
|
||||
input modes, etc) certain shells. ",
|
||||
),
|
||||
FormattedTextFragment::hyperlink(
|
||||
"Learn more",
|
||||
"https://docs.warp.dev/terminal/warpify/subshells",
|
||||
),
|
||||
];
|
||||
|
||||
let warpify_description = FormattedTextElement::new(
|
||||
FormattedText::new([FormattedTextLine::Line(warpify_description)]),
|
||||
let wormhole_description = Text::new(
|
||||
"Configure whether Galaxy attempts to \u{201c}Wormhole\u{201d} supported shells, adding blocks, full text editing, completions, and other Galaxy features."
|
||||
.to_string(),
|
||||
appearance.ui_font_family(),
|
||||
CONTENT_FONT_SIZE,
|
||||
appearance.ui_font_family(),
|
||||
appearance.ui_font_family(),
|
||||
blended_colors::text_sub(appearance.theme(), appearance.theme().surface_1()),
|
||||
self.learn_more_highlight_index.clone(),
|
||||
)
|
||||
.with_hyperlink_font_color(appearance.theme().accent().into_solid())
|
||||
.register_default_click_handlers(|url, _, ctx| {
|
||||
ctx.open_url(&url.url);
|
||||
})
|
||||
.soft_wrap(true)
|
||||
.with_color(blended_colors::text_sub(
|
||||
appearance.theme(),
|
||||
appearance.theme().surface_1(),
|
||||
))
|
||||
.finish();
|
||||
|
||||
Flex::column()
|
||||
.with_child(render_page_title("Wormhole", HEADER_FONT_SIZE, appearance))
|
||||
.with_child(warpify_description)
|
||||
.with_child(wormhole_description)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl SettingsWidget for TitleWidget {
|
||||
type View = WarpifyPageView;
|
||||
type View = WormholePageView;
|
||||
|
||||
fn search_terms(&self) -> &str {
|
||||
"ssh subshell galaxify session"
|
||||
@@ -536,20 +511,20 @@ struct SubshellsWidget {}
|
||||
impl SubshellsWidget {
|
||||
fn render_subshells_section(
|
||||
&self,
|
||||
view: &WarpifyPageView,
|
||||
view: &WormholePageView,
|
||||
appearance: &Appearance,
|
||||
app: &AppContext,
|
||||
) -> Box<dyn Element> {
|
||||
let mut column = Flex::column();
|
||||
|
||||
let warpify_settings = WarpifySettings::as_ref(app);
|
||||
let wormhole_settings = WormholeSettings::as_ref(app);
|
||||
|
||||
column.add_child(
|
||||
view.build_input_list(
|
||||
"Added commands",
|
||||
&warpify_settings.added_subshell_commands,
|
||||
&wormhole_settings.added_subshell_commands,
|
||||
&view.remove_added_command_button_states,
|
||||
WarpifyPageAction::RemoveAddedCommand,
|
||||
WormholePageAction::RemoveAddedCommand,
|
||||
&view.add_added_commands_editor,
|
||||
appearance,
|
||||
)
|
||||
@@ -559,9 +534,9 @@ impl SubshellsWidget {
|
||||
column.add_child(
|
||||
view.build_input_list(
|
||||
"Denylisted commands",
|
||||
&warpify_settings.subshell_command_denylist,
|
||||
&wormhole_settings.subshell_command_denylist,
|
||||
&view.remove_denylisted_command_button_states,
|
||||
WarpifyPageAction::RemoveDenylistedCommand,
|
||||
WormholePageAction::RemoveDenylistedCommand,
|
||||
&view.add_denylisted_commands_editor,
|
||||
appearance,
|
||||
)
|
||||
@@ -574,7 +549,7 @@ impl SubshellsWidget {
|
||||
}
|
||||
|
||||
impl SettingsWidget for SubshellsWidget {
|
||||
type View = WarpifyPageView;
|
||||
type View = WormholePageView;
|
||||
|
||||
fn search_terms(&self) -> &str {
|
||||
"galaxify subshell"
|
||||
@@ -594,13 +569,13 @@ impl SettingsWidget for SubshellsWidget {
|
||||
|
||||
#[derive(Default)]
|
||||
struct SSHWidget {
|
||||
enable_ssh_warpification_switch_state: SwitchStateHandle,
|
||||
enable_ssh_wormholing_switch_state: SwitchStateHandle,
|
||||
reuse_control_master_switch_state: SwitchStateHandle,
|
||||
local_only_icon_tooltip_states: RefCell<HashMap<String, MouseStateHandle>>,
|
||||
}
|
||||
|
||||
impl SettingsWidget for SSHWidget {
|
||||
type View = WarpifyPageView;
|
||||
type View = WormholePageView;
|
||||
|
||||
fn search_terms(&self) -> &str {
|
||||
"galaxify ssh"
|
||||
@@ -618,31 +593,29 @@ impl SettingsWidget for SSHWidget {
|
||||
.theme()
|
||||
.sub_text_color(appearance.theme().surface_2());
|
||||
|
||||
let enable_ssh_warpification = *WarpifySettings::as_ref(app)
|
||||
.enable_ssh_warpification
|
||||
.value();
|
||||
let enable_ssh_wormholing = *WormholeSettings::as_ref(app).enable_ssh_wormholing.value();
|
||||
|
||||
add_setting(
|
||||
&mut column,
|
||||
&WarpifySettings::as_ref(app).enable_ssh_warpification,
|
||||
&WormholeSettings::as_ref(app).enable_ssh_wormholing,
|
||||
move || {
|
||||
render_body_item::<WarpifyPageAction>(
|
||||
render_body_item::<WormholePageAction>(
|
||||
"Wormhole SSH Sessions".into(),
|
||||
None,
|
||||
LocalOnlyIconState::for_setting(
|
||||
EnableSshWarpification::storage_key(),
|
||||
EnableSshWarpification::sync_to_cloud(),
|
||||
EnableSshWormholing::storage_key(),
|
||||
EnableSshWormholing::sync_to_cloud(),
|
||||
&mut self.local_only_icon_tooltip_states.borrow_mut(),
|
||||
app,
|
||||
),
|
||||
ToggleState::Enabled,
|
||||
appearance,
|
||||
ui_builder
|
||||
.switch(self.enable_ssh_warpification_switch_state.clone())
|
||||
.check(enable_ssh_warpification)
|
||||
.switch(self.enable_ssh_wormholing_switch_state.clone())
|
||||
.check(enable_ssh_wormholing)
|
||||
.build()
|
||||
.on_click(move |ctx, _, _| {
|
||||
ctx.dispatch_typed_action(WarpifyPageAction::ToggleSshWarpification);
|
||||
ctx.dispatch_typed_action(WormholePageAction::ToggleSshWormholing);
|
||||
})
|
||||
.finish(),
|
||||
None,
|
||||
@@ -651,18 +624,18 @@ impl SettingsWidget for SSHWidget {
|
||||
);
|
||||
|
||||
if FeatureFlag::SshRemoteServer.is_enabled() {
|
||||
let label_color_override = if !enable_ssh_warpification {
|
||||
let label_color_override = if !enable_ssh_wormholing {
|
||||
Some(appearance.theme().disabled_ui_text_color())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
add_setting(
|
||||
&mut column,
|
||||
&WarpifySettings::as_ref(app).ssh_extension_install_mode,
|
||||
&WormholeSettings::as_ref(app).ssh_extension_install_mode,
|
||||
move || {
|
||||
Container::new(render_dropdown_item(
|
||||
appearance,
|
||||
"Install SSH extension",
|
||||
"Install Wormhole helper",
|
||||
Some(SSH_EXTENSION_INSTALL_MODE_DESCRIPTION),
|
||||
None,
|
||||
LocalOnlyIconState::for_setting(
|
||||
@@ -688,7 +661,7 @@ impl SettingsWidget for SSHWidget {
|
||||
&SshSettings::as_ref(app).reuse_existing_control_master,
|
||||
move || {
|
||||
let mut column = Flex::column();
|
||||
column.add_child(render_body_item::<WarpifyPageAction>(
|
||||
column.add_child(render_body_item::<WormholePageAction>(
|
||||
"Reuse existing SSH ControlMaster".into(),
|
||||
None,
|
||||
LocalOnlyIconState::for_setting(
|
||||
@@ -697,19 +670,19 @@ impl SettingsWidget for SSHWidget {
|
||||
&mut self.local_only_icon_tooltip_states.borrow_mut(),
|
||||
app,
|
||||
),
|
||||
enable_ssh_warpification.into(),
|
||||
enable_ssh_wormholing.into(),
|
||||
appearance,
|
||||
ui_builder
|
||||
.switch(self.reuse_control_master_switch_state.clone())
|
||||
.check(reuse_existing_control_master)
|
||||
.with_disabled(!enable_ssh_warpification)
|
||||
.with_disabled(!enable_ssh_wormholing)
|
||||
.build()
|
||||
.on_click(move |ctx, _, _| {
|
||||
if !enable_ssh_warpification {
|
||||
if !enable_ssh_wormholing {
|
||||
return;
|
||||
}
|
||||
ctx.dispatch_typed_action(
|
||||
WarpifyPageAction::ToggleReuseSshControlMaster,
|
||||
WormholePageAction::ToggleReuseSshControlMaster,
|
||||
);
|
||||
})
|
||||
.finish(),
|
||||
Reference in New Issue
Block a user