Mountain/ApplicationState/DTO/
WebviewStateDTO.rs

1//! # WebviewStateDTO
2//!
3//! # RESPONSIBILITY
4//! - Data transfer object for Webview panel state
5//! - Serializable format for gRPC/IPC transmission
6//! - Used by Mountain to track Webview lifecycle
7//!
8//! # FIELDS
9//! - Handle: Unique Webview UUID
10//! - ViewType: Extension-defined view type
11//! - Title: Current panel title
12//! - ContentOptions: Web content and security settings
13//! - PanelOptions: Panel behavior options
14//! - SideCarIdentifier: Host sidecar process ID
15//! - ExtensionIdentifier: Owner extension ID
16//! - IsActive: Focus state flag
17//! - IsVisible: Visibility state flag
18use CommonLibrary::Webview::DTO::WebviewContentOptionsDTO::WebviewContentOptionsDTO;
19use serde::{Deserialize, Serialize};
20// For PanelOptions, etc.
21use serde_json::Value;
22
23/// Maximum handle length (UUID string)
24const MAX_HANDLE_LENGTH:usize = 128;
25
26/// Maximum view type length
27const MAX_VIEW_TYPE_LENGTH:usize = 128;
28
29/// Maximum sidecar identifier length
30const MAX_SIDECAR_IDENTIFIER_LENGTH:usize = 128;
31
32/// Maximum extension identifier length
33const MAX_EXTENSION_IDENTIFIER_LENGTH:usize = 128;
34
35/// Maximum title length
36const MAX_TITLE_LENGTH:usize = 256;
37
38/// A struct that holds the complete state for a single Webview panel instance.
39/// This is stored in `ApplicationState` to track all active Webviews managed by
40/// the host.
41#[derive(Serialize, Deserialize, Debug, Clone)]
42#[serde(rename_all = "PascalCase")]
43pub struct WebviewStateDTO {
44	/// A unique UUID handle for this Webview instance.
45	pub Handle:String,
46
47	/// The view type of this Webview panel, as defined by the extension.
48	#[serde(skip_serializing_if = "String::is_empty")]
49	pub ViewType:String,
50
51	/// The current title of the Webview panel.
52	#[serde(skip_serializing_if = "String::is_empty")]
53	pub Title:String,
54
55	/// The content and security options for the Webview's content.
56	pub ContentOptions:WebviewContentOptionsDTO,
57
58	/// The options controlling the behavior of the Webview panel itself.
59	// DTO: WebviewPanelOptionsDTO
60	pub PanelOptions: Value,
61
62	/// The identifier of the sidecar process that owns this Webview.
63	#[serde(skip_serializing_if = "String::is_empty")]
64	pub SideCarIdentifier:String,
65
66	/// The identifier of the extension that owns this Webview.
67	#[serde(skip_serializing_if = "String::is_empty")]
68	pub ExtensionIdentifier:String,
69
70	/// A flag indicating if the Webview panel currently has focus.
71	pub IsActive:bool,
72
73	/// A flag indicating if the Webview panel is currently visible in the UI.
74	pub IsVisible:bool,
75}
76
77impl WebviewStateDTO {
78	/// Creates a new WebviewStateDTO with validation.
79	///
80	/// # Arguments
81	/// * `Handle` - Unique Webview handle
82	/// * `ViewType` - Extension-defined view type
83	/// * `Title` - Panel title
84	/// * `ContentOptions` - Web content options
85	/// * `PanelOptions` - Panel behavior options
86	/// * `SideCarIdentifier` - Sidecar process ID
87	/// * `ExtensionIdentifier` - Extension ID
88	///
89	/// # Returns
90	/// Result containing the DTO or validation error
91	pub fn New(
92		Handle:String,
93		ViewType:String,
94		Title:String,
95		ContentOptions:WebviewContentOptionsDTO,
96		PanelOptions:Value,
97		SideCarIdentifier:String,
98		ExtensionIdentifier:String,
99	) -> Result<Self, String> {
100		// Validate handle length
101		if Handle.len() > MAX_HANDLE_LENGTH {
102			return Err(format!("Handle exceeds maximum length of {} bytes", MAX_HANDLE_LENGTH));
103		}
104
105		// Validate view type length
106		if ViewType.len() > MAX_VIEW_TYPE_LENGTH {
107			return Err(format!("ViewType exceeds maximum length of {} bytes", MAX_VIEW_TYPE_LENGTH));
108		}
109
110		// Validate title length
111		if Title.len() > MAX_TITLE_LENGTH {
112			return Err(format!("Title exceeds maximum length of {} bytes", MAX_TITLE_LENGTH));
113		}
114
115		// Validate sidecar identifier length
116		if SideCarIdentifier.len() > MAX_SIDECAR_IDENTIFIER_LENGTH {
117			return Err(format!(
118				"SideCar identifier exceeds maximum length of {} bytes",
119				MAX_SIDECAR_IDENTIFIER_LENGTH
120			));
121		}
122
123		// Validate extension identifier length
124		if ExtensionIdentifier.len() > MAX_EXTENSION_IDENTIFIER_LENGTH {
125			return Err(format!(
126				"Extension identifier exceeds maximum length of {} bytes",
127				MAX_EXTENSION_IDENTIFIER_LENGTH
128			));
129		}
130
131		Ok(Self {
132			Handle,
133			ViewType,
134			Title,
135			ContentOptions,
136			PanelOptions,
137			SideCarIdentifier,
138			ExtensionIdentifier,
139			IsActive:false,
140			IsVisible:false,
141		})
142	}
143
144	/// Updates the focus state of the Webview.
145	///
146	/// # Arguments
147	/// * `IsActive` - New focus state
148	pub fn SetFocus(&mut self, IsActive:bool) { self.IsActive = IsActive; }
149
150	/// Updates the visibility state of the Webview.
151	///
152	/// # Arguments
153	/// * `IsVisible` - New visibility state
154	pub fn SetVisibility(&mut self, IsVisible:bool) { self.IsVisible = IsVisible; }
155
156	/// Updates the Webview title with validation.
157	///
158	/// # Arguments
159	/// * `Title` - New title
160	///
161	/// # Returns
162	/// Result indicating success or error if title too long
163	pub fn UpdateTitle(&mut self, Title:String) -> Result<(), String> {
164		if Title.len() > MAX_TITLE_LENGTH {
165			return Err(format!("Title exceeds maximum length of {} bytes", MAX_TITLE_LENGTH));
166		}
167
168		self.Title = Title;
169		Ok(())
170	}
171
172	/// Checks if the Webview is currently displayed (visible and focused).
173	pub fn IsDisplayed(&self) -> bool { self.IsVisible || self.IsActive }
174}