# 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 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': '75vh', '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' } ) ])