feat: add unified Settings sheet, MCP indicator, and Docker host config
- Add AppSettingsSheet (gear icon in Toolbar) with MCP, Docker, and AI sections - MCP Server: toggle on/off, port config, status badge, endpoint URL with copy - Docker: local/remote daemon selector with remote URL input - AI: moved Ollama settings into the unified sheet - MCP status probes actual TCP port for reliable running detection - Docker commands respect configurable docker host (-H flag) for remote daemons - MCP server supports graceful shutdown via tokio watch channel - Settings persisted to app_settings.json alongside existing config files - StatusBar shows MCP indicator (green/gray dot) with tooltip Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,7 @@ mod models;
|
||||
mod state;
|
||||
mod utils;
|
||||
|
||||
use models::settings::{AppSettings, DockerHost};
|
||||
use state::AppState;
|
||||
use std::sync::Arc;
|
||||
use tauri::Manager;
|
||||
@@ -24,12 +25,52 @@ pub fn run() {
|
||||
.expect("failed to resolve app data dir")
|
||||
.join("connections.json");
|
||||
|
||||
tauri::async_runtime::spawn(async move {
|
||||
if let Err(e) = mcp::start_mcp_server(state, connections_path, 9427).await {
|
||||
log::error!("MCP server error: {}", e);
|
||||
}
|
||||
// Read app settings
|
||||
let settings_path = app
|
||||
.path()
|
||||
.app_data_dir()
|
||||
.expect("failed to resolve app data dir")
|
||||
.join("app_settings.json");
|
||||
|
||||
let settings = if settings_path.exists() {
|
||||
std::fs::read_to_string(&settings_path)
|
||||
.ok()
|
||||
.and_then(|data| serde_json::from_str::<AppSettings>(&data).ok())
|
||||
.unwrap_or_default()
|
||||
} else {
|
||||
AppSettings::default()
|
||||
};
|
||||
|
||||
// Apply docker host from settings
|
||||
let docker_host = match settings.docker.host {
|
||||
DockerHost::Remote => settings.docker.remote_url.clone(),
|
||||
DockerHost::Local => None,
|
||||
};
|
||||
|
||||
let mcp_enabled = settings.mcp.enabled;
|
||||
let mcp_port = settings.mcp.port;
|
||||
|
||||
// Set docker host synchronously (state is fresh, no contention)
|
||||
let state_for_setup = state.clone();
|
||||
tauri::async_runtime::block_on(async {
|
||||
*state_for_setup.docker_host.write().await = docker_host;
|
||||
});
|
||||
|
||||
if mcp_enabled {
|
||||
let shutdown_rx = state.mcp_shutdown_tx.subscribe();
|
||||
let mcp_state = state.clone();
|
||||
tauri::async_runtime::spawn(async move {
|
||||
*mcp_state.mcp_running.write().await = true;
|
||||
if let Err(e) =
|
||||
mcp::start_mcp_server(mcp_state.clone(), connections_path, mcp_port, shutdown_rx)
|
||||
.await
|
||||
{
|
||||
log::error!("MCP server error: {}", e);
|
||||
}
|
||||
*mcp_state.mcp_running.write().await = false;
|
||||
});
|
||||
}
|
||||
|
||||
Ok(())
|
||||
})
|
||||
.invoke_handler(tauri::generate_handler![
|
||||
@@ -107,6 +148,10 @@ pub fn run() {
|
||||
commands::docker::start_container,
|
||||
commands::docker::stop_container,
|
||||
commands::docker::remove_container,
|
||||
// settings
|
||||
commands::settings::get_app_settings,
|
||||
commands::settings::save_app_settings,
|
||||
commands::settings::get_mcp_status,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
Reference in New Issue
Block a user