Collapse a project's sessions by clicking its name

This commit is contained in:
Georg Bauer
2026-07-25 23:58:21 +02:00
parent e44680541d
commit ce18a2db9b
7 changed files with 49 additions and 17 deletions

View File

@@ -178,7 +178,7 @@ pub(crate) enum Message {
ProjectNameChanged(String),
ConfirmProject,
CancelProject,
SelectProject(i32),
ToggleProject(i32),
DeleteProject(i32),
CreateSession(i32),
DiscardSession(i32),
@@ -718,20 +718,22 @@ impl App {
self.project_name_input.clear();
self.error = None;
}
Message::SelectProject(project_id) => {
if self.generating {
self.error =
Some("Stop the active generation before changing sessions.".into());
// Sidebar-only: collapsing a project leaves the open chat alone.
Message::ToggleProject(project_id) => {
let Some(item) = self
.projects
.iter_mut()
.find(|item| item.project.id == project_id)
else {
return Task::none();
};
let collapsed = !item.project.collapsed;
item.project.collapsed = collapsed;
if let Some(database) = &mut self.database
&& let Err(error) = database.set_project_collapsed(project_id, collapsed)
{
self.error = Some(error);
}
self.remember_project(project_id);
self.selected_session = None;
self.conversation.clear();
self.composer.clear();
self.context_used = 0;
self.context_limit = self.preferences.context_tokens.max(0) as u32;
self.tokens_per_second = None;
self.error = None;
}
Message::DeleteProject(project_id) => {
if self.generating && self.selected_project == Some(project_id) {

View File

@@ -195,6 +195,7 @@ mod tests {
id,
name: name.into(),
path: format!("/tmp/{name}"),
collapsed: false,
}
}

View File

@@ -155,12 +155,16 @@ impl App {
projects = projects.push(
row![
button(
row![icon(ICON_FOLDER, 17), text(&project.name).size(14)]
.spacing(9)
.align_y(Alignment::Center),
row![
text(if project.collapsed { "" } else { "" }).size(12),
icon(ICON_FOLDER, 17),
text(&project.name).size(14)
]
.spacing(9)
.align_y(Alignment::Center),
)
.width(Length::Fill)
.on_press(Message::SelectProject(project.id))
.on_press(Message::ToggleProject(project.id))
.style(button::text),
button(icon(ICON_NEW_SESSION, 15))
.on_press(Message::CreateSession(project.id))
@@ -173,6 +177,10 @@ impl App {
.align_y(Alignment::Center),
);
if project.collapsed {
continue;
}
for session in item
.sessions
.iter()

View File

@@ -257,6 +257,8 @@ pub struct Project {
pub id: i32,
pub name: String,
pub path: String,
/// Sidebar state: hides this project's session rows.
pub collapsed: bool,
}
#[derive(Insertable)]
@@ -536,6 +538,18 @@ impl Database {
.map_err(|error| error.to_string())
}
pub fn set_project_collapsed(
&mut self,
project_id: i32,
collapsed: bool,
) -> Result<(), String> {
diesel::update(projects::table.find(project_id))
.set(projects::collapsed.eq(collapsed))
.execute(&mut self.connection)
.map(|_| ())
.map_err(|error| error.to_string())
}
pub fn delete_project(&mut self, project_id: i32) -> Result<(), String> {
self.connection
.transaction(|connection| {
@@ -863,6 +877,9 @@ mod tests {
database.set_sidebar_collapsed(true).unwrap();
database.set_last_project(Some(project.id)).unwrap();
assert!(!loaded[0].project.collapsed);
database.set_project_collapsed(project.id, true).unwrap();
assert!(database.load_projects().unwrap()[0].project.collapsed);
database.delete_project(project.id).unwrap();
assert!(database.load_projects().unwrap().is_empty());

View File

@@ -15,6 +15,7 @@ diesel::table! {
id -> Integer,
name -> Text,
path -> Text,
collapsed -> Bool,
}
}