(
State(runtime): State<DashboardRuntime>,
Query(params): Query<ProjectsParams>,
)
| 115 | } |
| 116 | |
| 117 | pub(crate) async fn list( |
| 118 | State(runtime): State<DashboardRuntime>, |
| 119 | Query(params): Query<ProjectsParams>, |
| 120 | ) -> Json<Value> { |
| 121 | let limit = params.limit.unwrap_or(100).clamp(1, 250); |
| 122 | let Some(db) = GlobalDb::open().await else { |
| 123 | return Json(json!({ |
| 124 | "status": "missing_registry", |
| 125 | "projects": [], |
| 126 | "active_project_id": runtime.active_project_id(), |
| 127 | "active_project_root": runtime.active_project_root(), |
| 128 | })); |
| 129 | }; |
| 130 | |
| 131 | let mut projects = db.list_code_projects(limit + 1).await; |
| 132 | let truncated = projects.len() > limit; |
| 133 | projects.truncate(limit); |
| 134 | let active_project_id = runtime.active_project_id().map(str::to_string); |
| 135 | let rows = projects |
| 136 | .into_iter() |
| 137 | .map(|project| { |
| 138 | let is_active = Some(project.project_id.as_str()) == runtime.active_project_id(); |
| 139 | let label = Path::new(&project.display_root) |
| 140 | .file_name() |
| 141 | .and_then(|name| name.to_str()) |
| 142 | .unwrap_or(project.display_root.as_str()) |
| 143 | .to_string(); |
| 144 | json!({ |
| 145 | "project_id": project.project_id, |
| 146 | "label": label, |
| 147 | "project_root": project.display_root, |
| 148 | "canonical_root": project.canonical_root, |
| 149 | "default_branch": project.default_branch, |
| 150 | "last_seen_at": project.last_seen_at, |
| 151 | "is_active": is_active, |
| 152 | }) |
| 153 | }) |
| 154 | .collect::<Vec<_>>(); |
| 155 | |
| 156 | Json(json!({ |
| 157 | "status": "ok", |
| 158 | "limit": limit, |
| 159 | "truncated": truncated, |
| 160 | "active_project_id": active_project_id, |
| 161 | "active_project_root": runtime.active_project_root(), |
| 162 | "projects": rows, |
| 163 | })) |
| 164 | } |
| 165 | |
| 166 | pub(crate) async fn context( |
| 167 | State(runtime): State<DashboardRuntime>, |
no test coverage detected