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: renaming of groups persists into the zettel

+133 -52
+26 -26
.config/config.ron
··· 1 1 ( 2 2 directory: "/Users/suri/dev/projects/filaments/ZettelKasten", 3 3 global_key_binds: { 4 - "down": MoveDown, 4 + "ctrl-z": Suspend, 5 5 "up": MoveUp, 6 6 "ctrl-c": Quit, 7 - "ctrl-z": Suspend, 7 + "down": MoveDown, 8 8 }, 9 9 zk: ( 10 10 keybinds: { 11 - "ctrl-n": NewZettel, 12 - "enter": OpenZettel, 13 11 "tab": SwitchTo( 14 12 page: Todo(Explorer), 15 13 ), 14 + "ctrl-n": NewZettel, 15 + "enter": OpenZettel, 16 16 }, 17 17 ), 18 18 todo: ( 19 19 explorer: ( 20 20 keybinds: { 21 - "2": SwitchTo( 22 - page: Todo(Inspector), 23 - ), 24 - "g": NewSubGroup, 21 + "j": MoveDown, 25 22 "tab": SwitchTo( 26 23 page: Zk, 27 24 ), 28 - "shift-g": NewGroup, 29 - "j": MoveDown, 30 25 "k": MoveUp, 31 26 "1": SwitchTo( 32 27 page: Todo(Explorer), 33 28 ), 34 - "3": SwitchTo( 35 - page: Todo(TaskList), 36 - ), 29 + "g": NewSubGroup, 37 30 "t": NewTask, 38 31 "enter": SwitchTo( 39 32 page: Todo(Inspector), 40 33 ), 34 + "2": SwitchTo( 35 + page: Todo(Inspector), 36 + ), 37 + "3": SwitchTo( 38 + page: Todo(TaskList), 39 + ), 40 + "shift-g": NewGroup, 41 41 }, 42 42 ), 43 43 inspector: ( 44 44 keybinds: { 45 - "1": SwitchTo( 46 - page: Todo(Explorer), 47 - ), 45 + "p": EditPriority, 48 46 "tab": SwitchTo( 49 47 page: Zk, 50 48 ), ··· 53 51 ), 54 52 "3": SwitchTo( 55 53 page: Todo(TaskList), 54 + ), 55 + "1": SwitchTo( 56 + page: Todo(Explorer), 56 57 ), 57 58 "n": EditName, 58 - "p": EditPriority, 59 59 }, 60 60 ), 61 61 tasklist: ( 62 62 keybinds: { 63 - "k": MoveUp, 64 - "enter": SwitchTo( 65 - page: Todo(Inspector), 66 - ), 67 63 "tab": SwitchTo( 68 64 page: Zk, 69 65 ), 70 - "1": SwitchTo( 71 - page: Todo(Explorer), 66 + "3": SwitchTo( 67 + page: Todo(TaskList), 68 + ), 69 + "k": MoveUp, 70 + "j": MoveDown, 71 + "enter": SwitchTo( 72 + page: Todo(Inspector), 72 73 ), 73 74 "2": SwitchTo( 74 75 page: Todo(Inspector), 75 76 ), 76 - "3": SwitchTo( 77 - page: Todo(TaskList), 77 + "1": SwitchTo( 78 + page: Todo(Explorer), 78 79 ), 79 - "j": MoveDown, 80 80 }, 81 81 ), 82 82 ),
+3 -25
src/tui/components/todo/inspector/mod.rs
··· 15 15 Signal, 16 16 components::{Component, DEFAULT_NAME}, 17 17 }, 18 - types::{KastenHandle, TodoNode, TodoNodeKind}, 18 + types::{Group, KastenHandle, TodoNode, TodoNodeKind}, 19 19 }; 20 20 21 21 mod rootview; ··· 238 238 .clone() 239 239 .expect("Invariant Broken, this must be some id"); 240 240 241 - let kt = self.kh.read().await; 241 + let mut kt = self.kh.write().await; 242 242 match &self.render_data { 243 243 RenderData::Task { .. } => { 244 244 let _ = TaskEntity::load() ··· 252 252 .await?; 253 253 } 254 254 RenderData::Group { .. } => { 255 - let g = GroupEntity::load() 256 - .filter_by_nano_id(id.clone()) 257 - .with(TagEntity) 258 - .one(&kt.db) 259 - .await? 260 - .expect("Invariant Broken: Must exist"); 261 - let tag_id = g.tag.as_ref().expect("Must be loaded").nano_id.clone(); 262 - 263 - let _ = g 264 - .into_active_model() 265 - .set_name(new_name.as_str()) 266 - .save(&kt.db) 267 - .await?; 268 - 269 - TagEntity::load() 270 - .filter_by_nano_id(tag_id) 271 - .one(&kt.db) 272 - .await? 273 - .expect("Invariant Broken: Must exist") 274 - .into_active_model() 275 - .set_name(new_name.as_str()) 276 - .save(&kt.db) 277 - .await?; 255 + Group::alter_name(id.clone(), new_name, &mut kt).await?; 278 256 } 279 257 RenderData::Root { .. } => unreachable!("Already returned above"), 280 258 }
+30
src/types/frontmatter.rs
··· 117 117 118 118 Ok((Self::new(title, created_at, tag_strings), remaining)) 119 119 } 120 + 121 + pub fn flush_to_file(&self, path: impl AsRef<Path>) -> Result<()> { 122 + let path = path.as_ref(); 123 + let string = std::fs::read_to_string(path)?; 124 + 125 + let lines: Vec<_> = string.lines().collect(); 126 + 127 + let closing_delim = lines 128 + .iter() 129 + .enumerate() 130 + .skip(1) 131 + .find(|(_, line)| line.trim() == "---") 132 + .map(|(i, _)| i) 133 + .ok_or_else(|| eyre!("Could not find closing front matter delimiter"))?; 134 + 135 + let body = lines[closing_delim + 1..].join("\n"); 136 + 137 + std::fs::write(path, format!("{self}{body}"))?; 138 + Ok(()) 139 + } 140 + } 141 + 142 + impl From<Zettel> for FrontMatter { 143 + fn from(value: Zettel) -> Self { 144 + Self { 145 + title: value.title, 146 + created_at: value.created_at, 147 + tag_strings: value.tags.into_iter().map(|t| t.name).collect(), 148 + } 149 + } 120 150 } 121 151 122 152 impl Display for FrontMatter {
+40
src/types/group.rs
··· 39 39 .to_string() 40 40 } 41 41 42 + pub async fn alter_name( 43 + id: NanoId, 44 + new_name: impl Into<String>, 45 + kt: &mut Kasten, 46 + ) -> Result<()> { 47 + let new_name = new_name.into(); 48 + 49 + let g = GroupEntity::load() 50 + .filter_by_nano_id(id.clone()) 51 + .with(TagEntity) 52 + .with((ZettelEntity, TagEntity)) 53 + .one(&kt.db) 54 + .await? 55 + .expect("Invariant Broken: Must exist"); 56 + 57 + let tag_id = g.tag.as_ref().expect("Must be loaded").nano_id.clone(); 58 + 59 + let zettel_id = g.zettel_id.clone(); 60 + 61 + let _ = g 62 + .into_active_model() 63 + .set_name(new_name.as_str()) 64 + .save(&kt.db) 65 + .await?; 66 + 67 + TagEntity::load() 68 + .filter_by_nano_id(tag_id) 69 + .one(&kt.db) 70 + .await? 71 + .expect("Invariant Broken: Must exist") 72 + .into_active_model() 73 + .set_name(new_name.as_str()) 74 + .save(&kt.db) 75 + .await?; 76 + 77 + Zettel::alter_name(zettel_id.into(), new_name, kt).await?; 78 + 79 + Ok(()) 80 + } 81 + 42 82 pub async fn new( 43 83 name: impl Into<String>, 44 84 parent_id: Option<NanoId>,
+34 -1
src/types/zettel/mod.rs
··· 1 1 use std::path::Path; 2 2 3 3 use dto::{ 4 - DatabaseConnection, DateTime, TagEntity, ZettelActiveModel, ZettelEntity, ZettelModelEx, 4 + DatabaseConnection, DateTime, IntoActiveModel, TagEntity, ZettelActiveModel, ZettelEntity, 5 + ZettelModelEx, 5 6 }; 6 7 7 8 use color_eyre::eyre::{Context, Result}; ··· 40 41 .one(db) 41 42 .await? 42 43 .map(Into::into)) 44 + } 45 + 46 + pub async fn alter_name( 47 + id: ZettelId, 48 + new_name: impl Into<String>, 49 + kt: &mut Kasten, 50 + ) -> Result<()> { 51 + let new_name = new_name.into(); 52 + 53 + // ok we need to change it on the actual zettel and then change 54 + // it in the frontmatter 55 + let _ = ZettelEntity::load() 56 + .filter_by_nano_id(id.clone()) 57 + .one(&kt.db) 58 + .await? 59 + .expect("Must exist") 60 + .into_active_model() 61 + .set_title(new_name) 62 + .save(&kt.db) 63 + .await?; 64 + 65 + let zettel = Self::fetch_from_db(&id, &kt.db) 66 + .await? 67 + .expect("We just saved it"); 68 + 69 + let file_path = zettel.absolute_path(&kt.index); 70 + let new_fm = FrontMatter::from(zettel); 71 + 72 + new_fm.flush_to_file(file_path)?; 73 + kt.index.process_zid(&id)?; 74 + 75 + Ok(()) 43 76 } 44 77 45 78 pub async fn new(title: impl Into<String>, kt: &mut Kasten, tags: Vec<Tag>) -> Result<Self> {