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.

<img height="250" alt="global-skill-delete"
src="https://github.com/user-attachments/assets/d49ecc92-c195-42d2-924e-6fb9d024d2ec"
/>
<img height="250" alt="project-skill-delete"
src="https://github.com/user-attachments/assets/4b84af28-b8fd-4635-afe5-c1cd73d09e1a"
/>

Release Notes:

- Added a confirmation prompt when deleting skills from the settings
window.
This commit is contained in:
Smit Barmase authored and GitHub committed 2026-07-15 14:44:40 +00:00
1 parent 919ec316f3
commit 7862fff55c
1 file changed
+47 -6
+47 -6
View File
@@ -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,