diff --git a/crates/ely_app/src/shell/internal_pages/plugins.rs b/crates/ely_app/src/shell/internal_pages/plugins.rs index e1a3bd6..01ce01a 100644 --- a/crates/ely_app/src/shell/internal_pages/plugins.rs +++ b/crates/ely_app/src/shell/internal_pages/plugins.rs @@ -1,5 +1,6 @@ use ely_browser_core::{BrowserSnapshot, InstalledPlugin, PluginAuditAction, PluginAuditEvent}; use ely_design_system::colors; +use ely_domain::PluginId; use gpui::prelude::FluentBuilder; use gpui::{AnyElement, Context, IntoElement, ParentElement, Styled, div, px, rgb}; use gpui_component::{ @@ -91,7 +92,7 @@ impl ElyShell { .when_some(self.pending_plugin_install.clone(), |this, pending| { this.child(render_plugin_install_confirmation(&pending, cx)) }) - .child(render_plugin_list(snapshot)) + .child(render_plugin_list(snapshot, cx)) .child(render_plugin_audit_list(snapshot)), ) } @@ -170,7 +171,7 @@ fn render_plugin_install_confirmation( .into_any_element() } -fn render_plugin_list(snapshot: &BrowserSnapshot) -> AnyElement { +fn render_plugin_list(snapshot: &BrowserSnapshot, cx: &mut Context) -> AnyElement { if snapshot.installed_plugins.is_empty() { return div() .border_t_1() @@ -182,19 +183,32 @@ fn render_plugin_list(snapshot: &BrowserSnapshot) -> AnyElement { .into_any_element(); } + let rows = snapshot + .installed_plugins + .iter() + .enumerate() + .map(|(index, plugin)| render_plugin_row(index, plugin, cx)) + .collect::>(); + div() .flex() .flex_col() .border_t_1() .border_color(rgb(colors::HAIRLINE)) - .children(snapshot.installed_plugins.iter().map(render_plugin_row)) + .children(rows) .into_any_element() } -fn render_plugin_row(plugin: &InstalledPlugin) -> AnyElement { +fn render_plugin_row( + index: usize, + plugin: &InstalledPlugin, + cx: &mut Context, +) -> AnyElement { let high_risk_count = plugin.manifest().high_risk_permissions().count(); let status_color = if plugin.enabled() { colors::SUCCESS } else { colors::MUTED }; let status_label = if plugin.enabled() { "Enabled" } else { "Disabled" }; + let plugin_id = plugin.id().clone(); + let target_enabled = !plugin.enabled(); div() .py_3() @@ -235,11 +249,38 @@ fn render_plugin_row(plugin: &InstalledPlugin) -> AnyElement { .text_color(rgb(colors::MUTED)) .child(format!("{} permissions", plugin.manifest().permissions().len())) .child(format!("{high_risk_count} high risk")) - .child(div().text_color(rgb(status_color)).child(status_label)), + .child(div().text_color(rgb(status_color)).child(status_label)) + .child(render_plugin_state_button(index, plugin, plugin_id, target_enabled, cx)), ) .into_any_element() } +fn render_plugin_state_button( + index: usize, + plugin: &InstalledPlugin, + plugin_id: PluginId, + target_enabled: bool, + cx: &mut Context, +) -> AnyElement { + let label = if plugin.enabled() { "Disable" } else { "Enable" }; + let tooltip = if plugin.enabled() { "Disable Plugin" } else { "Enable Plugin" }; + let icon = if plugin.enabled() { IconName::CircleX } else { IconName::Check }; + let button = Button::new(("set-plugin-enabled", index)) + .xsmall() + .icon(icon) + .label(label) + .tooltip(tooltip) + .on_click(cx.listener(move |shell, _, _, cx| { + shell.set_plugin_enabled(plugin_id.clone(), target_enabled, cx); + })); + + if plugin.enabled() { + button.danger().into_any_element() + } else { + button.primary().into_any_element() + } +} + fn render_plugin_audit_list(snapshot: &BrowserSnapshot) -> AnyElement { if snapshot.plugin_audit_events.is_empty() { return div().into_any_element(); diff --git a/crates/ely_app/src/shell/plugins.rs b/crates/ely_app/src/shell/plugins.rs index 52c3679..1a5f37f 100644 --- a/crates/ely_app/src/shell/plugins.rs +++ b/crates/ely_app/src/shell/plugins.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use ely_domain::{PluginManifest, PluginPermission}; +use ely_domain::{PluginId, PluginManifest, PluginPermission}; use gpui::{Context, PathPromptOptions, Window}; use crate::services::{ @@ -86,6 +86,28 @@ impl ElyShell { cx.notify(); } + pub(super) fn set_plugin_enabled( + &mut self, + plugin_id: PluginId, + enabled: bool, + cx: &mut Context, + ) { + let result = match &mut self.state { + ShellState::Ready(core) => { + let action = if enabled { + core.enable_plugin(&plugin_id) + } else { + core.disable_plugin(&plugin_id) + }; + action.map_err(|error| error.to_string()) + } + ShellState::StartupError(message) => Err(message.clone()), + }; + + self.plugin_install_error = result.err(); + cx.notify(); + } + fn handle_plugin_package_result( &mut self, result: Result,