Coverage for src/lexigram/admin/ui/organisms/data_table/coordinator.py: 100%
31 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 15:04 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-21 15:04 +0800
1"""Data table coordinator component."""
3from __future__ import annotations
5from typing import Any
7from lexigram.admin.config import TableConfiguration
8from lexigram.admin.ui.organisms.data_table.actions import ActionManager
9from lexigram.admin.ui.organisms.data_table.rendering import DataTableRenderer
10from lexigram.ui import Component, TableState
13class DataTable(Component):
14 """
15 Main DataTable Coordinator.
16 Handles configuration, state management, and dispatches rendering to specific views.
17 """
19 def __init__(
20 self,
21 columns: list | None = None,
22 data: list[dict] | None = None,
23 state: TableState | None = None,
24 config: TableConfiguration | None = None,
25 # Legacy params
26 page: int = 1,
27 per_page: int = 20,
28 total: int | None = None,
29 filters: dict | None = None,
30 resource_prefix: str | None = None,
31 sort_by: str | None = None,
32 sort_order: str = "asc",
33 actions: list | None = None,
34 header_actions: list | None = None,
35 bulk_actions: list | None = None,
36 filter_options: dict | None = None,
37 layout_type: str | None = None,
38 data_view: str | None = None,
39 next_cursor: str | None = None,
40 summary: dict[str, Any] | None = None,
41 **props,
42 ) -> None:
43 super().__init__(**props)
45 # Resolve Configuration
46 if config:
47 self.config = config
48 else:
49 self.config = TableConfiguration(
50 columns=columns or [],
51 actions=actions or [],
52 header_actions=header_actions or [],
53 bulk_actions=bulk_actions or [],
54 filter_options=filter_options,
55 resource_prefix=resource_prefix,
56 resource_name=props.get("resource_name"),
57 default_view=data_view or "tabular",
58 default_layout=layout_type or "stack",
59 default_sort_by=sort_by,
60 default_sort_order=sort_order,
61 )
63 # Resolve State
64 if state:
65 self.state = state
66 else:
67 self.state = TableState(
68 search=filters.get("search", "") if filters else "",
69 sort_by=sort_by,
70 sort_order=sort_order,
71 page=page,
72 per_page=per_page,
73 filters=filters or {},
74 view=data_view or self.config.default_view,
75 layout=layout_type or self.config.default_layout,
76 )
78 self.data = data or []
79 self.total = total
80 self.user = props.get("user")
81 self.loading = props.get("loading", False)
82 self.error = props.get("error")
83 self.next_cursor = next_cursor
84 self.summary = summary
85 self.props = props
87 # Permission state: no permission service is bound at construction
88 # time in the framework; async callers may hoist checks via
89 # PermissionManager and inject the resulting dict here.
90 self.permissions = props.get("permissions") or {
91 "can_view": True,
92 "can_create": True,
93 "can_update": True,
94 "can_delete": True,
95 }
97 # Configure actions
98 self.action_manager = ActionManager(self.config, self.permissions)
99 self.action_manager.configure_actions()
101 # Show delete based on permissions
102 self.show_delete = (
103 props.get("show_delete", True) and self.permissions["can_delete"]
104 )
106 def render(self) -> Any:
107 """Render the data table using the modular renderer."""
108 renderer = DataTableRenderer(
109 data=self.data,
110 config=self.config,
111 state=self.state,
112 total=self.total,
113 user=self.user,
114 loading=self.loading,
115 error=self.error,
116 next_cursor=self.next_cursor,
117 summary=self.summary,
118 props=self.props,
119 )
120 return renderer.render()
123__all__ = ["DataTable"]