Add fibonacci time tracking. Use styled select state for values
This commit is contained in:
parent
f4e1b41568
commit
c13bb5acf7
@ -3,6 +3,7 @@ use seed::{prelude::*, *};
|
||||
use jirs_data::*;
|
||||
|
||||
use crate::api::send_ws_msg;
|
||||
use crate::modal::time_tracking::time_tracking_field;
|
||||
use crate::model::{CommentForm, EditIssueModal, ModalType, Model};
|
||||
use crate::shared::styled_avatar::StyledAvatar;
|
||||
use crate::shared::styled_button::StyledButton;
|
||||
@ -27,8 +28,11 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
modal.assignees_state.update(msg, orders);
|
||||
modal.priority_state.update(msg, orders);
|
||||
modal.estimate.update(msg);
|
||||
modal.estimate_select.update(msg, orders);
|
||||
modal.time_spent.update(msg);
|
||||
modal.time_spent_select.update(msg, orders);
|
||||
modal.time_remaining.update(msg);
|
||||
modal.time_remaining_select.update(msg, orders);
|
||||
|
||||
match msg {
|
||||
Msg::WsMsg(WsMsg::IssueUpdated(issue)) => {
|
||||
@ -137,9 +141,10 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
),
|
||||
));
|
||||
}
|
||||
// TimeSpent
|
||||
Msg::StrInputChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||
_value,
|
||||
..,
|
||||
) => {
|
||||
modal.payload.time_spent = modal.time_spent.represent_f64_as_i32();
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
@ -148,9 +153,21 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
PayloadVariant::OptionI32(modal.payload.time_spent),
|
||||
));
|
||||
}
|
||||
Msg::StyledSelectChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||
StyledSelectChange::Changed(..),
|
||||
) => {
|
||||
modal.payload.time_spent = modal.time_spent_select.values.get(0).map(|n| *n as i32);
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
modal.id,
|
||||
IssueFieldId::TimeSpent,
|
||||
PayloadVariant::OptionI32(modal.payload.time_spent),
|
||||
));
|
||||
}
|
||||
// Time Remaining
|
||||
Msg::StrInputChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||
_value,
|
||||
..,
|
||||
) => {
|
||||
modal.payload.time_remaining = modal.time_remaining.represent_f64_as_i32();
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
@ -159,6 +176,41 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
||||
));
|
||||
}
|
||||
Msg::StyledSelectChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||
StyledSelectChange::Changed(..),
|
||||
) => {
|
||||
modal.payload.time_remaining =
|
||||
modal.time_remaining_select.values.get(0).map(|n| *n as i32);
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
modal.id,
|
||||
IssueFieldId::TimeRemaining,
|
||||
PayloadVariant::OptionI32(modal.payload.time_remaining),
|
||||
));
|
||||
}
|
||||
// Estimate
|
||||
Msg::StrInputChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
..,
|
||||
) => {
|
||||
modal.payload.estimate = modal.estimate.represent_f64_as_i32();
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
modal.id,
|
||||
IssueFieldId::Estimate,
|
||||
PayloadVariant::OptionI32(modal.payload.estimate),
|
||||
));
|
||||
}
|
||||
Msg::StyledSelectChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
StyledSelectChange::Changed(..),
|
||||
) => {
|
||||
modal.payload.estimate = modal.estimate_select.values.get(0).map(|n| *n as i32);
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
modal.id,
|
||||
IssueFieldId::Estimate,
|
||||
PayloadVariant::OptionI32(modal.payload.estimate),
|
||||
));
|
||||
}
|
||||
Msg::ModalChanged(FieldChange::TabChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Description)),
|
||||
mode,
|
||||
@ -175,24 +227,15 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||
modal.comment_form.id = None;
|
||||
}
|
||||
}
|
||||
//
|
||||
// comments
|
||||
//
|
||||
Msg::StrInputChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
|
||||
text,
|
||||
) => {
|
||||
modal.comment_form.body = text.clone();
|
||||
}
|
||||
Msg::StrInputChanged(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
_value,
|
||||
) => {
|
||||
modal.payload.estimate = modal.estimate.represent_f64_as_i32();
|
||||
send_ws_msg(WsMsg::IssueUpdateRequest(
|
||||
modal.id,
|
||||
IssueFieldId::Estimate,
|
||||
PayloadVariant::OptionI32(modal.payload.estimate),
|
||||
));
|
||||
}
|
||||
Msg::SaveComment => {
|
||||
let msg = match modal.comment_form.id {
|
||||
Some(id) => WsMsg::UpdateComment(UpdateCommentPayload {
|
||||
@ -668,18 +711,13 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
||||
.unwrap_or_else(|| TimeTracking::Untracked);
|
||||
|
||||
let (estimate_field, tracking_field) = if time_tracking_type != TimeTracking::Untracked {
|
||||
let estimate = StyledInput::build(FieldId::EditIssueModal(EditIssueModalSection::Issue(
|
||||
IssueFieldId::Estimate,
|
||||
)))
|
||||
.valid(true)
|
||||
.value(modal.estimate.value.as_str())
|
||||
.build()
|
||||
.into_node();
|
||||
let estimate_field = StyledField::build()
|
||||
.input(estimate)
|
||||
.label("Original Estimate (hours)")
|
||||
.build()
|
||||
.into_node();
|
||||
let estimate_field = time_tracking_field(
|
||||
time_tracking_type,
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
"Original Estimate (hours)",
|
||||
&modal.estimate,
|
||||
&modal.estimate_select,
|
||||
);
|
||||
|
||||
let tracking = tracking_link(model, modal);
|
||||
let tracking_field = StyledField::build()
|
||||
|
@ -7,7 +7,7 @@ use crate::shared::styled_button::StyledButton;
|
||||
use crate::shared::styled_field::StyledField;
|
||||
use crate::shared::styled_input::{StyledInput, StyledInputState};
|
||||
use crate::shared::styled_modal::StyledModal;
|
||||
use crate::shared::styled_select::StyledSelect;
|
||||
use crate::shared::styled_select::{StyledSelect, StyledSelectState};
|
||||
use crate::shared::styled_select_child::*;
|
||||
use crate::shared::tracking_widget::{fibonacci_values, tracking_widget};
|
||||
use crate::shared::{find_issue, ToChild, ToNode};
|
||||
@ -47,12 +47,14 @@ pub fn view(model: &Model, issue_id: IssueId) -> Node<Msg> {
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||
"Time spent",
|
||||
&edit_issue_modal.time_spent,
|
||||
&edit_issue_modal.time_spent_select,
|
||||
);
|
||||
let time_remaining_field = time_tracking_field(
|
||||
time_tracking_type,
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||
"Time remaining",
|
||||
&edit_issue_modal.time_remaining,
|
||||
&edit_issue_modal.time_remaining_select,
|
||||
);
|
||||
|
||||
let inputs = div![
|
||||
@ -80,16 +82,24 @@ pub fn view(model: &Model, issue_id: IssueId) -> Node<Msg> {
|
||||
.into_node()
|
||||
}
|
||||
|
||||
fn time_tracking_field(
|
||||
pub fn time_tracking_field(
|
||||
time_tracking_type: TimeTracking,
|
||||
field_id: FieldId,
|
||||
label: &str,
|
||||
state: &StyledInputState,
|
||||
input_state: &StyledInputState,
|
||||
select_state: &StyledSelectState,
|
||||
) -> Node<Msg> {
|
||||
let input = match time_tracking_type {
|
||||
TimeTracking::Untracked => empty![],
|
||||
TimeTracking::Fibonacci => StyledSelect::build(field_id)
|
||||
.selected(vec![(state.to_i32().unwrap_or_default() as u32).to_child()])
|
||||
.selected(
|
||||
select_state
|
||||
.values
|
||||
.iter()
|
||||
.map(|n| (*n).to_child())
|
||||
.collect(),
|
||||
)
|
||||
.with_state(select_state)
|
||||
.options(
|
||||
fibonacci_values()
|
||||
.into_iter()
|
||||
@ -99,7 +109,7 @@ fn time_tracking_field(
|
||||
.build()
|
||||
.into_node(),
|
||||
TimeTracking::Hourly => StyledInput::build(field_id)
|
||||
.state(state)
|
||||
.state(input_state)
|
||||
.valid(true)
|
||||
.build()
|
||||
.into_node(),
|
||||
|
@ -40,8 +40,11 @@ pub struct EditIssueModal {
|
||||
pub priority_state: StyledSelectState,
|
||||
|
||||
pub estimate: StyledInputState,
|
||||
pub estimate_select: StyledSelectState,
|
||||
pub time_spent: StyledInputState,
|
||||
pub time_spent_select: StyledSelectState,
|
||||
pub time_remaining: StyledInputState,
|
||||
pub time_remaining_select: StyledSelectState,
|
||||
|
||||
pub description_editor_mode: Mode,
|
||||
|
||||
@ -69,33 +72,53 @@ impl EditIssueModal {
|
||||
reporter_id: issue.reporter_id,
|
||||
user_ids: issue.user_ids.clone(),
|
||||
},
|
||||
top_type_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||
EditIssueModalSection::Issue(IssueFieldId::Type),
|
||||
)),
|
||||
status_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||
EditIssueModalSection::Issue(IssueFieldId::Status),
|
||||
)),
|
||||
reporter_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||
EditIssueModalSection::Issue(IssueFieldId::Reporter),
|
||||
)),
|
||||
assignees_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||
EditIssueModalSection::Issue(IssueFieldId::Assignees),
|
||||
)),
|
||||
priority_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||
EditIssueModalSection::Issue(IssueFieldId::Priority),
|
||||
)),
|
||||
top_type_state: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Type)),
|
||||
issue.estimate.map(|v| vec![v as u32]).unwrap_or_default(),
|
||||
),
|
||||
status_state: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Status)),
|
||||
vec![issue.status.into()],
|
||||
),
|
||||
reporter_state: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Reporter)),
|
||||
vec![issue.reporter_id as u32],
|
||||
),
|
||||
assignees_state: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
|
||||
issue.user_ids.iter().map(|n| *n as u32).collect(),
|
||||
),
|
||||
priority_state: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Priority)),
|
||||
vec![issue.priority.into()],
|
||||
),
|
||||
estimate: StyledInputState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
value_for_time_tracking(&issue.estimate, &time_tracking_type),
|
||||
),
|
||||
estimate_select: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Estimate)),
|
||||
issue.estimate.map(|n| vec![n as u32]).unwrap_or_default(),
|
||||
),
|
||||
time_spent: StyledInputState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||
value_for_time_tracking(&issue.time_spent, &time_tracking_type),
|
||||
),
|
||||
time_spent_select: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeSpent)),
|
||||
issue.time_spent.map(|n| vec![n as u32]).unwrap_or_default(),
|
||||
),
|
||||
time_remaining: StyledInputState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||
value_for_time_tracking(&issue.time_remaining, &time_tracking_type),
|
||||
),
|
||||
time_remaining_select: StyledSelectState::new(
|
||||
FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::TimeRemaining)),
|
||||
issue
|
||||
.time_remaining
|
||||
.map(|n| vec![n as u32])
|
||||
.unwrap_or_default(),
|
||||
),
|
||||
description_editor_mode: Mode::View,
|
||||
comment_form: CommentForm {
|
||||
id: None,
|
||||
@ -143,12 +166,19 @@ impl Default for AddIssueModal {
|
||||
project_id: Default::default(),
|
||||
user_ids: Default::default(),
|
||||
reporter_id: Default::default(),
|
||||
type_state: StyledSelectState::new(FieldId::AddIssueModal(IssueFieldId::Type)),
|
||||
reporter_state: StyledSelectState::new(FieldId::AddIssueModal(IssueFieldId::Reporter)),
|
||||
assignees_state: StyledSelectState::new(FieldId::AddIssueModal(
|
||||
IssueFieldId::Assignees,
|
||||
)),
|
||||
priority_state: StyledSelectState::new(FieldId::AddIssueModal(IssueFieldId::Priority)),
|
||||
type_state: StyledSelectState::new(FieldId::AddIssueModal(IssueFieldId::Type), vec![]),
|
||||
reporter_state: StyledSelectState::new(
|
||||
FieldId::AddIssueModal(IssueFieldId::Reporter),
|
||||
vec![],
|
||||
),
|
||||
assignees_state: StyledSelectState::new(
|
||||
FieldId::AddIssueModal(IssueFieldId::Assignees),
|
||||
vec![],
|
||||
),
|
||||
priority_state: StyledSelectState::new(
|
||||
FieldId::AddIssueModal(IssueFieldId::Priority),
|
||||
vec![],
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -243,9 +273,10 @@ impl ProjectSettingsPage {
|
||||
time_tracking: Some(*time_tracking),
|
||||
},
|
||||
description_mode: EditorMode::View,
|
||||
project_category_state: StyledSelectState::new(FieldId::ProjectSettings(
|
||||
ProjectFieldId::Category,
|
||||
)),
|
||||
project_category_state: StyledSelectState::new(
|
||||
FieldId::ProjectSettings(ProjectFieldId::Category),
|
||||
vec![(*category).into()],
|
||||
),
|
||||
time_tracking: StyledCheckboxState::new(
|
||||
FieldId::ProjectSettings(ProjectFieldId::TimeTracking),
|
||||
(*time_tracking).into(),
|
||||
@ -317,7 +348,7 @@ impl Default for UsersPage {
|
||||
email: "".to_string(),
|
||||
email_touched: false,
|
||||
user_role: Default::default(),
|
||||
user_role_state: StyledSelectState::new(FieldId::Users(UsersFieldId::UserRole)),
|
||||
user_role_state: StyledSelectState::new(FieldId::Users(UsersFieldId::UserRole), vec![]),
|
||||
pending_invitations: vec![],
|
||||
error: "".to_string(),
|
||||
form_state: Default::default(),
|
||||
|
@ -51,12 +51,12 @@ impl StyledSelectState {
|
||||
}
|
||||
|
||||
impl StyledSelectState {
|
||||
pub fn new(field_id: FieldId) -> Self {
|
||||
pub fn new(field_id: FieldId, values: Vec<u32>) -> Self {
|
||||
Self {
|
||||
field_id,
|
||||
opened: false,
|
||||
text_filter: String::new(),
|
||||
values: vec![],
|
||||
values,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,7 @@ impl Into<UserRole> for u32 {
|
||||
|
||||
#[cfg_attr(feature = "backend", derive(FromSqlRow, AsExpression))]
|
||||
#[cfg_attr(feature = "backend", sql_type = "ProjectCategoryType")]
|
||||
#[derive(Clone, Deserialize, Serialize, Debug, PartialOrd, PartialEq, Hash)]
|
||||
#[derive(Clone, Copy, Deserialize, Serialize, Debug, PartialOrd, PartialEq, Hash)]
|
||||
pub enum ProjectCategory {
|
||||
Software,
|
||||
Marketing,
|
||||
|
Loading…
Reference in New Issue
Block a user