My personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

feat: Task creation

+113 -80
+1 -1
crates/dto/src/entity/task.rs
··· 2 2 3 3 use migration::prelude::Local; 4 4 use migration::types::*; 5 - use sea_orm::entity::prelude::*; 6 5 use sea_orm::ActiveValue::Set; 6 + use sea_orm::entity::prelude::*; 7 7 use std::future::ready; 8 8 use std::pin::Pin; 9 9
+1 -1
crates/dto/src/entity/zettel.rs
··· 1 1 //! `SeaORM` Entity, @generated by sea-orm-codegen 2.0 2 2 3 3 use migration::{prelude::Local, types::*}; 4 - use sea_orm::entity::prelude::*; 5 4 use sea_orm::ActiveValue::Set; 5 + use sea_orm::entity::prelude::*; 6 6 use std::{future::ready, pin::Pin}; 7 7 8 8 #[sea_orm::model]
+4 -63
src/cli/process.rs
··· 4 4 io::Write, 5 5 }; 6 6 7 - use color_eyre::eyre::{Context, Result, eyre}; 8 - use dto::{ 9 - Date, DateTime, GroupEntity, HasOne, IntoActiveModel, TagEntity, TaskActiveModel, TaskEntity, 10 - Time, ZettelEntity, 11 - }; 7 + use color_eyre::eyre::{Context, Result}; 12 8 use tower_lsp::{LspService, Server}; 13 9 14 10 use crate::{ ··· 19 15 }; 20 16 21 17 impl Commands { 22 - #[expect(clippy::too_many_lines)] 23 18 pub async fn process(self) -> Result<()> { 24 19 match self { 25 20 Self::Init { name } => { ··· 86 81 println!("created group {group:#?}"); 87 82 } 88 83 super::TodoSubcommand::Task { name, parent_id } => { 89 - // need to create the task 90 - let parent = GroupEntity::load() 91 - .with(TagEntity) 92 - .filter_by_nano_id(parent_id) 93 - .one(&kt.db) 94 - .await 95 - .with_context(|| "failed to communicate with db")? 96 - .ok_or_else(|| eyre!("could not find the group"))?; 97 - 98 - let HasOne::Loaded(tag) = parent.tag else { 99 - panic!("this has to be loaded since we just loaded it right above") 100 - }; 101 - 102 - let zettel = 103 - Zettel::new(name.clone(), &mut kt, vec![(*tag).into()]).await?; 104 - 105 - let inserted = TaskActiveModel::builder() 106 - .set_name(name) 107 - .set_group_id(parent.nano_id.clone()) 108 - .set_priority(Priority::default()) 109 - .set_zettel( 110 - ZettelEntity::load() 111 - .filter_by_nano_id(zettel.id) 112 - .one(&kt.db) 113 - .await? 114 - .expect("Zettel must exist since we just created it") 115 - .into_active_model(), 116 - ) 117 - .set_due(Some(DateTime::new( 118 - Date::from_ymd_opt(2026, 1, 31).unwrap(), 119 - Time::from_hms_opt(10, 10, 10).unwrap(), 120 - ))) 121 - .insert(&kt.db) 122 - .await?; 123 - 124 - let group = GroupEntity::load() 125 - .with(TagEntity) 126 - .with((ZettelEntity, TagEntity)) 127 - .filter_by_nano_id(parent.nano_id) 128 - .one(&kt.db) 129 - .await? 130 - .expect("We just inserted it"); 131 - 132 - let mut task = TaskEntity::load() 133 - .with((ZettelEntity, TagEntity)) 134 - .filter_by_nano_id(inserted.nano_id) 135 - .one(&kt.db) 136 - .await? 137 - .expect("We just inserted it"); 138 - 139 - task.group = HasOne::Loaded(Box::new(group)); 140 - 141 - println!("task: {task:#?}"); 142 - 143 - let task: Task = task.into(); 144 - 145 - println!("created task: {task:#?}"); 84 + let task = 85 + Task::new(name, parent_id, &mut kt, None, Priority::default()).await?; 86 + println!("created task {task:#?}"); 146 87 } 147 88 } 148 89 }
+1 -1
src/tui/components/todo/explorer.rs
··· 3 3 text::{Line, Span, Text}, 4 4 widgets::{Block, BorderType, Borders, List, ListState}, 5 5 }; 6 - use tracing::{debug, info}; 6 + use tracing::debug; 7 7 use tree::NodeId; 8 8 9 9 use crate::types::{TodoNode, TodoNodeKind, TodoTree};
+13 -2
src/tui/components/todo/mod.rs
··· 8 8 use serde::{Deserialize, Serialize}; 9 9 use strum::{Display, EnumIter}; 10 10 use tokio::sync::mpsc::UnboundedSender; 11 - use tracing::{debug, info}; 11 + use tracing::debug; 12 12 13 13 use crate::{ 14 14 tui::{Page, Signal, components::Component}, ··· 317 317 self.update_inspector_from_selection().await; 318 318 } 319 319 320 - Signal::NewGroup => { 320 + Signal::NewTask => { 321 + if self.active != TodoRegion::Explorer { 322 + return Ok(None); 323 + } 324 + 325 + debug!("Creating Task!"); 326 + let _kt = self.kh.write().await; 327 + todo!(); 328 + // let task = Task::new("wahoo", ); 329 + } 330 + 331 + Signal::NewSubGroup => { 321 332 if self.active != TodoRegion::Explorer { 322 333 return Ok(None); 323 334 }
+7 -1
src/tui/signal.rs
··· 56 56 zid: ZettelId, 57 57 }, 58 58 59 - /// Create a new `Group` 59 + /// Create a new `Group` inside the currently selected group 60 + NewSubGroup, 61 + 62 + /// Create a new `Group` in the current scope 60 63 NewGroup, 64 + 65 + /// Create a new `Task` 66 + NewTask, 61 67 62 68 /// this is fucking temporary 63 69 Helix {
-2
src/types/kasten/todo_tree.rs
··· 71 71 Ok(todo_tree) 72 72 } 73 73 74 - 75 - 76 74 #[async_recursion::async_recursion] 77 75 async fn add_group_to_tree( 78 76 &mut self,
+86 -9
src/types/task.rs
··· 1 - use dto::{ DateTime, NanoId, TaskModelEx}; 1 + use color_eyre::eyre::{Context, Result, eyre}; 2 + use dto::{ 3 + Date, DateTime, GroupEntity, HasOne, IntoActiveModel as _, NanoId, TagEntity, TaskActiveModel, 4 + TaskEntity, TaskModelEx, Time, ZettelEntity, 5 + }; 2 6 3 - use crate::types::{Group, Priority, Zettel, frontmatter}; 7 + use crate::types::{Group, Kasten, Priority, Zettel, frontmatter}; 4 8 5 9 /// a `Task` that you have to complete! 6 10 #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] 7 11 pub struct Task { 8 12 /// Should only be constructed from models. 9 - _private:(), 13 + _private: (), 10 14 11 15 pub id: NanoId, 12 16 pub name: String, ··· 22 26 } 23 27 24 28 impl Task { 29 + #[allow(clippy::unused_async)] 30 + #[allow(clippy::needless_pass_by_ref_mut)] 31 + pub async fn new( 32 + name: impl Into<String>, 33 + parent_id: NanoId, 34 + kt: &mut Kasten, 35 + due: Option<DateTime>, 36 + priority: Priority, 37 + ) -> Result<Self> { 38 + let name = name.into(); 39 + 40 + let parent = GroupEntity::load() 41 + .with(TagEntity) 42 + .filter_by_nano_id(parent_id) 43 + .one(&kt.db) 44 + .await 45 + .with_context(|| "failed to communicate with db")? 46 + .ok_or_else(|| eyre!("could not find the group"))?; 47 + 48 + let HasOne::Loaded(tag) = parent.tag else { 49 + panic!("this has to be loaded since we just loaded it right above") 50 + }; 51 + 52 + let zettel = Zettel::new(name.clone(), kt, vec![(*tag).into()]).await?; 53 + 54 + let inserted = TaskActiveModel::builder() 55 + .set_name(name) 56 + .set_group_id(parent.nano_id.clone()) 57 + .set_priority(priority) 58 + .set_zettel( 59 + ZettelEntity::load() 60 + .filter_by_nano_id(zettel.id) 61 + .one(&kt.db) 62 + .await? 63 + .expect("Zettel must exist since we just created it") 64 + .into_active_model(), 65 + ) 66 + .set_due(due) 67 + // .set_due(Some(DateTime::new( 68 + // Date::from_ymd_opt(2026, 1, 31).unwrap(), 69 + // Time::from_hms_opt(10, 10, 10).unwrap(), 70 + // ))) 71 + .insert(&kt.db) 72 + .await?; 73 + 74 + let group = GroupEntity::load() 75 + .with(TagEntity) 76 + .with((ZettelEntity, TagEntity)) 77 + .filter_by_nano_id(parent.nano_id) 78 + .one(&kt.db) 79 + .await? 80 + .expect("We just inserted it"); 81 + 82 + let mut task = TaskEntity::load() 83 + .with((ZettelEntity, TagEntity)) 84 + .filter_by_nano_id(inserted.nano_id) 85 + .one(&kt.db) 86 + .await? 87 + .expect("We just inserted it"); 88 + 89 + task.group = HasOne::Loaded(Box::new(group)); 90 + 91 + println!("task: {task:#?}"); 92 + 93 + // Ok(task.into()) 94 + 95 + todo!() 96 + } 97 + 25 98 pub fn due(&self) -> Option<String> { 26 - self.due.map(|due|due.format(frontmatter::DATE_FMT_STR).to_string()) 99 + self.due 100 + .map(|due| due.format(frontmatter::DATE_FMT_STR).to_string()) 27 101 } 28 102 pub fn finished_at(&self) -> Option<String> { 29 - self.finished_at. 30 - map(|finished_at|finished_at.format(frontmatter::DATE_FMT_STR).to_string()) 103 + self.finished_at 104 + .map(|finished_at| finished_at.format(frontmatter::DATE_FMT_STR).to_string()) 31 105 } 32 106 pub fn created_at(&self) -> String { 33 - self.created_at.format(frontmatter::DATE_FMT_STR).to_string() 107 + self.created_at 108 + .format(frontmatter::DATE_FMT_STR) 109 + .to_string() 34 110 } 35 111 pub fn modified_at(&self) -> String { 36 - self.modified_at.format(frontmatter::DATE_FMT_STR).to_string() 112 + self.modified_at 113 + .format(frontmatter::DATE_FMT_STR) 114 + .to_string() 37 115 } 38 116 } 39 117 ··· 63 141 "When fetching a Task from the database, we expect to always have the Group loaded!!", 64 142 ) 65 143 .into(), 66 - 67 144 } 68 145 } 69 146 }