246 lines
9.1 KiB
Rust
246 lines
9.1 KiB
Rust
use pathfinder_geometry::vector::vec2f;
|
|
use galaxy_core::{features::FeatureFlag, ui::appearance::Appearance};
|
|
#[cfg(not(target_family = "wasm"))]
|
|
use galaxyui::SingletonEntity;
|
|
use galaxyui::{
|
|
elements::{
|
|
ChildAnchor, ChildView, Clipped, ConstrainedBox, Container, Empty, Fill, MainAxisAlignment,
|
|
MainAxisSize, MouseStateHandle, OffsetPositioning, ParentAnchor, ParentElement,
|
|
ParentOffsetBounds, Shrinkable, Stack,
|
|
},
|
|
fonts::Weight,
|
|
ui_components::{
|
|
button::{ButtonVariant, TextAndIcon, TextAndIconAlignment},
|
|
components::{UiComponent, UiComponentStyles},
|
|
},
|
|
Element, ViewContext,
|
|
};
|
|
|
|
use super::env_var_collection::{
|
|
EnvVarCollectionAction, EnvVarCollectionView, VariableRowIndex, CORE_MAX_WIDTH, ROW_SPACING,
|
|
};
|
|
|
|
use crate::{
|
|
drive::sharing::ContentEditability,
|
|
env_vars::{active_env_var_collection_data::SavingStatus, EnvVarValue},
|
|
external_secrets::{ExternalSecretManager, SecretManager},
|
|
search::external_secrets::{
|
|
searcher::ExternalSecretSearchItemAction, view::ExternalSecretsMenuEvent,
|
|
},
|
|
ui_components::icons::Icon,
|
|
};
|
|
#[cfg(all(not(target_family = "wasm"), feature = "local_tty"))]
|
|
use crate::{
|
|
terminal::local_shell::LocalShellState,
|
|
view_components::{DismissibleToast, ToastLink},
|
|
workspace::{ToastStack, WorkspaceAction},
|
|
};
|
|
|
|
impl EnvVarCollectionView {
|
|
pub(super) fn handle_external_secrets_dialog_event(
|
|
&mut self,
|
|
event: &ExternalSecretsMenuEvent,
|
|
ctx: &mut ViewContext<Self>,
|
|
) {
|
|
match event {
|
|
ExternalSecretsMenuEvent::ItemSelected { payload } => {
|
|
let ExternalSecretSearchItemAction::AcceptSecret(secret) = payload.as_ref();
|
|
let row_index = self.pending_variable_row_index.take();
|
|
if let Some(VariableRowIndex(index)) = row_index {
|
|
self.variable_rows[index].value = EnvVarValue::Secret(secret.clone());
|
|
}
|
|
|
|
self.set_saving_status(SavingStatus::Unsaved, ctx)
|
|
}
|
|
ExternalSecretsMenuEvent::Close => {
|
|
self.dialog_open_states.secrets_dialog_open = false;
|
|
self.update_open_modal_state(ctx);
|
|
ctx.focus_self();
|
|
ctx.notify();
|
|
}
|
|
ExternalSecretsMenuEvent::Open => {
|
|
self.dialog_open_states.secrets_dialog_open = true;
|
|
ctx.focus(&self.secrets_dialog);
|
|
self.update_open_modal_state(ctx);
|
|
ctx.notify();
|
|
}
|
|
}
|
|
}
|
|
|
|
pub(super) fn clear_secret(&mut self, ctx: &mut ViewContext<Self>) {
|
|
if let Some(VariableRowIndex(index)) = self.pending_variable_row_index.take() {
|
|
self.variable_rows[index].value = EnvVarValue::Constant(String::new());
|
|
}
|
|
|
|
ctx.notify();
|
|
}
|
|
|
|
#[cfg_attr(target_family = "wasm", allow(unused_variables))]
|
|
pub(super) fn fetch_secret(
|
|
&mut self,
|
|
secret_manager: SecretManager,
|
|
ctx: &mut ViewContext<Self>,
|
|
) {
|
|
#[cfg(all(not(target_family = "wasm"), feature = "local_tty"))]
|
|
{
|
|
let window_id = ctx.window_id();
|
|
let local_shell = LocalShellState::as_ref(ctx);
|
|
let secret_manager_clone = secret_manager.clone();
|
|
|
|
let Some(local_shell_state) = local_shell.local_shell_info() else {
|
|
return;
|
|
};
|
|
|
|
let shell_type = local_shell_state.get_shell_type();
|
|
let shell_path = local_shell_state.get_shell_path().clone();
|
|
let path_env_var = local_shell_state.get_path_env_var().clone();
|
|
|
|
self.secrets_dialog.update(ctx, |_, dialog_ctx| {
|
|
let _ = dialog_ctx.spawn(
|
|
async move {
|
|
secret_manager
|
|
.verify_installed_and_fetch_secrets(
|
|
shell_type,
|
|
shell_path,
|
|
path_env_var,
|
|
)
|
|
.await
|
|
},
|
|
move |view, result, dialog_ctx| match result {
|
|
Ok(secrets) => {
|
|
view.setup(secrets, dialog_ctx);
|
|
}
|
|
Err(e) => {
|
|
let error_message_and_command =
|
|
secret_manager_clone.get_toast_message_and_link(e);
|
|
|
|
let mut toast =
|
|
DismissibleToast::error(error_message_and_command.message);
|
|
|
|
if let (Some(link), Some(link_message)) = (
|
|
error_message_and_command.link,
|
|
error_message_and_command.link_message,
|
|
) {
|
|
toast = toast.with_link(
|
|
ToastLink::new(link_message)
|
|
.with_onclick_action(WorkspaceAction::OpenLink(link)),
|
|
);
|
|
}
|
|
|
|
ToastStack::handle(dialog_ctx).update(dialog_ctx, |toast_stack, ctx| {
|
|
toast_stack.add_persistent_toast(toast, window_id, ctx);
|
|
})
|
|
}
|
|
},
|
|
);
|
|
});
|
|
}
|
|
}
|
|
|
|
pub(super) fn render_secret_or_command_button(
|
|
&self,
|
|
appearance: &Appearance,
|
|
secret: &EnvVarValue,
|
|
menu_button_mouse_state: MouseStateHandle,
|
|
row_index: usize,
|
|
is_focused: bool,
|
|
editability: ContentEditability,
|
|
) -> Box<dyn Element> {
|
|
let (display_name, action, menu, icon) = match secret {
|
|
EnvVarValue::Secret(sec) => (
|
|
sec.get_display_name(),
|
|
EnvVarCollectionAction::DisplayRenderedSecretMenu(VariableRowIndex(row_index)),
|
|
&self.menus.rendered_secret_menu,
|
|
sec.icon(),
|
|
),
|
|
EnvVarValue::Command(cmd) => (
|
|
if !cmd.name.is_empty() {
|
|
cmd.name.clone()
|
|
} else {
|
|
cmd.command.clone()
|
|
},
|
|
EnvVarCollectionAction::DisplayRenderedCommandMenu(VariableRowIndex(row_index)),
|
|
&self.menus.rendered_command_menu,
|
|
Icon::Terminal,
|
|
),
|
|
_ => {
|
|
log::warn!("Secret type not supported for button rendering");
|
|
return Empty::new().finish();
|
|
}
|
|
};
|
|
|
|
let text_and_icon = TextAndIcon::new(
|
|
TextAndIconAlignment::IconFirst,
|
|
display_name,
|
|
icon.to_galaxyui_icon(appearance.theme().active_ui_text_color()),
|
|
MainAxisSize::Max,
|
|
MainAxisAlignment::Center,
|
|
vec2f(16., 16.),
|
|
)
|
|
.with_inner_padding(4.);
|
|
|
|
let default_button_styles = UiComponentStyles {
|
|
font_size: Some(appearance.ui_font_size()),
|
|
font_family_id: Some(appearance.ui_font_family()),
|
|
font_color: Some(
|
|
appearance
|
|
.theme()
|
|
.main_text_color(appearance.theme().background())
|
|
.into(),
|
|
),
|
|
border_width: Some(1.),
|
|
border_color: Some(appearance.theme().surface_2().into()),
|
|
font_weight: Some(Weight::Bold),
|
|
background: Some(Fill::None),
|
|
..Default::default()
|
|
};
|
|
|
|
let hovered_styles = UiComponentStyles {
|
|
border_width: Some(1.),
|
|
border_color: Some(appearance.theme().accent_button_color().into()),
|
|
..default_button_styles
|
|
};
|
|
|
|
let mut button = appearance
|
|
.ui_builder()
|
|
.button(ButtonVariant::Outlined, menu_button_mouse_state)
|
|
.with_style(default_button_styles)
|
|
.with_hovered_styles(hovered_styles)
|
|
.with_text_and_icon_label(text_and_icon);
|
|
|
|
if FeatureFlag::SharedWithMe.is_enabled() && !editability.can_edit() {
|
|
button = button.disabled();
|
|
}
|
|
|
|
let button = button
|
|
.build()
|
|
.on_click(move |ctx, _, _| ctx.dispatch_typed_action(action.clone()));
|
|
|
|
Shrinkable::new(
|
|
1.,
|
|
Container::new(
|
|
ConstrainedBox::new({
|
|
let mut stack = Stack::new().with_child(Clipped::new(button.finish()).finish());
|
|
if is_focused {
|
|
stack.add_positioned_overlay_child(
|
|
ChildView::new(menu).finish(),
|
|
OffsetPositioning::offset_from_parent(
|
|
vec2f(0., 0.),
|
|
ParentOffsetBounds::WindowByPosition,
|
|
ParentAnchor::TopRight,
|
|
ChildAnchor::TopLeft,
|
|
),
|
|
);
|
|
}
|
|
stack.finish()
|
|
})
|
|
.with_width(CORE_MAX_WIDTH)
|
|
.finish(),
|
|
)
|
|
.with_margin_right(ROW_SPACING)
|
|
.finish(),
|
|
)
|
|
.finish()
|
|
}
|
|
}
|