Save estimated time. Change path on drop add issue. Better support for multi-page
This commit is contained in:
parent
ff5a43efc6
commit
cb6f41fe0a
@ -177,6 +177,9 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
|||||||
Msg::ChangePage(page) => {
|
Msg::ChangePage(page) => {
|
||||||
model.page = page.clone();
|
model.page = page.clone();
|
||||||
}
|
}
|
||||||
|
Msg::ToggleAboutTooltip => {
|
||||||
|
model.about_tooltip_visible = !model.about_tooltip_visible;
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
crate::ws::update(&msg, model, orders);
|
crate::ws::update(&msg, model, orders);
|
||||||
|
@ -109,6 +109,19 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
Msg::InputChanged(FieldId::EditIssueModal(EditIssueModalFieldId::CommentBody), text) => {
|
Msg::InputChanged(FieldId::EditIssueModal(EditIssueModalFieldId::CommentBody), text) => {
|
||||||
modal.comment_form.body = text.clone();
|
modal.comment_form.body = text.clone();
|
||||||
}
|
}
|
||||||
|
Msg::InputChanged(FieldId::EditIssueModal(EditIssueModalFieldId::Estimate), value) => {
|
||||||
|
match value.parse::<i32>() {
|
||||||
|
Ok(n) if !value.is_empty() => {
|
||||||
|
modal.payload.estimate = Some(n);
|
||||||
|
send_ws_msg(WsMsg::IssueUpdateRequest(modal.id, modal.payload.clone()));
|
||||||
|
}
|
||||||
|
_ if value.is_empty() => {
|
||||||
|
modal.payload.estimate = None;
|
||||||
|
send_ws_msg(WsMsg::IssueUpdateRequest(modal.id, modal.payload.clone()));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
Msg::SaveComment => {
|
Msg::SaveComment => {
|
||||||
let msg = match modal.comment_form.id {
|
let msg = match modal.comment_form.id {
|
||||||
Some(id) => WsMsg::UpdateComment(UpdateCommentPayload {
|
Some(id) => WsMsg::UpdateComment(UpdateCommentPayload {
|
||||||
@ -564,6 +577,14 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
|||||||
|
|
||||||
let estimate = StyledInput::build(FieldId::EditIssueModal(EditIssueModalFieldId::Estimate))
|
let estimate = StyledInput::build(FieldId::EditIssueModal(EditIssueModalFieldId::Estimate))
|
||||||
.valid(true)
|
.valid(true)
|
||||||
|
.value(
|
||||||
|
payload
|
||||||
|
.estimate
|
||||||
|
.as_ref()
|
||||||
|
.map(|n| n.to_string())
|
||||||
|
.clone()
|
||||||
|
.unwrap_or_default(),
|
||||||
|
)
|
||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
let estimate_field = StyledField::build()
|
let estimate_field = StyledField::build()
|
||||||
|
@ -16,7 +16,7 @@ mod issue_details;
|
|||||||
pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ModalDropped => match model.modals.pop() {
|
Msg::ModalDropped => match model.modals.pop() {
|
||||||
Some(ModalType::EditIssue(..)) => {
|
Some(ModalType::EditIssue(..)) | Some(ModalType::AddIssue(..)) => {
|
||||||
seed::push_route(vec!["board"]);
|
seed::push_route(vec!["board"]);
|
||||||
orders.send_msg(Msg::ChangePage(Page::Project));
|
orders.send_msg(Msg::ChangePage(Page::Project));
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ impl EditIssueModal {
|
|||||||
priority_state: StyledSelectState::new(FieldId::EditIssueModal(
|
priority_state: StyledSelectState::new(FieldId::EditIssueModal(
|
||||||
EditIssueModalFieldId::Priority,
|
EditIssueModalFieldId::Priority,
|
||||||
)),
|
)),
|
||||||
description_editor_mode: Mode::Editor,
|
description_editor_mode: Mode::View,
|
||||||
comment_form: CommentForm {
|
comment_form: CommentForm {
|
||||||
id: None,
|
id: None,
|
||||||
body: String::new(),
|
body: String::new(),
|
||||||
@ -178,9 +178,8 @@ pub struct UpdateProjectForm {
|
|||||||
pub fields: UpdateProjectPayload,
|
pub fields: UpdateProjectPayload,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct ProjectPage {
|
pub struct ProjectPage {
|
||||||
pub about_tooltip_visible: bool,
|
|
||||||
pub text_filter: String,
|
pub text_filter: String,
|
||||||
pub active_avatar_filters: Vec<UserId>,
|
pub active_avatar_filters: Vec<UserId>,
|
||||||
pub only_my_filter: bool,
|
pub only_my_filter: bool,
|
||||||
@ -190,10 +189,23 @@ pub struct ProjectPage {
|
|||||||
pub dirty_issues: Vec<IssueId>,
|
pub dirty_issues: Vec<IssueId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ProjectSettingsPage {
|
||||||
|
pub payload: UpdateProjectPayload,
|
||||||
|
pub project_type_state: StyledSelectState,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum PageContent {
|
||||||
|
Project(ProjectPage),
|
||||||
|
ProjectSettings(ProjectSettingsPage),
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Model {
|
pub struct Model {
|
||||||
pub host_url: String,
|
pub host_url: String,
|
||||||
pub access_token: Option<Uuid>,
|
pub access_token: Option<Uuid>,
|
||||||
|
pub about_tooltip_visible: bool,
|
||||||
|
|
||||||
// mapped
|
// mapped
|
||||||
pub comments_by_project_id: HashMap<ProjectId, Vec<Comment>>,
|
pub comments_by_project_id: HashMap<ProjectId, Vec<Comment>>,
|
||||||
@ -208,7 +220,7 @@ pub struct Model {
|
|||||||
|
|
||||||
// pages
|
// pages
|
||||||
pub page: Page,
|
pub page: Page,
|
||||||
pub project_page: ProjectPage,
|
pub page_content: PageContent,
|
||||||
|
|
||||||
pub project: Option<Project>,
|
pub project: Option<Project>,
|
||||||
pub user: Option<User>,
|
pub user: Option<User>,
|
||||||
@ -231,19 +243,11 @@ impl Default for Model {
|
|||||||
comments_by_project_id: Default::default(),
|
comments_by_project_id: Default::default(),
|
||||||
page: Page::Project,
|
page: Page::Project,
|
||||||
host_url,
|
host_url,
|
||||||
project_page: ProjectPage {
|
page_content: PageContent::Project(ProjectPage::default()),
|
||||||
about_tooltip_visible: false,
|
|
||||||
text_filter: "".to_string(),
|
|
||||||
active_avatar_filters: vec![],
|
|
||||||
only_my_filter: false,
|
|
||||||
recently_updated_filter: false,
|
|
||||||
dragged_issue_id: None,
|
|
||||||
last_drag_exchange_id: None,
|
|
||||||
dirty_issues: vec![],
|
|
||||||
},
|
|
||||||
modals: vec![],
|
modals: vec![],
|
||||||
project: None,
|
project: None,
|
||||||
comments: vec![],
|
comments: vec![],
|
||||||
|
about_tooltip_visible: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,7 @@ use seed::{prelude::*, *};
|
|||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
use crate::api::send_ws_msg;
|
||||||
use crate::model::{ModalType, Model, Page};
|
use crate::model::{ModalType, Model, Page, PageContent};
|
||||||
use crate::shared::styled_avatar::StyledAvatar;
|
use crate::shared::styled_avatar::StyledAvatar;
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_icon::{Icon, StyledIcon};
|
use crate::shared::styled_icon::{Icon, StyledIcon};
|
||||||
@ -14,6 +14,11 @@ use crate::shared::{drag_ev, inner_layout, ToNode};
|
|||||||
use crate::{EditIssueModalFieldId, FieldId, Msg};
|
use crate::{EditIssueModalFieldId, FieldId, Msg};
|
||||||
|
|
||||||
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
let project_page = match &mut model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
match msg {
|
match msg {
|
||||||
Msg::ChangePage(Page::Project)
|
Msg::ChangePage(Page::Project)
|
||||||
| Msg::ChangePage(Page::AddIssue)
|
| Msg::ChangePage(Page::AddIssue)
|
||||||
@ -44,9 +49,6 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
}
|
}
|
||||||
orders.skip().send_msg(Msg::ModalDropped);
|
orders.skip().send_msg(Msg::ModalDropped);
|
||||||
}
|
}
|
||||||
Msg::ToggleAboutTooltip => {
|
|
||||||
model.project_page.about_tooltip_visible = !model.project_page.about_tooltip_visible;
|
|
||||||
}
|
|
||||||
Msg::StyledSelectChanged(
|
Msg::StyledSelectChanged(
|
||||||
FieldId::EditIssueModal(EditIssueModalFieldId::IssueType),
|
FieldId::EditIssueModal(EditIssueModalFieldId::IssueType),
|
||||||
StyledSelectChange::Text(text),
|
StyledSelectChange::Text(text),
|
||||||
@ -64,12 +66,11 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::InputChanged(FieldId::TextFilterBoard, text) => {
|
Msg::InputChanged(FieldId::TextFilterBoard, text) => {
|
||||||
model.project_page.text_filter = text;
|
project_page.text_filter = text;
|
||||||
}
|
}
|
||||||
Msg::ProjectAvatarFilterChanged(user_id, active) => match active {
|
Msg::ProjectAvatarFilterChanged(user_id, active) => match active {
|
||||||
true => {
|
true => {
|
||||||
model.project_page.active_avatar_filters = model
|
project_page.active_avatar_filters = project_page
|
||||||
.project_page
|
|
||||||
.active_avatar_filters
|
.active_avatar_filters
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|id| **id != user_id)
|
.filter(|id| **id != user_id)
|
||||||
@ -77,25 +78,23 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
.collect();
|
.collect();
|
||||||
}
|
}
|
||||||
false => {
|
false => {
|
||||||
model.project_page.active_avatar_filters.push(user_id);
|
project_page.active_avatar_filters.push(user_id);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Msg::ProjectToggleOnlyMy => {
|
Msg::ProjectToggleOnlyMy => {
|
||||||
model.project_page.only_my_filter = !model.project_page.only_my_filter;
|
project_page.only_my_filter = !project_page.only_my_filter;
|
||||||
}
|
}
|
||||||
Msg::ProjectToggleRecentlyUpdated => {
|
Msg::ProjectToggleRecentlyUpdated => {
|
||||||
model.project_page.recently_updated_filter =
|
project_page.recently_updated_filter = !project_page.recently_updated_filter;
|
||||||
!model.project_page.recently_updated_filter;
|
|
||||||
}
|
}
|
||||||
Msg::ProjectClearFilters => {
|
Msg::ProjectClearFilters => {
|
||||||
let pp = &mut model.project_page;
|
project_page.active_avatar_filters = vec![];
|
||||||
pp.active_avatar_filters = vec![];
|
project_page.recently_updated_filter = false;
|
||||||
pp.recently_updated_filter = false;
|
project_page.only_my_filter = false;
|
||||||
pp.only_my_filter = false;
|
|
||||||
}
|
}
|
||||||
Msg::IssueDragStarted(issue_id) => crate::ws::issue::drag_started(issue_id, model),
|
Msg::IssueDragStarted(issue_id) => crate::ws::issue::drag_started(issue_id, model),
|
||||||
Msg::IssueDragStopped(_) => {
|
Msg::IssueDragStopped(_) => {
|
||||||
model.project_page.dragged_issue_id = None;
|
project_page.dragged_issue_id = None;
|
||||||
}
|
}
|
||||||
Msg::ExchangePosition(issue_bellow_id) => {
|
Msg::ExchangePosition(issue_bellow_id) => {
|
||||||
crate::ws::issue::exchange_position(issue_bellow_id, model)
|
crate::ws::issue::exchange_position(issue_bellow_id, model)
|
||||||
@ -165,11 +164,14 @@ fn project_board_filters(model: &Model) -> Node<Msg> {
|
|||||||
.build()
|
.build()
|
||||||
.into_node();
|
.into_node();
|
||||||
|
|
||||||
let project_page = &model.project_page;
|
let project_page = match &model.page_content {
|
||||||
|
PageContent::Project(page_content) => page_content,
|
||||||
|
_ => return empty![],
|
||||||
|
};
|
||||||
|
|
||||||
let only_my = StyledButton::build()
|
let only_my = StyledButton::build()
|
||||||
.empty()
|
.empty()
|
||||||
.active(model.project_page.only_my_filter)
|
.active(project_page.only_my_filter)
|
||||||
.text("Only My Issues")
|
.text("Only My Issues")
|
||||||
.on_click(mouse_ev(Ev::Click, |_| Msg::ProjectToggleOnlyMy))
|
.on_click(mouse_ev(Ev::Click, |_| Msg::ProjectToggleOnlyMy))
|
||||||
.build()
|
.build()
|
||||||
@ -205,7 +207,11 @@ fn project_board_filters(model: &Model) -> Node<Msg> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn avatars_filters(model: &Model) -> Node<Msg> {
|
fn avatars_filters(model: &Model) -> Node<Msg> {
|
||||||
let active_avatar_filters = &model.project_page.active_avatar_filters;
|
let project_page = match &model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return empty![],
|
||||||
|
};
|
||||||
|
let active_avatar_filters = &project_page.active_avatar_filters;
|
||||||
let avatars: Vec<Node<Msg>> = model
|
let avatars: Vec<Node<Msg>> = model
|
||||||
.users
|
.users
|
||||||
.iter()
|
.iter()
|
||||||
@ -242,7 +248,11 @@ fn project_board_lists(model: &Model) -> Node<Msg> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn project_issue_list(model: &Model, status: jirs_data::IssueStatus) -> Node<Msg> {
|
fn project_issue_list(model: &Model, status: jirs_data::IssueStatus) -> Node<Msg> {
|
||||||
let ids = if model.project_page.recently_updated_filter {
|
let project_page = match &model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return empty![],
|
||||||
|
};
|
||||||
|
let ids = if project_page.recently_updated_filter {
|
||||||
let mut v: Vec<(IssueId, NaiveDateTime)> = model
|
let mut v: Vec<(IssueId, NaiveDateTime)> = model
|
||||||
.issues
|
.issues
|
||||||
.iter()
|
.iter()
|
||||||
@ -261,8 +271,8 @@ fn project_issue_list(model: &Model, status: jirs_data::IssueStatus) -> Node<Msg
|
|||||||
.iter()
|
.iter()
|
||||||
.filter(|issue| {
|
.filter(|issue| {
|
||||||
issue_filter_status(issue, &status)
|
issue_filter_status(issue, &status)
|
||||||
&& issue_filter_with_text(issue, model.project_page.text_filter.as_str())
|
&& issue_filter_with_text(issue, project_page.text_filter.as_str())
|
||||||
&& issue_filter_with_only_my(issue, model.project_page.only_my_filter, &model.user)
|
&& issue_filter_with_only_my(issue, project_page.only_my_filter, &model.user)
|
||||||
&& issue_filter_with_only_recent(issue, &ids)
|
&& issue_filter_with_only_recent(issue, &ids)
|
||||||
})
|
})
|
||||||
.map(|issue| project_issue(model, issue))
|
.map(|issue| project_issue(model, issue))
|
||||||
|
@ -4,7 +4,6 @@ use crate::shared::styled_editor::StyledEditor;
|
|||||||
use crate::shared::styled_field::StyledField;
|
use crate::shared::styled_field::StyledField;
|
||||||
use crate::shared::styled_form::StyledForm;
|
use crate::shared::styled_form::StyledForm;
|
||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::styled_select::StyledSelect;
|
|
||||||
use crate::shared::{inner_layout, ToNode};
|
use crate::shared::{inner_layout, ToNode};
|
||||||
use crate::{model, FieldId, Msg, ProjectSettingsFieldId};
|
use crate::{model, FieldId, Msg, ProjectSettingsFieldId};
|
||||||
|
|
||||||
|
@ -61,14 +61,15 @@ fn about_tooltip_popup(model: &Model) -> Node<Msg> {
|
|||||||
.into_node();
|
.into_node();
|
||||||
|
|
||||||
styled_tooltip::StyledTooltip {
|
styled_tooltip::StyledTooltip {
|
||||||
visible: model.project_page.about_tooltip_visible,
|
visible: model.about_tooltip_visible,
|
||||||
class_name: "aboutTooltipPopup".to_string(),
|
class_name: "aboutTooltipPopup".to_string(),
|
||||||
children: div![
|
children: div![
|
||||||
ev(Ev::Click, |_| Msg::ToggleAboutTooltip),
|
ev(Ev::Click, |_| Msg::ToggleAboutTooltip),
|
||||||
attrs![At::Class => "feedbackDropdown"],
|
attrs![At::Class => "feedbackDropdown"],
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => "feedbackImageCont"],
|
attrs![At::Class => "feedbackImageCont"],
|
||||||
img![attrs![At::Src => "/feedback.png", At::Class => "feedbackImage"]]
|
img![attrs![At::Src => "/feedback.png"]],
|
||||||
|
class!["feedbackImage"],
|
||||||
],
|
],
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => "feedbackParagraph"],
|
attrs![At::Class => "feedbackParagraph"],
|
||||||
|
@ -9,6 +9,7 @@ pub struct StyledInput {
|
|||||||
id: FieldId,
|
id: FieldId,
|
||||||
icon: Option<Icon>,
|
icon: Option<Icon>,
|
||||||
valid: bool,
|
valid: bool,
|
||||||
|
value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StyledInput {
|
impl StyledInput {
|
||||||
@ -17,6 +18,7 @@ impl StyledInput {
|
|||||||
id,
|
id,
|
||||||
icon: None,
|
icon: None,
|
||||||
valid: None,
|
valid: None,
|
||||||
|
value: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -26,6 +28,7 @@ pub struct StyledInputBuilder {
|
|||||||
id: FieldId,
|
id: FieldId,
|
||||||
icon: Option<Icon>,
|
icon: Option<Icon>,
|
||||||
valid: Option<bool>,
|
valid: Option<bool>,
|
||||||
|
value: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl StyledInputBuilder {
|
impl StyledInputBuilder {
|
||||||
@ -39,11 +42,20 @@ impl StyledInputBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn value<S>(mut self, v: S) -> Self
|
||||||
|
where
|
||||||
|
S: Into<String>,
|
||||||
|
{
|
||||||
|
self.value = Some(v.into());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn build(self) -> StyledInput {
|
pub fn build(self) -> StyledInput {
|
||||||
StyledInput {
|
StyledInput {
|
||||||
id: self.id,
|
id: self.id,
|
||||||
icon: self.icon,
|
icon: self.icon,
|
||||||
valid: self.valid.unwrap_or_default(),
|
valid: self.valid.unwrap_or_default(),
|
||||||
|
value: self.value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -55,7 +67,12 @@ impl ToNode for StyledInput {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn render(values: StyledInput) -> Node<Msg> {
|
pub fn render(values: StyledInput) -> Node<Msg> {
|
||||||
let StyledInput { id, icon, valid } = values;
|
let StyledInput {
|
||||||
|
id,
|
||||||
|
icon,
|
||||||
|
valid,
|
||||||
|
value,
|
||||||
|
} = values;
|
||||||
|
|
||||||
let mut wrapper_class_list = vec!["styledInput".to_string(), format!("{}", id)];
|
let mut wrapper_class_list = vec!["styledInput".to_string(), format!("{}", id)];
|
||||||
if !valid {
|
if !valid {
|
||||||
@ -74,7 +91,7 @@ pub fn render(values: StyledInput) -> Node<Msg> {
|
|||||||
|
|
||||||
let mut handlers = vec![];
|
let mut handlers = vec![];
|
||||||
|
|
||||||
handlers.push(input_ev(Ev::KeyUp, move |value| {
|
handlers.push(input_ev(Ev::Change, move |value| {
|
||||||
Msg::InputChanged(id, value)
|
Msg::InputChanged(id, value)
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -85,6 +102,12 @@ pub fn render(values: StyledInput) -> Node<Msg> {
|
|||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
Msg::NoOp
|
Msg::NoOp
|
||||||
}),
|
}),
|
||||||
seed::input![attrs![At::Class => input_class_list.join(" ")], handlers],
|
seed::input![
|
||||||
|
attrs![
|
||||||
|
At::Class => input_class_list.join(" "),
|
||||||
|
At::Value => value.unwrap_or_default(),
|
||||||
|
],
|
||||||
|
handlers
|
||||||
|
],
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -1,21 +1,29 @@
|
|||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
use crate::api::send_ws_msg;
|
||||||
use crate::model::Model;
|
use crate::model::{Model, PageContent, ProjectPage};
|
||||||
|
|
||||||
pub fn drag_started(issue_id: IssueId, model: &mut Model) {
|
pub fn drag_started(issue_id: IssueId, model: &mut Model) {
|
||||||
model.project_page.dragged_issue_id = Some(issue_id);
|
let project_page = match &mut model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
project_page.dragged_issue_id = Some(issue_id);
|
||||||
|
|
||||||
mark_dirty(issue_id, model);
|
mark_dirty(issue_id, project_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn exchange_position(issue_bellow_id: IssueId, model: &mut Model) {
|
pub fn exchange_position(issue_bellow_id: IssueId, model: &mut Model) {
|
||||||
if model.project_page.dragged_issue_id == Some(issue_bellow_id)
|
let project_page = match &mut model.page_content {
|
||||||
|| model.project_page.last_drag_exchange_id == Some(issue_bellow_id)
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
if project_page.dragged_issue_id == Some(issue_bellow_id)
|
||||||
|
|| project_page.last_drag_exchange_id == Some(issue_bellow_id)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let dragged_id = match model.project_page.dragged_issue_id {
|
let dragged_id = match project_page.dragged_issue_id {
|
||||||
Some(id) => id,
|
Some(id) => id,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
@ -50,7 +58,7 @@ pub fn exchange_position(issue_bellow_id: IssueId, model: &mut Model) {
|
|||||||
for mut c in issues.into_iter() {
|
for mut c in issues.into_iter() {
|
||||||
if c.status == below.status && c.list_position > below.list_position {
|
if c.status == below.status && c.list_position > below.list_position {
|
||||||
c.list_position += 1;
|
c.list_position += 1;
|
||||||
mark_dirty(c.id, model);
|
mark_dirty(c.id, project_page);
|
||||||
}
|
}
|
||||||
model.issues.push(c);
|
model.issues.push(c);
|
||||||
}
|
}
|
||||||
@ -59,20 +67,25 @@ pub fn exchange_position(issue_bellow_id: IssueId, model: &mut Model) {
|
|||||||
}
|
}
|
||||||
std::mem::swap(&mut dragged.list_position, &mut below.list_position);
|
std::mem::swap(&mut dragged.list_position, &mut below.list_position);
|
||||||
|
|
||||||
mark_dirty(dragged.id, model);
|
mark_dirty(dragged.id, project_page);
|
||||||
mark_dirty(below.id, model);
|
mark_dirty(below.id, project_page);
|
||||||
|
|
||||||
model.issues.push(below);
|
model.issues.push(below);
|
||||||
model.issues.push(dragged);
|
model.issues.push(dragged);
|
||||||
model
|
model
|
||||||
.issues
|
.issues
|
||||||
.sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
.sort_by(|a, b| a.list_position.cmp(&b.list_position));
|
||||||
model.project_page.last_drag_exchange_id = Some(issue_bellow_id);
|
project_page.last_drag_exchange_id = Some(issue_bellow_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dropped(_status: IssueStatus, model: &mut Model) {
|
pub fn dropped(_status: IssueStatus, model: &mut Model) {
|
||||||
|
let project_page = match &mut model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
for issue in model.issues.iter() {
|
for issue in model.issues.iter() {
|
||||||
if !model.project_page.dirty_issues.contains(&issue.id) {
|
if !project_page.dirty_issues.contains(&issue.id) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,14 +104,19 @@ pub fn dropped(_status: IssueStatus, model: &mut Model) {
|
|||||||
reporter_id: issue.reporter_id,
|
reporter_id: issue.reporter_id,
|
||||||
user_ids: issue.user_ids.clone(),
|
user_ids: issue.user_ids.clone(),
|
||||||
};
|
};
|
||||||
model.project_page.dragged_issue_id = None;
|
project_page.dragged_issue_id = None;
|
||||||
send_ws_msg(WsMsg::IssueUpdateRequest(issue.id, payload));
|
send_ws_msg(WsMsg::IssueUpdateRequest(issue.id, payload));
|
||||||
model.project_page.last_drag_exchange_id = None;
|
project_page.last_drag_exchange_id = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn change_status(status: IssueStatus, model: &mut Model) {
|
pub fn change_status(status: IssueStatus, model: &mut Model) {
|
||||||
let issue_id = match model.project_page.dragged_issue_id.as_ref().cloned() {
|
let project_page = match &mut model.page_content {
|
||||||
|
PageContent::Project(project_page) => project_page,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let issue_id = match project_page.dragged_issue_id.as_ref().cloned() {
|
||||||
Some(issue_id) => issue_id,
|
Some(issue_id) => issue_id,
|
||||||
_ => return,
|
_ => return,
|
||||||
};
|
};
|
||||||
@ -136,12 +154,12 @@ pub fn change_status(status: IssueStatus, model: &mut Model) {
|
|||||||
issue.list_position = pos + 1;
|
issue.list_position = pos + 1;
|
||||||
model.issues.push(issue);
|
model.issues.push(issue);
|
||||||
|
|
||||||
mark_dirty(issue_id, model);
|
mark_dirty(issue_id, project_page);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn mark_dirty(id: IssueId, model: &mut Model) {
|
fn mark_dirty(id: IssueId, project_page: &mut ProjectPage) {
|
||||||
if !model.project_page.dirty_issues.contains(&id) {
|
if !project_page.dirty_issues.contains(&id) {
|
||||||
model.project_page.dirty_issues.push(id);
|
project_page.dirty_issues.push(id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user