use anyhow::Result;
use clap::Subcommand;
use serde_json::json;
use crate::api::LinearClient;
use crate::output::{print_json, OutputOptions};
#[derive(Subcommand, Debug)]
pub enum FavoriteCommands {
List,
Add {
id: String,
},
Remove {
id: String,
},
}
pub async fn handle(cmd: FavoriteCommands, output: &OutputOptions) -> Result<()> {
match cmd {
FavoriteCommands::List => list_favorites(output).await,
FavoriteCommands::Add { id } => add_favorite(&id, output).await,
FavoriteCommands::Remove { id } => remove_favorite(&id, output).await,
}
}
async fn list_favorites(output: &OutputOptions) -> Result<()> {
let client = LinearClient::new()?;
let query = r#"
query {
favorites(first: 100) {
nodes {
id
type
sortOrder
issue {
id
identifier
title
}
project {
id
name
}
label {
id
name
}
}
}
}
"#;
let result = client.query(query, None).await?;
let favorites = &result["data"]["favorites"]["nodes"];
print_json(favorites, output)?;
Ok(())
}
async fn add_favorite(id: &str, output: &OutputOptions) -> Result<()> {
let client = LinearClient::new()?;
let issue_query = r#"
query($identifier: String!) {
issue(id: $identifier) {
id
}
}
"#;
let issue_result = client
.query(issue_query, Some(json!({ "identifier": id })))
.await;
let is_issue = issue_result
.as_ref()
.map(|r| !r["data"]["issue"].is_null())
.unwrap_or(false);
let mutation = if is_issue {
r#"
mutation($issueId: String!) {
favoriteCreate(input: { issueId: $issueId }) {
success
favorite {
id
}
}
}
"#
} else {
r#"
mutation($projectId: String!) {
favoriteCreate(input: { projectId: $projectId }) {
success
favorite {
id
}
}
}
"#
};
let vars = if is_issue {
json!({ "issueId": id })
} else {
json!({ "projectId": id })
};
let result = client.mutate(mutation, Some(vars)).await?;
if output.is_json() {
print_json(&result["data"]["favoriteCreate"], output)?;
} else {
println!("Added {} to favorites", id);
}
Ok(())
}
async fn remove_favorite(id: &str, output: &OutputOptions) -> Result<()> {
let client = LinearClient::new()?;
let query = r#"
query {
favorites(first: 100) {
nodes {
id
issue { identifier }
project { id }
}
}
}
"#;
let result = client.query(query, None).await?;
let favorites = result["data"]["favorites"]["nodes"]
.as_array()
.cloned()
.unwrap_or_default();
let favorite = favorites.iter().find(|f| {
f["issue"]["identifier"].as_str() == Some(id) || f["project"]["id"].as_str() == Some(id)
});
if let Some(fav) = favorite {
let Some(fav_id) = fav["id"].as_str() else {
anyhow::bail!("Invalid favorite: missing id");
};
let mutation = r#"
mutation($id: String!) {
favoriteDelete(id: $id) {
success
}
}
"#;
let result = client
.mutate(mutation, Some(json!({ "id": fav_id })))
.await?;
if output.is_json() {
print_json(&result["data"]["favoriteDelete"], output)?;
} else {
println!("Removed {} from favorites", id);
}
} else {
anyhow::bail!("Favorite not found for: {}", id);
}
Ok(())
}