style: apply cargo fmt formatting
This commit is contained in:
parent
1011fc1db4
commit
c8a717adee
@ -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,
|
||||
|
||||
@ -30,10 +30,7 @@ impl Provider for OpenAiProvider {
|
||||
config: &ProviderConfig,
|
||||
) -> anyhow::Result<ChatResponse> {
|
||||
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,
|
||||
|
||||
@ -54,7 +54,13 @@ 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"}"#)
|
||||
write_audit_event(
|
||||
&conn,
|
||||
"test_action",
|
||||
"issue",
|
||||
"issue-123",
|
||||
r#"{"key":"val"}"#,
|
||||
)
|
||||
.expect("should insert");
|
||||
|
||||
let count: i64 = conn
|
||||
|
||||
@ -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<Vec<ProviderInfo>, 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(),
|
||||
|
||||
@ -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 {
|
||||
.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()
|
||||
};
|
||||
|
||||
@ -247,22 +247,28 @@ 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])
|
||||
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])
|
||||
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])
|
||||
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<ResolutionStep, String> {
|
||||
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())?;
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -9,9 +9,7 @@ use crate::state::{AppSettings, AppState};
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn check_ollama_installed() -> Result<OllamaStatus, String> {
|
||||
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<Vec<ModelRecommendation>, String> {
|
||||
// --- Settings commands ---
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn get_settings(
|
||||
state: tauri::State<'_, AppState>,
|
||||
) -> Result<AppSettings, String> {
|
||||
pub async fn get_settings(state: tauri::State<'_, AppState>) -> Result<AppSettings, String> {
|
||||
state
|
||||
.settings
|
||||
.lock()
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -19,7 +19,10 @@ pub struct WorkItem {
|
||||
}
|
||||
|
||||
pub async fn test_connection(_config: &AzureDevOpsConfig) -> Result<ConnectionResult, String> {
|
||||
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<TicketResult, String> {
|
||||
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<WorkItem, String> {
|
||||
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<TicketResult, String> {
|
||||
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(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -24,11 +24,17 @@ pub struct Page {
|
||||
}
|
||||
|
||||
pub async fn test_connection(_config: &ConfluenceConfig) -> Result<ConnectionResult, 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 list_spaces(_config: &ConfluenceConfig) -> Result<Vec<Space>, 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<PublishResult, 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 update_page(
|
||||
@ -48,5 +57,8 @@ pub async fn update_page(
|
||||
_content_html: &str,
|
||||
_version: i32,
|
||||
) -> Result<PublishResult, 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(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -20,7 +20,10 @@ pub struct Incident {
|
||||
}
|
||||
|
||||
pub async fn test_connection(_config: &ServiceNowConfig) -> Result<ConnectionResult, String> {
|
||||
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<TicketResult, String> {
|
||||
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<Incident, String> {
|
||||
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<TicketResult, String> {
|
||||
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(),
|
||||
)
|
||||
}
|
||||
|
||||
@ -8,13 +8,9 @@ pub async fn check_ollama() -> anyhow::Result<OllamaStatus> {
|
||||
"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]
|
||||
|
||||
@ -46,8 +46,7 @@ pub fn recommend_models(hw: &HardwareInfo) -> Vec<ModelRecommendation> {
|
||||
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),
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user