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 d20456971b887a99f266d6b1176ab3de0ef169a6
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Feb 6 18:18:02 2024 -0500

    Fix #1108
---
 karavan-designer/public/example/demo.camel.yaml    |  25 +++++
 karavan-designer/src/App.tsx                       |   2 +-
 .../src/designer/property/DslProperties.tsx        |   1 -
 .../src/topology/TopologyPropertiesPanel.tsx       | 103 ++++++++++++++++-----
 karavan-designer/src/topology/TopologyStore.ts     |   8 ++
 karavan-designer/src/topology/TopologyTab.tsx      |   5 +-
 karavan-designer/src/topology/topology.css         |  12 ++-
 karavan-space/src/designer/icons/KaravanIcons.tsx  |  47 ++--------
 karavan-space/src/designer/karavan.css             |   3 +
 .../src/designer/property/DslProperties.tsx        |   1 -
 karavan-space/src/knowledgebase/eip/EipTab.tsx     |  43 +++++++--
 .../src/topology/TopologyPropertiesPanel.tsx       | 103 ++++++++++++++++-----
 karavan-space/src/topology/TopologyStore.ts        |   8 ++
 karavan-space/src/topology/TopologyTab.tsx         |   5 +-
 karavan-space/src/topology/topology.css            |  16 +++-
 .../webui/src/designer/property/DslProperties.tsx  |   1 -
 .../webui/src/topology/TopologyPropertiesPanel.tsx | 103 ++++++++++++++++-----
 .../src/main/webui/src/topology/TopologyStore.ts   |   8 ++
 .../src/main/webui/src/topology/TopologyTab.tsx    |   5 +-
 .../src/main/webui/src/topology/topology.css       |  12 ++-
 20 files changed, 387 insertions(+), 124 deletions(-)

diff --git a/karavan-designer/public/example/demo.camel.yaml 
b/karavan-designer/public/example/demo.camel.yaml
index 9cb87f08..9d74d5d4 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -39,6 +39,31 @@
     from:
       id: from-6aee
       uri: timer
+      steps:
+        - to:
+            id: to-2df4
+            uri: direct
+            parameters:
+              name: first-firect
+        - to:
+            id: to-e017
+            uri: direct
+            parameters:
+              name: second_direct
+- route:
+    id: first-firect
+    from:
+      id: from-f155
+      uri: direct
+      parameters:
+        name: first-firect
+- route:
+    id: second_direct
+    from:
+      id: from-7ce0
+      uri: direct
+      parameters:
+        name: second_direct
 
 #      steps:
 #        - marshal:
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index a6613131..c7a7e461 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -69,7 +69,7 @@ interface State {
 class App extends React.Component<Props, State> {
 
     public state: State = {
-        pageId: "designer",
+        pageId: "topology",
         name: 'example.yaml',
         key: '',
         yaml: ''
diff --git a/karavan-designer/src/designer/property/DslProperties.tsx 
b/karavan-designer/src/designer/property/DslProperties.tsx
index ed56d2eb..656d816c 100644
--- a/karavan-designer/src/designer/property/DslProperties.tsx
+++ b/karavan-designer/src/designer/property/DslProperties.tsx
@@ -44,7 +44,6 @@ import {shallow} from "zustand/shallow";
 import {usePropertiesHook} from "./usePropertiesHook";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
 import EllipsisVIcon from 
'@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
-import QuestionIcon from 
'@patternfly/react-icons/dist/esm/icons/question-icon';
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
diff --git a/karavan-designer/src/topology/TopologyPropertiesPanel.tsx 
b/karavan-designer/src/topology/TopologyPropertiesPanel.tsx
index 8387ce1f..67edb46c 100644
--- a/karavan-designer/src/topology/TopologyPropertiesPanel.tsx
+++ b/karavan-designer/src/topology/TopologyPropertiesPanel.tsx
@@ -20,32 +20,93 @@ import {shallow} from "zustand/shallow";
 import {TopologySideBar} from "@patternfly/react-topology";
 import {useTopologyStore} from "./TopologyStore";
 import {DslProperties} from "../designer/property/DslProperties";
-import {Button, Flex, FlexItem, Text, Tooltip, TooltipPosition} from 
"@patternfly/react-core";
+import {
+    Button, DescriptionList,
+    DescriptionListDescription, DescriptionListGroup, DescriptionListTerm,
+    Flex,
+    FlexItem, Panel, PanelHeader, PanelMain, PanelMainBody,
+    Text, TextContent, TextVariants,
+    Tooltip,
+    TooltipPosition
+} from "@patternfly/react-core";
 import CloseIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
 
 interface Props {
     onSetFile: (fileName: string) => void
 }
 
-export function TopologyPropertiesPanel (props: Props) {
+export function TopologyPropertiesPanel(props: Props) {
 
-    const [selectedIds, setSelectedIds, fileName] = useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.fileName], shallow);
+    const [selectedIds, setSelectedIds, fileName, nodeData] = 
useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.fileName, s.nodeData], shallow);
+
+    console.log(nodeData)
+
+    function isRoute() {
+        if (nodeData && nodeData.type === 'route') {
+            const uri: string = nodeData?.step?.from.uri || '';
+            return uri !== undefined;
+        }
+        return false;
+    }
+
+    function isKamelet() {
+        if (nodeData && nodeData.type === 'step') {
+            const uri: string = nodeData?.step?.uri || '';
+            return uri.startsWith("kamelet");
+        }
+        return false;
+    }
+
+    function getFromInfo() {
+        if (isRoute()) {
+            const uri: string = nodeData?.step?.from.uri || '';
+            const name: string = nodeData?.step?.from.parameters?.name || '';
+            if (['direct','seda'].includes(uri)) {
+                return uri.concat(":").concat(name);
+            } else {
+                return uri;
+            }
+        }
+        return ""
+    }
+
+    function getTitle () {
+        return isRoute() ? "Route" : (isKamelet() ? "Kamelet" : "Component");
+    }
 
     function getHeader() {
         return (
-            <Flex className="properties-header" direction={{default: "row"}} 
justifyContent={{default: "justifyContentFlexStart"}}>
+            <Flex direction={{default: "row"}} justifyContent={{default: 
"justifyContentFlexStart"}}>
                 <FlexItem spacer={{ default: 'spacerNone' }}>
-                    <Text>Filename:</Text>
-                </FlexItem>
-                <FlexItem>
-                    <Button variant="link" onClick={event => {
-                        if (fileName) {
-                            props.onSetFile(fileName);
-                        }
-                    }}
-                    >{fileName}
-                    </Button>
+                    <Panel>
+                        <PanelHeader>
+                            <TextContent>
+                                <Text 
component={TextVariants.h3}>{getTitle()}</Text>
+                            </TextContent>
+                        </PanelHeader>
+                        <PanelMain>
+                            <PanelMainBody>
+                                <DescriptionList isHorizontal>
+                                    <DescriptionListGroup>
+                                        
<DescriptionListTerm>File</DescriptionListTerm>
+                                        <DescriptionListDescription>
+                                            <Button className="file-button" 
variant="link" onClick={_ => {
+                                                if (fileName) {
+                                                    props.onSetFile(fileName);
+                                                }
+                                            }}>{fileName}
+                                            </Button>
+                                        </DescriptionListDescription>
+                                    </DescriptionListGroup>
+                                    {isRoute() && <DescriptionListGroup>
+                                        
<DescriptionListTerm>From</DescriptionListTerm>
+                                        
<DescriptionListDescription>{getFromInfo()}</DescriptionListDescription>
+                                    </DescriptionListGroup>}
+                                </DescriptionList>
+                            </PanelMainBody>
+                        </PanelMain>
+                    </Panel>
                 </FlexItem>
                 <FlexItem align={{ default: 'alignRight' }}>
                     <Tooltip content={"Close"} position={TooltipPosition.top}>
@@ -58,11 +119,11 @@ export function TopologyPropertiesPanel (props: Props) {
 
     return (
         <TopologySideBar
-        className="topology-sidebar"
-        show={selectedIds.length > 0}
-        header={getHeader()}
-    >
-        <DslProperties designerType={'routes'}/>
-    </TopologySideBar>
+            className="topology-sidebar"
+            show={selectedIds.length > 0}
+            header={getHeader()}
+        >
+            <DslProperties designerType={'routes'}/>
+        </TopologySideBar>
     )
 }
diff --git a/karavan-designer/src/topology/TopologyStore.ts 
b/karavan-designer/src/topology/TopologyStore.ts
index 73aead9f..4e9ee643 100644
--- a/karavan-designer/src/topology/TopologyStore.ts
+++ b/karavan-designer/src/topology/TopologyStore.ts
@@ -35,6 +35,8 @@ interface TopologyState {
     setFileName: (fileName?: string) => void
     ranker: string
     setRanker: (ranker: string) => void
+    nodeData: any
+    setNodeData: (nodeData: any) => void
 }
 
 export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({
@@ -55,4 +57,10 @@ export const useTopologyStore = 
createWithEqualityFn<TopologyState>((set) => ({
             return {ranker: ranker};
         });
     },
+    nodeData: undefined,
+    setNodeData: (nodeData: any) => {
+    set((state: TopologyState) => {
+        return {nodeData: nodeData};
+    });
+},
 }), shallow)
diff --git a/karavan-designer/src/topology/TopologyTab.tsx 
b/karavan-designer/src/topology/TopologyTab.tsx
index 727905cc..1f2d165e 100644
--- a/karavan-designer/src/topology/TopologyTab.tsx
+++ b/karavan-designer/src/topology/TopologyTab.tsx
@@ -47,8 +47,8 @@ interface Props {
 
 export function TopologyTab(props: Props) {
 
-    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker] = 
useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker], shallow);
+    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, 
setNodeData] = useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker, s.setNodeData], shallow);
     const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], 
shallow)
 
     function setTopologySelected(model: Model, ids: string []) {
@@ -57,6 +57,7 @@ export function TopologyTab(props: Props) {
             const node = model.nodes?.filter(node => node.id === ids[0]);
             if (node && node.length > 0) {
                 const data = node[0].data;
+                setNodeData(data);
                 setFileName(data.fileName)
                 if (data.step) {
                     setSelectedStep(data.step)
diff --git a/karavan-designer/src/topology/topology.css 
b/karavan-designer/src/topology/topology.css
index c67f1f6b..24fe7679 100644
--- a/karavan-designer/src/topology/topology.css
+++ b/karavan-designer/src/topology/topology.css
@@ -41,8 +41,8 @@
     overflow: auto;
 }
 
-.karavan .topology-panel .properties-header {
-    padding: 10px;
+.karavan .topology-panel .properties .headers {
+    display: none;
 }
 
 .karavan .topology-panel .common-node .icon {
@@ -50,6 +50,14 @@
     width: 32px;
 }
 
+.karavan .topology-panel .pf-v5-c-panel__header {
+    padding-bottom: 0;
+}
+
+.karavan .topology-panel .file-button {
+    padding: 0;
+}
+
 .karavan .topology-sidebar .pf-topology-side-bar__header {
     margin-right: 0;
 }
diff --git a/karavan-space/src/designer/icons/KaravanIcons.tsx 
b/karavan-space/src/designer/icons/KaravanIcons.tsx
index b0b8042f..d1d06505 100644
--- a/karavan-space/src/designer/icons/KaravanIcons.tsx
+++ b/karavan-space/src/designer/icons/KaravanIcons.tsx
@@ -295,16 +295,13 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
     )
     if (icon === 'routes') return (
         <svg className="top-icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-            <defs>
-                <style>{".cls-1{fill:none;}"}</style>
-            </defs>
             <path
                 
d="M29,10H24v2h5v6H22v2h3v2.142a4,4,0,1,0,2,0V20h2a2.0027,2.0027,0,0,0,2-2V12A2.0023,2.0023,0,0,0,29,10ZM28,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,28,26Z"/>
             <path
                 
d="M19,6H14V8h5v6H12v2h3v6.142a4,4,0,1,0,2,0V16h2a2.0023,2.0023,0,0,0,2-2V8A2.0023,2.0023,0,0,0,19,6ZM18,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,18,26Z"/>
             <path
                 
d="M9,2H3A2.002,2.002,0,0,0,1,4v6a2.002,2.002,0,0,0,2,2H5V22.142a4,4,0,1,0,2,0V12H9a2.002,2.002,0,0,0,2-2V4A2.002,2.002,0,0,0,9,2ZM8,26a2,2,0,1,1-2-2A2.0023,2.0023,0,0,1,8,26ZM3,10V4H9l.0015,6Z"/>
-            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32"
+            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" fill='none' width="32"
                   height="32"/>
         </svg>)
     if (icon === 'route') return (
@@ -335,9 +332,6 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
     )
     if (icon === 'beans') return (
         <svg className="top-icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-            <defs>
-                <style>{".cls-1 {fill: none;}"}</style>
-            </defs>
             <title>data--1</title>
             <rect x="15" y="6" width="13" height="2"/>
             <rect x="15" y="24" width="13" height="2"/>
@@ -347,15 +341,12 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
             <path 
d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
                   transform="translate(0 0)"/>
             <g id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;">
-                <rect className="cls-1" width="32" height="32"/>
+                <rect fill='none' width="32" height="32"/>
             </g>
         </svg>
     )
     if (icon === 'dependencies') return (
         <svg className="top-icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-            <defs>
-                <style>{".cls-1 {fill: none;}"}</style>
-            </defs>
             <title>application</title>
             <path 
d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
                   transform="translate(0 0)"/>
@@ -366,7 +357,7 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
             <path 
d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
                   transform="translate(0 0)"/>
             <g id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;">
-                <rect className="cls-1" width="32" height="32"/>
+                <rect fill='none' width="32" height="32"/>
             </g>
         </svg>
     )
@@ -382,27 +373,21 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
         </svg>)
     if (icon === 'exception') return (
         <svg className="top-icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-            <defs>
-                <style>{".cls-1{fill:none;}"}</style>
-            </defs>
             <title>misuse--alt</title>
             <polygon
                 points="21.41 23 16 17.591 10.59 23 9 21.41 14.409 16 9 10.591 
10.591 9 16 14.409 21.409 9 23 10.591 17.591 16 23 21.41 21.41 23"/>
             <path 
d="M16,4A12,12,0,1,1,4,16,12.0136,12.0136,0,0,1,16,4m0-2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Z"
                   transform="translate(0)"/>
-            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32"
+            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" fill='none' width="32"
                   height="32"/>
         </svg>)
     if (icon === 'routeConfiguration') return (
-        <svg className="top-icon" width="32" height="32" viewBox="0 0 32 32">
-            <defs>
-                <style>{".cls-1{fill:none;}"}</style>
-            </defs>
+        <svg className="top-icon" width="32" height="32" viewBox="0 0 32 32">  
   
             <path
                 d="M28.83 21.17L25 17.37l.67-.67a1 1 0 000-1.41l-6-6a1 1 0 
00-1.41 0l-.79.79-6.76-6.79a1 1 0 00-1.41 0l-4 4-.12.15-4 6a1 1 0 00.12 1.26l3 
3a1 1 0 001.42 0L10 13.41l2.09 2.09-4.8 4.79a1 1 0 000 1.41l2 2a1 1 0 00.71.3 1 
1 0 00.52-.15l4.33-2.6 2.44 2.45a1 1 0 001.41 0l.67-.7 3.79 3.83a4 4 0 
005.66-5.66zM10 10.58l-5 5-1.71-1.71 3.49-5.24L10 5.41l6.09 6.09-2.59 2.58zm8 
11l-2.84-2.84-5 3-.74-.74L19 11.41 23.59 16zm9.42 3.83a2 2 0 01-2.83 
0l-3.8-3.79 2.83-2.83 3.8 3.79a2 2 0 010 [...]
             <path
                 d="M0 0H32V32H0z"
-                className="cls-1"
+                fill='none'
                 data-name="&lt;Transparent Rectangle&gt;"
             ></path>
         </svg>)
@@ -419,14 +404,11 @@ export function getDesignerIcon(icon: string): 
React.JSX.Element {
         </svg>)
     if (icon === 'code') return (
         <svg className="top-icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-            <defs>
-                <style>{".cls-1{fill:none;}"}</style>
-            </defs>
             <title>code</title>
             <polygon points="31 16 24 23 22.59 21.59 28.17 16 22.59 10.41 24 9 
31 16"/>
             <polygon points="1 16 8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 
16"/>
             <rect x="5.91" y="15" width="20.17" height="2" 
transform="translate(-3.6 27.31) rotate(-75)"/>
-            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32"
+            <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" fill='none' width="32"
                   height="32" transform="translate(0 32) rotate(-90)"/>
         </svg>)
     return <></>;
@@ -438,9 +420,6 @@ export class BeanIcon extends React.Component<any> {
     render() {
         return (
             <svg className="icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-                <defs>
-                    <style>{".cls-1 {fill: none;}"}</style>
-                </defs>
                 <title>data--1</title>
                 <rect x="15" y="6" width="13" height="2"/>
                 <rect x="15" y="24" width="13" height="2"/>
@@ -452,7 +431,7 @@ export class BeanIcon extends React.Component<any> {
                 <path 
d="M25,20a4,4,0,1,1,4-4A4,4,0,0,1,25,20Zm0-6a2,2,0,1,0,2,2A2,2,0,0,0,25,14Z"
                       transform="translate(0 0)"/>
                 <g id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;">
-                    <rect className="cls-1" width="32" height="32"/>
+                    <rect fill='none' width="32" height="32"/>
                 </g>
             </svg>
         )
@@ -464,9 +443,6 @@ export class DependencyIcon extends React.Component<any> {
     render() {
         return (
             <svg className="icon" width="32px" height="32px" viewBox="0 0 32 
32" id="icon">
-                <defs>
-                    <style>{".cls-1 {fill: none;}"}</style>
-                </defs>
                 <title>application</title>
                 <path 
d="M16,18H6a2,2,0,0,1-2-2V6A2,2,0,0,1,6,4H16a2,2,0,0,1,2,2V16A2,2,0,0,1,16,18ZM6,6V16H16V6Z"
                       transform="translate(0 0)"/>
@@ -477,7 +453,7 @@ export class DependencyIcon extends React.Component<any> {
                 <path 
d="M16,22v4H12V22h4m0-2H12a2,2,0,0,0-2,2v4a2,2,0,0,0,2,2h4a2,2,0,0,0,2-2V22a2,2,0,0,0-2-2Z"
                       transform="translate(0 0)"/>
                 <g id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;">
-                    <rect className="cls-1" width="32" height="32"/>
+                    <rect fill='none' width="32" height="32"/>
                 </g>
             </svg>
         )
@@ -508,13 +484,10 @@ export class ConceptIcon extends React.Component<any> {
     render() {
         return (
             <svg className="icon" width="32px" height="32px" viewBox="0 0 32 
32">
-                <defs>
-                    <style>{".cls-1 {fill: none;}"}</style>
-                </defs>
                 <title>concept</title>
                 <path
                     
d="M20.8851,19.4711a5.9609,5.9609,0,0,0,0-6.9422L23,10.4141l1.293,1.2929a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414l-4-4a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414L21.5859,9l-2.1148,2.1149a5.9609,5.9609,0,0,0-6.9422,0L10,8.5859V2H2v8H8.5859l2.529,2.5289a5.9609,5.9609,0,0,0,0,6.9422L9,21.5859,7.707,20.293a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414l4,4a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414L10.4141,23l2.1148-2.1149a5.960
 [...]
-                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1"
+                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" fill='none'
                       width="32" height="32"/>
             </svg>
         )
diff --git a/karavan-space/src/designer/karavan.css 
b/karavan-space/src/designer/karavan.css
index 5e558152..4d9a7162 100644
--- a/karavan-space/src/designer/karavan.css
+++ b/karavan-space/src/designer/karavan.css
@@ -811,3 +811,6 @@
     background-color: var(--pf-v5-global--BackgroundColor--light-300);
     margin-bottom: 100px;
 }
+.karavan .knowledbase-eip-section .pf-v5-c-toggle-group{
+    margin:16px;
+}
\ No newline at end of file
diff --git a/karavan-space/src/designer/property/DslProperties.tsx 
b/karavan-space/src/designer/property/DslProperties.tsx
index ed56d2eb..656d816c 100644
--- a/karavan-space/src/designer/property/DslProperties.tsx
+++ b/karavan-space/src/designer/property/DslProperties.tsx
@@ -44,7 +44,6 @@ import {shallow} from "zustand/shallow";
 import {usePropertiesHook} from "./usePropertiesHook";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
 import EllipsisVIcon from 
'@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
-import QuestionIcon from 
'@patternfly/react-icons/dist/esm/icons/question-icon';
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
diff --git a/karavan-space/src/knowledgebase/eip/EipTab.tsx 
b/karavan-space/src/knowledgebase/eip/EipTab.tsx
index e2757f9d..35cc9741 100644
--- a/karavan-space/src/knowledgebase/eip/EipTab.tsx
+++ b/karavan-space/src/knowledgebase/eip/EipTab.tsx
@@ -17,7 +17,7 @@
 import React from 'react';
 import {
     Gallery,
-    PageSection, PageSectionVariants
+    PageSection, PageSectionVariants,ToggleGroup,ToggleGroupItem
 } from '@patternfly/react-core';
 import '../../designer/karavan.css';
 import {EipCard} from "./EipCard";
@@ -25,6 +25,7 @@ import {EipModal} from "./EipModal";
 import {CamelModelMetadata, ElementMeta} from 
"karavan-core/lib/model/CamelMetadata";
 import {useKnowledgebaseStore} from "../KnowledgebaseStore";
 import {shallow} from "zustand/shallow";
+import { useSelectorStore } from '../../designer/DesignerStore';
 
 interface Props {
     dark: boolean,
@@ -36,20 +37,46 @@ export function EipTab(props: Props) {
     const [isModalOpen] = useKnowledgebaseStore((s) =>
         [s.isModalOpen], shallow)
 
-
-    const {filter} = props;
-    const elements = CamelModelMetadata
-        .filter(c => c.name.toLowerCase().includes(filter.toLowerCase()))
+        const [ selectedLabels, addSelectedLabel, deleteSelectedLabel] =
+        useSelectorStore((s) =>
+            [s.selectedLabels, s.addSelectedLabel, s.deleteSelectedLabel], 
shallow)
+        const { filter } = props;
+        const elements = CamelModelMetadata;
+        const filteredElements=CamelModelMetadata
+        .filter(c => 
c.name.toLowerCase().includes(filter.toLowerCase())).filter((dsl: ElementMeta) 
=> {
+            if (selectedLabels.length === 0) {
+                return true;
+            } else {
+                return dsl.labels.split(",").some(r => 
selectedLabels.includes(r));
+            }
+        })
         .sort((a: ElementMeta, b: ElementMeta) => a.name > b.name ? 1 : -1);
-
+     const eipLabels = [...new Set(elements.map(e => 
e.labels).join(",").split(",").filter(e => e !== 'eip'))];
+    function selectLabel(eipLabel: string) {
+            if (!selectedLabels.includes(eipLabel)) {
+                addSelectedLabel(eipLabel);
+            } else {
+                deleteSelectedLabel(eipLabel);
+            }
+        }
     return (
         <PageSection variant={props.dark ? PageSectionVariants.darker : 
PageSectionVariants.light}
-                     padding={{default: 'noPadding'}} 
className="kamelet-section">
+            padding={{ default: 'noPadding' }} className="kamelet-section 
knowledbase-eip-section">
+             <ToggleGroup aria-label="Labels" isCompact >
+                    {eipLabels.map(eipLabel => <ToggleGroupItem
+                        key={eipLabel}
+                        text={eipLabel}
+                        buttonId={eipLabel}
+                        isSelected={selectedLabels.includes(eipLabel)}
+                        onChange={selected => selectLabel(eipLabel)}
+                    />)}
+                </ToggleGroup>
+
             {isModalOpen && <EipModal/>}
             <PageSection isFilled className="kamelets-page"
                          variant={props.dark ? PageSectionVariants.darker : 
PageSectionVariants.light}>
                 <Gallery hasGutter>
-                    {elements.map(c => (
+                    {filteredElements.map(c => (
                         <EipCard key={c.name} element={c}/>
                     ))}
                 </Gallery>
diff --git a/karavan-space/src/topology/TopologyPropertiesPanel.tsx 
b/karavan-space/src/topology/TopologyPropertiesPanel.tsx
index 8387ce1f..67edb46c 100644
--- a/karavan-space/src/topology/TopologyPropertiesPanel.tsx
+++ b/karavan-space/src/topology/TopologyPropertiesPanel.tsx
@@ -20,32 +20,93 @@ import {shallow} from "zustand/shallow";
 import {TopologySideBar} from "@patternfly/react-topology";
 import {useTopologyStore} from "./TopologyStore";
 import {DslProperties} from "../designer/property/DslProperties";
-import {Button, Flex, FlexItem, Text, Tooltip, TooltipPosition} from 
"@patternfly/react-core";
+import {
+    Button, DescriptionList,
+    DescriptionListDescription, DescriptionListGroup, DescriptionListTerm,
+    Flex,
+    FlexItem, Panel, PanelHeader, PanelMain, PanelMainBody,
+    Text, TextContent, TextVariants,
+    Tooltip,
+    TooltipPosition
+} from "@patternfly/react-core";
 import CloseIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
 
 interface Props {
     onSetFile: (fileName: string) => void
 }
 
-export function TopologyPropertiesPanel (props: Props) {
+export function TopologyPropertiesPanel(props: Props) {
 
-    const [selectedIds, setSelectedIds, fileName] = useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.fileName], shallow);
+    const [selectedIds, setSelectedIds, fileName, nodeData] = 
useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.fileName, s.nodeData], shallow);
+
+    console.log(nodeData)
+
+    function isRoute() {
+        if (nodeData && nodeData.type === 'route') {
+            const uri: string = nodeData?.step?.from.uri || '';
+            return uri !== undefined;
+        }
+        return false;
+    }
+
+    function isKamelet() {
+        if (nodeData && nodeData.type === 'step') {
+            const uri: string = nodeData?.step?.uri || '';
+            return uri.startsWith("kamelet");
+        }
+        return false;
+    }
+
+    function getFromInfo() {
+        if (isRoute()) {
+            const uri: string = nodeData?.step?.from.uri || '';
+            const name: string = nodeData?.step?.from.parameters?.name || '';
+            if (['direct','seda'].includes(uri)) {
+                return uri.concat(":").concat(name);
+            } else {
+                return uri;
+            }
+        }
+        return ""
+    }
+
+    function getTitle () {
+        return isRoute() ? "Route" : (isKamelet() ? "Kamelet" : "Component");
+    }
 
     function getHeader() {
         return (
-            <Flex className="properties-header" direction={{default: "row"}} 
justifyContent={{default: "justifyContentFlexStart"}}>
+            <Flex direction={{default: "row"}} justifyContent={{default: 
"justifyContentFlexStart"}}>
                 <FlexItem spacer={{ default: 'spacerNone' }}>
-                    <Text>Filename:</Text>
-                </FlexItem>
-                <FlexItem>
-                    <Button variant="link" onClick={event => {
-                        if (fileName) {
-                            props.onSetFile(fileName);
-                        }
-                    }}
-                    >{fileName}
-                    </Button>
+                    <Panel>
+                        <PanelHeader>
+                            <TextContent>
+                                <Text 
component={TextVariants.h3}>{getTitle()}</Text>
+                            </TextContent>
+                        </PanelHeader>
+                        <PanelMain>
+                            <PanelMainBody>
+                                <DescriptionList isHorizontal>
+                                    <DescriptionListGroup>
+                                        
<DescriptionListTerm>File</DescriptionListTerm>
+                                        <DescriptionListDescription>
+                                            <Button className="file-button" 
variant="link" onClick={_ => {
+                                                if (fileName) {
+                                                    props.onSetFile(fileName);
+                                                }
+                                            }}>{fileName}
+                                            </Button>
+                                        </DescriptionListDescription>
+                                    </DescriptionListGroup>
+                                    {isRoute() && <DescriptionListGroup>
+                                        
<DescriptionListTerm>From</DescriptionListTerm>
+                                        
<DescriptionListDescription>{getFromInfo()}</DescriptionListDescription>
+                                    </DescriptionListGroup>}
+                                </DescriptionList>
+                            </PanelMainBody>
+                        </PanelMain>
+                    </Panel>
                 </FlexItem>
                 <FlexItem align={{ default: 'alignRight' }}>
                     <Tooltip content={"Close"} position={TooltipPosition.top}>
@@ -58,11 +119,11 @@ export function TopologyPropertiesPanel (props: Props) {
 
     return (
         <TopologySideBar
-        className="topology-sidebar"
-        show={selectedIds.length > 0}
-        header={getHeader()}
-    >
-        <DslProperties designerType={'routes'}/>
-    </TopologySideBar>
+            className="topology-sidebar"
+            show={selectedIds.length > 0}
+            header={getHeader()}
+        >
+            <DslProperties designerType={'routes'}/>
+        </TopologySideBar>
     )
 }
diff --git a/karavan-space/src/topology/TopologyStore.ts 
b/karavan-space/src/topology/TopologyStore.ts
index 73aead9f..4e9ee643 100644
--- a/karavan-space/src/topology/TopologyStore.ts
+++ b/karavan-space/src/topology/TopologyStore.ts
@@ -35,6 +35,8 @@ interface TopologyState {
     setFileName: (fileName?: string) => void
     ranker: string
     setRanker: (ranker: string) => void
+    nodeData: any
+    setNodeData: (nodeData: any) => void
 }
 
 export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({
@@ -55,4 +57,10 @@ export const useTopologyStore = 
createWithEqualityFn<TopologyState>((set) => ({
             return {ranker: ranker};
         });
     },
+    nodeData: undefined,
+    setNodeData: (nodeData: any) => {
+    set((state: TopologyState) => {
+        return {nodeData: nodeData};
+    });
+},
 }), shallow)
diff --git a/karavan-space/src/topology/TopologyTab.tsx 
b/karavan-space/src/topology/TopologyTab.tsx
index 727905cc..1f2d165e 100644
--- a/karavan-space/src/topology/TopologyTab.tsx
+++ b/karavan-space/src/topology/TopologyTab.tsx
@@ -47,8 +47,8 @@ interface Props {
 
 export function TopologyTab(props: Props) {
 
-    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker] = 
useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker], shallow);
+    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, 
setNodeData] = useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker, s.setNodeData], shallow);
     const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], 
shallow)
 
     function setTopologySelected(model: Model, ids: string []) {
@@ -57,6 +57,7 @@ export function TopologyTab(props: Props) {
             const node = model.nodes?.filter(node => node.id === ids[0]);
             if (node && node.length > 0) {
                 const data = node[0].data;
+                setNodeData(data);
                 setFileName(data.fileName)
                 if (data.step) {
                     setSelectedStep(data.step)
diff --git a/karavan-space/src/topology/topology.css 
b/karavan-space/src/topology/topology.css
index cb261e21..24fe7679 100644
--- a/karavan-space/src/topology/topology.css
+++ b/karavan-space/src/topology/topology.css
@@ -41,8 +41,8 @@
     overflow: auto;
 }
 
-.karavan .topology-panel .properties-header {
-    padding: 10px;
+.karavan .topology-panel .properties .headers {
+    display: none;
 }
 
 .karavan .topology-panel .common-node .icon {
@@ -50,6 +50,14 @@
     width: 32px;
 }
 
+.karavan .topology-panel .pf-v5-c-panel__header {
+    padding-bottom: 0;
+}
+
+.karavan .topology-panel .file-button {
+    padding: 0;
+}
+
 .karavan .topology-sidebar .pf-topology-side-bar__header {
     margin-right: 0;
 }
@@ -72,4 +80,8 @@
 .karavan .topology-sidebar .properties .pf-v5-c-form {
     pointer-events: none;
     opacity: 0.7;
+}
+.karavan .topology-sidebar .properties .pf-v5-c-form 
.pf-v5-c-form__group-label-help {
+    pointer-events: auto;
+    opacity: 1;
 }
\ No newline at end of file
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
 
b/karavan-web/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
index ed56d2eb..656d816c 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/designer/property/DslProperties.tsx
@@ -44,7 +44,6 @@ import {shallow} from "zustand/shallow";
 import {usePropertiesHook} from "./usePropertiesHook";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
 import EllipsisVIcon from 
'@patternfly/react-icons/dist/esm/icons/ellipsis-v-icon';
-import QuestionIcon from 
'@patternfly/react-icons/dist/esm/icons/question-icon';
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyPropertiesPanel.tsx
 
b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyPropertiesPanel.tsx
index 8387ce1f..67edb46c 100644
--- 
a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyPropertiesPanel.tsx
+++ 
b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyPropertiesPanel.tsx
@@ -20,32 +20,93 @@ import {shallow} from "zustand/shallow";
 import {TopologySideBar} from "@patternfly/react-topology";
 import {useTopologyStore} from "./TopologyStore";
 import {DslProperties} from "../designer/property/DslProperties";
-import {Button, Flex, FlexItem, Text, Tooltip, TooltipPosition} from 
"@patternfly/react-core";
+import {
+    Button, DescriptionList,
+    DescriptionListDescription, DescriptionListGroup, DescriptionListTerm,
+    Flex,
+    FlexItem, Panel, PanelHeader, PanelMain, PanelMainBody,
+    Text, TextContent, TextVariants,
+    Tooltip,
+    TooltipPosition
+} from "@patternfly/react-core";
 import CloseIcon from "@patternfly/react-icons/dist/esm/icons/times-icon";
 
 interface Props {
     onSetFile: (fileName: string) => void
 }
 
-export function TopologyPropertiesPanel (props: Props) {
+export function TopologyPropertiesPanel(props: Props) {
 
-    const [selectedIds, setSelectedIds, fileName] = useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.fileName], shallow);
+    const [selectedIds, setSelectedIds, fileName, nodeData] = 
useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.fileName, s.nodeData], shallow);
+
+    console.log(nodeData)
+
+    function isRoute() {
+        if (nodeData && nodeData.type === 'route') {
+            const uri: string = nodeData?.step?.from.uri || '';
+            return uri !== undefined;
+        }
+        return false;
+    }
+
+    function isKamelet() {
+        if (nodeData && nodeData.type === 'step') {
+            const uri: string = nodeData?.step?.uri || '';
+            return uri.startsWith("kamelet");
+        }
+        return false;
+    }
+
+    function getFromInfo() {
+        if (isRoute()) {
+            const uri: string = nodeData?.step?.from.uri || '';
+            const name: string = nodeData?.step?.from.parameters?.name || '';
+            if (['direct','seda'].includes(uri)) {
+                return uri.concat(":").concat(name);
+            } else {
+                return uri;
+            }
+        }
+        return ""
+    }
+
+    function getTitle () {
+        return isRoute() ? "Route" : (isKamelet() ? "Kamelet" : "Component");
+    }
 
     function getHeader() {
         return (
-            <Flex className="properties-header" direction={{default: "row"}} 
justifyContent={{default: "justifyContentFlexStart"}}>
+            <Flex direction={{default: "row"}} justifyContent={{default: 
"justifyContentFlexStart"}}>
                 <FlexItem spacer={{ default: 'spacerNone' }}>
-                    <Text>Filename:</Text>
-                </FlexItem>
-                <FlexItem>
-                    <Button variant="link" onClick={event => {
-                        if (fileName) {
-                            props.onSetFile(fileName);
-                        }
-                    }}
-                    >{fileName}
-                    </Button>
+                    <Panel>
+                        <PanelHeader>
+                            <TextContent>
+                                <Text 
component={TextVariants.h3}>{getTitle()}</Text>
+                            </TextContent>
+                        </PanelHeader>
+                        <PanelMain>
+                            <PanelMainBody>
+                                <DescriptionList isHorizontal>
+                                    <DescriptionListGroup>
+                                        
<DescriptionListTerm>File</DescriptionListTerm>
+                                        <DescriptionListDescription>
+                                            <Button className="file-button" 
variant="link" onClick={_ => {
+                                                if (fileName) {
+                                                    props.onSetFile(fileName);
+                                                }
+                                            }}>{fileName}
+                                            </Button>
+                                        </DescriptionListDescription>
+                                    </DescriptionListGroup>
+                                    {isRoute() && <DescriptionListGroup>
+                                        
<DescriptionListTerm>From</DescriptionListTerm>
+                                        
<DescriptionListDescription>{getFromInfo()}</DescriptionListDescription>
+                                    </DescriptionListGroup>}
+                                </DescriptionList>
+                            </PanelMainBody>
+                        </PanelMain>
+                    </Panel>
                 </FlexItem>
                 <FlexItem align={{ default: 'alignRight' }}>
                     <Tooltip content={"Close"} position={TooltipPosition.top}>
@@ -58,11 +119,11 @@ export function TopologyPropertiesPanel (props: Props) {
 
     return (
         <TopologySideBar
-        className="topology-sidebar"
-        show={selectedIds.length > 0}
-        header={getHeader()}
-    >
-        <DslProperties designerType={'routes'}/>
-    </TopologySideBar>
+            className="topology-sidebar"
+            show={selectedIds.length > 0}
+            header={getHeader()}
+        >
+            <DslProperties designerType={'routes'}/>
+        </TopologySideBar>
     )
 }
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyStore.ts 
b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyStore.ts
index 73aead9f..4e9ee643 100644
--- a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyStore.ts
+++ b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyStore.ts
@@ -35,6 +35,8 @@ interface TopologyState {
     setFileName: (fileName?: string) => void
     ranker: string
     setRanker: (ranker: string) => void
+    nodeData: any
+    setNodeData: (nodeData: any) => void
 }
 
 export const useTopologyStore = createWithEqualityFn<TopologyState>((set) => ({
@@ -55,4 +57,10 @@ export const useTopologyStore = 
createWithEqualityFn<TopologyState>((set) => ({
             return {ranker: ranker};
         });
     },
+    nodeData: undefined,
+    setNodeData: (nodeData: any) => {
+    set((state: TopologyState) => {
+        return {nodeData: nodeData};
+    });
+},
 }), shallow)
diff --git 
a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyTab.tsx 
b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyTab.tsx
index 727905cc..1f2d165e 100644
--- a/karavan-web/karavan-app/src/main/webui/src/topology/TopologyTab.tsx
+++ b/karavan-web/karavan-app/src/main/webui/src/topology/TopologyTab.tsx
@@ -47,8 +47,8 @@ interface Props {
 
 export function TopologyTab(props: Props) {
 
-    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker] = 
useTopologyStore((s) =>
-        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker], shallow);
+    const [selectedIds, setSelectedIds, setFileName, ranker, setRanker, 
setNodeData] = useTopologyStore((s) =>
+        [s.selectedIds, s.setSelectedIds, s.setFileName, s.ranker, 
s.setRanker, s.setNodeData], shallow);
     const [setSelectedStep] = useDesignerStore((s) => [s.setSelectedStep], 
shallow)
 
     function setTopologySelected(model: Model, ids: string []) {
@@ -57,6 +57,7 @@ export function TopologyTab(props: Props) {
             const node = model.nodes?.filter(node => node.id === ids[0]);
             if (node && node.length > 0) {
                 const data = node[0].data;
+                setNodeData(data);
                 setFileName(data.fileName)
                 if (data.step) {
                     setSelectedStep(data.step)
diff --git a/karavan-web/karavan-app/src/main/webui/src/topology/topology.css 
b/karavan-web/karavan-app/src/main/webui/src/topology/topology.css
index c67f1f6b..24fe7679 100644
--- a/karavan-web/karavan-app/src/main/webui/src/topology/topology.css
+++ b/karavan-web/karavan-app/src/main/webui/src/topology/topology.css
@@ -41,8 +41,8 @@
     overflow: auto;
 }
 
-.karavan .topology-panel .properties-header {
-    padding: 10px;
+.karavan .topology-panel .properties .headers {
+    display: none;
 }
 
 .karavan .topology-panel .common-node .icon {
@@ -50,6 +50,14 @@
     width: 32px;
 }
 
+.karavan .topology-panel .pf-v5-c-panel__header {
+    padding-bottom: 0;
+}
+
+.karavan .topology-panel .file-button {
+    padding: 0;
+}
+
 .karavan .topology-sidebar .pf-topology-side-bar__header {
     margin-right: 0;
 }


Reply via email to