mod graphql;
use crate::common::{
authorization_headers::authorization_headers, env_var::env_var,
execute_graphql_request::execute_graphql_request, fetch_user_id::fetch_user_id,
keyring::keyring, print_formatted_error::print_formatted_error,
};
use crate::projects::create::graphql::check_team_name::{check_team_name, CheckTeamName};
use crate::projects::create::graphql::create_project::{create_project, CreateProject};
use clap::Args;
use dialoguer::theme::ColorfulTheme;
use dialoguer::Input;
use graphql_client::GraphQLQuery;
use reqwest::Client;
use termimad::{
crossterm::style::{style, Color, Stylize},
minimad, MadSkin,
};
#[derive(Args, Debug)]
pub struct ProjectsCreateArgs {
#[clap(
short,
long,
help = "Project name, if not specified, the user will be prompted to enter the name"
)]
name: Option<String>,
#[clap(
short,
long,
help = "Team name, if not specified, the project will be added to personal projects"
)]
team_name: Option<String>,
#[clap(
short,
long,
help = "Access token, if not specified, the token will be taken from the keychain"
)]
access_token: Option<String>,
}
pub fn create(args: &ProjectsCreateArgs) {
let access_token = match &args.access_token {
Some(token) => token.clone(),
None => keyring::get("access_token"),
};
let client = Client::new();
let headers = authorization_headers(&access_token);
let team_name = match &args.team_name {
Some(team) if !team.is_empty() => team.clone(),
_ => "Personal projects".to_string(),
};
let check_team_error_message = format!("{} '{}' {}", "Team", team_name.clone(), "not found");
let team_response =
execute_graphql_request::<check_team_name::Variables, check_team_name::ResponseData>(
headers.clone(),
CheckTeamName::build_query,
&client,
&check_team_error_message,
check_team_name::Variables {
user_id: fetch_user_id(&access_token),
name: team_name.clone(),
},
)
.team;
let team_id = match team_response.len() {
1 => team_response[0].id,
_ => {
print_formatted_error(&check_team_error_message);
std::process::exit(1);
}
};
let project_name = match &args.name {
Some(name) => {
if name.trim().chars().count() < 2 {
print_formatted_error("The project name must be at least 2 characters long.");
std::process::exit(1);
}
name.clone()
}
None => {
match Input::with_theme(&ColorfulTheme::default())
.with_prompt("Type a project name:")
.validate_with(|name: &String| -> Result<(), &str> {
if name.trim().chars().count() < 2 {
return Err("The project name must be at least 2 characters long.");
} else {
Ok(())
}
})
.interact()
{
Ok(new_name) => new_name,
Err(_) => {
print_formatted_error("Failed to read the new project name.");
std::process::exit(1);
}
}
}
};
let create_project_error_message = "Failed to create a project";
let project_response =
execute_graphql_request::<create_project::Variables, create_project::ResponseData>(
headers.clone(),
CreateProject::build_query,
&client,
create_project_error_message,
create_project::Variables {
object: create_project::CreateProjectInput {
name: project_name.clone(),
active_team_id: team_id,
},
},
)
.create_project;
let project = match project_response {
Some(project) => project,
None => {
print_formatted_error(create_project_error_message);
std::process::exit(1);
}
};
let text_template = minimad::TextTemplate::from(
r#"
##### **✔ Project successfully created**
${description}
Project link: ${project-link}
Project token: **${project-token}**
Project ID for CLI: **${short-project-id}**
> *Please make sure to store this token in a safe place.*
> *If you ever lose or forget this token, you can regenerate it.*
> *However, be aware that any scripts or applications using this token will need to be updated accordingly.*
"#,
);
let mut expander = text_template.expander();
let project_id = project.id.to_string();
let description = if &team_name == "Personal projects" {
format!(
"You created the project named '{}' as a personal.",
&project_name
)
} else {
format!(
"You created the project named '{}' within the '{}' team.",
&project_name, &team_name
)
};
let project_link = style(format!(
"{}/projects/{}",
env_var("WEBAPP_URL"),
&project_id
))
.with(Color::Rgb {
r: (0),
g: (135),
b: (255),
})
.to_string();
expander
.set("description", &description)
.set("project-link", &project_link)
.set("project-id", &project_id)
.set("project-token", &project.token)
.set("short-project-id", &project_id[..4]);
let mut skin = MadSkin::default();
skin.bold.set_fg(Color::Green);
skin.print_expander(expander);
}