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 17:03:15 UTC

[camel-karavan] branch main updated: Topology in space

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 3a6ee123 Topology in space
3a6ee123 is described below

commit 3a6ee1239f39992701b091ea81c2b354ceaa6a42
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Fri Oct 20 13:03:07 2023 -0400

    Topology in space
---
 karavan-space/src/App.tsx                          | 21 +++++++++++++--
 .../src/designer/beans/BeanProperties.tsx          |  6 ++---
 karavan-space/src/designer/beans/BeansDesigner.tsx |  2 +-
 .../src/designer/kamelet/KameletDesigner.tsx       |  2 +-
 .../src/designer/route/usePropertiesHook.tsx       |  4 ++-
 karavan-space/src/topology/CustomNode.tsx          |  7 ++++-
 karavan-space/src/topology/TopologyApi.tsx         | 31 ++++++++++++++++++----
 karavan-space/src/topology/TopologyTab.tsx         |  1 -
 8 files changed, 59 insertions(+), 15 deletions(-)

diff --git a/karavan-space/src/App.tsx b/karavan-space/src/App.tsx
index c5d11f87..728230e8 100644
--- a/karavan-space/src/App.tsx
+++ b/karavan-space/src/App.tsx
@@ -23,14 +23,17 @@ import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {BlueprintIcon} from "@patternfly/react-icons";
 import KnowledgebaseIcon from "@patternfly/react-icons/dist/js/icons/book-open-icon";
+import TopologyIcon from "@patternfly/react-icons/dist/js/icons/topology-icon";
 import {KaravanIcon} from "./designer/utils/KaravanIcons";
 import './designer/karavan.css';
 import {SpacePage} from "./space/SpacePage";
 import {GithubModal} from "./space/GithubModal";
 import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
 import {KnowledgebasePage} from "./knowledgebase/KnowledgebasePage";
-import {EventBus, ToastMessage} from "./designer/utils/EventBus";
+import {EventBus} from "./designer/utils/EventBus";
 import {Notification} from "./designer/utils/Notification";
+import {TopologyTab} from "./topology/TopologyTab";
+import {IntegrationFile} from "./topology/TopologyStore";
 
 class MenuItem {
     pageId: string = '';
@@ -60,7 +63,7 @@ class App extends React.Component<Props, State> {
 
     public state: State = {
         pageId: "designer",
-        name: 'example.yaml',
+        name: 'example.camel.yaml',
         key: '',
         yaml: '',
         githubModalIsOpen: false
@@ -118,6 +121,7 @@ class App extends React.Component<Props, State> {
         const {pageId} = this.state;
         const pages: MenuItem[] = [
             new MenuItem("designer", "Designer", <BlueprintIcon/>),
+            new MenuItem("topology", "Topology", <TopologyIcon/>),
             new MenuItem("knowledgebase", "Knowledgebase", <KnowledgebaseIcon/>),
         ]
         return (<Flex className="nav-buttons" direction={{default: "column"}} style={{height: "100%"}}
@@ -144,6 +148,10 @@ class App extends React.Component<Props, State> {
         </Flex>)
     }
 
+    getIntegrationFiles(): IntegrationFile[]{
+        return [new IntegrationFile("example.camel.yaml", this.state.yaml)];
+    }
+
     getDesigner() {
         const {name, yaml, pageId} = this.state;
         const dark = document.body.className.includes('vscode-dark');
@@ -161,6 +169,15 @@ class App extends React.Component<Props, State> {
                 return (
                     <KnowledgebasePage dark={dark}/>
                 )
+            case "topology":
+                return (
+                    <TopologyTab
+                        files={this.getIntegrationFiles()}
+                        onSetFile={fileName => {}}
+                        onClickCreateButton={() => {}}
+                        hideToolbar={false}
+                    />
+                )
         }
     }
 
diff --git a/karavan-space/src/designer/beans/BeanProperties.tsx b/karavan-space/src/designer/beans/BeanProperties.tsx
index fdb73d2a..455291c4 100644
--- a/karavan-space/src/designer/beans/BeanProperties.tsx
+++ b/karavan-space/src/designer/beans/BeanProperties.tsx
@@ -73,7 +73,7 @@ export function BeanProperties (props: Props) {
 
     function onBeanPropertyUpdate ()  {
         if (selectedStep) {
-            const bean = CamelUtil.cloneBean(selectedStep);
+            const bean = CamelUtil.cloneBean(selectedStep as RegistryBeanDefinition);
             const beanProperties: any = {};
             properties.forEach((p: any) => beanProperties[p[0]] = p[1]);
             bean.properties = beanProperties;
@@ -83,7 +83,7 @@ export function BeanProperties (props: Props) {
 
     function beanFieldChanged (fieldId: string, value: string) {
         if (selectedStep) {
-            const bean = CamelUtil.cloneBean(selectedStep);
+            const bean = CamelUtil.cloneBean(selectedStep as RegistryBeanDefinition);
             (bean as any)[fieldId] = value;
             props.onChange(bean);
         }
@@ -137,7 +137,7 @@ export function BeanProperties (props: Props) {
 
     function cloneBean ()  {
         if (selectedStep) {
-            const bean = CamelUtil.cloneBean(selectedStep);
+            const bean = CamelUtil.cloneBean(selectedStep as RegistryBeanDefinition);
             bean.uuid = uuidv4();
             props.onClone(bean);
         }
diff --git a/karavan-space/src/designer/beans/BeansDesigner.tsx b/karavan-space/src/designer/beans/BeansDesigner.tsx
index 64bac96f..8cd99f25 100644
--- a/karavan-space/src/designer/beans/BeansDesigner.tsx
+++ b/karavan-space/src/designer/beans/BeansDesigner.tsx
@@ -49,7 +49,7 @@ export function BeansDesigner() {
     }
 
     function deleteBean() {
-        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep);
+        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep as RegistryBeanDefinition);
         setIntegration(i, false);
         setShowDeleteConfirmation(false);
         setSelectedStep(undefined);
diff --git a/karavan-space/src/designer/kamelet/KameletDesigner.tsx b/karavan-space/src/designer/kamelet/KameletDesigner.tsx
index dd889b92..c235ef9b 100644
--- a/karavan-space/src/designer/kamelet/KameletDesigner.tsx
+++ b/karavan-space/src/designer/kamelet/KameletDesigner.tsx
@@ -52,7 +52,7 @@ export function KameletDesigner() {
     }
 
     function deleteBean() {
-        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep);
+        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep as RegistryBeanDefinition);
         setIntegration(i, false);
         setShowDeleteConfirmation(false);
         setSelectedStep(undefined);
diff --git a/karavan-space/src/designer/route/usePropertiesHook.tsx b/karavan-space/src/designer/route/usePropertiesHook.tsx
index eba82bf2..87513b18 100644
--- a/karavan-space/src/designer/route/usePropertiesHook.tsx
+++ b/karavan-space/src/designer/route/usePropertiesHook.tsx
@@ -75,6 +75,7 @@ export function usePropertiesHook (isRouteDesigner: boolean = true) {
     }
 
     function onPropertyChange (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate){
+        value = value === '' ? undefined : value;
         if (selectedStep) {
             const clone = CamelUtil.cloneStep(selectedStep);
             (clone as any)[fieldId] = value;
@@ -99,7 +100,8 @@ export function usePropertiesHook (isRouteDesigner: boolean = true) {
     }
 
     function onParametersChange (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate)   {
-        if (selectedStep && selectedStep) {
+        value = value === '' ? undefined : value;
+        if (selectedStep) {
             const clone = (CamelUtil.cloneStep(selectedStep));
             const parameters: any = {...(clone as any).parameters};
             parameters[parameter] = value;
diff --git a/karavan-space/src/topology/CustomNode.tsx b/karavan-space/src/topology/CustomNode.tsx
index fb517ae9..d683d04f 100644
--- a/karavan-space/src/topology/CustomNode.tsx
+++ b/karavan-space/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-space/src/topology/TopologyApi.tsx b/karavan-space/src/topology/TopologyApi.tsx
index 44ff57a2..c60c197b 100644
--- a/karavan-space/src/topology/TopologyApi.tsx
+++ b/karavan-space/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-space/src/topology/TopologyTab.tsx b/karavan-space/src/topology/TopologyTab.tsx
index 306ca8fb..520bf8d2 100644
--- a/karavan-space/src/topology/TopologyTab.tsx
+++ b/karavan-space/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));