feat(bd-2g50): fill data gaps in issue detail view
Add references_full, user_notes_count, merge_requests_count computed fields to show issue. Add closed_at and confidential columns via migration 023. Closes: bd-2g50
This commit is contained in:
@@ -75,12 +75,17 @@ pub struct IssueDetail {
|
||||
pub author_username: String,
|
||||
pub created_at: i64,
|
||||
pub updated_at: i64,
|
||||
pub closed_at: Option<String>,
|
||||
pub confidential: bool,
|
||||
pub web_url: Option<String>,
|
||||
pub project_path: String,
|
||||
pub references_full: String,
|
||||
pub labels: Vec<String>,
|
||||
pub assignees: Vec<String>,
|
||||
pub due_date: Option<String>,
|
||||
pub milestone: Option<String>,
|
||||
pub user_notes_count: i64,
|
||||
pub merge_requests_count: usize,
|
||||
pub closing_merge_requests: Vec<ClosingMrRef>,
|
||||
pub discussions: Vec<DiscussionDetail>,
|
||||
pub status_name: Option<String>,
|
||||
@@ -122,6 +127,9 @@ pub fn run_show_issue(
|
||||
|
||||
let discussions = get_issue_discussions(&conn, issue.id)?;
|
||||
|
||||
let references_full = format!("{}#{}", issue.project_path, issue.iid);
|
||||
let merge_requests_count = closing_mrs.len();
|
||||
|
||||
Ok(IssueDetail {
|
||||
id: issue.id,
|
||||
iid: issue.iid,
|
||||
@@ -131,12 +139,17 @@ pub fn run_show_issue(
|
||||
author_username: issue.author_username,
|
||||
created_at: issue.created_at,
|
||||
updated_at: issue.updated_at,
|
||||
closed_at: issue.closed_at,
|
||||
confidential: issue.confidential,
|
||||
web_url: issue.web_url,
|
||||
project_path: issue.project_path,
|
||||
references_full,
|
||||
labels,
|
||||
assignees,
|
||||
due_date: issue.due_date,
|
||||
milestone: issue.milestone_title,
|
||||
user_notes_count: issue.user_notes_count,
|
||||
merge_requests_count,
|
||||
closing_merge_requests: closing_mrs,
|
||||
discussions,
|
||||
status_name: issue.status_name,
|
||||
@@ -156,10 +169,13 @@ struct IssueRow {
|
||||
author_username: String,
|
||||
created_at: i64,
|
||||
updated_at: i64,
|
||||
closed_at: Option<String>,
|
||||
confidential: bool,
|
||||
web_url: Option<String>,
|
||||
project_path: String,
|
||||
due_date: Option<String>,
|
||||
milestone_title: Option<String>,
|
||||
user_notes_count: i64,
|
||||
status_name: Option<String>,
|
||||
status_category: Option<String>,
|
||||
status_color: Option<String>,
|
||||
@@ -173,8 +189,12 @@ fn find_issue(conn: &Connection, iid: i64, project_filter: Option<&str>) -> Resu
|
||||
let project_id = resolve_project(conn, project)?;
|
||||
(
|
||||
"SELECT i.id, i.iid, i.title, i.description, i.state, i.author_username,
|
||||
i.created_at, i.updated_at, i.web_url, p.path_with_namespace,
|
||||
i.created_at, i.updated_at, i.closed_at, i.confidential,
|
||||
i.web_url, p.path_with_namespace,
|
||||
i.due_date, i.milestone_title,
|
||||
(SELECT COUNT(*) FROM notes n
|
||||
JOIN discussions d ON n.discussion_id = d.id
|
||||
WHERE d.noteable_type = 'Issue' AND d.noteable_id = i.id AND n.is_system = 0) AS user_notes_count,
|
||||
i.status_name, i.status_category, i.status_color,
|
||||
i.status_icon_name, i.status_synced_at
|
||||
FROM issues i
|
||||
@@ -185,8 +205,12 @@ fn find_issue(conn: &Connection, iid: i64, project_filter: Option<&str>) -> Resu
|
||||
}
|
||||
None => (
|
||||
"SELECT i.id, i.iid, i.title, i.description, i.state, i.author_username,
|
||||
i.created_at, i.updated_at, i.web_url, p.path_with_namespace,
|
||||
i.created_at, i.updated_at, i.closed_at, i.confidential,
|
||||
i.web_url, p.path_with_namespace,
|
||||
i.due_date, i.milestone_title,
|
||||
(SELECT COUNT(*) FROM notes n
|
||||
JOIN discussions d ON n.discussion_id = d.id
|
||||
WHERE d.noteable_type = 'Issue' AND d.noteable_id = i.id AND n.is_system = 0) AS user_notes_count,
|
||||
i.status_name, i.status_category, i.status_color,
|
||||
i.status_icon_name, i.status_synced_at
|
||||
FROM issues i
|
||||
@@ -201,6 +225,7 @@ fn find_issue(conn: &Connection, iid: i64, project_filter: Option<&str>) -> Resu
|
||||
let mut stmt = conn.prepare(sql)?;
|
||||
let issues: Vec<IssueRow> = stmt
|
||||
.query_map(param_refs.as_slice(), |row| {
|
||||
let confidential_val: i64 = row.get(9)?;
|
||||
Ok(IssueRow {
|
||||
id: row.get(0)?,
|
||||
iid: row.get(1)?,
|
||||
@@ -210,15 +235,18 @@ fn find_issue(conn: &Connection, iid: i64, project_filter: Option<&str>) -> Resu
|
||||
author_username: row.get(5)?,
|
||||
created_at: row.get(6)?,
|
||||
updated_at: row.get(7)?,
|
||||
web_url: row.get(8)?,
|
||||
project_path: row.get(9)?,
|
||||
due_date: row.get(10)?,
|
||||
milestone_title: row.get(11)?,
|
||||
status_name: row.get(12)?,
|
||||
status_category: row.get(13)?,
|
||||
status_color: row.get(14)?,
|
||||
status_icon_name: row.get(15)?,
|
||||
status_synced_at: row.get(16)?,
|
||||
closed_at: row.get(8)?,
|
||||
confidential: confidential_val != 0,
|
||||
web_url: row.get(10)?,
|
||||
project_path: row.get(11)?,
|
||||
due_date: row.get(12)?,
|
||||
milestone_title: row.get(13)?,
|
||||
user_notes_count: row.get(14)?,
|
||||
status_name: row.get(15)?,
|
||||
status_category: row.get(16)?,
|
||||
status_color: row.get(17)?,
|
||||
status_icon_name: row.get(18)?,
|
||||
status_synced_at: row.get(19)?,
|
||||
})
|
||||
})?
|
||||
.collect::<std::result::Result<Vec<_>, _>>()?;
|
||||
@@ -618,6 +646,7 @@ pub fn print_show_issue(issue: &IssueDetail) {
|
||||
println!("{}", "━".repeat(header.len().min(80)));
|
||||
println!();
|
||||
|
||||
println!("Ref: {}", style(&issue.references_full).dim());
|
||||
println!("Project: {}", style(&issue.project_path).cyan());
|
||||
|
||||
let state_styled = if issue.state == "opened" {
|
||||
@@ -627,6 +656,10 @@ pub fn print_show_issue(issue: &IssueDetail) {
|
||||
};
|
||||
println!("State: {}", state_styled);
|
||||
|
||||
if issue.confidential {
|
||||
println!(" {}", style("CONFIDENTIAL").red().bold());
|
||||
}
|
||||
|
||||
if let Some(status) = &issue.status_name {
|
||||
println!(
|
||||
"Status: {}",
|
||||
@@ -658,6 +691,10 @@ pub fn print_show_issue(issue: &IssueDetail) {
|
||||
println!("Created: {}", format_date(issue.created_at));
|
||||
println!("Updated: {}", format_date(issue.updated_at));
|
||||
|
||||
if let Some(closed_at) = &issue.closed_at {
|
||||
println!("Closed: {}", closed_at);
|
||||
}
|
||||
|
||||
if let Some(due) = &issue.due_date {
|
||||
println!("Due: {}", due);
|
||||
}
|
||||
@@ -931,12 +968,17 @@ pub struct IssueDetailJson {
|
||||
pub author_username: String,
|
||||
pub created_at: String,
|
||||
pub updated_at: String,
|
||||
pub closed_at: Option<String>,
|
||||
pub confidential: bool,
|
||||
pub web_url: Option<String>,
|
||||
pub project_path: String,
|
||||
pub references_full: String,
|
||||
pub labels: Vec<String>,
|
||||
pub assignees: Vec<String>,
|
||||
pub due_date: Option<String>,
|
||||
pub milestone: Option<String>,
|
||||
pub user_notes_count: i64,
|
||||
pub merge_requests_count: usize,
|
||||
pub closing_merge_requests: Vec<ClosingMrRefJson>,
|
||||
pub discussions: Vec<DiscussionDetailJson>,
|
||||
pub status_name: Option<String>,
|
||||
@@ -980,12 +1022,17 @@ impl From<&IssueDetail> for IssueDetailJson {
|
||||
author_username: issue.author_username.clone(),
|
||||
created_at: ms_to_iso(issue.created_at),
|
||||
updated_at: ms_to_iso(issue.updated_at),
|
||||
closed_at: issue.closed_at.clone(),
|
||||
confidential: issue.confidential,
|
||||
web_url: issue.web_url.clone(),
|
||||
project_path: issue.project_path.clone(),
|
||||
references_full: issue.references_full.clone(),
|
||||
labels: issue.labels.clone(),
|
||||
assignees: issue.assignees.clone(),
|
||||
due_date: issue.due_date.clone(),
|
||||
milestone: issue.milestone.clone(),
|
||||
user_notes_count: issue.user_notes_count,
|
||||
merge_requests_count: issue.merge_requests_count,
|
||||
closing_merge_requests: issue
|
||||
.closing_merge_requests
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user