fix(windows): restauration panel-only des fenêtres détachées suivant le projet en focus (#47)

Partie backend. Les fenêtres/panneaux détachés étaient restaurés avec un
project_id figé au moment du détachement, si bien qu'ils restaient collés à
un projet mort ou incohérent après redémarrage. Ils sont désormais restaurés
en mode panel-only, sans project_id figé, et suivent le projet en focus de la
fenêtre principale via un event focused-project exposé par la couche fenêtre.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-07-13 12:37:25 +02:00
parent 1e0cb16ead
commit 6387fac34f
6 changed files with 156 additions and 107 deletions

View File

@ -62,6 +62,7 @@ use domain::{
InboxError, InboxItem, InboxItemKind, InboxReceiptStatus, InboxSource, Project, ProjectId,
TaskId, TicketId,
};
use serde::{Deserialize, Serialize};
use serde_json::{json, Map, Value};
use uuid::Uuid;
@ -89,6 +90,18 @@ use crate::openai_tools::{AppOpenAiToolInvoker, LateBoundOpenAiToolInvoker};
use crate::pty::PtyBridge;
use crate::tickets::AppTicketToolProvider;
/// Focused project snapshot shared with detached panel windows.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct FocusedProjectDto {
/// Project id as a string.
pub id: String,
/// Project display name.
pub name: String,
/// Absolute project root.
pub root: String,
}
use infrastructure::StdioTransport;
use interprocess::local_socket::tokio::Listener as LocalSocketListener;
@ -907,6 +920,8 @@ pub struct AppState {
pub snapshot_open_windows: Arc<SnapshotOpenWindows>,
/// Load restorable Tauri webview-window state on startup.
pub restore_open_windows: Arc<RestoreOpenWindows>,
/// Project currently focused by the main window; panel-only windows follow it.
focused_project: Mutex<Option<FocusedProjectDto>>,
// --- Background tasks (B8) ---
/// Spawn a command-backed first-class background task.
pub spawn_background_command: Arc<SpawnBackgroundCommand>,
@ -2376,6 +2391,7 @@ impl AppState {
move_tab,
snapshot_open_windows,
restore_open_windows,
focused_project: Mutex::new(None),
spawn_background_command,
cancel_background_task,
retry_background_task,
@ -2383,6 +2399,23 @@ impl AppState {
}
}
/// Updates the focused project state. `None` means no project is focused/open.
pub fn set_focused_project(&self, project: Option<FocusedProjectDto>) {
*self
.focused_project
.lock()
.expect("focused project mutex poisoned") = project;
}
/// Returns the current focused project, if any.
#[must_use]
pub fn get_focused_project(&self) -> Option<FocusedProjectDto> {
self.focused_project
.lock()
.expect("focused project mutex poisoned")
.clone()
}
/// Starts a [`FsOrchestratorWatcher`] for `project` if one is not already
/// running for it (idempotent). The watcher tails the project's
/// `.ideai/requests/` tree and dispatches each request through the shared