feat(desktop): native reference graph for code symbol visualization#147
Conversation
Integrate reference-graph functionality natively into Superset Desktop, providing interactive graph visualization of code symbol references and call hierarchies using the existing LSP infrastructure. - Extend LanguageServiceProvider interface with findReferences, prepareCallHierarchy, and getIncomingCalls methods - Implement LSP-based methods in ExternalLspLanguageProvider - Implement tsserver-based methods in TypeScriptLanguageProvider - Add GraphBuilder service that constructs reference graphs via LSP - Add referenceGraph tRPC router - Add ReferenceGraphPane UI with @xyflow/react + ELK.js auto-layout - Add "reference-graph" pane type with tab store support - Add "Show Reference Graph" to editor context menu
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (13)
📝 WalkthroughWalkthroughシンボル参照とコールハイアラーキーを用いてワークスペース内の参照グラフを構築・返却するTRPCルーターとビルダーを追加し、言語サービスに参照/コールハイアラーキーAPIを実装。フロントエンドにReact Flow/ELKベースの参照グラフペーン、設定フラグ、エディタ統合、タブ管理を導入。 Changes
Sequence DiagramsequenceDiagram
actor User
participant Editor as Editor/Menu
participant Store as Tabs Store
participant TRPC as TRPC Router
participant LSM as Language Services Manager
participant Graph as Graph Builder
participant UI as React Flow UI
User->>Editor: コンテキストで「Show Reference Graph」
Editor->>Store: addReferenceGraphTab(workspaceId, path, lang, line, col)
Store->>TRPC: referenceGraph.buildGraph mutation
TRPC->>LSM: findReferences / prepareCallHierarchy
LSM->>LSM: resolve provider, call provider methods
LSM-->>TRPC: references / call-hierarchy items (or null)
TRPC->>Graph: buildReferenceGraph(request)
Graph->>Graph: collect nodes/edges, apply limits, read snippets
Graph-->>TRPC: ReferenceGraphData
TRPC-->>Store: graph data returned
Store->>UI: render ReferenceGraphPane with nodes/edges
UI->>UI: compute ELK layout, render React Flow
User->>UI: ダブルクリックノード
UI->>Editor: open file at node location
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 1 | ❌ 2❌ Failed checks (1 warning, 1 inconclusive)
✅ Passed checks (1 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
…ettings - Add referenceGraphEnabled column to local-db settings schema - Add getReferenceGraph/setReferenceGraph tRPC procedures - Add ReferenceGraphSettings toggle component in Editor Features section - Add settings search entry for Reference Graph - Default: enabled (true)
…ssues - Connect "Show Reference Graph" context menu to FileViewerPane via useEditorActions → FileEditorContextMenu → FileViewerContent chain - Gate context menu visibility on referenceGraphEnabled setting - Fix infinite re-render: stabilize mutateAsync via useRef instead of including unstable buildGraphMutation in useCallback deps - Add references/callHierarchy/documentSymbol to LSP client capabilities so non-TypeScript LSP servers enable these features - Use async fs.readFile instead of blocking readFileSync in graph-builder - Improve shouldExclude to match against path segments instead of naive string matching
There was a problem hiding this comment.
Actionable comments posted: 7
🧹 Nitpick comments (2)
packages/local-db/src/schema/schema.ts (1)
243-245:referenceGraphEnabledはDB側でもデフォルト有効に固定する方が安全です。現在は nullable のため
nullが残りやすく、設定値の解釈が呼び出し側依存になります。notNull().default(true)を付けて永続層で一貫性を持たせることを推奨します。🛠️ 変更案
- referenceGraphEnabled: integer("reference_graph_enabled", { - mode: "boolean", - }), + referenceGraphEnabled: integer("reference_graph_enabled", { + mode: "boolean", + }) + .notNull() + .default(true),🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/local-db/src/schema/schema.ts` around lines 243 - 245, The column definition for referenceGraphEnabled (currently defined as integer("reference_graph_enabled", { mode: "boolean" })) should be made non-nullable with a default true at the DB layer to avoid caller-side interpretation; update the schema entry for referenceGraphEnabled to apply notNull().default(true) so the persisted column always has a boolean value, and then regenerate/apply the corresponding migration so the DB schema and model stay in sync.apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceNode.tsx (1)
1-107: コンポーネント配置をガイドライン準拠に揃えてください。
ReferenceNodeをReferenceNode/ReferenceNode.tsx+ReferenceNode/index.tsの構成へ移すと、保守時の探索性と一貫性が上がります。As per coding guidelines, "Components must follow one-folder-per-component structure:
ComponentName/ComponentName.tsxwithindex.tsbarrel export".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceNode.tsx` around lines 1 - 107, Move the current file into a new folder named ReferenceNode and rename it ReferenceNode.tsx (keep the component as ReferenceNodeComponent and the exported memoized symbol ReferenceNode), then add a new barrel index.ts that re-exports the component (e.g. export { ReferenceNode } from './ReferenceNode'; or export { default } if you change to default export) so callers can import from the folder path; ensure you keep the existing exports/signatures (ReferenceNode, ReferenceNodeComponent, ReferenceNodeData) and update any imports elsewhere to import from the new ReferenceNode folder.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@apps/desktop/src/lib/trpc/routers/reference-graph/index.ts`:
- Around line 33-35: The router currently accepts input.absolutePath without
ensuring it lives under the resolved workspacePath (resolved via
resolveWorkspacePath), enabling path traversal; fix by resolving both
input.absolutePath and workspacePath with path.resolve, then verify the
resolvedAbsolutePath begins with resolvedWorkspacePath + path.sep, and if not
throw a TRPCError with code "BAD_REQUEST" and a clear message (e.g., "File path
is outside workspace boundaries"); add this check in the reference-graph router
before using absolutePath so functions like resolveWorkspacePath, subsequent
file reads, or graph generation only operate on in-workspace files.
In
`@apps/desktop/src/main/lib/language-services/lsp/ExternalLspLanguageProvider.ts`:
- Around line 384-386: In ExternalLspLanguageProvider replace the bare catch
blocks that just "return null" with error-capturing catches that accept the
thrown error (e.g., catch (err) { ... }), assign or record the error to the
appropriate state (set session.lastError = err for per-session failures and push
or merge into workspaceErrors for workspace-level failures), then return null;
ensure this change is applied to the three current catch sites so failures and
unsupported cases are distinguishable and recorded for diagnostics (use the
existing session.lastError and workspaceErrors symbols).
In `@apps/desktop/src/main/lib/reference-graph/graph-builder.ts`:
- Around line 264-279: The parallel recursion using Promise.all in
buildCallHierarchyGraph breaks the maxNodes budget because each branch checks
nodes.size < maxNodes concurrently before adding nodes; change the recursion to
consume the node budget deterministically by iterating pendingItems sequentially
(e.g., for..of) or by using a shared atomic counter/budget that is decremented
before calling addNodeFromCallHierarchyItem, so that
addNodeFromCallHierarchyItem and subsequent recursive calls respect the global
maxNodes limit; update buildCallHierarchyGraph to use the chosen approach and
ensure node insertion uses that single budget check instead of the current
concurrent nodes.size check.
- Around line 80-95: The current shouldExclude function only checks for
directory-segment equality (by stripping "**/" and "/**") so complex globs like
"**/*.test.ts" or "src/generated/**" are ignored; update shouldExclude to treat
excludePatterns as real glob patterns and test the file's workspace-relative
path against them (e.g., use a glob-matching library such as
minimatch/picomatch/micromatch) instead of extracting dirName, keeping the
existing signature and ensuring patterns like "**/node_modules/**",
"**/*.test.ts", and "src/generated/**" correctly match against the relative path
returned by path.relative; also keep ReferenceGraphRequest's glob contract
intact by running the matching on the relative path for each pattern.
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceGraphPane.tsx`:
- Around line 208-210: The file-name extraction using
refGraphState.absolutePath.split("/") fails for Windows paths (e.g.,
"C:\foo\bar.ts") and yields the full path; update the display logic in
ReferenceGraphPane (where refGraphState and absolutePath are used) to split on
both slashes or use a path-basename helper instead (e.g., replace split("/")
with a split on both "/" and "\" or call a cross-platform basename utility) so
the rendered value shows only the file name followed by ":" and
refGraphState.line.
- Around line 123-173: loadGraph currently allows out-of-order (stale) in-flight
responses to overwrite newer graph state; introduce a request generation counter
(useRef) that you increment before calling mutateAsyncRef.current, capture the
current generation in the async closure, and only call setNodes, setEdges,
setError, fitView, and setIsLoading for the latest generation (compare captured
generation to ref) to ignore stale responses; update loadGraph to increment e.g.
requestGenRef.current++, store const gen = requestGenRef.current before await,
and guard all state updates with if (gen === requestGenRef.current) { ... } so
only the most recent request mutates state (also ensure finally only clears
loading for the matching generation).
In `@apps/desktop/src/renderer/stores/tabs/utils.ts`:
- Around line 1109-1121: The code builds a tab/pane name by deriving fileName
with absolutePath.split("/") which breaks on Windows paths; replace that logic
to call the existing helper getPathBaseName(absolutePath) wherever fileName is
computed (e.g., the assignment to fileName used in the reference-graph
construction and the similar block at the second occurrence around the other
pane creation), ensuring name remains `References: ${fileName}:${line}` and
preserve the ReferenceGraphPaneState fields (absolutePath, languageId, line,
column) unchanged.
---
Nitpick comments:
In
`@apps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceNode.tsx`:
- Around line 1-107: Move the current file into a new folder named ReferenceNode
and rename it ReferenceNode.tsx (keep the component as ReferenceNodeComponent
and the exported memoized symbol ReferenceNode), then add a new barrel index.ts
that re-exports the component (e.g. export { ReferenceNode } from
'./ReferenceNode'; or export { default } if you change to default export) so
callers can import from the folder path; ensure you keep the existing
exports/signatures (ReferenceNode, ReferenceNodeComponent, ReferenceNodeData)
and update any imports elsewhere to import from the new ReferenceNode folder.
In `@packages/local-db/src/schema/schema.ts`:
- Around line 243-245: The column definition for referenceGraphEnabled
(currently defined as integer("reference_graph_enabled", { mode: "boolean" }))
should be made non-nullable with a default true at the DB layer to avoid
caller-side interpretation; update the schema entry for referenceGraphEnabled to
apply notNull().default(true) so the persisted column always has a boolean
value, and then regenerate/apply the corresponding migration so the DB schema
and model stay in sync.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: dc87ff4a-e07a-4af0-949e-f899d5681bba
⛔ Files ignored due to path filters (1)
bun.lockis excluded by!**/*.lock
📒 Files selected for processing (27)
apps/desktop/package.jsonapps/desktop/src/lib/trpc/routers/index.tsapps/desktop/src/lib/trpc/routers/reference-graph/index.tsapps/desktop/src/lib/trpc/routers/settings/index.tsapps/desktop/src/main/lib/language-services/lsp/ExternalLspLanguageProvider.tsapps/desktop/src/main/lib/language-services/manager.tsapps/desktop/src/main/lib/language-services/providers/typescript/TypeScriptLanguageProvider.tsapps/desktop/src/main/lib/language-services/types.tsapps/desktop/src/main/lib/reference-graph/graph-builder.tsapps/desktop/src/main/lib/reference-graph/index.tsapps/desktop/src/main/lib/reference-graph/types.tsapps/desktop/src/renderer/routes/_authenticated/settings/utils/settings-search/settings-search.tsapps/desktop/src/renderer/routes/_authenticated/settings/vscode-extensions/components/VscodeExtensionsSettings/VscodeExtensionsSettings.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/FileViewerPane.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileEditorContextMenu/FileEditorContextMenu.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/FileViewerPane/components/FileViewerContent/FileViewerContent.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceGraphPane.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/ReferenceNode.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/ReferenceGraphPane/index.tsapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/TabsContent/TabView/index.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/components/EditorContextMenu/EditorContextMenu.tsxapps/desktop/src/renderer/screens/main/components/WorkspaceView/ContentView/components/EditorContextMenu/useEditorActions.tsapps/desktop/src/renderer/stores/tabs/store.tsapps/desktop/src/renderer/stores/tabs/types.tsapps/desktop/src/renderer/stores/tabs/utils.tsapps/desktop/src/shared/tabs-types.tspackages/local-db/src/schema/schema.ts
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: bcbe4530b2
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
P1 fixes: - Add drizzle migration for reference_graph_enabled column (0044) - Add "reference-graph" to paneSchema in ui-state router for tab persistence - Pass actual cursor column via new getCursorPosition() adapter method Major fixes: - Log errors to session.lastError instead of silently swallowing in findReferences/prepareCallHierarchy/getIncomingCalls catch blocks - Switch parallel Promise.all recursion to sequential loop to respect maxNodes budget in call hierarchy graph building - Add request generation tracking to prevent stale responses from overwriting current graph state - Clarify excludePatterns API contract as directory segment matching Minor fixes: - Use getPathBaseName() for cross-platform path handling in tab names - Use regex split for Windows path compatibility in toolbar display - Add path traversal check in tRPC router (absolutePath must be within workspace)
Summary
変更内容
LanguageServiceProviderインターフェースにfindReferences,prepareCallHierarchy,getIncomingCallsを追加ExternalLspLanguageProvider(LSP) とTypeScriptLanguageProvider(tsserver) の両方に実装GraphBuilderサービス: LSP経由でグラフデータを構築(深さ制限・ノード数制限・glob除外フィルタ付き)referenceGraphtRPCルーターReferenceGraphPaneUIコンポーネント(ReactFlow + ELK.jsレイアウト + コードスニペット表示)reference-graphペインタイプとタブストアサポート新規依存パッケージ
elkjs- 自動グラフレイアウトエンジン@xyflow/react- apps/desktopに追加(packages/uiでは既存)Test plan
Summary by CodeRabbit