From cdeabb06aa18ea941fdb14fcbb459ddb4785ac43 Mon Sep 17 00:00:00 2001 From: Aravinth Manivannan Date: Sat, 3 Dec 2022 14:56:17 +0530 Subject: [PATCH] feat: dashboard homepage. List existing deployments with add site btn --- src/pages/dash/home.rs | 56 ++++++--- src/pages/dash/mod.rs | 30 ++++- src/pages/mod.rs | 3 +- templates/main.scss | 8 ++ templates/pages/dash/index.html | 197 ++++++++++---------------------- templates/pages/dash/main.scss | 81 +++++++++++++ 6 files changed, 225 insertions(+), 150 deletions(-) create mode 100644 templates/pages/dash/main.scss diff --git a/src/pages/dash/home.rs b/src/pages/dash/home.rs index 9188002..2a95717 100644 --- a/src/pages/dash/home.rs +++ b/src/pages/dash/home.rs @@ -16,14 +16,23 @@ */ use std::cell::RefCell; +use actix_identity::Identity; use actix_web::http::header::ContentType; +use serde::{Deserialize, Serialize}; use tera::Context; +use super::get_auth_middleware; use crate::ctx::api::v1::auth::Login as LoginPayload; +use crate::db::Site; +use crate::errors::ServiceResult; use crate::pages::errors::*; use crate::settings::Settings; use crate::AppCtx; +use crate::pages::errors::*; + +use super::TemplateSiteEvent; + pub use super::*; pub const DASH_HOME: TemplateFile = TemplateFile::new("dash_home", "pages/dash/index.html"); @@ -32,6 +41,12 @@ pub struct Home { ctx: RefCell, } +#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] +pub struct TemplateSite { + site: Site, + last_update: Option, +} + impl CtxError for Home { fn with_error(&self, e: &ReadableError) -> String { self.ctx.borrow_mut().insert(ERROR_KEY, e); @@ -40,10 +55,10 @@ impl CtxError for Home { } impl Home { - pub fn new(settings: &Settings, payload: Option<&LoginPayload>) -> Self { + pub fn new(settings: &Settings, sites: Option<&[TemplateSite]>) -> Self { let ctx = RefCell::new(context(settings)); - if let Some(payload) = payload { - ctx.borrow_mut().insert(PAYLOAD_KEY, payload); + if let Some(sites) = sites { + ctx.borrow_mut().insert(PAYLOAD_KEY, sites); } Self { ctx } } @@ -53,19 +68,34 @@ impl Home { .render(DASH_HOME.name, &self.ctx.borrow()) .unwrap() } - - pub fn page(s: &Settings) -> String { - let p = Self::new(s, None); - p.render() - } } -#[actix_web_codegen_const_routes::get(path = "PAGES.dash.home")] -#[tracing::instrument(name = "Dashboard homepage", skip(ctx))] -pub async fn get_home(ctx: AppCtx) -> impl Responder { - let home = Home::page(&ctx.settings); +async fn get_site_data(ctx: &AppCtx, id: &Identity) -> ServiceResult> { + let db_sites = ctx.db.list_all_sites(&id.identity().unwrap()).await?; + let mut sites = Vec::with_capacity(db_sites.len()); + for site in db_sites { + // TODO: impl method on DB to get latest "update" event + let mut events = ctx.db.list_all_site_events(&site.hostname).await?; + let last_update = if let Some(event) = events.pop() { + Some(event.into()) + } else { + None + }; + + sites.push(TemplateSite { site, last_update }); + } + Ok(sites) +} + +#[actix_web_codegen_const_routes::get(path = "PAGES.dash.home", wrap = "get_auth_middleware()")] +#[tracing::instrument(name = "Dashboard homepage", skip(ctx, id))] +pub async fn get_home(ctx: AppCtx, id: Identity) -> PageResult { + let sites = get_site_data(&ctx, &id) + .await + .map_err(|e| PageError::new(Home::new(&ctx.settings, None), e))?; + let home = Home::new(&ctx.settings, Some(&sites)).render(); let html = ContentType::html(); - HttpResponse::Ok().content_type(html).body(home) + Ok(HttpResponse::Ok().content_type(html).body(home)) } pub fn services(cfg: &mut web::ServiceConfig) { diff --git a/src/pages/dash/mod.rs b/src/pages/dash/mod.rs index 1d1611b..31be843 100644 --- a/src/pages/dash/mod.rs +++ b/src/pages/dash/mod.rs @@ -15,15 +15,43 @@ * along with this program. If not, see . */ use actix_web::*; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; +pub use super::get_auth_middleware; pub use super::{context, Footer, TemplateFile, PAGES, PAYLOAD_KEY, TEMPLATES}; -mod home; +use crate::db::Event; +use crate::db::LibrePagesEvent; + +pub mod home; +pub mod sites; + +#[derive(Clone, Debug, Eq, PartialEq, Serialize, Deserialize)] +pub struct TemplateSiteEvent { + pub event_type: Event, + pub time: i64, + pub site: String, + pub id: Uuid, +} + +impl From for TemplateSiteEvent { + fn from(e: LibrePagesEvent) -> Self { + Self { + event_type: e.event_type, + time: e.time.unix_timestamp(), + site: e.site, + id: e.id, + } + } +} pub fn register_templates(t: &mut tera::Tera) { home::DASH_HOME.register(t).expect(home::DASH_HOME.name); + sites::register_templates(t); } pub fn services(cfg: &mut web::ServiceConfig) { home::services(cfg); + sites::services(cfg); } diff --git a/src/pages/mod.rs b/src/pages/mod.rs index b505cc6..335090e 100644 --- a/src/pages/mod.rs +++ b/src/pages/mod.rs @@ -146,8 +146,8 @@ pub async fn home(ctx: AppCtx, id: &Identity) -> HttpResponse { } pub fn services(cfg: &mut web::ServiceConfig) { - auth::services(cfg); dash::services(cfg); + auth::services(cfg); } #[cfg(test)] @@ -169,6 +169,7 @@ mod tests { auth::login::LOGIN, auth::register::REGISTER, errors::ERROR_TEMPLATE, + super::dash::home::DASH_HOME, ] .iter() { diff --git a/templates/main.scss b/templates/main.scss index ea4c173..cf3033c 100644 --- a/templates/main.scss +++ b/templates/main.scss @@ -1,5 +1,13 @@ @import "defaults.scss"; @import "pages/auth/sass/main.scss"; @import "pages/auth/sass/form/main.scss"; +@import "pages/dash/main.scss"; @import "components/sass/footer/main.scss"; @import "components/nav/sass/main.scss"; + +.default-body { + display: flex; + @include fullscreen; + flex-direction: column; + justify-content: space-between; +} diff --git a/templates/pages/dash/index.html b/templates/pages/dash/index.html index 1f5c17c..f03af90 100644 --- a/templates/pages/dash/index.html +++ b/templates/pages/dash/index.html @@ -1,3 +1,43 @@ +{% extends 'base' %} +{% block title %} Add Site{% endblock title %} +{% block nav %} {% include "auth_nav" %} {% endblock nav %} +{% block main %} + +
+ +
+ +{% endblock main %} + + diff --git a/templates/pages/dash/main.scss b/templates/pages/dash/main.scss new file mode 100644 index 0000000..5ca7e6a --- /dev/null +++ b/templates/pages/dash/main.scss @@ -0,0 +1,81 @@ +.sites__main { + width: 100%; + margin: 20px; +} + +.sites__collection { + margin: auto; + width: 70%; + + border: 1px solid #e8ebed; + border-radius: 8px; +} + +.sites__actions { + width: 100%; + height: 50px; + display: flex; + flex-direction: row-reverse; + align-items: center; + box-sizing: border-box; + padding: 0px 20px; + margin: 10px 0; +} + +.sites__actions__new-site { + min-height: 36px; + background: green; + display: flex; + align-items: center; + padding: 0px 8px; +} + +.sites__actions__new-site > button { + margin: 0; + padding: 0; + height: 100%; + border: none; + width: 100%; + color: white; + background: none; +} + +.site__container { + box-sizing: border-box; + margin: 10px 0; + width: 100%; + display: flex; + justify-content: space-between; + padding: 10px 20px; + align-items: center; +} + +.site__container:hover { + background: #f7f8f8; +} + +.site__info--head { + display: flex; + align-items: center; +} + +.site__info--column { + margin-left: 20px; +} + +.site__info--column > p, +.site__info--column > a { + margin: 0; + padding: 0; +} +.site__container:visited, +.site__container { + color: black; + text-decoration: none; +} + +.site__container--preview { + width: 50px; + height: 50px; + border-radius: 50%; +}