From 6f594395f8a6479152b4f249ed6804f9eda18fa4 Mon Sep 17 00:00:00 2001 From: Mikhail Date: Sun, 17 May 2026 00:44:15 +0300 Subject: [PATCH] Link HTML5 object selection to source --- services/api-server/src/api_server/html5.py | 4 +++- services/api-server/src/api_server/main.py | 16 +++++++++++++++- services/api-server/tests/test_api.py | 3 +++ 3 files changed, 21 insertions(+), 2 deletions(-) diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py index c8950d3..0e02892 100644 --- a/services/api-server/src/api_server/html5.py +++ b/services/api-server/src/api_server/html5.py @@ -1120,7 +1120,7 @@ def render_html5_symbol_detail(project_id: str, references: object | None) -> st """ -def render_html5_source(node: object | None) -> str: +def render_html5_source(node: object | None, *, oob: bool = False) -> str: name = "source" if node is None else getattr(node, "qualified_name", None) or getattr(node, "name", "source") kind = "" if node is None else _enum_text(getattr(node, "kind", "")) lineage_id = "" if node is None else str(getattr(node, "lineage_id", "")) @@ -1133,12 +1133,14 @@ def render_html5_source(node: object | None) -> str: location = f"{source_path}:{line}" if source_path and line else source_path or "source unavailable" source_text = _node_source_text(node) line_count = len(source_text.splitlines()) or 1 + oob_attr = ' hx-swap-oob="outerHTML"' if oob else "" return f"""
diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py index cf33628..cb27045 100644 --- a/services/api-server/src/api_server/main.py +++ b/services/api-server/src/api_server/main.py @@ -1767,6 +1767,7 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res 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) + source_node = _source_node_for_object_context(project_id, impact) object_context = render_html5_object_context( project_id, schema, @@ -1780,8 +1781,9 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res flowchart, ) flowchart_context = render_html5_flowchart(project_id, flowchart, focus=object_name, oob=True) + source_context = render_html5_source(source_node, oob=True) if source_node is not None else "" return Response( - object_context + flowchart_context, + object_context + flowchart_context + source_context, media_type="text/html; charset=utf-8", ) @@ -8236,6 +8238,18 @@ def _integrations_for_object_context( ] +def _source_node_for_object_context( + project_id: str, + impact: ObjectImpactResponse, +) -> object | None: + snapshot = _project_snapshot_or_404(project_id) + for module in impact.modules: + node = _find_snapshot_node(snapshot, module.lineage_id) + if node is not None: + return node + return None + + def _current_import_source(project_id: str) -> ImportSourceKind: setup = _project_setup_response(project_id) if setup.current_source is not None: diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py index 3bf4e9a..5dc7def 100644 --- a/services/api-server/tests/test_api.py +++ b/services/api-server/tests/test_api.py @@ -328,6 +328,9 @@ def test_html5_object_context_fragment(tmp_path: Path): assert "data-html5-flowchart" in context.text assert 'hx-swap-oob="outerHTML"' in context.text assert "Карта связей · focus" in context.text + assert "data-html5-source" in context.text + assert "ObjectModule.bsl" in context.text + assert "Соединение = Новый HTTPСоединение" in context.text assert "1 signals" in context.text assert "1 errors" in context.text assert "125.0 ms" in context.text