feat(topology): return diagram presentation styles
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,11 @@
|
|||||||
from topology_api.db import read_cursor
|
from topology_api.db import read_cursor
|
||||||
|
|
||||||
|
|
||||||
|
def _require_presentation(condition, message):
|
||||||
|
if not condition:
|
||||||
|
raise RuntimeError(f"presentation_config_error: {message}")
|
||||||
|
|
||||||
|
|
||||||
def fetch_missions(base_code):
|
def fetch_missions(base_code):
|
||||||
"""Return missions for a base with their latest recorded event."""
|
"""Return missions for a base with their latest recorded event."""
|
||||||
with read_cursor() as cur:
|
with read_cursor() as cur:
|
||||||
@@ -249,6 +254,10 @@ def fetch_layout():
|
|||||||
dl.name AS layout_name,
|
dl.name AS layout_name,
|
||||||
dl.canvas_width,
|
dl.canvas_width,
|
||||||
dl.canvas_height,
|
dl.canvas_height,
|
||||||
|
COALESCE(layout_theme.id, default_theme.id) AS theme_id,
|
||||||
|
COALESCE(layout_theme.theme_key, default_theme.theme_key) AS theme_key,
|
||||||
|
COALESCE(layout_theme.name, default_theme.name) AS theme_name,
|
||||||
|
COALESCE(layout_theme.tokens, default_theme.tokens) AS theme_tokens,
|
||||||
dn.node_key,
|
dn.node_key,
|
||||||
dn.component_id,
|
dn.component_id,
|
||||||
c.component_key,
|
c.component_key,
|
||||||
@@ -269,12 +278,18 @@ def fetch_layout():
|
|||||||
ON member_component.id = member.component_id
|
ON member_component.id = member.component_id
|
||||||
WHERE member.diagram_node_id = dn.id
|
WHERE member.diagram_node_id = dn.id
|
||||||
) members ON true
|
) members ON true
|
||||||
|
LEFT JOIN diagram_themes layout_theme
|
||||||
|
ON layout_theme.id = dl.theme_id
|
||||||
|
LEFT JOIN diagram_themes default_theme
|
||||||
|
ON default_theme.base_id = dl.base_id
|
||||||
|
AND default_theme.is_default = true
|
||||||
WHERE dl.base_id = (SELECT id FROM bases WHERE code = 'guanghan')
|
WHERE dl.base_id = (SELECT id FROM bases WHERE code = 'guanghan')
|
||||||
AND dl.is_default = true
|
AND dl.is_default = true
|
||||||
ORDER BY dn.z_index, dn.node_key
|
ORDER BY dn.z_index, dn.node_key
|
||||||
""")
|
""")
|
||||||
nodes = []
|
nodes = []
|
||||||
layout_info = None
|
layout_info = None
|
||||||
|
theme_info = None
|
||||||
for row in cur.fetchall():
|
for row in cur.fetchall():
|
||||||
if layout_info is None:
|
if layout_info is None:
|
||||||
layout_info = {
|
layout_info = {
|
||||||
@@ -282,6 +297,13 @@ def fetch_layout():
|
|||||||
"name": row["layout_name"],
|
"name": row["layout_name"],
|
||||||
"canvasWidth": float(row["canvas_width"]),
|
"canvasWidth": float(row["canvas_width"]),
|
||||||
"canvasHeight": float(row["canvas_height"]),
|
"canvasHeight": float(row["canvas_height"]),
|
||||||
|
"themeKey": row["theme_key"],
|
||||||
|
}
|
||||||
|
theme_info = {
|
||||||
|
"id": row["theme_id"],
|
||||||
|
"key": row["theme_key"],
|
||||||
|
"name": row["theme_name"],
|
||||||
|
"tokens": row["theme_tokens"] or {},
|
||||||
}
|
}
|
||||||
nodes.append({
|
nodes.append({
|
||||||
"nodeKey": row["node_key"],
|
"nodeKey": row["node_key"],
|
||||||
@@ -298,4 +320,111 @@ def fetch_layout():
|
|||||||
"decorations": row["decorations"] or {},
|
"decorations": row["decorations"] or {},
|
||||||
"memberKeys": row["member_keys"] or [],
|
"memberKeys": row["member_keys"] or [],
|
||||||
})
|
})
|
||||||
return {"layout": layout_info, "nodes": nodes} if layout_info else None
|
if layout_info is None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
_require_presentation(theme_info and theme_info["id"], "default theme missing")
|
||||||
|
theme_id_val = theme_info["id"]
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT style_key, display_name, fill_color, stroke_color,
|
||||||
|
stroke_width, corner_radius, title_color, meta_color,
|
||||||
|
hint_color
|
||||||
|
FROM diagram_node_styles
|
||||||
|
WHERE theme_id = %(theme)s
|
||||||
|
ORDER BY style_key
|
||||||
|
""", {"theme": theme_id_val})
|
||||||
|
node_styles = {
|
||||||
|
row["style_key"]: {
|
||||||
|
"displayName": row["display_name"],
|
||||||
|
"fillColor": row["fill_color"],
|
||||||
|
"strokeColor": row["stroke_color"],
|
||||||
|
"strokeWidth": float(row["stroke_width"]),
|
||||||
|
"cornerRadius": float(row["corner_radius"]),
|
||||||
|
"titleColor": row["title_color"],
|
||||||
|
"metaColor": row["meta_color"],
|
||||||
|
"hintColor": row["hint_color"],
|
||||||
|
}
|
||||||
|
for row in cur.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT connection_type, display_name, stroke_color, stroke_width,
|
||||||
|
dash_array, line_cap, legend_group
|
||||||
|
FROM diagram_edge_styles
|
||||||
|
WHERE theme_id = %(theme)s
|
||||||
|
ORDER BY connection_type
|
||||||
|
""", {"theme": theme_id_val})
|
||||||
|
edge_styles = {
|
||||||
|
row["connection_type"]: {
|
||||||
|
"displayName": row["display_name"],
|
||||||
|
"strokeColor": row["stroke_color"],
|
||||||
|
"strokeWidth": float(row["stroke_width"]),
|
||||||
|
"dashArray": row["dash_array"],
|
||||||
|
"lineCap": row["line_cap"],
|
||||||
|
"legendGroup": row["legend_group"],
|
||||||
|
}
|
||||||
|
for row in cur.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT decoration_key, display_name, fill_color, stroke_color,
|
||||||
|
stroke_width, label, label_color, render_params
|
||||||
|
FROM diagram_decoration_styles
|
||||||
|
WHERE theme_id = %(theme)s
|
||||||
|
ORDER BY decoration_key
|
||||||
|
""", {"theme": theme_id_val})
|
||||||
|
decoration_styles = {
|
||||||
|
row["decoration_key"]: {
|
||||||
|
"displayName": row["display_name"],
|
||||||
|
"fillColor": row["fill_color"],
|
||||||
|
"strokeColor": row["stroke_color"],
|
||||||
|
"strokeWidth": float(row["stroke_width"]),
|
||||||
|
"label": row["label"],
|
||||||
|
"labelColor": row["label_color"],
|
||||||
|
"renderParams": row["render_params"] or {},
|
||||||
|
}
|
||||||
|
for row in cur.fetchall()
|
||||||
|
}
|
||||||
|
|
||||||
|
cur.execute("""
|
||||||
|
SELECT legend_key, label, item_type, style_ref, display_order
|
||||||
|
FROM diagram_legend_items
|
||||||
|
WHERE theme_id = %(theme)s
|
||||||
|
AND is_visible = true
|
||||||
|
ORDER BY display_order, legend_key
|
||||||
|
""", {"theme": theme_id_val})
|
||||||
|
legend_items = [
|
||||||
|
{
|
||||||
|
"key": row["legend_key"],
|
||||||
|
"label": row["label"],
|
||||||
|
"itemType": row["item_type"],
|
||||||
|
"styleRef": row["style_ref"],
|
||||||
|
"displayOrder": row["display_order"],
|
||||||
|
}
|
||||||
|
for row in cur.fetchall()
|
||||||
|
]
|
||||||
|
|
||||||
|
missing_node_styles = {
|
||||||
|
node["styleKey"] for node in nodes
|
||||||
|
} - set(node_styles)
|
||||||
|
_require_presentation(
|
||||||
|
not missing_node_styles,
|
||||||
|
f"missing node styles: {sorted(missing_node_styles)}",
|
||||||
|
)
|
||||||
|
|
||||||
|
return {
|
||||||
|
"layout": layout_info,
|
||||||
|
"nodes": nodes,
|
||||||
|
"presentation": {
|
||||||
|
"theme": {
|
||||||
|
"key": theme_info["key"],
|
||||||
|
"name": theme_info["name"],
|
||||||
|
"tokens": theme_info["tokens"],
|
||||||
|
},
|
||||||
|
"nodeStyles": node_styles,
|
||||||
|
"edgeStyles": edge_styles,
|
||||||
|
"decorationStyles": decoration_styles,
|
||||||
|
"legendItems": legend_items,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user