Prepare Gotcha 1.0 for release
This commit is contained in:
256
crates/app/src/presentation/details.rs
Normal file
256
crates/app/src/presentation/details.rs
Normal file
@@ -0,0 +1,256 @@
|
||||
use super::{helpers::*, *};
|
||||
|
||||
pub fn issue_page(details: IssueDetails) -> IssuePage {
|
||||
IssuePage {
|
||||
title: details
|
||||
.issue
|
||||
.title
|
||||
.clone()
|
||||
.unwrap_or_else(|| "Untitled issue".into()),
|
||||
state: work_item_state(details.issue.state.as_deref()),
|
||||
meta: issue_meta(&details.issue),
|
||||
milestone: issue_milestone(&details.issue),
|
||||
labels: details
|
||||
.issue
|
||||
.labels
|
||||
.as_deref()
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.filter_map(label_row)
|
||||
.collect(),
|
||||
body: details
|
||||
.issue
|
||||
.body
|
||||
.filter(|body| !body.is_empty())
|
||||
.unwrap_or_else(|| "No description provided.".into()),
|
||||
comments: details
|
||||
.comments
|
||||
.iter()
|
||||
.map(|comment| comment_row(comment, details.viewer_id))
|
||||
.collect(),
|
||||
has_more: details.has_more,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn issue_editor_page(data: IssueEditorData) -> IssueEditorPage {
|
||||
let selected_labels: std::collections::BTreeSet<_> = data
|
||||
.issue
|
||||
.as_ref()
|
||||
.and_then(|issue| issue.labels.as_deref())
|
||||
.unwrap_or_default()
|
||||
.iter()
|
||||
.filter_map(|label| label.id)
|
||||
.collect();
|
||||
let selected_milestone = data
|
||||
.issue
|
||||
.as_ref()
|
||||
.and_then(|issue| issue.milestone.as_ref())
|
||||
.and_then(|milestone| milestone.id);
|
||||
let mut labels: Vec<_> = data
|
||||
.labels
|
||||
.into_iter()
|
||||
.filter_map(|label| {
|
||||
let id = label.id?;
|
||||
Some(IssueEditorLabel {
|
||||
id,
|
||||
name: label.name?,
|
||||
selected: selected_labels.contains(&id),
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
labels.sort_by_key(|label| label.name.to_lowercase());
|
||||
let mut milestones: Vec<_> = data
|
||||
.milestones
|
||||
.into_iter()
|
||||
.filter(|milestone| {
|
||||
milestone.state.as_deref() != Some("closed") || milestone.id == selected_milestone
|
||||
})
|
||||
.filter_map(|milestone| {
|
||||
let id = milestone.id?;
|
||||
Some(IssueEditorMilestone {
|
||||
id,
|
||||
title: milestone.title?,
|
||||
selected: Some(id) == selected_milestone,
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
milestones.sort_by_key(|milestone| milestone.title.to_lowercase());
|
||||
IssueEditorPage {
|
||||
title: data
|
||||
.issue
|
||||
.as_ref()
|
||||
.and_then(|issue| issue.title.clone())
|
||||
.unwrap_or_default(),
|
||||
body: data
|
||||
.issue
|
||||
.as_ref()
|
||||
.and_then(|issue| issue.body.clone())
|
||||
.unwrap_or_default(),
|
||||
due_date: data
|
||||
.issue
|
||||
.as_ref()
|
||||
.and_then(|issue| issue.due_date.as_deref())
|
||||
.and_then(parse_api_date),
|
||||
closed: data.issue.as_ref().and_then(|issue| issue.state.as_deref()) == Some("closed"),
|
||||
labels,
|
||||
milestones,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pull_page(details: PullDetails) -> PullPage {
|
||||
let pull = &details.pull;
|
||||
let author = pull
|
||||
.user
|
||||
.as_ref()
|
||||
.and_then(|user| user.login.as_deref())
|
||||
.unwrap_or("unknown");
|
||||
let head = pull
|
||||
.head
|
||||
.as_ref()
|
||||
.and_then(|branch| branch.label.as_deref().or(branch.r#ref.as_deref()))
|
||||
.unwrap_or("head");
|
||||
let base = pull
|
||||
.base
|
||||
.as_ref()
|
||||
.and_then(|branch| branch.label.as_deref().or(branch.r#ref.as_deref()))
|
||||
.unwrap_or("base");
|
||||
let state = pull_state(pull);
|
||||
PullPage {
|
||||
title: pull
|
||||
.title
|
||||
.clone()
|
||||
.unwrap_or_else(|| "Untitled pull request".into()),
|
||||
state: work_item_state(pull.state.as_deref()),
|
||||
meta: format!(
|
||||
"#{} · {state} · {author} · {head} → {base}\n{} files · +{} −{} · {} comments",
|
||||
pull.number.unwrap_or_default(),
|
||||
pull.changed_files.unwrap_or_default(),
|
||||
pull.additions.unwrap_or_default(),
|
||||
pull.deletions.unwrap_or_default(),
|
||||
pull.comments.unwrap_or_default(),
|
||||
),
|
||||
body: pull
|
||||
.body
|
||||
.clone()
|
||||
.filter(|body| !body.is_empty())
|
||||
.unwrap_or_else(|| "No description provided.".into()),
|
||||
files_ref: pull_files_ref(pull),
|
||||
files: details.files.iter().filter_map(file_row).collect(),
|
||||
comments: details
|
||||
.comments
|
||||
.iter()
|
||||
.map(|comment| comment_row(comment, None))
|
||||
.collect(),
|
||||
has_more: details.has_more,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn file_rows(files: Vec<models::ChangedFile>) -> Vec<FileRow> {
|
||||
files.iter().filter_map(file_row).collect()
|
||||
}
|
||||
|
||||
pub fn commit_file_rows(files: Vec<models::CommitAffectedFiles>) -> Vec<FileRow> {
|
||||
files
|
||||
.into_iter()
|
||||
.filter_map(|file| {
|
||||
Some(FileRow {
|
||||
path: file.filename?,
|
||||
status: file.status.unwrap_or_else(|| "modified".into()),
|
||||
})
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn commit_details_page(commit: models::Commit, branch: Option<String>) -> CommitDetailsPage {
|
||||
let details = commit.commit.as_deref();
|
||||
let message = details
|
||||
.and_then(|details| details.message.as_deref())
|
||||
.unwrap_or("Commit");
|
||||
let mut lines = message.lines();
|
||||
let title = lines.next().unwrap_or("Commit").to_string();
|
||||
let description = lines.collect::<Vec<_>>().join("\n").trim().to_string();
|
||||
let author = details
|
||||
.and_then(|details| details.author.as_deref())
|
||||
.and_then(commit_user)
|
||||
.or_else(|| {
|
||||
commit
|
||||
.author
|
||||
.as_deref()
|
||||
.and_then(|author| author.login.clone())
|
||||
});
|
||||
let committer = details
|
||||
.and_then(|details| details.committer.as_deref())
|
||||
.and_then(commit_user)
|
||||
.or_else(|| {
|
||||
commit
|
||||
.committer
|
||||
.as_deref()
|
||||
.and_then(|committer| committer.login.clone())
|
||||
});
|
||||
let date = details
|
||||
.and_then(|details| details.committer.as_deref())
|
||||
.and_then(|committer| committer.date.as_deref())
|
||||
.or_else(|| {
|
||||
details
|
||||
.and_then(|details| details.author.as_deref())
|
||||
.and_then(|author| author.date.as_deref())
|
||||
})
|
||||
.or(commit.created.as_deref());
|
||||
let files = commit.files.unwrap_or_default();
|
||||
let mut metadata = Vec::new();
|
||||
if let Some(author) = author {
|
||||
metadata.push(metadata_row("Author", author, false));
|
||||
}
|
||||
if let Some(committer) = committer {
|
||||
metadata.push(metadata_row("Committer", committer, false));
|
||||
}
|
||||
if date.is_some() {
|
||||
metadata.push(metadata_row("Committed", compact_date(date), false));
|
||||
}
|
||||
if let Some(branch) = branch.filter(|branch| !branch.is_empty()) {
|
||||
metadata.push(metadata_row("Branch", branch, false));
|
||||
}
|
||||
metadata.push(metadata_row(
|
||||
"Commit",
|
||||
commit.sha.clone().unwrap_or_else(|| "unknown".into()),
|
||||
true,
|
||||
));
|
||||
let verification = details.and_then(|details| details.verification.as_deref());
|
||||
metadata.push(metadata_row(
|
||||
"Signature",
|
||||
match verification.filter(|verification| {
|
||||
verification
|
||||
.signature
|
||||
.as_deref()
|
||||
.is_some_and(|signature| !signature.is_empty())
|
||||
}) {
|
||||
Some(verification) if verification.verified.unwrap_or(false) => "Verified".into(),
|
||||
Some(_) => "Unverified".into(),
|
||||
None => "Unsigned".into(),
|
||||
},
|
||||
false,
|
||||
));
|
||||
CommitDetailsPage {
|
||||
title,
|
||||
description,
|
||||
metadata,
|
||||
files: commit_file_rows(files),
|
||||
}
|
||||
}
|
||||
|
||||
fn commit_user(user: &models::CommitUser) -> Option<String> {
|
||||
match (user.name.as_deref(), user.email.as_deref()) {
|
||||
(Some(name), Some(email)) => Some(format!("{name} <{email}>")),
|
||||
(Some(name), None) => Some(name.into()),
|
||||
(None, Some(email)) => Some(email.into()),
|
||||
(None, None) => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn metadata_row(label: &str, value: String, monospaced: bool) -> CommitMetadataRow {
|
||||
CommitMetadataRow {
|
||||
label: label.into(),
|
||||
value,
|
||||
monospaced,
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user