Skip to content

Commit

Permalink
feat(Canvas): Add Node mapper
Browse files Browse the repository at this point in the history
Currently, EIPs with children are rendered as containers, as opposed to in the past, where they were rendered as nodes.

The goal for this ticket is to be able to customize how each EIP is rendered.

This is an intermediate step between having a single class holding the
entire route vs having individual classes per EIP, each holding the
underlying code section they represent.

fix: #1329
  • Loading branch information
lordrip committed Aug 19, 2024
1 parent bf06625 commit 5526ebf
Show file tree
Hide file tree
Showing 28 changed files with 593 additions and 205 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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<T extends object> implements BaseVisualCamelEntity {
Expand Down Expand Up @@ -222,7 +222,7 @@ export abstract class AbstractCamelVisualEntity<T extends object> implements Bas
processorName: 'route',
});

const fromNode = CamelStepsService.getVizNodeFromProcessor(
const fromNode = NodeMapperService.getVizNode(
'from',
{
processorName: 'from' as keyof ProcessorDefinition,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -125,7 +125,7 @@ export class CamelErrorHandlerVisualEntity implements BaseVisualCamelEntity {
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const errorHandlerGroupNode = CamelStepsService.getVizNodeFromProcessor(
const errorHandlerGroupNode = NodeMapperService.getVizNode(
'errorHandler',
{ processorName: 'errorHandler' as keyof ProcessorDefinition },
this.errorHandlerDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -98,7 +98,7 @@ export class CamelInterceptFromVisualEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const interceptFromGroupNode = CamelStepsService.getVizNodeFromProcessor(
const interceptFromGroupNode = NodeMapperService.getVizNode(
CamelInterceptFromVisualEntity.ROOT_PATH,
{ processorName: CamelInterceptFromVisualEntity.ROOT_PATH as keyof ProcessorDefinition },
this.interceptFromDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -110,7 +110,7 @@ export class CamelInterceptSendToEndpointVisualEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const interceptSendToEndpointGroupNode = CamelStepsService.getVizNodeFromProcessor(
const interceptSendToEndpointGroupNode = NodeMapperService.getVizNode(
CamelInterceptSendToEndpointVisualEntity.ROOT_PATH,
{ processorName: CamelInterceptSendToEndpointVisualEntity.ROOT_PATH as keyof ProcessorDefinition },
this.interceptSendToEndpointDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -81,7 +81,7 @@ export class CamelInterceptVisualEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const interceptGroupNode = CamelStepsService.getVizNodeFromProcessor(
const interceptGroupNode = NodeMapperService.getVizNode(
CamelInterceptVisualEntity.ROOT_PATH,
{ processorName: CamelInterceptVisualEntity.ROOT_PATH as keyof ProcessorDefinition },
this.interceptDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,7 +83,7 @@ export class CamelOnCompletionVisualEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const onCompletionGroupNode = CamelStepsService.getVizNodeFromProcessor(
const onCompletionGroupNode = NodeMapperService.getVizNode(
CamelOnCompletionVisualEntity.ROOT_PATH,
{ processorName: CamelOnCompletionVisualEntity.ROOT_PATH as keyof ProcessorDefinition },
this.onCompletionDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -83,7 +83,7 @@ export class CamelOnExceptionVisualEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const onExceptionGroupNode = CamelStepsService.getVizNodeFromProcessor(
const onExceptionGroupNode = NodeMapperService.getVizNode(

Check warning on line 86 in packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts

View check run for this annotation

Codecov / codecov/patch

packages/ui/src/models/visualization/flows/camel-on-exception-visual-entity.ts#L86

Added line #L86 was not covered by tests
CamelOnExceptionVisualEntity.ROOT_PATH,
{ processorName: CamelOnExceptionVisualEntity.ROOT_PATH as keyof ProcessorDefinition },
this.onExceptionDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -119,7 +119,7 @@ export class CamelRestConfigurationVisualEntity implements BaseVisualCamelEntity
}

toVizNode(): IVisualizationNode<IVisualizationNodeData> {
const restConfigurationGroupNode = CamelStepsService.getVizNodeFromProcessor(
const restConfigurationGroupNode = NodeMapperService.getVizNode(
'restConfiguration',
{ processorName: 'restConfiguration' as keyof ProcessorDefinition },
this.restConfigurationDef,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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 }>
Expand Down Expand Up @@ -156,7 +156,7 @@ export class CamelRouteConfigurationVisualEntity
if (!Array.isArray(childEntities)) return;

childEntities.forEach((childEntity, index) => {
const childNode = CamelStepsService.getVizNodeFromProcessor(
const childNode = NodeMapperService.getVizNode(

Check warning on line 159 in packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts

View check run for this annotation

Codecov / codecov/patch

packages/ui/src/models/visualization/flows/camel-route-configuration-visual-entity.ts#L159

Added line #L159 was not covered by tests
`${CamelRouteConfigurationVisualEntity.ROOT_PATH}.${stepsProperty.name}.${index}.${
Object.keys(childEntity)[0]
}`,
Expand Down
Original file line number Diff line number Diff line change
@@ -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,
Expand All @@ -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({
Expand All @@ -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');
Expand All @@ -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');
});
});
});
Original file line number Diff line number Diff line change
@@ -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 [];

Check warning on line 69 in packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.ts

View check run for this annotation

Codecov / codecov/patch

packages/ui/src/models/visualization/flows/nodes/mappers/base-node-mapper.ts#L68-L69

Added lines #L68 - L69 were not covered by tests
}
}

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);
});
}
}
Loading

0 comments on commit 5526ebf

Please sign in to comment.