Coverage for src/lexigram/admin/dashboard/page_renderer.py: 94%

18 statements  

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

1"""Host-side renderer for structured management page content. 

2 

3``PageContent`` is the only way management pages reach the browser. This module 

4builds the page shell (header + body + pagination) via ``lexigram-ui``; the body 

5is rendered by ``render_content`` exactly like dashboard widgets. 

6""" 

7 

8from __future__ import annotations 

9 

10from starlette.responses import HTMLResponse 

11 

12from lexigram.admin.dashboard.content_renderer import render_content 

13from lexigram.contracts.admin.page_content import PageContent, PaginationContent 

14from lexigram.ui import PageSizeSelector, PaginationLinks, el, raw, render_to_string 

15 

16 

17def _render_pagination(pagination: PaginationContent) -> str: 

18 """Render the "Showing X to Y of Z" block + pager + page-size selector.""" 

19 total = pagination.total 

20 if total <= 0: 

21 return "" 

22 total_pages = max(1, (total + pagination.per_page - 1) // pagination.per_page) 

23 start_item = (pagination.page - 1) * pagination.per_page + 1 

24 end_item = min(pagination.page * pagination.per_page, total) 

25 return render_to_string( 

26 el( 

27 "div", 

28 { 

29 "class": ( 

30 "flex items-center justify-between border-t border-border " 

31 "bg-background px-4 py-3 mt-4" 

32 ), 

33 }, 

34 el( 

35 "p", 

36 { 

37 "class": ( 

38 "text-[11px] uppercase tracking-wider " 

39 "text-[var(--muted-foreground)] font-semibold" 

40 ), 

41 }, 

42 "Showing ", 

43 el("span", {"class": "font-bold"}, str(start_item)), 

44 " to ", 

45 el("span", {"class": "font-bold"}, str(end_item)), 

46 " of ", 

47 el("span", {"class": "font-bold"}, str(total)), 

48 " results", 

49 ), 

50 el( 

51 "div", 

52 {"class": "flex items-center space-x-4"}, 

53 PaginationLinks( 

54 page=pagination.page, 

55 total_pages=total_pages, 

56 per_page=pagination.per_page, 

57 base_url=pagination.base_url, 

58 ), 

59 PageSizeSelector( 

60 per_page=pagination.per_page, 

61 base_url=pagination.base_url, 

62 ), 

63 ), 

64 ) 

65 ) 

66 

67 

68def render_page_content(content: PageContent) -> HTMLResponse: 

69 """Render structured page content to an HTML response.""" 

70 body_html = render_content(content.body) 

71 pagination_html = ( 

72 _render_pagination(content.pagination) if content.pagination else "" 

73 ) 

74 html = render_to_string( 

75 el( 

76 "div", 

77 {"class": "space-y-6"}, 

78 el( 

79 "h1", 

80 {"class": "text-2xl font-semibold tracking-tight"}, 

81 content.title, 

82 ), 

83 el( 

84 "div", 

85 {"id": "table-data"}, 

86 raw(body_html), 

87 raw(pagination_html), 

88 ), 

89 ) 

90 ) 

91 return HTMLResponse(html)