[#54] feat: D3 force-directed plugin graph + consumes edges #88

Open
nazim wants to merge 1 commit from nazim/cobot:feat/d3-plugin-graph into main
Contributor

Closes #54

Changes

Replaces the static circle layout in the plugin graph with an interactive D3.js force-directed visualization.

Before

  • Nodes positioned in a circle by priority order
  • Static SVG, no physics
  • Hover tooltips only
  • No filtering

After

  • D3 force simulation with charge, collision, and link forces
  • Nodes colored by priority (d3.interpolateCool spectrum) with gradient legend
  • Node size scaled by connection count
  • Draggable nodes with proper drag physics
  • Click → detail panel showing version, layer, capabilities, extension points, implements
  • Hover → highlight connected nodes, dim unrelated ones
  • Filter by layer: Foundation (≤5), Core (≤18), Services (≤30), Orchestration (>30)
  • Filter by edge type: dependency, optional, implements, consumes
  • Text search filter: -name excludes, +name includes, plain text searches
  • Arrow markers on directed edges
  • consumes edges added to get_plugin_graph_data() — shows capability-based aggregation relationships (e.g. loop consumes llm, tools)

Files changed

  • cobot/plugins/web/templates/plugins.html — full rewrite with D3
  • cobot/plugins/web/plugin.py — added consumes edge generation

Tests

153 passed, 0 failed.

Closes #54 ## Changes Replaces the static circle layout in the plugin graph with an interactive **D3.js force-directed visualization**. ### Before - Nodes positioned in a circle by priority order - Static SVG, no physics - Hover tooltips only - No filtering ### After - **D3 force simulation** with charge, collision, and link forces - **Nodes colored by priority** (`d3.interpolateCool` spectrum) with gradient legend - **Node size** scaled by connection count - **Draggable nodes** with proper drag physics - **Click → detail panel** showing version, layer, capabilities, extension points, implements - **Hover → highlight** connected nodes, dim unrelated ones - **Filter by layer**: Foundation (≤5), Core (≤18), Services (≤30), Orchestration (>30) - **Filter by edge type**: dependency, optional, implements, consumes - **Text search filter**: `-name` excludes, `+name` includes, plain text searches - **Arrow markers** on directed edges - **`consumes` edges** added to `get_plugin_graph_data()` — shows capability-based aggregation relationships (e.g. loop consumes llm, tools) ### Files changed - `cobot/plugins/web/templates/plugins.html` — full rewrite with D3 - `cobot/plugins/web/plugin.py` — added `consumes` edge generation ### Tests 153 passed, 0 failed.
feat: D3 force-directed plugin graph + consumes edges
All checks were successful
CI / lint (pull_request) Successful in 9s
CI / test (3.11) (pull_request) Successful in 22s
CI / test (3.12) (pull_request) Successful in 23s
CI / test (3.13) (pull_request) Successful in 24s
E2E Tests / e2e (pull_request) Successful in 15s
CI / build (pull_request) Successful in 7s
b3f33a8d8a
Replace the static circle layout with an interactive D3.js force-directed
graph for plugin visualization.

Features:
- D3 force simulation with proper physics (charge, collision, link forces)
- Nodes colored by priority (d3.interpolateCool spectrum)
- Node size scaled by connection count
- Draggable nodes
- Click node → detail panel (version, layer, capabilities, ext points, implements)
- Hover → highlight connected nodes, dim others
- Filter by layer (Foundation/Core/Services/Orchestration)
- Filter by edge type (dependency/optional/implements/consumes)
- Text search filter (-name excludes, +name includes)
- Priority gradient legend
- Arrow markers on directed edges
- Consumes edges added to get_plugin_graph_data() (capability-based aggregation)

Closes #54
doxios left a comment
Collaborator

🔌 Plugin Architecture Review — PR #88

PR: [#88] feat: D3 force-directed plugin graph + consumes edges
Issue: Closes #54 (Phase 2: Web admin panel)
Author: nazim
Files changed: 2 (web/plugin.py, web/templates/plugins.html)
Diff: ~465 lines


What's Good

  1. consumes edges in get_plugin_graph_data() — Clean addition (17 lines), follows exact same pattern as existing dependency/optional/implements edges. Correctly iterates meta.consumes and matches against other.meta.capabilities. Well done.

  2. D3 force simulation — Proper use of d3.forceSimulation with charge, collision, center, and link forces. Drag behavior is correct (alphaTarget on start/end).

  3. Filter system — Layer/edge/text filters are well-designed. The -name/+name filter syntax is clever and useful for agents.

  4. Hover highlight — Connected-node highlighting with dimming is a nice UX touch.

  5. Detail panel — Click-to-inspect showing version, layer, capabilities, extension points, implements.


⚠️ Concerns

1. External CDN dependency (blocking)

<script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script>

Cobot's philosophy is self-sovereign — it should work offline, on air-gapped VPS, behind firewalls. Loading D3 from jsdelivr makes the plugin graph non-functional without internet access.

Fix: Vendor D3 into cobot/plugins/web/static/js/d3.min.js and reference it locally:

<script src="/static/js/d3.min.js"></script>

D3 v7 minified is ~270KB — acceptable for a bundled dependency.

2. Inline CSS replaces extracted stylesheet (blocking)

PR #81 specifically extracted CSS from plugins.html into static/css/graph.css to follow Cobot's CSS extraction convention. This PR puts all styles back inline in a <style> block.

Fix: Move the new styles into static/css/graph.css (replacing the old circle-layout styles). Keep the <link> tag in the template.

3. Hardcoded color values (non-blocking)

The inline CSS uses hardcoded hex colors (#1a1c24, #333, #0d0f14, etc.) instead of the CSS custom properties defined in main.css (var(--bg-secondary), var(--border), etc.).

Suggestion: Use the existing CSS variables for consistency.

4. No consumes field in PluginMeta fallback (non-blocking)

The code does for capability in meta.consumes — should use getattr(meta, 'consumes', []) or verify the field has a default.

5. No tests for consumes edge generation (non-blocking)

Add a test that creates two mock plugins where one consumes a capability the other provides, and verify the edge appears in the graph data.


🔧 Required Changes (blocking)

  1. Vendor D3.js locally — no CDN dependencies
  2. Move CSS to static/css/graph.css — follow the extraction convention from PR #81

💡 Suggestions (non-blocking)

  1. Use CSS custom properties instead of hardcoded colors
  2. Add defensive getattr for meta.consumes
  3. Add a test for consumes edge generation

Verdict: NEEDS-REVISION

The feature itself is excellent — the D3 visualization is a huge upgrade over the static circle layout, and the consumes edges are cleanly implemented. Just needs the two blocking items fixed (vendor D3, extract CSS) to align with Cobot's self-sovereign philosophy and existing conventions.

## 🔌 Plugin Architecture Review — PR #88 **PR:** [#88] feat: D3 force-directed plugin graph + consumes edges **Issue:** Closes #54 (Phase 2: Web admin panel) **Author:** nazim **Files changed:** 2 (`web/plugin.py`, `web/templates/plugins.html`) **Diff:** ~465 lines --- ### ✅ What's Good 1. **`consumes` edges in `get_plugin_graph_data()`** — Clean addition (17 lines), follows exact same pattern as existing dependency/optional/implements edges. Correctly iterates `meta.consumes` and matches against `other.meta.capabilities`. Well done. 2. **D3 force simulation** — Proper use of `d3.forceSimulation` with charge, collision, center, and link forces. Drag behavior is correct (alphaTarget on start/end). 3. **Filter system** — Layer/edge/text filters are well-designed. The `-name`/`+name` filter syntax is clever and useful for agents. 4. **Hover highlight** — Connected-node highlighting with dimming is a nice UX touch. 5. **Detail panel** — Click-to-inspect showing version, layer, capabilities, extension points, implements. --- ### ⚠️ Concerns #### 1. **External CDN dependency** (blocking) ```html <script src="https://cdn.jsdelivr.net/npm/d3@7/dist/d3.min.js"></script> ``` Cobot's philosophy is **self-sovereign** — it should work offline, on air-gapped VPS, behind firewalls. Loading D3 from jsdelivr makes the plugin graph non-functional without internet access. **Fix:** Vendor D3 into `cobot/plugins/web/static/js/d3.min.js` and reference it locally: ```html <script src="/static/js/d3.min.js"></script> ``` D3 v7 minified is ~270KB — acceptable for a bundled dependency. #### 2. **Inline CSS replaces extracted stylesheet** (blocking) PR #81 specifically extracted CSS from `plugins.html` into `static/css/graph.css` to follow Cobot's CSS extraction convention. This PR puts all styles back inline in a `<style>` block. **Fix:** Move the new styles into `static/css/graph.css` (replacing the old circle-layout styles). Keep the `<link>` tag in the template. #### 3. **Hardcoded color values** (non-blocking) The inline CSS uses hardcoded hex colors (`#1a1c24`, `#333`, `#0d0f14`, etc.) instead of the CSS custom properties defined in `main.css` (`var(--bg-secondary)`, `var(--border)`, etc.). **Suggestion:** Use the existing CSS variables for consistency. #### 4. **No `consumes` field in PluginMeta fallback** (non-blocking) The code does `for capability in meta.consumes` — should use `getattr(meta, 'consumes', [])` or verify the field has a default. #### 5. **No tests for `consumes` edge generation** (non-blocking) Add a test that creates two mock plugins where one consumes a capability the other provides, and verify the edge appears in the graph data. --- ### 🔧 Required Changes (blocking) 1. **Vendor D3.js locally** — no CDN dependencies 2. **Move CSS to `static/css/graph.css`** — follow the extraction convention from PR #81 ### 💡 Suggestions (non-blocking) 3. Use CSS custom properties instead of hardcoded colors 4. Add defensive `getattr` for `meta.consumes` 5. Add a test for `consumes` edge generation --- ### Verdict: **NEEDS-REVISION** The feature itself is excellent — the D3 visualization is a huge upgrade over the static circle layout, and the consumes edges are cleanly implemented. Just needs the two blocking items fixed (vendor D3, extract CSS) to align with Cobot's self-sovereign philosophy and existing conventions.
All checks were successful
CI / lint (pull_request) Successful in 9s
CI / test (3.11) (pull_request) Successful in 22s
CI / test (3.12) (pull_request) Successful in 23s
CI / test (3.13) (pull_request) Successful in 24s
E2E Tests / e2e (pull_request) Successful in 15s
CI / build (pull_request) Successful in 7s
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
This branch is out-of-date with the base branch
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u feat/d3-plugin-graph:nazim-feat/d3-plugin-graph
git switch nazim-feat/d3-plugin-graph
Sign in to join this conversation.
No reviewers
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
ultanio/cobot!88
No description provided.