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

29 statements  

« prev     ^ index     » next       coverage.py v7.13.5, created at 2026-08-13 22:14 +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.admin.ui.organisms.form_registry import FormFieldRegistry 

39 from lexigram.ui import MetricsCollector 

40 

41 container.singleton(ComponentRegistry, ComponentRegistry()) 

42 container.singleton(FormFieldRegistry, FormFieldRegistry()) 

43 

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

45 container.singleton(NavigationAssembler, NavigationAssembler) 

46 

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

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

49 container.singleton(LayoutManager, LayoutManager()) 

50 

51 container.singleton(MetricsCollector, MetricsCollector) 

52 

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

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

55 self._initialized = True 

56 

57 async def shutdown(self) -> None: 

58 """Shut down UI services.""" 

59 self._initialized = False 

60 

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

62 """Return UI infrastructure health status.""" 

63 return HealthCheckResult( 

64 component="admin_ui", 

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

66 message="Admin UI operational" 

67 if self._initialized 

68 else "Not yet initialized", 

69 ) 

70 

71 

72__all__ = ["AdminUISubProvider"]