Add Rig native model providers

This commit is contained in:
2026-08-06 15:03:00 -05:00
parent 634ce7ba00
commit 3fda5d414b
34 changed files with 2134 additions and 452 deletions
+28 -21
View File
@@ -7564,13 +7564,13 @@ impl SettingsWidget for ModelsOverviewWidget {
.with_spacing(8.)
.with_child(build_sub_header(appearance, "Models", None).finish())
.with_child(render_ai_setting_description(
"Configure Galaxy's direct model providers and agent runtimes in one place. OpenAI-compatible endpoints and Bedrock models run through Rig. ACP coding agents use the same Galaxy runtime boundary while retaining their own model, login, session, and tool loop.",
"Configure Galaxy's direct model providers and agent runtimes in one place. OpenAI-compatible, Anthropic, Gemini, Vertex AI, and Bedrock models run through Rig. ACP coding agents use the same Galaxy runtime boundary while retaining their own model, login, session, and tool loop.",
true,
app,
))
.with_child(render_ai_setting_description(
format!(
"{endpoint_count} OpenAI-compatible provider(s) with {endpoint_model_count} model(s); {bedrock_model_count} Bedrock model(s); {agent_runtime_count} enabled agent runtime(s)."
"{endpoint_count} configured provider(s) with {endpoint_model_count} model(s); {bedrock_model_count} Bedrock model(s); {agent_runtime_count} enabled agent runtime(s)."
),
true,
app,
@@ -7680,6 +7680,9 @@ impl OpenAIProviderSettingsWidget {
match provider.kind {
OpenAIProviderKind::OpenAICompatible => "OpenAI-compatible API",
OpenAIProviderKind::ChatGPTSubscription => "ChatGPT subscription",
OpenAIProviderKind::Anthropic => "Anthropic",
OpenAIProviderKind::Gemini => "Google Gemini",
OpenAIProviderKind::VertexAI => "Google Vertex AI",
}
}
@@ -7905,33 +7908,37 @@ impl SettingsWidget for OpenAIProviderSettingsWidget {
app,
));
column.add_child(render_ai_setting_description(
"Connect a ChatGPT subscription, OpenAI-compatible endpoint, AWS Bedrock account, or ACP agent runtime. Each provider can be enabled independently.",
"Connect a ChatGPT subscription, OpenAI-compatible endpoint, Anthropic, Gemini, Vertex AI, AWS Bedrock account, or ACP agent runtime. Each provider can be enabled independently.",
true,
app,
));
column.add_child(self.render_builtin_provider_card(
settings.bedrock_connection_name.value().as_str(),
"Use AWS credentials to access Bedrock foundation models directly.",
*settings.bedrock_enabled.value(),
self.bedrock_enabled_toggle.clone(),
AISettingsPageAction::ToggleBedrockEnabled,
&self.bedrock_edit_button,
&self.bedrock_remove_button,
appearance,
));
if cfg!(unix) && FeatureFlag::AgentClientProtocol.is_enabled() {
if !settings.bedrock_models.value().is_empty() {
column.add_child(self.render_builtin_provider_card(
settings.acp_connection_name.value().as_str(),
"Use a local session-oriented agent that owns its model and authentication.",
*settings.acp_enabled.value(),
self.acp_enabled_toggle.clone(),
AISettingsPageAction::ToggleAcpEnabled,
&self.acp_edit_button,
&self.acp_remove_button,
settings.bedrock_connection_name.value().as_str(),
"Use AWS credentials to access Bedrock foundation models directly.",
*settings.bedrock_enabled.value(),
self.bedrock_enabled_toggle.clone(),
AISettingsPageAction::ToggleBedrockEnabled,
&self.bedrock_edit_button,
&self.bedrock_remove_button,
appearance,
));
}
if cfg!(unix) && FeatureFlag::AgentClientProtocol.is_enabled() {
if *settings.acp_enabled.value() {
column.add_child(self.render_builtin_provider_card(
settings.acp_connection_name.value().as_str(),
"Use a local session-oriented agent that owns its model and authentication.",
*settings.acp_enabled.value(),
self.acp_enabled_toggle.clone(),
AISettingsPageAction::ToggleAcpEnabled,
&self.acp_edit_button,
&self.acp_remove_button,
appearance,
));
}
}
if providers.is_empty() {
column.add_child(render_ai_setting_description(
-15
View File
@@ -1167,9 +1167,6 @@ impl SettingsView {
// Warp Drive page
let warp_drive_page_handle =
ctx.add_typed_action_view(warp_drive_page::WarpDriveSettingsPageView::new);
ctx.subscribe_to_view(&warp_drive_page_handle, |me, _, event, ctx| {
me.handle_warp_drive_page_event(event, ctx);
});
let platform_page_handle = ctx.add_typed_action_view(platform_page::PlatformPageView::new);
ctx.subscribe_to_view(&platform_page_handle, |me, _, event, ctx| {
@@ -1738,18 +1735,6 @@ impl SettingsView {
}
}
fn handle_warp_drive_page_event(
&mut self,
event: &warp_drive_page::WarpDriveSettingsPageEvent,
ctx: &mut ViewContext<Self>,
) {
match event {
warp_drive_page::WarpDriveSettingsPageEvent::SignUp => {
ctx.emit(SettingsViewEvent::SignupAnonymousUser)
}
}
}
fn handle_ai_page_event(&mut self, event: &AISettingsPageEvent, ctx: &mut ViewContext<Self>) {
match event {
AISettingsPageEvent::FocusModal => ctx.focus(&self.search_editor),
+242 -82
View File
@@ -46,10 +46,51 @@ enum ProviderSetupStep {
pub enum ProviderSetupProviderType {
ChatGPTSubscription,
OpenAICompatible,
Anthropic,
Gemini,
VertexAI,
Bedrock,
Acp,
}
const PROVIDER_TYPE_OPTIONS: &[(ProviderSetupProviderType, &str, &str)] = &[
(
ProviderSetupProviderType::ChatGPTSubscription,
"ChatGPT subscription",
"Use your ChatGPT Plus or Pro subscription with native OAuth.",
),
(
ProviderSetupProviderType::OpenAICompatible,
"OpenAI-compatible API",
"Connect LiteLLM, Ollama, vLLM, or another compatible endpoint.",
),
(
ProviderSetupProviderType::Anthropic,
"Anthropic",
"Connect directly to Anthropic's native Messages API with an API key.",
),
(
ProviderSetupProviderType::Gemini,
"Google Gemini",
"Connect directly to Google's Gemini API with an API key.",
),
(
ProviderSetupProviderType::VertexAI,
"Google Vertex AI",
"Use Google Cloud Application Default Credentials for Vertex-hosted Gemini models.",
),
(
ProviderSetupProviderType::Bedrock,
"AWS Bedrock",
"Use the AWS Bedrock credentials and model configuration already managed by Galaxy.",
),
(
ProviderSetupProviderType::Acp,
"ACP agent runtime",
"Use a session-oriented ACP agent that owns its model and authentication.",
),
];
#[derive(Clone, Debug)]
pub struct BedrockProviderDraft {
pub name: String,
@@ -114,6 +155,8 @@ pub struct ProviderSetupModalBody {
draft_name: String,
draft_base_url: String,
draft_api_key: Option<String>,
draft_project_id: String,
draft_location: String,
draft_models: Vec<OpenAIModelConfig>,
draft_bedrock: BedrockProviderDraft,
draft_acp: AcpProviderDraft,
@@ -122,6 +165,8 @@ pub struct ProviderSetupModalBody {
name_editor: ViewHandle<EditorView>,
base_url_editor: ViewHandle<EditorView>,
api_key_editor: ViewHandle<EditorView>,
project_id_editor: ViewHandle<EditorView>,
location_editor: ViewHandle<EditorView>,
bedrock_profile_editor: ViewHandle<EditorView>,
bedrock_region_editor: ViewHandle<EditorView>,
bedrock_refresh_command_editor: ViewHandle<EditorView>,
@@ -134,6 +179,7 @@ pub struct ProviderSetupModalBody {
bedrock_cross_region_toggle: SwitchStateHandle,
bedrock_auto_login_toggle: SwitchStateHandle,
model_switches: Vec<SwitchStateHandle>,
provider_type_scroll_state: ClippedScrollStateHandle,
models_scroll_state: ClippedScrollStateHandle,
back_button: ViewHandle<ActionButton>,
cancel_button: ViewHandle<ActionButton>,
@@ -142,35 +188,28 @@ pub struct ProviderSetupModalBody {
impl ProviderSetupModalBody {
pub fn new(ctx: &mut ViewContext<Self>) -> Self {
let provider_type_buttons = [
(
ProviderSetupProviderType::ChatGPTSubscription,
"ChatGPT subscription",
),
(
ProviderSetupProviderType::OpenAICompatible,
"OpenAI-compatible API",
),
(ProviderSetupProviderType::Bedrock, "AWS Bedrock"),
(ProviderSetupProviderType::Acp, "ACP agent runtime"),
]
.into_iter()
.map(|(kind, label)| {
ctx.add_typed_action_view(move |_| {
ActionButton::new(label, NakedTheme)
.with_full_width(true)
.on_click(move |ctx| {
ctx.dispatch_typed_action(ProviderSetupModalBodyAction::SelectProvider(
kind,
));
})
let provider_type_buttons = PROVIDER_TYPE_OPTIONS
.iter()
.map(|(kind, label, _)| {
let kind = *kind;
let label = *label;
ctx.add_typed_action_view(move |_| {
ActionButton::new(label, NakedTheme)
.with_full_width(true)
.on_click(move |ctx| {
ctx.dispatch_typed_action(
ProviderSetupModalBodyAction::SelectProvider(kind),
);
})
})
})
})
.collect();
.collect();
let name_editor = Self::create_editor("Connection name", false, ctx);
let base_url_editor = Self::create_editor("https://api.example.com/v1", false, ctx);
let api_key_editor = Self::create_editor("sk-... (optional)", true, ctx);
let project_id_editor = Self::create_editor("my-google-cloud-project", false, ctx);
let location_editor = Self::create_editor("global", false, ctx);
let bedrock_profile_editor = Self::create_editor("default", false, ctx);
let bedrock_region_editor = Self::create_editor("us-east-1", false, ctx);
let bedrock_refresh_command_editor = Self::create_editor("aws sso login", false, ctx);
@@ -218,6 +257,19 @@ impl ProviderSetupModalBody {
ctx.notify();
}
});
ctx.subscribe_to_view(&project_id_editor, |me, editor, event, ctx| {
if matches!(event, EditorEvent::Edited(_)) {
me.draft_project_id = editor.as_ref(ctx).buffer_text(ctx);
me.update_next_button(ctx);
ctx.notify();
}
});
ctx.subscribe_to_view(&location_editor, |me, editor, event, ctx| {
if matches!(event, EditorEvent::Edited(_)) {
me.draft_location = editor.as_ref(ctx).buffer_text(ctx);
ctx.notify();
}
});
for (editor, update) in [
(bedrock_profile_editor.clone(), 0),
(bedrock_region_editor.clone(), 1),
@@ -286,6 +338,8 @@ impl ProviderSetupModalBody {
draft_name: String::new(),
draft_base_url: String::new(),
draft_api_key: None,
draft_project_id: String::new(),
draft_location: "global".to_string(),
draft_models: Vec::new(),
draft_bedrock: BedrockProviderDraft {
name: String::new(),
@@ -310,6 +364,8 @@ impl ProviderSetupModalBody {
name_editor,
base_url_editor,
api_key_editor,
project_id_editor,
location_editor,
bedrock_profile_editor,
bedrock_region_editor,
bedrock_refresh_command_editor,
@@ -322,6 +378,7 @@ impl ProviderSetupModalBody {
bedrock_cross_region_toggle: SwitchStateHandle::default(),
bedrock_auto_login_toggle: SwitchStateHandle::default(),
model_switches: Vec::new(),
provider_type_scroll_state: ClippedScrollStateHandle::default(),
models_scroll_state: ClippedScrollStateHandle::default(),
back_button,
cancel_button,
@@ -363,6 +420,8 @@ impl ProviderSetupModalBody {
self.draft_name.clear();
self.draft_base_url.clear();
self.draft_api_key = None;
self.draft_project_id.clear();
self.draft_location = "global".to_string();
self.draft_models.clear();
self.draft_bedrock = BedrockProviderDraft {
name: String::new(),
@@ -405,10 +464,15 @@ impl ProviderSetupModalBody {
ProviderSetupProviderType::ChatGPTSubscription
}
OpenAIProviderKind::OpenAICompatible => ProviderSetupProviderType::OpenAICompatible,
OpenAIProviderKind::Anthropic => ProviderSetupProviderType::Anthropic,
OpenAIProviderKind::Gemini => ProviderSetupProviderType::Gemini,
OpenAIProviderKind::VertexAI => ProviderSetupProviderType::VertexAI,
};
self.draft_name = provider.name;
self.draft_base_url = provider.base_url;
self.draft_api_key = provider.api_key;
self.draft_project_id = provider.project_id.unwrap_or_default();
self.draft_location = provider.location.unwrap_or_else(|| "global".to_string());
self.draft_models = provider.models;
self.discovery_state = DiscoveryState::Idle;
self.sync_editors(ctx);
@@ -483,6 +547,12 @@ impl ProviderSetupModalBody {
self.api_key_editor.update(ctx, |editor, ctx| {
editor.system_reset_buffer_text(self.draft_api_key.as_deref().unwrap_or_default(), ctx);
});
self.project_id_editor.update(ctx, |editor, ctx| {
editor.system_reset_buffer_text(&self.draft_project_id, ctx);
});
self.location_editor.update(ctx, |editor, ctx| {
editor.system_reset_buffer_text(&self.draft_location, ctx);
});
self.bedrock_profile_editor.update(ctx, |editor, ctx| {
editor.system_reset_buffer_text(&self.draft_bedrock.profile, ctx);
});
@@ -513,15 +583,12 @@ impl ProviderSetupModalBody {
}
fn sync_provider_type_buttons(&self, ctx: &mut ViewContext<Self>) {
for (index, button) in self.provider_type_buttons.iter().enumerate() {
let button_kind = match index {
0 => ProviderSetupProviderType::ChatGPTSubscription,
1 => ProviderSetupProviderType::OpenAICompatible,
2 => ProviderSetupProviderType::Bedrock,
_ => ProviderSetupProviderType::Acp,
};
for ((button_kind, _, _), button) in PROVIDER_TYPE_OPTIONS
.iter()
.zip(self.provider_type_buttons.iter())
{
button.update(ctx, |button, ctx| {
button.set_active(button_kind == self.provider_type, ctx);
button.set_active(*button_kind == self.provider_type, ctx);
});
}
}
@@ -555,6 +622,12 @@ impl ProviderSetupModalBody {
ProviderSetupProviderType::OpenAICompatible => {
self.draft_base_url.trim().is_empty()
}
ProviderSetupProviderType::Anthropic | ProviderSetupProviderType::Gemini => {
self.draft_api_key
.as_deref()
.is_none_or(|key| key.trim().is_empty())
}
ProviderSetupProviderType::VertexAI => self.draft_project_id.trim().is_empty(),
ProviderSetupProviderType::Acp => self.draft_acp.agent_id.trim().is_empty(),
ProviderSetupProviderType::ChatGPTSubscription
| ProviderSetupProviderType::Bedrock => false,
@@ -571,7 +644,10 @@ impl ProviderSetupModalBody {
),
ProviderSetupStep::Models => match self.provider_type {
ProviderSetupProviderType::OpenAICompatible
| ProviderSetupProviderType::ChatGPTSubscription => (
| ProviderSetupProviderType::ChatGPTSubscription
| ProviderSetupProviderType::Anthropic
| ProviderSetupProviderType::Gemini
| ProviderSetupProviderType::VertexAI => (
"Save",
self.draft_name.trim().is_empty()
|| !self.draft_models.iter().any(|model| model.enabled),
@@ -601,19 +677,48 @@ impl ProviderSetupModalBody {
ProviderSetupProviderType::OpenAICompatible
| ProviderSetupProviderType::Bedrock
| ProviderSetupProviderType::Acp => OpenAIProviderKind::OpenAICompatible,
ProviderSetupProviderType::Anthropic => OpenAIProviderKind::Anthropic,
ProviderSetupProviderType::Gemini => OpenAIProviderKind::Gemini,
ProviderSetupProviderType::VertexAI => OpenAIProviderKind::VertexAI,
},
enabled: true,
name: self.draft_name.trim().to_string(),
base_url: if self.provider_type == ProviderSetupProviderType::ChatGPTSubscription {
base_url: if matches!(
self.provider_type,
ProviderSetupProviderType::ChatGPTSubscription
| ProviderSetupProviderType::Anthropic
| ProviderSetupProviderType::Gemini
| ProviderSetupProviderType::VertexAI
) {
String::new()
} else {
self.draft_base_url.trim().trim_end_matches('/').to_string()
},
api_key: self
.draft_api_key
.as_deref()
.filter(|key| !key.trim().is_empty())
.map(str::to_string),
api_key: matches!(
self.provider_type,
ProviderSetupProviderType::OpenAICompatible
| ProviderSetupProviderType::Anthropic
| ProviderSetupProviderType::Gemini
)
.then(|| {
self.draft_api_key
.as_deref()
.filter(|key| !key.trim().is_empty())
.map(str::to_string)
})
.flatten(),
project_id: matches!(self.provider_type, ProviderSetupProviderType::VertexAI)
.then(|| self.draft_project_id.trim().to_string()),
location: matches!(self.provider_type, ProviderSetupProviderType::VertexAI).then(
|| {
let location = self.draft_location.trim();
if location.is_empty() {
"global".to_string()
} else {
location.to_string()
}
},
),
models: self.draft_models.clone(),
}
}
@@ -668,7 +773,10 @@ impl ProviderSetupModalBody {
));
return;
}
ProviderSetupProviderType::OpenAICompatible => {}
ProviderSetupProviderType::OpenAICompatible
| ProviderSetupProviderType::Anthropic
| ProviderSetupProviderType::Gemini
| ProviderSetupProviderType::VertexAI => {}
}
let provider = self.draft_provider();
@@ -776,51 +884,53 @@ impl ProviderSetupModalBody {
.with_color(appearance.theme().nonactive_ui_text_color().into())
.finish();
let cards = [
(
"ChatGPT subscription",
"Use your ChatGPT Plus or Pro subscription with native OAuth.",
),
(
"OpenAI-compatible API",
"Connect LiteLLM, Ollama, vLLM, or another compatible endpoint.",
),
(
"AWS Bedrock",
"Use the AWS Bedrock credentials and model configuration already managed by Galaxy.",
),
(
"ACP agent runtime",
"Use a session-oriented ACP agent that owns its model and authentication.",
),
]
.into_iter()
.enumerate()
.map(|(index, (label, description))| {
let button = ChildView::new(&self.provider_type_buttons[index]).finish();
Container::new(
Flex::column()
.with_spacing(8.)
.with_child(button)
.with_child(
Text::new(description, appearance.ui_font_family(), INPUT_FONT_SIZE)
.with_color(appearance.theme().nonactive_ui_text_color().into())
.soft_wrap(true)
.finish(),
)
.finish(),
)
.with_padding(Padding::uniform(12.))
.with_border(Border::all(1.).with_border_fill(appearance.theme().outline()))
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(6.)))
.finish()
})
.collect::<Vec<_>>();
let cards = PROVIDER_TYPE_OPTIONS
.iter()
.enumerate()
.map(|(index, (_, _, description))| {
let button = ChildView::new(&self.provider_type_buttons[index]).finish();
Container::new(
Flex::column()
.with_spacing(8.)
.with_child(button)
.with_child(
Text::new(*description, appearance.ui_font_family(), INPUT_FONT_SIZE)
.with_color(appearance.theme().nonactive_ui_text_color().into())
.soft_wrap(true)
.finish(),
)
.finish(),
)
.with_padding(Padding::uniform(12.))
.with_border(Border::all(1.).with_border_fill(appearance.theme().outline()))
.with_corner_radius(CornerRadius::with_all(Radius::Pixels(6.)))
.finish()
})
.collect::<Vec<_>>();
let list = Flex::column()
.with_spacing(10.)
.with_children(cards)
.finish();
let scrollable = ClippedScrollable::vertical(
self.provider_type_scroll_state.clone(),
list,
ScrollbarWidth::Auto,
appearance.theme().nonactive_ui_detail().into(),
appearance.theme().active_ui_detail().into(),
appearance.theme().surface_1().into(),
)
.with_overlayed_scrollbar()
.finish();
Flex::column()
.with_spacing(16.)
.with_child(description)
.with_children(cards)
.with_child(
ConstrainedBox::new(scrollable)
.with_max_height(360.)
.finish(),
)
.finish()
}
@@ -989,6 +1099,50 @@ impl ProviderSetupModalBody {
.finish(),
);
}
ProviderSetupProviderType::Anthropic => {
children.push(self.render_input(appearance, "API key", &self.api_key_editor));
children.push(
Text::new(
"The key is stored locally and is never synced to the cloud. Models will be discovered from Anthropic after the connection test.",
appearance.ui_font_family(),
INPUT_FONT_SIZE,
)
.with_color(appearance.theme().nonactive_ui_text_color().into())
.soft_wrap(true)
.finish(),
);
}
ProviderSetupProviderType::Gemini => {
children.push(self.render_input(appearance, "API key", &self.api_key_editor));
children.push(
Text::new(
"The key is stored locally and is never synced to the cloud. Models will be discovered from Google's Gemini API after the connection test.",
appearance.ui_font_family(),
INPUT_FONT_SIZE,
)
.with_color(appearance.theme().nonactive_ui_text_color().into())
.soft_wrap(true)
.finish(),
);
}
ProviderSetupProviderType::VertexAI => {
children.push(self.render_input(
appearance,
"Google Cloud project ID",
&self.project_id_editor,
));
children.push(self.render_input(appearance, "Location", &self.location_editor));
children.push(
Text::new(
"Vertex AI uses Google Application Default Credentials. Run `gcloud auth application-default login` before testing the connection.",
appearance.ui_font_family(),
INPUT_FONT_SIZE,
)
.with_color(appearance.theme().nonactive_ui_text_color().into())
.soft_wrap(true)
.finish(),
);
}
ProviderSetupProviderType::Bedrock => {
children.push(Self::render_label(appearance, "Authentication method"));
children.push(
@@ -1422,7 +1576,10 @@ impl TypedActionView for ProviderSetupModalBody {
}
ProviderSetupStep::Models => match self.provider_type {
ProviderSetupProviderType::OpenAICompatible
| ProviderSetupProviderType::ChatGPTSubscription => {
| ProviderSetupProviderType::ChatGPTSubscription
| ProviderSetupProviderType::Anthropic
| ProviderSetupProviderType::Gemini
| ProviderSetupProviderType::VertexAI => {
if self.draft_name.trim().is_empty()
|| !self.draft_models.iter().any(|model| model.enabled)
{
@@ -1529,6 +1686,9 @@ fn provider_type_label(kind: ProviderSetupProviderType) -> &'static str {
match kind {
ProviderSetupProviderType::OpenAICompatible => "OpenAI-compatible API",
ProviderSetupProviderType::ChatGPTSubscription => "ChatGPT subscription",
ProviderSetupProviderType::Anthropic => "Anthropic",
ProviderSetupProviderType::Gemini => "Google Gemini",
ProviderSetupProviderType::VertexAI => "Google Vertex AI",
ProviderSetupProviderType::Bedrock => "AWS Bedrock",
ProviderSetupProviderType::Acp => "ACP agent runtime",
}
+9 -120
View File
@@ -1,17 +1,13 @@
use galaxy_core::features::FeatureFlag;
use galaxy_core::report_if_error;
use galaxy_core::settings::ToggleableSetting as _;
use galaxyui::fonts::Weight;
use galaxyui::keymap::ContextPredicate;
use galaxyui::ui_components::button::ButtonVariant;
use galaxyui::ui_components::components::{Coords, UiComponent, UiComponentStyles};
use galaxyui::ui_components::components::UiComponent;
use galaxyui::ui_components::switch::SwitchStateHandle;
use galaxyui::{
id, Action, AppContext, Entity, SingletonEntity, TypedActionView, View, ViewContext, ViewHandle,
};
use warpui::elements::{
Container, Element, Flex, MouseStateHandle, ParentElement, Shrinkable, Text,
};
use warpui::elements::{Element, MouseStateHandle};
use super::settings_page::{
render_body_item, AdditionalInfo, MatchData, PageType, SettingsPageMeta,
@@ -22,13 +18,11 @@ use super::{
SettingsAction, SettingsSection, ToggleSettingActionPair, ToggleState,
};
use crate::appearance::Appearance;
use crate::auth::AuthStateProvider;
use crate::drive::settings::WarpDriveSettings;
#[derive(Debug, Clone)]
pub enum WarpDriveSettingsPageAction {
ToggleShowWarpDrive,
SignUp,
OpenUrl(String),
}
@@ -44,8 +38,8 @@ pub fn init_actions_from_parent_view<T: Action + Clone>(
WarpDriveSettingsPageAction::ToggleShowWarpDrive,
)),
SettingActionPairContexts::new(
context.clone() & !id!(flags::ENABLE_WARP_DRIVE) & !id!("IsAnonymousUser"),
context.clone() & id!(flags::ENABLE_WARP_DRIVE) & !id!("IsAnonymousUser"),
context.clone() & !id!(flags::ENABLE_WARP_DRIVE),
context.clone() & id!(flags::ENABLE_WARP_DRIVE),
),
None,
)
@@ -54,10 +48,6 @@ pub fn init_actions_from_parent_view<T: Action + Clone>(
);
}
pub enum WarpDriveSettingsPageEvent {
SignUp,
}
pub struct WarpDriveSettingsPageView {
page: PageType<Self>,
}
@@ -66,10 +56,7 @@ impl WarpDriveSettingsPageView {
pub fn new(_ctx: &mut ViewContext<Self>) -> Self {
Self {
page: PageType::new_uncategorized(
vec![
Box::new(WarpDriveHeaderWidget::default()),
Box::new(WarpDriveToggleWidget::default()),
],
vec![Box::new(WarpDriveToggleWidget::default())],
None,
),
}
@@ -77,7 +64,7 @@ impl WarpDriveSettingsPageView {
}
impl Entity for WarpDriveSettingsPageView {
type Event = WarpDriveSettingsPageEvent;
type Event = ();
}
impl TypedActionView for WarpDriveSettingsPageView {
@@ -91,9 +78,6 @@ impl TypedActionView for WarpDriveSettingsPageView {
});
ctx.notify();
}
WarpDriveSettingsPageAction::SignUp => {
ctx.emit(WarpDriveSettingsPageEvent::SignUp);
}
WarpDriveSettingsPageAction::OpenUrl(url) => {
ctx.open_url(url.as_str());
}
@@ -139,88 +123,6 @@ impl From<ViewHandle<WarpDriveSettingsPageView>> for SettingsPageViewHandle {
}
}
#[derive(Default)]
struct WarpDriveHeaderWidget {
sign_up_button: MouseStateHandle,
}
impl SettingsWidget for WarpDriveHeaderWidget {
type View = WarpDriveSettingsPageView;
fn search_terms(&self) -> &str {
"warp drive sign up"
}
fn should_render(&self, app: &AppContext) -> bool {
FeatureFlag::SkipFirebaseAnonymousUser.is_enabled()
&& AuthStateProvider::as_ref(app)
.get()
.is_anonymous_or_logged_out()
}
fn render(
&self,
_view: &Self::View,
appearance: &Appearance,
_app: &AppContext,
) -> Box<dyn Element> {
let ui_builder = appearance.ui_builder();
let message = Container::new(
Text::new_inline(
"To use Galaxy Drive, please create an account.".to_string(),
appearance.ui_font_family(),
14.,
)
.with_color(
appearance
.theme()
.sub_text_color(appearance.theme().surface_2())
.into_solid(),
)
.finish(),
)
.with_margin_right(16.)
.finish();
let button = Container::new(
ui_builder
.button(ButtonVariant::Accent, self.sign_up_button.clone())
.with_style(UiComponentStyles {
font_size: Some(14.),
font_weight: Some(Weight::Semibold),
border_radius: Some(galaxyui::elements::CornerRadius::with_all(
galaxyui::elements::Radius::Pixels(4.),
)),
padding: Some(Coords {
top: 8.,
bottom: 8.,
left: 24.,
right: 24.,
}),
..Default::default()
})
.with_text_label("Sign up".to_owned())
.build()
.on_click(move |ctx, _, _| {
ctx.dispatch_typed_action(WarpDriveSettingsPageAction::SignUp);
})
.finish(),
)
.finish();
Container::new(
Flex::row()
.with_cross_axis_alignment(galaxyui::elements::CrossAxisAlignment::Center)
.with_child(Shrinkable::new(1., message).finish())
.with_child(button)
.finish(),
)
.with_padding_bottom(15.)
.finish()
}
}
#[derive(Default)]
struct WarpDriveToggleWidget {
switch_state: SwitchStateHandle,
@@ -241,10 +143,6 @@ impl SettingsWidget for WarpDriveToggleWidget {
app: &AppContext,
) -> Box<dyn Element> {
let settings = WarpDriveSettings::as_ref(app);
let is_anonymous_or_logged_out = FeatureFlag::SkipFirebaseAnonymousUser.is_enabled()
&& AuthStateProvider::as_ref(app)
.get()
.is_anonymous_or_logged_out();
render_body_item::<WarpDriveSettingsPageAction>(
"Galaxy Drive".into(),
@@ -257,24 +155,15 @@ impl SettingsWidget for WarpDriveToggleWidget {
tooltip_override_text: None,
}),
LocalOnlyIconState::Hidden,
if is_anonymous_or_logged_out {
ToggleState::Disabled
} else {
ToggleState::Enabled
},
ToggleState::Enabled,
appearance,
appearance
.ui_builder()
.switch(self.switch_state.clone())
.check(*settings.enable_warp_drive && !is_anonymous_or_logged_out)
.with_disabled(is_anonymous_or_logged_out)
.check(*settings.enable_warp_drive)
.build()
.on_click(move |ctx, _, _| {
if !is_anonymous_or_logged_out {
ctx.dispatch_typed_action(
WarpDriveSettingsPageAction::ToggleShowWarpDrive,
);
}
ctx.dispatch_typed_action(WarpDriveSettingsPageAction::ToggleShowWarpDrive);
})
.finish(),
Some("Galaxy Drive is a workspace in your terminal where you can save Workflows, Notebooks, Prompts, and Environment Variables for personal use or to share with a team.".into()),