commit 853c01f05eb699a038ebd4633ed23b0ca3c68c4d
parent dbac595bd53bb4307f8a337a47b108779ac27ef6
Author: Andy Khramtsov <>
Date: Sun, 31 May 2026 14:57:27 +0300
refactor: split callback
Diffstat:
1 file changed, 70 insertions(+), 45 deletions(-)
diff --git a/src/rsdeps/pages/home.py b/src/rsdeps/pages/home.py
@@ -692,15 +692,13 @@ def display_cargo_lock_packages(inputs, state):
@callback(
dict(
- graph=Output(ids.dependency_graph, "figure"),
+ graph=Output(ids.dependency_graph, "figure", allow_duplicate=True),
cache=Output(ids.cache_store, "data"),
- selected_node_store=Output(ids.selected_node_store, "data"),
- details=Output(ids.selected_node_details, "children"),
+ selected_node_store=Output(ids.selected_node_store, "data", allow_duplicate=True),
+ details=Output(ids.selected_node_details, "children", allow_duplicate=True),
),
dict(
generate=Input(ids.generate_button, "n_clicks"),
- click_data=Input(ids.dependency_graph, "clickData"),
- reset_highlight_button=Input(ids.reset_highlight_button, "n_clicks"),
),
dict(
cargo_toml=State(ids.cargo_toml_textarea, "value"),
@@ -711,21 +709,73 @@ def display_cargo_lock_packages(inputs, state):
),
prevent_initial_call=True,
)
-def visualize(inputs, state):
- pressed_generate = bool(ctx.triggered_id and ctx.triggered_id == ids.generate_button)
- invalid_cache = bool(
+def generate(inputs, state):
+ if not state["cargo_lock"]:
+ raise PreventUpdate
+ try:
+ cargo_toml = parse_cargo_toml(state["cargo_toml"] or "")
+ except tomllib.TOMLDecodeError:
+ cargo_toml = None
+ try:
+ cargo_lock = parse_cargo_lock(state["cargo_lock"] or "")
+ except tomllib.TOMLDecodeError as error:
+ raise PreventUpdate from error
+ df_graph = files_into_graph(cargo_toml, cargo_lock)
+ positions = compute_node_positions(df_graph)
+ adjacency_list = compute_adjacency_list(df_graph)
+ cache = {
+ "positions": positions,
+ "adjacency_list": wrap_adjacency_list(adjacency_list),
+ "df_graph_nodes": df_graph.nodes.serialize(format="json"),
+ "df_graph_arcs": df_graph.arcs.serialize(format="json"),
+ }
+
+ old_fig = state["figure"]
+ old_uirevision = old_fig.get("layout", {}).get("uirevision", 0)
+
+ fig = draw_graph_figure(df_graph, positions, adjacency_list, selected_node=None)
+ fig.update_layout(
+ uirevision=old_uirevision + 1,
+ )
+
+ return dict(
+ graph=fig,
+ cache=cache,
+ details="",
+ selected_node_store=dict(selected=None),
+ )
+
+
+@callback(
+ dict(
+ graph=Output(ids.dependency_graph, "figure", allow_duplicate=True),
+ selected_node_store=Output(ids.selected_node_store, "data", allow_duplicate=True),
+ details=Output(ids.selected_node_details, "children", allow_duplicate=True),
+ ),
+ dict(
+ click_data=Input(ids.dependency_graph, "clickData"),
+ reset_highlight_button=Input(ids.reset_highlight_button, "n_clicks"),
+ ),
+ dict(
+ cache=State(ids.cache_store, "data"),
+ selected_node_store=State(ids.selected_node_store, "data"),
+ figure=State(ids.dependency_graph, "figure"),
+ ),
+ prevent_initial_call=True,
+)
+def update(inputs, state):
+ 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
or state["cache"].get("adjacency_list") is None
- )
-
- clean = pressed_generate or invalid_cache
+ ):
+ raise PreventUpdate
if ctx.triggered_id and ctx.triggered_id == ids.reset_highlight_button:
selected = None
- elif inputs["click_data"] and "points" in inputs["click_data"] and not clean:
+ elif inputs["click_data"] and "points" in inputs["click_data"]:
point = inputs["click_data"]["points"][0]
selected = point.get("customdata", None)
else:
@@ -733,34 +783,12 @@ def visualize(inputs, state):
if state["selected_node_store"] and state["selected_node_store"].get("selected") == selected:
selected = None
- if clean:
- if not state["cargo_lock"]:
- raise PreventUpdate
- try:
- cargo_toml = parse_cargo_toml(state["cargo_toml"] or "")
- except tomllib.TOMLDecodeError:
- cargo_toml = None
- try:
- cargo_lock = parse_cargo_lock(state["cargo_lock"] or "")
- except tomllib.TOMLDecodeError as error:
- raise PreventUpdate from error
- df_graph = files_into_graph(cargo_toml, cargo_lock)
- positions = compute_node_positions(df_graph)
- adjacency_list = compute_adjacency_list(df_graph)
- cache = {
- "positions": positions,
- "adjacency_list": wrap_adjacency_list(adjacency_list),
- "df_graph_nodes": df_graph.nodes.serialize(format="json"),
- "df_graph_arcs": df_graph.arcs.serialize(format="json"),
- }
- else:
- positions = state["cache"]["positions"]
- adjacency_list = unwrap_adjacency_list(state["cache"]["adjacency_list"])
- df_graph = DfGraph(
- 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
+ positions = state["cache"]["positions"]
+ adjacency_list = unwrap_adjacency_list(state["cache"]["adjacency_list"])
+ df_graph = DfGraph(
+ 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"),
+ )
details = [
item
@@ -773,16 +801,13 @@ def visualize(inputs, state):
][:-1]
old_fig = state["figure"]
- old_uirevision = old_fig.get("layout", {}).get("uirevision", 0)
+ uirevision = old_fig.get("layout", {}).get("uirevision", 0)
fig = draw_graph_figure(df_graph, positions, adjacency_list, selected)
- fig.update_layout(
- uirevision=old_uirevision + 1 if clean else old_uirevision,
- )
+ fig.update_layout(uirevision=uirevision)
return dict(
graph=fig,
- cache=cache,
details=details,
selected_node_store=dict(selected=selected),
)