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

[camel-karavan] branch feature-836 updated (a0300a68 -> 23b79297)

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

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


 discard a0300a68 Fix #862
 discard 1b230441 Fixed issue with RouteDesigner top/left #836
 discard c1c184b5 Fixed issue with Select Steps #836
 discard 4f8a93e1 Fixed issue with Expressions for #836
 discard 425975b3 Properties for #836
 discard bff7ef31 Copy and Paste for #836
 discard f432faaf Copy and Paste for #836
 discard 64a8c66a Fix connections issues #836
 discard 63223071 Download YAML and PNG #836
 discard 27ebf976 Delete element for #836
 discard 0f739725 Selector for #836
 discard 27f94cc8 Connections for #836
 discard c60f3ed4 Resize works
 discard a2c1b127 Scroll works
 discard e4e70e8f First try
     add cc70d0d2 Fix minor errors
     add e00921df fix: css typos (#870)
     new 23b79297 Fix #836

This update added new revisions after undoing existing revisions.
That is to say, some revisions that were in the old version of the
branch are not in the new version.  This situation occurs
when a user --force pushes a change and generates a repository
containing something like this:

 * -- * -- B -- O -- O -- O   (a0300a68)
            \
             N -- N -- N   refs/heads/feature-836 (23b79297)

You should already have received notification emails for all of the O
revisions, and so the following emails describe only the N revisions
from the common base, B.

Any revisions marked "omit" are not gone; other references still
refer to them.  Any revisions marked "discard" are gone forever.

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 karavan-designer/public/example/demo.camel.yaml    | 130 +++----
 karavan-designer/src/App.tsx                       |   3 +-
 karavan-designer/src/DesignerPage.tsx              | 138 ++++----
 karavan-designer/src/designer/KaravanDesigner.tsx  | 130 ++++---
 karavan-designer/src/designer/KaravanStore.ts      |  72 ++--
 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          |  14 +-
 karavan-designer/src/designer/rest/RestCard.tsx    |  93 +++--
 .../src/designer/rest/RestConfigurationCard.tsx    |  53 ++-
 .../src/designer/rest/RestDesigner.tsx             | 272 ++++++---------
 .../src/designer/rest/RestMethodCard.tsx           |  52 ++-
 .../src/designer/rest/RestMethodSelector.tsx       |  48 +--
 .../src/designer/route/DeleteConfirmation.tsx      |   2 +-
 .../src/designer/route/DslConnections.tsx          |  19 +-
 karavan-designer/src/designer/route/DslElement.tsx |   2 +-
 .../src/designer/route/DslProperties.tsx           |  22 +-
 .../src/designer/route/DslSelector.tsx             |   2 +-
 .../src/designer/route/RouteDesigner.tsx           |  13 +-
 .../route/property/ComponentParameterField.tsx     | 344 +++++++++----------
 .../designer/route/property/DataFormatField.tsx    | 171 +++++----
 .../designer/route/property/DslPropertyField.tsx   | 382 +++++++++++----------
 .../designer/route/property/ExpressionField.tsx    |  19 +-
 .../route/property/InfrastructureSelector.tsx      | 129 +++----
 .../route/property/KameletPropertyField.tsx        | 180 +++++-----
 .../src/designer/route/property/ModalEditor.tsx    |  97 +++---
 .../src/designer/route/property/ObjectField.tsx    |  74 ++--
 .../designer/route/useDrawerMutationsObserver.tsx  |   1 -
 .../src/designer/route/usePropertiesHook.tsx       |  52 ++-
 .../src/designer/route/useResizeObserver.tsx       |   1 -
 .../src/designer/route/useRouteDesignerHook.tsx    |  24 +-
 .../src/designer/templates/TemplatesDesigner.tsx   |  71 ----
 karavan-designer/src/designer/utils/CamelUi.tsx    |  22 ++
 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 ---
 .../camel/karavan/api/InfrastructureResource.java  |  16 +-
 .../apache/camel/karavan/api/LogWatchResource.java |   4 +-
 41 files changed, 1529 insertions(+), 1640 deletions(-)
 delete mode 100644 karavan-designer/src/designer/templates/TemplatesDesigner.tsx
 create mode 100644 karavan-designer/src/designer/utils/IntegrationHeader.tsx
 delete mode 100644 karavan-designer/src/designer/utils/KaravanComponents.tsx


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

Posted by ma...@apache.org.
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