feat: Improve dashboard functionality and stability
This commit introduces several improvements to the dashboard: - Refactored the component structure for consistency, defining callbacks within the `render` function. - Added robust error handling to data loading and callbacks to prevent crashes. - Implemented linking for SO and AIR columns in the source table. - Added and improved filtering and display options for tables. - Left-aligned columns in tables for better readability. - Cleaned up unused component files.
This commit is contained in:
@ -7,15 +7,6 @@ import dash_bootstrap_components as dbc
|
||||
from ..data.loader_gz import MTBFSchema
|
||||
from . import ids
|
||||
|
||||
import pandas as pd
|
||||
from dash import Dash, dcc, html, dash_table, Input, Output, State, callback_context
|
||||
from datetime import datetime
|
||||
import os
|
||||
import dash_bootstrap_components as dbc
|
||||
|
||||
from ..data.loader_gz import MTBFSchema
|
||||
from . import ids
|
||||
|
||||
def render(app: Dash, data: pd.DataFrame) -> html.Div:
|
||||
@app.callback(
|
||||
Output(ids.DATA_TABLE, "children"),
|
||||
@ -24,46 +15,68 @@ def render(app: Dash, data: pd.DataFrame) -> html.Div:
|
||||
Input(ids.WEEK_DROPDOWN, "value"),
|
||||
Input(ids.PU_HITS_SELECTOR, "value"),
|
||||
Input(ids.SINGLE_HITTER_FILTER, "value"),
|
||||
Input(ids.SYSTEM_FILTER, "value"),
|
||||
Input("span", "value"),
|
||||
],
|
||||
)
|
||||
def update_data_table(
|
||||
years: list[str], weeks: list[str], u_hits: bool, remove_single: bool
|
||||
year: int, week: int, u_hits: bool, remove_single: bool, systems: list[str], span: int
|
||||
) -> html.Div:
|
||||
filtered_data = data.query(
|
||||
"year in @years and week in @weeks"
|
||||
)
|
||||
if filtered_data.shape[0] == 0:
|
||||
return html.Div("No data selected.")
|
||||
try:
|
||||
print(f'year: {year}, week: {week}, span: {span}, systems: {systems}')
|
||||
if not all([year, week, span]):
|
||||
return html.Div("No data selected.")
|
||||
|
||||
hits_col = MTBFSchema.U_HITS if u_hits else MTBFSchema.P_HITS
|
||||
|
||||
# Count 'Y' values
|
||||
hits_data = filtered_data[filtered_data[hits_col] == 'Y']
|
||||
|
||||
table_data = hits_data.groupby(MTBFSchema.AIR).agg(
|
||||
count=(hits_col, 'size'),
|
||||
air_issue_description=(MTBFSchema.AIR_ISSUE_DESCRIPTION, lambda x: ', '.join(x.dropna().astype(str).unique())),
|
||||
close_notes=(MTBFSchema.CLOSE_NOTES, lambda x: ', '.join(x.dropna().astype(str).unique()))
|
||||
).reset_index()
|
||||
|
||||
if remove_single:
|
||||
table_data = table_data[table_data['count'] > 1]
|
||||
years = [year]
|
||||
|
||||
table_data = table_data.sort_values('count', ascending=False)
|
||||
|
||||
# Reorder columns
|
||||
table_data = table_data[[MTBFSchema.AIR, 'air_issue_description', 'close_notes', 'count']]
|
||||
start_week = week - span + 1
|
||||
weeks = list(range(start_week, week + 1))
|
||||
|
||||
return dash_table.DataTable(
|
||||
id=ids.MTBF_PAR_TABLE, # Using this ID for feedback callbacks
|
||||
data=table_data.to_dict("records"),
|
||||
columns=[{"name": i, "id": i} for i in table_data.columns],
|
||||
page_size=10,
|
||||
row_selectable='single',
|
||||
selected_rows=[],
|
||||
filter_action='native',
|
||||
sort_action='native'
|
||||
)
|
||||
filtered_data = data.query(
|
||||
"year in @years and Week_Number in @weeks and System in @systems"
|
||||
)
|
||||
if filtered_data.shape[0] == 0:
|
||||
return html.Div("No data selected.")
|
||||
|
||||
hits_col = MTBFSchema.U_HITS if u_hits else MTBFSchema.P_HITS
|
||||
|
||||
# Count 'Y' values
|
||||
hits_data = filtered_data[filtered_data[hits_col] == 'Y']
|
||||
|
||||
table_data = hits_data.groupby([MTBFSchema.AIR, MTBFSchema.SYSTEM]).agg(
|
||||
count=(hits_col, 'size'),
|
||||
air_issue_description=(MTBFSchema.AIR_ISSUE_DESCRIPTION, lambda x: ', '.join(x.dropna().astype(str).unique())),
|
||||
close_notes=(MTBFSchema.CLOSE_NOTES, lambda x: ', '.join(x.dropna().astype(str).unique()))
|
||||
).reset_index()
|
||||
|
||||
if remove_single:
|
||||
table_data = table_data[table_data['count'] > 1]
|
||||
|
||||
table_data['air_issue_description'] = table_data['air_issue_description'].apply(lambda s: s[:80] + '...' if len(s) > 80 else s)
|
||||
|
||||
table_data = table_data.sort_values('count', ascending=False)
|
||||
|
||||
# Reorder columns
|
||||
table_data = table_data[[MTBFSchema.AIR, MTBFSchema.SYSTEM, 'air_issue_description', 'close_notes', 'count']]
|
||||
|
||||
return dash_table.DataTable(
|
||||
id=ids.MTBF_PAR_TABLE, # Using this ID for feedback callbacks
|
||||
data=table_data.to_dict("records"),
|
||||
columns=[{"name": i, "id": i} for i in table_data.columns],
|
||||
page_size=10,
|
||||
row_selectable='single',
|
||||
selected_rows=[],
|
||||
filter_action='native',
|
||||
sort_action='native',
|
||||
style_cell_conditional=[
|
||||
{
|
||||
'if': {'column_id': c},
|
||||
'textAlign': 'left'
|
||||
} for c in ['Close_notes', 'count']
|
||||
]
|
||||
)
|
||||
except Exception as e:
|
||||
return html.Div(f"An error occurred in data_table: {e}")
|
||||
|
||||
@app.callback(
|
||||
Output(ids.FEEDBACK_MODAL, "is_open"),
|
||||
|
Reference in New Issue
Block a user