Change Epic to own type

This commit is contained in:
Adrian Woźniak 2020-08-10 22:34:19 +02:00
parent 940cdf8e31
commit 02a2ecdd01
14 changed files with 517 additions and 390 deletions

722
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -50,6 +50,7 @@ pub fn update(msg: &Msg, model: &mut crate::model::Model, orders: &mut impl Orde
project_id: modal.project_id.unwrap_or(project_id),
user_ids: modal.user_ids.clone(),
reporter_id: modal.reporter_id.unwrap_or_else(|| user_id),
epic_id: modal.epic_id,
};
send_ws_msg(
jirs_data::WsMsg::IssueCreateRequest(payload),

View File

@ -161,10 +161,11 @@ pub struct AddIssueModal {
pub estimate: Option<i32>,
pub time_spent: Option<i32>,
pub time_remaining: Option<i32>,
pub project_id: Option<i32>,
pub user_ids: Vec<i32>,
pub reporter_id: Option<i32>,
pub issue_status_id: i32,
pub project_id: Option<jirs_data::ProjectId>,
pub user_ids: Vec<jirs_data::UserId>,
pub reporter_id: Option<jirs_data::UserId>,
pub issue_status_id: jirs_data::IssueStatusId,
pub epic_id: Option<jirs_data::UserId>,
// modal fields
pub title_state: StyledInputState,
@ -188,6 +189,7 @@ impl Default for AddIssueModal {
user_ids: Default::default(),
reporter_id: Default::default(),
issue_status_id: Default::default(),
epic_id: Default::default(),
title_state: StyledInputState::new(FieldId::AddIssueModal(IssueFieldId::Title), ""),
type_state: StyledSelectState::new(FieldId::AddIssueModal(IssueFieldId::Type), vec![]),
reporter_state: StyledSelectState::new(

View File

@ -203,11 +203,11 @@ impl std::fmt::Display for Icon {
impl From<IssueType> for Icon {
fn from(t: IssueType) -> Self {
use IssueType::*;
match t {
IssueType::Task => Icon::Task,
IssueType::Bug => Icon::Bug,
IssueType::Story => Icon::Story,
IssueType::Epic => Icon::Epic,
Task => Icon::Task,
Bug => Icon::Bug,
Story => Icon::Story,
}
}
}

View File

@ -153,7 +153,9 @@ impl RteMsg {
let res = seed::document().query_selector(format!("#{}", identifier).as_str());
if let Ok(Some(el)) = res {
if let Ok(el) = el.dyn_into::<web_sys::HtmlElement>() {
el.focus().is_ok();
if let Err(e) = el.focus() {
log!(e)
}
}
}
None

View File

@ -28,6 +28,7 @@ pub type IssueStatusId = i32;
pub type InvitationId = i32;
pub type Position = i32;
pub type MessageId = i32;
pub type EpicId = i32;
pub type EmailString = String;
pub type UsernameString = String;
pub type TitleString = String;
@ -41,19 +42,14 @@ pub enum IssueType {
Task,
Bug,
Story,
Epic,
}
impl ToVec for IssueType {
type Item = IssueType;
fn ordered() -> Vec<Self> {
vec![
IssueType::Task,
IssueType::Bug,
IssueType::Story,
IssueType::Epic,
]
use IssueType::*;
vec![Task, Bug, Story]
}
}
@ -65,11 +61,11 @@ impl Default for IssueType {
impl IssueType {
pub fn to_label(&self) -> &str {
use IssueType::*;
match self {
IssueType::Task => "Task",
IssueType::Bug => "Bug",
IssueType::Story => "Story",
IssueType::Epic => "Epic",
Task => "Task",
Bug => "Bug",
Story => "Story",
}
}
}
@ -80,7 +76,6 @@ impl Into<u32> for IssueType {
IssueType::Task => 1,
IssueType::Bug => 2,
IssueType::Story => 3,
IssueType::Epic => 4,
}
}
}
@ -91,7 +86,6 @@ impl Into<IssueType> for u32 {
1 => IssueType::Task,
2 => IssueType::Bug,
3 => IssueType::Story,
4 => IssueType::Epic,
_ => IssueType::Task,
}
}
@ -103,7 +97,6 @@ impl std::fmt::Display for IssueType {
IssueType::Task => f.write_str("task"),
IssueType::Bug => f.write_str("bug"),
IssueType::Story => f.write_str("story"),
IssueType::Epic => f.write_str("epic"),
}
}
}
@ -434,6 +427,7 @@ pub struct Issue {
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub issue_status_id: IssueStatusId,
pub epic_id: Option<EpicId>,
pub user_ids: Vec<i32>,
}
@ -612,6 +606,17 @@ pub struct Message {
pub updated_at: NaiveDateTime,
}
#[cfg_attr(feature = "backend", derive(Queryable))]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct Epic {
pub id: EpicId,
pub name: String,
pub user_id: UserId,
pub project_id: ProjectId,
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
}
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
pub struct CreateCommentPayload {
pub user_id: Option<UserId>,
@ -639,6 +644,7 @@ pub struct CreateIssuePayload {
pub user_ids: Vec<UserId>,
pub reporter_id: UserId,
pub issue_status_id: IssueStatusId,
pub epic_id: Option<EpicId>,
}
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]

View File

@ -55,7 +55,6 @@ fn issue_type_from_sql(bytes: Option<&[u8]>) -> deserialize::Result<IssueType> {
b"task" => Ok(IssueType::Task),
b"bug" => Ok(IssueType::Bug),
b"story" => Ok(IssueType::Story),
b"epic" => Ok(IssueType::Epic),
_ => Ok(IssueType::Task),
}
}
@ -78,7 +77,6 @@ impl ToSql<IssueTypeType, Pg> for IssueType {
IssueType::Task => out.write_all(b"task")?,
IssueType::Story => out.write_all(b"story")?,
IssueType::Bug => out.write_all(b"bug")?,
IssueType::Epic => out.write_all(b"epic")?,
}
Ok(IsNull::No)
}

View File

@ -0,0 +1,21 @@
ALTER TABLE "issues"
ALTER COLUMN "issue_type"
SET DATA TYPE TEXT
USING "issue_type"::TEXT;
DROP TYPE IF EXISTS "IssueTypeType" CASCADE;
CREATE TYPE "IssueTypeType" AS ENUM (
'task',
'bug',
'story',
'epic'
);
ALTER TABLE "issues"
ALTER COLUMN "issue_type"
SET DATA TYPE "IssueTypeType"
USING "issue_type"::"IssueTypeType";
ALTER TABLE "issues" DROP COLUMN "epic_id";
DROP TABLE IF EXISTS epics;

View File

@ -0,0 +1,33 @@
ALTER TABLE "issues"
ALTER COLUMN "issue_type"
SET DATA TYPE TEXT
USING "issue_type"::TEXT;
UPDATE "issues"
SET "issue_type" = 'task'
WHERE "issue_type" = 'epic';
DROP TYPE IF EXISTS "IssueTypeType" CASCADE;
CREATE TYPE "IssueTypeType" AS ENUM (
'task',
'bug',
'story'
);
ALTER TABLE "issues"
ALTER COLUMN "issue_type"
SET DATA TYPE "IssueTypeType"
USING "issue_type"::"IssueTypeType";
CREATE TABLE epics (
id serial primary key not null,
name text not null,
user_id integer not null references users (id),
project_id integer not null references projects (id),
created_at timestamp not null default now(),
updated_at timestamp not null default now()
);
ALTER TABLE "issues"
ADD COLUMN "epic_id" integer
REFERENCES "epics" ( "id" ) NULL;

View File

@ -214,9 +214,10 @@ pub struct CreateIssue {
pub estimate: Option<i32>,
pub time_spent: Option<i32>,
pub time_remaining: Option<i32>,
pub project_id: i32,
pub reporter_id: i32,
pub user_ids: Vec<i32>,
pub project_id: jirs_data::ProjectId,
pub reporter_id: jirs_data::UserId,
pub user_ids: Vec<jirs_data::UserId>,
pub epic_id: Option<jirs_data::EpicId>,
}
impl Message for CreateIssue {
@ -272,6 +273,7 @@ impl Handler<CreateIssue> for DbExecutor {
time_remaining: msg.time_remaining,
reporter_id: msg.reporter_id,
project_id: msg.project_id,
epic_id: msg.epic_id,
};
let issue = diesel::insert_into(issues)

View File

@ -1,5 +1,6 @@
#![feature(async_closure)]
#![feature(vec_remove_item)]
#![recursion_limit = "256"]
#[macro_use]
extern crate diesel;

View File

@ -3,7 +3,7 @@ use serde::{Deserialize, Serialize};
use uuid::Uuid;
use jirs_data::{
InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId,
EpicId, InvitationState, IssuePriority, IssueStatusId, IssueType, ProjectCategory, ProjectId,
TimeTracking, UserId,
};
@ -34,6 +34,7 @@ pub struct Issue {
pub created_at: NaiveDateTime,
pub updated_at: NaiveDateTime,
pub issue_status_id: IssueStatusId,
pub epic_id: Option<EpicId>,
}
impl Into<jirs_data::Issue> for Issue {
@ -54,6 +55,7 @@ impl Into<jirs_data::Issue> for Issue {
created_at: self.created_at,
updated_at: self.updated_at,
issue_status_id: self.issue_status_id,
epic_id: self.epic_id,
user_ids: vec![],
}
@ -75,6 +77,7 @@ pub struct CreateIssueForm {
pub reporter_id: UserId,
pub project_id: ProjectId,
pub issue_status_id: IssueStatusId,
pub epic_id: Option<EpicId>,
}
#[derive(Debug, Serialize, Deserialize, Insertable)]

View File

@ -47,6 +47,53 @@ table! {
}
}
table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
/// Representation of the `epics` table.
///
/// (Automatically generated by Diesel.)
epics (id) {
/// The `id` column of the `epics` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
id -> Int4,
/// The `name` column of the `epics` table.
///
/// Its SQL type is `Text`.
///
/// (Automatically generated by Diesel.)
name -> Text,
/// The `user_id` column of the `epics` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
user_id -> Int4,
/// The `project_id` column of the `epics` table.
///
/// Its SQL type is `Int4`.
///
/// (Automatically generated by Diesel.)
project_id -> Int4,
/// The `created_at` column of the `epics` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
created_at -> Timestamp,
/// The `updated_at` column of the `epics` table.
///
/// Its SQL type is `Timestamp`.
///
/// (Automatically generated by Diesel.)
updated_at -> Timestamp,
}
}
table! {
use diesel::sql_types::*;
use jirs_data::sql::*;
@ -304,6 +351,12 @@ table! {
///
/// (Automatically generated by Diesel.)
issue_status_id -> Int4,
/// The `epic_id` column of the `issues` table.
///
/// Its SQL type is `Nullable<Int4>`.
///
/// (Automatically generated by Diesel.)
epic_id -> Nullable<Int4>,
}
}
@ -592,11 +645,14 @@ table! {
joinable!(comments -> issues (issue_id));
joinable!(comments -> users (user_id));
joinable!(epics -> projects (project_id));
joinable!(epics -> users (user_id));
joinable!(invitations -> projects (project_id));
joinable!(invitations -> users (invited_by_id));
joinable!(issue_assignees -> issues (issue_id));
joinable!(issue_assignees -> users (user_id));
joinable!(issue_statuses -> projects (project_id));
joinable!(issues -> epics (epic_id));
joinable!(issues -> issue_statuses (issue_status_id));
joinable!(issues -> projects (project_id));
joinable!(issues -> users (reporter_id));
@ -606,6 +662,7 @@ joinable!(user_projects -> users (user_id));
allow_tables_to_appear_in_same_query!(
comments,
epics,
invitations,
issue_assignees,
issue_statuses,

View File

@ -106,6 +106,7 @@ impl WsHandler<CreateIssuePayload> for WebSocketActor {
project_id: msg.project_id,
reporter_id: msg.reporter_id,
user_ids: msg.user_ids,
epic_id: msg.epic_id,
};
let m = match block_on(self.db.send(msg)) {
Ok(Ok(issue)) => Some(WsMsg::IssueCreated(issue.into())),