@@ -329,20 +329,172 @@ func (m *DashboardModel) renderLogScrollContent(height int, logWidth int) []stri
329
329
" • Stream logs: kubectl logs -f pod | gonzo" ,
330
330
" • From file: gonzo < application.log" ,
331
331
"" ,
332
+ }
333
+
334
+ // Add current filters section if any are applied
335
+ filterStatus := m .buildFilterStatus ()
336
+ if len (filterStatus ) > 0 {
337
+ instructions = append (instructions , "🔍 Current filters:" )
338
+ instructions = append (instructions , filterStatus ... )
339
+ instructions = append (instructions , "" )
340
+ }
341
+
342
+ instructions = append (instructions , []string {
332
343
"📋 Key commands:" ,
333
344
" • ?/h: Show help" ,
334
345
" • /: Filter logs (regex)" ,
346
+ " • Ctrl+f: Filter logs by severity" ,
335
347
" • s: Search and highlight" ,
336
348
" • Tab: Navigate sections" ,
337
349
" • q: Quit" ,
350
+ }... )
351
+
352
+ // Handle scrolling for instructions if they exceed available height
353
+ availableLines := height - 1 // Reserve space for status line that's already added
354
+ if availableLines < 1 {
355
+ availableLines = 1
338
356
}
339
357
340
- logLines = append (logLines , instructions ... )
358
+ if len (instructions ) > availableLines {
359
+ // Add scroll indicators and implement scrolling
360
+ maxScroll := len (instructions ) - availableLines + 1 // +1 for scroll indicator space
361
+ if m .instructionsScrollOffset > maxScroll {
362
+ m .instructionsScrollOffset = maxScroll
363
+ }
364
+ if m .instructionsScrollOffset < 0 {
365
+ m .instructionsScrollOffset = 0
366
+ }
367
+
368
+ // Add scroll up indicator if not at top
369
+ if m .instructionsScrollOffset > 0 {
370
+ scrollUpIndicator := lipgloss .NewStyle ().
371
+ Foreground (ColorGray ).
372
+ Render (fmt .Sprintf (" ↑ %d more lines above" , m .instructionsScrollOffset ))
373
+ logLines = append (logLines , scrollUpIndicator )
374
+ availableLines -- // Use one line for indicator
375
+ }
376
+
377
+ // Show visible portion of instructions
378
+ endIdx := m .instructionsScrollOffset + availableLines
379
+ if endIdx > len (instructions ) {
380
+ endIdx = len (instructions )
381
+ }
382
+
383
+ // Reserve space for bottom scroll indicator if needed
384
+ if endIdx < len (instructions ) {
385
+ availableLines -- // Reserve space for bottom indicator
386
+ endIdx = m .instructionsScrollOffset + availableLines
387
+ }
388
+
389
+ // Add visible instructions
390
+ visibleInstructions := instructions [m .instructionsScrollOffset :endIdx ]
391
+ logLines = append (logLines , visibleInstructions ... )
392
+
393
+ // Add scroll down indicator if not at bottom
394
+ if endIdx < len (instructions ) {
395
+ remaining := len (instructions ) - endIdx
396
+ scrollDownIndicator := lipgloss .NewStyle ().
397
+ Foreground (ColorGray ).
398
+ Render (fmt .Sprintf (" ↓ %d more lines below (use ↑↓ or k/j to scroll)" , remaining ))
399
+ logLines = append (logLines , scrollDownIndicator )
400
+ }
401
+ } else {
402
+ // All instructions fit, no scrolling needed
403
+ logLines = append (logLines , instructions ... )
404
+ }
341
405
}
342
406
343
407
return logLines
344
408
}
345
409
410
+ // buildFilterStatus returns a list of currently applied filters for display when no logs are shown
411
+ func (m * DashboardModel ) buildFilterStatus () []string {
412
+ var filters []string
413
+
414
+ // Check severity filter
415
+ if m .severityFilterActive {
416
+ disabledSeverities := []string {}
417
+ enabledSeverities := []string {}
418
+
419
+ severityLevels := []string {"FATAL" , "CRITICAL" , "ERROR" , "WARN" , "INFO" , "DEBUG" , "TRACE" , "UNKNOWN" }
420
+ for _ , severity := range severityLevels {
421
+ if enabled , exists := m .severityFilter [severity ]; exists {
422
+ if enabled {
423
+ enabledSeverities = append (enabledSeverities , severity )
424
+ } else {
425
+ disabledSeverities = append (disabledSeverities , severity )
426
+ }
427
+ }
428
+ }
429
+
430
+ if len (enabledSeverities ) > 0 && len (enabledSeverities ) < len (severityLevels ) {
431
+ if len (enabledSeverities ) <= 3 {
432
+ filters = append (filters , " • Severity: Only showing " + joinWithCommas (enabledSeverities ))
433
+ } else {
434
+ filters = append (filters , " • Severity: Hiding " + joinWithCommas (disabledSeverities ))
435
+ }
436
+ } else if len (enabledSeverities ) == 0 {
437
+ filters = append (filters , " • Severity: All severities disabled (no logs will show)" )
438
+ }
439
+ }
440
+
441
+ // Check regex filter
442
+ if m .filterRegex != nil {
443
+ pattern := m .filterInput .Value ()
444
+ if pattern == "" && m .filterRegex != nil {
445
+ pattern = m .filterRegex .String ()
446
+ }
447
+ if pattern != "" {
448
+ filters = append (filters , " • Regex filter: " + pattern )
449
+ }
450
+ }
451
+
452
+ // Check search term
453
+ if m .searchTerm != "" {
454
+ filters = append (filters , " • Search highlight: " + m .searchTerm )
455
+ }
456
+
457
+ // Add instructions for clearing filters if any are active
458
+ if len (filters ) > 0 {
459
+ filters = append (filters , "" )
460
+ filters = append (filters , " 💡 To clear filters:" )
461
+ if m .severityFilterActive {
462
+ filters = append (filters , " • Ctrl+F → Select All → Enter (enable all severities)" )
463
+ }
464
+ if m .filterRegex != nil {
465
+ filters = append (filters , " • / → Backspace/Delete → Enter (clear regex)" )
466
+ }
467
+ if m .searchTerm != "" {
468
+ filters = append (filters , " • s → Backspace/Delete → Enter (clear search)" )
469
+ }
470
+ }
471
+
472
+ return filters
473
+ }
474
+
475
+ // joinWithCommas joins a slice of strings with commas and "and" before the last item
476
+ func joinWithCommas (items []string ) string {
477
+ if len (items ) == 0 {
478
+ return ""
479
+ }
480
+ if len (items ) == 1 {
481
+ return items [0 ]
482
+ }
483
+ if len (items ) == 2 {
484
+ return items [0 ] + " and " + items [1 ]
485
+ }
486
+
487
+ result := ""
488
+ for i , item := range items {
489
+ if i == len (items )- 1 {
490
+ result += "and " + item
491
+ } else {
492
+ result += item + ", "
493
+ }
494
+ }
495
+ return result
496
+ }
497
+
346
498
// renderLogScroll renders the scrolling log section
347
499
func (m * DashboardModel ) renderLogScroll (height int ) string {
348
500
// Use most of terminal width for logs
0 commit comments