Handle multiple modals, fix copy icon background
This commit is contained in:
parent
f778f5a5c5
commit
2bc2e5f73e
@ -3,153 +3,3 @@
|
|||||||
padding-top: 18px;
|
padding-top: 18px;
|
||||||
border-top: 1px solid var(--borderLight);
|
border-top: 1px solid var(--borderLight);
|
||||||
}
|
}
|
||||||
|
|
||||||
.styledButton {
|
|
||||||
display: inline-flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
height: 32px;
|
|
||||||
vertical-align: middle;
|
|
||||||
line-height: 1;
|
|
||||||
white-space: nowrap;
|
|
||||||
border-radius: 3px;
|
|
||||||
transition: all 0.1s;
|
|
||||||
appearance: none;
|
|
||||||
cursor: pointer;
|
|
||||||
user-select: none;
|
|
||||||
font-size: 14.5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.withIcon > span.text {
|
|
||||||
margin-left: 7px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton:disabled {
|
|
||||||
opacity: 0.6;
|
|
||||||
cursor: default;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton:not(.onlyIcon) {
|
|
||||||
padding: 0 12px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.onlyIcon {
|
|
||||||
padding: 0 9px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.primary, .styledButton.primary > i {
|
|
||||||
color: #fff;
|
|
||||||
background: var(--primary);
|
|
||||||
font-family: var(--font-medium);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.primary:not(:disabled):hover {
|
|
||||||
filter: brightness(115%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.primary:not(:disabled):active {
|
|
||||||
filter: brightness(110%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.primary:not(:disabled).isActive {
|
|
||||||
filter: brightness(110%);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.success, .styledButton.success > i {
|
|
||||||
color: #fff;
|
|
||||||
background: var(--success);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.danger, .styledButton.danger > i {
|
|
||||||
color: #fff;
|
|
||||||
background: var(--danger);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.secondary, .styledButton.secondary > i {
|
|
||||||
color: var(--textDark);
|
|
||||||
background: var(--secondary);
|
|
||||||
font-family: var(--font-regular);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.secondary:not(:disabled):hover {
|
|
||||||
background: var(--backgroundLight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.secondary:not(:disabled):active {
|
|
||||||
color: var(--primary);
|
|
||||||
background: var(--backgroundLightPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.secondary:not(:disabled).isActive {
|
|
||||||
color: var(--primary);
|
|
||||||
background: var(--backgroundLightPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.empty, .styledButton.empty > i {
|
|
||||||
background: #fff;
|
|
||||||
color: var(--textDark);
|
|
||||||
font-family: var(--font-regular);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.empty:not(:disabled):hover {
|
|
||||||
background: var(--backgroundLight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.empty:not(:disabled):active {
|
|
||||||
color: var(--primary);
|
|
||||||
background: var(--backgroundLightPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledButton.empty:not(:disabled).isActive {
|
|
||||||
color: var(--primary);
|
|
||||||
background: var(--backgroundLightPrimary);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput {
|
|
||||||
position: relative;
|
|
||||||
display: inline-block;
|
|
||||||
height: 32px;
|
|
||||||
width: 100%;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput > .inputElement {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
padding: 0 7px;
|
|
||||||
border-radius: 3px;
|
|
||||||
border: 1px solid var(--borderLightest);
|
|
||||||
color: var(--textDarkest);
|
|
||||||
background: var(--backgroundLightest);
|
|
||||||
transition: background 0.1s;
|
|
||||||
font-family: var(--font-regular);
|
|
||||||
font-size: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput > .inputElement.withIcon {
|
|
||||||
padding-left: 32px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput > i.styledIcon {
|
|
||||||
font-size: 15px;
|
|
||||||
position: absolute;
|
|
||||||
top: 8px;
|
|
||||||
left: 8px;
|
|
||||||
pointer-events: none;
|
|
||||||
color: #5E6C84;
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput > .inputElement:hover {
|
|
||||||
background: var(--backgroundLight);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput > .inputElement:focus {
|
|
||||||
background: #fff;
|
|
||||||
border: 1px solid var(--borderInputFocus);
|
|
||||||
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
|
||||||
}
|
|
||||||
|
|
||||||
.styledInput.invalid,
|
|
||||||
.styledInput.invalid:focus {
|
|
||||||
border: 1px solid var(--danger);
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
|
100
jirs-client/js/css/styledButton.css
Normal file
100
jirs-client/js/css/styledButton.css
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
.styledButton {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
height: 32px;
|
||||||
|
vertical-align: middle;
|
||||||
|
line-height: 1;
|
||||||
|
white-space: nowrap;
|
||||||
|
border-radius: 3px;
|
||||||
|
transition: all 0.1s;
|
||||||
|
appearance: none;
|
||||||
|
cursor: pointer;
|
||||||
|
user-select: none;
|
||||||
|
font-size: 14.5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.withIcon > span.text {
|
||||||
|
margin-left: 7px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton:disabled {
|
||||||
|
opacity: 0.6;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton:not(.onlyIcon) {
|
||||||
|
padding: 0 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.onlyIcon {
|
||||||
|
padding: 0 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.primary, .styledButton.primary > i {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--primary);
|
||||||
|
font-family: var(--font-medium);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.primary:not(:disabled):hover {
|
||||||
|
filter: brightness(115%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.primary:not(:disabled):active {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.primary:not(:disabled).isActive {
|
||||||
|
filter: brightness(110%);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.success, .styledButton.success > i {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--success);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.danger, .styledButton.danger > i {
|
||||||
|
color: #fff;
|
||||||
|
background: var(--danger);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.secondary, .styledButton.secondary > i {
|
||||||
|
color: var(--textDark);
|
||||||
|
background: var(--secondary);
|
||||||
|
font-family: var(--font-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.secondary:not(:disabled):hover {
|
||||||
|
background: var(--backgroundLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.secondary:not(:disabled):active {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--backgroundLightPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.secondary:not(:disabled).isActive {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--backgroundLightPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.empty, .styledButton.empty > i {
|
||||||
|
background: #fff;
|
||||||
|
color: var(--textDark);
|
||||||
|
font-family: var(--font-regular);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.empty:not(:disabled):hover, .styledButton.empty:not(:disabled):hover > i {
|
||||||
|
background: var(--backgroundLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.empty:not(:disabled):active {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--backgroundLightPrimary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledButton.empty:not(:disabled).isActive {
|
||||||
|
color: var(--primary);
|
||||||
|
background: var(--backgroundLightPrimary);
|
||||||
|
}
|
48
jirs-client/js/css/styledInput.css
Normal file
48
jirs-client/js/css/styledInput.css
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
.styledInput {
|
||||||
|
position: relative;
|
||||||
|
display: inline-block;
|
||||||
|
height: 32px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput > .inputElement {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 7px;
|
||||||
|
border-radius: 3px;
|
||||||
|
border: 1px solid var(--borderLightest);
|
||||||
|
color: var(--textDarkest);
|
||||||
|
background: var(--backgroundLightest);
|
||||||
|
transition: background 0.1s;
|
||||||
|
font-family: var(--font-regular);
|
||||||
|
font-size: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput > .inputElement.withIcon {
|
||||||
|
padding-left: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput > i.styledIcon {
|
||||||
|
font-size: 15px;
|
||||||
|
position: absolute;
|
||||||
|
top: 8px;
|
||||||
|
left: 8px;
|
||||||
|
pointer-events: none;
|
||||||
|
color: #5E6C84;
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput > .inputElement:hover {
|
||||||
|
background: var(--backgroundLight);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput > .inputElement:focus {
|
||||||
|
background: #fff;
|
||||||
|
border: 1px solid var(--borderInputFocus);
|
||||||
|
box-shadow: 0 0 0 1px var(--borderInputFocus);
|
||||||
|
}
|
||||||
|
|
||||||
|
.styledInput.invalid,
|
||||||
|
.styledInput.invalid:focus {
|
||||||
|
border: 1px solid var(--danger);
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
@ -9,6 +9,8 @@
|
|||||||
@import "css/styledTooltip.css";
|
@import "css/styledTooltip.css";
|
||||||
@import "css/styledAvatar.css";
|
@import "css/styledAvatar.css";
|
||||||
@import "css/styledSelect.css";
|
@import "css/styledSelect.css";
|
||||||
|
@import "css/styledButton.css";
|
||||||
|
@import "css/styledInput.css";
|
||||||
@import "css/app.css";
|
@import "css/app.css";
|
||||||
@import "css/modal.css";
|
@import "css/modal.css";
|
||||||
@import "css/issue.css";
|
@import "css/issue.css";
|
||||||
|
@ -9,6 +9,7 @@ use crate::shared::styled_select::StyledSelectChange;
|
|||||||
mod api;
|
mod api;
|
||||||
mod api_handlers;
|
mod api_handlers;
|
||||||
mod login;
|
mod login;
|
||||||
|
mod modal;
|
||||||
mod model;
|
mod model;
|
||||||
mod project;
|
mod project;
|
||||||
mod project_settings;
|
mod project_settings;
|
||||||
@ -51,7 +52,7 @@ pub enum Msg {
|
|||||||
IssueUpdateResult(FetchObject<String>),
|
IssueUpdateResult(FetchObject<String>),
|
||||||
|
|
||||||
// modals
|
// modals
|
||||||
CloseModal,
|
PopModal,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
@ -62,12 +63,10 @@ fn update(msg: Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
|||||||
Msg::ChangePage(page) => {
|
Msg::ChangePage(page) => {
|
||||||
model.page = page;
|
model.page = page;
|
||||||
}
|
}
|
||||||
Msg::CloseModal => {
|
|
||||||
model.modal = None;
|
|
||||||
}
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
crate::shared::update(&msg, model, orders);
|
crate::shared::update(&msg, model, orders);
|
||||||
|
crate::modal::update(&msg, model, orders);
|
||||||
match model.page {
|
match model.page {
|
||||||
Page::Project => project::update(msg, model, orders),
|
Page::Project => project::update(msg, model, orders),
|
||||||
Page::EditIssue(_id) => project::update(msg, model, orders),
|
Page::EditIssue(_id) => project::update(msg, model, orders),
|
||||||
|
115
jirs-client/src/modal/mod.rs
Normal file
115
jirs-client/src/modal/mod.rs
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
use crate::api::update_issue;
|
||||||
|
use crate::model::{EditIssueModal, ModalType, Page};
|
||||||
|
use crate::project::issue_details;
|
||||||
|
use crate::shared::modal::{Modal, Variant as ModalVariant};
|
||||||
|
use crate::shared::styled_select::StyledSelectChange;
|
||||||
|
use crate::shared::{find_issue, ToNode};
|
||||||
|
use crate::{model, FieldId, Msg};
|
||||||
|
use jirs_data::{Issue, IssueType, UpdateIssuePayload};
|
||||||
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
|
pub fn update(msg: &Msg, model: &mut model::Model, orders: &mut impl Orders<Msg>) {
|
||||||
|
match msg {
|
||||||
|
Msg::PopModal => match model.modals.pop() {
|
||||||
|
_ => (),
|
||||||
|
},
|
||||||
|
Msg::ChangePage(Page::EditIssue(issue_id)) => {
|
||||||
|
let value = find_issue(model, *issue_id)
|
||||||
|
.map(|issue| issue.issue_type.clone())
|
||||||
|
.unwrap_or_else(|| IssueType::Task);
|
||||||
|
model.modals.push(ModalType::EditIssue(
|
||||||
|
*issue_id,
|
||||||
|
EditIssueModal {
|
||||||
|
id: *issue_id,
|
||||||
|
top_select_opened: false,
|
||||||
|
top_select_filter: "".to_string(),
|
||||||
|
value,
|
||||||
|
link_copied: false,
|
||||||
|
},
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
Msg::StyledSelectChanged(FieldId::IssueTypeEditModalTop, change) => {
|
||||||
|
match (change, model.modals.last_mut()) {
|
||||||
|
(StyledSelectChange::Text(ref text), Some(ModalType::EditIssue(_, modal))) => {
|
||||||
|
modal.top_select_filter = text.clone();
|
||||||
|
}
|
||||||
|
(
|
||||||
|
StyledSelectChange::DropDownVisibility(flag),
|
||||||
|
Some(ModalType::EditIssue(_, modal)),
|
||||||
|
) => {
|
||||||
|
modal.top_select_opened = *flag;
|
||||||
|
}
|
||||||
|
(
|
||||||
|
StyledSelectChange::Changed(value),
|
||||||
|
Some(ModalType::EditIssue(issue_id, modal)),
|
||||||
|
) => {
|
||||||
|
modal.value = (*value).into();
|
||||||
|
let project = match model.project.as_mut() {
|
||||||
|
Some(p) => p,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
let mut found: Option<&mut Issue> = None;
|
||||||
|
for issue in project.issues.iter_mut() {
|
||||||
|
if issue.id == *issue_id {
|
||||||
|
found = Some(issue);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let issue = match found {
|
||||||
|
Some(i) => i,
|
||||||
|
_ => return,
|
||||||
|
};
|
||||||
|
|
||||||
|
let form = UpdateIssuePayload {
|
||||||
|
title: Some(issue.title.clone()),
|
||||||
|
issue_type: Some(modal.value.clone()),
|
||||||
|
status: Some(issue.status.clone()),
|
||||||
|
priority: Some(issue.priority.clone()),
|
||||||
|
list_position: Some(issue.list_position),
|
||||||
|
description: Some(issue.description.clone()),
|
||||||
|
description_text: Some(issue.description_text.clone()),
|
||||||
|
estimate: Some(issue.estimate.clone()),
|
||||||
|
time_spent: Some(issue.time_spent.clone()),
|
||||||
|
time_remaining: Some(issue.time_remaining.clone()),
|
||||||
|
project_id: Some(issue.project_id.clone()),
|
||||||
|
user_ids: Some(issue.user_ids.clone()),
|
||||||
|
};
|
||||||
|
orders.skip().perform_cmd(update_issue(
|
||||||
|
model.host_url.clone(),
|
||||||
|
*issue_id,
|
||||||
|
form,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||||
|
let modals: Vec<Node<Msg>> = model
|
||||||
|
.modals
|
||||||
|
.iter()
|
||||||
|
.map(|modal| match modal {
|
||||||
|
ModalType::EditIssue(issue_id, modal) => {
|
||||||
|
if let Some(issue) = find_issue(model, *issue_id) {
|
||||||
|
let details = issue_details(model, issue, &modal);
|
||||||
|
let modal = Modal {
|
||||||
|
variant: ModalVariant::Center,
|
||||||
|
width: 1040,
|
||||||
|
with_icon: false,
|
||||||
|
children: vec![details],
|
||||||
|
}
|
||||||
|
.into_node();
|
||||||
|
modal
|
||||||
|
} else {
|
||||||
|
empty![]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => empty![],
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
section![id!["modals"], modals]
|
||||||
|
}
|
@ -84,7 +84,7 @@ pub struct Model {
|
|||||||
pub page: Page,
|
pub page: Page,
|
||||||
pub host_url: String,
|
pub host_url: String,
|
||||||
pub project_page: ProjectPage,
|
pub project_page: ProjectPage,
|
||||||
pub modal: Option<ModalType>,
|
pub modals: Vec<ModalType>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Model {
|
impl Default for Model {
|
||||||
@ -109,7 +109,7 @@ impl Default for Model {
|
|||||||
recently_updated_filter: false,
|
recently_updated_filter: false,
|
||||||
dragged_issue_id: None,
|
dragged_issue_id: None,
|
||||||
},
|
},
|
||||||
modal: None,
|
modals: vec![],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,14 +2,12 @@ use seed::{prelude::*, *};
|
|||||||
|
|
||||||
use jirs_data::*;
|
use jirs_data::*;
|
||||||
|
|
||||||
use crate::api::update_issue;
|
use crate::model::{EditIssueModal, Icon, Model, Page};
|
||||||
use crate::model::{EditIssueModal, Icon, ModalType, Model, Page};
|
|
||||||
use crate::shared::modal::{Modal, Variant as ModalVariant};
|
|
||||||
use crate::shared::styled_avatar::StyledAvatar;
|
use crate::shared::styled_avatar::StyledAvatar;
|
||||||
use crate::shared::styled_button::{StyledButton, Variant as ButtonVariant};
|
use crate::shared::styled_button::{StyledButton, Variant as ButtonVariant};
|
||||||
use crate::shared::styled_input::StyledInput;
|
use crate::shared::styled_input::StyledInput;
|
||||||
use crate::shared::styled_select::{StyledSelect, StyledSelectChange};
|
use crate::shared::styled_select::StyledSelect;
|
||||||
use crate::shared::{drag_ev, find_issue, inner_layout, ToNode};
|
use crate::shared::{drag_ev, inner_layout, ToNode};
|
||||||
use crate::{FieldId, IssueId, Msg};
|
use crate::{FieldId, IssueId, 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>) {
|
||||||
@ -22,26 +20,13 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
.skip()
|
.skip()
|
||||||
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
||||||
}
|
}
|
||||||
Msg::ChangePage(Page::EditIssue(issue_id)) => {
|
Msg::ChangePage(Page::EditIssue(_issue_id)) => {
|
||||||
orders
|
orders
|
||||||
.skip()
|
.skip()
|
||||||
.perform_cmd(crate::api::fetch_current_project(model.host_url.clone()));
|
.perform_cmd(crate::api::fetch_current_project(model.host_url.clone()));
|
||||||
orders
|
orders
|
||||||
.skip()
|
.skip()
|
||||||
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
.perform_cmd(crate::api::fetch_current_user(model.host_url.clone()));
|
||||||
let value = find_issue(model, issue_id)
|
|
||||||
.map(|issue| issue.issue_type.clone())
|
|
||||||
.unwrap_or_else(|| IssueType::Task);
|
|
||||||
model.modal = Some(ModalType::EditIssue(
|
|
||||||
issue_id,
|
|
||||||
EditIssueModal {
|
|
||||||
id: issue_id,
|
|
||||||
top_select_opened: false,
|
|
||||||
top_select_filter: "".to_string(),
|
|
||||||
value,
|
|
||||||
link_copied: false,
|
|
||||||
},
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
Msg::ToggleAboutTooltip => {
|
Msg::ToggleAboutTooltip => {
|
||||||
model.project_page.about_tooltip_visible = !model.project_page.about_tooltip_visible;
|
model.project_page.about_tooltip_visible = !model.project_page.about_tooltip_visible;
|
||||||
@ -131,61 +116,6 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
_ => error!("Drag stopped before drop :("),
|
_ => error!("Drag stopped before drop :("),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Msg::StyledSelectChanged(FieldId::IssueTypeEditModalTop, change) => {
|
|
||||||
match (change, model.modal.as_mut()) {
|
|
||||||
(StyledSelectChange::Text(ref text), Some(ModalType::EditIssue(_, modal))) => {
|
|
||||||
modal.top_select_filter = text.clone();
|
|
||||||
}
|
|
||||||
(
|
|
||||||
StyledSelectChange::DropDownVisibility(flag),
|
|
||||||
Some(ModalType::EditIssue(_, modal)),
|
|
||||||
) => {
|
|
||||||
modal.top_select_opened = flag;
|
|
||||||
}
|
|
||||||
(
|
|
||||||
StyledSelectChange::Changed(value),
|
|
||||||
Some(ModalType::EditIssue(issue_id, modal)),
|
|
||||||
) => {
|
|
||||||
modal.value = value.into();
|
|
||||||
let project = match model.project.as_mut() {
|
|
||||||
Some(p) => p,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
let mut found: Option<&mut Issue> = None;
|
|
||||||
for issue in project.issues.iter_mut() {
|
|
||||||
if issue.id == *issue_id {
|
|
||||||
found = Some(issue);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
let issue = match found {
|
|
||||||
Some(i) => i,
|
|
||||||
_ => return,
|
|
||||||
};
|
|
||||||
|
|
||||||
let form = UpdateIssuePayload {
|
|
||||||
title: Some(issue.title.clone()),
|
|
||||||
issue_type: Some(modal.value.clone()),
|
|
||||||
status: Some(issue.status.clone()),
|
|
||||||
priority: Some(issue.priority.clone()),
|
|
||||||
list_position: Some(issue.list_position),
|
|
||||||
description: Some(issue.description.clone()),
|
|
||||||
description_text: Some(issue.description_text.clone()),
|
|
||||||
estimate: Some(issue.estimate.clone()),
|
|
||||||
time_spent: Some(issue.time_spent.clone()),
|
|
||||||
time_remaining: Some(issue.time_remaining.clone()),
|
|
||||||
project_id: Some(issue.project_id.clone()),
|
|
||||||
user_ids: Some(issue.user_ids.clone()),
|
|
||||||
};
|
|
||||||
orders.skip().perform_cmd(update_issue(
|
|
||||||
model.host_url.clone(),
|
|
||||||
*issue_id,
|
|
||||||
form,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Msg::IssueUpdateResult(fetched) => {
|
Msg::IssueUpdateResult(fetched) => {
|
||||||
crate::api_handlers::update_issue_response(&fetched, model);
|
crate::api_handlers::update_issue_response(&fetched, model);
|
||||||
}
|
}
|
||||||
@ -194,25 +124,6 @@ pub fn update(msg: Msg, model: &mut crate::model::Model, orders: &mut impl Order
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn view(model: &Model) -> Node<Msg> {
|
pub fn view(model: &Model) -> Node<Msg> {
|
||||||
let modal = match &model.modal {
|
|
||||||
Some(ModalType::EditIssue(issue_id, modal)) => {
|
|
||||||
if let Some(issue) = find_issue(model, *issue_id) {
|
|
||||||
let details = issue_details(model, issue, &modal);
|
|
||||||
let modal = Modal {
|
|
||||||
variant: ModalVariant::Center,
|
|
||||||
width: 1040,
|
|
||||||
with_icon: false,
|
|
||||||
children: vec![details],
|
|
||||||
}
|
|
||||||
.into_node();
|
|
||||||
Some(modal)
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
_ => None,
|
|
||||||
};
|
|
||||||
|
|
||||||
let project_section = vec![
|
let project_section = vec![
|
||||||
breadcrumbs(model),
|
breadcrumbs(model),
|
||||||
header(),
|
header(),
|
||||||
@ -220,7 +131,12 @@ pub fn view(model: &Model) -> Node<Msg> {
|
|||||||
project_board_lists(model),
|
project_board_lists(model),
|
||||||
];
|
];
|
||||||
|
|
||||||
inner_layout(model, "projectPage", project_section, modal)
|
inner_layout(
|
||||||
|
model,
|
||||||
|
"projectPage",
|
||||||
|
project_section,
|
||||||
|
crate::modal::view(model),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn breadcrumbs(model: &Model) -> Node<Msg> {
|
fn breadcrumbs(model: &Model) -> Node<Msg> {
|
||||||
@ -512,7 +428,7 @@ impl crate::shared::styled_select::SelectOption for IssueTypeOption {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn issue_details(_model: &Model, issue: &Issue, modal: &EditIssueModal) -> Node<Msg> {
|
pub fn issue_details(_model: &Model, issue: &Issue, modal: &EditIssueModal) -> Node<Msg> {
|
||||||
let issue_id = issue.id;
|
let issue_id = issue.id;
|
||||||
|
|
||||||
let issue_type_select = StyledSelect {
|
let issue_type_select = StyledSelect {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use seed::prelude::*;
|
use seed::{prelude::*, *};
|
||||||
|
|
||||||
use crate::shared::inner_layout;
|
use crate::shared::inner_layout;
|
||||||
use crate::{model, Msg};
|
use crate::{model, Msg};
|
||||||
@ -8,5 +8,5 @@ pub fn update(_msg: Msg, _model: &mut model::Model, _orders: &mut impl Orders<Ms
|
|||||||
pub fn view(model: &model::Model) -> Node<Msg> {
|
pub fn view(model: &model::Model) -> Node<Msg> {
|
||||||
let project_section = vec![];
|
let project_section = vec![];
|
||||||
|
|
||||||
inner_layout(model, "projectSettings", project_section, None)
|
inner_layout(model, "projectSettings", project_section, empty![])
|
||||||
}
|
}
|
||||||
|
@ -45,12 +45,8 @@ pub fn inner_layout(
|
|||||||
model: &Model,
|
model: &Model,
|
||||||
page_name: &str,
|
page_name: &str,
|
||||||
children: Vec<Node<Msg>>,
|
children: Vec<Node<Msg>>,
|
||||||
modal: Option<Node<Msg>>,
|
modal_node: Node<Msg>,
|
||||||
) -> Node<Msg> {
|
) -> Node<Msg> {
|
||||||
let modal_node = match modal {
|
|
||||||
Some(modal) => vec![modal],
|
|
||||||
_ => vec![],
|
|
||||||
};
|
|
||||||
article![
|
article![
|
||||||
modal_node,
|
modal_node,
|
||||||
attrs![At::Class => "inner-layout"],
|
attrs![At::Class => "inner-layout"],
|
||||||
|
@ -57,7 +57,7 @@ pub fn render(values: Modal) -> Node<Msg> {
|
|||||||
empty![]
|
empty![]
|
||||||
};
|
};
|
||||||
|
|
||||||
let close_handler = mouse_ev(Ev::Click, |_| Msg::CloseModal);
|
let close_handler = mouse_ev(Ev::Click, |_| Msg::PopModal);
|
||||||
let body_handler = mouse_ev(Ev::Click, |ev| {
|
let body_handler = mouse_ev(Ev::Click, |ev| {
|
||||||
ev.stop_propagation();
|
ev.stop_propagation();
|
||||||
Msg::NoOp
|
Msg::NoOp
|
||||||
|
@ -349,11 +349,4 @@ joinable!(issues -> users (reporter_id));
|
|||||||
joinable!(tokens -> users (user_id));
|
joinable!(tokens -> users (user_id));
|
||||||
joinable!(users -> projects (project_id));
|
joinable!(users -> projects (project_id));
|
||||||
|
|
||||||
allow_tables_to_appear_in_same_query!(
|
allow_tables_to_appear_in_same_query!(comments, issue_assignees, issues, projects, tokens, users,);
|
||||||
comments,
|
|
||||||
issue_assignees,
|
|
||||||
issues,
|
|
||||||
projects,
|
|
||||||
tokens,
|
|
||||||
users,
|
|
||||||
);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user