Coverage for src/lexigram/admin/di/sub_providers/ui.py: 96%

27 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-21 14:56 +0800

1"""Admin UI sub-provider — rendering, component registry, forms, navigation.""" 

2 

3from __future__ import annotations 

4 

5from typing import TYPE_CHECKING 

6 

7from lexigram.contracts.core.health import HealthCheckResult, HealthStatus 

8 

9if TYPE_CHECKING: 

10 from lexigram.admin.config import AdminConfig 

11 from lexigram.contracts.core.di import ( 

12 ContainerRegistrarProtocol, 

13 ContainerResolverProtocol, 

14 ) 

15 

16 

17class AdminUISubProvider: 

18 """Manages admin UI infrastructure: rendering, components, forms, navigation. 

19 

20 Registers UI services: renderer, component registry, form renderer, navigation. 

21 """ 

22 

23 def __init__(self, config: AdminConfig, **kwargs: object) -> None: 

24 self._config = config 

25 self._kwargs = kwargs 

26 self._initialized = False 

27 

28 @property 

29 def config(self) -> AdminConfig: 

30 """Return current admin config.""" 

31 return self._config 

32 

33 async def register(self, container: ContainerRegistrarProtocol) -> None: 

34 """Register UI services: component registry, form renderer, navigation, layout.""" 

35 from lexigram.admin.layout.layout_manager import LayoutManager 

36 from lexigram.admin.navigation.assembler import NavigationAssembler 

37 from lexigram.admin.services.component_registry import ComponentRegistry 

38 from lexigram.ui import MetricsCollector 

39 

40 container.singleton(ComponentRegistry, ComponentRegistry()) 

41 

42 # Register navigation assembler (container will instantiate via DI) 

43 container.singleton(NavigationAssembler, NavigationAssembler) 

44 

45 # Pre-construct LayoutManager to avoid the container trying to resolve 

46 # LayoutType (an enum, not a registered service) as a dependency. 

47 container.singleton(LayoutManager, LayoutManager()) 

48 

49 container.singleton(MetricsCollector, MetricsCollector) 

50 

51 async def boot(self, container: ContainerResolverProtocol) -> None: 

52 """Boot UI services: initialize component registry and navigation.""" 

53 self._initialized = True 

54 

55 async def shutdown(self) -> None: 

56 """Shut down UI services.""" 

57 self._initialized = False 

58 

59 async def health_check(self, timeout: float = 5.0) -> HealthCheckResult: 

60 """Return UI infrastructure health status.""" 

61 return HealthCheckResult( 

62 component="admin_ui", 

63 status=HealthStatus.HEALTHY if self._initialized else HealthStatus.UNKNOWN, 

64 message="Admin UI operational" 

65 if self._initialized 

66 else "Not yet initialized", 

67 ) 

68 

69 

70__all__ = ["AdminUISubProvider"]