Merge branch 'feature/columns_modal' into dev
This commit is contained in:
@@ -194,7 +194,7 @@ p.version > a {
|
|||||||
margin: 12px 0 12px 0;
|
margin: 12px 0 12px 0;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.table-menu > * {
|
.table-menu > * {
|
||||||
@@ -240,7 +240,11 @@ table.cell-table th {
|
|||||||
.dash-table-container
|
.dash-table-container
|
||||||
.dash-spreadsheet-container
|
.dash-spreadsheet-container
|
||||||
.dash-spreadsheet-inner
|
.dash-spreadsheet-inner
|
||||||
th.dash-header {
|
th.dash-header,
|
||||||
|
.dash-table-container
|
||||||
|
.dash-spreadsheet-container
|
||||||
|
.dash-spreadsheet-inner
|
||||||
|
th.dash-select-header {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
color: white;
|
color: white;
|
||||||
font-family: "Inter", sans-serif;
|
font-family: "Inter", sans-serif;
|
||||||
@@ -258,7 +262,13 @@ table.cell-table th {
|
|||||||
.dash-spreadsheet-inner
|
.dash-spreadsheet-inner
|
||||||
table.cell-table
|
table.cell-table
|
||||||
tr:first-of-type
|
tr:first-of-type
|
||||||
th.dash-header:first-of-type {
|
th.dash-header:first-of-type,
|
||||||
|
.dash-table-container
|
||||||
|
.dash-spreadsheet-container
|
||||||
|
.dash-spreadsheet-inner
|
||||||
|
table.cell-table
|
||||||
|
tr:first-of-type
|
||||||
|
th.dash-select-header:first-of-type {
|
||||||
border-top-left-radius: 3px !important;
|
border-top-left-radius: 3px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -354,6 +364,11 @@ table.cell-table th {
|
|||||||
right: 5px;
|
right: 5px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#column_list .show-hide,
|
||||||
|
#table .show-hide {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
.show-hide-menu-item > input {
|
.show-hide-menu-item > input {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-4
@@ -258,10 +258,12 @@ class DataTable(dash_table.DataTable):
|
|||||||
page_action: Literal["native", "custom", "none"] = "native",
|
page_action: Literal["native", "custom", "none"] = "native",
|
||||||
sort_action: Literal["native", "custom", "none"] = "native",
|
sort_action: Literal["native", "custom", "none"] = "native",
|
||||||
filter_action: Literal["native", "custom", "none"] = "native",
|
filter_action: Literal["native", "custom", "none"] = "native",
|
||||||
|
style_cell_conditional: list | None = None,
|
||||||
|
style_cell: dict | None = None,
|
||||||
**kwargs,
|
**kwargs,
|
||||||
):
|
):
|
||||||
# Styles de base
|
# Styles de base
|
||||||
style_cell_conditional = [
|
style_cell_conditional_common = [
|
||||||
{
|
{
|
||||||
"if": {"column_id": "objet"},
|
"if": {"column_id": "objet"},
|
||||||
"minWidth": "350px",
|
"minWidth": "350px",
|
||||||
@@ -291,6 +293,8 @@ class DataTable(dash_table.DataTable):
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
|
style_cell_common = {"fontFamily": "Inter", "fontSize": "16px"}
|
||||||
|
|
||||||
for key in data_schema.keys():
|
for key in data_schema.keys():
|
||||||
field = data_schema[key]
|
field = data_schema[key]
|
||||||
if field["type"] in ["number", "integer"]:
|
if field["type"] in ["number", "integer"]:
|
||||||
@@ -299,7 +303,16 @@ class DataTable(dash_table.DataTable):
|
|||||||
"textAlign": "right",
|
"textAlign": "right",
|
||||||
# "fontFamily": "Fira Code",
|
# "fontFamily": "Fira Code",
|
||||||
}
|
}
|
||||||
style_cell_conditional.append(rule)
|
style_cell_conditional_common.append(rule)
|
||||||
|
|
||||||
|
style_cell_conditional = (
|
||||||
|
style_cell_conditional or []
|
||||||
|
) + style_cell_conditional_common
|
||||||
|
if style_cell:
|
||||||
|
style_cell.update(style_cell_common)
|
||||||
|
else:
|
||||||
|
style_cell = style_cell_common
|
||||||
|
style_header = style_cell
|
||||||
|
|
||||||
# Initialisation de la classe parente avec les arguments
|
# Initialisation de la classe parente avec les arguments
|
||||||
super().__init__(
|
super().__init__(
|
||||||
@@ -322,8 +335,8 @@ class DataTable(dash_table.DataTable):
|
|||||||
style_cell_conditional=style_cell_conditional,
|
style_cell_conditional=style_cell_conditional,
|
||||||
data_timestamp=0,
|
data_timestamp=0,
|
||||||
markdown_options={"html": True},
|
markdown_options={"html": True},
|
||||||
style_header={"fontFamily": "Inter", "fontSize": "16px"},
|
style_header=style_header,
|
||||||
style_cell={"fontFamily": "Inter", "fontSize": "16px"},
|
style_cell=style_cell,
|
||||||
tooltip_duration=8000,
|
tooltip_duration=8000,
|
||||||
tooltip_delay=350,
|
tooltip_delay=350,
|
||||||
hidden_columns=hidden_columns,
|
hidden_columns=hidden_columns,
|
||||||
|
|||||||
+143
-5
@@ -21,6 +21,8 @@ from dash import (
|
|||||||
|
|
||||||
from src.figures import DataTable
|
from src.figures import DataTable
|
||||||
from src.utils import (
|
from src.utils import (
|
||||||
|
columns,
|
||||||
|
data_schema,
|
||||||
df,
|
df,
|
||||||
filter_table_data,
|
filter_table_data,
|
||||||
get_default_hidden_columns,
|
get_default_hidden_columns,
|
||||||
@@ -61,9 +63,70 @@ datatable = html.Div(
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def make_tableau_columns_table():
|
||||||
|
table_data = []
|
||||||
|
table_columns = [
|
||||||
|
{
|
||||||
|
"id": col,
|
||||||
|
"name": data_schema[col]["title"],
|
||||||
|
"description": data_schema[col]["description"],
|
||||||
|
}
|
||||||
|
for col in df.columns
|
||||||
|
]
|
||||||
|
for column in table_columns:
|
||||||
|
new_column = {
|
||||||
|
"id": column["id"],
|
||||||
|
"name": column["name"],
|
||||||
|
"description": data_schema[column["id"]]["description"],
|
||||||
|
}
|
||||||
|
table_data.append(new_column)
|
||||||
|
|
||||||
|
table = (
|
||||||
|
DataTable(
|
||||||
|
row_selectable="multi",
|
||||||
|
data=table_data,
|
||||||
|
filter_action="none",
|
||||||
|
sort_action="none",
|
||||||
|
style_cell={
|
||||||
|
"textAlign": "left",
|
||||||
|
},
|
||||||
|
columns=[
|
||||||
|
{
|
||||||
|
"name": "Nom",
|
||||||
|
"id": "name",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Description",
|
||||||
|
"id": "description",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "column_id",
|
||||||
|
"id": "id",
|
||||||
|
},
|
||||||
|
],
|
||||||
|
hidden_columns=["id"],
|
||||||
|
style_cell_conditional=[
|
||||||
|
{
|
||||||
|
"if": {"column_id": "description"},
|
||||||
|
"minWidth": "450px",
|
||||||
|
"overflow": "hidden",
|
||||||
|
"lineHeight": "18px",
|
||||||
|
"whiteSpace": "normal",
|
||||||
|
}
|
||||||
|
],
|
||||||
|
page_action="none",
|
||||||
|
dtid="column_list",
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
return table
|
||||||
|
|
||||||
|
|
||||||
layout = [
|
layout = [
|
||||||
dcc.Location(id="tableau_url", refresh=False),
|
dcc.Location(id="tableau_url", refresh=False),
|
||||||
dcc.Store(id="filter-cleanup-trigger"),
|
dcc.Store(id="filter-cleanup-trigger"),
|
||||||
|
dcc.Store(id="tableau-hidden-columns"),
|
||||||
html.Script(
|
html.Script(
|
||||||
type="application/ld+json",
|
type="application/ld+json",
|
||||||
id="dataset_jsonld",
|
id="dataset_jsonld",
|
||||||
@@ -192,7 +255,7 @@ layout = [
|
|||||||
),
|
),
|
||||||
dbc.ModalFooter(
|
dbc.ModalFooter(
|
||||||
dbc.Button(
|
dbc.Button(
|
||||||
"Close",
|
"Fermer",
|
||||||
id="tableau_help_close",
|
id="tableau_help_close",
|
||||||
className="ms-auto",
|
className="ms-auto",
|
||||||
n_clicks=0,
|
n_clicks=0,
|
||||||
@@ -221,6 +284,11 @@ layout = [
|
|||||||
children=[
|
children=[
|
||||||
html.Div(
|
html.Div(
|
||||||
[
|
[
|
||||||
|
dbc.Button(
|
||||||
|
"Colonnes affichées",
|
||||||
|
id="tableau_columns_open",
|
||||||
|
className="column_list",
|
||||||
|
),
|
||||||
html.P("lignes", id="nb_rows"),
|
html.P("lignes", id="nb_rows"),
|
||||||
html.Div(id="copy-container"),
|
html.Div(id="copy-container"),
|
||||||
dcc.Input(id="share-url", readOnly=True, style={"display": "none"}),
|
dcc.Input(id="share-url", readOnly=True, style={"display": "none"}),
|
||||||
@@ -235,6 +303,27 @@ layout = [
|
|||||||
],
|
],
|
||||||
className="table-menu",
|
className="table-menu",
|
||||||
),
|
),
|
||||||
|
dbc.Modal(
|
||||||
|
[
|
||||||
|
dbc.ModalHeader(dbc.ModalTitle("Choix des colonnes à afficher")),
|
||||||
|
dbc.ModalBody(
|
||||||
|
id="tableau_columns_body", children=make_tableau_columns_table()
|
||||||
|
),
|
||||||
|
dbc.ModalFooter(
|
||||||
|
dbc.Button(
|
||||||
|
"Fermer",
|
||||||
|
id="tableau_columns_close",
|
||||||
|
className="ms-auto",
|
||||||
|
n_clicks=0,
|
||||||
|
)
|
||||||
|
),
|
||||||
|
],
|
||||||
|
id="tableau_columns",
|
||||||
|
is_open=False,
|
||||||
|
fullscreen="md-down",
|
||||||
|
scrollable=True,
|
||||||
|
size="xl",
|
||||||
|
),
|
||||||
datatable,
|
datatable,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -297,7 +386,7 @@ def download_data(n_clicks, filter_query, sort_by, hidden_columns: list = None):
|
|||||||
@callback(
|
@callback(
|
||||||
Output("table", "filter_query"),
|
Output("table", "filter_query"),
|
||||||
Output("table", "sort_by"),
|
Output("table", "sort_by"),
|
||||||
Output("table", "hidden_columns"),
|
Output("tableau-hidden-columns", "data"),
|
||||||
Output("tableau_url", "search", allow_duplicate=True),
|
Output("tableau_url", "search", allow_duplicate=True),
|
||||||
Output("filter-cleanup-trigger", "data"),
|
Output("filter-cleanup-trigger", "data"),
|
||||||
Input("tableau_url", "search"),
|
Input("tableau_url", "search"),
|
||||||
@@ -368,9 +457,9 @@ def sync_url_and_reset_button(filter_query, sort_by, hidden_columns, href):
|
|||||||
params["tris"] = json.dumps(sort_by)
|
params["tris"] = json.dumps(sort_by)
|
||||||
|
|
||||||
if hidden_columns:
|
if hidden_columns:
|
||||||
columns = invert_columns(hidden_columns)
|
table_columns = invert_columns(hidden_columns)
|
||||||
columns = ",".join(columns)
|
table_columns = ",".join(table_columns)
|
||||||
params["colonnes"] = columns
|
params["colonnes"] = table_columns
|
||||||
|
|
||||||
query_string = urllib.parse.urlencode(params)
|
query_string = urllib.parse.urlencode(params)
|
||||||
full_url = f"{base_url}?{query_string}" if query_string else base_url
|
full_url = f"{base_url}?{query_string}" if query_string else base_url
|
||||||
@@ -414,3 +503,52 @@ def toggle_tableau_help(click_open, click_close, is_open):
|
|||||||
if click_open or click_close:
|
if click_open or click_close:
|
||||||
return not is_open
|
return not is_open
|
||||||
return is_open
|
return is_open
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output("tableau-hidden-columns", "data", allow_duplicate=True),
|
||||||
|
Input("column_list", "selected_rows"),
|
||||||
|
prevent_initial_call=True,
|
||||||
|
)
|
||||||
|
def update_hidden_columns_from_checkboxes(selected_columns):
|
||||||
|
if selected_columns:
|
||||||
|
selected_columns = [columns[i] for i in selected_columns]
|
||||||
|
hidden_columns = [col for col in columns if col not in selected_columns]
|
||||||
|
return hidden_columns
|
||||||
|
else:
|
||||||
|
return []
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output("table", "hidden_columns", allow_duplicate=True),
|
||||||
|
Input(
|
||||||
|
"tableau-hidden-columns",
|
||||||
|
"data",
|
||||||
|
),
|
||||||
|
prevent_initial_call=True,
|
||||||
|
)
|
||||||
|
def store_hidden_columns(hidden_columns):
|
||||||
|
return hidden_columns
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output("column_list", "selected_rows"),
|
||||||
|
Input("table", "hidden_columns"),
|
||||||
|
State("column_list", "selected_rows"), # pour éviter la boucle infinie
|
||||||
|
)
|
||||||
|
def update_checkboxes_from_hidden_columns(hidden_cols, current_checkboxes):
|
||||||
|
# Show all columns that are NOT hidden
|
||||||
|
visible_cols = [columns.index(col) for col in columns if col not in hidden_cols]
|
||||||
|
return visible_cols
|
||||||
|
|
||||||
|
|
||||||
|
@callback(
|
||||||
|
Output("tableau_columns", "is_open"),
|
||||||
|
Input("tableau_columns_open", "n_clicks"),
|
||||||
|
Input("tableau_columns_close", "n_clicks"),
|
||||||
|
State("tableau_columns", "is_open"),
|
||||||
|
)
|
||||||
|
def toggle_tableau_columns(click_open, click_close, is_open):
|
||||||
|
if click_open or click_close:
|
||||||
|
return not is_open
|
||||||
|
return is_open
|
||||||
|
|||||||
+3
-1
@@ -2,6 +2,7 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import uuid
|
import uuid
|
||||||
|
from collections import OrderedDict
|
||||||
from time import localtime, sleep
|
from time import localtime, sleep
|
||||||
|
|
||||||
import polars as pl
|
import polars as pl
|
||||||
@@ -456,7 +457,7 @@ def get_data_schema() -> dict:
|
|||||||
else:
|
else:
|
||||||
raise Exception(f"Chemin vers le schéma invalide: {path}")
|
raise Exception(f"Chemin vers le schéma invalide: {path}")
|
||||||
|
|
||||||
new_schema = {}
|
new_schema = OrderedDict()
|
||||||
|
|
||||||
for col in original_schema["fields"]:
|
for col in original_schema["fields"]:
|
||||||
new_schema[col["name"]] = col
|
new_schema[col["name"]] = col
|
||||||
@@ -757,3 +758,4 @@ meta_content = {
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
data_schema = get_data_schema()
|
data_schema = get_data_schema()
|
||||||
|
columns = df.columns
|
||||||
|
|||||||
Reference in New Issue
Block a user