Coverage for src / lexigram / admin / contributors / core.py: 60%

48 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-13 22:14 +0800

1"""Core admin contributor — built-in dashboard surfaces.""" 

2 

3from __future__ import annotations 

4 

5from collections.abc import Sequence 

6from typing import TYPE_CHECKING, cast 

7 

8from lexigram.admin.dashboard.chart_widget import ChartWidget 

9from lexigram.contracts.admin.contributor import BaseAdminContributor 

10from lexigram.contracts.admin.errors import AdminError, WidgetNotFoundError 

11from lexigram.contracts.admin.types import ( 

12 AdminHealthDefinition, 

13 DashboardWidgetDefinition, 

14 NavigationContribution, 

15 WidgetCategory, 

16 WidgetParams, 

17 WidgetSize, 

18 WidgetViewModel, 

19) 

20from lexigram.contracts.core.result import Result 

21from lexigram.result import Err, Ok 

22from lexigram.ui import ChartConfig, ChartDataPoint, ChartType 

23 

24if TYPE_CHECKING: 

25 from lexigram.contracts.core.di import ContainerResolverProtocol 

26 

27 

28class CoreAdminContributor(BaseAdminContributor): 

29 """Built-in contributor providing core dashboard surfaces. 

30 

31 Provides the framework health overview widget, the main dashboard 

32 navigation entry, and the system-wide health check surface. 

33 """ 

34 

35 name = "core" 

36 display_name = "Core" 

37 group = "system" 

38 icon = "layout-dashboard" 

39 priority = 0 

40 

41 def __init__(self) -> None: 

42 self._container: ContainerResolverProtocol | None = None 

43 

44 async def on_admin_boot(self, container: object) -> None: 

45 self._container = container # type: ignore[assignment] 

46 

47 def get_dashboard_widgets(self) -> Sequence[DashboardWidgetDefinition]: 

48 """Return core dashboard widgets: health overview, recent activity, and metrics.""" 

49 return [ 

50 DashboardWidgetDefinition( 

51 name="health", 

52 title="Framework Health", 

53 contributor="core", 

54 render_endpoint="/admin/core/widgets/health", 

55 size=WidgetSize.FULL, 

56 category=WidgetCategory.HEALTH, 

57 refresh_interval_seconds=10, 

58 order=0, 

59 icon="heart-pulse", 

60 description="Aggregated health status of all framework providers.", 

61 ), 

62 DashboardWidgetDefinition( 

63 name="activity", 

64 title="Recent Activity", 

65 contributor="core", 

66 render_endpoint="/admin/core/widgets/activity", 

67 size=WidgetSize.LARGE, 

68 category=WidgetCategory.ACTIVITY, 

69 refresh_interval_seconds=15, 

70 order=90, 

71 icon="activity", 

72 description="Recent admin operations and system events.", 

73 ), 

74 DashboardWidgetDefinition( 

75 name="chart_metrics", 

76 title="Framework Metrics", 

77 contributor="core", 

78 render_endpoint="/admin/core/widgets/chart_metrics", 

79 size=WidgetSize.FULL, 

80 category=WidgetCategory.METRICS, 

81 refresh_interval_seconds=30, 

82 order=50, 

83 icon="bar-chart-3", 

84 description="Key framework performance metrics visualized.", 

85 ), 

86 ] 

87 

88 def get_navigation_items(self) -> Sequence[NavigationContribution]: 

89 """Return core navigation: Dashboard link.""" 

90 return [ 

91 NavigationContribution( 

92 label="Dashboard", 

93 url="/admin/", 

94 icon="layout-dashboard", 

95 group="", 

96 order=0, 

97 ), 

98 ] 

99 

100 def get_health_definitions(self) -> Sequence[AdminHealthDefinition]: 

101 """Return core health definitions.""" 

102 return [ 

103 AdminHealthDefinition( 

104 name="admin_core", 

105 contributor="core", 

106 component="Admin Core", 

107 check_endpoint="/admin/core/health/admin_core", 

108 icon="shield-check", 

109 description="Admin panel core services health.", 

110 ), 

111 ] 

112 

113 async def render_widget( 

114 self, 

115 widget_name: str, 

116 params: WidgetParams, 

117 resolver: ContainerResolverProtocol | None = None, 

118 ) -> Result[WidgetViewModel, AdminError]: 

119 """Render core widgets. 

120 

121 Args: 

122 widget_name: Name of the widget to render. 

123 params: Widget parameters. 

124 

125 Returns: 

126 Result containing a WidgetViewModel with rendered HTML in ``body``, 

127 or WidgetNotFoundError if the widget is not found. 

128 """ 

129 

130 if widget_name == "health": 

131 return cast( 

132 "Result[WidgetViewModel, AdminError]", 

133 Ok(WidgetViewModel(body=self._render_health_widget())), 

134 ) 

135 if widget_name == "activity": 

136 return cast( 

137 "Result[WidgetViewModel, AdminError]", 

138 Ok(WidgetViewModel(body=self._render_activity_widget())), 

139 ) 

140 if widget_name == "chart_metrics": 

141 return cast( 

142 "Result[WidgetViewModel, AdminError]", 

143 Ok(WidgetViewModel(body=self._render_chart_metrics_widget())), 

144 ) 

145 result: Result[WidgetViewModel, AdminError] = cast( 

146 "Result[WidgetViewModel, AdminError]", 

147 Err(WidgetNotFoundError(self.name, widget_name)), 

148 ) 

149 return result 

150 

151 def _render_health_widget(self) -> str: 

152 """Render the framework health widget.""" 

153 return '<div class="widget framework-health"><div class="status healthy"><span class="indicator"></span>Healthy</div></div>' 

154 

155 def _render_activity_widget(self) -> str: 

156 """Render the recent activity widget.""" 

157 return '<div class="widget recent-activity"><ul class="activity-list"><li class="activity-item">No recent activity</li></ul></div>' 

158 

159 def _render_chart_metrics_widget(self) -> str: 

160 """Render the framework metrics bar chart widget.""" 

161 data = [ 

162 ChartDataPoint(label="Active Users", value=847, color="blue"), 

163 ChartDataPoint(label="Requests/min", value=2341, color="green"), 

164 ChartDataPoint(label="Error Rate", value=1.2, color="red"), 

165 ChartDataPoint(label="Avg Latency", value=45, color="amber"), 

166 ChartDataPoint(label="Memory %", value=68, color="purple"), 

167 ] 

168 chart = ChartWidget( 

169 title="Framework Metrics", 

170 chart_type=ChartType.BAR, 

171 data=data, 

172 chart_config=ChartConfig( 

173 show_grid=True, 

174 show_labels=True, 

175 animate=True, 

176 height="200px", 

177 ), 

178 refresh_interval=30, 

179 col_span=1, 

180 ) 

181 return str(chart) 

182 

183 async def render_health_check( 

184 self, 

185 check_name: str, 

186 ) -> Result[str, AdminError]: 

187 """Render health check for admin core. 

188 

189 Args: 

190 check_name: Name of the health check. 

191 

192 Returns: 

193 Result with rendered HTML or error. 

194 """ 

195 if check_name == "admin_core": 

196 return cast( 

197 "Result[str, AdminError]", 

198 Ok( 

199 '<div class="health-check admin-core"><span class="status healthy">Admin Core Operational</span></div>' 

200 ), 

201 ) 

202 return cast( 

203 "Result[str, AdminError]", 

204 Err(AdminError(f"Unknown health check: {check_name}")), 

205 ) 

206 

207 

208__all__ = ["CoreAdminContributor"]