From a1d7e149841f65c1b58dc56f0d71777c3fec60d0 Mon Sep 17 00:00:00 2001 From: eraden Date: Thu, 29 Apr 2021 23:21:48 +0200 Subject: [PATCH] Some issue information, better look, issues count --- jirs-client/js/css/epicsPage.scss | 59 +++++++++++++---- jirs-client/src/pages/epics_page/model.rs | 30 +++++++-- jirs-client/src/pages/epics_page/update.rs | 10 ++- jirs-client/src/pages/epics_page/view.rs | 76 ++++++++++++++++------ 4 files changed, 140 insertions(+), 35 deletions(-) diff --git a/jirs-client/js/css/epicsPage.scss b/jirs-client/js/css/epicsPage.scss index f2c9fc1d..115afcdf 100644 --- a/jirs-client/js/css/epicsPage.scss +++ b/jirs-client/js/css/epicsPage.scss @@ -1,5 +1,8 @@ #epics { > section { + max-width: 1024px; + margin: 0 auto; + > h1 { font-family: var(--font-bold); } @@ -7,7 +10,8 @@ > .description { font-family: var(--font-regular); margin: { - top: 5px; + top: 16px; + bottom: 16px; } } @@ -22,19 +26,52 @@ > li.epic { padding: 0; - margin: { - top: 5px; - bottom: 5px; - }; - display: flex; - justify-content: space-between; + margin: 5px 0 0; - > .epicName { - // + > .firstRow { + display: flex; + justify-content: space-between; + margin: { + top: 5px; + bottom: 5px; + }; + + > .epicName { + font-family: var(--font-black); + font-size: 16px; + } + + > .date { + width: 400px; + display: flex; + justify-content: space-between; + } + + > .counter { + // + } } - > .date { - width: 250px; + > .secondRow { + margin: { + top: 5px; + bottom: 5px; + left: 20px; + right: 20px; + }; + + > .issues { + > .issue { + display: flex; + justify-content: space-between; + + > .flags { + display: flex; + justify-content: space-between; + width: 40px; + } + } + } } } } diff --git a/jirs-client/src/pages/epics_page/model.rs b/jirs-client/src/pages/epics_page/model.rs index a22bd356..4003b4f0 100644 --- a/jirs-client/src/pages/epics_page/model.rs +++ b/jirs-client/src/pages/epics_page/model.rs @@ -1,8 +1,30 @@ -#[derive(Debug)] -pub struct EpicsPage {} +use std::collections::HashMap; + +use jirs_data::{EpicId, IssueId}; + +use crate::model::Model; + +#[derive(Debug, Default)] +pub struct EpicsPage { + pub(crate) issues_per_epic: HashMap>, +} impl EpicsPage { - pub fn new() -> Self { - Self {} + pub fn new(model: &Model) -> Self { + let issues_per_epic = Self::build_issues_per_epic(model); + Self { issues_per_epic } + } + + pub fn build_issues_per_epic(model: &Model) -> HashMap> { + model.issues().iter().fold(HashMap::new(), |mut h, issue| { + if let Some(epic_id) = issue.epic_id.as_ref() { + h.entry(*epic_id).or_default().push(issue.id); + } + h + }) + } + + pub fn issues(&self, epic_id: EpicId) -> Option<&Vec> { + self.issues_per_epic.get(&epic_id) } } diff --git a/jirs-client/src/pages/epics_page/update.rs b/jirs-client/src/pages/epics_page/update.rs index 14a4ff7f..b5bf2af6 100644 --- a/jirs-client/src/pages/epics_page/update.rs +++ b/jirs-client/src/pages/epics_page/update.rs @@ -1,6 +1,7 @@ use seed::app::Orders; use crate::model::{Model, Page, PageContent}; +use crate::pages::epics_page::EpicsPage; use crate::ws::board_load; use crate::{Msg, OperationKind, ResourceKind}; @@ -21,10 +22,17 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order board_load(model, orders); build_page_content(model); } + Msg::ResourceChanged(ResourceKind::Issue, OperationKind::ListLoaded, ..) => { + let hash = EpicsPage::build_issues_per_epic(model); + crate::match_page_mut!(model, Epics).issues_per_epic = hash; + } _ => (), } } fn build_page_content(model: &mut Model) { - model.page_content = PageContent::Epics(Box::new(super::EpicsPage::new())); + if matches!(model.page_content, PageContent::Epics(..)) { + return; + } + model.page_content = PageContent::Epics(Box::new(super::EpicsPage::new(model))); } diff --git a/jirs-client/src/pages/epics_page/view.rs b/jirs-client/src/pages/epics_page/view.rs index d9d325d0..2fa32a1c 100644 --- a/jirs-client/src/pages/epics_page/view.rs +++ b/jirs-client/src/pages/epics_page/view.rs @@ -1,38 +1,49 @@ use chrono::NaiveDateTime; +use jirs_data::Issue; use seed::prelude::*; use seed::*; +use crate::components::styled_icon::{Icon, StyledIcon}; use crate::model::Model; use crate::shared::inner_layout; use crate::Msg; pub fn view(model: &Model) -> Node { + let page = crate::match_page!(model, Epics; Empty); + let epics: Vec> = model .epics .iter() .map(|epic| { + let issues = page + .issues(epic.id) + .map(|v| { + v.iter() + .filter_map(|i| model.issues_by_id.get(i)) + .collect::>() + }) + .unwrap_or_default(); + li![ C!["epic"], - div![C!["epicName"], &epic.name], div![ - C!["date"], + C!["firstRow"], + div![C!["epicName"], &epic.name], div![ - C!["startsAt"], - span!["Stats At:"], - span![epic - .starts_at - .as_ref() - .map(|d| format!("{}", d.format("%e %B %Y"))) - .unwrap_or_default()] + C!["date"], + date_field("Starts at:", "startsAt", epic.starts_at.as_ref()), + date_field("Ends at:", "endsAt", epic.ends_at.as_ref()), ], + div![C!["counter"], "Number of issues:", issues.len()], + ], + div![ + C!["secondRow"], div![ - C!["endsAt"], - span!["Ends At: "], - span![epic - .ends_at - .as_ref() - .map(|d| format!("{}", d.format("%e %B %Y"))) - .unwrap_or_default()] + C!["issues"], + issues + .into_iter() + .map(|issue| render_issue(issue)) + .collect::>>() ] ] ] @@ -44,14 +55,41 @@ pub fn view(model: &Model) -> Node { "epics", &[section![ h1!["Epics"], - p!["Epics and issues grouped in them"], + p![C!["description"], "Epics and issues grouped in them"], ul![C!["epicsList"], epics] ]], ) } -fn date_field(name: &str, date: Option<&NaiveDateTime>) -> Node { +fn date_field( + name: &'static str, + class_name: &'static str, + date: Option<&NaiveDateTime>, +) -> Node { match date { - _ => Node::Empty, + None => Node::Empty, + Some(d) => div![ + C![class_name], + span![name], + span![format!("{}", d.format("%e %B %Y"))] + ], } } + +fn render_issue(issue: &Issue) -> Node { + div![ + C!["issue"], + div![C!["name"], issue.title.as_str()], + div![ + C!["flags"], + div![ + C!["type"], + StyledIcon::from(Icon::from(issue.issue_type)).render() + ], + div![ + C!["priority"], + StyledIcon::from(Icon::from(issue.priority)).render() + ], + ] + ] +}