Add relationship-aware graph flow
This commit is contained in:
parent
9bd41c5982
commit
440ca7510f
11 changed files with 567 additions and 80 deletions
|
|
@ -91,12 +91,20 @@ class VisualizationTests(unittest.TestCase):
|
|||
viewport_logic = script.split("function viewportForPositions", 1)[1].split(
|
||||
"function selectNode", 1
|
||||
)[0]
|
||||
relation_constants = script.split("const relationStyles", 1)[1].split("const $", 1)[0]
|
||||
relation_logic = script.split("function relationHash", 1)[1].split(
|
||||
"function applyViewport", 1
|
||||
)[0]
|
||||
topology_logic = script.split("function analyzeTopology", 1)[1].split(
|
||||
"function renderNeighborhood", 1
|
||||
)[0]
|
||||
harness = (
|
||||
"const defaultViewport = Object.freeze({x: -600, y: -410, width: 1200, height: 820});\n"
|
||||
"function viewportForPositions"
|
||||
"const relationStyles"
|
||||
+ relation_constants
|
||||
+ "function relationHash"
|
||||
+ relation_logic
|
||||
+ "function viewportForPositions"
|
||||
+ viewport_logic
|
||||
+ "function analyzeTopology"
|
||||
+ topology_logic
|
||||
|
|
@ -141,6 +149,42 @@ const centered = viewportCenteredOn(
|
|||
if (centered.width !== 500 || centered.height !== 300) fail("center preserves zoom");
|
||||
if (centered.x !== positions.get("child-two").x - 250) fail("center x");
|
||||
if (centered.y !== positions.get("child-two").y - 150) fail("center y");
|
||||
if (relationStyle("calls").family !== "Execution") fail("calls family");
|
||||
if (relationStyle("reads").flow !== "reverse") fail("reads flow direction");
|
||||
if (relationStyle("documents").flow !== null) fail("documents excluded from flow");
|
||||
if (relationStyle("unknown_relation").family !== "Other") fail("fallback relation family");
|
||||
const flowData = {
|
||||
root: "primary",
|
||||
depth: 2,
|
||||
nodes: [
|
||||
{node_id: "primary"},
|
||||
{node_id: "caller"},
|
||||
{node_id: "dependency"},
|
||||
{node_id: "reader"},
|
||||
{node_id: "document"},
|
||||
],
|
||||
edges: [
|
||||
{source_id: "caller", relation: "calls", target_id: "primary"},
|
||||
{source_id: "primary", relation: "depends_on", target_id: "dependency"},
|
||||
{source_id: "primary", relation: "reads", target_id: "reader"},
|
||||
{source_id: "document", relation: "documents", target_id: "primary"},
|
||||
],
|
||||
};
|
||||
const flow = buildFlowGraph(flowData);
|
||||
const flowIds = new Set(flow.nodes.map((node) => node.node_id));
|
||||
if (!flowIds.has("caller") || !flowIds.has("dependency") || !flowIds.has("reader")) {
|
||||
fail("upstream flow membership");
|
||||
}
|
||||
if (flowIds.has("document")) fail("evidence leaked into flow");
|
||||
const flowPositions = layoutFlow(flow.nodes, flow.root, flow.topology);
|
||||
if (flowPositions.get("primary").x !== 0) fail("flow destination position");
|
||||
if (flowPositions.get("caller").x >= flowPositions.get("primary").x) {
|
||||
fail("flow upstream direction");
|
||||
}
|
||||
const dependencyEdge = flow.edges.find((edge) => edge.relation === "depends_on");
|
||||
if (dependencyEdge.source_id !== "dependency" || dependencyEdge.target_id !== "primary") {
|
||||
fail("dependency semantic reversal");
|
||||
}
|
||||
"""
|
||||
)
|
||||
result = subprocess.run(
|
||||
|
|
@ -188,6 +232,8 @@ if (centered.y !== positions.get("child-two").y - 150) fail("center y");
|
|||
self.assertIn('id="view-nodes"', html)
|
||||
self.assertIn('id="view-flow"', html)
|
||||
self.assertIn('id="neighborhood-sections"', html)
|
||||
self.assertIn('id="relationship-key"', html)
|
||||
self.assertIn('id="relationship-key-list"', html)
|
||||
self.assertNotIn('id="details"', html)
|
||||
self.assertIn(".empty[hidden] { display: none; }", html)
|
||||
self.assertIn("html, body { height: 100%; overflow: hidden; }", html)
|
||||
|
|
@ -204,11 +250,19 @@ if (centered.y !== positions.get("child-two").y - 150) fail("center y");
|
|||
self.assertIn("beginDialogDrag", html)
|
||||
self.assertIn('setupPanelResizer("left")', html)
|
||||
self.assertIn('setupPanelResizer("right")', html)
|
||||
self.assertIn("Primary focus", html)
|
||||
self.assertIn("Edge & context", html)
|
||||
self.assertIn("Focus node", html)
|
||||
self.assertIn("Outgoing paths", html)
|
||||
self.assertIn("Incoming & lateral", html)
|
||||
self.assertNotIn(">Children<", html)
|
||||
self.assertIn("distanceShade", html)
|
||||
self.assertIn("viewportForPositions", html)
|
||||
self.assertIn("centerSelectedNode", html)
|
||||
self.assertIn("relationStyles", html)
|
||||
self.assertIn("appendRelationMarker", html)
|
||||
self.assertIn("renderRelationshipKey", html)
|
||||
self.assertIn("semanticFlowEdge", html)
|
||||
self.assertIn("buildFlowGraph", html)
|
||||
self.assertIn("layoutFlow", html)
|
||||
self.assertIn("filterByDescriptor", html)
|
||||
self.assertIn("api(`filter?${params}`)", html)
|
||||
self.assertIn('setViewMode("flow")', html)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue