| 1 | //! `/{repo}/refs` — branches and tags. |
| 2 | |
| 3 | use askama::Template; |
| 4 | use axum::http::StatusCode; |
| 5 | use axum::response::Response; |
| 6 | |
| 7 | use super::repo::{Active, Crumb, Ctx, RepoNav, set_cache_headers}; |
| 8 | use super::{Layout, render}; |
| 9 | use crate::git::refs::RefEntry; |
| 10 | use crate::render::time; |
| 11 | |
| 12 | pub struct RefRow { |
| 13 | pub name: String, |
| 14 | pub url: String, |
| 15 | pub subject: String, |
| 16 | pub age: String, |
| 17 | pub iso: String, |
| 18 | pub is_default: bool, |
| 19 | } |
| 20 | |
| 21 | #[derive(Template)] |
| 22 | #[template(path = "refs.html")] |
| 23 | pub struct RefsPage { |
| 24 | pub layout: Layout, |
| 25 | pub nav: RepoNav, |
| 26 | pub crumbs: Vec<Crumb>, |
| 27 | pub here: Option<String>, |
| 28 | pub branches: Vec<RefRow>, |
| 29 | pub tags: Vec<RefRow>, |
| 30 | } |
| 31 | |
| 32 | pub fn page(ctx: &Ctx) -> Response { |
| 33 | let etag = ctx.etag("refs"); |
| 34 | if let Some(res) = ctx.not_modified(&etag, false) { |
| 35 | return res; |
| 36 | } |
| 37 | let refs = match ctx.refs() { |
| 38 | Ok(refs) => refs, |
| 39 | Err(e) => return ctx.internal_error(e), |
| 40 | }; |
| 41 | let now = time::now(); |
| 42 | let default = ctx.repo.meta.default_branch.as_deref(); |
| 43 | let row = |r: &RefEntry| RefRow { |
| 44 | name: r.name.clone(), |
| 45 | url: ctx.url("tree", &r.name, b""), |
| 46 | subject: r |
| 47 | .tag_subject |
| 48 | .clone() |
| 49 | .unwrap_or_else(|| r.info.subject.clone()), |
| 50 | age: time::relative(r.info.committer_time, now), |
| 51 | iso: time::iso(r.info.committer_time), |
| 52 | is_default: false, |
| 53 | }; |
| 54 | let mut branches: Vec<RefRow> = refs.branches.iter().map(row).collect(); |
| 55 | // The default branch leads the list. |
| 56 | if let Some(i) = branches |
| 57 | .iter() |
| 58 | .position(|b| Some(b.name.as_str()) == default) |
| 59 | { |
| 60 | let mut b = branches.remove(i); |
| 61 | b.is_default = true; |
| 62 | branches.insert(0, b); |
| 63 | } |
| 64 | let crumbs = vec![Crumb { |
| 65 | name: ctx.repo.name.clone(), |
| 66 | url: ctx.repo_url(), |
| 67 | }]; |
| 68 | let page = RefsPage { |
| 69 | layout: Layout::new( |
| 70 | ctx.state, |
| 71 | ctx.config, |
| 72 | Some(&format!("Refs · {}", ctx.repo.name)), |
| 73 | ), |
| 74 | nav: ctx.nav(Active::Refs, None, |_| String::new()), |
| 75 | crumbs, |
| 76 | here: Some("Refs".into()), |
| 77 | branches, |
| 78 | tags: refs.tags.iter().map(row).collect(), |
| 79 | }; |
| 80 | let mut res = render(StatusCode::OK, &page); |
| 81 | set_cache_headers(&mut res, &etag, false); |
| 82 | res |
| 83 | } |