Skip to main content

Mountain/Track/Effect/CreateEffectForRequest/
StatusBar.rs

1//! # StatusBar Effect (CreateEffectForRequest)
2//!
3//! Effect constructors for status bar RPC methods from the Cocoon extension
4//! host. Delegates to the `StatusBarProvider` trait on `MountainEnvironment`.
5//!
6//! ## Methods handled
7//!
8//! | Method | Description |
9//! |---|---|
10//! | `$statusBar:set` | Create or update a status bar entry |
11//! | `$statusBar:dispose` | Remove a status bar entry by ID |
12//! | `$setStatusBarMessage` | Set a simple text message in the status bar |
13//! | `$disposeStatusBarMessage` | Remove a status bar message by ID |
14
15use std::sync::Arc;
16
17use CommonLibrary::{
18	Environment::Requires::Requires,
19	StatusBar::{DTO::StatusBarEntryDTO::StatusBarEntryDTO, StatusBarProvider::StatusBarProvider},
20};
21use serde_json::{Value, json};
22use tauri::Runtime;
23
24use crate::Track::Effect::{
25	CreateEffectForRequest::Utilities::Params::{obj_bool, obj_f64, obj_str, string_at},
26	MappedEffectType::MappedEffect,
27};
28
29pub fn CreateEffect<R:Runtime>(MethodName:&str, Parameters:Value) -> Option<Result<MappedEffect, String>> {
30	match MethodName {
31		"$statusBar:set" => {
32			crate::effect!(run_time, {
33				let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
34
35				// The extension host serialises this as an object with named fields,
36				// matching the shape used by the RPC layer (EntryIdentifier = id).
37				let entry_id = Parameters
38					.get("id")
39					.and_then(Value::as_str)
40					.ok_or_else(|| "$statusBar:set: missing 'id' field".to_string())?;
41
42				let item_id = Parameters.get("itemId").and_then(Value::as_str).unwrap_or(entry_id);
43
44				let ext_id = obj_str(&Parameters, "extensionId");
45
46				let text = obj_str(&Parameters, "text").to_string();
47
48				let tooltip = Parameters.get("tooltip").cloned();
49
50				let command = Parameters.get("command").cloned();
51
52				let color = Parameters.get("color").cloned();
53
54				let background_color = Parameters.get("backgroundColor").cloned();
55
56				let is_aligned_left = obj_bool(&Parameters, "alignLeft");
57
58				let priority = obj_f64(&Parameters, "priority");
59
60				let accessibility = Parameters.get("accessibilityInformation").cloned();
61
62				let entry = StatusBarEntryDTO {
63					EntryIdentifier:entry_id.to_string(),
64					ItemIdentifier:item_id.to_string(),
65					ExtensionIdentifier:ext_id.to_string(),
66					Name:None,
67					Text:text,
68					Tooltip:tooltip,
69					HasTooltipProvider:false,
70					Command:command,
71					Color:color,
72					BackgroundColor:background_color,
73					IsAlignedLeft:is_aligned_left,
74					Priority:priority,
75					AccessibilityInformation:accessibility,
76				};
77
78				provider
79					.SetStatusBarEntry(entry)
80					.await
81					.map(|_| json!(null))
82					.map_err(|e| e.to_string())
83			})
84		},
85
86		"$statusBar:dispose" => {
87			crate::effect!(run_time, {
88				let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
89
90				// Require a non-empty id - a missing id would silently target the
91				// wrong entry (previously fell back to the literal string "id").
92				let id = Parameters
93					.get(0)
94					.and_then(Value::as_str)
95					.filter(|s| !s.is_empty())
96					.ok_or_else(|| "$statusBar:dispose: missing or empty entry id".to_string())?;
97
98				provider
99					.DisposeStatusBarEntry(id.to_string())
100					.await
101					.map(|_| json!(null))
102					.map_err(|e| e.to_string())
103			})
104		},
105
106		// Cocoon's `Window/Status/Bar.ts` sends `setStatusBarText` as a
107		// fire-and-forget notification when an extension's StatusBarItem
108		// text mutates (`set text(...)`). It carries `{ itemId, text }`
109		// only - the rest of the entry (id, alignment, priority, etc.)
110		// was set when the item was first created. Forward to the
111		// StatusBarProvider's text-only mutation path. Without this arm,
112		// status bar text never updates after the initial create.
113		"setStatusBarText" => {
114			crate::effect!(run_time, {
115				let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
116
117				let item_id = obj_str(&Parameters, "itemId");
118
119				if item_id.is_empty() {
120					return Err("setStatusBarText: missing 'itemId' field".to_string());
121				}
122
123				let text = obj_str(&Parameters, "text").to_string();
124
125				// Re-use the text-only message path (same semantics as
126				// `$setStatusBarMessage`). The item lives under itemId
127				// from the prior `$statusBar:set` registration.
128				provider
129					.SetStatusBarMessage(item_id.to_string(), text)
130					.await
131					.map(|_| json!(null))
132					.map_err(|e| e.to_string())
133			})
134		},
135
136		"$setStatusBarMessage" => {
137			crate::effect!(run_time, {
138				let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
139
140				let message_id = Parameters
141					.get(0)
142					.and_then(Value::as_str)
143					.filter(|s| !s.is_empty())
144					.ok_or_else(|| "$setStatusBarMessage: missing or empty message id".to_string())?;
145
146				let text = string_at(&Parameters, 1);
147
148				provider
149					.SetStatusBarMessage(message_id.to_string(), text)
150					.await
151					.map(|_| json!(null))
152					.map_err(|e| e.to_string())
153			})
154		},
155
156		"$disposeStatusBarMessage" => {
157			crate::effect!(run_time, {
158				let provider:Arc<dyn StatusBarProvider> = run_time.Environment.Require();
159
160				let message_id = Parameters
161					.get(0)
162					.and_then(Value::as_str)
163					.filter(|s| !s.is_empty())
164					.ok_or_else(|| "$disposeStatusBarMessage: missing or empty message id".to_string())?;
165
166				provider
167					.DisposeStatusBarMessage(message_id.to_string())
168					.await
169					.map(|_| json!(null))
170					.map_err(|e| e.to_string())
171			})
172		},
173
174		_ => None,
175	}
176}