fix: show only enabled datasource & MCP list (#523)

* fix: show only enabled datasource & MCP list

* docs: update notes

* fix: show only enabled datasource & MCP list
This commit is contained in:
BiggerRain
2025-05-17 12:01:18 +08:00
committed by GitHub
parent 7f3e602bb3
commit 91c9cd5725
8 changed files with 132 additions and 115 deletions

View File

@@ -13,6 +13,7 @@
"elif",
"errmsg",
"fullscreen",
"fulltext",
"headlessui",
"Icdbb",
"icns",

View File

@@ -32,6 +32,7 @@ Information about release notes of Coco Server is provided here.
- fix: fixed the newly created session has no title when it is deleted #511
- fix: loading chat history for potential empty attachments
- fix: datasource & MCP list synchronization update #521
- fix: show only enabled datasource & MCP list
### ✈️ Improvements

View File

@@ -26,7 +26,7 @@ pub async fn get_response_body_text(response: Response) -> Result<String, String
.await
.map_err(|e| format!("Failed to read response body: {}, code: {}", e, status))?;
log::debug!("Response status: {}, body: {}", status, &body);
//log::debug!("Response status: {}, body: {}", status, &body);
if status < 200 || status >= 400 {
// Try to parse the error body

View File

@@ -210,7 +210,7 @@ pub fn run() {
})
.on_window_event(|window, event| match event {
WindowEvent::CloseRequested { api, .. } => {
dbg!("Close requested event received");
//dbg!("Close requested event received");
window.hide().unwrap();
api.prevent_close();
}
@@ -225,10 +225,10 @@ pub fn run() {
has_visible_windows,
..
} => {
dbg!(
"Reopen event received: has_visible_windows = {}",
has_visible_windows
);
// dbg!(
// "Reopen event received: has_visible_windows = {}",
// has_visible_windows
// );
if has_visible_windows {
return;
}
@@ -289,7 +289,7 @@ async fn hide_coco<R: Runtime>(app: AppHandle<R>) {
}
fn move_window_to_active_monitor<R: Runtime>(window: &Window<R>) {
dbg!("Moving window to active monitor");
//dbg!("Moving window to active monitor");
// Try to get the available monitors, handle failure gracefully
let available_monitors = match window.available_monitors() {
Ok(monitors) => monitors,

View File

@@ -4,6 +4,7 @@ use crate::server::connector::get_connector_by_id;
use crate::server::http_client::HttpClient;
use crate::server::servers::get_all_servers;
use lazy_static::lazy_static;
use serde_json::Value;
use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use tauri::{AppHandle, Runtime};
@@ -12,7 +13,7 @@ use tauri::{AppHandle, Runtime};
pub struct GetDatasourcesByServerOptions {
pub from: Option<u32>,
pub size: Option<u32>,
pub query: Option<String>,
pub query: Option<serde_json::Value>,
}
lazy_static! {
@@ -32,7 +33,7 @@ pub fn save_datasource_to_cache(server_id: &str, datasources: Vec<DataSource>) {
#[allow(dead_code)]
pub fn get_datasources_from_cache(server_id: &str) -> Option<HashMap<String, DataSource>> {
let cache = DATASOURCE_CACHE.read().unwrap(); // Acquire read lock
// dbg!("cache: {:?}", &cache);
// dbg!("cache: {:?}", &cache);
let server_cache = cache.get(server_id)?; // Get the server's cache
Some(server_cache.clone())
}
@@ -100,31 +101,14 @@ pub async fn datasource_search(
) -> Result<Vec<DataSource>, String> {
let from = options.as_ref().and_then(|opt| opt.from).unwrap_or(0);
let size = options.as_ref().and_then(|opt| opt.size).unwrap_or(10000);
let query = options
.and_then(|opt| opt.query)
.unwrap_or(String::default());
let mut body = serde_json::json!({
"from": from,
"size": size,
});
if !query.is_empty() {
body["query"] = serde_json::json!({
"bool": {
"must": [{
"query_string": {
"fields": ["combined_fulltext"],
"query": query,
"fuzziness": "AUTO",
"fuzzy_prefix_length": 2,
"fuzzy_max_expansions": 10,
"fuzzy_transpositions": true,
"allow_leading_wildcard": false
}
}]
}
});
if let Some(q) = options.unwrap().query {
body["query"] = q;
}
// Perform the async HTTP request outside the cache lock
@@ -134,12 +118,12 @@ pub async fn datasource_search(
None,
Some(reqwest::Body::from(body.to_string())),
)
.await
.map_err(|e| format!("Error fetching datasource: {}", e))?;
.await
.map_err(|e| format!("Error fetching datasource: {}", e))?;
// Parse the search results from the response
let datasources: Vec<DataSource> = parse_search_results(resp).await.map_err(|e| {
dbg!("Error parsing search results: {}", &e);
//dbg!("Error parsing search results: {}", &e);
e.to_string()
})?;
@@ -152,35 +136,17 @@ pub async fn datasource_search(
#[tauri::command]
pub async fn mcp_server_search(
id: &str,
options: Option<GetDatasourcesByServerOptions>,
from: u32,
size: u32,
query: Option<HashMap<String, Value>>,
) -> Result<Vec<DataSource>, String> {
let from = options.as_ref().and_then(|opt| opt.from).unwrap_or(0);
let size = options.as_ref().and_then(|opt| opt.size).unwrap_or(10000);
let query = options
.and_then(|opt| opt.query)
.unwrap_or(String::default());
let mut body = serde_json::json!({
"from": from,
"size": size,
"from": from,
"size": size,
});
if !query.is_empty() {
body["query"] = serde_json::json!({
"bool": {
"must": [{
"query_string": {
"fields": ["combined_fulltext"],
"query": query,
"fuzziness": "AUTO",
"fuzzy_prefix_length": 2,
"fuzzy_max_expansions": 10,
"fuzzy_transpositions": true,
"allow_leading_wildcard": false
}
}]
}
});
if let Some(q) = query {
body["query"] = serde_json::to_value(q).map_err(|e| e.to_string())?;
}
// Perform the async HTTP request outside the cache lock
@@ -190,12 +156,12 @@ pub async fn mcp_server_search(
None,
Some(reqwest::Body::from(body.to_string())),
)
.await
.map_err(|e| format!("Error fetching datasource: {}", e))?;
.await
.map_err(|e| format!("Error fetching datasource: {}", e))?;
// Parse the search results from the response
let mcp_server: Vec<DataSource> = parse_search_results(resp).await.map_err(|e| {
dbg!("Error parsing search results: {}", &e);
//dbg!("Error parsing search results: {}", &e);
e.to_string()
})?;

View File

@@ -44,28 +44,28 @@ impl HttpClient {
headers: Option<HashMap<String, String>>,
body: Option<reqwest::Body>,
) -> Result<reqwest::Response, String> {
log::debug!(
"Sending Request: {}, query_params: {:?}, header: {:?}, body: {:?}",
&url,
&query_params,
&headers,
&body
);
// log::debug!(
// "Sending Request: {}, query_params: {:?}, header: {:?}, body: {:?}",
// &url,
// &query_params,
// &headers,
// &body
// );
let request_builder =
Self::get_request_builder(method, url, headers, query_params, body).await;
let response = request_builder.send().await.map_err(|e| {
dbg!("Failed to send request: {}", &e);
//dbg!("Failed to send request: {}", &e);
format!("Failed to send request: {}", e)
})?;
log::debug!(
"Request: {}, Response status: {:?}, header: {:?}",
&url,
&response.status(),
&response.headers()
);
// log::debug!(
// "Request: {}, Response status: {:?}, header: {:?}",
// &url,
// &response.status(),
// &response.headers()
// );
Ok(response)
}
@@ -165,12 +165,12 @@ impl HttpClient {
headers.insert("X-API-TOKEN".to_string(), t);
}
log::debug!(
"Sending request to server: {}, url: {}, headers: {:?}",
&server_id,
&url,
&headers
);
// log::debug!(
// "Sending request to server: {}, url: {}, headers: {:?}",
// &server_id,
// &url,
// &headers
// );
Self::send_raw_request(method, &url, query_params, Some(headers), body).await
} else {

View File

@@ -82,34 +82,31 @@ export function AssistantList({ assistantIDs = [] }: AssistantListProps) {
size,
};
if (debounceKeyword || assistantIDs.length > 0) {
body.query = {
bool: {
must: [
{term: {"enabled": true}}
],
body.query = {
bool: {
must: [{ term: { enabled: true } }],
},
};
if (debounceKeyword) {
body.query.bool.must.push({
query_string: {
fields: ["combined_fulltext"],
query: debounceKeyword,
fuzziness: "AUTO",
fuzzy_prefix_length: 2,
fuzzy_max_expansions: 10,
fuzzy_transpositions: true,
allow_leading_wildcard: false,
},
};
if (debounceKeyword) {
body.query.bool.must.push({
query_string: {
fields: ["combined_fulltext"],
query: debounceKeyword,
fuzziness: "AUTO",
fuzzy_prefix_length: 2,
fuzzy_max_expansions: 10,
fuzzy_transpositions: true,
allow_leading_wildcard: false,
},
});
}
if (assistantIDs.length > 0) {
body.query.bool.must.push({
terms: {
id: assistantIDs.map((id) => id),
},
});
}
});
}
if (assistantIDs.length > 0) {
body.query.bool.must.push({
terms: {
id: assistantIDs.map((id) => id),
},
});
}
if (isTauri) {

View File

@@ -23,7 +23,7 @@ import platformAdapter from "@/utils/platformAdapter";
import { useStartupStore } from "@/stores/startupStore";
import { DataSource } from "@/types/commands";
import { useThemeStore } from "@/stores/themeStore";
import { Get } from "@/api/axiosRequest";
import { Post } from "@/api/axiosRequest";
import { useConnectStore } from "@/stores/connectStore";
import { useAppearanceStore } from "@/stores/appearanceStore";
@@ -217,14 +217,41 @@ function SearchChat({
) {
return [];
}
const body: Record<string, any> = {
id: serverId,
from: options?.from || 0,
size: options?.size || 1000,
};
body.query = {
bool: {
must: [{ term: { enabled: true } }],
},
};
if (options?.query) {
body.query.bool.must.push({
query_string: {
fields: ["combined_fulltext"],
query: options?.query,
fuzziness: "AUTO",
fuzzy_prefix_length: 2,
fuzzy_max_expansions: 10,
fuzzy_transpositions: true,
allow_leading_wildcard: false,
},
});
}
let response: any;
if (isTauri) {
response = await platformAdapter.invokeBackend("datasource_search", {
id: serverId,
options,
options: body,
});
} else {
const [error, res]: any = await Get("/datasource/_search");
const [error, res]: any = await Post("/datasource/_search", body);
if (error) {
console.error("_search", error);
return [];
@@ -258,14 +285,39 @@ function SearchChat({
if (!(assistantConfig.mcpEnabled && assistantConfig.mcpVisible)) {
return [];
}
const body: Record<string, any> = {
id: serverId,
from: options?.from || 0,
size: options?.size || 1000,
};
body.query = {
bool: {
must: [{ term: { enabled: true } }],
},
};
if (options?.query) {
body.query.bool.must.push({
query_string: {
fields: ["combined_fulltext"],
query: options?.query,
fuzziness: "AUTO",
fuzzy_prefix_length: 2,
fuzzy_max_expansions: 10,
fuzzy_transpositions: true,
allow_leading_wildcard: false,
},
});
}
let response: any;
if (isTauri) {
response = await platformAdapter.invokeBackend("mcp_server_search", {
id: serverId,
options,
});
response = await platformAdapter.invokeBackend(
"mcp_server_search",
body
);
} else {
const [error, res]: any = await Get("/mcp_server/_search");
const [error, res]: any = await Post("/mcp_server/_search", body);
if (error) {
console.error("_search", error);
return [];