use super::*;
pub fn create_project(
args: flags::AddArgs,
app: toado::Server,
) -> Result<(i64, String), toado::Error> {
let theme = get_input_theme();
let name = option_or_input(
args.name,
dialoguer::Input::with_theme(&theme)
.with_prompt("Name")
.validate_with(|input: &String| validate_name(input)),
)?;
let start_time = if args.optional {
None
} else {
option_or_input_option(
args.start_time,
dialoguer::Input::with_theme(&theme).with_prompt("Start Time (optional)"),
)?
};
let end_time = if args.optional {
None
} else {
option_or_input_option(
args.end_time,
dialoguer::Input::with_theme(&theme).with_prompt("End Time (optional)"),
)?
};
let notes = if args.optional {
None
} else {
option_or_input_option(
args.notes,
dialoguer::Input::with_theme(&theme).with_prompt("Notes (optional)"),
)?
};
let id = app.add_project(toado::AddProjectArgs {
name: name.clone(),
start_time,
end_time,
notes,
})?;
Ok((id, name))
}
pub fn update_project(
args: flags::UpdateArgs,
app: toado::Server,
config: &config::Config,
) -> Result<u64, toado::Error> {
let theme = dialoguer::theme::ColorfulTheme::default();
let search_term = option_or_input(
args.term.clone(),
dialoguer::Input::with_theme(&theme).with_prompt("Project name"),
)?;
let project = prompt_project_selection(
&app,
search_term,
toado::QueryCols::Some(vec!["id", "name", "start_time", "end_time"]),
&theme,
config,
)?;
let project_id = match project.id {
Some(id) => id,
None => return Err(Into::into("project id should exist")),
};
let condition = toado::QueryConditions::Equal {
col: "id",
value: project_id,
}
.to_string();
let (name, start_time, end_time, notes) = if args.has_project_update_values() {
(
toado::UpdateAction::from(args.name),
nullable_into_update_action(args.start_time),
nullable_into_update_action(args.end_time),
nullable_into_update_action(args.notes),
)
} else {
let current_name = match project.name {
Some(value) => value,
None => return Err(Into::into("project name should exist")),
};
let current_start_time = project.start_time.unwrap_or("".to_string());
let current_end_time = project.end_time.unwrap_or("".to_string());
let current_notes = project.notes.unwrap_or("".to_string());
let name: String = dialoguer::Input::with_theme(&theme)
.with_prompt("Name")
.validate_with(|input: &String| validate_name(input))
.with_initial_text(current_name)
.interact_text()?;
let start_time: String = dialoguer::Input::with_theme(&theme)
.with_prompt("Start Time (optional)")
.with_initial_text(current_start_time)
.allow_empty(true)
.interact_text()?;
let end_time: String = dialoguer::Input::with_theme(&theme)
.with_prompt("End Time (optional)")
.with_initial_text(current_end_time)
.allow_empty(true)
.interact_text()?;
let notes: String = dialoguer::Input::with_theme(&theme)
.with_prompt("Notes (optional)")
.with_initial_text(current_notes)
.allow_empty(true)
.interact_text()?;
(
toado::UpdateAction::Some(name),
toado::UpdateAction::from(start_time),
toado::UpdateAction::from(end_time),
toado::UpdateAction::from(notes),
)
};
app.update_project(Some(condition), name, start_time, end_time, notes)
}
pub fn delete_project(
args: flags::DeleteArgs,
app: toado::Server,
config: &config::Config,
) -> Result<Option<i64>, toado::Error> {
let theme = dialoguer::theme::ColorfulTheme::default();
let search_term = option_or_input(
args.term,
dialoguer::Input::with_theme(&theme).with_prompt("Project name"),
)?;
let project = prompt_project_selection(
&app,
search_term,
toado::QueryCols::Some(vec!["id", "name", "start_time"]),
&theme,
config,
)?;
let id = match project.id {
Some(id) => id,
None => return Err(Into::into("project id should exist")),
};
let affected_rows = app.delete_project(Some(
toado::QueryConditions::Equal {
col: "id",
value: id,
}
.to_string(),
))?;
if affected_rows >= 1 {
Ok(Some(id))
} else {
Err(Into::into("no project deleted"))
}
}
pub fn list_projects(
args: flags::ListArgs,
app: toado::Server,
config: &config::Config,
) -> Result<Option<String>, toado::Error> {
let (cols, order_by, order_dir, limit, offset) = parse_list_args(&args);
let projects = app.select_project(cols, None, order_by, order_dir, limit, offset)?;
let num_projects = projects.len();
let mut table_string = formatting::format_project_list(projects, args.verbose, &config.table);
if !args.full {
table_string.push_str(&list_footer(
offset,
num_projects,
app.get_table_row_count(toado::Tables::Projects)?,
));
}
Ok(Some(table_string))
}
fn prompt_project_selection(
app: &toado::Server,
search_term: String,
cols: toado::QueryCols,
theme: &dyn dialoguer::theme::Theme,
config: &config::Config,
) -> Result<toado::Project, toado::Error> {
let select_condition = match search_term.parse::<usize>() {
Ok(num) => toado::QueryConditions::Equal {
col: "id",
value: num.to_string(),
},
Err(_) => toado::QueryConditions::Like {
col: "name",
value: format!("'%{search_term}%'"),
},
};
let mut projects = app.select_project(
cols,
Some(select_condition.to_string()),
Some(toado::OrderBy::Name),
None,
Some(toado::RowLimit::All),
None,
)?;
if projects.is_empty() {
return Err(Into::into(format!("no project matches {search_term}")));
}
if projects.len() == 1 {
Ok(projects.remove(0))
}
else {
let project_strings: Vec<String> =
formatting::format_project_list(projects.clone(), false, &config.table)
.split('\n')
.map(|line| line.to_string())
.collect();
match projects.get(
dialoguer::Select::with_theme(theme)
.with_prompt("Select project")
.items(&project_strings)
.interact()?,
) {
Some(project) => Ok(project.clone()),
None => Err(Into::into("selected project should exist")),
}
}
}