diff --git a/src-tauri/src/ai/anthropic.rs b/src-tauri/src/ai/anthropic.rs index ba826fee..0312aeaa 100644 --- a/src-tauri/src/ai/anthropic.rs +++ b/src-tauri/src/ai/anthropic.rs @@ -106,10 +106,7 @@ impl Provider for AnthropicProvider { }) }); - let model = json["model"] - .as_str() - .unwrap_or(&config.model) - .to_string(); + let model = json["model"].as_str().unwrap_or(&config.model).to_string(); Ok(ChatResponse { content, diff --git a/src-tauri/src/ai/openai.rs b/src-tauri/src/ai/openai.rs index 232caf45..57df3c56 100644 --- a/src-tauri/src/ai/openai.rs +++ b/src-tauri/src/ai/openai.rs @@ -30,10 +30,7 @@ impl Provider for OpenAiProvider { config: &ProviderConfig, ) -> anyhow::Result { let client = reqwest::Client::new(); - let url = format!( - "{}/chat/completions", - config.api_url.trim_end_matches('/') - ); + let url = format!("{}/chat/completions", config.api_url.trim_end_matches('/')); let body = serde_json::json!({ "model": config.model, diff --git a/src-tauri/src/audit/log.rs b/src-tauri/src/audit/log.rs index 1b060c7c..7db8d241 100644 --- a/src-tauri/src/audit/log.rs +++ b/src-tauri/src/audit/log.rs @@ -54,8 +54,14 @@ mod tests { #[test] fn test_write_audit_event_inserts_row() { let conn = setup_test_db(); - write_audit_event(&conn, "test_action", "issue", "issue-123", r#"{"key":"val"}"#) - .expect("should insert"); + write_audit_event( + &conn, + "test_action", + "issue", + "issue-123", + r#"{"key":"val"}"#, + ) + .expect("should insert"); let count: i64 = conn .prepare("SELECT COUNT(*) FROM audit_log") diff --git a/src-tauri/src/commands/ai.rs b/src-tauri/src/commands/ai.rs index 41b1ec62..f1befd58 100644 --- a/src-tauri/src/commands/ai.rs +++ b/src-tauri/src/commands/ai.rs @@ -48,10 +48,7 @@ pub async fn analyze_logs( }, Message { role: "user".into(), - content: format!( - "Analyze logs for issue {}:\n\n{}", - issue_id, log_contents - ), + content: format!("Analyze logs for issue {}:\n\n{}", issue_id, log_contents), }, ]; @@ -61,8 +58,13 @@ pub async fn analyze_logs( .map_err(|e| e.to_string())?; let content = &response.content; - let summary = extract_section(content, "SUMMARY:") - .unwrap_or_else(|| content.lines().next().unwrap_or("Analysis complete").to_string()); + let summary = extract_section(content, "SUMMARY:").unwrap_or_else(|| { + content + .lines() + .next() + .unwrap_or("Analysis complete") + .to_string() + }); let key_findings = extract_list(content, "KEY_FINDINGS:"); let suggested_why1 = extract_section(content, "FIRST_WHY:") .unwrap_or_else(|| "Why did this issue occur?".to_string()); @@ -76,7 +78,8 @@ pub async fn analyze_logs( "ai_analyze_logs".to_string(), "issue".to_string(), issue_id.clone(), - serde_json::json!({ "log_file_ids": log_file_ids, "provider": provider_config.name }).to_string(), + serde_json::json!({ "log_file_ids": log_file_ids, "provider": provider_config.name }) + .to_string(), ); db.execute( "INSERT INTO audit_log (id, timestamp, action, entity_type, entity_id, user_id, details) \ @@ -275,10 +278,7 @@ pub async fn list_providers() -> Result, String> { ProviderInfo { name: "gemini".to_string(), supports_streaming: false, - models: vec![ - "gemini-1.5-pro".to_string(), - "gemini-1.5-flash".to_string(), - ], + models: vec!["gemini-1.5-pro".to_string(), "gemini-1.5-flash".to_string()], }, ProviderInfo { name: "mistral".to_string(), diff --git a/src-tauri/src/commands/analysis.rs b/src-tauri/src/commands/analysis.rs index 049163e5..8e205049 100644 --- a/src-tauri/src/commands/analysis.rs +++ b/src-tauri/src/commands/analysis.rs @@ -64,8 +64,13 @@ pub async fn upload_log_file( "INSERT INTO audit_log (id, timestamp, action, entity_type, entity_id, user_id, details) \ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", rusqlite::params![ - entry.id, entry.timestamp, entry.action, - entry.entity_type, entry.entity_id, entry.user_id, entry.details + entry.id, + entry.timestamp, + entry.action, + entry.entity_type, + entry.entity_id, + entry.user_id, + entry.details ], ); @@ -163,14 +168,16 @@ pub async fn apply_redactions( .unwrap_or_default(); drop(db); raw.into_iter() - .map(|(id, pii_type, start, end, original, replacement)| pii::PiiSpan { - id, - pii_type, - start: start as usize, - end: end as usize, - original, - replacement, - }) + .map( + |(id, pii_type, start, end, original, replacement)| pii::PiiSpan { + id, + pii_type, + start: start as usize, + end: end as usize, + original, + replacement, + }, + ) .filter(|span| approved_span_ids.contains(&span.id)) .collect() }; diff --git a/src-tauri/src/commands/db.rs b/src-tauri/src/commands/db.rs index 1c781fb3..a9cb70be 100644 --- a/src-tauri/src/commands/db.rs +++ b/src-tauri/src/commands/db.rs @@ -247,23 +247,29 @@ pub async fn update_issue( } #[tauri::command] -pub async fn delete_issue( - issue_id: String, - state: State<'_, AppState>, -) -> Result<(), String> { +pub async fn delete_issue(issue_id: String, state: State<'_, AppState>) -> Result<(), String> { let db = state.db.lock().map_err(|e| e.to_string())?; // Delete related records (CASCADE should handle this, but be explicit) db.execute("DELETE FROM ai_messages WHERE conversation_id IN (SELECT id FROM ai_conversations WHERE issue_id = ?1)", [&issue_id]) .map_err(|e| e.to_string())?; - db.execute("DELETE FROM ai_conversations WHERE issue_id = ?1", [&issue_id]) - .map_err(|e| e.to_string())?; - db.execute("DELETE FROM pii_spans WHERE log_file_id IN (SELECT id FROM log_files WHERE issue_id = ?1)", [&issue_id]) - .map_err(|e| e.to_string())?; + db.execute( + "DELETE FROM ai_conversations WHERE issue_id = ?1", + [&issue_id], + ) + .map_err(|e| e.to_string())?; + db.execute( + "DELETE FROM pii_spans WHERE log_file_id IN (SELECT id FROM log_files WHERE issue_id = ?1)", + [&issue_id], + ) + .map_err(|e| e.to_string())?; db.execute("DELETE FROM log_files WHERE issue_id = ?1", [&issue_id]) .map_err(|e| e.to_string())?; - db.execute("DELETE FROM resolution_steps WHERE issue_id = ?1", [&issue_id]) - .map_err(|e| e.to_string())?; + db.execute( + "DELETE FROM resolution_steps WHERE issue_id = ?1", + [&issue_id], + ) + .map_err(|e| e.to_string())?; db.execute("DELETE FROM issues WHERE id = ?1", [&issue_id]) .map_err(|e| e.to_string())?; @@ -364,13 +370,7 @@ pub async fn add_five_why( evidence: String, state: State<'_, AppState>, ) -> Result { - let step = ResolutionStep::new( - issue_id.clone(), - step_order, - why_question, - answer, - evidence, - ); + let step = ResolutionStep::new(issue_id.clone(), step_order, why_question, answer, evidence); let db = state.db.lock().map_err(|e| e.to_string())?; db.execute( @@ -444,8 +444,13 @@ pub async fn add_timeline_event( "INSERT INTO audit_log (id, timestamp, action, entity_type, entity_id, user_id, details) \ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", rusqlite::params![ - entry.id, entry.timestamp, entry.action, - entry.entity_type, entry.entity_id, entry.user_id, entry.details + entry.id, + entry.timestamp, + entry.action, + entry.entity_type, + entry.entity_id, + entry.user_id, + entry.details ], ) .map_err(|e| e.to_string())?; diff --git a/src-tauri/src/commands/docs.rs b/src-tauri/src/commands/docs.rs index 950f75c2..9aac0364 100644 --- a/src-tauri/src/commands/docs.rs +++ b/src-tauri/src/commands/docs.rs @@ -52,8 +52,13 @@ pub async fn generate_rca( "INSERT INTO audit_log (id, timestamp, action, entity_type, entity_id, user_id, details) \ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", rusqlite::params![ - entry.id, entry.timestamp, entry.action, - entry.entity_type, entry.entity_id, entry.user_id, entry.details + entry.id, + entry.timestamp, + entry.action, + entry.entity_type, + entry.entity_id, + entry.user_id, + entry.details ], ); @@ -94,8 +99,13 @@ pub async fn generate_postmortem( "INSERT INTO audit_log (id, timestamp, action, entity_type, entity_id, user_id, details) \ VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7)", rusqlite::params![ - entry.id, entry.timestamp, entry.action, - entry.entity_type, entry.entity_id, entry.user_id, entry.details + entry.id, + entry.timestamp, + entry.action, + entry.entity_type, + entry.entity_id, + entry.user_id, + entry.details ], ); @@ -103,10 +113,7 @@ pub async fn generate_postmortem( } #[tauri::command] -pub async fn update_document( - doc_id: String, - content_md: String, -) -> Result<(), String> { +pub async fn update_document(doc_id: String, content_md: String) -> Result<(), String> { // Documents are generated on-demand and held in memory / frontend state. // This is a no-op placeholder. In a future version with a documents table, // this would persist updates. diff --git a/src-tauri/src/commands/system.rs b/src-tauri/src/commands/system.rs index 30509265..7baf15a2 100644 --- a/src-tauri/src/commands/system.rs +++ b/src-tauri/src/commands/system.rs @@ -9,9 +9,7 @@ use crate::state::{AppSettings, AppState}; #[tauri::command] pub async fn check_ollama_installed() -> Result { - installer::check_ollama() - .await - .map_err(|e| e.to_string()) + installer::check_ollama().await.map_err(|e| e.to_string()) } #[tauri::command] @@ -55,9 +53,7 @@ pub async fn recommend_models() -> Result, String> { // --- Settings commands --- #[tauri::command] -pub async fn get_settings( - state: tauri::State<'_, AppState>, -) -> Result { +pub async fn get_settings(state: tauri::State<'_, AppState>) -> Result { state .settings .lock() diff --git a/src-tauri/src/docs/exporter.rs b/src-tauri/src/docs/exporter.rs index 70fd3eba..550476d1 100644 --- a/src-tauri/src/docs/exporter.rs +++ b/src-tauri/src/docs/exporter.rs @@ -35,8 +35,7 @@ pub fn export_pdf(content_md: &str, title: &str, output_path: &str) -> anyhow::R for line_info in &lines { if line_count >= max_lines_per_page { - let (new_page, new_layer) = - doc.add_page(Mm(210.0), Mm(297.0), "Layer 1"); + let (new_page, new_layer) = doc.add_page(Mm(210.0), Mm(297.0), "Layer 1"); current_layer = doc.get_page(new_page).get_layer(new_layer); y_pos = margin_top; line_count = 0; @@ -185,13 +184,18 @@ mod tests { #[test] fn test_markdown_to_lines_title() { let lines = markdown_to_lines("# My Title\n\nSome text"); - assert!(lines.iter().any(|l| l.text == "My Title" && matches!(l.style, LineStyle::Title))); + assert!(lines + .iter() + .any(|l| l.text == "My Title" && matches!(l.style, LineStyle::Title))); } #[test] fn test_markdown_to_lines_heading() { let lines = markdown_to_lines("## Section\n### Subsection"); - let headings: Vec<_> = lines.iter().filter(|l| matches!(l.style, LineStyle::Heading)).collect(); + let headings: Vec<_> = lines + .iter() + .filter(|l| matches!(l.style, LineStyle::Heading)) + .collect(); assert_eq!(headings.len(), 2); } @@ -204,7 +208,9 @@ mod tests { #[test] fn test_markdown_to_lines_table_row() { let lines = markdown_to_lines("| Col1 | Col2 |\n|------|------|\n| A | B |"); - assert!(lines.iter().any(|l| l.text.contains("Col1") && l.text.contains("Col2"))); + assert!(lines + .iter() + .any(|l| l.text.contains("Col1") && l.text.contains("Col2"))); } #[test] diff --git a/src-tauri/src/docs/postmortem.rs b/src-tauri/src/docs/postmortem.rs index 6cf8d295..43501027 100644 --- a/src-tauri/src/docs/postmortem.rs +++ b/src-tauri/src/docs/postmortem.rs @@ -5,10 +5,7 @@ pub fn generate_postmortem_markdown(detail: &IssueDetail) -> String { let mut md = String::new(); - md.push_str(&format!( - "# Blameless Post-Mortem: {}\n\n", - issue.title - )); + md.push_str(&format!("# Blameless Post-Mortem: {}\n\n", issue.title)); // Header metadata md.push_str("## Metadata\n\n"); @@ -19,7 +16,11 @@ pub fn generate_postmortem_markdown(detail: &IssueDetail) -> String { md.push_str(&format!("- **Last Updated:** {}\n", issue.updated_at)); md.push_str(&format!( "- **Assigned To:** {}\n", - if issue.assigned_to.is_empty() { "_Unassigned_" } else { &issue.assigned_to } + if issue.assigned_to.is_empty() { + "_Unassigned_" + } else { + &issue.assigned_to + } )); md.push_str("- **Authors:** _[Add authors]_\n"); md.push_str("- **Reviewers:** _[Add reviewers]_\n\n"); diff --git a/src-tauri/src/docs/rca.rs b/src-tauri/src/docs/rca.rs index d73450d4..99737d03 100644 --- a/src-tauri/src/docs/rca.rs +++ b/src-tauri/src/docs/rca.rs @@ -15,7 +15,14 @@ pub fn generate_rca_markdown(detail: &IssueDetail) -> String { md.push_str(&format!("| **Status** | {} |\n", issue.status)); md.push_str(&format!("| **Severity** | {} |\n", issue.severity)); md.push_str(&format!("| **Source** | {} |\n", issue.source)); - md.push_str(&format!("| **Assigned To** | {} |\n", if issue.assigned_to.is_empty() { "Unassigned" } else { &issue.assigned_to })); + md.push_str(&format!( + "| **Assigned To** | {} |\n", + if issue.assigned_to.is_empty() { + "Unassigned" + } else { + &issue.assigned_to + } + )); md.push_str(&format!("| **Created** | {} |\n", issue.created_at)); md.push_str(&format!("| **Last Updated** | {} |\n", issue.updated_at)); if let Some(ref resolved) = issue.resolved_at { diff --git a/src-tauri/src/integrations/azuredevops.rs b/src-tauri/src/integrations/azuredevops.rs index d3fb208b..e25333b5 100644 --- a/src-tauri/src/integrations/azuredevops.rs +++ b/src-tauri/src/integrations/azuredevops.rs @@ -19,7 +19,10 @@ pub struct WorkItem { } pub async fn test_connection(_config: &AzureDevOpsConfig) -> Result { - Err("Azure DevOps integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Azure DevOps integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn create_work_item( @@ -29,14 +32,20 @@ pub async fn create_work_item( _work_item_type: &str, _severity: &str, ) -> Result { - Err("Azure DevOps integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Azure DevOps integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn get_work_item( _config: &AzureDevOpsConfig, _work_item_id: i64, ) -> Result { - Err("Azure DevOps integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Azure DevOps integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn update_work_item( @@ -44,5 +53,8 @@ pub async fn update_work_item( _work_item_id: i64, _updates: serde_json::Value, ) -> Result { - Err("Azure DevOps integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Azure DevOps integration available in v0.2. Please update to the latest version." + .to_string(), + ) } diff --git a/src-tauri/src/integrations/confluence.rs b/src-tauri/src/integrations/confluence.rs index e8b92436..9df38feb 100644 --- a/src-tauri/src/integrations/confluence.rs +++ b/src-tauri/src/integrations/confluence.rs @@ -24,11 +24,17 @@ pub struct Page { } pub async fn test_connection(_config: &ConfluenceConfig) -> Result { - Err("Confluence integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Confluence integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn list_spaces(_config: &ConfluenceConfig) -> Result, String> { - Err("Confluence integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Confluence integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn publish_page( @@ -38,7 +44,10 @@ pub async fn publish_page( _content_html: &str, _parent_page_id: Option<&str>, ) -> Result { - Err("Confluence integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Confluence integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn update_page( @@ -48,5 +57,8 @@ pub async fn update_page( _content_html: &str, _version: i32, ) -> Result { - Err("Confluence integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "Confluence integration available in v0.2. Please update to the latest version." + .to_string(), + ) } diff --git a/src-tauri/src/integrations/servicenow.rs b/src-tauri/src/integrations/servicenow.rs index 52720143..d1d6ba64 100644 --- a/src-tauri/src/integrations/servicenow.rs +++ b/src-tauri/src/integrations/servicenow.rs @@ -20,7 +20,10 @@ pub struct Incident { } pub async fn test_connection(_config: &ServiceNowConfig) -> Result { - Err("ServiceNow integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "ServiceNow integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn create_incident( @@ -30,14 +33,20 @@ pub async fn create_incident( _urgency: &str, _impact: &str, ) -> Result { - Err("ServiceNow integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "ServiceNow integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn get_incident( _config: &ServiceNowConfig, _incident_number: &str, ) -> Result { - Err("ServiceNow integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "ServiceNow integration available in v0.2. Please update to the latest version." + .to_string(), + ) } pub async fn update_incident( @@ -45,5 +54,8 @@ pub async fn update_incident( _incident_number: &str, _updates: serde_json::Value, ) -> Result { - Err("ServiceNow integration available in v0.2. Please update to the latest version.".to_string()) + Err( + "ServiceNow integration available in v0.2. Please update to the latest version." + .to_string(), + ) } diff --git a/src-tauri/src/ollama/installer.rs b/src-tauri/src/ollama/installer.rs index 02fb533c..6048d93c 100644 --- a/src-tauri/src/ollama/installer.rs +++ b/src-tauri/src/ollama/installer.rs @@ -8,13 +8,9 @@ pub async fn check_ollama() -> anyhow::Result { "which" }; - let which_result = std::process::Command::new(which_cmd) - .arg("ollama") - .output(); + let which_result = std::process::Command::new(which_cmd).arg("ollama").output(); - let installed = which_result - .map(|o| o.status.success()) - .unwrap_or(false); + let installed = which_result.map(|o| o.status.success()).unwrap_or(false); let version = if installed { std::process::Command::new("ollama") @@ -104,7 +100,10 @@ mod tests { fn test_macos_install_guide() { let guide = get_install_instructions("macos"); assert_eq!(guide.platform, "macOS"); - assert!(guide.steps.iter().any(|s| s.contains("dmg") || s.contains("Applications"))); + assert!(guide + .steps + .iter() + .any(|s| s.contains("dmg") || s.contains("Applications"))); } #[test] diff --git a/src-tauri/src/ollama/recommender.rs b/src-tauri/src/ollama/recommender.rs index 437e93a2..f25391a8 100644 --- a/src-tauri/src/ollama/recommender.rs +++ b/src-tauri/src/ollama/recommender.rs @@ -46,8 +46,7 @@ pub fn recommend_models(hw: &HardwareInfo) -> Vec { size: "40 GB".to_string(), min_ram_gb: 48.0, description: "Full Llama 3.1 70B. Best quality, requires significant RAM.".to_string(), - recommended: ram >= 48.0 - || (has_gpu && hw.gpu_vram_gb.unwrap_or(0.0) >= 40.0), + recommended: ram >= 48.0 || (has_gpu && hw.gpu_vram_gb.unwrap_or(0.0) >= 40.0), }, ];