From 34b87bcbe41c194f2604164e705a7f4b0c4eac92 Mon Sep 17 00:00:00 2001 From: Amolith Date: Wed, 18 Mar 2026 22:33:49 -0600 Subject: [PATCH] Allow task_type to be updated after creation --- src/cli.rs | 4 ++++ src/cmd/mod.rs | 2 ++ src/cmd/update.rs | 3 +++ src/cmd/webui/project/mutations.rs | 3 +++ src/ops.rs | 4 ++++ tests/cli_update.rs | 19 +++++++++++++++++++ 6 files changed, 35 insertions(+) diff --git a/src/cli.rs b/src/cli.rs index fd0ec7a91b3ca1e8a6b65a3420d49efec6dbcc53..e2be9629ac15d6627fa2f9f312d1e8d6778313fe 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -112,6 +112,10 @@ pub enum Command { /// Set description #[arg(short = 'd', long = "desc")] desc: Option, + + /// Set task type (e.g. task, bug, feature) + #[arg(long = "type")] + task_type: Option, }, /// Mark task(s) as closed diff --git a/src/cmd/mod.rs b/src/cmd/mod.rs index 17fbbbd1096911f6790af29f438fd4dfc359e431..db8d1bafc4c1da565abb8f774dacaed934df8780 100644 --- a/src/cmd/mod.rs +++ b/src/cmd/mod.rs @@ -94,6 +94,7 @@ pub fn dispatch(cli: &Cli) -> Result<()> { effort, title, desc, + task_type, } => { let root = require_root()?; let pri = priority.as_deref().map(Priority::parse).transpose()?; @@ -107,6 +108,7 @@ pub fn dispatch(cli: &Cli) -> Result<()> { effort: eff, title: title.as_deref(), desc: desc.as_deref(), + task_type: task_type.as_deref(), json: cli.json, }, ) diff --git a/src/cmd/update.rs b/src/cmd/update.rs index 5a6eaac8dff0a98c18d2dd132c8173f22b2ffe75..6c8c0e51e1514a65a4f9b28c361aa931b44048b7 100644 --- a/src/cmd/update.rs +++ b/src/cmd/update.rs @@ -12,6 +12,7 @@ pub struct Opts<'a> { pub effort: Option, pub title: Option<&'a str>, pub desc: Option<&'a str>, + pub task_type: Option<&'a str>, pub json: bool, } @@ -30,6 +31,7 @@ pub fn run(root: &Path, id: &str, opts: Opts) -> Result<()> { && opts.effort.is_none() && opts.title.is_none() && opts.desc.is_none() + && opts.task_type.is_none() { let interactive = std::env::var("TD_FORCE_EDITOR").is_ok() || std::io::IsTerminal::is_terminal(&std::io::stdin()); @@ -73,6 +75,7 @@ pub fn run(root: &Path, id: &str, opts: Opts) -> Result<()> { effort: opts.effort, title: title_override.map(String::from), description: desc_override.map(String::from), + task_type: opts.task_type.map(String::from), }, )?; diff --git a/src/cmd/webui/project/mutations.rs b/src/cmd/webui/project/mutations.rs index b84bf25e80eb52d48daf56320b38efb4d2ec19c4..0d9489d004786c509106c4cdbf417544134ac970 100644 --- a/src/cmd/webui/project/mutations.rs +++ b/src/cmd/webui/project/mutations.rs @@ -60,6 +60,8 @@ pub(in crate::cmd::webui) struct UpdateForm { #[serde(default)] effort: Option, #[serde(default)] + task_type: Option, + #[serde(default)] redirect: Option, } @@ -197,6 +199,7 @@ pub(in crate::cmd::webui) async fn update_handler( .transpose()?, title: form.title.filter(|s| !s.is_empty()), description: form.description, + task_type: form.task_type.filter(|s| !s.is_empty()), }, )?; diff --git a/src/ops.rs b/src/ops.rs index b59d1d1429641502bf26500627eb421b9228326d..f00ba1b718addf4217ad36e41b9ef1cc08928a81 100644 --- a/src/ops.rs +++ b/src/ops.rs @@ -83,6 +83,7 @@ pub struct UpdateOpts { pub effort: Option, pub title: Option, pub description: Option, + pub task_type: Option, } /// Update task fields and return the refreshed task. @@ -108,6 +109,9 @@ pub fn update_task(store: &Store, task_id: &TaskId, opts: UpdateOpts) -> Result< if let Some(ref d) = opts.description { task.insert("description", d.as_str())?; } + if let Some(ref tt) = opts.task_type { + task.insert("type", tt.as_str())?; + } task.insert("updated_at", ts.clone())?; Ok(()) })?; diff --git a/tests/cli_update.rs b/tests/cli_update.rs index e66183bd35b0545ee58b32d52e64e94ad358eaf7..b32b35f3c4253bcdfeb96ff48c776705acbb7ed1 100644 --- a/tests/cli_update.rs +++ b/tests/cli_update.rs @@ -129,6 +129,25 @@ fn update_changes_effort() { assert_eq!(t["effort"].as_str().unwrap(), "high"); } +#[test] +fn update_changes_task_type() { + let tmp = init_tmp(); + let id = create_task(&tmp, "Reclassify me"); + + // Default type is "task" + let t = get_task_json(&tmp, &id); + assert_eq!(t["type"].as_str().unwrap(), "task"); + + td(&tmp) + .args(["update", &id, "--type", "bug"]) + .current_dir(&tmp) + .assert() + .success(); + + let t = get_task_json(&tmp, &id); + assert_eq!(t["type"].as_str().unwrap(), "bug"); +} + // ── done ───────────────────────────────────────────────────────────── #[test]