diff --git a/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts b/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts index e010275d8..b27c69430 100644 --- a/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/abstract-camel-visual-entity.ts @@ -18,7 +18,7 @@ import { createVisualizationNode } from '../visualization-node'; import { CamelComponentDefaultService } from './support/camel-component-default.service'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelProcessorStepsProperties, CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export abstract class AbstractCamelVisualEntity implements BaseVisualCamelEntity { @@ -222,7 +222,7 @@ export abstract class AbstractCamelVisualEntity implements Bas processorName: 'route', }); - const fromNode = CamelStepsService.getVizNodeFromProcessor( + const fromNode = NodeMapperService.getVizNode( 'from', { processorName: 'from' as keyof ProcessorDefinition, diff --git a/packages/ui/src/models/visualization/flows/camel-error-handler-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-error-handler-visual-entity.ts index 406650415..a11d2ec35 100644 --- a/packages/ui/src/models/visualization/flows/camel-error-handler-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-error-handler-visual-entity.ts @@ -11,7 +11,7 @@ import { NodeInteraction, VisualComponentSchema, } from '../base-visual-entity'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; export class CamelErrorHandlerVisualEntity implements BaseVisualCamelEntity { id: string; @@ -125,7 +125,7 @@ export class CamelErrorHandlerVisualEntity implements BaseVisualCamelEntity { } toVizNode(): IVisualizationNode { - const errorHandlerGroupNode = CamelStepsService.getVizNodeFromProcessor( + const errorHandlerGroupNode = NodeMapperService.getVizNode( 'errorHandler', { processorName: 'errorHandler' as keyof ProcessorDefinition }, this.errorHandlerDef, diff --git a/packages/ui/src/models/visualization/flows/camel-intercept-from-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-intercept-from-visual-entity.ts index e0220f930..79e538504 100644 --- a/packages/ui/src/models/visualization/flows/camel-intercept-from-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-intercept-from-visual-entity.ts @@ -11,7 +11,7 @@ import { import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export class CamelInterceptFromVisualEntity @@ -98,7 +98,7 @@ export class CamelInterceptFromVisualEntity } toVizNode(): IVisualizationNode { - const interceptFromGroupNode = CamelStepsService.getVizNodeFromProcessor( + const interceptFromGroupNode = NodeMapperService.getVizNode( CamelInterceptFromVisualEntity.ROOT_PATH, { processorName: CamelInterceptFromVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.interceptFromDef, diff --git a/packages/ui/src/models/visualization/flows/camel-intercept-send-to-endpoint-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-intercept-send-to-endpoint-visual-entity.ts index e5ebbfb21..50749e6f7 100644 --- a/packages/ui/src/models/visualization/flows/camel-intercept-send-to-endpoint-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-intercept-send-to-endpoint-visual-entity.ts @@ -11,7 +11,7 @@ import { import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export class CamelInterceptSendToEndpointVisualEntity @@ -110,7 +110,7 @@ export class CamelInterceptSendToEndpointVisualEntity } toVizNode(): IVisualizationNode { - const interceptSendToEndpointGroupNode = CamelStepsService.getVizNodeFromProcessor( + const interceptSendToEndpointGroupNode = NodeMapperService.getVizNode( CamelInterceptSendToEndpointVisualEntity.ROOT_PATH, { processorName: CamelInterceptSendToEndpointVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.interceptSendToEndpointDef, diff --git a/packages/ui/src/models/visualization/flows/camel-intercept-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-intercept-visual-entity.ts index 57310f461..b55b228ba 100644 --- a/packages/ui/src/models/visualization/flows/camel-intercept-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-intercept-visual-entity.ts @@ -11,7 +11,7 @@ import { import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export class CamelInterceptVisualEntity @@ -81,7 +81,7 @@ export class CamelInterceptVisualEntity } toVizNode(): IVisualizationNode { - const interceptGroupNode = CamelStepsService.getVizNodeFromProcessor( + const interceptGroupNode = NodeMapperService.getVizNode( CamelInterceptVisualEntity.ROOT_PATH, { processorName: CamelInterceptVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.interceptDef, diff --git a/packages/ui/src/models/visualization/flows/camel-on-completion-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-on-completion-visual-entity.ts index 7d0be41f7..da490c664 100644 --- a/packages/ui/src/models/visualization/flows/camel-on-completion-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-on-completion-visual-entity.ts @@ -11,7 +11,7 @@ import { import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export class CamelOnCompletionVisualEntity @@ -83,7 +83,7 @@ export class CamelOnCompletionVisualEntity } toVizNode(): IVisualizationNode { - const onCompletionGroupNode = CamelStepsService.getVizNodeFromProcessor( + const onCompletionGroupNode = NodeMapperService.getVizNode( CamelOnCompletionVisualEntity.ROOT_PATH, { processorName: CamelOnCompletionVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.onCompletionDef, diff --git a/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts index 2417d7d3d..b3a6ac452 100644 --- a/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts @@ -11,7 +11,7 @@ import { import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; import { CamelRouteVisualEntityData } from './support/camel-component-types'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; import { ModelValidationService } from './support/validators/model-validation.service'; export class CamelOnExceptionVisualEntity @@ -83,7 +83,7 @@ export class CamelOnExceptionVisualEntity } toVizNode(): IVisualizationNode { - const onExceptionGroupNode = CamelStepsService.getVizNodeFromProcessor( + const onExceptionGroupNode = NodeMapperService.getVizNode( CamelOnExceptionVisualEntity.ROOT_PATH, { processorName: CamelOnExceptionVisualEntity.ROOT_PATH as keyof ProcessorDefinition }, this.onExceptionDef, diff --git a/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts index dc434089e..3adbbe428 100644 --- a/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-rest-configuration-visual-entity.ts @@ -14,7 +14,7 @@ import { VisualComponentSchema, } from '../base-visual-entity'; import { CamelCatalogService } from './camel-catalog.service'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; export class CamelRestConfigurationVisualEntity implements BaseVisualCamelEntity { id: string; @@ -119,7 +119,7 @@ export class CamelRestConfigurationVisualEntity implements BaseVisualCamelEntity } toVizNode(): IVisualizationNode { - const restConfigurationGroupNode = CamelStepsService.getVizNodeFromProcessor( + const restConfigurationGroupNode = NodeMapperService.getVizNode( 'restConfiguration', { processorName: 'restConfiguration' as keyof ProcessorDefinition }, this.restConfigurationDef, diff --git a/packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts b/packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts index 54ab3cbfc..1436ee893 100644 --- a/packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts +++ b/packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts @@ -18,7 +18,7 @@ import { createVisualizationNode } from '../visualization-node'; import { AbstractCamelVisualEntity } from './abstract-camel-visual-entity'; import { CamelCatalogService } from './camel-catalog.service'; import { CamelComponentSchemaService } from './support/camel-component-schema.service'; -import { CamelStepsService } from './support/camel-steps.service'; +import { NodeMapperService } from './nodes/node-mapper.service'; export class CamelRouteConfigurationVisualEntity extends AbstractCamelVisualEntity<{ routeConfiguration: RouteConfigurationDefinition }> @@ -156,7 +156,7 @@ export class CamelRouteConfigurationVisualEntity if (!Array.isArray(childEntities)) return; childEntities.forEach((childEntity, index) => { - const childNode = CamelStepsService.getVizNodeFromProcessor( + const childNode = NodeMapperService.getVizNode( `${CamelRouteConfigurationVisualEntity.ROOT_PATH}.${stepsProperty.name}.${index}.${ Object.keys(childEntity)[0] }`, diff --git a/packages/ui/src/models/visualization/flows/support/camel-steps.service.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.test.ts similarity index 54% rename from packages/ui/src/models/visualization/flows/support/camel-steps.service.test.ts rename to packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.test.ts index 8462095d4..ca11ac6ed 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-steps.service.test.ts +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.test.ts @@ -1,13 +1,19 @@ import { ProcessorDefinition, RouteDefinition } from '@kaoto/camel-catalog/types'; -import { ICamelElementLookupResult } from './camel-component-types'; -import { CamelStepsService } from './camel-steps.service'; +import { ICamelElementLookupResult } from '../../support/camel-component-types'; +import { RootNodeMapper } from '../root-node-mapper'; +import { BaseNodeMapper } from './base-node-mapper'; -describe('CamelStepsService', () => { +describe('BaseNodeMapper', () => { + let mapper: BaseNodeMapper; let path: string; let componentLookup: ICamelElementLookupResult; let entityDefinition: unknown; beforeEach(() => { + const rootNodeMapper = new RootNodeMapper(); + mapper = new BaseNodeMapper(rootNodeMapper); + rootNodeMapper.registerDefaultMapper(mapper); + path = 'from'; componentLookup = { processorName: 'from' as keyof ProcessorDefinition, @@ -18,7 +24,7 @@ describe('CamelStepsService', () => { describe('getVizNodeFromProcessor', () => { it('should return a VisualizationNode', () => { - const vizNode = CamelStepsService.getVizNodeFromProcessor(path, componentLookup, entityDefinition); + const vizNode = mapper.getVizNodeFromProcessor(path, componentLookup, entityDefinition); expect(vizNode).toBeDefined(); expect(vizNode.data).toMatchObject({ @@ -37,7 +43,7 @@ describe('CamelStepsService', () => { }, }; - const vizNode = CamelStepsService.getVizNodeFromProcessor(path, componentLookup, routeDefinition); + const vizNode = mapper.getVizNodeFromProcessor(path, componentLookup, routeDefinition); expect(vizNode.getChildren()).toHaveLength(2); expect(vizNode.getChildren()?.[0].data.path).toBe('from.steps.0.log'); expect(vizNode.getChildren()?.[1].data.path).toBe('from.steps.1.to'); @@ -49,27 +55,24 @@ describe('CamelStepsService', () => { uri: 'timer:timerName', steps: [ { - choice: { - when: [ - { expression: { simple: { expression: '${body} == 1' } } }, - { expression: { simple: { expression: '${body} == 2' } } }, - ], - otherwise: { steps: [{ log: 'logName' }] }, + doTry: { + doCatch: [{ exception: ['java.lang.RuntimeException'] }, { exception: ['java.lang.RuntimeException'] }], + doFinally: { steps: [{ log: 'logName' }] }, }, }, ], }, }; - const vizNode = CamelStepsService.getVizNodeFromProcessor(path, componentLookup, routeDefinition); + const vizNode = mapper.getVizNodeFromProcessor(path, componentLookup, routeDefinition); expect(vizNode.getChildren()).toHaveLength(1); - expect(vizNode.getChildren()?.[0].data.path).toBe('from.steps.0.choice'); + expect(vizNode.getChildren()?.[0].data.path).toBe('from.steps.0.doTry'); - const choiceNode = vizNode.getChildren()?.[0]; - expect(choiceNode?.getChildren()).toHaveLength(3); - expect(choiceNode?.getChildren()?.[0].data.path).toBe('from.steps.0.choice.when.0'); - expect(choiceNode?.getChildren()?.[1].data.path).toBe('from.steps.0.choice.when.1'); - expect(choiceNode?.getChildren()?.[2].data.path).toBe('from.steps.0.choice.otherwise'); + const doTryNode = vizNode.getChildren()?.[0]; + expect(doTryNode?.getChildren()).toHaveLength(3); + expect(doTryNode?.getChildren()?.[0].data.path).toBe('from.steps.0.doTry.doCatch.0'); + expect(doTryNode?.getChildren()?.[1].data.path).toBe('from.steps.0.doTry.doCatch.1'); + expect(doTryNode?.getChildren()?.[2].data.path).toBe('from.steps.0.doTry.doFinally'); }); }); }); diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.ts new file mode 100644 index 000000000..b63d789d9 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.ts @@ -0,0 +1,117 @@ +import { DoCatch, ProcessorDefinition, When1 } from '@kaoto/camel-catalog/types'; +import { getValue } from '../../../../../utils'; +import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver'; +import { IVisualizationNode } from '../../../base-visual-entity'; +import { createVisualizationNode } from '../../../visualization-node'; +import { CamelComponentSchemaService } from '../../support/camel-component-schema.service'; +import { + CamelProcessorStepsProperties, + CamelRouteVisualEntityData, + ICamelElementLookupResult, +} from '../../support/camel-component-types'; +import { INodeMapper } from '../node-mapper'; + +export class BaseNodeMapper implements INodeMapper { + constructor(private readonly rootNodeMapper: INodeMapper) {} + + getVizNodeFromProcessor( + path: string, + componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + const nodeIconType = componentLookup.componentName ? NodeIconType.Component : NodeIconType.EIP; + const data: CamelRouteVisualEntityData = { + path, + icon: NodeIconResolver.getIcon(CamelComponentSchemaService.getIconName(componentLookup), nodeIconType), + processorName: componentLookup.processorName, + componentName: componentLookup.componentName, + }; + + const vizNode = createVisualizationNode(componentLookup.componentName ?? componentLookup.processorName, data); + + const childrenStepsProperties = CamelComponentSchemaService.getProcessorStepsProperties( + componentLookup.processorName, + ); + + if (childrenStepsProperties.length > 0) { + vizNode.data.isGroup = true; + } + + childrenStepsProperties.forEach((stepsProperty) => { + const childrenVizNodes = this.getVizNodesFromChildren(path, stepsProperty, entityDefinition); + + childrenVizNodes.forEach((childVizNode) => { + vizNode.addChild(childVizNode); + }); + }); + + return vizNode; + } + + protected getVizNodesFromChildren( + path: string, + stepsProperty: CamelProcessorStepsProperties, + entityDefinition: unknown, + ): IVisualizationNode[] { + const subpath = `${path}.${stepsProperty.name}`; + + switch (stepsProperty.type) { + case 'branch': + return this.getChildrenFromBranch(subpath, entityDefinition); + + case 'single-clause': + return this.getChildrenFromSingleClause(subpath, entityDefinition); + + case 'array-clause': + return this.getChildrenFromArrayClause(subpath, entityDefinition); + + default: + return []; + } + } + + protected getChildrenFromBranch(path: string, entityDefinition: unknown): IVisualizationNode[] { + const stepsList = getValue(entityDefinition, path, []) as ProcessorDefinition[]; + + return stepsList.reduce((accStepsNodes, step, index) => { + const singlePropertyName = Object.keys(step)[0]; + const childPath = `${path}.${index}.${singlePropertyName}`; + const childComponentLookup = CamelComponentSchemaService.getCamelComponentLookup( + childPath, + getValue(step, singlePropertyName), + ); + + const vizNode = this.rootNodeMapper.getVizNodeFromProcessor(childPath, childComponentLookup, entityDefinition); + + const previousVizNode = accStepsNodes[accStepsNodes.length - 1]; + if (previousVizNode !== undefined) { + previousVizNode.setNextNode(vizNode); + vizNode.setPreviousNode(previousVizNode); + } + + accStepsNodes.push(vizNode); + return accStepsNodes; + }, [] as IVisualizationNode[]); + } + + protected getChildrenFromSingleClause(path: string, entityDefinition: unknown): IVisualizationNode[] { + const childComponentLookup = CamelComponentSchemaService.getCamelComponentLookup(path, entityDefinition); + + /** If the single-clause property is not defined, we don't create a IVisualizationNode for it */ + if (getValue(entityDefinition, path) === undefined) return []; + + return [this.rootNodeMapper.getVizNodeFromProcessor(path, childComponentLookup, entityDefinition)]; + } + + protected getChildrenFromArrayClause(path: string, entityDefinition: unknown): IVisualizationNode[] { + const expressionList = getValue(entityDefinition, path, []) as When1[] | DoCatch[]; + + return expressionList.map((_step, index) => { + const childPath = `${path}.${index}`; + const processorName = path.split('.').pop() as keyof ProcessorDefinition; + const childComponentLookup = { processorName }; // when, doCatch + + return this.rootNodeMapper.getVizNodeFromProcessor(childPath, childComponentLookup, entityDefinition); + }); + } +} diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.test.ts new file mode 100644 index 000000000..6669d2557 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.test.ts @@ -0,0 +1,69 @@ +import { RouteDefinition } from '@kaoto/camel-catalog/types'; +import { RootNodeMapper } from '../root-node-mapper'; +import { ChoiceNodeMapper } from './choice-node-mapper'; +import { OtherwiseNodeMapper } from './otherwise-node-mapper'; +import { WhenNodeMapper } from './when-node-mapper'; +import { noopNodeMapper } from './testing/noop-node-mapper'; + +describe('ChoiceNodeMapper', () => { + let mapper: ChoiceNodeMapper; + let routeDefinition: RouteDefinition; + const path = 'from.steps.0.choice'; + + beforeEach(() => { + const rootNodeMapper = new RootNodeMapper(); + const whenNodeMapper = new WhenNodeMapper(rootNodeMapper); + const otherwiseNodeMapper = new OtherwiseNodeMapper(rootNodeMapper); + rootNodeMapper.registerDefaultMapper(mapper); + rootNodeMapper.registerMapper('when', whenNodeMapper); + rootNodeMapper.registerMapper('otherwise', otherwiseNodeMapper); + rootNodeMapper.registerMapper('log', noopNodeMapper); + + mapper = new ChoiceNodeMapper(rootNodeMapper); + + routeDefinition = { + from: { + uri: 'timer:timerName', + steps: [ + { + choice: { + when: [{ simple: "${header.foo} == 'bar'" }, { simple: "${header.foo} == 'baz'" }], + otherwise: { + steps: [{ log: 'logName' }], + }, + }, + }, + ], + }, + }; + }); + + it('should return children', () => { + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'choice' }, routeDefinition); + + expect(vizNode.getChildren()).toHaveLength(3); + }); + + it('should return `when` nodes as children', () => { + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'choice' }, routeDefinition); + + expect(vizNode.getChildren()?.[0].data.path).toBe('from.steps.0.choice.when.0'); + expect(vizNode.getChildren()?.[1].data.path).toBe('from.steps.0.choice.when.1'); + }); + + it('should return an `otherwise` node if defined', () => { + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'choice' }, routeDefinition); + + expect(vizNode.getChildren()?.[2].data.path).toBe('from.steps.0.choice.otherwise'); + }); + + it('should not return an `otherwise` node if not defined', () => { + routeDefinition.from.steps[0].choice!.otherwise = undefined; + + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'choice' }, routeDefinition); + + expect(vizNode.getChildren()).toHaveLength(2); + expect(vizNode.getChildren()?.[0].data.path).toBe('from.steps.0.choice.when.0'); + expect(vizNode.getChildren()?.[1].data.path).toBe('from.steps.0.choice.when.1'); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.ts new file mode 100644 index 000000000..41d2185a3 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/choice-node-mapper.ts @@ -0,0 +1,37 @@ +import { ProcessorDefinition } from '@kaoto/camel-catalog/types'; +import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver'; +import { IVisualizationNode } from '../../../base-visual-entity'; +import { createVisualizationNode } from '../../../visualization-node'; +import { CamelRouteVisualEntityData, ICamelElementLookupResult } from '../../support/camel-component-types'; +import { BaseNodeMapper } from './base-node-mapper'; + +export class ChoiceNodeMapper extends BaseNodeMapper { + getVizNodeFromProcessor( + path: string, + _componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + const processorName: keyof ProcessorDefinition = 'choice'; + + const data: CamelRouteVisualEntityData = { + path, + icon: NodeIconResolver.getIcon(processorName, NodeIconType.EIP), + processorName, + isGroup: true, + }; + + const vizNode = createVisualizationNode(processorName, data); + + const whenNodes = this.getChildrenFromArrayClause(`${path}.when`, entityDefinition); + whenNodes.forEach((whenNode) => { + vizNode.addChild(whenNode); + }); + + const otherwiseNode = this.getChildrenFromSingleClause(`${path}.otherwise`, entityDefinition); + if (otherwiseNode.length > 0) { + vizNode.addChild(otherwiseNode[0]); + } + + return vizNode; + } +} diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.test.ts new file mode 100644 index 000000000..5a16e9685 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.test.ts @@ -0,0 +1,40 @@ +import { RouteDefinition } from '@kaoto/camel-catalog/types'; +import { RootNodeMapper } from '../root-node-mapper'; +import { OtherwiseNodeMapper } from './otherwise-node-mapper'; +import { noopNodeMapper } from './testing/noop-node-mapper'; + +describe('OtherwiseNodeMapper', () => { + let mapper: OtherwiseNodeMapper; + let routeDefinition: RouteDefinition; + const path = 'from.steps.0.choice.otherwise'; + + beforeEach(() => { + const rootNodeMapper = new RootNodeMapper(); + rootNodeMapper.registerDefaultMapper(mapper); + rootNodeMapper.registerMapper('log', noopNodeMapper); + + mapper = new OtherwiseNodeMapper(rootNodeMapper); + + routeDefinition = { + from: { + uri: 'timer:timerName', + steps: [ + { + choice: { + when: [{ simple: "${header.foo} == 'bar'" }, { simple: "${header.foo} == 'baz'" }], + otherwise: { + steps: [{ log: 'logName' }], + }, + }, + }, + ], + }, + }; + }); + + it('should return children', () => { + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'otherwise' }, routeDefinition); + + expect(vizNode.getChildren()).toHaveLength(1); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.ts new file mode 100644 index 000000000..0a299e467 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/otherwise-node-mapper.ts @@ -0,0 +1,32 @@ +import { ProcessorDefinition } from '@kaoto/camel-catalog/types'; +import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver'; +import { IVisualizationNode } from '../../../base-visual-entity'; +import { createVisualizationNode } from '../../../visualization-node'; +import { CamelRouteVisualEntityData, ICamelElementLookupResult } from '../../support/camel-component-types'; +import { BaseNodeMapper } from './base-node-mapper'; + +export class OtherwiseNodeMapper extends BaseNodeMapper { + getVizNodeFromProcessor( + path: string, + _componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + const processorName: keyof ProcessorDefinition = 'otherwise'; + + const data: CamelRouteVisualEntityData = { + path, + icon: NodeIconResolver.getIcon(processorName, NodeIconType.EIP), + processorName, + isGroup: true, + }; + + const vizNode = createVisualizationNode(processorName, data); + + const children = this.getChildrenFromBranch(`${path}.steps`, entityDefinition); + children.forEach((child) => { + vizNode.addChild(child); + }); + + return vizNode; + } +} diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/testing/noop-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/testing/noop-node-mapper.ts new file mode 100644 index 000000000..8cc2bf700 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/testing/noop-node-mapper.ts @@ -0,0 +1,8 @@ +import { createVisualizationNode } from '../../../../visualization-node'; +import { INodeMapper } from '../../node-mapper'; + +export const noopNodeMapper: INodeMapper = { + getVizNodeFromProcessor: () => { + return createVisualizationNode('noop', {}); + }, +}; diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.test.ts new file mode 100644 index 000000000..dfd2487a0 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.test.ts @@ -0,0 +1,43 @@ +import { RouteDefinition } from '@kaoto/camel-catalog/types'; +import { RootNodeMapper } from '../root-node-mapper'; +import { noopNodeMapper } from './testing/noop-node-mapper'; +import { WhenNodeMapper } from './when-node-mapper'; + +describe('WhenNodeMapper', () => { + let mapper: WhenNodeMapper; + let routeDefinition: RouteDefinition; + const path = 'from.steps.0.choice.when.0'; + + beforeEach(() => { + const rootNodeMapper = new RootNodeMapper(); + rootNodeMapper.registerDefaultMapper(mapper); + rootNodeMapper.registerMapper('log', noopNodeMapper); + + mapper = new WhenNodeMapper(rootNodeMapper); + + routeDefinition = { + from: { + uri: 'timer:timerName', + steps: [ + { + choice: { + when: [ + { expression: { simple: { expression: "${header.foo} == 'bar'" } }, steps: [{ log: 'logName' }] }, + { expression: { simple: { expression: "${header.foo} == 'baz'" } }, steps: [{ log: 'logName' }] }, + ], + otherwise: { + steps: [{ log: 'logName' }], + }, + }, + }, + ], + }, + }; + }); + + it('should return children', () => { + const vizNode = mapper.getVizNodeFromProcessor(path, { processorName: 'when' }, routeDefinition); + + expect(vizNode.getChildren()).toHaveLength(1); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.ts new file mode 100644 index 000000000..b2d5a9135 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/mappers/when-node-mapper.ts @@ -0,0 +1,32 @@ +import { ProcessorDefinition } from '@kaoto/camel-catalog/types'; +import { NodeIconResolver, NodeIconType } from '../../../../../utils/node-icon-resolver'; +import { IVisualizationNode } from '../../../base-visual-entity'; +import { createVisualizationNode } from '../../../visualization-node'; +import { CamelRouteVisualEntityData, ICamelElementLookupResult } from '../../support/camel-component-types'; +import { BaseNodeMapper } from './base-node-mapper'; + +export class WhenNodeMapper extends BaseNodeMapper { + getVizNodeFromProcessor( + path: string, + _componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + const processorName: keyof ProcessorDefinition = 'when'; + + const data: CamelRouteVisualEntityData = { + path, + icon: NodeIconResolver.getIcon(processorName, NodeIconType.EIP), + processorName, + isGroup: true, + }; + + const vizNode = createVisualizationNode(processorName, data); + + const children = this.getChildrenFromBranch(`${path}.steps`, entityDefinition); + children.forEach((child) => { + vizNode.addChild(child); + }); + + return vizNode; + } +} diff --git a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts new file mode 100644 index 000000000..3ea9ec016 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.test.ts @@ -0,0 +1,20 @@ +import { BaseNodeMapper } from './mappers/base-node-mapper'; +import { ChoiceNodeMapper } from './mappers/choice-node-mapper'; +import { OtherwiseNodeMapper } from './mappers/otherwise-node-mapper'; +import { WhenNodeMapper } from './mappers/when-node-mapper'; +import { NodeMapperService } from './node-mapper.service'; +import { RootNodeMapper } from './root-node-mapper'; + +describe('NodeMapperService', () => { + it('should initialize the root node mapper', () => { + const registerDefaultMapperSpy = jest.spyOn(RootNodeMapper.prototype, 'registerDefaultMapper'); + const registerMapperSpy = jest.spyOn(RootNodeMapper.prototype, 'registerMapper'); + + NodeMapperService.getVizNode('path', { processorName: 'log' }, {}); + + expect(registerDefaultMapperSpy).toHaveBeenCalledWith(expect.any(BaseNodeMapper)); + expect(registerMapperSpy).toHaveBeenCalledWith('choice', expect.any(ChoiceNodeMapper)); + expect(registerMapperSpy).toHaveBeenCalledWith('when', expect.any(WhenNodeMapper)); + expect(registerMapperSpy).toHaveBeenCalledWith('otherwise', expect.any(OtherwiseNodeMapper)); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts new file mode 100644 index 000000000..4d896699b --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/node-mapper.service.ts @@ -0,0 +1,36 @@ +import { IVisualizationNode } from '../../base-visual-entity'; +import { ICamelElementLookupResult } from '../support/camel-component-types'; +import { BaseNodeMapper } from './mappers/base-node-mapper'; +import { ChoiceNodeMapper } from './mappers/choice-node-mapper'; +import { OtherwiseNodeMapper } from './mappers/otherwise-node-mapper'; +import { WhenNodeMapper } from './mappers/when-node-mapper'; +import { INodeMapper } from './node-mapper'; +import { RootNodeMapper } from './root-node-mapper'; + +export class NodeMapperService { + private static rootNodeMapper: RootNodeMapper; + + static getVizNode( + path: string, + componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + return this.getInstance().getVizNodeFromProcessor(path, componentLookup, entityDefinition); + } + + private static getInstance(): INodeMapper { + if (!this.rootNodeMapper) { + NodeMapperService.initializeRootNodeMapper(); + } + + return this.rootNodeMapper; + } + + private static initializeRootNodeMapper() { + this.rootNodeMapper = new RootNodeMapper(); + this.rootNodeMapper.registerDefaultMapper(new BaseNodeMapper(this.rootNodeMapper)); + this.rootNodeMapper.registerMapper('choice', new ChoiceNodeMapper(this.rootNodeMapper)); + this.rootNodeMapper.registerMapper('when', new WhenNodeMapper(this.rootNodeMapper)); + this.rootNodeMapper.registerMapper('otherwise', new OtherwiseNodeMapper(this.rootNodeMapper)); + } +} diff --git a/packages/ui/src/models/visualization/flows/nodes/node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/node-mapper.ts new file mode 100644 index 000000000..5a3338cb6 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/node-mapper.ts @@ -0,0 +1,10 @@ +import { IVisualizationNode } from '../../base-visual-entity'; +import { ICamelElementLookupResult } from '../support/camel-component-types'; + +export interface INodeMapper { + getVizNodeFromProcessor( + path: string, + componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode; +} diff --git a/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.test.ts b/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.test.ts new file mode 100644 index 000000000..407440ad8 --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.test.ts @@ -0,0 +1,52 @@ +import { noopNodeMapper } from './mappers/testing/noop-node-mapper'; +import { RootNodeMapper } from './root-node-mapper'; + +describe('RootNodeMapper', () => { + it('should allow consumers to register mappers', () => { + const rootNodeMapper = new RootNodeMapper(); + + rootNodeMapper.registerMapper('log', noopNodeMapper); + + expect(() => rootNodeMapper.getVizNodeFromProcessor('path', { processorName: 'log' }, {})).not.toThrow(); + }); + + it('should allow consumers to register a default mapper', () => { + const rootNodeMapper = new RootNodeMapper(); + + rootNodeMapper.registerDefaultMapper(noopNodeMapper); + + expect(() => rootNodeMapper.getVizNodeFromProcessor('path', { processorName: 'log' }, {})).not.toThrow(); + }); + + it('should throw an error when no mapper is found', () => { + const rootNodeMapper = new RootNodeMapper(); + + expect(() => rootNodeMapper.getVizNodeFromProcessor('path', { processorName: 'log' }, {})).toThrowError( + 'No mapper found for processor: log', + ); + }); + + describe('getVizNodeFromProcessor', () => { + it('should delegate to the default mapper when no mapper is found', () => { + const rootNodeMapper = new RootNodeMapper(); + rootNodeMapper.registerDefaultMapper(noopNodeMapper); + jest.spyOn(noopNodeMapper, 'getVizNodeFromProcessor'); + + const vizNode = rootNodeMapper.getVizNodeFromProcessor('path', { processorName: 'log' }, {}); + + expect(noopNodeMapper.getVizNodeFromProcessor).toHaveBeenCalledWith('path', { processorName: 'log' }, {}); + expect(vizNode).toBeDefined(); + }); + + it('should delegate to the registered mapper', () => { + const rootNodeMapper = new RootNodeMapper(); + rootNodeMapper.registerMapper('log', noopNodeMapper); + jest.spyOn(noopNodeMapper, 'getVizNodeFromProcessor'); + + const vizNode = rootNodeMapper.getVizNodeFromProcessor('path', { processorName: 'log' }, {}); + + expect(noopNodeMapper.getVizNodeFromProcessor).toHaveBeenCalledWith('path', { processorName: 'log' }, {}); + expect(vizNode).toBeDefined(); + }); + }); +}); diff --git a/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.ts b/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.ts new file mode 100644 index 000000000..66324f54f --- /dev/null +++ b/packages/ui/src/models/visualization/flows/nodes/root-node-mapper.ts @@ -0,0 +1,31 @@ +import { ProcessorDefinition } from '@kaoto/camel-catalog/types'; +import { IVisualizationNode } from '../../base-visual-entity'; +import { ICamelElementLookupResult } from '../support/camel-component-types'; +import { INodeMapper } from './node-mapper'; + +export class RootNodeMapper implements INodeMapper { + private readonly mappers: Map = new Map(); + private defaultMapper: INodeMapper | undefined; + + registerMapper(processorName: keyof ProcessorDefinition, mapper: INodeMapper): void { + this.mappers.set(processorName, mapper); + } + + registerDefaultMapper(mapper: INodeMapper): void { + this.defaultMapper = mapper; + } + + getVizNodeFromProcessor( + path: string, + componentLookup: ICamelElementLookupResult, + entityDefinition: unknown, + ): IVisualizationNode { + const mapper = this.mappers.get(componentLookup.processorName) || this.defaultMapper; + + if (!mapper) { + throw new Error(`No mapper found for processor: ${componentLookup.processorName}`); + } + + return mapper.getVizNodeFromProcessor(path, componentLookup, entityDefinition); + } +} diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts index d1a1e2988..b25a1d66c 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.test.ts @@ -7,6 +7,7 @@ import { CatalogKind } from '../../../catalog-kind'; import { NodeLabelType } from '../../../settings/settings.model'; import { CamelCatalogService } from '../camel-catalog.service'; import { CamelComponentSchemaService } from './camel-component-schema.service'; +import { CamelProcessorStepsProperties } from './camel-component-types'; describe('CamelComponentSchemaService', () => { let path: string; @@ -471,7 +472,7 @@ describe('CamelComponentSchemaService', () => { [ 'choice', [ - { name: 'when', type: 'clause-list' }, + { name: 'when', type: 'array-clause' }, { name: 'otherwise', type: 'single-clause' }, ], ], @@ -479,7 +480,7 @@ describe('CamelComponentSchemaService', () => { 'doTry', [ { name: 'steps', type: 'branch' }, - { name: 'doCatch', type: 'clause-list' }, + { name: 'doCatch', type: 'array-clause' }, { name: 'doFinally', type: 'single-clause' }, ], ], @@ -489,11 +490,11 @@ describe('CamelComponentSchemaService', () => { [ 'routeConfiguration', [ - { name: 'intercept', type: 'clause-list' }, - { name: 'interceptFrom', type: 'clause-list' }, - { name: 'interceptSendToEndpoint', type: 'clause-list' }, - { name: 'onException', type: 'clause-list' }, - { name: 'onCompletion', type: 'clause-list' }, + { name: 'intercept', type: 'array-clause' }, + { name: 'interceptFrom', type: 'array-clause' }, + { name: 'interceptSendToEndpoint', type: 'array-clause' }, + { name: 'onException', type: 'array-clause' }, + { name: 'onCompletion', type: 'array-clause' }, ], ], ['intercept', [{ name: 'steps', type: 'branch' }]], @@ -501,13 +502,16 @@ describe('CamelComponentSchemaService', () => { ['interceptSendToEndpoint', [{ name: 'steps', type: 'branch' }]], ['onException', [{ name: 'steps', type: 'branch' }]], ['onCompletion', [{ name: 'steps', type: 'branch' }]], - ])(`should return the steps properties for '%s'`, (processorName, result) => { - const stepsProperties = CamelComponentSchemaService.getProcessorStepsProperties( - processorName as keyof ProcessorDefinition, - ); - - expect(stepsProperties).toEqual(result); - }); + ] as [string, CamelProcessorStepsProperties[]][])( + `should return the steps properties for '%s'`, + (processorName, result) => { + const stepsProperties = CamelComponentSchemaService.getProcessorStepsProperties( + processorName as keyof ProcessorDefinition, + ); + + expect(stepsProperties).toEqual(result); + }, + ); }); describe('getIconName', () => { diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts index bf2264424..d3983a7d1 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-schema.service.ts @@ -176,24 +176,24 @@ export class CamelComponentSchemaService { case 'choice': return [ - { name: 'when', type: 'clause-list' }, + { name: 'when', type: 'array-clause' }, { name: 'otherwise', type: 'single-clause' }, ]; case 'doTry': return [ { name: 'steps', type: 'branch' }, - { name: 'doCatch', type: 'clause-list' }, + { name: 'doCatch', type: 'array-clause' }, { name: 'doFinally', type: 'single-clause' }, ]; case 'routeConfiguration' as keyof ProcessorDefinition: return [ - { name: 'intercept', type: 'clause-list' }, - { name: 'interceptFrom', type: 'clause-list' }, - { name: 'interceptSendToEndpoint', type: 'clause-list' }, - { name: 'onException', type: 'clause-list' }, - { name: 'onCompletion', type: 'clause-list' }, + { name: 'intercept', type: 'array-clause' }, + { name: 'interceptFrom', type: 'array-clause' }, + { name: 'interceptSendToEndpoint', type: 'array-clause' }, + { name: 'onException', type: 'array-clause' }, + { name: 'onCompletion', type: 'array-clause' }, ]; default: diff --git a/packages/ui/src/models/visualization/flows/support/camel-component-types.ts b/packages/ui/src/models/visualization/flows/support/camel-component-types.ts index fcf0513da..0ae59bd25 100644 --- a/packages/ui/src/models/visualization/flows/support/camel-component-types.ts +++ b/packages/ui/src/models/visualization/flows/support/camel-component-types.ts @@ -20,7 +20,7 @@ export interface CamelProcessorStepsProperties { * Property handling type * single-clause: the property can have a single-clause type of processor, f.i. `otherwise` and `doFinally` * branch: the property have a list of `processors`, f.i. `steps` - * clause-list: the property can have a list of clause processors, usually in the shape of `expression`, f.i. `when` and `doCatch` + * array-clause: the property is an array of clause processors, usually in the shape of `expression`, f.i. `when` and `doCatch` */ - type: 'single-clause' | 'branch' | 'clause-list'; + type: 'single-clause' | 'branch' | 'array-clause'; } diff --git a/packages/ui/src/models/visualization/flows/support/camel-steps.service.ts b/packages/ui/src/models/visualization/flows/support/camel-steps.service.ts deleted file mode 100644 index eb145d74e..000000000 --- a/packages/ui/src/models/visualization/flows/support/camel-steps.service.ts +++ /dev/null @@ -1,104 +0,0 @@ -/* eslint-disable no-case-declarations */ -import { DoCatch, ProcessorDefinition, When1 } from '@kaoto/camel-catalog/types'; -import { getValue } from '../../../../utils'; -import { NodeIconResolver, NodeIconType } from '../../../../utils/node-icon-resolver'; -import { IVisualizationNode } from '../../base-visual-entity'; -import { createVisualizationNode } from '../../visualization-node'; -import { CamelComponentSchemaService } from './camel-component-schema.service'; -import { - CamelProcessorStepsProperties, - CamelRouteVisualEntityData, - ICamelElementLookupResult, -} from './camel-component-types'; - -export class CamelStepsService { - static getVizNodeFromProcessor( - path: string, - componentLookup: ICamelElementLookupResult, - entityDefinition: unknown, - ): IVisualizationNode { - const nodeIconType = componentLookup.componentName ? NodeIconType.Component : NodeIconType.EIP; - const data: CamelRouteVisualEntityData = { - path, - icon: NodeIconResolver.getIcon(CamelComponentSchemaService.getIconName(componentLookup), nodeIconType), - processorName: componentLookup.processorName, - componentName: componentLookup.componentName, - }; - - const vizNode = createVisualizationNode(componentLookup.componentName ?? componentLookup.processorName, data); - - const childrenStepsProperties = CamelComponentSchemaService.getProcessorStepsProperties( - componentLookup.processorName as keyof ProcessorDefinition, - ); - - if (childrenStepsProperties.length > 0) { - vizNode.data.isGroup = true; - } - - childrenStepsProperties.forEach((stepsProperty) => { - const childrenVizNodes = this.getVizNodesFromChildren(path, stepsProperty, entityDefinition); - childrenVizNodes.forEach((childVizNode) => { - vizNode.addChild(childVizNode); - }); - }); - - return vizNode; - } - - private static getVizNodesFromChildren( - path: string, - stepsProperty: CamelProcessorStepsProperties, - entityDefinition: unknown, - ): IVisualizationNode[] { - let singlePath: string; - - switch (stepsProperty.type) { - case 'branch': - singlePath = `${path}.${stepsProperty.name}`; - const stepsList = getValue(entityDefinition, singlePath, []) as ProcessorDefinition[]; - - return stepsList.reduce((accStepsNodes, step, index) => { - const singlePropertyName = Object.keys(step)[0]; - const childPath = `${singlePath}.${index}.${singlePropertyName}`; - const childComponentLookup = CamelComponentSchemaService.getCamelComponentLookup( - childPath, - getValue(step, singlePropertyName), - ); - - const vizNode = this.getVizNodeFromProcessor(childPath, childComponentLookup, entityDefinition); - - const previousVizNode = accStepsNodes[accStepsNodes.length - 1]; - if (previousVizNode !== undefined) { - previousVizNode.setNextNode(vizNode); - vizNode.setPreviousNode(previousVizNode); - } - - accStepsNodes.push(vizNode); - return accStepsNodes; - }, [] as IVisualizationNode[]); - - case 'single-clause': - const childPath = `${path}.${stepsProperty.name}`; - const childComponentLookup = CamelComponentSchemaService.getCamelComponentLookup(childPath, entityDefinition); - - /** If the single-clause property is not defined, we don't create a IVisualizationNode for it */ - if (getValue(entityDefinition, childPath) === undefined) return []; - - return [this.getVizNodeFromProcessor(childPath, childComponentLookup, entityDefinition)]; - - case 'clause-list': - singlePath = `${path}.${stepsProperty.name}`; - const expressionList = getValue(entityDefinition, singlePath, []) as When1[] | DoCatch[]; - - return expressionList.map((_step, index) => { - const childPath = `${singlePath}.${index}`; - const childComponentLookup = { processorName: stepsProperty.name as keyof ProcessorDefinition }; // when, doCatch - - return this.getVizNodeFromProcessor(childPath, childComponentLookup, entityDefinition); - }); - - default: - return []; - } - } -} diff --git a/packages/ui/src/tests/__snapshots__/nodes-edges.test.ts.snap b/packages/ui/src/tests/__snapshots__/nodes-edges.test.ts.snap index 07d25688f..c9d8e049d 100644 --- a/packages/ui/src/tests/__snapshots__/nodes-edges.test.ts.snap +++ b/packages/ui/src/tests/__snapshots__/nodes-edges.test.ts.snap @@ -72,7 +72,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -119,7 +118,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -132,7 +130,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -412,7 +409,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -459,7 +455,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -472,7 +467,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -572,7 +566,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -619,7 +612,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -632,7 +624,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -759,7 +750,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` [Circular], ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -816,7 +806,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -829,7 +818,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -1274,7 +1262,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -1331,7 +1318,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -1344,7 +1330,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -1784,7 +1769,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` [Circular], ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -1840,7 +1824,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -1854,7 +1837,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` [Circular], ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -2299,7 +2281,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -2355,7 +2336,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -2369,7 +2349,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` [Circular], ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -2827,7 +2806,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -2874,7 +2852,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -2887,7 +2864,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -3390,7 +3366,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -3437,7 +3412,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -3450,7 +3424,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -3512,7 +3485,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -3559,7 +3531,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -3572,7 +3543,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -3724,7 +3694,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -3771,7 +3740,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -3784,7 +3752,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -4103,7 +4070,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -4150,7 +4116,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -4163,7 +4128,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -4246,7 +4210,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -4293,7 +4256,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -4306,7 +4268,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice", @@ -4429,7 +4390,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.when.0", @@ -4476,7 +4436,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice.otherwise", @@ -4489,7 +4448,6 @@ exports[`Nodes and Edges should generate edges for steps with branches 1`] = ` }, ], "data": { - "componentName": undefined, "icon": "", "isGroup": true, "path": "from.steps.0.choice",