aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Gattozzi <mgattozzi@gmail.com>2019-12-23 19:36:16 -0500
committerMichael Gattozzi <mgattozzi@gmail.com>2019-12-23 19:36:16 -0500
commit90ae6068b2cc2256e9d6dce1e88124e92394254f (patch)
tree06cbb3e17988754bedaf4faa1e906974962925dd
parent9544d1b769114099fb72974aec1f8caeceda6014 (diff)
Add the ability to assign users to tickets
-rw-r--r--ticket/src/main.rs75
-rw-r--r--ticket/src/tui.rs22
2 files changed, 91 insertions, 6 deletions
diff --git a/ticket/src/main.rs b/ticket/src/main.rs
index 88e86cd..652bd01 100644
--- a/ticket/src/main.rs
+++ b/ticket/src/main.rs
@@ -52,6 +52,23 @@ enum Cmd {
Close { id: Uuid },
/// Comment on a ticket from the command line
Comment { id: Uuid, message: String },
+ /// Assing someone to a ticket from the command line
+ Assign {
+ id: Uuid,
+ #[structopt(subcommand)]
+ to: Placeholder,
+ },
+}
+
+#[derive(structopt::StructOpt)]
+enum Placeholder {
+ To(Who),
+}
+
+#[derive(structopt::StructOpt)]
+enum Who {
+ Me,
+ Them { id: Uuid, name: String },
}
#[paw::main]
@@ -69,6 +86,7 @@ fn main(args: Args) {
Cmd::Show { id } => show(id),
Cmd::Close { id } => close(id),
Cmd::Comment { id, message } => comment(id, message),
+ Cmd::Assign { id, to } => assign(id, to),
} {
error!("{}", e);
std::process::exit(1);
@@ -135,7 +153,9 @@ fn new() -> Result<()> {
version: Version::V1,
};
- save_ticket(&t)
+ save_ticket(&t)?;
+ println!("Ticket Created: {}", t.id);
+ Ok(())
}
fn show(id: Uuid) -> Result<()> {
@@ -154,7 +174,19 @@ fn show(id: Uuid) -> Result<()> {
if ticket.assignees.is_empty() {
"None".to_owned().blue()
} else {
- ticket.assignees.join(", ").blue()
+ let mut commas = ticket.assignees.len();
+ ticket
+ .assignees
+ .into_iter()
+ .fold(String::new(), |mut acc, (_, name)| {
+ acc.push_str(&name.0);
+ if commas > 1 {
+ acc.push_str(", ");
+ commas -= 1;
+ }
+ acc
+ })
+ .blue()
},
ticket.description,
ticket.comments.values().fold(
@@ -205,7 +237,7 @@ fn migrate() -> Result<()> {
title: t.title,
status: t.status,
id: uuid_v1()?,
- assignees: t.assignee.map_or_else(Vec::new, |a| vec![a]),
+ assignees: Vec::new(),
description: t.description,
comments: BTreeMap::new(),
version: Version::V1,
@@ -240,6 +272,41 @@ fn comment(id: Uuid, message: String) -> Result<()> {
save_ticket(&ticket)?;
Ok(())
}
+
+fn assign(id: Uuid, to: Placeholder) -> Result<()> {
+ let mut ticket = get_all_tickets()?
+ .into_iter()
+ .find(|t| t.id == id)
+ .ok_or_else(|| {
+ format_err!("The uuid '{}' is not associated with any ticket")
+ })?;
+ match to {
+ Placeholder::To(who) => match who {
+ Who::Me => {
+ let config = get_user_config()?;
+ if !ticket
+ .assignees
+ .iter()
+ .any(|(id, name)| config.uuid == *id && config.name == name.0)
+ {
+ ticket.assignees.push((config.uuid, Name(config.name)));
+ }
+ save_ticket(&ticket)?;
+ }
+ Who::Them { id, name } => {
+ let assignee_does_not_exist =
+ !ticket.assignees.iter().any(|(id_inside, name_inside)| {
+ id == *id_inside && name == name_inside.0
+ });
+ if assignee_does_not_exist {
+ ticket.assignees.push((id, Name(name)));
+ }
+ save_ticket(&ticket)?;
+ }
+ },
+ }
+ Ok(())
+}
#[derive(Serialize, Deserialize, Debug)]
/// The fundamental type this tool revolves around. The ticket represents
/// everything about an issue or future plan for the code base.
@@ -247,7 +314,7 @@ pub struct Ticket {
title: String,
status: Status,
id: Uuid,
- assignees: Vec<String>,
+ assignees: Vec<(Uuid, Name)>,
description: String,
version: Version,
#[serde(serialize_with = "toml::ser::tables_last")]
diff --git a/ticket/src/tui.rs b/ticket/src/tui.rs
index a4fdd35..015ecc9 100644
--- a/ticket/src/tui.rs
+++ b/ticket/src/tui.rs
@@ -369,13 +369,31 @@ impl<'a> App<'a> {
];
let name_style =
Style::default().fg(Color::Cyan).modifier(Modifier::BOLD);
+ if i.0.assignees.is_empty() {
+ desc.push(Text::styled("\nAssignees\n---------\n", header));
+ } else {
+ desc.push(Text::styled("\nAssignees\n---------\n", header));
+ if i.0.assignees.len() == 1 {
+ let (_, name) = &i.0.assignees[0];
+ desc.push(Text::styled(name.0.clone(), name_style));
+ } else {
+ for (idx, (_, name)) in i.0.assignees.iter().enumerate() {
+ if idx < i.0.assignees.len() - 1 {
+ desc.push(Text::styled(format!("{}, ", name.0), name_style));
+ } else {
+ desc.push(Text::styled(name.0.clone(), name_style));
+ }
+ }
+ }
+ }
+
if i.0.comments.is_empty() {
desc.push(Text::styled("\nComments\n--------\n", header));
} else {
desc.push(Text::styled("\nComments\n--------\n", header));
for (_, name, comment) in i.0.comments.values() {
- desc.push(Text::styled(format!("\n{}\n", name.0), name_style));
- desc.push(Text::raw(format!("{}\n", comment.0)));
+ desc.push(Text::styled(format!("{}\n", name.0), name_style));
+ desc.push(Text::raw(format!("{}\n\n", comment.0)));
}
}
desc