Coverage for src/lexigram/admin/ui/molecules/debug_panel.py: 28%

18 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-24 23:31 +0800

1"""Debug Panel molecule for Lexigram Admin.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING, Any 

6 

7from lexigram.di.decorators import inject 

8from lexigram.ui import Component, el 

9 

10if TYPE_CHECKING: 

11 from lexigram.admin.services.htmx_perf import HTMXPerformanceMonitor 

12 

13 

14@inject 

15class DebugPanel(Component): 

16 """A slide-over or collapsible panel for performance debugging.""" 

17 

18 def __init__(self, monitor: HTMXPerformanceMonitor, **props: Any) -> None: 

19 super().__init__(**props) 

20 self.monitor = monitor 

21 

22 def render(self) -> Any: 

23 stats = self.monitor.get_stats() 

24 

25 # Performance metrics 

26 metrics = [ 

27 el( 

28 "div", 

29 el("span", "Total HTMX Requests: ", class_="font-medium"), 

30 el("span", str(stats.get("total_requests", 0))), 

31 class_="mb-1", 

32 ), 

33 el( 

34 "div", 

35 el("span", "Avg Duration: ", class_="font-medium"), 

36 el("span", f"{stats.get('avg_duration_ms', 0):.1f}ms"), 

37 class_="mb-1", 

38 ), 

39 el( 

40 "div", 

41 el("span", "Max Duration: ", class_="font-medium"), 

42 el("span", f"{stats.get('max_duration_ms', 0):.1f}ms"), 

43 class_="mb-1", 

44 ), 

45 ] 

46 

47 # Slow requests list 

48 slow_list = [] 

49 if stats.get("slow_requests"): 

50 slow_list.append( 

51 el( 

52 "h4", "Slow Requests", class_="font-bold mt-4 mb-2 text-destructive" 

53 ), 

54 ) 

55 for req in stats["slow_requests"]: 

56 slow_list.append( 

57 el( 

58 "div", 

59 el( 

60 "span", 

61 f"{req['method']} {req['url']}", 

62 class_="text-xs truncate block", 

63 ), 

64 el( 

65 "span", 

66 f"{req['duration_ms']:.1f}ms", 

67 class_="text-xs font-bold", 

68 ), 

69 class_="p-2 bg-destructive/10 rounded mb-1", 

70 ), 

71 ) 

72 

73 return el( 

74 "div", 

75 el( 

76 "div", 

77 el("h3", "Lexigram Debug", class_="text-lg font-bold mb-4"), 

78 *metrics, 

79 *slow_list, 

80 el( 

81 "button", 

82 "Clear Stats", 

83 hx_post="/admin//debug/clear", 

84 class_="mt-6 w-full py-2 bg-muted hover:bg-muted rounded text-sm transition-colors text-foreground", 

85 ), 

86 class_="p-6 h-full overflow-y-auto", 

87 ), 

88 id="debug-panel", 

89 class_="fixed right-0 top-0 bottom-0 w-80 bg-card shadow-2xl border-l border-border z-50 transform transition-transform", 

90 # We assume Alpine.js is present or using simple CSS/HTMX for toggle 

91 x_data="{ open: false }", 

92 x_show="open", 

93 # Toggle logic would be handled by a button elsewhere triggering 'open' 

94 **self.props, 

95 )