Skip to main content

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 = "camelCase")]
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
94		ViewType:String,
95
96		Title:String,
97
98		ContentOptions:WebviewContentOptionsDTO,
99
100		PanelOptions:Value,
101
102		SideCarIdentifier:String,
103
104		ExtensionIdentifier:String,
105	) -> Result<Self, String> {
106		// Validate handle length
107		if Handle.len() > MAX_HANDLE_LENGTH {
108			return Err(format!("Handle exceeds maximum length of {} bytes", MAX_HANDLE_LENGTH));
109		}
110
111		// Validate view type length
112		if ViewType.len() > MAX_VIEW_TYPE_LENGTH {
113			return Err(format!("ViewType exceeds maximum length of {} bytes", MAX_VIEW_TYPE_LENGTH));
114		}
115
116		// Validate title length
117		if Title.len() > MAX_TITLE_LENGTH {
118			return Err(format!("Title exceeds maximum length of {} bytes", MAX_TITLE_LENGTH));
119		}
120
121		// Validate sidecar identifier length
122		if SideCarIdentifier.len() > MAX_SIDECAR_IDENTIFIER_LENGTH {
123			return Err(format!(
124				"SideCar identifier exceeds maximum length of {} bytes",
125				MAX_SIDECAR_IDENTIFIER_LENGTH
126			));
127		}
128
129		// Validate extension identifier length
130		if ExtensionIdentifier.len() > MAX_EXTENSION_IDENTIFIER_LENGTH {
131			return Err(format!(
132				"Extension identifier exceeds maximum length of {} bytes",
133				MAX_EXTENSION_IDENTIFIER_LENGTH
134			));
135		}
136
137		Ok(Self {
138			Handle,
139			ViewType,
140			Title,
141			ContentOptions,
142			PanelOptions,
143			SideCarIdentifier,
144			ExtensionIdentifier,
145			IsActive:false,
146			IsVisible:false,
147		})
148	}
149
150	/// Updates the focus state of the Webview.
151	///
152	/// # Arguments
153	/// * `IsActive` - New focus state
154	pub fn SetFocus(&mut self, IsActive:bool) { self.IsActive = IsActive; }
155
156	/// Updates the visibility state of the Webview.
157	///
158	/// # Arguments
159	/// * `IsVisible` - New visibility state
160	pub fn SetVisibility(&mut self, IsVisible:bool) { self.IsVisible = IsVisible; }
161
162	/// Updates the Webview title with validation.
163	///
164	/// # Arguments
165	/// * `Title` - New title
166	///
167	/// # Returns
168	/// Result indicating success or error if title too long
169	pub fn UpdateTitle(&mut self, Title:String) -> Result<(), String> {
170		if Title.len() > MAX_TITLE_LENGTH {
171			return Err(format!("Title exceeds maximum length of {} bytes", MAX_TITLE_LENGTH));
172		}
173
174		self.Title = Title;
175
176		Ok(())
177	}
178
179	/// Checks if the Webview is currently displayed (visible and focused).
180	pub fn IsDisplayed(&self) -> bool { self.IsVisible || self.IsActive }
181}