use tauri::command; use crate::error::AppError; use crate::models::{MissionPlan, SubTask, SubTaskType, Task}; #[command] pub fn add_task(mission: MissionPlan) -> MissionPlan { let mut m = mission; let new_id = m.next_task_id(); m.tasks.push(Task::new(new_id)); m.task_count = m.tasks.len() as u32; m } #[command] pub fn copy_task(mission: MissionPlan, task_id: u32) -> Result { let mut m = mission; let src = m.tasks.iter() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))? .clone(); let new_id = m.next_task_id(); let mut new_task = src; new_task.id = new_id; new_task.scheduled_time = "2000-01-01T00:00:00".to_string(); new_task.start_time = None; new_task.end_time = None; new_task.duration_minutes = 0.0; new_task.estimated_duration_minutes = 0.0; new_task.status = "Waiting".to_string(); // Reset subtask IDs for sub in &mut new_task.sub_tasks { sub.id = uuid::Uuid::new_v4().to_string(); sub.start_time = None; sub.end_time = None; sub.duration_minutes = 0.0; sub.estimated_duration_minutes = 0.0; sub.status = "Waiting".to_string(); } m.tasks.push(new_task); m.task_count = m.tasks.len() as u32; Ok(m) } #[command] pub fn remove_task(mission: MissionPlan, task_id: u32) -> Result { let mut m = mission; let pos = m.tasks.iter().position(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; m.tasks.remove(pos); m.task_count = m.tasks.len() as u32; Ok(m) } #[command] pub fn add_sub_task( mission: MissionPlan, task_id: u32, sub_task_type: SubTaskType, ) -> Result { let mut m = mission; let task = m.tasks.iter_mut() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; // Check: same type already exists if task.has_type(&sub_task_type) { return Err(AppError::Validation(format!( "Task #{} already has a {} sub-task", task_id, sub_task_type.label() ))); } task.sub_tasks.push(SubTask::new(sub_task_type)); Ok(m) } #[command] pub fn remove_sub_task( mission: MissionPlan, task_id: u32, sub_task_id: String, ) -> Result { let mut m = mission; let task = m.tasks.iter_mut() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; let pos = task.sub_tasks.iter().position(|s| s.id == sub_task_id) .ok_or(AppError::SubTaskNotFound(sub_task_id))?; task.sub_tasks.remove(pos); Ok(m) } #[command] pub fn update_sub_task( mission: MissionPlan, task_id: u32, sub_task: SubTask, ) -> Result { let mut m = mission; let task = m.tasks.iter_mut() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; let pos = task.sub_tasks.iter().position(|s| s.id == sub_task.id) .ok_or(AppError::SubTaskNotFound(sub_task.id.clone()))?; task.sub_tasks[pos] = sub_task; Ok(m) } #[command] pub fn update_task( mission: MissionPlan, task: Task, ) -> Result { let mut m = mission; let pos = m.tasks.iter().position(|t| t.id == task.id) .ok_or(AppError::TaskNotFound(task.id))?; m.tasks[pos] = task; Ok(m) } #[command] pub fn reorder_sub_tasks( mission: MissionPlan, task_id: u32, from_index: usize, to_index: usize, ) -> Result { let mut m = mission; let task = m.tasks.iter_mut() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; if from_index >= task.sub_tasks.len() || to_index >= task.sub_tasks.len() { return Err(AppError::Validation("Index out of bounds".into())); } let sub = task.sub_tasks.remove(from_index); task.sub_tasks.insert(to_index, sub); Ok(m) } #[command] pub fn validate_sub_task_order( mission: MissionPlan, task_id: u32, ) -> Result { let task = mission.tasks.iter() .find(|t| t.id == task_id) .ok_or(AppError::TaskNotFound(task_id))?; let mut found_camera = false; for sub in &task.sub_tasks { if sub.sub_task_type.is_camera_type() { found_camera = true; } else if found_camera && sub.sub_task_type.is_hyperspectral() { return Ok(false); } } Ok(true) }