Small refactor
This commit is contained in:
parent
1117e878a8
commit
e5280618aa
@ -307,11 +307,21 @@ impl Model {
|
||||
self.user.as_ref().map(|u| u.id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn user_name(&self) -> Option<&str> {
|
||||
self.user.as_ref().map(|u| u.name())
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn project_id(&self) -> Option<ProjectId> {
|
||||
self.project.as_ref().map(|p| p.id)
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn project_name(&self) -> Option<&str> {
|
||||
self.project.as_ref().map(|u| u.name())
|
||||
}
|
||||
|
||||
pub fn current_user_role(&self) -> UserRole {
|
||||
self.current_user_project
|
||||
.as_ref()
|
||||
|
@ -22,16 +22,11 @@ pub fn view(model: &Model) -> Node<Msg> {
|
||||
}
|
||||
|
||||
fn breadcrumbs(model: &Model) -> Node<Msg> {
|
||||
let project_name = model
|
||||
.project
|
||||
.as_ref()
|
||||
.map(|p| p.name.as_str())
|
||||
.unwrap_or_default();
|
||||
div![
|
||||
C!["breadcrumbsContainer"],
|
||||
span!["Projects"],
|
||||
span![C!["breadcrumbsDivider"], "/"],
|
||||
span![project_name],
|
||||
span![model.project_name().unwrap_or_default()],
|
||||
span![C!["breadcrumbsDivider"], "/"],
|
||||
span!["Kanban Board"]
|
||||
]
|
||||
@ -41,17 +36,16 @@ fn header(model: &Model) -> Node<Msg> {
|
||||
if !model.show_extras {
|
||||
return Node::Empty;
|
||||
}
|
||||
let button = StyledButton::secondary_with_text_and_icon(
|
||||
"Repository",
|
||||
StyledIcon::from(Icon::Github).render(),
|
||||
)
|
||||
.render();
|
||||
div![
|
||||
id!["projectBoardHeader"],
|
||||
div![id!["boardName"], C!["headerChild"], "Kanban board"],
|
||||
a![
|
||||
attrs![At::Href => "https://gitlab.com/adrian.wozniak/jirs", At::Target => "__blank", At::Rel => "noreferrer noopener"],
|
||||
button
|
||||
StyledButton::secondary_with_text_and_icon(
|
||||
"Repository",
|
||||
StyledIcon::from(Icon::Github).render(),
|
||||
)
|
||||
.render()
|
||||
]
|
||||
]
|
||||
}
|
||||
|
@ -6,13 +6,12 @@ use crate::components::styled_avatar::*;
|
||||
use crate::components::styled_button::{ButtonVariant, StyledButton};
|
||||
use crate::components::styled_icon::*;
|
||||
use crate::model::PageContent;
|
||||
use crate::{BoardPageChange, Model, Msg, Page, PageChanged};
|
||||
use crate::{match_page, BoardPageChange, Model, Msg, Page, PageChanged};
|
||||
|
||||
#[inline(always)]
|
||||
pub fn project_board_lists(model: &Model) -> Node<Msg> {
|
||||
let project_page = match &model.page_content {
|
||||
PageContent::Project(project_page) => project_page,
|
||||
_ => return empty![],
|
||||
};
|
||||
let project_page = match_page!(model, Project; Empty);
|
||||
|
||||
let rows = project_page.visible_issues.iter().map(|per_epic| {
|
||||
let columns: Vec<Node<Msg>> = per_epic
|
||||
.per_status_issues
|
||||
@ -78,6 +77,7 @@ pub fn project_board_lists(model: &Model) -> Node<Msg> {
|
||||
div![C!["rows"], rows]
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
fn project_issue_list(
|
||||
model: &Model,
|
||||
status_id: IssueStatusId,
|
||||
@ -86,7 +86,7 @@ fn project_issue_list(
|
||||
) -> Node<Msg> {
|
||||
let issues: Vec<Node<Msg>> = issues
|
||||
.iter()
|
||||
.map(|issue| project_issue(model, issue))
|
||||
.map(|issue| ProjectIssue { model, issue }.render())
|
||||
.collect();
|
||||
let drop_handler = {
|
||||
let send_status = status_id;
|
||||
@ -121,15 +121,23 @@ fn project_issue_list(
|
||||
]
|
||||
}
|
||||
|
||||
fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
||||
let is_dragging = match &model.page_content {
|
||||
pub struct ProjectIssue<'l> {
|
||||
pub model: &'l Model,
|
||||
pub issue: &'l Issue,
|
||||
}
|
||||
|
||||
impl<'l> ProjectIssue<'l> {
|
||||
#[inline(always)]
|
||||
pub fn render(self) -> Node<Msg> {
|
||||
let is_dragging = match &self.model.page_content {
|
||||
PageContent::Project(project_page) => project_page.issue_drag.is_dragging(),
|
||||
_ => false,
|
||||
};
|
||||
let avatars: Vec<Node<Msg>> = issue
|
||||
let avatars: Vec<Node<Msg>> = self
|
||||
.issue
|
||||
.user_ids
|
||||
.iter()
|
||||
.filter_map(|id| model.users_by_id.get(id))
|
||||
.filter_map(|id| self.model.users_by_id.get(id))
|
||||
.map(|user| {
|
||||
StyledAvatar {
|
||||
avatar_url: user.avatar_url.as_deref(),
|
||||
@ -142,22 +150,22 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
||||
.collect();
|
||||
|
||||
let issue_type_icon = StyledIcon {
|
||||
icon: issue.issue_type.into(),
|
||||
class_list: issue.issue_type.to_str(),
|
||||
color: Some(issue.issue_type.to_str()),
|
||||
icon: self.issue.issue_type.into(),
|
||||
class_list: self.issue.issue_type.to_str(),
|
||||
color: Some(self.issue.issue_type.to_str()),
|
||||
..Default::default()
|
||||
}
|
||||
.render();
|
||||
|
||||
let priority_icon = StyledIcon {
|
||||
icon: issue.priority.into(),
|
||||
class_list: issue.priority.to_str(),
|
||||
color: Some(issue.priority.to_str()),
|
||||
icon: self.issue.priority.into(),
|
||||
class_list: self.issue.priority.to_str(),
|
||||
color: Some(self.issue.priority.to_str()),
|
||||
..Default::default()
|
||||
}
|
||||
.render();
|
||||
|
||||
let issue_id = issue.id;
|
||||
let issue_id = self.issue.id;
|
||||
let drag_started = drag_ev(Ev::DragStart, move |ev| {
|
||||
ev.stop_propagation();
|
||||
Some(Msg::PageChanged(PageChanged::Board(
|
||||
@ -193,20 +201,18 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
||||
Msg::ChangePage(Page::EditIssue(issue_id))
|
||||
});
|
||||
|
||||
let href = format!("/issues/{id}", id = issue_id);
|
||||
|
||||
a![
|
||||
drag_started,
|
||||
on_click,
|
||||
C!["issueLink"],
|
||||
attrs![At::Href => href],
|
||||
attrs![At::Href => format!("/issues/{id}", id = issue_id)],
|
||||
IF![is_dragging => div![C!["dragCover"], drag_over_handler]],
|
||||
div![
|
||||
C!["issue"],
|
||||
attrs![At::Draggable => true],
|
||||
drag_stopped,
|
||||
drag_out,
|
||||
p![C!["title"], issue.title.as_str()],
|
||||
p![C!["title"], self.issue.title.as_str()],
|
||||
div![
|
||||
C!["bottom"],
|
||||
div![
|
||||
@ -218,3 +224,4 @@ fn project_issue(model: &Model, issue: &Issue) -> Node<Msg> {
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -43,52 +43,48 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
send_ws_msg(m, model.ws.as_ref(), orders);
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
pub fn render(model: &Model) -> Vec<Node<Msg>> {
|
||||
let logo_svg = img![
|
||||
attrs![At::Src => "/logo2.svg"; At::Style => "background: rgba(244,244,244,.8); border-radius: 24px;"]
|
||||
];
|
||||
|
||||
let user_icon = match model.user.as_ref() {
|
||||
Some(user) => {
|
||||
let avatar = StyledAvatar {
|
||||
let user_icon = model.user.as_ref().map_or_else(
|
||||
|| {
|
||||
StyledIcon {
|
||||
icon: Icon::User,
|
||||
size: Some(21),
|
||||
..Default::default()
|
||||
}
|
||||
.render()
|
||||
},
|
||||
|user| {
|
||||
i![
|
||||
C!["styledIcon"],
|
||||
StyledAvatar {
|
||||
avatar_url: user.avatar_url.as_deref(),
|
||||
size: 27,
|
||||
name: &user.name,
|
||||
..StyledAvatar::default()
|
||||
}
|
||||
.render();
|
||||
i![C!["styledIcon"], avatar]
|
||||
}
|
||||
_ => StyledIcon {
|
||||
icon: Icon::User,
|
||||
size: Some(21),
|
||||
..Default::default()
|
||||
}
|
||||
.render(),
|
||||
};
|
||||
|
||||
let messages = if model.messages.is_empty() {
|
||||
empty![]
|
||||
} else {
|
||||
navbar_left_item(
|
||||
"Messages",
|
||||
Icon::Message,
|
||||
None,
|
||||
Some(mouse_ev(Ev::Click, |ev| {
|
||||
ev.prevent_default();
|
||||
Msg::ToggleTooltip(styled_tooltip::TooltipVariant::Messages)
|
||||
})),
|
||||
)
|
||||
};
|
||||
.render()
|
||||
]
|
||||
},
|
||||
);
|
||||
|
||||
let issue_nav = if model.issue_statuses.is_empty() {
|
||||
vec![]
|
||||
} else {
|
||||
vec![
|
||||
navbar_left_item("Search issues", Icon::Search, None, None),
|
||||
navbar_left_item(
|
||||
"Search issues",
|
||||
StyledIcon::from(Icon::Search).render(),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
navbar_left_item(
|
||||
"Create Issue",
|
||||
Icon::Plus,
|
||||
StyledIcon::from(Icon::Plus).render(),
|
||||
Some("/add-issue"),
|
||||
Some(mouse_ev("click", |ev| {
|
||||
ev.stop_propagation();
|
||||
@ -119,10 +115,18 @@ pub fn render(model: &Model) -> Vec<Node<Msg>> {
|
||||
div![
|
||||
C!["bottom"],
|
||||
navbar_left_item("Profile", user_icon, Some("/profile"), Some(go_to_profile)),
|
||||
messages,
|
||||
IF![!model.messages.is_empty() => navbar_left_item(
|
||||
"Messages",
|
||||
StyledIcon::from(Icon::Message).render(),
|
||||
None,
|
||||
Some(mouse_ev(Ev::Click, |ev| {
|
||||
ev.prevent_default();
|
||||
Msg::ToggleTooltip(styled_tooltip::TooltipVariant::Messages)
|
||||
})),
|
||||
)],
|
||||
IF![model.show_extras => about_tooltip(
|
||||
model,
|
||||
navbar_left_item("About", Icon::Help, None, None)
|
||||
navbar_left_item("About", StyledIcon::from(Icon::Help).render(), None, None)
|
||||
)],
|
||||
],
|
||||
],
|
||||
@ -130,15 +134,12 @@ pub fn render(model: &Model) -> Vec<Node<Msg>> {
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn navbar_left_item<I>(
|
||||
fn navbar_left_item(
|
||||
text: &str,
|
||||
icon: I,
|
||||
icon: Node<Msg>,
|
||||
href: Option<&str>,
|
||||
on_click: Option<EventHandler<Msg>>,
|
||||
) -> Node<Msg>
|
||||
where
|
||||
I: IntoNavItemIcon,
|
||||
{
|
||||
) -> Node<Msg> {
|
||||
let styled_icon = icon.into_nav_item_icon();
|
||||
|
||||
a![
|
||||
|
@ -221,6 +221,12 @@ pub struct Project {
|
||||
pub time_tracking: TimeTracking,
|
||||
}
|
||||
|
||||
impl Project {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, Debug, PartialEq)]
|
||||
pub struct Issue {
|
||||
pub id: EpicId,
|
||||
@ -291,6 +297,12 @@ pub struct User {
|
||||
pub updated_at: NaiveDateTime,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn name(&self) -> &str {
|
||||
&self.name
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(Queryable))]
|
||||
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
|
||||
pub struct UserProject {
|
||||
|
Loading…
Reference in New Issue
Block a user