Add HTML5 flowchart fragment
This commit is contained in:
@@ -231,6 +231,7 @@ def render_html5_editor(
|
||||
{render_html5_symbols(snapshot, q, project_id)}
|
||||
</div>
|
||||
{render_html5_symbol_detail(project_id, None)}
|
||||
{render_html5_flowchart(project_id, None)}
|
||||
{render_html5_project_report(project_id, None)}
|
||||
{render_html5_review(project_id, None)}
|
||||
{render_html5_authoring_preview(project_id, None)}
|
||||
@@ -246,6 +247,48 @@ def render_html5_editor(
|
||||
return _page(f"SFERA HTML5 - {project_id}", content)
|
||||
|
||||
|
||||
def render_html5_flowchart(project_id: str, flowchart: object | None) -> str:
|
||||
if flowchart is None:
|
||||
return f"""
|
||||
<div
|
||||
class="flowchart-panel"
|
||||
data-html5-flowchart
|
||||
hx-get="/html5/projects/{quote(project_id)}/flowchart"
|
||||
hx-trigger="load"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<div class="panel-title">Карта связей</div>
|
||||
<p class="muted padded">Сервер собирает граф проекта.</p>
|
||||
</div>
|
||||
"""
|
||||
nodes = getattr(flowchart, "nodes", []) or []
|
||||
edges = getattr(flowchart, "edges", []) or []
|
||||
mode = str(getattr(flowchart, "mode", "overview"))
|
||||
body = "".join(_flowchart_edge_item(item, nodes) for item in edges[:10])
|
||||
if not body:
|
||||
body = "".join(_flowchart_node_item(item) for item in nodes[:10])
|
||||
if not body:
|
||||
body = '<p class="muted padded">Связи проекта не найдены</p>'
|
||||
return f"""
|
||||
<div
|
||||
class="flowchart-panel"
|
||||
data-html5-flowchart
|
||||
hx-get="/html5/projects/{quote(project_id)}/flowchart"
|
||||
hx-trigger="every 30s"
|
||||
hx-swap="outerHTML"
|
||||
>
|
||||
<div class="panel-title">Карта связей · {escape(mode)}</div>
|
||||
<dl class="report-grid">
|
||||
{_metric("Nodes", len(nodes))}
|
||||
{_metric("Edges", len(edges))}
|
||||
{_metric("Total nodes", getattr(flowchart, "total_nodes", 0))}
|
||||
{_metric("Total edges", getattr(flowchart, "total_edges", 0))}
|
||||
</dl>
|
||||
<div class="compact-list">{body}</div>
|
||||
</div>
|
||||
"""
|
||||
|
||||
|
||||
def render_html5_project_report(project_id: str, report: dict | None) -> str:
|
||||
if report is None:
|
||||
return f"""
|
||||
@@ -1527,6 +1570,19 @@ def _flowchart_edge_item(edge: object, nodes: Iterable[object]) -> str:
|
||||
"""
|
||||
|
||||
|
||||
def _flowchart_node_item(node: object) -> str:
|
||||
name = str(getattr(node, "qualified_name", "") or getattr(node, "label", "") or "node")
|
||||
kind = str(getattr(node, "kind", "") or "NODE")
|
||||
level = getattr(node, "level", 0)
|
||||
count = getattr(node, "count", 1)
|
||||
return f"""
|
||||
<article class="object-context-item" data-html5-flowchart-node="{escape(kind)}">
|
||||
<strong>{escape(name)}</strong>
|
||||
<small>{escape(kind)} · level {escape(str(level))} · count {escape(str(count))}</small>
|
||||
</article>
|
||||
"""
|
||||
|
||||
|
||||
def _authoring_diff_item(line: object) -> str:
|
||||
kind = str(getattr(line, "kind", ""))
|
||||
text = str(getattr(line, "text", ""))
|
||||
|
||||
@@ -43,6 +43,7 @@ from api_server.html5 import (
|
||||
render_html5_authoring_preview_result,
|
||||
render_html5_authoring_rollback_result,
|
||||
render_html5_editor,
|
||||
render_html5_flowchart,
|
||||
render_html5_index,
|
||||
render_html5_metadata_apply_result,
|
||||
render_html5_metadata_preview_result,
|
||||
@@ -1741,6 +1742,20 @@ async def html5_project_review(project_id: str) -> Response:
|
||||
)
|
||||
|
||||
|
||||
@app.get("/html5/projects/{project_id}/flowchart")
|
||||
async def html5_project_flowchart(
|
||||
project_id: str,
|
||||
focus: str | None = None,
|
||||
depth: int = 1,
|
||||
limit: int = 80,
|
||||
) -> Response:
|
||||
flowchart = await project_flowchart(project_id, focus=focus, depth=depth, limit=limit)
|
||||
return Response(
|
||||
render_html5_flowchart(project_id, flowchart),
|
||||
media_type="text/html; charset=utf-8",
|
||||
)
|
||||
|
||||
|
||||
@app.get("/html5/projects/{project_id}/objects/context/{object_name}")
|
||||
async def html5_project_object_context(project_id: str, object_name: str) -> Response:
|
||||
schema = await get_object_schema(project_id, object_name)
|
||||
|
||||
@@ -108,6 +108,8 @@ def test_html5_server_rendered_project_editor(tmp_path: Path):
|
||||
assert "data-html5-editor" in editor.text
|
||||
assert "data-html5-symbol-results" in editor.text
|
||||
assert "data-html5-symbol-detail" in editor.text
|
||||
assert "data-html5-flowchart" in editor.text
|
||||
assert f'hx-get="/html5/projects/{project_id}/flowchart"' in editor.text
|
||||
assert "data-html5-project-report" in editor.text
|
||||
assert f'hx-get="/html5/projects/{project_id}/report"' in editor.text
|
||||
assert "data-html5-review" in editor.text
|
||||
@@ -335,6 +337,38 @@ def test_html5_object_context_fragment(tmp_path: Path):
|
||||
assert "<html" not in context.text
|
||||
|
||||
|
||||
def test_html5_flowchart_fragment(tmp_path: Path):
|
||||
client = TestClient(app)
|
||||
project_id = f"html5-flowchart-{uuid4()}"
|
||||
(tmp_path / "module.bsl").write_text(
|
||||
"""
|
||||
Процедура ПровестиЗаказ()
|
||||
ПроверитьОстатки();
|
||||
Движения.ОстаткиТоваров.Записать();
|
||||
КонецПроцедуры
|
||||
|
||||
Процедура ПроверитьОстатки()
|
||||
КонецПроцедуры
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
indexed = client.post("/projects/index", json={"path": str(tmp_path), "project_id": project_id})
|
||||
assert indexed.status_code == 200
|
||||
|
||||
flowchart = client.get(
|
||||
f"/html5/projects/{project_id}/flowchart",
|
||||
params={"focus": "ПровестиЗаказ"},
|
||||
)
|
||||
assert flowchart.status_code == 200
|
||||
assert "text/html" in flowchart.headers["content-type"]
|
||||
assert "data-html5-flowchart" in flowchart.text
|
||||
assert "Карта связей" in flowchart.text
|
||||
assert "Nodes" in flowchart.text
|
||||
assert "Edges" in flowchart.text
|
||||
assert "ПровестиЗаказ" in flowchart.text or "ПроверитьОстатки" in flowchart.text
|
||||
assert "<html" not in flowchart.text
|
||||
|
||||
|
||||
def test_html5_project_setup_renders_server_fragments():
|
||||
client = TestClient(app)
|
||||
project_id = f"html5-setup-{uuid4()}"
|
||||
|
||||
Reference in New Issue
Block a user