mirror of
https://github.com/infinilabs/coco-app.git
synced 2025-12-16 03:27:43 +01:00
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:
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
@@ -13,6 +13,7 @@
|
|||||||
"elif",
|
"elif",
|
||||||
"errmsg",
|
"errmsg",
|
||||||
"fullscreen",
|
"fullscreen",
|
||||||
|
"fulltext",
|
||||||
"headlessui",
|
"headlessui",
|
||||||
"Icdbb",
|
"Icdbb",
|
||||||
"icns",
|
"icns",
|
||||||
|
|||||||
@@ -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: fixed the newly created session has no title when it is deleted #511
|
||||||
- fix: loading chat history for potential empty attachments
|
- fix: loading chat history for potential empty attachments
|
||||||
- fix: datasource & MCP list synchronization update #521
|
- fix: datasource & MCP list synchronization update #521
|
||||||
|
- fix: show only enabled datasource & MCP list
|
||||||
|
|
||||||
### ✈️ Improvements
|
### ✈️ Improvements
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ pub async fn get_response_body_text(response: Response) -> Result<String, String
|
|||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Failed to read response body: {}, code: {}", e, status))?;
|
.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 {
|
if status < 200 || status >= 400 {
|
||||||
// Try to parse the error body
|
// Try to parse the error body
|
||||||
@@ -49,4 +49,4 @@ pub async fn get_response_body_text(response: Response) -> Result<String, String
|
|||||||
} else {
|
} else {
|
||||||
Ok(body)
|
Ok(body)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -210,7 +210,7 @@ pub fn run() {
|
|||||||
})
|
})
|
||||||
.on_window_event(|window, event| match event {
|
.on_window_event(|window, event| match event {
|
||||||
WindowEvent::CloseRequested { api, .. } => {
|
WindowEvent::CloseRequested { api, .. } => {
|
||||||
dbg!("Close requested event received");
|
//dbg!("Close requested event received");
|
||||||
window.hide().unwrap();
|
window.hide().unwrap();
|
||||||
api.prevent_close();
|
api.prevent_close();
|
||||||
}
|
}
|
||||||
@@ -225,10 +225,10 @@ pub fn run() {
|
|||||||
has_visible_windows,
|
has_visible_windows,
|
||||||
..
|
..
|
||||||
} => {
|
} => {
|
||||||
dbg!(
|
// dbg!(
|
||||||
"Reopen event received: has_visible_windows = {}",
|
// "Reopen event received: has_visible_windows = {}",
|
||||||
has_visible_windows
|
// has_visible_windows
|
||||||
);
|
// );
|
||||||
if has_visible_windows {
|
if has_visible_windows {
|
||||||
return;
|
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>) {
|
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
|
// Try to get the available monitors, handle failure gracefully
|
||||||
let available_monitors = match window.available_monitors() {
|
let available_monitors = match window.available_monitors() {
|
||||||
Ok(monitors) => monitors,
|
Ok(monitors) => monitors,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ use crate::server::connector::get_connector_by_id;
|
|||||||
use crate::server::http_client::HttpClient;
|
use crate::server::http_client::HttpClient;
|
||||||
use crate::server::servers::get_all_servers;
|
use crate::server::servers::get_all_servers;
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
|
use serde_json::Value;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use tauri::{AppHandle, Runtime};
|
use tauri::{AppHandle, Runtime};
|
||||||
@@ -12,7 +13,7 @@ use tauri::{AppHandle, Runtime};
|
|||||||
pub struct GetDatasourcesByServerOptions {
|
pub struct GetDatasourcesByServerOptions {
|
||||||
pub from: Option<u32>,
|
pub from: Option<u32>,
|
||||||
pub size: Option<u32>,
|
pub size: Option<u32>,
|
||||||
pub query: Option<String>,
|
pub query: Option<serde_json::Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
@@ -32,7 +33,7 @@ pub fn save_datasource_to_cache(server_id: &str, datasources: Vec<DataSource>) {
|
|||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn get_datasources_from_cache(server_id: &str) -> Option<HashMap<String, DataSource>> {
|
pub fn get_datasources_from_cache(server_id: &str) -> Option<HashMap<String, DataSource>> {
|
||||||
let cache = DATASOURCE_CACHE.read().unwrap(); // Acquire read lock
|
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
|
let server_cache = cache.get(server_id)?; // Get the server's cache
|
||||||
Some(server_cache.clone())
|
Some(server_cache.clone())
|
||||||
}
|
}
|
||||||
@@ -100,31 +101,14 @@ pub async fn datasource_search(
|
|||||||
) -> Result<Vec<DataSource>, String> {
|
) -> Result<Vec<DataSource>, String> {
|
||||||
let from = options.as_ref().and_then(|opt| opt.from).unwrap_or(0);
|
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 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!({
|
let mut body = serde_json::json!({
|
||||||
"from": from,
|
"from": from,
|
||||||
"size": size,
|
"size": size,
|
||||||
});
|
});
|
||||||
|
|
||||||
if !query.is_empty() {
|
if let Some(q) = options.unwrap().query {
|
||||||
body["query"] = serde_json::json!({
|
body["query"] = q;
|
||||||
"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
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the async HTTP request outside the cache lock
|
// Perform the async HTTP request outside the cache lock
|
||||||
@@ -134,12 +118,12 @@ pub async fn datasource_search(
|
|||||||
None,
|
None,
|
||||||
Some(reqwest::Body::from(body.to_string())),
|
Some(reqwest::Body::from(body.to_string())),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Error fetching datasource: {}", e))?;
|
.map_err(|e| format!("Error fetching datasource: {}", e))?;
|
||||||
|
|
||||||
// Parse the search results from the response
|
// Parse the search results from the response
|
||||||
let datasources: Vec<DataSource> = parse_search_results(resp).await.map_err(|e| {
|
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()
|
e.to_string()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
@@ -152,35 +136,17 @@ pub async fn datasource_search(
|
|||||||
#[tauri::command]
|
#[tauri::command]
|
||||||
pub async fn mcp_server_search(
|
pub async fn mcp_server_search(
|
||||||
id: &str,
|
id: &str,
|
||||||
options: Option<GetDatasourcesByServerOptions>,
|
from: u32,
|
||||||
|
size: u32,
|
||||||
|
query: Option<HashMap<String, Value>>,
|
||||||
) -> Result<Vec<DataSource>, String> {
|
) -> 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!({
|
let mut body = serde_json::json!({
|
||||||
"from": from,
|
"from": from,
|
||||||
"size": size,
|
"size": size,
|
||||||
});
|
});
|
||||||
|
|
||||||
if !query.is_empty() {
|
if let Some(q) = query {
|
||||||
body["query"] = serde_json::json!({
|
body["query"] = serde_json::to_value(q).map_err(|e| e.to_string())?;
|
||||||
"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
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Perform the async HTTP request outside the cache lock
|
// Perform the async HTTP request outside the cache lock
|
||||||
@@ -190,12 +156,12 @@ pub async fn mcp_server_search(
|
|||||||
None,
|
None,
|
||||||
Some(reqwest::Body::from(body.to_string())),
|
Some(reqwest::Body::from(body.to_string())),
|
||||||
)
|
)
|
||||||
.await
|
.await
|
||||||
.map_err(|e| format!("Error fetching datasource: {}", e))?;
|
.map_err(|e| format!("Error fetching datasource: {}", e))?;
|
||||||
|
|
||||||
// Parse the search results from the response
|
// Parse the search results from the response
|
||||||
let mcp_server: Vec<DataSource> = parse_search_results(resp).await.map_err(|e| {
|
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()
|
e.to_string()
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
|||||||
@@ -44,28 +44,28 @@ impl HttpClient {
|
|||||||
headers: Option<HashMap<String, String>>,
|
headers: Option<HashMap<String, String>>,
|
||||||
body: Option<reqwest::Body>,
|
body: Option<reqwest::Body>,
|
||||||
) -> Result<reqwest::Response, String> {
|
) -> Result<reqwest::Response, String> {
|
||||||
log::debug!(
|
// log::debug!(
|
||||||
"Sending Request: {}, query_params: {:?}, header: {:?}, body: {:?}",
|
// "Sending Request: {}, query_params: {:?}, header: {:?}, body: {:?}",
|
||||||
&url,
|
// &url,
|
||||||
&query_params,
|
// &query_params,
|
||||||
&headers,
|
// &headers,
|
||||||
&body
|
// &body
|
||||||
);
|
// );
|
||||||
|
|
||||||
let request_builder =
|
let request_builder =
|
||||||
Self::get_request_builder(method, url, headers, query_params, body).await;
|
Self::get_request_builder(method, url, headers, query_params, body).await;
|
||||||
|
|
||||||
let response = request_builder.send().await.map_err(|e| {
|
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)
|
format!("Failed to send request: {}", e)
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
log::debug!(
|
// log::debug!(
|
||||||
"Request: {}, Response status: {:?}, header: {:?}",
|
// "Request: {}, Response status: {:?}, header: {:?}",
|
||||||
&url,
|
// &url,
|
||||||
&response.status(),
|
// &response.status(),
|
||||||
&response.headers()
|
// &response.headers()
|
||||||
);
|
// );
|
||||||
|
|
||||||
Ok(response)
|
Ok(response)
|
||||||
}
|
}
|
||||||
@@ -165,12 +165,12 @@ impl HttpClient {
|
|||||||
headers.insert("X-API-TOKEN".to_string(), t);
|
headers.insert("X-API-TOKEN".to_string(), t);
|
||||||
}
|
}
|
||||||
|
|
||||||
log::debug!(
|
// log::debug!(
|
||||||
"Sending request to server: {}, url: {}, headers: {:?}",
|
// "Sending request to server: {}, url: {}, headers: {:?}",
|
||||||
&server_id,
|
// &server_id,
|
||||||
&url,
|
// &url,
|
||||||
&headers
|
// &headers
|
||||||
);
|
// );
|
||||||
|
|
||||||
Self::send_raw_request(method, &url, query_params, Some(headers), body).await
|
Self::send_raw_request(method, &url, query_params, Some(headers), body).await
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -82,34 +82,31 @@ export function AssistantList({ assistantIDs = [] }: AssistantListProps) {
|
|||||||
size,
|
size,
|
||||||
};
|
};
|
||||||
|
|
||||||
if (debounceKeyword || assistantIDs.length > 0) {
|
body.query = {
|
||||||
body.query = {
|
bool: {
|
||||||
bool: {
|
must: [{ term: { enabled: true } }],
|
||||||
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({
|
if (assistantIDs.length > 0) {
|
||||||
query_string: {
|
body.query.bool.must.push({
|
||||||
fields: ["combined_fulltext"],
|
terms: {
|
||||||
query: debounceKeyword,
|
id: assistantIDs.map((id) => id),
|
||||||
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 (isTauri) {
|
if (isTauri) {
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import platformAdapter from "@/utils/platformAdapter";
|
|||||||
import { useStartupStore } from "@/stores/startupStore";
|
import { useStartupStore } from "@/stores/startupStore";
|
||||||
import { DataSource } from "@/types/commands";
|
import { DataSource } from "@/types/commands";
|
||||||
import { useThemeStore } from "@/stores/themeStore";
|
import { useThemeStore } from "@/stores/themeStore";
|
||||||
import { Get } from "@/api/axiosRequest";
|
import { Post } from "@/api/axiosRequest";
|
||||||
import { useConnectStore } from "@/stores/connectStore";
|
import { useConnectStore } from "@/stores/connectStore";
|
||||||
import { useAppearanceStore } from "@/stores/appearanceStore";
|
import { useAppearanceStore } from "@/stores/appearanceStore";
|
||||||
|
|
||||||
@@ -217,14 +217,41 @@ function SearchChat({
|
|||||||
) {
|
) {
|
||||||
return [];
|
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;
|
let response: any;
|
||||||
if (isTauri) {
|
if (isTauri) {
|
||||||
response = await platformAdapter.invokeBackend("datasource_search", {
|
response = await platformAdapter.invokeBackend("datasource_search", {
|
||||||
id: serverId,
|
id: serverId,
|
||||||
options,
|
options: body,
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
const [error, res]: any = await Get("/datasource/_search");
|
const [error, res]: any = await Post("/datasource/_search", body);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("_search", error);
|
console.error("_search", error);
|
||||||
return [];
|
return [];
|
||||||
@@ -258,14 +285,39 @@ function SearchChat({
|
|||||||
if (!(assistantConfig.mcpEnabled && assistantConfig.mcpVisible)) {
|
if (!(assistantConfig.mcpEnabled && assistantConfig.mcpVisible)) {
|
||||||
return [];
|
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;
|
let response: any;
|
||||||
if (isTauri) {
|
if (isTauri) {
|
||||||
response = await platformAdapter.invokeBackend("mcp_server_search", {
|
response = await platformAdapter.invokeBackend(
|
||||||
id: serverId,
|
"mcp_server_search",
|
||||||
options,
|
body
|
||||||
});
|
);
|
||||||
} else {
|
} else {
|
||||||
const [error, res]: any = await Get("/mcp_server/_search");
|
const [error, res]: any = await Post("/mcp_server/_search", body);
|
||||||
if (error) {
|
if (error) {
|
||||||
console.error("_search", error);
|
console.error("_search", error);
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
Reference in New Issue
Block a user