@@ -107,12 +100,21 @@ def render_html5_editor(
-
- HTML5 editor
{escape(selected_module.qualified_name if selected_module else project_id)}
{escape(source_text)}
+ {render_html5_source(selected_module)}
Нет результатов
' + return "".join(_symbol_result(node) for node in results) + + +def render_html5_source(node: object | None) -> str: + name = "source" if node is None else getattr(node, "qualified_name", None) or getattr(node, "name", "source") + return f'{escape(_node_source_text(node))}'
+
+
def _page(title: str, body: str) -> str:
return f"""
@@ -196,11 +221,19 @@ def _topbar(project_id: str, project_nav: str) -> str:
"""
-def _tree_item(node: object) -> str:
+def _tree_item(project_id: str, node: object) -> str:
name = getattr(node, "qualified_name", None) or getattr(node, "name", "")
kind = getattr(node, "kind", "")
kind_value = str(kind.value if hasattr(kind, "value") else kind)
- return f'{escape(str(name))}{escape(kind_value)}'
+ lineage_id = str(getattr(node, "lineage_id", ""))
+ return (
+ f''
+ f'{escape(str(name))}{escape(kind_value)}'
+ )
def _symbol_result(node: object) -> str:
diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py
index 6b27fab..e08c1a3 100644
--- a/services/api-server/src/api_server/main.py
+++ b/services/api-server/src/api_server/main.py
@@ -35,7 +35,7 @@ from fastapi.responses import PlainTextResponse, Response, StreamingResponse
from neo4j import AsyncGraphDatabase
from pydantic import BaseModel, Field
-from api_server.html5 import render_html5_editor, render_html5_index, render_html5_status
+from api_server.html5 import render_html5_editor, render_html5_index, render_html5_source, render_html5_status, render_html5_symbols
from impact_engine import object_impact, routine_impact
from incremental_indexer import rebuild_changed_file
from integration_topology import IntegrationKind, build_integration_topology
@@ -1618,6 +1618,27 @@ async def html5_project_events(project_id: str, once: bool = False) -> Streaming
)
+@app.get("/html5/projects/{project_id}/symbols")
+async def html5_project_symbols(project_id: str, q: str = "") -> Response:
+ snapshot = _project_snapshot_or_404(project_id)
+ return Response(
+ render_html5_symbols(snapshot, q),
+ media_type="text/html; charset=utf-8",
+ )
+
+
+@app.get("/html5/projects/{project_id}/source/{lineage_id}")
+async def html5_project_source(project_id: str, lineage_id: str) -> Response:
+ snapshot = _project_snapshot_or_404(project_id)
+ node = _find_snapshot_node(snapshot, lineage_id)
+ if node is None:
+ raise HTTPException(status_code=404, detail=f"Lineage not found: {lineage_id}")
+ return Response(
+ render_html5_source(node),
+ media_type="text/html; charset=utf-8",
+ )
+
+
@app.get("/version")
async def version() -> dict[str, str]:
return {"name": "sfera", "version": "0.1.0"}
diff --git a/services/api-server/tests/test_api.py b/services/api-server/tests/test_api.py
index f98f900..5e60419 100644
--- a/services/api-server/tests/test_api.py
+++ b/services/api-server/tests/test_api.py
@@ -107,6 +107,10 @@ def test_html5_server_rendered_project_editor(tmp_path: Path):
assert 'data-html5-page="editor"' in editor.text
assert "data-html5-editor" in editor.text
assert "data-html5-symbol-results" in editor.text
+ assert 'hx-get="/html5/projects/' in editor.text
+ assert 'hx-target="[data-html5-symbol-results]"' in editor.text
+ assert 'hx-target="[data-html5-source]"' in editor.text
+ assert 'hx-swap="outerHTML"' in editor.text
assert "hx-ext=\"sse\"" in editor.text
assert f"sse-connect=\"/html5/projects/{project_id}/events\"" in editor.text
assert "htmx.org" in editor.text
@@ -121,6 +125,22 @@ def test_html5_server_rendered_project_editor(tmp_path: Path):
assert "data:" in first_chunk
assert project_id in first_chunk
+ symbols = client.get(f"/html5/projects/{project_id}/symbols", params={"q": "Проверить"})
+ assert symbols.status_code == 200
+ assert "text/html" in symbols.headers["content-type"]
+ assert 'data-html5-symbol' in symbols.text
+ assert "Проверить" in symbols.text
+ assert "