feat: rag-embedding-ai-chat #1
@@ -307,8 +307,7 @@ pub async fn delete_repository(
|
||||
Extension(agent): AgentExt,
|
||||
Path(id): Path<String>,
|
||||
) -> Result<Json<serde_json::Value>, StatusCode> {
|
||||
let oid =
|
||||
mongodb::bson::oid::ObjectId::parse_str(&id).map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
let oid = mongodb::bson::oid::ObjectId::parse_str(&id).map_err(|_| StatusCode::BAD_REQUEST)?;
|
||||
let db = &agent.db;
|
||||
|
||||
// Delete the repository
|
||||
@@ -333,10 +332,7 @@ pub async fn delete_repository(
|
||||
.await;
|
||||
let _ = db.graph_nodes().delete_many(doc! { "repo_id": &id }).await;
|
||||
let _ = db.graph_edges().delete_many(doc! { "repo_id": &id }).await;
|
||||
let _ = db
|
||||
.graph_builds()
|
||||
.delete_many(doc! { "repo_id": &id })
|
||||
.await;
|
||||
let _ = db.graph_builds().delete_many(doc! { "repo_id": &id }).await;
|
||||
let _ = db
|
||||
.impact_analyses()
|
||||
.delete_many(doc! { "repo_id": &id })
|
||||
|
||||
@@ -244,6 +244,7 @@ pub struct DastFinding {
|
||||
}
|
||||
|
||||
impl DastFinding {
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn new(
|
||||
scan_run_id: String,
|
||||
target_id: String,
|
||||
|
||||
@@ -20,6 +20,12 @@ pub struct Toasts {
|
||||
next_id: Signal<usize>,
|
||||
}
|
||||
|
||||
impl Default for Toasts {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl Toasts {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
|
||||
@@ -65,10 +65,7 @@ pub async fn add_repository(
|
||||
pub async fn delete_repository(repo_id: String) -> Result<(), ServerFnError> {
|
||||
let state: super::server_state::ServerState =
|
||||
dioxus_fullstack::FullstackContext::extract().await?;
|
||||
let url = format!(
|
||||
"{}/api/v1/repositories/{repo_id}",
|
||||
state.agent_api_url
|
||||
);
|
||||
let url = format!("{}/api/v1/repositories/{repo_id}", state.agent_api_url);
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let resp = client
|
||||
|
||||
@@ -2,7 +2,6 @@ use dioxus::prelude::*;
|
||||
|
||||
use crate::app::Route;
|
||||
use crate::components::page_header::PageHeader;
|
||||
use crate::infrastructure::chat::fetch_embedding_status;
|
||||
use crate::infrastructure::repositories::fetch_repositories;
|
||||
|
||||
#[component]
|
||||
|
||||
@@ -49,7 +49,7 @@ pub fn DastFindingsPage() -> Element {
|
||||
}
|
||||
td {
|
||||
Link {
|
||||
to: Route::DastFindingDetailPage { id: id },
|
||||
to: Route::DastFindingDetailPage { id },
|
||||
"{finding.get(\"title\").and_then(|v| v.as_str()).unwrap_or(\"-\")}"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,13 +27,13 @@ pub fn GraphExplorerPage(repo_id: String) -> Element {
|
||||
let mut inspector_open = use_signal(|| false);
|
||||
|
||||
// Search state
|
||||
let mut search_query = use_signal(|| String::new());
|
||||
let mut search_results = use_signal(|| Vec::<serde_json::Value>::new());
|
||||
let mut file_filter = use_signal(|| String::new());
|
||||
let mut search_query = use_signal(String::new);
|
||||
let mut search_results = use_signal(Vec::<serde_json::Value>::new);
|
||||
let mut file_filter = use_signal(String::new);
|
||||
|
||||
// Store serialized graph JSON in signals so use_effect can react to them
|
||||
let mut nodes_json = use_signal(|| String::new());
|
||||
let mut edges_json = use_signal(|| String::new());
|
||||
let mut nodes_json = use_signal(String::new);
|
||||
let mut edges_json = use_signal(String::new);
|
||||
let mut graph_ready = use_signal(|| false);
|
||||
|
||||
// When resource resolves, serialize the data into signals
|
||||
@@ -404,7 +404,7 @@ pub fn GraphExplorerPage(repo_id: String) -> Element {
|
||||
} else if node_count > 0 {
|
||||
// Data exists but nodes array was empty (shouldn't happen)
|
||||
div { class: "loading", "Loading graph visualization..." }
|
||||
} else if matches!(&*graph_data.read(), None) {
|
||||
} else if (*graph_data.read()).is_none() {
|
||||
div { class: "loading", "Loading graph data..." }
|
||||
} else {
|
||||
div { class: "graph-empty-state",
|
||||
|
||||
@@ -95,8 +95,10 @@ impl WebCrawler {
|
||||
let document = Html::parse_document(&body);
|
||||
|
||||
// Extract links
|
||||
let link_selector = Selector::parse("a[href]")
|
||||
.unwrap_or_else(|_| Selector::parse("a").expect("valid selector"));
|
||||
let link_selector = match Selector::parse("a[href]") {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
for element in document.select(&link_selector) {
|
||||
if let Some(href) = element.value().attr("href") {
|
||||
if let Some(absolute_url) = self.resolve_url(&base, &url, href) {
|
||||
@@ -110,10 +112,14 @@ impl WebCrawler {
|
||||
}
|
||||
|
||||
// Extract forms
|
||||
let form_selector = Selector::parse("form")
|
||||
.unwrap_or_else(|_| Selector::parse("form").expect("valid selector"));
|
||||
let input_selector = Selector::parse("input, select, textarea")
|
||||
.unwrap_or_else(|_| Selector::parse("input").expect("valid selector"));
|
||||
let form_selector = match Selector::parse("form") {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
let input_selector = match Selector::parse("input, select, textarea") {
|
||||
Ok(s) => s,
|
||||
Err(_) => continue,
|
||||
};
|
||||
|
||||
for form in document.select(&form_selector) {
|
||||
let action = form.value().attr("action").unwrap_or("");
|
||||
|
||||
@@ -121,10 +121,10 @@ impl ReconAgent {
|
||||
|
||||
let body_lower = body.to_lowercase();
|
||||
for (tech, pattern) in &patterns {
|
||||
if body_lower.contains(&pattern.to_lowercase()) {
|
||||
if !result.technologies.contains(&tech.to_string()) {
|
||||
result.technologies.push(tech.to_string());
|
||||
}
|
||||
if body_lower.contains(&pattern.to_lowercase())
|
||||
&& !result.technologies.contains(&tech.to_string())
|
||||
{
|
||||
result.technologies.push(tech.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -109,8 +109,8 @@ pub fn detect_communities(code_graph: &CodeGraph) -> u32 {
|
||||
let mut comm_remap: HashMap<u32, u32> = HashMap::new();
|
||||
let mut next_id: u32 = 0;
|
||||
for &c in community.values() {
|
||||
if !comm_remap.contains_key(&c) {
|
||||
comm_remap.insert(c, next_id);
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = comm_remap.entry(c) {
|
||||
e.insert(next_id);
|
||||
next_id += 1;
|
||||
}
|
||||
}
|
||||
@@ -137,8 +137,7 @@ pub fn detect_communities(code_graph: &CodeGraph) -> u32 {
|
||||
|
||||
/// Apply community assignments back to code nodes
|
||||
pub fn apply_communities(code_graph: &mut CodeGraph) -> u32 {
|
||||
let count = detect_communities_with_assignment(code_graph);
|
||||
count
|
||||
detect_communities_with_assignment(code_graph)
|
||||
}
|
||||
|
||||
/// Detect communities and write assignments into the nodes
|
||||
@@ -235,8 +234,8 @@ fn detect_communities_with_assignment(code_graph: &mut CodeGraph) -> u32 {
|
||||
let mut comm_remap: HashMap<u32, u32> = HashMap::new();
|
||||
let mut next_id: u32 = 0;
|
||||
for &c in community.values() {
|
||||
if !comm_remap.contains_key(&c) {
|
||||
comm_remap.insert(c, next_id);
|
||||
if let std::collections::hash_map::Entry::Vacant(e) = comm_remap.entry(c) {
|
||||
e.insert(next_id);
|
||||
next_id += 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,17 +96,15 @@ impl EmbeddingStore {
|
||||
};
|
||||
|
||||
if status == EmbeddingBuildStatus::Completed || status == EmbeddingBuildStatus::Failed {
|
||||
update
|
||||
.get_document_mut("$set")
|
||||
.unwrap()
|
||||
.insert("completed_at", mongodb::bson::DateTime::now());
|
||||
if let Ok(set_doc) = update.get_document_mut("$set") {
|
||||
set_doc.insert("completed_at", mongodb::bson::DateTime::now());
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(msg) = error_message {
|
||||
update
|
||||
.get_document_mut("$set")
|
||||
.unwrap()
|
||||
.insert("error_message", msg);
|
||||
if let Ok(set_doc) = update.get_document_mut("$set") {
|
||||
set_doc.insert("error_message", msg);
|
||||
}
|
||||
}
|
||||
|
||||
self.builds
|
||||
|
||||
@@ -133,10 +133,10 @@ impl GraphEngine {
|
||||
}
|
||||
|
||||
/// Try to resolve an edge target to a known node
|
||||
fn resolve_edge_target<'a>(
|
||||
fn resolve_edge_target(
|
||||
&self,
|
||||
target: &str,
|
||||
node_map: &'a HashMap<String, NodeIndex>,
|
||||
node_map: &HashMap<String, NodeIndex>,
|
||||
) -> Option<NodeIndex> {
|
||||
// Direct match
|
||||
if let Some(idx) = node_map.get(target) {
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
#![allow(clippy::only_used_in_recursion)]
|
||||
#![allow(clippy::too_many_arguments)]
|
||||
|
||||
pub mod graph;
|
||||
pub mod parsers;
|
||||
pub mod search;
|
||||
|
||||
@@ -7,6 +7,12 @@ use tree_sitter::{Node, Parser};
|
||||
|
||||
pub struct JavaScriptParser;
|
||||
|
||||
impl Default for JavaScriptParser {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl JavaScriptParser {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
|
||||
@@ -7,6 +7,12 @@ use tree_sitter::{Node, Parser};
|
||||
|
||||
pub struct PythonParser;
|
||||
|
||||
impl Default for PythonParser {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl PythonParser {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
|
||||
@@ -7,6 +7,12 @@ use tree_sitter::{Node, Parser};
|
||||
|
||||
pub struct RustParser;
|
||||
|
||||
impl Default for RustParser {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl RustParser {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
|
||||
@@ -7,6 +7,12 @@ use tree_sitter::{Node, Parser};
|
||||
|
||||
pub struct TypeScriptParser;
|
||||
|
||||
impl Default for TypeScriptParser {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
impl TypeScriptParser {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
|
||||
Reference in New Issue
Block a user