You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2023/10/20 16:57:17 UTC
[camel-karavan] branch main updated: Topology creates edge between consumer-producer
This is an automated email from the ASF dual-hosted git repository.
marat pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git
The following commit(s) were added to refs/heads/main by this push:
new 8807c3ef Topology creates edge between consumer-producer
8807c3ef is described below
commit 8807c3efd6761b62a764c7673c8472c2079bb869
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Oct 20 12:57:10 2023 -0400
Topology creates edge between consumer-producer
---
karavan-core/src/core/api/CamelDefinitionApiExt.ts | 6 +-
karavan-core/src/core/api/CamelUtil.ts | 16 +++--
karavan-core/src/core/api/TopologyUtils.ts | 62 ++++++++++++++++--
karavan-core/src/core/model/TopologyDefinition.ts | 18 ++++--
karavan-designer/public/example/demo.camel.yaml | 74 ++++++++++++++++++----
karavan-designer/src/topology/CustomNode.tsx | 7 +-
karavan-designer/src/topology/TopologyApi.tsx | 31 +++++++--
karavan-designer/src/topology/TopologyTab.tsx | 1 -
8 files changed, 177 insertions(+), 38 deletions(-)
diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 6ec8ffe5..f9372830 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -690,11 +690,7 @@ export class CamelDefinitionApiExt {
return [];
};
- static getParametersValue = (
- element: CamelElement | undefined,
- propertyName: string,
- pathParameter?: boolean,
- ): any => {
+ static getParametersValue = (element: CamelElement | undefined, propertyName: string, pathParameter?: boolean): any => {
if (element && (element as any).parameters) {
return (element as any).parameters[propertyName];
}
diff --git a/karavan-core/src/core/api/CamelUtil.ts b/karavan-core/src/core/api/CamelUtil.ts
index 7178150f..93544263 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -159,9 +159,15 @@ export class CamelUtil {
}
};
- static getKameletProperties = (element: any): Property[] => {
+ static getKameletProperties = (element: any, requiredOnly: boolean = false): Property[] => {
const kamelet = CamelUtil.getKamelet(element);
- return kamelet ? KameletApi.getKameletProperties(kamelet?.metadata.name) : [];
+ const props:Property[] = kamelet ? KameletApi.getKameletProperties(kamelet?.metadata.name) : [];
+ if (requiredOnly) {
+ const required = kamelet?.spec.definition.required;
+ return props.filter(value => required?.includes(value.id));
+ } else {
+ return props;
+ }
};
static getKameletRequiredParameters = (element: any): string[] => {
@@ -229,11 +235,7 @@ export class CamelUtil {
if (!CamelUtil.isKameletComponent(element)) {
const requiredProperties = CamelUtil.getComponentProperties(element).filter(p => p.required);
for (const property of requiredProperties) {
- const value = CamelDefinitionApiExt.getParametersValue(
- element,
- property.name,
- property.kind === 'path',
- );
+ const value = CamelDefinitionApiExt.getParametersValue(element, property.name, property.kind === 'path');
if (value === undefined || (property.type === 'string' && value.trim().length === 0)) {
result[0] = false;
result[1].push(`${property.displayName} is required`);
diff --git a/karavan-core/src/core/api/TopologyUtils.ts b/karavan-core/src/core/api/TopologyUtils.ts
index 4f99f295..d3ae1671 100644
--- a/karavan-core/src/core/api/TopologyUtils.ts
+++ b/karavan-core/src/core/api/TopologyUtils.ts
@@ -37,6 +37,8 @@ import {
import { ComponentApi } from './ComponentApi';
import { CamelDefinitionApiExt } from './CamelDefinitionApiExt';
import { CamelDisplayUtil } from './CamelDisplayUtil';
+import { CamelMetadataApi } from '../model/CamelMetadata';
+import { CamelUtil } from './CamelUtil';
const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"];
@@ -58,6 +60,48 @@ export class TopologyUtils {
(TopologyUtils.isComponentInternal(component.component.label) || TopologyUtils.hasInternalUri(element));
}
+ static getConnectorType = (element: CamelElement): 'component' | 'kamelet' => {
+ return CamelUtil.isKameletComponent(element) ? 'kamelet' : 'component';
+ }
+
+ static cutKameletUriSuffix = (uri: string): string => {
+ if (uri.endsWith("-sink")) {
+ return uri.substring(0, uri.length - 5);
+ } else if (uri.endsWith("-source")) {
+ return uri.substring(0, uri.length - 7);
+ } else if (uri.endsWith("-action")) {
+ return uri.substring(0, uri.length - 7);
+ } else {
+ return uri;
+ }
+ }
+
+ static getUniqueUri = (element: CamelElement): string => {
+ const uri:string = (element as any).uri || '';
+ let result = uri.startsWith("kamelet") ? TopologyUtils.cutKameletUriSuffix(uri).concat(":") : uri.concat(":");
+ const className = element.dslName;
+ if (className === 'FromDefinition' || className === 'ToDefinition') {
+ if (!CamelUtil.isKameletComponent(element)) {
+ const requiredProperties = CamelUtil.getComponentProperties(element).filter(p => p.required);
+ for (const property of requiredProperties) {
+ const value = CamelDefinitionApiExt.getParametersValue(element, property.name, property.kind === 'path');
+ if (value !== undefined && property.type === 'string' && value.trim().length > 0) {
+ result = result + property.name + "=" + value + "&";
+ }
+ }
+ } else {
+ const requiredProperties = CamelUtil.getKameletProperties(element, true);
+ for (const property of requiredProperties) {
+ const value = CamelDefinitionApiExt.getParametersValue(element, property.id);
+ if (value !== undefined && property.type === 'string' && value.trim().length > 0) {
+ result = result + property.id + "=" + value + "&";
+ }
+ }
+ }
+ }
+ return result;
+ }
+
static isComponentInternal = (label: string): boolean => {
const labels = label.split(",");
if (labels.includes('core') && (
@@ -143,7 +187,9 @@ export class TopologyUtils {
const id = 'incoming-' + r.id;
const title = CamelDisplayUtil.getTitle(r.from);
const type = TopologyUtils.isElementInternalComponent(r.from) ? 'internal' : 'external';
- return new TopologyIncomingNode(id, type, r.id, title, filename, r.from);
+ const connectorType = TopologyUtils.getConnectorType(r.from);
+ const uniqueUri = TopologyUtils.getUniqueUri(r.from);
+ return new TopologyIncomingNode(id, type, connectorType, r.id, title, filename, r.from, uniqueUri);
}) || [];
result.push(...routeElements)
})
@@ -177,7 +223,9 @@ export class TopologyUtils {
const id = 'outgoing-' + route.id + '-' + e.id;
const title = CamelDisplayUtil.getTitle(e);
const type = TopologyUtils.isElementInternalComponent(e) ? 'internal' : 'external';
- result.push(new TopologyOutgoingNode(id, type, route.id, title, filename, e));
+ const connectorType = TopologyUtils.getConnectorType(e);
+ const uniqueUri = TopologyUtils.getUniqueUri(e);
+ result.push(new TopologyOutgoingNode(id, type, connectorType, route.id, title, filename, e, uniqueUri));
})
})
@@ -213,8 +261,6 @@ export class TopologyUtils {
return result;
}
-
-
static getNodeIdByUriAndName(tins: TopologyIncomingNode[], uri: string, name: string): string | undefined {
if (uri && name) {
const node = tins
@@ -242,6 +288,14 @@ export class TopologyUtils {
}
}
+ static getNodeIdByUniqueUri(tins: TopologyIncomingNode[], uniqueUri: string): string | undefined {
+ const node = tins
+ .filter(r => r.uniqueUri === uniqueUri).at(0);
+ if (node) {
+ return node.id;
+ }
+ }
+
static getRouteIdByUri(tins: TopologyIncomingNode[], uri: string): string | undefined {
const parts = uri.split(":");
if (parts.length > 1) {
diff --git a/karavan-core/src/core/model/TopologyDefinition.ts b/karavan-core/src/core/model/TopologyDefinition.ts
index 9b3cfe40..f238f5b9 100644
--- a/karavan-core/src/core/model/TopologyDefinition.ts
+++ b/karavan-core/src/core/model/TopologyDefinition.ts
@@ -39,18 +39,23 @@ export class TopologyRestNode {
export class TopologyIncomingNode {
id: string;
type: 'internal' | 'external';
+ connectorType: 'component' | 'kamelet';
routeId: string;
title: string;
fileName: string;
from: FromDefinition;
-
- constructor(id: string, type: 'internal' | 'external', routeId: string, title: string, fileName: string, from: FromDefinition) {
+ uniqueUri?: string;
+
+
+ constructor(id: string, type: "internal" | "external", connectorType: "component" | "kamelet", routeId: string, title: string, fileName: string, from: FromDefinition, uniqueUri: string) {
this.id = id;
this.type = type;
+ this.connectorType = connectorType;
this.routeId = routeId;
this.title = title;
this.fileName = fileName;
this.from = from;
+ this.uniqueUri = uniqueUri;
}
}
@@ -75,17 +80,22 @@ export class TopologyRouteNode {
export class TopologyOutgoingNode {
id: string;
type: 'internal' | 'external';
+ connectorType: 'component' | 'kamelet';
routeId: string;
title: string;
fileName: string;
step: CamelElement;
+ uniqueUri?: string;
- constructor(id: string, type: 'internal' | 'external', routeId: string, title: string, fileName: string, step: CamelElement) {
+
+ constructor(id: string, type: "internal" | "external", connectorType: "component" | "kamelet", routeId: string, title: string, fileName: string, step: CamelElement, uniqueUri: string) {
this.id = id;
- this.type = type
+ this.type = type;
+ this.connectorType = connectorType;
this.routeId = routeId;
this.title = title;
this.fileName = fileName;
this.step = step;
+ this.uniqueUri = uniqueUri;
}
}
\ No newline at end of file
diff --git a/karavan-designer/public/example/demo.camel.yaml b/karavan-designer/public/example/demo.camel.yaml
index 3c682878..69ff1495 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -1,20 +1,72 @@
- route:
- id: route-fbf9
+ id: route-605c
+ from:
+ uri: activemq
+ id: from-3131
+ parameters:
+ destinationName: test
+ steps:
+ - marshal:
+ id: marshal-1452
+ - log:
+ message: ${body}
+ id: log-c8e7
+- route:
+ id: route-e4bb
from:
- uri: kamelet:beer-source
- id: from-9d5b
+ uri: kamelet:timer-source
+ id: from-dd68
+ parameters:
+ message: '1111'
steps:
- to:
uri: activemq
- id: to-0fd2
+ id: to-4fca
+ parameters:
+ destinationName: test
+- route:
+ id: route-0a30
+ from:
+ uri: amqp
+ id: from-ca7d
+ parameters:
+ destinationName: hello
+ steps:
+ - log:
+ message: ${body}
+ id: log-d0f4
- to:
- uri: asterisk
- id: to-b9ca
+ uri: kamelet:kafka-not-secured-sink
+ id: to-c86f
+ parameters:
+ topic: topic1
+ bootstrapServers: localhost:9092
+- route:
+ id: route-e39c
+ from:
+ uri: kamelet:kafka-not-secured-source
+ id: from-d419
+ parameters:
+ bootstrapServers: localhost:9092
+ topic: topic1
+ steps:
- to:
- uri: aws2-ec2
- id: to-3c6a
+ uri: direct
+ id: to-7401
+ parameters:
+ name: hello
- route:
- id: route-605c
+ id: route-be79
from:
- uri: activemq
- id: from-3131
\ No newline at end of file
+ uri: kamelet:kafka-not-secured-source
+ id: from-27e8
+ parameters:
+ bootstrapServers: localhost:9092
+ topic: topic2
+- route:
+ id: hello
+ from:
+ uri: direct
+ id: from-db43
+ parameters:
+ name: hello
diff --git a/karavan-designer/src/topology/CustomNode.tsx b/karavan-designer/src/topology/CustomNode.tsx
index fb517ae9..d683d04f 100644
--- a/karavan-designer/src/topology/CustomNode.tsx
+++ b/karavan-designer/src/topology/CustomNode.tsx
@@ -43,11 +43,16 @@ function getIcon(data: any) {
const CustomNode: React.FC<any> = observer(({ element, ...rest }) => {
const data = element.getData();
+ const badge:string = data.badge?.substring(0,1).toUpperCase();
return (
<DefaultNode
+ badge={badge}
+ showStatusDecorator
className="common-node"
- element={element} {...rest}
+ scaleLabel={false}
+ element={element}
+ {...rest}
>
{getIcon(data)}
</DefaultNode>
diff --git a/karavan-designer/src/topology/TopologyApi.tsx b/karavan-designer/src/topology/TopologyApi.tsx
index 44ff57a2..c60c197b 100644
--- a/karavan-designer/src/topology/TopologyApi.tsx
+++ b/karavan-designer/src/topology/TopologyApi.tsx
@@ -38,9 +38,9 @@ import {
TopologyRestNode,
TopologyRouteNode
} from "karavan-core/lib/model/TopologyDefinition";
-import CustomGroup from "./CustomGroup";
import CustomEdge from "./CustomEdge";
import {IntegrationFile} from "./TopologyStore";
+import CustomGroup from "./CustomGroup";
const NODE_DIAMETER = 60;
@@ -62,7 +62,7 @@ export function getIncomingNodes(tins: TopologyIncomingNode[]): NodeModel[] {
status: NodeStatus.default,
data: {
isAlternate: false,
- badge: tin.type,
+ badge: tin.connectorType,
icon: 'element',
type: 'step',
step: tin.from,
@@ -110,7 +110,7 @@ export function getOutgoingNodes(tons: TopologyOutgoingNode[]): NodeModel[] {
icon: 'element',
type: 'step',
step: tin.step,
- badge: tin.type,
+ badge: tin.connectorType,
fileName: tin.fileName
}
}
@@ -146,6 +146,26 @@ export function getOutgoingEdges(tons: TopologyOutgoingNode[]): EdgeModel[] {
});
}
+export function getExternalEdges(tons: TopologyOutgoingNode[], tins: TopologyIncomingNode[]): EdgeModel[] {
+ const result: EdgeModel[]= [];
+ tons.filter(ton => ton.type === 'external').forEach((ton, index) => {
+ const uniqueUri = ton.uniqueUri;
+ if (uniqueUri) {
+ const target = TopologyUtils.getNodeIdByUniqueUri(tins, uniqueUri);
+ const node: EdgeModel = {
+ id: 'external-' + ton.id + '-' + index,
+ type: 'edge',
+ source: ton.id,
+ target: target,
+ edgeStyle: EdgeStyle.dotted,
+ animationSpeed: EdgeAnimationSpeed.slow
+ }
+ if (target) result.push(node);
+ }
+ });
+ return result;
+}
+
export function getRestNodes(tins: TopologyRestNode[]): NodeModel[] {
return tins.map(tin => {
return {
@@ -217,8 +237,8 @@ export function getModel(files: IntegrationFile[]): Model {
const nodes: NodeModel[] = [];
const groups: NodeModel[] = troutes.map(r => {
const children = [r.id]
- children.push(... tins.filter(i => i.routeId === r.routeId && i.type === 'external').map(i => i.id));
- children.push(... tons.filter(i => i.routeId === r.routeId && i.type === 'external').map(i => i.id));
+ children.push(...tins.filter(i => i.routeId === r.routeId && i.type === 'external').map(i => i.id));
+ children.push(...tons.filter(i => i.routeId === r.routeId && i.type === 'external').map(i => i.id));
return {
id: 'group-' + r.routeId,
children: children,
@@ -242,6 +262,7 @@ export function getModel(files: IntegrationFile[]): Model {
edges.push(...getOutgoingEdges(tons));
edges.push(...getRestEdges(trestns, tins));
edges.push(...getInternalEdges(tons, tins));
+ edges.push(...getExternalEdges(tons,tins));
return {nodes: nodes, edges: edges, graph: {id: 'g1', type: 'graph', layout: 'Dagre'}};
}
diff --git a/karavan-designer/src/topology/TopologyTab.tsx b/karavan-designer/src/topology/TopologyTab.tsx
index 306ca8fb..520bf8d2 100644
--- a/karavan-designer/src/topology/TopologyTab.tsx
+++ b/karavan-designer/src/topology/TopologyTab.tsx
@@ -68,7 +68,6 @@ export function TopologyTab (props: Props) {
}
const controller = React.useMemo(() => {
- console.log(props.files)
const model = getModel(props.files);
const newController = new Visualization();
newController.registerLayoutFactory((_, graph) => new DagreLayout(graph));