From 7862fff55ccf4de673ea4ec00b8b173c2d25b281 Mon Sep 17 00:00:00 2001 From: Smit Barmase Date: Wed, 15 Jul 2026 20:14:40 +0530 Subject: [PATCH] settings_ui: Add confirmation prompt before deleting a skill (#61044) Previously, clicking the trash icon on the Skills settings page immediately moved the skill's directory to the trash. This PR now shows a confirmation prompt explains what will be deleted and where it's shared before anything is moved to the trash. This is because that directory is shared with other agent tools (`~/.agents/skills` or `{project}/.agents/skills`), deleting it silently affects more than just Zed, I think it's better to explain that. global-skill-delete project-skill-delete Release Notes: - Added a confirmation prompt when deleting skills from the settings window. --- crates/settings_ui/src/pages/skills_setup.rs | 53 +++++++++++++++++--- 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/crates/settings_ui/src/pages/skills_setup.rs b/crates/settings_ui/src/pages/skills_setup.rs index bf450c76c2..3700467a5d 100644 --- a/crates/settings_ui/src/pages/skills_setup.rs +++ b/crates/settings_ui/src/pages/skills_setup.rs @@ -1,9 +1,10 @@ -use agent_skills::{Skill, SkillIndex, encode_skill_share_link}; +use agent_skills::{Skill, SkillIndex, SkillSource, encode_skill_share_link}; use fs::RemoveOptions; -use gpui::{App, ClipboardItem, ScrollHandle, SharedString, prelude::*}; +use gpui::{App, ClipboardItem, PromptLevel, ScrollHandle, SharedString, prelude::*}; use ui::{Divider, Tooltip, prelude::*}; use util::ResultExt as _; +use util::paths::PathExt as _; use crate::pages::SkillCreatorOpenMode; use crate::{SettingsUiFile, SettingsWindow}; @@ -115,6 +116,12 @@ fn render_skill_row( ) -> AnyElement { let skill_file_path = skill.skill_file_path.clone(); let directory_path = skill.directory_path.clone(); + let skill_name = skill.name.clone(); + + let (skill_scope, shared_scope) = match &skill.source { + SkillSource::ProjectLocal { .. } => ("project", "used in this project"), + _ => ("global", "on this machine"), + }; let share_copied = settings_window.last_copied_skill_directory_path.as_deref() == Some(skill.directory_path.as_path()); @@ -214,19 +221,53 @@ fn render_skill_row( .icon_size(IconSize::Small) .tooltip(Tooltip::text("Delete Skill")) .on_click(cx.listener( - move |settings_window, _event, _window, cx| { + move |settings_window, _event, window, cx| { let directory_path = directory_path.clone(); - if !settings_window + if settings_window .hidden_deleted_skill_directory_paths - .insert(directory_path.clone()) + .contains(&directory_path) { return; } - cx.notify(); + + let prompt_message = + format!("Delete the {skill_scope} skill \"{skill_name}\"?"); + let prompt_detail = format!( + "This will move {} to the trash. This skill is shared with other \ + agent tools {shared_scope}, so it will no longer be available to \ + them either.", + directory_path.compact().display(), + ); + let answer = window.prompt( + PromptLevel::Info, + &prompt_message, + Some(&prompt_detail), + &["Delete", "Cancel"], + cx, + ); let app_state = workspace::AppState::global(cx); let fs = app_state.fs.clone(); cx.spawn(async move |settings_window, cx| { + if answer.await != Ok(0) { + return; + } + + let confirmed = settings_window + .update(cx, |settings_window, cx| { + let inserted = settings_window + .hidden_deleted_skill_directory_paths + .insert(directory_path.clone()); + if inserted { + cx.notify(); + } + inserted + }) + .unwrap_or(false); + if !confirmed { + return; + } + let trash_result = fs .trash( &directory_path,