feat: adds some Navigator actions

This commit is contained in:
itsscb 2024-08-12 16:05:57 +02:00
parent 5411e39548
commit 7ec23699a8

@ -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<Box<dyn Page>>,
prompts: Prompts,
db: Rc<JiraDatabase>
db: Rc<JiraDatabase>,
}
impl Navigator {
pub fn new(db: Rc<JiraDatabase>) -> Self {
todo!()
Self {
pages: vec![],
prompts: Prompts::new(),
db,
}
}
pub fn get_current_page(&self) -> Option<&Box<dyn Page>> {
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::<EpicDetail>();
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);
}
}
}