Add interactive deletion of sessions (#2357)
Co-authored-by: Yingjie He <yingjiehe@squareup.com>
This commit is contained in:
committed by
GitHub
parent
7699fc261f
commit
7e28762cac
@@ -90,17 +90,12 @@ enum SessionCommand {
|
|||||||
)]
|
)]
|
||||||
ascending: bool,
|
ascending: bool,
|
||||||
},
|
},
|
||||||
#[command(about = "Remove sessions")]
|
#[command(about = "Remove sessions. Runs interactively if no ID or regex is provided.")]
|
||||||
Remove {
|
Remove {
|
||||||
#[arg(short, long, help = "session id to be removed", default_value = "")]
|
#[arg(short, long, help = "Session ID to be removed (optional)")]
|
||||||
id: String,
|
id: Option<String>,
|
||||||
#[arg(
|
#[arg(short, long, help = "Regex for removing matched sessions (optional)")]
|
||||||
short,
|
regex: Option<String>,
|
||||||
long,
|
|
||||||
help = "regex for removing matched session",
|
|
||||||
default_value = ""
|
|
||||||
)]
|
|
||||||
regex: String,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,18 +1,20 @@
|
|||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
|
use cliclack::{confirm, multiselect};
|
||||||
use goose::session::info::{get_session_info, SessionInfo, SortOrder};
|
use goose::session::info::{get_session_info, SessionInfo, SortOrder};
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use std::fs;
|
use std::fs;
|
||||||
|
|
||||||
|
const TRUNCATED_DESC_LENGTH: usize = 60;
|
||||||
|
|
||||||
pub fn remove_sessions(sessions: Vec<SessionInfo>) -> Result<()> {
|
pub fn remove_sessions(sessions: Vec<SessionInfo>) -> Result<()> {
|
||||||
println!("The following sessions will be removed:");
|
println!("The following sessions will be removed:");
|
||||||
for session in &sessions {
|
for session in &sessions {
|
||||||
println!("- {}", session.id);
|
println!("- {}", session.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
let should_delete =
|
let should_delete = confirm("Are you sure you want to delete these sessions?")
|
||||||
cliclack::confirm("Are you sure you want to delete all these sessions? (yes/no):")
|
.initial_value(false)
|
||||||
.initial_value(true)
|
.interact()?;
|
||||||
.interact()?;
|
|
||||||
|
|
||||||
if should_delete {
|
if should_delete {
|
||||||
for session in sessions {
|
for session in sessions {
|
||||||
@@ -27,8 +29,50 @@ pub fn remove_sessions(sessions: Vec<SessionInfo>) -> Result<()> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn handle_session_remove(id: String, regex_string: String) -> Result<()> {
|
fn prompt_interactive_session_selection(sessions: &[SessionInfo]) -> Result<Vec<SessionInfo>> {
|
||||||
let sessions = match get_session_info(SortOrder::Descending) {
|
if sessions.is_empty() {
|
||||||
|
println!("No sessions to delete.");
|
||||||
|
return Ok(vec![]);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut selector = multiselect(
|
||||||
|
"Select sessions to delete (use spacebar, Enter to confirm, Ctrl+C to cancel):",
|
||||||
|
);
|
||||||
|
|
||||||
|
let display_map: std::collections::HashMap<String, SessionInfo> = sessions
|
||||||
|
.iter()
|
||||||
|
.map(|s| {
|
||||||
|
let desc = if s.metadata.description.is_empty() {
|
||||||
|
"(no description)"
|
||||||
|
} else {
|
||||||
|
&s.metadata.description
|
||||||
|
};
|
||||||
|
let truncated_desc = if desc.len() > TRUNCATED_DESC_LENGTH {
|
||||||
|
format!("{}...", &desc[..TRUNCATED_DESC_LENGTH - 3])
|
||||||
|
} else {
|
||||||
|
desc.to_string()
|
||||||
|
};
|
||||||
|
let display_text = format!("{} - {} ({})", s.modified, truncated_desc, s.id);
|
||||||
|
(display_text, s.clone())
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
for display_text in display_map.keys() {
|
||||||
|
selector = selector.item(display_text.clone(), display_text.clone(), "");
|
||||||
|
}
|
||||||
|
|
||||||
|
let selected_display_texts: Vec<String> = selector.interact()?;
|
||||||
|
|
||||||
|
let selected_sessions: Vec<SessionInfo> = selected_display_texts
|
||||||
|
.into_iter()
|
||||||
|
.filter_map(|text| display_map.get(&text).cloned())
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
Ok(selected_sessions)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn handle_session_remove(id: Option<String>, regex_string: Option<String>) -> Result<()> {
|
||||||
|
let all_sessions = match get_session_info(SortOrder::Descending) {
|
||||||
Ok(sessions) => sessions,
|
Ok(sessions) => sessions,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("Failed to retrieve sessions: {:?}", e);
|
tracing::error!("Failed to retrieve sessions: {:?}", e);
|
||||||
@@ -37,29 +81,35 @@ pub fn handle_session_remove(id: String, regex_string: String) -> Result<()> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let matched_sessions: Vec<SessionInfo>;
|
let matched_sessions: Vec<SessionInfo>;
|
||||||
if !id.is_empty() {
|
|
||||||
if let Some(session) = sessions.iter().find(|s| s.id == id) {
|
if let Some(id_val) = id {
|
||||||
|
if let Some(session) = all_sessions.iter().find(|s| s.id == id_val) {
|
||||||
matched_sessions = vec![session.clone()];
|
matched_sessions = vec![session.clone()];
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow::anyhow!("Session '{}' not found.", id));
|
return Err(anyhow::anyhow!("Session '{}' not found.", id_val));
|
||||||
}
|
}
|
||||||
} else if !regex_string.is_empty() {
|
} else if let Some(regex_val) = regex_string {
|
||||||
let session_regex = Regex::new(®ex_string)
|
let session_regex = Regex::new(®ex_val)
|
||||||
.with_context(|| format!("Invalid regex pattern '{}'", regex_string))?;
|
.with_context(|| format!("Invalid regex pattern '{}'", regex_val))?;
|
||||||
matched_sessions = sessions
|
|
||||||
|
matched_sessions = all_sessions
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|session| session_regex.is_match(&session.id))
|
.filter(|session| session_regex.is_match(&session.id))
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
if matched_sessions.is_empty() {
|
if matched_sessions.is_empty() {
|
||||||
println!(
|
println!("Regex string '{}' does not match any sessions", regex_val);
|
||||||
"Regex string '{}' does not match any sessions",
|
|
||||||
regex_string
|
|
||||||
);
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
return Err(anyhow::anyhow!("Neither --regex nor --id flags provided."));
|
if all_sessions.is_empty() {
|
||||||
|
return Err(anyhow::anyhow!("No sessions found."));
|
||||||
|
}
|
||||||
|
matched_sessions = prompt_interactive_session_selection(&all_sessions)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
if matched_sessions.is_empty() {
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
remove_sessions(matched_sessions)
|
remove_sessions(matched_sessions)
|
||||||
|
|||||||
Reference in New Issue
Block a user