Auto-cleanup des filtres après restauration URL
This commit is contained in:
@@ -0,0 +1,105 @@
|
||||
window.dash_clientside = Object.assign({}, window.dash_clientside, {
|
||||
clientside: {
|
||||
clean_filters: function (trigger) {
|
||||
if (!trigger) {
|
||||
return window.dash_clientside.no_update;
|
||||
}
|
||||
|
||||
// Helper to set value on a React text input
|
||||
const setNativeValue = (element, value) => {
|
||||
const valueSetter = Object.getOwnPropertyDescriptor(
|
||||
element,
|
||||
"value"
|
||||
).set;
|
||||
const prototype = Object.getPrototypeOf(element);
|
||||
const prototypeValueSetter = Object.getOwnPropertyDescriptor(
|
||||
prototype,
|
||||
"value"
|
||||
).set;
|
||||
|
||||
if (valueSetter && valueSetter !== prototypeValueSetter) {
|
||||
prototypeValueSetter.call(element, value);
|
||||
} else {
|
||||
valueSetter.call(element, value);
|
||||
}
|
||||
|
||||
element.dispatchEvent(new Event("input", { bubbles: true }));
|
||||
};
|
||||
|
||||
const cleanInputs = () => {
|
||||
const inputs = document.querySelectorAll(
|
||||
'.dash-filter input[type="text"]'
|
||||
);
|
||||
inputs.forEach((input) => {
|
||||
let val = input.value;
|
||||
let original = val;
|
||||
|
||||
// Remove "icontains " prefix
|
||||
if (/^icontains\s+/i.test(val)) {
|
||||
val = val.replace(/^icontains\s+/i, "");
|
||||
// Check for surrounding quotes (single or double) and remove them
|
||||
if (
|
||||
(val.startsWith('"') && val.endsWith('"')) ||
|
||||
(val.startsWith("'") && val.endsWith("'"))
|
||||
) {
|
||||
val = val.substring(1, val.length - 1);
|
||||
}
|
||||
}
|
||||
// Handle relational operators (i<, s>, i<=, etc.)
|
||||
else if (/^[is][<>]=?/i.test(val)) {
|
||||
val = val.substring(1);
|
||||
}
|
||||
|
||||
if (val !== original) {
|
||||
try {
|
||||
// Try setting it the React-friendly way
|
||||
setNativeValue(input, val);
|
||||
} catch (e) {
|
||||
// Fallback to direct assignment if fancy way fails
|
||||
input.value = val;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
// Use MutationObserver to wait for table to appear/update
|
||||
const observer = new MutationObserver((mutations) => {
|
||||
cleanInputs();
|
||||
});
|
||||
|
||||
const target = document.querySelector(".dash-table-container");
|
||||
if (target) {
|
||||
observer.observe(target, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
attributes: true,
|
||||
attributeFilter: ["value"],
|
||||
});
|
||||
|
||||
// Disconnect after 5 seconds
|
||||
setTimeout(() => {
|
||||
observer.disconnect();
|
||||
}, 5000);
|
||||
|
||||
// Also try immediately just in case
|
||||
cleanInputs();
|
||||
} else {
|
||||
// Poll briefly if container not found yet
|
||||
const checkInterval = setInterval(() => {
|
||||
const t = document.querySelector(".dash-table-container");
|
||||
if (t) {
|
||||
clearInterval(checkInterval);
|
||||
observer.observe(t, { childList: true, subtree: true });
|
||||
setTimeout(() => observer.disconnect(), 5000);
|
||||
cleanInputs();
|
||||
}
|
||||
}, 200);
|
||||
|
||||
// Stop polling after 2s if still nothing
|
||||
setTimeout(() => clearInterval(checkInterval), 2000);
|
||||
}
|
||||
|
||||
return window.dash_clientside.no_update;
|
||||
},
|
||||
},
|
||||
});
|
||||
+30
-3
@@ -1,10 +1,22 @@
|
||||
import json
|
||||
import os
|
||||
import urllib.parse
|
||||
import uuid
|
||||
from datetime import datetime
|
||||
|
||||
import polars as pl
|
||||
from dash import Input, Output, State, callback, dcc, html, no_update, register_page
|
||||
from dash import (
|
||||
ClientsideFunction,
|
||||
Input,
|
||||
Output,
|
||||
State,
|
||||
callback,
|
||||
clientside_callback,
|
||||
dcc,
|
||||
html,
|
||||
no_update,
|
||||
register_page,
|
||||
)
|
||||
|
||||
from src.figures import DataTable
|
||||
from src.utils import (
|
||||
@@ -50,6 +62,7 @@ datatable = html.Div(
|
||||
|
||||
layout = [
|
||||
dcc.Location(id="tableau_url", refresh=False),
|
||||
dcc.Store(id="filter-cleanup-trigger"),
|
||||
html.Script(
|
||||
type="application/ld+json",
|
||||
id="dataset_jsonld",
|
||||
@@ -272,12 +285,13 @@ def download_data(n_clicks, filter_query, sort_by, hidden_columns: list = None):
|
||||
Output("table", "sort_by"),
|
||||
Output("table", "hidden_columns"),
|
||||
Output("tableau_url", "search", allow_duplicate=True),
|
||||
Output("filter-cleanup-trigger", "data"),
|
||||
Input("tableau_url", "search"),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
def restore_view_from_url(search):
|
||||
if not search:
|
||||
return no_update, no_update, no_update, no_update
|
||||
return no_update, no_update, no_update, no_update, no_update
|
||||
|
||||
params = urllib.parse.parse_qs(search.lstrip("?"))
|
||||
logger.debug("params", params)
|
||||
@@ -285,9 +299,11 @@ def restore_view_from_url(search):
|
||||
filter_query = no_update
|
||||
sort_by = no_update
|
||||
hidden_columns = no_update
|
||||
trigger_cleanup = no_update
|
||||
|
||||
if "filtres" in params:
|
||||
filter_query = params["filtres"][0]
|
||||
trigger_cleanup = str(uuid.uuid4())
|
||||
|
||||
if "tris" in params:
|
||||
try:
|
||||
@@ -300,7 +316,18 @@ def restore_view_from_url(search):
|
||||
verified_columns = [column for column in columns if column in schema.names()]
|
||||
hidden_columns = invert_columns(verified_columns)
|
||||
|
||||
return filter_query, sort_by, hidden_columns, ""
|
||||
return filter_query, sort_by, hidden_columns, "", trigger_cleanup
|
||||
|
||||
|
||||
clientside_callback(
|
||||
ClientsideFunction(
|
||||
namespace="clientside",
|
||||
function_name="clean_filters",
|
||||
),
|
||||
Output("filter-cleanup-trigger", "data", allow_duplicate=True),
|
||||
Input("filter-cleanup-trigger", "data"),
|
||||
prevent_initial_call=True,
|
||||
)
|
||||
|
||||
|
||||
@callback(
|
||||
|
||||
Reference in New Issue
Block a user