- Disable Topology Map panel in router.setup.ts - Comment out panel registration (line ~85) - Add comprehensive SHELVED.md documentation explaining: * Why feature was shelved (SVG text layout complexity, visual quality) * What was implemented (graph analysis, folder aggregation, etc.) * Lessons learned and better approaches for future * Alternative enhancement suggestions - Code remains in codebase for potential future revival - Recommend React Flow or HTML/CSS approach instead of SVG
VIEW-001: Project Topology Map
View Type: 🗺️ Meta View (replaces canvas with project-wide view)
Overview
A high-level "Google Maps" view of the entire project's component structure. Shows how components relate to each other as a navigable graph, with a "You Are Here" indicator and the ability to jump to any component.
Estimate: 4-5 days
Priority: HIGH
Complexity: Medium
Dependencies: VIEW-000 (Foundation)
The Problem
When working in a complex Noodl project:
- You can't see how many components exist or how they relate
- You lose track of where you are when deep in nested components
- There's no way to get a "big picture" view of the project architecture
- Finding a component means hunting through the Components Panel tree
The Solution
A visual map showing:
- Every component as a box/node
- Arrows showing which components use which others
- "You Are Here" highlight on the current component
- Click-to-navigate to any component
- Breadcrumb trail showing how you got to your current location
User Stories
-
As a new developer joining a project, I want to see the overall structure so I can understand how the app is organized.
-
As a developer debugging, I want to see where the current component fits in the hierarchy so I understand the context.
-
As a developer navigating, I want to click on any component in the map to jump directly to it.
-
As a developer planning, I want to see which components are reused in multiple places.
UI Design
Main View
┌─────────────────────────────────────────────────────────────────┐
│ Project Topology [Fit] [−][+]│
├─────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────┐ ┌─────────┐ ┌─────────┐ │
│ │ Login │ │ Home │ │ Profile │ 📄 PAGES │
│ │ Page │ │ Page │ │ Page │ │
│ └────┬────┘ └────┬────┘ └────┬────┘ │
│ │ │ │ │
│ │ ┌──────────┼───────────────┤ │
│ │ │ │ │ │
│ ▼ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────┐ ┌──────────────┐ │
│ │ AuthFlow │ │ NavBar │ │ UserCard │ 🧩 SHARED │
│ │ ★ YOU ARE │ │ (×3) │ │ (×2) │ │
│ │ HERE │ └─────────┘ └──────────────┘ │
│ └──────┬──────┘ │ │
│ │ │ │
│ ▼ ▼ │
│ ┌─────────────┐ ┌──────────────┐ │
│ │ LoginForm │ │ AvatarIcon │ 🔧 NESTED │
│ │ Component │ │ Component │ │
│ └─────────────┘ └──────────────┘ │
│ │
├─────────────────────────────────────────────────────────────────┤
│ 📍 Path: App Shell → Login Page → AuthFlow │
│ 📊 23 components total | 8 pages | 12 shared | 3 nested │
└─────────────────────────────────────────────────────────────────┘
Component Node Styling
| Component Type | Visual Style |
|---|---|
| Page | Larger box, 📄 icon, distinct color |
| Shared (used 2+ times) | Badge showing usage count (×3) |
| Current ("You Are Here") | Highlighted border, ★ indicator |
| Has subcomponents | Subtle "expandable" indicator |
| Orphan (unused) | Dimmed, warning style |
Interactions
- Click component → Jump to that component in canvas
- Hover component → Show tooltip with summary (node count, I/O ports)
- Double-click → Expand to show internal structure (optional)
- Drag to pan → Navigate large maps
- Scroll to zoom → Zoom in/out
- [Fit] button → Fit entire map in view
- Click breadcrumb → Navigate to that ancestor component
Technical Design
Data Model
interface TopologyNode {
component: ComponentModel;
name: string;
fullName: string;
type: 'page' | 'component';
usageCount: number; // How many places use this component
usedBy: string[]; // Which components use this one
uses: string[]; // Which components this one uses
depth: number; // Nesting depth from root
isCurrentComponent: boolean;
}
interface TopologyEdge {
from: string; // Component fullName
to: string; // Component fullName
count: number; // How many instances
}
interface TopologyGraph {
nodes: TopologyNode[];
edges: TopologyEdge[];
currentPath: string[]; // Breadcrumb path
}
Building the Graph
function buildTopologyGraph(project: ProjectModel): TopologyGraph {
const nodes: TopologyNode[] = [];
const edges: TopologyEdge[] = [];
// 1. Collect all components
project.forEachComponent((component) => {
nodes.push({
component,
name: component.name,
fullName: component.fullName,
type: isPageComponent(component) ? 'page' : 'component',
usageCount: 0,
usedBy: [],
uses: [],
depth: 0,
isCurrentComponent: false
});
});
// 2. Find all component usages (nodes of type that matches a component name)
nodes.forEach((node) => {
node.component.graph.forEachNode((graphNode) => {
if (isComponentInstance(graphNode)) {
const usedComponentName = graphNode.type.name;
const usedNode = nodes.find((n) => n.fullName === usedComponentName);
if (usedNode) {
usedNode.usageCount++;
usedNode.usedBy.push(node.fullName);
node.uses.push(usedComponentName);
edges.push({
from: node.fullName,
to: usedComponentName,
count: 1 // Aggregate later
});
}
}
});
});
// 3. Calculate depths (BFS from pages)
calculateDepths(nodes, edges);
return { nodes, edges, currentPath: [] };
}
Layout Algorithm
Use a hierarchical layout (like Dagre) to position nodes:
import dagre from 'dagre';
function layoutTopology(graph: TopologyGraph): PositionedTopologyGraph {
const g = new dagre.graphlib.Graph();
g.setGraph({ rankdir: 'TB', ranksep: 80, nodesep: 50 });
g.setDefaultEdgeLabel(() => ({}));
// Add nodes with estimated sizes
graph.nodes.forEach((node) => {
const width = node.type === 'page' ? 140 : 120;
const height = 60;
g.setNode(node.fullName, { width, height });
});
// Add edges
graph.edges.forEach((edge) => {
g.setEdge(edge.from, edge.to);
});
dagre.layout(g);
// Extract positions
return graph.nodes.map((node) => ({
...node,
x: g.node(node.fullName).x,
y: g.node(node.fullName).y
}));
}
Rendering
Could use:
- SVG - Simple, good for moderate sizes
- Canvas - Better performance for large graphs
- React Flow - Library specifically for this (already used elsewhere?)
Recommend starting with SVG for simplicity, refactor to Canvas if performance issues.
Implementation Phases
Phase 1: Data Collection (1 day)
- Implement
buildTopologyGraph()using VIEW-000 utilities - Correctly identify component instances vs regular nodes
- Calculate usage counts and relationships
- Determine page vs component classification
Verification:
- All components in project appear in graph
- Component usage relationships are correct
- Pages correctly identified
Phase 2: Layout Algorithm (1 day)
- Integrate Dagre.js for hierarchical layout
- Position pages at top, shared components in middle, nested at bottom
- Handle edge cases (cycles, orphans)
- Calculate viewport bounds
Verification:
- Layout produces non-overlapping nodes
- Hierarchy is visually clear
- Large graphs don't break
Phase 3: Basic Rendering (1 day)
- Create
TopologyMapViewReact component - Render nodes as styled boxes
- Render edges as lines/arrows
- Implement pan and zoom
- Add "Fit to View" button
Verification:
- Graph renders correctly
- Can pan and zoom
- Fit button works
Phase 4: Interactivity (1 day)
- Click node → Navigate to component
- Hover → Show tooltip
- Highlight current component
- Show breadcrumb path
- Add "You Are Here" indicator
Verification:
- Clicking navigates correctly
- Current component highlighted
- Breadcrumb shows path
Phase 5: Polish (0.5-1 day)
- Style refinement (colors, icons, badges)
- Add usage count badges
- Add orphan warnings
- Performance optimization if needed
- Add to Analysis Panel tabs
Verification:
- Visually polished
- Integrates with Analysis Panel
- Performance acceptable on large projects
Files to Create
packages/noodl-editor/src/editor/src/views/AnalysisPanel/
└── TopologyMapView/
├── index.ts
├── TopologyMapView.tsx
├── TopologyMapView.module.scss
├── TopologyNode.tsx
├── TopologyEdge.tsx
├── TopologyTooltip.tsx
├── Breadcrumbs.tsx
└── useTopologyGraph.ts
Success Criteria
- Shows all components in the project
- Correctly displays which components use which
- "You Are Here" correctly highlights current component
- Click navigation works
- Breadcrumb trail is accurate
- Renders reasonably fast (< 1s) for projects with 50+ components
- Layout is readable (no major overlaps)
Future Enhancements
- Expand/collapse - Click to expand a component and show its internal node summary
- Filter - Show only pages, only shared, only orphans
- Search - Find and highlight a component by name
- Minimap - Small overview when zoomed in
- Export - Export as PNG/SVG for documentation
Risks & Mitigations
| Risk | Mitigation |
|---|---|
| Large projects (100+ components) | Virtual rendering, progressive loading |
| Complex nesting causes layout issues | Test with deeply nested projects early |
| Dagre.js performance | Consider WebWorker for layout calculation |
Dependencies
- VIEW-000 Foundation (for
buildComponentDependencyGraph) - Dagre.js (layout library)
Blocks
- None (independent view)