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

@@ -0,0 +1 @@
ALTER TABLE projects DROP COLUMN collapsed;

View File

@@ -0,0 +1,2 @@
ALTER TABLE projects ADD COLUMN collapsed BOOLEAN NOT NULL DEFAULT FALSE
CHECK (collapsed IN (FALSE, TRUE));

View File

@@ -178,7 +178,7 @@ pub(crate) enum Message {
ProjectNameChanged(String), ProjectNameChanged(String),
ConfirmProject, ConfirmProject,
CancelProject, CancelProject,
SelectProject(i32), ToggleProject(i32),
DeleteProject(i32), DeleteProject(i32),
CreateSession(i32), CreateSession(i32),
DiscardSession(i32), DiscardSession(i32),
@@ -718,20 +718,22 @@ impl App {
self.project_name_input.clear(); self.project_name_input.clear();
self.error = None; self.error = None;
} }
Message::SelectProject(project_id) => { // Sidebar-only: collapsing a project leaves the open chat alone.
if self.generating { Message::ToggleProject(project_id) => {
self.error = let Some(item) = self
Some("Stop the active generation before changing sessions.".into()); .projects
.iter_mut()
.find(|item| item.project.id == project_id)
else {
return Task::none(); 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) => { Message::DeleteProject(project_id) => {
if self.generating && self.selected_project == Some(project_id) { if self.generating && self.selected_project == Some(project_id) {

View File

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

View File

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

View File

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

View File

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