v9.12: remove all edges from graph (frontend + backend)

This commit is contained in:
Naeel
2026-04-16 15:39:01 +03:00
parent 2ec13f85f2
commit 2813d52d3b
3 changed files with 16 additions and 140 deletions
+7 -96
View File
@@ -1,10 +1,8 @@
from fastapi import FastAPI, Header, HTTPException, Request
from fastapi.responses import StreamingResponse
from fastapi.staticfiles import StaticFiles
import httpx
from typing import Annotated
import asyncio
import json
import time
app = FastAPI()
@@ -193,21 +191,6 @@ async def get_graph(
if cnt and realm_name:
realm_to_platform[realm_name] = uid_d
# Build directed edges from dependencies/dependentInstances
# Arrow points TO the dependency (what you depend on)
edge_set: set[tuple[str, str]] = set()
for uid_d, inst_d in detail_map.items():
if uid_d not in allowed_uids:
continue
for dep in inst_d.get("dependencies", []) or []:
src = dep.get("uid") or dep.get("instanceUid") or ""
if src and src in allowed_uids and src != uid_d:
edge_set.add((uid_d, src)) # uid_d depends on src, arrow uid_d→src
for dep_on in inst_d.get("dependentInstances", []) or []:
dst = dep_on.get("uid") or dep_on.get("instanceUid") or ""
if dst and dst in allowed_uids and dst != uid_d:
edge_set.add((dst, uid_d)) # dst depends on uid_d, arrow dst→uid_d
nodes = []
for uid_i in allowed_uids:
i = uid_to_inst.get(uid_i, {})
@@ -241,22 +224,21 @@ async def get_graph(
for _n in nodes:
_l = _n.get("lane", "unknown")
_lane_counts[_l] = _lane_counts.get(_l, 0) + 1
print(f"[GRAPH] Lanes: {_lane_counts}, nodes: {len(nodes)}, edges: {len(edge_set)}", flush=True)
print(f"[GRAPH] Lanes: {_lane_counts}, nodes: {len(nodes)}", flush=True)
for _n in nodes:
if _n["lane"] in ("platform", "singleton"):
print(f" {_n['lane'].upper()}: {_n['label']} | svc={_n['svc']}", flush=True)
edges = [{"source": s, "target": t} for s, t in sorted(edge_set)]
base_graph = {"nodes": nodes, "edges": edges}
base_graph = {"nodes": nodes, "edges": []}
GRAPH_CACHE[cache_key] = (now, base_graph)
# Return full graph fast
if not root_uid:
return {
"nodes": base_graph["nodes"],
"edges": base_graph["edges"],
"edges": [],
"total_nodes": len(base_graph["nodes"]),
"total_edges": len(base_graph["edges"]),
"total_edges": 0,
"cached": bool(cached),
}
@@ -264,87 +246,16 @@ async def get_graph(
if root_uid not in node_ids:
return {"nodes": [], "edges": [], "total_nodes": 0, "total_edges": 0, "cached": bool(cached)}
adj: dict[str, set[str]] = {uid: set() for uid in node_ids}
for e in base_graph["edges"]:
s, t = e["source"], e["target"]
if s in adj and t in adj:
adj[s].add(t)
adj[t].add(s)
frontier = {root_uid}
seen = {root_uid}
for _ in range(depth):
nxt = set()
for node in frontier:
nxt |= adj.get(node, set())
nxt -= seen
if not nxt:
break
seen |= nxt
frontier = nxt
sub_nodes = [n for n in base_graph["nodes"] if n["id"] in seen]
sub_edges = [e for e in base_graph["edges"] if e["source"] in seen and e["target"] in seen]
sub_nodes = [n for n in base_graph["nodes"] if n["id"] == root_uid]
return {
"nodes": sub_nodes,
"edges": sub_edges,
"edges": [],
"total_nodes": len(sub_nodes),
"total_edges": len(sub_edges),
"total_edges": 0,
"cached": bool(cached),
}
@app.get("/api/instances/stream")
async def stream_instances(
request: Request,
x_deck_token: Annotated[str | None, Header()] = None,
x_deck_env: Annotated[str | None, Header()] = None,
):
if not x_deck_token:
raise HTTPException(status_code=401, detail="Token required")
_, deck_api = resolve_deck_api(x_deck_env)
all_instances = await fetch_all_instances(x_deck_token, deck_api)
uid_to_inst = {
i.get("instanceUid"): i
for i in all_instances
if i.get("instanceUid")
}
async def generate():
sem = asyncio.Semaphore(20)
queue: asyncio.Queue = asyncio.Queue()
total = len(uid_to_inst)
async def fetch_one(uid: str, client: httpx.AsyncClient):
async with sem:
try:
r = await client.get(
f"{deck_api}/index.cfm/instances/{uid}",
headers=auth_headers(x_deck_token),
)
detail = None if r.status_code >= 400 else r.json().get("instance")
except Exception:
detail = None
await queue.put((uid, detail))
async with httpx.AsyncClient(timeout=25) as shared_client:
tasks = [
asyncio.create_task(fetch_one(uid, shared_client))
for uid in uid_to_inst
]
for _ in range(total):
uid, detail = await queue.get()
row = dict(uid_to_inst.get(uid, {}))
if detail:
row["_detail"] = detail
yield json.dumps(row, ensure_ascii=False) + "\n"
yield json.dumps({"_done": True, "total": total}, ensure_ascii=False) + "\n"
return StreamingResponse(generate(), media_type="application/x-ndjson")
@app.get("/api/instances/{uid}")
async def get_instance(
request: Request,