src/server/http/repo/issues.rs
Ref: Size: 3.7 KiB
use std::sync::Arc;
use axum::extract::{Path, State};
use axum::response::{IntoResponse, Response};
use super::{AppState, CommentView, collab_counts, internal_error, not_found, open_repo};
#[derive(Debug)]
pub struct IssueListItem {
pub id: String,
pub short_id: String,
pub status: String,
pub title: String,
pub author: String,
pub labels: String,
pub updated: String,
}
#[derive(Debug)]
pub struct IssueDetailView {
pub title: String,
pub body: String,
pub status: String,
pub author: String,
pub labels: String,
pub assignees: String,
pub close_reason: Option<String>,
pub comments: Vec<CommentView>,
}
#[derive(askama::Template, askama_web::WebTemplate)]
#[template(path = "issues.html")]
pub struct IssuesTemplate {
pub site_title: String,
pub repo_name: String,
pub active_section: String,
pub open_patches: usize,
pub open_issues: usize,
pub issues: Vec<IssueListItem>,
}
#[derive(askama::Template, askama_web::WebTemplate)]
#[template(path = "issue_detail.html")]
pub struct IssueDetailTemplate {
pub site_title: String,
pub repo_name: String,
pub active_section: String,
pub open_patches: usize,
pub open_issues: usize,
pub issue: IssueDetailView,
}
pub async fn issues(
Path(repo_name): Path<String>,
State(state): State<Arc<AppState>>,
) -> Response {
let (_entry, repo) = match open_repo(&state, &repo_name) {
Ok(r) => r,
Err(resp) => return resp,
};
let (open_patches, open_issues) = collab_counts(&repo);
let all_issues = git_collab::state::list_issues_with_archived(&repo).unwrap_or_default();
let issues = all_issues
.into_iter()
.map(|i| {
let id = i.id.clone();
let short_id = id[..8.min(id.len())].to_string();
IssueListItem {
short_id,
id,
status: i.status.as_str().to_string(),
title: i.title,
author: i.author.name,
labels: i.labels.join(", "),
updated: i.last_updated,
}
})
.collect();
IssuesTemplate {
site_title: state.site_title.clone(),
repo_name,
active_section: "issues".to_string(),
open_patches,
open_issues,
issues,
}
.into_response()
}
pub async fn issue_detail(
Path((repo_name, issue_id)): Path<(String, String)>,
State(state): State<Arc<AppState>>,
) -> Response {
let (_entry, repo) = match open_repo(&state, &repo_name) {
Ok(r) => r,
Err(resp) => return resp,
};
let (open_patches, open_issues) = collab_counts(&repo);
let (ref_name, full_id) = match git_collab::state::resolve_issue_ref(&repo, &issue_id) {
Ok(r) => r,
Err(_) => return not_found(&state, format!("Issue '{}' not found.", issue_id)),
};
let is = match git_collab::state::IssueState::from_ref(&repo, &ref_name, &full_id) {
Ok(s) => s,
Err(_) => return internal_error(&state, "Failed to load issue state."),
};
let issue = IssueDetailView {
title: is.title,
body: is.body,
status: is.status.as_str().to_string(),
author: is.author.name,
labels: is.labels.join(", "),
assignees: is.assignees.join(", "),
close_reason: is.close_reason,
comments: is.comments.into_iter().map(|c| CommentView {
author: c.author.name,
body: c.body,
timestamp: c.timestamp,
}).collect(),
};
IssueDetailTemplate {
site_title: state.site_title.clone(),
repo_name,
active_section: "issues".to_string(),
open_patches,
open_issues,
issue,
}
.into_response()
}