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.)
This commit is contained in:
parent
4459b339ff
commit
25c7c494fd
179
PLAN.md
179
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
|
- **Local-First**: Your data, your folder, your control
|
||||||
- **Fast**: Sub-second startup, instant response
|
- **Fast**: Sub-second startup, instant response
|
||||||
- **Cross-Platform**: Single codebase, all platforms
|
- **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)
|
**Data Format**: Tasks stored as markdown files with YAML frontmatter (Obsidian-compatible)
|
||||||
**Storage**: User selects folder location (e.g., `~/Documents/Tasks`, `~/Dropbox/Tasks`)
|
**Storage**: User selects folder location for each workspace (e.g., `~/Documents/Tasks`, `~/Dropbox/TeamTasks`)
|
||||||
**Sync**: Optional WebDAV for cross-device synchronization
|
**Sync**: Optional per-workspace WebDAV for cross-device synchronization
|
||||||
**Architecture**: Backend/frontend separation with CLI-first development
|
**Architecture**: Backend/frontend separation with CLI-first development
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
@ -108,7 +109,12 @@ enum SortOrder {
|
||||||
}
|
}
|
||||||
|
|
||||||
AppConfig {
|
AppConfig {
|
||||||
local_path: PathBuf,
|
workspaces: HashMap<String, WorkspaceConfig>,
|
||||||
|
current_workspace: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
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`.
|
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`
|
- Windows: `%APPDATA%/bevy-tasks/config.json`
|
||||||
- Linux: `~/.config/bevy-tasks/config.json`
|
- Linux: `~/.config/bevy-tasks/config.json`
|
||||||
- macOS: `~/Library/Application Support/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
|
#### Core Library API
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
|
|
@ -265,11 +285,16 @@ tokio = { workspace = true }
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- [ ] Cargo workspace setup
|
- [ ] Cargo workspace setup
|
||||||
- [ ] Data models (Task, TaskList, AppConfig)
|
- [ ] Data models (Task, TaskList, AppConfig, WorkspaceConfig)
|
||||||
- [ ] Markdown file I/O with YAML frontmatter parsing
|
- [ ] Markdown file I/O with YAML frontmatter parsing
|
||||||
- [ ] Local storage implementation
|
- [ ] Local storage implementation
|
||||||
- [ ] Repository pattern and public API
|
- [ ] 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: `add` command (create tasks)
|
||||||
- [ ] CLI: `list` command (view tasks)
|
- [ ] CLI: `list` command (view tasks)
|
||||||
- [ ] CLI: `complete` command (mark done)
|
- [ ] CLI: `complete` command (mark done)
|
||||||
|
|
@ -277,30 +302,45 @@ tokio = { workspace = true }
|
||||||
- [ ] CLI: `edit` command (modify tasks)
|
- [ ] CLI: `edit` command (modify tasks)
|
||||||
- [ ] Two sort modes: manual ordering and by due date
|
- [ ] Two sort modes: manual ordering and by due date
|
||||||
- [ ] CLI: `sort` command (switch between manual/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)
|
- [ ] Comprehensive unit and integration tests (>80% coverage)
|
||||||
|
|
||||||
### CLI Usage Examples
|
### CLI Usage Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# First run: initialize tasks folder
|
# First run: initialize a workspace (creates named workspace)
|
||||||
$ bevy-tasks init ~/Documents/Tasks
|
$ bevy-tasks init ~/Documents/Tasks --name personal
|
||||||
✓ Initialized tasks folder at ~/Documents/Tasks
|
✓ 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"
|
✓ Created default list "My Tasks"
|
||||||
|
|
||||||
# Or use a cloud-synced folder
|
# List all workspaces
|
||||||
$ bevy-tasks init ~/Dropbox/Tasks
|
$ bevy-tasks workspace list
|
||||||
✓ Initialized tasks folder at ~/Dropbox/Tasks
|
personal: ~/Documents/Tasks (current)
|
||||||
✓ Created default list "My Tasks"
|
shared: ~/Dropbox/TeamTasks
|
||||||
|
|
||||||
# Add tasks
|
# Switch between workspaces
|
||||||
$ bevy-tasks add "Buy groceries" --list "Personal"
|
$ 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)
|
✓ Created task "Buy groceries" (550e8400-e29b-41d4-a716-446655440000)
|
||||||
|
|
||||||
$ bevy-tasks add "Review PR #123" --list "Work" --due "2025-11-15"
|
$ bevy-tasks add "Review PR #123" --list "Work" --due "2025-11-15"
|
||||||
✓ Created task "Review PR #123" (7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c)
|
✓ Created task "Review PR #123" (7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c)
|
||||||
Due: 2025-11-15
|
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
|
$ bevy-tasks list
|
||||||
My Tasks (3 tasks)
|
My Tasks (3 tasks)
|
||||||
[ ] Buy groceries
|
[ ] Buy groceries
|
||||||
|
|
@ -311,6 +351,12 @@ Work (2 tasks)
|
||||||
[ ] Review PR #123 (due: 2025-11-15)
|
[ ] Review PR #123 (due: 2025-11-15)
|
||||||
[ ] Team meeting prep
|
[ ] 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
|
# List tasks in specific list
|
||||||
$ bevy-tasks list --list "Work"
|
$ bevy-tasks list --list "Work"
|
||||||
Work (2 tasks)
|
Work (2 tasks)
|
||||||
|
|
@ -321,7 +367,7 @@ Work (2 tasks)
|
||||||
$ bevy-tasks complete 550e8400-e29b-41d4-a716-446655440000
|
$ bevy-tasks complete 550e8400-e29b-41d4-a716-446655440000
|
||||||
✓ Completed task "Buy groceries"
|
✓ Completed task "Buy groceries"
|
||||||
|
|
||||||
# Edit a task
|
# Edit a task (opens in $EDITOR)
|
||||||
$ bevy-tasks edit 7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c
|
$ bevy-tasks edit 7f3a9c21-b8d2-4e5f-9a1c-3d8e7f6a2b1c
|
||||||
# Opens editor with task file
|
# Opens editor with task file
|
||||||
✓ Updated task "Review PR #123"
|
✓ 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
|
$ bevy-tasks delete 550e8400-e29b-41d4-a716-446655440000
|
||||||
✓ Deleted task "Buy groceries"
|
✓ Deleted task "Buy groceries"
|
||||||
|
|
||||||
# Change folder location later
|
# Remove a workspace
|
||||||
$ bevy-tasks config set-folder ~/new/location
|
$ bevy-tasks workspace remove shared
|
||||||
✓ Updated tasks folder location to ~/new/location
|
⚠ Warning: This will delete all tasks in workspace "shared"
|
||||||
✓ Migrated 15 tasks from ~/Documents/Tasks
|
Continue? (y/n): y
|
||||||
|
✓ Removed workspace "shared"
|
||||||
|
|
||||||
# Sort order
|
# Sort order
|
||||||
$ bevy-tasks sort manual --list "Work"
|
$ bevy-tasks sort manual --list "Work"
|
||||||
|
|
@ -363,9 +410,10 @@ cargo build
|
||||||
cargo test -p bevy-tasks-core
|
cargo test -p bevy-tasks-core
|
||||||
|
|
||||||
# Run CLI
|
# 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 -- add "Test task"
|
||||||
cargo run -p bevy-tasks-cli -- list
|
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`:
|
Add WebDAV support to `bevy-tasks-core`:
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
// Update AppConfig
|
// Update WorkspaceConfig to include WebDAV
|
||||||
AppConfig {
|
WorkspaceConfig {
|
||||||
local_path: PathBuf, // User-selected tasks folder (required)
|
path: PathBuf,
|
||||||
webdav_url: Option<String>,
|
webdav_url: Option<String>,
|
||||||
webdav_credentials: Option<Credentials>,
|
|
||||||
last_sync: Option<DateTime>,
|
last_sync: Option<DateTime>,
|
||||||
// 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<String, WorkspaceConfig>,
|
||||||
|
current_workspace: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sync methods to TaskRepository
|
// Add sync methods to TaskRepository
|
||||||
|
|
@ -437,17 +489,25 @@ keyring = "3.0"
|
||||||
### CLI Usage Examples
|
### CLI Usage Examples
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Setup WebDAV
|
# Setup WebDAV for current workspace
|
||||||
$ bevy-tasks sync --setup
|
$ bevy-tasks sync --setup
|
||||||
WebDAV URL: https://nextcloud.example.com/remote.php/dav/files/username/Tasks
|
WebDAV URL: https://nextcloud.example.com/remote.php/dav/files/username/Tasks
|
||||||
Username: myuser
|
Username: myuser
|
||||||
Password: ********
|
Password: ********
|
||||||
✓ WebDAV credentials saved to system keychain
|
✓ 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
|
$ 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/.listdata.json
|
||||||
Uploading My Tasks/Buy groceries.md
|
Uploading My Tasks/Buy groceries.md
|
||||||
Uploading Work/Review PR #123.md
|
Uploading Work/Review PR #123.md
|
||||||
|
|
@ -455,26 +515,44 @@ Syncing to https://nextcloud.example.com/...
|
||||||
|
|
||||||
# Pull changes from WebDAV server
|
# Pull changes from WebDAV server
|
||||||
$ bevy-tasks sync --pull
|
$ 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 Work/Team meeting notes.md
|
||||||
Downloading Personal/Call mom.md
|
Downloading Personal/Call mom.md
|
||||||
✓ Pulled 2 files from WebDAV server
|
✓ Pulled 2 files from WebDAV server
|
||||||
|
|
||||||
# Automatic two-way sync
|
# Automatic two-way sync
|
||||||
$ bevy-tasks sync
|
$ bevy-tasks sync
|
||||||
Syncing with https://nextcloud.example.com/...
|
Syncing workspace "personal" with https://nextcloud.example.com/...
|
||||||
↑ Uploading My Tasks/New task.md
|
↑ Uploading My Tasks/New task.md
|
||||||
↓ Downloading Work/Updated task.md
|
↓ Downloading Work/Updated task.md
|
||||||
= No changes for 15 files
|
= No changes for 15 files
|
||||||
✓ Sync complete
|
✓ 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
|
$ bevy-tasks sync --status
|
||||||
|
Workspace: personal
|
||||||
WebDAV Server: https://nextcloud.example.com/remote.php/dav/files/username/Tasks
|
WebDAV Server: https://nextcloud.example.com/remote.php/dav/files/username/Tasks
|
||||||
Status: Connected
|
Status: Connected
|
||||||
Last sync: 2025-10-27 14:32:15
|
Last sync: 2025-10-27 14:32:15
|
||||||
Local changes: 2 files modified
|
Local changes: 2 files modified
|
||||||
Remote changes: 0 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
|
### Deliverables
|
||||||
|
|
@ -532,23 +610,34 @@ crates/bevy-tasks-gui/
|
||||||
```
|
```
|
||||||
|
|
||||||
#### First Run Experience
|
#### 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`)
|
- User selects where to store tasks (e.g., `~/Documents/Tasks`)
|
||||||
- No default hidden directories
|
- 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+)
|
#### App Configuration (Phase 3+)
|
||||||
|
|
||||||
**Update AppConfig** to include UI preferences:
|
**Update AppConfig** to include UI preferences:
|
||||||
```rust
|
```rust
|
||||||
AppConfig {
|
AppConfig {
|
||||||
local_path: PathBuf, // From Phase 1
|
workspaces: HashMap<String, WorkspaceConfig>, // From Phase 1
|
||||||
webdav_url: Option<String>, // From Phase 2
|
current_workspace: Option<String>,
|
||||||
webdav_credentials: Option<Credentials>,
|
|
||||||
last_sync: Option<DateTime>,
|
|
||||||
theme: Theme, // NEW: light/dark mode
|
theme: Theme, // NEW: light/dark mode
|
||||||
window_size: Option<(u32, u32)>, // NEW: remember window size
|
window_size: Option<(u32, u32)>, // NEW: remember window size
|
||||||
last_opened_list: Option<Uuid>, // NEW: restore last view
|
last_opened_list_per_workspace: HashMap<String, Uuid>, // NEW: per-workspace last view
|
||||||
|
}
|
||||||
|
|
||||||
|
WorkspaceConfig {
|
||||||
|
path: PathBuf,
|
||||||
|
webdav_url: Option<String>, // From Phase 2
|
||||||
|
last_sync: Option<DateTime>,
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -591,14 +680,16 @@ egui = "0.31" # Core egui library
|
||||||
### Features
|
### Features
|
||||||
|
|
||||||
- [ ] egui framework integration
|
- [ ] 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
|
- [ ] Basic task list view
|
||||||
- [ ] Create new tasks
|
- [ ] Create new tasks
|
||||||
- [ ] Edit existing tasks
|
- [ ] Edit existing tasks
|
||||||
- [ ] Delete tasks
|
- [ ] Delete tasks
|
||||||
- [ ] Mark tasks complete/incomplete
|
- [ ] Mark tasks complete/incomplete
|
||||||
- [ ] Settings screen (change folder, WebDAV config)
|
- [ ] Settings screen (manage workspaces, WebDAV config)
|
||||||
- [ ] Sync status indicators
|
- [ ] Sync status indicators (per workspace)
|
||||||
- [ ] Desktop support (Windows, Linux, macOS)
|
- [ ] Desktop support (Windows, Linux, macOS)
|
||||||
|
|
||||||
### Deliverables
|
### Deliverables
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue