Make HTML5 flowchart nodes navigable
This commit is contained in:
@@ -275,9 +275,9 @@ def render_html5_flowchart(
|
|||||||
nodes = getattr(flowchart, "nodes", []) or []
|
nodes = getattr(flowchart, "nodes", []) or []
|
||||||
edges = getattr(flowchart, "edges", []) or []
|
edges = getattr(flowchart, "edges", []) or []
|
||||||
mode = str(getattr(flowchart, "mode", "overview"))
|
mode = str(getattr(flowchart, "mode", "overview"))
|
||||||
body = "".join(_flowchart_edge_item(item, nodes) for item in edges[:10])
|
body = "".join(_flowchart_edge_item(project_id, item, nodes, normalized_depth) for item in edges[:10])
|
||||||
if not body:
|
if not body:
|
||||||
body = "".join(_flowchart_node_item(item) for item in nodes[:10])
|
body = "".join(_flowchart_node_item(project_id, item, normalized_depth) for item in nodes[:10])
|
||||||
if not body:
|
if not body:
|
||||||
body = '<p class="muted padded">Связи проекта не найдены</p>'
|
body = '<p class="muted padded">Связи проекта не найдены</p>'
|
||||||
return f"""
|
return f"""
|
||||||
@@ -482,7 +482,7 @@ def render_html5_object_context(
|
|||||||
compact_body += ''.join(_named_node_item("read", item) for item in query_tables[:8])
|
compact_body += ''.join(_named_node_item("read", item) for item in query_tables[:8])
|
||||||
compact_body += ''.join(_named_node_item("write", item) for item in writes[:8])
|
compact_body += ''.join(_named_node_item("write", item) for item in writes[:8])
|
||||||
compact_body += ''.join(_named_node_item("call", item) for item in callees[:8])
|
compact_body += ''.join(_named_node_item("call", item) for item in callees[:8])
|
||||||
compact_body += ''.join(_flowchart_edge_item(item, flow_nodes) for item in flow_edges[:8])
|
compact_body += ''.join(_flowchart_edge_item(project_id, item, flow_nodes, 1) for item in flow_edges[:8])
|
||||||
compact_body += ''.join(_named_node_item("routine", item) for item in routines[:8])
|
compact_body += ''.join(_named_node_item("routine", item) for item in routines[:8])
|
||||||
compact_body += ''.join(_named_node_item("job", item) for item in jobs[:6])
|
compact_body += ''.join(_named_node_item("job", item) for item in jobs[:6])
|
||||||
compact_body = compact_body or '<p class="muted padded">Impact-связи не найдены</p>'
|
compact_body = compact_body or '<p class="muted padded">Impact-связи не найдены</p>'
|
||||||
@@ -503,7 +503,7 @@ def render_html5_object_context(
|
|||||||
compact_body += ''.join(_named_node_item("read", item) for item in query_tables[:4])
|
compact_body += ''.join(_named_node_item("read", item) for item in query_tables[:4])
|
||||||
compact_body += ''.join(_named_node_item("write", item) for item in writes[:4])
|
compact_body += ''.join(_named_node_item("write", item) for item in writes[:4])
|
||||||
compact_body += ''.join(_named_node_item("call", item) for item in callees[:6])
|
compact_body += ''.join(_named_node_item("call", item) for item in callees[:6])
|
||||||
compact_body += ''.join(_flowchart_edge_item(item, flow_nodes) for item in flow_edges[:8])
|
compact_body += ''.join(_flowchart_edge_item(project_id, item, flow_nodes, 1) for item in flow_edges[:8])
|
||||||
compact_body += ''.join(_runtime_summary_item(item) for item in runtime_items[:6])
|
compact_body += ''.join(_runtime_summary_item(item) for item in runtime_items[:6])
|
||||||
compact_body += ''.join(_knowledge_record_item(item) for item in knowledge_items[:6])
|
compact_body += ''.join(_knowledge_record_item(item) for item in knowledge_items[:6])
|
||||||
compact_body += ''.join(_privacy_marker_item(item) for item in privacy_markers[:6])
|
compact_body += ''.join(_privacy_marker_item(item) for item in privacy_markers[:6])
|
||||||
@@ -1734,7 +1734,20 @@ def _integration_endpoint_item(endpoint: object) -> str:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
def _flowchart_edge_item(edge: object, nodes: Iterable[object]) -> str:
|
def _flowchart_focus_link(project_id: str, name: str, depth: int) -> str:
|
||||||
|
url = _flowchart_url(project_id, name, depth)
|
||||||
|
return f"""
|
||||||
|
<a
|
||||||
|
href="{url}"
|
||||||
|
hx-get="{url}"
|
||||||
|
hx-target="[data-html5-flowchart]"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
data-html5-flowchart-focus="{escape(name)}"
|
||||||
|
>{escape(name)}</a>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def _flowchart_edge_item(project_id: str, edge: object, nodes: Iterable[object], depth: int) -> str:
|
||||||
node_names = {
|
node_names = {
|
||||||
str(getattr(node, "id", "")): str(getattr(node, "qualified_name", "") or getattr(node, "label", ""))
|
str(getattr(node, "id", "")): str(getattr(node, "qualified_name", "") or getattr(node, "label", ""))
|
||||||
for node in nodes
|
for node in nodes
|
||||||
@@ -1746,7 +1759,7 @@ def _flowchart_edge_item(edge: object, nodes: Iterable[object]) -> str:
|
|||||||
return f"""
|
return f"""
|
||||||
<article class="object-context-item" data-html5-object-context-item="flow-edge">
|
<article class="object-context-item" data-html5-object-context-item="flow-edge">
|
||||||
<strong>{escape(label)}</strong>
|
<strong>{escape(label)}</strong>
|
||||||
<small>{escape(source)} -> {escape(target)} · {escape(kind)}</small>
|
<small>{_flowchart_focus_link(project_id, source, depth)} -> {_flowchart_focus_link(project_id, target, depth)} · {escape(kind)}</small>
|
||||||
</article>
|
</article>
|
||||||
"""
|
"""
|
||||||
|
|
||||||
@@ -1779,13 +1792,21 @@ def _flowchart_depth_actions(project_id: str, focus: str | None, active_depth: i
|
|||||||
return f'<nav class="object-actions" data-html5-flowchart-actions>{"".join(buttons)}</nav>'
|
return f'<nav class="object-actions" data-html5-flowchart-actions>{"".join(buttons)}</nav>'
|
||||||
|
|
||||||
|
|
||||||
def _flowchart_node_item(node: object) -> str:
|
def _flowchart_node_item(project_id: str, node: object, depth: int) -> str:
|
||||||
name = str(getattr(node, "qualified_name", "") or getattr(node, "label", "") or "node")
|
name = str(getattr(node, "qualified_name", "") or getattr(node, "label", "") or "node")
|
||||||
kind = str(getattr(node, "kind", "") or "NODE")
|
kind = str(getattr(node, "kind", "") or "NODE")
|
||||||
level = getattr(node, "level", 0)
|
level = getattr(node, "level", 0)
|
||||||
count = getattr(node, "count", 1)
|
count = getattr(node, "count", 1)
|
||||||
|
url = _flowchart_url(project_id, name, depth)
|
||||||
return f"""
|
return f"""
|
||||||
<article class="object-context-item" data-html5-flowchart-node="{escape(kind)}">
|
<article
|
||||||
|
class="object-context-item"
|
||||||
|
data-html5-flowchart-node="{escape(kind)}"
|
||||||
|
data-html5-flowchart-focus="{escape(name)}"
|
||||||
|
hx-get="{url}"
|
||||||
|
hx-target="[data-html5-flowchart]"
|
||||||
|
hx-swap="outerHTML"
|
||||||
|
>
|
||||||
<strong>{escape(name)}</strong>
|
<strong>{escape(name)}</strong>
|
||||||
<small>{escape(kind)} · level {escape(str(level))} · count {escape(str(count))}</small>
|
<small>{escape(kind)} · level {escape(str(level))} · count {escape(str(count))}</small>
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -341,6 +341,7 @@ def test_html5_object_context_fragment(tmp_path: Path):
|
|||||||
assert "https://api.example.local/orders" in context.text
|
assert "https://api.example.local/orders" in context.text
|
||||||
assert "OUTBOUND" in context.text
|
assert "OUTBOUND" in context.text
|
||||||
assert "data-html5-object-context-item=\"flow-edge\"" in context.text
|
assert "data-html5-object-context-item=\"flow-edge\"" in context.text
|
||||||
|
assert "data-html5-flowchart-focus" in context.text
|
||||||
assert "data-html5-flowchart" in context.text
|
assert "data-html5-flowchart" in context.text
|
||||||
assert 'hx-swap-oob="outerHTML"' in context.text
|
assert 'hx-swap-oob="outerHTML"' in context.text
|
||||||
assert "Карта связей · focus" in context.text
|
assert "Карта связей · focus" in context.text
|
||||||
@@ -427,6 +428,7 @@ def test_html5_flowchart_fragment(tmp_path: Path):
|
|||||||
assert "Depth 3" in flowchart.text
|
assert "Depth 3" in flowchart.text
|
||||||
assert "depth=2" in flowchart.text
|
assert "depth=2" in flowchart.text
|
||||||
assert 'hx-target="[data-html5-flowchart]"' in flowchart.text
|
assert 'hx-target="[data-html5-flowchart]"' in flowchart.text
|
||||||
|
assert "data-html5-flowchart-focus" in flowchart.text
|
||||||
assert 'hx-swap-oob="outerHTML"' not in flowchart.text
|
assert 'hx-swap-oob="outerHTML"' not in flowchart.text
|
||||||
assert "Карта связей" in flowchart.text
|
assert "Карта связей" in flowchart.text
|
||||||
assert "Nodes" in flowchart.text
|
assert "Nodes" in flowchart.text
|
||||||
|
|||||||
Reference in New Issue
Block a user