Skip to content

feat(dashboard): add file/class dual-view toggle to reduce graph clutter#132

Merged
Lum1104 merged 3 commits into
Lum1104:mainfrom
Xingkai98:feat/dashboard-file-class-views
May 10, 2026
Merged

feat(dashboard): add file/class dual-view toggle to reduce graph clutter#132
Lum1104 merged 3 commits into
Lum1104:mainfrom
Xingkai98:feat/dashboard-file-class-views

Conversation

@Xingkai98
Copy link
Copy Markdown
Contributor

@Xingkai98 Xingkai98 commented May 8, 2026

Summary

  • Add detailLevel state ("file" | "class") to the dashboard
  • File view (default): only file nodes + file→file edges. Clean architecture overview, 164 nodes instead of 854.
  • Class view: files + class nodes with optional [fn] function toggle
  • Toggle UI in header: [Files] [+Classes] [fn]

Use Case

在分析 Hermes Agent(一个大型 Python 项目,3,732 个节点、3,186 条边)的知识图谱时,dashboard 的图视图变得极其卡顿——缩放/拖拽几乎不可用,而且连线密密麻麻什么也看不清楚。

排查后发现根因是单个 layer 视图展开 function 节点的 contains 边后,仅 Core Agent System 层就从 164 个文件节点膨胀到 854 个节点、1,651 条边(其中 1,268 条是 function 的 contains/exports 边)。绝大多数场景下用户不需要看到 function 级别的细节,只需要文件级的架构依赖概览。

Proposed Solution

添加 detailLevel 双视图切换:

  • Files 视图(默认):只展示文件节点和 file→file 边(imports/depends_on),不展开 contains 边。Core Agent System 层从 854 节点降到 164 节点,缩放流畅。
  • +Classes 视图:在文件节点基础上叠加 class 节点(通过 contains 边展开),展示 contains/exports/inherits 边。附带 [fn] 开关让用户手动选择是否展开 function 节点——故意保留性能代价,由用户自主决定。

切换视图时自动清除容器布局缓存,保证 React Flow 重新计算布局。

Review fixes (e29f461)

  1. setDetailLevel("file") now resets showFunctionsInClassView: false so the fn toggle doesn't resurrect when switching back to +Classes after a file-view round-trip.
  2. Detail-level toolbar gated on viewMode !== "domain" so it doesn't render in domain view where it has no effect.

Alternatives Considered

  1. Classes 视图只展示类节点(不含文件):试过在 class 模式下过滤掉所有文件节点,只保留 class 节点和 class↔class 边。但知识图谱中 class↔class 边极少(Hermes Agent 仅 14 条 inherits,没有 depends_on/calls 等),大部分类节点变成孤岛,没有实用价值。最终改为 file+class 叠加模式。

  2. 始终默认隐藏 function 节点:最初考虑过直接在所有视图隐藏 function 来减少节点数。但 function 展开在某些场景有价值(如分析单个文件的代码结构),一刀切不合适。最终用可选的 [fn] 开关让用户自主控制。

Files changed

packages/dashboard/src/:

  • store.ts — new state + actions
  • components/GraphView.tsx — conditional contains-edge expansion
  • App.tsx — view toggle UI in header

Additional Context

  • Dashboard 目前没有 React 组件测试(仅 utils 单元测试 42 个),此改动遵循现有模式
  • 改动对知识图谱数据格式无依赖,适用于任何项目

Tested

  • File view: smooth zoom/pan with Hermes Agent graph (164 nodes / 269 edges)
  • Class view: contains/exports/inherits edges visible (~237 nodes / ~369 edges)
  • fn toggle: function expansion opt-in
  • TypeScript compiles clean
  • All 670 existing tests pass
  • Review fixes: fn toggle reset on view switch, toolbar hidden in domain view

Contribution Checklist

Per CONTRIBUTING.md:

  • Code follows the project's style guidelines — TypeScript strict, existing Zustand/React hooks patterns
  • All tests pass (pnpm test) — 670 tests passed
  • New code has test coverage — consistent with existing pattern (dashboard has no React component tests, only utility tests)
  • Documentation is updated — N/A (dashboard UI change, not API change)
  • Commit messages follow convention — feat(dashboard): ...
  • PR description clearly explains changes
  • No console.log or debug code left behind — no new console statements in diff
  • Branch is up to date with main — rebased on upstream/main

🤖 Generated with Claude Code

Add detailLevel state ("file" | "class") to separate architecture-level
file dependencies from code-structure class views. File view shows only
file nodes and file→file edges (imports/depends_on), eliminating ~85%
of nodes/edges that previously caused severe zoom/pan lag. Class view
adds class nodes via contains edges with an optional function toggle.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@Xingkai98 Xingkai98 force-pushed the feat/dashboard-file-class-views branch from 8482412 to c1bc4bf Compare May 8, 2026 17:57
@Lum1104
Copy link
Copy Markdown
Owner

Lum1104 commented May 10, 2026

Code review

Found 2 issues:

  1. setDetailLevel("file") does not reset showFunctionsInClassView. After enabling +Classes → toggling fn on → switching back to Files → returning to +Classes, function nodes silently appear and the fn button renders highlighted without the user pressing it in this new class-view session. The cache-clearing block already mirrors the "any time the visible node set changes, clear caches" pattern; the toggle state should be cleared too so the sub-option doesn't resurrect itself.

setDetailLevel: (level) =>
set({
detailLevel: level,
// Detail level changes which nodes are visible; cached positions stale.
containerLayoutCache: new Map(),
containerSizeMemory: new Map(),
expandedContainers: new Set(),
pendingFocusContainer: null,
}),

  1. The new detail-level toolbar (Files / +Classes / fn) is gated only by !isKnowledgeGraph, not by viewMode !== "domain". In domain view, <DomainGraphView /> is rendered (not <GraphView />) and ignores detailLevel, so clicking the buttons there flushes structural-view caches (containerLayoutCache, containerSizeMemory, expandedContainers, pendingFocusContainer) for no benefit and shows misleading "active" styling for a control that has no effect on what is on screen. Compare with the structural/domain toggle just above (L413), which correctly gates on the view state.

<DiffToggle />
{/* Detail level: file view (architecture) / class view (code structure) */}
{!isKnowledgeGraph && (
<>
<div className="w-px h-5 bg-border-subtle" />
<div className="flex items-center bg-elevated rounded-lg p-0.5">
<button
type="button"
onClick={() => setDetailLevel("file")}
title="Files only — architecture-level dependencies (fast)"
className={`px-3 py-1 text-xs font-medium rounded-md transition-colors ${
detailLevel === "file"
? "bg-accent/20 text-accent"
: "text-text-muted hover:text-text-secondary"
}`}
>
Files
</button>
<button
type="button"
onClick={() => setDetailLevel("class")}
title="Files + Classes — code structure with inheritance"
className={`px-3 py-1 text-xs font-medium rounded-md transition-colors ${
detailLevel === "class"
? "bg-accent/20 text-accent"
: "text-text-muted hover:text-text-secondary"
}`}
>
+Classes
</button>
</div>
{detailLevel === "class" && (
<button
type="button"
onClick={toggleShowFunctionsInClassView}
title="Toggle function nodes (may slow down rendering)"
className={`text-[10px] font-semibold uppercase tracking-wider px-2 py-1 rounded border transition-colors ${
showFunctionsInClassView
? "border-amber-500/50 bg-amber-500/10 text-amber-400"
: "border-border-medium bg-elevated text-text-muted hover:text-text-secondary"
}`}
>
fn
</button>
)}
</>
)}
<div className="flex items-center gap-1">
{(isKnowledgeGraph ? [

Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

Xingkai98 added 2 commits May 10, 2026 15:40
…n domain view

- Issue 1: setDetailLevel now resets showFunctionsInClassView so the fn
  toggle doesn't resurrect when re-entering class view after a file-view
  round-trip.
- Issue 2: detail-level toolbar (Files/+Classes/fn) now gated on
  viewMode !== "domain" so it doesn't render in domain view where it has
  no effect.
@Lum1104 Lum1104 merged commit e638ed8 into Lum1104:main May 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants