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/08/28 17:11:18 UTC

[camel-karavan] 01/01: Fix #836

This is an automated email from the ASF dual-hosted git repository.

marat pushed a commit to branch feature-836
in repository https://gitbox.apache.org/repos/asf/camel-karavan.git

commit 23b792978c43d3cc49c8581bc62e5197838c3320
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Mon Aug 28 13:10:52 2023 -0400

    Fix #836
---
 karavan-core/src/core/api/CamelDefinitionYaml.ts   |   2 +-
 karavan-core/src/core/api/CamelDisplayUtil.ts      |   8 +-
 karavan-core/src/core/api/CamelUtil.ts             |   2 +-
 .../src/core/model/IntegrationDefinition.ts        |   2 +-
 karavan-designer/package-lock.json                 |  64 +-
 karavan-designer/package.json                      |   3 +-
 karavan-designer/public/example/demo.camel.yaml    |  74 +++
 karavan-designer/src/App.tsx                       |  47 +-
 karavan-designer/src/DesignerPage.tsx              | 138 ++---
 karavan-designer/src/designer/KaravanDesigner.tsx  | 161 ++---
 karavan-designer/src/designer/KaravanStore.ts      | 244 ++++++++
 karavan-designer/src/designer/MainToolbar.tsx      |   2 +-
 karavan-designer/src/designer/beans/BeanCard.tsx   |  47 +-
 .../src/designer/beans/BeanProperties.tsx          | 174 +++---
 .../src/designer/beans/BeansDesigner.tsx           | 159 ++---
 karavan-designer/src/designer/karavan.css          |  51 +-
 karavan-designer/src/designer/rest/RestCard.tsx    |  93 ++-
 .../src/designer/rest/RestConfigurationCard.tsx    |  53 +-
 .../src/designer/rest/RestDesigner.tsx             | 281 ++++-----
 .../src/designer/rest/RestMethodCard.tsx           |  52 +-
 .../src/designer/rest/RestMethodSelector.tsx       |  48 +-
 .../src/designer/route/DeleteConfirmation.tsx      |  51 ++
 .../src/designer/route/DslConnections.tsx          | 245 ++++----
 karavan-designer/src/designer/route/DslElement.tsx | 457 +++++++-------
 .../src/designer/route/DslProperties.tsx           | 223 +++----
 .../src/designer/route/DslSelector.tsx             | 217 +++----
 .../src/designer/route/RouteDesigner.tsx           | 238 +++----
 .../src/designer/route/RouteDesignerLogic.tsx      | 396 ------------
 .../route/property/ComponentParameterField.tsx     | 344 +++++------
 .../designer/route/property/DataFormatField.tsx    | 184 +++---
 .../designer/route/property/DslPropertyField.tsx   | 681 +++++++++++----------
 .../designer/route/property/ExpressionField.tsx    | 185 +++---
 .../route/property/InfrastructureSelector.tsx      | 129 ++--
 .../route/property/KameletPropertyField.tsx        | 180 +++---
 .../src/designer/route/property/ModalEditor.tsx    |  97 ++-
 .../src/designer/route/property/ObjectField.tsx    |  84 +--
 .../route/useDrawerMutationsObserver.tsx}          |  31 +-
 .../src/designer/route/usePropertiesHook.tsx       | 128 ++++
 .../route/useResizeObserver.tsx}                   |  31 +-
 .../src/designer/route/useRouteDesignerHook.tsx    | 302 +++++++++
 .../src/designer/templates/TemplatesDesigner.tsx   |  71 ---
 karavan-designer/src/designer/utils/CamelUi.tsx    |  26 +-
 karavan-designer/src/designer/utils/EventBus.ts    |  16 +-
 .../src/designer/utils/InfrastructureAPI.ts        |  34 +
 .../src/designer/utils/IntegrationHeader.tsx       |  41 ++
 .../src/designer/utils/KaravanComponents.tsx       |  44 --
 .../src/designer/utils/KaravanIcons.tsx            | 217 +++++--
 karavan-designer/src/index.css                     |   6 -
 karavan-designer/src/index.tsx                     |   8 +-
 49 files changed, 3314 insertions(+), 3057 deletions(-)

diff --git a/karavan-core/src/core/api/CamelDefinitionYaml.ts b/karavan-core/src/core/api/CamelDefinitionYaml.ts
index 073b1a5f..ba086ef7 100644
--- a/karavan-core/src/core/api/CamelDefinitionYaml.ts
+++ b/karavan-core/src/core/api/CamelDefinitionYaml.ts
@@ -68,7 +68,7 @@ export class CamelDefinitionYaml {
         }
 
         delete object.uuid;
-        delete object.show;
+        delete object.showChildren;
 
         for (const [key, value] of Object.entries(object) as [string, any][]) {
             if (value instanceof CamelElement || (typeof value === 'object' && value?.dslName)) {
diff --git a/karavan-core/src/core/api/CamelDisplayUtil.ts b/karavan-core/src/core/api/CamelDisplayUtil.ts
index 887099ef..eee33ccb 100644
--- a/karavan-core/src/core/api/CamelDisplayUtil.ts
+++ b/karavan-core/src/core/api/CamelDisplayUtil.ts
@@ -75,13 +75,9 @@ export class CamelDisplayUtil {
         return clone;
     };
 
-    static setElementVisibility = (
-        step: CamelElement,
-        showChildren: boolean,
-        expandedUuids: string[],
-    ): CamelElement => {
+    static setElementVisibility = (step: CamelElement, showChildren: boolean, expandedUuids: string[]): CamelElement => {
         const result = CamelDefinitionApi.createStep(step.dslName, step);
-        result.show = showChildren;
+        result.showChildren = showChildren;
         if (result.dslName === 'StepDefinition') {
             showChildren = expandedUuids.includes(result.uuid);
         }
diff --git a/karavan-core/src/core/api/CamelUtil.ts b/karavan-core/src/core/api/CamelUtil.ts
index 791ec0fa..65579d59 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -209,7 +209,7 @@ export class CamelUtil {
                     result[1].push(`${property.displayName} is required`);
                 } else if (property.type === 'ExpressionDefinition') {
                     const expressionMeta = CamelMetadataApi.getCamelModelMetadataByClassName('ExpressionDefinition');
-                    const expressionCheck = expressionMeta?.properties.some(ep => {
+                    const expressionCheck = expressionMeta && value!== undefined && expressionMeta?.properties.some(ep => {
                         const expValue = value[ep.name];
                         if (expValue) {
                             const checkedExpression = CamelUtil.checkRequired(expValue);
diff --git a/karavan-core/src/core/model/IntegrationDefinition.ts b/karavan-core/src/core/model/IntegrationDefinition.ts
index 1d2519b3..3af3c6c5 100644
--- a/karavan-core/src/core/model/IntegrationDefinition.ts
+++ b/karavan-core/src/core/model/IntegrationDefinition.ts
@@ -52,7 +52,7 @@ export class Integration {
 export class CamelElement {
     uuid: string = '';
     dslName: string = '';
-    show: boolean = true;
+    showChildren: boolean = true;
 
     constructor(dslName: string) {
         this.uuid = uuidv4();
diff --git a/karavan-designer/package-lock.json b/karavan-designer/package-lock.json
index a9956967..d6fbc8b5 100644
--- a/karavan-designer/package-lock.json
+++ b/karavan-designer/package-lock.json
@@ -9,7 +9,7 @@
       "version": "4.0.0-RC2",
       "license": "Apache-2.0",
       "dependencies": {
-        "@monaco-editor/react": "4.5.0",
+        "@monaco-editor/react": "4.5.1",
         "@patternfly/patternfly": "^5.0.2",
         "@patternfly/react-core": "^5.0.0",
         "@patternfly/react-table": "^5.0.0",
@@ -24,7 +24,8 @@
         "react": "18.2.0",
         "react-dom": "18.2.0",
         "rxjs": "7.8.1",
-        "uuid": "9.0.0"
+        "uuid": "9.0.0",
+        "zustand": "^4.4.1"
       },
       "devDependencies": {
         "@svgr/webpack": "^7.0.0",
@@ -36,7 +37,7 @@
         "@typescript-eslint/eslint-plugin": "^5.59.2",
         "@typescript-eslint/parser": "^5.59.2",
         "eslint": "^8.39.0",
-        "monaco-editor": "0.38.0",
+        "monaco-editor": "0.41.0",
         "react-scripts": "5.0.1",
         "typescript": "^4.9.5"
       }
@@ -3198,9 +3199,9 @@
       }
     },
     "node_modules/@monaco-editor/react": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.5.0.tgz",
-      "integrity": "sha512-VJMkp5Fe1+w8pLEq8tZPHZKu8zDXQIA1FtiDTSNccg1D3wg1YIZaH2es2Qpvop1k62g3c/YySRb3bnGXu2XwYQ==",
+      "version": "4.5.1",
+      "resolved": "https://registry.npmjs.org/@monaco-editor/react/-/react-4.5.1.tgz",
+      "integrity": "sha512-NNDFdP+2HojtNhCkRfE6/D6ro6pBNihaOzMbGK84lNWzRu+CfBjwzGt4jmnqimLuqp5yE5viHS2vi+QOAnD5FQ==",
       "dependencies": {
         "@monaco-editor/loader": "^1.3.3"
       },
@@ -3996,7 +3997,7 @@
       "version": "15.7.5",
       "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz",
       "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==",
-      "dev": true
+      "devOptional": true
     },
     "node_modules/@types/qs": {
       "version": "6.9.7",
@@ -4014,7 +4015,7 @@
       "version": "18.2.0",
       "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.0.tgz",
       "integrity": "sha512-0FLj93y5USLHdnhIhABk83rm8XEGA7kH3cr+YUlvxoUGp1xNt/DINUMvqPxLyOQMzLmZe8i4RTHbvb8MC7NmrA==",
-      "dev": true,
+      "devOptional": true,
       "dependencies": {
         "@types/prop-types": "*",
         "@types/scheduler": "*",
@@ -4049,7 +4050,7 @@
       "version": "0.16.3",
       "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz",
       "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==",
-      "dev": true
+      "devOptional": true
     },
     "node_modules/@types/semver": {
       "version": "7.3.13",
@@ -6530,7 +6531,7 @@
       "version": "3.1.2",
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.2.tgz",
       "integrity": "sha512-I7K1Uu0MBPzaFKg4nI5Q7Vs2t+3gWWW648spaF+Rg7pI9ds18Ugn+lvg4SHczUdKlHI5LWBXyqfS8+DufyBsgQ==",
-      "dev": true
+      "devOptional": true
     },
     "node_modules/dagre": {
       "version": "0.8.5",
@@ -9388,7 +9389,7 @@
       "version": "9.0.21",
       "resolved": "https://registry.npmjs.org/immer/-/immer-9.0.21.tgz",
       "integrity": "sha512-bc4NBHqOqSfRW7POMkHd51LvClaeMXpm8dx0e8oE2GORbq5aRK7Bxl4FyzVLdGtLmvLKL7BTDBG5ACQm4HWjTA==",
-      "dev": true,
+      "devOptional": true,
       "funding": {
         "type": "opencollective",
         "url": "https://opencollective.com/immer"
@@ -12777,9 +12778,9 @@
       }
     },
     "node_modules/monaco-editor": {
-      "version": "0.38.0",
-      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.38.0.tgz",
-      "integrity": "sha512-11Fkh6yzEmwx7O0YoLxeae0qEGFwmyPRlVxpg7oF9czOOCB/iCjdJrG5I67da5WiXK3YJCxoz9TJFE8Tfq/v9A=="
+      "version": "0.41.0",
+      "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.41.0.tgz",
+      "integrity": "sha512-1o4olnZJsiLmv5pwLEAmzHTE/5geLKQ07BrGxlF4Ri/AXAc2yyDGZwHjiTqD8D/ROKUZmwMA28A+yEowLNOEcA=="
     },
     "node_modules/ms": {
       "version": "2.1.2",
@@ -17384,6 +17385,14 @@
         "requires-port": "^1.0.0"
       }
     },
+    "node_modules/use-sync-external-store": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.2.0.tgz",
+      "integrity": "sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==",
+      "peerDependencies": {
+        "react": "^16.8.0 || ^17.0.0 || ^18.0.0"
+      }
+    },
     "node_modules/util-deprecate": {
       "version": "1.0.2",
       "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@@ -18430,6 +18439,33 @@
       "funding": {
         "url": "https://github.com/sponsors/sindresorhus"
       }
+    },
+    "node_modules/zustand": {
+      "version": "4.4.1",
+      "resolved": "https://registry.npmjs.org/zustand/-/zustand-4.4.1.tgz",
+      "integrity": "sha512-QCPfstAS4EBiTQzlaGP1gmorkh/UL1Leaj2tdj+zZCZ/9bm0WS7sI2wnfD5lpOszFqWJ1DcPnGoY8RDL61uokw==",
+      "dependencies": {
+        "use-sync-external-store": "1.2.0"
+      },
+      "engines": {
+        "node": ">=12.7.0"
+      },
+      "peerDependencies": {
+        "@types/react": ">=16.8",
+        "immer": ">=9.0",
+        "react": ">=16.8"
+      },
+      "peerDependenciesMeta": {
+        "@types/react": {
+          "optional": true
+        },
+        "immer": {
+          "optional": true
+        },
+        "react": {
+          "optional": true
+        }
+      }
     }
   }
 }
diff --git a/karavan-designer/package.json b/karavan-designer/package.json
index 548304dd..a89a6b7e 100644
--- a/karavan-designer/package.json
+++ b/karavan-designer/package.json
@@ -41,7 +41,8 @@
     "react": "18.2.0",
     "react-dom": "18.2.0",
     "rxjs": "7.8.1",
-    "uuid": "9.0.0"
+    "uuid": "9.0.0",
+    "zustand": "^4.4.1"
   },
   "devDependencies": {
     "@svgr/webpack": "^7.0.0",
diff --git a/karavan-designer/public/example/demo.camel.yaml b/karavan-designer/public/example/demo.camel.yaml
new file mode 100644
index 00000000..46692463
--- /dev/null
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -0,0 +1,74 @@
+- route:
+    id: route-f435
+    from:
+      uri: kamelet:timer-source
+      id: from-e52c
+      steps:
+        - filter:
+              expression: {}
+              id: filter-064f
+#        - choice:
+#            when:
+#              - expression: {}
+#                id: when-064f
+#                steps:
+#                  - multicast:
+#                      id: multicast-38cea
+#                      steps:
+#                        - bean:
+#                            id: bean-3b8e
+#                        - log:
+#                            message: ${body}
+#                            id: log-546f
+#                        - loop:
+#                            expression: {}
+#                            id: loop-4635
+#                            steps:
+#                              - convertBodyTo:
+#                                  id: convertBodyTo-1cae
+#            otherwise:
+#              id: otherwise-0b09
+#              steps:
+#                - filter:
+#                    expression: {}
+#                    id: filter-a02b
+#            id: choice-c53c
+#        - doTry:
+#            id: doTry-8fd5
+#            doCatch:
+#              - id: doCatch-1071
+#              - id: doCatch-c38e
+#            steps:
+#              - routingSlip:
+#                  expression: {}
+#                  id: routingSlip-a85a
+#- route:
+#    id: route-178a
+#    from:
+#      uri: kamelet:aws-cloudtrail-source
+#      id: from-3e7d
+#      steps:
+#        - multicast:
+#            id: multicast-eef7
+#            steps:
+#              - bean:
+#                  id: bean-a5ef
+#              - aggregate:
+#                  id: aggregate-f5d8
+#              - aggregate:
+#                  id: aggregate-b9e7
+#              - aggregate:
+#                  id: aggregate-5eb8
+#              - aggregate:
+#                  id: aggregate-c57e
+#              - aggregate:
+#                  id: aggregate-1cd4
+#              - bean:
+#                  id: bean-72a1
+#              - choice:
+#                  when:
+#                    - expression: {}
+#                      id: when-a56b
+#                  otherwise:
+#                    id: otherwise-9f31
+#                  id: choice-1905
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index b9cae192..02476d89 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -18,8 +18,8 @@ import * as React from "react";
 import {
     Alert,
     AlertActionCloseButton, AlertGroup,
-    Bullseye, Button, Divider, Flex, FlexItem,
-    Page, Spinner, Tooltip,
+    Bullseye, Button, Divider, Flex, FlexItem, Masthead, MastheadBrand, MastheadContent, MastheadMain, MastheadToggle,
+    Page, PageSidebar, PageSidebarBody, PageToggleButton, Spinner, Tooltip,
 } from "@patternfly/react-core";
 import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
@@ -94,7 +94,8 @@ class App extends React.Component<Props, State> {
             fetch("kamelets/kamelets.yaml"),
             fetch("components/components.json"),
             fetch("snippets/org.apache.camel.AggregationStrategy"),
-            fetch("snippets/org.apache.camel.Processor")
+            fetch("snippets/org.apache.camel.Processor"),
+            fetch("example/demo.camel.yaml")
             // fetch("components/supported-components.json"),
         ]).then(responses =>
             Promise.all(responses.map(response => response.text()))
@@ -113,6 +114,10 @@ class App extends React.Component<Props, State> {
             TemplateApi.saveTemplate("org.apache.camel.Processor", data[3]);
 
             if (data[4]) {
+                this.setState({yaml: data[4], name: "demo.camel.yaml"})
+            }
+
+            if (data[5]) {
                 ComponentApi.saveSupportedComponents(data[4]);
                 ComponentApi.setSupportedOnly(true);
             }
@@ -122,8 +127,7 @@ class App extends React.Component<Props, State> {
     }
 
     save(filename: string, yaml: string, propertyOnly: boolean) {
-        this.setState({name: filename, yaml: yaml});
-        // console.log(yaml);
+        console.log(yaml);
     }
 
     getSpinner() {
@@ -183,6 +187,17 @@ class App extends React.Component<Props, State> {
         }
     }
 
+    getHeader = () => (
+        <Masthead>
+        </Masthead>
+    );
+
+    getSidebar = () => (
+        <PageSidebar isSidebarOpen={true} id="fill-sidebar">
+            <PageSidebarBody>Navigation</PageSidebarBody>
+        </PageSidebar>
+    );
+
     public render() {
         const {loaded} = this.state;
         return (
@@ -197,18 +212,16 @@ class App extends React.Component<Props, State> {
                         </Alert>
                     ))}
                 </AlertGroup>
-                <>
-                    <Flex direction={{default: "row"}} style={{width: "100%", height: "100%"}}
-                          alignItems={{default: "alignItemsStretch"}} spaceItems={{default: 'spaceItemsNone'}}>
-                        <FlexItem>
-                            {this.pageNav()}
-                        </FlexItem>
-                        <FlexItem flex={{default: "flex_2"}} style={{height: "100%"}}>
-                            {loaded !== true && this.getSpinner()}
-                            {loaded === true && this.getPage()}
-                        </FlexItem>
-                    </Flex>
-                </>
+                <Flex direction={{default: "row"}} style={{width: "100%", height: "100%"}}
+                      alignItems={{default: "alignItemsStretch"}} spaceItems={{default: 'spaceItemsNone'}}>
+                    <FlexItem>
+                        {this.pageNav()}
+                    </FlexItem>
+                    <FlexItem flex={{default: "flex_2"}} style={{height: "100%"}}>
+                        {loaded !== true && this.getSpinner()}
+                        {loaded === true && this.getPage()}
+                </FlexItem>
+                </Flex>
             </Page>
         )
     }
diff --git a/karavan-designer/src/DesignerPage.tsx b/karavan-designer/src/DesignerPage.tsx
index 9bcc0a2e..8b6b380b 100644
--- a/karavan-designer/src/DesignerPage.tsx
+++ b/karavan-designer/src/DesignerPage.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useEffect, useState} from 'react';
 import {
     Toolbar,
     ToolbarContent,
@@ -26,7 +26,8 @@ import DownloadIcon from "@patternfly/react-icons/dist/esm/icons/download-icon";
 import DownloadImageIcon from "@patternfly/react-icons/dist/esm/icons/image-icon";
 import {KaravanDesigner} from "./designer/KaravanDesigner";
 import Editor from "@monaco-editor/react";
-import {EventBus} from "./designer/utils/EventBus";
+import {EventBus, IntegrationUpdate} from "./designer/utils/EventBus";
+import {InfrastructureAPI} from "./designer/utils/InfrastructureAPI";
 
 interface Props {
     name: string,
@@ -35,25 +36,23 @@ interface Props {
     onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
 }
 
-interface State {
-    mode: "design" | "code",
-}
-
-export class DesignerPage extends React.Component<Props, State> {
+export const DesignerPage = (props: Props) => {
 
-    public state: State = {
-        mode: 'design',
-    };
+    const [mode, setMode] = useState<"design" | "code">('design');
+    const [yaml, setYaml] = useState<string>(props.yaml);
 
-    componentDidMount() {
-    }
+    useEffect(() => {
+        console.log("DesignerPage")
+        // setYaml();
+    }, []);
 
-    save(filename: string, yaml: string, propertyOnly: boolean) {
-        this.props.onSave?.call(this, filename, yaml, propertyOnly);
+    function save(filename: string, yaml: string, propertyOnly: boolean) {
+        setYaml(yaml);
+        props.onSave(filename, yaml, propertyOnly);
     }
 
-    download = () => {
-        const {name, yaml} = this.props;
+    function download () {
+        const {name, yaml} = props;
         if (name && yaml) {
             const a = document.createElement('a');
             a.setAttribute('download', 'example.yaml');
@@ -62,18 +61,17 @@ export class DesignerPage extends React.Component<Props, State> {
         }
     }
 
-    downloadImage = () => {
+    function downloadImage () {
         EventBus.sendCommand("downloadImage");
     }
 
-    getDesigner = () => {
-        const {name, yaml} = this.props;
+    function getDesigner () {
         return (
             <KaravanDesigner
-                dark={this.props.dark}
-                filename={name}
+                dark={props.dark}
+                filename={props.name}
                 yaml={yaml}
-                onSave={(filename, yaml, propertyOnly) => this.save(filename, yaml, propertyOnly)}
+                onSave={(filename, yaml, propertyOnly) => save(filename, yaml, propertyOnly)}
                 onGetCustomCode={name => {
                     return new Promise<string | undefined>(resolve => resolve(undefined))
                 }}
@@ -84,8 +82,7 @@ export class DesignerPage extends React.Component<Props, State> {
         )
     }
 
-    getEditor = () => {
-        const {name, yaml} = this.props;
+    function getEditor () {
         return (
             <Editor
                 height="100vh"
@@ -95,58 +92,55 @@ export class DesignerPage extends React.Component<Props, State> {
                 className={'code-editor'}
                 onChange={(value, ev) => {
                     if (value) {
-                        this.save(name, value, false)
+                        save(props.name, value, false)
                     }
                 }}
             />
         )
     }
 
-    render() {
-        const {mode} = this.state;
-        return (
-            <PageSection className="kamelet-section designer-page" padding={{default: 'noPadding'}}>
-                <PageSection className="tools-section" padding={{default: 'noPadding'}}
-                             style={{backgroundColor:"transparent", paddingLeft: "var(--pf-v5-c-page__main-section--PaddingLeft)"}}>
-                    <Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
-                        <FlexItem>
-                            <TextContent className="header">
-                                <Text component="h2">Designer</Text>
-                            </TextContent>
-                        </FlexItem>
-                        <FlexItem>
-                            <Toolbar id="toolbar-group-types">
-                                <ToolbarContent>
-                                    <ToolbarItem>
-                                        <ToggleGroup>
-                                            <ToggleGroupItem text="Design" buttonId="design" isSelected={mode === "design"}
-                                                             onChange={(_event, s) => this.setState({mode: "design"})} />
-                                            <ToggleGroupItem text="Code" buttonId="code" isSelected={mode === "code"}
-                                                             onChange={(_event, s) => this.setState({mode: "code"})} />
-                                        </ToggleGroup>
-                                    </ToolbarItem>
-                                    <ToolbarItem>
-                                        <Tooltip content="Download YAML" position={"bottom"}>
-                                            <Button variant="primary" icon={<DownloadIcon/>} onClick={e => this.download()}>
-                                                YAML
-                                            </Button>
-                                        </Tooltip>
-                                    </ToolbarItem>
-                                    <ToolbarItem>
-                                        <Tooltip content="Download image" position={"bottom"}>
-                                            <Button variant="secondary" icon={<DownloadImageIcon/>} onClick={e => this.downloadImage()}>
-                                                Image
-                                            </Button>
-                                        </Tooltip>
-                                    </ToolbarItem>
-                                </ToolbarContent>
-                            </Toolbar>
-                        </FlexItem>
-                    </Flex>
-                </PageSection>
-                {mode === 'design' && this.getDesigner()}
-                {mode === 'code'  && this.getEditor()}
-            </PageSection>
-        );
-    }
+    return (
+        <PageSection className="designer-page" padding={{default: 'noPadding'}}>
+            <div className="tools-section" //padding={{default: 'noPadding'}}
+                 style={{backgroundColor:"transparent", paddingLeft: "var(--pf-v5-c-page__main-section--PaddingLeft)"}}>
+                <Flex className="tools" justifyContent={{default: 'justifyContentSpaceBetween'}}>
+                    <FlexItem>
+                        <TextContent className="header">
+                            <Text component="h2">Designer</Text>
+                        </TextContent>
+                    </FlexItem>
+                    <FlexItem>
+                        <Toolbar id="toolbar-group-types">
+                            <ToolbarContent>
+                                <ToolbarItem>
+                                    <ToggleGroup>
+                                        <ToggleGroupItem text="Design" buttonId="design" isSelected={mode === "design"}
+                                                         onChange={(_event, s) => setMode("design")} />
+                                        <ToggleGroupItem text="Code" buttonId="code" isSelected={mode === "code"}
+                                                         onChange={(_event, s) => setMode("code")} />
+                                    </ToggleGroup>
+                                </ToolbarItem>
+                                <ToolbarItem>
+                                    <Tooltip content="Download YAML" position={"bottom"}>
+                                        <Button variant="primary" icon={<DownloadIcon/>} onClick={e => download()}>
+                                            YAML
+                                        </Button>
+                                    </Tooltip>
+                                </ToolbarItem>
+                                <ToolbarItem>
+                                    <Tooltip content="Download image" position={"bottom"}>
+                                        <Button variant="secondary" icon={<DownloadImageIcon/>} onClick={e => downloadImage()}>
+                                            Image
+                                        </Button>
+                                    </Tooltip>
+                                </ToolbarItem>
+                            </ToolbarContent>
+                        </Toolbar>
+                    </FlexItem>
+                </Flex>
+            </div>
+            {mode === 'design' && getDesigner()}
+            {mode === 'code'  && getEditor()}
+        </PageSection>
+    )
 };
\ No newline at end of file
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx b/karavan-designer/src/designer/KaravanDesigner.tsx
index a2556b2a..b101edd7 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/KaravanDesigner.tsx
@@ -14,10 +14,16 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useEffect, useState} from 'react';
 import {
     Badge,
-    PageSection, PageSectionVariants, Tab, Tabs, TabTitleIcon, TabTitleText, Tooltip,
+    PageSection,
+    PageSectionVariants,
+    Switch,
+    Tab,
+    Tabs,
+    TabTitleIcon, TabTitleText,
+    Tooltip,
 } from '@patternfly/react-core';
 import './karavan.css';
 import {RouteDesigner} from "./route/RouteDesigner";
@@ -25,9 +31,13 @@ import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
 import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelUi} from "./utils/CamelUi";
-import {BeansDesigner} from "./beans/BeansDesigner";
-import {RestDesigner} from "./rest/RestDesigner";
+import {useDesignerStore, useIntegrationStore} from "./KaravanStore";
+import {shallow} from "zustand/shallow";
 import {getDesignerIcon} from "./utils/KaravanIcons";
+import {InfrastructureAPI} from "./utils/InfrastructureAPI";
+import {EventBus, IntegrationUpdate} from "./utils/EventBus";
+import {RestDesigner} from "./rest/RestDesigner";
+import {BeansDesigner} from "./beans/BeansDesigner";
 
 interface Props {
     onSave: (filename: string, yaml: string, propertyOnly: boolean) => void
@@ -36,70 +46,57 @@ interface Props {
     filename: string
     yaml: string
     dark: boolean
+    hideLogDSL?: boolean
     tab?: string
 }
 
-interface State {
-    tab: string
-    integration: Integration
-    key: string
-    propertyOnly: boolean
-}
-
-export class KaravanInstance {
-    static designer: KaravanDesigner;
-
-    static set(designer: KaravanDesigner): void  {
-        KaravanInstance.designer = designer;
-    }
-
-    static get(): KaravanDesigner {
-        return KaravanInstance.designer;
-    }
-
-    static getProps(): Props {
-        return KaravanInstance.designer?.props;
-    }
-}
-
-export class KaravanDesigner extends React.Component<Props, State> {
-
-    getIntegration = (yaml: string, filename: string): Integration => {
-       if (yaml && CamelDefinitionYaml.yamlIsIntegration(yaml)) {
-           return CamelDefinitionYaml.yamlToIntegration(this.props.filename, this.props.yaml)
-       } else {
-           return Integration.createNew(filename, 'plain');
-       }
-    }
-
-    public state: State = {
-        tab: this.props.tab ? this.props.tab : 'routes',
-        integration: this.getIntegration(this.props.yaml, this.props.filename),
-        key: "",
-        propertyOnly: false,
-    }
-
-    componentDidMount() {
-        KaravanInstance.set(this);
-    }
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, this.props.filename, this.getCode(this.state.integration), this.state.propertyOnly);
+export function KaravanDesigner (props: Props) {
+
+    const [tab, setTab] = useState<string>('routes');
+    const [setDark, hideLogDSL, setHideLogDSL, setSelectedStep, reset] = useDesignerStore((s) =>
+        [s.setDark, s.hideLogDSL, s.setHideLogDSL, s.setSelectedStep, s.reset], shallow)
+    const [integration, setIntegration] = useIntegrationStore((s) =>
+        [s.integration, s.setIntegration], shallow)
+
+    useEffect(() => {
+        const sub = EventBus.onIntegrationUpdate()?.subscribe((update: IntegrationUpdate) =>
+            save(update.integration, update.propertyOnly));
+        InfrastructureAPI.setOnSaveCustomCode(props.onSaveCustomCode);
+        InfrastructureAPI.setOnGetCustomCode(props.onGetCustomCode);
+        InfrastructureAPI.setOnSave(props.onSave);
+
+        setSelectedStep(undefined);
+        setIntegration(makeIntegration(props.yaml, props.filename), false);
+        reset();
+        setDark(props.dark);
+        setHideLogDSL(props.hideLogDSL === true);
+        return () => {
+            sub?.unsubscribe();
+            setSelectedStep(undefined);
+            reset();
+        };
+    }, []);
+
+    function makeIntegration(yaml: string, filename: string): Integration {
+        if (yaml && CamelDefinitionYaml.yamlIsIntegration(yaml)) {
+            return CamelDefinitionYaml.yamlToIntegration(props.filename, props.yaml)
+        } else {
+            return Integration.createNew(filename, 'plain');
         }
     }
 
-    save = (integration: Integration, propertyOnly: boolean): void => {
-        this.setState({key: Math.random().toString(), integration: integration, propertyOnly: propertyOnly});
+    function save(integration: Integration, propertyOnly: boolean): void {
+        const code = getCode(integration);
+        props.onSave(props.filename, code, propertyOnly);
     }
 
-    getCode = (integration: Integration): string => {
+    function getCode(integration: Integration): string {
         const clone = CamelUtil.cloneIntegration(integration);
         return CamelDefinitionYaml.integrationToYaml(clone);
     }
 
-    getTab(title: string, tooltip: string, icon: string) {
-        const counts = CamelUi.getFlowCounts(this.state.integration);
+    function getTab(title: string, tooltip: string, icon: string) {
+        const counts = CamelUi.getFlowCounts(integration);
         const count = counts.has(icon) && counts.get(icon) ? counts.get(icon) : undefined;
         const showCount = count && count > 0;
         return (
@@ -115,25 +112,37 @@ export class KaravanDesigner extends React.Component<Props, State> {
         )
     }
 
-    render() {
-        const tab = this.state.tab;
-        return (
-            <PageSection variant={this.props.dark ? PageSectionVariants.darker : PageSectionVariants.light} className="page" isFilled padding={{default: 'noPadding'}}>
-                <Tabs className="main-tabs" activeKey={tab} onSelect={(event, tabIndex) => this.setState({tab: tabIndex.toString()})} style={{width: "100%"}}>
-                    <Tab eventKey='routes' title={this.getTab("Routes", "Integration flows", "routes")}></Tab>
-                    <Tab eventKey='rest' title={this.getTab("REST", "REST services", "rest")}></Tab>
-                    <Tab eventKey='beans' title={this.getTab("Beans", "Beans Configuration", "beans")}></Tab>
+    return (
+        <PageSection variant={props.dark ? PageSectionVariants.darker : PageSectionVariants.light} className="page"
+                     isFilled padding={{default: 'noPadding'}}>
+            <div className={"main-tabs-wrapper"}>
+                <Tabs className="main-tabs"
+                      activeKey={tab}
+                      onSelect={(event, tabIndex) => {
+                          setTab(tabIndex.toString());
+                          setSelectedStep(undefined);
+                      }}
+                      style={{width: "100%"}}>
+                    <Tab eventKey='routes' title={getTab("Routes", "Integration flows", "routes")}></Tab>
+                    <Tab eventKey='rest' title={getTab("REST", "REST services", "rest")}></Tab>
+                    <Tab eventKey='beans' title={getTab("Beans", "Beans Configuration", "beans")}></Tab>
                 </Tabs>
-                    {tab === 'routes' && <RouteDesigner integration={this.state.integration}
-                                                        onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
-                                                        dark={this.props.dark}/>}
-                    {tab === 'rest' && <RestDesigner integration={this.state.integration}
-                                                     onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
-                                                     dark={this.props.dark}/>}
-                    {tab === 'beans' && <BeansDesigner integration={this.state.integration}
-                                                       onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
-                                                       dark={this.props.dark}/>}
-            </PageSection>
-        )
-    }
+                {tab === 'routes' && <Tooltip content={"Hide Log elements"}>
+                    <Switch
+                        isReversed
+                        isChecked={hideLogDSL}
+                        onChange={(_, checked) => {
+                            setHideLogDSL(checked)
+                        }}
+                        id="hideLogDSL"
+                        name="hideLogDSL"
+                        className={"hide-log"}
+                    />
+                </Tooltip>}
+            </div>
+            {tab === 'routes' && <RouteDesigner/>}
+            {tab === 'rest' && <RestDesigner/>}
+            {tab === 'beans' && <BeansDesigner/>}
+        </PageSection>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/KaravanStore.ts b/karavan-designer/src/designer/KaravanStore.ts
new file mode 100644
index 00000000..e524e625
--- /dev/null
+++ b/karavan-designer/src/designer/KaravanStore.ts
@@ -0,0 +1,244 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {DslPosition, EventBus} from "./utils/EventBus";
+import {createWithEqualityFn} from "zustand/traditional";
+import {shallow} from "zustand/shallow";
+
+interface IntegrationState {
+    integration: Integration;
+    json: string;
+    setIntegration: (integration: Integration, propertyOnly: boolean) => void;
+    propertyOnly: boolean;
+    reset: () => void;
+}
+
+export const useIntegrationStore = createWithEqualityFn<IntegrationState>((set) => ({
+    integration: Integration.createNew("demo", "plain"),
+    propertyOnly: false,
+    json: '{}',
+    setIntegration: (integration: Integration, propertyOnly: boolean) => {
+        set((state: IntegrationState) => {
+            const json = JSON.stringify(integration);
+            if (state.json === json) {
+                return {integration: state.integration, propertyOnly: state.propertyOnly, json: state.json};
+            } else {
+                EventBus.sendIntegrationUpdate(integration, propertyOnly);
+                return {integration: integration, propertyOnly: propertyOnly, json: json};
+            }
+        })
+    },
+    reset: () => {
+        set({integration: Integration.createNew("demo", "plain"), json: '{}', propertyOnly: false});
+    }
+}), shallow)
+
+
+interface SelectorStateState {
+    showSelector: boolean;
+    setShowSelector: (showSelector: boolean) => void;
+    showSteps: boolean;
+    setShowSteps: (showSteps: boolean) => void;
+    parentDsl?: string;
+    setParentDsl: (parentDsl?: string) => void;
+    parentId: string;
+    setParentId: (parentId: string) => void;
+    selectorTabIndex?: string | number
+    setSelectorTabIndex: (selectorTabIndex?: string | number) => void;
+    selectedPosition?: number;
+    setSelectedPosition: (selectedPosition?: number) => void;
+    selectedLabels: string [];
+    addSelectedLabel: (label: string) => void;
+    deleteSelectedLabel: (label: string) => void;
+    clearSelectedLabels: () => void;
+}
+
+export const useSelectorStore = createWithEqualityFn<SelectorStateState>((set) => ({
+    showSelector: false,
+    deleteMessage: '',
+    parentId: '',
+    showSteps: true,
+    selectedLabels: [],
+    addSelectedLabel: (label: string) => {
+        set(state => ({
+            selectedLabels: [...state.selectedLabels, label]
+        }))
+    },
+    deleteSelectedLabel: (label: string) => {
+        set(state => ({
+            selectedLabels: [...state.selectedLabels.filter(x => x !== label)]
+        }))
+    },
+    clearSelectedLabels: () => {
+        set((state: SelectorStateState) => {
+            state.selectedLabels.length = 0;
+            return state;
+        })
+    },
+    setSelectedLabels: (selectedLabels: string []) => {
+        set({selectedLabels: selectedLabels})
+    },
+    setSelectorTabIndex: (selectorTabIndex?: string | number) => {
+        set({selectorTabIndex: selectorTabIndex})
+    },
+    setParentDsl: (parentDsl?: string) => {
+        set({parentDsl: parentDsl})
+    },
+    setShowSelector: (showSelector: boolean) => {
+        set({showSelector: showSelector})
+    },
+    setShowSteps: (showSteps: boolean) => {
+        set({showSteps: showSteps})
+    },
+    setParentId: (parentId: string) => {
+        set({parentId: parentId})
+    },
+    setSelectedPosition: (selectedPosition?: number) => {
+        set({selectedPosition: selectedPosition})
+    },
+}), shallow)
+
+
+interface ConnectionsState {
+    steps: Map<string, DslPosition>;
+    addStep: (uuid: string, position: DslPosition) => void;
+    deleteStep: (uuid: string) => void;
+    clearSteps: () => void;
+    setSteps: (steps: Map<string, DslPosition>) => void;
+}
+
+export const useConnectionsStore = createWithEqualityFn<ConnectionsState>((set) => ({
+    steps: new Map<string, DslPosition>(),
+    addStep: (uuid: string, position: DslPosition) => {
+        set(state => ({
+            steps: new Map(state.steps).set(uuid, position),
+        }))
+    },
+    deleteStep: (uuid: string) => {
+        set((state: ConnectionsState) => {
+            // state.steps.clear();
+            Array.from(state.steps.entries())
+                .filter(value => value[1]?.parent?.uuid !== uuid)
+                .forEach(value => state.steps.set(value[0], value[1]));
+            state.steps.delete(uuid)
+            return state;
+        })
+    },
+    clearSteps: () => {
+        set((state: ConnectionsState) => {
+            state.steps.clear();
+            return state;
+        })
+    },
+    setSteps: (steps: Map<string, DslPosition>) => {
+        set({steps: steps})
+    },
+}), shallow)
+
+type DesignerState = {
+    dark: boolean;
+    hideLogDSL: boolean;
+    shiftKeyPressed: boolean;
+    showDeleteConfirmation: boolean;
+    showMoveConfirmation: boolean;
+    deleteMessage: string;
+    selectedStep?: CamelElement;
+    selectedUuids: string[];
+    clipboardSteps: CamelElement[];
+    width: number,
+    height: number,
+    top: number,
+    left: number,
+}
+const designerState: DesignerState = {
+    dark: false,
+    hideLogDSL: false,
+    shiftKeyPressed: false,
+    showDeleteConfirmation: false,
+    showMoveConfirmation: false,
+    deleteMessage: '',
+    selectedUuids: [],
+    clipboardSteps: [],
+    width: 0,
+    height: 0,
+    top: 0,
+    left: 0,
+};
+
+type DesignerAction = {
+    setDark: (dark: boolean) => void;
+    setHideLogDSL: (hideLogDSL: boolean) => void;
+    setShiftKeyPressed: (shiftKeyPressed: boolean) => void;
+    setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => void;
+    setShowMoveConfirmation: (showMoveConfirmation: boolean) => void;
+    setDeleteMessage: (deleteMessage: string) => void;
+    setSelectedStep: (selectedStep?: CamelElement) => void;
+    setSelectedUuids: (selectedUuids: string[]) => void;
+    setClipboardSteps: (clipboardSteps: CamelElement[]) => void;
+    setPosition: (width: number, height: number, top: number, left: number) => void;
+    reset: () => void;
+}
+
+export const useDesignerStore = createWithEqualityFn<DesignerState & DesignerAction>((set) => ({
+    ...designerState,
+    setDark: (dark: boolean) => {
+        set({dark: dark})
+    },
+    setHideLogDSL: (hideLogDSL: boolean) => {
+        set({hideLogDSL: hideLogDSL})
+    },
+    setShiftKeyPressed: (shiftKeyPressed: boolean) => {
+        set({shiftKeyPressed: shiftKeyPressed})
+    },
+    setSelectedStep: (selectedStep?: CamelElement) => {
+        set({selectedStep: selectedStep})
+    },
+    setShowDeleteConfirmation: (showDeleteConfirmation: boolean) => {
+        set({showDeleteConfirmation: showDeleteConfirmation})
+    },
+    setShowMoveConfirmation: (showMoveConfirmation: boolean) => {
+        set({showMoveConfirmation: showMoveConfirmation})
+    },
+    setDeleteMessage: (deleteMessage: string) => {
+        set({deleteMessage: deleteMessage})
+    },
+    setSelectedUuids: (selectedUuids: string[]) => {
+        set((state: DesignerState) => {
+            state.selectedUuids.length = 0;
+            state.selectedUuids.push(...selectedUuids);
+            return state;
+        })
+    },
+    setClipboardSteps: (clipboardSteps: CamelElement[]) => {
+        set((state: DesignerState) => {
+            state.clipboardSteps.length = 0;
+            state.clipboardSteps.push(...clipboardSteps);
+            return state;
+        })
+    },
+    width: 100,
+    height: 100,
+    top: 0,
+    left: 0,
+    setPosition: (width: number, height: number, top: number, left: number) => {
+        set({width: width, height: height, top: top, left: left})
+    },
+    reset: () => {
+        set(designerState);
+    }
+}), shallow)
\ No newline at end of file
diff --git a/karavan-designer/src/designer/MainToolbar.tsx b/karavan-designer/src/designer/MainToolbar.tsx
index ed344840..8923b70c 100644
--- a/karavan-designer/src/designer/MainToolbar.tsx
+++ b/karavan-designer/src/designer/MainToolbar.tsx
@@ -9,7 +9,7 @@ interface Props {
     tools: React.ReactNode;
 }
 
-export const MainToolbar = (props: Props) => {
+export function MainToolbar(props: Props) {
 
     return (
         <PageSection className="tools-section" variant={PageSectionVariants.light}>
diff --git a/karavan-designer/src/designer/beans/BeanCard.tsx b/karavan-designer/src/designer/beans/BeanCard.tsx
index d9eac357..74dd884b 100644
--- a/karavan-designer/src/designer/beans/BeanCard.tsx
+++ b/karavan-designer/src/designer/beans/BeanCard.tsx
@@ -19,47 +19,42 @@ import {
     Button
 } from '@patternfly/react-core';
 import '../karavan.css';
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {RegistryBeanDefinition} from "karavan-core/lib/model/CamelDefinition";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import {useDesignerStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
 
 interface Props {
     bean: RegistryBeanDefinition
-    selectedStep?: RegistryBeanDefinition
-    integration: Integration
     selectElement: (element: RegistryBeanDefinition) => void
     deleteElement: (element: RegistryBeanDefinition) => void
 }
 
-export class BeanCard extends React.Component<Props, any> {
+export function BeanCard (props: Props) {
 
-    selectElement = (evt: React.MouseEvent) => {
+    const [ selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow)
+
+    function selectElement (evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.props.bean);
+        props.selectElement(props.bean);
     }
 
-    delete = (evt: React.MouseEvent) => {
+    function onDelete (evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.bean);
+        props.deleteElement(props.bean);
     }
 
-    render() {
-        const bean = this.props.bean;
-        return (
-            <div className={this.props.selectedStep?.uuid === bean.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"} onClick={e => this.selectElement(e)}>
-                <div className="header">
-                    <div className="title">BEAN</div>
-                    <div className="title">{bean.name}</div>
-                    <div className="description">{bean.type}</div>
-                    {/*<Tooltip position={"bottom"} content={<div>Add REST method</div>}>*/}
-                        {/*<Button variant={"link"} icon={<AddIcon/>} aria-label="Add" onClick={e => this.selectMethod(e)} className="add-button">Add method</Button>*/}
-                    {/*</Tooltip>*/}
-                    <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button>
-                </div>
-                <div className="rest-content" key={Math.random().toString()}>
-
-                </div>
+    const bean = props.bean;
+    return (
+        <div className={selectedStep?.uuid === bean.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"} onClick={e => selectElement(e)}>
+            <div className="header">
+                <div className="title">Bean</div>
+                <div className="title">{bean.name}</div>
+                <div className="description">{bean.type}</div>
+                <Button variant="link" className="delete-button" onClick={e => onDelete(e)}>
+                    <DeleteIcon/>
+                </Button>
             </div>
-        );
-    }
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx b/karavan-designer/src/designer/beans/BeanProperties.tsx
index 4470c01a..b271ce8d 100644
--- a/karavan-designer/src/designer/beans/BeanProperties.tsx
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Form,
     FormGroup,
@@ -31,7 +31,6 @@ import {SensitiveKeys} from "karavan-core/lib/model/CamelMetadata";
 import {v4 as uuidv4} from "uuid";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
 import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
-import {IntegrationHeader} from "../utils/KaravanComponents";
 import CloneIcon from '@patternfly/react-icons/dist/esm/icons/clone-icon'
 import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 import {InfrastructureSelector} from "../route/property/InfrastructureSelector";
@@ -40,6 +39,9 @@ import {InfrastructureAPI} from "../utils/InfrastructureAPI";
 import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
 import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
+import {useDesignerStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {IntegrationHeader} from "../utils/IntegrationHeader";
 
 
 interface Props {
@@ -50,110 +52,95 @@ interface Props {
     onClone: (bean: RegistryBeanDefinition) => void
 }
 
-interface State {
-    bean?: RegistryBeanDefinition
-    properties: Map<string, [string, string, boolean]>
-    key: string,
-    showInfrastructureSelector: boolean
-    infrastructureSelectorUuid?: string
-    infrastructureSelectorProperty?: string
-}
+export function BeanProperties (props: Props) {
 
-export class BeanProperties extends React.Component<Props, State> {
+    const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow);
+    const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false);
+    const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined);
+    const [infrastructureSelectorUuid, setInfrastructureSelectorUuid] = useState<string | undefined>(undefined);
+    const [properties, setProperties] =
+        useState<Map<string, [string, string, boolean]>>(props.bean?.properties ? preparePropertiesMap(props.bean?.properties) : new Map<string, [string, string, boolean]>());
 
-    preparePropertiesMap = (properties: any): Map<string, [string, string, boolean]> => {
+
+    function preparePropertiesMap (properties: any): Map<string, [string, string, boolean]>  {
         const result = new Map<string, [string, string, boolean]>();
         Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k, properties[k], false]));
         return result;
     }
 
-    public state: State = {
-        bean: this.props.bean,
-        key: '',
-        showInfrastructureSelector: false,
-        properties: this.props.bean?.properties ? this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, [string, string, boolean]>()
-    };
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevProps.bean?.uuid !== this.props.bean?.uuid) {
-            this.setBean(this.props.bean);
-        }
-        if (prevState.key !== this.state.key && this.state.bean) {
-            const bean = CamelUtil.cloneBean(this.state.bean);
-            const properties: any = {};
-            this.state.properties.forEach(p => properties[p[0]] = p[1]);
-            bean.properties = properties;
-            this.setState({bean: bean});
-            this.props.onChange?.call(this, bean);
+    function onBeanPropertyUpdate ()  {
+        if (selectedStep) {
+            const bean = CamelUtil.cloneBean(selectedStep);
+            const beanProperties: any = {};
+            properties.forEach((p: any) => beanProperties[p[0]] = p[1]);
+            bean.properties = beanProperties;
+            props.onChange(bean);
         }
     }
 
-    setBean = (bean?: RegistryBeanDefinition) => {
-        this.setState({
-            bean: bean,
-            properties: bean?.properties ? this.preparePropertiesMap(bean.properties) : new Map<string, [string, string, false]>()
-        });
-    }
-
-    beanChanged = (fieldId: string, value: string) => {
-        if (this.state.bean) {
-            const bean = CamelUtil.cloneBean(this.state.bean);
+    function beanFieldChanged (fieldId: string, value: string) {
+        if (selectedStep) {
+            const bean = CamelUtil.cloneBean(selectedStep);
             (bean as any)[fieldId] = value;
-            this.setState({bean: bean});
-            this.props.onChange?.call(this, bean);
+            props.onChange(bean);
         }
     }
 
-    propertyChanged = (uuid: string, key: string, value: string, showPassword: boolean) => {
-        this.setState(state => {
-            state.properties.set(uuid, [key, value, showPassword]);
-            return {properties: state.properties, key: Math.random().toString()};
-        })
+    function propertyChanged (uuid: string, key: string, value: string, showPassword: boolean)  {
+        setProperties(prevState => {
+            prevState.set(uuid, [key, value, showPassword]);
+            return prevState;
+        });
+        onBeanPropertyUpdate();
     }
 
-    propertyDeleted = (uuid: string) => {
-        this.setState(state => {
-            state.properties.delete(uuid);
-            return {properties: state.properties, key: Math.random().toString()};
+    function propertyDeleted (uuid: string)  {
+        setProperties(prevState => {
+            prevState.delete(uuid);
+            return prevState;
         })
+        onBeanPropertyUpdate();
     }
 
-    selectInfrastructure = (value: string) => {
-        const propertyId = this.state.infrastructureSelectorProperty;
-        const uuid = this.state.infrastructureSelectorUuid;
+    function selectInfrastructure (value: string)  {
+        const propertyId = infrastructureSelectorProperty;
+        const uuid = infrastructureSelectorUuid;
         if (propertyId && uuid){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
-            this.propertyChanged(uuid, propertyId, value, false);
-            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
+            propertyChanged(uuid, propertyId, value, false);
+            setInfrastructureSelector(false);
+            setInfrastructureSelectorProperty(undefined);
         }
     }
 
-    openInfrastructureSelector = (uuid: string, propertyName: string) => {
-        this.setState({infrastructureSelectorUuid: uuid, infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
+    function openInfrastructureSelector (uuid: string, propertyName: string)  {
+        setInfrastructureSelector(true);
+        setInfrastructureSelectorProperty(propertyName);
+        setInfrastructureSelectorUuid(uuid);
     }
 
-    closeInfrastructureSelector = () => {
-        this.setState({showInfrastructureSelector: false})
+    function closeInfrastructureSelector ()  {
+        setInfrastructureSelector(false);
     }
 
-    getInfrastructureSelectorModal() {
+    function getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showInfrastructureSelector}
-                onClose={() => this.closeInfrastructureSelector()}
-                onSelect={this.selectInfrastructure}/>)
+                isOpen={infrastructureSelector}
+                onClose={() => closeInfrastructureSelector()}
+                onSelect={selectInfrastructure}/>)
     }
 
-    cloneBean = () => {
-        if (this.state.bean) {
-            const bean = CamelUtil.cloneBean(this.state.bean);
+    function cloneBean ()  {
+        if (selectedStep) {
+            const bean = CamelUtil.cloneBean(selectedStep);
             bean.uuid = uuidv4();
-            this.props.onClone?.call(this, bean);
+            props.onClone(bean);
         }
     }
 
-    getLabelIcon = (displayName: string, description: string) => {
+    function getLabelIcon (displayName: string, description: string)  {
         return (
             <Popover
                     position={"left"}
@@ -174,28 +161,28 @@ export class BeanProperties extends React.Component<Props, State> {
         )
     }
 
-    getBeanForm() {
-        const bean = this.state.bean;
+    function getBeanForm() {
+        const bean = (selectedStep as RegistryBeanDefinition);
         return (
             <>
                 <div className="headers">
                     <div className="top">
                         <Title headingLevel="h1" size="md">Bean</Title>
                         <Tooltip content="Clone bean" position="bottom">
-                            <Button variant="link" onClick={() => this.cloneBean()} icon={<CloneIcon/>}/>
+                            <Button variant="link" onClick={() => cloneBean()} icon={<CloneIcon/>}/>
                         </Tooltip>
                     </div>
                 </div>
-                <FormGroup label="Name" fieldId="name" isRequired labelIcon={this.getLabelIcon("Name", "Bean name used as a reference ex: myBean")}>
+                <FormGroup label="Name" fieldId="name" isRequired labelIcon={getLabelIcon("Name", "Bean name used as a reference ex: myBean")}>
                     <TextInput className="text-field" isRequired type="text" id="name" name="name" value={bean?.name}
-                                onChange={(_, value)=> this.beanChanged("name", value)}/>
+                                onChange={(_, value)=> beanFieldChanged("name", value)}/>
                 </FormGroup>
-                <FormGroup label="Type" fieldId="type" isRequired labelIcon={this.getLabelIcon("Type", "Bean class Canonical Name ex: org.demo.MyBean")}>
+                <FormGroup label="Type" fieldId="type" isRequired labelIcon={getLabelIcon("Type", "Bean class Canonical Name ex: org.demo.MyBean")}>
                     <TextInput className="text-field" isRequired type="text" id="type" name="type" value={bean?.type}
-                        onChange={(_, value) => this.beanChanged("type", value)}/>
+                        onChange={(_, value) => beanFieldChanged("type", value)}/>
                 </FormGroup>
                 <FormGroup label="Properties" fieldId="properties" className="bean-properties">
-                    {Array.from(this.state.properties.entries()).map((v, index, array) => {
+                    {Array.from(properties.entries()).map((v, index, array) => {
                         const i = v[0];
                         const key = v[1][0];
                         const value = v[1][1];
@@ -207,12 +194,12 @@ export class BeanProperties extends React.Component<Props, State> {
                             <div key={"key-" + i} className="bean-property">
                                 <TextInput placeholder="Bean Field Name" className="text-field" isRequired type="text" id="key" name="key" value={key}
                                             onChange={(_, beanFieldName) => {
-                                                this.propertyChanged(i, beanFieldName, value, showPassword)
+                                                propertyChanged(i, beanFieldName, value, showPassword)
                                             }}/>
                                 <InputGroup>
                                     {inInfrastructure &&
                                         <Tooltip position="bottom-end" content="Select value from Infrastructure">
-                                        <Button variant="control" onClick={e => this.openInfrastructureSelector(i, key)}>
+                                        <Button variant="control" onClick={e => openInfrastructureSelector(i, key)}>
                                             {icon}
                                         </Button>
                                     </Tooltip>}
@@ -226,35 +213,34 @@ export class BeanProperties extends React.Component<Props, State> {
                                             name="value"
                                             value={value}
                                             onChange={(_, value) => {
-                                                this.propertyChanged(i, key, value, showPassword)
+                                                propertyChanged(i, key, value, showPassword)
                                             }}/>
                                     </InputGroupItem>
                                     {isSecret && <Tooltip position="bottom-end" content={showPassword ? "Hide" : "Show"}>
-                                        <Button variant="control" onClick={e => this.propertyChanged(i, key, value, !showPassword)}>
+                                        <Button variant="control" onClick={e => propertyChanged(i, key, value, !showPassword)}>
                                             {showPassword ? <ShowIcon/> : <HideIcon/>}
                                         </Button>
                                     </Tooltip>}
                                 </InputGroup>
-                                <Button variant="link" className="delete-button" onClick={e => this.propertyDeleted(i)}><DeleteIcon/></Button>
+                                <Button variant="link" className="delete-button" onClick={e => propertyDeleted(i)}><DeleteIcon/></Button>
                             </div>
                         )
                     })}
-                    <Button variant="link" className="add-button" onClick={e => this.propertyChanged(uuidv4(), '', '', false)}>
+                    <Button variant="link" className="add-button" onClick={e => propertyChanged(uuidv4(), '', '', false)}>
                         <AddIcon/>Add property</Button>
                 </FormGroup>
             </>
         )
     }
 
-    render() {
-        return (
-            <div className='properties' key={this.state.bean ? this.state.bean.uuid : 'integration'}>
-                <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
-                    {this.state.bean === undefined && <IntegrationHeader integration={this.props.integration}/>}
-                    {this.state.bean !== undefined && this.getBeanForm()}
-                </Form>
-                {this.getInfrastructureSelectorModal()}
-            </div>
-        )
-    }
+    const bean = (selectedStep as RegistryBeanDefinition);
+    return (
+        <div className='properties' key={bean ? bean.uuid : 'integration'}>
+            <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
+                {bean === undefined && <IntegrationHeader/>}
+                {bean !== undefined && getBeanForm()}
+            </Form>
+            {getInfrastructureSelectorModal()}
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/beans/BeansDesigner.tsx b/karavan-designer/src/designer/beans/BeansDesigner.tsx
index 2c9a681f..ae603aac 100644
--- a/karavan-designer/src/designer/beans/BeansDesigner.tsx
+++ b/karavan-designer/src/designer/beans/BeansDesigner.tsx
@@ -20,145 +20,114 @@ import {
 } from '@patternfly/react-core';
 import '../karavan.css';
 import {RegistryBeanDefinition} from "karavan-core/lib/model/CamelDefinition";
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelUi} from "../utils/CamelUi";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 import {BeanProperties} from "./BeanProperties";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {BeanCard} from "./BeanCard";
+import {useDesignerStore, useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
 
-interface Props {
-    onSave?: (integration: Integration, propertyOnly: boolean) => void
-    integration: Integration
-    dark: boolean
-}
-
-interface State {
-    integration: Integration
-    showDeleteConfirmation: boolean
-    selectedBean?: RegistryBeanDefinition
-    key: string
-    propertyOnly: boolean
-}
+export function BeansDesigner () {
 
-export class BeansDesigner extends React.Component<Props, State> {
+    const [integration, setIntegration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
+    const [dark, selectedStep, showDeleteConfirmation, setShowDeleteConfirmation, setSelectedStep] = useDesignerStore((s) =>
+        [s.dark, s.selectedStep, s.showDeleteConfirmation, s.setShowDeleteConfirmation, s.setSelectedStep], shallow)
 
-    public state: State = {
-        integration: this.props.integration,
-        showDeleteConfirmation: false,
-        key: "",
-        propertyOnly: false
-    };
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, this.state.integration, this.state.propertyOnly);
-        }
-    }
 
-    showDeleteConfirmation = (bean: RegistryBeanDefinition) => {
-        this.setState({selectedBean: bean, showDeleteConfirmation: true});
+    function onShowDeleteConfirmation (bean: RegistryBeanDefinition) {
+        setSelectedStep(bean);
+        setShowDeleteConfirmation(true);
     }
 
-    onIntegrationUpdate = (i: Integration) => {
-        this.setState({integration: i, propertyOnly: false, showDeleteConfirmation: false, key: Math.random().toString()});
+    function deleteBean () {
+        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(integration, selectedStep);
+        setIntegration(i, false);
+        setShowDeleteConfirmation(false);
+        setSelectedStep(undefined);
     }
 
-    deleteBean = () => {
-        const i = CamelDefinitionApiExt.deleteBeanFromIntegration(this.state.integration, this.state.selectedBean);
-        this.setState({
-            integration: i,
-            showDeleteConfirmation: false,
-            key: Math.random().toString(),
-            selectedBean: new RegistryBeanDefinition(),
-            propertyOnly: false
-        });
-    }
-
-    changeBean = (bean: RegistryBeanDefinition) => {
-        const clone = CamelUtil.cloneIntegration(this.state.integration);
+    function changeBean (bean: RegistryBeanDefinition) {
+        const clone = CamelUtil.cloneIntegration(integration);
         const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
-        this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), selectedBean: bean});
+        setIntegration(i, false);
+        setSelectedStep(bean);
     }
 
-    getDeleteConfirmation() {
+    function getDeleteConfirmation() {
         return (<Modal
             className="modal-delete"
             title="Confirmation"
-            isOpen={this.state.showDeleteConfirmation}
-            onClose={() => this.setState({showDeleteConfirmation: false})}
+            isOpen={showDeleteConfirmation}
+            onClose={() => setShowDeleteConfirmation(false)}
             actions={[
-                <Button key="confirm" variant="primary" onClick={e => this.deleteBean()}>Delete</Button>,
+                <Button key="confirm" variant="primary" onClick={e => deleteBean()}>Delete</Button>,
                 <Button key="cancel" variant="link"
-                        onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
+                        onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
             ]}
-            onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
+            onEscapePress={e => setShowDeleteConfirmation(false)}>
             <div>
                 Delete bean from integration?
             </div>
         </Modal>)
     }
 
-    selectBean = (bean?: RegistryBeanDefinition) => {
-        this.setState({selectedBean: bean})
+    function selectBean (bean?: RegistryBeanDefinition) {
+        setSelectedStep(bean);
     }
 
-    unselectBean = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
+    function unselectBean (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) {
         if ((evt.target as any).dataset.click === 'BEANS') {
             evt.stopPropagation()
-            this.setState({selectedBean: undefined})
+            setSelectedStep(undefined);
         }
     };
 
-    createBean = () => {
-        this.changeBean(new RegistryBeanDefinition());
+    function createBean () {
+        changeBean(new RegistryBeanDefinition());
     }
 
-    getPropertiesPanel() {
+    function getPropertiesPanel() {
         return (
             <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'} maxSize={'800px'} minSize={'300px'}>
-                <BeanProperties integration={this.props.integration}
-                                bean={this.state.selectedBean}
-                                dark={this.props.dark}
-                                onChange={this.changeBean}
-                                onClone={this.changeBean}/>
+                <BeanProperties integration={integration}
+                                bean={selectedStep}
+                                dark={dark}
+                                onChange={changeBean}
+                                onClone={changeBean}/>
             </DrawerPanelContent>
         )
     }
 
-    render() {
-        const beans = CamelUi.getBeans(this.state.integration);
-        return (
-            <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}>
-                <div className="rest-page-columns">
-                    <Drawer isExpanded isInline>
-                        <DrawerContent panelContent={this.getPropertiesPanel()}>
-                            <DrawerContentBody>
-                                <div className="graph" data-click="REST"  onClick={event => this.unselectBean(event)}>
-                                    <div className="flows">
-                                        {beans?.map(bean => <BeanCard key={bean.uuid + this.state.key}
-                                                                      selectedStep={this.state.selectedBean}
-                                                                      bean={bean}
-                                                                      integration={this.props.integration}
-                                                                      selectElement={this.selectBean}
-                                                                      deleteElement={this.showDeleteConfirmation}/>)}
-                                        <div className="add-rest">
-                                            <Button
-                                                variant={beans?.length === 0 ? "primary" : "secondary"}
-                                                data-click="ADD_REST"
-                                                icon={<PlusIcon/>}
-                                                onClick={e => this.createBean()}>Create bean
-                                            </Button>
-                                        </div>
+    const beans = CamelUi.getBeans(integration);
+    return (
+        <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}>
+            <div className="rest-page-columns">
+                <Drawer isExpanded isInline>
+                    <DrawerContent panelContent={getPropertiesPanel()}>
+                        <DrawerContentBody>
+                            <div className="graph" data-click="REST"  onClick={event => unselectBean(event)}>
+                                <div className="flows">
+                                    {beans?.map((bean, index) => <BeanCard key={bean.uuid + index}
+                                                                  bean={bean}
+                                                                  selectElement={selectBean}
+                                                                  deleteElement={onShowDeleteConfirmation}/>)}
+                                    <div className="add-rest">
+                                        <Button
+                                            variant={beans?.length === 0 ? "primary" : "secondary"}
+                                            data-click="ADD_REST"
+                                            icon={<PlusIcon/>}
+                                            onClick={e => createBean()}>Create bean
+                                        </Button>
                                     </div>
                                 </div>
-                            </DrawerContentBody>
-                        </DrawerContent>
-                    </Drawer>
-                </div>
-                {this.getDeleteConfirmation()}
-            </PageSection>
-        )
-    }
+                            </div>
+                        </DrawerContentBody>
+                    </DrawerContent>
+                </Drawer>
+            </div>
+            {getDeleteConfirmation()}
+        </PageSection>
+    )
 }
diff --git a/karavan-designer/src/designer/karavan.css b/karavan-designer/src/designer/karavan.css
index 049e4e7a..72597f22 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -34,6 +34,11 @@
     height: 36px;
 }
 
+.karavan .pf-v5-c-switch__input:focus ~ .pf-v5-c-switch__toggle {
+    outline: transparent;
+    outline-offset: 0;
+}
+
 .karavan .header-button {
     margin-left: var(--pf-v5-c-page__header-tools--MarginRight);
 }
@@ -231,10 +236,13 @@
     flex-direction: column;
 }
 
+.karavan main {
+    overflow: hidden;
+}
+
 /*DSL*/
 .karavan .dsl-page {
-    flex: 1;
-    overflow: auto;
+    height: 100%;
 }
 
 .karavan .dsl-page .dsl-page-columns {
@@ -247,12 +255,31 @@
     height: 24px;
 }
 
-.karavan .main-tabs .top-menu-item {
+.karavan .designer-page .main-tabs-wrapper {
     display: flex;
     flex-direction: row;
+    justify-content: space-between;
+    align-items: center;
+    position: relative;
 }
 
-.karavan .main-tabs .top-menu-item .count {
+.karavan .designer-page .main-tabs-wrapper::before {
+    content: "";
+    position: absolute;
+    right: 0;
+    bottom: 0;
+    left: 0;
+    border: solid;
+    border-width: 0 0 var(--pf-v5-global--BorderWidth--sm) 0;
+    border-bottom-color: var(--pf-v5-global--BorderColor--100);
+}
+
+.karavan .designer-page .main-tabs-wrapper .main-tabs .top-menu-item {
+    display: flex;
+    flex-direction: row;
+}
+
+.karavan .designer-page .main-tabs-wrapper .main-tabs .top-menu-item .count {
     background: var(--pf-v5-global--active-color--100);
     color: white;
     height: fit-content;
@@ -261,12 +288,12 @@
     min-width: 0px;
 }
 
-.karavan .main-tabs .pf-v5-c-tabs__link .pf-v5-c-tabs__item-icon {
+.karavan .designer-page .main-tabs-wrapper .main-tabs .pf-v5-c-tabs__link .pf-v5-c-tabs__item-icon {
     height: 24px;
     margin-right: 0;
 }
 
-.karavan .main-tabs .pf-v5-c-tabs__item-text {
+.karavan .designer-page .main-tabs-wrapper .main-tabs .pf-v5-c-tabs__item-text {
     font-size: 14px;
     font-weight: bold;
     margin-top: auto;
@@ -274,6 +301,11 @@
     margin-right: 6px;
 }
 
+.karavan .designer-page .page .main-tabs-wrapper .hide-log {
+    white-space: nowrap;
+    margin-right: 16px;
+}
+
 /*Properties*/
 .karavan .properties {
     border: 1px solid #eee;
@@ -551,8 +583,8 @@
 
 .karavan .dsl-page .flows {
     width: 100%;
-    position: relative;
-    margin-bottom: 80px;
+    position: absolute;
+    /*margin-bottom: 80px;*/
 }
 
 .karavan .dsl-page .flows .add-flow {
@@ -1384,6 +1416,9 @@
 
 .karavan .designer-page {
     background-color: white;
+    display: flex;
+    flex-direction: column;
+    height: 100%;
 }
 
 .karavan .designer-page .project-page-section {
diff --git a/karavan-designer/src/designer/rest/RestCard.tsx b/karavan-designer/src/designer/rest/RestCard.tsx
index e4e487f7..5177f41c 100644
--- a/karavan-designer/src/designer/rest/RestCard.tsx
+++ b/karavan-designer/src/designer/rest/RestCard.tsx
@@ -20,7 +20,7 @@ import {
 } from '@patternfly/react-core';
 import '../karavan.css';
 import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {RestDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {GetDefinition, RestDefinition} from "karavan-core/lib/model/CamelDefinition";
 import {RestMethodCard} from "./RestMethodCard";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
 import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
@@ -34,45 +34,76 @@ interface Props {
     deleteElement: (element: CamelElement) => void
 }
 
-export class RestCard extends React.Component<Props, any> {
+export function RestCard(props: Props) {
 
-    selectElement = (evt: React.MouseEvent) => {
+    function selectElement(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.props.rest);
+        props.selectElement(props.rest);
     }
 
-    selectMethod = (evt: React.MouseEvent) => {
+    function selectMethod(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectMethod.call(this, this.props.rest);
+        props.selectMethod(props.rest);
     }
 
-    delete = (evt: React.MouseEvent) => {
+    function onDelete(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.rest);
+        props.deleteElement(props.rest);
     }
 
-    render() {
-        const rest = this.props.rest;
-        return (
-            <div className={this.props.selectedStep?.uuid === rest.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"} onClick={e => this.selectElement(e)}>
-                <div className="header">
-                    <div className="title">REST</div>
-                    <div className="title">{rest.path}</div>
-                    <div className="description">{rest.description}</div>
-                    <Tooltip position={"bottom"} content={<div>Add REST method</div>}>
-                        <Button variant={"link"} icon={<AddIcon/>} aria-label="Add" onClick={e => this.selectMethod(e)} className="add-button">Add method</Button>
-                    </Tooltip>
-                    <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button>
-                </div>
-                <div className="rest-content" key={Math.random().toString()}>
-                    {rest.get?.map(get => <RestMethodCard key={get.uuid} method={get} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                    {rest.post?.map(post => <RestMethodCard key={post.uuid} method={post} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                    {rest.put?.map(put => <RestMethodCard key={put.uuid} method={put} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                    {rest.patch?.map(patch => <RestMethodCard key={patch.uuid} method={patch} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                    {rest.delete?.map(del => <RestMethodCard key={del.uuid} method={del} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                    {rest.head?.map(head => <RestMethodCard key={head.uuid} method={head} selectedStep={this.props.selectedStep} integration={this.props.integration} selectElement={this.props.selectElement} deleteElement={this.props.deleteElement}/>)}
-                </div>
+    const rest = props.rest;
+    return (
+        <div
+            className={props.selectedStep?.uuid === rest.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"}
+            onClick={e => selectElement(e)}>
+            <div className="header">
+                <div className="title">REST</div>
+                <div className="title">{rest.path}</div>
+                <div className="description">{rest.description}</div>
+                <Tooltip position={"bottom"} content={<div>Add REST method</div>}>
+                    <Button variant={"link"} icon={<AddIcon/>} aria-label="Add" onClick={e => selectMethod(e)}
+                            className="add-button">Add method</Button>
+                </Tooltip>
+                <Button variant="link" className="delete-button" onClick={e => onDelete(e)}><DeleteIcon/></Button>
             </div>
-        );
-    }
+            <div className="rest-content" key={Math.random().toString()}>
+                {rest.get?.map((get: GetDefinition) =>
+                    <RestMethodCard key={get.uuid}
+                                    method={get}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+                {rest.post?.map(post =>
+                    <RestMethodCard key={post.uuid}
+                                    method={post}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+                {rest.put?.map(put =>
+                    <RestMethodCard key={put.uuid}
+                                    method={put}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+                {rest.patch?.map(patch =>
+                    <RestMethodCard key={patch.uuid}
+                                    method={patch}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+                {rest.delete?.map(del =>
+                    <RestMethodCard key={del.uuid}
+                                    method={del}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+                {rest.head?.map(head =>
+                    <RestMethodCard key={head.uuid}
+                                    method={head}
+                                    selectElement={props.selectElement}
+                                    deleteElement={props.deleteElement}
+                    />)}
+            </div>
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/rest/RestConfigurationCard.tsx b/karavan-designer/src/designer/rest/RestConfigurationCard.tsx
index c05dc4ff..8c7ba2ff 100644
--- a/karavan-designer/src/designer/rest/RestConfigurationCard.tsx
+++ b/karavan-designer/src/designer/rest/RestConfigurationCard.tsx
@@ -17,52 +17,43 @@
 import React from 'react';
 import {Button} from '@patternfly/react-core';
 import '../karavan.css';
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
 import {RestConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition";
 
 interface Props {
     restConfig: RestConfigurationDefinition
     selectedRestConfig?: CamelElement
-    integration: Integration
     selectElement: (element: CamelElement) => void
     deleteElement: (element: CamelElement) => void
 }
 
-interface State {
-    restConfig: RestConfigurationDefinition
-    expanded: boolean
-}
-
-export class RestConfigurationCard extends React.Component<Props, State> {
+export function RestConfigurationCard (props: Props) {
 
-    public state: State = {
-        restConfig: this.props.restConfig,
-        expanded: false
-    };
-
-    selectElement = (evt: React.MouseEvent) => {
+    function selectElement(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.state.restConfig);
+        props.selectElement(props.restConfig);
     }
 
-    delete = (evt: React.MouseEvent) => {
+    function onDelete(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.restConfig);
+        props.deleteElement(props.restConfig);
     }
 
-    render() {
-        const restConfig = this.state.restConfig;
-        const desc = restConfig.host && restConfig.port
-            ? restConfig.host + ":" + restConfig.port
-            : (restConfig.host ? restConfig.host : "") + (restConfig.port ? restConfig.port : "");
-        return (
-            <div className={this.props.selectedRestConfig?.uuid === restConfig.uuid ? "rest-config-card rest-config-card-selected" : "rest-config-card rest-config-card-unselected"} onClick={e => this.selectElement(e)}>
-                <div className="title">Configuration</div>
-                <div className="title">{restConfig.contextPath}</div>
-                <div className="description">{desc}</div>
-                <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button>
-            </div>
-        );
-    }
+    const restConfig = props.restConfig;
+    const desc = restConfig.host && restConfig.port
+        ? restConfig.host + ":" + restConfig.port
+        : (restConfig.host ? restConfig.host : "") + (restConfig.port ? restConfig.port : "");
+    return (
+        <div className={props.selectedRestConfig?.uuid === restConfig.uuid ? "rest-config-card rest-config-card-selected" : "rest-config-card rest-config-card-unselected"} 
+             onClick={e => selectElement(e)}>
+            <div className="title">Configuration</div>
+            <div className="title">{restConfig.contextPath}</div>
+            <div className="description">{desc}</div>
+            <Button variant="link" className="delete-button"
+                    onClick={e => onDelete(e)}>
+                <DeleteIcon/>
+            </Button>
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx b/karavan-designer/src/designer/rest/RestDesigner.tsx
index d13d07e6..7d1508ff 100644
--- a/karavan-designer/src/designer/rest/RestDesigner.tsx
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -20,9 +20,8 @@ import {
     PageSection
 } from '@patternfly/react-core';
 import '../karavan.css';
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {DslProperties} from "../route/DslProperties";
-import {RouteToCreate} from "../utils/CamelUi";
 import {RestCard} from "./RestCard";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {RestConfigurationDefinition, RestContextRefDefinition, RestDefinition} from "karavan-core/lib/model/CamelDefinition";
@@ -33,259 +32,205 @@ import {DslMetaModel} from "../utils/DslMetaModel";
 import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
 import {RestConfigurationCard} from "./RestConfigurationCard";
 import {v4 as uuidv4} from "uuid";
+import {useDesignerStore, useIntegrationStore, useSelectorStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
 
-interface Props {
-    onSave?: (integration: Integration, propertyOnly: boolean) => void
-    integration: Integration
-    dark: boolean
-}
-
-interface State {
-    integration: Integration
-    selectedStep?: CamelElement
-    key: string
-    showSelector: boolean
-    showDeleteConfirmation: boolean
-    propertyOnly: boolean
-}
-
-export class RestDesigner extends React.Component<Props, State> {
-
-    public state: State = {
-        integration: this.props.integration,
-        key: "",
-        showSelector: false,
-        showDeleteConfirmation: false,
-        propertyOnly: false
-    };
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, this.state.integration, this.state.propertyOnly);
-        }
-    }
+export function RestDesigner() {
 
-    onIntegrationUpdate = (i: Integration) => {
-        this.setState({integration: i, showSelector: false, key: Math.random().toString(), propertyOnly: false});
-    }
-
-    selectElement = (element: CamelElement) => {
-        this.setState({selectedStep: element})
-    }
+    const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow)
+    const [dark, selectedStep, showDeleteConfirmation, setShowDeleteConfirmation, setPosition, width, height, top, left, hideLogDSL, setSelectedStep] = useDesignerStore((s) =>
+        [s.dark, s.selectedStep, s.showDeleteConfirmation, s.setShowDeleteConfirmation, s.setPosition, s.width, s.height, s.top, s.left, s.hideLogDSL, s.setSelectedStep], shallow)
 
-    onPropertyUpdate = (element: CamelElement, newRoute?: RouteToCreate) => {
-        if (newRoute) {
-            let i = CamelDefinitionApiExt.updateIntegrationRestElement(this.state.integration, element);
-            const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName + ":" + newRoute.name})
-            const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
-            i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
-            const clone = CamelUtil.cloneIntegration(i);
-            this.setState({
-                integration: clone,
-                key: Math.random().toString(),
-                showSelector: false,
-                selectedStep: element,
-                propertyOnly: false
-            });
-        } else {
-            const clone = CamelUtil.cloneIntegration(this.state.integration);
-            const i = CamelDefinitionApiExt.updateIntegrationRestElement(clone, element);
-            this.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
-        }
+    const [showSelector, setShowSelector] = useSelectorStore((s) => [s.showSelector, s.setShowSelector], shallow)
+    
+    function selectElement (element: CamelElement) {
+        setSelectedStep(element);
     }
 
-    unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
+    function unselectElement (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) {
         if ((evt.target as any).dataset.click === 'REST') {
             evt.stopPropagation()
-            this.setState({selectedStep: undefined,})
+            setSelectedStep(undefined);
         }
     }
 
-    addRest = (rest: RestDefinition) => {
-        const clone = CamelUtil.cloneIntegration(this.state.integration);
+    function addRest (rest: RestDefinition) {
+        const clone = CamelUtil.cloneIntegration(integration);
         const i = CamelDefinitionApiExt.addRestToIntegration(clone, rest);
-        this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), selectedStep: rest});
+        setIntegration(i, false);
+        setSelectedStep(rest);
     }
 
-    createRest = () => {
-        this.addRest(new RestDefinition());
+    function createRest () {
+        addRest(new RestDefinition());
     }
 
-    createRestConfiguration = () => {
-        this.addRest(new RestConfigurationDefinition());
+    function createRestConfiguration () {
+        addRest(new RestConfigurationDefinition());
     }
 
-    showDeleteConfirmation = (element: CamelElement) => {
-        this.setState({selectedStep: element, showSelector: false, showDeleteConfirmation: true});
+    function onShowDeleteConfirmation (element: CamelElement) {
+        setSelectedStep(element);
+        setShowDeleteConfirmation(true);
     }
 
-    deleteElement = () => {
-        const step = this.state.selectedStep;
-        if (step) {
+    function deleteElement () {
+        if (selectedStep) {
             let i;
-            if (step.dslName === 'RestDefinition') i = CamelDefinitionApiExt.deleteRestFromIntegration(this.state.integration, step.uuid);
-            else if (step.dslName === 'RestConfigurationDefinition') i = CamelDefinitionApiExt.deleteRestConfigurationFromIntegration(this.state.integration);
-            else i = CamelDefinitionApiExt.deleteRestMethodFromIntegration(this.state.integration, step.uuid);
-            this.setState({
-                integration: i,
-                showSelector: false,
-                showDeleteConfirmation: false,
-                key: Math.random().toString(),
-                selectedStep: undefined,
-                propertyOnly: false
-            });
+            if (selectedStep.dslName === 'RestDefinition') i = CamelDefinitionApiExt.deleteRestFromIntegration(integration, selectedStep.uuid);
+            else if (selectedStep.dslName === 'RestConfigurationDefinition') i = CamelDefinitionApiExt.deleteRestConfigurationFromIntegration(integration);
+            else i = CamelDefinitionApiExt.deleteRestMethodFromIntegration(integration, selectedStep.uuid);
+            setIntegration(i, false);
+            setSelectedStep(undefined);
+            setShowDeleteConfirmation(false);
         }
     }
 
-    getDeleteConfirmation() {
+    function getDeleteConfirmation() {
         return (<Modal
             className="modal-delete"
             title="Confirmation"
-            isOpen={this.state.showDeleteConfirmation}
-            onClose={() => this.setState({showDeleteConfirmation: false})}
+            isOpen={showDeleteConfirmation}
+            onClose={() => setShowDeleteConfirmation(false)}
             actions={[
-                <Button key="confirm" variant="primary" onClick={e => this.deleteElement()}>Delete</Button>,
+                <Button key="confirm" variant="primary" onClick={e => deleteElement()}>Delete</Button>,
                 <Button key="cancel" variant="link"
-                        onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
+                        onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
             ]}
-            onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
+            onEscapePress={e => setShowDeleteConfirmation(false)}>
             <div>
                 Delete element from integration?
             </div>
         </Modal>)
     }
 
-    closeMethodSelector = () => {
-        this.setState({showSelector: false})
+    function closeMethodSelector () {
+        setShowSelector(false);
     }
 
-    onMethodSelect = (method: DslMetaModel) => {
-        if (this.state.selectedStep) {
-            const clone = CamelUtil.cloneIntegration(this.state.integration);
+    function onMethodSelect (method: DslMetaModel) {
+        if (selectedStep) {
+            const clone = CamelUtil.cloneIntegration(integration);
             const m = CamelDefinitionApi.createStep(method.dsl, {});
-            const i = CamelDefinitionApiExt.addRestMethodToIntegration(clone, m, this.state.selectedStep?.uuid);
-            this.setState({integration: i, key: Math.random().toString(), selectedStep: m, showSelector: false});
+            const i = CamelDefinitionApiExt.addRestMethodToIntegration(clone, m, selectedStep?.uuid);
+            setIntegration(i, false);
+            setSelectedStep(m);
+            setShowSelector(false);
         }
     }
 
-    cloneRest = (rest: CamelElement) => {
+    function cloneRest (rest: CamelElement) {
         if (rest.dslName === 'RestDefinition'){
             const cloneRest = CamelUtil.cloneStep(rest);
             cloneRest.uuid = uuidv4();
-            const cloneIntegration = CamelUtil.cloneIntegration(this.state.integration);
+            const cloneIntegration = CamelUtil.cloneIntegration(integration);
             const i = CamelDefinitionApiExt.addRestToIntegration(cloneIntegration, cloneRest);
-            this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), selectedStep: cloneRest});
+            setIntegration(i, false);
+            setSelectedStep(cloneRest);
         } else if (rest.dslName === 'RestConfigurationDefinition') {
             // could be only one RestConfigurationDefinition
-        } else if (this.state.selectedStep) {
-            const parentId = CamelDefinitionApiExt.findRestMethodParent(this.state.integration, rest);
+        } else if (selectedStep) {
+            const parentId = CamelDefinitionApiExt.findRestMethodParent(integration, rest);
             if (parentId){
                 const cloneRest = CamelUtil.cloneStep(rest);
                 cloneRest.uuid = uuidv4();
-                const cloneIntegration = CamelUtil.cloneIntegration(this.state.integration);
+                const cloneIntegration = CamelUtil.cloneIntegration(integration);
                 const i = CamelDefinitionApiExt.addRestMethodToIntegration(cloneIntegration, cloneRest, parentId);
-                this.setState({integration: i, key: Math.random().toString(), selectedStep: cloneRest, showSelector: false});
+                setIntegration(i, false);
+                setSelectedStep(cloneRest);
             }
         }
     }
 
-    selectMethod = (element: CamelElement) => {
-        this.setState({selectedStep: element, showSelector: true})
+    function selectMethod (element: CamelElement) {
+        setSelectedStep(element);
+        setShowSelector(true);
     }
 
-    getSelectorModal() {
+    function getSelectorModal() {
         return (
             <Modal
                 title="Select method"
                 width={'90%'}
                 className='dsl-modal'
-                isOpen={this.state.showSelector}
-                onClose={() => this.closeMethodSelector()}
+                isOpen={showSelector}
+                onClose={() => closeMethodSelector()}
                 actions={{}}>
-                <RestMethodSelector
-                    dark={this.props.dark}
-                    onMethodSelect={this.onMethodSelect}/>
+                <RestMethodSelector onMethodSelect={onMethodSelect}/>
             </Modal>)
     }
 
-    getRestConfigurationCard(config: RestContextRefDefinition) {
+    function getRestConfigurationCard(config: RestContextRefDefinition) {
         return (<>
             <RestConfigurationCard key={Math.random().toString()}
-                                   selectedRestConfig={this.state.selectedStep}
+                                   selectedRestConfig={selectedStep}
                                    restConfig={config}
-                                   integration={this.props.integration}
-                                   selectElement={this.selectElement}
-                                   deleteElement={this.showDeleteConfirmation}/>
+                                   selectElement={selectElement}
+                                   deleteElement={onShowDeleteConfirmation}/>
         </>)
     }
 
-    getRestCards(data: RestDefinition[]) {
+    function getRestCards(data: RestDefinition[]) {
         return (<>
-            {data?.map(rest => <RestCard key={rest.uuid + this.state.key}
-                                         selectedStep={this.state.selectedStep}
+            {data?.map((rest, index) =>
+                <RestCard key={rest.uuid + index}
+                                         selectedStep={selectedStep}
                                          rest={rest}
-                                         integration={this.props.integration}
-                                         selectMethod={this.selectMethod}
-                                         selectElement={this.selectElement}
-                                         deleteElement={this.showDeleteConfirmation}/>)}
+                                         integration={integration}
+                                         selectMethod={selectMethod}
+                                         selectElement={selectElement}
+                                         deleteElement={onShowDeleteConfirmation}
+                />
+            )}
         </>)
     }
 
 
-    getPropertiesPanel() {
+    function getPropertiesPanel() {
         return (
             <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'} maxSize={'800px'} minSize={'300px'}>
-                <DslProperties
-                    integration={this.props.integration}
-                    step={this.state.selectedStep}
-                    onIntegrationUpdate={this.onIntegrationUpdate}
-                    onPropertyUpdate={this.onPropertyUpdate}
-                    isRouteDesigner={false}
-                    onClone={this.cloneRest}
-                    dark={this.props.dark}/>
+                <DslProperties isRouteDesigner={false}/>
             </DrawerPanelContent>
         )
     }
 
-    render() {
-        const data = this.props.integration.spec.flows?.filter(f => f.dslName === 'RestDefinition');
-        const configData = this.props.integration.spec.flows?.filter(f => f.dslName === 'RestConfigurationDefinition');
-        const config = configData && Array.isArray(configData) ? configData[0] : undefined;
-        return (
-            <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}>
-                <div className="rest-page-columns">
-                    <Drawer isExpanded isInline>
-                        <DrawerContent panelContent={this.getPropertiesPanel()}>
-                            <DrawerContentBody>
-                                <div className="graph" data-click="REST" onClick={event => this.unselectElement(event)}>
-                                    <div className="flows">
-                                        {config && this.getRestConfigurationCard(config)}
-                                        {data && this.getRestCards(data)}
-                                        <div className="add-rest">
+    const data = integration.spec.flows?.filter(f => f.dslName === 'RestDefinition');
+    const configData = integration.spec.flows?.filter(f => f.dslName === 'RestConfigurationDefinition');
+    const config = configData && Array.isArray(configData) ? configData[0] : undefined;
+    return (
+        <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}>
+            <div className="rest-page-columns">
+                <Drawer isExpanded isInline>
+                    <DrawerContent panelContent={getPropertiesPanel()}>
+                        <DrawerContentBody>
+                            <div className="graph" data-click="REST" onClick={event => unselectElement(event)}>
+                                <div className="flows">
+                                    {config && getRestConfigurationCard(config)}
+                                    {data && getRestCards(data)}
+                                    <div className="add-rest">
+                                        <Button
+                                            variant={data?.length === 0 ? "primary" : "secondary"}
+                                            data-click="ADD_REST"
+                                            icon={<PlusIcon/>}
+                                            onClick={e => createRest()}>Create service
+                                        </Button>
+                                        {config === undefined &&
                                             <Button
-                                                variant={data?.length === 0 ? "primary" : "secondary"}
-                                                data-click="ADD_REST"
+                                                variant="secondary"
+                                                data-click="ADD_REST_REST_CONFIG"
                                                 icon={<PlusIcon/>}
-                                                onClick={e => this.createRest()}>Create service
+                                                onClick={e => createRestConfiguration()}>Create configuration
                                             </Button>
-                                            {config === undefined &&
-                                                <Button
-                                                    variant="secondary"
-                                                    data-click="ADD_REST_REST_CONFIG"
-                                                    icon={<PlusIcon/>}
-                                                    onClick={e => this.createRestConfiguration()}>Create configuration
-                                                </Button>
-                                            }
-                                        </div>
+                                        }
                                     </div>
                                 </div>
-                            </DrawerContentBody>
-                        </DrawerContent>
-                    </Drawer>
-                </div>
-                {this.getSelectorModal()}
-                {this.getDeleteConfirmation()}
-            </PageSection>
-        )
-    }
+                            </div>
+                        </DrawerContentBody>
+                    </DrawerContent>
+                </Drawer>
+            </div>
+            {getSelectorModal()}
+            {getDeleteConfirmation()}
+        </PageSection>
+    )
 }
diff --git a/karavan-designer/src/designer/rest/RestMethodCard.tsx b/karavan-designer/src/designer/rest/RestMethodCard.tsx
index b1a5cdc1..f27e364c 100644
--- a/karavan-designer/src/designer/rest/RestMethodCard.tsx
+++ b/karavan-designer/src/designer/rest/RestMethodCard.tsx
@@ -17,50 +17,40 @@
 import React from 'react';
 import {Button} from '@patternfly/react-core';
 import '../karavan.css';
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import {useDesignerStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
 
-interface Props<T> {
+interface Props<T extends CamelElement> {
     method: T
-    selectedStep?: CamelElement
-    integration: Integration
     selectElement: (element: CamelElement) => void
     deleteElement: (element: CamelElement) => void
 }
 
-interface State<T> {
-    method: T
-    expanded: boolean
-}
-
-export class RestMethodCard extends React.Component<Props<any>, State<any>> {
+export function RestMethodCard<T extends CamelElement> (props: Props<T>) {
 
-    public state: State<any> = {
-        method: this.props.method,
-        expanded: false
-    };
+    const [selectedStep] = useDesignerStore((s) => [s.selectedStep], shallow)
 
-    selectElement = (evt: React.MouseEvent) => {
+    function selectElement (evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.state.method);
+        props.selectElement(props.method);
     }
 
-    delete = (evt: React.MouseEvent) => {
+    function onDelete (evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.method);
+        props.deleteElement(props.method);
     }
 
-    render() {
-        const method = this.state.method;
-        return (
-            <div className={this.props.selectedStep?.uuid === method.uuid ? "method-card method-card-selected" : "method-card method-card-unselected"} onClick={e => this.selectElement(e)}>
-                <div className="method">{method.dslName.replace('Definition', '').toUpperCase()}</div>
-                <div className="rest-method-desc">
-                    <div className="title">{method.path}</div>
-                    <div className="description">{method.description}</div>
-                </div>
-                <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button>
+    const method: any = props.method;
+    return (
+        <div className={selectedStep?.uuid === method.uuid ? "method-card method-card-selected" : "method-card method-card-unselected"} onClick={e => selectElement(e)}>
+            <div className="method">{method.dslName.replace('Definition', '').toUpperCase()}</div>
+            <div className="rest-method-desc">
+                <div className="title">{method.path}</div>
+                <div className="description">{method.description}</div>
             </div>
-        );
-    }
-}
+            <Button variant="link" className="delete-button" onClick={e => onDelete(e)}><DeleteIcon/></Button>
+        </div>
+    )
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/rest/RestMethodSelector.tsx b/karavan-designer/src/designer/rest/RestMethodSelector.tsx
index d3c4ec66..bbd4cccb 100644
--- a/karavan-designer/src/designer/rest/RestMethodSelector.tsx
+++ b/karavan-designer/src/designer/rest/RestMethodSelector.tsx
@@ -24,34 +24,26 @@ import {
 import '../karavan.css';
 import {CamelUi} from "../utils/CamelUi";
 import {DslMetaModel} from "../utils/DslMetaModel";
+import {useDesignerStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
 
 interface Props {
     onMethodSelect: (method: DslMetaModel) => void
-    dark: boolean
 }
 
-interface State {
-}
-
-export class RestMethodSelector extends React.Component<Props, State> {
-
-    public state: State = {};
-
-
-    selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
-        this.setState({tabIndex: eventKey})
-    }
+export function RestMethodSelector(props: Props) {
 
+    const [dark] = useDesignerStore((s) => [s.dark], shallow)
 
-    selectMethod = (evt: React.MouseEvent, method: any) => {
+    function selectMethod (evt: React.MouseEvent, method: any) {
         evt.stopPropagation()
-        this.props.onMethodSelect.call(this, method);
+        props.onMethodSelect(method);
     }
 
-    getCard(dsl: DslMetaModel, index: number) {
+    function getCard(dsl: DslMetaModel, index: number) {
         return (
             <Card key={dsl.dsl + index}  isCompact className="dsl-card"
-                  onClick={event => this.selectMethod(event, dsl)}>
+                  onClick={event => selectMethod(event, dsl)}>
                 <CardHeader>
                     {CamelUi.getIconForDsl(dsl)}
                     <Text>{dsl.title}</Text>
@@ -74,17 +66,15 @@ export class RestMethodSelector extends React.Component<Props, State> {
         )
     }
 
-    render() {
-        return (
-            <PageSection variant={this.props.dark ? "darker" : "light"}>
-                <Tabs style={{overflow: 'hidden'}} activeKey="methods" onSelect={this.selectTab}>
-                        <Tab eventKey="methods" title={<TabTitleText>Methods</TabTitleText>}>
-                            <Gallery hasGutter className="dsl-gallery">
-                                {CamelUi.getSelectorRestMethodModels().map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))}
-                            </Gallery>
-                        </Tab>
-                </Tabs>
-            </PageSection>
-        );
-    }
+    return (
+        <PageSection variant={dark ? "darker" : "light"}>
+            <Tabs style={{overflow: 'hidden'}} activeKey="methods" onSelect={event => {}}>
+                <Tab eventKey="methods" title={<TabTitleText>Methods</TabTitleText>}>
+                    <Gallery hasGutter className="dsl-gallery">
+                        {CamelUi.getSelectorRestMethodModels().map((dsl: DslMetaModel, index: number) => getCard(dsl, index))}
+                    </Gallery>
+                </Tab>
+            </Tabs>
+        </PageSection>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/DeleteConfirmation.tsx b/karavan-designer/src/designer/route/DeleteConfirmation.tsx
new file mode 100644
index 00000000..999a4752
--- /dev/null
+++ b/karavan-designer/src/designer/route/DeleteConfirmation.tsx
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, Modal,
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import {useDesignerStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+
+export function DeleteConfirmation() {
+
+
+    const {deleteElement} = useRouteDesignerHook();
+
+    const [showDeleteConfirmation, deleteMessage , setShowDeleteConfirmation] =
+        useDesignerStore((s) => [s.showDeleteConfirmation, s.deleteMessage, s.setShowDeleteConfirmation], shallow)
+
+    return (
+        <Modal
+            className="modal-delete"
+            title="Confirmation"
+            isOpen={showDeleteConfirmation}
+            onClose={() => setShowDeleteConfirmation(false)}
+            actions={[
+                <Button key="confirm" variant="primary" onClick={e => deleteElement()}>Delete</Button>,
+                <Button key="cancel" variant="link"
+                        onClick={e => setShowDeleteConfirmation(false)}>Cancel</Button>
+            ]}
+            onEscapePress={e => setShowDeleteConfirmation(false)}>
+            <div>
+                {deleteMessage}
+            </div>
+        </Modal>
+    )
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx
index 938042d4..9f3578ad 100644
--- a/karavan-designer/src/designer/route/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -14,67 +14,52 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useEffect} from 'react';
 import '../karavan.css';
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {DslPosition, EventBus} from "../utils/EventBus";
 import {CamelUi} from "../utils/CamelUi";
-import {Subscription} from "rxjs";
 import {SagaDefinition} from "karavan-core/lib/model/CamelDefinition";
-
-interface Props {
-    integration: Integration
-    width: number
-    height: number
-    top: number
-    left: number
-}
-
-interface State {
-    integration: Integration
-    steps: Map<string, DslPosition>
-}
+import {useConnectionsStore, useDesignerStore, useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 
 const overlapGap: number = 40;
 const outgoingDefinitions: string[] = ['ToDefinition', 'KameletDefinition', 'ToDynamicDefinition', "PollEnrichDefinition", "EnrichDefinition", "WireTapDefinition", "SagaDefinition"];
 
+export function DslConnections() {
 
-export class DslConnections extends React.Component<Props, State> {
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+    const [width, height, top, left] = useDesignerStore((s) =>
+        [s.width, s.height, s.top, s.left], shallow)
+    const [ steps, addStep, deleteStep, clearSteps] = useConnectionsStore((s) => [s.steps, s.addStep, s.deleteStep, s.clearSteps], shallow)
 
-    public state: State = {
-        integration: this.props.integration,
-        steps: new Map<string, DslPosition>(),
-    };
-    sub?: Subscription;
+    useEffect(() => {
+        const sub = EventBus.onPosition()?.subscribe((evt: DslPosition) => setPosition(evt));
+        return () => {
+            sub?.unsubscribe();
+        };
+    });
 
-    componentDidMount() {
-        this.sub = EventBus.onPosition()?.subscribe((evt: DslPosition) => this.setPosition(evt));
-    }
-
-    componentWillUnmount() {
-        this.sub?.unsubscribe();
-    }
+    useEffect(() => {
+        const toDelete: string[] = Array.from(steps.keys()).filter(k => CamelDefinitionApiExt.findElementInIntegration(integration, k) === undefined);
+        toDelete.forEach(key => deleteStep(key));
+    }, [integration]);
 
-    setPosition(evt: DslPosition) {
+    function setPosition(evt: DslPosition) {
         if (evt.command === "add") {
-            this.setState(prevState => ({steps: prevState.steps.set(evt.step.uuid, evt)}));
+            addStep(evt.step.uuid, evt);
+        }
+        else if (evt.command === "delete") {
+            deleteStep(evt.step.uuid);
+        }
+        else if (evt.command === "clean") {
+            clearSteps();
         }
-        else if (evt.command === "delete") this.setState(prevState => {
-            prevState.steps.clear();
-            Array.from(prevState.steps.entries())
-                .filter(value => value[1]?.parent?.uuid !== evt.step.uuid)
-                .forEach(value => prevState.steps.set(value[0], value[1]));
-            prevState.steps.delete(evt.step.uuid);
-            return {steps: prevState.steps};
-        });
-        else if (evt.command === "clean") this.setState(prevState => {
-            prevState.steps.clear();
-            return {steps: prevState.steps};
-        });
     }
 
-    getIncomings() {
-        let outs: [string, number][] = Array.from(this.state.steps.values())
+    function getIncomings() {
+        let outs: [string, number][] = Array.from(steps.values())
             .filter(pos => ["FromDefinition"].includes(pos.step.dslName))
             .filter(pos => !CamelUi.isElementInternalComponent(pos.step))
             .filter(pos => !(pos.step.dslName === 'FromDefinition' && CamelUi.hasInternalUri(pos.step)))
@@ -84,17 +69,17 @@ export class DslConnections extends React.Component<Props, State> {
                 return y1 > y2 ? 1 : -1
             })
             .map(pos => [pos.step.uuid, pos.headerRect.y]);
-        while (this.hasOverlap(outs)) {
-            outs = this.addGap(outs);
+        while (hasOverlap(outs)) {
+            outs = addGap(outs);
         }
         return outs;
     }
 
-    getIncoming(data: [string, number]) {
-        const pos = this.state.steps.get(data[0]);
+    function getIncoming(data: [string, number]) {
+        const pos = steps.get(data[0]);
         if (pos) {
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
+            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
 
             const incomingX = 20;
@@ -103,8 +88,6 @@ export class DslConnections extends React.Component<Props, State> {
             const lineX2 = fromX - r * 2 + 7;
             const lineY2 = fromY;
 
-            const imageX = incomingX - r + 5;
-            const imageY = fromY - r + 5;
             return (
                 <g key={pos.step.uuid + "-incoming"}>
                     <circle cx={incomingX} cy={fromY} r={r} className="circle-incoming"/>
@@ -117,10 +100,10 @@ export class DslConnections extends React.Component<Props, State> {
         }
     }
 
-    getIncomingIcons(data: [string, number]) {
-        const pos = this.state.steps.get(data[0]);
+    function getIncomingIcons(data: [string, number]) {
+        const pos = steps.get(data[0]);
         if (pos) {
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
             const incomingX = 20;
             const imageX = incomingX - r + 5;
@@ -133,7 +116,7 @@ export class DslConnections extends React.Component<Props, State> {
         }
     }
 
-    hasOverlap(data: [string, number][]): boolean {
+    function hasOverlap(data: [string, number][]): boolean {
         let result = false;
         data.forEach((d, i, arr) => {
             if (i > 0 && d[1] - arr[i - 1][1] < overlapGap) result = true;
@@ -141,7 +124,7 @@ export class DslConnections extends React.Component<Props, State> {
         return result;
     }
 
-    addGap(data: [string, number][]): [string, number][] {
+    function addGap(data: [string, number][]): [string, number][] {
         const result: [string, number][] = [];
         data.forEach((d, i, arr) => {
             if (i > 0 && d[1] - arr[i - 1][1] < overlapGap) result.push([d[0], d[1] + overlapGap])
@@ -151,8 +134,8 @@ export class DslConnections extends React.Component<Props, State> {
     }
 
 
-    getOutgoings(): [string, number][] {
-        let outs: [string, number][] = Array.from(this.state.steps.values())
+    function getOutgoings(): [string, number][] {
+        let outs: [string, number][] = Array.from(steps.values())
             .filter(pos => outgoingDefinitions.includes(pos.step.dslName))
             .filter(pos => pos.step.dslName !== 'KameletDefinition' || (pos.step.dslName === 'KameletDefinition' && !CamelUi.isActionKamelet(pos.step)))
             .filter(pos => pos.step.dslName === 'ToDefinition' && !CamelUi.isActionKamelet(pos.step) && !CamelUi.isElementInternalComponent(pos.step))
@@ -163,21 +146,21 @@ export class DslConnections extends React.Component<Props, State> {
                 const y2 = pos2.headerRect.y + pos2.headerRect.height / 2;
                 return y1 > y2 ? 1 : -1
             })
-            .map(pos => [pos.step.uuid, pos.headerRect.y - this.props.top]);
-        while (this.hasOverlap(outs)) {
-            outs = this.addGap(outs);
+            .map(pos => [pos.step.uuid, pos.headerRect.y - top]);
+        while (hasOverlap(outs)) {
+            outs = addGap(outs);
         }
         return outs;
     }
 
-    getOutgoing(data: [string, number]) {
-        const pos = this.state.steps.get(data[0]);
+    function getOutgoing(data: [string, number]) {
+        const pos = steps.get(data[0]);
         if (pos) {
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
+            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
 
-            const outgoingX = this.props.width - 20;
+            const outgoingX = width - 20;
             const outgoingY = data[1] + 15;
 
             const lineX1 = fromX + r;
@@ -203,11 +186,11 @@ export class DslConnections extends React.Component<Props, State> {
         }
     }
 
-    getOutgoingIcons(data: [string, number]) {
-        const pos = this.state.steps.get(data[0]);
+    function getOutgoingIcons(data: [string, number]) {
+        const pos = steps.get(data[0]);
         if (pos) {
             const r = pos.headerRect.height / 2;
-            const outgoingX = this.props.width - 20;
+            const outgoingX = width - 20;
             const outgoingY = data[1] + 15;
             const imageX = outgoingX - r + 5;
             const imageY = outgoingY - r + 5;
@@ -219,55 +202,55 @@ export class DslConnections extends React.Component<Props, State> {
         }
     }
 
-    getInternals(): [string, number, boolean][] {
-        let outs: [string, number, boolean][] = Array.from(this.state.steps.values())
+    function getInternals(): [string, number, boolean][] {
+        let outs: [string, number, boolean][] = Array.from(steps.values())
             .filter(pos => outgoingDefinitions.includes(pos.step.dslName) && CamelUi.hasInternalUri(pos.step))
             .sort((pos1: DslPosition, pos2: DslPosition) => {
                 const y1 = pos1.headerRect.y + pos1.headerRect.height / 2;
                 const y2 = pos2.headerRect.y + pos2.headerRect.height / 2;
                 return y1 > y2 ? 1 : -1
             })
-            .map(pos => [pos.step.uuid, pos.headerRect.y - this.props.top, pos.isSelected]);
+            .map(pos => [pos.step.uuid, pos.headerRect.y - top, pos.isSelected]);
         return outs;
     }
 
-    getInternalLines(data: [string, number, boolean]) {
-        const pos = this.state.steps.get(data[0]);
+    function getInternalLines(data: [string, number, boolean]) {
+        const pos = steps.get(data[0]);
         const uri = (pos?.step as any).uri;
         if (uri && uri.length && pos) {
             const key = pos.step.uuid + "-outgoing"
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
+            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
             const className = (CamelUi.hasDirectUri(pos.step) ? "path-direct" : "path-seda") + (data[2] ? "-selected" : "");
-            return this.getInternalLine(uri, key, className, fromX, fromY, r, data[1]);
+            return getInternalLine(uri, key, className, fromX, fromY, r, data[1]);
         } else if (pos?.step.dslName === 'SagaDefinition'){
             const saga = (pos?.step as SagaDefinition);
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
+            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
             const r = pos.headerRect.height / 2;
             const result:any[] = [];
             if (saga.completion && (saga.completion.startsWith("direct") || saga.completion.startsWith("seda"))){
                 const key = pos.step.uuid + "-completion"
                 const className = saga.completion.startsWith("direct") ? "path-direct" : "path-seda";
-                result.push(this.getInternalLine(saga.completion, key, className, fromX, fromY, r, data[1]));
+                result.push(getInternalLine(saga.completion, key, className, fromX, fromY, r, data[1]));
             }
             if (saga.compensation && (saga.compensation.startsWith("direct") || saga.compensation.startsWith("seda"))){
                 const key = pos.step.uuid + "-compensation"
                 const className = saga.compensation.startsWith("direct") ? "path-direct" : "path-seda";
-                result.push(this.getInternalLine(saga.compensation, key, className, fromX, fromY, r, data[1]));
+                result.push(getInternalLine(saga.compensation, key, className, fromX, fromY, r, data[1]));
             }
             return result;
         }
     }
 
-    getInternalLine(uri: string, key: string, className: string, fromX: number, fromY: number, r: number, i: number) {
-        const target = Array.from(this.state.steps.values())
+    function getInternalLine(uri: string, key: string, className: string, fromX: number, fromY: number, r: number, i: number) {
+        const target = Array.from(steps.values())
             .filter(s => s.step.dslName === 'FromDefinition')
             .filter(s => (s.step as any).uri && (s.step as any).uri === uri)[0];
         if (target) {
-            const targetX = target.headerRect.x + target.headerRect.width / 2 - this.props.left;
-            const targetY = target.headerRect.y + target.headerRect.height / 2 - this.props.top;
+            const targetX = target.headerRect.x + target.headerRect.width / 2 - left;
+            const targetY = target.headerRect.y + target.headerRect.height / 2 - top;
             const gap = 100;
             const add = 0.2;
 
@@ -294,7 +277,7 @@ export class DslConnections extends React.Component<Props, State> {
                 const pointX4 = pointLX + coefX;
                 const pointY4 = endY;
 
-                return this.getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
+                return getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
             } else if (targetX > fromX && targetX - fromX < gap) {
                 const startX = fromX - r;
                 const startY = fromY;
@@ -317,7 +300,7 @@ export class DslConnections extends React.Component<Props, State> {
                 const pointX4 = pointLX - coefX/2;
                 const pointY4 = endY;
 
-                return this.getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
+                return getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
             } else if (targetX <= fromX && fromX - targetX < gap) {
                 const startX = fromX + r;
                 const startY = fromY;
@@ -340,7 +323,7 @@ export class DslConnections extends React.Component<Props, State> {
                 const pointX4 = pointLX - coefX/2;
                 const pointY4 = endY;
 
-                return this.getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
+                return getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
             } else {
                 const startX = fromX - r;
                 const startY = fromY;
@@ -363,12 +346,12 @@ export class DslConnections extends React.Component<Props, State> {
                 const pointX4 = pointLX + coefX;
                 const pointY4 = endY;
 
-                return this.getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
+                return getInternalPath(key, className, startX, startY, pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, pointX4, pointY4, endX, endY);
             }
         }
     }
 
-    getInternalPath(key: string, className: string, startX: number, startY: number, pointX1: number, pointY1: number, pointX2: number, pointY2: number, pointLX: number, pointLY: number,
+    function getInternalPath(key: string, className: string, startX: number, startY: number, pointX1: number, pointY1: number, pointX2: number, pointY2: number, pointLX: number, pointLY: number,
                     pointX3: number, pointY3: number, pointX4: number, pointY4: number, endX: number, endY: number) {
         return (
             <g key={key}>
@@ -380,35 +363,35 @@ export class DslConnections extends React.Component<Props, State> {
         )
     }
 
-    getCircle(pos: DslPosition) {
-        const cx = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-        const cy = pos.headerRect.y + pos.headerRect.height / 2 - this.props.top;
+    function getCircle(pos: DslPosition) {
+        const cx = pos.headerRect.x + pos.headerRect.width / 2 - left;
+        const cy = pos.headerRect.y + pos.headerRect.height / 2 - top;
         const r = pos.headerRect.height / 2;
         return (
             <circle cx={cx} cy={cy} r={r} stroke="transparent" strokeWidth="3" fill="transparent" key={pos.step.uuid + "-circle"}/>
         )
     }
 
-    hasSteps = (step: CamelElement): boolean => {
+    function hasSteps  (step: CamelElement): boolean  {
         return (step.hasSteps() && !['FromDefinition'].includes(step.dslName))
             || ['RouteDefinition', 'TryDefinition', 'ChoiceDefinition', 'SwitchDefinition'].includes(step.dslName);
     }
 
-    getPreviousStep(pos: DslPosition) {
-        return Array.from(this.state.steps.values())
+    function getPreviousStep(pos: DslPosition) {
+        return Array.from(steps.values())
             .filter(p => pos.parent?.uuid === p.parent?.uuid)
             .filter(p => p.inSteps)
             .filter(p => p.position === pos.position - 1)[0];
     }
 
-    getArrow(pos: DslPosition) {
-        const endX = pos.headerRect.x + pos.headerRect.width / 2 - this.props.left;
-        const endY = pos.headerRect.y - 9 - this.props.top;
+    function getArrow(pos: DslPosition) {
+        const endX = pos.headerRect.x + pos.headerRect.width / 2 - left;
+        const endY = pos.headerRect.y - 9 - top;
         if (pos.parent) {
-            const parent = this.state.steps.get(pos.parent.uuid);
+            const parent = steps.get(pos.parent.uuid);
             if (parent) {
-                const startX = parent.headerRect.x + parent.headerRect.width / 2 - this.props.left;
-                const startY = parent.headerRect.y + parent.headerRect.height - this.props.top;
+                const startX = parent.headerRect.x + parent.headerRect.width / 2 - left;
+                const startY = parent.headerRect.y + parent.headerRect.height - top;
                 if ((!pos.inSteps || (pos.inSteps && pos.position === 0)) && parent.step.dslName !== 'MulticastDefinition') {
                     return (
                         <path name={pos.step.dslName} d={`M ${startX},${startY} C ${startX},${endY} ${endX},${startY}   ${endX},${endY}`}
@@ -419,22 +402,22 @@ export class DslConnections extends React.Component<Props, State> {
                         <path d={`M ${startX},${startY} C ${startX},${endY} ${endX},${startY}   ${endX},${endY}`}
                               className="path" key={pos.step.uuid} markerEnd="url(#arrowhead)"/>
                     )
-                } else if (pos.inSteps && pos.position > 0 && !this.hasSteps(pos.step)) {
-                    const prev = this.getPreviousStep(pos);
+                } else if (pos.inSteps && pos.position > 0 && !hasSteps(pos.step)) {
+                    const prev = getPreviousStep(pos);
                     if (prev) {
-                        const r = this.hasSteps(prev.step) ? prev.rect : prev.headerRect;
-                        const prevX = r.x + r.width / 2 - this.props.left;
-                        const prevY = r.y + r.height - this.props.top;
+                        const r = hasSteps(prev.step) ? prev.rect : prev.headerRect;
+                        const prevX = r.x + r.width / 2 - left;
+                        const prevY = r.y + r.height - top;
                         return (
                             <line x1={prevX} y1={prevY} x2={endX} y2={endY} className="path" key={pos.step.uuid} markerEnd="url(#arrowhead)"/>
                         )
                     }
-                } else if (pos.inSteps && pos.position > 0 && this.hasSteps(pos.step)) {
-                    const prev = this.getPreviousStep(pos);
+                } else if (pos.inSteps && pos.position > 0 && hasSteps(pos.step)) {
+                    const prev = getPreviousStep(pos);
                     if (prev) {
-                        const r = this.hasSteps(prev.step) ? prev.rect : prev.headerRect;
-                        const prevX = r.x + r.width / 2 - this.props.left;
-                        const prevY = r.y + r.height - this.props.top;
+                        const r = hasSteps(prev.step) ? prev.rect : prev.headerRect;
+                        const prevX = r.x + r.width / 2 - left;
+                        const prevY = r.y + r.height - top;
                         return (
                             <line x1={prevX} y1={prevY} x2={endX} y2={endY} className="path" key={pos.step.uuid} markerEnd="url(#arrowhead)"/>
                         )
@@ -444,33 +427,31 @@ export class DslConnections extends React.Component<Props, State> {
         }
     }
 
-    getSvg() {
-        const steps = Array.from(this.state.steps.values());
+    function getSvg() {
+        const stepsArray = Array.from(steps.values());
         return (
             <svg
-                style={{width: this.props.width, height: this.props.height, position: "absolute", left: 0, top: 0}}
-                viewBox={"0 0 " + this.props.width + " " + this.props.height}>
+                style={{width: width, height: height + 80, position: "absolute", left: 0, top: 0}}
+                viewBox={"0 0 " + (width) + " " + (height + 80)}>
                 <defs>
                     <marker id="arrowhead" markerWidth="9" markerHeight="6" refX="0" refY="3" orient="auto" className="arrow">
                         <polygon points="0 0, 9 3, 0 6"/>
                     </marker>
                 </defs>
-                {steps.map(pos => this.getCircle(pos))}
-                {steps.map(pos => this.getArrow(pos))}
-                {this.getIncomings().map(p => this.getIncoming(p))}
-                {this.getOutgoings().map(p => this.getOutgoing(p))}
-                {/*{this.getInternals().map((p) => this.getInternalLines(p)).flat()}*/}
+                {stepsArray.map(pos => getCircle(pos))}
+                {stepsArray.map(pos => getArrow(pos))}
+                {getIncomings().map(p => getIncoming(p))}
+                {getOutgoings().map(p => getOutgoing(p))}
+                {/*{getInternals().map((p) => getInternalLines(p)).flat()}*/}
             </svg>
         )
     }
 
-    render() {
-        return (
-            <div className="connections" style={{width: this.props.width, height: this.props.height, marginTop: "8px"}}>
-                {this.getSvg()}
-                {this.getIncomings().map(p => this.getIncomingIcons(p))}
-                {this.getOutgoings().map(p => this.getOutgoingIcons(p))}
-            </div>
-        );
-    }
+    return (
+        <div id="connections" className="connections" style={{ width: width, height: height + 80}}>
+            {getSvg()}
+            {getIncomings().map(p => getIncomingIcons(p))}
+            {getOutgoings().map(p => getOutgoingIcons(p))}
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/route/DslElement.tsx b/karavan-designer/src/designer/route/DslElement.tsx
index 2ea1aaa2..f3283154 100644
--- a/karavan-designer/src/designer/route/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React, {CSSProperties} from 'react';
+import React, {CSSProperties, useEffect, useMemo, useRef, useState} from 'react';
 import {
     Button,
     Flex,
@@ -25,147 +25,133 @@ import '../karavan.css';
 import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
 import InsertIcon from "@patternfly/react-icons/dist/js/icons/arrow-alt-circle-right-icon";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelUi} from "../utils/CamelUi";
 import {EventBus} from "../utils/EventBus";
 import {ChildElement, CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
-import ReactDOM from "react-dom";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
+import {useDesignerStore, useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {useRouteDesignerHook} from "./useRouteDesignerHook";
 
 interface Props {
-    integration: Integration,
     step: CamelElement,
     parent: CamelElement | undefined,
-    deleteElement: any
-    selectElement: any
-    openSelector: (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean, position?: number | undefined) => void
-    moveElement: (source: string, target: string, asChild: boolean) => void
-    selectedUuid: string []
     inSteps: boolean
     position: number
 }
 
-interface State {
-    showSelector: boolean
-    showMoveConfirmation: boolean
-    moveElements: [string | undefined, string | undefined]
-    tabIndex: string | number
-    isDragging: boolean
-    isDraggedOver: boolean
-}
+export function DslElement(props: Props) {
+
+    const headerRef = React.useRef<HTMLDivElement>(null);
+    const {selectElement, moveElement, onShowDeleteConfirmation, openSelector} = useRouteDesignerHook();
+
+    const [integration] = useIntegrationStore((s) => [s.integration, s.setIntegration], shallow)
 
-export class DslElement extends React.Component<Props, State> {
-
-    public state: State = {
-        showSelector: false,
-        showMoveConfirmation: false,
-        moveElements: [undefined, undefined],
-        tabIndex: 0,
-        isDragging: false,
-        isDraggedOver: false,
-    };
-
-    //
-    // componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-    //     if (prevState.selectedUuid !== this.props.selectedUuid) {
-    //         this.setState({selectedUuid: this.props.selectedUuid});
-    //     }
-    // }
-
-    openSelector = (evt: React.MouseEvent, showSteps: boolean = true, isInsert: boolean = false) => {
+    const [selectedUuids, selectedStep, showMoveConfirmation, setShowMoveConfirmation, hideLogDSL] =
+        useDesignerStore((s) =>
+        [s.selectedUuids, s.selectedStep, s.showMoveConfirmation, s.setShowMoveConfirmation, s.hideLogDSL], shallow)
+    const [isDragging, setIsDragging] = useState<boolean>(false);
+
+    const [isDraggedOver, setIsDraggedOver] = useState<boolean>(false);
+    const [moveElements, setMoveElements] = useState<[string | undefined, string | undefined]>([undefined, undefined]);
+
+    function onOpenSelector(evt: React.MouseEvent, showSteps: boolean = true, isInsert: boolean = false) {
         evt.stopPropagation();
-        if (isInsert && this.props.parent) {
-            this.props.openSelector.call(this, this.props.parent.uuid, this.props.parent.dslName, showSteps, this.props.position);
+        if (isInsert && props.parent) {
+            openSelector(props.parent.uuid, props.parent.dslName, showSteps, props.position);
         } else {
-            this.props.openSelector.call(this, this.props.step.uuid, this.props.step.dslName, showSteps);
+            openSelector(props.step.uuid, props.step.dslName, showSteps);
         }
     }
 
-    closeDslSelector = () => {
-        this.setState({showSelector: false})
-    }
-
-    delete = (evt: React.MouseEvent) => {
+    function onDeleteElement(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.step.uuid);
+        onShowDeleteConfirmation(props.step.uuid);
     }
 
-    selectElement = (evt: React.MouseEvent) => {
+    function onSelectElement(evt: React.MouseEvent) {
         evt.stopPropagation();
-        this.props.selectElement.call(this, this.props.step);
+        selectElement(props.step);
     }
 
-    dragElement = (event: React.DragEvent<HTMLDivElement>, element: CamelElement) => {
+    function dragElement(event: React.DragEvent<HTMLDivElement>, element: CamelElement) {
         event.preventDefault();
         event.stopPropagation();
-        this.setState({isDraggedOver: false});
+        setIsDraggedOver(false);
         const sourceUuid = event.dataTransfer.getData("text/plain");
         const targetUuid = element.uuid;
         if (sourceUuid !== targetUuid) {
-            if (element.hasSteps()){
-                this.setState({showMoveConfirmation: true, moveElements: [sourceUuid, targetUuid]});
+            if (element.hasSteps()) {
+                setShowMoveConfirmation(true);
+                setMoveElements([sourceUuid, targetUuid])
             } else {
-                this.props.moveElement?.call(this, sourceUuid, targetUuid, false);
+                moveElement(sourceUuid, targetUuid, false);
             }
         }
     }
 
-    confirmMove = (asChild: boolean) => {
-        const sourceUuid = this.state.moveElements[0];
-        const targetUuid = this.state.moveElements[1];
+    function confirmMove(asChild: boolean) {
+        const sourceUuid = moveElements[0];
+        const targetUuid = moveElements[1];
         if (sourceUuid && targetUuid && sourceUuid !== targetUuid) {
-            this.props.moveElement?.call(this, sourceUuid, targetUuid, asChild);
-            this.setState({showMoveConfirmation: false, moveElements: [undefined, undefined]})
+            moveElement(sourceUuid, targetUuid, asChild);
+            cancelMove();
         }
     }
 
-    cancelMove = () => {
-        this.setState({showMoveConfirmation: false, moveElements: [undefined, undefined]})
+    function cancelMove() {
+        setShowMoveConfirmation(false);
+        setMoveElements([undefined, undefined]);
+    }
+
+    function isElementSelected(): boolean {
+        return selectedUuids.includes(props.step.uuid);
     }
 
-    isSelected = (): boolean => {
-        return this.props.selectedUuid.includes(this.props.step.uuid);
+    function isElementHidden(): boolean {
+        return props.step.dslName === 'LogDefinition' && hideLogDSL;
     }
 
-    hasBorder = (): boolean => {
-        return (this.props.step?.hasSteps() && !['FromDefinition'].includes(this.props.step.dslName))
+    function hasBorder(): boolean {
+        return (props.step?.hasSteps() && !['FromDefinition'].includes(props.step.dslName))
             || ['RouteConfigurationDefinition',
                 'RouteDefinition',
                 'TryDefinition',
                 'ChoiceDefinition',
-                'SwitchDefinition'].includes(this.props.step.dslName);
+                'SwitchDefinition'].includes(props.step.dslName);
     }
 
-    isNotDraggable = (): boolean => {
-        return ['FromDefinition', 'RouteConfigurationDefinition', 'RouteDefinition', 'WhenDefinition', 'OtherwiseDefinition'].includes(this.props.step.dslName);
+    function isNotDraggable(): boolean {
+        return ['FromDefinition', 'RouteConfigurationDefinition', 'RouteDefinition', 'WhenDefinition', 'OtherwiseDefinition'].includes(props.step.dslName);
     }
 
-    isWide = (): boolean => {
+    function isWide(): boolean {
         return ['RouteConfigurationDefinition', 'RouteDefinition', 'ChoiceDefinition', 'SwitchDefinition', 'MulticastDefinition', 'TryDefinition', 'CircuitBreakerDefinition']
-            .includes(this.props.step.dslName);
+            .includes(props.step.dslName);
     }
 
-    isAddStepButtonLeft = (): boolean => {
+    function isAddStepButtonLeft(): boolean {
         return ['MulticastDefinition']
-            .includes(this.props.step.dslName);
+            .includes(props.step.dslName);
     }
 
-    isHorizontal = (): boolean => {
-        return ['MulticastDefinition'].includes(this.props.step.dslName);
+    function isHorizontal(): boolean {
+        return ['MulticastDefinition'].includes(props.step.dslName);
     }
 
-    isRoot = (): boolean => {
-        return ['RouteConfigurationDefinition', 'RouteDefinition'].includes(this.props.step?.dslName);
+    function isRoot(): boolean {
+        return ['RouteConfigurationDefinition', 'RouteDefinition'].includes(props.step?.dslName);
     }
 
-    isInStepWithChildren = () => {
-        const step: CamelElement = this.props.step;
+    function isInStepWithChildren() {
+        const step: CamelElement = props.step;
         const children = CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName);
-        return children.filter((c: ChildElement) => c.name === 'steps' || c.multiple).length > 0 && this.props.inSteps;
+        return children.filter((c: ChildElement) => c.name === 'steps' || c.multiple).length > 0 && props.inSteps;
     }
 
-    getChildrenInfo = (step: CamelElement): [boolean, number, boolean, number, number] => {
+    function getChildrenInfo(step: CamelElement): [boolean, number, boolean, number, number] {
         const children = CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName);
         const hasStepsField = children.filter((c: ChildElement) => c.name === 'steps').length === 1;
         const stepsChildrenCount = children
@@ -185,115 +171,134 @@ export class DslElement extends React.Component<Props, State> {
         return [hasStepsField, stepsChildrenCount, hasNonStepsFields, nonStepChildrenCount, childrenCount]
     }
 
-    hasWideChildrenElement = () => {
-        const [hasStepsField, stepsChildrenCount, hasNonStepsFields, nonStepChildrenCount, childrenCount] = this.getChildrenInfo(this.props.step);
-        if (this.isHorizontal() && stepsChildrenCount > 1) return true;
+    function hasWideChildrenElement() {
+        const [hasStepsField, stepsChildrenCount, hasNonStepsFields, nonStepChildrenCount, childrenCount] = getChildrenInfo(props.step);
+        if (isHorizontal() && stepsChildrenCount > 1) return true;
         else if (hasStepsField && stepsChildrenCount > 0 && hasNonStepsFields && nonStepChildrenCount > 0) return true;
         else if (!hasStepsField && hasNonStepsFields && childrenCount > 1) return true;
         else if (hasStepsField && stepsChildrenCount > 0 && hasNonStepsFields && childrenCount > 1) return true;
         else return false;
     }
 
-    hasBorderOverSteps = (step: CamelElement) => {
-        const [hasStepsField, stepsChildrenCount, hasNonStepsFields, nonStepChildrenCount] = this.getChildrenInfo(step);
+    function hasBorderOverSteps(step: CamelElement) {
+        const [hasStepsField, stepsChildrenCount, hasNonStepsFields, nonStepChildrenCount] = getChildrenInfo(step);
         if (hasStepsField && stepsChildrenCount > 0 && hasNonStepsFields && nonStepChildrenCount > 0) return true;
         else return false;
     }
 
-    getHeaderStyle = () => {
+    function getHeaderStyle() {
         const style: CSSProperties = {
-            width: this.isWide() ? "100%" : "",
-            fontWeight: this.isSelected() ? "bold" : "normal",
+            width: isWide() ? "100%" : "",
+            fontWeight: isElementSelected() ? "bold" : "normal",
         };
         return style;
     }
 
-    sendPosition = (el: HTMLDivElement | null, isSelected: boolean) => {
-        const node = ReactDOM.findDOMNode(this);
-        if (node && el) {
-            const header = Array.from(node.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0];
-            if (header) {
-                const headerIcon: any = Array.from(header.childNodes.values()).filter((n: any) => n.classList.contains("header-icon"))[0];
-                const headerRect = headerIcon.getBoundingClientRect();
-                const rect = el.getBoundingClientRect();
-                if (this.props.step.show){
-                    EventBus.sendPosition("add", this.props.step, this.props.parent, rect, headerRect, this.props.position, this.props.inSteps, isSelected);
-                } else {
-                    EventBus.sendPosition("delete", this.props.step, this.props.parent, new DOMRect(), new DOMRect(), 0);
+    function sendPosition(el: HTMLDivElement | null) {
+        const isSelected = isElementSelected();
+        const isHidden = isElementHidden();
+        if (isHidden) {
+            EventBus.sendPosition("delete", props.step, props.parent, new DOMRect(), new DOMRect(), 0);
+        } else {
+            if (el) {
+                const header = Array.from(el.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0];
+                if (header) {
+                    const headerIcon: any = Array.from(header.childNodes.values()).filter((n: any) => n.classList.contains("header-icon"))[0];
+                    const headerRect = headerIcon.getBoundingClientRect();
+                    const rect = el.getBoundingClientRect();
+                    if (props.step.showChildren) {
+                        EventBus.sendPosition("add", props.step, props.parent, rect, headerRect, props.position, props.inSteps, isSelected);
+                    } else {
+                        EventBus.sendPosition("delete", props.step, props.parent, new DOMRect(), new DOMRect(), 0);
+                    }
                 }
             }
         }
     }
 
-    getHeader = () => {
-        const step: CamelElement = this.props.step;
-        const parent = this.props.parent;
+    function getAvailableModels() { // TODO: make static list-of-values instead
+        const step: CamelElement = props.step
+        return CamelUi.getSelectorModelsForParent(step.dslName, false);
+    }
+
+    const availableModels = useMemo(
+        () => getAvailableModels(),
+        [props.step.dslName]
+    );
+
+
+    function getHeader() {
+        const step: CamelElement = props.step;
+        const parent = props.parent;
         const inRouteConfiguration = parent !== undefined && parent.dslName === 'RouteConfigurationDefinition';
-        const availableModels = CamelUi.getSelectorModelsForParent(step.dslName, false);
         const showAddButton = !['CatchDefinition', 'RouteDefinition'].includes(step.dslName) && availableModels.length > 0;
         const showInsertButton =
             !['FromDefinition', 'RouteConfigurationDefinition', 'RouteDefinition', 'CatchDefinition', 'FinallyDefinition', 'WhenDefinition', 'OtherwiseDefinition'].includes(step.dslName)
             && !inRouteConfiguration;
         const headerClass = ['RouteConfigurationDefinition', 'RouteDefinition'].includes(step.dslName) ? "header-route" : "header"
-        const headerClasses = this.isSelected() ? headerClass + " selected" : headerClass;
+        const headerClasses = isElementSelected() ? headerClass + " selected" : headerClass;
         return (
-            <div className={headerClasses} style={this.getHeaderStyle()}>
-                {!['RouteConfigurationDefinition', 'RouteDefinition'].includes(this.props.step.dslName) &&
-                    <div ref={el => this.sendPosition(el, this.isSelected())}
-                         className={"header-icon"}
-                         style={this.isWide() ? {width: ""} : {}}>
+            <div className={headerClasses} style={getHeaderStyle()} ref={headerRef}>
+                {!['RouteConfigurationDefinition', 'RouteDefinition'].includes(props.step.dslName) &&
+                    <div
+                        ref={el => sendPosition(el)}
+                        className={"header-icon"}
+                        style={isWide() ? {width: ""} : {}}>
                         {CamelUi.getIconForElement(step)}
                     </div>
                 }
-                <div className={this.hasWideChildrenElement() ? "header-text" : ""}>
-                    {this.hasWideChildrenElement() && <div className="spacer"/>}
-                    {this.getHeaderTextWithTooltip(step)}
+                <div className={hasWideChildrenElement() ? "header-text" : ""}>
+                    {hasWideChildrenElement() && <div className="spacer"/>}
+                    {getHeaderTextWithTooltip(step)}
                 </div>
-                {showInsertButton && this.getInsertElementButton()}
-                {this.getDeleteButton()}
-                {showAddButton && this.getAddElementButton()}
+                {showInsertButton && getInsertElementButton()}
+                {getDeleteButton()}
+                {showAddButton && getAddElementButton()}
             </div>
         )
     }
 
-    getHeaderTextWithTooltip = (step: CamelElement) => {
+    function getHeaderTextWithTooltip(step: CamelElement) {
         const checkRequired = CamelUtil.checkRequired(step);
-        const title = (step as any).description ? (step as any).description : CamelUi.getElementTitle(this.props.step);
-        let className = this.hasWideChildrenElement() ? "text text-right" : "text text-bottom";
+        const title = (step as any).description ? (step as any).description : CamelUi.getElementTitle(props.step);
+        let className = hasWideChildrenElement() ? "text text-right" : "text text-bottom";
         if (!checkRequired[0]) className = className + " header-text-required";
-        if (checkRequired[0]) return <Text className={className}>{title}</Text>
+        if (checkRequired[0]) {
+            return <Text className={className}>{title}</Text>
+        }
         else return (
             <Tooltip position={"right"} className="tooltip-required-field"
-                     content={checkRequired[1].map((text, i) =>(<div key={i}>{text}</div>))}>
+                     content={checkRequired[1].map((text, i) => (<div key={i}>{text}</div>))}>
                 <Text className={className}>{title}</Text>
             </Tooltip>
         )
     }
 
-    getHeaderWithTooltip = (tooltip: string | undefined) => {
+    function getHeaderWithTooltip(tooltip: string | undefined) {
         return (
-            <Tooltip position={"left"}
-                     content={<div>{tooltip}</div>}>
-                {this.getHeader()}
-            </Tooltip>
+            <>
+                {getHeader()}
+                <Tooltip triggerRef={headerRef} position={"left"} content={<div>{tooltip}</div>}/>
+            </>
+
         )
     }
 
-    getHeaderTooltip = (): string | undefined => {
-        if (CamelUi.isShowExpressionTooltip(this.props.step)) return CamelUi.getExpressionTooltip(this.props.step);
-        if (CamelUi.isShowUriTooltip(this.props.step)) return CamelUi.getUriTooltip(this.props.step);
+    function getHeaderTooltip(): string | undefined {
+        if (CamelUi.isShowExpressionTooltip(props.step)) return CamelUi.getExpressionTooltip(props.step);
+        if (CamelUi.isShowUriTooltip(props.step)) return CamelUi.getUriTooltip(props.step);
         return undefined;
     }
 
-    getElementHeader = () => {
-        const tooltip = this.getHeaderTooltip();
-        if (tooltip !== undefined && !this.state.isDragging) {
-            return this.getHeaderWithTooltip(tooltip);
+    function getElementHeader() {
+        const tooltip = getHeaderTooltip();
+        if (tooltip !== undefined && !isDragging) {
+            return getHeaderWithTooltip(tooltip);
         }
-        return this.getHeader();
+        return getHeader();
     }
 
-    getChildrenStyle = () => {
+    function getChildrenStyle() {
         const style: CSSProperties = {
             display: "flex",
             flexDirection: "row",
@@ -301,22 +306,22 @@ export class DslElement extends React.Component<Props, State> {
         return style;
     }
 
-    getChildrenElementsStyle = (child: ChildElement, notOnlySteps: boolean) => {
-        const step = this.props.step;
-        const isBorder = child.name === 'steps' && this.hasBorderOverSteps(step);
+    function getChildrenElementsStyle(child: ChildElement, notOnlySteps: boolean) {
+        const step = props.step;
+        const isBorder = child.name === 'steps' && hasBorderOverSteps(step);
         const style: CSSProperties = {
             borderStyle: isBorder ? "dotted" : "none",
             borderColor: "var(--step-border-color)",
             borderWidth: "1px",
             borderRadius: "16px",
-            display: this.isHorizontal() || child.name !== 'steps' ? "flex" : "block",
+            display: isHorizontal() || child.name !== 'steps' ? "flex" : "block",
             flexDirection: "row",
         }
         return style;
     }
 
-    getChildElements = () => {
-        const step: CamelElement = this.props.step;
+    function getChildElements() {
+        const step: CamelElement = props.step;
         let children: ChildElement[] = CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName);
         const notOnlySteps = children.filter(c => c.name === 'steps').length === 1
             && children.filter(c => c.multiple && c.name !== 'steps').length > 0;
@@ -331,163 +336,159 @@ export class DslElement extends React.Component<Props, State> {
             children = children.filter(value => value.name !== 'onWhen')
         }
         return (
-            <div key={step.uuid + "-children"} className="children" style={this.getChildrenStyle()}>
-                {children.map((child: ChildElement, index: number) => this.getChildDslElements(child, index, notOnlySteps))}
+            <div key={step.uuid + "-children"} className="children" style={getChildrenStyle()}>
+                {children.map((child: ChildElement, index: number) => getChildDslElements(child, index, notOnlySteps))}
             </div>
         )
     }
 
-    getChildDslElements = (child: ChildElement, index: number, notOnlySteps: boolean) => {
-        const step = this.props.step;
+    function getChildDslElements(child: ChildElement, index: number, notOnlySteps: boolean) {
+        const step = props.step;
         const children: CamelElement[] = CamelDefinitionApiExt.getElementChildren(step, child);
         if (children.length > 0) {
             return (
-                <div className={child.name + " has-child"} style={this.getChildrenElementsStyle(child, notOnlySteps)} key={step.uuid + "-child-" + index}>
+                <div className={child.name + " has-child"} style={getChildrenElementsStyle(child, notOnlySteps)}
+                     key={step.uuid + "-child-" + index}>
                     {children.map((element, index) => (
                         <div key={step.uuid + child.className + index}>
                             <DslElement
-                                integration={this.props.integration}
-                                openSelector={this.props.openSelector}
-                                deleteElement={this.props.deleteElement}
-                                selectElement={this.props.selectElement}
-                                moveElement={this.props.moveElement}
-                                selectedUuid={this.props.selectedUuid}
                                 inSteps={child.name === 'steps'}
                                 position={index}
                                 step={element}
                                 parent={step}/>
                         </div>
                     ))}
-                    {child.name === 'steps' && this.getAddStepButton()}
+                    {child.name === 'steps' && getAddStepButton()}
                 </div>
             )
         } else if (child.name === 'steps') {
             return (
-                <div className={child.name + " has-child"} style={this.getChildrenElementsStyle(child, notOnlySteps)} key={step.uuid + "-child-" + index}>
-                    {this.getAddStepButton()}
+                <div className={child.name + " has-child"} style={getChildrenElementsStyle(child, notOnlySteps)}
+                     key={step.uuid + "-child-" + index}>
+                    {getAddStepButton()}
                 </div>
             )
         }
     }
 
-    getAddStepButton() {
-        const {integration, step, selectedUuid} = this.props;
-        const hideAddButton = step.dslName === 'StepDefinition' && !CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, selectedUuid.at(0));
+    function getAddStepButton() {
+        const {step} = props;
+        const hideAddButton = step.dslName === 'StepDefinition' && !CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, selectedUuids.at(0));
         if (hideAddButton) return (<></>)
         else return (
             <Tooltip position={"bottom"}
                      content={<div>{"Add step to " + CamelUi.getTitle(step)}</div>}>
-                <button type="button" aria-label="Add" onClick={e => this.openSelector(e)}
-                        className={this.isAddStepButtonLeft() ? "add-button add-button-left" : "add-button add-button-bottom"}>
-                    <AddIcon />
+                <button type="button" aria-label="Add" onClick={e => onOpenSelector(e)}
+                        className={isAddStepButtonLeft() ? "add-button add-button-left" : "add-button add-button-bottom"}>
+                    <AddIcon/>
                 </button>
             </Tooltip>
         )
     }
 
-    getAddElementButton() {
+    function getAddElementButton() {
         return (
-            <Tooltip position={"bottom"} content={<div>{"Add DSL element to " + CamelUi.getTitle(this.props.step)}</div>}>
+            <Tooltip position={"bottom"} content={<div>{"Add DSL element to " + CamelUi.getTitle(props.step)}</div>}>
                 <button
                     type="button"
                     aria-label="Add"
-                    onClick={e => this.openSelector(e, false)}
+                    onClick={e => onOpenSelector(e, false)}
                     className={"add-element-button"}>
-                    <AddIcon />
+                    <AddIcon/>
                 </button>
             </Tooltip>
         )
     }
 
-    getInsertElementButton() {
+    function getInsertElementButton() {
         return (
             <Tooltip position={"left"} content={<div>{"Insert element before"}</div>}>
-                <button type="button" aria-label="Insert" onClick={e => this.openSelector(e, true, true)} className={"insert-element-button"}><InsertIcon />
+                <button type="button" aria-label="Insert" onClick={e => onOpenSelector(e, true, true)}
+                        className={"insert-element-button"}><InsertIcon/>
                 </button>
             </Tooltip>
         )
     }
 
-    getDeleteButton() {
+    function getDeleteButton() {
         return (
             <Tooltip position={"right"} content={<div>{"Delete element"}</div>}>
-                <button type="button" aria-label="Delete" onClick={e => this.delete(e)} className="delete-button"><DeleteIcon /></button>
+                <button type="button" aria-label="Delete" onClick={e => onDeleteElement(e)} className="delete-button">
+                    <DeleteIcon/></button>
             </Tooltip>
         )
     }
 
-    getMoveConfirmation() {
+    function getMoveConfirmation() {
         return (
             <Modal
                 aria-label="title"
                 className='move-modal'
-                isOpen={this.state.showMoveConfirmation}
+                isOpen={showMoveConfirmation}
                 variant={ModalVariant.small}
             ><Flex direction={{default: "column"}}>
                 <div>Select move type:</div>
-                <Button key="place" variant="primary" onClick={event => this.confirmMove(false)}>Shift (target down)</Button>
-                <Button key="child" variant="secondary" onClick={event => this.confirmMove(true)}>Move as target step</Button>
-                <Button key="cancel" variant="tertiary" onClick={event => this.cancelMove()}>Cancel</Button>
+                <Button key="place" variant="primary" onClick={event => confirmMove(false)}>Shift (target down)</Button>
+                <Button key="child" variant="secondary" onClick={event => confirmMove(true)}>Move as target
+                    step</Button>
+                <Button key="cancel" variant="tertiary" onClick={event => cancelMove()}>Cancel</Button>
             </Flex>
 
             </Modal>
         )
     }
 
-    render() {
-        const element: CamelElement = this.props.step;
-        const className = "step-element" + (this.isSelected() ? " step-element-selected" : "")
-            + (!this.props.step.show ? " hidden-step" : "");
-        return (
-            <div key={"root" + element.uuid}
-                 className={className}
-                 ref={el => this.sendPosition(el, this.isSelected())}
-                 style={{
-                     borderStyle: this.hasBorder() ? "dotted" : "none",
-                     borderColor: this.isSelected() ? "var(--step-border-color-selected)" : "var(--step-border-color)",
-                     marginTop: this.isInStepWithChildren() ? "16px" : "8px",
-                     zIndex: element.dslName === 'ToDefinition' ? 20 : 10,
-                     boxShadow: this.state.isDraggedOver ? "0px 0px 1px 2px var(--step-border-color-selected)" : "none",
-                 }}
-                 onMouseOver={event => event.stopPropagation()}
-                 onClick={event => this.selectElement(event)}
-                 onDragStart={event => {
-                     event.stopPropagation();
-                     event.dataTransfer.setData("text/plain", element.uuid);
-                     (event.target as any).style.opacity = .5;
-                     this.setState({isDragging: true});
-                 }}
-                 onDragEnd={event => {
-                     (event.target as any).style.opacity = '';
-                     this.setState({isDragging: false});
-                 }}
-                 onDragOver={event => {
-                     event.preventDefault();
-                     event.stopPropagation();
-                     if (element.dslName !== 'FromDefinition' && !this.state.isDragging) {
-                         this.setState({isDraggedOver: true});
-                     }
-                 }}
-                 onDragEnter={event => {
-                     event.preventDefault();
-                     event.stopPropagation();
-                     if (element.dslName !== 'FromDefinition') {
-                         this.setState({isDraggedOver: true});
-                     }
-                 }}
-                 onDragLeave={event => {
-                     event.preventDefault();
-                     event.stopPropagation();
-                     this.setState({isDraggedOver: false});
-
-                 }}
-                 onDrop={event => this.dragElement(event, element)}
-                 draggable={!this.isNotDraggable()}
-            >
-                {this.getElementHeader()}
-                {this.getChildElements()}
-                {this.getMoveConfirmation()}
-            </div>
-        )
-    }
+    const element: CamelElement = props.step;
+    const className = "step-element" + (isElementSelected() ? " step-element-selected" : "") + (!props.step.showChildren ? " hidden-step" : "");
+    return (
+        <div key={"root" + element.uuid}
+             className={className}
+             ref={el => sendPosition(el)}
+             style={{
+                 display: isElementHidden() ? "none" : "flex",
+                 borderStyle: hasBorder() ? "dotted" : "none",
+                 borderColor: isElementSelected() ? "var(--step-border-color-selected)" : "var(--step-border-color)",
+                 marginTop: isInStepWithChildren() ? "16px" : "8px",
+                 zIndex: element.dslName === 'ToDefinition' ? 20 : 10,
+                 boxShadow: isDraggedOver ? "0px 0px 1px 2px var(--step-border-color-selected)" : "none",
+             }}
+             onMouseOver={event => event.stopPropagation()}
+             onClick={event => onSelectElement(event)}
+             onDragStart={event => {
+                 event.stopPropagation();
+                 event.dataTransfer.setData("text/plain", element.uuid);
+                 (event.target as any).style.opacity = .5;
+                 setIsDragging(true);
+             }}
+             onDragEnd={event => {
+                 (event.target as any).style.opacity = '';
+                 setIsDragging(false);
+             }}
+             onDragOver={event => {
+                 event.preventDefault();
+                 event.stopPropagation();
+                 if (element.dslName !== 'FromDefinition' && !isDragging) {
+                     setIsDraggedOver(true);
+                 }
+             }}
+             onDragEnter={event => {
+                 event.preventDefault();
+                 event.stopPropagation();
+                 if (element.dslName !== 'FromDefinition') {
+                     setIsDraggedOver(true);
+                 }
+             }}
+             onDragLeave={event => {
+                 event.preventDefault();
+                 event.stopPropagation();
+                 setIsDraggedOver(false);
+             }}
+             onDrop={event => dragElement(event, element)}
+             draggable={!isNotDraggable()}
+        >
+            {getElementHeader()}
+            {getChildElements()}
+            {getMoveConfirmation()}
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/route/DslProperties.tsx b/karavan-designer/src/designer/route/DslProperties.tsx
index 87f93c79..337e12c0 100644
--- a/karavan-designer/src/designer/route/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Form,
     Text,
@@ -25,101 +25,35 @@ import '../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
 import {DataFormatField} from "./property/DataFormatField";
 import {DslPropertyField} from "./property/DslPropertyField";
-import {
-    ExpressionDefinition,
-    DataFormatDefinition
-} from "karavan-core/lib/model/CamelDefinition";
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {CamelUi, RouteToCreate} from "../utils/CamelUi";
+import {CamelUi} from "../utils/CamelUi";
 import {CamelMetadataApi, DataFormats, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
-import {IntegrationHeader} from "../utils/KaravanComponents";
+import {IntegrationHeader} from "../utils/IntegrationHeader";
 import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
+import {useDesignerStore, useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {usePropertiesHook} from "./usePropertiesHook";
 
 interface Props {
-    integration: Integration,
-    step?: CamelElement,
-    onIntegrationUpdate?: any,
-    onPropertyUpdate?: (element: CamelElement, newRoute?: RouteToCreate) => void
-    onClone?: (element: CamelElement) => void
     isRouteDesigner: boolean
-    dark: boolean
-}
-
-interface State {
-    step?: CamelElement,
-    selectStatus: Map<string, boolean>
-    isShowAdvanced: boolean
-    isDescriptionExpanded?: boolean
 }
 
-export class DslProperties extends React.Component<Props, State> {
-
-    public state: State = {
-        step: this.props.step,
-        selectStatus: new Map<string, boolean>(),
-        isShowAdvanced: false
-    };
-
-    propertyChanged = (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) => {
-        if (this.state.step) {
-            const clone = CamelUtil.cloneStep(this.state.step);
-            (clone as any)[fieldId] = value;
-            this.setStep(clone)
-            this.props.onPropertyUpdate?.call(this, clone, newRoute);
-        }
-    }
-
-    dataFormatChanged = (value: DataFormatDefinition) => {
-        value.uuid = this.state.step?.uuid ? this.state.step?.uuid : value.uuid;
-        this.setStep(value);
-        this.props.onPropertyUpdate?.call(this, value);
-    }
-
-    expressionChanged = (propertyName: string, exp: ExpressionDefinition) => {
-        if (this.state.step) {
-            const clone = (CamelUtil.cloneStep(this.state.step));
-            (clone as any)[propertyName] = exp;
-            this.setStep(clone);
-            this.props.onPropertyUpdate?.call(this, clone);
-        }
-    }
+export function DslProperties(props: Props) {
 
-    parametersChanged = (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => {
-        if (this.state.step && this.state.step) {
-            const clone = (CamelUtil.cloneStep(this.state.step));
-            const parameters: any = {...(clone as any).parameters};
-            parameters[parameter] = value;
-            (clone as any).parameters = parameters;
-            this.setStep(clone);
-            this.props.onPropertyUpdate?.call(this, clone, newRoute);
-        }
-    }
+    const [integration, setIntegration] = useIntegrationStore((state) =>
+        [state.integration, state.setIntegration], shallow)
 
-    cloneElement = () => {
-        if (this.state.step) {
-            this.props.onClone?.call(this, this.state.step);
-        }
-    }
+    const {cloneElement, onDataFormatChange, onPropertyChange, onParametersChange, onExpressionChange} = usePropertiesHook(props.isRouteDesigner);
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevProps.step !== this.props.step) {
-            this.setStep(this.props.step);
-        }
-    }
+    const [selectedStep, dark, setSelectedStep, setSelectedUuids] = useDesignerStore((s) =>
+        [s.selectedStep, s.dark, s.setSelectedStep, s.setSelectedUuids], shallow)
 
-    setStep = (step?: CamelElement) => {
-        this.setState({
-            step: step,
-            selectStatus: new Map<string, boolean>()
-        });
-    }
+    const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
+    const [isDescriptionExpanded, setIsDescriptionExpanded] = useState<boolean>(false);
 
-    getRouteHeader= (): JSX.Element => {
-        const isDescriptionExpanded = this.state.isDescriptionExpanded;
-        const title = this.state.step && CamelUi.getTitle(this.state.step)
-        const description =  this.state.step &&  CamelUi.getDescription(this.state.step);
+    function getRouteHeader(): JSX.Element {
+        const title = selectedStep && CamelUi.getTitle(selectedStep)
+        const description = selectedStep && CamelUi.getDescription(selectedStep);
         const descriptionLines: string [] = description ? description?.split("\n") : [""];
         return (
             <div className="headers">
@@ -127,40 +61,42 @@ export class DslProperties extends React.Component<Props, State> {
                     <Title headingLevel="h1" size="md">{title}</Title>
                 </div>
                 <Text component={TextVariants.p}>{descriptionLines.at(0)}</Text>
-                {descriptionLines.length > 1 && <ExpandableSection toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'}
-                                                                   onToggle={(_event, isExpanded) => this.setState({isDescriptionExpanded: !isDescriptionExpanded})}
-                                                                   isExpanded={isDescriptionExpanded}>
-                    {descriptionLines.filter((value, index) => index > 0)
-                        .map((desc, index, array) => <Text key={index} component={TextVariants.p}>{desc}</Text>)}
-                </ExpandableSection>}
+                {descriptionLines.length > 1 &&
+                    <ExpandableSection toggleText={isDescriptionExpanded ? 'Show less' : 'Show more'}
+                                       onToggle={(_event, isExpanded) => setIsDescriptionExpanded(!isDescriptionExpanded)}
+                                       isExpanded={isDescriptionExpanded}>
+                        {descriptionLines.filter((value, index) => index > 0)
+                            .map((desc, index, array) => <Text key={index} component={TextVariants.p}>{desc}</Text>)}
+                    </ExpandableSection>}
             </div>
         )
     }
 
-    getClonableElementHeader = (): JSX.Element => {
-        const title = this.state.step && CamelUi.getTitle(this.state.step);
-        const description = this.state.step?.dslName ? CamelMetadataApi.getCamelModelMetadataByClassName(this.state.step?.dslName)?.description : title;
+    function getClonableElementHeader(): JSX.Element {
+        const title = selectedStep && CamelUi.getTitle(selectedStep);
+        const description = selectedStep?.dslName ? CamelMetadataApi.getCamelModelMetadataByClassName(selectedStep?.dslName)?.description : title;
         const descriptionLines: string [] = description ? description?.split("\n") : [""];
         return (
             <div className="headers">
                 <div className="top">
                     <Title headingLevel="h1" size="md">{title}</Title>
                     <Tooltip content="Clone element" position="bottom">
-                        <Button variant="link" onClick={() => this.cloneElement()} icon={<CloneIcon/>}/>
+                        <Button variant="link" onClick={() => cloneElement()} icon={<CloneIcon/>}/>
                     </Tooltip>
                 </div>
-                {descriptionLines.map((desc, index, array) => <Text key={index} component={TextVariants.p}>{desc}</Text>)}
+                {descriptionLines.map((desc, index, array) => <Text key={index}
+                                                                    component={TextVariants.p}>{desc}</Text>)}
             </div>
         )
     }
 
-    getComponentHeader = (): JSX.Element => {
-        if (this.props.isRouteDesigner) return this.getRouteHeader()
-        else return this.getClonableElementHeader();
+    function getComponentHeader(): JSX.Element {
+        if (props.isRouteDesigner) return getRouteHeader()
+        else return getClonableElementHeader();
     }
 
-    getProperties = (): PropertyMeta[] => {
-        const dslName = this.state.step?.dslName;
+    function getProperties(): PropertyMeta[] {
+        const dslName = selectedStep?.dslName;
         return CamelDefinitionApiExt.getElementProperties(dslName)
             // .filter((p: PropertyMeta) => (showAdvanced && p.label.includes('advanced')) || (!showAdvanced && !p.label.includes('advanced')))
             .filter((p: PropertyMeta) => !p.isObject || (p.isObject && !CamelUi.dslHasSteps(p.type)) || (dslName === 'CatchDefinition' && p.name === 'onWhen'))
@@ -168,58 +104,55 @@ export class DslProperties extends React.Component<Props, State> {
         // .filter((p: PropertyMeta) => dslName && !(['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(dslName) && ['param', 'responseMessage'].includes(p.name))) // TODO: configure this properties
     }
 
-    getPropertyFields = (properties: PropertyMeta[]) => {
+    function getPropertyFields(properties: PropertyMeta[]) {
         return (<>
             {properties.map((property: PropertyMeta) =>
                 <DslPropertyField key={property.name}
-                                  integration={this.props.integration}
                                   property={property}
-                                  element={this.state.step}
-                                  value={this.state.step ? (this.state.step as any)[property.name] : undefined}
-                                  onExpressionChange={this.expressionChanged}
-                                  onParameterChange={this.parametersChanged}
-                                  onDataFormatChange={this.dataFormatChanged}
-                                  onChange={this.propertyChanged}
-                                  dark={this.props.dark}/>
+                                  element={selectedStep}
+                                  value={selectedStep ? (selectedStep as any)[property.name] : undefined}
+                                  onExpressionChange={onExpressionChange}
+                                  onParameterChange={onParametersChange}
+                                  onDataFormatChange={onDataFormatChange}
+                                  onPropertyChange={onPropertyChange}
+                />
             )}
         </>)
     }
 
-    render() {
-        const dataFormats = DataFormats.map(value => value[0]);
-        const dataFormatElement = this.state.step !== undefined && ['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName);
-        const properties = !dataFormatElement
-                    ? this.getProperties()
-                    : this.getProperties().filter(p => !dataFormats.includes(p.name));
-        const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
-        const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
-        return (
-            <div key={this.state.step ? this.state.step.uuid : 'integration'}
-                 className='properties'>
-                <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
-                    {this.state.step === undefined && <IntegrationHeader integration={this.props.integration}/>}
-                    {this.state.step && this.getComponentHeader()}
-                    {this.getPropertyFields(propertiesMain)}
-                    {this.state.step && !['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName)
-                        && propertiesAdvanced.length > 0 &&
-                        <ExpandableSection
-                            toggleText={'Advanced properties'}
-                            onToggle={(_event, isExpanded) => this.setState({isShowAdvanced: !this.state.isShowAdvanced})}
-                            isExpanded={this.state.isShowAdvanced}>
-                            <div className="parameters">
-                                {this.getPropertyFields(propertiesAdvanced)}
-                            </div>
-                        </ExpandableSection>}
-                    {this.state.step && ['MarshalDefinition', 'UnmarshalDefinition'].includes(this.state.step.dslName) &&
-                        <DataFormatField
-                            integration={this.props.integration}
-                            dslName={this.state.step.dslName}
-                            value={this.state.step}
-                            onDataFormatChange={this.dataFormatChanged}
-                            dark={this.props.dark}/>
-                    }
-                </Form>
-            </div>
-        )
-    }
+    const dataFormats = DataFormats.map(value => value[0]);
+    const dataFormatElement = selectedStep !== undefined && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName);
+    const properties = !dataFormatElement
+        ? getProperties()
+        : getProperties().filter(p => !dataFormats.includes(p.name));
+    const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
+    const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
+    return (
+        <div key={selectedStep ? selectedStep.uuid : 'integration'}
+             className='properties'>
+            <Form autoComplete="off" onSubmit={event => event.preventDefault()}>
+                {selectedStep === undefined && <IntegrationHeader/>}
+                {selectedStep && getComponentHeader()}
+                {getPropertyFields(propertiesMain)}
+                {selectedStep && !['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName)
+                    && propertiesAdvanced.length > 0 &&
+                    <ExpandableSection
+                        toggleText={'Advanced properties'}
+                        onToggle={(_event, isExpanded) => setShowAdvanced(!showAdvanced)}
+                        isExpanded={showAdvanced}>
+                        <div className="parameters">
+                            {getPropertyFields(propertiesAdvanced)}
+                        </div>
+                    </ExpandableSection>}
+                {selectedStep && ['MarshalDefinition', 'UnmarshalDefinition'].includes(selectedStep.dslName) &&
+                    <DataFormatField
+                        integration={integration}
+                        dslName={selectedStep.dslName}
+                        value={selectedStep}
+                        onDataFormatChange={onDataFormatChange}
+                        dark={dark}/>
+                }
+            </Form>
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/route/DslSelector.tsx b/karavan-designer/src/designer/route/DslSelector.tsx
index 47eb3b39..2e383cb6 100644
--- a/karavan-designer/src/designer/route/DslSelector.tsx
+++ b/karavan-designer/src/designer/route/DslSelector.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useEffect, useState} from 'react';
 import {
     Badge,
     Card, CardBody, CardFooter, CardHeader, Flex, FlexItem, Form, FormGroup, Gallery, Modal, PageSection,
@@ -24,66 +24,62 @@ import {
 import '../karavan.css';
 import {CamelUi} from "../utils/CamelUi";
 import {DslMetaModel} from "../utils/DslMetaModel";
+import {useDesignerStore, useSelectorStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {useRouteDesignerHook} from "./useRouteDesignerHook";
 
 interface Props {
-    onDslSelect: (dsl: DslMetaModel, parentId: string, position?: number | undefined) => void,
-    onClose?: () => void,
-    parentId: string,
-    parentDsl?: string,
-    showSteps: boolean,
-    dark: boolean,
-    isOpen: boolean,
-    position?: number
     tabIndex?: string | number
 }
 
-interface State {
-    tabIndex: string | number
-    filter: string;
-    selectedLabels: string []
-}
+export function DslSelector (props: Props) {
 
-export class DslSelector extends React.Component<Props, State> {
+    const [showSelector, showSteps, parentId, parentDsl, selectorTabIndex, setShowSelector, setSelectorTabIndex,
+        selectedPosition, selectedLabels, addSelectedLabel, deleteSelectedLabel] =
+        useSelectorStore((s) =>
+            [s.showSelector, s.showSteps, s.parentId, s.parentDsl, s.selectorTabIndex, s.setShowSelector, s.setSelectorTabIndex,
+                s.selectedPosition, s.selectedLabels, s.addSelectedLabel, s.deleteSelectedLabel], shallow)
 
-    public state: State = {
-        tabIndex: this.props.tabIndex ? this.props.tabIndex : (this.props.parentDsl ? 'eip' : 'kamelet'),
-        filter: '',
-        selectedLabels: []
-    }
 
-    selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
-        this.setState({tabIndex: eventKey});
-    }
+    const [dark] = useDesignerStore((s) => [s.dark], shallow)
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevProps.parentDsl !== this.props.parentDsl) {
-            this.setState({tabIndex: CamelUi.getSelectorModelTypes(this.props.parentDsl, this.props.showSteps)[0][0]});
-        }
+    const {onDslSelect} = useRouteDesignerHook();
+
+
+    const [filter, setFilter] = useState<string>('');
+
+    useEffect(() => {
+    }, [selectedLabels]);
+
+
+    function selectTab(evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) {
+        setSelectorTabIndex(eventKey);
     }
 
-    selectDsl = (evt: React.MouseEvent, dsl: any) => {
+    function selectDsl(evt: React.MouseEvent, dsl: any) {
         evt.stopPropagation();
-        this.setState({filter: ""});
-        this.props.onDslSelect.call(this, dsl, this.props.parentId, this.props.position);
+        setFilter('');
+        setShowSelector(false);
+        onDslSelect(dsl, parentId, selectedPosition);
     }
 
-    searchInput = () => {
+    function searchInput() {
         return (
             <Form isHorizontal className="search" autoComplete="off">
                 <FormGroup fieldId="search">
-                    <TextInput className="text-field" type="text" id="search" name="search" 
-                            value={this.state.filter}
-                            onChange={(_, value) => this.setState({filter: value})}/>
+                    <TextInput className="text-field" type="text" id="search" name="search"
+                               value={filter}
+                               onChange={(_, value) => setFilter(value)}/>
                 </FormGroup>
             </Form>
         )
     }
 
-    getCard(dsl: DslMetaModel, index: number) {
+    function getCard(dsl: DslMetaModel, index: number) {
         const labels = dsl.labels !== undefined ? dsl.labels.split(",").filter(label => label !== 'eip') : [];
         return (
             <Card key={dsl.dsl + index} isCompact className="dsl-card"
-                  onClick={event => this.selectDsl(event, dsl)}>
+                  onClick={event => selectDsl(event, dsl)}>
                 <CardHeader className="header-labels">
                     <Badge isRead className="support-level labels">{dsl.supportLevel}</Badge>
                     {['kamelet', 'component'].includes(dsl.navigation.toLowerCase()) &&
@@ -99,7 +95,8 @@ export class DslSelector extends React.Component<Props, State> {
                 </CardBody>
                 <CardFooter className="footer-labels">
                     <div style={{display: "flex", flexDirection: "row", justifyContent: "start"}}>
-                        {labels.map(label => <Badge key={label} isRead className="labels">{label}</Badge>)}
+                        {labels.map((label, index) => <Badge key={label + "-" + index} isRead
+                                                             className="labels">{label}</Badge>)}
                     </div>
 
                 </CardFooter>
@@ -107,90 +104,80 @@ export class DslSelector extends React.Component<Props, State> {
         )
     }
 
-    close = () => {
-        this.setState({filter: ""});
-        this.props.onClose?.call(this);
+    function close() {
+        setFilter('');
+        setShowSelector(false);
     }
 
-    selectLabel = (eipLabel: string) => {
-        if (!this.state.selectedLabels.includes(eipLabel)) {
-            this.setState((state) => {
-                state.selectedLabels.push(eipLabel);
-                return state
-            })
+    function selectLabel(eipLabel: string) {
+        if (!selectedLabels.includes(eipLabel)) {
+            addSelectedLabel(eipLabel);
         } else {
-            this.setState((state) => {
-                const index = state.selectedLabels.findIndex((label) => label === eipLabel);
-                state.selectedLabels.splice(index, 1);
-                return state;
-            })
+            deleteSelectedLabel(eipLabel);
         }
     }
 
-    render() {
-        const isEip = this.state.tabIndex === 'eip';
-        const {parentDsl, isOpen} = this.props;
-        const title = parentDsl === undefined ? "Select source" : "Select step";
-        const navigation: string = this.state.tabIndex ? this.state.tabIndex.toString() : "";
-        const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, navigation, this.props.showSteps);
-        const eipLabels = [...new Set(elements.map(e => e.labels).join(",").split(",").filter(e => e !== 'eip'))];
-        const filteredElement = elements
-            .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, this.state.filter))
-            .filter((dsl: DslMetaModel) => {
-                if (!isEip || this.state.selectedLabels.length === 0) {
-                    return true;
-                } else {
-                    return dsl.labels.split(",").some(r => this.state.selectedLabels.includes(r));
-                }
-            });
+    const isEip = selectorTabIndex === 'eip';
+    const title = parentDsl === undefined ? "Select source" : "Select step";
+    const navigation: string = selectorTabIndex ? selectorTabIndex.toString() : '';
+    const elements = CamelUi.getSelectorModelsForParentFiltered(parentDsl, navigation, showSteps);
+    const eipLabels = [...new Set(elements.map(e => e.labels).join(",").split(",").filter(e => e !== 'eip'))];
+    const filteredElement = elements
+        .filter((dsl: DslMetaModel) => CamelUi.checkFilter(dsl, filter))
+        .filter((dsl: DslMetaModel) => {
+            if (!isEip || selectedLabels.length === 0) {
+                return true;
+            } else {
+                return dsl.labels.split(",").some(r => selectedLabels.includes(r));
+            }
+        });
 
-        return (
-            <Modal
-                aria-label={title}
-                width={'90%'}
-                className='dsl-modal'
-                isOpen={this.props.isOpen}
-                onClose={() => this.close()}
-                header={
-                    <Flex direction={{default: "column"}}>
-                        <FlexItem>
-                            <h3>{title}</h3>
-                            {this.searchInput()}
-                        </FlexItem>
-                        <FlexItem>
-                            <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex}
-                                  onSelect={this.selectTab}>
-                                {parentDsl !== undefined &&
-                                    <Tab eventKey={"eip"} key={"tab-eip"}
-                                         title={<TabTitleText>Integration Patterns</TabTitleText>}>
-                                    </Tab>
-                                }
-                                <Tab eventKey={'kamelet'} key={"tab-kamelet"}
-                                     title={<TabTitleText>Kamelets</TabTitleText>}>
+    return (
+        <Modal
+            aria-label={title}
+            width={'90%'}
+            className='dsl-modal'
+            isOpen={showSelector}
+            onClose={() => close()}
+            header={
+                <Flex direction={{default: "column"}}>
+                    <FlexItem>
+                        <h3>{title}</h3>
+                        {searchInput()}
+                    </FlexItem>
+                    <FlexItem>
+                        <Tabs style={{overflow: 'hidden'}} activeKey={selectorTabIndex}
+                              onSelect={selectTab}>
+                            {parentDsl !== undefined &&
+                                <Tab eventKey={"eip"} key={"tab-eip"}
+                                     title={<TabTitleText>Integration Patterns</TabTitleText>}>
                                 </Tab>
-                                <Tab eventKey={'component'} key={'tab-component'}
-                                     title={<TabTitleText>Components</TabTitleText>}>
-                                </Tab>
-                            </Tabs>
-                        </FlexItem>
-                    </Flex>
-                }
-                actions={{}}>
-                <PageSection padding={{default:"noPadding"}} variant={this.props.dark ? "darker" : "light"}>
-                    {isEip && <ToggleGroup aria-label="Labels" isCompact>
-                        {eipLabels.map(eipLabel => <ToggleGroupItem
-                            key={eipLabel}
-                            text={eipLabel}
-                            buttonId={eipLabel}
-                            isSelected={this.state.selectedLabels.includes(eipLabel)}
-                            onChange={selected => this.selectLabel(eipLabel)}
-                        />)}
-                    </ToggleGroup>}
-                    <Gallery key={"gallery-" + navigation} hasGutter className="dsl-gallery">
-                        {isOpen && filteredElement.map((dsl: DslMetaModel, index: number) => this.getCard(dsl, index))}
-                    </Gallery>
-                </PageSection>
-            </Modal>
-        )
-    }
+                            }
+                            <Tab eventKey={'kamelet'} key={"tab-kamelet"}
+                                 title={<TabTitleText>Kamelets</TabTitleText>}>
+                            </Tab>
+                            <Tab eventKey={'component'} key={'tab-component'}
+                                 title={<TabTitleText>Components</TabTitleText>}>
+                            </Tab>
+                        </Tabs>
+                    </FlexItem>
+                </Flex>
+            }
+            actions={{}}>
+            <PageSection padding={{default: "noPadding"}} variant={dark ? "darker" : "light"}>
+                {isEip && <ToggleGroup aria-label="Labels" isCompact>
+                    {eipLabels.map(eipLabel => <ToggleGroupItem
+                        key={eipLabel}
+                        text={eipLabel}
+                        buttonId={eipLabel}
+                        isSelected={selectedLabels.includes(eipLabel)}
+                        onChange={selected => selectLabel(eipLabel)}
+                    />)}
+                </ToggleGroup>}
+                <Gallery key={"gallery-" + navigation} hasGutter className="dsl-gallery">
+                    {showSelector && filteredElement.map((dsl: DslMetaModel, index: number) => getCard(dsl, index))}
+                </Gallery>
+            </PageSection>
+        </Modal>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx b/karavan-designer/src/designer/route/RouteDesigner.tsx
index f7607b90..fcf2d6fe 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -14,182 +14,109 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useCallback, useEffect, useRef} from 'react';
 import {
     Drawer,
     DrawerPanelContent,
     DrawerContent,
     DrawerContentBody,
-    Button, Modal,
-    PageSection,
+    Button
 } from '@patternfly/react-core';
 import '../karavan.css';
 import {DslSelector} from "./DslSelector";
 import {DslProperties} from "./DslProperties";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {DslConnections} from "./DslConnections";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {DslElement} from "./DslElement";
 import {CamelUi} from "../utils/CamelUi";
-import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {RouteDesignerLogic} from "./RouteDesignerLogic";
+import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import {useConnectionsStore, useDesignerStore, useIntegrationStore, useSelectorStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+import useResizeObserver from "./useResizeObserver";
+import {Command, EventBus} from "../utils/EventBus";
+import useMutationsObserver from "./useDrawerMutationsObserver";
+import {DeleteConfirmation} from "./DeleteConfirmation";
 
-interface Props {
-    onSave?: (integration: Integration, propertyOnly: boolean) => void
-    integration: Integration
-    dark: boolean
-}
+export function RouteDesigner() {
 
-export interface RouteDesignerState {
-    logic: RouteDesignerLogic
-    integration: Integration
-    selectedStep?: CamelElement
-    showSelector: boolean
-    showDeleteConfirmation: boolean
-    deleteMessage: string
-    parentId: string
-    parentDsl?: string
-    selectedPosition?: number
-    showSteps: boolean
-    selectedUuids: string []
-    key: string
-    width: number
-    height: number
-    top: number
-    left: number
-    clipboardSteps: CamelElement[]
-    shiftKeyPressed?: boolean
-    ref?: any
-    printerRef?: any
-    propertyOnly: boolean
-    selectorTabIndex?: string | number
-}
+    const {openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement} = useRouteDesignerHook();
 
-export class RouteDesigner extends React.Component<Props, RouteDesignerState> {
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+    const [showDeleteConfirmation, setPosition, width, height, top, left, hideLogDSL] = useDesignerStore((s) =>
+        [s.showDeleteConfirmation, s.setPosition, s.width, s.height, s.top, s.left, s.hideLogDSL], shallow)
 
-    public state: RouteDesignerState = {
-        logic: new RouteDesignerLogic(this),
-        integration: CamelDisplayUtil.setIntegrationVisibility(this.props.integration, undefined),
-        showSelector: false,
-        showDeleteConfirmation: false,
-        deleteMessage: '',
-        parentId: '',
-        showSteps: true,
-        selectedUuids: [],
-        clipboardSteps: [],
-        key: "",
-        width: 1000,
-        height: 1000,
-        top: 0,
-        left: 0,
-        ref: React.createRef(),
-        printerRef: React.createRef(),
-        propertyOnly: false,
-    };
+    const [showSelector] = useSelectorStore((s) => [s.showSelector], shallow)
 
-    componentDidMount() {
-        this.state.logic.componentDidMount();
-    }
-
-    componentWillUnmount() {
-        this.state.logic.componentWillUnmount();
-    }
-
-    handleResize = (event: any) => {
-        return this.state.logic.handleResize(event);
-    }
-
-    handleKeyDown = (event: KeyboardEvent) => {
-        return this.state.logic.handleKeyDown(event);
-    }
+    const [clearSteps] = useConnectionsStore((s) => [s.clearSteps], shallow)
 
-    handleKeyUp = (event: KeyboardEvent) => {
-        return this.state.logic.handleKeyUp(event);
-    }
+    const onChangeGraphSize = useCallback((target: HTMLDivElement)  => {
+        changeGraphSize();
+    }, [])
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
-        return this.state.logic.componentDidUpdate(prevState, snapshot);
+    function changeGraphSize ()  {
+        if (flowRef && flowRef.current) {
+            const el = flowRef.current;
+            const rect = el.getBoundingClientRect();
+            setPosition(rect.width, rect.height, rect.top, rect.left)
+        }
     }
 
-    getSelectorModal() {
-        return (
-            <DslSelector
-                isOpen={this.state.showSelector}
-                onClose={() => this.state.logic.closeDslSelector()}
-                dark={this.props.dark}
-                parentId={this.state.parentId}
-                parentDsl={this.state.parentDsl}
-                showSteps={this.state.showSteps}
-                position={this.state.selectedPosition}
-                tabIndex={this.state.selectorTabIndex}
-                onDslSelect={this.state.logic.onDslSelect}/>)
-    }
+    const firstRef = useResizeObserver(onChangeGraphSize);
+    const secondRef = useMutationsObserver(onChangeGraphSize);
+    const printerRef = useRef<HTMLDivElement | null>(null);
+    const flowRef = useRef<HTMLDivElement | null>(null);
 
-    getDeleteConfirmation() {
-        let htmlContent: string = this.state.deleteMessage;
-        return (<Modal
-            className="modal-delete"
-            title="Confirmation"
-            isOpen={this.state.showDeleteConfirmation}
-            onClose={() => this.setState({showDeleteConfirmation: false})}
-            actions={[
-                <Button key="confirm" variant="primary" onClick={e => this.state.logic.deleteElement()}>Delete</Button>,
-                <Button key="cancel" variant="link"
-                        onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
-            ]}
-            onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
-            <div>
-                {htmlContent}
-            </div>
-        </Modal>)
-    }
+    useEffect(()=> {
+        // window.addEventListener('resize', changeGraphSize);
+        const interval = setInterval(() => {
+            changeGraphSize();
+        }, 500);
+        window.addEventListener('keydown', handleKeyDown);
+        window.addEventListener('keyup', handleKeyUp);
+        const commandSub = EventBus.onCommand()?.subscribe((command: Command) => onCommand(command, printerRef));
+        if (flowRef.current === null) {
+            clearSteps();
+        } else {
+            changeGraphSize();
+        }
+        return ()=> {
+            clearInterval(interval)
+            // window.removeEventListener('resize', changeGraphSize);
+            window.removeEventListener('keydown', handleKeyDown);
+            window.removeEventListener('keyup', handleKeyUp);
+            commandSub?.unsubscribe();
+        }
+    }, [showSelector, integration])
 
-    getPropertiesPanel() {
+    function getPropertiesPanel() {
         return (
-            <DrawerPanelContent onResize={(_event, width) => this.setState({key: Math.random().toString()})}
-                                style={{transform: "initial"}} isResizable hasNoBorder defaultSize={'400px'}
+            <DrawerPanelContent style={{transform: "initial"}} isResizable hasNoBorder defaultSize={'400px'}
                                 maxSize={'800px'} minSize={'300px'}>
-                <DslProperties ref={this.state.ref}
-                               integration={this.state.integration}
-                               step={this.state.selectedStep}
-                               onIntegrationUpdate={this.state.logic.onIntegrationUpdate}
-                               onPropertyUpdate={this.state.logic.onPropertyUpdate}
-                               isRouteDesigner={true}
-                               dark={this.props.dark}/>
+                <DslProperties isRouteDesigner={true}/>
             </DrawerPanelContent>
         )
     }
 
-    getGraph() {
-        const {selectedUuids, integration, key, width, height, top, left} = this.state;
+    function getGraph() {
         const routes = CamelUi.getRoutes(integration);
         const routeConfigurations = CamelUi.getRouteConfigurations(integration);
         return (
-            <div ref={this.state.printerRef} className="graph">
-                <DslConnections height={height} width={width} top={top} left={left} integration={integration}/>
-                <div className="flows" data-click="FLOWS" onClick={event => this.state.logic.unselectElement(event)}
-                     ref={el => this.state.logic.onResizePage(el)}>
+            <div className="graph" ref={printerRef}>
+                <DslConnections/>
+                <div id="flows"
+                     className="flows"
+                     data-click="FLOWS"
+                     onClick={event => {unselectElement(event)}}
+                     ref={flowRef}>
                     {routeConfigurations?.map((routeConfiguration, index: number) => (
-                        <DslElement key={routeConfiguration.uuid + key}
-                                    integration={integration}
-                                    openSelector={this.state.logic.openSelector}
-                                    deleteElement={this.state.logic.showDeleteConfirmation}
-                                    selectElement={this.state.logic.selectElement}
-                                    moveElement={this.state.logic.moveElement}
-                                    selectedUuid={selectedUuids}
+                        <DslElement key={routeConfiguration.uuid}
                                     inSteps={false}
                                     position={index}
                                     step={routeConfiguration}
                                     parent={undefined}/>
                     ))}
                     {routes?.map((route: any, index: number) => (
-                        <DslElement key={route.uuid + key}
-                                    integration={integration}
-                                    openSelector={this.state.logic.openSelector}
-                                    deleteElement={this.state.logic.showDeleteConfirmation}
-                                    selectElement={this.state.logic.selectElement}
-                                    moveElement={this.state.logic.moveElement}
-                                    selectedUuid={selectedUuids}
+                        <DslElement key={route.uuid}
                                     inSteps={false}
                                     position={index}
                                     step={route}
@@ -199,31 +126,36 @@ export class RouteDesigner extends React.Component<Props, RouteDesignerState> {
                         <Button
                             variant={routes.length === 0 ? "primary" : "secondary"}
                             icon={<PlusIcon/>}
-                            onClick={e => this.state.logic.openSelector(undefined, undefined)}>Create route
+                            onClick={e => {
+                                openSelector(undefined, undefined)
+                            }}
+                        >
+                            Create route
                         </Button>
                         <Button
                             variant="secondary"
                             icon={<PlusIcon/>}
-                            onClick={e => this.state.logic.createRouteConfiguration()}>Create configuration
+                            onClick={e => createRouteConfiguration()}
+                        >
+                            Create configuration
                         </Button>
                     </div>
                 </div>
             </div>)
     }
 
-    render() {
-        return (
-            <PageSection className="dsl-page" isFilled padding={{default: 'noPadding'}}>
-                <div className="dsl-page-columns">
-                    <Drawer isExpanded isInline>
-                        <DrawerContent panelContent={this.getPropertiesPanel()}>
-                            <DrawerContentBody>{this.getGraph()}</DrawerContentBody>
-                        </DrawerContent>
-                    </Drawer>
-                </div>
-                {this.state.showSelector === true && this.getSelectorModal()}
-                {this.getDeleteConfirmation()}
-            </PageSection>
-        );
-    }
+    const hasFlows = integration?.spec?.flows?.length && integration?.spec?.flows?.length > 0;
+    return (
+        <div className="dsl-page" ref={firstRef}>
+            <div className="dsl-page-columns" ref={secondRef}>
+                <Drawer isExpanded isInline>
+                    <DrawerContent panelContent={getPropertiesPanel()}>
+                        <DrawerContentBody>{hasFlows && getGraph()}</DrawerContentBody>
+                    </DrawerContent>
+                </Drawer>
+            </div>
+            {showSelector && <DslSelector/>}
+            {showDeleteConfirmation && <DeleteConfirmation/>}
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/RouteDesignerLogic.tsx b/karavan-designer/src/designer/route/RouteDesignerLogic.tsx
deleted file mode 100644
index b352a056..00000000
--- a/karavan-designer/src/designer/route/RouteDesignerLogic.tsx
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react';
-import '../karavan.css';
-import {DslMetaModel} from "../utils/DslMetaModel";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {ChoiceDefinition, FromDefinition, LogDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
-import {Command, EventBus} from "../utils/EventBus";
-import {RouteToCreate} from "../utils/CamelUi";
-import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {toPng} from 'html-to-image';
-import {RouteDesigner, RouteDesignerState} from "./RouteDesigner";
-import {findDOMNode} from "react-dom";
-import {Subscription} from "rxjs";
-import debounce from 'lodash.debounce';
-
-export class RouteDesignerLogic {
-
-    routeDesigner: RouteDesigner
-    commandSub?: Subscription
-
-    constructor(routeDesigner: RouteDesigner) {
-        this.routeDesigner = routeDesigner;
-    }
-
-    componentDidMount() {
-        window.addEventListener('resize', this.routeDesigner.handleResize);
-        window.addEventListener('keydown', this.routeDesigner.handleKeyDown);
-        window.addEventListener('keyup', this.routeDesigner.handleKeyUp);
-        const element = findDOMNode(this.routeDesigner.state.ref.current)?.parentElement?.parentElement;
-        const checkResize = (mutations: any) => {
-            const el = mutations[0].target;
-            const w = el.clientWidth;
-            const isChange = mutations.map((m: any) => `${m.oldValue}`).some((prev: any) => prev.indexOf(`width: ${w}px`) === -1);
-            if (isChange) this.routeDesigner.setState({key: Math.random().toString()});
-        }
-        if (element) {
-            const observer = new MutationObserver(checkResize);
-            observer.observe(element, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
-        }
-        this.commandSub = EventBus.onCommand()?.subscribe((command: Command) => this.onCommand(command));
-    }
-
-    componentWillUnmount() {
-        window.removeEventListener('resize', this.routeDesigner.handleResize);
-        window.removeEventListener('keydown', this.routeDesigner.handleKeyDown);
-        window.removeEventListener('keyup', this.routeDesigner.handleKeyUp);
-        this.commandSub?.unsubscribe();
-    }
-
-    handleResize = (event: any) => {
-        this.routeDesigner.setState({key: Math.random().toString()});
-    }
-
-    handleKeyDown = (event: KeyboardEvent) => {
-        if ((event.shiftKey)) {
-            this.routeDesigner.setState({shiftKeyPressed: true});
-        }
-        if (window.document.hasFocus() && window.document.activeElement) {
-            if (['BODY', 'MAIN'].includes(window.document.activeElement.tagName)) {
-                let charCode = String.fromCharCode(event.which).toLowerCase();
-                if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
-                    this.copyToClipboard();
-                } else if ((event.ctrlKey || event.metaKey) && charCode === 'v') {
-                    this.pasteFromClipboard();
-                }
-            }
-        } else {
-            if (event.repeat) {
-                window.dispatchEvent(event);
-            }
-        }
-    }
-
-    handleKeyUp = (event: KeyboardEvent) => {
-        this.routeDesigner.setState({shiftKeyPressed: false});
-        if (event.repeat) {
-            window.dispatchEvent(event);
-        }
-    }
-
-    componentDidUpdate = (prevState: Readonly<RouteDesignerState>, snapshot?: any) => {
-        if (prevState.key !== this.routeDesigner.state.key) {
-            this.routeDesigner.props.onSave?.call(this, this.routeDesigner.state.integration, this.routeDesigner.state.propertyOnly);
-        }
-    }
-
-    copyToClipboard = (): void => {
-        const {integration, selectedUuids} = this.routeDesigner.state;
-        const steps: CamelElement[] = []
-        selectedUuids.forEach(selectedUuid => {
-            const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
-            if (selectedElement) {
-                steps.push(selectedElement);
-            }
-        })
-        if (steps.length >0) {
-            this.routeDesigner.setState(prevState => ({
-                key: Math.random().toString(),
-                clipboardSteps: [...steps]
-            }));
-        }
-    }
-    pasteFromClipboard = (): void => {
-        const {integration, selectedUuids, clipboardSteps} = this.routeDesigner.state;
-        if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
-            const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
-            const route = CamelDefinitionApi.createRouteDefinition({from: clone});
-            this.addStep(route, '', 0)
-        } else if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'RouteDefinition') {
-            const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
-            this.addStep(clone, '', 0)
-        } else if (selectedUuids.length === 1) {
-            const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
-            clipboardSteps.reverse().forEach(clipboardStep => {
-                if (clipboardStep && targetMeta.parentUuid) {
-                    const clone = CamelUtil.cloneStep(clipboardStep, true);
-                    this.addStep(clone, targetMeta.parentUuid, targetMeta.position);
-                }
-            })
-        }
-    }
-
-    onCommand = (command: Command) => {
-        switch (command.command){
-            case "downloadImage": this.integrationImageDownload()
-        }
-    }
-
-    onPropertyUpdate = debounce((element: CamelElement, newRoute?: RouteToCreate) => {
-        if (newRoute) {
-            let i = CamelDefinitionApiExt.updateIntegrationRouteElement(this.routeDesigner.state.integration, element);
-            const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}});
-            const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
-            i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
-            const clone = CamelUtil.cloneIntegration(i);
-            this.routeDesigner.setState(prevState => ({
-                integration: clone,
-                key: Math.random().toString(),
-                showSelector: false,
-                selectedStep: element,
-                propertyOnly: false,
-                selectedUuids: [element.uuid]
-            }));
-        } else {
-            const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
-            const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
-            this.routeDesigner.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
-        }
-    }, 300, {leading: true})
-
-    showDeleteConfirmation = (id: string) => {
-        let message: string;
-        const uuidsToDelete:string [] = [id];
-        let ce: CamelElement;
-        ce = CamelDefinitionApiExt.findElementInIntegration(this.routeDesigner.state.integration, id)!;
-        if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this.routeDesigner.  Use its uuid.
-            let flows = this.routeDesigner.state.integration.spec.flows!;
-            for (let i = 0; i < flows.length; i++) {
-                if (flows[i].dslName === 'RouteDefinition') {
-                    let routeDefinition: RouteDefinition = flows[i];
-                    if (routeDefinition.from.uuid === id) {
-                        uuidsToDelete.push(routeDefinition.uuid);
-                        break;
-                    }
-                }
-            }
-            message = 'Deleting the first element will delete the entire route!';
-        } else if (ce.dslName === 'RouteDefinition') {
-            message = 'Delete route?';
-        } else if (ce.dslName === 'RouteConfigurationDefinition') {
-            message = 'Delete route configuration?';
-        } else {
-            message = 'Delete element from route?';
-        }
-        this.routeDesigner.setState(prevState => ({
-            showSelector: false,
-            showDeleteConfirmation: true,
-            deleteMessage: message,
-            selectedUuids: uuidsToDelete,
-        }));
-    }
-
-    deleteElement = () => {
-        this.routeDesigner.state.selectedUuids.forEach(uuidToDelete => {
-            const i = CamelDefinitionApiExt.deleteStepFromIntegration(this.routeDesigner.state.integration, uuidToDelete);
-            this.routeDesigner.setState(prevState => ({
-                integration: i,
-                showSelector: false,
-                showDeleteConfirmation: false,
-                deleteMessage: '',
-                key: Math.random().toString(),
-                selectedStep: undefined,
-                propertyOnly: false,
-                selectedUuids: [uuidToDelete],
-            }));
-            const el = new CamelElement("");
-            el.uuid = uuidToDelete;
-            EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0);
-        });
-    }
-
-    selectElement = (element: CamelElement) => {
-        const {shiftKeyPressed, selectedUuids, integration} = this.routeDesigner.state;
-        let canNotAdd: boolean = false;
-        if (shiftKeyPressed) {
-            const hasFrom = selectedUuids.map(e => CamelDefinitionApiExt.findElementInIntegration(integration, e)?.dslName === 'FromDefinition').filter(r => r).length > 0;
-            canNotAdd = hasFrom || (selectedUuids.length > 0 && element.dslName === 'FromDefinition');
-        }
-        const add = shiftKeyPressed && !selectedUuids.includes(element.uuid);
-        const remove = shiftKeyPressed && selectedUuids.includes(element.uuid);
-        const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, element.uuid);
-        this.routeDesigner.setState((prevState: RouteDesignerState) => {
-            if (remove) {
-                const index = prevState.selectedUuids.indexOf(element.uuid);
-                prevState.selectedUuids.splice(index, 1);
-            } else if (add && !canNotAdd) {
-                prevState.selectedUuids.push(element.uuid);
-            }
-            const uuid: string = prevState.selectedUuids.includes(element.uuid) ? element.uuid : prevState.selectedUuids.at(0) || '';
-            const selectedElement = shiftKeyPressed ? CamelDefinitionApiExt.findElementInIntegration(integration, uuid) : element;
-            return {
-                integration: i,
-                selectedStep: selectedElement,
-                showSelector: false,
-                selectedUuids: shiftKeyPressed ? [...prevState.selectedUuids] : [element.uuid],
-            }
-        });
-    }
-
-    unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
-        if ((evt.target as any).dataset.click === 'FLOWS') {
-            evt.stopPropagation()
-            const i = CamelDisplayUtil.setIntegrationVisibility(this.routeDesigner.state.integration, undefined);
-            this.routeDesigner.setState(prevState => ({
-                integration: i,
-                selectedStep: undefined,
-                showSelector: false,
-                selectedPosition: undefined,
-                selectedUuids: [],
-            }));
-        }
-    }
-
-    openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
-        this.routeDesigner.setState({
-            showSelector: true,
-            parentId: parentId || '',
-            parentDsl: parentDsl,
-            showSteps: showSteps,
-            selectedPosition: position,
-            selectorTabIndex: selectorTabIndex
-        })
-    }
-
-    closeDslSelector = () => {
-        this.routeDesigner.setState({showSelector: false})
-    }
-
-    onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
-        switch (dsl.dsl) {
-            case 'FromDefinition' :
-                const route = CamelDefinitionApi.createRouteDefinition({from: new FromDefinition({uri: dsl.uri})});
-                this.addStep(route, parentId, position)
-                break;
-            case 'ToDefinition' :
-                const to = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
-                this.addStep(to, parentId, position)
-                break;
-            case 'ToDynamicDefinition' :
-                const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
-                this.addStep(toD, parentId, position)
-                break;
-            case 'KameletDefinition' :
-                const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: dsl.name});
-                this.addStep(kamelet, parentId, position)
-                break;
-            default:
-                const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
-                const augmentedStep = this.setDslDefaults(step);
-                this.addStep(augmentedStep, parentId, position)
-                break;
-        }
-    }
-
-    setDslDefaults(step: CamelElement): CamelElement {
-        if (step.dslName === 'LogDefinition') {
-            // eslint-disable-next-line no-template-curly-in-string
-            (step as LogDefinition).message = "${body}";
-        }
-        if (step.dslName === 'ChoiceDefinition') {
-            (step as ChoiceDefinition).when?.push(CamelDefinitionApi.createStep('WhenDefinition', undefined));
-            (step as ChoiceDefinition).otherwise = CamelDefinitionApi.createStep('OtherwiseDefinition', undefined);
-        }
-        return step;
-    }
-
-    createRouteConfiguration = () => {
-        const clone = CamelUtil.cloneIntegration(this.routeDesigner.state.integration);
-        const routeConfiguration = new RouteConfigurationDefinition();
-        const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
-        this.routeDesigner.setState(prevState => ({
-            integration: i,
-            propertyOnly: false,
-            key: Math.random().toString(),
-            selectedStep: routeConfiguration,
-            selectedUuids: [routeConfiguration.uuid],
-        }));
-    }
-
-    addStep = (step: CamelElement, parentId: string, position?: number | undefined) => {
-        const i = CamelDefinitionApiExt.addStepToIntegration(this.routeDesigner.state.integration, step, parentId, position);
-        const clone = CamelUtil.cloneIntegration(i);
-        EventBus.sendPosition("clean", step, undefined, new DOMRect(), new DOMRect(), 0);
-        const selectedStep = step.dslName === 'RouteDefinition' ? (step as RouteDefinition).from  : step;
-        this.routeDesigner.setState(prevState => ({
-            integration: clone,
-            key: Math.random().toString(),
-            showSelector: false,
-            selectedStep: selectedStep,
-            propertyOnly: false,
-            selectedUuids: [selectedStep.uuid],
-        }));
-    }
-
-    onIntegrationUpdate = (i: Integration) => {
-        this.routeDesigner.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
-    }
-
-    moveElement = (source: string, target: string, asChild: boolean) => {
-        const i = CamelDefinitionApiExt.moveRouteElement(this.routeDesigner.state.integration, source, target, asChild);
-        const clone = CamelUtil.cloneIntegration(i);
-        const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
-        this.routeDesigner.setState(prevState => ({
-            integration: clone,
-            key: Math.random().toString(),
-            showSelector: false,
-            selectedStep: selectedStep,
-            propertyOnly: false,
-            selectedUuids: [source],
-        }));
-    }
-
-    onResizePage(el: HTMLDivElement | null) {
-        const rect = el?.getBoundingClientRect();
-        if (el && rect && (el.scrollWidth !== this.routeDesigner.state.width || el.scrollHeight !== this.routeDesigner.state.height || rect.top !== this.routeDesigner.state.top || rect.left !== this.routeDesigner.state.left)) {
-            this.routeDesigner.setState({width: el.scrollWidth, height: el.scrollHeight, top: rect.top, left: rect.left})
-        }
-    }
-
-    downloadIntegrationImage(dataUrl: string) {
-        const a = document.createElement('a');
-        a.setAttribute('download', 'karavan-routes.png');
-        a.setAttribute('href', dataUrl);
-        a.click();
-    }
-
-    integrationImageDownloadFilter = (node: HTMLElement) => {
-        const exclusionClasses = ['add-flow'];
-        return !exclusionClasses.some(classname => {
-            return node.classList === undefined ? false : node.classList.contains(classname);
-        });
-    }
-
-    integrationImageDownload() {
-        if (this.routeDesigner.state.printerRef.current === null) {
-            return
-        }
-        toPng(this.routeDesigner.state.printerRef.current, {
-            style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter,
-            height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
-        }).then(v => {
-            toPng(this.routeDesigner.state.printerRef.current, {
-                style: {overflow: 'hidden'}, cacheBust: true, filter: this.integrationImageDownloadFilter,
-                height: this.routeDesigner.state.height, width: this.routeDesigner.state.width, backgroundColor: this.routeDesigner.props.dark ? "black" : "white"
-            }).then(this.downloadIntegrationImage);
-        })
-    }
-}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
index 69175d98..34c6cadb 100644
--- a/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
+++ b/karavan-designer/src/designer/route/property/ComponentParameterField.tsx
@@ -14,23 +14,23 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useRef, useState} from 'react';
 import {
-	FormGroup,
-	TextInput,
-	Popover,
-	Switch,
-	InputGroup,
-	TextArea,
-	Tooltip,
-	Button,
-	capitalize, InputGroupItem
+    FormGroup,
+    TextInput,
+    Popover,
+    Switch,
+    InputGroup,
+    TextArea,
+    Tooltip,
+    Button,
+    capitalize, InputGroupItem
 } from '@patternfly/react-core';
 import {
-	Select,
-	SelectVariant,
-	SelectDirection,
-	SelectOption
+    Select,
+    SelectVariant,
+    SelectDirection,
+    SelectOption
 } from '@patternfly/react-core/deprecated';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -48,70 +48,68 @@ import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
 import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
 import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {usePropertiesHook} from "../usePropertiesHook";
+import {useDesignerStore, useIntegrationStore} from "../../KaravanStore";
+import {shallow} from "zustand/shallow";
 
 const prefix = "parameters";
 const beanPrefix = "#bean:";
 
 interface Props {
     property: ComponentProperty,
-    integration: Integration,
     element?: CamelElement,
     value: any,
     onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => void
 }
 
-interface State {
-    selectStatus: Map<string, boolean>
-    showEditor: boolean
-    showPassword: boolean
-    showInfrastructureSelector: boolean
-    infrastructureSelectorProperty?: string
-    ref: any
-    id: string
-}
+export function ComponentParameterField(props: Props) {
 
-export class ComponentParameterField extends React.Component<Props, State> {
+    const {onParametersChange, getInternalComponentName} = usePropertiesHook();
 
-    public state: State = {
-        selectStatus: new Map<string, boolean>(),
-        showEditor: false,
-        showPassword: false,
-        showInfrastructureSelector: false,
-        ref: React.createRef(),
-        id: prefix + "-" + this.props.property.name
-    }
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+
+    const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
+    const [showEditor, setShowEditor] = useState<boolean>(false);
+    const [showPassword, setShowPassword] = useState<boolean>(false);
+    const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false);
+    const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined);
 
-    parametersChanged = (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => {
-        this.props.onParameterChange?.call(this, parameter, value, pathParameter, newRoute);
-        this.setState({selectStatus: new Map<string, boolean>([[parameter, false]])});
+    const [id, setId] = useState<string>(prefix + "-" + props.property.name);
+    const ref = useRef<any>(null);
+
+
+    function parametersChanged(parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) {
+        onParametersChange(parameter, value, pathParameter, newRoute);
+        setSelectStatus(new Map<string, boolean>([[parameter, false]]))
     }
 
-    openSelect = (propertyName: string, isExpanded: boolean) => {
-        this.setState({selectStatus: new Map<string, boolean>([[propertyName, isExpanded]])});
+    function openSelect(propertyName: string, isExpanded: boolean) {
+        setSelectStatus(new Map<string, boolean>([[propertyName, isExpanded]]))
     }
 
-    isSelectOpen = (propertyName: string): boolean => {
-        return this.state.selectStatus.has(propertyName) && this.state.selectStatus.get(propertyName) === true;
+    function isSelectOpen(propertyName: string): boolean {
+        return selectStatus.has(propertyName) && selectStatus.get(propertyName) === true;
     }
 
-    getSelectBean = (property: ComponentProperty, value: any) => {
+    function getSelectBean(property: ComponentProperty, value: any) {
         const selectOptions: JSX.Element[] = [];
-        const beans = CamelUi.getBeans(this.props.integration);
+        const beans = CamelUi.getBeans(integration);
         if (beans) {
             selectOptions.push(<SelectOption key={0} value={"Select..."} isPlaceholder/>);
-            selectOptions.push(...beans.map((bean) => <SelectOption key={bean.name} value={beanPrefix + bean.name} description={bean.type}/>));
+            selectOptions.push(...beans.map((bean) => <SelectOption key={bean.name} value={beanPrefix + bean.name}
+                                                                    description={bean.type}/>));
         }
         return (
             <Select
-                id={this.state.id} name={this.state.id}
+                id={id} name={id}
                 variant={SelectVariant.single}
                 aria-label={property.name}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
-                onSelect={(e, value, isPlaceholder) => this.parametersChanged(property.name, (!isPlaceholder ? value : undefined))}
+                onSelect={(e, value, isPlaceholder) => parametersChanged(property.name, (!isPlaceholder ? value : undefined))}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
             >
@@ -120,30 +118,19 @@ export class ComponentParameterField extends React.Component<Props, State> {
         )
     }
 
-    canBeInternalUri = (property: ComponentProperty): boolean => {
-        if (this.props.element && this.props.element.dslName === 'ToDefinition' && property.name === 'name') {
-            const uri: string = (this.props.element as ToDefinition).uri || '';
+    function canBeInternalUri(property: ComponentProperty): boolean {
+        if (props.element && props.element.dslName === 'ToDefinition' && property.name === 'name') {
+            const uri: string = (props.element as ToDefinition).uri || '';
             return uri.startsWith("direct") || uri.startsWith("seda");
         } else {
             return false;
         }
     }
 
-    getInternalComponentName = (property: ComponentProperty): string => {
-        if (this.props.element && this.props.element.dslName === 'ToDefinition' && property.name === 'name') {
-            const uri: string = (this.props.element as ToDefinition).uri || '';
-            if (uri.startsWith("direct")) return "direct";
-            if (uri.startsWith("seda")) return "seda";
-            return '';
-        } else {
-            return '';
-        }
-    }
-
-    getInternalUriSelect = (property: ComponentProperty, value: any) => {
+    function getInternalUriSelect(property: ComponentProperty, value: any) {
         const selectOptions: JSX.Element[] = [];
-        const componentName = this.getInternalComponentName(property);
-        const internalUris = CamelUi.getInternalRouteUris(this.props.integration, componentName, false);
+        const componentName = getInternalComponentName(property.name, props.element);
+        const internalUris = CamelUi.getInternalRouteUris(integration, componentName, false);
         const uris: string [] = [];
         uris.push(...internalUris);
         if (value && value.length > 0 && !uris.includes(value)) {
@@ -153,111 +140,115 @@ export class ComponentParameterField extends React.Component<Props, State> {
             selectOptions.push(...uris.map((value: string) =>
                 <SelectOption key={value} value={value ? value.trim() : value}/>));
         }
-        return <InputGroup id={this.state.id} name={this.state.id}>
-            <InputGroupItem><Select
-                id={this.state.id} name={this.state.id}
-                placeholderText="Select or type an URI"
-                variant={SelectVariant.typeahead}
-                aria-label={property.name}
-                onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
-                }}
-                onSelect={(e, value, isPlaceholder) => {
-                    this.parametersChanged(property.name, (!isPlaceholder ? value : undefined), property.kind === 'path', undefined);
-                }}
-                selections={value}
-                isOpen={this.isSelectOpen(property.name)}
-                isCreatable={true}
-                createText=""
-                isInputFilterPersisted={true}
-                aria-labelledby={property.name}
-                direction={SelectDirection.down}
-            >
-                {selectOptions}
-            </Select></InputGroupItem>
-            <InputGroupItem><Tooltip position="bottom-end" content={"Create route"}>
-                <Button isDisabled={value === undefined} variant="control" onClick={e => {
-                    if (value) {
-                        const newRoute = !internalUris.includes(value.toString()) ? new RouteToCreate(componentName, value.toString()) : undefined;
-                        this.parametersChanged(property.name, value, property.kind === 'path', newRoute);
-                    }
-                }}>
-                    {<PlusIcon/>}
-                </Button>
-            </Tooltip></InputGroupItem>
+        return <InputGroup id={id} name={id}>
+            <InputGroupItem isFill>
+                <Select
+                    id={id} name={id}
+                    placeholderText="Select or type an URI"
+                    variant={SelectVariant.typeahead}
+                    aria-label={property.name}
+                    onToggle={(_event, isExpanded) => {
+                        openSelect(property.name, isExpanded)
+                    }}
+                    onSelect={(e, value, isPlaceholder) => {
+                        parametersChanged(property.name, (!isPlaceholder ? value : undefined), property.kind === 'path', undefined);
+                    }}
+                    selections={value}
+                    isOpen={isSelectOpen(property.name)}
+                    isCreatable={true}
+                    createText=""
+                    isInputFilterPersisted={true}
+                    aria-labelledby={property.name}
+                    direction={SelectDirection.down}>
+                    {selectOptions}
+                </Select>
+            </InputGroupItem>
+            <InputGroupItem>
+                <Tooltip position="bottom-end" content={"Create route"}>
+                    <Button isDisabled={value === undefined} variant="control" onClick={e => {
+                        if (value) {
+                            const newRoute = !internalUris.includes(value.toString())
+                                ? CamelUi.createNewInternalRoute(componentName.concat(...':',value.toString()))
+                                : undefined;
+                            parametersChanged(property.name, value, property.kind === 'path', newRoute);
+                        }
+                    }}>
+                        {<PlusIcon/>}
+                    </Button>
+                </Tooltip>
+            </InputGroupItem>
         </InputGroup>
     }
 
-    selectInfrastructure = (value: string) => {
+    function selectInfrastructure(value: string) {
         // check if there is a selection
-        const textVal = this.state.ref.current;
+        const textVal = ref.current;
         const cursorStart = textVal.selectionStart;
         const cursorEnd = textVal.selectionEnd;
-        if (cursorStart !== cursorEnd){
-            const prevValue = this.props.value;
+        if (cursorStart !== cursorEnd) {
+            const prevValue = props.value;
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyName = this.state.infrastructureSelectorProperty;
+        const propertyName = infrastructureSelectorProperty;
         if (propertyName) {
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
-            this.parametersChanged(propertyName, value);
-            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
+            parametersChanged(propertyName, value);
+            setInfrastructureSelector(false);
+            setInfrastructureSelectorProperty(undefined);
         }
     }
 
-    openInfrastructureSelector = (propertyName: string) => {
-        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
+    function openInfrastructureSelector(propertyName: string) {
+        setInfrastructureSelector(true);
+        setInfrastructureSelectorProperty(propertyName);
     }
 
-    closeInfrastructureSelector = () => {
-        this.setState({showInfrastructureSelector: false})
-    }
 
-    getInfrastructureSelectorModal() {
+    function getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showInfrastructureSelector}
-                onClose={() => this.closeInfrastructureSelector()}
-                onSelect={this.selectInfrastructure}/>)
+                isOpen={infrastructureSelector}
+                onClose={() => setInfrastructureSelector(false)}
+                onSelect={selectInfrastructure}/>)
     }
 
-    getStringInput(property: ComponentProperty, value: any) {
-        const {showEditor, showPassword} = this.state;
+    function getStringInput(property: ComponentProperty, value: any) {
         const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
         const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return <InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}>
-                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
+                <Tooltip position="bottom-end"
+                         content={"Select from " + capitalize((InfrastructureAPI.infrastructure))}>
+                    <Button variant="control" onClick={e => openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) &&
-                <TextInput className="text-field" isRequired ref={this.state.ref}
+                <TextInput className="text-field" isRequired ref={ref}
                            type={property.secret && !showPassword ? "password" : "text"}
-                           id={this.state.id} name={this.state.id}
+                           id={id} name={id}
                            value={value !== undefined ? value : property.defaultValue}
-                           onChange={(e, value) => this.parametersChanged(property.name, value, property.kind === 'path')}/>}
+                           onChange={(e, value) => parametersChanged(property.name, value, property.kind === 'path')}/>}
             {showEditor && !property.secret &&
-                <TextArea autoResize={true} ref={this.state.ref}
+                <TextArea autoResize={true} ref={ref}
                           className="text-field" isRequired
                           type="text"
-                          id={this.state.id} name={this.state.id}
+                          id={id} name={id}
                           value={value !== undefined ? value : property.defaultValue}
-                          onChange={(e, value) => this.parametersChanged(property.name, value, property.kind === 'path')}/>}
+                          onChange={(e, value) => parametersChanged(property.name, value, property.kind === 'path')}/>}
             {!property.secret &&
                 <Tooltip position="bottom-end" content={showEditor ? "Change to TextField" : "Change to Text Area"}>
-                    <Button variant="control" onClick={e => this.setState({showEditor: !showEditor})}>
+                    <Button variant="control" onClick={e => setShowEditor(!showEditor)}>
                         {showEditor ? <CompressIcon/> : <ExpandIcon/>}
                     </Button>
                 </Tooltip>
             }
             {property.secret &&
                 <Tooltip position="bottom-end" content={showPassword ? "Hide" : "Show"}>
-                    <Button variant="control" onClick={e => this.setState({showPassword: !showPassword})}>
+                    <Button variant="control" onClick={e => setShowPassword(!showPassword)}>
                         {showPassword ? <ShowIcon/> : <HideIcon/>}
                     </Button>
                 </Tooltip>
@@ -265,20 +256,20 @@ export class ComponentParameterField extends React.Component<Props, State> {
         </InputGroup>
     }
 
-    getTextInput = (property: ComponentProperty, value: any) => {
+    function getTextInput(property: ComponentProperty, value: any) {
         return (
             <TextInput
                 className="text-field" isRequired
                 type={['integer', 'int', 'number'].includes(property.type) ? 'number' : (property.secret ? "password" : "text")}
-                id={this.state.id} name={this.state.id}
+                id={id} name={id}
                 value={value !== undefined ? value : property.defaultValue}
-                onChange={(e, value) => {
-                    this.parametersChanged(property.name, ['integer', 'int', 'number'].includes(property.type) ? Number(value) : value, property.kind === 'path')
+                onChange={(_, value) => {
+                    parametersChanged(property.name, ['integer', 'int', 'number'].includes(property.type) ? Number(value) : value, property.kind === 'path')
                 }}/>
         )
     }
 
-    getSelect = (property: ComponentProperty, value: any) => {
+    function getSelect(property: ComponentProperty, value: any) {
         const selectOptions: JSX.Element[] = []
         if (property.enum && property.enum.length > 0) {
             selectOptions.push(<SelectOption key={0} value={"Select ..."} isPlaceholder/>);
@@ -286,15 +277,15 @@ export class ComponentParameterField extends React.Component<Props, State> {
         }
         return (
             <Select
-                id={this.state.id} name={this.state.id}
+                id={id} name={id}
                 variant={SelectVariant.single}
                 aria-label={property.name}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
-                onSelect={(e, value, isPlaceholder) => this.parametersChanged(property.name, (!isPlaceholder ? value : undefined), property.kind === 'path')}
+                onSelect={(e, value, isPlaceholder) => parametersChanged(property.name, (!isPlaceholder ? value : undefined), property.kind === 'path')}
                 selections={value !== undefined ? value.toString() : property.defaultValue}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
             >
@@ -303,56 +294,53 @@ export class ComponentParameterField extends React.Component<Props, State> {
         )
     }
 
-    getSwitch = (property: ComponentProperty, value: any) => {
+    function getSwitch(property: ComponentProperty, value: any) {
         return (
             <Switch
-                id={this.state.id} name={this.state.id}
+                id={id} name={id}
                 value={value?.toString()}
-                aria-label={this.state.id}
+                aria-label={id}
                 isChecked={value !== undefined ? Boolean(value) : property.defaultValue !== undefined && property.defaultValue === 'true'}
-                onChange={e => this.parametersChanged(property.name, !Boolean(value))}/>
+                onChange={e => parametersChanged(property.name, !Boolean(value))}/>
         )
     }
 
-    render() {
-        const property: ComponentProperty = this.props.property;
-        const value = this.props.value;
-        const id = this.state.id;
-        return (
-            <FormGroup
-                key={id}
-                label={property.displayName}
-                isRequired={property.required}
-                labelIcon={
-                    <Popover
-                        position={"left"}
-                        headerContent={property.displayName}
-                        bodyContent={property.description}
-                        footerContent={
-                            <div>
-                                {property.defaultValue !== undefined && <div>{"Default: " + property.defaultValue}</div>}
-                                {property.required && <div>{property.displayName + " is required"}</div>}
-                            </div>
-                        }>
-                        <button type="button" aria-label="More info" onClick={e => e.preventDefault()}
-                                className="pf-v5-c-form__group-label-help">
-                            <HelpIcon />
-                        </button>
-                    </Popover>
-                }>
-                {this.canBeInternalUri(property) && this.getInternalUriSelect(property, value)}
-                {property.type === 'string' && property.enum === undefined && !this.canBeInternalUri(property)
-                    && this.getStringInput(property, value)}
-                {['duration', 'integer', 'int', 'number'].includes(property.type) && property.enum === undefined && !this.canBeInternalUri(property)
-                    && this.getTextInput(property, value)}
-                {['object'].includes(property.type) && !property.enum
-                    && this.getSelectBean(property, value)}
-                {['string', 'object'].includes(property.type) && property.enum
-                    && this.getSelect(property, value)}
-                {property.type === 'boolean'
-                    && this.getSwitch(property, value)}
-                {this.getInfrastructureSelectorModal()}
-            </FormGroup>
-        )
-    }
+    const property: ComponentProperty = props.property;
+    const value = props.value;
+    return (
+        <FormGroup
+            key={id}
+            label={property.displayName}
+            isRequired={property.required}
+            labelIcon={
+                <Popover
+                    position={"left"}
+                    headerContent={property.displayName}
+                    bodyContent={property.description}
+                    footerContent={
+                        <div>
+                            {property.defaultValue !== undefined && <div>{"Default: " + property.defaultValue}</div>}
+                            {property.required && <div>{property.displayName + " is required"}</div>}
+                        </div>
+                    }>
+                    <button type="button" aria-label="More info" onClick={e => e.preventDefault()}
+                            className="pf-v5-c-form__group-label-help">
+                        <HelpIcon/>
+                    </button>
+                </Popover>
+            }>
+            {canBeInternalUri(property) && getInternalUriSelect(property, value)}
+            {property.type === 'string' && property.enum === undefined && !canBeInternalUri(property)
+                && getStringInput(property, value)}
+            {['duration', 'integer', 'int', 'number'].includes(property.type) && property.enum === undefined && !canBeInternalUri(property)
+                && getTextInput(property, value)}
+            {['object'].includes(property.type) && !property.enum
+                && getSelectBean(property, value)}
+            {['string', 'object'].includes(property.type) && property.enum
+                && getSelect(property, value)}
+            {property.type === 'boolean'
+                && getSwitch(property, value)}
+            {getInfrastructureSelectorModal()}
+        </FormGroup>
+    )
 }
diff --git a/karavan-designer/src/designer/route/property/DataFormatField.tsx b/karavan-designer/src/designer/route/property/DataFormatField.tsx
index ef447b6f..71fd3402 100644
--- a/karavan-designer/src/designer/route/property/DataFormatField.tsx
+++ b/karavan-designer/src/designer/route/property/DataFormatField.tsx
@@ -14,15 +14,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import {
-	ExpandableSection
+    ExpandableSection
 } from '@patternfly/react-core';
 import {
-	Select,
-	SelectVariant,
-	SelectDirection,
-	SelectOption
+    Select,
+    SelectVariant,
+    SelectDirection,
+    SelectOption
 } from '@patternfly/react-core/deprecated';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -42,135 +42,107 @@ interface Props {
     dark: boolean,
 }
 
-interface State {
-    selectIsOpen: boolean
-    dataFormat: string
-    isShowAdvanced: boolean
-}
-
-export class DataFormatField extends React.Component<Props, State> {
+export function DataFormatField(props: Props) {
 
-    public state: State = {
-        selectIsOpen: false,
-        dataFormat: CamelDefinitionApiExt.getDataFormat(this.props.value)?.name || "json",
-        isShowAdvanced: false
-    }
+    const [selectIsOpen, setSelectIsOpen] = useState<boolean>(false);
+    const [showAdvanced, setShowAdvanced] = useState<boolean>(false);
 
-    componentDidMount() {
-        if (CamelDefinitionApiExt.getDataFormat(this.props.value)?.name === undefined) {
-            this.dataFormatChanged("json", CamelDefinitionApi.createDataFormat('JsonDataFormat', {}));
-        }
+    function getDataFormatString() {
+        return CamelDefinitionApiExt.getDataFormat(props.value)?.name || 'json';
     }
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        const newDataFormat = CamelDefinitionApiExt.getDataFormat(this.props.value)?.name || "json"
-        if (prevProps.value
-            && (prevProps.value.uuid !== this.props.value.uuid
-                || prevState.dataFormat !== newDataFormat)
-        ) {
-            this.setState({
-                dataFormat: newDataFormat
-            });
-        }
+    function openSelect() {
+        setSelectIsOpen(true)
     }
 
-    openSelect = () => {
-        this.setState({selectIsOpen: true});
-    }
-
-    dataFormatChanged = (dataFormat: string, value?: CamelElement) => {
+    function dataFormatChanged(dataFormat: string, value?: CamelElement) {
         if (dataFormat !== (value as any).dataFormatName) {
             const className = CamelMetadataApi.getCamelDataFormatMetadataByName(dataFormat)?.className;
             value = CamelDefinitionApi.createDataFormat(className || '', {}); // perhaps copy other similar fields later
         }
-        const df = CamelDefinitionApi.createStep(this.props.dslName, {});
+        const df = CamelDefinitionApi.createStep(props.dslName, {});
         (df as any)[dataFormat] = value;
-        this.props.onDataFormatChange?.call(this, df);
-        this.setState({selectIsOpen: false});
+        (df as any)['uuid'] = props.value.uuid;
+        (df as any)['id'] = (props.value as any)['id'];
+
+        props.onDataFormatChange?.(df);
+        setSelectIsOpen(false);
     }
 
-    propertyChanged = (fieldId: string, value: string | number | boolean | any) => {
-        const df = this.getDataFormatValue();
+    function propertyChanged(fieldId: string, value: string | number | boolean | any) {
+        const df = getDataFormatValue();
         if (df) {
             (df as any)[fieldId] = value;
-            this.dataFormatChanged(this.state.dataFormat, df);
+            dataFormatChanged(getDataFormatString(), df);
         }
     }
 
-    getDataFormatValue = (): CamelElement => {
-        return (this.props.value as any)[this.state.dataFormat]
-            ? (this.props.value as any)[this.state.dataFormat]
-            : CamelDefinitionApi.createDataFormat(this.state.dataFormat, (this.props.value as any)[this.state.dataFormat]);
+    function getDataFormatValue(): CamelElement {
+        const dataFormatString = getDataFormatString();
+        return (props.value as any)[dataFormatString]
+            ? (props.value as any)[dataFormatString]
+            : CamelDefinitionApi.createDataFormat(dataFormatString, (props.value as any)[dataFormatString]);
     }
 
-    getPropertyFields = (value: any, properties: PropertyMeta[]) => {
+    function getPropertyFields(value: any, properties: PropertyMeta[]) {
         return (<>
             {value && properties?.map((property: PropertyMeta) =>
-                <DslPropertyField key={property.name} property={property}
-                                  integration={this.props.integration}
-                                  element={value}
-                                  value={value ? (value as any)[property.name] : undefined}
-                                  onExpressionChange={exp => {
-                                  }}
-                                  onParameterChange={parameter => {
-                                      console.log(parameter)
-                                  }}
-                                  onDataFormatChange={dataFormat => {
-                                      console.log(dataFormat)
-                                  }}
-                                  dark={this.props.dark}
-                                  onChange={this.propertyChanged}/>
+                <DslPropertyField
+                    key={property.name}
+                    property={property}
+                    value={value ? (value as any)[property.name] : undefined}
+                    onPropertyChange={propertyChanged}
+                />
             )}
         </>)
     }
 
-    render() {
-        const value = this.getDataFormatValue();
-        const dataFormat = DataFormats.find((l: [string, string, string]) => l[0] === this.state.dataFormat);
-        const properties = CamelDefinitionApiExt.getElementPropertiesByName(this.state.dataFormat).sort((a, b) => a.name === 'library' ? -1 : 1);
-        const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
-        const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
-        const selectOptions: JSX.Element[] = []
-        DataFormats.forEach((lang: [string, string, string]) => {
-            const s = <SelectOption key={lang[0]} value={lang[0]} description={lang[2]}/>;
-            selectOptions.push(s);
-        })
-        return (
+    const value = getDataFormatValue();
+    const dataFormatString = getDataFormatString();
+    const dataFormat = DataFormats.find((l: [string, string, string]) => l[0] === dataFormatString);
+    const properties = CamelDefinitionApiExt.getElementPropertiesByName(dataFormatString).sort((a, b) => a.name === 'library' ? -1 : 1);
+    const propertiesMain = properties.filter(p => !p.label.includes("advanced"));
+    const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
+    const selectOptions: JSX.Element[] = []
+    DataFormats.forEach((lang: [string, string, string]) => {
+        const s = <SelectOption key={lang[0]} value={lang[0]} description={lang[2]}/>;
+        selectOptions.push(s);
+    })
+    return (
+        <div>
             <div>
+                <label className="pf-v5-c-form__label" htmlFor="expression">
+                    <span className="pf-v5-c-form__label-text">{"Data Format"}</span>
+                    <span className="pf-v5-c-form__label-required" aria-hidden="true"> *</span>
+                </label>
+                <Select
+                    variant={SelectVariant.typeahead}
+                    aria-label={"dataFormat"}
+                    onToggle={() => {
+                        openSelect()
+                    }}
+                    onSelect={(_, dataFormat, isPlaceholder) => dataFormatChanged(dataFormat.toString(), value)}
+                    selections={dataFormat}
+                    isOpen={selectIsOpen}
+                    aria-labelledby={"dataFormat"}
+                    direction={SelectDirection.down}
+                >
+                    {selectOptions}
+                </Select>
+            </div>
+            <div className="object">
                 <div>
-                    <label className="pf-v5-c-form__label" htmlFor="expression">
-                        <span className="pf-v5-c-form__label-text">{"Data Format"}</span>
-                        <span className="pf-v5-c-form__label-required" aria-hidden="true"> *</span>
-                    </label>
-                    <Select
-                        variant={SelectVariant.typeahead}
-                        aria-label={"dataFormat"}
-                        onToggle={() => {
-                            this.openSelect()
-                        }}
-                        onSelect={(e, dataFormat, isPlaceholder) => this.dataFormatChanged(dataFormat.toString(), value)}
-                        selections={dataFormat}
-                        isOpen={this.state.selectIsOpen}
-                        aria-labelledby={"dataFormat"}
-                        direction={SelectDirection.down}
-                    >
-                        {selectOptions}
-                    </Select>
+                    {getPropertyFields(value, propertiesMain)}
+                    {propertiesAdvanced.length > 0 &&
+                        <ExpandableSection
+                            toggleText={'Advanced properties'}
+                            onToggle={(_event, isExpanded) => setShowAdvanced(!showAdvanced)}
+                            isExpanded={showAdvanced}>
+                            {getPropertyFields(value, propertiesAdvanced)}
+                        </ExpandableSection>}
                 </div>
-                <div className="object">
-                    <div>
-                        {this.getPropertyFields(value, propertiesMain)}
-                        {propertiesAdvanced.length > 0 &&
-                            <ExpandableSection
-                                toggleText={'Advanced properties'}
-                                onToggle={(_event, isExpanded) => this.setState({isShowAdvanced: !this.state.isShowAdvanced})}
-                                isExpanded={this.state.isShowAdvanced}>
-                                {this.getPropertyFields(value, propertiesAdvanced)}
-                            </ExpandableSection>}
-                    </div>
 
-                </div>
             </div>
-        )
-    }
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index 3021baf2..aceff154 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
@@ -14,31 +14,31 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useRef, useState} from 'react';
 import {
-	FormGroup,
-	TextInput,
-	Popover,
-	Switch,
-	ExpandableSection,
-	TextArea,
-	Chip,
-	TextInputGroup,
-	TextInputGroupMain,
-	TextInputGroupUtilities,
-	ChipGroup,
-	Button,
-	Text,
-	Tooltip,
-	Card,
-	InputGroup,
-	capitalize, InputGroupItem
+    FormGroup,
+    TextInput,
+    Popover,
+    Switch,
+    ExpandableSection,
+    TextArea,
+    Chip,
+    TextInputGroup,
+    TextInputGroupMain,
+    TextInputGroupUtilities,
+    ChipGroup,
+    Button,
+    Text,
+    Tooltip,
+    Card,
+    InputGroup,
+    capitalize, InputGroupItem
 } from '@patternfly/react-core';
 import {
-	Select,
-	SelectVariant,
-	SelectDirection,
-	SelectOption
+    Select,
+    SelectVariant,
+    SelectDirection,
+    SelectOption
 } from '@patternfly/react-core/deprecated';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
@@ -50,10 +50,8 @@ import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt"
 import {ExpressionField} from "./ExpressionField";
 import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
 import {ComponentParameterField} from "./ComponentParameterField";
-import {DataFormatDefinition} from "karavan-core/lib/model/CamelDefinition";
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {KameletPropertyField} from "./KameletPropertyField";
-import {ExpressionDefinition} from "karavan-core/lib/model/CamelDefinition";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {ObjectField} from "./ObjectField";
 import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
@@ -66,104 +64,98 @@ import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon
 import {InfrastructureSelector} from "./InfrastructureSelector";
 import {InfrastructureAPI} from "../../utils/InfrastructureAPI";
 import EditorIcon from "@patternfly/react-icons/dist/js/icons/code-icon";
-import {TemplateApi} from "karavan-core/lib/api/TemplateApi";
 import {ModalEditor} from "./ModalEditor";
-import {KaravanInstance} from "../../KaravanDesigner";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
+import {useDesignerStore, useIntegrationStore} from "../../KaravanStore";
+import {shallow} from "zustand/shallow";
+import {DataFormatDefinition, ExpressionDefinition} from "karavan-core/lib/model/CamelDefinition";
 
 interface Props {
     property: PropertyMeta,
+    element?: CamelElement
     value: any,
-    onChange?: (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) => void,
+    onPropertyChange?: (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) => void,
     onExpressionChange?: (propertyName: string, exp: ExpressionDefinition) => void,
     onDataFormatChange?: (value: DataFormatDefinition) => void,
     onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate) => void,
-    element?: CamelElement
-    integration: Integration,
     hideLabel?: boolean,
     dslLanguage?: [string, string, string],
-    dark: boolean
 }
 
-interface State {
-    selectStatus: Map<string, boolean>,
-    isShowAdvanced: Map<string, boolean>,
-    arrayValues: Map<string, string>,
-    showEditor: boolean
-    infrastructureSelector: boolean
-    infrastructureSelectorProperty?: string
-    customCode?: string
-    ref: any
-}
+export function DslPropertyField(props: Props) {
 
-export class DslPropertyField extends React.Component<Props, State> {
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+    const [dark] = useDesignerStore((s) => [s.dark], shallow)
 
-    public state: State = {
-        selectStatus: new Map<string, boolean>(),
-        arrayValues: new Map<string, string>(),
-        isShowAdvanced: new Map<string, boolean>(),
-        showEditor: false,
-        infrastructureSelector: false,
-        ref: React.createRef(),
-    };
+    const [isShowAdvanced, setIsShowAdvanced] = useState<Map<string, boolean>>(new Map<string, boolean>());
+    const [arrayValues, setArrayValues] = useState<Map<string, string>>(new Map<string, string>());
+    const [selectStatus, setSelectStatus] = useState<Map<string, boolean>>(new Map<string, boolean>());
+    const [showEditor, setShowEditor] = useState<boolean>(false);
+    const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false);
+    const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined);
+    const [customCode, setCustomCode] = useState<string | undefined>(undefined);
 
-    openSelect = (propertyName: string, isExpanded: boolean) => {
-        this.setState({selectStatus: new Map<string, boolean>([[propertyName, isExpanded]])});
+    const ref = useRef<any>(null);
+
+    function openSelect(propertyName: string, isExpanded: boolean) {
+        setSelectStatus(new Map<string, boolean>([[propertyName, isExpanded]]))
     }
 
-    clearSelection = (propertyName: string) => {
-        this.setState({selectStatus: new Map<string, boolean>([[propertyName, false]])});
-    };
+    function clearSelection(propertyName: string) {
+        setSelectStatus(new Map<string, boolean>([[propertyName, false]]))
+    }
 
-    isSelectOpen = (propertyName: string): boolean => {
-        return this.state.selectStatus.has(propertyName) && this.state.selectStatus.get(propertyName) === true;
+    function isSelectOpen(propertyName: string): boolean {
+        return selectStatus.get(propertyName) === true;
     }
 
-    propertyChanged = (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) => {
-        if (fieldId === 'id' && CamelDefinitionApiExt.hasElementWithId(this.props.integration, value)) {
-            value = this.props.value;
+    function propertyChanged(fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate) {
+        if (fieldId === 'id' && CamelDefinitionApiExt.hasElementWithId(integration, value)) {
+            value = props.element;
         }
-        this.props.onChange?.call(this, fieldId, value, newRoute);
-        this.setState({selectStatus: new Map<string, boolean>([[fieldId, false]])});
+        props.onPropertyChange?.(fieldId, value, newRoute);
+        clearSelection(fieldId);
     }
 
-    arrayChanged = (fieldId: string, value: string) => {
-        const tv = this.state.arrayValues;
-        tv.set(fieldId, value);
-        this.setState({arrayValues: tv});
+    function arrayChanged(fieldId: string, value: string) {
+        setArrayValues(prevState => {
+            prevState.set(fieldId, value);
+            return prevState;
+        })
     }
 
-    arrayDeleteValue = (fieldId: string, element: string) => {
-        const property: PropertyMeta = this.props.property;
-        let value = this.props.value;
+    function arrayDeleteValue(fieldId: string, element: string) {
+        const property: PropertyMeta = props.property;
+        let value = props.value;
         if (property.isArray && property.type === 'string') {
-            this.propertyChanged(fieldId, (value as any).filter((x: string) => x !== element))
+            propertyChanged(fieldId, (value as any).filter((x: string) => x !== element))
         }
     }
 
-    arraySave = (fieldId: string) => {
-        const newValue = this.state.arrayValues.get(fieldId);
-        const property: PropertyMeta = this.props.property;
-        let value = this.props.value;
+    function arraySave(fieldId: string) {
+        const newValue = arrayValues.get(fieldId);
+        const property: PropertyMeta = props.property;
+        let value = props.value;
         if (newValue !== undefined && newValue.length > 0 && property.isArray && property.type === 'string') {
             if (value) (value as any).push(newValue)
             else value = [newValue];
         }
-        this.propertyChanged(fieldId, value);
-        this.arrayChanged(fieldId, "");
+        propertyChanged(fieldId, value);
+        arrayChanged(fieldId, "");
     }
 
-    getLabel = (property: PropertyMeta, value: any) => {
-        if (!this.isMultiValueField(property) && property.isObject && !property.isArray && !["ExpressionDefinition"].includes(property.type)) {
+    function getLabel(property: PropertyMeta, value: any) {
+        if (!isMultiValueField(property) && property.isObject && !property.isArray && !["ExpressionDefinition"].includes(property.type)) {
             const tooltip = value ? "Delete " + property.name : "Add " + property.name;
             const className = value ? "change-button delete-button" : "change-button add-button";
             const x = value ? undefined : CamelDefinitionApi.createStep(property.type, {});
-            const icon = value ? (<DeleteIcon />) : (<AddIcon />);
+            const icon = value ? (<DeleteIcon/>) : (<AddIcon/>);
             return (
                 <div style={{display: "flex"}}>
                     <Text>{property.displayName} </Text>
                     <Tooltip position={"top"} content={<div>{tooltip}</div>}>
-                        <button className={className} onClick={e => this.props.onChange?.call(this, property.name, x)} aria-label="Add element">
+                        <button className={className} onClick={e => props.onPropertyChange?.(property.name, x)}
+                                aria-label="Add element">
                             {icon}
                         </button>
                     </Tooltip>
@@ -174,141 +166,162 @@ export class DslPropertyField extends React.Component<Props, State> {
         }
     }
 
-    isUriReadOnly = (property: PropertyMeta): boolean => {
-        const dslName: string = this.props.element?.dslName || '';
+    function isUriReadOnly(property: PropertyMeta): boolean {
+        const dslName: string = props.element?.dslName || '';
         return property.name === 'uri' && !['ToDynamicDefinition', 'WireTapDefinition'].includes(dslName)
     }
 
-    selectInfrastructure = (value: string) => {
+    function selectInfrastructure(value: string) {
         // check if there is a selection
-        const textVal = this.state.ref.current;
-        const cursorStart = textVal.selectionStart;
-        const cursorEnd = textVal.selectionEnd;
-        if (cursorStart !== cursorEnd) {
-            const prevValue = this.props.value;
-            const selectedText = prevValue.substring(cursorStart, cursorEnd)
-            value = prevValue.replace(selectedText, value);
-        }
-        const propertyName = this.state.infrastructureSelectorProperty;
-        if (propertyName) {
-            if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
-            this.propertyChanged(propertyName, value);
-            this.setState({infrastructureSelector: false, infrastructureSelectorProperty: undefined})
+        const textVal = ref.current;
+        if (textVal != null) {
+            const cursorStart = textVal.selectionStart;
+            const cursorEnd = textVal.selectionEnd;
+            if (cursorStart !== cursorEnd) {
+                const prevValue = props.value;
+                const selectedText = prevValue.substring(cursorStart, cursorEnd)
+                value = prevValue.replace(selectedText, value);
+            }
+            const propertyName = infrastructureSelectorProperty;
+            if (propertyName) {
+                if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
+                propertyChanged(propertyName, value);
+                setInfrastructureSelector(false);
+                setInfrastructureSelectorProperty(undefined);
+            }
         }
     }
 
-    openInfrastructureSelector = (propertyName: string) => {
-        this.setState({infrastructureSelectorProperty: propertyName, infrastructureSelector: true});
+    function openInfrastructureSelector(propertyName: string) {
+        setInfrastructureSelector(true);
+        setInfrastructureSelectorProperty(propertyName);
     }
 
-    closeInfrastructureSelector = () => {
-        this.setState({infrastructureSelector: false})
+    function closeInfrastructureSelector() {
+        setInfrastructureSelector(false);
     }
 
-    getInfrastructureSelectorModal() {
+    function getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.infrastructureSelector}
-                onClose={() => this.closeInfrastructureSelector()}
-                onSelect={this.selectInfrastructure}/>)
+                isOpen={infrastructureSelector}
+                onClose={() => closeInfrastructureSelector()}
+                onSelect={selectInfrastructure}/>)
     }
 
-    getStringInput = (property: PropertyMeta, value: any) => {
-        const showEditor = this.state.showEditor;
+    function getStringInput(property: PropertyMeta, value: any) {
         const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
         const noInfraSelectorButton = ["uri", "id", "description", "group"].includes(property.name);
         const icon = InfrastructureAPI.infrastructure === 'kubernetes' ? <KubernetesIcon/> : <DockerIcon/>
         return (<InputGroup>
             {inInfrastructure && !showEditor && !noInfraSelectorButton &&
-                <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
-                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.name)}>
-                        {icon}
-                    </Button>
-                </Tooltip>}
-            {(!showEditor || property.secret) && <TextInput
-                ref={this.state.ref}
-                className="text-field" isRequired 
-                type={['integer', 'number'].includes(property.type) ? 'number' : (property.secret ? "password" : "text")}
-                id={property.name} name={property.name}
-                value={value?.toString()}
-                onChange={(_, v) => this.propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
-                readOnlyVariant={this.isUriReadOnly(property) ? "default" : undefined}/>
+                <InputGroupItem>
+                    <Tooltip position="bottom-end"
+                             content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
+                        <Button variant="control" onClick={e => openInfrastructureSelector(property.name)}>
+                            {icon}
+                        </Button>
+                    </Tooltip>
+                </InputGroupItem>
             }
-            {showEditor && !property.secret && <TextArea
-                ref={this.state.ref}
-                autoResize={true}
-                className="text-field" isRequired 
-                type="text"
-                id={property.name} name={property.name}
-                value={value?.toString()}
-                onChange={(_, v) => this.propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
-                readOnlyVariant={this.isUriReadOnly(property) ? "default" : undefined}/>
+            {(!showEditor || property.secret) &&
+                <InputGroupItem isFill>
+                    <TextInput ref={ref}
+                               className="text-field" isRequired
+                               type={['integer', 'number'].includes(property.type) ? 'number' : (property.secret ? "password" : "text")}
+                               id={property.name} name={property.name}
+                               value={value?.toString()}
+                               onChange={(_, v) => propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
+                               readOnlyVariant={isUriReadOnly(property) ? "default" : undefined}/>
+                </InputGroupItem>
+            }
+            {showEditor && !property.secret &&
+                <InputGroupItem isFill>
+                    <TextArea ref={ref}
+                              autoResize={true}
+                              className="text-field" isRequired
+                              type="text"
+                              id={property.name} name={property.name}
+                              value={value?.toString()}
+                              onChange={(_, v) => propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
+                              readOnlyVariant={isUriReadOnly(property) ? "default" : undefined}/>
+                </InputGroupItem>
             }
             {!property.secret &&
-                <Tooltip position="bottom-end" content={showEditor ? "Change to TextField" : "Change to Text Area"}>
-                    <Button variant="control" onClick={e => this.setState({showEditor: !showEditor})}>
-                        {showEditor ? <CompressIcon/> : <ExpandIcon/>}
-                    </Button>
-                </Tooltip>
+                <InputGroupItem>
+                    <Tooltip position="bottom-end" content={showEditor ? "Change to TextField" : "Change to Text Area"}>
+                        <Button variant="control" onClick={e => setShowEditor(!showEditor)}>
+                            {showEditor ? <CompressIcon/> : <ExpandIcon/>}
+                        </Button>
+                    </Tooltip>
+                </InputGroupItem>
             }
         </InputGroup>)
     }
 
-    showCode = (name: string, javaType: string) => {
-        const {property} = this.props;
-        KaravanInstance.getProps().onGetCustomCode.call(this, name, property.javaType).then(value => {
-            if (value === undefined) {
-                const code = TemplateApi.generateCode(property.javaType, name);
-                this.setState({customCode: code, showEditor: true})
-            } else {
-                this.setState({customCode: value, showEditor: true})
-            }
-        }).catch(reason => console.log(reason))
+    function showCode(name: string, javaType: string) {
+        const {property} = props;
+        // TODO: 
+        // InfrastructureAPI.onGetCustomCode?.(name, property.javaType).then(value => {
+        //     if (value === undefined) {
+        //         const code = TemplateApi.generateCode(property.javaType, name);
+        //         setShowEditor(true);
+        //         setCustomCode(code);
+        //     } else {
+        //         setShowEditor(true);
+        //         setCustomCode(value);
+        //     }
+        // }).catch((reason: any) => console.log(reason))
     }
 
-    getJavaTypeGeneratedInput = (property: PropertyMeta, value: any) => {
-        const {dslLanguage, dark} = this.props;
-        const {showEditor, customCode} = this.state;
+    function getJavaTypeGeneratedInput(property: PropertyMeta, value: any) {
+        const {dslLanguage} = props;
         return (<InputGroup>
-            <InputGroupItem isFill >
+            <InputGroupItem isFill>
                 <TextInput
-                    ref={this.state.ref}
-                    className="text-field" isRequired 
+                    ref={ref}
+                    className="text-field" isRequired
                     type="text"
                     id={property.name} name={property.name}
                     value={value?.toString()}
                     onChange={(_, value) => {
-                        this.propertyChanged(property.name, CamelUtil.capitalizeName(value?.replace(/\s/g, '')))
+                        propertyChanged(property.name, CamelUtil.capitalizeName(value?.replace(/\s/g, '')))
                     }}
-                    readOnlyVariant={this.isUriReadOnly(property) ? "default" : undefined}/>
+                    readOnlyVariant={isUriReadOnly(property) ? "default" : undefined}/>
+            </InputGroupItem>
+            <InputGroupItem>
+                <Tooltip position="bottom-end" content={"Create Java Class"}>
+                    <Button isDisabled={value?.length === 0} variant="control"
+                            onClick={e => showCode(value, property.javaType)}>
+                        <PlusIcon/>
+                    </Button>
+                </Tooltip>
+            </InputGroupItem>
+            <InputGroupItem>
+                <ModalEditor property={property}
+                             customCode={customCode}
+                             showEditor={showEditor}
+                             dark={dark}
+                             dslLanguage={dslLanguage}
+                             title="Java Class"
+                             onClose={() => setShowEditor(false)}
+                             onSave={(fieldId, value1) => {
+                                 propertyChanged(fieldId, value);
+                                 // TODO:
+                                 // KaravanInstance.getProps().onSaveCustomCode?.call(this, value, value1);
+                                 setShowEditor(false)
+                             }}/>
             </InputGroupItem>
-            <InputGroupItem><Tooltip position="bottom-end" content={"Create Java Class"}>
-                <Button isDisabled={value?.length === 0} variant="control" onClick={e => this.showCode(value, property.javaType)}>
-                    <PlusIcon/>
-                </Button>
-            </Tooltip></InputGroupItem>
-            <InputGroupItem><ModalEditor property={property}
-                         customCode={customCode}
-                         showEditor={showEditor}
-                         dark={dark}
-                         dslLanguage={dslLanguage}
-                         title="Java Class"
-                         onClose={() => this.setState({showEditor: false})}
-                         onSave={(fieldId, value1) => {
-                             this.propertyChanged(fieldId, value);
-                             KaravanInstance.getProps().onSaveCustomCode?.call(this, value, value1);
-                             this.setState({showEditor: false});
-                         }}/></InputGroupItem>
         </InputGroup>)
     }
 
-    getTextArea = (property: PropertyMeta, value: any) => {
-        const {dslLanguage, dark} = this.props;
-        const {showEditor} = this.state;
+    function getTextArea(property: PropertyMeta, value: any) {
+        const {dslLanguage} = props;
         return (
             <InputGroup>
-                <InputGroupItem isFill ><TextArea
+                <InputGroupItem isFill>
+                    <TextArea
                     autoResize
                     className="text-field" isRequired
                     type={"text"}
@@ -316,52 +329,54 @@ export class DslPropertyField extends React.Component<Props, State> {
                     name={property.name}
                     height={"100px"}
                     value={value?.toString()}
-                    onChange={(_, v) => this.propertyChanged(property.name, v)}/></InputGroupItem>
-                <InputGroupItem><Tooltip position="bottom-end" content={"Show Editor"}>
-                    <Button variant="control" onClick={e => this.setState({showEditor: !showEditor})}>
+                    onChange={(_, v) => propertyChanged(property.name, v)}/>
+                </InputGroupItem>
+                <InputGroupItem>
+                    <Tooltip position="bottom-end" content={"Show Editor"}>
+                    <Button variant="control" onClick={e => setShowEditor(!showEditor)}>
                         <EditorIcon/>
                     </Button>
-                </Tooltip></InputGroupItem>
-                <InputGroupItem><ModalEditor property={property}
-                             customCode={value}
-                             showEditor={showEditor}
-                             dark={dark}
-                             dslLanguage={dslLanguage}
-                             title={`Expression (${dslLanguage?.[0]})`}
-                             onClose={() => this.setState({showEditor: false})}
-                             onSave={(fieldId, value1) => {
-                                 this.propertyChanged(fieldId, value1);
-                                 this.setState({showEditor: false});
-                             }}/></InputGroupItem>
+                </Tooltip>
+                </InputGroupItem>
+                {showEditor && <InputGroupItem>
+                    <ModalEditor property={property}
+                                 customCode={value}
+                                 showEditor={showEditor}
+                                 dark={dark}
+                                 dslLanguage={dslLanguage}
+                                 title={`Expression (${dslLanguage?.[0]})`}
+                                 onClose={() => setShowEditor(false)}
+                                 onSave={(fieldId, value1) => {
+                                     propertyChanged(fieldId, value1);
+                                     setShowEditor(false);
+                                 }}/>
+                </InputGroupItem>}
             </InputGroup>
         )
     }
 
-    getExpressionField = (property: PropertyMeta, value: any) => {
+    function getExpressionField(property: PropertyMeta, value: any) {
         return (
             <div className="expression">
-                <ExpressionField property={property}
-                                 value={value}
-                                 onExpressionChange={this.props.onExpressionChange}
-                                 integration={this.props.integration}
-                                 dark={this.props.dark}/>
+                <ExpressionField
+                    property={property}
+                    value={value}
+                    onExpressionChange={props.onExpressionChange}/>
             </div>
         )
     }
 
-    getObjectField = (property: PropertyMeta, value: any) => {
+    function getObjectField(property: PropertyMeta, value: any) {
         return (
             <div className="object">
                 {value && <ObjectField property={property}
                                        value={value}
-                                       onPropertyUpdate={this.props.onChange}
-                                       integration={this.props.integration}
-                                       dark={this.props.dark}/>}
+                                       onPropertyUpdate={propertyChanged}/>}
             </div>
         )
     }
 
-    getSwitch = (property: PropertyMeta, value: any) => {
+    function getSwitch(property: PropertyMeta, value: any) {
         const isChecked = value !== undefined ? Boolean(value) : Boolean(property.defaultValue !== undefined && property.defaultValue === 'true');
         return (
             <Switch
@@ -369,27 +384,28 @@ export class DslPropertyField extends React.Component<Props, State> {
                 value={value?.toString()}
                 aria-label={property.name}
                 isChecked={isChecked}
-                onChange={(_, v) => this.propertyChanged(property.name, v)}/>
+                onChange={(_, v) => propertyChanged(property.name, v)}/>
         )
     }
 
-    getSelectBean = (property: PropertyMeta, value: any) => {
+    function getSelectBean(property: PropertyMeta, value: any) {
         const selectOptions: JSX.Element[] = [];
-        const beans = CamelUi.getBeans(this.props.integration);
+        const beans = CamelUi.getBeans(integration);
         if (beans) {
             selectOptions.push(<SelectOption key={0} value={"Select..."} isPlaceholder/>);
-            selectOptions.push(...beans.map((bean) => <SelectOption key={bean.name} value={bean.name} description={bean.type}/>));
+            selectOptions.push(...beans.map((bean) => <SelectOption key={bean.name} value={bean.name}
+                                                                    description={bean.type}/>));
         }
         return (
             <Select
                 variant={SelectVariant.single}
                 aria-label={property.name}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
-                onSelect={(e, value, isPlaceholder) => this.propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
+                onSelect={(e, value, isPlaceholder) => propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
             >
@@ -398,7 +414,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    getSelect = (property: PropertyMeta, value: any) => {
+    function getSelect(property: PropertyMeta, value: any) {
         const selectOptions: JSX.Element[] = []
         if (property.enumVals && property.enumVals.length > 0) {
             selectOptions.push(<SelectOption key={0} value={"Select " + property.name} isPlaceholder/>);
@@ -410,11 +426,11 @@ export class DslPropertyField extends React.Component<Props, State> {
                 variant={SelectVariant.single}
                 aria-label={property.name}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
-                onSelect={(e, value, isPlaceholder) => this.propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
+                onSelect={(e, value, isPlaceholder) => propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 id={property.name}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
@@ -424,11 +440,11 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    getMediaTypeSelectOptions(filter?: string): JSX.Element [] {
+    function getMediaTypeSelectOptions(filter?: string): JSX.Element [] {
         const options: JSX.Element [] = [
-            <SelectOption key={0} value="Select Media Type" isPlaceholder />
+            <SelectOption key={0} value="Select Media Type" isPlaceholder/>
         ];
-        const mediaTypes: JSX.Element[] =  filter
+        const mediaTypes: JSX.Element[] = filter
             ? MediaTypes.filter(mt => mt.includes(filter)).map((value: string) =>
                 <SelectOption key={value} value={value.trim()}/>)
             : MediaTypes.map((value: string) =>
@@ -437,30 +453,30 @@ export class DslPropertyField extends React.Component<Props, State> {
         return options;
     }
 
-    getMediaTypeSelect = (property: PropertyMeta, value: any) => {
+    function getMediaTypeSelect(property: PropertyMeta, value: any) {
         return (
             <Select
                 placeholderText="Select Media Type"
                 variant={SelectVariant.typeahead}
                 aria-label={property.name}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
-                onSelect={(e, value, isPlaceholder) => this.propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
+                onSelect={(e, value, isPlaceholder) => propertyChanged(property.name, (!isPlaceholder ? value : undefined))}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 isCreatable={false}
                 isInputFilterPersisted={false}
-                onFilter={(e, text) => this.getMediaTypeSelectOptions(text)}
+                onFilter={(e, text) => getMediaTypeSelectOptions(text)}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
             >
-                {this.getMediaTypeSelectOptions()}
+                {getMediaTypeSelectOptions()}
             </Select>
         )
     }
 
-    canBeInternalUri = (property: PropertyMeta, element?: CamelElement): boolean => {
+    function canBeInternalUri(property: PropertyMeta, element?: CamelElement): boolean {
         if (element?.dslName === 'WireTapDefinition' && property.name === 'uri') {
             return true;
         } else if (element?.dslName === 'SagaDefinition' && ['compensation', 'completion'].includes(property.name)) {
@@ -472,9 +488,9 @@ export class DslPropertyField extends React.Component<Props, State> {
         }
     }
 
-    canBeMediaType = (property: PropertyMeta, element?: CamelElement): boolean => {
+    function canBeMediaType(property: PropertyMeta, element?: CamelElement): boolean {
         if (element
-            && ['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(element?.dslName)
+            && ['RestDefinition', 'GetDefinition', 'PostDefinition', 'PutDefinition', 'PatchDefinition', 'DeleteDefinition', 'HeadDefinition'].includes(element.dslName)
             && ['consumes', 'produces'].includes(property.name)) {
             return true;
         } else {
@@ -482,34 +498,35 @@ export class DslPropertyField extends React.Component<Props, State> {
         }
     }
 
-    javaTypeGenerated = (property: PropertyMeta): boolean => {
+    function javaTypeGenerated(property: PropertyMeta): boolean {
         return property.javaType.length !== 0;
     }
 
-    getInternalUriSelect = (property: PropertyMeta, value: any) => {
+    function getInternalUriSelect(property: PropertyMeta, value: any) {
+        console.log("getInternalUriSelect", property, value)
         const selectOptions: JSX.Element[] = [];
-        const urls = CamelUi.getInternalRouteUris(this.props.integration, "direct");
-        urls.push(...CamelUi.getInternalRouteUris(this.props.integration, "seda"));
+        const urls = CamelUi.getInternalRouteUris(integration, "direct");
+        urls.push(...CamelUi.getInternalRouteUris(integration, "seda"));
         if (urls && urls.length > 0) {
             selectOptions.push(...urls.map((value: string) =>
                 <SelectOption key={value} value={value.trim()}/>));
         }
         return (
+            <InputGroup id={property.name} name={property.name}>
+                <InputGroupItem isFill>
             <Select
                 placeholderText="Select or type an URI"
                 variant={SelectVariant.typeahead}
                 aria-label={property.name}
-                onClear={event => this.clearSelection(property.name)}
+                onClear={event => propertyChanged(property.name, undefined, undefined)}
                 onToggle={(_event, isExpanded) => {
-                    this.openSelect(property.name, isExpanded)
+                    openSelect(property.name, isExpanded)
                 }}
                 onSelect={(e, value, isPlaceholder) => {
-                    const url = value.toString().split(":");
-                    const newRoute = !urls.includes(value.toString()) && (['direct', 'seda'].includes(url[0])) ? new RouteToCreate(url[0], url[1]) : undefined;
-                    this.propertyChanged(property.name, (!isPlaceholder ? value : undefined), newRoute)
+                    propertyChanged(property.name, (!isPlaceholder ? value : undefined), undefined)
                 }}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 isCreatable={true}
                 isInputFilterPersisted={true}
                 aria-labelledby={property.name}
@@ -517,73 +534,87 @@ export class DslPropertyField extends React.Component<Props, State> {
             >
                 {selectOptions}
             </Select>
+                </InputGroupItem>
+                <InputGroupItem>
+                    <Tooltip position="bottom-end" content={"Create route"}>
+                        <Button isDisabled={value === undefined} variant="control" onClick={e => {
+                            if (value) {
+                                const newRoute = CamelUi.createNewInternalRoute(value);
+                                propertyChanged(property.name, value, newRoute)
+                            }
+                        }}>
+                            {<PlusIcon/>}
+                        </Button>
+                    </Tooltip>
+                </InputGroupItem>
+            </InputGroup>
         )
     }
 
-    onMultiValueObjectUpdate = (index: number, fieldId: string, value: CamelElement) => {
-        const mValue = [...this.props.value];
+    function onMultiValueObjectUpdate(index: number, fieldId: string, value: CamelElement) {
+        const mValue = [...props.value];
         mValue[index] = value;
-        this.props.onChange?.call(this, fieldId, mValue);
+        props.onPropertyChange?.(fieldId, mValue);
     }
 
-    isKeyValueObject(property: PropertyMeta) {
+    function isKeyValueObject(property: PropertyMeta) {
         const props = CamelDefinitionApiExt.getElementProperties(property.type);
         return props.length === 2 && props.filter(p => p.name === 'key').length === 1 && props.filter(p => p.name === 'value').length === 1;
     }
 
-    getMultiObjectFieldProps(property: PropertyMeta, value: any, v: any, index: number, hideLabel: boolean = false) {
+    function getMultiObjectFieldProps(property: PropertyMeta, value: any, v: any, index: number, hideLabel: boolean = false) {
         return (<>
             <div className="object">
                 {value && <ObjectField property={property}
                                        hideLabel={hideLabel}
-                                       value={v}
-                                       onPropertyUpdate={(f, v) => this.onMultiValueObjectUpdate(index, f, v)}
-                                       integration={this.props.integration}
-                                       dark={this.props.dark}/>}
+                                       onPropertyUpdate={(f, v) => onMultiValueObjectUpdate(index, f, v)}
+                />}
             </div>
             <Button variant="link" className="delete-button" onClick={e => {
                 const v = Array.from(value);
                 v.splice(index, 1);
-                this.propertyChanged(property.name, v);
+                propertyChanged(property.name, v);
             }}><DeleteIcon/></Button>
         </>)
     }
 
-    getMultiValueObjectField = (property: PropertyMeta, value: any) => {
-        const isKeyValue = this.isKeyValueObject(property);
+    function getMultiValueObjectField(property: PropertyMeta, value: any) {
+        const isKeyValue = isKeyValueObject(property);
         return (
             <div>
                 {value && Array.from(value).map((v: any, index: number) => {
                     if (isKeyValue)
                         return <div key={property + "-" + index} className="object-key-value">
-                            {this.getMultiObjectFieldProps(property, value, v, index, index > 0)}
+                            {getMultiObjectFieldProps(property, value, v, index, index > 0)}
                         </div>
                     else
                         return <Card key={property + "-" + index} className="object-value">
-                            {this.getMultiObjectFieldProps(property, value, v, index)}
+                            {getMultiObjectFieldProps(property, value, v, index)}
                         </Card>
                 })}
                 <Button variant="link" className="add-button"
-                        onClick={e => this.propertyChanged(property.name, [...value, CamelDefinitionApi.createStep(property.type, {})])}><AddIcon/>{"Add " + property.displayName}
+                        onClick={e => propertyChanged(property.name, [...value, CamelDefinitionApi.createStep(property.type, {})])}><AddIcon/>{"Add " + property.displayName}
                 </Button>
             </div>
         )
     }
 
-    getMultiValueField = (property: PropertyMeta, value: any) => {
+    function getMultiValueField(property: PropertyMeta, value: any) {
         return (
             <div>
                 <TextInputGroup className="input-group">
-                    <TextInputGroupMain value={this.state.arrayValues.get(property.name)} onChange={(e, v) => this.arrayChanged(property.name, v)} onKeyUp={e => {
-                        if (e.key === 'Enter') this.arraySave(property.name)
+                    <TextInputGroupMain value={arrayValues.get(property.name)}
+                                        onChange={(e, v) => arrayChanged(property.name, v)} onKeyUp={e => {
+                        if (e.key === 'Enter') arraySave(property.name)
                     }}>
                         <ChipGroup>
                             {value && Array.from(value).map((v: any, index: number) => (
-                                <Chip key={"chip-" + index} className="chip" onClick={() => this.arrayDeleteValue(property.name, v)}>{v.toString()}</Chip>))}
+                                <Chip key={"chip-" + index} className="chip"
+                                      onClick={() => arrayDeleteValue(property.name, v)}>{v.toString()}</Chip>))}
                         </ChipGroup>
                     </TextInputGroupMain>
                     <TextInputGroupUtilities>
-                        <Button variant="plain" onClick={e => this.arraySave(property.name)} aria-label="Add element">
+                        <Button variant="plain" onClick={e => arraySave(property.name)} aria-label="Add element">
                             <PlusIcon/>
                         </Button>
                     </TextInputGroupUtilities>
@@ -592,8 +623,8 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    getKameletParameters = () => {
-        const element = this.props.element;
+    function getKameletParameters() {
+        const element = props.element;
         const requiredParameters = CamelUtil.getKameletRequiredParameters(element);
         return (
             <div className="parameters">
@@ -603,49 +634,48 @@ export class DslPropertyField extends React.Component<Props, State> {
                         property={property}
                         value={CamelDefinitionApiExt.getParametersValue(element, property.id)}
                         required={requiredParameters?.includes(property.id)}
-                        onParameterChange={this.props.onParameterChange}
                     />)}
             </div>
         )
     }
 
-    getMainComponentParameters = (properties: ComponentProperty[]) => {
+    function getMainComponentParameters(properties: ComponentProperty[]) {
+        const element = props.element;
         return (
             <div className="parameters">
                 {properties.map(kp => {
-                    const value = CamelDefinitionApiExt.getParametersValue(this.props.element, kp.name, kp.kind === 'path');
+                    const value = CamelDefinitionApiExt.getParametersValue(element, kp.name, kp.kind === 'path');
                     return (<ComponentParameterField
                         key={kp.name}
                         property={kp}
-                        element={this.props.element}
-                        integration={this.props.integration}
                         value={value}
-                        onParameterChange={this.props.onParameterChange}
+                        element={props.element}
+                        onParameterChange={props.onParameterChange}
                     />)
                 })}
             </div>
         )
     }
 
-    getExpandableComponentParameters = (properties: ComponentProperty[], label: string) => {
+    function getExpandableComponentParameters(properties: ComponentProperty[], label: string) {
+        const element = props.element;
         return (
             <ExpandableSection
                 toggleText={label}
                 onToggle={(_event, isExpanded) => {
-                    this.setState(state => {
-                        state.isShowAdvanced.set(label, !state.isShowAdvanced.get(label));
-                        return {isShowAdvanced: state.isShowAdvanced};
+                    setIsShowAdvanced(prevState => {
+                        prevState.set(label, !prevState.get(label));
+                        return prevState;
                     })
                 }}
-                isExpanded={this.state.isShowAdvanced.has(label) && this.state.isShowAdvanced.get(label)}>
+                isExpanded={isShowAdvanced.has(label) && isShowAdvanced.get(label)}>
                 <div className="parameters">
                     {properties.map(kp =>
                         <ComponentParameterField
                             key={kp.name}
                             property={kp}
-                            integration={this.props.integration}
-                            value={CamelDefinitionApiExt.getParametersValue(this.props.element, kp.name, kp.kind === 'path')}
-                            onParameterChange={this.props.onParameterChange}
+                            value={CamelDefinitionApiExt.getParametersValue(element, kp.name, kp.kind === 'path')}
+                            onParameterChange={props.onParameterChange}
                         />
                     )}
                 </div>
@@ -653,7 +683,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    getLabelIcon = (property: PropertyMeta) => {
+    function getLabelIcon(property: PropertyMeta) {
         return (
             property.description
                 ? <Popover
@@ -662,7 +692,8 @@ export class DslPropertyField extends React.Component<Props, State> {
                     bodyContent={property.description}
                     footerContent={
                         <div>
-                            {property.defaultValue !== undefined && property.defaultValue.toString().trim().length > 0 && <div>{"Default: " + property.defaultValue}</div>}
+                            {property.defaultValue !== undefined && property.defaultValue.toString().trim().length > 0 &&
+                                <div>{"Default: " + property.defaultValue}</div>}
                             {property.required && <b>Required</b>}
                         </div>
                     }>
@@ -670,7 +701,7 @@ export class DslPropertyField extends React.Component<Props, State> {
                         e.preventDefault();
                         e.stopPropagation();
                     }} className="pf-v5-c-form__group-label-help">
-                        <HelpIcon />
+                        <HelpIcon/>
                     </button>
                 </Popover>
                 : <div></div>
@@ -678,72 +709,72 @@ export class DslPropertyField extends React.Component<Props, State> {
     }
 
 
-    isMultiValueField = (property: PropertyMeta): boolean => {
+    function isMultiValueField(property: PropertyMeta): boolean {
         return ['string'].includes(property.type) && property.name !== 'expression' && property.isArray && !property.enumVals;
     }
 
-    getComponentParameters(property: PropertyMeta) {
-        const properties = CamelUtil.getComponentProperties(this.props.element);
+    function getComponentParameters(property: PropertyMeta) {
+        const element = props.element;
+        const properties = CamelUtil.getComponentProperties(element);
         const propertiesMain = properties.filter(p => !p.label.includes("advanced") && !p.label.includes("security") && !p.label.includes("scheduler"));
         const propertiesAdvanced = properties.filter(p => p.label.includes("advanced"));
         const propertiesScheduler = properties.filter(p => p.label.includes("scheduler"));
         const propertiesSecurity = properties.filter(p => p.label.includes("security"));
         return (
             <>
-                {property.name === 'parameters' && this.getMainComponentParameters(propertiesMain)}
-                {property.name === 'parameters' && this.props.element && propertiesScheduler.length > 0
-                    && this.getExpandableComponentParameters(propertiesScheduler, "Scheduler parameters")}
-                {property.name === 'parameters' && this.props.element && propertiesSecurity.length > 0
-                    && this.getExpandableComponentParameters(propertiesSecurity, "Security parameters")}
-                {property.name === 'parameters' && this.props.element && propertiesAdvanced.length > 0
-                    && this.getExpandableComponentParameters(propertiesAdvanced, "Advanced parameters")}
+                {property.name === 'parameters' && getMainComponentParameters(propertiesMain)}
+                {property.name === 'parameters' && element && propertiesScheduler.length > 0
+                    && getExpandableComponentParameters(propertiesScheduler, "Scheduler parameters")}
+                {property.name === 'parameters' && element && propertiesSecurity.length > 0
+                    && getExpandableComponentParameters(propertiesSecurity, "Security parameters")}
+                {property.name === 'parameters' && element && propertiesAdvanced.length > 0
+                    && getExpandableComponentParameters(propertiesAdvanced, "Advanced parameters")}
             </>
         )
     }
 
-    render() {
-        const isKamelet = CamelUtil.isKameletComponent(this.props.element);
-        const property: PropertyMeta = this.props.property;
-        const value = this.props.value;
-        return (
-            <div>
-                <FormGroup
-                    label={this.props.hideLabel ? undefined : this.getLabel(property, value)}
-                    isRequired={property.required}
-                    labelIcon={this.getLabelIcon(property)}>
-                    {value && ["ExpressionDefinition", "ExpressionSubElementDefinition"].includes(property.type)
-                        && this.getExpressionField(property, value)}
-                    {property.isObject && !property.isArray && !["ExpressionDefinition", "ExpressionSubElementDefinition"].includes(property.type)
-                        && this.getObjectField(property, value)}
-                    {property.isObject && property.isArray && !this.isMultiValueField(property)
-                        && this.getMultiValueObjectField(property, value)}
-                    {property.name === 'expression' && property.type === "string" && !property.isArray
-                        && this.getTextArea(property, value)}
-                    {this.canBeInternalUri(property, this.props.element)
-                        && this.getInternalUriSelect(property, value)}
-                    {this.canBeMediaType(property, this.props.element)
-                        && this.getMediaTypeSelect(property, value)}
-                    {this.javaTypeGenerated(property)
-                        && this.getJavaTypeGeneratedInput(property, value)}
-                    {['string', 'duration', 'integer', 'number'].includes(property.type) && property.name !== 'expression' && !property.name.endsWith("Ref")
-                        && !property.isArray && !property.enumVals
-                        && !this.canBeInternalUri(property, this.props.element)
-                        && !this.canBeMediaType(property, this.props.element)
-                        && !this.javaTypeGenerated(property)
-                        && this.getStringInput(property, value)}
-                    {['string'].includes(property.type) && property.name.endsWith("Ref") && !property.isArray && !property.enumVals
-                        && this.getSelectBean(property, value)}
-                    {this.isMultiValueField(property)
-                        && this.getMultiValueField(property, value)}
-                    {property.type === 'boolean'
-                        && this.getSwitch(property, value)}
-                    {property.enumVals
-                        && this.getSelect(property, value)}
-                    {isKamelet && property.name === 'parameters' && this.getKameletParameters()}
-                    {!isKamelet && property.name === 'parameters' && this.getComponentParameters(property)}
-                </FormGroup>
-                {this.getInfrastructureSelectorModal()}
-            </div>
-        )
-    }
+    const element = props.element;
+    const isKamelet = CamelUtil.isKameletComponent(element);
+    const property: PropertyMeta = props.property;
+    const value = props.value;
+    return (
+        <div>
+            <FormGroup
+                label={props.hideLabel ? undefined : getLabel(property, value)}
+                isRequired={property.required}
+                labelIcon={getLabelIcon(property)}>
+                {value !== undefined && ["ExpressionDefinition", "ExpressionSubElementDefinition"].includes(property.type)
+                    && getExpressionField(property, value)}
+                {property.isObject && !property.isArray && !["ExpressionDefinition", "ExpressionSubElementDefinition"].includes(property.type)
+                    && getObjectField(property, value)}
+                {property.isObject && property.isArray && !isMultiValueField(property)
+                    && getMultiValueObjectField(property, value)}
+                {property.name === 'expression' && property.type === "string" && !property.isArray
+                    && getTextArea(property, value)}
+                {canBeInternalUri(property, element)
+                    && getInternalUriSelect(property, value)}
+                {canBeMediaType(property, element)
+                    && getMediaTypeSelect(property, value)}
+                {javaTypeGenerated(property)
+                    && getJavaTypeGeneratedInput(property, value)}
+                {['string', 'duration', 'integer', 'number'].includes(property.type) && property.name !== 'expression' && !property.name.endsWith("Ref")
+                    && !property.isArray && !property.enumVals
+                    && !canBeInternalUri(property, element)
+                    && !canBeMediaType(property, element)
+                    && !javaTypeGenerated(property)
+                    && getStringInput(property, value)}
+                {['string'].includes(property.type) && property.name.endsWith("Ref") && !property.isArray && !property.enumVals
+                    && getSelectBean(property, value)}
+                {isMultiValueField(property)
+                    && getMultiValueField(property, value)}
+                {property.type === 'boolean'
+                    && getSwitch(property, value)}
+                {property.enumVals
+                    && getSelect(property, value)}
+                {isKamelet && property.name === 'parameters' && getKameletParameters()}
+                {!isKamelet && property.name === 'parameters' && getComponentParameters(property)}
+            </FormGroup>
+            {getInfrastructureSelectorModal()}
+        </div>
+    )
 }
diff --git a/karavan-designer/src/designer/route/property/ExpressionField.tsx b/karavan-designer/src/designer/route/property/ExpressionField.tsx
index 135c11fe..0aaf81c1 100644
--- a/karavan-designer/src/designer/route/property/ExpressionField.tsx
+++ b/karavan-designer/src/designer/route/property/ExpressionField.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import {
 	FormGroup,
 	Popover
@@ -31,7 +31,7 @@ import HelpIcon from "@patternfly/react-icons/dist/js/icons/help-icon";
 import {CamelMetadataApi, Languages, PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 import {ExpressionDefinition} from "karavan-core/lib/model/CamelDefinition";
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
 import {DslPropertyField} from "./DslPropertyField";
 import {CamelUi} from "../../utils/CamelUi";
@@ -39,129 +39,120 @@ import {CamelUi} from "../../utils/CamelUi";
 interface Props {
     property: PropertyMeta,
     value: CamelElement,
-    onExpressionChange?: (propertyName: string, exp: ExpressionDefinition) => void
-    integration: Integration,
-    dark: boolean,
+    onExpressionChange?: (propertyName: string, exp: ExpressionDefinition) => void,
 }
 
-interface State {
-    selectIsOpen: boolean;
-}
-
-export class ExpressionField extends React.Component<Props, State> {
+export function ExpressionField(props: Props) {
 
-    public state: State = {
-        selectIsOpen: false,
-    }
+    const [selectIsOpen, setSelectIsOpen] = useState<boolean>(false);
 
-    openSelect = (isExpanded: boolean) => {
-        this.setState({selectIsOpen: isExpanded});
+    function openSelect (isExpanded: boolean) {
+        setSelectIsOpen(isExpanded);
     }
 
-    expressionChanged = (language: string, value: CamelElement) => {
+    function expressionChanged (language: string, value: CamelElement) {
         if (language !== (value as any).expressionName) {
             const className = CamelMetadataApi.getCamelLanguageMetadataByName(language)?.className;
             value = CamelDefinitionApi.createExpression(className || '', {expression: (value as any).expression}); // perhaps copy other similar fields later
         }
         const exp = new ExpressionDefinition();
         (exp as any)[language] = value;
-        if (this.props.value) (exp as any).uuid = this.props.value.uuid;
-        this.props.onExpressionChange?.call(this, this.props.property.name, exp);
-        this.setState({selectIsOpen: false});
+        if (props.value) {
+            (exp as any).uuid = props.value.uuid;
+        }
+        props.onExpressionChange?.(props.property.name, exp);
+        setSelectIsOpen(false);
     }
 
-    propertyChanged = (fieldId: string, value: string | number | boolean | any) => {
-        const expression = this.getExpressionValue();
+    function propertyChanged (fieldId: string, value: string | number | boolean | any) {
+        const expression = getExpressionValue();
         if (expression) {
             (expression as any)[fieldId] = value;
-            this.expressionChanged(this.getValueLanguage(), expression);
+            expressionChanged(getValueLanguage(), expression);
         }
     }
 
-    getValueClassName = (): string => {
-        return CamelDefinitionApiExt.getExpressionLanguageClassName(this.props.value) || 'SimpleExpression';
+    function getValueClassName (): string {
+        return CamelDefinitionApiExt.getExpressionLanguageClassName(props.value) || 'SimpleExpression';
     }
 
-    getValueLanguage = (): string => {
-        return CamelDefinitionApiExt.getExpressionLanguageName(this.props.value) || 'simple';
+    function getValueLanguage (): string {
+        return CamelDefinitionApiExt.getExpressionLanguageName(props.value) || 'simple';
     }
 
-    getExpressionValue = (): CamelElement => {
-        const language = this.getValueLanguage();
-        return this.props.value && (this.props.value as any)[language]
-            ? (this.props.value as any)[language]
-            : CamelDefinitionApi.createExpression(this.getValueClassName(), this.props.value);
+    function getExpressionValue (): CamelElement {
+        const language = getValueLanguage();
+        return props.value && (props.value as any)[language]
+            ? (props.value as any)[language]
+            : CamelDefinitionApi.createExpression(getValueClassName(), props.value);
     }
 
-    getProps = (): PropertyMeta[] => {
-        const dslName = this.getValueClassName();
+    function getProps (): PropertyMeta[] {
+        const dslName = getValueClassName();
         return CamelDefinitionApiExt.getElementProperties(dslName)
             .filter(p => p.name !== 'id')
             .filter(p => !p.isObject || (p.isObject && !CamelUi.dslHasSteps(p.type)) || (dslName === 'CatchDefinition' && p.name === 'onWhen'));
     }
 
-    render() {
-        const property: PropertyMeta = this.props.property;
-        const value = this.getExpressionValue();
-        const dslLanguage = Languages.find((l: [string, string, string]) => l[0] === this.getValueLanguage());
-        const selectOptions: JSX.Element[] = []
-        Languages.forEach((lang: [string, string, string]) => {
-            const s = <SelectOption key={lang[0]} value={lang[0]} description={lang[2]}/>;
-            selectOptions.push(s);
-        })
-        return (
-            <div>
-                <label className="pf-v5-c-form__label" htmlFor="expression">
-                    <span className="pf-v5-c-form__label-text">Language</span>
-                    <span className="pf-v5-c-form__label-required" aria-hidden="true"> *</span>
-                </label>
-                <Select
-                    variant={SelectVariant.typeahead}
-                    aria-label={property.name}
-                    onToggle={(_event, isExpanded) => {
-                        this.openSelect(isExpanded)
-                    }}
-                    onSelect={(e, lang, isPlaceholder) => {
-                        this.expressionChanged(lang.toString(), value);
-                    }}
-                    selections={dslLanguage}
-                    isOpen={this.state.selectIsOpen}
-                    aria-labelledby={property.name}
-                    direction={SelectDirection.down}
-                >
-                    {selectOptions}
-                </Select>
-                <FormGroup
-                    key={property.name}
-                    fieldId={property.name}
-                    labelIcon={property.description ?
-                        <Popover
-                            position={"left"}
-                            headerContent={property.displayName}
-                            bodyContent={property.description}>
-                            <button type="button" aria-label="More info" onClick={e => {
-                                e.preventDefault();
-                                e.stopPropagation();
-                            }}
-                                    className="pf-v5-c-form__group-label-help">
-                                <HelpIcon />
-                            </button>
-                        </Popover> : <div></div>
-                    }>
-                    {value && this.getProps().map((property: PropertyMeta) =>
-                        <DslPropertyField key={property.name + this.props.value?.uuid} property={property}
-                                          integration={this.props.integration}
-                                          element={value}
-                                          value={value ? (value as any)[property.name] : undefined}
-                                          onExpressionChange={exp => {}}
-                                          onParameterChange={parameter => {console.log(parameter)}}
-                                          onDataFormatChange={dataFormat => {console.log(dataFormat)}}
-                                          onChange={this.propertyChanged}
-                                          dark={this.props.dark}
-                                          dslLanguage={dslLanguage}/>
-                    )}
-                </FormGroup>
-            </div>
-        )
-    }
+    const property: PropertyMeta = props.property;
+    const value = getExpressionValue();
+    const dslLanguage = Languages.find((l: [string, string, string]) => l[0] === getValueLanguage());
+    const selectOptions: JSX.Element[] = []
+    Languages.forEach((lang: [string, string, string]) => {
+        const s = <SelectOption key={lang[0]} value={lang[0]} description={lang[2]}/>;
+        selectOptions.push(s);
+    })
+    return (
+        <div>
+            <label className="pf-v5-c-form__label" htmlFor="expression">
+                <span className="pf-v5-c-form__label-text">Language</span>
+                <span className="pf-v5-c-form__label-required" aria-hidden="true"> *</span>
+            </label>
+            <Select
+                variant={SelectVariant.typeahead}
+                aria-label={property.name}
+                onToggle={(_event, isExpanded) => {
+                    openSelect(isExpanded)
+                }}
+                onSelect={(e, lang, isPlaceholder) => {
+                    expressionChanged(lang.toString(), value);
+                }}
+                selections={dslLanguage}
+                isOpen={selectIsOpen}
+                aria-labelledby={property.name}
+                direction={SelectDirection.down}
+            >
+                {selectOptions}
+            </Select>
+            <FormGroup
+                key={property.name}
+                fieldId={property.name}
+                labelIcon={property.description ?
+                    <Popover
+                        position={"left"}
+                        headerContent={property.displayName}
+                        bodyContent={property.description}>
+                        <button type="button" aria-label="More info" onClick={e => {
+                            e.preventDefault();
+                            e.stopPropagation();
+                        }}
+                                className="pf-v5-c-form__group-label-help">
+                            <HelpIcon />
+                        </button>
+                    </Popover> : <div></div>
+                }>
+                {value && getProps().map((property: PropertyMeta) =>
+                    <DslPropertyField key={property.name + props.value?.uuid}
+                                      property={property}
+                                      value={value ? (value as any)[property.name] : undefined}
+                                      dslLanguage={dslLanguage}
+                                      onExpressionChange={exp => {}}
+                                      onParameterChange={parameter => {}}
+                                      onDataFormatChange={dataFormat => {}}
+                                      onPropertyChange={propertyChanged}
+                    />
+                )}
+            </FormGroup>
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
index a9e9649f..38555892 100644
--- a/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
+++ b/karavan-designer/src/designer/route/property/InfrastructureSelector.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import {
     Badge,
     Button, capitalize, Flex, FlexItem,
@@ -32,51 +32,33 @@ interface Props {
     dark: boolean,
 }
 
-interface State {
-    tabIndex: string | number
-    filter?: string
-    configMaps:  string[]
-    secrets:  string[]
-    services:  string[]
-}
-
-export class InfrastructureSelector extends React.Component<Props, State> {
+export function InfrastructureSelector(props: Props) {
 
-    public state: State = {
-        tabIndex: "configMap",
-        configMaps: InfrastructureAPI.configMaps,
-        secrets: InfrastructureAPI.secrets,
-        services: InfrastructureAPI.services
-    };
-
-    selectTab = (evt: React.MouseEvent<HTMLElement, MouseEvent>, eventKey: string | number) => {
-        this.setState({tabIndex: eventKey})
-    }
+    const [tabIndex, setTabIndex] = useState<string | number>("configMap");
+    const [filter, setFilter] = useState<string>();
 
-    checkFilter = (name: string): boolean => {
-        if (this.state.filter !== undefined && name) {
-            return name.toLowerCase().includes(this.state.filter.toLowerCase())
+    function checkFilter  (name: string): boolean {
+        if (filter !== undefined && name) {
+            return name.toLowerCase().includes(filter.toLowerCase())
         } else {
             return true;
         }
     }
 
-    searchInput = () => {
+    function searchInput () {
         return (
             <Form isHorizontal className="search" autoComplete="off">
                 <FormGroup fieldId="search">
                     <TextInput className="text-field" type="text" id="search" name="search" 
-                            value={this.state.filter}
-                            onChange={(_, value) => {
-                                this.setState({filter: value})
-                            }}/>
+                            value={filter}
+                            onChange={(_, value) => setFilter(value)}/>
                 </FormGroup>
             </Form>
         )
     }
 
-    getConfigMapTable() {
-        const configMaps = this.state.configMaps;
+    function getConfigMapTable() {
+        const configMaps = InfrastructureAPI.configMaps;
         return (
             <Table variant='compact' borders={false}>
                 <Thead>
@@ -88,7 +70,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                 </Thead>
                 <Tbody>
                     {configMaps
-                        .filter(name => this.checkFilter(name))
+                        .filter(name => checkFilter(name))
                         .map((name, idx: number) => {
                             const configMapName = name.split("/")[0];
                             const data = name.split("/")[1];
@@ -102,7 +84,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                                     </Td>
                                     <Td noPadding>
                                         <Button style={{padding: '6px'}} variant={"link"} onClick={
-                                            e => this.props.onSelect?.call(this, "configmap:" + name)}>
+                                            e => props.onSelect?.("configmap:" + name)}>
                                             {data}
                                         </Button>
                                     </Td>
@@ -114,8 +96,8 @@ export class InfrastructureSelector extends React.Component<Props, State> {
         )
     }
 
-    getSecretsTable() {
-        const secrets = this.state.secrets;
+    function getSecretsTable() {
+        const secrets = InfrastructureAPI.secrets;
         return (
             <Table variant='compact' borders={false}>
                 <Thead>
@@ -127,7 +109,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                 </Thead>
                 <Tbody>
                     {secrets
-                        .filter(name => this.checkFilter(name))
+                        .filter(name => checkFilter(name))
                         .map((name, idx: number) => {
                             const configMapName = name.split("/")[0];
                             const data = name.split("/")[1];
@@ -141,7 +123,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                                     </Td>
                                     <Td noPadding>
                                         <Button style={{padding: '6px'}} variant={"link"} onClick={
-                                            e => this.props.onSelect?.call(this, "secret:" + name)}>
+                                            e => props.onSelect?.("secret:" + name)}>
                                             {data}
                                         </Button>
                                     </Td>
@@ -153,8 +135,8 @@ export class InfrastructureSelector extends React.Component<Props, State> {
         )
     }
 
-    getServicesTable() {
-        const services = this.state.services;
+    function getServicesTable() {
+        const services = InfrastructureAPI.services;
         return (
             <Table variant='compact' borders={false}>
                 <Thead>
@@ -168,7 +150,7 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                 </Thead>
                 <Tbody>
                     {services
-                        .filter(name => this.checkFilter(name))
+                        .filter(name => checkFilter(name))
                         .map((name, idx: number) => {
                             const serviceName = name.split("|")[0];
                             const hostPort = name.split("|")[1];
@@ -184,19 +166,19 @@ export class InfrastructureSelector extends React.Component<Props, State> {
                                     {/*</Td>*/}
                                     <Td noPadding>
                                         <Button style={{padding: '6px'}} variant={"link"} onClick={
-                                            e => this.props.onSelect?.call(this, hostPort)}>
+                                            e => props.onSelect?.(hostPort)}>
                                             {serviceName}
                                         </Button>
                                     </Td>
                                     <Td noPadding>
                                         <Button style={{padding: '6px'}} variant={"link"} onClick={
-                                            e => this.props.onSelect?.call(this, host)}>
+                                            e => props.onSelect?.(host)}>
                                             {host}
                                         </Button>
                                     </Td>
                                     <Td noPadding>
                                         <Button style={{padding: '6px'}} variant={"link"} onClick={
-                                            e => this.props.onSelect?.call(this, port)}>
+                                            e => props.onSelect?.(port)}>
                                             {port}
                                         </Button>
                                     </Td>
@@ -208,37 +190,34 @@ export class InfrastructureSelector extends React.Component<Props, State> {
         )
     }
 
-    render() {
-        const tabIndex = this.state.tabIndex;
-        const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services'];
-        return (
-            <Modal
-                aria-label="Select from Infrastructure"
-                width={'50%'}
-                className='dsl-modal'
-                isOpen={this.props.isOpen}
-                onClose={this.props.onClose}
-                header={
-                    <Flex direction={{default: "column"}}>
-                        <FlexItem>
-                            <h3>{"Select from " + capitalize(InfrastructureAPI.infrastructure)}</h3>
-                            {this.searchInput()}
-                        </FlexItem>
-                        <FlexItem>
-                            <Tabs style={{overflow: 'hidden'}} activeKey={this.state.tabIndex} onSelect={this.selectTab}>
-                                {tabs.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)}
-                            </Tabs>
-                        </FlexItem>
-                    </Flex>
-                }
-                actions={{}}>
-                <PageSection variant={this.props.dark ? "darker" : "light"}>
-                    {this.searchInput()}
-                    {tabIndex === 'configMap' && this.getConfigMapTable()}
-                    {tabIndex === 'secret' && this.getSecretsTable()}
-                    {tabIndex === 'services' && this.getServicesTable()}
-                </PageSection>
-            </Modal>
-        )
-    }
+    const tabs = InfrastructureAPI.infrastructure === 'kubernetes' ? ['configMap', 'secret', 'services'] : ['services'];
+    return (
+        <Modal
+            aria-label="Select from Infrastructure"
+            width={'50%'}
+            className='dsl-modal'
+            isOpen={props.isOpen}
+            onClose={props.onClose}
+            header={
+                <Flex direction={{default: "column"}}>
+                    <FlexItem>
+                        <h3>{"Select from " + capitalize(InfrastructureAPI.infrastructure)}</h3>
+                        {searchInput()}
+                    </FlexItem>
+                    <FlexItem>
+                        <Tabs style={{overflow: 'hidden'}} activeKey={tabIndex} onSelect={(_, eventKey) => setTabIndex(eventKey)}>
+                            {tabs.map(tab => <Tab eventKey={tab} key={tab} title={<TabTitleText>{capitalize(tab)}</TabTitleText>} />)}
+                        </Tabs>
+                    </FlexItem>
+                </Flex>
+            }
+            actions={{}}>
+            <PageSection variant={props.dark ? "darker" : "light"}>
+                {searchInput()}
+                {tabIndex === 'configMap' && getConfigMapTable()}
+                {tabIndex === 'secret' && getSecretsTable()}
+                {tabIndex === 'services' && getServicesTable()}
+            </PageSection>
+        </Modal>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
index e837677f..69446142 100644
--- a/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/KameletPropertyField.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useRef, useState} from 'react';
 import {
     FormGroup,
     TextInput,
@@ -33,80 +33,66 @@ import KubernetesIcon from "@patternfly/react-icons/dist/js/icons/openshift-icon
 import ShowIcon from "@patternfly/react-icons/dist/js/icons/eye-icon";
 import HideIcon from "@patternfly/react-icons/dist/js/icons/eye-slash-icon";
 import DockerIcon from "@patternfly/react-icons/dist/js/icons/docker-icon";
+import {usePropertiesHook} from "../usePropertiesHook";
 
 interface Props {
     property: Property,
     value: any,
     required: boolean,
-    onParameterChange?: (parameter: string, value: string | number | boolean | any, pathParameter?: boolean) => void
 }
 
-interface State {
-    selectIsOpen: boolean
-    showEditor: boolean
-    showPassword: boolean
-    showInfrastructureSelector: boolean
-    infrastructureSelectorProperty?: string
-    ref: any
-}
+export function KameletPropertyField(props: Props) {
 
-export class KameletPropertyField extends React.Component<Props, State> {
+    const {onParametersChange} = usePropertiesHook();
 
-    public state: State = {
-        selectIsOpen: false,
-        showEditor: false,
-        showPassword: false,
-        showInfrastructureSelector: false,
-        ref: React.createRef(),
-    }
+    const [selectIsOpen, setSelectIsOpen] = useState<boolean>(false);
+    const [showEditor, setShowEditor] = useState<boolean>(false);
+    const [showPassword, setShowPassword] = useState<boolean>(false);
+    const [infrastructureSelector, setInfrastructureSelector] = useState<boolean>(false);
+    const [infrastructureSelectorProperty, setInfrastructureSelectorProperty] = useState<string | undefined>(undefined);
 
-    openSelect = () => {
-        this.setState({selectIsOpen: true});
-    }
+    const ref = useRef<any>(null);
 
-    parametersChanged = (parameter: string, value: string | number | boolean | any, pathParameter?: boolean) => {
-        this.props.onParameterChange?.call(this, parameter, value, pathParameter);
-        this.setState({selectIsOpen: false});
+    function parametersChanged (parameter: string, value: string | number | boolean | any, pathParameter?: boolean)  {
+        onParametersChange(parameter, value, pathParameter);
+        setSelectIsOpen(false);
     }
 
-    selectInfrastructure = (value: string) => {
+    function selectInfrastructure (value: string)  {
         // check if there is a selection
-        const textVal = this.state.ref.current;
+        const textVal = ref.current;
         const cursorStart = textVal.selectionStart;
         const cursorEnd = textVal.selectionEnd;
         if (cursorStart !== cursorEnd){
-            const prevValue = this.props.value;
+            const prevValue =  props.value;
             const selectedText = prevValue.substring(cursorStart, cursorEnd)
             value = prevValue.replace(selectedText, value);
         }
-        const propertyId = this.state.infrastructureSelectorProperty;
+        const propertyId = infrastructureSelectorProperty;
         if (propertyId){
             if (value.startsWith("config") || value.startsWith("secret")) value = "{{" + value + "}}";
-            this.parametersChanged(propertyId, value);
-            this.setState({showInfrastructureSelector: false, infrastructureSelectorProperty: undefined})
+            parametersChanged(propertyId, value);
+            setInfrastructureSelector(false);
+            setInfrastructureSelectorProperty(undefined);
         }
     }
 
-    openInfrastructureSelector = (propertyName: string) => {
-        this.setState({infrastructureSelectorProperty: propertyName, showInfrastructureSelector: true});
-    }
-
-    closeInfrastructureSelector = () => {
-        this.setState({showInfrastructureSelector: false})
+    function openInfrastructureSelector (propertyName: string)  {
+        setInfrastructureSelector(true);
+        setInfrastructureSelectorProperty(propertyName);
     }
 
-    getInfrastructureSelectorModal() {
+    function getInfrastructureSelectorModal() {
         return (
             <InfrastructureSelector
                 dark={false}
-                isOpen={this.state.showInfrastructureSelector}
-                onClose={() => this.closeInfrastructureSelector()}
-                onSelect={this.selectInfrastructure}/>)
+                isOpen={infrastructureSelector}
+                onClose={() => setInfrastructureSelector(false)}
+                onSelect={selectInfrastructure}/>)
     }
 
-    getStringInput() {
-        const {showEditor, showPassword} = this.state;
-        const {property, value} = this.props;
+    function getStringInput() {
+        const {property, value} = props;
         const prefix = "parameters";
         const id = prefix + "-" + property.id;
         const inInfrastructure = InfrastructureAPI.infrastructure !== 'local';
@@ -116,35 +102,35 @@ export class KameletPropertyField extends React.Component<Props, State> {
         return <InputGroup>
             {showInfraSelectorButton  &&
                 <Tooltip position="bottom-end" content={"Select from " + capitalize(InfrastructureAPI.infrastructure)}>
-                    <Button variant="control" onClick={e => this.openInfrastructureSelector(property.id)}>
+                    <Button variant="control" onClick={e => openInfrastructureSelector(property.id)}>
                         {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.format === "password") &&
                 <TextInput
-                    ref={this.state.ref}
+                    ref={ref}
                     className="text-field" isRequired
                     type={property.format && !showPassword ? "password" : "text"}
                     id={id} name={id}
                     value={value}
-                    onChange={(e, value) => this.parametersChanged(property.id, value)}/>}
+                    onChange={(e, value) => parametersChanged(property.id, value)}/>}
             {showEditor && property.format !== "password" &&
                 <TextArea autoResize={true}
                           className="text-field" isRequired
                           type="text"
                           id={id} name={id}
                           value={value}
-                          onChange={(e, value) => this.parametersChanged(property.id, value)}/>}
+                          onChange={(e, value) => parametersChanged(property.id, value)}/>}
             {property.format !== "password" &&
                 <Tooltip position="bottom-end" content={showEditor ? "Change to TextField" : "Change to Text Area"}>
-                    <Button variant="control" onClick={e => this.setState({showEditor: !showEditor})}>
+                    <Button variant="control" onClick={e => setShowEditor(!showEditor)}>
                         {showEditor ? <CompressIcon/> : <ExpandIcon/>}
                     </Button>
                 </Tooltip>
             }
             {property.format === "password" &&
                 <Tooltip position="bottom-end" content={showPassword ? "Hide" : "Show"}>
-                    <Button variant="control" onClick={e => this.setState({showPassword: !showPassword})}>
+                    <Button variant="control" onClick={e => setShowPassword(!showPassword)}>
                         {showPassword ? <ShowIcon/> : <HideIcon/>}
                     </Button>
                 </Tooltip>
@@ -152,53 +138,51 @@ export class KameletPropertyField extends React.Component<Props, State> {
         </InputGroup>
     }
 
-    render() {
-        const property = this.props.property;
-        const value = this.props.value;
-        const prefix = "parameters";
-        const id = prefix + "-" + property.id;
-        return (
-            <div>
-                <FormGroup
-                    key={id}
-                    label={property.title}
-                    fieldId={id}
-                    isRequired={this.props.required}
-                    labelIcon={
-                        <Popover
-                            position={"left"}
-                            headerContent={property.title}
-                            bodyContent={property.description}
-                            footerContent={
-                                <div>
-                                    {property.default !== undefined &&
-                                        <div>Default: {property.default.toString()}</div>}
-                                    {property.example !== undefined && <div>Example: {property.example}</div>}
-                                </div>
-                            }>
-                            <button type="button" aria-label="More info" onClick={e => e.preventDefault()}
-                                    className="pf-v5-c-form__group-label-help">
-                                <HelpIcon />
-                            </button>
-                        </Popover>
-                    }>
-                    {property.type === 'string' && this.getStringInput()
-                    }
-                    {['integer', 'int', 'number'].includes(property.type) &&
-                        <TextInput className="text-field" isRequired type='number' id={id} name={id} value={value}
-                                   onChange={(e, value) => this.parametersChanged(property.id, Number(value))}
-                        />
-                    }
-                    {property.type === 'boolean' && <Switch
-                        id={id} name={id}
-                        value={value?.toString()}
-                        aria-label={id}
-                        isChecked={Boolean(value) === true}
-                        onChange={e => this.parametersChanged(property.id, !Boolean(value))}/>
-                    }
-                </FormGroup>
-                {this.getInfrastructureSelectorModal()}
-            </div>
-        )
-    }
+    const property =  props.property;
+    const value =  props.value;
+    const prefix = "parameters";
+    const id = prefix + "-" + property.id;
+    return (
+        <div>
+            <FormGroup
+                key={id}
+                label={property.title}
+                fieldId={id}
+                isRequired={ props.required}
+                labelIcon={
+                    <Popover
+                        position={"left"}
+                        headerContent={property.title}
+                        bodyContent={property.description}
+                        footerContent={
+                            <div>
+                                {property.default !== undefined &&
+                                    <div>Default: {property.default.toString()}</div>}
+                                {property.example !== undefined && <div>Example: {property.example}</div>}
+                            </div>
+                        }>
+                        <button type="button" aria-label="More info" onClick={e => e.preventDefault()}
+                                className="pf-v5-c-form__group-label-help">
+                            <HelpIcon />
+                        </button>
+                    </Popover>
+                }>
+                {property.type === 'string' && getStringInput()
+                }
+                {['integer', 'int', 'number'].includes(property.type) &&
+                    <TextInput className="text-field" isRequired type='number' id={id} name={id} value={value}
+                               onChange={(e, value) => parametersChanged(property.id, Number(value))}
+                    />
+                }
+                {property.type === 'boolean' && <Switch
+                    id={id} name={id}
+                    value={value?.toString()}
+                    aria-label={id}
+                    isChecked={Boolean(value) === true}
+                    onChange={e => parametersChanged(property.id, !Boolean(value))}/>
+                }
+            </FormGroup>
+            {getInfrastructureSelectorModal()}
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/ModalEditor.tsx b/karavan-designer/src/designer/route/property/ModalEditor.tsx
index ac953db3..3b18975b 100644
--- a/karavan-designer/src/designer/route/property/ModalEditor.tsx
+++ b/karavan-designer/src/designer/route/property/ModalEditor.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useEffect, useState} from 'react';
 import {
     Button,
     Modal,
@@ -36,64 +36,53 @@ interface Props {
     showEditor: boolean
 }
 
-interface State {
-    customCode: any,
-}
-
-export class ModalEditor extends React.Component<Props, State> {
+export function ModalEditor(props: Props) {
 
-    public state: State = {
-        customCode: this.props.customCode,
-    }
+    const [customCode, setCustomCode] = useState<string | undefined>();
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevProps.showEditor !== this.props.showEditor) {
-            this.setState({customCode: this.props.customCode})
-        }
-    }
+    useEffect(() => {
+        setCustomCode(props.customCode)
+    },[]);
 
-    close(){
-        this.props.onClose?.call(this);
+    function close(){
+        props.onClose();
     }
 
-    closeAndSave(){
-        this.props.onSave?.call(this, this.props.property.name, this.state.customCode);
+    function closeAndSave(){
+        props.onSave(props.property.name, customCode);
     }
 
-    render() {
-        const {dark, dslLanguage, title, showEditor} = this.props;
-        const {customCode} = this.state;
-        return (
-            <Modal
-                aria-label={"expression"}
-                variant={ModalVariant.large}
-                header={<React.Fragment>
-                    <Title id="modal-custom-header-label" headingLevel="h1" size={TitleSizes['2xl']}>
-                        {title}
-                    </Title>
-                    <p className="pf-v5-u-pt-sm">{dslLanguage?.[2]}</p>
-                </React.Fragment>}
-                isOpen={showEditor}
-                onClose={() => this.close()}
-                actions={[
-                    <Button key="save" variant="primary" size="sm"
-                            onClick={e => this.closeAndSave()}>Save</Button>,
-                    <Button key="cancel" variant="secondary" size="sm"
-                            onClick={e => this.close()}>Close</Button>
-                ]}
-                onEscapePress={e => this.close()}>
-                <Editor
-                    height="400px"
-                    width="100%"
-                    defaultLanguage={'java'}
-                    language={'java'}
-                    theme={dark ? 'vs-dark' : 'light'}
-                    options={{lineNumbers: "off", folding: false, lineNumbersMinChars: 10, showUnused: false, fontSize: 12, minimap: {enabled: false}}}
-                    value={customCode?.toString()}
-                    className={'code-editor'}
-                    onChange={(value: any, ev: any) => this.setState({customCode: value})}
-                />
-            </Modal>
-        )
-    }
+    const {dark, dslLanguage, title, showEditor} = props;
+    return (
+        <Modal
+            aria-label={"expression"}
+            variant={ModalVariant.large}
+            header={<React.Fragment>
+                <Title id="modal-custom-header-label" headingLevel="h1" size={TitleSizes['2xl']}>
+                    {title}
+                </Title>
+                <p className="pf-v5-u-pt-sm">{dslLanguage?.[2]}</p>
+            </React.Fragment>}
+            isOpen={showEditor}
+            onClose={() => close()}
+            actions={[
+                <Button key="save" variant="primary" size="sm"
+                        onClick={e => closeAndSave()}>Save</Button>,
+                <Button key="cancel" variant="secondary" size="sm"
+                        onClick={e => close()}>Close</Button>
+            ]}
+            onEscapePress={e => close()}>
+            <Editor
+                height="400px"
+                width="100%"
+                defaultLanguage={'java'}
+                language={'java'}
+                theme={dark ? 'vs-dark' : 'light'}
+                options={{lineNumbers: "off", folding: false, lineNumbersMinChars: 10, showUnused: false, fontSize: 12, minimap: {enabled: false}}}
+                value={customCode?.toString()}
+                className={'code-editor'}
+                onChange={(value,_) => setCustomCode(value)}
+            />
+        </Modal>
+    )
 }
diff --git a/karavan-designer/src/designer/route/property/ObjectField.tsx b/karavan-designer/src/designer/route/property/ObjectField.tsx
index a72019b5..4d59d4f0 100644
--- a/karavan-designer/src/designer/route/property/ObjectField.tsx
+++ b/karavan-designer/src/designer/route/property/ObjectField.tsx
@@ -14,81 +14,65 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {useState} from 'react';
 import '../../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
 import {DslPropertyField} from "./DslPropertyField";
 import {
     ExpressionDefinition,
 } from "karavan-core/lib/model/CamelDefinition";
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import { PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
 
 interface Props {
     property: PropertyMeta,
-    value?: CamelElement,
-    onPropertyUpdate?: (fieldId: string, value: CamelElement) => void
-    integration: Integration,
+    onPropertyUpdate: (fieldId: string, value: CamelElement) => void
     hideLabel?: boolean
-    dark: boolean
-}
-
-interface State {
     value?: CamelElement,
-    selectStatus: Map<string, boolean>
 }
 
-export class ObjectField extends React.Component<Props, State> {
-    public state: State = {
-        value: this.props.value,
-        selectStatus: new Map<string, boolean>(),
-    };
+export function ObjectField(props: Props) {
 
-    propertyChanged = (fieldId: string, value: string | number | boolean | any) => {
-        if (this.props.value) {
-            const clone = CamelUtil.cloneStep(this.props.value);
+    const [value, setValue] = useState<CamelElement | undefined>(props.value);
+
+    function propertyChanged (fieldId: string, value: string | number | boolean | any) {
+        if (props.value) {
+            const clone = CamelUtil.cloneStep(props.value);
             (clone as any)[fieldId] = value;
-            this.setStep(clone)
-            this.props.onPropertyUpdate?.call(this, this.props.property.name, clone);
+            setStep(clone)
+            props.onPropertyUpdate(props.property.name, clone);
         }
     }
 
-    expressionChanged = (propertyName: string, value:ExpressionDefinition) => {
-        if (this.props.value) {
-            const clone = CamelUtil.cloneStep(this.props.value);
+    function expressionChanged (propertyName: string, value:ExpressionDefinition) {
+        if (props.value) {
+            const clone = CamelUtil.cloneStep(props.value);
             (clone as any)[propertyName] = value;
-            this.setStep(clone)
-            this.props.onPropertyUpdate?.call(this, this.props.property.name, clone);
+            setStep(clone)
+            props.onPropertyUpdate(props.property.name, clone);
         }
     }
 
-    setStep = (step?: CamelElement) => {
-        this.setState({
-            value: step,
-            selectStatus: new Map<string, boolean>()
-        });
+    function setStep (step?: CamelElement) {
+        setValue(step);
     }
 
-    render() {
-        const value = this.props.value;
-        return (
-                <div className="object-field">
-                    {value && CamelDefinitionApiExt.getElementProperties(value.dslName).map((property: PropertyMeta)  =>
-                        <DslPropertyField key={property.name}
-                                          hideLabel={this.props.hideLabel}
-                                          integration={this.props.integration}
-                                          property={property}
-                                          element={value}
-                                          value={value ? (value as any)[property.name] : undefined}
-                                          onExpressionChange={this.expressionChanged}
-                                          onParameterChange={(parameter, value) => this.propertyChanged(property.name, value)}
-                                          onDataFormatChange={value1 => {}}
-                                          onChange={(fieldId, value) => this.propertyChanged(property.name, value)}
-                                          dark={this.props.dark}/>
-                    )}
-                </div>
-        )
-    }
+    const val = props.value;
+    return (
+        <div className="object-field">
+            {val && CamelDefinitionApiExt.getElementProperties(val.dslName).map((property: PropertyMeta)  =>
+                <DslPropertyField key={property.name}
+                                  property={property}
+                                  element={value}
+                                  onExpressionChange={expressionChanged}
+                                  onParameterChange={(parameter, value) => propertyChanged(property.name, value)}
+                                  onDataFormatChange={value1 => {}}
+                                  onPropertyChange={(fieldId, value) => propertyChanged(property.name, value)}
+                                  value={val ? (val as any)[property.name] : undefined}
+                />
+            )}
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/index.tsx b/karavan-designer/src/designer/route/useDrawerMutationsObserver.tsx
similarity index 51%
copy from karavan-designer/src/index.tsx
copy to karavan-designer/src/designer/route/useDrawerMutationsObserver.tsx
index 53d84ae5..45b528aa 100644
--- a/karavan-designer/src/index.tsx
+++ b/karavan-designer/src/designer/route/useDrawerMutationsObserver.tsx
@@ -14,12 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
-import "./index.css";
-import "@patternfly/patternfly/patternfly.css";
-import App from "./App";
-import {createRoot} from "react-dom/client";
 
-const container = document.getElementById('root');
-const root = createRoot(container!);
-root.render(<App/>);
\ No newline at end of file
+import { useLayoutEffect, useRef } from 'react';
+
+function useMutationsObserver<T extends HTMLElement>(callback: (target: T, mutations: any) => void) {
+    const ref = useRef<T>(null)
+
+    useLayoutEffect(() => {
+        const element = ref?.current;
+        if (!element) {
+            return;
+        }
+        const drawer = element.childNodes[0].childNodes[0].childNodes[1];
+        const observer2 = new MutationObserver(mutations => callback(element, mutations));
+        observer2.observe(drawer, {attributes: true, attributeOldValue: true, attributeFilter: ['style']});
+        return () => {
+            // observer1.disconnect();
+            observer2.disconnect();
+        };
+    }, [callback, ref]);
+
+    return ref
+}
+
+export default useMutationsObserver;
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/usePropertiesHook.tsx b/karavan-designer/src/designer/route/usePropertiesHook.tsx
new file mode 100644
index 00000000..058ae5f2
--- /dev/null
+++ b/karavan-designer/src/designer/route/usePropertiesHook.tsx
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import '../karavan.css';
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {
+    DataFormatDefinition, ExpressionDefinition, ToDefinition,
+} from "karavan-core/lib/model/CamelDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
+import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
+import {RouteToCreate} from "../utils/CamelUi";
+import {useDesignerStore, useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+
+export function usePropertiesHook (isRouteDesigner: boolean = true) {
+
+    const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow)
+    const [ selectedStep, setSelectedStep, setSelectedUuids] = useDesignerStore((s) =>
+        [s.selectedStep, s.setSelectedStep, s.setSelectedUuids], shallow)
+
+    function onPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) {
+        if (isRouteDesigner) {
+            onRoutePropertyUpdate(element, newRoute);
+        } else {
+            onRestPropertyUpdate(element, newRoute);
+        }
+    }
+
+    function onRoutePropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) {
+        if (newRoute) {
+            let i = CamelDefinitionApiExt.updateIntegrationRouteElement(integration, element);
+            const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}});
+            const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
+            i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
+            const clone = CamelUtil.cloneIntegration(i);
+            setIntegration(clone, false);
+            setSelectedStep(element);
+            setSelectedUuids([element.uuid]);
+        } else {
+            const clone = CamelUtil.cloneIntegration(integration);
+            const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
+            setIntegration(i, true);
+        }
+    }
+
+    function onRestPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) {
+        if (newRoute) {
+            let i = CamelDefinitionApiExt.updateIntegrationRestElement(integration, element);
+            const f = CamelDefinitionApi.createFromDefinition({uri: newRoute.componentName, parameters: {name: newRoute.name}});
+            const r = CamelDefinitionApi.createRouteDefinition({from: f, id: newRoute.name})
+            i = CamelDefinitionApiExt.addStepToIntegration(i, r, '');
+            const clone = CamelUtil.cloneIntegration(i);
+            setIntegration(clone, false);
+            setSelectedStep(element);
+        } else {
+            const clone = CamelUtil.cloneIntegration(integration);
+            const i = CamelDefinitionApiExt.updateIntegrationRestElement(clone, element);
+            setIntegration(i, true);
+            // setSelectedStep(element);
+        }
+    }
+
+    function onPropertyChange (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate){
+        if (selectedStep) {
+            const clone = CamelUtil.cloneStep(selectedStep);
+            (clone as any)[fieldId] = value;
+            setSelectedStep(clone)
+            onPropertyUpdate(clone, newRoute);
+        }
+    }
+
+    function onDataFormatChange (value: DataFormatDefinition)   {
+        value.uuid = selectedStep?.uuid ? selectedStep?.uuid : value.uuid;
+        setSelectedStep(value);
+        onPropertyUpdate(value);
+    }
+
+    function onExpressionChange (propertyName: string, exp: ExpressionDefinition)   {
+        if (selectedStep) {
+            const clone = (CamelUtil.cloneStep(selectedStep));
+            (clone as any)[propertyName] = exp;
+            setSelectedStep(clone);
+            onPropertyUpdate(clone);
+        }
+    }
+
+    function onParametersChange (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate)   {
+        if (selectedStep && selectedStep) {
+            const clone = (CamelUtil.cloneStep(selectedStep));
+            const parameters: any = {...(clone as any).parameters};
+            parameters[parameter] = value;
+            (clone as any).parameters = parameters;
+            setSelectedStep(clone);
+            onPropertyUpdate(clone, newRoute);
+        }
+    }
+
+    function getInternalComponentName(propertyName: string, element?: CamelElement): string {
+        if (element && element.dslName === 'ToDefinition' && propertyName === 'name') {
+            const uri: string = (element as ToDefinition).uri || '';
+            if (uri.startsWith("direct")) return "direct";
+            if (uri.startsWith("seda")) return "seda";
+            return '';
+        } else {
+            return '';
+        }
+    }
+
+    function cloneElement ()   {
+        // TODO:
+    }
+
+    return {cloneElement, onPropertyChange, onParametersChange, onDataFormatChange, onExpressionChange, getInternalComponentName}
+}
\ No newline at end of file
diff --git a/karavan-designer/src/index.tsx b/karavan-designer/src/designer/route/useResizeObserver.tsx
similarity index 56%
copy from karavan-designer/src/index.tsx
copy to karavan-designer/src/designer/route/useResizeObserver.tsx
index 53d84ae5..dc04401d 100644
--- a/karavan-designer/src/index.tsx
+++ b/karavan-designer/src/designer/route/useResizeObserver.tsx
@@ -14,12 +14,27 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
-import "./index.css";
-import "@patternfly/patternfly/patternfly.css";
-import App from "./App";
-import {createRoot} from "react-dom/client";
 
-const container = document.getElementById('root');
-const root = createRoot(container!);
-root.render(<App/>);
\ No newline at end of file
+import { useLayoutEffect, useRef } from 'react';
+
+function useResizeObserver<T extends HTMLElement>(callback: (target: T, entry: ResizeObserverEntry) => void) {
+    const ref = useRef<T>(null)
+
+    useLayoutEffect(() => {
+        const element = ref?.current;
+        if (!element) {
+            return;
+        }
+        const observer1 = new ResizeObserver((entries) => {
+            callback(element, entries[0]);
+        });
+        observer1.observe(element);
+        return () => {
+            observer1.disconnect();
+        };
+    }, [callback, ref]);
+
+    return ref
+}
+
+export default useResizeObserver;
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
new file mode 100644
index 00000000..28dceaca
--- /dev/null
+++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
@@ -0,0 +1,302 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import '../karavan.css';
+import {DslMetaModel} from "../utils/DslMetaModel";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {ChoiceDefinition, FromDefinition, LogDefinition, RouteConfigurationDefinition, RouteDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
+import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
+import {Command, EventBus} from "../utils/EventBus";
+import {RouteToCreate} from "../utils/CamelUi";
+import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
+import {toPng} from 'html-to-image';
+import {RouteDesigner} from "./RouteDesigner";
+import {findDOMNode} from "react-dom";
+import {Subscription} from "rxjs";
+import debounce from 'lodash.debounce';
+import {useDesignerStore, useIntegrationStore, useSelectorStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+
+export function useRouteDesignerHook () {
+
+    const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow)
+    const [selectedUuids,clipboardSteps,shiftKeyPressed,
+        setShowDeleteConfirmation, setDeleteMessage, setSelectedStep, setSelectedUuids, setClipboardSteps, setShiftKeyPressed,
+        width, height, dark, hideLogDSL] = useDesignerStore((s) =>
+        [s.selectedUuids,s.clipboardSteps, s.shiftKeyPressed,
+            s.setShowDeleteConfirmation, s.setDeleteMessage, s.setSelectedStep, s.setSelectedUuids, s.setClipboardSteps, s.setShiftKeyPressed,
+            s.width, s.height, s.dark, s.hideLogDSL], shallow)
+    const [setParentId, setShowSelector, setSelectorTabIndex, setParentDsl, setShowSteps, setSelectedPosition] = useSelectorStore((s) =>
+        [s.setParentId, s.setShowSelector, s.setSelectorTabIndex, s.setParentDsl, s.setShowSteps, s.setSelectedPosition], shallow)
+
+    function  onCommand (command: Command, printerRef: React.MutableRefObject<HTMLDivElement | null>) {
+        switch (command.command){
+            case "downloadImage": integrationImageDownload(printerRef);
+        }
+    }
+
+    const onShowDeleteConfirmation = (id: string) => {
+        let message: string;
+        const uuidsToDelete:string [] = [id];
+        let ce: CamelElement;
+        ce = CamelDefinitionApiExt.findElementInIntegration(integration, id)!;
+        if (ce.dslName === 'FromDefinition') { // Get the RouteDefinition for this.routeDesigner.  Use its uuid.
+            let flows = integration.spec.flows!;
+            for (let i = 0; i < flows.length; i++) {
+                if (flows[i].dslName === 'RouteDefinition') {
+                    let routeDefinition: RouteDefinition = flows[i];
+                    if (routeDefinition.from.uuid === id) {
+                        uuidsToDelete.push(routeDefinition.uuid);
+                        break;
+                    }
+                }
+            }
+            message = 'Deleting the first element will delete the entire route!';
+        } else if (ce.dslName === 'RouteDefinition') {
+            message = 'Delete route?';
+        } else if (ce.dslName === 'RouteConfigurationDefinition') {
+            message = 'Delete route configuration?';
+        } else {
+            message = 'Delete element from route?';
+        }
+        setShowDeleteConfirmation(true);
+        setDeleteMessage(message);
+        setSelectedUuids(uuidsToDelete);
+    }
+
+    const deleteElement = () =>  {
+        selectedUuids.forEach(uuidToDelete => {
+            const i = CamelDefinitionApiExt.deleteStepFromIntegration(integration, uuidToDelete);
+            setIntegration(i, false);
+            setShowSelector(false);
+            setShowDeleteConfirmation(false);
+            setDeleteMessage('');
+            setSelectedStep(undefined);
+            setSelectedUuids([uuidToDelete]);
+
+            const el = new CamelElement("");
+            el.uuid = uuidToDelete;
+            EventBus.sendPosition("delete", el, undefined, new DOMRect(), new DOMRect(), 0);
+        });
+    }
+
+    const selectElement = (element: CamelElement) =>  {
+        const uuids = [...selectedUuids];
+        let canNotAdd: boolean = false;
+        if (shiftKeyPressed) {
+            const hasFrom = uuids.map(e => CamelDefinitionApiExt.findElementInIntegration(integration, e)?.dslName === 'FromDefinition').filter(r => r).length > 0;
+            canNotAdd = hasFrom || (uuids.length > 0 && element.dslName === 'FromDefinition');
+        }
+        const add = shiftKeyPressed && !uuids.includes(element.uuid);
+        const remove = shiftKeyPressed && uuids.includes(element.uuid);
+        // TODO: do we need to change Integration just for select????
+        const i = CamelDisplayUtil.setIntegrationVisibility(integration, element.uuid);
+
+        if (remove) {
+            const index = uuids.indexOf(element.uuid);
+            uuids.splice(index, 1);
+        } else if (add && !canNotAdd) {
+            uuids.push(element.uuid);
+        }
+        const uuid: string = uuids.includes(element.uuid) ? element.uuid : uuids.at(0) || '';
+        const selectedElement = shiftKeyPressed ? CamelDefinitionApiExt.findElementInIntegration(integration, uuid) : element;
+
+        setIntegration(i, true);
+        setSelectedStep(selectedElement);
+        setSelectedUuids(shiftKeyPressed ? [...uuids] : [element.uuid])
+    }
+
+    function handleKeyDown (event: KeyboardEvent) {
+        if ((event.shiftKey)) {
+            setShiftKeyPressed(true);
+        }
+        if (window.document.hasFocus() && window.document.activeElement) {
+            if (['BODY', 'MAIN'].includes(window.document.activeElement.tagName)) {
+                let charCode = String.fromCharCode(event.which).toLowerCase();
+                if ((event.ctrlKey || event.metaKey) && charCode === 'c') {
+                    copyToClipboard();
+                } else if ((event.ctrlKey || event.metaKey) && charCode === 'v') {
+                    pasteFromClipboard();
+                }
+            }
+        } else {
+            if (event.repeat) {
+                window.dispatchEvent(event);
+            }
+        }
+    }
+
+    function handleKeyUp (event: KeyboardEvent) {
+        setShiftKeyPressed(false);
+        if (event.repeat) {
+            window.dispatchEvent(event);
+        }
+    }
+
+    function copyToClipboard  (): void {
+        const steps: CamelElement[] = []
+        selectedUuids.forEach(selectedUuid => {
+            const selectedElement = CamelDefinitionApiExt.findElementInIntegration(integration, selectedUuid);
+            if (selectedElement) {
+                steps.push(selectedElement);
+            }
+        })
+        if (steps.length > 0) {
+            setClipboardSteps(steps);
+        }
+    }
+    function pasteFromClipboard (): void {
+        if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'FromDefinition') {
+            const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+            const route = CamelDefinitionApi.createRouteDefinition({from: clone});
+            addStep(route, '', 0)
+        } else if (clipboardSteps.length === 1 && clipboardSteps[0]?.dslName === 'RouteDefinition') {
+            const clone = CamelUtil.cloneStep(clipboardSteps[0], true);
+            addStep(clone, '', 0)
+        } else if (selectedUuids.length === 1) {
+            const targetMeta = CamelDefinitionApiExt.findElementMetaInIntegration(integration, selectedUuids[0]);
+            clipboardSteps.reverse().forEach(clipboardStep => {
+                if (clipboardStep && targetMeta.parentUuid) {
+                    const clone = CamelUtil.cloneStep(clipboardStep, true);
+                    addStep(clone, targetMeta.parentUuid, targetMeta.position);
+                }
+            })
+        }
+    }
+
+    function unselectElement (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) {
+        if ((evt.target as any).dataset.click === 'FLOWS') {
+            evt.stopPropagation()
+            const i = CamelDisplayUtil.setIntegrationVisibility(integration, undefined);
+            setIntegration(i, true);
+            setSelectedStep(undefined);
+            setSelectedPosition(undefined);
+            setSelectedUuids([]);
+        }
+    }
+
+    const openSelector = (parentId: string | undefined, parentDsl: string | undefined, showSteps: boolean = true, position?: number | undefined, selectorTabIndex?: string | number) => {
+        setShowSelector(true);
+        setParentId(parentId || '');
+        setParentDsl(parentDsl);
+        setShowSteps(showSteps);
+        setSelectedPosition(position);
+        setSelectorTabIndex((parentId === undefined && parentDsl === undefined) ? 'kamelet' : 'eip');
+    }
+
+    const onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
+        switch (dsl.dsl) {
+            case 'FromDefinition' :
+                const route = CamelDefinitionApi.createRouteDefinition({from: new FromDefinition({uri: dsl.uri})});
+                addStep(route, parentId, position)
+                break;
+            case 'ToDefinition' :
+                const to = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
+                addStep(to, parentId, position)
+                break;
+            case 'ToDynamicDefinition' :
+                const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: dsl.uri});
+                addStep(toD, parentId, position)
+                break;
+            case 'KameletDefinition' :
+                const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: dsl.name});
+                addStep(kamelet, parentId, position)
+                break;
+            default:
+                const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
+                const augmentedStep = setDslDefaults(step);
+                addStep(augmentedStep, parentId, position)
+                break;
+        }
+    }
+
+    function setDslDefaults(step: CamelElement): CamelElement {
+        if (step.dslName === 'LogDefinition') {
+            // eslint-disable-next-line no-template-curly-in-string
+            (step as LogDefinition).message = "${body}";
+        }
+        if (step.dslName === 'ChoiceDefinition') {
+            (step as ChoiceDefinition).when?.push(CamelDefinitionApi.createStep('WhenDefinition', undefined));
+            (step as ChoiceDefinition).otherwise = CamelDefinitionApi.createStep('OtherwiseDefinition', undefined);
+        }
+        return step;
+    }
+
+    const createRouteConfiguration = () => {
+        const clone = CamelUtil.cloneIntegration(integration);
+        const routeConfiguration = new RouteConfigurationDefinition();
+        const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
+        setIntegration(i, false);
+        setSelectedStep(routeConfiguration);
+        setSelectedUuids([routeConfiguration.uuid]);
+    }
+
+    const addStep = (step: CamelElement, parentId: string, position?: number | undefined) => {
+        const clone = CamelUtil.cloneIntegration(integration);
+        const i = CamelDefinitionApiExt.addStepToIntegration(clone, step, parentId, position);
+        const selectedStep = step.dslName === 'RouteDefinition' ? (step as RouteDefinition).from  : step;
+        setIntegration(i, false);
+        setSelectedStep(selectedStep);
+        setSelectedUuids([selectedStep.uuid]);
+    }
+
+
+    const moveElement = (source: string, target: string, asChild: boolean) => {
+        const i = CamelDefinitionApiExt.moveRouteElement(integration, source, target, asChild);
+        const clone = CamelUtil.cloneIntegration(i);
+        const selectedStep = CamelDefinitionApiExt.findElementInIntegration(clone, source);
+
+        setIntegration(clone, false);
+        setShowSelector(false);
+        setSelectedStep(selectedStep);
+        setSelectedUuids([source]);
+    }
+
+    function downloadIntegrationImage(dataUrl: string) {
+        const a = document.createElement('a');
+        a.setAttribute('download', 'karavan-routes.png');
+        a.setAttribute('href', dataUrl);
+        a.click();
+    }
+
+    function  integrationImageDownloadFilter (node: HTMLElement) {
+        const exclusionClasses = ['add-flow'];
+        return !exclusionClasses.some(classname => {
+            return node.classList === undefined ? false : node.classList.contains(classname);
+        });
+    }
+
+    function integrationImageDownload(printerRef: React.MutableRefObject<HTMLDivElement | null>) {
+        const ref = printerRef.current;
+        if (ref !== null) {
+            toPng(ref, {
+                style: {overflow: 'hidden'}, cacheBust: true, filter: integrationImageDownloadFilter,
+                height: height, width: width, backgroundColor: dark ? "black" : "white"
+            }).then(v => {
+                toPng(ref, {
+                    style: {overflow: 'hidden'}, cacheBust: true, filter: integrationImageDownloadFilter,
+                    height: height, width: width, backgroundColor: dark ? "black" : "white"
+                }).then(downloadIntegrationImage);
+            })
+        }
+    }
+
+    return { deleteElement, selectElement, moveElement, onShowDeleteConfirmation, onDslSelect, openSelector,
+        createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement}
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/templates/TemplatesDesigner.tsx b/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
deleted file mode 100644
index ffc5d9d9..00000000
--- a/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react';
-import {
-     EmptyState, EmptyStateBody, EmptyStateIcon,
-    PageSection, EmptyStateHeader, 
-} from '@patternfly/react-core';
-import '../karavan.css';
-import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
-import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
-
-interface Props {
-    onSave?: (integration: Integration, propertyOnly: boolean) => void
-    integration: Integration
-    dark: boolean
-}
-
-interface State {
-    integration: Integration
-    selectedStep?: CamelElement
-    key: string
-    propertyOnly: boolean
-}
-
-export class TemplatesDesigner extends React.Component<Props, State> {
-
-    public state: State = {
-        integration: this.props.integration,
-        key: "",
-        propertyOnly: false
-    };
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, this.state.integration, this.state.propertyOnly);
-        }
-    }
-
-    onIntegrationUpdate = (i: Integration) => {
-        this.setState({integration: i, key: Math.random().toString()});
-    }
-
-    render() {
-        return (
-            <PageSection className="templates-page" isFilled padding={{default: 'noPadding'}}>
-                <div className="templates-page-columns">
-                    <EmptyState>
-                        <EmptyStateHeader titleText="Templates" icon={<EmptyStateIcon icon={CubesIcon} />} headingLevel="h4" />
-                        <EmptyStateBody>
-                            Templates not implemented yet
-                        </EmptyStateBody>
-                    </EmptyState>
-                </div>
-            </PageSection>
-        );
-    }
-}
diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx
index 8d4157c4..c5d63801 100644
--- a/karavan-designer/src/designer/utils/CamelUi.tsx
+++ b/karavan-designer/src/designer/utils/CamelUi.tsx
@@ -81,7 +81,7 @@ import {
     SplitIcon,
     SpringIcon,
     TerminalIcon,
-    TestingIcon,
+    TestingIcon, ToIcon,
     TransformationIcon,
     ValidationIcon,
     WebserviceIcon,
@@ -161,6 +161,16 @@ const connectorNavs = ['routing', "transformation", "error", "configuration", "e
 
 export class CamelUi {
 
+    static createNewInternalRoute = (uri: string): RouteToCreate | undefined => {
+        const uris = uri.toString().split(":");
+        const componentName = uris[0];
+        const name = uris[1];
+        if (['direct', 'seda'].includes(componentName)) {
+            return new RouteToCreate(componentName, name)
+        }
+        return undefined;
+    }
+
     static getSelectorModelTypes = (parentDsl: string | undefined, showSteps: boolean = true, filter: string | undefined = undefined): [string, number][] => {
         const navs = CamelUi.getSelectorModelsForParent(parentDsl, showSteps).map(dsl => dsl.navigation.split(","))
             .reduce((accumulator, value) => accumulator.concat(value), [])
@@ -705,6 +715,8 @@ export class CamelUi {
         switch (dslName) {
             case 'AggregateDefinition':
                 return <AggregateIcon/>;
+            case 'ToDefinition':
+                return <ToIcon/>;
             case 'ChoiceDefinition' :
                 return <ChoiceIcon/>;
             case 'SplitDefinition' :
@@ -723,6 +735,18 @@ export class CamelUi {
                 return <InterceptFrom/>;
             case 'InterceptSendToEndpointDefinition' :
                 return <InterceptSendToEndpoint/>;
+            case 'GetDefinition' :
+                return <ApiIcon/>;
+            case 'PostDefinition' :
+                return <ApiIcon/>;
+            case 'PutDefinition' :
+                return <ApiIcon/>;
+            case 'PatchDefinition' :
+                return <ApiIcon/>;
+            case 'DeleteDefinition' :
+                return <ApiIcon/>;
+            case 'HeadDefinition' :
+                return <ApiIcon/>;
             default:
                 return this.getIconFromSource(CamelUi.getIconSrcForName(dslName))
         }
diff --git a/karavan-designer/src/designer/utils/EventBus.ts b/karavan-designer/src/designer/utils/EventBus.ts
index aeae6ff7..ec11019e 100644
--- a/karavan-designer/src/designer/utils/EventBus.ts
+++ b/karavan-designer/src/designer/utils/EventBus.ts
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 import {Subject} from 'rxjs';
-import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
 
 const positions = new Subject<DslPosition>();
 
@@ -59,6 +59,17 @@ export class Command {
     }
 }
 
+const updates = new Subject<IntegrationUpdate>();
+export class IntegrationUpdate {
+    integration: Integration;
+    propertyOnly: boolean;
+
+    constructor(integration: Integration, propertyOnly: boolean) {
+        this.integration = integration;
+        this.propertyOnly = propertyOnly;
+    }
+}
+
 export const EventBus = {
     sendPosition: (command: "add" | "delete" | "clean",
                    step: CamelElement,
@@ -70,6 +81,9 @@ export const EventBus = {
                    isSelected: boolean = false) => positions.next(new DslPosition(command, step, parent, rect, headerRect, position, inSteps, isSelected)),
     onPosition: () => positions.asObservable(),
 
+    sendIntegrationUpdate: (i: Integration, propertyOnly: boolean) => updates.next(new IntegrationUpdate(i, propertyOnly)),
+    onIntegrationUpdate: () => updates.asObservable(),
+
     sendCommand: (command: string, data?: any) => commands.next(new Command(command, data)),
     onCommand: () => commands.asObservable(),
 }
diff --git a/karavan-designer/src/designer/utils/InfrastructureAPI.ts b/karavan-designer/src/designer/utils/InfrastructureAPI.ts
index 8b182dc1..f0d8faef 100644
--- a/karavan-designer/src/designer/utils/InfrastructureAPI.ts
+++ b/karavan-designer/src/designer/utils/InfrastructureAPI.ts
@@ -1,5 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 export class InfrastructureAPI {
 
+    // code API
+    static onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>;
+    static onSaveCustomCode: (name: string, code: string) => void;
+    static onSave: (filename: string, yaml: string, propertyOnly: boolean) => void;
+
+    static setOnGetCustomCode(onGetCustomCode: (name: string, javaType: string) => Promise<string | undefined>){
+        this.onGetCustomCode = onGetCustomCode
+    }
+
+    static setOnSaveCustomCode(onSaveCustomCode: (name: string, code: string) => void){
+        this.onSaveCustomCode = onSaveCustomCode
+    }
+
+    static setOnSave(onSave:(filename: string, yaml: string, propertyOnly: boolean) => void){
+        this.onSave = onSave
+    }
+
+    // Kubernetes/Docker API
     static infrastructure: 'kubernetes' | 'docker' | 'local' = 'local';
     static configMaps: string[] = [];
     static secrets: string[] = [];
diff --git a/karavan-designer/src/designer/utils/IntegrationHeader.tsx b/karavan-designer/src/designer/utils/IntegrationHeader.tsx
new file mode 100644
index 00000000..c117d434
--- /dev/null
+++ b/karavan-designer/src/designer/utils/IntegrationHeader.tsx
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {FormGroup, TextInput, Title} from "@patternfly/react-core";
+import {useIntegrationStore} from "../KaravanStore";
+import {shallow} from "zustand/shallow";
+
+export function IntegrationHeader () {
+
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+
+    return (
+        <div className="headers">
+            <Title headingLevel="h1" size="md">Integration</Title>
+            {/*<FormGroup label="Title" fieldId="title" isRequired>*/}
+            {/*    <TextInput className="text-field" type="text" id="title" name="title" isReadOnly*/}
+            {/*               value={*/}
+            {/*                   CamelUi.titleFromName(this.props.integration.metadata.name)*/}
+            {/*               }/>*/}
+            {/*</FormGroup>*/}
+            <FormGroup label="Name" fieldId="name" isRequired>
+                <TextInput className="text-field" type="text" id="name" name="name"
+                           value={integration.metadata.name} readOnlyVariant="default"/>
+            </FormGroup>
+        </div>
+    )
+}
diff --git a/karavan-designer/src/designer/utils/KaravanComponents.tsx b/karavan-designer/src/designer/utils/KaravanComponents.tsx
deleted file mode 100644
index faddd84d..00000000
--- a/karavan-designer/src/designer/utils/KaravanComponents.tsx
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react';
-import {FormGroup, TextInput, Title} from "@patternfly/react-core";
-import {Integration} from "karavan-core/lib/model/IntegrationDefinition";
-
-interface Props {
-    integration: Integration,
-}
-
-export class IntegrationHeader extends React.Component<Props> {
-
-    render() {
-        return (
-            <div className="headers">
-                <Title headingLevel="h1" size="md">Integration</Title>
-                {/*<FormGroup label="Title" fieldId="title" isRequired>*/}
-                {/*    <TextInput className="text-field" type="text" id="title" name="title" isReadOnly*/}
-                {/*               value={*/}
-                {/*                   CamelUi.titleFromName(this.props.integration.metadata.name)*/}
-                {/*               }/>*/}
-                {/*</FormGroup>*/}
-                <FormGroup label="Name" fieldId="name" isRequired>
-                    <TextInput className="text-field" type="text" id="name" name="name" 
-                               value={this.props.integration.metadata.name} readOnlyVariant="default"/>
-                </FormGroup>
-            </div>
-        )
-    }
-}
diff --git a/karavan-designer/src/designer/utils/KaravanIcons.tsx b/karavan-designer/src/designer/utils/KaravanIcons.tsx
index b7228640..17560ff4 100644
--- a/karavan-designer/src/designer/utils/KaravanIcons.tsx
+++ b/karavan-designer/src/designer/utils/KaravanIcons.tsx
@@ -495,6 +495,28 @@ export function AggregateIcon() {
     );
 }
 
+export function ToIcon() {
+    return (
+        <svg
+            xmlns="http://www.w3.org/2000/svg"
+            width={800}
+            height={800}
+            viewBox="0 0 32 32"
+            className="icon"
+        >
+            <path
+                d="M24 22v-1h6v-2h-6v-6h6v-2h-6v-1a2 2 0 0 0-2-2h-6a8.007 8.007 0 0 0-7.93 7v2A8.007 8.007 0 0 0 16 24h6a2 2 0 0 0 2-2zm-8 0a6 6 0 1 1 0-12h6v12z"/>
+            <path
+                d="M0 0h32v32H0z"
+                data-name="&lt;Transparent Rectangle&gt;"
+                style={{
+                    fill: "none",
+                }}
+            />
+        </svg>
+    );
+}
+
 export function ChoiceIcon() {
     return (
         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 700 700" className="icon">
@@ -794,6 +816,7 @@ export function MessagingIcon() {
         </svg>
     );
 }
+
 export function SchedulingIcon() {
     return (
         <svg
@@ -802,8 +825,8 @@ export function SchedulingIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M16 30a14 14 0 1 1 14-14 14 14 0 0 1-14 14Zm0-26a12 12 0 1 0 12 12A12 12 0 0 0 16 4Z" />
-            <path d="M20.59 22 15 16.41V7h2v8.58l5 5.01L20.59 22z" />
+            <path d="M16 30a14 14 0 1 1 14-14 14 14 0 0 1-14 14Zm0-26a12 12 0 1 0 12 12A12 12 0 0 0 16 4Z"/>
+            <path d="M20.59 22 15 16.41V7h2v8.58l5 5.01L20.59 22z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -823,7 +846,8 @@ export function HttpIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M30 11h-5v10h2v-3h3a2.003 2.003 0 0 0 2-2v-3a2.002 2.002 0 0 0-2-2Zm-3 5v-3h3l.001 3ZM10 13h2v8h2v-8h2v-2h-6v2zM23 11h-6v2h2v8h2v-8h2v-2zM6 11v4H3v-4H1v10h2v-4h3v4h2V11H6z" />
+            <path
+                d="M30 11h-5v10h2v-3h3a2.003 2.003 0 0 0 2-2v-3a2.002 2.002 0 0 0-2-2Zm-3 5v-3h3l.001 3ZM10 13h2v8h2v-8h2v-2h-6v2zM23 11h-6v2h2v8h2v-8h2v-2zM6 11v4H3v-4H1v10h2v-4h3v4h2V11H6z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -834,6 +858,7 @@ export function HttpIcon() {
         </svg>
     );
 }
+
 export function GoogleCloudIcon() {
     return (
         <svg
@@ -862,6 +887,7 @@ export function GoogleCloudIcon() {
         </svg>
     );
 }
+
 export function AwsIcon() {
     return (
         <svg
@@ -876,12 +902,15 @@ export function AwsIcon() {
                 d="M4.51 7.687c0 .197.02.357.058.475.042.117.096.245.17.384a.233.233 0 0 1 .037.123c0 .053-.032.107-.1.16l-.336.224a.255.255 0 0 1-.138.048c-.054 0-.107-.026-.16-.074a1.652 1.652 0 0 1-.192-.251 4.137 4.137 0 0 1-.165-.315c-.415.491-.936.737-1.564.737-.447 0-.804-.129-1.064-.385-.261-.256-.394-.598-.394-1.025 0-.454.16-.822.484-1.1.325-.278.756-.416 1.304-.416.18 0 .367.016.564.042.197.027.4.07.612.118v-.39c0-.406-.085-.689-.25-.854-.17-.166-.458-.246-.868-.246-.186 0-.37 [...]
             />
             <g fill="#F90" fillRule="evenodd" clipRule="evenodd">
-                <path d="M14.465 11.813c-1.75 1.297-4.294 1.986-6.481 1.986-3.065 0-5.827-1.137-7.913-3.027-.165-.15-.016-.353.18-.235 2.257 1.313 5.04 2.109 7.92 2.109 1.941 0 4.075-.406 6.039-1.239.293-.133.543.192.255.406z" />
-                <path d="M15.194 10.98c-.223-.287-1.479-.138-2.048-.069-.17.022-.197-.128-.043-.24 1-.705 2.645-.502 2.836-.267.192.24-.053 1.89-.99 2.68-.143.123-.281.06-.218-.1.213-.53.687-1.72.463-2.003z" />
+                <path
+                    d="M14.465 11.813c-1.75 1.297-4.294 1.986-6.481 1.986-3.065 0-5.827-1.137-7.913-3.027-.165-.15-.016-.353.18-.235 2.257 1.313 5.04 2.109 7.92 2.109 1.941 0 4.075-.406 6.039-1.239.293-.133.543.192.255.406z"/>
+                <path
+                    d="M15.194 10.98c-.223-.287-1.479-.138-2.048-.069-.17.022-.197-.128-.043-.24 1-.705 2.645-.502 2.836-.267.192.24-.053 1.89-.99 2.68-.143.123-.281.06-.218-.1.213-.53.687-1.72.463-2.003z"/>
             </g>
         </svg>
     );
 }
+
 export function MailIcon() {
     return (
         <svg
@@ -891,7 +920,8 @@ export function MailIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"email"}</title>
-            <path d="M28 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2Zm-2.2 2L16 14.78 6.2 8ZM4 24V8.91l11.43 7.91a1 1 0 0 0 1.14 0L28 8.91V24Z" />
+            <path
+                d="M28 6H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h24a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2Zm-2.2 2L16 14.78 6.2 8ZM4 24V8.91l11.43 7.91a1 1 0 0 0 1.14 0L28 8.91V24Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -902,6 +932,7 @@ export function MailIcon() {
         </svg>
     );
 }
+
 export function IotIcon() {
     return (
         <svg
@@ -911,9 +942,10 @@ export function IotIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"iot--platform"}</title>
-            <path d="M30 19h-4v-4h-2v9H8V8h9V6h-4V2h-2v4H8a2.002 2.002 0 0 0-2 2v3H2v2h4v6H2v2h4v3a2.002 2.002 0 0 0 2 2h3v4h2v-4h6v4h2v-4h3a2.003 2.003 0 0 0 2-2v-3h4Z" />
-            <path d="M21 21H11V11h10Zm-8-2h6v-6h-6ZM31 13h-2A10.012 10.012 0 0 0 19 3V1a12.013 12.013 0 0 1 12 12Z" />
-            <path d="M26 13h-2a5.006 5.006 0 0 0-5-5V6a7.008 7.008 0 0 1 7 7Z" />
+            <path
+                d="M30 19h-4v-4h-2v9H8V8h9V6h-4V2h-2v4H8a2.002 2.002 0 0 0-2 2v3H2v2h4v6H2v2h4v3a2.002 2.002 0 0 0 2 2h3v4h2v-4h6v4h2v-4h3a2.003 2.003 0 0 0 2-2v-3h4Z"/>
+            <path d="M21 21H11V11h10Zm-8-2h6v-6h-6ZM31 13h-2A10.012 10.012 0 0 0 19 3V1a12.013 12.013 0 0 1 12 12Z"/>
+            <path d="M26 13h-2a5.006 5.006 0 0 0-5-5V6a7.008 7.008 0 0 1 7 7Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -924,6 +956,7 @@ export function IotIcon() {
         </svg>
     );
 }
+
 export function GithubIcon() {
     return (
         <svg
@@ -933,10 +966,13 @@ export function GithubIcon() {
             data-view-component="true"
             viewBox="0 0 16 16"
             className="icon">
-            <path d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16. [...]
+            <path
+                d="M8 0c4.42 0 8 3.58 8 8a8.013 8.013 0 0 1-5.45 7.59c-.4.08-.55-.17-.55-.38 0-.27.01-1.13.01-2.2 0-.75-.25-1.23-.54-1.48 1.78-.2 3.65-.88 3.65-3.95 0-.88-.31-1.59-.82-2.15.08-.2.36-1.02-.08-2.12 0 0-.67-.22-2.2.82-.64-.18-1.32-.27-2-.27-.68 0-1.36.09-2 .27-1.53-1.03-2.2-.82-2.2-.82-.44 1.1-.16 1.92-.08 2.12-.51.56-.82 1.28-.82 2.15 0 3.06 1.86 3.75 3.64 3.95-.23.2-.44.55-.51 1.07-.46.21-1.61.55-2.33-.66-.15-.24-.6-.83-1.23-.82-.67.01-.27.38.01.53.34.19.73.9.82 1.13.16.45 [...]
         </svg>
     );
-}export function CassandraIcon() {
+}
+
+export function CassandraIcon() {
     return (
         <svg
             xmlns="http://www.w3.org/2000/svg"
@@ -946,7 +982,7 @@ export function GithubIcon() {
             viewBox="0 0 113.63554 58.899029"
             className="icon">
             <defs>
-                <path id="a" d="M24.216.082v24.141H.053V.082z" />
+                <path id="a" d="M24.216.082v24.141H.053V.082z"/>
             </defs>
             <g
                 style={{
@@ -998,7 +1034,7 @@ export function GithubIcon() {
                 />
                 <g transform="translate(43.304 10.642)">
                     <mask id="b" fill="#fff">
-                        <use xlinkHref="#a" />
+                        <use xlinkHref="#a"/>
                     </mask>
                     <path
                         fill="#fff"
@@ -1026,6 +1062,7 @@ export function GithubIcon() {
         </svg>
     );
 }
+
 export function ActivemqIcon() {
     return (
         <svg
@@ -1042,16 +1079,16 @@ export function ActivemqIcon() {
                     x={-0.017}
                     y={-0.011}
                 >
-                    <feFlood floodColor="#000" floodOpacity={0.498} result="flood" />
+                    <feFlood floodColor="#000" floodOpacity={0.498} result="flood"/>
                     <feComposite
                         in="flood"
                         in2="SourceGraphic"
                         operator="in"
                         result="composite1"
                     />
-                    <feGaussianBlur in="composite1" result="blur" stdDeviation={0.2} />
-                    <feOffset dx={1} dy={1} result="offset" />
-                    <feComposite in="SourceGraphic" in2="offset" result="composite2" />
+                    <feGaussianBlur in="composite1" result="blur" stdDeviation={0.2}/>
+                    <feOffset dx={1} dy={1} result="offset"/>
+                    <feComposite in="SourceGraphic" in2="offset" result="composite2"/>
                 </filter>
             </defs>
             <g
@@ -1313,6 +1350,7 @@ export function ActivemqIcon() {
         </svg>
     );
 }
+
 export function KafkaIcon() {
     return (
         <svg
@@ -1329,6 +1367,7 @@ export function KafkaIcon() {
         </svg>
     );
 }
+
 export function GrapeIcon() {
     return (
         <svg
@@ -1363,6 +1402,7 @@ export function GrapeIcon() {
         </svg>
     );
 }
+
 export function MachineLearningIcon() {
     return (
         <svg
@@ -1371,8 +1411,10 @@ export function MachineLearningIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M27 24a2.96 2.96 0 0 0-1.285.3l-4.3-4.3H18v2h2.586l3.715 3.715A2.966 2.966 0 0 0 24 27a3 3 0 1 0 3-3Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 13a2.995 2.995 0 0 0-2.816 2H18v2h6.184A2.995 2.995 0 1 0 27 13Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 2a3.003 3.003 0 0 0-3 3 2.966 2.966 0 0 0 .348 1.373L20.596 10H18v2h3.404l4.4-4.252A2.999 2.999 0 1 0 27 2Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1Z" />
-            <path d="M18 6h2V4h-2a3.976 3.976 0 0 0-3 1.382A3.976 3.976 0 0 0 12 4h-1a9.01 9.01 0 0 0-9 9v6a9.01 9.01 0 0 0 9 9h1a3.976 3.976 0 0 0 3-1.382A3.976 3.976 0 0 0 18 28h2v-2h-2a2.002 2.002 0 0 1-2-2V8a2.002 2.002 0 0 1 2-2Zm-6 20h-1a7.005 7.005 0 0 1-6.92-6H6v-2H4v-4h3a3.003 3.003 0 0 0 3-3V9H8v2a1 1 0 0 1-1 1H4.08A7.005 7.005 0 0 1 11 6h1a2.002 2.002 0 0 1 2 2v4h-2v2h2v4h-2a3.003 3.003 0 0 0-3 3v2h2v-2a1 1 0 0 1 1-1h2v4a2.002 2.002 0 0 1-2 2Z" />
+            <path
+                d="M27 24a2.96 2.96 0 0 0-1.285.3l-4.3-4.3H18v2h2.586l3.715 3.715A2.966 2.966 0 0 0 24 27a3 3 0 1 0 3-3Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 13a2.995 2.995 0 0 0-2.816 2H18v2h6.184A2.995 2.995 0 1 0 27 13Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1ZM27 2a3.003 3.003 0 0 0-3 3 2.966 2.966 0 0 0 .348 1.373L20.596 10H18v2h3.404l4.4-4.252A2.999 2.999 0 1 0 27 2Zm0 4a1 1 0 1 1 1-1 1 1 0 0 1-1 1Z"/>
+            <path
+                d="M18 6h2V4h-2a3.976 3.976 0 0 0-3 1.382A3.976 3.976 0 0 0 12 4h-1a9.01 9.01 0 0 0-9 9v6a9.01 9.01 0 0 0 9 9h1a3.976 3.976 0 0 0 3-1.382A3.976 3.976 0 0 0 18 28h2v-2h-2a2.002 2.002 0 0 1-2-2V8a2.002 2.002 0 0 1 2-2Zm-6 20h-1a7.005 7.005 0 0 1-6.92-6H6v-2H4v-4h3a3.003 3.003 0 0 0 3-3V9H8v2a1 1 0 0 1-1 1H4.08A7.005 7.005 0 0 1 11 6h1a2.002 2.002 0 0 1 2 2v4h-2v2h2v4h-2a3.003 3.003 0 0 0-3 3v2h2v-2a1 1 0 0 1 1-1h2v4a2.002 2.002 0 0 1-2 2Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1383,6 +1425,7 @@ export function MachineLearningIcon() {
         </svg>
     );
 }
+
 export function TerminalIcon() {
     return (
         <svg
@@ -1392,8 +1435,9 @@ export function TerminalIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"terminal"}</title>
-            <path d="M26 4.01H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-20a2 2 0 0 0-2-2Zm0 2v4H6v-4Zm-20 20v-14h20v14Z" />
-            <path d="m10.76 16.18 2.82 2.83-2.82 2.83 1.41 1.41 4.24-4.24-4.24-4.24-1.41 1.41z" />
+            <path
+                d="M26 4.01H6a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h20a2 2 0 0 0 2-2v-20a2 2 0 0 0-2-2Zm0 2v4H6v-4Zm-20 20v-14h20v14Z"/>
+            <path d="m10.76 16.18 2.82 2.83-2.82 2.83 1.41 1.41 4.24-4.24-4.24-4.24-1.41 1.41z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1404,6 +1448,7 @@ export function TerminalIcon() {
         </svg>
     );
 }
+
 export function SapIcon() {
     return (
         <svg
@@ -1429,6 +1474,7 @@ export function SapIcon() {
         </svg>
     );
 }
+
 export function ScriptIcon() {
     return (
         <svg
@@ -1438,8 +1484,10 @@ export function ScriptIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"script"}</title>
-            <path d="m18.83 26 2.58-2.58L20 22l-4 4 4 4 1.42-1.41L18.83 26zM27.17 26l-2.58 2.58L26 30l4-4-4-4-1.42 1.41L27.17 26z" />
-            <path d="M14 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h6Zm4-23.6 5.6 5.6H18Z" />
+            <path
+                d="m18.83 26 2.58-2.58L20 22l-4 4 4 4 1.42-1.41L18.83 26zM27.17 26l-2.58 2.58L26 30l4-4-4-4-1.42 1.41L27.17 26z"/>
+            <path
+                d="M14 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h6Zm4-23.6 5.6 5.6H18Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1450,6 +1498,7 @@ export function ScriptIcon() {
         </svg>
     );
 }
+
 export function ValidationIcon() {
     return (
         <svg
@@ -1458,8 +1507,9 @@ export function ValidationIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="m22 27.18-2.59-2.59L18 26l4 4 8-8-1.41-1.41L22 27.18z" />
-            <path d="M15 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h7Zm3-23.6 5.6 5.6H18Z" />
+            <path d="m22 27.18-2.59-2.59L18 26l4 4 8-8-1.41-1.41L22 27.18z"/>
+            <path
+                d="M15 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6v6h2v-8a.91.91 0 0 0-.3-.7l-7-7A.909.909 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h7Zm3-23.6 5.6 5.6H18Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1470,6 +1520,7 @@ export function ValidationIcon() {
         </svg>
     );
 }
+
 export function OpenstackIcon() {
     return (
         <svg
@@ -1486,6 +1537,7 @@ export function OpenstackIcon() {
         </svg>
     );
 }
+
 export function OpenshiftIcon() {
     return (
         <svg
@@ -1530,6 +1582,7 @@ export function OpenshiftIcon() {
         </svg>
     );
 }
+
 export function RefIcon() {
     return (
         <svg
@@ -1538,8 +1591,9 @@ export function RefIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M4 20v2h4.586L2 28.586 3.414 30 10 23.414V28h2v-8H4zM30 30h-8v-8h8Zm-6-2h4v-4h-4ZM20 20h-8v-8h8Zm-6-2h4v-4h-4Z" />
-            <path d="M24 17h-2v-2h2a4 4 0 0 0 0-8H12V5h12a6 6 0 0 1 0 12ZM10 10H2V2h8ZM4 8h4V4H4Z" />
+            <path
+                d="M4 20v2h4.586L2 28.586 3.414 30 10 23.414V28h2v-8H4zM30 30h-8v-8h8Zm-6-2h4v-4h-4ZM20 20h-8v-8h8Zm-6-2h4v-4h-4Z"/>
+            <path d="M24 17h-2v-2h2a4 4 0 0 0 0-8H12V5h12a6 6 0 0 1 0 12ZM10 10H2V2h8ZM4 8h4V4H4Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1550,6 +1604,7 @@ export function RefIcon() {
         </svg>
     );
 }
+
 export function RedisIcon() {
     return (
         <svg
@@ -1598,6 +1653,7 @@ export function RedisIcon() {
         </svg>
     );
 }
+
 export function SearchIcon() {
     return (
         <svg
@@ -1606,7 +1662,8 @@ export function SearchIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="m29 27.586-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9 9.01 9.01 0 0 1-9-9Z" />
+            <path
+                d="m29 27.586-7.552-7.552a11.018 11.018 0 1 0-1.414 1.414L27.586 29ZM4 13a9 9 0 1 1 9 9 9.01 9.01 0 0 1-9-9Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1617,6 +1674,7 @@ export function SearchIcon() {
         </svg>
     );
 }
+
 export function BlockchainIcon() {
     return (
         <svg
@@ -1626,7 +1684,7 @@ export function BlockchainIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"blockchain"}</title>
-            <path d="M6 24H4V8h2ZM28 8h-2v16h2Zm-4-2V4H8v2Zm0 22v-2H8v2Z" />
+            <path d="M6 24H4V8h2ZM28 8h-2v16h2Zm-4-2V4H8v2Zm0 22v-2H8v2Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1637,6 +1695,7 @@ export function BlockchainIcon() {
         </svg>
     );
 }
+
 export function ChatIcon() {
     return (
         <svg
@@ -1646,8 +1705,9 @@ export function ChatIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"chat"}</title>
-            <path d="M17.74 30 16 29l4-7h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h9v2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4h20a4 4 0 0 1 4 4v12a4 4 0 0 1-4 4h-4.84Z" />
-            <path d="M8 10h16v2H8zM8 16h10v2H8z" />
+            <path
+                d="M17.74 30 16 29l4-7h6a2 2 0 0 0 2-2V8a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v12a2 2 0 0 0 2 2h9v2H6a4 4 0 0 1-4-4V8a4 4 0 0 1 4-4h20a4 4 0 0 1 4 4v12a4 4 0 0 1-4 4h-4.84Z"/>
+            <path d="M8 10h16v2H8zM8 16h10v2H8z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1658,6 +1718,7 @@ export function ChatIcon() {
         </svg>
     );
 }
+
 export function WorkflowIcon() {
     return (
         <svg
@@ -1667,10 +1728,12 @@ export function WorkflowIcon() {
             height={800}
             viewBox="0 0 512 512"
             className="icon">
-            <path d="M445.66 49.341H340.206L294.008 3.143c-4.192-4.191-10.99-4.191-15.183 0l-49.341 49.342c-4.192 4.192-4.192 10.99 0 15.183l46.198 46.198v38.494h-80.516c-5.929 0-10.736 4.806-10.736 10.735v21.471h-42.942v-21.471c0-5.929-4.806-10.735-10.736-10.735H66.34c-5.929 0-10.735 4.806-10.735 10.735v64.413c0 5.929 4.806 10.735 10.735 10.735h20.755v93.798c0 5.929 4.806 10.736 10.735 10.736h95.437l-10.346 10.346c-4.192 4.192-4.193 10.99 0 15.182a10.7 10.7 0 0 0 7.591 3.144c2.747 0 5.4 [...]
+            <path
+                d="M445.66 49.341H340.206L294.008 3.143c-4.192-4.191-10.99-4.191-15.183 0l-49.341 49.342c-4.192 4.192-4.192 10.99 0 15.183l46.198 46.198v38.494h-80.516c-5.929 0-10.736 4.806-10.736 10.735v21.471h-42.942v-21.471c0-5.929-4.806-10.735-10.736-10.735H66.34c-5.929 0-10.735 4.806-10.735 10.735v64.413c0 5.929 4.806 10.735 10.735 10.735h20.755v93.798c0 5.929 4.806 10.736 10.735 10.736h95.437l-10.346 10.346c-4.192 4.192-4.193 10.99 0 15.182a10.7 10.7 0 0 0 7.591 3.144c2.747 0 5.495 [...]
         </svg>
     );
 }
+
 export function WebserviceIcon() {
     return (
         <svg
@@ -1680,7 +1743,8 @@ export function WebserviceIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"fog"}</title>
-            <path d="M25.829 13.116A10.02 10.02 0 0 0 16 5v2a8.023 8.023 0 0 1 7.865 6.493l.259 1.346 1.349.245A5.502 5.502 0 0 1 24.508 26H16v2h8.508a7.502 7.502 0 0 0 1.32-14.884ZM8 24h6v2H8zM4 24h2v2H4zM6 20h8v2H6zM2 20h2v2H2zM8 16h6v2H8zM4 16h2v2H4zM10 12h4v2h-4zM6 12h2v2H6zM12 8h2v2h-2z" />
+            <path
+                d="M25.829 13.116A10.02 10.02 0 0 0 16 5v2a8.023 8.023 0 0 1 7.865 6.493l.259 1.346 1.349.245A5.502 5.502 0 0 1 24.508 26H16v2h8.508a7.502 7.502 0 0 0 1.32-14.884ZM8 24h6v2H8zM4 24h2v2H4zM6 20h8v2H6zM2 20h2v2H2zM8 16h6v2H8zM4 16h2v2H4zM10 12h4v2h-4zM6 12h2v2H6zM12 8h2v2h-2z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1691,6 +1755,7 @@ export function WebserviceIcon() {
         </svg>
     );
 }
+
 export function MobileIcon() {
     return (
         <svg
@@ -1699,9 +1764,10 @@ export function MobileIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M23 7h4v4h-4zM23 13h4v4h-4zM17 7h4v4h-4zM17 13h4v4h-4z" />
-            <circle cx={14.5} cy={24.5} r={1.5} />
-            <path d="M21 30H8a2.002 2.002 0 0 1-2-2V4a2.002 2.002 0 0 1 2-2h13v2H8v24h13v-8h2v8a2.002 2.002 0 0 1-2 2Z" />
+            <path d="M23 7h4v4h-4zM23 13h4v4h-4zM17 7h4v4h-4zM17 13h4v4h-4z"/>
+            <circle cx={14.5} cy={24.5} r={1.5}/>
+            <path
+                d="M21 30H8a2.002 2.002 0 0 1-2-2V4a2.002 2.002 0 0 1 2-2h13v2H8v24h13v-8h2v8a2.002 2.002 0 0 1-2 2Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1712,6 +1778,7 @@ export function MobileIcon() {
         </svg>
     );
 }
+
 export function ClusterIcon() {
     return (
         <svg
@@ -1720,7 +1787,8 @@ export function ClusterIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M16 7a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM11 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM7 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM21 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM25 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM4 21a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0  [...]
+            <path
+                d="M16 7a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM11 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM7 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM21 30a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM25 11a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1 0 1 1 1.001 1.001 0 0 0-1-1ZM4 21a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Zm0-4a1 1 0 1  [...]
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1731,6 +1799,7 @@ export function ClusterIcon() {
         </svg>
     );
 }
+
 export function RpcIcon() {
     return (
         <svg
@@ -1739,7 +1808,7 @@ export function RpcIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="m14 26 1.41-1.41L7.83 17H28v-2H7.83l7.58-7.59L14 6 4 16l10 10z" />
+            <path d="m14 26 1.41-1.41L7.83 17H28v-2H7.83l7.58-7.59L14 6 4 16l10 10z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1750,6 +1819,7 @@ export function RpcIcon() {
         </svg>
     );
 }
+
 export function InfinispanIcon() {
     return (
         <svg
@@ -1777,6 +1847,7 @@ export function InfinispanIcon() {
         </svg>
     );
 }
+
 export function TransformationIcon() {
     return (
         <svg
@@ -1786,7 +1857,8 @@ export function TransformationIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"data-share"}</title>
-            <path d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2ZM2 6h6v2H2zM2 2h8v2H2z" />
+            <path
+                d="M5 25v-9.172l-3.586 3.586L0 18l6-6 6 6-1.414 1.414L7 15.828V25h12v2H7a2.002 2.002 0 0 1-2-2ZM24 22h4a2.002 2.002 0 0 1 2 2v4a2.002 2.002 0 0 1-2 2h-4a2.002 2.002 0 0 1-2-2v-4a2.002 2.002 0 0 1 2-2Zm4 6v-4h-4.002L24 28ZM27 6v9.172l3.586-3.586L32 13l-6 6-6-6 1.414-1.414L25 15.172V6H13V4h12a2.002 2.002 0 0 1 2 2ZM2 6h6v2H2zM2 2h8v2H2z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1797,6 +1869,7 @@ export function TransformationIcon() {
         </svg>
     );
 }
+
 export function TestingIcon() {
     return (
         <svg
@@ -1805,8 +1878,10 @@ export function TestingIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M28 17v5H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-5ZM18 28h-4v-4h4Z" />
-            <path d="M30 10V8h-2.101a4.968 4.968 0 0 0-.732-1.753l1.49-1.49-1.414-1.414-1.49 1.49A4.968 4.968 0 0 0 24 4.101V2h-2v2.101a4.968 4.968 0 0 0-1.753.732l-1.49-1.49-1.414 1.414 1.49 1.49A4.968 4.968 0 0 0 18.101 8H16v2h2.101a4.968 4.968 0 0 0 .732 1.753l-1.49 1.49 1.414 1.414 1.49-1.49a4.968 4.968 0 0 0 1.753.732V16h2v-2.101a4.968 4.968 0 0 0 1.753-.732l1.49 1.49 1.414-1.414-1.49-1.49A4.968 4.968 0 0 0 27.899 10Zm-7 2a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z" />
+            <path
+                d="M28 17v5H4V6h10V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-5ZM18 28h-4v-4h4Z"/>
+            <path
+                d="M30 10V8h-2.101a4.968 4.968 0 0 0-.732-1.753l1.49-1.49-1.414-1.414-1.49 1.49A4.968 4.968 0 0 0 24 4.101V2h-2v2.101a4.968 4.968 0 0 0-1.753.732l-1.49-1.49-1.414 1.414 1.49 1.49A4.968 4.968 0 0 0 18.101 8H16v2h2.101a4.968 4.968 0 0 0 .732 1.753l-1.49 1.49 1.414 1.414 1.49-1.49a4.968 4.968 0 0 0 1.753.732V16h2v-2.101a4.968 4.968 0 0 0 1.753-.732l1.49 1.49 1.414-1.414-1.49-1.49A4.968 4.968 0 0 0 27.899 10Zm-7 2a3 3 0 1 1 3-3 3.003 3.003 0 0 1-3 3Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1817,6 +1892,7 @@ export function TestingIcon() {
         </svg>
     );
 }
+
 export function ApiIcon() {
     return (
         <svg
@@ -1826,7 +1902,8 @@ export function ApiIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"api"}</title>
-            <path d="M26 22a3.86 3.86 0 0 0-2 .57l-3.09-3.1a6 6 0 0 0 0-6.94L24 9.43a3.86 3.86 0 0 0 2 .57 4 4 0 1 0-4-4 3.86 3.86 0 0 0 .57 2l-3.1 3.09a6 6 0 0 0-6.94 0L9.43 8A3.86 3.86 0 0 0 10 6a4 4 0 1 0-4 4 3.86 3.86 0 0 0 2-.57l3.09 3.1a6 6 0 0 0 0 6.94L8 22.57A3.86 3.86 0 0 0 6 22a4 4 0 1 0 4 4 3.86 3.86 0 0 0-.57-2l3.1-3.09a6 6 0 0 0 6.94 0l3.1 3.09a3.86 3.86 0 0 0-.57 2 4 4 0 1 0 4-4Zm0-18a2 2 0 1 1-2 2 2 2 0 0 1 2-2ZM4 6a2 2 0 1 1 2 2 2 2 0 0 1-2-2Zm2 22a2 2 0 1 1 2-2 2 2 0 0 1 [...]
+            <path
+                d="M26 22a3.86 3.86 0 0 0-2 .57l-3.09-3.1a6 6 0 0 0 0-6.94L24 9.43a3.86 3.86 0 0 0 2 .57 4 4 0 1 0-4-4 3.86 3.86 0 0 0 .57 2l-3.1 3.09a6 6 0 0 0-6.94 0L9.43 8A3.86 3.86 0 0 0 10 6a4 4 0 1 0-4 4 3.86 3.86 0 0 0 2-.57l3.09 3.1a6 6 0 0 0 0 6.94L8 22.57A3.86 3.86 0 0 0 6 22a4 4 0 1 0 4 4 3.86 3.86 0 0 0-.57-2l3.1-3.09a6 6 0 0 0 6.94 0l3.1 3.09a3.86 3.86 0 0 0-.57 2 4 4 0 1 0 4-4Zm0-18a2 2 0 1 1-2 2 2 2 0 0 1 2-2ZM4 6a2 2 0 1 1 2 2 2 2 0 0 1-2-2Zm2 22a2 2 0 1 1 2-2 2 2 0 0 1-2 [...]
             <path
                 d="M0 0h32v32H0z"
                 style={{
@@ -1836,6 +1913,7 @@ export function ApiIcon() {
         </svg>
     );
 }
+
 export function MonitoringIcon() {
     return (
         <svg
@@ -1844,8 +1922,10 @@ export function MonitoringIcon() {
             height={800}
             viewBox="0 0 32 32"
             className="icon">
-            <path d="M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6ZM18 28h-4v-4h4Z" />
-            <path d="M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76 3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04-3.082 10.018A1 1 0 0 1 18 18Z" />
+            <path
+                d="M28 16v6H4V6h7V4H4a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h8v4H8v2h16v-2h-4v-4h8a2 2 0 0 0 2-2v-6ZM18 28h-4v-4h4Z"/>
+            <path
+                d="M18 18h-.01a1 1 0 0 1-.951-.725L15.246 11H11V9h5a1 1 0 0 1 .962.725l1.074 3.76 3.009-9.78A1.014 1.014 0 0 1 22 3a.98.98 0 0 1 .949.684L24.72 9H30v2h-6a1 1 0 0 1-.949-.684l-1.013-3.04-3.082 10.018A1 1 0 0 1 18 18Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1856,6 +1936,7 @@ export function MonitoringIcon() {
         </svg>
     );
 }
+
 export function NetworkingIcon() {
     return (
         <svg
@@ -1865,13 +1946,18 @@ export function NetworkingIcon() {
             height={800}
             viewBox="0 0 511.984 511.984"
             className="icon">
-            <path d="M207.29 287.991H48.735C30.687 287.991 16 302.375 16 320.054v111.868c0 17.679 14.688 32.063 32.735 32.063H207.29c18.031 0 32.703-14.384 32.703-32.063V320.054c0-17.679-14.672-32.063-32.703-32.063zm0 143.996-159.291-.064.736-111.932 159.259.064.048 111.645c0 .015-.192.287-.752.287z" />
-            <path d="M383.988 239.992H127.996c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-31.999h223.993v31.999c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c0-8.832-7.167-16-15.999-16z" />
-            <path d="M463.25 287.991H304.727c-18.047 0-32.735 14.384-32.735 32.063v111.868c0 17.679 14.688 32.063 32.735 32.063H463.25c18.047 0 32.735-14.384 32.735-32.063V320.054c-.001-17.679-14.688-32.063-32.735-32.063zm0 143.996-159.259-.064.736-111.932 159.259.064.064 111.645c-.016-.001-.208.287-.8.287zM415.987 479.985h-63.998c-8.832 0-16 7.168-16 16s7.168 16 16 16h63.998c8.832 0 16-7.168 16-16s-7.168-16-16-16zM335.253 0H176.73c-18.047 0-32.735 14.384-32.735 32.063v111.869c0 17.679 1 [...]
-            <path d="M255.992 191.994c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c.001-8.832-7.167-16-15.999-16z" />
+            <path
+                d="M207.29 287.991H48.735C30.687 287.991 16 302.375 16 320.054v111.868c0 17.679 14.688 32.063 32.735 32.063H207.29c18.031 0 32.703-14.384 32.703-32.063V320.054c0-17.679-14.672-32.063-32.703-32.063zm0 143.996-159.291-.064.736-111.932 159.259.064.048 111.645c0 .015-.192.287-.752.287z"/>
+            <path
+                d="M383.988 239.992H127.996c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-31.999h223.993v31.999c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c0-8.832-7.167-16-15.999-16z"/>
+            <path
+                d="M463.25 287.991H304.727c-18.047 0-32.735 14.384-32.735 32.063v111.868c0 17.679 14.688 32.063 32.735 32.063H463.25c18.047 0 32.735-14.384 32.735-32.063V320.054c-.001-17.679-14.688-32.063-32.735-32.063zm0 143.996-159.259-.064.736-111.932 159.259.064.064 111.645c-.016-.001-.208.287-.8.287zM415.987 479.985h-63.998c-8.832 0-16 7.168-16 16s7.168 16 16 16h63.998c8.832 0 16-7.168 16-16s-7.168-16-16-16zM335.253 0H176.73c-18.047 0-32.735 14.384-32.735 32.063v111.869c0 17.679 14. [...]
+            <path
+                d="M255.992 191.994c-8.832 0-16 7.168-16 16v47.998c0 8.832 7.168 16 16 16s15.999-7.168 15.999-16v-47.998c.001-8.832-7.167-16-15.999-16z"/>
         </svg>
     );
 }
+
 export function HealthIcon() {
     return (
         <svg
@@ -1889,10 +1975,11 @@ export function HealthIcon() {
                 d="M27 7h0c-2.6-2.7-6.9-2.7-9.5 0l-1.3 1.4c-.1.1-.4.1-.5 0L14.4 7C11.8 4.3 7.6 4.3 5 7h0c-2.6 2.7-2.6 7.1 0 9.8l1.6 1.6 9.2 9.5c.1.1.4.1.5 0l9.2-9.5 1.6-1.6c2.6-2.7 2.6-7.1-.1-9.8z"
                 className="st0"
             />
-            <path d="M9 15h3l2-2 2 4 2-5 2 3h3" className="st0" />
+            <path d="M9 15h3l2-2 2 4 2-5 2 3h3" className="st0"/>
         </svg>
     );
 }
+
 export function KubernetesIcon() {
     return (
         <svg
@@ -1925,6 +2012,7 @@ export function KubernetesIcon() {
         </svg>
     );
 }
+
 export function DocumentIcon() {
     return (
         <svg
@@ -1934,7 +2022,8 @@ export function DocumentIcon() {
             viewBox="0 0 32 32"
             className="icon">
             <title>{"document--blank"}</title>
-            <path d="m25.7 9.3-7-7A.908.908 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h16a2.006 2.006 0 0 0 2-2V10a.908.908 0 0 0-.3-.7ZM18 4.4l5.6 5.6H18ZM24 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6Z" />
+            <path
+                d="m25.7 9.3-7-7A.908.908 0 0 0 18 2H8a2.006 2.006 0 0 0-2 2v24a2.006 2.006 0 0 0 2 2h16a2.006 2.006 0 0 0 2-2V10a.908.908 0 0 0-.3-.7ZM18 4.4l5.6 5.6H18ZM24 28H8V4h8v6a2.006 2.006 0 0 0 2 2h6Z"/>
             <path
                 d="M0 0h32v32H0z"
                 data-name="&lt;Transparent Rectangle&gt;"
@@ -1945,6 +2034,7 @@ export function DocumentIcon() {
         </svg>
     );
 }
+
 export function GitIcon() {
     return (
         <svg
@@ -1963,6 +2053,7 @@ export function GitIcon() {
         </svg>
     );
 }
+
 export function SocialIcon() {
     return (
         <svg
@@ -1990,6 +2081,7 @@ export function SocialIcon() {
         </svg>
     );
 }
+
 export function DebeziumIcon() {
     return (
         <svg
@@ -2006,8 +2098,8 @@ export function DebeziumIcon() {
                     y2={114.02}
                     gradientUnits="userSpaceOnUse"
                 >
-                    <stop offset={0} stopColor="#91d443" />
-                    <stop offset={1} stopColor="#48bfe0" />
+                    <stop offset={0} stopColor="#91d443"/>
+                    <stop offset={1} stopColor="#48bfe0"/>
                 </linearGradient>
                 <linearGradient
                     xlinkHref="#linear-gradient"
@@ -2078,6 +2170,7 @@ export function DebeziumIcon() {
         </svg>
     );
 }
+
 export function IgniteIcon() {
     return (
         <svg
@@ -2098,6 +2191,7 @@ export function IgniteIcon() {
         </svg>
     );
 }
+
 export function HazelcastIcon() {
     return (
         <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 133.3 133.3" className="icon">
@@ -2135,6 +2229,7 @@ export function HazelcastIcon() {
         </svg>
     );
 }
+
 export function AzureIcon() {
     return (
         <svg
@@ -2153,8 +2248,8 @@ export function AzureIcon() {
                     gradientTransform="matrix(1 0 0 -1 1075 158)"
                     gradientUnits="userSpaceOnUse"
                 >
-                    <stop offset={0} stopColor="#114a8b" />
-                    <stop offset={1} stopColor="#0669bc" />
+                    <stop offset={0} stopColor="#114a8b"/>
+                    <stop offset={1} stopColor="#0669bc"/>
                 </linearGradient>
                 <linearGradient
                     id="b"
@@ -2165,11 +2260,11 @@ export function AzureIcon() {
                     gradientTransform="matrix(1 0 0 -1 1075 158)"
                     gradientUnits="userSpaceOnUse"
                 >
-                    <stop offset={0} stopOpacity={0.3} />
-                    <stop offset={0.071} stopOpacity={0.2} />
-                    <stop offset={0.321} stopOpacity={0.1} />
-                    <stop offset={0.623} stopOpacity={0.05} />
-                    <stop offset={1} stopOpacity={0} />
+                    <stop offset={0} stopOpacity={0.3}/>
+                    <stop offset={0.071} stopOpacity={0.2}/>
+                    <stop offset={0.321} stopOpacity={0.1}/>
+                    <stop offset={0.623} stopOpacity={0.05}/>
+                    <stop offset={1} stopOpacity={0}/>
                 </linearGradient>
                 <linearGradient
                     id="c"
@@ -2180,8 +2275,8 @@ export function AzureIcon() {
                     gradientTransform="matrix(1 0 0 -1 1075 158)"
                     gradientUnits="userSpaceOnUse"
                 >
-                    <stop offset={0} stopColor="#3ccbf4" />
-                    <stop offset={1} stopColor="#2892df" />
+                    <stop offset={0} stopColor="#3ccbf4"/>
+                    <stop offset={1} stopColor="#2892df"/>
                 </linearGradient>
             </defs>
             <path
diff --git a/karavan-designer/src/index.css b/karavan-designer/src/index.css
index d2ffcae4..a7341d7a 100644
--- a/karavan-designer/src/index.css
+++ b/karavan-designer/src/index.css
@@ -8,14 +8,8 @@ body,
 #root {
   margin: 0;
   height: 100%;
-}
-
-#root {
   display: flex;
   flex-direction: column;
-}
-
-.karavan .pf-v5-c-page__main {
   overflow: hidden;
 }
 
diff --git a/karavan-designer/src/index.tsx b/karavan-designer/src/index.tsx
index 53d84ae5..5a495994 100644
--- a/karavan-designer/src/index.tsx
+++ b/karavan-designer/src/index.tsx
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-import React from 'react';
+import React, {StrictMode} from 'react';
 import "./index.css";
 import "@patternfly/patternfly/patternfly.css";
 import App from "./App";
@@ -22,4 +22,8 @@ import {createRoot} from "react-dom/client";
 
 const container = document.getElementById('root');
 const root = createRoot(container!);
-root.render(<App/>);
\ No newline at end of file
+root.render(
+    // <StrictMode>
+        <App />
+    // </StrictMode>
+);
\ No newline at end of file