commit e072873bed67c1c3e212f916c04ce428c2494832
parent f10c4d5415831beb86a998bba5c37182500e656c
Author: Andy Khramtsov <>
Date: Thu, 28 May 2026 02:03:36 +0300
feat: collapse tables
Diffstat:
3 files changed, 143 insertions(+), 22 deletions(-)
diff --git a/src/deps/aio_components/__init__.py b/src/deps/aio_components/__init__.py
@@ -1 +1,2 @@
+from . import collapse_aio as collapse_aio
from . import table_aio as table_aio
diff --git a/src/deps/aio_components/collapse_aio.py b/src/deps/aio_components/collapse_aio.py
@@ -0,0 +1,111 @@
+import uuid
+from typing import Any
+
+import dash
+from dash import MATCH, Input, Output, State, callback, dcc, html
+
+
+class CollapseAIO(html.Div):
+ """
+ Collapse that always eagerly loads its content
+
+ Example usage:
+ ```
+ CollapseAIO(
+ "some-unique-id",
+ "Some label",
+ [html.Div("Some content")],
+ )
+ ```
+ """
+
+ class ids:
+ def button(aio_id: Any):
+ return {
+ "component": "CollapseAIO",
+ "subcomponent": "button",
+ "aio_id": aio_id,
+ }
+
+ def arrow(aio_id: Any):
+ return {
+ "component": "CollapseAIO",
+ "subcomponent": "arrow",
+ "aio_id": aio_id,
+ }
+
+ def memory_store(aio_id: Any):
+ return {
+ "component": "CollapseAIO",
+ "subcomponent": "memory_store",
+ "aio_id": aio_id,
+ }
+
+ def store(aio_id: Any):
+ return {
+ "component": "CollapseAIO",
+ "subcomponent": "store",
+ "aio_id": aio_id,
+ }
+
+ def content(aio_id: Any):
+ return {
+ "component": "CollapseAIO",
+ "subcomponent": "content",
+ "aio_id": aio_id,
+ }
+
+ ids = ids
+
+ def __init__(self, aio_id=None, label="Collapse", content=None, default_hidden: bool = False):
+ if content is None:
+ content = []
+ if aio_id is None:
+ aio_id = str(uuid.uuid4())
+ super().__init__(
+ children=[
+ dcc.Store(
+ id=self.ids.memory_store(aio_id),
+ storage_type="memory",
+ data={"default_hidden": default_hidden},
+ ),
+ dcc.Store(id=self.ids.store(aio_id), storage_type="local", data={}),
+ dcc.Button(
+ id=self.ids.button(aio_id),
+ className="collapse-button",
+ children=[html.Div(id=self.ids.arrow(aio_id), className="collapse-button__arrow-right"), label],
+ ),
+ html.Div(
+ id=self.ids.content(aio_id),
+ className="",
+ children=content,
+ ),
+ ],
+ )
+
+ @callback(
+ dict(
+ class_name=Output(ids.content(MATCH), "className"),
+ arrow=Output(ids.arrow(MATCH), "className"),
+ store_data=Output(ids.store(MATCH), "data"),
+ ),
+ dict(
+ button=Input(ids.button(MATCH), "n_clicks"),
+ ),
+ dict(
+ store_data=State(ids.store(MATCH), "data"),
+ memory_store_data=State(ids.memory_store(MATCH), "data"),
+ class_name=State(ids.content(MATCH), "className"),
+ ),
+ )
+ def switch_tab(inputs, state):
+ hidden = state["store_data"].get("hidden", state["memory_store_data"]["default_hidden"])
+ if dash.ctx.triggered_id is not None:
+ hidden = not hidden
+ arrow = "collapse-button__arrow-right" if hidden else "collapse-button__arrow-down"
+ class_name = "hidden" if hidden else ""
+ return dict(
+ class_name=class_name,
+ arrow=arrow,
+ store_data={"hidden": hidden},
+ )
diff --git a/src/deps/pages/home.py b/src/deps/pages/home.py
@@ -9,6 +9,7 @@ from dash import Input, Output, State, callback, ctx, dcc, html
from dash.exceptions import PreventUpdate
from plotly import graph_objects as go
+from deps.aio_components.collapse_aio import CollapseAIO
from deps.aio_components.table_aio import TableAIO
dash.register_page(__name__, path="/", order=1)
@@ -23,6 +24,7 @@ class ids:
upload_cargo_toml: str = "upload-cargo-toml"
cargo_toml_filename_display: str = "cargo-toml-filename-display"
+ collapse_tables: str = "collapse-tables"
cargo_lock_table: str = "cargo-lock-table"
cargo_toml_table: str = "cargo-toml-table"
@@ -68,28 +70,35 @@ def layout():
html.Div(id=ids.cargo_lock_filename_display, children="Empty"),
],
),
- dcc.Button(id=ids.recalculate_button, children="Recalculate"),
- html.H3("Cargo toml dependencies"),
- TableAIO(
- aio_id=ids.cargo_toml_table,
- column_defs=[
- {"field": i, "colId": i}
- for i in [
- "name",
- ]
- ],
- ),
- html.H3("Cargo lock packages"),
- TableAIO(
- aio_id=ids.cargo_lock_table,
- column_defs=[
- {"field": i, "colId": i}
- for i in [
- "name",
- "version",
- "checksum",
- "dependencies",
- ]
+ CollapseAIO(
+ aio_id=ids.collapse_tables,
+ label="Table view",
+ default_hidden=True,
+ content=[
+ dcc.Button(id=ids.recalculate_button, children="Recalculate"),
+ html.H3("Cargo toml dependencies"),
+ TableAIO(
+ aio_id=ids.cargo_toml_table,
+ column_defs=[
+ {"field": i, "colId": i}
+ for i in [
+ "name",
+ ]
+ ],
+ ),
+ html.H3("Cargo lock packages"),
+ TableAIO(
+ aio_id=ids.cargo_lock_table,
+ column_defs=[
+ {"field": i, "colId": i}
+ for i in [
+ "name",
+ "version",
+ "checksum",
+ "dependencies",
+ ]
+ ],
+ ),
],
),
dcc.Button(id=ids.generate_button, children="Generate"),