Coverage for src/lexigram/admin/lib/template/render.py: 20%

20 statements  

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

1"""Template utilities for lexigram-admin. 

2 

3Provides simple template rendering functions for standalone pages 

4like login, error, etc. Uses StandaloneLayout for consistent styling. 

5""" 

6 

7from typing import Any 

8 

9from markupsafe import escape 

10 

11from lexigram.admin.ui.layouts import ( 

12 StandaloneLayout, 

13 StandaloneLayoutConfig, 

14 StandaloneLayoutContext, 

15) 

16 

17 

18def render_template( 

19 template_name: str, 

20 context: dict[str, Any] | None = None, 

21 **kwargs: Any, 

22) -> str: 

23 """Render a named template. 

24 

25 This is a simple fallback template renderer. For full template support, 

26 use the Jinja2 integration in ui/templates_jinja.py. 

27 

28 Args: 

29 template_name: Template name (used as title) 

30 context: Template context 

31 **kwargs: Additional context values 

32 

33 Returns: 

34 HTML string 

35 """ 

36 ctx = context or {} 

37 ctx.update(kwargs) 

38 

39 title = ctx.get("title", template_name) 

40 content = ctx.get("content", "") 

41 

42 # Include debug info when error template is requested 

43 if template_name == "debug_error.html": 

44 exc_type = ctx.get("exc_type", "") 

45 exc_message = ctx.get("exc_message", "") 

46 traceback = ctx.get("traceback", "") 

47 traceback_plain = ctx.get("traceback_plain", "") 

48 debug_html = f""" 

49 <div class="error-details" style="margin-top: 1rem; padding: 1rem; background: #fef2f2; border: 1px solid #fecaca; border-radius: 4px;"> 

50 <h2 style="color: #b91c1c;">{escape(str(exc_type))}</h2> 

51 <pre style="white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.85rem; margin-top: 0.5rem;">{escape(str(exc_message))}</pre> 

52 <details style="margin-top: 0.5rem;"> 

53 <summary style="cursor: pointer; font-weight: 500;">Traceback</summary> 

54 <pre style="white-space: pre-wrap; word-break: break-word; font-family: monospace; font-size: 0.75rem; max-height: 400px; overflow: auto; margin-top: 0.25rem; background: #1f2937; color: #e5e7eb; padding: 0.75rem; border-radius: 4px;">{escape(str(traceback_plain))}</pre> 

55 </details> 

56 </div> 

57 """ 

58 content = debug_html 

59 

60 config = StandaloneLayoutConfig( 

61 show_footer=False, 

62 show_logo=False, 

63 centered=False, 

64 ) 

65 layout_context = StandaloneLayoutContext( 

66 page_title=title, 

67 ) 

68 

69 page_content = f""" 

70 <main class="container" style="padding: 2rem;"> 

71 <h1>{escape(title)}</h1> 

72 {content} 

73 </main> 

74 """ 

75 

76 layout = StandaloneLayout(config=config, context=layout_context) 

77 return layout.render(page_content)