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: create sub groups

+105 -46
+26 -26
.config/config.ron
··· 1 1 ( 2 2 directory: "/Users/suri/dev/projects/filaments/ZettelKasten", 3 3 global_key_binds: { 4 - "down": MoveDown, 5 - "up": MoveUp, 6 4 "ctrl-z": Suspend, 5 + "up": MoveUp, 6 + "down": MoveDown, 7 7 "ctrl-c": Quit, 8 8 }, 9 9 zk: ( 10 10 keybinds: { 11 - "enter": OpenZettel, 12 - "ctrl-n": NewZettel, 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), 21 + "tab": SwitchTo( 22 + page: Zk, 23 23 ), 24 24 "3": SwitchTo( 25 25 page: Todo(TaskList), 26 26 ), 27 - "1": SwitchTo( 28 - page: Todo(Explorer), 27 + "g": NewSubGroup, 28 + "k": MoveUp, 29 + "2": SwitchTo( 30 + page: Todo(Inspector), 29 31 ), 30 - "k": MoveUp, 31 - "shift-g": NewSubGroup, 32 32 "j": MoveDown, 33 - "k": MoveUp, 34 - "tab": SwitchTo( 35 - page: Zk, 33 + "shift-g": NewGroup, 34 + "1": SwitchTo( 35 + page: Todo(Explorer), 36 36 ), 37 37 }, 38 38 ), ··· 41 41 "3": SwitchTo( 42 42 page: Todo(TaskList), 43 43 ), 44 - "tab": SwitchTo( 45 - page: Zk, 44 + "1": SwitchTo( 45 + page: Todo(Explorer), 46 46 ), 47 47 "2": SwitchTo( 48 48 page: Todo(Inspector), 49 49 ), 50 - "1": SwitchTo( 51 - page: Todo(Explorer), 50 + "tab": SwitchTo( 51 + page: Zk, 52 52 ), 53 53 }, 54 54 ), 55 55 tasklist: ( 56 56 keybinds: { 57 - "tab": SwitchTo( 58 - page: Zk, 59 - ), 60 - "3": SwitchTo( 61 - page: Todo(TaskList), 62 - ), 57 + "k": MoveUp, 63 58 "1": SwitchTo( 64 59 page: Todo(Explorer), 65 60 ), 66 - "j": MoveDown, 67 - "k": MoveUp, 68 61 "2": SwitchTo( 69 62 page: Todo(Inspector), 70 63 ), 64 + "3": SwitchTo( 65 + page: Todo(TaskList), 66 + ), 67 + "j": MoveDown, 68 + "tab": SwitchTo( 69 + page: Zk, 70 + ), 71 71 }, 72 72 ), 73 73 ), 74 - ) 74 + )
+2 -1
.config/default_config.ron
··· 22 22 "3": SwitchTo(page: Todo(TaskList)), 23 23 "j": MoveDown, 24 24 "k": MoveUp, 25 - "g": NewGroup 25 + "shift-g": NewGroup, 26 + "g": NewSubGroup, 26 27 }, 27 28 ), 28 29 inspector: (
+3 -1
justfile
··· 19 19 # Run all tests 20 20 test: 21 21 cargo nextest r {{_cargo_flags}} 22 - 22 + reset: 23 + rm -rf ZettleKasten 24 + cargo run -- init 23 25 24 26 # Only used to build / generate entities 25 27 dev-db := justfile_directory() + "/target/dev.db"
+31 -1
src/tui/components/todo/explorer.rs
··· 6 6 use tracing::debug; 7 7 use tree::NodeId; 8 8 9 - use crate::types::{TodoNode, TodoNodeKind, TodoTree}; 9 + use crate::types::{Group, TodoNode, TodoNodeKind, TodoTree}; 10 10 11 11 pub struct Explorer<'text> { 12 12 pub render_list: ratatui::widgets::List<'text>, ··· 78 78 .border_style(Style::new().fg(Color::Gray)) 79 79 .border_type(BorderType::Rounded), 80 80 ); 81 + } 82 + 83 + /// Returns the parent `Group` of the current selection in the `Explorer` 84 + pub fn group_of_current_selection<'tree>(&self, tree: &'tree TodoTree) -> Option<&'tree Group> { 85 + let selected = self.id_list.get(self.state.selected()?)?; 86 + 87 + if let TodoNodeKind::Group(group) = &tree 88 + .tree 89 + .get(selected) 90 + .expect("Invaraint Broken! This must be a valid id") 91 + .data() 92 + .kind 93 + { 94 + return Some(group); 95 + } 96 + 97 + let mut ancestors = tree.tree.ancestors(selected).expect("Must be a valid id"); 98 + 99 + ancestors 100 + .next() 101 + .and_then(|parent| match &parent.data().kind { 102 + TodoNodeKind::Root => None, 103 + 104 + TodoNodeKind::Task(_) => { 105 + panic!("Invariant broken! how is a task a parent?!") 106 + } 107 + 108 + TodoNodeKind::Group(group) => Some(group), 109 + }) 110 + .map(|g| &**g) 81 111 } 82 112 } 83 113
+19 -10
src/tui/components/todo/mod.rs
··· 28 28 signal_tx: Option<UnboundedSender<Signal>>, 29 29 kh: KastenHandle, 30 30 layouts: Layouts, 31 + 31 32 explorer: Option<Explorer<'text>>, 32 33 task_list: Option<TaskList<'text>>, 33 34 inspector: Option<Inspector<'text>>, ··· 238 239 self.task_list = Some(task_list); 239 240 self.inspector = Some(inspector); 240 241 241 - // match self.active { 242 - 243 - // ins 244 - 245 - // } 246 - 247 242 Ok(()) 248 243 } 249 244 ··· 322 317 return Ok(None); 323 318 } 324 319 325 - debug!("Creating Task!"); 326 - let _kt = self.kh.write().await; 327 - todo!(); 328 - // let task = Task::new("wahoo", ); 320 + todo!() 321 + 322 + // let ancestors = kt.todo_tree.tree.ancestors(node_id) = todo!(); 323 + // let task = Task::new("wahoo"); 329 324 } 330 325 331 326 Signal::NewSubGroup => { 327 + if self.active != TodoRegion::Explorer { 328 + return Ok(None); 329 + } 330 + let mut kt = self.kh.write().await; 331 + let parent = explorer 332 + .group_of_current_selection(&kt.todo_tree) 333 + .map(|parent| parent.id.clone()); 334 + let group = Group::new(NanoId::default().to_string(), parent, &mut kt).await?; 335 + drop(kt); 336 + debug!("Created group: {group:#?}"); 337 + return Ok(Some(Signal::Refresh)); 338 + } 339 + 340 + Signal::NewGroup => { 332 341 if self.active != TodoRegion::Explorer { 333 342 return Ok(None); 334 343 }
+5
src/tui/components/viewport/mod.rs
··· 65 65 async fn init(&mut self, area: Size) -> color_eyre::Result<()> { 66 66 self.zk.init(area).await?; 67 67 self.todo.init(area).await?; 68 + 69 + self.signal_tx.as_mut().unwrap().send(Signal::SwitchTo { 70 + page: Page::default(), 71 + })?; 72 + 68 73 Ok(()) 69 74 } 70 75
+17 -5
src/tui/components/zk/mod.rs
··· 7 7 use tracing::info; 8 8 9 9 use crate::{ 10 - tui::{Signal, components::Component}, 10 + tui::{Page, Signal, components::Component}, 11 11 types::{KastenHandle, Zettel}, 12 12 }; 13 13 ··· 36 36 zettel_list: Option<ZettelList<'text>>, 37 37 zettel_view: Option<ZettelView<'text>>, 38 38 preview: Option<Preview<'text>>, 39 + 40 + active: bool, 39 41 } 40 42 41 43 struct Layouts { ··· 97 99 zettel_list: None, 98 100 zettel_view: None, 99 101 preview: None, 102 + 103 + active: false, 100 104 } 101 105 } 102 106 ··· 308 312 let zettel_list = self.zettel_list.as_mut().expect("Must be initialized"); 309 313 let search = self.search.as_mut().expect("Must be initialized"); 310 314 match signal { 315 + Signal::SwitchTo { page } => { 316 + self.active = page == Page::Zk; 317 + } 318 + 311 319 Signal::Refresh => { 312 320 self.refresh().await?; 313 321 } 314 322 315 323 Signal::MoveDown => { 316 - zettel_list.state.select_next(); 317 - self.update_views_from_zettel_list_selection().await?; 324 + if self.active { 325 + zettel_list.state.select_next(); 326 + self.update_views_from_zettel_list_selection().await?; 327 + } 318 328 } 319 329 Signal::MoveUp => { 320 - zettel_list.state.select_previous(); 321 - self.update_views_from_zettel_list_selection().await?; 330 + if self.active { 331 + zettel_list.state.select_previous(); 332 + self.update_views_from_zettel_list_selection().await?; 333 + } 322 334 } 323 335 324 336 Signal::OpenZettel => {
+2 -2
src/types/task.rs
··· 1 1 use color_eyre::eyre::{Context, Result, eyre}; 2 2 use dto::{ 3 - Date, DateTime, GroupEntity, HasOne, IntoActiveModel as _, NanoId, TagEntity, TaskActiveModel, 4 - TaskEntity, TaskModelEx, Time, ZettelEntity, 3 + DateTime, GroupEntity, HasOne, IntoActiveModel as _, NanoId, TagEntity, TaskActiveModel, 4 + TaskEntity, TaskModelEx, ZettelEntity, 5 5 }; 6 6 7 7 use crate::types::{Group, Kasten, Priority, Zettel, frontmatter};