feat(core): add move_task and rename_list to onyx-core
Add TaskRepository::move_task() to move tasks between lists and rename_list() to rename lists on the filesystem. Adds rename_list to the Storage trait with FileSystemStorage implementation. Includes tests for both operations plus duplicate-name error case. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6959b1f44f
commit
c4c03679ae
|
|
@ -68,6 +68,17 @@ impl TaskRepository {
|
||||||
self.storage.delete_list(list_id)
|
self.storage.delete_list(list_id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rename_list(&mut self, list_id: Uuid, new_name: String) -> Result<()> {
|
||||||
|
self.storage.rename_list(list_id, new_name)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn move_task(&mut self, from_list_id: Uuid, to_list_id: Uuid, task_id: Uuid) -> Result<()> {
|
||||||
|
let task = self.storage.read_task(from_list_id, task_id)?;
|
||||||
|
self.storage.write_task(to_list_id, &task)?;
|
||||||
|
self.storage.delete_task(from_list_id, task_id)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// Task ordering
|
// Task ordering
|
||||||
pub fn reorder_task(&mut self, list_id: Uuid, task_id: Uuid, new_position: usize) -> Result<()> {
|
pub fn reorder_task(&mut self, list_id: Uuid, task_id: Uuid, new_position: usize) -> Result<()> {
|
||||||
let mut metadata = self.storage.read_list_metadata(list_id)?;
|
let mut metadata = self.storage.read_list_metadata(list_id)?;
|
||||||
|
|
@ -320,6 +331,54 @@ mod tests {
|
||||||
assert!(lists.is_empty());
|
assert!(lists.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_move_task_between_lists() {
|
||||||
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
let mut repo = TaskRepository::init(temp_dir.path().to_path_buf()).unwrap();
|
||||||
|
|
||||||
|
let list_a = repo.create_list("List A".to_string()).unwrap();
|
||||||
|
let list_b = repo.create_list("List B".to_string()).unwrap();
|
||||||
|
let task = repo.create_task(list_a.id, Task::new("Movable".to_string())).unwrap();
|
||||||
|
|
||||||
|
repo.move_task(list_a.id, list_b.id, task.id).unwrap();
|
||||||
|
|
||||||
|
let tasks_a = repo.list_tasks(list_a.id).unwrap();
|
||||||
|
assert_eq!(tasks_a.len(), 0);
|
||||||
|
|
||||||
|
let tasks_b = repo.list_tasks(list_b.id).unwrap();
|
||||||
|
assert_eq!(tasks_b.len(), 1);
|
||||||
|
assert_eq!(tasks_b[0].title, "Movable");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rename_list() {
|
||||||
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
let mut repo = TaskRepository::init(temp_dir.path().to_path_buf()).unwrap();
|
||||||
|
|
||||||
|
let list = repo.create_list("Old Name".to_string()).unwrap();
|
||||||
|
repo.rename_list(list.id, "New Name".to_string()).unwrap();
|
||||||
|
|
||||||
|
let renamed = repo.get_list(list.id).unwrap();
|
||||||
|
assert_eq!(renamed.title, "New Name");
|
||||||
|
|
||||||
|
// Old directory should be gone
|
||||||
|
assert!(!temp_dir.path().join("Old Name").exists());
|
||||||
|
assert!(temp_dir.path().join("New Name").exists());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rename_list_duplicate_name() {
|
||||||
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
let mut repo = TaskRepository::init(temp_dir.path().to_path_buf()).unwrap();
|
||||||
|
|
||||||
|
repo.create_list("A".to_string()).unwrap();
|
||||||
|
let list_b = repo.create_list("B".to_string()).unwrap();
|
||||||
|
|
||||||
|
let result = repo.rename_list(list_b.id, "A".to_string());
|
||||||
|
assert!(result.is_err());
|
||||||
|
assert!(matches!(result.unwrap_err(), Error::InvalidData(_)));
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_delete_list_removes_from_root_metadata() {
|
fn test_delete_list_removes_from_root_metadata() {
|
||||||
let temp_dir = TempDir::new().unwrap();
|
let temp_dir = TempDir::new().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -88,6 +88,8 @@ pub trait Storage {
|
||||||
fn read_root_metadata(&self) -> Result<RootMetadata>;
|
fn read_root_metadata(&self) -> Result<RootMetadata>;
|
||||||
fn write_root_metadata(&mut self, metadata: &RootMetadata) -> Result<()>;
|
fn write_root_metadata(&mut self, metadata: &RootMetadata) -> Result<()>;
|
||||||
|
|
||||||
|
fn rename_list(&mut self, list_id: Uuid, new_name: String) -> Result<()>;
|
||||||
|
|
||||||
fn read_list_metadata(&self, list_id: Uuid) -> Result<ListMetadata>;
|
fn read_list_metadata(&self, list_id: Uuid) -> Result<ListMetadata>;
|
||||||
fn write_list_metadata(&mut self, metadata: &ListMetadata) -> Result<()>;
|
fn write_list_metadata(&mut self, metadata: &ListMetadata) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
@ -464,6 +466,27 @@ impl Storage for FileSystemStorage {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rename_list(&mut self, list_id: Uuid, new_name: String) -> Result<()> {
|
||||||
|
let old_dir = self.list_dir_path(list_id)?;
|
||||||
|
let new_dir = self.list_dir_path_by_name(&new_name);
|
||||||
|
|
||||||
|
if new_dir.exists() {
|
||||||
|
return Err(Error::InvalidData(format!("A list named '{}' already exists", new_name)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::rename(&old_dir, &new_dir)?;
|
||||||
|
|
||||||
|
// Update metadata timestamp
|
||||||
|
let metadata_path = new_dir.join(".listdata.json");
|
||||||
|
let content = fs::read_to_string(&metadata_path)?;
|
||||||
|
let mut metadata: ListMetadata = serde_json::from_str(&content)?;
|
||||||
|
metadata.updated_at = Utc::now();
|
||||||
|
let json = serde_json::to_string_pretty(&metadata)?;
|
||||||
|
fs::write(&metadata_path, json)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
fn read_root_metadata(&self) -> Result<RootMetadata> {
|
fn read_root_metadata(&self) -> Result<RootMetadata> {
|
||||||
self.read_root_metadata_internal()
|
self.read_root_metadata_internal()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue