|
6 | 6 | //! built-in fallback. The desktop UI tracks which space the user is |
7 | 7 | //! viewing in its own Zustand store (frontend-only state). |
8 | 8 |
|
9 | | -use mcpmux_core::{validate_workspace_root, Space, SpaceBaseDir, WorkspaceRootValidation}; |
| 9 | +use mcpmux_core::{ |
| 10 | + application::UserSpaceSyncService, validate_workspace_root, Space, SpaceBaseDir, |
| 11 | + WorkspaceRootValidation, |
| 12 | +}; |
10 | 13 | use std::sync::Arc; |
11 | 14 | use tauri::{AppHandle, State}; |
12 | 15 | use tokio::sync::RwLock; |
@@ -193,7 +196,28 @@ pub async fn save_space_config( |
193 | 196 | serde_json::from_str::<serde_json::Value>(&content) |
194 | 197 | .map_err(|e| format!("Invalid JSON: {}", e))?; |
195 | 198 |
|
196 | | - std::fs::write(&config_path, content).map_err(|e| format!("Failed to write config file: {}", e)) |
| 199 | + std::fs::write(&config_path, content) |
| 200 | + .map_err(|e| format!("Failed to write config file: {}", e))?; |
| 201 | + |
| 202 | + // Do not rely solely on the debounced file watcher. The UI reloads immediately |
| 203 | + // after this command returns, so sync the just-saved file into InstalledServer |
| 204 | + // records synchronously to avoid stale/missing custom-server state. |
| 205 | + let sync_service = UserSpaceSyncService::new(state.installed_server_repository.clone()); |
| 206 | + let sync_result = sync_service |
| 207 | + .sync_from_file(&space_id, &config_path) |
| 208 | + .await |
| 209 | + .map_err(|e| format!("Failed to sync custom server config: {}", e))?; |
| 210 | + |
| 211 | + if sync_result.has_changes() { |
| 212 | + info!( |
| 213 | + "[save_space_config] Synced custom server config: {} added, {} updated, {} removed", |
| 214 | + sync_result.added.len(), |
| 215 | + sync_result.updated.len(), |
| 216 | + sync_result.removed.len() |
| 217 | + ); |
| 218 | + } |
| 219 | + |
| 220 | + Ok(()) |
197 | 221 | } |
198 | 222 |
|
199 | 223 | /// Remove a server from the space configuration file |
|
0 commit comments