{% extends "base.html" %} {% import "_links.html" as links with context %} {% block title %}Graph โ€” Cairn Dashboard{% endblock %} {% block view_title %}Graph{% endblock %} {% block content %}

Graph

{#- Layout toggle (FR-004): links swap only the layout param, keeping scope/focus/repo/depth (window_control link conventions); the active layout renders as . app.js intercepts clicks on the anchors to toggle the live network without a reload. FR-003: links.url keeps the selected store riding the href; empty selection keeps the bare hrefs, byte-identical. -#} {% macro layout_href(kind) -%} {% set q = {"layout": kind, "scope": scope} %} {%- if focus %}{% set _ = q.update({"focus": focus}) %}{% endif %} {%- if repo %}{% set _ = q.update({"repo": repo}) %}{% endif %} {%- if depth %}{% set _ = q.update({"depth": depth}) %}{% endif %} {{- links.url(request.url.path, q) }} {%- endmacro %}

Layout: {%- for kind, label in [("force", "force"), ("hier", "hierarchical")] %} {% if not loop.first %} ยท {% endif %}{% if kind == layout %}{{ label }}{% else %}{{ label }}{% endif %} {%- endfor %}

{#- Node inspect (FR-004, D-004): selecting a node on the canvas swaps this hint for an anchor to that symbol's neighborhood graph (scope=symbol&focus=...); deselecting restores the hint. Distinct from double-click, which expands in place. -#}

select a node to inspect

{#- Community legend: app.js renders it from the same palette it colored the nodes with (top 8 communities + overflow), so the swatches can never drift from the canvas. Hidden until filled; absent when the graph is empty. -#} {% if graph.nodes %} {% endif %}

scope {{ scope }} โ€” {{ graph.metadata.get("node_count", graph.nodes | length) }} nodes, {{ graph.metadata.get("edge_count", graph.edges | length) }} edges shown {%- if graph.metadata.get("total") is not none %}, {{ graph.metadata.total }} in the full result {%- endif %}; scope queries are capped, so a count at the cap means the graph was truncated.

{% if graph.nodes %}
{#- Overlay controls float over the canvas's bottom-left; app.js wires the data-graph-action buttons to vis zoom/fit. -#}
{% else %}

No nodes for this scope โ€” adjust the controls above.

{% endif %} {#- FR-003: a selected store rides the page for app.js (search and expansion fetches stay on that store); no selection renders the tag byte-identical to the pre-seam page. -#}
{% endblock %} {% block scripts %} {% endblock %}