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

@ -10,7 +10,7 @@ use domain::ids::{TabId, WindowId};
use std::collections::HashSet;
use domain::layout::{PersistedWindowKind, PersistedWindowState, WindowStateSnapshot, Workspace};
use domain::ports::{IdGenerator, ProjectStore, StoreError, WindowStateStore};
use domain::ports::{IdGenerator, ProjectStore, WindowStateStore};
use crate::error::AppError;
@ -115,21 +115,24 @@ pub struct RestoreOpenWindowsOutput {
/// Loads and filters the latest persisted OS window snapshot.
pub struct RestoreOpenWindows {
windows: Arc<dyn WindowStateStore>,
projects: Arc<dyn ProjectStore>,
_projects: Arc<dyn ProjectStore>,
}
impl RestoreOpenWindows {
/// Builds the use case from its ports.
#[must_use]
pub fn new(windows: Arc<dyn WindowStateStore>, projects: Arc<dyn ProjectStore>) -> Self {
Self { windows, projects }
Self {
windows,
_projects: projects,
}
}
/// Loads restorable windows.
///
/// Views are ignored if their project no longer exists or if their persisted
/// identity is incomplete. Duplicate labels are ignored after the first
/// occurrence.
/// Views are panel-only: their persisted project id, including legacy
/// `view-<panel>-<project>` identities, is ignored. Duplicate labels are ignored
/// after the first occurrence.
///
/// # Errors
/// [`AppError::Store`] on snapshot read failure.
@ -146,17 +149,10 @@ impl RestoreOpenWindows {
match window.kind {
PersistedWindowKind::Main => windows.push(window),
PersistedWindowKind::View => {
let Some(project_id) = window.project_id else {
continue;
};
if window.panel.is_none() || window.url.is_none() {
if window.panel.is_none() {
continue;
}
match self.projects.load_project(project_id).await {
Ok(_) => windows.push(window),
Err(StoreError::NotFound) => {}
Err(e) => return Err(e.into()),
}
windows.push(window);
}
}
}