diff --git a/src/navigator.rs b/src/navigator.rs index 5ca2d23..5bb58cf 100644 --- a/src/navigator.rs +++ b/src/navigator.rs @@ -1,39 +1,64 @@ -use anyhow::{anyhow, Result, Context, Ok}; +use anyhow::{anyhow, Context, Ok, Result}; use std::rc::Rc; -use crate::{ui::{Page, HomePage, EpicDetail, StoryDetail, Prompts}, db::JiraDatabase, models::Action}; +use crate::{ + db::JiraDatabase, + models::Action, + ui::{EpicDetail, HomePage, Page, Prompts, StoryDetail}, +}; pub struct Navigator { pages: Vec>, prompts: Prompts, - db: Rc + db: Rc, } impl Navigator { pub fn new(db: Rc) -> Self { - todo!() + Self { + pages: vec![], + prompts: Prompts::new(), + db, + } } pub fn get_current_page(&self) -> Option<&Box> { - todo!() // this should always return the last element in the pages vector + self.pages.last() } pub fn handle_action(&mut self, action: Action) -> Result<()> { match action { Action::NavigateToEpicDetail { epic_id } => { - todo!() // create a new EpicDetail instance and add it to the pages vector + // create a new EpicDetail instance and add it to the pages vector + self.pages.push(Box::new(EpicDetail { + epic_id, + db: Rc::clone(&self.db), + })); } Action::NavigateToStoryDetail { epic_id, story_id } => { - todo!() // create a new StoryDetail instance and add it to the pages vector + // create a new StoryDetail instance and add it to the pages vector + self.pages.push(Box::new(StoryDetail { + epic_id, + story_id, + db: Rc::clone(&self.db), + })); } Action::NavigateToPreviousPage => { - todo!() // remove the last page from the pages vector + // remove the last page from the pages vector + let _ = self.pages.pop(); } Action::CreateEpic => { - todo!() // prompt the user to create a new epic and persist it in the database + // prompt the user to create a new epic and persist it in the database + self.db.create_epic((self.prompts.create_epic)()); } Action::UpdateEpicStatus { epic_id } => { - todo!() // prompt the user to update status and persist it in the database + todo!(); // prompt the user to update status and persist it in the database + // let status = (self.prompts.update_status)().(|| { + // return Err(anyhow!("failed to update epic status") + // .context(format!("invalid status given"))); + // }); + self.db + .update_epic_status(epic_id, crate::models::Status::Open); } Action::DeleteEpic { epic_id } => { todo!() // prompt the user to delete the epic and persist it in the database @@ -48,8 +73,9 @@ impl Navigator { todo!() // prompt the user to delete the story and persist it in the database } Action::Exit => { - todo!() // remove all pages from the pages vector - }, + // remove all pages from the pages vector + self.pages.clear(); + } } Ok(()) @@ -68,12 +94,17 @@ impl Navigator { #[cfg(test)] mod tests { - use crate::{db::test_utils::MockDB, models::{Epic, Status, Story}}; use super::*; + use crate::{ + db::test_utils::MockDB, + models::{Epic, Status, Story}, + }; #[test] fn should_start_on_home_page() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); let nav = Navigator::new(db); assert_eq!(nav.get_page_count(), 1); @@ -86,18 +117,25 @@ mod tests { #[test] fn handle_action_should_navigate_pages() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); let mut nav = Navigator::new(db); - - nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }).unwrap(); + + nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }) + .unwrap(); assert_eq!(nav.get_page_count(), 2); let current_page = nav.get_current_page().unwrap(); let epic_detail_page = current_page.as_any().downcast_ref::(); assert_eq!(epic_detail_page.is_some(), true); - nav.handle_action(Action::NavigateToStoryDetail { epic_id: 1, story_id: 2 }).unwrap(); + nav.handle_action(Action::NavigateToStoryDetail { + epic_id: 1, + story_id: 2, + }) + .unwrap(); assert_eq!(nav.get_page_count(), 3); let current_page = nav.get_current_page().unwrap(); @@ -127,12 +165,19 @@ mod tests { #[test] fn handle_action_should_clear_pages_on_exit() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); let mut nav = Navigator::new(db); - - nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }).unwrap(); - nav.handle_action(Action::NavigateToStoryDetail { epic_id: 1, story_id: 2 }).unwrap(); + + nav.handle_action(Action::NavigateToEpicDetail { epic_id: 1 }) + .unwrap(); + nav.handle_action(Action::NavigateToStoryDetail { + epic_id: 1, + story_id: 2, + }) + .unwrap(); nav.handle_action(Action::Exit).unwrap(); assert_eq!(nav.get_page_count(), 0); @@ -140,7 +185,9 @@ mod tests { #[test] fn handle_action_should_handle_create_epic() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); let mut nav = Navigator::new(Rc::clone(&db)); @@ -148,7 +195,7 @@ mod tests { prompts.create_epic = Box::new(|| Epic::new("name".to_owned(), "description".to_owned())); nav.set_prompts(prompts); - + nav.handle_action(Action::CreateEpic).unwrap(); let db_state = db.read_db().unwrap(); @@ -161,8 +208,12 @@ mod tests { #[test] fn handle_action_should_handle_update_epic() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); - let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap(); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); + let epic_id = db + .create_epic(Epic::new("".to_owned(), "".to_owned())) + .unwrap(); let mut nav = Navigator::new(Rc::clone(&db)); @@ -170,17 +221,25 @@ mod tests { prompts.update_status = Box::new(|| Some(Status::InProgress)); nav.set_prompts(prompts); - - nav.handle_action(Action::UpdateEpicStatus { epic_id }).unwrap(); + + nav.handle_action(Action::UpdateEpicStatus { epic_id }) + .unwrap(); let db_state = db.read_db().unwrap(); - assert_eq!(db_state.epics.get(&epic_id).unwrap().status, Status::InProgress); + assert_eq!( + db_state.epics.get(&epic_id).unwrap().status, + Status::InProgress + ); } #[test] fn handle_action_should_handle_delete_epic() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); - let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap(); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); + let epic_id = db + .create_epic(Epic::new("".to_owned(), "".to_owned())) + .unwrap(); let mut nav = Navigator::new(Rc::clone(&db)); @@ -188,7 +247,7 @@ mod tests { prompts.delete_epic = Box::new(|| true); nav.set_prompts(prompts); - + nav.handle_action(Action::DeleteEpic { epic_id }).unwrap(); let db_state = db.read_db().unwrap(); @@ -197,8 +256,12 @@ mod tests { #[test] fn handle_action_should_handle_create_story() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); - let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap(); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); + let epic_id = db + .create_epic(Epic::new("".to_owned(), "".to_owned())) + .unwrap(); let mut nav = Navigator::new(Rc::clone(&db)); @@ -206,7 +269,7 @@ mod tests { prompts.create_story = Box::new(|| Story::new("name".to_owned(), "description".to_owned())); nav.set_prompts(prompts); - + nav.handle_action(Action::CreateStory { epic_id }).unwrap(); let db_state = db.read_db().unwrap(); @@ -219,9 +282,15 @@ mod tests { #[test] fn handle_action_should_handle_update_story() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); - let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap(); - let story_id = db.create_story(Story::new("".to_owned(), "".to_owned()), epic_id).unwrap(); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); + let epic_id = db + .create_epic(Epic::new("".to_owned(), "".to_owned())) + .unwrap(); + let story_id = db + .create_story(Story::new("".to_owned(), "".to_owned()), epic_id) + .unwrap(); let mut nav = Navigator::new(Rc::clone(&db)); @@ -229,18 +298,28 @@ mod tests { prompts.update_status = Box::new(|| Some(Status::InProgress)); nav.set_prompts(prompts); - - nav.handle_action(Action::UpdateStoryStatus { story_id }).unwrap(); + + nav.handle_action(Action::UpdateStoryStatus { story_id }) + .unwrap(); let db_state = db.read_db().unwrap(); - assert_eq!(db_state.stories.get(&story_id).unwrap().status, Status::InProgress); + assert_eq!( + db_state.stories.get(&story_id).unwrap().status, + Status::InProgress + ); } #[test] fn handle_action_should_handle_delete_story() { - let db = Rc::new(JiraDatabase { database: Box::new(MockDB::new()) }); - let epic_id = db.create_epic(Epic::new("".to_owned(), "".to_owned())).unwrap(); - let story_id = db.create_story(Story::new("".to_owned(), "".to_owned()), epic_id).unwrap(); + let db = Rc::new(JiraDatabase { + database: Box::new(MockDB::new()), + }); + let epic_id = db + .create_epic(Epic::new("".to_owned(), "".to_owned())) + .unwrap(); + let story_id = db + .create_story(Story::new("".to_owned(), "".to_owned()), epic_id) + .unwrap(); let mut nav = Navigator::new(Rc::clone(&db)); @@ -248,10 +327,11 @@ mod tests { prompts.delete_story = Box::new(|| true); nav.set_prompts(prompts); - - nav.handle_action(Action::DeleteStory { epic_id, story_id }).unwrap(); + + nav.handle_action(Action::DeleteStory { epic_id, story_id }) + .unwrap(); let db_state = db.read_db().unwrap(); assert_eq!(db_state.stories.len(), 0); } -} \ No newline at end of file +}