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

commit b23fe7eacc9772969bcf25a8ca72265138559130
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Wed Feb 14 16:44:15 2024 -0500

    Incoming navigation for #1109
---
 karavan-space/src/App.tsx                          |  2 +-
 karavan-space/src/designer/DesignerStore.ts        | 17 ++++-
 karavan-space/src/designer/KaravanDesigner.tsx     | 10 +--
 .../src/designer/route/DslConnections.tsx          | 74 ++++++++++++++++++----
 .../src/designer/utils/InfrastructureAPI.ts        |  4 +-
 karavan-space/src/space/SpacePage.tsx              |  7 +-
 karavan-space/src/topology/TopologyApi.tsx         |  2 +-
 karavan-space/src/topology/TopologyStore.ts        |  9 ---
 karavan-space/src/topology/TopologyTab.tsx         |  5 +-
 9 files changed, 94 insertions(+), 36 deletions(-)

diff --git a/karavan-space/src/App.tsx b/karavan-space/src/App.tsx
index 77d1289e..2adec90f 100644
--- a/karavan-space/src/App.tsx
+++ b/karavan-space/src/App.tsx
@@ -33,7 +33,7 @@ import {KnowledgebasePage} from 
"./knowledgebase/KnowledgebasePage";
 import {EventBus} from "./designer/utils/EventBus";
 import {Notification} from "./designer/utils/Notification";
 import {TopologyTab} from "./topology/TopologyTab";
-import {IntegrationFile} from "./topology/TopologyStore";
+import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
 
 class MenuItem {
     pageId: string = '';
diff --git a/karavan-space/src/designer/DesignerStore.ts 
b/karavan-space/src/designer/DesignerStore.ts
index ef95b8d4..7a6aab41 100644
--- a/karavan-space/src/designer/DesignerStore.ts
+++ b/karavan-space/src/designer/DesignerStore.ts
@@ -20,6 +20,7 @@ import {DslPosition, EventBus} from "./utils/EventBus";
 import {createWithEqualityFn} from "zustand/traditional";
 import {shallow} from "zustand/shallow";
 import {RegistryBeanDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
 
 interface IntegrationState {
     integration: Integration;
@@ -27,6 +28,9 @@ interface IntegrationState {
     setIntegration: (integration: Integration, propertyOnly: boolean) => void;
     propertyOnly: boolean;
     reset: () => void;
+    files: IntegrationFile []
+    setFiles: (files: IntegrationFile []) => void
+    resetFiles: (files: IntegrationFile []) => void
 }
 
 export const useIntegrationStore = 
createWithEqualityFn<IntegrationState>((set) => ({
@@ -46,7 +50,18 @@ export const useIntegrationStore = 
createWithEqualityFn<IntegrationState>((set)
     },
     reset: () => {
         set({integration: Integration.createNew("demo", "plain"), json: '{}', 
propertyOnly: false});
-    }
+    },
+    files: [],
+    setFiles: (files: IntegrationFile []) => {
+        set((state: IntegrationState) => {
+            return {files: files};
+        });
+    },
+    resetFiles: (files: IntegrationFile []) => {
+        set((state: IntegrationState) => {
+            return {files: [...files]};
+        });
+    },
 }), shallow)
 
 
diff --git a/karavan-space/src/designer/KaravanDesigner.tsx 
b/karavan-space/src/designer/KaravanDesigner.tsx
index 05831a38..9fbe3864 100644
--- a/karavan-space/src/designer/KaravanDesigner.tsx
+++ b/karavan-space/src/designer/KaravanDesigner.tsx
@@ -28,7 +28,7 @@ import {
 import './karavan.css';
 import {RouteDesigner} from "./route/RouteDesigner";
 import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {Integration, IntegrationFile} from 
"karavan-core/lib/model/IntegrationDefinition";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelUi} from "./utils/CamelUi";
 import {useDesignerStore, useIntegrationStore} from "./DesignerStore";
@@ -48,7 +48,7 @@ interface Props {
     onSaveCustomCode: (name: string, code: string) => void
     onGetCustomCode: (name: string, javaType: string) => Promise<string | 
undefined>
     onSavePropertyPlaceholder: (key: string, value: string) => void
-    onInternalConsumerClick: (uri: string, name: string) => void
+    onInternalConsumerClick: (uri?: string, name?: string, routeId?: string) 
=> void
     filename: string
     yaml: string
     dark: boolean
@@ -57,6 +57,7 @@ interface Props {
     tab?: "routes" | "rest" | "beans"
     propertyPlaceholders: string[]
     beans: RegistryBeanDefinition[]
+    files: IntegrationFile[]
 }
 
 export function KaravanDesigner(props: Props) {
@@ -65,8 +66,8 @@ export function KaravanDesigner(props: Props) {
     const [setDark, hideLogDSL, setHideLogDSL, setSelectedStep, reset, badge, 
message, setPropertyPlaceholders, setBeans] =
         useDesignerStore((s) =>
         [s.setDark, s.hideLogDSL, s.setHideLogDSL, s.setSelectedStep, s.reset, 
s.notificationBadge, s.notificationMessage, s.setPropertyPlaceholders, 
s.setBeans], shallow)
-    const [integration, setIntegration] = useIntegrationStore((s) =>
-        [s.integration, s.setIntegration], shallow)
+    const [integration, setIntegration, resetFiles] = useIntegrationStore((s) 
=>
+        [s.integration, s.setIntegration, s.resetFiles], shallow)
 
     useEffect(() => {
         const sub = EventBus.onIntegrationUpdate()?.subscribe((update: 
IntegrationUpdate) =>
@@ -92,6 +93,7 @@ export function KaravanDesigner(props: Props) {
         setDark(props.dark);
         setPropertyPlaceholders(props.propertyPlaceholders)
         setBeans(props.beans)
+        resetFiles(props.files)
         setHideLogDSL(props.hideLogDSL === true);
         return () => {
             sub?.unsubscribe();
diff --git a/karavan-space/src/designer/route/DslConnections.tsx 
b/karavan-space/src/designer/route/DslConnections.tsx
index ebb89933..99339f7c 100644
--- a/karavan-space/src/designer/route/DslConnections.tsx
+++ b/karavan-space/src/designer/route/DslConnections.tsx
@@ -24,28 +24,45 @@ import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt"
 import {TopologyUtils} from "karavan-core/lib/api/TopologyUtils";
 import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {v4 as uuidv4} from "uuid";
-import {DeleteElementIcon} from "../utils/ElementIcons";
-import {Button} from "@patternfly/react-core";
+import {Button, Tooltip} from "@patternfly/react-core";
 import {InfrastructureAPI} from "../utils/InfrastructureAPI";
+import {getIntegrations} from "../../topology/TopologyApi";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 
 const overlapGap: number = 40;
 
 export function DslConnections() {
 
-    const [integration] = useIntegrationStore((state) => [state.integration], 
shallow)
+    const [integration, files] = useIntegrationStore((s) => [s.integration, 
s.files], shallow)
     const [width, height, top, left, hideLogDSL] = useDesignerStore((s) =>
         [s.width, s.height, s.top, s.left, s.hideLogDSL], shallow)
     const [steps, addStep, deleteStep, clearSteps] =
         useConnectionsStore((s) => [s.steps, s.addStep, s.deleteStep, 
s.clearSteps], shallow)
 
     const [svgKey, setSvgKey] = useState<string>('svgKey');
+    const [tons, setTons] = useState<Map<string, string[]>>(new Map<string, 
string[]>());
 
     useEffect(() => {
+        const integrations = getIntegrations(files);
+        setTons(prevState => {
+            const data = new Map<string, string[]>();
+            TopologyUtils.findTopologyOutgoingNodes(integrations).forEach(t => 
{
+                const key = (t.step as any)?.uri + ':' + (t.step as 
any)?.parameters.name;
+                if (data.has(key)) {
+                    const list = data.get(key) || [];
+                    list.push(t.routeId);
+                    data.set(key, list);
+                } else {
+                    data.set(key, [t.routeId]);
+                }
+            });
+            return data;
+        });
         const sub1 = EventBus.onPosition()?.subscribe((evt: DslPosition) => 
setPosition(evt));
         return () => {
             sub1?.unsubscribe();
         };
-    });
+    }, [files]);
 
     useEffect(() => {
         const toDelete1: string[] = Array.from(steps.keys()).filter(k => 
CamelDefinitionApiExt.findElementInIntegration(integration, k) === undefined);
@@ -63,11 +80,17 @@ export function DslConnections() {
         }
     }
 
+    function isElementInternalComponent (element: CamelElement): boolean {
+        const uri = (element as any).uri;
+        const component = ComponentApi.findByName(uri);
+        return component !== undefined && 
(TopologyUtils.isComponentInternal(component.component.label));
+    }
+
     function getIncomings() {
         let outs: [string, number][] = Array.from(steps.values())
             .filter(pos => ["FromDefinition"].includes(pos.step.dslName))
-            .filter(pos => !TopologyUtils.isElementInternalComponent(pos.step))
-            .filter(pos => !(pos.step.dslName === 'FromDefinition' && 
TopologyUtils.hasInternalUri(pos.step)))
+            .filter(pos => !isElementInternalComponent(pos.step))
+            // .filter(pos => !(pos.step.dslName === 'FromDefinition' && 
TopologyUtils.hasInternalUri(pos.step)))
             .filter(pos => !(pos.step.dslName === 'FromDefinition' && 
(pos.step as any).uri === 'kamelet:source'))
             .sort((pos1: DslPosition, pos2: DslPosition) => {
                 const y1 = pos1.headerRect.y + pos1.headerRect.height / 2;
@@ -104,9 +127,22 @@ export function DslConnections() {
         }
     }
 
+    // function getToDirectSteps(name: string) {
+    //     return Array.from(steps.values())
+    //         .filter(s => s.step.dslName === 'ToDefinition')
+    //         .filter(s =>  ['direct','seda'].includes((s.step as any)?.uri))
+    //         .filter(s =>  (s.step as any)?.parameters?.name === name)
+    // }
+
     function getIncomingIcons(data: [string, number]) {
         const pos = steps.get(data[0]);
         if (pos) {
+            const step = (pos.step as any);
+            const uri = step?.uri;
+            const directOrSeda: boolean = step && uri && step?.dslName === 
'FromDefinition' && ['direct','seda'].includes(uri);
+            const name: string = directOrSeda ? (step?.parameters?.name) : 
undefined;
+            const routes = directOrSeda ? tons.get(uri + ':' +name) || [] : [];
+            // const localDirects = getToDirectSteps(name);
             const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
             const incomingX = 20;
@@ -116,6 +152,16 @@ export function DslConnections() {
                 <div key={pos.step.uuid + "-icon"}
                      style={{display: "block", position: "absolute", top: 
imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
+                    {routes.map((routeId, index) =>
+                        <Tooltip key={`${routeId}:${index}`} content={`Go to 
route:${routeId}`} position={"right"}>
+                            <Button style={{position: 'absolute', left: 27, 
top: (index * 16) + (12), whiteSpace: 'nowrap', zIndex: 300, padding: 0}}
+                                    variant={'link'}
+                                    aria-label="Goto"
+                                    onClick={_ => 
InfrastructureAPI.onInternalConsumerClick(undefined, undefined, routeId)}>
+                                {routeId}
+                            </Button>
+                        </Tooltip>
+                    )}
                 </div>
             )
         }
@@ -204,13 +250,15 @@ export function DslConnections() {
                 <div key={pos.step.uuid + "-icon"}
                      style={{display: "block", position: "absolute", top: 
imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
-                    {directOrSeda &&
-                        <Button style={{position: 'absolute', right: 27, top: 
-12, whiteSpace: 'nowrap', zIndex: 300, padding: 0}}
-                               variant={'link'}
-                                aria-label="Goto"
-                                onClick={_ => 
InfrastructureAPI.onInternalConsumerClick(uri, name)}>
-                            {name}
-                        </Button>
+                    {name !== undefined &&
+                        <Tooltip content={`Go to ${uri}:${name}`} 
position={"left"}>
+                            <Button style={{position: 'absolute', right: 27, 
top: -12, whiteSpace: 'nowrap', zIndex: 300, padding: 0}}
+                                   variant={'link'}
+                                    aria-label="Goto"
+                                    onClick={_ => 
InfrastructureAPI.onInternalConsumerClick(uri, name, undefined)}>
+                                {name}
+                            </Button>
+                        </Tooltip>
                     }
                 </div>
             )
diff --git a/karavan-space/src/designer/utils/InfrastructureAPI.ts 
b/karavan-space/src/designer/utils/InfrastructureAPI.ts
index 77ef1bd3..c386d6fc 100644
--- a/karavan-space/src/designer/utils/InfrastructureAPI.ts
+++ b/karavan-space/src/designer/utils/InfrastructureAPI.ts
@@ -21,7 +21,7 @@ export class InfrastructureAPI {
     static onSaveCustomCode: (name: string, code: string) => void;
     static onSave: (filename: string, yaml: string, propertyOnly: boolean) => 
void;
     static onSavePropertyPlaceholder: (key: string, value: string) => void;
-    static onInternalConsumerClick: (uri: string, name: string) => void;
+    static onInternalConsumerClick: (uri?: string, name?: string, routeId?: 
string) => void;
 
     static setOnGetCustomCode(onGetCustomCode: (name: string, javaType: 
string) => Promise<string | undefined>){
         this.onGetCustomCode = onGetCustomCode
@@ -39,7 +39,7 @@ export class InfrastructureAPI {
         this.onSavePropertyPlaceholder = onSavePropertyPlaceholder
     }
 
-    static setOnInternalConsumerClick(onInternalConsumerClick:(uri: string, 
name: string) => void){
+    static setOnInternalConsumerClick(onInternalConsumerClick:(uri?: string, 
name?: string, routeId?: string) => void){
         this.onInternalConsumerClick = onInternalConsumerClick
     }
 
diff --git a/karavan-space/src/space/SpacePage.tsx 
b/karavan-space/src/space/SpacePage.tsx
index 24c62b66..548e5025 100644
--- a/karavan-space/src/space/SpacePage.tsx
+++ b/karavan-space/src/space/SpacePage.tsx
@@ -28,7 +28,7 @@ import DownloadImageIcon from 
"@patternfly/react-icons/dist/esm/icons/image-icon
 import GithubImageIcon from 
"@patternfly/react-icons/dist/esm/icons/github-icon";
 import UploadIcon from "@patternfly/react-icons/dist/esm/icons/upload-icon";
 import {KaravanDesigner} from "../designer/KaravanDesigner";
-import Editor from "@monaco-editor/react";
+import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
 import {UploadModal} from "./UploadModal";
 import {EventBus} from "../designer/utils/EventBus";
 
@@ -111,9 +111,10 @@ export class SpacePage extends React.Component<Props, 
State> {
                 propertyPlaceholders={[]}
                 beans={[]}
                 onSavePropertyPlaceholder={(key, value) => {}}
-                onInternalConsumerClick={(uri, name) => {
-                    console.log("onInternalConsumerClick", uri, name)
+                onInternalConsumerClick={(uri?: string, name?: string, 
routeId?: string) => {
+                    console.log("onInternalConsumerClick", uri, name, routeId)
                 }}
+                files={[new IntegrationFile("example.camel.yaml", yaml)]}
             />
         )
     }
diff --git a/karavan-space/src/topology/TopologyApi.tsx 
b/karavan-space/src/topology/TopologyApi.tsx
index c60c197b..a640d508 100644
--- a/karavan-space/src/topology/TopologyApi.tsx
+++ b/karavan-space/src/topology/TopologyApi.tsx
@@ -39,7 +39,7 @@ import {
     TopologyRouteNode
 } from "karavan-core/lib/model/TopologyDefinition";
 import CustomEdge from "./CustomEdge";
-import {IntegrationFile} from "./TopologyStore";
+import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
 import CustomGroup from "./CustomGroup";
 
 const NODE_DIAMETER = 60;
diff --git a/karavan-space/src/topology/TopologyStore.ts 
b/karavan-space/src/topology/TopologyStore.ts
index 4e9ee643..517e2794 100644
--- a/karavan-space/src/topology/TopologyStore.ts
+++ b/karavan-space/src/topology/TopologyStore.ts
@@ -18,15 +18,6 @@
 import {createWithEqualityFn} from "zustand/traditional";
 import {shallow} from "zustand/shallow";
 
-export class IntegrationFile {
-    name: string = '';
-    code: string = '';
-
-    constructor(name: string, code: string) {
-        this.name = name;
-        this.code = code;
-    }
-}
 
 interface TopologyState {
     selectedIds: string []
diff --git a/karavan-space/src/topology/TopologyTab.tsx 
b/karavan-space/src/topology/TopologyTab.tsx
index 1f2d165e..694eeb64 100644
--- a/karavan-space/src/topology/TopologyTab.tsx
+++ b/karavan-space/src/topology/TopologyTab.tsx
@@ -31,10 +31,11 @@ import {
 } from '@patternfly/react-topology';
 import {customComponentFactory, getModel} from "./TopologyApi";
 import {shallow} from "zustand/shallow";
-import {IntegrationFile, useTopologyStore} from "./TopologyStore";
+import {useTopologyStore} from "./TopologyStore";
 import {TopologyPropertiesPanel} from "./TopologyPropertiesPanel";
 import {TopologyToolbar} from "./TopologyToolbar";
 import {useDesignerStore} from "../designer/DesignerStore";
+import {IntegrationFile} from "karavan-core/lib/model/IntegrationDefinition";
 
 interface Props {
     files: IntegrationFile[],
@@ -137,7 +138,7 @@ export function TopologyTab(props: Props) {
         });
     }, [ranker, controller, setRanker]);
 
-        return (
+    return (
         <TopologyView
             className="topology-panel"
             contextToolbar={!props.hideToolbar

Reply via email to