lmjtfy.git / apps / lmjtfy / src / view / repos.rs
repos.rsannotatedrepos.rssource137 lines · 5.8 KB · raw

The code host's front page: every repository the Worker serves, each with the command that clones it and a button that copies it. Pure: the listings in, markup out. Which repositories there are is not decided here; clone::Repo::ALL is, and the Worker hands that over.

6use maud::{DOCTYPE, Markup, PreEscaped, html};
8use super::code::{Meta, Project, preview};
9use super::{JS, clone_line_as, head, icon, icons, nav};
10use crate::host::Host;

One repository, as the page lists it.

13pub struct Listing {
14    pub project: Project,

What to run to clone it, from the code host's address.

16    pub command: String,

What GitHub says about it; None if GitHub could not be read.

18    pub meta: Option<Meta>,
19}

What the copy button of a repository copies: clone-lmjtfy.git.

22fn copied(project: &Project) -> String {
23    format!("clone-{}", project.served)
24}

GET / at the code host. origin is where the page is, for its picture.

27pub fn page(origin: &str, listings: &[Listing]) -> Markup {
28    let about = "Every repository served here, and the command to clone it. No GitHub account needed.";
29    html! {
30        (DOCTYPE)
31        html lang="en" {
32            (head(preview(origin, "lmjtfy.git", "LMJTFY · the code", about, "main")))
33            body {
34                div .sheet {
35                    div .wrap {
36                        (nav(Host::Code))
37                        div .headline {
38                            p .eyebrow { "git clone ............. code.lmjtfy.fun" }
39                            h1 { "The Code" }
40                        }
41                        div .stack {
42                            @for listing in listings {
43                                (card(listing))
44                            }
45                            p .meta {
46                                "It can be cloned and pulled, and nothing else. Open a repository to read it. "
47                                "The site itself is at " a href=(Host::Code.home_link()) { "lmjtfy.fun" } "."
48                            }
49                        }
50                    }
51                }
52                script { (PreEscaped(JS)) }
53            }
54        }
55    }
56}
58fn card(listing: &Listing) -> Markup {
59    let project = &listing.project;
60    html! {
61        div .win {
62            div .bar-title {
63                (icon(&icons::JEV, ""))
64                a .dark href={ "/" (project.served) } { (project.served) }
65                span .meta { (project.branch) }
66            }
67            div .body {
68                @if let Some(meta) = &listing.meta {
69                    @if !meta.about().is_empty() { p { (meta.about()) } }
70                    (meta.details())
71                }
72                (clone_line_as(&copied(project), &listing.command, html! { a href={ "/" (project.served) } { "Browse:" } }))
73            }
74        }
75    }
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81    use crate::clone::Repo;
82
83    fn listings(origin: &str) -> Vec<Listing> {
84        Repo::ALL.iter().map(|repo| Listing { project: repo.project(), command: repo.command(origin), meta: None }).collect()
85    }

The page is what the Worker serves, and nothing else: every repository in Repo::ALL is on it, once, with its own command and its own copy button, and a repository is on it only if it can be cloned.

90    #[test]
91    fn the_page_lists_every_served_repository_and_only_those() {
92        let html = page("https://code.x.test", &listings("https://code.x.test")).into_string();
93        for repo in Repo::ALL {
94            let served = repo.served();
95            let command = format!("<code id=\"clone-{served}\">{}</code>", repo.command("https://code.x.test"));
96            assert_eq!(html.matches(&command).count(), 1, "{served}: {html}");
97            assert!(html.contains(&format!("data-copy=\"clone-{served}\"")), "{served}");
98            assert!(html.contains(&format!("href=\"/{served}\"")), "{served}");
99            assert_eq!(Repo::named(served), Some(repo));
100        }
101        // Every command on the page is one of them.
102        assert_eq!(html.matches("<code id=\"clone-").count(), Repo::ALL.len(), "{html}");
103        assert_eq!(html.matches("data-copy=").count(), Repo::ALL.len());
104        // A name that is not served is not offered.
105        assert!(!html.contains("nosuchrepo"), "{html}");
106    }
108    #[test]
109    fn a_card_shows_what_github_says_and_nothing_when_it_says_nothing() {
110        let mut all = listings("https://code.x.test");
111        all[0].meta = Meta::parse(r#"{"description":"Says <hi>.","homepage":"https://w.test","topics":["rust"]}"#);
112        let html = page("https://code.x.test", &all).into_string();
113        assert!(html.contains("<p>Says &lt;hi&gt;.</p>"), "{html}");
114        assert!(html.contains(r#"<span class="topic">rust</span>"#), "{html}");
115        assert!(html.contains(r#"href="https://w.test""#), "{html}");
116        // The other cards had no answer: no paragraph, no chips.
117        assert_eq!(html.matches("class=\"topic\"").count(), 1);
118        assert_eq!(html.matches("<p>").count(), 1, "{html}");
119    }
120
121    #[test]
122    fn a_repository_with_a_submodule_is_cloned_with_it() {
123        let html = page("https://code.x.test", &listings("https://code.x.test")).into_string();
124        assert!(html.contains("git clone --recurse-submodules https://code.x.test/lmjtfy.git"), "{html}");
125        assert!(html.contains("git clone https://code.x.test/jevcrates.git<"), "{html}");
126    }
127
128    #[test]
129    fn the_page_does_not_reach_for_the_live_routes() {
130        let html = page("https://code.x.test", &[]).into_string();
131        // No place for page.js to open a socket into, and the title leads
132        // home to the other address.
133        assert!(!html.contains("id=\"online\""), "{html}");
134        assert!(!html.contains("id=\"toasts\""), "{html}");
135        assert!(html.contains("<a href=\"https://lmjtfy.fun/\">LMJTFY</a>"), "{html}");
136    }
137}