use crate::core::entity::{Team, TeamId, User, WorkflowState};
use crate::core::store::{IssueSource, Store, TeamContext};
#[derive(Debug, Clone, PartialEq)]
pub enum Request {
Teams,
Context { team_id: TeamId },
Labels { team_id: TeamId },
}
pub fn load() -> Request {
Request::Teams
}
pub fn load_labels(team_id: TeamId) -> Request {
Request::Labels { team_id }
}
pub fn pick_initial(
teams: &[Team],
remembered: Option<&TeamId>,
configured: Option<&str>,
) -> Option<usize> {
remembered
.and_then(|id| teams.iter().position(|t| &t.id == id))
.or_else(|| {
let wanted = configured?;
teams
.iter()
.position(|t| t.name == wanted || t.key == wanted)
})
}
pub fn switch(store: &mut Store, team_id: TeamId) -> Option<Request> {
store.issues[IssueSource::Team].reset();
store.projects.reset();
store.cycles.reset();
store.forget_pages();
for source in [
IssueSource::My,
IssueSource::View,
IssueSource::Project,
IssueSource::Cycle,
] {
store.issues[source].loaded = false;
}
ensure_context(store, team_id)
}
pub fn ensure_context(store: &mut Store, team_id: TeamId) -> Option<Request> {
if store.team_contexts.contains_key(&team_id)
|| !store.requested.team_contexts.insert(team_id.clone())
{
return None;
}
Some(Request::Context { team_id })
}
pub fn context_arrived(
store: &mut Store,
team_id: TeamId,
states: Vec<WorkflowState>,
members: Vec<User>,
) {
store.requested.team_contexts.remove(&team_id);
store
.team_contexts
.insert(team_id, TeamContext { states, members });
}
pub fn context_failed(store: &mut Store, team_id: &TeamId) {
store.requested.team_contexts.remove(team_id);
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::entity::Preset;
use crate::core::usecase::issue;
fn team(id: &str, name: &str, key: &str) -> Team {
serde_json::from_str(&format!(r#"{{"id":"{id}","name":"{name}","key":"{key}"}}"#)).unwrap()
}
fn teams() -> Vec<Team> {
vec![team("t1", "Core", "COR"), team("t2", "Design", "DES")]
}
#[test]
fn the_teams_are_asked_for() {
assert_eq!(load(), Request::Teams);
}
#[test]
fn a_teams_labels_are_asked_for() {
assert_eq!(
load_labels(TeamId::from("t")),
Request::Labels {
team_id: "t".into()
}
);
}
#[test]
fn the_remembered_team_comes_first() {
let t2 = TeamId::from("t2");
assert_eq!(pick_initial(&teams(), Some(&t2), Some("Core")), Some(1));
}
#[test]
fn the_configured_team_is_found_by_name_or_key() {
assert_eq!(pick_initial(&teams(), None, Some("Design")), Some(1));
assert_eq!(pick_initial(&teams(), None, Some("DES")), Some(1));
}
#[test]
fn otherwise_the_first_team() {
assert_eq!(pick_initial(&teams(), None, None), None);
let gone = TeamId::from("gone");
assert_eq!(pick_initial(&teams(), Some(&gone), Some("Nope")), None);
}
#[test]
fn switching_drops_the_old_teams_lists() {
let mut store = Store::default();
issue::open_team_issues(&mut store, TeamId::from("t1"), Preset::Active);
store.issues[IssueSource::Team].items =
vec![serde_json::from_str(r#"{"id":"i","identifier":"COR-1","title":"t"}"#).unwrap()];
store.requested.cursors.insert("c1".into());
let request = switch(&mut store, TeamId::from("t2"));
assert_eq!(
request,
Some(Request::Context {
team_id: "t2".into()
})
);
assert!(store.issues[IssueSource::Team].items.is_empty());
assert!(store.issues[IssueSource::Team].of.is_none());
assert!(store.requested.cursors.is_empty());
}
#[test]
fn a_teams_context_is_asked_for_once() {
let mut store = Store::default();
let t = TeamId::from("t");
assert!(ensure_context(&mut store, t.clone()).is_some());
assert_eq!(ensure_context(&mut store, t.clone()), None);
context_arrived(&mut store, t.clone(), Vec::new(), Vec::new());
assert_eq!(ensure_context(&mut store, t), None);
}
#[test]
fn a_failed_context_is_asked_for_again() {
let mut store = Store::default();
let t = TeamId::from("t");
ensure_context(&mut store, t.clone());
context_failed(&mut store, &t);
assert!(ensure_context(&mut store, t).is_some());
}
}