The kebab menu and docs referred to a task "due date" but the field was just a date; this change renames due_date/group_by_due_date and related identifiers to date/group_by_date across Rust, TypeScript, Svelte, CLI, docs and tests to keep terminology consistent. Updates include API/command names, storage/models, repository methods, UI text, JS variables and builder/parse functions so code, tests and documentation all use "date" semantics. Preserve old "group_by_due_date" field name Add serde alias to ListMetadata.group_by_date so older .listdata.json files that used the previous field name (group_by_due_date) can still be deserialized correctly. This fixes serialization/deserialization issues encountered at /home/trztn/Documents/Onyx and /var/home/trztn/Nextcloud/Onyx. the frontmatter due should be date... I don't want due anywhere - Renamed `TaskFrontmatter.due` → `TaskFrontmatter.date`; YAML key on disk is now `date:` instead of `due:` - Added `#[serde(alias = "due")]` so existing task files with `due:` frontmatter still deserialize correctly - Updated google_tasks.rs to write `date:` instead of `due:` in generated YAML - Renamed CLI `--due` flag to `--date`; updated function signature and display string "Due:" → "Date:" Remove serde aliases and rename due→date Drop backwards-compat aliases and update frontmatter/metadata to use the canonical "date"/"group_by_date" fields. The aliases for group_by_due_date and due were removed to avoid maintaining backward-compatibility and to reflect the current schema. Updated storage types to rename the fields and adjusted serialization attributes so YAML/JSON frontmatter and .listdata.json files now use group_by_date and date consistently.
278 lines
7 KiB
Rust
278 lines
7 KiB
Rust
mod commands;
|
|
mod output;
|
|
|
|
use anyhow::Result;
|
|
use clap::{Parser, Subcommand};
|
|
use commands::*;
|
|
|
|
#[derive(Parser)]
|
|
#[command(name = "onyx")]
|
|
#[command(about = "A local-first, cross-platform tasks application", long_about = None)]
|
|
struct Cli {
|
|
#[command(subcommand)]
|
|
command: Commands,
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
enum Commands {
|
|
/// Initialize a new workspace
|
|
Init {
|
|
/// Path to store tasks
|
|
path: String,
|
|
/// Name of the workspace
|
|
#[arg(short, long)]
|
|
name: String,
|
|
},
|
|
|
|
/// Manage workspaces
|
|
#[command(subcommand)]
|
|
Workspace(WorkspaceCommands),
|
|
|
|
/// Manage task lists
|
|
#[command(subcommand)]
|
|
List(ListCommands),
|
|
|
|
/// Add a new task
|
|
Add {
|
|
/// Task title
|
|
title: String,
|
|
/// List to add task to
|
|
#[arg(short, long)]
|
|
list: Option<String>,
|
|
/// Date (ISO 8601 format: YYYY-MM-DD or YYYY-MM-DDTHH:MM:SS)
|
|
#[arg(short, long)]
|
|
date: Option<String>,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Mark a task as complete
|
|
Complete {
|
|
/// Task ID
|
|
task_id: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Delete a task
|
|
Delete {
|
|
/// Task ID
|
|
task_id: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Edit a task
|
|
Edit {
|
|
/// Task ID
|
|
task_id: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Toggle group-by-date for a list
|
|
#[command(subcommand)]
|
|
Group(GroupCommands),
|
|
|
|
/// Sync workspace with WebDAV server
|
|
Sync {
|
|
/// Run initial setup (URL, credentials)
|
|
#[arg(long)]
|
|
setup: bool,
|
|
/// Push-only sync (upload local changes)
|
|
#[arg(long, conflicts_with_all = ["pull", "setup", "status"])]
|
|
push: bool,
|
|
/// Pull-only sync (download remote changes)
|
|
#[arg(long, conflicts_with_all = ["push", "setup", "status"])]
|
|
pull: bool,
|
|
/// Show sync status
|
|
#[arg(long, conflicts_with_all = ["push", "pull", "setup"])]
|
|
status: bool,
|
|
/// Show status for all workspaces (with --status)
|
|
#[arg(long, requires = "status")]
|
|
all: bool,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
enum WorkspaceCommands {
|
|
/// Add a new workspace
|
|
Add {
|
|
/// Name of the workspace
|
|
name: String,
|
|
/// Path to store tasks
|
|
path: String,
|
|
},
|
|
|
|
/// List all workspaces
|
|
List,
|
|
|
|
/// Switch to a different workspace
|
|
Switch {
|
|
/// Name of the workspace
|
|
name: String,
|
|
},
|
|
|
|
/// Remove a workspace
|
|
Remove {
|
|
/// Name of the workspace
|
|
name: String,
|
|
},
|
|
|
|
/// Update workspace path without moving files
|
|
Retarget {
|
|
/// Name of the workspace
|
|
name: String,
|
|
/// New path
|
|
path: String,
|
|
},
|
|
|
|
/// Move workspace files to a new location
|
|
Migrate {
|
|
/// Name of the workspace
|
|
name: String,
|
|
/// New path
|
|
path: String,
|
|
},
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
enum ListCommands {
|
|
/// Create a new task list
|
|
Create {
|
|
/// Name of the list
|
|
name: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Show all tasks (or tasks in a specific list)
|
|
Show {
|
|
/// Name of the list to show
|
|
#[arg(short, long)]
|
|
list: Option<String>,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Delete a task list
|
|
Delete {
|
|
/// Name of the list to delete
|
|
name: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
}
|
|
|
|
#[derive(Subcommand)]
|
|
enum GroupCommands {
|
|
/// Enable group-by-date for a list
|
|
Enable {
|
|
/// Name of the list
|
|
#[arg(short, long)]
|
|
list: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
|
|
/// Disable group-by-date for a list
|
|
Disable {
|
|
/// Name of the list
|
|
#[arg(short, long)]
|
|
list: String,
|
|
/// Workspace to use
|
|
#[arg(short, long)]
|
|
workspace: Option<String>,
|
|
},
|
|
}
|
|
|
|
fn main() -> Result<()> {
|
|
let cli = Cli::parse();
|
|
|
|
match cli.command {
|
|
Commands::Init { path, name } => {
|
|
init::execute(path, name)?;
|
|
}
|
|
Commands::Workspace(cmd) => match cmd {
|
|
WorkspaceCommands::Add { name, path } => {
|
|
workspace::add(name, path)?;
|
|
}
|
|
WorkspaceCommands::List => {
|
|
workspace::list()?;
|
|
}
|
|
WorkspaceCommands::Switch { name } => {
|
|
workspace::switch(name)?;
|
|
}
|
|
WorkspaceCommands::Remove { name } => {
|
|
workspace::remove(name)?;
|
|
}
|
|
WorkspaceCommands::Retarget { name, path } => {
|
|
workspace::retarget(name, path)?;
|
|
}
|
|
WorkspaceCommands::Migrate { name, path } => {
|
|
workspace::migrate(name, path)?;
|
|
}
|
|
},
|
|
Commands::List(cmd) => match cmd {
|
|
ListCommands::Create { name, workspace } => {
|
|
list::create(name, workspace)?;
|
|
}
|
|
ListCommands::Show { list, workspace } => {
|
|
list::show(list, workspace)?;
|
|
}
|
|
ListCommands::Delete { name, workspace } => {
|
|
list::delete(name, workspace)?;
|
|
}
|
|
},
|
|
Commands::Add { title, list, date, workspace } => {
|
|
task::add(title, list, date, workspace)?;
|
|
}
|
|
Commands::Complete { task_id, workspace } => {
|
|
task::complete(task_id, workspace)?;
|
|
}
|
|
Commands::Delete { task_id, workspace } => {
|
|
task::delete(task_id, workspace)?;
|
|
}
|
|
Commands::Edit { task_id, workspace } => {
|
|
task::edit(task_id, workspace)?;
|
|
}
|
|
Commands::Group(cmd) => match cmd {
|
|
GroupCommands::Enable { list, workspace } => {
|
|
group::enable(list, workspace)?;
|
|
}
|
|
GroupCommands::Disable { list, workspace } => {
|
|
group::disable(list, workspace)?;
|
|
}
|
|
},
|
|
Commands::Sync { setup, push, pull, status, all, workspace } => {
|
|
if setup {
|
|
sync::setup(workspace)?;
|
|
} else if status {
|
|
sync::status(workspace, all)?;
|
|
} else {
|
|
let mode = if push {
|
|
onyx_core::sync::SyncMode::Push
|
|
} else if pull {
|
|
onyx_core::sync::SyncMode::Pull
|
|
} else {
|
|
onyx_core::sync::SyncMode::Full
|
|
};
|
|
sync::execute(mode, workspace)?;
|
|
}
|
|
},
|
|
}
|
|
|
|
Ok(())
|
|
}
|