use crate::core::store::{ListOf, Opening, PageAsk};
pub mod agent;
pub mod cycle;
pub mod favorite;
pub mod instance;
pub mod issue;
pub mod notes;
pub mod project;
pub mod team;
pub mod user;
pub mod view;
pub mod workspace;
#[derive(Debug, Clone, PartialEq)]
pub enum Request {
Issue(issue::Request),
Project(project::Request),
Cycle(cycle::Request),
Team(team::Request),
View(view::Request),
Favorite(favorite::Request),
User(user::Request),
Notes(notes::Request),
Agent(agent::Request),
}
macro_rules! from_aggregate {
($($variant:ident($module:ident)),* $(,)?) => {$(
impl From<$module::Request> for Request {
fn from(request: $module::Request) -> Self {
Self::$variant(request)
}
}
)*};
}
from_aggregate!(
Issue(issue),
Project(project),
Cycle(cycle),
Team(team),
View(view),
Favorite(favorite),
User(user),
Notes(notes),
Agent(agent),
);
impl Request {
pub fn page(ask: PageAsk) -> Self {
let PageAsk { of, after } = ask;
match of {
ListOf::TeamIssues { team_id, preset } => issue::Request::TeamIssues {
team_id,
preset,
after,
}
.into(),
ListOf::MyIssues(user_id) => issue::Request::MyIssues { user_id, after }.into(),
ListOf::ViewIssues(view_id) => issue::Request::ViewIssues { view_id, after }.into(),
ListOf::ProjectIssues(project_id) => {
issue::Request::ProjectIssues { project_id, after }.into()
}
ListOf::CycleIssues(cycle_id) => issue::Request::CycleIssues { cycle_id, after }.into(),
ListOf::TeamProjects(team_id) => {
project::Request::TeamProjects { team_id, after }.into()
}
ListOf::ViewProjects(view_id) => {
project::Request::ViewProjects { view_id, after }.into()
}
ListOf::TeamCycles(team_id) => cycle::Request::TeamCycles { team_id, after }.into(),
}
}
pub fn cursor(&self) -> Option<&str> {
match self {
Self::Issue(request) => request.cursor(),
Self::Project(request) => request.cursor(),
Self::Cycle(request) => request.cursor(),
_ => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub enum Open {
Cached,
Fetch(Request),
Replace(Request),
}
impl Open {
pub fn request(self) -> Option<Request> {
match self {
Self::Cached => None,
Self::Fetch(request) | Self::Replace(request) => Some(request),
}
}
pub fn replaced(&self) -> bool {
matches!(self, Self::Replace(_))
}
}
impl From<Opening> for Open {
fn from(opening: Opening) -> Self {
match opening {
Opening::Cached => Self::Cached,
Opening::Fetch(ask) => Self::Fetch(Request::page(ask)),
Opening::Replace(ask) => Self::Replace(Request::page(ask)),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, thiserror::Error)]
pub enum Refusal {
#[error("Current user is not loaded yet")]
ViewerNotLoaded,
#[error("A title is required")]
TitleRequired,
#[error("A name is required")]
NameRequired,
#[error("A project needs at least one team")]
TeamRequired,
#[error("The target date {target} is before the start date {start}")]
EndsBeforeItStarts { start: String, target: String },
#[error("Nothing to change")]
NothingToChange,
#[error("An issue cannot be its own parent")]
OwnParent,
#[error("Label {0} is both added and removed")]
LabelAddedAndRemoved(String),
#[error("The comment is empty")]
EmptyComment,
#[error("No comment {0} on this issue")]
NoSuchComment(String),
#[error("Only {0}, who wrote it, can edit or delete this comment")]
NotYourComment(String),
#[error("No {0} to copy")]
NothingToCopy(&'static str),
#[error("Nothing to open here")]
NothingToOpen,
#[error("Jumping to an agent needs herdr")]
NeedsHerdr,
#[error("No herdr agent is working on {0}")]
NoAgentOn(String),
#[error("No notes yet")]
NoNotes,
#[error("Only one workspace is signed in \u{2014} `linear-tui auth login` adds another")]
OnlyOneWorkspace,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::core::entity::{Preset, TeamId};
#[test]
fn a_next_page_request_carries_its_cursor() {
let lists = [
ListOf::TeamIssues {
team_id: TeamId::from("t"),
preset: Preset::All,
},
ListOf::MyIssues("u".into()),
ListOf::ViewIssues("v".into()),
ListOf::ProjectIssues("p".into()),
ListOf::CycleIssues("c".into()),
ListOf::TeamProjects(TeamId::from("t")),
ListOf::ViewProjects("v".into()),
ListOf::TeamCycles(TeamId::from("t")),
];
for of in lists {
let request = Request::page(PageAsk {
of,
after: Some("next".into()),
});
assert_eq!(request.cursor(), Some("next"), "{request:?}");
}
for other in [
Request::from(team::Request::Teams),
issue::Request::Detail {
issue_id: "i".into(),
}
.into(),
project::Request::OpenInBrowser("u".into()).into(),
] {
assert_eq!(other.cursor(), None, "{other:?}");
}
}
}