Uninstall plugins from settings
This commit is contained in:
@@ -9,7 +9,7 @@ use gpui_component::{
|
||||
scroll::ScrollableElement,
|
||||
};
|
||||
|
||||
use super::super::plugins::PendingPluginInstall;
|
||||
use super::super::plugins::{PendingPluginInstall, PendingPluginUninstall};
|
||||
use super::{ElyShell, render_canvas_surface};
|
||||
|
||||
impl ElyShell {
|
||||
@@ -92,6 +92,9 @@ impl ElyShell {
|
||||
.when_some(self.pending_plugin_install.clone(), |this, pending| {
|
||||
this.child(render_plugin_install_confirmation(&pending, cx))
|
||||
})
|
||||
.when_some(self.pending_plugin_uninstall.clone(), |this, pending| {
|
||||
this.child(render_plugin_uninstall_confirmation(&pending, cx))
|
||||
})
|
||||
.child(render_plugin_list(snapshot, cx))
|
||||
.child(render_plugin_audit_list(snapshot)),
|
||||
)
|
||||
@@ -171,6 +174,68 @@ fn render_plugin_install_confirmation(
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_plugin_uninstall_confirmation(
|
||||
pending: &PendingPluginUninstall,
|
||||
cx: &mut Context<ElyShell>,
|
||||
) -> AnyElement {
|
||||
div()
|
||||
.rounded_md()
|
||||
.border_1()
|
||||
.border_color(rgb(colors::ERROR))
|
||||
.px_3()
|
||||
.py_2()
|
||||
.flex()
|
||||
.items_center()
|
||||
.justify_between()
|
||||
.gap_3()
|
||||
.child(
|
||||
div()
|
||||
.min_w_0()
|
||||
.flex()
|
||||
.flex_col()
|
||||
.gap_1()
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.font_semibold()
|
||||
.text_color(rgb(colors::ERROR))
|
||||
.child(format!("Confirm uninstall for {}", pending.plugin_name())),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.text_xs()
|
||||
.truncate()
|
||||
.text_color(rgb(colors::MUTED))
|
||||
.child(pending.plugin_id().as_str().to_string()),
|
||||
),
|
||||
)
|
||||
.child(
|
||||
div()
|
||||
.flex()
|
||||
.items_center()
|
||||
.gap_2()
|
||||
.child(
|
||||
Button::new("cancel-plugin-uninstall")
|
||||
.ghost()
|
||||
.xsmall()
|
||||
.label("Cancel")
|
||||
.on_click(cx.listener(|shell, _, _, cx| {
|
||||
shell.cancel_plugin_uninstall(cx);
|
||||
})),
|
||||
)
|
||||
.child(
|
||||
Button::new("confirm-plugin-uninstall")
|
||||
.danger()
|
||||
.xsmall()
|
||||
.label("Uninstall")
|
||||
.on_click(cx.listener(|shell, _, _, cx| {
|
||||
shell.confirm_plugin_uninstall(cx);
|
||||
})),
|
||||
),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_plugin_list(snapshot: &BrowserSnapshot, cx: &mut Context<ElyShell>) -> AnyElement {
|
||||
if snapshot.installed_plugins.is_empty() {
|
||||
return div()
|
||||
@@ -208,6 +273,7 @@ fn render_plugin_row(
|
||||
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 plugin_name = plugin.manifest().name().to_string();
|
||||
let target_enabled = !plugin.enabled();
|
||||
|
||||
div()
|
||||
@@ -250,7 +316,14 @@ fn render_plugin_row(
|
||||
.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(render_plugin_state_button(index, plugin, plugin_id, target_enabled, cx)),
|
||||
.child(render_plugin_state_button(
|
||||
index,
|
||||
plugin,
|
||||
plugin_id.clone(),
|
||||
target_enabled,
|
||||
cx,
|
||||
))
|
||||
.child(render_plugin_uninstall_button(index, plugin_id, plugin_name, cx)),
|
||||
)
|
||||
.into_any_element()
|
||||
}
|
||||
@@ -281,6 +354,24 @@ fn render_plugin_state_button(
|
||||
}
|
||||
}
|
||||
|
||||
fn render_plugin_uninstall_button(
|
||||
index: usize,
|
||||
plugin_id: PluginId,
|
||||
plugin_name: String,
|
||||
cx: &mut Context<ElyShell>,
|
||||
) -> AnyElement {
|
||||
Button::new(("uninstall-plugin", index))
|
||||
.danger()
|
||||
.xsmall()
|
||||
.icon(IconName::Delete)
|
||||
.label("Remove")
|
||||
.tooltip("Uninstall Plugin")
|
||||
.on_click(cx.listener(move |shell, _, _, cx| {
|
||||
shell.request_plugin_uninstall(plugin_id.clone(), plugin_name.clone(), cx);
|
||||
}))
|
||||
.into_any_element()
|
||||
}
|
||||
|
||||
fn render_plugin_audit_list(snapshot: &BrowserSnapshot) -> AnyElement {
|
||||
if snapshot.plugin_audit_events.is_empty() {
|
||||
return div().into_any_element();
|
||||
@@ -332,6 +423,7 @@ fn plugin_audit_action_label(action: &PluginAuditAction) -> &'static str {
|
||||
PluginAuditAction::Installed => "Installed",
|
||||
PluginAuditAction::Enabled => "Enabled",
|
||||
PluginAuditAction::Disabled => "Disabled",
|
||||
PluginAuditAction::Uninstalled => "Uninstalled",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ use gpui::{App, AppContext, Context, Entity, FocusHandle, Focusable, Subscriptio
|
||||
use gpui_component::input::{InputEvent, InputState, SelectAll};
|
||||
|
||||
use downloads::PendingDownloadFileAction;
|
||||
use plugins::PendingPluginInstall;
|
||||
use plugins::{PendingPluginInstall, PendingPluginUninstall};
|
||||
|
||||
use crate::{
|
||||
CloseCurrentTab, FocusAddressBar, FocusCommandMode, OpenDownloads, OpenHistory, OpenNewTab,
|
||||
@@ -32,6 +32,7 @@ pub struct ElyShell {
|
||||
download_security_confirmation: Option<PendingDownloadFileAction>,
|
||||
plugin_install_error: Option<String>,
|
||||
pending_plugin_install: Option<PendingPluginInstall>,
|
||||
pending_plugin_uninstall: Option<PendingPluginUninstall>,
|
||||
_command_subscription: Subscription,
|
||||
}
|
||||
|
||||
@@ -92,6 +93,7 @@ impl ElyShell {
|
||||
download_security_confirmation: None,
|
||||
plugin_install_error: None,
|
||||
pending_plugin_install: None,
|
||||
pending_plugin_uninstall: None,
|
||||
_command_subscription: command_subscription,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,12 @@ pub(super) struct PendingPluginInstall {
|
||||
high_risk_permissions: Vec<PluginPermission>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub(super) struct PendingPluginUninstall {
|
||||
plugin_id: PluginId,
|
||||
plugin_name: String,
|
||||
}
|
||||
|
||||
impl PendingPluginInstall {
|
||||
fn new(package: VerifiedPluginPackage, high_risk_permissions: Vec<PluginPermission>) -> Self {
|
||||
Self { package, high_risk_permissions }
|
||||
@@ -30,6 +36,20 @@ impl PendingPluginInstall {
|
||||
}
|
||||
}
|
||||
|
||||
impl PendingPluginUninstall {
|
||||
fn new(plugin_id: PluginId, plugin_name: String) -> Self {
|
||||
Self { plugin_id, plugin_name }
|
||||
}
|
||||
|
||||
pub(super) fn plugin_id(&self) -> &PluginId {
|
||||
&self.plugin_id
|
||||
}
|
||||
|
||||
pub(super) fn plugin_name(&self) -> &str {
|
||||
&self.plugin_name
|
||||
}
|
||||
}
|
||||
|
||||
impl ElyShell {
|
||||
pub(super) fn choose_plugin_package(&mut self, window: &mut Window, cx: &mut Context<Self>) {
|
||||
let prompt = cx.prompt_for_paths(PathPromptOptions {
|
||||
@@ -86,6 +106,31 @@ impl ElyShell {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(super) fn request_plugin_uninstall(
|
||||
&mut self,
|
||||
plugin_id: PluginId,
|
||||
plugin_name: String,
|
||||
cx: &mut Context<Self>,
|
||||
) {
|
||||
self.pending_plugin_uninstall = Some(PendingPluginUninstall::new(plugin_id, plugin_name));
|
||||
self.plugin_install_error = None;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(super) fn cancel_plugin_uninstall(&mut self, cx: &mut Context<Self>) {
|
||||
self.pending_plugin_uninstall = None;
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
pub(super) fn confirm_plugin_uninstall(&mut self, cx: &mut Context<Self>) {
|
||||
let Some(pending) = self.pending_plugin_uninstall.take() else {
|
||||
cx.notify();
|
||||
return;
|
||||
};
|
||||
|
||||
self.uninstall_plugin(pending.plugin_id, cx);
|
||||
}
|
||||
|
||||
pub(super) fn set_plugin_enabled(
|
||||
&mut self,
|
||||
plugin_id: PluginId,
|
||||
@@ -108,6 +153,19 @@ impl ElyShell {
|
||||
cx.notify();
|
||||
}
|
||||
|
||||
fn uninstall_plugin(&mut self, plugin_id: PluginId, cx: &mut Context<Self>) {
|
||||
let result = match &mut self.state {
|
||||
ShellState::Ready(core) => PluginPackageStore::application()
|
||||
.and_then(|store| store.remove_plugin(&plugin_id))
|
||||
.map_err(|error| error.to_string())
|
||||
.and_then(|_| core.uninstall_plugin(&plugin_id).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<VerifiedPluginPackage, PluginPackageError>,
|
||||
|
||||
Reference in New Issue
Block a user