Better fmt, remove select builder

This commit is contained in:
Adrian Woźniak 2021-04-16 15:20:25 +02:00
parent e6ef4d6b0e
commit 2b40f9fd91
144 changed files with 1731 additions and 1935 deletions

View File

@ -1,7 +1,5 @@
use { use actix;
actix, use rusoto_s3::{PutObjectRequest, S3Client, S3};
rusoto_s3::{PutObjectRequest, S3Client, S3},
};
#[derive(Debug)] #[derive(Debug)]
pub enum AmazonError { pub enum AmazonError {

View File

@ -1,8 +1,8 @@
use { use diesel::prelude::*;
crate::{db_find, tokens::FindAccessToken}, use jirs_data::User;
diesel::prelude::*,
jirs_data::User, use crate::db_find;
}; use crate::tokens::FindAccessToken;
db_find! { db_find! {
AuthorizeUser, AuthorizeUser,

View File

@ -1,8 +1,7 @@
use { use diesel::prelude::*;
crate::{db_create, db_delete, db_load, db_update}, use jirs_data::{Comment, CommentId, IssueId, UserId};
diesel::prelude::*,
jirs_data::{Comment, CommentId, IssueId, UserId}, use crate::{db_create, db_delete, db_load, db_update};
};
db_load! { db_load! {
LoadIssueComments, LoadIssueComments,

View File

@ -1,9 +1,8 @@
use { use derive_db_execute::Execute;
crate::{db_create, db_delete, db_load, db_update}, use diesel::prelude::*;
derive_db_execute::Execute, use jirs_data::{DescriptionString, Epic, EpicId, ProjectId};
diesel::prelude::*,
jirs_data::{DescriptionString, Epic, EpicId, ProjectId}, use crate::{db_create, db_delete, db_load, db_update};
};
#[derive(Execute)] #[derive(Execute)]
#[db_exec(schema = "epics", result = "Epic", find = "epics.find(msg.epic_id)")] #[db_exec(schema = "epics", result = "Epic", find = "epics.find(msg.epic_id)")]

View File

@ -1,16 +1,15 @@
use { use actix::{Handler, Message};
crate::{ use diesel::prelude::*;
db_create, db_delete, db_find, db_load, db_pool, db_update, use jirs_data::{
tokens::CreateBindToken,
users::{LookupUser, Register},
DbExecutor, DbPooledConn, InvitationError,
},
actix::{Handler, Message},
diesel::prelude::*,
jirs_data::{
EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token, EmailString, Invitation, InvitationId, InvitationState, InvitationToken, ProjectId, Token,
User, UserId, UserRole, UsernameString, User, UserId, UserRole, UsernameString,
}, };
use crate::tokens::CreateBindToken;
use crate::users::{LookupUser, Register};
use crate::{
db_create, db_delete, db_find, db_load, db_pool, db_update, DbExecutor, DbPooledConn,
InvitationError,
}; };
db_find! { db_find! {

View File

@ -1,8 +1,8 @@
use { use diesel::expression::dsl::not;
crate::{db_create, db_delete, db_load, db_load_field}, use diesel::prelude::*;
diesel::{expression::dsl::not, prelude::*}, use jirs_data::{IssueAssignee, IssueId, UserId};
jirs_data::{IssueAssignee, IssueId, UserId},
}; use crate::{db_create, db_delete, db_load, db_load_field};
db_create! { db_create! {
AsignMultiple, AsignMultiple,

View File

@ -1,8 +1,7 @@
use { use diesel::prelude::*;
crate::{db_create, db_delete, db_load, db_update}, use jirs_data::{IssueStatus, IssueStatusId, Position, ProjectId, TitleString};
diesel::prelude::*,
jirs_data::{IssueStatus, IssueStatusId, Position, ProjectId, TitleString}, use crate::{db_create, db_delete, db_load, db_update};
};
db_load! { db_load! {
LoadIssueStatuses, LoadIssueStatuses,

View File

@ -1,9 +1,9 @@
use { use derive_db_execute::Execute;
crate::models::Issue, use diesel::expression::sql_literal::sql;
derive_db_execute::Execute, use diesel::prelude::*;
diesel::{expression::sql_literal::sql, prelude::*}, use jirs_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId};
jirs_data::{IssueId, IssuePriority, IssueStatusId, IssueType, ProjectId, UserId},
}; use crate::models::Issue;
#[derive(Default, Execute)] #[derive(Default, Execute)]
#[db_exec( #[db_exec(
@ -112,12 +112,11 @@ pub struct DeleteIssue {
} }
mod inner { mod inner {
use { use derive_db_execute::Execute;
crate::models::Issue, use diesel::prelude::*;
derive_db_execute::Execute, use jirs_data::{IssuePriority, IssueStatusId, IssueType};
diesel::prelude::*,
jirs_data::{IssuePriority, IssueStatusId, IssueType}, use crate::models::Issue;
};
#[derive(Default, Execute)] #[derive(Default, Execute)]
#[db_exec( #[db_exec(

View File

@ -3,12 +3,10 @@
#[macro_use] #[macro_use]
extern crate diesel; extern crate diesel;
use actix::{Actor, SyncContext};
use diesel::pg::PgConnection;
use diesel::r2d2::{self, ConnectionManager};
pub use errors::*; pub use errors::*;
use {
actix::{Actor, SyncContext},
diesel::pg::PgConnection,
diesel::r2d2::{self, ConnectionManager},
};
pub mod authorize_user; pub mod authorize_user;
pub mod comments; pub mod comments;
@ -72,7 +70,8 @@ pub struct Guard<'l> {
impl<'l> Guard<'l> { impl<'l> Guard<'l> {
pub fn new(conn: &'l DbPooledConn) -> Result<Self, crate::DatabaseError> { pub fn new(conn: &'l DbPooledConn) -> Result<Self, crate::DatabaseError> {
use diesel::{connection::TransactionManager, prelude::*}; use diesel::connection::TransactionManager;
use diesel::prelude::*;
let tm = conn.transaction_manager(); let tm = conn.transaction_manager();
tm.begin_transaction(conn).map_err(|e| { tm.begin_transaction(conn).map_err(|e| {
log::error!("{:?}", e); log::error!("{:?}", e);

View File

@ -1,11 +1,8 @@
use { use diesel::prelude::*;
crate::{ use jirs_data::{BindToken, Message, MessageId, MessageType, User, UserId};
db_create, db_delete, db_load,
users::{FindUser, LookupUser}, use crate::users::{FindUser, LookupUser};
}, use crate::{db_create, db_delete, db_load};
diesel::prelude::*,
jirs_data::{BindToken, Message, MessageId, MessageType, User, UserId},
};
db_load! { db_load! {
LoadMessages, LoadMessages,

View File

@ -1,13 +1,12 @@
use { use chrono::NaiveDateTime;
crate::schema::*, use jirs_data::{
chrono::NaiveDateTime, EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId,
jirs_data::{ TimeTracking, UserId,
EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory,
ProjectId, TimeTracking, UserId,
},
serde::{Deserialize, Serialize},
uuid::Uuid,
}; };
use serde::{Deserialize, Serialize};
use uuid::Uuid;
use crate::schema::*;
#[derive(Serialize, Debug, Deserialize, Queryable)] #[derive(Serialize, Debug, Deserialize, Queryable)]
pub struct Issue { pub struct Issue {

View File

@ -1,8 +1,7 @@
use { use diesel::prelude::*;
crate::{db_create, db_find, db_load, db_update}, use jirs_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId};
diesel::prelude::*,
jirs_data::{NameString, Project, ProjectCategory, ProjectId, TimeTracking, UserId}, use crate::{db_create, db_find, db_load, db_update};
};
db_find! { db_find! {
LoadCurrentProject, LoadCurrentProject,
@ -12,11 +11,10 @@ db_find! {
} }
mod inner { mod inner {
use { use diesel::prelude::*;
crate::db_create, use jirs_data::{NameString, Project, ProjectCategory, TimeTracking};
diesel::prelude::*,
jirs_data::{NameString, Project, ProjectCategory, TimeTracking}, use crate::db_create;
};
db_create! { db_create! {
CreateProject, CreateProject,

View File

@ -1,8 +1,7 @@
use { use diesel::prelude::*;
crate::{db_create, db_find, db_update}, use jirs_data::{Token, UserId};
diesel::prelude::*,
jirs_data::{Token, UserId}, use crate::{db_create, db_find, db_update};
};
db_find! { db_find! {
FindUserId, FindUserId,

View File

@ -1,8 +1,7 @@
use { use diesel::prelude::*;
crate::{db_create, db_delete, db_find, db_load, db_update}, use jirs_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole};
diesel::prelude::*,
jirs_data::{ProjectId, UserId, UserProject, UserProjectId, UserRole}, use crate::{db_create, db_delete, db_find, db_load, db_update};
};
db_find! { db_find! {
CurrentUserProject, CurrentUserProject,
@ -27,11 +26,10 @@ db_load! {
} }
mod inner { mod inner {
use { use diesel::prelude::*;
crate::db_update, use jirs_data::{UserId, UserProject, UserProjectId};
diesel::prelude::*,
jirs_data::{UserId, UserProject, UserProjectId}, use crate::db_update;
};
db_update! { db_update! {
ChangeProjectIsCurrent, ChangeProjectIsCurrent,

View File

@ -1,11 +1,9 @@
use { use diesel::prelude::*;
crate::{ use jirs_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString};
db_create, db_find, db_load, db_update, projects::CreateProject, q,
user_projects::CreateUserProject, DbPooledConn, use crate::projects::CreateProject;
}, use crate::user_projects::CreateUserProject;
diesel::prelude::*, use crate::{db_create, db_find, db_load, db_update, q, DbPooledConn};
jirs_data::{EmailString, IssueId, ProjectId, User, UserId, UserRole, UsernameString},
};
db_find! { db_find! {
FindUser, FindUser,
@ -156,12 +154,10 @@ db_update! {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use diesel::connection::TransactionManager; use diesel::connection::TransactionManager;
use jirs_data::{Project, ProjectCategory}; use jirs_data::{Project, ProjectCategory};
use crate::build_pool;
use super::*; use super::*;
use crate::build_pool;
#[test] #[test]
fn check_collision() { fn check_collision() {

View File

@ -1,9 +1,9 @@
use { use std::io::Write;
actix::SyncContext, use std::path::PathBuf;
actix_files::{self, Files},
jirs_config::fs::Configuration, use actix::SyncContext;
std::{io::Write, path::PathBuf}, use actix_files::{self, Files};
}; use jirs_config::fs::Configuration;
#[derive(Debug)] #[derive(Debug)]
pub enum FsError { pub enum FsError {

View File

@ -1,14 +1,11 @@
use { use std::sync::Arc;
actix::{Actor, Handler, SyncContext},
jirs_data::HighlightedCode, use actix::{Actor, Handler, SyncContext};
simsearch::SimSearch, use jirs_data::HighlightedCode;
std::sync::Arc, use simsearch::SimSearch;
syntect::{ use syntect::easy::HighlightLines;
easy::HighlightLines, use syntect::highlighting::{Style, ThemeSet};
highlighting::{Style, ThemeSet}, use syntect::parsing::SyntaxSet;
parsing::SyntaxSet,
},
};
mod load; mod load;

View File

@ -1,9 +1,8 @@
use { use std::io::BufRead;
bincode::{deserialize_from, Result},
flate2::bufread::ZlibDecoder, use bincode::{deserialize_from, Result};
serde::de::DeserializeOwned, use flate2::bufread::ZlibDecoder;
std::io::BufRead, use serde::de::DeserializeOwned;
};
fn from_reader<T: DeserializeOwned, R: BufRead>(input: R) -> Result<T> { fn from_reader<T: DeserializeOwned, R: BufRead>(input: R) -> Result<T> {
let mut decoder = ZlibDecoder::new(input); let mut decoder = ZlibDecoder::new(input);

View File

@ -1,8 +1,7 @@
use { use actix::{Handler, Message};
crate::MailExecutor, use uuid::Uuid;
actix::{Handler, Message},
uuid::Uuid, use crate::MailExecutor;
};
#[derive(Debug)] #[derive(Debug)]
pub struct Invite { pub struct Invite {

View File

@ -1,8 +1,7 @@
use { use actix::{Handler, Message};
crate::MailExecutor, use uuid::Uuid;
actix::{Handler, Message},
uuid::Uuid, use crate::MailExecutor;
};
#[derive(Debug)] #[derive(Debug)]
pub struct Welcome { pub struct Welcome {

View File

@ -1,19 +1,21 @@
use std::io::Write; use std::io::Write;
use actix::Addr;
use actix_multipart::{Field, Multipart};
use actix_web::http::header::ContentDisposition;
use actix_web::web::Data;
use actix_web::{post, web, Error, HttpResponse};
use database_actor::authorize_user::AuthorizeUser;
use database_actor::user_projects::CurrentUserProject;
use database_actor::users::UpdateAvatarUrl;
use database_actor::DbExecutor;
#[cfg(feature = "local-storage")] #[cfg(feature = "local-storage")]
use filesystem_actor; use filesystem_actor;
use { use futures::executor::block_on;
actix::Addr, use futures::{StreamExt, TryStreamExt};
actix_multipart::{Field, Multipart}, use jirs_data::{User, UserId, WsMsg};
actix_web::{http::header::ContentDisposition, post, web, web::Data, Error, HttpResponse}, use websocket_actor::server::InnerMsg::BroadcastToChannel;
database_actor::{ use websocket_actor::server::WsServer;
authorize_user::AuthorizeUser, user_projects::CurrentUserProject, users::UpdateAvatarUrl,
DbExecutor,
},
futures::{executor::block_on, StreamExt, TryStreamExt},
jirs_data::{User, UserId, WsMsg},
websocket_actor::server::{InnerMsg::BroadcastToChannel, WsServer},
};
#[post("/")] #[post("/")]
pub async fn upload( pub async fn upload(

View File

@ -1,6 +1,6 @@
use actix_web::HttpResponse; use actix_web::HttpResponse;
use jirs_data::msg::WsError;
use jirs_data::{msg::WsError, ErrorResponse}; use jirs_data::ErrorResponse;
const TOKEN_NOT_FOUND: &str = "Token not found"; const TOKEN_NOT_FOUND: &str = "Token not found";
const DATABASE_CONNECTION_FAILED: &str = "Database connection failed"; const DATABASE_CONNECTION_FAILED: &str = "Database connection failed";

View File

@ -1,11 +1,11 @@
use { use actix::Addr;
actix::Addr, use actix_multipart::Field;
actix_multipart::Field, use actix_web::http::header::ContentDisposition;
actix_web::{http::header::ContentDisposition, web::Data, Error}, use actix_web::web::Data;
futures::StreamExt, use actix_web::Error;
jirs_data::UserId, use futures::StreamExt;
tokio::sync::broadcast::{Receiver, Sender}, use jirs_data::UserId;
}; use tokio::sync::broadcast::{Receiver, Sender};
#[cfg(all(feature = "local-storage", feature = "aws-s3"))] #[cfg(all(feature = "local-storage", feature = "aws-s3"))]
pub(crate) async fn handle_image( pub(crate) async fn handle_image(

View File

@ -1,14 +1,15 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use actix::Addr;
use actix_web::web::Data;
use actix_web::{HttpRequest, HttpResponse};
use database_actor::authorize_user::AuthorizeUser;
use database_actor::DbExecutor;
pub use errors::*; pub use errors::*;
use { use jirs_data::User;
crate::middleware::authorize::token_from_headers,
actix::Addr, use crate::middleware::authorize::token_from_headers;
actix_web::{web::Data, HttpRequest, HttpResponse},
database_actor::{authorize_user::AuthorizeUser, DbExecutor},
jirs_data::User,
};
pub mod avatar; pub mod avatar;
pub mod errors; pub mod errors;

View File

@ -1,15 +1,12 @@
use { use std::task::{Context, Poll};
actix_service::{Service, Transform},
actix_web::{ use actix_service::{Service, Transform};
dev::{ServiceRequest, ServiceResponse}, use actix_web::dev::{ServiceRequest, ServiceResponse};
http::header::{self}, use actix_web::http::header::{self};
http::HeaderMap, use actix_web::http::HeaderMap;
Error, use actix_web::Error;
}, use futures::future::{ok, FutureExt, LocalBoxFuture, Ready};
futures::future::{ok, FutureExt, LocalBoxFuture, Ready}, use jirs_data::User;
jirs_data::User,
std::task::{Context, Poll},
};
type Db = actix_web::web::Data<database_actor::DbPool>; type Db = actix_web::web::Data<database_actor::DbPool>;

View File

@ -1,16 +1,13 @@
use { use actix::AsyncContext;
crate::{ use database_actor::authorize_user::AuthorizeUser;
use database_actor::tokens::{CreateBindToken, FindBindToken};
use database_actor::users::LookupUser;
use futures::executor::block_on;
use jirs_data::{Token, WsMsg};
use mail_actor::welcome::Welcome;
use crate::{
db_or_debug_and_return, mail_or_debug_and_return, WebSocketActor, WsHandler, WsResult, db_or_debug_and_return, mail_or_debug_and_return, WebSocketActor, WsHandler, WsResult,
},
actix::AsyncContext,
database_actor::{
authorize_user::AuthorizeUser,
tokens::{CreateBindToken, FindBindToken},
users::LookupUser,
},
futures::executor::block_on,
jirs_data::{Token, WsMsg},
mail_actor::welcome::Welcome,
}; };
pub struct Authenticate { pub struct Authenticate {

View File

@ -1,8 +1,7 @@
use { use futures::executor::block_on;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use jirs_data::{CommentId, CreateCommentPayload, IssueId, UpdateCommentPayload, WsMsg};
futures::executor::block_on,
jirs_data::{CommentId, CreateCommentPayload, IssueId, UpdateCommentPayload, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct LoadIssueComments { pub struct LoadIssueComments {
pub issue_id: IssueId, pub issue_id: IssueId,

View File

@ -1,9 +1,7 @@
use jirs_data::IssueType; use futures::executor::block_on;
use { use jirs_data::{DescriptionString, EpicId, IssueType, NameString, UserProject, WsMsg};
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult},
futures::executor::block_on, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
jirs_data::{DescriptionString, EpicId, NameString, UserProject, WsMsg},
};
pub struct LoadEpics; pub struct LoadEpics;
@ -60,7 +58,7 @@ impl WsHandler<UpdateEpic> for WebSocketActor {
self, self,
database_actor::epics::UpdateEpic { database_actor::epics::UpdateEpic {
project_id: *project_id, project_id: *project_id,
epic_id: epic_id, epic_id,
name: name.clone(), name: name.clone(),
} }
); );
@ -80,7 +78,7 @@ impl WsHandler<DeleteEpic> for WebSocketActor {
self, self,
database_actor::epics::DeleteEpic { database_actor::epics::DeleteEpic {
user_id: *user_id, user_id: *user_id,
epic_id: epic_id, epic_id,
} }
); );
Ok(Some(WsMsg::EpicDeleted(epic_id, n))) Ok(Some(WsMsg::EpicDeleted(epic_id, n)))

View File

@ -1,8 +1,7 @@
use { use futures::executor::block_on;
crate::{actor_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use jirs_data::{Code, Lang, WsMsg};
futures::executor::block_on,
jirs_data::{Code, Lang, WsMsg}, use crate::{actor_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct HighlightCode(pub Lang, pub Code); pub struct HighlightCode(pub Lang, pub Code);

View File

@ -1,13 +1,14 @@
use { use database_actor::invitations;
crate::{ use database_actor::messages::CreateMessageReceiver;
db_or_debug_and_return, mail_or_debug_and_return, server::InnerMsg, WebSocketActor, use futures::executor::block_on;
WsHandler, WsMessageSender, WsResult, use jirs_data::{
},
database_actor::{invitations, messages::CreateMessageReceiver},
futures::executor::block_on,
jirs_data::{
EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg, EmailString, InvitationId, InvitationToken, MessageType, UserRole, UsernameString, WsMsg,
}, };
use crate::server::InnerMsg;
use crate::{
db_or_debug_and_return, mail_or_debug_and_return, WebSocketActor, WsHandler, WsMessageSender,
WsResult,
}; };
pub struct ListInvitation; pub struct ListInvitation;

View File

@ -1,9 +1,8 @@
use { use database_actor::issue_statuses;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use futures::executor::block_on;
database_actor::issue_statuses, use jirs_data::{IssueStatusId, Position, TitleString, WsMsg};
futures::executor::block_on,
jirs_data::{IssueStatusId, Position, TitleString, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct LoadIssueStatuses; pub struct LoadIssueStatuses;

View File

@ -1,17 +1,15 @@
use { use std::collections::HashMap;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult},
database_actor::{ use database_actor::issue_assignees::LoadAssignees;
issue_assignees::LoadAssignees, use database_actor::issues::{LoadProjectIssues, UpdateIssue};
issues::{LoadProjectIssues, UpdateIssue}, use futures::executor::block_on;
}, use jirs_data::{
futures::executor::block_on,
jirs_data::{
CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, IssueStatusId, ListPosition, CreateIssuePayload, IssueAssignee, IssueFieldId, IssueId, IssueStatusId, ListPosition,
PayloadVariant, WsMsg, PayloadVariant, WsMsg,
},
std::collections::HashMap,
}; };
use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
pub struct UpdateIssueHandler { pub struct UpdateIssueHandler {
pub id: i32, pub id: i32,
pub field_id: IssueFieldId, pub field_id: IssueFieldId,

View File

@ -1,9 +1,8 @@
use { use database_actor::messages;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use futures::executor::block_on;
database_actor::messages, use jirs_data::{MessageId, WsMsg};
futures::executor::block_on,
jirs_data::{MessageId, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct LoadMessages; pub struct LoadMessages;

View File

@ -1,7 +1,14 @@
pub use { pub use auth::*;
auth::*, comments::*, epics::*, hi::*, invitations::*, issue_statuses::*, issues::*, pub use comments::*;
messages::*, projects::*, user_projects::*, users::*, pub use epics::*;
}; pub use hi::*;
pub use invitations::*;
pub use issue_statuses::*;
pub use issues::*;
pub use messages::*;
pub use projects::*;
pub use user_projects::*;
pub use users::*;
pub mod auth; pub mod auth;
pub mod comments; pub mod comments;

View File

@ -1,9 +1,8 @@
use { use database_actor as db;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use futures::executor::block_on;
database_actor as db, use jirs_data::{UpdateProjectPayload, UserProject, WsMsg};
futures::executor::block_on,
jirs_data::{UpdateProjectPayload, UserProject, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
impl WsHandler<UpdateProjectPayload> for WebSocketActor { impl WsHandler<UpdateProjectPayload> for WebSocketActor {
fn handle_msg(&mut self, msg: UpdateProjectPayload, _ctx: &mut Self::Context) -> WsResult { fn handle_msg(&mut self, msg: UpdateProjectPayload, _ctx: &mut Self::Context) -> WsResult {

View File

@ -1,9 +1,8 @@
use { use database_actor as db;
crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult}, use futures::executor::block_on;
database_actor as db, use jirs_data::{UserProjectId, WsMsg};
futures::executor::block_on,
jirs_data::{UserProjectId, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct LoadUserProjects; pub struct LoadUserProjects;

View File

@ -1,11 +1,10 @@
use { use database_actor::users::Register as DbRegister;
crate::{ use database_actor::{self};
db_or_debug_and_return, handlers::auth::Authenticate, WebSocketActor, WsHandler, WsResult, use futures::executor::block_on;
}, use jirs_data::{UserId, UserProject, UserRole, WsMsg};
database_actor::{self, users::Register as DbRegister},
futures::executor::block_on, use crate::handlers::auth::Authenticate;
jirs_data::{UserId, UserProject, UserRole, WsMsg}, use crate::{db_or_debug_and_return, WebSocketActor, WsHandler, WsResult};
};
pub struct LoadProjectUsers; pub struct LoadProjectUsers;

View File

@ -1,24 +1,20 @@
#[macro_use] #[macro_use]
extern crate log; extern crate log;
use { use actix::{Actor, ActorContext, Addr, AsyncContext, Handler, Recipient, StreamHandler};
crate::{ use actix_web::web::{self, Data};
handlers::*, use actix_web::{get, Error, HttpRequest, HttpResponse};
server::{InnerMsg, WsServer}, use actix_web_actors::ws;
}, use database_actor::projects::LoadCurrentProject;
actix::{Actor, ActorContext, Addr, AsyncContext, Handler, Recipient, StreamHandler}, use database_actor::user_projects::CurrentUserProject;
actix_web::{ use database_actor::DbExecutor;
get, use futures::executor::block_on;
web::{self, Data}, use jirs_data::{Project, User, UserProject, WsMsg};
Error, HttpRequest, HttpResponse, use log::*;
}, use mail_actor::MailExecutor;
actix_web_actors::ws,
database_actor::{projects::LoadCurrentProject, user_projects::CurrentUserProject, DbExecutor}, use crate::handlers::*;
futures::executor::block_on, use crate::server::{InnerMsg, WsServer};
jirs_data::{Project, User, UserProject, WsMsg},
log::*,
mail_actor::MailExecutor,
};
pub mod handlers; pub mod handlers;
pub mod prelude; pub mod prelude;

View File

@ -1,8 +1,7 @@
use { use std::collections::HashMap;
actix::{Actor, Context, Recipient},
jirs_data::{ProjectId, UserId, WsMsg}, use actix::{Actor, Context, Recipient};
std::collections::HashMap, use jirs_data::{ProjectId, UserId, WsMsg};
};
#[derive(actix::Message, Debug)] #[derive(actix::Message, Debug)]
#[rtype(result = "()")] #[rtype(result = "()")]

View File

@ -3,11 +3,12 @@ mod utils;
extern crate proc_macro; extern crate proc_macro;
use { use std::iter::Peekable;
crate::parse_attr::Attributes,
proc_macro::{token_stream::IntoIter, TokenStream, TokenTree}, use proc_macro::token_stream::IntoIter;
std::iter::Peekable, use proc_macro::{TokenStream, TokenTree};
};
use crate::parse_attr::Attributes;
fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attributes>) { fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attributes>) {
let mut attrs: Option<Attributes> = None; let mut attrs: Option<Attributes> = None;
@ -70,7 +71,6 @@ fn parse_meta(mut it: Peekable<IntoIter>) -> (Peekable<IntoIter>, Option<Attribu
/// pub name: String /// pub name: String
/// } /// }
/// ``` /// ```
///
#[proc_macro_derive(Execute, attributes(db_exec))] #[proc_macro_derive(Execute, attributes(db_exec))]
pub fn derive_enum_iter(item: TokenStream) -> TokenStream { pub fn derive_enum_iter(item: TokenStream) -> TokenStream {
let mut it = item.into_iter().peekable(); let mut it = item.into_iter().peekable();

View File

@ -1,6 +1,8 @@
use proc_macro::{token_stream::IntoIter, TokenTree};
use std::iter::Peekable; use std::iter::Peekable;
use proc_macro::token_stream::IntoIter;
use proc_macro::TokenTree;
#[derive(Default, Debug)] #[derive(Default, Debug)]
pub struct Attributes { pub struct Attributes {
pub result: Option<String>, pub result: Option<String>,

View File

@ -1,6 +1,8 @@
use proc_macro::{token_stream::IntoIter, TokenTree};
use std::iter::Peekable; use std::iter::Peekable;
use proc_macro::token_stream::IntoIter;
use proc_macro::TokenTree;
pub fn skip_pub(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> { pub fn skip_pub(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
if let Some(TokenTree::Ident(ident)) = it.next() { if let Some(TokenTree::Ident(ident)) = it.next() {
if ident.to_string().as_str() != "pub" { if ident.to_string().as_str() != "pub" {

View File

@ -1,9 +1,9 @@
extern crate proc_macro; extern crate proc_macro;
use { use std::iter::Peekable;
proc_macro::{token_stream::IntoIter, TokenStream, TokenTree},
std::iter::Peekable, use proc_macro::token_stream::IntoIter;
}; use proc_macro::{TokenStream, TokenTree};
fn skip_meta(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> { fn skip_meta(mut it: Peekable<IntoIter>) -> Peekable<IntoIter> {
while let Some(token) = it.peek() { while let Some(token) = it.peek() {

View File

@ -1,22 +1,18 @@
use { use std::error::Error;
std::{ use std::io;
error::Error, use std::sync::atomic::{AtomicBool, Ordering};
io, use std::sync::{mpsc, Arc};
sync::{ use std::time::Duration;
atomic::{AtomicBool, Ordering},
mpsc, Arc, use termion::event::Key;
}, use termion::input::MouseTerminal;
time::Duration, use termion::raw::IntoRawMode;
}, use termion::screen::AlternateScreen;
termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::AlternateScreen}, use tui::backend::TermionBackend;
tui::{ use tui::layout::{Constraint, Direction, Layout};
backend::TermionBackend, use tui::style::{Color, Style};
layout::{Constraint, Direction, Layout}, use tui::widgets::{Block, Borders, Tabs};
style::{Color, Style}, use tui::Terminal;
widgets::{Block, Borders, Tabs},
Terminal,
},
};
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub struct Config { pub struct Config {
@ -68,8 +64,8 @@ impl Events {
// eprintln!("{}", err); // eprintln!("{}", err);
// return; // return;
// } // }
// if !ignore_exit_key.load(Ordering::Relaxed) && key == config.exit_key { // if !ignore_exit_key.load(Ordering::Relaxed) && key ==
// return; // config.exit_key { return;
// } // }
// } // }
// } // }
@ -84,8 +80,8 @@ impl Events {
Events { Events {
rx, rx,
ignore_exit_key, ignore_exit_key,
// input_handle, /* input_handle,
// tick_handle, * tick_handle, */
} }
} }

View File

@ -1,8 +1,8 @@
use { use jirs_data::{EpicId, IssueStatusId, WsMsg};
crate::{components::styled_editor::Mode as TabMode, FieldId}, use seed::prelude::WebSocketMessage;
jirs_data::{EpicId, IssueStatusId, WsMsg},
seed::prelude::WebSocketMessage, use crate::components::styled_editor::Mode as TabMode;
}; use crate::FieldId;
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum FieldChange { pub enum FieldChange {

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::Msg;
#[derive(Debug)] #[derive(Debug)]
pub struct StyledAvatar<'l> { pub struct StyledAvatar<'l> {

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, ButtonId, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::{ButtonId, Msg};
#[allow(dead_code)] #[allow(dead_code)]
pub enum ButtonVariant { pub enum ButtonVariant {

View File

@ -1,11 +1,8 @@
use { use seed::prelude::*;
crate::{ use seed::*;
shared::{IntoChild, ToNode},
FieldId, Msg, use crate::shared::ToNode;
}, use crate::{FieldId, Msg};
jirs_data::TimeTracking,
seed::{prelude::*, *},
};
#[derive(Debug)] #[derive(Debug)]
pub struct StyledCheckboxState { pub struct StyledCheckboxState {
@ -30,12 +27,12 @@ impl StyledCheckboxState {
#[derive(Debug)] #[derive(Debug)]
pub struct ChildBuilder<'l> { pub struct ChildBuilder<'l> {
field_id: Option<FieldId>, pub field_id: Option<FieldId>,
name: &'l str, pub name: &'l str,
label: &'l str, pub label: &'l str,
value: u32, pub value: u32,
selected: bool, pub selected: bool,
class_list: Vec<String>, pub class_list: &'l str,
} }
impl<'l> Default for ChildBuilder<'l> { impl<'l> Default for ChildBuilder<'l> {
@ -46,7 +43,7 @@ impl<'l> Default for ChildBuilder<'l> {
label: "", label: "",
value: 0, value: 0,
selected: false, selected: false,
class_list: vec![], class_list: "",
} }
} }
} }
@ -77,11 +74,8 @@ impl<'l> ChildBuilder<'l> {
self self
} }
pub fn add_class<S>(mut self, name: S) -> Self pub fn class_list(mut self, name: &'l str) -> Self {
where self.class_list = name;
S: Into<String>,
{
self.class_list.push(name.into());
self self
} }
} }
@ -94,7 +88,7 @@ impl<'l> ToNode for ChildBuilder<'l> {
label, label,
value, value,
selected, selected,
mut class_list, class_list,
} = self; } = self;
let id = field_id.as_ref().map(|f| f.to_string()).unwrap_or_default(); let id = field_id.as_ref().map(|f| f.to_string()).unwrap_or_default();
@ -103,9 +97,6 @@ impl<'l> ToNode for ChildBuilder<'l> {
field_id_clone.map(|field_id| Msg::U32InputChanged(field_id, value)) field_id_clone.map(|field_id| Msg::U32InputChanged(field_id, value))
}); });
class_list.push("styledCheckboxChild".to_string());
class_list.push(if selected { "selected" } else { "" }.to_string());
let input_attrs = if selected { let input_attrs = if selected {
attrs![At::Type => "radio", At::Name => name, At::Checked => selected, At::Id => format!("{}-{}", id, name)] attrs![At::Type => "radio", At::Name => name, At::Checked => selected, At::Id => format!("{}-{}", id, name)]
} else { } else {
@ -113,7 +104,11 @@ impl<'l> ToNode for ChildBuilder<'l> {
}; };
div![ div![
attrs![At::Class => class_list.join(" ")], C![
"styledCheckboxChild",
class_list,
IF![selected => "selected"]
],
handler, handler,
label![attrs![At::For => format!("{}-{}", id, name)], label], label![attrs![At::For => format!("{}-{}", id, name)], label],
input![input_attrs], input![input_attrs],
@ -216,27 +211,3 @@ where
opt, opt,
] ]
} }
impl<'l> IntoChild<'l> for TimeTracking {
type Builder = ChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
Self::Builder::default()
.label(match self {
TimeTracking::Untracked => "No tracking",
TimeTracking::Fibonacci => "Fibonacci (Bad mode)",
TimeTracking::Hourly => "Evil Mode (Hourly)",
})
.name(match self {
TimeTracking::Untracked => "untracked",
TimeTracking::Fibonacci => "fibonacci",
TimeTracking::Hourly => "hourly",
})
.add_class(match self {
TimeTracking::Untracked => "untracked",
TimeTracking::Fibonacci => "fibonacci",
TimeTracking::Hourly => "hourly",
})
.value((self).into())
}
}

View File

@ -1,13 +1,10 @@
use { use seed::prelude::*;
crate::{ use seed::{EventHandler, *};
components::{styled_button::StyledButton, styled_modal::StyledModal},
shared::ToNode,
Msg,
},
seed::{prelude::*, EventHandler, *},
};
use crate::components::styled_button::ButtonVariant; use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_modal::StyledModal;
use crate::shared::ToNode;
use crate::Msg;
const TITLE: &str = "Warning"; const TITLE: &str = "Warning";
const MESSAGE: &str = "Are you sure you want to continue with this action?"; const MESSAGE: &str = "Are you sure you want to continue with this action?";

View File

@ -1,19 +1,15 @@
use { use std::ops::RangeInclusive;
crate::{
components::{
styled_button::StyledButton, styled_icon::Icon, styled_tooltip::StyledTooltip,
},
shared::ToNode,
FieldId, Msg,
},
chrono::prelude::*,
chrono::Duration,
seed::{prelude::*, *},
std::ops::RangeInclusive,
};
use crate::components::styled_button::ButtonVariant; use chrono::prelude::*;
use crate::components::styled_tooltip::TooltipVariant; use chrono::Duration;
use seed::prelude::*;
use seed::*;
use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_icon::Icon;
use crate::components::styled_tooltip::{StyledTooltip, TooltipVariant};
use crate::shared::ToNode;
use crate::{FieldId, Msg};
#[derive(Debug)] #[derive(Debug)]
pub enum StyledDateTimeChanged { pub enum StyledDateTimeChanged {

View File

@ -1,9 +1,9 @@
use { use seed::prelude::*;
crate::{ use seed::*;
components::styled_textarea::StyledTextarea, shared::ToNode, FieldChange, FieldId, Msg,
}, use crate::components::styled_textarea::StyledTextarea;
seed::{prelude::*, *}, use crate::shared::ToNode;
}; use crate::{FieldChange, FieldId, Msg};
#[derive(Debug, Clone, PartialOrd, PartialEq, Hash)] #[derive(Debug, Clone, PartialOrd, PartialEq, Hash)]
pub enum Mode { pub enum Mode {

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::Msg;
#[derive(Debug)] #[derive(Debug)]
pub struct StyledField<'l> { pub struct StyledField<'l> {
@ -22,57 +23,12 @@ impl<'l> Default for StyledField<'l> {
} }
} }
impl<'l> StyledField<'l> {
pub fn build() -> StyledFieldBuilder<'l> {
StyledFieldBuilder::default()
}
}
impl<'l> ToNode for StyledField<'l> { impl<'l> ToNode for StyledField<'l> {
fn into_node(self) -> Node<Msg> { fn into_node(self) -> Node<Msg> {
render(self) render(self)
} }
} }
#[derive(Default, Debug)]
pub struct StyledFieldBuilder<'l> {
label: Option<&'l str>,
tip: Option<&'l str>,
input: Option<Node<Msg>>,
class_list: &'l str,
}
impl<'l> StyledFieldBuilder<'l> {
pub fn label(mut self, label: &'l str) -> Self {
self.label = Some(label);
self
}
pub fn tip(mut self, tip: &'l str) -> Self {
self.tip = Some(tip);
self
}
pub fn input(mut self, input: Node<Msg>) -> Self {
self.input = Some(input);
self
}
pub fn class_list(mut self, name: &'l str) -> Self {
self.class_list = name;
self
}
pub fn build(self) -> StyledField<'l> {
StyledField {
label: self.label.unwrap_or_default(),
tip: self.tip,
input: self.input.unwrap_or(empty![]),
class_list: self.class_list,
}
}
}
pub fn render(values: StyledField) -> Node<Msg> { pub fn render(values: StyledField) -> Node<Msg> {
let StyledField { let StyledField {
label, label,

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::Msg;
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StyledForm<'l> { pub struct StyledForm<'l> {

View File

@ -1,9 +1,11 @@
use { use std::borrow::Cow;
crate::{shared::ToNode, Msg},
jirs_data::{IssuePriority, IssueType}, use jirs_data::{IssuePriority, IssueType};
seed::{prelude::*, *}, use seed::prelude::*;
std::borrow::Cow, use seed::*;
};
use crate::shared::ToNode;
use crate::Msg;
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
@ -245,37 +247,6 @@ impl ToNode for Icon {
} }
} }
pub struct StyledIconBuilder<'l> {
pub icon: Icon,
pub size: Option<i32>,
pub class_list: &'l str,
pub style_list: Vec<Cow<'l, str>>,
pub color: Option<Cow<'l, str>>,
pub on_click: Option<EventHandler<Msg>>,
}
impl<'l> StyledIconBuilder<'l> {
pub fn size(mut self, size: i32) -> Self {
self.size = Some(size);
self
}
pub fn class_list(mut self, name: &'l str) -> Self {
self.class_list = name;
self
}
pub fn with_color(mut self, color: &'l str) -> Self {
self.color = Some(Cow::Borrowed(color));
self
}
pub fn on_click(mut self, on_click: EventHandler<Msg>) -> Self {
self.on_click = Some(on_click);
self
}
}
pub struct StyledIcon<'l> { pub struct StyledIcon<'l> {
pub icon: Icon, pub icon: Icon,
pub size: Option<i32>, pub size: Option<i32>,

View File

@ -1,8 +1,9 @@
use { use seed::prelude::*;
crate::{shared::ToNode, FieldId, Msg}, use seed::*;
seed::{prelude::*, *}, use web_sys::File;
web_sys::File,
}; use crate::shared::ToNode;
use crate::{FieldId, Msg};
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct StyledImageInputState { pub struct StyledImageInputState {

View File

@ -1,11 +1,9 @@
use { use seed::prelude::*;
crate::{ use seed::*;
components::styled_icon::{Icon, StyledIcon},
shared::ToNode, use crate::components::styled_icon::{Icon, StyledIcon};
FieldId, Msg, use crate::shared::ToNode;
}, use crate::{FieldId, Msg};
seed::{prelude::*, *},
};
#[derive(Clone, Debug, PartialOrd, PartialEq)] #[derive(Clone, Debug, PartialOrd, PartialEq)]
pub enum InputVariant { pub enum InputVariant {

View File

@ -1,8 +1,10 @@
use { use std::str::FromStr;
crate::{shared::ToNode, Msg},
seed::{prelude::*, *}, use seed::prelude::*;
std::str::FromStr, use seed::*;
};
use crate::shared::ToNode;
use crate::Msg;
pub struct StyledLink<'l> { pub struct StyledLink<'l> {
pub children: Vec<Node<Msg>>, pub children: Vec<Node<Msg>>,
@ -10,48 +12,6 @@ pub struct StyledLink<'l> {
pub href: &'l str, pub href: &'l str,
} }
impl<'l> StyledLink<'l> {
// pub fn build() -> StyledLinkBuilder<'l> {
// StyledLinkBuilder::default()
// }
}
#[derive(Default)]
pub struct StyledLinkBuilder<'l> {
children: Vec<Node<Msg>>,
class_list: &'l str,
href: &'l str,
}
impl<'l> StyledLinkBuilder<'l> {
pub fn add_child(mut self, child: Node<Msg>) -> Self {
self.children.push(child);
self
}
pub fn class_list(mut self, name: &'l str) -> Self {
self.class_list = name;
self
}
pub fn href(mut self, href: &'l str) -> Self {
self.href = href;
self
}
pub fn text(self, s: &'l str) -> Self {
self.add_child(span![s])
}
pub fn build(self) -> StyledLink<'l> {
StyledLink {
children: self.children,
class_list: self.class_list,
href: self.href,
}
}
}
impl<'l> ToNode for StyledLink<'l> { impl<'l> ToNode for StyledLink<'l> {
fn into_node(self) -> Node<Msg> { fn into_node(self) -> Node<Msg> {
render(self) render(self)

View File

@ -1,11 +1,9 @@
use { use seed::prelude::*;
crate::{ use seed::*;
components::styled_icon::{Icon, StyledIcon},
shared::ToNode, use crate::components::styled_icon::{Icon, StyledIcon};
Msg, use crate::shared::ToNode;
}, use crate::Msg;
seed::{prelude::*, *},
};
#[allow(dead_code)] #[allow(dead_code)]
#[derive(Debug, Copy, Clone, PartialOrd, PartialEq)] #[derive(Debug, Copy, Clone, PartialOrd, PartialEq)]

View File

@ -1,14 +1,12 @@
use { use std::collections::HashMap;
crate::{
components::{ use seed::prelude::*;
styled_icon::{Icon, StyledIcon}, use seed::*;
styled_select_child::*,
}, use crate::components::styled_icon::{Icon, StyledIcon};
shared::ToNode, use crate::components::styled_select_child::*;
FieldId, Msg, use crate::shared::ToNode;
}, use crate::{FieldId, Msg};
seed::{prelude::*, *},
};
#[derive(Clone, Debug, PartialEq)] #[derive(Clone, Debug, PartialEq)]
pub enum StyledSelectChanged { pub enum StyledSelectChanged {
@ -71,7 +69,7 @@ impl StyledSelectState {
} }
} }
pub fn update(&mut self, msg: &Msg, _orders: &mut impl Orders<Msg>) { pub fn update(&mut self, msg: &Msg, orders: &mut impl Orders<Msg>) {
let field_id = match msg { let field_id = match msg {
Msg::StyledSelectChanged(field_id, ..) => field_id, Msg::StyledSelectChanged(field_id, ..) => field_id,
_ => return, _ => return,
@ -87,6 +85,7 @@ impl StyledSelectState {
} }
} }
Msg::StyledSelectChanged(_, StyledSelectChanged::Text(text)) => { Msg::StyledSelectChanged(_, StyledSelectChanged::Text(text)) => {
orders.skip();
self.text_filter = text.clone(); self.text_filter = text.clone();
} }
Msg::StyledSelectChanged(_, StyledSelectChanged::Changed(Some(v))) => { Msg::StyledSelectChanged(_, StyledSelectChanged::Changed(Some(v))) => {
@ -112,7 +111,7 @@ impl StyledSelectState {
pub struct StyledSelect<'l, Options> pub struct StyledSelect<'l, Options>
where where
Options: Iterator<Item = StyledSelectChildBuilder<'l>>, Options: Iterator<Item = StyledSelectChild<'l>>,
{ {
pub id: FieldId, pub id: FieldId,
pub variant: SelectVariant, pub variant: SelectVariant,
@ -121,7 +120,7 @@ where
pub valid: bool, pub valid: bool,
pub is_multi: bool, pub is_multi: bool,
pub options: Option<Options>, pub options: Option<Options>,
pub selected: Vec<StyledSelectChildBuilder<'l>>, pub selected: Vec<StyledSelectChild<'l>>,
pub text_filter: &'l str, pub text_filter: &'l str,
pub opened: bool, pub opened: bool,
pub clearable: bool, pub clearable: bool,
@ -129,7 +128,7 @@ where
impl<'l, Options> Default for StyledSelect<'l, Options> impl<'l, Options> Default for StyledSelect<'l, Options>
where where
Options: Iterator<Item = StyledSelectChildBuilder<'l>>, Options: Iterator<Item = StyledSelectChild<'l>>,
{ {
fn default() -> Self { fn default() -> Self {
Self { Self {
@ -150,7 +149,7 @@ where
impl<'l, Options> ToNode for StyledSelect<'l, Options> impl<'l, Options> ToNode for StyledSelect<'l, Options>
where where
Options: Iterator<Item = StyledSelectChildBuilder<'l>>, Options: Iterator<Item = StyledSelectChild<'l>>,
{ {
fn into_node(self) -> Node<Msg> { fn into_node(self) -> Node<Msg> {
render(self) render(self)
@ -159,7 +158,7 @@ where
pub fn render<'l, Options>(values: StyledSelect<'l, Options>) -> Node<Msg> pub fn render<'l, Options>(values: StyledSelect<'l, Options>) -> Node<Msg>
where where
Options: Iterator<Item = StyledSelectChildBuilder<'l>>, Options: Iterator<Item = StyledSelectChild<'l>>,
{ {
let StyledSelect { let StyledSelect {
id, id,
@ -221,13 +220,16 @@ where
empty![] empty![]
}; };
let skip = selected.iter().fold(HashMap::new(), |mut h, o| {
h.insert(o.value, true);
h
});
let children: Vec<Node<Msg>> = if let Some(options) = options { let children: Vec<Node<Msg>> = if let Some(options) = options {
options options
.filter(|o| !selected.contains(&o) && o.match_text(text_filter)) .filter(|o| !skip.contains_key(&o.value) && o.match_text(text_filter))
.map(|child| { .map(|child| {
let child = child.build(DisplayType::SelectOption);
let value = child.value(); let value = child.value();
let node = child.into_node(); let node = child.render_option();
let on_change = { let on_change = {
let field_id = id.clone(); let field_id = id.clone();
@ -245,21 +247,6 @@ where
vec![] vec![]
}; };
let text_input = if opened {
seed::input![
C!["dropDownInput"],
attrs![
At::Name => name,
At::Type => "text"
At::Placeholder => "Search"
At::AutoFocus => "true",
],
on_text,
]
} else {
empty![]
};
let option_list = match (opened, children.is_empty()) { let option_list = match (opened, children.is_empty()) {
(false, _) => empty![], (false, _) => empty![],
(_, true) => seed::div![C!["noOptions"], "No results"], (_, true) => seed::div![C!["noOptions"], "No results"],
@ -281,10 +268,7 @@ where
vec![div![C!["valueMulti"], children]] vec![div![C!["valueMulti"], children]]
} else { } else {
selected selected.into_iter().map(|m| m.render_value()).collect()
.into_iter()
.map(|m| render_value(m.build(DisplayType::SelectValue).into_node()))
.collect()
}; };
seed::div![ seed::div![
@ -303,29 +287,25 @@ where
div![ div![
C!["dropDown"], C!["dropDown"],
attrs![At::Style => dropdown_style.as_str()], attrs![At::Style => dropdown_style.as_str()],
text_input, IF![opened => seed::input![
C!["dropDownInput"],
attrs![
At::Name => name,
At::Type => "text"
At::Placeholder => "Search"
At::AutoFocus => "true",
],
on_text,
]],
option_list option_list
] ]
] ]
} }
fn render_value(mut content: Node<Msg>) -> Node<Msg> { fn into_multi_value(child: StyledSelectChild, id: FieldId) -> Node<Msg> {
content.add_class("value");
content
}
fn into_multi_value(opt: StyledSelectChildBuilder, id: FieldId) -> Node<Msg> {
let close_icon = StyledIcon {
icon: Icon::Close,
size: Some(14),
..Default::default()
}
.into_node();
let child = opt.build(DisplayType::SelectValue);
let value = child.value(); let value = child.value();
let mut opt = child.into_node(); let opt = child.render_multi_value();
opt.add_class("value").add_child(close_icon);
let handler = { let handler = {
let field_id = id; let field_id = id;

View File

@ -1,25 +1,23 @@
use { use seed::prelude::*;
crate::{ use seed::*;
components::styled_select::SelectVariant,
shared::{IntoChild, ToChild, ToNode},
Msg,
},
seed::{prelude::*, *},
};
use crate::components::styled_avatar::StyledAvatar; use crate::components::styled_icon::{Icon, StyledIcon};
use crate::components::styled_icon::StyledIcon; use crate::components::styled_select::SelectVariant;
use crate::shared::ToNode;
use crate::Msg;
#[derive(Copy, Clone, PartialEq)]
#[repr(u8)]
pub enum DisplayType { pub enum DisplayType {
SelectOption, SelectOption,
SelectValue, SelectValue,
SelectMultiValue,
} }
pub struct StyledSelectChild<'l> { pub struct StyledSelectChild<'l> {
pub name: Option<&'l str>, pub name: Option<&'l str>,
pub icon: Option<Node<Msg>>, pub icon: Option<Node<Msg>>,
pub text: Option<&'l str>, pub text: Option<&'l str>,
pub display_type: DisplayType,
pub value: u32, pub value: u32,
pub class_list: &'l str, pub class_list: &'l str,
pub variant: SelectVariant, pub variant: SelectVariant,
@ -31,7 +29,6 @@ impl<'l> Default for StyledSelectChild<'l> {
name: None, name: None,
icon: None, icon: None,
text: None, text: None,
display_type: DisplayType::SelectOption,
value: 0, value: 0,
class_list: "", class_list: "",
variant: Default::default(), variant: Default::default(),
@ -44,95 +41,37 @@ impl<'l> StyledSelectChild<'l> {
pub fn value(&self) -> u32 { pub fn value(&self) -> u32 {
self.value self.value
} }
}
impl<'l> ToNode for StyledSelectChild<'l> { #[inline(always)]
fn into_node(self) -> Node<Msg> { pub fn render_value(self) -> Node<Msg> {
render(self) render(DisplayType::SelectValue, self)
}
}
#[derive(Debug)]
pub struct StyledSelectChildBuilder<'l> {
pub icon: Option<Node<Msg>>,
pub text: Option<&'l str>,
pub name: Option<&'l str>,
pub value: u32,
pub class_list: &'l str,
pub variant: SelectVariant,
}
impl<'l> Default for StyledSelectChildBuilder<'l> {
fn default() -> Self {
Self {
icon: None,
text: None,
name: None,
value: 0,
class_list: "",
variant: Default::default(),
}
}
}
impl<'l> PartialEq for StyledSelectChildBuilder<'l> {
fn eq(&self, other: &Self) -> bool {
self.value == other.value
}
}
impl<'l> StyledSelectChildBuilder<'l> {
pub fn icon(mut self, icon: Node<Msg>) -> Self {
self.icon = Some(icon);
self
} }
pub fn text<'m: 'l>(mut self, text: &'m str) -> Self { #[inline(always)]
self.text = Some(text); pub fn render_multi_value(self) -> Node<Msg> {
self render(DisplayType::SelectMultiValue, self)
} }
pub fn name(mut self, name: &'l str) -> Self { #[inline(always)]
self.name = Some(name); pub fn render_option(self) -> Node<Msg> {
self render(DisplayType::SelectOption, self)
}
pub fn value(mut self, value: u32) -> Self {
self.value = value;
self
} }
#[inline(always)]
pub fn match_text(&self, text: &str) -> bool { pub fn match_text(&self, text: &str) -> bool {
self.text self.text
.as_ref() .as_ref()
.map(|t| t.to_lowercase().contains(text.to_lowercase().as_str())) .map(|t| t.to_lowercase().contains(text.to_lowercase().as_str()))
.unwrap_or(true) .unwrap_or(true)
} }
pub fn class_list<'m: 'l>(mut self, name: &'m str) -> Self {
self.class_list = name;
self
}
pub fn build(self, display_type: DisplayType) -> StyledSelectChild<'l> {
StyledSelectChild {
name: self.name,
icon: self.icon,
text: self.text,
display_type,
value: self.value,
class_list: self.class_list,
variant: self.variant,
}
}
} }
pub fn render(values: StyledSelectChild) -> Node<Msg> { #[inline(always)]
pub fn render(display_type: DisplayType, values: StyledSelectChild) -> Node<Msg> {
let StyledSelectChild { let StyledSelectChild {
name, name,
icon, icon,
text, text,
display_type,
value: _, value: _,
class_list, class_list,
variant, variant,
@ -152,7 +91,7 @@ pub fn render(values: StyledSelectChild) -> Node<Msg> {
.unwrap_or_default(), .unwrap_or_default(),
match display_type { match display_type {
DisplayType::SelectOption => "optionLabel", DisplayType::SelectOption => "optionLabel",
DisplayType::SelectValue => "selectItemLabel", DisplayType::SelectValue | DisplayType::SelectMultiValue => "selectItemLabel",
}, },
class_list class_list
], ],
@ -167,168 +106,22 @@ pub fn render(values: StyledSelectChild) -> Node<Msg> {
name.as_deref().unwrap_or_default(), name.as_deref().unwrap_or_default(),
match display_type { match display_type {
DisplayType::SelectOption => "optionItem", DisplayType::SelectOption => "optionItem",
DisplayType::SelectValue => "selectItem", DisplayType::SelectValue | DisplayType::SelectMultiValue => "selectItem value",
}, },
class_list class_list
], ],
icon_node, icon_node,
label_node label_node,
IF![display_type == DisplayType::SelectMultiValue => close_icon()]
] ]
} }
impl<'l> ToChild<'l> for jirs_data::User { #[inline(always)]
type Builder = StyledSelectChildBuilder<'l>; fn close_icon() -> Node<Msg> {
StyledIcon {
fn to_child<'m: 'l>(&'m self) -> Self::Builder { icon: Icon::Close,
let avatar = StyledAvatar { size: Some(14),
size: 20,
name: &self.name,
avatar_url: self.avatar_url.as_deref(),
..StyledAvatar::default()
}
.into_node();
StyledSelectChildBuilder {
value: self.id as u32,
icon: Some(avatar),
text: Some(self.name.as_str()),
..Default::default() ..Default::default()
} }
} .into_node()
}
impl<'l> IntoChild<'l> for jirs_data::IssuePriority {
type Builder = StyledSelectChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
let icon = StyledIcon {
icon: self.clone().into(),
class_list: self.to_str(),
..Default::default()
}
.into_node();
StyledSelectChildBuilder {
icon: Some(icon),
text: Some(self.to_str()),
class_list: self.to_str(),
value: self.into(),
..Default::default()
}
}
}
impl<'l> ToChild<'l> for jirs_data::IssueStatus {
type Builder = StyledSelectChildBuilder<'l>;
fn to_child<'m: 'l>(&'m self) -> Self::Builder {
StyledSelectChildBuilder {
value: self.id as u32,
class_list: self.name.as_str(),
text: Some(self.name.as_str()),
..Default::default()
}
}
}
impl<'l> IntoChild<'l> for jirs_data::IssueType {
type Builder = StyledSelectChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
let name = self.to_label();
let type_icon = StyledIcon {
icon: self.clone().into(),
class_list: name,
..Default::default()
}
.into_node();
StyledSelectChildBuilder {
class_list: name,
text: Some(name),
icon: Some(type_icon),
value: self.into(),
..Default::default()
}
}
}
impl<'l> IntoChild<'l> for jirs_data::ProjectCategory {
type Builder = StyledSelectChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
StyledSelectChildBuilder {
class_list: self.to_str(),
text: Some(self.to_str()),
value: self.into(),
..Default::default()
}
}
}
impl<'l> IntoChild<'l> for jirs_data::UserRole {
type Builder = StyledSelectChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
let name = self.to_str();
StyledSelectChildBuilder {
text: Some(name),
value: self.into(),
class_list: name,
..Default::default()
}
}
}
macro_rules! id_name_builder {
() => {
fn to_child<'m: 'l>(&'m self) -> Self::Builder {
StyledSelectChildBuilder {
text: Some(self.name.as_str()),
value: self.id as u32,
..Default::default()
}
}
};
}
impl<'l> ToChild<'l> for jirs_data::Project {
type Builder = StyledSelectChildBuilder<'l>;
id_name_builder!();
}
impl<'l> ToChild<'l> for jirs_data::Epic {
type Builder = StyledSelectChildBuilder<'l>;
id_name_builder!();
}
impl<'l> ToChild<'l> for u32 {
type Builder = StyledSelectChildBuilder<'l>;
fn to_child<'m: 'l>(&'m self) -> Self::Builder {
let name = stringify!(self);
StyledSelectChildBuilder {
class_list: name,
text: Some(name),
value: *self,
..Default::default()
}
}
}
pub type Label = String;
pub type Value = u32;
impl<'l> ToChild<'l> for (Label, Value) {
type Builder = StyledSelectChildBuilder<'l>;
fn to_child<'m: 'l>(&'m self) -> Self::Builder {
StyledSelectChildBuilder {
text: Some(self.0.as_str()),
value: self.1,
..Default::default()
}
}
} }

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, FieldId, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::{FieldId, Msg};
#[derive(Debug)] #[derive(Debug)]
pub struct StyledTextarea<'l> { pub struct StyledTextarea<'l> {
@ -43,8 +44,8 @@ const PADDING_TOP_BOTTOM: f64 = 17f64;
const BORDER_TOP_BOTTOM: f64 = 2f64; const BORDER_TOP_BOTTOM: f64 = 2f64;
const ADDITIONAL_HEIGHT: f64 = PADDING_TOP_BOTTOM + BORDER_TOP_BOTTOM; const ADDITIONAL_HEIGHT: f64 = PADDING_TOP_BOTTOM + BORDER_TOP_BOTTOM;
// height = `calc( (${$0.value.split("\n").length}px * ( 15 * 1.4285 )) + 17px + 2px)` // height = `calc( (${$0.value.split("\n").length}px * ( 15 * 1.4285 )) + 17px +
// where: // 2px)` where:
// * 15 is font-size // * 15 is font-size
// * 1.4285 is line-height // * 1.4285 is line-height
// * 17 is padding top + bottom // * 17 is padding top + bottom

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{shared::ToNode, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::shared::ToNode;
use crate::Msg;
#[derive(Debug, Copy, Clone)] #[derive(Debug, Copy, Clone)]
pub enum TooltipVariant { pub enum TooltipVariant {

View File

@ -1,7 +1,7 @@
use { use seed::prelude::*;
crate::Msg, use seed::*;
seed::{prelude::*, *},
}; use crate::Msg;
#[inline(always)] #[inline(always)]
pub fn render() -> Node<Msg> { pub fn render() -> Node<Msg> {

View File

@ -1,22 +1,21 @@
#![feature(type_ascription, trait_alias, drain_filter)] #![feature(type_ascription, trait_alias, drain_filter)]
use { pub use changes::*;
crate::{ pub use components::*;
components::{ pub use fields::*;
styled_date_time_input::StyledDateTimeChanged, pub use images::*;
styled_select::StyledSelectChanged, use jirs_data::*;
styled_tooltip, use seed::prelude::*;
styled_tooltip::{TooltipVariant as StyledTooltip, TooltipVariant}, use seed::*;
}, use web_sys::File;
model::{ModalType, Model, Page},
shared::{go_to_board, go_to_login}, use crate::components::styled_date_time_input::StyledDateTimeChanged;
ws::{flush_queue, open_socket, read_incoming, send_ws_msg}, use crate::components::styled_select::StyledSelectChanged;
}, use crate::components::styled_tooltip;
jirs_data::*, use crate::components::styled_tooltip::{TooltipVariant as StyledTooltip, TooltipVariant};
seed::{prelude::*, *}, use crate::model::{ModalType, Model, Page};
web_sys::File, use crate::shared::{go_to_board, go_to_login};
}; use crate::ws::{flush_queue, open_socket, read_incoming, send_ws_msg};
pub use {changes::*, components::*, fields::*, images::*};
// use crate::shared::styled_rte::RteMsg; // use crate::shared::styled_rte::RteMsg;

View File

@ -1,4 +1,5 @@
pub use {model::*, view::*}; pub use model::*;
pub use view::*;
mod model; mod model;
mod view; mod view;

View File

@ -1,8 +1,9 @@
use { use jirs_data::CommentId;
crate::{model, shared::ToNode, styled_confirm_modal::StyledConfirmModal, Msg}, use seed::prelude::*;
jirs_data::CommentId,
seed::prelude::*, use crate::shared::ToNode;
}; use crate::styled_confirm_modal::StyledConfirmModal;
use crate::{model, Msg};
pub fn view(_model: &model::Model, modal: &super::Model) -> Node<Msg> { pub fn view(_model: &model::Model, modal: &super::Model) -> Node<Msg> {
let comment_id: CommentId = modal.comment_id; let comment_id: CommentId = modal.comment_id;

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,7 +1,10 @@
use { use seed::prelude::*;
crate::{components::styled_modal::StyledModal, model::Model, shared::ToNode, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::components::styled_modal::StyledModal;
use crate::model::Model;
use crate::shared::ToNode;
use crate::Msg;
pub fn view(model: &Model) -> Node<Msg> { pub fn view(model: &Model) -> Node<Msg> {
let text = format!("{:#?}", model); let text = format!("{:#?}", model);

View File

@ -1,15 +1,12 @@
use { use jirs_data::{Epic, EpicId};
crate::{ use seed::prelude::Node;
components::{styled_field::StyledField, styled_select::StyledSelect},
model::{IssueModal, Model},
shared::{ToChild, ToNode},
FieldId, Msg,
},
jirs_data::EpicId,
seed::prelude::Node,
};
use crate::components::styled_select::SelectVariant; use crate::components::styled_field::StyledField;
use crate::components::styled_select::{SelectVariant, StyledSelect};
use crate::components::styled_select_child::StyledSelectChild;
use crate::model::{IssueModal, Model};
use crate::shared::ToNode;
use crate::{FieldId, Msg};
pub fn epic_field<Modal>(model: &Model, modal: &Modal, field_id: FieldId) -> Option<Node<Msg>> pub fn epic_field<Modal>(model: &Model, modal: &Modal, field_id: FieldId) -> Option<Node<Msg>>
where where
@ -18,16 +15,15 @@ where
if model.epics.is_empty() { if model.epics.is_empty() {
return None; return None;
} }
let selected = modal
.epic_id_value()
.and_then(|id| model.epics.iter().find(|epic| epic.id == id as EpicId))
.map(|epic| vec![epic.to_child()])
.unwrap_or_default();
let input = StyledSelect { let input = StyledSelect {
id: field_id, id: field_id,
name: "epic", name: "epic",
selected, selected: vec![modal
options: Some(model.epics.iter().map(|epic| epic.to_child())), .epic_id_value()
.and_then(|id| model.epics.iter().find(|epic| epic.id == id as EpicId))
.map(epic_select_option)
.unwrap_or_default()],
options: Some(model.epics.iter().map(epic_select_option)),
variant: SelectVariant::Normal, variant: SelectVariant::Normal,
clearable: true, clearable: true,
text_filter: modal.epic_state().text_filter.as_str(), text_filter: modal.epic_state().text_filter.as_str(),
@ -46,3 +42,11 @@ where
.into_node(), .into_node(),
) )
} }
fn epic_select_option<'l>(epic: &'l Epic) -> StyledSelectChild<'l> {
StyledSelectChild {
value: epic.id as u32,
text: Some(epic.name.as_str()),
..Default::default()
}
}

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,7 +1,6 @@
use { use jirs_data::{EpicId, IssueId};
crate::model,
jirs_data::{EpicId, IssueId}, use crate::model;
};
#[derive(Clone, Debug, PartialOrd, PartialEq)] #[derive(Clone, Debug, PartialOrd, PartialEq)]
pub struct Model { pub struct Model {

View File

@ -1,8 +1,8 @@
use { use jirs_data::WsMsg;
crate::{ws::send_ws_msg, Msg, OperationKind, ResourceKind}, use seed::prelude::*;
jirs_data::WsMsg,
seed::prelude::*, use crate::ws::send_ws_msg;
}; use crate::{Msg, OperationKind, ResourceKind};
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 modal = match &mut model.modals_mut().delete_epic { let modal = match &mut model.modals_mut().delete_epic {

View File

@ -1,13 +1,13 @@
use { use seed::prelude::*;
crate::{ use seed::*;
components::{styled_button::*, styled_confirm_modal::*, styled_icon::*, styled_modal::*},
modals::epics_delete::Model, use crate::components::styled_button::*;
model, use crate::components::styled_confirm_modal::*;
shared::ToNode, use crate::components::styled_icon::*;
Msg, use crate::components::styled_modal::*;
}, use crate::modals::epics_delete::Model;
seed::{prelude::*, *}, use crate::shared::ToNode;
}; use crate::{model, Msg};
pub fn view(model: &model::Model, modal: &Model) -> Node<Msg> { pub fn view(model: &model::Model, modal: &Model) -> Node<Msg> {
if modal.related_issues.is_empty() { if modal.related_issues.is_empty() {

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,11 +1,9 @@
use { use jirs_data::*;
crate::{ use seed::prelude::Orders;
components::{styled_checkbox::StyledCheckboxState, styled_input::*},
model, FieldId, Msg, use crate::components::styled_checkbox::StyledCheckboxState;
}, use crate::components::styled_input::*;
jirs_data::*, use crate::{model, FieldId, Msg};
seed::prelude::Orders,
};
#[derive(Debug)] #[derive(Debug)]
pub struct Model { pub struct Model {

View File

@ -1,8 +1,7 @@
use { use jirs_data::{EpicFieldId, IssueType, WsMsg};
crate::{send_ws_msg, FieldId, Msg, OperationKind, ResourceKind}, use seed::prelude::*;
jirs_data::{EpicFieldId, IssueType, WsMsg},
seed::prelude::*, use crate::{send_ws_msg, FieldId, Msg, OperationKind, ResourceKind};
};
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 modal = match &mut model.modals.edit_epic { let modal = match &mut model.modals.edit_epic {

View File

@ -1,17 +1,15 @@
use { use jirs_data::{EpicFieldId, IssueType};
crate::{ use seed::prelude::*;
components::{ use seed::*;
styled_button::*, styled_checkbox::*, styled_icon::Icon, styled_input::*,
styled_modal::*, use crate::components::styled_button::*;
}, use crate::components::styled_checkbox::*;
modals::epics_edit::Model, use crate::components::styled_icon::Icon;
model, use crate::components::styled_input::*;
shared::{IntoChild, ToNode}, use crate::components::styled_modal::*;
FieldId, Msg, use crate::modals::epics_edit::Model;
}, use crate::shared::{IntoChild, ToNode};
jirs_data::{EpicFieldId, IssueType}, use crate::{model, FieldId, Msg};
seed::{prelude::*, *},
};
pub struct IssueTypeWrapper(IssueType); pub struct IssueTypeWrapper(IssueType);
@ -23,7 +21,7 @@ impl<'l> IntoChild<'l> for IssueTypeWrapper {
.label(self.0.to_label()) .label(self.0.to_label())
.name(self.0.to_str()) .name(self.0.to_str())
.value(self.0.into()) .value(self.0.into())
.add_class(self.0.to_str()) .class_list(self.0.to_str())
} }
} }
@ -68,7 +66,7 @@ fn transform_into_available(modal: &super::Model) -> Node<Msg> {
.options( .options(
IssueType::default() IssueType::default()
.into_iter() .into_iter()
.map(|ty| IssueTypeWrapper(ty).into_child()), .map(issue_type_select_option),
) )
.state(&modal.transform_into) .state(&modal.transform_into)
.build(FieldId::EditEpic(EpicFieldId::TransformInto)) .build(FieldId::EditEpic(EpicFieldId::TransformInto))
@ -86,6 +84,17 @@ fn transform_into_available(modal: &super::Model) -> Node<Msg> {
div![C!["transform available"], div![types], div![execute]] div![C!["transform available"], div![types], div![execute]]
} }
#[inline(always)]
fn issue_type_select_option<'l>(ty: IssueType) -> ChildBuilder<'l> {
ChildBuilder {
name: ty.to_str(),
label: ty.to_label(),
value: ty.into(),
class_list: ty.to_str(),
..Default::default()
}
}
fn transform_into_unavailable(modal: &super::Model) -> Node<Msg> { fn transform_into_unavailable(modal: &super::Model) -> Node<Msg> {
let (n, s) = match modal.related_issues.len() { let (n, s) = match modal.related_issues.len() {
1 => (1.to_string(), "issue"), 1 => (1.to_string(), "issue"),

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,8 +1,8 @@
use { use jirs_data::WsMsg;
crate::{model::Model, Msg, OperationKind, ResourceKind}, use seed::prelude::*;
jirs_data::WsMsg,
seed::prelude::*, use crate::model::Model;
}; use crate::{Msg, OperationKind, ResourceKind};
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
let _modal = match &mut model.modals_mut().delete_issue_status_modal { let _modal = match &mut model.modals_mut().delete_issue_status_modal {

View File

@ -1,8 +1,9 @@
use { use jirs_data::IssueStatusId;
crate::{components::styled_confirm_modal::StyledConfirmModal, model, shared::ToNode, Msg}, use seed::prelude::*;
jirs_data::IssueStatusId,
seed::prelude::*, use crate::components::styled_confirm_modal::StyledConfirmModal;
}; use crate::shared::ToNode;
use crate::{model, Msg};
pub fn view(_model: &model::Model, issue_status_id: IssueStatusId) -> Node<Msg> { pub fn view(_model: &model::Model, issue_status_id: IssueStatusId) -> Node<Msg> {
StyledConfirmModal { StyledConfirmModal {

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,17 +1,13 @@
use { use derive_enum_iter::EnumIter;
crate::{ use derive_enum_primitive::EnumPrimitive;
components::{ use jirs_data::{IssueFieldId, IssuePriority};
styled_date_time_input::*, styled_input::*, styled_select::*, styled_select_child::*, use seed::prelude::*;
},
model::IssueModal, use crate::components::styled_date_time_input::*;
shared::{IntoChild, ToNode}, use crate::components::styled_input::*;
FieldId, Msg, use crate::components::styled_select::*;
}, use crate::model::IssueModal;
derive_enum_iter::EnumIter, use crate::{FieldId, Msg};
derive_enum_primitive::EnumPrimitive,
jirs_data::{IssueFieldId, IssuePriority},
seed::prelude::*,
};
#[derive(Copy, Clone, EnumPrimitive, EnumIter)] #[derive(Copy, Clone, EnumPrimitive, EnumIter)]
pub enum Type { pub enum Type {
@ -53,43 +49,6 @@ impl Type {
} }
} }
impl<'l> IntoChild<'l> for Type {
type Builder = StyledSelectChildBuilder<'l>;
fn into_child(self) -> Self::Builder {
let name = match self {
Type::Task => "Task",
Type::Bug => "Bug",
Type::Story => "Story",
Type::Epic => "Epic",
};
let value: u32 = self.into();
let type_icon = {
use crate::components::styled_icon::*;
StyledIcon {
icon: match self {
Type::Task => Icon::Task,
Type::Bug => Icon::Bug,
Type::Story => Icon::Story,
Type::Epic => Icon::Epic,
},
class_list: name,
..Default::default()
}
.into_node()
};
StyledSelectChildBuilder {
class_list: name,
text: Some(name),
icon: Some(type_icon),
value,
..Default::default()
}
}
}
#[derive(Clone, Debug, PartialOrd, PartialEq)] #[derive(Clone, Debug, PartialOrd, PartialEq)]
pub struct Model { pub struct Model {
pub priority: IssuePriority, pub priority: IssuePriority,

View File

@ -1,11 +1,10 @@
use { use jirs_data::{IssueFieldId, UserId, WsMsg};
crate::{ use seed::prelude::*;
components::styled_select::StyledSelectChanged, model::IssueModal, ws::send_ws_msg,
FieldId, Msg, OperationKind, ResourceKind, use crate::components::styled_select::StyledSelectChanged;
}, use crate::model::IssueModal;
jirs_data::{IssueFieldId, UserId, WsMsg}, use crate::ws::send_ws_msg;
seed::prelude::*, use crate::{FieldId, Msg, OperationKind, ResourceKind};
};
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 user_id = model.user_id().unwrap_or_default(); let user_id = model.user_id().unwrap_or_default();

View File

@ -1,25 +1,23 @@
use { use jirs_data::{IssueFieldId, IssuePriority, User};
crate::{ use seed::prelude::*;
components::{ use seed::*;
styled_button::StyledButton, styled_date_time_input::StyledDateTimeInput,
styled_field::StyledField, styled_form::StyledForm, styled_input::StyledInput,
styled_modal::StyledModal, styled_select::StyledSelect,
styled_textarea::StyledTextarea,
},
modals::{
epic_field,
issues_create::{Model as AddIssueModal, Type},
},
model::Model,
shared::{IntoChild, ToChild, ToNode},
FieldId, Msg,
},
jirs_data::{IssueFieldId, IssuePriority},
seed::{prelude::*, *},
};
use crate::components::styled_button::ButtonVariant; use crate::components::styled_avatar::StyledAvatar;
use crate::components::styled_select::SelectVariant; use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_date_time_input::StyledDateTimeInput;
use crate::components::styled_field::StyledField;
use crate::components::styled_form::StyledForm;
use crate::components::styled_icon::{Icon, StyledIcon};
use crate::components::styled_input::StyledInput;
use crate::components::styled_modal::StyledModal;
use crate::components::styled_select::{SelectVariant, StyledSelect};
use crate::components::styled_select_child::StyledSelectChild;
use crate::components::styled_textarea::StyledTextarea;
use crate::modals::epic_field;
use crate::modals::issues_create::{Model as AddIssueModal, Type};
use crate::model::Model;
use crate::shared::ToNode;
use crate::{FieldId, Msg};
pub fn view(model: &Model, modal: &AddIssueModal) -> Node<Msg> { pub fn view(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
let issue_type = modal let issue_type = modal
@ -40,26 +38,24 @@ pub fn view(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
Type::Epic => { Type::Epic => {
let name_field = name_field(modal); let name_field = name_field(modal);
let starts = StyledField::build() let starts = StyledField {
.input( input: StyledDateTimeInput::build()
StyledDateTimeInput::build()
.state(&modal.epic_starts_at_state) .state(&modal.epic_starts_at_state)
.build(FieldId::AddIssueModal(IssueFieldId::EpicStartsAt)) .build(FieldId::AddIssueModal(IssueFieldId::EpicStartsAt))
.into_node(), .into_node(),
) label: "Starts at",
.label("Starts at") ..Default::default()
.build() }
.into_node(); .into_node();
let end = StyledField::build() let end = StyledField {
.input( input: StyledDateTimeInput::build()
StyledDateTimeInput::build()
.state(&modal.epic_ends_at_state) .state(&modal.epic_ends_at_state)
.build(FieldId::AddIssueModal(IssueFieldId::EpicEndsAt)) .build(FieldId::AddIssueModal(IssueFieldId::EpicEndsAt))
.into_node(), .into_node(),
) label: "Ends at",
.label("Ends at") ..Default::default()
.build() }
.into_node(); .into_node();
form.add_field(name_field).add_field(starts).add_field(end) form.add_field(name_field).add_field(starts).add_field(end)
@ -129,19 +125,16 @@ fn issue_type_field(modal: &AddIssueModal) -> Node<Msg> {
text_filter: modal.type_state.text_filter.as_str(), text_filter: modal.type_state.text_filter.as_str(),
opened: modal.type_state.opened, opened: modal.type_state.opened,
valid: true, valid: true,
options: Some(Type::Task.into_iter().map(|t| t.into_child().name("type"))), options: Some(Type::Task.into_iter().map(type_select_option)),
selected: vec![{ selected: vec![type_select_option(
let v: Type = modal modal
.type_state .type_state
.values .values
.get(0) .get(0)
.cloned() .cloned()
.unwrap_or_default() .unwrap_or_default()
.into(); .into(),
v )],
}
.into_child()
.name("type")],
..Default::default() ..Default::default()
} }
.into_node(); .into_node();
@ -154,6 +147,37 @@ fn issue_type_field(modal: &AddIssueModal) -> Node<Msg> {
.into_node() .into_node()
} }
#[inline(always)]
fn type_select_option<'l>(t: Type) -> StyledSelectChild<'l> {
let name = match t {
Type::Task => "Task",
Type::Bug => "Bug",
Type::Story => "Story",
Type::Epic => "Epic",
};
StyledSelectChild {
class_list: name,
text: Some(name),
icon: Some(
StyledIcon {
icon: match t {
Type::Task => Icon::Task,
Type::Bug => Icon::Bug,
Type::Story => Icon::Story,
Type::Epic => Icon::Epic,
},
class_list: name,
..Default::default()
}
.into_node(),
),
name: Some("type"),
value: t.into(),
..Default::default()
}
}
#[inline] #[inline]
fn short_summary_field(modal: &AddIssueModal) -> Node<Msg> { fn short_summary_field(modal: &AddIssueModal) -> Node<Msg> {
let short_summary = StyledInput { let short_summary = StyledInput {
@ -199,13 +223,13 @@ fn reporter_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
variant: SelectVariant::Normal, variant: SelectVariant::Normal,
text_filter: modal.reporter_state.text_filter.as_str(), text_filter: modal.reporter_state.text_filter.as_str(),
opened: modal.reporter_state.opened, opened: modal.reporter_state.opened,
options: Some(model.users.iter().map(|u| u.to_child().name("reporter"))), options: Some(model.users.iter().map(reporter_select_option)),
selected: model selected: model
.users .users
.iter() .iter()
.filter_map(|user| { .filter_map(|user| {
if user.id == reporter_id { if user.id == reporter_id {
Some(user.to_child().name("reporter")) Some(reporter_select_option(user))
} else { } else {
None None
} }
@ -224,6 +248,25 @@ fn reporter_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
.into_node() .into_node()
} }
#[inline(always)]
fn reporter_select_option(user: &User) -> StyledSelectChild {
StyledSelectChild {
value: user.id as u32,
icon: Some(
StyledAvatar {
size: 20,
name: &user.name,
avatar_url: user.avatar_url.as_deref(),
..StyledAvatar::default()
}
.into_node(),
),
text: Some(user.name.as_str()),
name: Some("reporter"),
..Default::default()
}
}
fn assignees_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> { fn assignees_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
let assignees = StyledSelect { let assignees = StyledSelect {
id: FieldId::AddIssueModal(IssueFieldId::Assignees), id: FieldId::AddIssueModal(IssueFieldId::Assignees),
@ -231,13 +274,13 @@ fn assignees_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
is_multi: true, is_multi: true,
text_filter: modal.assignees_state.text_filter.as_str(), text_filter: modal.assignees_state.text_filter.as_str(),
opened: modal.assignees_state.opened, opened: modal.assignees_state.opened,
options: Some(model.users.iter().map(|u| u.to_child().name("assignees"))), options: Some(model.users.iter().map(assignee_select_option)),
selected: model selected: model
.users .users
.iter() .iter()
.filter_map(|user| { .filter_map(|user| {
if modal.user_ids.contains(&user.id) { if modal.user_ids.contains(&user.id) {
Some(user.to_child().name("assignees")) Some(assignee_select_option(user))
} else { } else {
None None
} }
@ -248,14 +291,34 @@ fn assignees_field(model: &Model, modal: &AddIssueModal) -> Node<Msg> {
..Default::default() ..Default::default()
} }
.into_node(); .into_node();
StyledField::build() StyledField {
.input(assignees) input: assignees,
.label("Assignees") label: "Assignees",
.tip("") tip: Some(""),
.build() ..Default::default()
}
.into_node() .into_node()
} }
#[inline(always)]
fn assignee_select_option(user: &User) -> StyledSelectChild {
StyledSelectChild {
value: user.id as u32,
icon: Some(
StyledAvatar {
size: 20,
name: &user.name,
avatar_url: user.avatar_url.as_deref(),
..StyledAvatar::default()
}
.into_node(),
),
text: Some(user.name.as_str()),
name: Some("assignees"),
..Default::default()
}
}
fn issue_priority_field(modal: &AddIssueModal) -> Node<Msg> { fn issue_priority_field(modal: &AddIssueModal) -> Node<Msg> {
let priorities = IssuePriority::default().into_iter(); let priorities = IssuePriority::default().into_iter();
let select_priority = StyledSelect { let select_priority = StyledSelect {
@ -265,8 +328,8 @@ fn issue_priority_field(modal: &AddIssueModal) -> Node<Msg> {
text_filter: modal.priority_state.text_filter.as_str(), text_filter: modal.priority_state.text_filter.as_str(),
opened: modal.priority_state.opened, opened: modal.priority_state.opened,
valid: true, valid: true,
options: Some(priorities.map(|p| p.into_child().name("priority"))), options: Some(priorities.map(priority_select_option)),
selected: vec![modal.priority.into_child().name("priority")], selected: vec![priority_select_option(modal.priority)],
..Default::default() ..Default::default()
} }
.into_node(); .into_node();
@ -279,6 +342,24 @@ fn issue_priority_field(modal: &AddIssueModal) -> Node<Msg> {
.into_node() .into_node()
} }
fn priority_select_option<'l>(priority: IssuePriority) -> StyledSelectChild<'l> {
StyledSelectChild {
icon: Some(
StyledIcon {
icon: priority.clone().into(),
class_list: priority.to_str(),
..Default::default()
}
.into_node(),
),
text: Some(priority.to_str()),
class_list: priority.to_str(),
value: priority.into(),
name: Some("priority"),
..Default::default()
}
}
fn name_field(modal: &AddIssueModal) -> Node<Msg> { fn name_field(modal: &AddIssueModal) -> Node<Msg> {
let name = StyledInput { let name = StyledInput {
value: modal.title_state.value.as_str(), value: modal.title_state.value.as_str(),

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{components::styled_confirm_modal::StyledConfirmModal, model, shared::ToNode, Msg},
seed::prelude::*, use crate::components::styled_confirm_modal::StyledConfirmModal;
}; use crate::shared::ToNode;
use crate::{model, Msg};
pub fn view(model: &model::Model) -> Node<Msg> { pub fn view(model: &model::Model) -> Node<Msg> {
let issue_id = match &model.modals().delete_issue_confirm { let issue_id = match &model.modals().delete_issue_confirm {

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,17 +1,13 @@
use { use jirs_data::{Issue, IssueFieldId, IssueId, TimeTracking, UpdateIssuePayload};
crate::{ use seed::prelude::*;
components::{
styled_date_time_input::StyledDateTimeInputState, styled_editor::Mode, use crate::components::styled_date_time_input::StyledDateTimeInputState;
styled_editor::StyledEditorState, styled_input::StyledInputState, use crate::components::styled_editor::{Mode, StyledEditorState};
styled_select::StyledSelectState, use crate::components::styled_input::StyledInputState;
}, use crate::components::styled_select::StyledSelectState;
modals::time_tracking::value_for_time_tracking, use crate::modals::time_tracking::value_for_time_tracking;
model::{CommentForm, IssueModal}, use crate::model::{CommentForm, IssueModal};
EditIssueModalSection, FieldId, Msg, use crate::{EditIssueModalSection, FieldId, Msg};
},
jirs_data::{Issue, IssueFieldId, IssueId, TimeTracking, UpdateIssuePayload},
seed::prelude::*,
};
#[derive(Clone, Debug, PartialOrd, PartialEq)] #[derive(Clone, Debug, PartialOrd, PartialEq)]
pub struct Model { pub struct Model {

View File

@ -1,13 +1,10 @@
use { use jirs_data::*;
crate::{ use seed::prelude::*;
components::styled_select::StyledSelectChanged,
model::{IssueModal, Model}, use crate::components::styled_select::StyledSelectChanged;
ws::send_ws_msg, use crate::model::{IssueModal, Model};
EditIssueModalSection, FieldChange, FieldId, Msg, OperationKind, ResourceKind, use crate::ws::send_ws_msg;
}, use crate::{EditIssueModalSection, FieldChange, FieldId, Msg, OperationKind, ResourceKind};
jirs_data::*,
seed::prelude::*,
};
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
let modal = match &mut model.modals.edit_issue { let modal = match &mut model.modals.edit_issue {
@ -303,7 +300,6 @@ pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
} }
// //
// comments // comments
//
Msg::StrInputChanged( Msg::StrInputChanged(
FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)), FieldId::EditIssueModal(EditIssueModalSection::Comment(CommentFieldId::Body)),
text, text,

View File

@ -1,26 +1,27 @@
use { use comments::*;
crate::{ use jirs_data::{
components::{ CommentFieldId, IssueFieldId, IssuePriority, IssueStatus, IssueType, TimeTracking,
styled_avatar::StyledAvatar, styled_button::StyledButton, styled_editor::StyledEditor, UpdateIssuePayload, User,
styled_field::StyledField, styled_icon::Icon, styled_input::StyledInput,
styled_modal::*, styled_select::StyledSelect,
},
modals::{
epic_field, issues_edit::Model as EditIssueModal, time_tracking::time_tracking_field,
},
model::{ModalType, Model},
shared::{tracking_widget::tracking_link, IntoChild, ToChild, ToNode},
EditIssueModalSection, FieldChange, FieldId, Msg,
},
comments::*,
jirs_data::{CommentFieldId, IssueFieldId, IssuePriority, IssueType, TimeTracking},
seed::{prelude::*, *},
}; };
use seed::prelude::*;
use seed::*;
use crate::components::styled_button::ButtonVariant; use crate::components::styled_avatar::StyledAvatar;
use crate::components::styled_icon::StyledIcon; use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_select::SelectVariant; use crate::components::styled_editor::StyledEditor;
use crate::components::styled_select_child::StyledSelectChildBuilder; use crate::components::styled_field::StyledField;
use crate::components::styled_icon::{Icon, StyledIcon};
use crate::components::styled_input::StyledInput;
use crate::components::styled_modal::*;
use crate::components::styled_select::{SelectVariant, StyledSelect, StyledSelectState};
use crate::components::styled_select_child::StyledSelectChild;
use crate::modals::epic_field;
use crate::modals::issues_edit::Model as EditIssueModal;
use crate::modals::time_tracking::time_tracking_field;
use crate::model::{ModalType, Model};
use crate::shared::tracking_widget::tracking_link;
use crate::shared::ToNode;
use crate::{EditIssueModalSection, FieldChange, FieldId, Msg};
mod comments; mod comments;
@ -149,27 +150,9 @@ fn modal_header(_model: &Model, modal: &EditIssueModal) -> Node<Msg> {
options: Some( options: Some(
IssueType::default() IssueType::default()
.into_iter() .into_iter()
.map(|t| t.into_child().name("type")), .map(|t| type_select_option(t, &text)),
), ),
selected: vec![{ selected: vec![type_select_option(payload.issue_type, &text)],
let name = payload.issue_type.to_label();
let type_icon = StyledIcon {
icon: payload.issue_type.clone().into(),
class_list: name,
..Default::default()
}
.into_node();
StyledSelectChildBuilder {
class_list: name,
text: Some(&text),
icon: Some(type_icon),
value: payload.issue_type.into(),
name: Some("type"),
..Default::default()
}
}],
..Default::default() ..Default::default()
} }
.into_node() .into_node()
@ -187,6 +170,26 @@ fn modal_header(_model: &Model, modal: &EditIssueModal) -> Node<Msg> {
] ]
} }
#[inline(always)]
fn type_select_option<'l>(t: IssueType, text: &'l str) -> StyledSelectChild<'l> {
let name = t.to_label();
StyledSelectChild {
class_list: name,
text: Some(text),
icon: Some(
StyledIcon {
icon: t.clone().into(),
class_list: name,
..Default::default()
}
.into_node(),
),
value: t.into(),
name: Some("type"),
..Default::default()
}
}
fn left_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> { fn left_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
let EditIssueModal { let EditIssueModal {
payload, payload,
@ -220,7 +223,11 @@ fn left_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
} }
.into_node() .into_node()
}; };
let description_field = StyledField::build().input(description).build().into_node(); let description_field = StyledField {
input: description,
..Default::default()
}
.into_node();
let user_avatar = StyledAvatar { let user_avatar = StyledAvatar {
avatar_url: model.user.as_ref().and_then(|u| u.avatar_url.as_deref()), avatar_url: model.user.as_ref().and_then(|u| u.avatar_url.as_deref()),
@ -283,110 +290,13 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
.. ..
} = modal; } = modal;
let status = StyledSelect { let status_field = status_select(model, payload, status_state);
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::IssueStatusId)),
name: "status",
opened: status_state.opened,
variant: SelectVariant::Normal,
text_filter: status_state.text_filter.as_str(),
options: Some(
model
.issue_statuses
.iter()
.map(|opt| opt.to_child().name("status")),
),
selected: model
.issue_statuses
.iter()
.filter(|is| is.id == payload.issue_status_id)
.map(|is| is.to_child().name("status"))
.collect(),
valid: true, let assignees_field = assignees_select(model, payload, assignees_state);
..Default::default()
}
.into_node();
let status_field = StyledField::build()
.input(status)
.label("Status")
.build()
.into_node();
let assignees = StyledSelect { let reporter_field = reporters_select(model, payload, reporter_state);
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
name: "assignees",
variant: SelectVariant::Empty,
is_multi: true,
opened: assignees_state.opened,
text_filter: assignees_state.text_filter.as_str(),
options: Some(
model
.users
.iter()
.map(|user| user.to_child().name("assignees")),
),
selected: model
.users
.iter()
.filter(|user| payload.user_ids.contains(&user.id))
.map(|user| user.to_child().name("assignees"))
.collect(),
..Default::default()
}
.into_node();
let assignees_field = StyledField::build()
.input(assignees)
.label("Assignees")
.build()
.into_node();
let reporter = StyledSelect { let priority_field = priorities_select(payload, priority_state);
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Reporter)),
name: "reporter",
opened: reporter_state.opened,
variant: SelectVariant::Empty,
text_filter: reporter_state.text_filter.as_str(),
options: Some(
model
.users
.iter()
.map(|user| user.to_child().name("reporter")),
),
selected: model
.users
.iter()
.filter(|user| payload.reporter_id == user.id)
.map(|user| user.to_child().name("reporter"))
.collect(),
..Default::default()
}
.into_node();
let reporter_field = StyledField::build()
.input(reporter)
.label("Reporter")
.build()
.into_node();
let priority = StyledSelect {
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Priority)),
name: "priority",
variant: SelectVariant::Empty,
opened: priority_state.opened,
text_filter: priority_state.text_filter.as_str(),
options: Some(
IssuePriority::default()
.into_iter()
.map(|p| p.into_child().name("priority")),
),
selected: vec![payload.priority.into_child().name("priority")],
..Default::default()
}
.into_node();
let priority_field = StyledField::build()
.input(priority)
.label("Priority")
.build()
.into_node();
let time_tracking_type = model let time_tracking_type = model
.project .project
@ -404,11 +314,12 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
); );
let tracking = tracking_link(model, modal); let tracking = tracking_link(model, modal);
let tracking_field = StyledField::build() let tracking_field = StyledField {
.label("TIME TRACKING") label: "TIME TRACKING",
.tip("") tip: Some(""),
.input(tracking) input: tracking,
.build() ..Default::default()
}
.into_node(); .into_node();
(estimate_field, tracking_field) (estimate_field, tracking_field)
} else { } else {
@ -433,3 +344,192 @@ fn right_modal_column(model: &Model, modal: &EditIssueModal) -> Node<Msg> {
epic_field, epic_field,
] ]
} }
#[inline(always)]
fn priorities_select(
payload: &UpdateIssuePayload,
priority_state: &StyledSelectState,
) -> Node<Msg> {
let priority = StyledSelect {
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Priority)),
name: "priority",
variant: SelectVariant::Empty,
opened: priority_state.opened,
text_filter: priority_state.text_filter.as_str(),
options: Some(
IssuePriority::default()
.into_iter()
.map(priority_select_option),
),
selected: vec![priority_select_option(payload.priority)],
..Default::default()
}
.into_node();
StyledField {
label: "Priority",
input: priority,
..Default::default()
}
.into_node()
}
#[inline(always)]
fn priority_select_option<'l>(ip: IssuePriority) -> StyledSelectChild<'l> {
StyledSelectChild {
icon: Some(
StyledIcon {
icon: ip.clone().into(),
class_list: ip.to_str(),
..Default::default()
}
.into_node(),
),
text: Some(ip.to_str()),
class_list: ip.to_str(),
value: ip.into(),
name: Some("priority"),
..Default::default()
}
}
#[inline(always)]
fn status_select(
model: &Model,
payload: &UpdateIssuePayload,
status_state: &StyledSelectState,
) -> Node<Msg> {
let status = StyledSelect {
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::IssueStatusId)),
name: "status",
opened: status_state.opened,
variant: SelectVariant::Normal,
text_filter: status_state.text_filter.as_str(),
options: Some(model.issue_statuses.iter().map(issue_status_select_option)),
selected: model
.issue_statuses
.iter()
.filter(|is| is.id == payload.issue_status_id)
.map(issue_status_select_option)
.collect(),
valid: true,
..Default::default()
}
.into_node();
StyledField {
label: "Status",
input: status,
..Default::default()
}
.into_node()
}
#[inline(always)]
fn issue_status_select_option<'l>(is: &'l IssueStatus) -> StyledSelectChild<'l> {
StyledSelectChild {
value: is.id as u32,
class_list: is.name.as_str(),
text: Some(is.name.as_str()),
name: Some("status"),
..Default::default()
}
}
#[inline(always)]
fn reporters_select(
model: &Model,
payload: &UpdateIssuePayload,
reporter_state: &StyledSelectState,
) -> Node<Msg> {
let reporter = StyledSelect {
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Reporter)),
name: "reporter",
opened: reporter_state.opened,
variant: SelectVariant::Empty,
text_filter: reporter_state.text_filter.as_str(),
options: Some(model.users.iter().map(reporter_select_option)),
selected: model
.users
.iter()
.filter(|user| payload.reporter_id == user.id)
.map(reporter_select_option)
.collect(),
..Default::default()
}
.into_node();
StyledField {
label: "Reporter",
input: reporter,
..Default::default()
}
.into_node()
}
#[inline(always)]
fn reporter_select_option<'l>(user: &'l User) -> StyledSelectChild<'l> {
StyledSelectChild {
value: user.id as u32,
icon: Some(
StyledAvatar {
size: 20,
name: &user.name,
avatar_url: user.avatar_url.as_deref(),
..StyledAvatar::default()
}
.into_node(),
),
text: Some(user.name.as_str()),
name: Some("reporter"),
..Default::default()
}
}
#[inline(always)]
fn assignees_select(
model: &Model,
payload: &UpdateIssuePayload,
assignees_state: &StyledSelectState,
) -> Node<Msg> {
let assignees = StyledSelect {
id: FieldId::EditIssueModal(EditIssueModalSection::Issue(IssueFieldId::Assignees)),
name: "assignees",
variant: SelectVariant::Empty,
is_multi: true,
opened: assignees_state.opened,
text_filter: assignees_state.text_filter.as_str(),
options: Some(model.users.iter().map(assignee_select_option)),
selected: model
.users
.iter()
.filter(|user| payload.user_ids.contains(&user.id))
.map(assignee_select_option)
.collect(),
..Default::default()
}
.into_node();
StyledField {
input: assignees,
label: "Assignees",
..Default::default()
}
.into_node()
}
#[inline(always)]
fn assignee_select_option<'l>(user: &'l User) -> StyledSelectChild<'l> {
StyledSelectChild {
value: user.id as u32,
icon: Some(
StyledAvatar {
size: 20,
name: &user.name,
avatar_url: user.avatar_url.as_deref(),
..StyledAvatar::default()
}
.into_node(),
),
text: Some(user.name.as_str()),
name: Some("assignees"),
..Default::default()
}
}

View File

@ -1,19 +1,14 @@
use { use jirs_data::{Comment, CommentFieldId};
crate::{ use seed::prelude::*;
components::{ use seed::*;
styled_avatar::StyledAvatar, styled_button::StyledButton,
styled_textarea::StyledTextarea,
},
modals::issues_edit::Model as EditIssueModal,
model::{CommentForm, ModalType, Model},
shared::ToNode,
EditIssueModalSection, FieldChange, FieldId, Msg,
},
jirs_data::{Comment, CommentFieldId},
seed::{prelude::*, *},
};
use crate::components::styled_button::ButtonVariant; use crate::components::styled_avatar::StyledAvatar;
use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_textarea::StyledTextarea;
use crate::modals::issues_edit::Model as EditIssueModal;
use crate::model::{CommentForm, ModalType, Model};
use crate::shared::ToNode;
use crate::{EditIssueModalSection, FieldChange, FieldId, Msg};
pub fn build_comment_form(form: &CommentForm) -> Vec<Node<Msg>> { pub fn build_comment_form(form: &CommentForm) -> Vec<Node<Msg>> {
let submit_comment_form = mouse_ev(Ev::Click, move |ev| { let submit_comment_form = mouse_ev(Ev::Click, move |ev| {

View File

@ -1,4 +1,6 @@
pub use {epic_field::*, update::*, view::*}; pub use epic_field::*;
pub use update::*;
pub use view::*;
pub mod comments_delete; pub mod comments_delete;
#[cfg(debug_assertions)] #[cfg(debug_assertions)]

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,22 +1,17 @@
use { use jirs_data::{IssueFieldId, IssueId, TimeTracking};
crate::{ use seed::prelude::*;
components::{ use seed::*;
styled_button::StyledButton,
styled_field::StyledField, use crate::components::styled_button::StyledButton;
styled_input::{StyledInput, StyledInputState}, use crate::components::styled_field::StyledField;
styled_modal::StyledModal, use crate::components::styled_input::{StyledInput, StyledInputState};
styled_select::{StyledSelect, StyledSelectState}, use crate::components::styled_modal::StyledModal;
}, use crate::components::styled_select::{StyledSelect, StyledSelectState};
model::Model, use crate::components::styled_select_child::StyledSelectChild;
shared::{ use crate::model::Model;
tracking_widget::{fibonacci_values, tracking_widget}, use crate::shared::tracking_widget::{fibonacci_value_name, fibonacci_values, tracking_widget};
ToChild, ToNode, use crate::shared::ToNode;
}, use crate::{EditIssueModalSection, FieldId, Msg};
EditIssueModalSection, FieldId, Msg,
},
jirs_data::{IssueFieldId, IssueId, TimeTracking},
seed::{prelude::*, *},
};
pub fn value_for_time_tracking(v: &Option<i32>, time_tracking_type: &TimeTracking) -> String { pub fn value_for_time_tracking(v: &Option<i32>, time_tracking_type: &TimeTracking) -> String {
match (time_tracking_type, v.as_ref()) { match (time_tracking_type, v.as_ref()) {
@ -85,7 +80,7 @@ pub fn view(model: &Model, modal: &super::Model) -> Node<Msg> {
.into_node() .into_node()
} }
#[inline] #[inline(always)]
pub fn time_tracking_field( pub fn time_tracking_field(
time_tracking_type: TimeTracking, time_tracking_type: TimeTracking,
field_id: FieldId, field_id: FieldId,
@ -101,12 +96,18 @@ pub fn time_tracking_field(
selected: select_state selected: select_state
.values .values
.iter() .iter()
.map(|n| (*n).to_child()) .copied()
.map(fibonacci_value_select_option)
.collect(), .collect(),
text_filter: select_state.text_filter.as_str(), text_filter: select_state.text_filter.as_str(),
opened: select_state.opened, opened: select_state.opened,
options: Some(fibonacci_values.iter().map(|v| v.to_child())), options: Some(
fibonacci_values
.iter()
.copied()
.map(fibonacci_value_select_option),
),
..Default::default() ..Default::default()
} }
.into_node(), .into_node(),
@ -125,3 +126,14 @@ pub fn time_tracking_field(
} }
.into_node() .into_node()
} }
fn fibonacci_value_select_option<'l>(value: u32) -> StyledSelectChild<'l> {
let name = fibonacci_value_name(value);
StyledSelectChild {
class_list: name,
text: Some(name),
value,
..Default::default()
}
}

View File

@ -1,14 +1,11 @@
use jirs_data::{CommentId, IssueStatusId}; use jirs_data::{CommentId, EpicId, IssueId, IssueStatusId, TimeTracking, WsMsg};
use { use seed::prelude::*;
crate::{ use seed::*;
model::{ModalType, Model, Page},
shared::go_to_board, use crate::model::{ModalType, Model, Page};
ws::send_ws_msg, use crate::shared::go_to_board;
FieldChange, FieldId, Msg, OperationKind, ResourceKind, use crate::ws::send_ws_msg;
}, use crate::{FieldChange, FieldId, Msg, OperationKind, ResourceKind};
jirs_data::{EpicId, IssueId, TimeTracking, WsMsg},
seed::{prelude::*, *},
};
pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: &Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {
match msg { match msg {

View File

@ -1,7 +1,8 @@
use { use seed::prelude::*;
crate::{model::*, Msg}, use seed::*;
seed::{prelude::*, *},
}; use crate::model::*;
use crate::Msg;
pub fn view(model: &Model) -> Node<Msg> { pub fn view(model: &Model) -> Node<Msg> {
let nodes = model let nodes = model

View File

@ -1,20 +1,21 @@
use { use std::collections::hash_map::HashMap;
crate::{
components::styled_select::StyledSelectState, use jirs_data::*;
pages::{ use seed::app::Orders;
invite_page::InvitePage, profile_page::model::ProfilePage, use seed::browser::web_socket::WebSocket;
project_page::model::ProjectPage, project_settings_page::ProjectSettingsPage, use serde::{Deserialize, Serialize};
reports_page::model::ReportsPage, sign_in_page::model::SignInPage, use uuid::Uuid;
sign_up_page::model::SignUpPage, users_page::model::UsersPage,
}, use crate::components::styled_select::StyledSelectState;
Msg, use crate::pages::invite_page::InvitePage;
}, use crate::pages::profile_page::model::ProfilePage;
jirs_data::*, use crate::pages::project_page::model::ProjectPage;
seed::{app::Orders, browser::web_socket::WebSocket}, use crate::pages::project_settings_page::ProjectSettingsPage;
serde::{Deserialize, Serialize}, use crate::pages::reports_page::model::ReportsPage;
std::collections::hash_map::HashMap, use crate::pages::sign_in_page::model::SignInPage;
uuid::Uuid, use crate::pages::sign_up_page::model::SignUpPage;
}; use crate::pages::users_page::model::UsersPage;
use crate::Msg;
pub trait IssueModal { pub trait IssueModal {
fn epic_id_value(&self) -> Option<u32>; fn epic_id_value(&self) -> Option<u32>;

View File

@ -1,4 +1,6 @@
pub use {model::*, update::*, view::*}; pub use model::*;
pub use update::*;
pub use view::*;
mod model; mod model;
mod update; mod update;

View File

@ -1,15 +1,15 @@
use { use std::str::FromStr;
crate::{
authorize_or_redirect, use jirs_data::fields::*;
model::{Model, Page, PageContent}, use jirs_data::WsMsg;
pages::invite_page::InvitePage, use seed::prelude::*;
shared::write_auth_token,
ws::send_ws_msg, use crate::model::{Model, Page, PageContent};
FieldId, InvitationPageChange, Msg, PageChanged, WebSocketChanged, use crate::pages::invite_page::InvitePage;
}, use crate::shared::write_auth_token;
jirs_data::{fields::*, WsMsg}, use crate::ws::send_ws_msg;
seed::prelude::*, use crate::{
std::str::FromStr, authorize_or_redirect, FieldId, InvitationPageChange, Msg, PageChanged, WebSocketChanged,
}; };
pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) { pub fn update(msg: Msg, model: &mut Model, orders: &mut impl Orders<Msg>) {

View File

@ -1,21 +1,16 @@
use { use jirs_data::fields::*;
crate::{ use seed::prelude::*;
components::{ use seed::*;
styled_button::StyledButton, styled_field::StyledField, styled_form::StyledForm,
styled_input::StyledInput,
},
match_page,
model::{Model, PageContent},
pages::invite_page::InvitePage,
shared::{outer_layout, ToNode},
validations::is_token,
FieldId, InvitationPageChange, Msg, PageChanged,
},
jirs_data::fields::*,
seed::{prelude::*, *},
};
use crate::components::styled_button::ButtonVariant; use crate::components::styled_button::{ButtonVariant, StyledButton};
use crate::components::styled_field::StyledField;
use crate::components::styled_form::StyledForm;
use crate::components::styled_input::StyledInput;
use crate::model::{Model, PageContent};
use crate::pages::invite_page::InvitePage;
use crate::shared::{outer_layout, ToNode};
use crate::validations::is_token;
use crate::{match_page, FieldId, InvitationPageChange, Msg, PageChanged};
pub fn view(model: &Model) -> Node<Msg> { pub fn view(model: &Model) -> Node<Msg> {
let page = match_page!(model, Invite; Empty); let page = match_page!(model, Invite; Empty);

Some files were not shown because too many files have changed in this diff Show More