Skip to content

Commit

Permalink
feat(canvas): Add a container for Pipes
Browse files Browse the repository at this point in the history
  • Loading branch information
shivamG640 committed May 15, 2024
1 parent 7136d90 commit 53672a9
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 21 deletions.
1 change: 1 addition & 0 deletions packages/camel-catalog/assembly/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@
-->
<additionalSchema>${inputDirectory}/schema/PipeErrorHandler.json</additionalSchema>
<additionalSchema>${inputDirectory}/schema/KameletConfiguration.json</additionalSchema>
<additionalSchema>${inputDirectory}/schema/PipeConfiguration.json</additionalSchema>
</additionalSchemas>
</configuration>
</execution>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"additionalProperties": false,
"description": "Schema for Pipe configuration",
"properties": {
"name": {
"title": "Name",
"description": "Name of the Pipe",
"type": "string"
},
"labels": {
"additionalProperties": {
"default": "",
"type": "string"
},
"title": "Additional Labels",
"description": "Map of string keys and values that can be used to organize and categorize (scope and select) objects. May match selectors of replication controllers and services. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/labels",
"type": "object"
},
"annotations": {
"additionalProperties": {
"default": "",
"type": "string"
},
"title": "Additional Annotations",
"description": "Annotations is an unstructured key value map stored with a resource that may be set by external tools to store and retrieve arbitrary metadata. They are not queryable and should be preserved when modifying objects. More info: https://kubernetes.io/docs/concepts/overview/working-with-objects/annotations",
"type": "object"
}
},
"required": [
"name"
]
}
Original file line number Diff line number Diff line change
Expand Up @@ -219,13 +219,16 @@ private void processCatalog(CamelYamlDslSchemaProcessor schemaProcessor, Path in
var catalogMap = catalogProcessor.processCatalog();
catalogMap.forEach((name, catalog) -> {
try {
// Adding Kamelet Configuration Schema to the Entities Catalog
// Adding Kamelet & Pipe Configuration Schema to the Entities Catalog
if (name.equals("entities")) {
var catalogNode = jsonMapper.readTree(catalog);
var schema = inputDir.resolve("schema").resolve("KameletConfiguration.json");
((ObjectNode) catalogNode).putObject("KameletConfiguration").putObject("propertiesSchema");
((ObjectNode) catalogNode.path("KameletConfiguration").path("propertiesSchema"))
String files[] = {"KameletConfiguration.json", "PipeConfiguration.json"};
for (String file : files) {
var schema = inputDir.resolve("schema").resolve(file);
((ObjectNode) catalogNode).putObject(file.split("\\.")[0]).putObject("propertiesSchema");
((ObjectNode) catalogNode.path(file.split("\\.")[0]).path("propertiesSchema"))
.setAll((ObjectNode) jsonMapper.readTree(schema.toFile()));
}

StringWriter writer = new StringWriter();
var jsonGenerator = new JsonFactory().createGenerator(writer).useDefaultPrettyPrinter();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ describe('Pipe', () => {

beforeEach(async () => {
pipeCR = cloneDeep(pipeJson);
pipe = new PipeVisualEntity(pipeCR.spec!);
pipe = new PipeVisualEntity(pipeCR.spec!, pipeCR.metadata!);
kameletCatalogMap = await import('@kaoto/camel-catalog/' + catalogIndex.catalogs.kamelets.file);
CamelCatalogService.setCatalogKey(CatalogKind.Kamelet, kameletCatalogMap as Record<string, IKameletDefinition>);
});
Expand Down Expand Up @@ -74,7 +74,7 @@ describe('Pipe', () => {
it('should not update the model if no path is provided', () => {
const originalObject = JSON.parse(JSON.stringify(pipeJson));

pipe.updateModel(undefined, undefined);
pipe.updateModel(undefined, undefined as unknown as Record<string, unknown>);

expect(originalObject).toEqual(pipeJson);
});
Expand Down Expand Up @@ -160,22 +160,23 @@ describe('Pipe', () => {
});

describe('toVizNode', () => {
it('should return the viz node and set the initial path to `source`', () => {
it('should return the viz node and set the initial path to `#`', () => {
const vizNode = pipe.toVizNode();

expect(vizNode).toBeDefined();
expect(vizNode.data.path).toEqual('source');
expect(vizNode.data.path).toEqual('#');
});

it('should use the uri as the node label', () => {
const vizNode = pipe.toVizNode();

expect(vizNode.getNodeLabel()).toEqual('webhook-source');
expect(vizNode.getNodeLabel()).toEqual('webhook-binding');
});

it('should set the node labels as `Unknown` if the uri is not available', () => {
pipe = new PipeVisualEntity({});
const sourceNode = pipe.toVizNode();

const sourceNode = pipe.toVizNode().getChildren()![0];
const sinkNode = sourceNode.getNextNode();

expect(sourceNode.getNodeLabel()).toEqual('source: Unknown');
Expand All @@ -185,15 +186,21 @@ describe('Pipe', () => {
it('should populate the viz node chain with the steps', () => {
const vizNode = pipe.toVizNode();

expect(vizNode.data.path).toEqual('source');
expect(vizNode.getNodeLabel()).toEqual('webhook-source');
expect(vizNode.data.path).toEqual('#');
expect(vizNode.getNodeLabel()).toEqual('webhook-binding');
expect(vizNode.getPreviousNode()).toBeUndefined();
expect(vizNode.getNextNode()).toBeDefined();
expect(vizNode.getNextNode()).toBeUndefined();
expect(vizNode.getChildren()).toBeDefined();

const source = vizNode.getChildren()![0];
expect(source.getNodeLabel()).toEqual('webhook-source');
expect(source.getPreviousNode()).toBeUndefined();
expect(source.getNextNode()).toBeDefined();

const steps0 = vizNode.getNextNode()!;
const steps0 = source.getNextNode()!;
expect(steps0.data.path).toEqual('steps.0');
expect(steps0.getNodeLabel()).toEqual('delay-action');
expect(steps0.getPreviousNode()).toBe(vizNode);
expect(steps0.getPreviousNode()).toBe(source);
expect(steps0.getNextNode()).toBeDefined();

const sink = steps0.getNextNode()!;
Expand Down
64 changes: 58 additions & 6 deletions packages/ui/src/models/visualization/flows/pipe-visual-entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,16 @@ import get from 'lodash/get';
import set from 'lodash/set';
import { getCamelRandomId } from '../../../camel-utils/camel-random-id';
import { SchemaService } from '../../../components/Form/schema.service';
import { getArrayProperty, NodeIconResolver, ROOT_PATH } from '../../../utils';
import {
getArrayProperty,
NodeIconResolver,
NodeIconType,
ROOT_PATH,
getCustomSchemaFromPipe,
updatePipeFromCustomSchema,
setValue,
getValue,
} from '../../../utils';
import { DefinedComponent } from '../../camel-catalog-index';
import { EntityType } from '../../camel/entities';
import { PipeMetadata, PipeSpec, PipeStep } from '../../camel/entities/pipe-overrides';
Expand All @@ -18,6 +27,9 @@ import {
import { createVisualizationNode } from '../visualization-node';
import { KameletSchemaService } from './support/kamelet-schema.service';
import { ModelValidationService } from './support/validators/model-validation.service';
import { KaotoSchemaDefinition } from '../../kaoto-schema';
import { CamelCatalogService } from './camel-catalog.service';
import { CatalogKind } from '../../catalog-kind';

export class PipeVisualEntity implements BaseVisualCamelEntity {
id: string;
Expand Down Expand Up @@ -48,6 +60,10 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {
getNodeLabel(path?: string): string {
if (!path) return '';

if (path === ROOT_PATH) {
return this.id;
}

const stepModel = get(this.spec, path) as PipeStep;
return KameletSchemaService.getNodeLabel(stepModel, path);
}
Expand All @@ -61,6 +77,14 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {

getComponentSchema(path?: string): VisualComponentSchema | undefined {
if (!path) return undefined;
if (path === ROOT_PATH) {
return {
title: 'Pipe',
schema: this.getRootPipeSchema(),
definition: getCustomSchemaFromPipe(this.metadata),
};
}

const stepModel = get(this.spec, path) as PipeStep;
return KameletSchemaService.getVisualComponentSchema(stepModel);
}
Expand All @@ -73,11 +97,17 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {
return this.spec;
}

updateModel(path: string | undefined, value: unknown): void {
updateModel(path: string | undefined, value: Record<string, unknown>): void {
if (!path) return;

const stepModel = get(this.spec, path) as PipeStep;
if (stepModel) set(stepModel, 'properties', value);
if (path === ROOT_PATH) {
updatePipeFromCustomSchema(this.metadata, value);
this.id = this.metadata.name as string;
return;
}

const stepModel = getValue(this.spec, path) as PipeStep;
if (stepModel) setValue(stepModel, 'properties', value);
}

/**
Expand Down Expand Up @@ -178,15 +208,24 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {
}

toVizNode(): IVisualizationNode {
const pipeGroupNode = createVisualizationNode(this.id, {
path: ROOT_PATH,
entity: this,
isGroup: true,
icon: NodeIconResolver.getIcon(this.type, NodeIconType.VisualEntity),
});

const sourceNode = this.getVizNodeFromStep(this.spec.source, 'source', true);
const stepNodes = this.getVizNodesFromSteps(this.spec.steps);
const sinkNode = this.getVizNodeFromStep(this.spec.sink, 'sink');
/** If there are no steps, we link the `source` and the `sink` together */

pipeGroupNode.addChild(sourceNode);

if (stepNodes.length === 0) {
sourceNode.setNextNode(sinkNode);
sinkNode.setPreviousNode(sourceNode);
return sourceNode;
return pipeGroupNode;
}

/** Connect the `source` with the first step */
Expand All @@ -203,7 +242,7 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {
sinkNode.setPreviousNode(lastStepNode);
}

return sourceNode;
return pipeGroupNode;
}

private getVizNodeFromStep(step: PipeStep, path: string, isRoot = false): IVisualizationNode {
Expand Down Expand Up @@ -241,4 +280,17 @@ export class PipeVisualEntity implements BaseVisualCamelEntity {
return acc;
}, [] as IVisualizationNode[]);
}

private getRootPipeSchema(): KaotoSchemaDefinition['schema'] {
const rootPipeDefinition = CamelCatalogService.getComponent(CatalogKind.Entity, 'PipeConfiguration');

if (rootPipeDefinition === undefined) return {} as unknown as KaotoSchemaDefinition['schema'];

let schema = {} as unknown as KaotoSchemaDefinition['schema'];
if (rootPipeDefinition.propertiesSchema !== undefined) {
schema = rootPipeDefinition.propertiesSchema;
}

return schema;
}
}
1 change: 1 addition & 0 deletions packages/ui/src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,5 @@ export * from './resolve-ref-if-needed';
export * from './set-value';
export * from './get-custom-schema-from-kamelet';
export * from './update-kamelet-from-custom-schema';
export * from './pipe-custom-schema';
export * from './weight-schema-properties';
29 changes: 29 additions & 0 deletions packages/ui/src/utils/pipe-custom-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { getValue } from './get-value';
import { setValue } from './set-value';
import { PipeMetadata } from '../models/camel/entities/pipe-overrides';

export const getCustomSchemaFromPipe = (metadata: PipeMetadata) => {
const name = getValue(metadata, 'name', '');
const annotations = getValue(metadata, 'annotations', {} as Record<string, unknown>);
const labels = getValue(metadata, 'labels', {} as Record<string, unknown>);

const customSchema = {
name,
labels: labels,
annotations: annotations,
};

return customSchema;
};

export const updatePipeFromCustomSchema = (metadata: PipeMetadata, value: Record<string, unknown>): void => {
const previousName = getValue(metadata, 'name');
const newName: string = getValue(value, 'name');
setValue(metadata, 'name', newName ?? previousName);

const newLabels = Object.assign({}, getValue(value, 'labels', {}));
const newAnnotations = Object.assign({}, getValue(value, 'annotations', {}));

setValue(metadata, 'labels', newLabels);
setValue(metadata, 'annotations', newAnnotations);
};

0 comments on commit 53672a9

Please sign in to comment.