diff options
| author | soryu <soryu@soryu.co> | 2026-01-19 13:47:32 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-01-19 13:47:32 +0000 |
| commit | 0833fb1f30c0c3b920157deb882e0e902c3af02a (patch) | |
| tree | 45110fb8cb9277dfbaccfeb53ed9c1f76975022b /makima/src/daemon/tui/views/tasks.rs | |
| parent | 786510379bed060db2b3742b7dfca671552d2c34 (diff) | |
| download | soryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.tar.gz soryu-0833fb1f30c0c3b920157deb882e0e902c3af02a.zip | |
Add interactive TUI browser for tasks, contracts, and files (makima view) (#7)
* feat(tui): Implement fuzzy search with real-time filtering and highlighting
Adds comprehensive fuzzy search functionality to the TUI browser:
## Fuzzy Matching (fuzzy.rs)
- FuzzyMatcher wrapper using SkimMatcherV2 from fuzzy-matcher crate
- fuzzy_match() returns score and matched character indices
- fuzzy_match_all() supports multi-term search (space-separated)
- Recency-aware scoring to boost recent items in results
- Unit tests for all matching scenarios
## App State (app.rs)
- FilteredItem struct with index, score, and matched_indices
- apply_filter() uses fuzzy matching with score-based sorting
- match_count() and has_no_matches() helper methods
- Results sorted by match score (highest first)
## List View (list_view.rs)
- Highlighted matched characters in search results
- Yellow bold styling for matched chars
- Status icons with color coding
## Search Input (search_input.rs)
- Real-time match count display (X/Y matches)
- Visual feedback for no matches (red border)
- Placeholder text when search is empty
- Active search mode indication (yellow border)
## Event Handling (event.rs)
- Arrow key navigation while in search mode
- Ctrl+K/J for vim-style navigation during search
- Delete key support alongside backspace
- Ctrl+U to clear search query
- Tab toggles preview while searching
- Escape clears search and exits search mode
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Task completion checkpoint
* [WIP] Heartbeat checkpoint - 2026-01-19 11:20:34 UTC
* Task completion checkpoint
* [WIP] Heartbeat checkpoint - 2026-01-19 11:31:19 UTC
* Task completion checkpoint
* [WIP] Heartbeat checkpoint - 2026-01-19 11:39:07 UTC
* fix(tui): Fix module exports and main binary integration
- Update mod.rs to properly export app, event, fuzzy, and ui modules
- Add run() function for TUI entry point
- Fix run_view() to use ViewCommand enum instead of ViewArgs
- Fix event handling to use poll_event and handle_key_event
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
Diffstat (limited to 'makima/src/daemon/tui/views/tasks.rs')
| -rw-r--r-- | makima/src/daemon/tui/views/tasks.rs | 71 |
1 files changed, 71 insertions, 0 deletions
diff --git a/makima/src/daemon/tui/views/tasks.rs b/makima/src/daemon/tui/views/tasks.rs new file mode 100644 index 0000000..fd52b11 --- /dev/null +++ b/makima/src/daemon/tui/views/tasks.rs @@ -0,0 +1,71 @@ +//! Tasks view implementation. + +use uuid::Uuid; + +use crate::daemon::api::ApiClient; +use crate::daemon::tui::app::ListItem; + +/// Load tasks from API +pub async fn load_tasks( + client: &ApiClient, + contract_id: Option<Uuid>, +) -> Result<Vec<ListItem>, Box<dyn std::error::Error>> { + let Some(contract_id) = contract_id else { + // TODO: Implement listing all tasks across contracts + return Ok(Vec::new()); + }; + + let result = client.supervisor_tasks(contract_id).await?; + + // Parse JSON response into ListItem + let tasks: Vec<serde_json::Value> = serde_json::from_value(result.0)?; + + let items = tasks + .into_iter() + .filter_map(|t| { + let id_str = t.get("id")?.as_str()?; + let id = Uuid::parse_str(id_str).ok()?; + + Some(ListItem { + id, + name: t + .get("name") + .and_then(|v| v.as_str()) + .unwrap_or("Unnamed") + .to_string(), + status: t.get("status").and_then(|v| v.as_str()).map(String::from), + description: t + .get("progressSummary") + .and_then(|v| v.as_str()) + .map(String::from), + updated_at: t + .get("updatedAt") + .and_then(|v| v.as_str()) + .unwrap_or_default() + .to_string(), + extra: t, + }) + }) + .collect(); + + Ok(items) +} + +/// Get full task details for preview +pub async fn get_task_preview( + client: &ApiClient, + task_id: Uuid, +) -> Result<String, Box<dyn std::error::Error>> { + let result = client.supervisor_get_task(task_id).await?; + let task: serde_json::Value = result.0; + + Ok(format!( + "Name: {}\nStatus: {}\nPlan: {}\n\nProgress:\n{}", + task.get("name").and_then(|v| v.as_str()).unwrap_or("-"), + task.get("status").and_then(|v| v.as_str()).unwrap_or("-"), + task.get("plan").and_then(|v| v.as_str()).unwrap_or("-"), + task.get("progressSummary") + .and_then(|v| v.as_str()) + .unwrap_or("-"), + )) +} |
