Skip to content

Commit 822744a

Browse files
committed
Assistant checkpoint: Fix TypeScript compilation errors by removing duplicate class
Assistant generated file changes: - src/mindmap.ts: Remove duplicate NodeQMindMap class and keep only JsonSchemaAdapter - src/index.ts: Import JsonSchemaAdapter from mindmap module, Add import at the top of the file --- User prompt: still causing errors.. analyze again what causing issues: https://github.com/workflow-builder/nodeq-mindmap/actions/runs/16894311687/job/47860944436 Replit-Commit-Author: Assistant Replit-Commit-Session-Id: e5c8aa2d-05f7-401c-b338-9e102c33d9ab
1 parent 6a44c9d commit 822744a

File tree

2 files changed

+46
-190
lines changed

2 files changed

+46
-190
lines changed

src/index.ts

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import * as d3 from 'd3';
22
import { PipelineEngine } from './pipeline-engine';
3+
import { JsonSchemaAdapter } from './mindmap';
34
import type { DataSample, PipelineConfig } from './types';
45

56
export interface MindMapNode {
@@ -37,37 +38,7 @@ export interface NodeQConfig {
3738
onDataTransformed?: (result: any) => void;
3839
}
3940

40-
export class JsonSchemaAdapter {
41-
static convertToStandard(data: any): MindMapNode {
42-
if (!data || typeof data !== 'object') {
43-
return { topic: 'Invalid Data', summary: 'Unable to process data' };
44-
}
45-
const root: MindMapNode = {
46-
topic: data.topic || data.title || data.name || 'Root',
47-
summary: data.summary || data.description || undefined,
48-
skills: Array.isArray(data.skills) ? data.skills : undefined,
49-
children: []
50-
};
51-
const entries = Object.entries(data).filter(([k]) => !['topic','title','name','summary','description','skills','children'].includes(k));
52-
for (const [key, value] of entries) {
53-
if (value && typeof value === 'object') {
54-
root.children!.push({
55-
topic: key,
56-
summary: Array.isArray(value) ? `${value.length} item(s)` : undefined,
57-
children: Array.isArray(value)
58-
? value.slice(0, 20).map((v, i) => typeof v === 'object' ? { topic: `${key}[${i}]`, children: [this.convertToStandard(v)] } : { topic: String(v) })
59-
: [this.convertToStandard(value)]
60-
});
61-
} else {
62-
root.children!.push({ topic: `${key}: ${String(value)}` });
63-
}
64-
}
65-
if (Array.isArray((data as any).children)) {
66-
root.children!.push(...(data as any).children.map((c: any) => this.convertToStandard(c)));
67-
}
68-
return root;
69-
}
70-
}
41+
import { JsonSchemaAdapter } from './mindmap';
7142

7243
type InternalConfig = {
7344
container: string | HTMLElement;

src/mindmap.ts

Lines changed: 44 additions & 159 deletions
Original file line numberDiff line numberDiff line change
@@ -1,172 +1,57 @@
1-
import * as d3 from 'd3';
2-
import { MindMapNode, NodeQConfig, Theme } from './types';
3-
import { JsonSchemaAdapter } from './json-adapter';
4-
5-
export class NodeQMindMap {
6-
private config: Required<NodeQConfig>;
7-
private svg: d3.Selection<SVGSVGElement, unknown, null, undefined> | null = null;
8-
private g: d3.Selection<SVGGElement, unknown, null, undefined> | null = null;
9-
private data: MindMapNode;
10-
private container: HTMLElement;
11-
12-
constructor(config: NodeQConfig) {
13-
this.config = {
14-
container: config.container,
15-
data: config.data,
16-
width: config.width || 800,
17-
height: config.height || 600,
18-
theme: {
19-
nodeColor: '#4299e1',
20-
textColor: '#2d3748',
21-
linkColor: '#a0aec0',
22-
backgroundColor: '#ffffff',
23-
fontSize: 14,
24-
fontFamily: 'Arial, sans-serif',
25-
...config.theme
26-
},
27-
interactive: config.interactive !== undefined ? config.interactive : true,
28-
zoomable: config.zoomable !== undefined ? config.zoomable : true,
29-
collapsible: config.collapsible !== undefined ? config.collapsible : true,
30-
nodeSpacing: config.nodeSpacing || 200,
31-
levelSpacing: config.levelSpacing || 300,
32-
onNodeClick: config.onNodeClick || (() => {}),
33-
onNodeHover: config.onNodeHover || (() => {})
34-
};
35-
36-
// Get container element
37-
if (typeof this.config.container === 'string') {
38-
const element = document.querySelector(this.config.container);
39-
if (!element) {
40-
throw new Error(`Container element not found: ${this.config.container}`);
41-
}
42-
this.container = element as HTMLElement;
43-
} else {
44-
this.container = this.config.container;
1+
import { MindMapNode } from './types';
2+
3+
export class JsonSchemaAdapter {
4+
static convertToStandard(data: any): MindMapNode {
5+
if (!data || typeof data !== 'object') {
6+
return {
7+
topic: 'Invalid Data',
8+
summary: 'Unable to process the provided data',
9+
skills: ['error']
10+
};
4511
}
4612

47-
// Convert data to standard format
48-
this.data = JsonSchemaAdapter.convertToStandard(this.config.data);
49-
}
50-
51-
render(): void {
52-
this.createSVG();
53-
this.renderMindMap();
54-
}
55-
56-
updateData(data: any): void {
57-
this.config.data = data;
58-
this.data = JsonSchemaAdapter.convertToStandard(data);
59-
this.renderMindMap();
60-
}
13+
// Extract basic properties
14+
const topic = data.topic || data.title || data.name || data.label || 'Unnamed Node';
15+
const summary = data.summary || data.description || data.details || undefined;
16+
const skills = this.extractSkills(data);
17+
const children = this.extractChildren(data);
18+
19+
const result: MindMapNode = {
20+
topic,
21+
summary,
22+
skills,
23+
children: children ? children.map(child => this.convertToStandard(child)) : undefined
24+
};
6125

62-
updateTheme(theme: Partial<Theme>): void {
63-
this.config.theme = { ...this.config.theme, ...theme };
64-
this.renderMindMap();
65-
}
26+
// Add any additional properties
27+
const excludedKeys = ['topic', 'title', 'name', 'label', 'summary', 'description', 'details', 'skills', 'tags', 'categories', 'keywords', 'attributes', 'children', 'items', 'nodes', 'subitems', 'elements', 'branches'];
6628

67-
exportSVG(): string {
68-
if (!this.svg) return '';
69-
return new XMLSerializer().serializeToString(this.svg.node()!);
70-
}
29+
Object.keys(data).forEach(key => {
30+
if (!excludedKeys.includes(key)) {
31+
result[key] = data[key];
32+
}
33+
});
7134

72-
destroy(): void {
73-
if (this.svg) {
74-
this.svg.remove();
75-
}
35+
return result;
7636
}
7737

78-
private createSVG(): void {
79-
// Clear existing content
80-
d3.select(this.container).selectAll('*').remove();
81-
82-
// Create SVG
83-
this.svg = d3.select(this.container)
84-
.append('svg')
85-
.attr('width', this.config.width)
86-
.attr('height', this.config.height)
87-
.style('background-color', this.config.theme.backgroundColor || '#ffffff');
88-
89-
// Create main group for zooming/panning
90-
this.g = this.svg.append('g');
91-
92-
// Add zoom behavior if enabled
93-
if (this.config.zoomable) {
94-
const zoom = d3.zoom<SVGSVGElement, unknown>()
95-
.scaleExtent([0.1, 3])
96-
.on('zoom', (event) => {
97-
this.g!.attr('transform', event.transform);
98-
});
99-
100-
this.svg.call(zoom);
38+
private static extractSkills(obj: any): string[] | undefined {
39+
const skillFields = ['skills', 'tags', 'categories', 'keywords', 'attributes'];
40+
for (const field of skillFields) {
41+
if (Array.isArray(obj[field])) {
42+
return obj[field].filter((item: any) => typeof item === 'string');
43+
}
10144
}
45+
return undefined;
10246
}
10347

104-
private renderMindMap(): void {
105-
if (!this.g) return;
106-
107-
// Clear existing content
108-
this.g.selectAll('*').remove();
109-
110-
// Create hierarchy
111-
const root = d3.hierarchy(this.data);
112-
113-
// Create tree layout
114-
const treeLayout = d3.tree<MindMapNode>()
115-
.size([this.config.height - 100, this.config.width - 200])
116-
.separation((a, b) => a.parent === b.parent ? 1 : 2);
117-
118-
// Generate tree
119-
const treeData = treeLayout(root);
120-
121-
// Create links
122-
this.g.selectAll('.link')
123-
.data(treeData.links())
124-
.enter()
125-
.append('path')
126-
.attr('class', 'link')
127-
.attr('d', d3.linkHorizontal<any, any>()
128-
.x(d => d.y + 100)
129-
.y(d => d.x + 50)
130-
)
131-
.style('fill', 'none')
132-
.style('stroke', this.config.theme.linkColor || '#a0aec0')
133-
.style('stroke-width', 2);
134-
135-
// Create nodes
136-
const nodes = this.g.selectAll('.node')
137-
.data(treeData.descendants())
138-
.enter()
139-
.append('g')
140-
.attr('class', 'node')
141-
.attr('transform', d => `translate(${d.y + 100},${d.x + 50})`);
142-
143-
// Add node circles
144-
nodes.append('circle')
145-
.attr('r', 8)
146-
.style('fill', this.config.theme.nodeColor || '#4299e1')
147-
.style('stroke', '#fff')
148-
.style('stroke-width', 2);
149-
150-
// Add node labels
151-
nodes.append('text')
152-
.attr('dy', '.35em')
153-
.attr('x', d => d.children ? -13 : 13)
154-
.style('text-anchor', d => d.children ? 'end' : 'start')
155-
.style('font-family', this.config.theme.fontFamily || 'Arial, sans-serif')
156-
.style('font-size', `${this.config.theme.fontSize || 14}px`)
157-
.style('fill', this.config.theme.textColor || '#2d3748')
158-
.text(d => d.data.topic);
159-
160-
// Add interactivity
161-
if (this.config.interactive) {
162-
nodes
163-
.style('cursor', 'pointer')
164-
.on('click', (event, d) => {
165-
this.config.onNodeClick(d.data);
166-
})
167-
.on('mouseover', (event, d) => {
168-
this.config.onNodeHover(d.data);
169-
});
48+
private static extractChildren(obj: any): any[] | undefined {
49+
const childFields = ['children', 'items', 'nodes', 'subitems', 'elements', 'branches'];
50+
for (const field of childFields) {
51+
if (Array.isArray(obj[field])) {
52+
return obj[field];
53+
}
17054
}
55+
return undefined;
17156
}
17257
}

0 commit comments

Comments
 (0)