mirror of
https://github.com/catlog22/Claude-Code-Workflow.git
synced 2026-02-11 02:33:51 +08:00
feat: Enhance graph exploration with file and module filtering options
This commit is contained in:
@@ -1108,6 +1108,12 @@ const i18n = {
|
||||
'graph.references': 'references',
|
||||
'graph.affectedSymbols': 'Affected Symbols',
|
||||
'graph.depth': 'Depth',
|
||||
'graph.scope': 'Scope',
|
||||
'graph.allFiles': 'All Files',
|
||||
'graph.byModule': 'By Module',
|
||||
'graph.byFile': 'By File',
|
||||
'graph.selectModule': 'Select a module...',
|
||||
'graph.selectFile': 'Select a file...',
|
||||
|
||||
// CLI Sync (used in claude-manager.js)
|
||||
'claude.cliSync': 'CLI Auto-Sync',
|
||||
@@ -2300,6 +2306,12 @@ const i18n = {
|
||||
'graph.references': '引用',
|
||||
'graph.symbolType': '符号类型',
|
||||
'graph.affectedSymbols': '受影响符号',
|
||||
'graph.scope': '范围',
|
||||
'graph.allFiles': '所有文件',
|
||||
'graph.byModule': '按模块',
|
||||
'graph.byFile': '按文件',
|
||||
'graph.selectModule': '选择模块...',
|
||||
'graph.selectFile': '选择文件...',
|
||||
|
||||
// CLI Sync (used in claude-manager.js)
|
||||
'claude.cliSync': 'CLI 自动同步',
|
||||
|
||||
@@ -8,7 +8,7 @@ var coreMemGraphZoom = null;
|
||||
var coreMemGraphSimulation = null;
|
||||
|
||||
async function renderCoreMemoryView() {
|
||||
const content = document.getElementById('content');
|
||||
const content = document.getElementById('mainContent');
|
||||
hideStatsAndCarousel();
|
||||
|
||||
// Fetch core memories
|
||||
|
||||
@@ -20,6 +20,11 @@ var edgeFilters = {
|
||||
};
|
||||
var selectedNode = null;
|
||||
var searchProcessData = null;
|
||||
var availableFiles = [];
|
||||
var availableModules = [];
|
||||
var selectedFile = null;
|
||||
var selectedModule = null;
|
||||
var filterMode = 'all'; // 'all', 'file', 'module'
|
||||
|
||||
// ========== Node/Edge Colors ==========
|
||||
var NODE_COLORS = {
|
||||
@@ -53,7 +58,8 @@ async function renderGraphExplorer() {
|
||||
// Load data
|
||||
await Promise.all([
|
||||
loadGraphData(),
|
||||
loadSearchProcessData()
|
||||
loadSearchProcessData(),
|
||||
loadFilesAndModules()
|
||||
]);
|
||||
|
||||
// Render layout
|
||||
@@ -71,11 +77,22 @@ async function renderGraphExplorer() {
|
||||
// ========== Data Loading ==========
|
||||
async function loadGraphData() {
|
||||
try {
|
||||
var nodesResp = await fetch('/api/graph/nodes');
|
||||
// Build query parameters based on filter mode
|
||||
var queryParams = new URLSearchParams();
|
||||
if (filterMode === 'file' && selectedFile) {
|
||||
queryParams.set('file', selectedFile);
|
||||
} else if (filterMode === 'module' && selectedModule) {
|
||||
queryParams.set('module', selectedModule);
|
||||
}
|
||||
|
||||
var nodesUrl = '/api/graph/nodes' + (queryParams.toString() ? '?' + queryParams.toString() : '');
|
||||
var edgesUrl = '/api/graph/edges' + (queryParams.toString() ? '?' + queryParams.toString() : '');
|
||||
|
||||
var nodesResp = await fetch(nodesUrl);
|
||||
if (!nodesResp.ok) throw new Error('Failed to load graph nodes');
|
||||
var nodesData = await nodesResp.json();
|
||||
|
||||
var edgesResp = await fetch('/api/graph/edges');
|
||||
var edgesResp = await fetch(edgesUrl);
|
||||
if (!edgesResp.ok) throw new Error('Failed to load graph edges');
|
||||
var edgesData = await edgesResp.json();
|
||||
|
||||
@@ -91,6 +108,23 @@ async function loadGraphData() {
|
||||
}
|
||||
}
|
||||
|
||||
async function loadFilesAndModules() {
|
||||
try {
|
||||
var response = await fetch('/api/graph/files');
|
||||
if (!response.ok) throw new Error('Failed to load files and modules');
|
||||
var data = await response.json();
|
||||
|
||||
availableFiles = data.files || [];
|
||||
availableModules = data.modules || [];
|
||||
return { files: availableFiles, modules: availableModules };
|
||||
} catch (err) {
|
||||
console.error('Failed to load files and modules:', err);
|
||||
availableFiles = [];
|
||||
availableModules = [];
|
||||
return { files: [], modules: [] };
|
||||
}
|
||||
}
|
||||
|
||||
async function loadCoreMemoryGraphData() {
|
||||
try {
|
||||
var response = await fetch('/api/core-memory/graph');
|
||||
@@ -219,6 +253,40 @@ function renderGraphView() {
|
||||
|
||||
function renderFilterDropdowns() {
|
||||
return '<div class="filter-dropdowns">' +
|
||||
// Scope filter
|
||||
'<div class="filter-group scope-filter">' +
|
||||
'<label>' + t('graph.scope') + '</label>' +
|
||||
'<div class="scope-selector">' +
|
||||
'<label class="filter-radio">' +
|
||||
'<input type="radio" name="scopeMode" value="all" ' + (filterMode === 'all' ? 'checked' : '') + ' onchange="changeScopeMode(\'all\')">' +
|
||||
'<span>' + t('graph.allFiles') + '</span>' +
|
||||
'</label>' +
|
||||
'<label class="filter-radio">' +
|
||||
'<input type="radio" name="scopeMode" value="module" ' + (filterMode === 'module' ? 'checked' : '') + ' onchange="changeScopeMode(\'module\')">' +
|
||||
'<span>' + t('graph.byModule') + '</span>' +
|
||||
'</label>' +
|
||||
'<label class="filter-radio">' +
|
||||
'<input type="radio" name="scopeMode" value="file" ' + (filterMode === 'file' ? 'checked' : '') + ' onchange="changeScopeMode(\'file\')">' +
|
||||
'<span>' + t('graph.byFile') + '</span>' +
|
||||
'</label>' +
|
||||
'</div>' +
|
||||
// Module selector (shown when filterMode === 'module')
|
||||
(filterMode === 'module' ?
|
||||
'<select id="moduleSelect" class="filter-select" onchange="selectModule(this.value)">' +
|
||||
'<option value="">' + t('graph.selectModule') + '</option>' +
|
||||
availableModules.map(function(module) {
|
||||
return '<option value="' + escapeHtml(module) + '" ' + (selectedModule === module ? 'selected' : '') + '>' + escapeHtml(module) + '</option>';
|
||||
}).join('') +
|
||||
'</select>' : '') +
|
||||
// File selector (shown when filterMode === 'file')
|
||||
(filterMode === 'file' ?
|
||||
'<select id="fileSelect" class="filter-select" onchange="selectFile(this.value)">' +
|
||||
'<option value="">' + t('graph.selectFile') + '</option>' +
|
||||
availableFiles.map(function(file) {
|
||||
return '<option value="' + escapeHtml(file) + '" ' + (selectedFile === file ? 'selected' : '') + '>' + escapeHtml(file) + '</option>';
|
||||
}).join('') +
|
||||
'</select>' : '') +
|
||||
'</div>' +
|
||||
'<div class="filter-group">' +
|
||||
'<label>' + t('graph.nodeTypes') + '</label>' +
|
||||
Object.keys(NODE_COLORS).map(function(type) {
|
||||
@@ -845,6 +913,42 @@ function cleanupGraphExplorer() {
|
||||
searchProcessData = null;
|
||||
}
|
||||
|
||||
// ========== Scope Filter Actions ==========
|
||||
async function changeScopeMode(mode) {
|
||||
filterMode = mode;
|
||||
selectedFile = null;
|
||||
selectedModule = null;
|
||||
|
||||
// Re-render the filter panel
|
||||
var sidebar = document.querySelector('.graph-sidebar');
|
||||
if (sidebar) {
|
||||
var controlsSection = sidebar.querySelector('.graph-controls-section');
|
||||
if (controlsSection) {
|
||||
controlsSection.innerHTML = '<h3>' + t('graph.filters') + '</h3>' + renderFilterDropdowns();
|
||||
if (window.lucide) lucide.createIcons();
|
||||
}
|
||||
}
|
||||
|
||||
// If mode is 'all', reload graph immediately
|
||||
if (mode === 'all') {
|
||||
await refreshGraphData();
|
||||
}
|
||||
}
|
||||
|
||||
async function selectModule(modulePath) {
|
||||
selectedModule = modulePath;
|
||||
if (modulePath) {
|
||||
await refreshGraphData();
|
||||
}
|
||||
}
|
||||
|
||||
async function selectFile(filePath) {
|
||||
selectedFile = filePath;
|
||||
if (filePath) {
|
||||
await refreshGraphData();
|
||||
}
|
||||
}
|
||||
|
||||
// Register cleanup on navigation (called by navigation.js before switching views)
|
||||
if (typeof window !== 'undefined') {
|
||||
window.cleanupGraphExplorer = cleanupGraphExplorer;
|
||||
|
||||
Reference in New Issue
Block a user