84 lines
3.2 KiB
Python
84 lines
3.2 KiB
Python
# File: logs/view.py
|
|
# Copyright (C) 2026 Erick Ahmed
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
|
|
import pandas as pd
|
|
from dash import html, dash_table, dcc
|
|
import dash_bootstrap_components as dbc
|
|
|
|
PAGE_SIZE = 25000
|
|
|
|
def prepare_logs_data(df: pd.DataFrame) -> pd.DataFrame:
|
|
if df is None or df.empty:
|
|
return pd.DataFrame()
|
|
|
|
df = df.copy()
|
|
|
|
if 'j1939_metadata' in df.columns:
|
|
df['Priority'] = df['j1939_metadata'].apply(lambda x: x.get('Priority') if isinstance(x, dict) else None)
|
|
df['PF'] = df['j1939_metadata'].apply(lambda x: x.get('PF') if isinstance(x, dict) else None)
|
|
df['PS'] = df['j1939_metadata'].apply(lambda x: x.get('PS') if isinstance(x, dict) else None)
|
|
df['SA'] = df['j1939_metadata'].apply(lambda x: x.get('SA') if isinstance(x, dict) else None)
|
|
df['DA'] = df['j1939_metadata'].apply(lambda x: x.get('DA') if isinstance(x, dict) else None)
|
|
df['PGN'] = df['j1939_metadata'].apply(lambda x: x.get('PGN') if isinstance(x, dict) else None)
|
|
else:
|
|
for col in ['Priority', 'PF', 'PS', 'SA', 'DA', 'PGN']:
|
|
df[col] = None
|
|
|
|
for i in range(8):
|
|
col = f'b{i}'
|
|
if col in df.columns:
|
|
df[col] = df[col].apply(lambda x: f"{int(x):02X}" if pd.notna(x) else "")
|
|
else:
|
|
df[col] = ""
|
|
|
|
if 'ID' in df.columns:
|
|
df['ID'] = df['ID'].astype(str)
|
|
|
|
display_cols = ['Timestamp', 'ID', 'DLC', 'b0', 'b1', 'b2', 'b3', 'b4', 'b5', 'b6', 'b7', 'Priority', 'PF', 'PS', 'SA', 'DA', 'PGN']
|
|
display_df = df[[c for c in display_cols if c in df.columns]]
|
|
|
|
return display_df.fillna("")
|
|
|
|
def get_logs_table_component():
|
|
return html.Div([
|
|
html.Div(id='logs-info-text', className="text-muted mb-2"),
|
|
dash_table.DataTable(
|
|
id='logs-table',
|
|
virtualization=True,
|
|
page_action='none',
|
|
style_table={'overflowX': 'auto', 'height': '70vh', 'overflowY': 'auto'},
|
|
style_header={
|
|
'backgroundColor': '#1a1a1a',
|
|
'color': 'white',
|
|
'fontWeight': 'bold',
|
|
'textAlign': 'center',
|
|
'position': 'sticky',
|
|
'top': 0
|
|
},
|
|
style_data={
|
|
'backgroundColor': '#f8f9fa',
|
|
'color': '#2a2a2a',
|
|
'textAlign': 'center'
|
|
},
|
|
style_data_conditional=[
|
|
{
|
|
'if': {'row_index': 'odd'},
|
|
'backgroundColor': 'rgb(240, 240, 240)'
|
|
}
|
|
],
|
|
style_cell={
|
|
'minWidth': '80px',
|
|
'padding': '5px',
|
|
'textAlign': 'center',
|
|
'fontFamily': 'Segoe UI, Arial, sans-serif'
|
|
}
|
|
),
|
|
html.Div([
|
|
dbc.Button("Prev", id='logs-prev-btn', color="secondary", outline=True, size="sm", className="me-2"),
|
|
html.Div(id='logs-page-nav', className="d-inline-block", style={'verticalAlign': 'middle'}),
|
|
dbc.Button("Next", id='logs-next-btn', color="secondary", outline=True, size="sm", className="ms-2"),
|
|
], className="d-flex justify-content-center align-items-center mt-3"),
|
|
dcc.Store(id='logs-current-page', data=0),
|
|
])
|