use anyhow::Result;
use crate::operations::rename_config_project_mapping;
use crate::projects::{inferred_project_key_for_add_with_database, project_has_config_mapping};
use crate::tui::store::{MutationMessage, TaskScope};
use crate::undo::UndoCommand;
use super::TuiStore;
impl TuiStore {
pub(crate) async fn create_project(&mut self, name: String) -> Result<String> {
let name = name.trim().to_string();
let outcome = self
.database
.create_project(&self.active_workspace, &name)
.await?;
let commands = if outcome.created {
vec![UndoCommand::DeleteCreatedProject {
project_key: outcome.project.key.clone(),
create_change_id: outcome.change_id.unwrap_or_default(),
expected_name: outcome.project.name.clone(),
expected_prefix: outcome.project.prefix.clone(),
}]
} else {
Vec::new()
};
self.record_undo_commands(&format!("project {}", outcome.project.key), commands)
.await?;
self.refresh(None).await?;
Ok(format!("created project {}", outcome.project.key))
}
pub(crate) async fn delete_project(&mut self, project: &str) -> Result<MutationMessage> {
let project = self
.database
.resolve_existing_project(&self.active_workspace.id, project)
.await?;
let config_mapping = project_has_config_mapping(
&self.active_workspace.id,
&self.active_workspace.key,
&project.key,
)
.unwrap_or(false);
let outcome = self
.database
.delete_project(&self.active_workspace, &project.key)
.await?;
if self.scope_project() == Some(outcome.project.key.as_str()) {
self.view_state.scope = TaskScope::Workspace;
}
let selected = self.refresh(None).await?;
let mut message = format!("deleted project {}", outcome.project.key);
if config_mapping {
message.push_str("; config path mappings were left unchanged");
}
Ok(MutationMessage::new(message, selected))
}
pub(crate) async fn rename_project(
&mut self,
project: &str,
new_name: String,
) -> Result<MutationMessage> {
let outcome = self
.database
.rename_project(&self.active_workspace, project, &new_name, None)
.await?;
let config_mapping = if outcome.changed {
rename_config_project_mapping(
&self.active_workspace,
&outcome.previous.key,
&outcome.project.key,
)?
} else {
project_has_config_mapping(
&self.active_workspace.id,
&self.active_workspace.key,
&outcome.previous.key,
)
.unwrap_or(false)
};
if outcome.changed {
self.record_undo_commands(
&format!("project {}", outcome.project.key),
vec![UndoCommand::SetProjectMetadata {
project_id: outcome.project.id.clone(),
before_key: outcome.previous.key.clone(),
before_name: outcome.previous.name.clone(),
before_prefix: outcome.previous.prefix.clone(),
after_key: outcome.project.key.clone(),
after_name: outcome.project.name.clone(),
after_prefix: outcome.project.prefix.clone(),
}],
)
.await?;
}
if self.scope_project() == Some(outcome.previous.key.as_str()) {
self.view_state.scope = TaskScope::Project(outcome.project.key.clone());
}
let selected = self.refresh(None).await?;
let mut message = format!(
"renamed project {} prefix={}",
outcome.project.key, outcome.project.prefix
);
if !outcome.changed {
message = format!("renamed project {} changed=none", outcome.project.key);
} else if config_mapping {
message.push_str("; updated config path mappings");
}
Ok(MutationMessage::new(message, selected))
}
pub(crate) async fn create_label(&mut self, name: String) -> Result<String> {
let name = name.trim().to_string();
let outcome = self
.database
.create_label(&self.active_workspace, &name)
.await?;
let commands = if outcome.created {
vec![UndoCommand::DeleteCreatedLabel {
label: outcome.name.clone(),
create_change_id: outcome.change_id.unwrap_or_default(),
}]
} else {
Vec::new()
};
self.record_undo_commands(&format!("label {}", outcome.name), commands)
.await?;
self.labels = self
.database
.list_labels(&self.active_workspace.id, None)
.await?;
Ok(format!("created label {}", outcome.name))
}
pub(crate) async fn inferred_add_project(&self) -> Result<Option<String>> {
inferred_project_key_for_add_with_database(&self.database, &self.active_workspace).await
}
}