mirror of
https://github.com/abhigyanpatwari/GitNexus.git
synced 2026-10-29 06:32:28 +00:00
feat: add more node types in filter panel (#519)
* fix(web): enable Cypher queries when connected to backend server Route queries through HTTP API in backend mode instead of checking local WASM database. Made-with: Cursor * chore: add Maven/Gradle wrapper files to default ignore list Add build wrapper scripts and directories to hardcoded ignore lists: - Directories: .mvn, .gradle, gradle - Files: mvnw, mvnw.cmd, gradlew, gradlew.bat These are build infrastructure files, not source code. Made-with: Cursor * ci: re-trigger CI (Windows flaky timeout) Made-with: Cursor * feat: add more node types in filter panel * feat: add more node types in filter panel * revert additional changes * test(web): add unit tests for filter panel node types - FILTERABLE_LABELS: verify new types (Enum, Type, Decorator, Variable) have colors, sizes, and no duplicates - Filter panel icons: verify every filterable label has an icon mapped and all icons are exported from lucide-icons - Color legend: verify new types are included, ordered correctly, and are a subset of FILTERABLE_LABELS Made-with: Cursor
This commit is contained in:
parent
961f004c4b
commit
b398e58e53
5 changed files with 132 additions and 3 deletions
|
|
@ -14,6 +14,9 @@ import {
|
|||
Variable,
|
||||
Hash,
|
||||
Target,
|
||||
List,
|
||||
AtSign,
|
||||
Type,
|
||||
} from '@/lib/lucide-icons';
|
||||
import { useAppState } from '../hooks/useAppState';
|
||||
import { FILTERABLE_LABELS, NODE_COLORS, ALL_EDGE_TYPES, EDGE_INFO, type EdgeType } from '../lib/constants';
|
||||
|
|
@ -187,7 +190,11 @@ const getNodeTypeIcon = (label: NodeLabel) => {
|
|||
case 'Function': return Braces;
|
||||
case 'Method': return Braces;
|
||||
case 'Interface': return Hash;
|
||||
case 'Enum': return List;
|
||||
case 'Type': return Type;
|
||||
case 'Decorator': return AtSign;
|
||||
case 'Import': return FileCode;
|
||||
case 'Variable': return Variable;
|
||||
default: return Variable;
|
||||
}
|
||||
};
|
||||
|
|
@ -501,7 +508,7 @@ export const FileTreePanel = ({ onFocusNode }: FileTreePanelProps) => {
|
|||
Color Legend
|
||||
</h3>
|
||||
<div className="grid grid-cols-2 gap-2">
|
||||
{(['Folder', 'File', 'Class', 'Function', 'Interface', 'Method'] as NodeLabel[]).map(label => (
|
||||
{(['Folder', 'File', 'Class', 'Interface', 'Enum', 'Type', 'Function', 'Method', 'Variable', 'Decorator'] as NodeLabel[]).map(label => (
|
||||
<div key={label} className="flex items-center gap-1.5">
|
||||
<div
|
||||
className="w-2.5 h-2.5 rounded-full"
|
||||
|
|
|
|||
|
|
@ -112,15 +112,18 @@ export const DEFAULT_VISIBLE_LABELS: NodeLabel[] = [
|
|||
'Type',
|
||||
];
|
||||
|
||||
// All filterable labels
|
||||
// All filterable labels (in display order)
|
||||
export const FILTERABLE_LABELS: NodeLabel[] = [
|
||||
'Folder',
|
||||
'File',
|
||||
'Class',
|
||||
'Interface',
|
||||
'Enum',
|
||||
'Type',
|
||||
'Function',
|
||||
'Method',
|
||||
'Variable',
|
||||
'Interface',
|
||||
'Decorator',
|
||||
'Import',
|
||||
];
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ export {
|
|||
AlertCircle,
|
||||
AlertTriangle,
|
||||
ArrowRight,
|
||||
AtSign,
|
||||
Brain,
|
||||
Box,
|
||||
Braces,
|
||||
|
|
@ -39,6 +40,7 @@ export {
|
|||
Layers,
|
||||
Lightbulb,
|
||||
LightbulbOff,
|
||||
List,
|
||||
Loader2,
|
||||
Maximize2,
|
||||
MousePointerClick,
|
||||
|
|
@ -63,6 +65,7 @@ export {
|
|||
Target,
|
||||
Terminal,
|
||||
Trash2,
|
||||
Type,
|
||||
Upload,
|
||||
User,
|
||||
Variable,
|
||||
|
|
|
|||
|
|
@ -59,6 +59,41 @@ describe('DEFAULT_VISIBLE_LABELS', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('FILTERABLE_LABELS', () => {
|
||||
it('includes all newly added node types', () => {
|
||||
expect(FILTERABLE_LABELS).toContain('Enum');
|
||||
expect(FILTERABLE_LABELS).toContain('Type');
|
||||
expect(FILTERABLE_LABELS).toContain('Decorator');
|
||||
expect(FILTERABLE_LABELS).toContain('Variable');
|
||||
});
|
||||
|
||||
it('every filterable label has a defined color in NODE_COLORS', () => {
|
||||
for (const label of FILTERABLE_LABELS) {
|
||||
expect(NODE_COLORS).toHaveProperty(label);
|
||||
expect(NODE_COLORS[label as keyof typeof NODE_COLORS]).toMatch(/^#[0-9a-f]{6}$/i);
|
||||
}
|
||||
});
|
||||
|
||||
it('every filterable label has a defined size in NODE_SIZES', () => {
|
||||
for (const label of FILTERABLE_LABELS) {
|
||||
expect(NODE_SIZES).toHaveProperty(label);
|
||||
expect(NODE_SIZES[label as keyof typeof NODE_SIZES]).toBeGreaterThan(0);
|
||||
}
|
||||
});
|
||||
|
||||
it('has no duplicate entries', () => {
|
||||
const unique = new Set(FILTERABLE_LABELS);
|
||||
expect(unique.size).toBe(FILTERABLE_LABELS.length);
|
||||
});
|
||||
|
||||
it('is a subset of DEFAULT_VISIBLE_LABELS plus togglable labels', () => {
|
||||
const allKnown = new Set(Object.keys(NODE_COLORS));
|
||||
for (const label of FILTERABLE_LABELS) {
|
||||
expect(allKnown.has(label)).toBe(true);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('edge types', () => {
|
||||
it('ALL_EDGE_TYPES contains all EDGE_INFO keys', () => {
|
||||
const edgeInfoKeys = Object.keys(EDGE_INFO).sort();
|
||||
|
|
|
|||
81
gitnexus-web/test/unit/filter-panel.test.ts
Normal file
81
gitnexus-web/test/unit/filter-panel.test.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { describe, expect, it } from 'vitest';
|
||||
import { FILTERABLE_LABELS, NODE_COLORS } from '../../src/lib/constants';
|
||||
import type { NodeLabel } from '../../src/core/graph/types';
|
||||
import * as lucideIcons from '../../src/lib/lucide-icons';
|
||||
|
||||
const LEGEND_LABELS: NodeLabel[] = [
|
||||
'Folder', 'File', 'Class', 'Interface', 'Enum', 'Type',
|
||||
'Function', 'Method', 'Variable', 'Decorator',
|
||||
];
|
||||
|
||||
const ICON_MAP: Record<string, string> = {
|
||||
Folder: 'Folder',
|
||||
File: 'FileCode',
|
||||
Class: 'Box',
|
||||
Function: 'Braces',
|
||||
Method: 'Braces',
|
||||
Interface: 'Hash',
|
||||
Enum: 'List',
|
||||
Type: 'Type',
|
||||
Decorator: 'AtSign',
|
||||
Import: 'FileCode',
|
||||
Variable: 'Variable',
|
||||
};
|
||||
|
||||
describe('filter panel icon mappings', () => {
|
||||
it('every filterable label has a mapped icon', () => {
|
||||
for (const label of FILTERABLE_LABELS) {
|
||||
expect(ICON_MAP).toHaveProperty(label);
|
||||
}
|
||||
});
|
||||
|
||||
it('every mapped icon is exported from lucide-icons', () => {
|
||||
const exportedNames = new Set(Object.keys(lucideIcons));
|
||||
const requiredIcons = new Set(Object.values(ICON_MAP));
|
||||
for (const iconName of requiredIcons) {
|
||||
expect(exportedNames.has(iconName), `${iconName} should be exported from lucide-icons`).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('newly added node types have distinct icons', () => {
|
||||
expect(ICON_MAP.Enum).toBe('List');
|
||||
expect(ICON_MAP.Type).toBe('Type');
|
||||
expect(ICON_MAP.Decorator).toBe('AtSign');
|
||||
});
|
||||
});
|
||||
|
||||
describe('color legend', () => {
|
||||
it('includes all newly added node types', () => {
|
||||
expect(LEGEND_LABELS).toContain('Enum');
|
||||
expect(LEGEND_LABELS).toContain('Type');
|
||||
expect(LEGEND_LABELS).toContain('Decorator');
|
||||
expect(LEGEND_LABELS).toContain('Variable');
|
||||
});
|
||||
|
||||
it('every legend label has a color defined', () => {
|
||||
for (const label of LEGEND_LABELS) {
|
||||
expect(NODE_COLORS).toHaveProperty(label);
|
||||
expect(NODE_COLORS[label]).toMatch(/^#[0-9a-f]{6}$/i);
|
||||
}
|
||||
});
|
||||
|
||||
it('legend labels match the order used in FileTreePanel', () => {
|
||||
const expected: NodeLabel[] = [
|
||||
'Folder', 'File', 'Class', 'Interface', 'Enum', 'Type',
|
||||
'Function', 'Method', 'Variable', 'Decorator',
|
||||
];
|
||||
expect(LEGEND_LABELS).toEqual(expected);
|
||||
});
|
||||
|
||||
it('legend labels are a subset of filterable labels plus Import', () => {
|
||||
const filterableSet = new Set(FILTERABLE_LABELS);
|
||||
for (const label of LEGEND_LABELS) {
|
||||
expect(filterableSet.has(label), `${label} should be in FILTERABLE_LABELS`).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
it('has no duplicate entries', () => {
|
||||
const unique = new Set(LEGEND_LABELS);
|
||||
expect(unique.size).toBe(LEGEND_LABELS.length);
|
||||
});
|
||||
});
|
||||
Loading…
Add table
Reference in a new issue