-
Notifications
You must be signed in to change notification settings - Fork 29
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore(Canvas): Split
CanvasService
in ControllerService
and `Flow…
…Service` Split `CanvasService` for better separation of concerns. fix: #1329
- Loading branch information
Showing
3 changed files
with
228 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
112 changes: 112 additions & 0 deletions
112
packages/ui/src/components/Visualization/Canvas/flow.service.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,112 @@ | ||
import { createVisualizationNode } from '../../../models/visualization'; | ||
import { BaseVisualCamelEntity } from '../../../models/visualization/base-visual-entity'; | ||
import { FlowService } from './flow.service'; | ||
|
||
describe('FlowService', () => { | ||
beforeEach(() => { | ||
FlowService.nodes = []; | ||
FlowService.edges = []; | ||
}); | ||
|
||
it('should start with an empty nodes array', () => { | ||
expect(FlowService.nodes).toEqual([]); | ||
}); | ||
|
||
it('should start with an empty edges array', () => { | ||
expect(FlowService.edges).toEqual([]); | ||
}); | ||
|
||
describe('getFlowDiagram', () => { | ||
it('should return nodes and edges for a simple VisualizationNode', () => { | ||
const vizNode = createVisualizationNode('node', {}); | ||
|
||
const { nodes, edges } = FlowService.getFlowDiagram(vizNode); | ||
|
||
expect(nodes).toMatchSnapshot(); | ||
expect(edges).toMatchSnapshot(); | ||
}); | ||
|
||
it('should return nodes and edges for a group with children', () => { | ||
const groupVizNode = createVisualizationNode('group', { isGroup: true }); | ||
const child1VizNode = createVisualizationNode('child1', {}); | ||
const child2VizNode = createVisualizationNode('child2', {}); | ||
groupVizNode.addChild(child1VizNode); | ||
groupVizNode.addChild(child2VizNode); | ||
|
||
const { nodes, edges } = FlowService.getFlowDiagram(groupVizNode); | ||
|
||
expect(nodes).toMatchSnapshot(); | ||
expect(edges).toMatchSnapshot(); | ||
}); | ||
|
||
it('should return nodes and edges for a two-nodes VisualizationNode', () => { | ||
const vizNode = createVisualizationNode('node', {}); | ||
const childNode = createVisualizationNode('child', {}); | ||
vizNode.addChild(childNode); | ||
|
||
const { nodes, edges } = FlowService.getFlowDiagram(vizNode); | ||
|
||
expect(nodes).toMatchSnapshot(); | ||
expect(edges).toMatchSnapshot(); | ||
}); | ||
|
||
it('should return nodes and edges for a multiple nodes VisualizationNode', () => { | ||
const vizNode = createVisualizationNode('node', {}); | ||
|
||
const setHeaderNode = createVisualizationNode('set-header', {}); | ||
vizNode.setNextNode(setHeaderNode); | ||
setHeaderNode.setPreviousNode(vizNode); | ||
|
||
const choiceNode = createVisualizationNode('choice', {}); | ||
setHeaderNode.setNextNode(choiceNode); | ||
choiceNode.setPreviousNode(setHeaderNode); | ||
|
||
const directNode = createVisualizationNode('direct', {}); | ||
choiceNode.setNextNode(directNode); | ||
directNode.setPreviousNode(choiceNode); | ||
|
||
const whenNode = createVisualizationNode('when', {}); | ||
choiceNode.addChild(whenNode); | ||
|
||
const otherwiseNode = createVisualizationNode('otherwise', {}); | ||
choiceNode.addChild(otherwiseNode); | ||
|
||
const whenLeafNode = createVisualizationNode('when-leaf', {}); | ||
whenNode.addChild(whenLeafNode); | ||
|
||
const processNode = createVisualizationNode('process', {}); | ||
otherwiseNode.addChild(processNode); | ||
const logNode = createVisualizationNode('log', {}); | ||
processNode.addChild(logNode); | ||
|
||
const { nodes, edges } = FlowService.getFlowDiagram(vizNode); | ||
|
||
expect(nodes).toMatchSnapshot(); | ||
expect(edges).toMatchSnapshot(); | ||
}); | ||
|
||
it('should return a group node for a multiple nodes VisualizationNode with a group', () => { | ||
const routeNode = createVisualizationNode('route', { | ||
entity: { getId: () => 'myId' } as BaseVisualCamelEntity, | ||
isGroup: true, | ||
}); | ||
|
||
const fromNode = createVisualizationNode('timer', { | ||
path: 'from', | ||
icon: undefined, | ||
processorName: 'from', | ||
componentName: 'timer', | ||
}); | ||
routeNode.addChild(fromNode); | ||
|
||
const { nodes, edges } = FlowService.getFlowDiagram(routeNode); | ||
|
||
expect(nodes).toHaveLength(2); | ||
expect(edges).toHaveLength(0); | ||
|
||
const group = nodes[nodes.length - 1]; | ||
expect(group.children).toEqual(['timer-1234']); | ||
expect(group.group).toBeTruthy(); | ||
}); | ||
}); | ||
}); |
114 changes: 114 additions & 0 deletions
114
packages/ui/src/components/Visualization/Canvas/flow.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import { EdgeStyle } from '@patternfly/react-topology'; | ||
import { IVisualizationNode } from '../../../models/visualization/base-visual-entity'; | ||
import { CanvasDefaults } from './canvas.defaults'; | ||
import { CanvasEdge, CanvasNode, CanvasNodesAndEdges } from './canvas.models'; | ||
|
||
export class FlowService { | ||
static nodes: CanvasNode[] = []; | ||
static edges: CanvasEdge[] = []; | ||
private static visitedNodes: string[] = []; | ||
|
||
static getFlowDiagram(vizNode: IVisualizationNode): CanvasNodesAndEdges { | ||
this.nodes = []; | ||
this.edges = []; | ||
this.visitedNodes = []; | ||
|
||
this.appendNodesAndEdges(vizNode); | ||
|
||
return { nodes: this.nodes, edges: this.edges }; | ||
} | ||
|
||
/** Method for iterating over all the IVisualizationNode and its children using a depth-first algorithm */ | ||
private static appendNodesAndEdges(vizNodeParam: IVisualizationNode): void { | ||
if (this.visitedNodes.includes(vizNodeParam.id)) { | ||
return; | ||
} | ||
|
||
let node: CanvasNode; | ||
|
||
const children = vizNodeParam.getChildren(); | ||
if (vizNodeParam.data.isGroup && children) { | ||
children.forEach((child) => { | ||
this.appendNodesAndEdges(child); | ||
}); | ||
|
||
const containerId = vizNodeParam.id; | ||
node = this.getContainer(containerId, { | ||
label: containerId, | ||
children: children.map((child) => child.id), | ||
parentNode: vizNodeParam.getParentNode()?.id, | ||
data: { vizNode: vizNodeParam }, | ||
}); | ||
} else { | ||
node = this.getCanvasNode(vizNodeParam); | ||
} | ||
|
||
/** Add node */ | ||
this.nodes.push(node); | ||
this.visitedNodes.push(node.id); | ||
|
||
/** Add edges */ | ||
this.edges.push(...this.getEdgesFromVizNode(vizNodeParam)); | ||
} | ||
|
||
private static getCanvasNode(vizNodeParam: IVisualizationNode): CanvasNode { | ||
/** Join the parent if exist to form a group */ | ||
const parentNode = | ||
vizNodeParam.getParentNode()?.getChildren() !== undefined ? vizNodeParam.getParentNode()?.id : undefined; | ||
|
||
return this.getNode(vizNodeParam.id, { | ||
parentNode, | ||
data: { vizNode: vizNodeParam }, | ||
}); | ||
} | ||
|
||
private static getEdgesFromVizNode(vizNodeParam: IVisualizationNode): CanvasEdge[] { | ||
const edges: CanvasEdge[] = []; | ||
|
||
if (vizNodeParam.getNextNode() !== undefined) { | ||
edges.push(this.getEdge(vizNodeParam.id, vizNodeParam.getNextNode()!.id)); | ||
} | ||
|
||
return edges; | ||
} | ||
|
||
private static getContainer( | ||
id: string, | ||
options: { label?: string; children?: string[]; parentNode?: string; data?: CanvasNode['data'] } = {}, | ||
): CanvasNode { | ||
return { | ||
id, | ||
type: 'group', | ||
group: true, | ||
label: options.label ?? id, | ||
children: options.children ?? [], | ||
parentNode: options.parentNode, | ||
data: options.data, | ||
style: { | ||
padding: CanvasDefaults.DEFAULT_NODE_DIAMETER * 0.8, | ||
}, | ||
}; | ||
} | ||
|
||
private static getNode(id: string, options: { parentNode?: string; data?: CanvasNode['data'] } = {}): CanvasNode { | ||
return { | ||
id, | ||
type: 'node', | ||
parentNode: options.parentNode, | ||
data: options.data, | ||
width: CanvasDefaults.DEFAULT_NODE_DIAMETER, | ||
height: CanvasDefaults.DEFAULT_NODE_DIAMETER, | ||
shape: CanvasDefaults.DEFAULT_NODE_SHAPE, | ||
}; | ||
} | ||
|
||
private static getEdge(source: string, target: string): CanvasEdge { | ||
return { | ||
id: `${source}-to-${target}`, | ||
type: 'edge', | ||
source, | ||
target, | ||
edgeStyle: EdgeStyle.solid, | ||
}; | ||
} | ||
} |