015f300941651035945b5cdd98aeada97e4337aa / frogue / src / views / compare.rs
Raw
use actix_web::HttpResponse;
use maud::{Markup, Render, html};
use crate::repositories::git;
use crate::views::{
Page, RefSummary,
commit::{diff_stats_summary, file_diffs},
commits::CommitLine,
components::{Complaint, RefSelect, RepositoryChrome, RepositoryTab},
repositories::CommitSummary,
};
/// The body of the compare page, showing the diff between two revisions.
pub(super) struct CompareBody<'a> {
pub(super) owner: &'a str,
pub(super) slug: &'a str,
pub(super) visibility: &'a str,
pub(super) default_branch: &'a str,
pub(super) base: &'a str,
pub(super) head: &'a str,
pub(super) commits: &'a [CommitSummary],
pub(super) files: &'a [git::DiffFile],
pub(super) viewer: Option<&'a str>,
}
impl Render for CompareBody<'_> {
fn render(&self) -> Markup {
html! {
(RepositoryChrome {
owner: self.owner,
slug: self.slug,
visibility: self.visibility,
default_branch: self.default_branch,
current_tab: RepositoryTab::Compare,
is_owner: self.viewer == Some(self.owner),
})
div class="compare-header" {
p {
"Comparing "
a href=(format!("/~{}/{}/commits/{}", self.owner, self.slug, self.base)) {
code { (self.base) }
}
" ... "
a href=(format!("/~{}/{}/commits/{}", self.owner, self.slug, self.head)) {
code { (self.head) }
}
}
}
@if !self.commits.is_empty() {
h3 { "Commits (" (self.commits.len()) ")" }
ul class="commits" {
@for commit in self.commits {
li {
(CommitLine {
owner: self.owner,
slug: self.slug,
commit,
})
}
}
}
}
@if !self.files.is_empty() {
div class="commit-stats" {
(diff_stats_summary(self.files))
}
div class="commit-diff" {
(file_diffs(self.files))
}
} @else {
p class="empty" {
"No differences between " (self.base) " and " (self.head) "."
}
}
}
}
}
/// The body of the compare landing page, with a form to pick two revisions.
pub(super) struct CompareFormBody<'a> {
pub(super) owner: &'a str,
pub(super) slug: &'a str,
pub(super) visibility: &'static str,
pub(super) default_branch: &'a str,
pub(super) branches: &'a [RefSummary],
pub(super) tags: &'a [RefSummary],
pub(super) patches: &'a [PatchSummary],
pub(super) error: Option<&'a str>,
pub(super) viewer: Option<&'a str>,
}
/// A patch proposal for the compare form.
pub struct PatchSummary {
pub number: i64,
pub summary: String,
}
impl Render for CompareFormBody<'_> {
fn render(&self) -> Markup {
html! {
(RepositoryChrome {
owner: self.owner,
slug: self.slug,
visibility: self.visibility,
default_branch: self.default_branch,
current_tab: RepositoryTab::Compare,
is_owner: self.viewer == Some(self.owner),
})
(Complaint(self.error))
@if self.branches.is_empty() && self.tags.is_empty() && self.patches.is_empty() {
p class="empty" { "Nothing to compare yet." }
} @else {
form method="get" action=(format!("/~{}/{}/compare", self.owner, self.slug)) class="compare-form" {
(RefSelect {
name: "from",
label: "Compare",
branches: self.branches,
tags: self.tags,
patches: self.patches,
selected: self.default_branch,
})
span class="dots" { "..." }
(RefSelect {
name: "to",
label: "with",
branches: self.branches,
tags: self.tags,
patches: self.patches,
selected: self.default_branch,
})
button type="submit" { "Compare" }
}
}
}
}
}
/// The compare page showing the diff between two revisions.
pub fn compare(
viewer: Option<&str>,
owner: &str,
slug: &str,
visibility: &'static str,
default_branch: &str,
base: &str,
head: &str,
commits: &[CommitSummary],
files: &[git::DiffFile],
) -> HttpResponse {
Page {
title: format!("~{owner}/{slug}: Compare {base}...{head} - Frogue"),
viewer: viewer.map(str::to_string),
extra_head: None,
body: CompareBody {
owner,
slug,
visibility,
default_branch,
base,
head,
commits,
files,
viewer,
},
}
.into_response()
}
/// The compare landing page with a form to pick two revisions.
pub fn compare_form(
viewer: Option<&str>,
owner: &str,
slug: &str,
visibility: &'static str,
default_branch: &str,
branches: &[RefSummary],
tags: &[RefSummary],
patches: &[PatchSummary],
error: Option<&str>,
) -> HttpResponse {
Page {
title: format!("~{owner}/{slug}: Compare - Frogue"),
viewer: viewer.map(str::to_string),
extra_head: None,
body: CompareFormBody {
owner,
slug,
visibility,
default_branch,
branches,
tags,
patches,
error,
viewer,
},
}
.into_response()
}