Skip to content

User interface #12

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 86 commits into from
Aug 26, 2016
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
86 commits
Select commit Hold shift + click to select a range
f59bc5f
Initial commit of user interface of cratesfyi
onur Jun 3, 2016
8b0e943
Use different class than search-input
onur Jun 23, 2016
04ff2f8
Syntax highlighting with highlightjs
onur Jun 23, 2016
f833e0f
Add most starred crates
onur Jun 26, 2016
e2e7ef9
Add author handler
onur Jul 2, 2016
1b91f74
Fix grid size
onur Jul 2, 2016
ee96a66
Add right margin to search input in navigation
onur Jul 2, 2016
5707a24
Show github fields (stars, forks, issue count)
onur Jul 3, 2016
fe75703
Improve responsive layout
onur Jul 3, 2016
16c447c
Fix github issue count
onur Jul 3, 2016
a8c15ac
Add colors for build status icons
onur Jul 10, 2016
e3581d9
Activate I am feeling lucky button
onur Jul 21, 2016
cfb9573
Add Rust submenu to navigation
onur Jul 21, 2016
0c05d5d
Set warning font-family to sans
onur Jul 21, 2016
77c9e5a
Use pure-min.css in rustdoc
onur Jul 22, 2016
c9c0da8
Revert "Use pure-min.css in rustdoc"
onur Jul 22, 2016
444ff0c
Use menus-min.css to get all purecss menu bundle
onur Jul 22, 2016
6b5b125
Serve static pages from CRATESFYI_PREFIX env var
onur Jul 22, 2016
559aa81
Add link colors to crates readme
onur Jul 22, 2016
9412409
Add set_status to Page
jonhoo Jul 22, 2016
ae38172
Add a less generic error type
jonhoo Jul 22, 2016
7ec10ad
Give error rendering access to templates
jonhoo Jul 22, 2016
7671714
Give more consistent rendering when content is missing
jonhoo Jul 22, 2016
92061ed
Handle searches with no query
jonhoo Jul 22, 2016
4b49358
Merge branch 'jonhoo-web-404' into web
onur Jul 23, 2016
4a0e000
Fix query
onur Jul 25, 2016
cb3a6af
Merge branch 'master' into web
onur Jul 25, 2016
15d746c
Bring start-web-server subcommand back
onur Jul 25, 2016
0916258
Don't 500 on a route with no match
mattyhall Jul 28, 2016
aebc5f0
Merge branch 'mattyhall-web' into web
onur Jul 29, 2016
70a485e
Merge branch 'master' into web
onur Jul 30, 2016
be6c7d6
Add release activity chart
onur Jul 23, 2016
c37a187
Reverse release activity vectors
onur Jul 30, 2016
2b97d6b
Update routes
onur Jul 30, 2016
17d3174
Add sponsor logo
onur Jul 30, 2016
1f3c0df
Show another warning if crate is not a library
onur Jul 31, 2016
a0c46a4
Replace cratesfyi with docs.rs in templates
onur Jul 31, 2016
1faf8dc
Add platform selector
onur Jul 31, 2016
2e4da75
Adjust platforms submenu
onur Jul 31, 2016
b1bf7f1
Add margin-bottom to warning container
onur Jul 31, 2016
b958995
Show completion rate for beta
onur Jul 31, 2016
f0933ca
Hide search input in navigation on small screens
onur Aug 8, 2016
f418de8
Hide navigation item titles on small screens
onur Aug 8, 2016
1871c03
Add padding to landing search form
onur Aug 8, 2016
6723cea
Fix platforms menu position on firefox
onur Aug 20, 2016
533cfec
Add metadata to Cargo.lock
onur Aug 20, 2016
c9bce04
Revert "Show completion rate for beta"
onur Aug 20, 2016
6c8db4f
Add about page
onur Aug 5, 2016
0b6e9de
Update about.hbs
GuillaumeGomez Aug 21, 2016
f80bec9
Update about.hbs
GuillaumeGomez Aug 21, 2016
6ffd678
Update about.hbs
GuillaumeGomez Aug 21, 2016
5c28a54
Add GuillaumeGomez and Mark-Simulacrum to contributors
onur Aug 21, 2016
ef9b33b
Increase size of search input in home page
onur Aug 21, 2016
eac99b7
Remove only padding from code blocks in readme
onur Aug 21, 2016
2c30ac6
Fix padding in navigation
onur Aug 21, 2016
6ba56f9
Add a bit padding and margin to left column in crate-details
onur Aug 21, 2016
f4a490a
Add underline text-decoration to a:hover's in about
onur Aug 21, 2016
7a54d0d
Add home icon to homepage link
onur Aug 21, 2016
5db7897
Remove builds tab
onur Aug 21, 2016
036b1bf
Decrease padding in navigation title and description
onur Aug 21, 2016
15b5516
Fix position of sidebar in rustdocs
onur Aug 21, 2016
707725f
Show builds tabs onlf if user on builds page
onur Aug 22, 2016
29491cb
Minimalize Rust submenu in navigation
onur Aug 22, 2016
ece1891
Add cache protection to style.css
onur Aug 22, 2016
8fd7261
Add update-release-activity subcommand
onur Aug 22, 2016
cb40f6f
Add simple daemon
onur Aug 23, 2016
a4e2973
Show error detail if a package fails to build in que
onur Aug 23, 2016
9826ca0
Merge branch 'master' into web-merge
onur Aug 23, 2016
0222cd3
Update daemon
onur Aug 24, 2016
f222804
Update sources before build
onur Aug 24, 2016
efdf588
Use plural form of platforms in navigation menu
onur Aug 24, 2016
10d26cd
Update search index every 3 hours
onur Aug 24, 2016
82e1eb1
Save pid file into prefix
onur Aug 24, 2016
e861688
Merge branch 'master' into web
onur Aug 24, 2016
64b42f4
Fix syntax
onur Aug 24, 2016
065a2f8
Update README
onur Aug 24, 2016
a0c6899
Merge branch 'doc' into web
onur Aug 24, 2016
4038d5f
Update README
onur Aug 24, 2016
cf27c9e
Add a bit margin to releases container
onur Aug 24, 2016
cc41c5a
Add github_updater to daemon
onur Aug 24, 2016
188700e
Increase delay between pull requests
onur Aug 26, 2016
6757c91
Update TODO's
onur Aug 26, 2016
ea2a91e
Fix title of about page
onur Aug 26, 2016
2ef3ffa
Fix email address
onur Aug 26, 2016
48d341a
Increase static file cache duration to 12 months
onur Aug 26, 2016
62fccee
Fix top position of sidebar
onur Aug 26, 2016
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions src/web/crate_details.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@



use super::{NoCrate, MetaData, duration_to_str, match_version, render_markdown};
use super::{MetaData, duration_to_str, match_version, render_markdown};
use super::error::Nope;
use super::page::Page;
use db::connect_db;
use iron::prelude::*;
Expand Down Expand Up @@ -194,7 +195,7 @@ pub fn crate_details_handler(req: &mut Request) -> IronResult<Response> {

match_version(&conn, &name, req_version)
.and_then(|version| CrateDetails::new(&conn, &name, &version))
.ok_or(IronError::new(NoCrate, status::NotFound))
.ok_or(IronError::new(Nope::CrateNotFound, status::NotFound))
.and_then(|details| {
Page::new(details)
.set_true("show_package_navigation")
Expand Down
68 changes: 68 additions & 0 deletions src/web/error.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
use std::error::Error;
use iron::prelude::*;
use iron::Handler;
use iron::status;
use web::page::Page;
use std::fmt;

#[derive(Debug, Copy, Clone)]
pub enum Nope {
ResourceNotFound,
CrateNotFound,
NoResults,
}

impl fmt::Display for Nope {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(self.description())
}
}

impl Error for Nope {
fn description(&self) -> &str {
match *self {
Nope::ResourceNotFound => "Requested resource not found",
Nope::CrateNotFound => "Requested crate not found",
Nope::NoResults => "Search yielded no results",
}
}
}

impl Handler for Nope {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
match *self {
Nope::ResourceNotFound => {
// user tried to navigate to a resource (doc page/file) that doesn't exist
Page::new("no such resource".to_owned())
.set_status(status::NotFound)
.title("The requested resource does not exist")
.to_resp("error")
}
Nope::CrateNotFound => {
// user tried to navigate to a crate that doesn't exist
Page::new("no such crate".to_owned())
.set_status(status::NotFound)
.title("The requested crate does not exist")
.to_resp("error")
}
Nope::NoResults => {
use params::{Params, Value};
let params = req.get::<Params>().unwrap();
if let Some(&Value::String(ref query)) = params.find(&["query"]) {
// this used to be a search
Page::new(Vec::<super::releases::Release>::new())
.set_status(status::NotFound)
.set("search_query", &query)
.title(&format!("No crates found matching '{}'", query))
.to_resp("releases")
} else {
// user did a search with no search terms
Page::new(Vec::<super::releases::Release>::new())
.set_status(status::NotFound)
.title("No results given for empty search query")
.to_resp("releases")
}
}
}
}
}
2 changes: 1 addition & 1 deletion src/web/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ impl Handler for DatabaseFileHandler {
if let Some(file) = File::from_path(&conn, &path) {
Ok(file.serve())
} else {
Err(IronError::new(super::NoCrate, status::NotFound))
Err(IronError::new(super::error::Nope::CrateNotFound, status::NotFound))
}
}
}
85 changes: 38 additions & 47 deletions src/web/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,14 @@ mod source;
mod pool;
mod file;
mod builds;
mod error;

use std::{env, fmt};
use std::env;
use std::error::Error;
use std::time::Duration;
use std::path::PathBuf;
use iron::prelude::*;
use iron::{status, Handler};
use iron::Handler;
use router::Router;
use staticfile::Static;
use handlebars_iron::{HandlebarsEngine, DirectorySource};
Expand All @@ -31,22 +32,6 @@ use std::collections::BTreeMap;
const STATIC_FILE_CACHE_DURATION: u64 = 60 * 60 * 24 * 3; // 3 days


// This is a generic error used in routes
#[derive(Debug)]
struct NoCrate;

impl fmt::Display for NoCrate {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str("Crate not found.")
}
}

impl Error for NoCrate {
fn description(&self) -> &str { "No Crate" }
}



struct CratesfyiHandler {
router_handler: Box<Handler>,
database_file_handler: Box<Handler>,
Expand All @@ -55,6 +40,22 @@ struct CratesfyiHandler {


impl CratesfyiHandler {
fn chain<H: Handler>(base: H) -> Chain {
// TODO: Use DocBuilderOptions for paths
let mut hbse = HandlebarsEngine::new();
hbse.add(Box::new(DirectorySource::new("./templates", ".hbs")));

// load templates
if let Err(e) = hbse.reload() {
panic!("Failed to load handlebar templates: {}", e.description());
}

let mut chain = Chain::new(base);
chain.link_before(pool::Pool::new());
chain.link_after(hbse);
chain
}

pub fn new() -> CratesfyiHandler {
let mut router = Router::new();
router.get("/", releases::home_page);
Expand All @@ -79,19 +80,7 @@ impl CratesfyiHandler {
router.get("/source/:name/:version/*", source::source_browser_handler);
router.get("/search", releases::search_handler);

// TODO: Use DocBuilderOptions for paths
let mut hbse = HandlebarsEngine::new();
hbse.add(Box::new(DirectorySource::new("./templates", ".hbs")));

// load templates
if let Err(e) = hbse.reload() {
panic!("Failed to load handlebar templates: {}", e.description());
}

let mut router_chain = Chain::new(router);
router_chain.link_before(pool::Pool::new());
router_chain.link_after(hbse);

let router_chain = Self::chain(router);
let prefix = PathBuf::from(env::var("CRATESFYI_PREFIX").unwrap()).join("public_html");
let static_handler = Static::new(prefix)
.cache(Duration::from_secs(STATIC_FILE_CACHE_DURATION));
Expand All @@ -107,23 +96,25 @@ impl CratesfyiHandler {

impl Handler for CratesfyiHandler {
fn handle(&self, req: &mut Request) -> IronResult<Response> {
// try router first then staticfile handler
// try router first then db/static file handler
// return 404 if none of them return Ok
match self.router_handler.handle(req) {
Ok(res) => return Ok(res),
Err(e) => debug!("{}", e.description())
};

// if router fails try to serve files from database first
// and then try static handler. if all of them fails, return 404
// TODO: Add a custom 404 page
if let Ok(res) = self.database_file_handler.handle(req) {
Ok(res)
} else if let Ok(res) = self.static_handler.handle(req) {
Ok(res)
} else {
Ok(Response::with((status::NotFound, "404 FAILED IN CRATESFYIHANDLER")))
}
self.router_handler
.handle(req)
.or_else(|e| {
// if router fails try to serve files from database first
self.database_file_handler.handle(req).or(Err(e))
})
.or_else(|e| {
// and then try static handler. if all of them fails, return 404
self.static_handler.handle(req).or(Err(e))
})
.or_else(|e| {
debug!("{}", e.description());
let err: error::Nope = *e.error
.downcast::<error::Nope>()
.expect("all cratesfyi errors should be of type Nope");
Self::chain(err).handle(req)
})
}
}

Expand Down
14 changes: 12 additions & 2 deletions src/web/page.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use handlebars_iron::Template;
pub struct Page<T: ToJson> {
title: Option<String>,
content: T,
status: status::Status,
varss: BTreeMap<String, String>,
varsb: BTreeMap<String, bool>,
varsi: BTreeMap<String, i64>,
Expand All @@ -21,6 +22,7 @@ impl<T: ToJson> Page<T> {
Page {
title: None,
content: content,
status: status::Ok,
varss: BTreeMap::new(),
varsb: BTreeMap::new(),
varsi: BTreeMap::new(),
Expand Down Expand Up @@ -62,10 +64,18 @@ impl<T: ToJson> Page<T> {
}


pub fn to_resp(self, template: &str) -> IronResult<Response> {
/// Sets status code for response
pub fn set_status(mut self, s: status::Status) -> Page<T> {
self.status = s;
self
}


pub fn to_resp(self, template: &str) -> IronResult<Response> {
let mut resp = Response::new();
let status = self.status;
let temp = Template::new(template, self);
resp.set_mut(temp).set_mut(status::Ok);
resp.set_mut(temp).set_mut(status);
Ok(resp)
}
}
Expand Down
17 changes: 9 additions & 8 deletions src/web/releases.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
//! Releases web handlers


use super::{NoCrate, duration_to_str, match_version};
use super::{duration_to_str, match_version};
use super::error::Nope;
use super::page::Page;
use super::pool::Pool;
use iron::prelude::*;
Expand All @@ -19,7 +20,7 @@ const RELEASES_IN_HOME: i64 = 15;
const RELEASES_IN_RELEASES: i64 = 30;


struct Release {
pub struct Release {
name: String,
version: String,
description: Option<String>,
Expand Down Expand Up @@ -243,7 +244,7 @@ pub fn releases_handler(req: &mut Request) -> IronResult<Response> {
let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::ReleaseTime);

if packages.is_empty() {
return Err(IronError::new(NoCrate, status::NotFound));
return Err(IronError::new(Nope::CrateNotFound, status::NotFound));
}

// Show next and previous page buttons
Expand Down Expand Up @@ -280,7 +281,7 @@ pub fn stars_handler(req: &mut Request) -> IronResult<Response> {
let packages = get_releases(conn, page_number, RELEASES_IN_RELEASES, Order::GithubStars);

if packages.is_empty() {
return Err(IronError::new(NoCrate, status::NotFound));
return Err(IronError::new(Nope::CrateNotFound, status::NotFound));
}

// Show next and previous page buttons
Expand Down Expand Up @@ -317,7 +318,7 @@ pub fn author_handler(req: &mut Request) -> IronResult<Response> {
let author = req.extensions.get::<Router>().unwrap().find("author");

if author.is_none() {
return Err(IronError::new(NoCrate, status::NotFound));
return Err(IronError::new(Nope::CrateNotFound, status::NotFound));
}

let (author_name, packages) = get_releases_by_author(conn,
Expand All @@ -326,7 +327,7 @@ pub fn author_handler(req: &mut Request) -> IronResult<Response> {
author.unwrap());

if packages.is_empty() {
return Err(IronError::new(NoCrate, status::NotFound));
return Err(IronError::new(Nope::CrateNotFound, status::NotFound));
}

// Show next and previous page buttons
Expand Down Expand Up @@ -383,7 +384,7 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {

let search_query = query.replace(" ", " & ");
get_search_results(&conn, &search_query, 1, RELEASES_IN_RELEASES)
.ok_or(IronError::new(NoCrate, status::NotFound))
.ok_or(IronError::new(Nope::NoResults, status::NotFound))
.and_then(|(_, results)| {
// FIXME: There is no pagination
Page::new(results)
Expand All @@ -392,6 +393,6 @@ pub fn search_handler(req: &mut Request) -> IronResult<Response> {
.to_resp("releases")
})
} else {
Err(IronError::new(NoCrate, status::NotFound))
Err(IronError::new(Nope::NoResults, status::NotFound))
}
}
9 changes: 5 additions & 4 deletions src/web/rustdoc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use iron::prelude::*;
use iron::{status, Url};
use iron::modifiers::Redirect;
use router::Router;
use super::{NoCrate, match_version};
use super::match_version;
use super::error::Nope;
use super::page::Page;
use rustc_serialize::json::{Json, ToJson};
use std::collections::BTreeMap;
Expand Down Expand Up @@ -88,7 +89,7 @@ pub fn rustdoc_redirector_handler(req: &mut Request) -> IronResult<Response> {

let version = match match_version(&conn, &crate_name, req_version) {
Some(v) => v,
None => return Err(IronError::new(NoCrate, status::NotFound)),
None => return Err(IronError::new(Nope::CrateNotFound, status::NotFound)),
};

// get target name
Expand Down Expand Up @@ -119,14 +120,14 @@ pub fn rustdoc_html_server_handler(req: &mut Request) -> IronResult<Response> {

// don't touch anything other than html files
if !path.ends_with(".html") {
return Err(IronError::new(NoCrate, status::NotFound));
return Err(IronError::new(Nope::ResourceNotFound, status::NotFound));
}

let conn = req.extensions.get::<Pool>().unwrap();

let file = match File::from_path(&conn, &path) {
Some(f) => f,
None => return Err(IronError::new(NoCrate, status::NotFound)),
None => return Err(IronError::new(Nope::ResourceNotFound, status::NotFound)),
};

let (mut in_head, mut in_body) = (false, false);
Expand Down
2 changes: 2 additions & 0 deletions templates/error.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
{{> header}}
{{> footer}}
Loading