commit 1e86c03288c62d75f2d4b51ec524a71c109bdec3
parent e072873bed67c1c3e212f916c04ce428c2494832
Author: Andy Khramtsov <>
Date: Thu, 28 May 2026 03:03:44 +0300
feat: add selected node details
Diffstat:
1 file changed, 43 insertions(+), 20 deletions(-)
diff --git a/src/deps/pages/home.py b/src/deps/pages/home.py
@@ -27,11 +27,12 @@ class ids:
collapse_tables: str = "collapse-tables"
cargo_lock_table: str = "cargo-lock-table"
cargo_toml_table: str = "cargo-toml-table"
-
recalculate_button: str = "recalculate-button"
+
generate_button: str = "generate-button"
dependency_graph: str = "dependency-graph"
reset_highlight_button: str = "reset-highlight-button"
+ selected_node_details: str = "selected-node-details"
cache_store: str = "cache-store"
@@ -106,13 +107,20 @@ def layout():
dcc.Graph(
id=ids.dependency_graph,
figure={},
- style={"height": 800},
+ style={"height": 1000},
),
dcc.Button(id=ids.reset_highlight_button, children="Reset highlight"),
+ html.Div(id=ids.selected_node_details),
],
)
+def parse_node_details(details: dict) -> str:
+ details = {key: val for key, val in details.items()}
+ details["dependencies"] = "[" + ",".join([f"<br> {dep}" for dep in details["dependencies"] or []]) + "<br>]"
+ return "<br>".join([f"{key}: {val}" for key, val in details.items()])
+
+
def parse_cargo_toml(contents: str) -> pl.DataFrame:
toml = tomllib.loads(contents)
dependencies = toml.get("dependencies", {})
@@ -269,17 +277,20 @@ def draw_graph_figure(
edge_x.extend([x0, x1, None])
edge_y.extend([y0, y1, None])
- edge_trace = go.Scatter(x=edge_x, y=edge_y, line=dict(width=1.0, color="#B0BEC0"), hoverinfo="skip", mode="lines")
+ edge_trace = (
+ go.Scatter(x=edge_x, y=edge_y, line=dict(width=1.0, color="#A0A0A0"), hoverinfo="skip", mode="lines")
+ if not selected_node
+ else go.Scatter(x=edge_x, y=edge_y, line=dict(width=1.0, color="#D0D0D0"), hoverinfo="skip", mode="lines")
+ )
edge_trace_highlight = go.Scatter(
- x=edge_x_highlight, y=edge_y_highlight, line=dict(width=1.0, color="#707EF0"), hoverinfo="skip", mode="lines"
+ x=edge_x_highlight, y=edge_y_highlight, line=dict(width=1.5, color="#8080F0"), hoverinfo="skip", mode="lines"
)
node_x = []
node_y = []
short_labels = []
hover_details = []
- colors = []
- sizes = []
+ marker_colors = []
text_colors = []
custom_data = []
for row in df_graph["nodes"].iter_rows(named=True):
@@ -289,34 +300,31 @@ def draw_graph_figure(
node_x.append(x)
node_y.append(y)
short_labels.append(row["short_label"])
- hover_details.append("<br>".join([f"<b>{key}:</b> {val}" for key, val in row["full_details"].items()]))
+ hover_details.append(parse_node_details(row["full_details"]))
custom_data.append(node_id)
- base_color = "#C1829E" if row["full_details"]["explicit"] else "#3182CE"
+ base_color = "#F0A0A0" if row["full_details"]["explicit"] else "#A0A0F0"
if not selected_node:
- colors.append(base_color)
- sizes.append(28)
- text_colors.append("#2D3748")
+ marker_colors.append(base_color)
+ text_colors.append("#303030")
elif node_id in highlight_nodes:
- colors.append("#ED8936" if node_id != selected_node else "#3182CE")
- sizes.append(34)
+ marker_colors.append(base_color if node_id != selected_node else "#A0F0A0")
text_colors.append("#000000")
else:
- colors.append("#E2E8F0")
- sizes.append(20)
- text_colors.append("#A0AEC0")
+ marker_colors.append("#E0E0E0")
+ text_colors.append("#A0A0A0")
node_trace = go.Scatter(
x=node_x,
y=node_y,
mode="markers+text",
text=short_labels,
- textposition="top center",
+ textposition="middle left",
hovertext=hover_details,
hoverinfo="text",
customdata=custom_data,
- marker=dict(showscale=False, color=colors, size=16, line=dict(width=2, color="white")),
- textfont=dict(size=11, color=text_colors),
+ marker=dict(showscale=False, color=marker_colors, size=16, line=dict(width=1, color="white")),
+ textfont=dict(size=10, color=text_colors),
)
fig = go.Figure(
@@ -432,7 +440,11 @@ def display_cargo_lock_packages(inputs, state):
@callback(
- dict(graph=Output(ids.dependency_graph, "figure"), cache=Output(ids.cache_store, "data")),
+ dict(
+ graph=Output(ids.dependency_graph, "figure"),
+ cache=Output(ids.cache_store, "data"),
+ details=Output(ids.selected_node_details, "children"),
+ ),
dict(
generate=Input(ids.generate_button, "n_clicks"),
click_data=Input(ids.dependency_graph, "clickData"),
@@ -488,9 +500,20 @@ def visualize(inputs, state):
)
cache = dash.no_update
+ details = [
+ item
+ for part in (
+ parse_node_details(df_graph["nodes"].filter(pl.col("node_id") == selected).to_dicts()[0]["full_details"])
+ if selected
+ else ""
+ ).split("<br>")
+ for item in (part, html.Br())
+ ]
+
fig = draw_graph_figure(df_graph, positions, selected)
return dict(
graph=fig,
cache=cache,
+ details=details,
)