use super::super::routes::DashboardState;
use crate::config::project::ProjectConfig;
use axum::extract::State;
use axum::Json;
use serde_json::{json, Value};
pub async fn get_project_info(State(state): State<DashboardState>) -> Json<Value> {
let root = &state.project_root;
let config = ProjectConfig::load_or_default(root)
.unwrap_or_else(|_| ProjectConfig::default_for("unknown".to_string()));
let name = config.project.name.clone();
let languages = detect_languages(root);
let (git_branch, git_dirty) = git_info(root);
Json(json!({
"name": name,
"root": root.display().to_string(),
"languages": languages,
"git_branch": git_branch,
"git_dirty": git_dirty,
}))
}
fn detect_languages(root: &std::path::Path) -> Vec<String> {
let mut langs = std::collections::BTreeSet::new();
for entry in walkdir::WalkDir::new(root)
.max_depth(4)
.into_iter()
.filter_map(|e| e.ok())
.filter(|e| e.file_type().is_file())
.take(500)
{
if let Some(lang) = crate::ast::detect_language(entry.path()) {
langs.insert(lang.to_string());
}
}
langs.into_iter().collect()
}
fn git_info(root: &std::path::Path) -> (Option<String>, bool) {
match crate::git::open_repo(root) {
Ok(repo) => {
let branch = repo
.head()
.ok()
.and_then(|h| h.shorthand().map(String::from));
let dirty = repo.statuses(None).map(|s| !s.is_empty()).unwrap_or(false);
(branch, dirty)
}
Err(_) => (None, false),
}
}