Some issue information, better look, issues count
This commit is contained in:
parent
8ae4cc22ba
commit
a1d7e14984
@ -1,5 +1,8 @@
|
|||||||
#epics {
|
#epics {
|
||||||
> section {
|
> section {
|
||||||
|
max-width: 1024px;
|
||||||
|
margin: 0 auto;
|
||||||
|
|
||||||
> h1 {
|
> h1 {
|
||||||
font-family: var(--font-bold);
|
font-family: var(--font-bold);
|
||||||
}
|
}
|
||||||
@ -7,7 +10,8 @@
|
|||||||
> .description {
|
> .description {
|
||||||
font-family: var(--font-regular);
|
font-family: var(--font-regular);
|
||||||
margin: {
|
margin: {
|
||||||
top: 5px;
|
top: 16px;
|
||||||
|
bottom: 16px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -22,19 +26,52 @@
|
|||||||
|
|
||||||
> li.epic {
|
> li.epic {
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: {
|
margin: 5px 0 0;
|
||||||
top: 5px;
|
|
||||||
bottom: 5px;
|
|
||||||
};
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-between;
|
|
||||||
|
|
||||||
> .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 {
|
> .secondRow {
|
||||||
width: 250px;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,30 @@
|
|||||||
#[derive(Debug)]
|
use std::collections::HashMap;
|
||||||
pub struct EpicsPage {}
|
|
||||||
|
use jirs_data::{EpicId, IssueId};
|
||||||
|
|
||||||
|
use crate::model::Model;
|
||||||
|
|
||||||
|
#[derive(Debug, Default)]
|
||||||
|
pub struct EpicsPage {
|
||||||
|
pub(crate) issues_per_epic: HashMap<EpicId, Vec<IssueId>>,
|
||||||
|
}
|
||||||
|
|
||||||
impl EpicsPage {
|
impl EpicsPage {
|
||||||
pub fn new() -> Self {
|
pub fn new(model: &Model) -> Self {
|
||||||
Self {}
|
let issues_per_epic = Self::build_issues_per_epic(model);
|
||||||
|
Self { issues_per_epic }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_issues_per_epic(model: &Model) -> HashMap<EpicId, Vec<IssueId>> {
|
||||||
|
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<IssueId>> {
|
||||||
|
self.issues_per_epic.get(&epic_id)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use seed::app::Orders;
|
use seed::app::Orders;
|
||||||
|
|
||||||
use crate::model::{Model, Page, PageContent};
|
use crate::model::{Model, Page, PageContent};
|
||||||
|
use crate::pages::epics_page::EpicsPage;
|
||||||
use crate::ws::board_load;
|
use crate::ws::board_load;
|
||||||
use crate::{Msg, OperationKind, ResourceKind};
|
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);
|
board_load(model, orders);
|
||||||
build_page_content(model);
|
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) {
|
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)));
|
||||||
}
|
}
|
||||||
|
@ -1,38 +1,49 @@
|
|||||||
use chrono::NaiveDateTime;
|
use chrono::NaiveDateTime;
|
||||||
|
use jirs_data::Issue;
|
||||||
use seed::prelude::*;
|
use seed::prelude::*;
|
||||||
use seed::*;
|
use seed::*;
|
||||||
|
|
||||||
|
use crate::components::styled_icon::{Icon, StyledIcon};
|
||||||
use crate::model::Model;
|
use crate::model::Model;
|
||||||
use crate::shared::inner_layout;
|
use crate::shared::inner_layout;
|
||||||
use crate::Msg;
|
use crate::Msg;
|
||||||
|
|
||||||
pub fn view(model: &Model) -> Node<Msg> {
|
pub fn view(model: &Model) -> Node<Msg> {
|
||||||
|
let page = crate::match_page!(model, Epics; Empty);
|
||||||
|
|
||||||
let epics: Vec<Node<Msg>> = model
|
let epics: Vec<Node<Msg>> = model
|
||||||
.epics
|
.epics
|
||||||
.iter()
|
.iter()
|
||||||
.map(|epic| {
|
.map(|epic| {
|
||||||
|
let issues = page
|
||||||
|
.issues(epic.id)
|
||||||
|
.map(|v| {
|
||||||
|
v.iter()
|
||||||
|
.filter_map(|i| model.issues_by_id.get(i))
|
||||||
|
.collect::<Vec<&Issue>>()
|
||||||
|
})
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
li![
|
li![
|
||||||
C!["epic"],
|
C!["epic"],
|
||||||
div![C!["epicName"], &epic.name],
|
|
||||||
div![
|
div![
|
||||||
C!["date"],
|
C!["firstRow"],
|
||||||
|
div![C!["epicName"], &epic.name],
|
||||||
div![
|
div![
|
||||||
C!["startsAt"],
|
C!["date"],
|
||||||
span!["Stats At:"],
|
date_field("Starts at:", "startsAt", epic.starts_at.as_ref()),
|
||||||
span![epic
|
date_field("Ends at:", "endsAt", epic.ends_at.as_ref()),
|
||||||
.starts_at
|
|
||||||
.as_ref()
|
|
||||||
.map(|d| format!("{}", d.format("%e %B %Y")))
|
|
||||||
.unwrap_or_default()]
|
|
||||||
],
|
],
|
||||||
|
div![C!["counter"], "Number of issues:", issues.len()],
|
||||||
|
],
|
||||||
|
div![
|
||||||
|
C!["secondRow"],
|
||||||
div![
|
div![
|
||||||
C!["endsAt"],
|
C!["issues"],
|
||||||
span!["Ends At: "],
|
issues
|
||||||
span![epic
|
.into_iter()
|
||||||
.ends_at
|
.map(|issue| render_issue(issue))
|
||||||
.as_ref()
|
.collect::<Vec<Node<Msg>>>()
|
||||||
.map(|d| format!("{}", d.format("%e %B %Y")))
|
|
||||||
.unwrap_or_default()]
|
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
]
|
]
|
||||||
@ -44,14 +55,41 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
"epics",
|
"epics",
|
||||||
&[section![
|
&[section![
|
||||||
h1!["Epics"],
|
h1!["Epics"],
|
||||||
p!["Epics and issues grouped in them"],
|
p![C!["description"], "Epics and issues grouped in them"],
|
||||||
ul![C!["epicsList"], epics]
|
ul![C!["epicsList"], epics]
|
||||||
]],
|
]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn date_field(name: &str, date: Option<&NaiveDateTime>) -> Node<Msg> {
|
fn date_field(
|
||||||
|
name: &'static str,
|
||||||
|
class_name: &'static str,
|
||||||
|
date: Option<&NaiveDateTime>,
|
||||||
|
) -> Node<Msg> {
|
||||||
match date {
|
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<Msg> {
|
||||||
|
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()
|
||||||
|
],
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user