Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(viz) Replace Camel Route steps #288

Merged
merged 3 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions packages/ui/src/camel-utils/camel-to-tile.adapter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,19 @@ describe('camelComponentToTile', () => {
expect(tile.tags).toEqual(['label1', 'label2']);
expect(tile.version).toEqual('4.0.0');
});

it('should populate tags with `consumerOnly` and `producerOnly` when applicable', () => {
const componentDef = {
component: {
consumerOnly: true,
producerOnly: true,
},
} as ICamelComponentDefinition;

const tile = camelComponentToTile(componentDef);

expect(tile.tags).toEqual(['consumerOnly', 'producerOnly']);
});
});

describe('camelProcessorToTile', () => {
Expand Down
6 changes: 6 additions & 0 deletions packages/ui/src/camel-utils/camel-to-tile.adapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ export const camelComponentToTile = (componentDef: ICamelComponentDefinition): I
if (label) {
tags.push(...label.split(','));
}
if (componentDef.component.consumerOnly) {
tags.push('consumerOnly');
}
if (componentDef.component.producerOnly) {
tags.push('producerOnly');
}

return {
type: CatalogKind.Component,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ export const ItemReplaceNode: FunctionComponent<IDataTestID> = (props) => {

/** Open Catalog modal, filtering the compatible nodes */
const definedComponent = await catalogModalContext?.getNewComponent(compatibleNodes);
console.log(definedComponent);
if (!definedComponent) return;

/** Add new node to the entities */
Expand Down
47 changes: 44 additions & 3 deletions packages/ui/src/models/camel/camel-route-resource.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import { RouteDefinition } from '@kaoto-next/camel-catalog/types';
import { ITile } from '../../components/Catalog';
import { isDefined } from '../../utils';
import { CatalogFilter } from '../catalog-filter';
import { CatalogKind } from '../catalog-kind';
import { AddStepMode } from '../visualization/base-visual-entity';
import { CamelRouteVisualEntity, isCamelRoute } from '../visualization/flows';
import { flowTemplateService } from '../visualization/flows/flow-templates-service';
import { CamelComponentSchemaService } from '../visualization/flows/support/camel-component-schema.service';
import { CamelRouteVisualEntityData } from '../visualization/flows/support/camel-component-types';
import { BeansEntity, isBeans } from '../visualization/metadata';
import { BeansAwareResource, CamelResource } from './camel-resource';
Expand Down Expand Up @@ -95,10 +96,50 @@ export class CamelRouteResource implements CamelResource, BeansAwareResource {

/** Components Catalog related methods */
getCompatibleComponents(mode: AddStepMode, visualEntityData: CamelRouteVisualEntityData): CatalogFilter {
return {
filterFunction: this.getFilterFunction(mode, visualEntityData),
};
}

private getFilterFunction(mode: AddStepMode, visualEntityData: CamelRouteVisualEntityData): (item: ITile) => boolean {
if (mode === AddStepMode.ReplaceStep && visualEntityData.path === 'from') {
/**
* For the `from` step we want to show only components which are not `producerOnly`,
* as this mean that they can be used only as a consumer.
*/
return (item: ITile) => {
return item.type === CatalogKind.Component && !item.tags.includes('producerOnly');
};
}

if (mode === AddStepMode.InsertSpecialChildStep) {
return CamelComponentSchemaService.getCompatibleComponents(visualEntityData.processorName);
/**
* specialChildren is a map of processor names and their special children.
*/
const specialChildren: Record<string, string[]> = {
choice: ['when', 'otherwise'],
doTry: ['doCatch', 'doFinally'],
};

/**
* For special child steps, we need to check which type of processor it is, in order to determine
* what kind of components we want to show.
*/
return (item: ITile) => {
if (item.type !== CatalogKind.Processor || specialChildren[visualEntityData.processorName] === undefined) {
return false;
}

return specialChildren[visualEntityData.processorName].includes(item.name);
};
}

return {};
/**
* For the rest, we want to filter out components that are `consumerOnly`,
* as this mean that they can be used only as a consumer.
*/
return (item: ITile) => {
return !item.tags.includes('consumerOnly');
};
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -234,11 +234,11 @@ describe('Camel Route', () => {
expect(vizNode.data.label).toEqual('timer:tutorial');
});

it('should set an empty label if the uri is not available', () => {
it('should set a default label if the uri is not available', () => {
camelEntity = new CamelRouteVisualEntity({ from: {} } as RouteDefinition);
const vizNode = camelEntity.toVizNode();

expect(vizNode.data.label).toEqual('');
expect(vizNode.data.label).toEqual('from: Unknown');
});

it('should populate the viz node chain with the steps', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,18 @@ export class CamelRouteVisualEntity implements BaseVisualCamelEntity {
targetProperty?: string;
}) {
if (options.data.path === undefined) return;
console.log(options);

const defaultValue = CamelComponentDefaultService.getDefaultNodeDefinitionValue(options.definedComponent);
const stepsProperties = CamelComponentSchemaService.getProcessorStepsProperties(
(options.data as CamelRouteVisualEntityData).processorName as keyof ProcessorDefinition,
);

if (options.mode === AddStepMode.InsertChildStep || options.mode === AddStepMode.InsertSpecialChildStep) {
/** Replace the root `from` step */
if (options.mode === AddStepMode.ReplaceStep && options.data.path === 'from' && isDefined(this.route.from)) {
const fromValue = CamelComponentDefaultService.getDefaultFromDefinitionValue(options.definedComponent);
Object.assign(this.route.from, fromValue);
return;
} else if (options.mode === AddStepMode.InsertChildStep || options.mode === AddStepMode.InsertSpecialChildStep) {
this.insertChildStep(options, stepsProperties, defaultValue);

return;
}

Expand Down Expand Up @@ -134,10 +136,14 @@ export class CamelRouteVisualEntity implements BaseVisualCamelEntity {
* last: setHeader
*/
if (!Number.isInteger(Number(last)) && Number.isInteger(Number(penultimate))) {
const desiredIndex = options.mode === AddStepMode.PrependStep ? Number(penultimate) : Number(penultimate) + 1;
/** If we're in Append mode, we need to insert the step after the selected index hence `Number(penultimate) + 1` */
const desiredStartIndex = options.mode === AddStepMode.AppendStep ? Number(penultimate) + 1 : Number(penultimate);

/** If we're in Replace mode, we need to delete the existing step */
const deleteCount = options.mode === AddStepMode.ReplaceStep ? 1 : 0;

const stepsArray: ProcessorDefinition[] = get(this.route, pathArray.slice(0, -2), []);
stepsArray.splice(desiredIndex, 0, defaultValue);
stepsArray.splice(desiredStartIndex, deleteCount, defaultValue);

return;
}
Expand Down Expand Up @@ -205,14 +211,11 @@ export class CamelRouteVisualEntity implements BaseVisualCamelEntity {
const stepsProperties = CamelComponentSchemaService.getProcessorStepsProperties(
(data as CamelRouteVisualEntityData).processorName as keyof ProcessorDefinition,
);
const catalogFilter = CamelComponentSchemaService.getCompatibleComponents(
(data as CamelRouteVisualEntityData).processorName as keyof ProcessorDefinition,
);
const canHavePreviousStep = CamelComponentSchemaService.canHavePreviousStep(
(data as CamelRouteVisualEntityData).processorName,
);
const canHaveChildren = stepsProperties.find((property) => property.type === 'branch') !== undefined;
const canHaveSpecialChildren = Object.keys(catalogFilter).length > 0;
const canHaveSpecialChildren = Object.keys(stepsProperties).length > 1;

return {
canHavePreviousStep,
Expand All @@ -226,6 +229,11 @@ export class CamelRouteVisualEntity implements BaseVisualCamelEntity {
const rootNode = this.getVizNodeFromProcessor('from', { processorName: 'from' as keyof ProcessorDefinition });
rootNode.data.entity = this;

if (!this.route.from?.uri) {
rootNode.data.label = 'from: Unknown';
rootNode.data.icon = NodeIconResolver.getPlaceholderIcon();
}

return rootNode;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ import { CatalogKind } from '../../../catalog-kind';
* This class is meant to provide working default values for Camel components.
*/
export class CamelComponentDefaultService {
/**
* Get the default definition for the `from` component
*/
static getDefaultFromDefinitionValue(definedComponent: DefinedComponent): ProcessorDefinition {
return parse(`
id: ${getCamelRandomId('from')}
uri: "${definedComponent.name}"
parameters: {}
`);
}

/**
* Get the default value for a given component and property
*/
Expand All @@ -27,14 +38,12 @@ export class CamelComponentDefaultService {
}

private static getDefaultValueFromComponent(componentName: string): object {
switch (componentName) {
default:
return parse(`
to:
uri: "${componentName}"
id: ${getCamelRandomId('to')}
`);
}
return parse(`
to:
id: ${getCamelRandomId('to')}
uri: "${componentName}"
parameters: {}
`);
}

private static getDefaultValueFromKamelet(kameletName: string): object {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import type { JSONSchemaType } from 'ajv';
import { isDefined } from '../../../../utils';
import { ICamelComponentProperty } from '../../../camel-components-catalog';
import { ICamelProcessorProperty } from '../../../camel-processors-catalog';
import { CatalogFilter } from '../../../catalog-filter';
import { CatalogKind } from '../../../catalog-kind';
import { VisualComponentSchema } from '../../base-visual-entity';
import { CamelCatalogService } from '../camel-catalog.service';
Expand Down Expand Up @@ -77,25 +76,6 @@ export class CamelComponentSchemaService {
return !this.DISABLED_SIBLING_STEPS.includes(processorName);
}

static getCompatibleComponents(processorName: keyof ProcessorDefinition): CatalogFilter {
switch (processorName) {
case 'choice':
return {
kinds: [CatalogKind.Processor],
names: ['when', 'otherwise'],
};

case 'doTry':
return {
kinds: [CatalogKind.Processor],
names: ['doCatch', 'doFinally'],
};

default:
return {};
}
}

static getProcessorStepsProperties(processorName: keyof ProcessorDefinition): CamelProcessorStepsProperties[] {
switch (processorName) {
/** choice */ case 'when':
Expand Down