diff --git a/services/api-server/src/api_server/html5.py b/services/api-server/src/api_server/html5.py
index 22ce8f4..4decd8b 100644
--- a/services/api-server/src/api_server/html5.py
+++ b/services/api-server/src/api_server/html5.py
@@ -339,6 +339,52 @@ def render_html5_project_report(project_id: str, report: dict | None) -> str:
"""
+def render_html5_object_report(
+ project_id: str,
+ impact: object,
+ *,
+ access: object | None = None,
+ privacy: object | None = None,
+ runtime: Iterable[object] | None = None,
+ integrations: Iterable[object] | None = None,
+ oob: bool = False,
+) -> str:
+ obj = getattr(impact, "object", None)
+ name = getattr(obj, "qualified_name", None) or getattr(obj, "name", None) or getattr(impact, "object_name", "object")
+ grants = getattr(access, "grants", []) if access is not None else []
+ markers = getattr(privacy, "markers", []) if privacy is not None else []
+ runtime_items = list(runtime or [])
+ integration_items = list(integrations or [])
+ metrics = [
+ ("Routines", len(getattr(impact, "routines", []) or [])),
+ ("Commands", len(getattr(impact, "commands", []) or [])),
+ ("Reads", len(getattr(impact, "query_tables", []) or [])),
+ ("Writes", len(getattr(impact, "writes", []) or [])),
+ ("Roles", len(grants) or len(getattr(impact, "roles", []) or [])),
+ ("Runtime", len(runtime_items)),
+ ("Privacy", len(markers)),
+ ("Integrations", len(integration_items)),
+ ]
+ oob_attr = ' hx-swap-oob="outerHTML"' if oob else ""
+ return f"""
+
+
Отчет объекта
+
+ {escape(str(name))}
+ server focused summary
+
+
{''.join(_metric(label, value) for label, value in metrics)}
+
+ """
+
+
def render_html5_review(project_id: str, findings: list[dict] | None) -> str:
if findings is None:
return f"""
diff --git a/services/api-server/src/api_server/main.py b/services/api-server/src/api_server/main.py
index 3183db3..d5a8d0c 100644
--- a/services/api-server/src/api_server/main.py
+++ b/services/api-server/src/api_server/main.py
@@ -48,6 +48,7 @@ from api_server.html5 import (
render_html5_metadata_apply_result,
render_html5_metadata_preview_result,
render_html5_object_context,
+ render_html5_object_report,
render_html5_project_setup,
render_html5_project_rows,
render_html5_project_report,
@@ -1784,8 +1785,17 @@ async def html5_project_object_context(project_id: str, object_name: str) -> Res
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 ""
symbol_context = render_html5_symbol_detail(project_id, symbol_references, oob=True)
+ report_context = render_html5_object_report(
+ project_id,
+ impact,
+ access=access,
+ privacy=privacy,
+ runtime=runtime,
+ integrations=integrations,
+ oob=True,
+ )
return Response(
- object_context + flowchart_context + source_context + symbol_context,
+ object_context + flowchart_context + source_context + symbol_context + report_context,
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 fda668d..b89c7be 100644
--- a/services/api-server/tests/test_api.py
+++ b/services/api-server/tests/test_api.py
@@ -334,6 +334,9 @@ def test_html5_object_context_fragment(tmp_path: Path):
assert "data-html5-symbol-detail" in context.text
assert "Символ · DOCUMENT" in context.text
assert "HAS_ATTRIBUTE" in context.text
+ assert "data-html5-project-report" in context.text
+ assert "Отчет объекта" in context.text
+ assert "server focused summary" in context.text
assert "1 signals" in context.text
assert "1 errors" in context.text
assert "125.0 ms" in context.text