feat: Sessions an Projekt/Workspace binden [appimage]
Some checks failed
Build AppImage / build (push) Failing after 3m54s

Sessions werden jetzt nach aktivem Projekt gefiltert (working_dir).
Beim Projektwechsel sieht man nur noch die Sessions die zu diesem
Projekt gehören. Backend: load_sessions_filtered() mit optionalem
WHERE working_dir-Filter. Ohne Projekt: alle Sessions (abwärtskompatibel).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Eddy 2026-04-21 13:27:33 +02:00
parent ebbb65a1a9
commit c2db56f392
3 changed files with 39 additions and 12 deletions

View file

@ -519,13 +519,12 @@ impl Database {
/// Lädt alle Sessions (neueste zuerst)
pub fn load_sessions(&self, limit: usize) -> SqlResult<Vec<Session>> {
let mut stmt = self.conn.prepare(
"SELECT id, claude_session_id, title, working_dir, message_count,
token_input, token_output, cost_usd, status, created_at, updated_at, last_message
FROM sessions ORDER BY updated_at DESC LIMIT ?1"
)?;
self.load_sessions_filtered(limit, None)
}
let sessions = stmt.query_map(params![limit as i64], |row| {
/// Sessions laden, optional gefiltert nach working_dir (Projekt-Bindung)
pub fn load_sessions_filtered(&self, limit: usize, working_dir: Option<&str>) -> SqlResult<Vec<Session>> {
let row_mapper = |row: &rusqlite::Row| -> rusqlite::Result<Session> {
Ok(Session {
id: row.get(0)?,
claude_session_id: row.get(1)?,
@ -540,7 +539,23 @@ impl Database {
updated_at: row.get(10)?,
last_message: row.get(11)?,
})
})?.collect::<SqlResult<Vec<_>>>()?;
};
let sessions = if let Some(dir) = working_dir {
let mut stmt = self.conn.prepare(
"SELECT id, claude_session_id, title, working_dir, message_count,
token_input, token_output, cost_usd, status, created_at, updated_at, last_message
FROM sessions WHERE working_dir = ?1 ORDER BY updated_at DESC LIMIT ?2"
)?;
stmt.query_map(params![dir, limit as i64], row_mapper)?.collect::<SqlResult<Vec<_>>>()?
} else {
let mut stmt = self.conn.prepare(
"SELECT id, claude_session_id, title, working_dir, message_count,
token_input, token_output, cost_usd, status, created_at, updated_at, last_message
FROM sessions ORDER BY updated_at DESC LIMIT ?1"
)?;
stmt.query_map(params![limit as i64], row_mapper)?.collect::<SqlResult<Vec<_>>>()?
};
Ok(sessions)
}

View file

@ -53,16 +53,17 @@ pub async fn update_session(
db.update_session(&session).map_err(|e| e.to_string())
}
/// Alle Sessions laden
/// Alle Sessions laden (optional gefiltert nach working_dir)
#[tauri::command]
pub async fn list_sessions(
app: AppHandle,
limit: Option<usize>,
working_dir: Option<String>,
) -> Result<Vec<Session>, String> {
let limit = limit.unwrap_or(50);
let state = app.state::<Arc<Mutex<db::Database>>>();
let db = state.lock().unwrap();
db.load_sessions(limit).map_err(|e| e.to_string())
db.load_sessions_filtered(limit, working_dir.as_deref()).map_err(|e| e.to_string())
}
/// Session nach ID laden

View file

@ -110,7 +110,7 @@
activeProject = project;
showProjectList = false;
console.log(`📂 Projekt gewechselt: ${project.name} → ${project.working_dir}`);
// Sessions neu laden (gefiltert nach Projekt wäre Zukunftsmusik)
// Sessions gefiltert nach Projekt-Verzeichnis laden
await loadSessions();
} catch (err) {
console.error('Fehler beim Projektwechsel:', err);
@ -131,9 +131,20 @@
async function loadSessions() {
try {
sessions = await invoke('list_sessions', { limit: 50 });
// Sessions nach aktivem Projekt filtern (working_dir)
const workingDir = activeProject?.working_dir ?? undefined;
sessions = await invoke('list_sessions', { limit: 50, workingDir: workingDir });
const active: Session | null = await invoke('get_active_session');
activeSessionId = active?.id || null;
// Prüfen ob aktive Session zum aktuellen Projekt gehört
if (active && (!workingDir || active.working_dir === workingDir)) {
activeSessionId = active.id;
} else if (sessions.length > 0) {
// Erste Session des Projekts aktivieren
activeSessionId = sessions[0].id;
} else {
activeSessionId = null;
}
$currentSessionId = activeSessionId;
// Wenn aktive Session existiert, Nachrichten laden