From 25c7c494fdd88156f178d27d2129e5f3938633fd Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 4 Nov 2025 15:53:48 +0000 Subject: [PATCH 1/2] Add support for multiple named workspaces Updates the project plan to support multiple independent task workspaces, allowing users to maintain separate task folders for different contexts (e.g., personal vs shared/collaborative). Key changes: Data Model: - AppConfig now contains HashMap of named WorkspaceConfig - WorkspaceConfig holds path and WebDAV settings per workspace - current_workspace field tracks active workspace CLI Features: - `init` command now creates named workspace - New workspace management commands: - workspace add: Add additional workspaces - workspace list: View all workspaces - workspace switch: Change current workspace - workspace remove: Delete workspace - All commands support --workspace flag for explicit targeting - Commands use current workspace by default Phase 2 (WebDAV): - Per-workspace WebDAV configuration - Each workspace can sync to different WebDAV server - Sync commands are workspace-aware - Status command shows per-workspace or all workspaces Phase 3 (GUI): - Workspace selector dropdown in toolbar - Quick-switch between workspaces UI - Workspace setup dialog on first launch - Settings panel for workspace management - Per-workspace last opened list tracking Benefits: - Separate personal and shared/collaborative task folders - Different sync configurations per workspace - Better organization for different contexts - Flexible folder locations (local, Dropbox, etc.) --- PLAN.md | 179 ++++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 135 insertions(+), 44 deletions(-) diff --git a/PLAN.md b/PLAN.md index 38a1c4e..372d2db 100644 --- a/PLAN.md +++ b/PLAN.md @@ -8,10 +8,11 @@ A **local-first, cross-platform tasks application** inspired by Google Tasks. Bu - **Local-First**: Your data, your folder, your control - **Fast**: Sub-second startup, instant response - **Cross-Platform**: Single codebase, all platforms +- **Flexible**: Multiple workspaces for different contexts (personal, shared, work, etc.) **Data Format**: Tasks stored as markdown files with YAML frontmatter (Obsidian-compatible) -**Storage**: User selects folder location (e.g., `~/Documents/Tasks`, `~/Dropbox/Tasks`) -**Sync**: Optional WebDAV for cross-device synchronization +**Storage**: User selects folder location for each workspace (e.g., `~/Documents/Tasks`, `~/Dropbox/TeamTasks`) +**Sync**: Optional per-workspace WebDAV for cross-device synchronization **Architecture**: Backend/frontend separation with CLI-first development --- @@ -108,7 +109,12 @@ enum SortOrder { } AppConfig { - local_path: PathBuf, + workspaces: HashMap, + current_workspace: Option, +} + +WorkspaceConfig { + path: PathBuf, } ``` @@ -157,11 +163,25 @@ AppConfig { When `sort_order` is `"manual"`, the `task_order` array defines the sequence. When `sort_order` is `"by_due_date"`, tasks are grouped first and then sorted within each group by `task_order`. -**App Configuration** (separate from task data): +**App Configuration** (separate from task data, supports multiple workspaces): - Windows: `%APPDATA%/bevy-tasks/config.json` - Linux: `~/.config/bevy-tasks/config.json` - macOS: `~/Library/Application Support/bevy-tasks/config.json` +```json +{ + "workspaces": { + "personal": { + "path": "/home/user/Documents/Tasks" + }, + "shared": { + "path": "/home/user/Dropbox/TeamTasks" + } + }, + "current_workspace": "personal" +} +``` + #### Core Library API ```rust @@ -265,11 +285,16 @@ tokio = { workspace = true } ### Features - [ ] Cargo workspace setup -- [ ] Data models (Task, TaskList, AppConfig) +- [ ] Data models (Task, TaskList, AppConfig, WorkspaceConfig) - [ ] Markdown file I/O with YAML frontmatter parsing - [ ] Local storage implementation - [ ] Repository pattern and public API -- [ ] CLI: `init` command (user selects folder) +- [ ] Multiple workspace support +- [ ] CLI: `init` command (create named workspace) +- [ ] CLI: `workspace add` command (add additional workspaces) +- [ ] CLI: `workspace list` command (view all workspaces) +- [ ] CLI: `workspace switch` command (change current workspace) +- [ ] CLI: `workspace remove` command (delete workspace) - [ ] CLI: `add` command (create tasks) - [ ] CLI: `list` command (view tasks) - [ ] CLI: `complete` command (mark done) @@ -277,30 +302,45 @@ tokio = { workspace = true } - [ ] CLI: `edit` command (modify tasks) - [ ] Two sort modes: manual ordering and by due date - [ ] CLI: `sort` command (switch between manual/by-due-date) +- [ ] Support for `--workspace` flag on all commands - [ ] Comprehensive unit and integration tests (>80% coverage) ### CLI Usage Examples ```bash -# First run: initialize tasks folder -$ bevy-tasks init ~/Documents/Tasks -✓ Initialized tasks folder at ~/Documents/Tasks +# First run: initialize a workspace (creates named workspace) +$ bevy-tasks init ~/Documents/Tasks --name personal +✓ Initialized workspace "personal" at ~/Documents/Tasks +✓ Created default list "My Tasks" +✓ Set "personal" as current workspace + +# Add more workspaces (e.g., for shared/collaborative tasks) +$ bevy-tasks workspace add shared ~/Dropbox/TeamTasks +✓ Added workspace "shared" at ~/Dropbox/TeamTasks ✓ Created default list "My Tasks" -# Or use a cloud-synced folder -$ bevy-tasks init ~/Dropbox/Tasks -✓ Initialized tasks folder at ~/Dropbox/Tasks -✓ Created default list "My Tasks" +# List all workspaces +$ bevy-tasks workspace list + personal: ~/Documents/Tasks (current) + shared: ~/Dropbox/TeamTasks -# Add tasks -$ bevy-tasks add "Buy groceries" --list "Personal" +# Switch between workspaces +$ bevy-tasks workspace switch shared +✓ Switched to workspace "shared" + +# Add tasks (uses current workspace by default) +$ bevy-tasks add "Buy groceries" ✓ Created task "Buy groceries" (550e8400-e29b-41d4-a716-446655440000) $ bevy-tasks add "Review PR #123" --list "Work" --due "2025-11-15" ✓ Created task "Review PR #123" (7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c) Due: 2025-11-15 -# List all tasks +# Or specify workspace explicitly +$ bevy-tasks add "Team meeting" --workspace shared +✓ Created task "Team meeting" in workspace "shared" + +# List all tasks (from current workspace) $ bevy-tasks list My Tasks (3 tasks) [ ] Buy groceries @@ -311,6 +351,12 @@ Work (2 tasks) [ ] Review PR #123 (due: 2025-11-15) [ ] Team meeting prep +# List tasks from specific workspace +$ bevy-tasks list --workspace shared +Shared Tasks (2 tasks) + [ ] Team meeting + [ ] Quarterly planning + # List tasks in specific list $ bevy-tasks list --list "Work" Work (2 tasks) @@ -321,7 +367,7 @@ Work (2 tasks) $ bevy-tasks complete 550e8400-e29b-41d4-a716-446655440000 ✓ Completed task "Buy groceries" -# Edit a task +# Edit a task (opens in $EDITOR) $ bevy-tasks edit 7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c # Opens editor with task file ✓ Updated task "Review PR #123" @@ -330,10 +376,11 @@ $ bevy-tasks edit 7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c $ bevy-tasks delete 550e8400-e29b-41d4-a716-446655440000 ✓ Deleted task "Buy groceries" -# Change folder location later -$ bevy-tasks config set-folder ~/new/location -✓ Updated tasks folder location to ~/new/location -✓ Migrated 15 tasks from ~/Documents/Tasks +# Remove a workspace +$ bevy-tasks workspace remove shared +⚠ Warning: This will delete all tasks in workspace "shared" +Continue? (y/n): y +✓ Removed workspace "shared" # Sort order $ bevy-tasks sort manual --list "Work" @@ -363,9 +410,10 @@ cargo build cargo test -p bevy-tasks-core # Run CLI -cargo run -p bevy-tasks-cli -- init ~/test-tasks +cargo run -p bevy-tasks-cli -- init ~/test-tasks --name test cargo run -p bevy-tasks-cli -- add "Test task" cargo run -p bevy-tasks-cli -- list +cargo run -p bevy-tasks-cli -- workspace list ``` --- @@ -381,13 +429,17 @@ cargo run -p bevy-tasks-cli -- list Add WebDAV support to `bevy-tasks-core`: ```rust -// Update AppConfig -AppConfig { - local_path: PathBuf, // User-selected tasks folder (required) +// Update WorkspaceConfig to include WebDAV +WorkspaceConfig { + path: PathBuf, webdav_url: Option, - webdav_credentials: Option, last_sync: Option, - // Note: list_order and last_opened_list in .metadata.json at root of tasks folder +} + +// AppConfig remains the same (workspaces + current_workspace) +AppConfig { + workspaces: HashMap, + current_workspace: Option, } // Add sync methods to TaskRepository @@ -437,17 +489,25 @@ keyring = "3.0" ### CLI Usage Examples ```bash -# Setup WebDAV +# Setup WebDAV for current workspace $ bevy-tasks sync --setup WebDAV URL: https://nextcloud.example.com/remote.php/dav/files/username/Tasks Username: myuser Password: ******** ✓ WebDAV credentials saved to system keychain -✓ Connection verified +✓ Connection verified for workspace "personal" -# Push local changes to WebDAV server +# Setup WebDAV for specific workspace +$ bevy-tasks sync --setup --workspace shared +WebDAV URL: https://nextcloud.example.com/remote.php/dav/files/username/SharedTasks +Username: myuser +Password: ******** +✓ WebDAV credentials saved to system keychain +✓ Connection verified for workspace "shared" + +# Push local changes to WebDAV server (current workspace) $ bevy-tasks sync --push -Syncing to https://nextcloud.example.com/... +Syncing workspace "personal" to https://nextcloud.example.com/... Uploading My Tasks/.listdata.json Uploading My Tasks/Buy groceries.md Uploading Work/Review PR #123.md @@ -455,26 +515,44 @@ Syncing to https://nextcloud.example.com/... # Pull changes from WebDAV server $ bevy-tasks sync --pull -Syncing from https://nextcloud.example.com/... +Syncing workspace "personal" from https://nextcloud.example.com/... Downloading Work/Team meeting notes.md Downloading Personal/Call mom.md ✓ Pulled 2 files from WebDAV server # Automatic two-way sync $ bevy-tasks sync -Syncing with https://nextcloud.example.com/... +Syncing workspace "personal" with https://nextcloud.example.com/... ↑ Uploading My Tasks/New task.md ↓ Downloading Work/Updated task.md = No changes for 15 files ✓ Sync complete -# Check sync status +# Sync specific workspace +$ bevy-tasks sync --workspace shared +Syncing workspace "shared" with https://nextcloud.example.com/... +✓ Sync complete (no changes) + +# Check sync status for current workspace $ bevy-tasks sync --status +Workspace: personal WebDAV Server: https://nextcloud.example.com/remote.php/dav/files/username/Tasks Status: Connected Last sync: 2025-10-27 14:32:15 Local changes: 2 files modified Remote changes: 0 files modified + +# Check sync status for all workspaces +$ bevy-tasks sync --status --all +Workspace: personal + WebDAV: https://nextcloud.example.com/.../Tasks + Status: Connected + Last sync: 2025-10-27 14:32:15 + +Workspace: shared + WebDAV: https://nextcloud.example.com/.../SharedTasks + Status: Connected + Last sync: 2025-10-27 14:28:42 ``` ### Deliverables @@ -532,23 +610,34 @@ crates/bevy-tasks-gui/ ``` #### First Run Experience -- Show folder picker dialog on first launch +- Show workspace setup dialog on first launch +- User creates first workspace with name and folder location - User selects where to store tasks (e.g., `~/Documents/Tasks`) - No default hidden directories -- Remember choice in app config +- Remember workspaces in app config + +#### Workspace UI Elements +- Workspace selector dropdown in toolbar +- Quick-switch between workspaces +- Visual indicator of current workspace +- Settings panel to manage workspaces (add/remove/configure) #### App Configuration (Phase 3+) **Update AppConfig** to include UI preferences: ```rust AppConfig { - local_path: PathBuf, // From Phase 1 - webdav_url: Option, // From Phase 2 - webdav_credentials: Option, - last_sync: Option, + workspaces: HashMap, // From Phase 1 + current_workspace: Option, theme: Theme, // NEW: light/dark mode window_size: Option<(u32, u32)>, // NEW: remember window size - last_opened_list: Option, // NEW: restore last view + last_opened_list_per_workspace: HashMap, // NEW: per-workspace last view +} + +WorkspaceConfig { + path: PathBuf, + webdav_url: Option, // From Phase 2 + last_sync: Option, } ``` @@ -591,14 +680,16 @@ egui = "0.31" # Core egui library ### Features - [ ] egui framework integration -- [ ] Folder picker dialog on first launch +- [ ] Workspace setup dialog on first launch +- [ ] Workspace selector in toolbar +- [ ] Quick-switch between workspaces - [ ] Basic task list view - [ ] Create new tasks - [ ] Edit existing tasks - [ ] Delete tasks - [ ] Mark tasks complete/incomplete -- [ ] Settings screen (change folder, WebDAV config) -- [ ] Sync status indicators +- [ ] Settings screen (manage workspaces, WebDAV config) +- [ ] Sync status indicators (per workspace) - [ ] Desktop support (Windows, Linux, macOS) ### Deliverables From 7a9faea2875fa9299e43aa0da2b5e00b452892f4 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 4 Nov 2025 16:19:39 +0000 Subject: [PATCH 2/2] Simplify task ordering and add workspace management commands MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Changes task ordering model: - Remove SortOrder enum (Manual/ByDueDate) - Replace with simple group_by_due_date boolean - Tasks always use manual ordering via task_order array - Grouping by due date is optional view toggle Data model changes: - TaskList.sort_order → TaskList.group_by_due_date: bool - .listdata.json: "sort_order" → "group_by_due_date": false - API: set_sort_order() → set_group_by_due_date() - CLI: sort command → group enable/disable command Benefits: - Simpler mental model: always manual order, optional grouping - Less complex to implement and reason about - User always has ordering control via task_order - Grouping is just a view option Add workspace path management: - workspace retarget: Update path in config (files already moved) Use when files moved externally or different mount point - workspace migrate: Move files AND update config Use to relocate workspace to new folder Clarify edit command behavior: - Added note that edit is CLI-only (not mobile/GUI) - Explains: creates temp file, opens $EDITOR, blocks, parses - GUI/mobile use get_task() + update_task() directly workspace remove behavior: - Only removes from config, files remain on disk - User responsible for deleting files if desired --- PLAN.md | 66 ++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 27 deletions(-) diff --git a/PLAN.md b/PLAN.md index 372d2db..a8c3b34 100644 --- a/PLAN.md +++ b/PLAN.md @@ -97,15 +97,10 @@ enum TaskStatus { TaskList { id: Uuid, title: String, // Derived from folder name - tasks: Vec, // Ordered according to sort_order preference + tasks: Vec, // Ordered by task_order, optionally grouped by due date created_at: DateTime, updated_at: DateTime, - sort_order: SortOrder, // How to sort: Manual or ByDueDate -} - -enum SortOrder { - Manual, // Use task_order from .listdata.json - ByDueDate, // Group by due_date, then sort by task_order within groups + group_by_due_date: bool, // If true, group by due date before applying task_order } AppConfig { @@ -148,7 +143,7 @@ WorkspaceConfig { "id": "list-uuid-1", "created_at": "2025-10-26T10:00:00Z", "updated_at": "2025-10-27T14:30:00Z", - "sort_order": "manual", + "group_by_due_date": false, "task_order": [ "task-uuid-1", "task-uuid-2", @@ -157,11 +152,10 @@ WorkspaceConfig { } ``` -**Sort Order Options**: -- `"manual"` - Tasks ordered by hand (uses `task_order` array) -- `"by_due_date"` - Tasks automatically sorted by due date (tasks without due dates appear at end) - -When `sort_order` is `"manual"`, the `task_order` array defines the sequence. When `sort_order` is `"by_due_date"`, tasks are grouped first and then sorted within each group by `task_order`. +**Task Ordering**: +- Tasks are always ordered according to the `task_order` array (manual ordering) +- When `group_by_due_date` is `true`, tasks are first grouped by their due date, then sorted within each group by `task_order` +- Tasks without due dates appear at the end when grouping is enabled **App Configuration** (separate from task data, supports multiple workspaces): - Windows: `%APPDATA%/bevy-tasks/config.json` @@ -209,9 +203,9 @@ impl TaskRepository { pub fn reorder_task(&mut self, list_id: Uuid, task_id: Uuid, new_position: usize) -> Result<()>; pub fn get_task_order(&self, list_id: Uuid) -> Result>; - // Sort preference (modifies .listdata.json) - pub fn set_sort_order(&mut self, list_id: Uuid, sort_order: SortOrder) -> Result<()>; - pub fn get_sort_order(&self, list_id: Uuid) -> Result; + // Grouping preference (modifies .listdata.json) + pub fn set_group_by_due_date(&mut self, list_id: Uuid, enabled: bool) -> Result<()>; + pub fn get_group_by_due_date(&self, list_id: Uuid) -> Result; } pub trait Storage { @@ -295,13 +289,15 @@ tokio = { workspace = true } - [ ] CLI: `workspace list` command (view all workspaces) - [ ] CLI: `workspace switch` command (change current workspace) - [ ] CLI: `workspace remove` command (delete workspace) +- [ ] CLI: `workspace retarget` command (update workspace path without moving files) +- [ ] CLI: `workspace migrate` command (move files to new location) - [ ] CLI: `add` command (create tasks) - [ ] CLI: `list` command (view tasks) - [ ] CLI: `complete` command (mark done) - [ ] CLI: `delete` command (remove tasks) -- [ ] CLI: `edit` command (modify tasks) -- [ ] Two sort modes: manual ordering and by due date -- [ ] CLI: `sort` command (switch between manual/by-due-date) +- [ ] CLI: `edit` command (modify tasks - CLI only, creates temp file) +- [ ] Manual task ordering (always via task_order array) +- [ ] CLI: `group` command (toggle group-by-due-date for a list) - [ ] Support for `--workspace` flag on all commands - [ ] Comprehensive unit and integration tests (>80% coverage) @@ -367,27 +363,43 @@ Work (2 tasks) $ bevy-tasks complete 550e8400-e29b-41d4-a716-446655440000 ✓ Completed task "Buy groceries" -# Edit a task (opens in $EDITOR) +# Edit a task (CLI-only: creates temp file, opens $EDITOR, blocks until editor exits, then parses) $ bevy-tasks edit 7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c -# Opens editor with task file +# Opens editor with task markdown file +# User edits and saves, then exits editor ✓ Updated task "Review PR #123" # Delete a task $ bevy-tasks delete 550e8400-e29b-41d4-a716-446655440000 ✓ Deleted task "Buy groceries" +# Retarget workspace (files already at new location, just update config) +$ bevy-tasks workspace retarget personal ~/new/path/to/Tasks +✓ Workspace "personal" now points to ~/new/path/to/Tasks + +# Migrate workspace (move files to new location) +$ bevy-tasks workspace migrate personal ~/Dropbox/Tasks +⚠ This will move all files from ~/Documents/Tasks to ~/Dropbox/Tasks +Continue? (y/n): y +Moving files... + Moved .metadata.json + Moved My Tasks/ (15 files) + Moved Work/ (8 files) +✓ Migrated 23 files to ~/Dropbox/Tasks +✓ Workspace "personal" now points to ~/Dropbox/Tasks + # Remove a workspace $ bevy-tasks workspace remove shared -⚠ Warning: This will delete all tasks in workspace "shared" +⚠ Warning: This will delete workspace config (files remain on disk) Continue? (y/n): y ✓ Removed workspace "shared" -# Sort order -$ bevy-tasks sort manual --list "Work" -✓ Set sort order to "manual" for list "Work" +# Toggle grouping by due date (tasks always use manual task_order within groups) +$ bevy-tasks group enable --list "Work" +✓ Enabled group-by-due-date for list "Work" -$ bevy-tasks sort by-due-date --list "Personal" -✓ Set sort order to "by due date" for list "Personal" +$ bevy-tasks group disable --list "Personal" +✓ Disabled group-by-due-date for list "Personal" ``` ### Deliverables