Coverage for src/lexigram/admin/ui/molecules/debug_panel.py: 44%
18 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:26 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 14:26 +0800
1"""Debug Panel molecule for Lexigram Admin."""
3from __future__ import annotations
5from typing import TYPE_CHECKING, Any
7from lexigram.di.decorators import inject
8from lexigram.ui import Component, el
10if TYPE_CHECKING:
11 from lexigram.admin.services.htmx_perf import HTMXPerformanceMonitor
14@inject
15class DebugPanel(Component):
16 """A slide-over or collapsible panel for performance debugging."""
18 def __init__(self, monitor: HTMXPerformanceMonitor, **props: Any) -> None:
19 super().__init__(**props)
20 self.monitor = monitor
22 def render(self) -> Any:
23 stats = self.monitor.get_stats()
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 ]
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 )
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 )