Source code for duck.etc.blueprints.dashboard.ui.components.logs_panel
"""
LogsPanel component — renders a scrollable stream of recent server
log entries with level badges, timestamps, and source labels.
"""
from duck.html.components import InnerComponent
from duck.html.components.container import Container
[docs]
class LogsPanel(InnerComponent):
"""
Renders a scrollable log stream panel.
Each entry shows a timestamp, level badge, source module,
and the log message text.
Props:
data (list[dict]): Output of services.get_recent_logs().
"""
[docs]
def get_element(self) -> str:
"""
Returns:
The HTML element tag for this component.
"""
return "div"
[docs]
def on_create(self) -> None:
"""
Builds the logs panel with header and scrollable log list.
"""
super().on_create()
data = self.kwargs.get("data", [])
self.props["class"] = "db-panel"
self.add_children([
self.build_header(data),
self.build_body(data),
])
[docs]
def build_body(self, data: list) -> Container:
"""
Returns the scrollable log list body.
Args:
data: List of log entry dicts.
Returns:
A Container with the log entries rendered inside.
"""
if not data:
return Container(
klass="db-panel-body",
inner_html='<span class="db-loading">No log entries.</span>',
)
entries_html = "".join(self.render_entry(e) for e in data)
return Container(
klass="db-panel-body",
inner_html=f'<div class="db-logs-list">{entries_html}</div>',
)
[docs]
def render_entry(self, entry: dict) -> str:
"""
Returns the HTML string for a single log entry row.
Args:
entry: Dict with keys: level, message, ts, source.
Returns:
HTML string for the log entry div.
"""
level = entry.get("level", "INFO")
message = entry.get("message", "")
ts = entry.get("ts", "")
source = entry.get("source", "")
level_class = f"db-level-{level.lower()}"
return (
f'<div class="db-log-entry">'
f'<span class="db-log-ts">{ts}</span>'
f'<span class="db-log-level {level_class}">{level}</span>'
f'<span class="db-log-source">{source}</span>'
f'<span class="db-log-message">{message}</span>'
f'</div>'
)