diff --git a/apps/cli/src/main.rs b/apps/cli/src/main.rs index ee6d9b6fa..d79dc0f66 100644 --- a/apps/cli/src/main.rs +++ b/apps/cli/src/main.rs @@ -47,6 +47,9 @@ enum Commands { /// Networking and pairing #[command(subcommand)] Network(NetworkCommands), + /// Job commands + #[command(subcommand)] + Job(JobCommands), } #[derive(Subcommand, Debug)] @@ -116,6 +119,14 @@ enum PairCommands { Cancel { session_id: Uuid }, } +#[derive(Subcommand, Debug)] +enum JobCommands { + /// List jobs + List { #[arg(long)] status: Option }, + /// Job info + Info { job_id: Uuid }, +} + #[derive(Parser, Debug, Clone)] struct SpacedropArgs { /// Target device ID @@ -554,7 +565,13 @@ async fn main() -> Result<()> { println!("Added location {} -> {}", out.id, out.path.display()); } Commands::Location(LocationCommands::List) => { - println!("Listing locations is not available yet in this build"); + // If only one library exists, use it; else require --library later (omitted for brevity) + let libs: Vec = core + .query(&sd_core::ops::libraries::list::query::ListLibrariesQuery::basic()) + .await?; + let library_id = if libs.len() == 1 { libs[0].id } else { anyhow::bail!("Specify --library to list locations when multiple libraries exist") }; + let out: sd_core::ops::locations::list::output::LocationsListOutput = core.query(&sd_core::ops::locations::list::query::LocationsListQuery { library_id }).await?; + for loc in out.locations { println!("- {} {}", loc.id, loc.path.display()); } } Commands::Location(LocationCommands::Remove { location_id }) => { let _out: sd_core::ops::locations::remove::output::LocationRemoveOutput = core.action(&sd_core::ops::locations::remove::action::LocationRemoveInput { location_id }).await?; @@ -655,6 +672,28 @@ async fn main() -> Result<()> { } } } + Commands::Job(cmd) => { + match cmd { + JobCommands::List { status } => { + // There isn't a direct op; use library job manager via a helper query when available. For now, use running jobs + let libs: Vec = core + .query(&sd_core::ops::libraries::list::query::ListLibrariesQuery::basic()) + .await?; + if libs.is_empty() { println!("No libraries found"); } + for lib in libs { + let running = core.query(&sd_core::ops::indexing::state::RunningJobsQuery { library_id: lib.id }).await; + if let Ok(running_jobs) = running { + for j in running_jobs.jobs { println!("- {} {} {}%", j.id, j.name, (j.progress * 100.0) as u32); } + } else { + println!("Library {}: jobs listing not available", lib.id); + } + } + } + JobCommands::Info { job_id } => { + println!("Job {} info not available yet", job_id); + } + } + } } Ok(()) diff --git a/core/src/ops/locations/list/mod.rs b/core/src/ops/locations/list/mod.rs new file mode 100644 index 000000000..8b39707e7 --- /dev/null +++ b/core/src/ops/locations/list/mod.rs @@ -0,0 +1,6 @@ +pub mod query; +pub mod output; + +pub use query::*; +pub use output::*; + diff --git a/core/src/ops/locations/list/output.rs b/core/src/ops/locations/list/output.rs new file mode 100644 index 000000000..221b68329 --- /dev/null +++ b/core/src/ops/locations/list/output.rs @@ -0,0 +1,16 @@ +use serde::{Deserialize, Serialize}; +use std::path::PathBuf; +use uuid::Uuid; + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LocationInfo { + pub id: Uuid, + pub path: PathBuf, + pub name: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct LocationsListOutput { + pub locations: Vec, +} + diff --git a/core/src/ops/locations/list/query.rs b/core/src/ops/locations/list/query.rs new file mode 100644 index 000000000..5895a2b29 --- /dev/null +++ b/core/src/ops/locations/list/query.rs @@ -0,0 +1,32 @@ +use super::output::{LocationInfo, LocationsListOutput}; +use crate::{context::CoreContext, cqrs::Query}; +use anyhow::Result; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; +use std::sync::Arc; + +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] +pub struct LocationsListQuery { + pub library_id: uuid::Uuid, +} + +impl Query for LocationsListQuery { + type Output = LocationsListOutput; + + async fn execute(self, context: Arc) -> Result { + // Fetch library and query locations table + let library = context.library_manager.get_library(self.library_id).await.ok_or_else(|| anyhow::anyhow!("Library not found"))?; + let db = library.db().conn(); + let rows = crate::infra::db::entities::location::Entity::find() + .filter(crate::infra::db::entities::location::Column::LibraryId.eq(self.library_id)) + .all(db) + .await?; + let mut out = Vec::new(); + for r in rows { + out.push(LocationInfo { id: r.uuid, path: std::path::PathBuf::from(r.path), name: r.name }); + } + Ok(LocationsListOutput { locations: out }) + } +} + +crate::register_query!(LocationsListQuery, "locations.list"); + diff --git a/core/src/ops/locations/mod.rs b/core/src/ops/locations/mod.rs index eb6fc220e..8434d1137 100644 --- a/core/src/ops/locations/mod.rs +++ b/core/src/ops/locations/mod.rs @@ -4,8 +4,10 @@ pub mod add; // pub mod index; // Module removed during migration pub mod remove; pub mod rescan; +pub mod list; pub use add::*; // pub use index::*; // Module removed during migration pub use remove::*; -pub use rescan::*; \ No newline at end of file +pub use rescan::*; +pub use list::*; \ No newline at end of file