rsdeps

Cargo.lock visualizer (mirror)
Log | Files | Refs | README | LICENSE

commit 05a2206867b1e62159e09e8aa9f083b8c1001ef5
parent cf3a1dda0282c09daee28f73b5c6e095dcf5eb78
Author: Andy Khramtsov <>
Date:   Thu, 28 May 2026 01:05:04 +0300

feat: cache graph

Diffstat:
Msrc/deps/pages/home.py | 62++++++++++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 46 insertions(+), 16 deletions(-)

diff --git a/src/deps/pages/home.py b/src/deps/pages/home.py @@ -1,4 +1,5 @@ import base64 +import io import tomllib import dash @@ -30,6 +31,8 @@ class ids: dependency_graph: str = "dependency-graph" reset_highlight_button: str = "reset-highlight-button" + cache_store: str = "cache-store" + def layout(): return html.Div( @@ -37,6 +40,7 @@ def layout(): children=[ html.H2("Cargo dependency visualisation"), html.H3("Cargo toml"), + dcc.Store(id=ids.cache_store, storage_type="memory"), dcc.Textarea( id=ids.cargo_toml_textarea, placeholder="Cargo.toml contents", @@ -394,9 +398,7 @@ def display_cargo_lock_packages(inputs, state): @callback( - dict( - graph=Output(ids.dependency_graph, "figure"), - ), + dict(graph=Output(ids.dependency_graph, "figure"), cache=Output(ids.cache_store, "data")), dict( generate=Input(ids.generate_button, "n_clicks"), click_data=Input(ids.dependency_graph, "clickData"), @@ -405,29 +407,57 @@ def display_cargo_lock_packages(inputs, state): dict( cargo_toml=State(ids.cargo_toml_textarea, "value"), cargo_lock=State(ids.cargo_lock_textarea, "value"), + cache=State(ids.cache_store, "data"), ), ) def visualize(inputs, state): - if not state["cargo_toml"] or not state["cargo_lock"]: - raise PreventUpdate - try: - cargo_toml = parse_cargo_toml(state["cargo_toml"]) - cargo_lock = parse_cargo_lock(state["cargo_lock"]) - except tomllib.TOMLDecodeError as error: - raise PreventUpdate from error + if ctx.triggered_id and ctx.triggered_id == ids.generate_button: + print("clean") + clean = True + if ( + not state["cache"] + or state["cache"].get("positions") is None + or state["cache"].get("df_graph_nodes") is None + or state["cache"].get("df_graph_arcs") is None + ): + clean = True + else: + clean = False - selected = None if ctx.triggered_id and ctx.triggered_id == ids.reset_highlight_button: selected = None - elif inputs["click_data"] and "points" in inputs["click_data"]: + elif inputs["click_data"] and "points" in inputs["click_data"] and not clean: point = inputs["click_data"]["points"][0] - if "customdata" in point: - selected = point["customdata"] + selected = point.get("customdata", None) + else: + selected = None + + if clean: + if not state["cargo_toml"] or not state["cargo_lock"]: + raise PreventUpdate + try: + cargo_toml = parse_cargo_toml(state["cargo_toml"]) + cargo_lock = parse_cargo_lock(state["cargo_lock"]) + except tomllib.TOMLDecodeError as error: + raise PreventUpdate from error + df_graph = parse_graph(cargo_toml, cargo_lock) + positions = compute_positions(df_graph) + cache = { + "positions": positions, + "df_graph_nodes": df_graph["nodes"].serialize(format="json"), + "df_graph_arcs": df_graph["arcs"].serialize(format="json"), + } + else: + positions = state["cache"]["positions"] + df_graph = dict( + nodes=pl.DataFrame.deserialize(io.StringIO(state["cache"]["df_graph_nodes"]), format="json"), + arcs=pl.DataFrame.deserialize(io.StringIO(state["cache"]["df_graph_arcs"]), format="json"), + ) + cache = dash.no_update - df_graph = parse_graph(cargo_toml, cargo_lock) - positions = compute_positions(df_graph) fig = draw_graph_figure(df_graph, positions, selected) return dict( graph=fig, + cache=cache, )