diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py
index 40681d3..c7f5c3e 100644
--- a/services/api-server/src/api_server/html5.py
+++ b/services/api-server/src/api_server/html5.py
@@ -326,6 +326,7 @@ def render_html5_object_context(
knowledge: Iterable[object] | None = None,
privacy: object | None = None,
integrations: Iterable[object] | None = None,
+ flowchart: object | None = None,
) -> str:
if schema is None or impact is None:
return f"""
@@ -353,6 +354,8 @@ def render_html5_object_context(
knowledge_items = list(knowledge or [])
privacy_markers = getattr(privacy, "markers", []) if privacy is not None else []
integration_items = list(integrations or [])
+ flow_nodes = getattr(flowchart, "nodes", []) if flowchart is not None else []
+ flow_edges = getattr(flowchart, "edges", []) if flowchart is not None else []
return f"""
Object context
@@ -372,6 +375,8 @@ def render_html5_object_context(
{_metric("Writes", len(writes))}
{_metric("Calls", len(callees))}
{_metric("Integrations", len(integration_items))}
+ {_metric("Graph nodes", len(flow_nodes))}
+ {_metric("Graph edges", len(flow_edges))}
{_metric("Runtime", len(runtime_items))}
{_metric("Knowledge", len(knowledge_items))}
{_metric("Privacy", len(privacy_markers))}
@@ -386,6 +391,7 @@ def render_html5_object_context(
{''.join(_named_node_item("read", item) for item in query_tables[:4])}
{''.join(_named_node_item("write", item) for item in writes[:4])}
{''.join(_named_node_item("call", item) for item in callees[:6])}
+ {''.join(_flowchart_edge_item(item, flow_nodes) for item in flow_edges[:8])}
{''.join(_runtime_summary_item(item) for item in runtime_items[:6])}
{''.join(_knowledge_record_item(item) for item in knowledge_items[:6])}
{''.join(_privacy_marker_item(item) for item in privacy_markers[:6])}
@@ -1504,6 +1510,23 @@ def _integration_endpoint_item(endpoint: object) -> str:
"""
+def _flowchart_edge_item(edge: object, nodes: Iterable[object]) -> str:
+ node_names = {
+ str(getattr(node, "id", "")): str(getattr(node, "qualified_name", "") or getattr(node, "label", ""))
+ for node in nodes
+ }
+ source = node_names.get(str(getattr(edge, "source", "")), str(getattr(edge, "source", "")))
+ target = node_names.get(str(getattr(edge, "target", "")), str(getattr(edge, "target", "")))
+ label = str(getattr(edge, "label", "") or getattr(edge, "kind", "") or "link")
+ kind = str(getattr(edge, "kind", "") or "FLOW")
+ return f"""
+
+ {escape(label)}
+ {escape(source)} -> {escape(target)} ยท {escape(kind)}
+
+ """
+
+
def _authoring_diff_item(line: object) -> str:
kind = str(getattr(line, "kind", ""))
text = str(getattr(line, "text", ""))
diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py
index a122a43..d9ecb95 100644
--- a/services/api-server/src/api_server/main.py
+++ b/services/api-server/src/api_server/main.py
@@ -1749,6 +1749,7 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res
ui = await get_object_ui(project_id, object_name)
privacy = await object_privacy(project_id, object_name)
integrations = _integrations_for_object_context(project_id, impact)
+ flowchart = await project_flowchart(project_id, focus=object_name, depth=1, limit=40)
runtime = _runtime_for_object_context(project_id, impact)
knowledge = _knowledge_for_object_context(schema, impact, ui)
return Response(
@@ -1762,6 +1763,7 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res
knowledge,
privacy,
integrations,
+ flowchart,
),
media_type="text/html; charset=utf-8",
)
diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py
index c1e7f6b..8526598 100644
--- a/services/api-server/tests/test_api.py
+++ b/services/api-server/tests/test_api.py
@@ -322,6 +322,7 @@ def test_html5_object_context_fragment(tmp_path: Path):
assert "HTTPConnection" in context.text
assert "https://api.example.local/orders" in context.text
assert "OUTBOUND" in context.text
+ assert "data-html5-object-context-item=\"flow-edge\"" in context.text
assert "1 signals" in context.text
assert "1 errors" in context.text
assert "125.0 ms" in context.text