@@ -6,7 +6,7 @@ use std::io;
66use std:: path:: Path ;
77use std:: time:: Duration ;
88
9- use lash_db:: repository:: { FileRepository , TaskRepository } ;
9+ use lash_db:: repository:: { FileRepository , LabelRepository , TaskRepository } ;
1010
1111use crate :: error:: { TuiError , TuiResult } ;
1212use crate :: event:: { poll_event, AppEvent } ;
@@ -73,6 +73,12 @@ impl TuiApp {
7373 . map_err ( |e| TuiError :: App ( format ! ( "Failed to load tasks: {e}" ) ) ) ?;
7474 }
7575
76+ // Load labels with stats
77+ let label_repo = LabelRepository :: new ( & conn) ;
78+ state. labels = label_repo
79+ . get_label_stats ( )
80+ . map_err ( |e| TuiError :: App ( format ! ( "Failed to load labels: {e}" ) ) ) ?;
81+
7682 Ok ( Self {
7783 terminal,
7884 conn,
@@ -138,12 +144,13 @@ impl TuiApp {
138144 AppEvent :: ExpandAll => self . handle_expand_all ( ) ,
139145 AppEvent :: CollapseAll => self . handle_collapse_all ( ) ,
140146
147+ AppEvent :: LabelFilter => self . handle_label_toggle ( ) ?,
148+ AppEvent :: ClearFilters => self . state . clear_label_filter ( ) ,
149+
141150 // TODO: implement these features
142151 AppEvent :: ExpandNode
143152 | AppEvent :: CollapseNode
144- | AppEvent :: ClearFilters
145153 | AppEvent :: Search
146- | AppEvent :: LabelFilter
147154 | AppEvent :: DependencyGraph
148155 | AppEvent :: PrevTask
149156 | AppEvent :: NextTask
@@ -163,35 +170,47 @@ impl TuiApp {
163170
164171 /// Handle selection/enter in current pane
165172 fn handle_select ( & mut self ) -> TuiResult < ( ) > {
173+ use crate :: state:: { FocusedPane , NavMode } ;
174+
166175 match self . state . focused_pane {
167- crate :: state:: FocusedPane :: Navigation => {
168- // Check if tree view is active and get selected node info
169- if let Some ( selected) = self . state . selected_tree_node ( ) {
170- if selected. is_directory {
171- // Toggle expand/collapse for directories
172- self . state . toggle_selected_node ( ) ;
173- } else if let Some ( file) = selected. file_record {
174- // Load tasks for file and switch to detail pane
175- let task_repo = TaskRepository :: new ( & self . conn ) ;
176- self . state . tasks = task_repo
177- . get_by_file ( file. id )
178- . map_err ( |e| TuiError :: App ( format ! ( "Failed to load tasks: {e}" ) ) ) ?;
179- self . state . selected_task_index = 0 ;
180- self . state . switch_pane ( ) ;
176+ FocusedPane :: Navigation => {
177+ match self . state . nav_mode {
178+ NavMode :: Files | NavMode :: SearchResults => {
179+ // Check if tree view is active and get selected node info
180+ if let Some ( selected) = self . state . selected_tree_node ( ) {
181+ if selected. is_directory {
182+ // Toggle expand/collapse for directories
183+ self . state . toggle_selected_node ( ) ;
184+ } else if let Some ( file) = selected. file_record {
185+ // Load tasks for file and switch to detail pane
186+ let task_repo = TaskRepository :: new ( & self . conn ) ;
187+ self . state . tasks = task_repo. get_by_file ( file. id ) . map_err ( |e| {
188+ TuiError :: App ( format ! ( "Failed to load tasks: {e}" ) )
189+ } ) ?;
190+ self . state . selected_task_index = 0 ;
191+ self . state . build_task_tree ( ) ;
192+ self . state . switch_pane ( ) ;
193+ }
194+ } else {
195+ // Fallback for flat view: load tasks for selected file
196+ if let Some ( file) = self . state . selected_file ( ) {
197+ let task_repo = TaskRepository :: new ( & self . conn ) ;
198+ self . state . tasks = task_repo. get_by_file ( file. id ) . map_err ( |e| {
199+ TuiError :: App ( format ! ( "Failed to load tasks: {e}" ) )
200+ } ) ?;
201+ self . state . selected_task_index = 0 ;
202+ self . state . build_task_tree ( ) ;
203+ self . state . switch_pane ( ) ;
204+ }
205+ }
181206 }
182- } else {
183- // Fallback for flat view: load tasks for selected file
184- if let Some ( file) = self . state . selected_file ( ) {
185- let task_repo = TaskRepository :: new ( & self . conn ) ;
186- self . state . tasks = task_repo
187- . get_by_file ( file. id )
188- . map_err ( |e| TuiError :: App ( format ! ( "Failed to load tasks: {e}" ) ) ) ?;
189- self . state . selected_task_index = 0 ;
190- self . state . switch_pane ( ) ;
207+ NavMode :: Labels => {
208+ // Select a label and filter tasks
209+ self . handle_label_select ( ) ?;
191210 }
192211 }
193212 }
194- crate :: state :: FocusedPane :: Detail => {
213+ FocusedPane :: Detail => {
195214 // Enter on detail pane shows task details
196215 // TODO: Implement task detail view
197216 }
@@ -329,6 +348,43 @@ impl TuiApp {
329348 }
330349 }
331350 }
351+
352+ /// Handle toggling between files and labels view
353+ fn handle_label_toggle ( & mut self ) -> TuiResult < ( ) > {
354+ // Reload labels to ensure we have latest stats
355+ let label_repo = LabelRepository :: new ( & self . conn ) ;
356+ self . state . labels = label_repo
357+ . get_label_stats ( )
358+ . map_err ( |e| TuiError :: App ( format ! ( "Failed to load labels: {e}" ) ) ) ?;
359+
360+ self . state . toggle_nav_mode ( ) ;
361+ Ok ( ( ) )
362+ }
363+
364+ /// Handle selecting a label to filter tasks
365+ fn handle_label_select ( & mut self ) -> TuiResult < ( ) > {
366+ let Some ( label) = self . state . selected_label ( ) else {
367+ return Ok ( ( ) ) ;
368+ } ;
369+
370+ let label_name = label. name . clone ( ) ;
371+
372+ // Load tasks with this label
373+ let task_repo = TaskRepository :: new ( & self . conn ) ;
374+ self . state . tasks = task_repo
375+ . find_by_label ( & label_name)
376+ . map_err ( |e| TuiError :: App ( format ! ( "Failed to load tasks for label: {e}" ) ) ) ?;
377+
378+ // Set current filter and reset selection
379+ self . state . current_label_filter = Some ( label_name) ;
380+ self . state . selected_task_index = 0 ;
381+ self . state . build_task_tree ( ) ;
382+
383+ // Switch to detail pane to show filtered tasks
384+ self . state . focused_pane = crate :: state:: FocusedPane :: Detail ;
385+
386+ Ok ( ( ) )
387+ }
332388}
333389
334390impl Drop for TuiApp {
0 commit comments