feat(window): support des fenêtres plugin-hébergées (backend)

Étend le port/usecases window et layout.customPluginLayout pour ouvrir et
piloter des fenêtres OS hébergeant un layout plugin, en réutilisant
contributes.layouts plutôt qu'un système de fenêtres parallèle. Câble la
commande Tauri et l'état app-tauri correspondants.

Cargo test -p domain --test window : 5/5
Cargo test -p application --test window_usecases : 7/7
Cargo test -p infrastructure --test window_state_store : 1/1
Cargo test -p app-tauri view_window_tests : 8/8

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-08-04 00:39:42 +02:00
parent 3ea1d58b38
commit 551eb09ad2
14 changed files with 884 additions and 95 deletions

View File

@ -1095,6 +1095,21 @@ pub enum PersistedWindowKind {
Main,
/// A detached project view window.
View,
/// A detached window hosting a plugin-contributed layout.
PluginLayout,
}
/// Persisted plugin layout surface hosted by a detached OS window.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
#[serde(rename_all = "camelCase")]
pub struct PersistedPluginLayoutWindow {
/// Provider plugin id.
pub plugin_id: PluginId,
/// Layout type declared by the provider plugin.
pub layout_type: PluginLayoutType,
/// Opaque plugin-owned initial/window state.
#[serde(default)]
pub state: serde_json::Value,
}
/// Physical top-left position of a window or monitor.
@ -1149,6 +1164,9 @@ pub struct PersistedWindowState {
/// Legacy detached view project id. Ignored by panel-only restore.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub project_id: Option<crate::ids::ProjectId>,
/// Plugin layout surface. Present only for [`PersistedWindowKind::PluginLayout`].
#[serde(default, skip_serializing_if = "Option::is_none")]
pub plugin_layout: Option<PersistedPluginLayoutWindow>,
/// App URL loaded in the window.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub url: Option<String>,

View File

@ -194,9 +194,9 @@ pub use git::GitRepository;
pub use layout::{
CustomPluginLayoutCell, Direction, GridCell, GridContainer, LayoutError, LayoutNode,
LayoutTree, LeafCell, PersistedMonitorState, PersistedWindowKind, PersistedWindowPosition,
PersistedWindowSize, PersistedWindowState, SplitContainer, Tab, WeightedChild, Window,
WindowStateSnapshot, Workspace, WINDOW_STATE_SNAPSHOT_VERSION,
LayoutTree, LeafCell, PersistedMonitorState, PersistedPluginLayoutWindow, PersistedWindowKind,
PersistedWindowPosition, PersistedWindowSize, PersistedWindowState, SplitContainer, Tab,
WeightedChild, Window, WindowStateSnapshot, Workspace, WINDOW_STATE_SNAPSHOT_VERSION,
};
pub use events::{DomainEvent, OrchestrationSource};

View File

@ -103,6 +103,7 @@ fn window_state_snapshot_round_trips_with_camel_case_schema() {
kind: PersistedWindowKind::View,
panel: Some("tickets".to_owned()),
project_id: Some(ProjectId::from_uuid(Uuid::from_u128(42))),
plugin_layout: None,
url: Some(
"index.html?panel=tickets&project=00000000-0000-0000-0000-00000000002a".to_owned(),
),