Save estimated time. Change path on drop add issue. Better support for multi-page
This commit is contained in:
parent
cb6f41fe0a
commit
02d2c958b7
@ -3,6 +3,9 @@
|
||||
padding: 0 30px 60px;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* LEFT */
|
||||
/*===================================================*/
|
||||
.issueDetails > .content > .left {
|
||||
width: 65%;
|
||||
padding-right: 50px;
|
||||
@ -108,11 +111,56 @@
|
||||
margin-right: 6px;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* RIGHT */
|
||||
/*===================================================*/
|
||||
.issueDetails > .content > .right {
|
||||
width: 35%;
|
||||
padding-top: 5px;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink {
|
||||
padding: 4px 4px 2px 0;
|
||||
border-radius: 4px;
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink:hover {
|
||||
background: var(--backgroundLight);
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink > .trackingWidget {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink > .trackingWidget > .watchIcon {
|
||||
color: var(--textMedium);
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink > .trackingWidget > .right {
|
||||
width: 90%;
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink > .trackingWidget > .right > .barCounter {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--backgroundMedium);
|
||||
}
|
||||
|
||||
.issueDetails > .content > .right > .styledField > .trackingLink > .trackingWidget > .right > .barCounter > .bar {
|
||||
height: 5px;
|
||||
border-radius: 4px;
|
||||
background: var(--primary);
|
||||
transition: all 0.1s;
|
||||
}
|
||||
|
||||
/*===================================================*/
|
||||
/* TOP ACTIONS */
|
||||
/*===================================================*/
|
||||
.issueDetails > .topActions {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
20
jirs-client/js/css/timeTracking.css
Normal file
20
jirs-client/js/css/timeTracking.css
Normal file
@ -0,0 +1,20 @@
|
||||
.timeTrackingModal {
|
||||
padding: 20px 25px 25px;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .modalTitle {
|
||||
padding-bottom: 14px;
|
||||
font-family: var(--font-medium);
|
||||
font-weight: normal;
|
||||
font-size: 20px
|
||||
}
|
||||
|
||||
.timeTrackingModal > .inputs {
|
||||
display: flex;
|
||||
margin: 20px -5px 30px;
|
||||
}
|
||||
|
||||
.timeTrackingModal > .inputs > .inputContainer {
|
||||
margin: 0 5px;
|
||||
width: 50%;
|
||||
}
|
@ -21,3 +21,4 @@
|
||||
@import "./css/app.css";
|
||||
@import "./css/issue.css";
|
||||
@import "./css/project.css";
|
||||
@import "./css/timeTracking.css";
|
||||
|
@ -8,7 +8,7 @@ use crate::shared::styled_avatar::StyledAvatar;
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_editor::StyledEditor;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
use crate::shared::styled_icon::Icon;
|
||||
use crate::shared::styled_icon::{Icon, StyledIcon};
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::styled_select::{StyledSelect, StyledSelectChange};
|
||||
use crate::shared::styled_select_child::ToStyledSelectChild;
|
||||
@ -593,12 +593,86 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let tracking = tracking_widget(model, modal);
|
||||
let tracking_field = StyledField::build()
|
||||
.label("TIME TRACKING")
|
||||
.tip("")
|
||||
.input(tracking)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
div![
|
||||
attrs![At::Class => "right"],
|
||||
status_field,
|
||||
assignees_field,
|
||||
reporter_field,
|
||||
priority_field,
|
||||
estimate_field
|
||||
estimate_field,
|
||||
tracking_field,
|
||||
]
|
||||
}
|
||||
|
||||
fn tracking_widget(_model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
||||
let EditIssueModal {
|
||||
id,
|
||||
payload:
|
||||
UpdateIssuePayload {
|
||||
estimate,
|
||||
time_spent,
|
||||
time_remaining,
|
||||
..
|
||||
},
|
||||
..
|
||||
} = modal;
|
||||
|
||||
let issue_id = *id;
|
||||
|
||||
let icon = StyledIcon::build(Icon::Stopwatch)
|
||||
.add_class("watchIcon")
|
||||
.size(32)
|
||||
.build()
|
||||
.into_node();
|
||||
|
||||
let bar_width = calc_bar_width(estimate, time_spent, time_remaining);
|
||||
let handler = mouse_ev(Ev::Click, move |_| {
|
||||
Msg::ModalOpened(ModalType::TimeTracking(issue_id))
|
||||
});
|
||||
|
||||
div![
|
||||
class!["trackingLink"],
|
||||
handler,
|
||||
div![
|
||||
class!["trackingWidget"],
|
||||
icon,
|
||||
div![
|
||||
class!["right"],
|
||||
div![
|
||||
class!["barCounter"],
|
||||
div![
|
||||
class!["bar"],
|
||||
attrs![At::Style => format!("width: {}%", bar_width)]
|
||||
]
|
||||
]
|
||||
]
|
||||
],
|
||||
]
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn calc_bar_width(
|
||||
estimate: &Option<i32>,
|
||||
time_spent: &Option<i32>,
|
||||
time_remaining: &Option<i32>,
|
||||
) -> f64 {
|
||||
match (estimate, time_spent, time_remaining) {
|
||||
(Some(estimate), Some(spent), _) => {
|
||||
((*spent as f64 / *estimate as f64) * 100f64).max(100f64)
|
||||
}
|
||||
(_, Some(spent), Some(remaining)) => {
|
||||
(*spent as f64 / (*spent as f64 + *remaining as f64)) * 100f64
|
||||
}
|
||||
(None, None, _) => 100f64,
|
||||
(None, _, _) => 0f64,
|
||||
_ => 0f64,
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ use crate::{model, FieldChange, FieldId, Msg};
|
||||
mod add_issue;
|
||||
mod confirm_delete_issue;
|
||||
mod issue_details;
|
||||
mod time_tracking;
|
||||
|
||||
pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||
match msg {
|
||||
@ -88,6 +89,7 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
||||
.build()
|
||||
.into_node()
|
||||
}
|
||||
ModalType::TimeTracking(issue_id) => time_tracking::view(model, *issue_id),
|
||||
})
|
||||
.collect();
|
||||
section![id!["modals"], modals]
|
||||
|
28
jirs-client/src/modal/time_tracking.rs
Normal file
28
jirs-client/src/modal/time_tracking.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use seed::{prelude::*, *};
|
||||
|
||||
use jirs_data::IssueId;
|
||||
|
||||
use crate::model::Model;
|
||||
use crate::shared::styled_input::StyledInput;
|
||||
use crate::shared::styled_modal::StyledModal;
|
||||
use crate::shared::{find_issue, ToNode};
|
||||
use crate::Msg;
|
||||
|
||||
pub fn view(model: &Model, issue_id: IssueId) -> Node<Msg> {
|
||||
let issue = match find_issue(model, issue_id) {
|
||||
Some(issue) => issue,
|
||||
_ => return empty![],
|
||||
};
|
||||
|
||||
let modal_title = div![class!["modalTitle"], "Time tracking"];
|
||||
|
||||
// let time_spent = StyledInput::build()
|
||||
|
||||
let inputs = div![class!["inputs"], ""];
|
||||
|
||||
StyledModal::build()
|
||||
.add_class("timeTrackingModal")
|
||||
.children(vec![modal_title, inputs])
|
||||
.build()
|
||||
.into_node()
|
||||
}
|
@ -15,6 +15,7 @@ pub enum ModalType {
|
||||
EditIssue(IssueId, EditIssueModal),
|
||||
DeleteIssueConfirm(IssueId),
|
||||
DeleteCommentConfirm(CommentId),
|
||||
TimeTracking(IssueId),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialOrd, PartialEq, Hash)]
|
||||
|
@ -7,7 +7,7 @@ export const TrackingLink = styled.div`
|
||||
border-radius: 4px;
|
||||
transition: background 0.1s;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
user-select: none;
|
||||
&:hover {
|
||||
background: ${color.backgroundLight};
|
||||
}
|
||||
@ -19,7 +19,8 @@ export const ModalContents = styled.div`
|
||||
|
||||
export const ModalTitle = styled.div`
|
||||
padding-bottom: 14px;
|
||||
${ font.medium };font-weight: normal;
|
||||
${ font.medium };
|
||||
font-weight: normal;
|
||||
font-size: 20px
|
||||
`;
|
||||
|
||||
|
@ -36,5 +36,6 @@ export const SectionTitle = styled.div`
|
||||
text-transform: uppercase;
|
||||
color: ${color.textMedium};
|
||||
font-size: 12.5px
|
||||
font-family: "CircularStdBold"; font-weight: normal
|
||||
font-family: "CircularStdBold";
|
||||
font-weight: normal;
|
||||
`;
|
||||
|
Loading…
Reference in New Issue
Block a user