from dash import html, dcc, dash_table, register_page, Input, Output, State, callback
from dotenv import load_dotenv
import os
import polars as pl
from src.utils import split_filter_part
load_dotenv()
df = pl.scan_parquet(os.getenv("DATA_FILE_PARQUET_PATH"))
title = "Tableau"
register_page(__name__, path="/", title=f"decp.info - {title}", name=title, order=1)
datatable = dash_table.DataTable(
cell_selectable=False,
id="table",
page_size=20,
page_current=0,
page_action="custom",
filter_action="custom",
filter_options={"case": "insensitive", "placeholder_text": "Filtrer..."},
columns=[{"name": i, "id": i} for i in df.collect_schema().names()],
selected_columns=[],
selected_rows=[],
# sort_action="native",
# sort_mode="multi",
export_format="xlsx",
export_columns="visible",
export_headers="ids",
style_cell_conditional=[
{
"if": {"column_id": "objet"},
"minWidth": "350px",
"textAlign": "left",
"overflow": "hidden",
"lineHeight": "14px",
"whiteSpace": "normal",
},
],
data_timestamp=0,
)
layout = [
html.Div(
html.Details(
children=[
html.Summary(html.H3("Utilisation")),
dcc.Markdown(
"""
**Filtres**
Vous pouvez appliquer un filtre pour chaque colonne en entrant du texte sous le nom de la colonne, puis en tapant sur `Entrée`.
- Champs textuels : la recherche est insensible à la casse (majuscules/minuscules).
- Champs numériques : possibilité d'ajouter < ou > devant le chiffre recherché pour chercher des valeurs inférieures ou supérieur.
**Télécharger le résultat**
Vous pouvez télécharger le résultat de vos filtres et tris en cliquant sur Télécharger au format Excel.
Les colonnes supprimées seront absentes du fichier téléchargé.
Si vous téléchargez un volume important de données, il se peut que vous attendiez quelques minutes avant le début du téléchargement.
"""
),
],
id="instructions",
),
id="header",
),
# html.Div(
# [
# "Recherche dans objet : ",
# dcc.Input(id="search", value="", type="text"),
# ]
# )]),
dcc.Loading(
overlay_style={"visibility": "visible", "filter": "blur(2px)"},
id="loading-1",
type="default",
children=datatable,
),
]
@callback(
Output("table", "data"),
Output("table", "data_timestamp"),
Input("table", "page_current"),
Input("table", "page_size"),
Input("table", "filter_query"),
State("table", "data_timestamp"),
)
def update_table(page_current, page_size, filter_query, data_timestamp):
print(" + + + + + + + + + + + + + + + + + + ")
print("Filter query:", filter_query)
# 1. Apply Filters
dff = df # start from the original data
if filter_query:
filtering_expressions = filter_query.split(" && ")
for filter_part in filtering_expressions:
col_name, operator, filter_value = split_filter_part(filter_part)
print("filter_value:", filter_value)
print("filter_value_type:", type(filter_value))
if operator in ("<", "<=", ">", ">="):
filter_value = int(filter_value)
if operator == "<":
dff = dff.filter(pl.col(col_name) < filter_value)
elif operator == ">":
dff = dff.filter(pl.col(col_name) > filter_value)
elif operator == ">=":
dff = dff.filter(pl.col(col_name) >= filter_value)
elif operator == "<=":
dff = dff.filter(pl.col(col_name) <= filter_value)
# these operators match polars series filter operators
elif operator == "contains":
dff = dff.filter(pl.col(col_name).str.contains("(?i)" + filter_value))
# elif operator == 'datestartswith':
# dff = dff.filter(pl.col(col_name).str.startswith(filter_value)")
# 2. Paginate Data
start_row = page_current * page_size
# end_row = (page_current + 1) * page_size
dff = dff.slice(start_row, page_size).collect()
# print("dff_sliced:", dff.select("titulaire.typeId"))
dff = dff.to_dicts()
return dff, data_timestamp + 1 # update data, update timestamp