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}