from dash import html, dcc, dash_table, Input, Output, State from dash.exceptions import PreventUpdate from ..libs.stage.stage import AbstractStage def layout_factory(stages: list[AbstractStage]): def layout(stage_name=None, schema_name=None, table_name=None): stage = stages[stage_name] df = stage.read(table=table_name, schema=schema_name) return html.Div([ dcc.Store(id="table_backup"), html.Div([ html.H2([ dcc.Link( f"{stage.name}", href=f"/stage/{stage.name}", className="hover:underline" ), html.Span(" > "), dcc.Link( f"{schema_name}", href=f"/stg/{stage.name}/schema/{schema_name}", className="hover:underline" ), html.Span(" > "), html.Span(table_name), ], className="text-2xl" ), html.Div([ html.Button( "Editer", id="btn_edit", className="rounded border px-2 py-1", style={"display": "block"} ), html.Button( "Sauver", id="btn_save", className="rounded border px-2 py-1 border-green-500 hover:bg-green-500", style={"display": "none"} ), html.Button( "Annuler", id="btn_cancel", className="rounded border px-2 py-1 border-red-500 hover:bg-red-500", style={"display": "none"} ), ], className="flex flex-row space-x-2", id="toolbar" ), ], className="flex flex-row justify-between p-4" ), html.Div([ html.Div([ dash_table.DataTable( id="datatable", data=df.to_dict('records'), columns=[{"name": i, "id": i} for i in df.columns], filter_action="native", sort_action="native", sort_mode="multi", editable=False ) ]) ], className="overflow-y-auto" ), ], className="p-2" ) return layout def callback_factory(app): @app.callback( Output("datatable", 'editable', allow_duplicate=True), Output("table_backup", 'data'), Input("btn_edit", "n_clicks"), State("datatable", 'data'), prevent_initial_call=True ) def activate_editable(n_clicks, df_src): if n_clicks is None: raise PreventUpdate if n_clicks > 0: df_backup = df_src.copy() return True, df_backup raise PreventUpdate @app.callback( Output("datatable", 'editable', allow_duplicate=True), Output("datatable", 'data', allow_duplicate=True), Input("btn_cancel", "n_clicks"), State("table_backup", 'data'), prevent_initial_call=True ) def cancel_modifications(n_clicks, data): if n_clicks is None: raise PreventUpdate if n_clicks > 0 and data is not None: return False, data.copy() raise PreventUpdate @app.callback( Output("datatable", 'editable'), Output("datatable", 'data'), Input("btn_save", "n_clicks"), State("datatable", 'editable'), ) def save_modifications(n_clicks, editable): if n_clicks is None: raise PreventUpdate if n_clicks > 0: return not editable return editable @app.callback( Output("btn_edit", "style"), Output("btn_save", "style"), Output("btn_cancel", "style"), Input("datatable", "editable"), ) def toolbar(editable): if editable: return {"display": "none"}, {"display": "block"}, {"display": "block"} return {"display": "block"}, {"display": "none"}, {"display": "none"}