Delete issue status full logic
This commit is contained in:
parent
b2cbb251d1
commit
4d07639e90
3
jirs-client/js/css/deleteIssueStatus.css
Normal file
3
jirs-client/js/css/deleteIssueStatus.css
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
.deleteIssueStatus {
|
||||||
|
min-width: 800px;
|
||||||
|
}
|
@ -55,3 +55,21 @@
|
|||||||
text-align: center;
|
text-align: center;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > .removeColumn {
|
||||||
|
text-align: center;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:hover > .columnName > .removeColumn,
|
||||||
|
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:focus > .columnName > .removeColumn,
|
||||||
|
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview:active > .columnName > .removeColumn {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#projectSettings > .formContainer .styledForm > .formElement > .styledField > .columnsSection > .columns > .columnPreview > .columnName > .issueCount {
|
||||||
|
text-transform: none;
|
||||||
|
padding-top: 15px;
|
||||||
|
}
|
||||||
|
@ -67,7 +67,7 @@
|
|||||||
--font-black: "CircularStdBlack";
|
--font-black: "CircularStdBlack";
|
||||||
}
|
}
|
||||||
|
|
||||||
:root {
|
:root { /* user without avatar */
|
||||||
--avatar-color-1: rgb(218, 118, 87);
|
--avatar-color-1: rgb(218, 118, 87);
|
||||||
--avatar-color-2: rgb(106, 218, 87);
|
--avatar-color-2: rgb(106, 218, 87);
|
||||||
--avatar-color-3: rgb(87, 132, 218);
|
--avatar-color-3: rgb(87, 132, 218);
|
||||||
|
@ -240,6 +240,9 @@ pub enum Msg {
|
|||||||
AddIssue,
|
AddIssue,
|
||||||
DeleteIssue(IssueId),
|
DeleteIssue(IssueId),
|
||||||
|
|
||||||
|
// issue statuses
|
||||||
|
DeleteIssueStatus(IssueStatusId),
|
||||||
|
|
||||||
// comments
|
// comments
|
||||||
SaveComment,
|
SaveComment,
|
||||||
DeleteComment(CommentId),
|
DeleteComment(CommentId),
|
||||||
|
43
jirs-client/src/modal/delete_issue_status.rs
Normal file
43
jirs-client/src/modal/delete_issue_status.rs
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
use seed::prelude::*;
|
||||||
|
|
||||||
|
use jirs_data::{IssueStatusId, WsMsg};
|
||||||
|
|
||||||
|
use crate::api::send_ws_msg;
|
||||||
|
use crate::model::{DeleteIssueStatusModal, ModalType, Model};
|
||||||
|
use crate::shared::styled_confirm_modal::StyledConfirmModal;
|
||||||
|
use crate::shared::ToNode;
|
||||||
|
use crate::{model, Msg};
|
||||||
|
|
||||||
|
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
let _modal: &mut Box<DeleteIssueStatusModal> =
|
||||||
|
match model.modals.iter_mut().find_map(|modal| match modal {
|
||||||
|
ModalType::DeleteIssueStatusModal(modal) => Some(modal),
|
||||||
|
_ => None,
|
||||||
|
}) {
|
||||||
|
Some(m) => m,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
match msg {
|
||||||
|
Msg::DeleteIssueStatus(issue_status_id) => {
|
||||||
|
send_ws_msg(WsMsg::IssueStatusDelete(*issue_status_id));
|
||||||
|
}
|
||||||
|
Msg::WsMsg(WsMsg::IssueStatusDelete(_)) => {
|
||||||
|
orders.skip().perform_cmd(Msg::ModalDropped);
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view(_model: &model::Model, issue_status_id: IssueStatusId) -> Node<Msg> {
|
||||||
|
StyledConfirmModal::build()
|
||||||
|
.title("Delete column")
|
||||||
|
.cancel_text("No")
|
||||||
|
.confirm_text("Yes")
|
||||||
|
.on_confirm(mouse_ev(Ev::Click, move |_| {
|
||||||
|
Msg::DeleteIssueStatus(issue_status_id)
|
||||||
|
}))
|
||||||
|
.message("Are you sure you want to delete column?")
|
||||||
|
.build()
|
||||||
|
.into_node()
|
||||||
|
}
|
@ -292,10 +292,10 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
|
|||||||
|
|
||||||
pub fn view(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
pub fn view(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => "issueDetails"],
|
class!["issueDetails"],
|
||||||
top_modal_row(model, modal),
|
top_modal_row(model, modal),
|
||||||
div![
|
div![
|
||||||
attrs![At::Class => "content"],
|
class!["content"],
|
||||||
left_modal_column(model, modal),
|
left_modal_column(model, modal),
|
||||||
right_modal_column(model, modal),
|
right_modal_column(model, modal),
|
||||||
],
|
],
|
||||||
|
@ -11,6 +11,7 @@ use crate::{model, FieldChange, FieldId, Msg};
|
|||||||
|
|
||||||
mod add_issue;
|
mod add_issue;
|
||||||
mod confirm_delete_issue;
|
mod confirm_delete_issue;
|
||||||
|
mod delete_issue_status;
|
||||||
mod issue_details;
|
mod issue_details;
|
||||||
pub mod time_tracking;
|
pub mod time_tracking;
|
||||||
|
|
||||||
@ -57,6 +58,7 @@ pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>
|
|||||||
}
|
}
|
||||||
add_issue::update(msg, model, orders);
|
add_issue::update(msg, model, orders);
|
||||||
issue_details::update(msg, model, orders);
|
issue_details::update(msg, model, orders);
|
||||||
|
delete_issue_status::update(msg, model, orders);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(model: &model::Model) -> Node<Msg> {
|
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||||
@ -90,6 +92,9 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
.into_node()
|
.into_node()
|
||||||
}
|
}
|
||||||
ModalType::TimeTracking(issue_id) => time_tracking::view(model, *issue_id),
|
ModalType::TimeTracking(issue_id) => time_tracking::view(model, *issue_id),
|
||||||
|
ModalType::DeleteIssueStatusModal(delete_issue_modal) => {
|
||||||
|
delete_issue_status::view(model, delete_issue_modal.delete_id)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.collect();
|
.collect();
|
||||||
section![id!["modals"], modals]
|
section![id!["modals"], modals]
|
||||||
|
@ -21,6 +21,7 @@ pub enum ModalType {
|
|||||||
DeleteIssueConfirm(IssueId),
|
DeleteIssueConfirm(IssueId),
|
||||||
DeleteCommentConfirm(CommentId),
|
DeleteCommentConfirm(CommentId),
|
||||||
TimeTracking(IssueId),
|
TimeTracking(IssueId),
|
||||||
|
DeleteIssueStatusModal(Box<DeleteIssueStatusModal>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
@ -30,9 +31,24 @@ pub struct CommentForm {
|
|||||||
pub creating: bool,
|
pub creating: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
|
pub struct DeleteIssueStatusModal {
|
||||||
|
pub delete_id: IssueStatusId,
|
||||||
|
pub receiver_id: Option<IssueStatusId>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DeleteIssueStatusModal {
|
||||||
|
pub fn new(delete_id: IssueStatusId) -> Self {
|
||||||
|
Self {
|
||||||
|
delete_id,
|
||||||
|
receiver_id: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
#[derive(Clone, Debug, PartialOrd, PartialEq)]
|
||||||
pub struct EditIssueModal {
|
pub struct EditIssueModal {
|
||||||
pub id: i32,
|
pub id: IssueId,
|
||||||
pub link_copied: bool,
|
pub link_copied: bool,
|
||||||
pub payload: UpdateIssuePayload,
|
pub payload: UpdateIssuePayload,
|
||||||
pub top_type_state: StyledSelectState,
|
pub top_type_state: StyledSelectState,
|
||||||
|
@ -1,11 +1,14 @@
|
|||||||
use seed::{prelude::*, *};
|
use seed::{prelude::*, *};
|
||||||
|
use wasm_bindgen::__rt::std::collections::HashMap;
|
||||||
|
|
||||||
use jirs_data::{
|
use jirs_data::{
|
||||||
IssueStatus, IssueStatusId, ProjectCategory, TimeTracking, ToVec, UpdateProjectPayload, WsMsg,
|
IssueStatus, IssueStatusId, ProjectCategory, TimeTracking, ToVec, UpdateProjectPayload, WsMsg,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::api::send_ws_msg;
|
use crate::api::send_ws_msg;
|
||||||
use crate::model::{Model, Page, PageContent, ProjectSettingsPage};
|
use crate::model::{
|
||||||
|
DeleteIssueStatusModal, ModalType, Model, Page, PageContent, ProjectSettingsPage,
|
||||||
|
};
|
||||||
use crate::shared::styled_button::StyledButton;
|
use crate::shared::styled_button::StyledButton;
|
||||||
use crate::shared::styled_checkbox::StyledCheckbox;
|
use crate::shared::styled_checkbox::StyledCheckbox;
|
||||||
use crate::shared::styled_editor::StyledEditor;
|
use crate::shared::styled_editor::StyledEditor;
|
||||||
@ -31,12 +34,14 @@ pub fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>)
|
|||||||
Msg::WsMsg(WsMsg::AuthorizeLoaded(..)) => {
|
Msg::WsMsg(WsMsg::AuthorizeLoaded(..)) => {
|
||||||
send_ws_msg(WsMsg::ProjectRequest);
|
send_ws_msg(WsMsg::ProjectRequest);
|
||||||
send_ws_msg(WsMsg::IssueStatusesRequest);
|
send_ws_msg(WsMsg::IssueStatusesRequest);
|
||||||
|
send_ws_msg(WsMsg::ProjectIssuesRequest);
|
||||||
}
|
}
|
||||||
Msg::ChangePage(Page::ProjectSettings) => {
|
Msg::ChangePage(Page::ProjectSettings) => {
|
||||||
build_page_content(model);
|
build_page_content(model);
|
||||||
if model.user.is_some() {
|
if model.user.is_some() {
|
||||||
send_ws_msg(WsMsg::ProjectRequest);
|
send_ws_msg(WsMsg::ProjectRequest);
|
||||||
send_ws_msg(WsMsg::IssueStatusesRequest);
|
send_ws_msg(WsMsg::IssueStatusesRequest);
|
||||||
|
send_ws_msg(WsMsg::ProjectIssuesRequest);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::WsMsg(WsMsg::ProjectLoaded(..)) => {
|
Msg::WsMsg(WsMsg::ProjectLoaded(..)) => {
|
||||||
@ -245,6 +250,12 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
|
|
||||||
let width = 100f64 / (model.issue_statuses.len() + 1) as f64;
|
let width = 100f64 / (model.issue_statuses.len() + 1) as f64;
|
||||||
let column_style = format!("width: calc({width}% - 10px)", width = width);
|
let column_style = format!("width: calc({width}% - 10px)", width = width);
|
||||||
|
let mut per_column_issue_count = HashMap::new();
|
||||||
|
for issue in model.issues.iter() {
|
||||||
|
*per_column_issue_count
|
||||||
|
.entry(issue.issue_status_id)
|
||||||
|
.or_insert(0) += 1;
|
||||||
|
}
|
||||||
let columns: Vec<Node<Msg>> = model
|
let columns: Vec<Node<Msg>> = model
|
||||||
.issue_statuses
|
.issue_statuses
|
||||||
.iter()
|
.iter()
|
||||||
@ -288,13 +299,32 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
div![class!["columnName"], input]
|
div![class!["columnName"], input]
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
let edit = mouse_ev(Ev::Click, move |_| {
|
let on_edit = mouse_ev(Ev::Click, move |_| {
|
||||||
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::EditIssueStatusName(Some(id))))
|
Msg::PageChanged(PageChanged::ProjectSettings(ProjectPageChange::EditIssueStatusName(Some(id))))
|
||||||
});
|
});
|
||||||
|
let issue_count_in_column = per_column_issue_count.get(&id).cloned().unwrap_or_default();
|
||||||
|
let delete_row = if issue_count_in_column == 0 {
|
||||||
|
let on_delete = mouse_ev(Ev::Click, move |ev| {
|
||||||
|
ev.prevent_default();
|
||||||
|
ev.stop_propagation();
|
||||||
|
Msg::ModalOpened(Box::new(ModalType::DeleteIssueStatusModal(Box::new(DeleteIssueStatusModal::new(id)))))
|
||||||
|
});
|
||||||
|
let delete = StyledButton::build()
|
||||||
|
.primary()
|
||||||
|
.add_class("removeColumn")
|
||||||
|
.icon(Icon::Trash)
|
||||||
|
.on_click(on_delete)
|
||||||
|
.build()
|
||||||
|
.into_node();
|
||||||
|
div![class!["removeColumn"], delete]
|
||||||
|
} else {
|
||||||
|
div![class!["issueCount"], format!("Issues in column: {}", issue_count_in_column)]
|
||||||
|
};
|
||||||
|
|
||||||
div![
|
div![
|
||||||
class!["columnPreview"],
|
class!["columnPreview"],
|
||||||
attrs![At::Style => column_style.as_str(), At::Draggable => "true", At::DropZone => "true"],
|
attrs![At::Style => column_style.as_str(), At::Draggable => "true", At::DropZone => "true"],
|
||||||
div![class!["columnName"], span![is.name], edit],
|
div![class!["columnName"], span![is.name], on_edit, delete_row],
|
||||||
drag_started,
|
drag_started,
|
||||||
drag_stopped,
|
drag_stopped,
|
||||||
drag_over_handler,
|
drag_over_handler,
|
||||||
@ -352,7 +382,12 @@ pub fn view(model: &model::Model) -> Node<Msg> {
|
|||||||
|
|
||||||
let project_section = vec![div![class!["formContainer"], form]];
|
let project_section = vec![div![class!["formContainer"], form]];
|
||||||
|
|
||||||
inner_layout(model, "projectSettings", project_section, empty![])
|
inner_layout(
|
||||||
|
model,
|
||||||
|
"projectSettings",
|
||||||
|
project_section,
|
||||||
|
crate::modal::view(model),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn exchange_position(bellow_id: IssueStatusId, model: &mut Model) {
|
fn exchange_position(bellow_id: IssueStatusId, model: &mut Model) {
|
||||||
|
@ -29,11 +29,11 @@ impl Variant {
|
|||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StyledModal {
|
pub struct StyledModal {
|
||||||
pub variant: Variant,
|
variant: Variant,
|
||||||
pub width: usize,
|
width: usize,
|
||||||
pub with_icon: bool,
|
with_icon: bool,
|
||||||
pub children: Vec<Node<Msg>>,
|
children: Vec<Node<Msg>>,
|
||||||
pub class_list: Vec<String>,
|
class_list: Vec<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToNode for StyledModal {
|
impl ToNode for StyledModal {
|
||||||
@ -63,6 +63,10 @@ impl StyledModalBuilder {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// pub fn center(mut self) -> Self {
|
||||||
|
// self.variant(Variant::Center)
|
||||||
|
// }
|
||||||
|
|
||||||
pub fn width(mut self, width: usize) -> Self {
|
pub fn width(mut self, width: usize) -> Self {
|
||||||
self.width = Some(width);
|
self.width = Some(width);
|
||||||
self
|
self
|
||||||
|
Loading…
Reference in New Issue
Block a user