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/24 23:26:19 UTC

[camel-karavan] 05/06: Properties for #836

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

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

commit 425975b36e3faa5ca08ffbd3460cec8e73c25ad2
Author: Marat Gubaidullin <ma...@Marats-MacBook-Pro.local>
AuthorDate: Thu Aug 24 15:59:02 2023 -0400

    Properties for #836
---
 karavan-core/src/core/api/CamelUtil.ts             |   2 +-
 karavan-designer/public/example/demo.camel.yaml    | 857 +--------------------
 karavan-designer/src/designer/KaravanDesigner.tsx  |   9 -
 .../src/designer/rest/RestDesigner.tsx             |   9 +-
 .../src/designer/route/DslConnections.tsx          |   1 +
 karavan-designer/src/designer/route/DslElement.tsx |   7 +-
 .../src/designer/route/DslProperties.tsx           | 213 ++---
 .../src/designer/route/RouteDesigner.tsx           |  20 +-
 .../designer/route/property/DataFormatField.tsx    |  15 +-
 .../designer/route/property/DslPropertyField.tsx   | 516 +++++++------
 .../designer/route/property/ExpressionField.tsx    | 181 ++---
 .../src/designer/route/property/ObjectField.tsx    |  12 +-
 .../src/designer/route/usePropertiesHook.tsx       | 103 +++
 .../src/designer/route/useRouteDesignerHook.tsx    | 112 +--
 karavan-designer/src/designer/utils/CamelUi.tsx    |   4 +-
 .../src/designer/utils/KaravanIcons.tsx            |  22 +
 16 files changed, 586 insertions(+), 1497 deletions(-)

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-designer/public/example/demo.camel.yaml b/karavan-designer/public/example/demo.camel.yaml
index 14003ed0..46692463 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -4,865 +4,16 @@
       uri: kamelet:timer-source
       id: from-e52c
       steps:
-        - 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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- route:
-#    id: route-f435
-#    from:
-#      uri: kamelet:timer-source
-#      id: from-e52c
-#      steps:
-#        - choice:
-#            when:
-#              - expression: {}
-#                id: when-064f
-#                steps:
-#                  - multicast:
-#                      id: multicast-38ce
-#                      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
-#- 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-38ce
+#                      id: multicast-38cea
 #                      steps:
 #                        - bean:
 #                            id: bean-3b8e
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx b/karavan-designer/src/designer/KaravanDesigner.tsx
index 3c68baee..bb8a8538 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/KaravanDesigner.tsx
@@ -42,15 +42,6 @@ interface Props {
 }
 
 export class KaravanInstance {
-    // static designer: KaravanDesigner;
-
-    // static set(designer: KaravanDesigner): void  {
-    //     KaravanInstance.designer = designer;
-    // }
-    //
-    // static get(): KaravanDesigner {
-    //     return KaravanInstance.designer;
-    // }
 
     static getProps(): Props {
         return {
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx b/karavan-designer/src/designer/rest/RestDesigner.tsx
index d13d07e6..0921488b 100644
--- a/karavan-designer/src/designer/rest/RestDesigner.tsx
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -235,14 +235,7 @@ export class RestDesigner extends React.Component<Props, State> {
     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>
         )
     }
diff --git a/karavan-designer/src/designer/route/DslConnections.tsx b/karavan-designer/src/designer/route/DslConnections.tsx
index a2505f4f..1002103e 100644
--- a/karavan-designer/src/designer/route/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -40,6 +40,7 @@ export const DslConnections = () => {
     }, []);
 
     function setPosition(evt: DslPosition) {
+        console.log("setPosition : ", evt);
         if (evt.command === "add") {
             addStep(evt.step.uuid, evt);
         }
diff --git a/karavan-designer/src/designer/route/DslElement.tsx b/karavan-designer/src/designer/route/DslElement.tsx
index 5cdfabf5..dc73dc68 100644
--- a/karavan-designer/src/designer/route/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -194,10 +194,11 @@ export const DslElement = (props: Props) => {
     }
 
     function sendPosition(el: HTMLDivElement | null, isSelected: boolean) {
-        const node = el;
-        if (node && el) {
-            const header = Array.from(node.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0];
+        // console.log("sendPosition1 : ", selectedStep)
+        if (el) {
+            const header = Array.from(el.childNodes.values()).filter((n: any) => n.classList.contains("header"))[0];
             if (header) {
+                // console.log("sendPosition2 : ", selectedStep, el)
                 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();
diff --git a/karavan-designer/src/designer/route/DslProperties.tsx b/karavan-designer/src/designer/route/DslProperties.tsx
index 87f93c79..be8c405a 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,33 @@ 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 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 const 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] = useIntegrationStore((state) => [state.integration], shallow)
 
-    cloneElement = () => {
-        if (this.state.step) {
-            this.props.onClone?.call(this, this.state.step);
-        }
-    }
+    const {cloneElement, onDataFormatChange} = usePropertiesHook();
 
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevProps.step !== this.props.step) {
-            this.setStep(this.props.step);
-        }
-    }
+    const [selectedStep, dark] = useDesignerStore((s) => [s.selectedStep, s.dark], 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 +59,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 +102,49 @@ 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}/>
+                                  value={selectedStep ? (selectedStep as any)[property.name] : undefined}/>
             )}
         </>)
     }
 
-    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 integration={integration}/>}
+                {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/RouteDesigner.tsx b/karavan-designer/src/designer/route/RouteDesigner.tsx
index a69105cb..8614418c 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -46,7 +46,7 @@ import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
 
 export const RouteDesigner = () => {
 
-    const {openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp} = useRouteDesignerHook();
+    const {openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp, unselectElement} = useRouteDesignerHook();
 
     const [integration] = useIntegrationStore((state) => [state.integration], shallow)
     const [showDeleteConfirmation , setPosition,] = useDesignerStore((s) => [s.showDeleteConfirmation, s.setPosition], shallow)
@@ -98,13 +98,7 @@ export const RouteDesigner = () => {
         return (
             <DrawerPanelContent style={{transform: "initial"}} isResizable hasNoBorder defaultSize={'400px'}
                                 maxSize={'800px'} minSize={'300px'}>
-                {/*<DslProperties ref={ref}*/}
-                {/*               integration={integration}*/}
-                {/*               step={selectedStep}*/}
-                {/*               onIntegrationUpdate={logic.onIntegrationUpdate}*/}
-                {/*               onPropertyUpdate={logic.onPropertyUpdate}*/}
-                {/*               isRouteDesigner={true}*/}
-                {/*               dark={props.dark}/>*/}
+                <DslProperties isRouteDesigner={true}/>
             </DrawerPanelContent>
         )
     }
@@ -115,11 +109,11 @@ export const RouteDesigner = () => {
         return (
             <div className="graph" ref={printerRef}>
                 <DslConnections/>
-                <div id="flows" className="flows" data-click="FLOWS" onClick={event => {
-                    // logic.unselectElement(event)
-                }}
-                     ref={flowRef}
-                >
+                <div id="flows"
+                     className="flows"
+                     data-click="FLOWS"
+                     onClick={event => {unselectElement(event)}}
+                     ref={flowRef}>
                     {routeConfigurations?.map((routeConfiguration, index: number) => (
                         <DslElement key={routeConfiguration.uuid}
                                     inSteps={false}
diff --git a/karavan-designer/src/designer/route/property/DataFormatField.tsx b/karavan-designer/src/designer/route/property/DataFormatField.tsx
index ef447b6f..474fc6cf 100644
--- a/karavan-designer/src/designer/route/property/DataFormatField.tsx
+++ b/karavan-designer/src/designer/route/property/DataFormatField.tsx
@@ -106,20 +106,7 @@ export class DataFormatField extends React.Component<Props, State> {
     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}/>
             )}
         </>)
     }
diff --git a/karavan-designer/src/designer/route/property/DslPropertyField.tsx b/karavan-designer/src/designer/route/property/DslPropertyField.tsx
index 0dca7151..7bfe7f9b 100644
--- a/karavan-designer/src/designer/route/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/route/property/DslPropertyField.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,
@@ -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,95 +64,94 @@ 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 {usePropertiesHook} from "../usePropertiesHook";
 
 interface Props {
     property: PropertyMeta,
+    element?: CamelElement,
     value: any,
-    onChange?: (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,
+    expressionTextChanged?: (fieldId: string, value: string | number | boolean | any) => void,
     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 const DslPropertyField = (props: Props) => {
+
+    const [integration] = useIntegrationStore((state) => [state.integration], shallow)
+    const [dark] = useDesignerStore((s) => [s.dark], shallow)
+    const {onPropertyChange, onParametersChange} = usePropertiesHook();
 
-export class DslPropertyField extends React.Component<Props, State> {
+    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);
 
-    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 ref = useRef<any>(null);
 
-    openSelect = (propertyName: string, isExpanded: boolean) => {
-        this.setState({selectStatus: new Map<string, boolean>([[propertyName, isExpanded]])});
+    function openSelect (propertyName: string, isExpanded: boolean ) {
+        setSelectStatus(prevState => {
+            prevState.set(propertyName, isExpanded);
+            return prevState;
+        })
+        // setState({selectStatus: new Map<string, boolean>([[propertyName, isExpanded]])});
     }
 
-    clearSelection = (propertyName: string) => {
-        this.setState({selectStatus: new Map<string, boolean>([[propertyName, false]])});
-    };
+    function clearSelection (propertyName: string ) {
+        setSelectStatus(prevState => {
+            prevState.set(propertyName, false);
+            return prevState;
+        })
+        // setState({selectStatus: 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.has(propertyName) && 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]])});
+        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, {});
@@ -163,7 +160,7 @@ export class DslPropertyField extends React.Component<Props, State> {
                 <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 => onPropertyChange(property.name, x)} aria-label="Add element">
                             {icon}
                         </button>
                     </Tooltip>
@@ -174,80 +171,83 @@ 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)}>
+                    <Button variant="control" onClick={e => openInfrastructureSelector(property.name)}>
                         {icon}
                     </Button>
                 </Tooltip>}
             {(!showEditor || property.secret) && <TextInput
-                ref={this.state.ref}
+                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) => this.propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
-                readOnlyVariant={this.isUriReadOnly(property) ? "default" : undefined}/>
+                onChange={(_, v) => propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
+                readOnlyVariant={isUriReadOnly(property) ? "default" : undefined}/>
             }
             {showEditor && !property.secret && <TextArea
-                ref={this.state.ref}
+                ref={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}/>
+                onChange={(_, v) => propertyChanged(property.name, ['integer', 'number'].includes(property.type) ? Number(v) : v)}
+                readOnlyVariant={isUriReadOnly(property) ? "default" : undefined}/>
             }
             {!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>
@@ -255,36 +255,38 @@ export class DslPropertyField extends React.Component<Props, State> {
         </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: any) => console.log(reason))
+    function showCode (name: string, javaType: string ) {
+        const {property} = props;
+        // TODO: 
+        // KaravanInstance.getProps().onGetCustomCode.call(this, 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 >
                 <TextInput
-                    ref={this.state.ref}
+                    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 => this.showCode(value, property.javaType)}>
+                <Button isDisabled={value?.length === 0} variant="control" onClick={e => showCode(value, property.javaType)}>
                     <PlusIcon/>
                 </Button>
             </Tooltip></InputGroupItem>
@@ -294,18 +296,26 @@ export class DslPropertyField extends React.Component<Props, State> {
                          dark={dark}
                          dslLanguage={dslLanguage}
                          title="Java Class"
-                         onClose={() => this.setState({showEditor: false})}
+                         onClose={() => setShowEditor(false)}
                          onSave={(fieldId, value1) => {
-                             this.propertyChanged(fieldId, value);
-                             KaravanInstance.getProps().onSaveCustomCode?.call(this, value, value1);
-                             this.setState({showEditor: false});
+                             propertyChanged(fieldId, value);
+                             // TODO: 
+                             // KaravanInstance.getProps().onSaveCustomCode?.call(this, value, value1);
+                             setShowEditor(false)
                          }}/></InputGroupItem>
         </InputGroup>)
     }
 
-    getTextArea = (property: PropertyMeta, value: any) => {
-        const {dslLanguage, dark} = this.props;
-        const {showEditor} = this.state;
+    function onTextAreaPropertyChange (fieldId: string, value: string | number | boolean | any) {
+        if (props.expressionTextChanged !== undefined) {
+            props.expressionTextChanged(fieldId, value);
+        } else {
+            propertyChanged(fieldId, value);
+        }
+    }
+
+    function getTextArea (property: PropertyMeta, value: any ) {
+        const {dslLanguage} = props;
         return (
             <InputGroup>
                 <InputGroupItem isFill ><TextArea
@@ -316,9 +326,9 @@ export class DslPropertyField extends React.Component<Props, State> {
                     name={property.name}
                     height={"100px"}
                     value={value?.toString()}
-                    onChange={(_, v) => this.propertyChanged(property.name, v)}/></InputGroupItem>
+                    onChange={(_, v) => onTextAreaPropertyChange(property.name, v)}/></InputGroupItem>
                 <InputGroupItem><Tooltip position="bottom-end" content={"Show Editor"}>
-                    <Button variant="control" onClick={e => this.setState({showEditor: !showEditor})}>
+                    <Button variant="control" onClick={e => setShowEditor(!showEditor)}>
                         <EditorIcon/>
                     </Button>
                 </Tooltip></InputGroupItem>
@@ -328,40 +338,36 @@ export class DslPropertyField extends React.Component<Props, State> {
                              dark={dark}
                              dslLanguage={dslLanguage}
                              title={`Expression (${dslLanguage?.[0]})`}
-                             onClose={() => this.setState({showEditor: false})}
+                             onClose={() => setShowEditor(false)}
                              onSave={(fieldId, value1) => {
-                                 this.propertyChanged(fieldId, value1);
-                                 this.setState({showEditor: false});
+                                 onTextAreaPropertyChange(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}/>
             </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}
+                                       integration={integration}
+                                       dark={dark}/>}
             </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,13 +375,13 @@ 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}/>));
@@ -385,11 +391,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)}
                 aria-labelledby={property.name}
                 direction={SelectDirection.down}
             >
@@ -398,7 +404,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 +416,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,7 +430,7 @@ 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 />
         ];
@@ -437,30 +443,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 +478,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,14 +488,14 @@ 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 ) {
         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()}/>));
@@ -499,17 +505,17 @@ export class DslPropertyField extends React.Component<Props, State> {
                 placeholderText="Select or type an URI"
                 variant={SelectVariant.typeahead}
                 aria-label={property.name}
-                onClear={event => this.clearSelection(property.name)}
+                onClear={event => clearSelection(property.name)}
                 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), newRoute)
                 }}
                 selections={value}
-                isOpen={this.isSelectOpen(property.name)}
+                isOpen={isSelectOpen(property.name)}
                 isCreatable={true}
                 isInputFilterPersisted={true}
                 aria-labelledby={property.name}
@@ -520,70 +526,70 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    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);
+        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)}
+                                       integration={integration}
+                                       dark={dark}/>}
             </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 +598,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 +609,51 @@ 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}
+                        onParameterChange={onParametersChange}
                     />)}
             </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}
+                        element={element}
+                        integration={integration}
                         value={value}
-                        onParameterChange={this.props.onParameterChange}
+                        onParameterChange={onParametersChange}
                     />)
                 })}
             </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}
+                            integration={integration}
+                            value={CamelDefinitionApiExt.getParametersValue(element, kp.name, kp.kind === 'path')}
+                            onParameterChange={onParametersChange}
                         />
                     )}
                 </div>
@@ -653,7 +661,7 @@ export class DslPropertyField extends React.Component<Props, State> {
         )
     }
 
-    getLabelIcon = (property: PropertyMeta) => {
+    function getLabelIcon (property: PropertyMeta ) {
         return (
             property.description
                 ? <Popover
@@ -678,72 +686,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 && ["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..9a341d41 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,137 +31,124 @@ 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";
+import {usePropertiesHook} from "../usePropertiesHook";
 
 interface Props {
     property: PropertyMeta,
     value: CamelElement,
-    onExpressionChange?: (propertyName: string, exp: ExpressionDefinition) => void
-    integration: Integration,
-    dark: boolean,
 }
 
-interface State {
-    selectIsOpen: boolean;
-}
-
-export class ExpressionField extends React.Component<Props, State> {
+export const ExpressionField = (props: Props) => {
 
-    public state: State = {
-        selectIsOpen: false,
-    }
+    const {onExpressionChange} = usePropertiesHook();
+    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;
+        onExpressionChange(props.property.name, exp);
+        setSelectIsOpen(false);
     }
 
-    propertyChanged = (fieldId: string, value: string | number | boolean | any) => {
-        const expression = this.getExpressionValue();
+    function expressionTextChanged (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}
+                                      element={value}
+                                      value={value ? (value as any)[property.name] : undefined}
+                                      dslLanguage={dslLanguage}
+                                      expressionTextChanged={expressionTextChanged}/>
+                )}
+            </FormGroup>
+        </div>
+    )
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/property/ObjectField.tsx b/karavan-designer/src/designer/route/property/ObjectField.tsx
index a72019b5..1ebc93f2 100644
--- a/karavan-designer/src/designer/route/property/ObjectField.tsx
+++ b/karavan-designer/src/designer/route/property/ObjectField.tsx
@@ -76,17 +76,7 @@ export class ObjectField extends React.Component<Props, State> {
         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}/>
+                        <DslPropertyField key={property.name} property={property} value={value ? (value as any)[property.name] : undefined}/>
                     )}
                 </div>
         )
diff --git a/karavan-designer/src/designer/route/usePropertiesHook.tsx b/karavan-designer/src/designer/route/usePropertiesHook.tsx
new file mode 100644
index 00000000..a3e4e5cd
--- /dev/null
+++ b/karavan-designer/src/designer/route/usePropertiesHook.tsx
@@ -0,0 +1,103 @@
+/*
+ * 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,
+} 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 const usePropertiesHook = () => {
+
+    const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow)
+    const [ selectedStep,setPropertyOnly, setSelectedStep, setSelectedUuids] = useDesignerStore((s) =>
+        [s.selectedStep,s.setPropertyOnly, s.setSelectedStep, s.setSelectedUuids], shallow)
+
+    function onPropertyUpdate (element: CamelElement, newRoute?: RouteToCreate) {
+        console.log("-> onPropertyUpdate", element, newRoute)
+        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);
+            setSelectedStep(element);
+            setPropertyOnly(false);
+            setSelectedUuids([element.uuid]);
+        } else {
+            const clone = CamelUtil.cloneIntegration(integration);
+            const i = CamelDefinitionApiExt.updateIntegrationRouteElement(clone, element);
+            setIntegration(i);
+            setPropertyOnly(true);
+        }
+    }
+
+    function onPropertyChange (fieldId: string, value: string | number | boolean | any, newRoute?: RouteToCreate){
+        console.log("onPropertyChange", fieldId, value,);
+        console.log("onPropertyChange", selectedStep);
+        if (selectedStep) {
+            const clone = CamelUtil.cloneStep(selectedStep);
+            (clone as any)[fieldId] = value;
+            setSelectedStep(clone)
+            console.log("onPropertyChange", 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)   {
+        console.log("onExpressionChange", propertyName, exp);
+        console.log("onExpressionChange", selectedStep);
+        if (selectedStep) {
+            const clone = (CamelUtil.cloneStep(selectedStep));
+            (clone as any)[propertyName] = exp;
+            setSelectedStep(clone);
+            console.log("onExpressionChange", clone);
+            onPropertyUpdate(clone);
+        }
+    }
+
+    function onParametersChange (parameter: string, value: string | number | boolean | any, pathParameter?: boolean, newRoute?: RouteToCreate)   {
+        console.log("onParametersChange", parameter, value);
+        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 cloneElement ()   {
+        // TODO:
+    }
+
+    return {onPropertyChange, onParametersChange, cloneElement, onDataFormatChange, onExpressionChange}
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
index d7ed9027..61208dfa 100644
--- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
@@ -38,77 +38,21 @@ import {setTabIndex} from "@patternfly/react-core";
 export const useRouteDesignerHook = () => {
 
     const [integration, setIntegration] = useIntegrationStore((state) => [state.integration, state.setIntegration], shallow)
-    const [ showDeleteConfirmation, propertyOnly,deleteMessage, selectedUuids,clipboardSteps,selectedStep,shiftKeyPressed,
-        setShowDeleteConfirmation,setPropertyOnly, setDeleteMessage, setSelectedStep, setSelectedUuids, setClipboardSteps, setPosition, setShiftKeyPressed,
-        width, height, top, left, dark] = useDesignerStore((s) =>
-        [s.showDeleteConfirmation, s.propertyOnly,s.deleteMessage, s.selectedUuids,s.clipboardSteps, s.selectedStep, s.shiftKeyPressed,
-             s.setShowDeleteConfirmation,s.setPropertyOnly,s.setDeleteMessage, s.setSelectedStep, s.setSelectedUuids, s.setClipboardSteps, s.setPosition, s.setShiftKeyPressed,
-            s.width, s.height, s.top, s.left, s.dark], shallow)
+    const [selectedUuids,clipboardSteps,shiftKeyPressed,
+        setShowDeleteConfirmation,setPropertyOnly, setDeleteMessage, setSelectedStep, setSelectedUuids, setClipboardSteps, setShiftKeyPressed,
+        width, height, dark] = useDesignerStore((s) =>
+        [s.selectedUuids,s.clipboardSteps, s.shiftKeyPressed,
+            s.setShowDeleteConfirmation,s.setPropertyOnly,s.setDeleteMessage, s.setSelectedStep, s.setSelectedUuids, s.setClipboardSteps, s.setShiftKeyPressed,
+            s.width, s.height, s.dark], shallow)
     const [setParentId, setShowSelector, setSelectorTabIndex, setParentDsl, setShowSteps, setSelectedPosition] = useSelectorStore((s) =>
         [s.setParentId, s.setShowSelector, s.setSelectorTabIndex, s.setParentDsl, s.setShowSteps, s.setSelectedPosition], shallow)
 
-    // const commandSub = EventBus.onCommand()?.subscribe((command: Command) => onCommand(command));
-    //
-    //
-    // function 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));
-    // }
-    //
-    // function componentWillUnmount() {
-    //     window.removeEventListener('resize', this.routeDesigner.handleResize);
-    //     window.removeEventListener('keydown', this.routeDesigner.handleKeyDown);
-    //     window.removeEventListener('keyup', this.routeDesigner.handleKeyUp);
-    //     this.commandSub?.unsubscribe();
-    // }
-    //
-    // function handleResize = (event: any) => {
-    //     this.routeDesigner.setState({key: Math.random().toString()});
-    // }
-    //
-
-    //
     function  onCommand (command: Command, printerRef: React.MutableRefObject<HTMLDivElement | null>) {
         switch (command.command){
             case "downloadImage": integrationImageDownload(printerRef);
         }
     }
-    //
-    // function 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})
-    //
+
     const onShowDeleteConfirmation = (id: string) => {
         let message: string;
         const uuidsToDelete:string [] = [id];
@@ -239,21 +183,17 @@ export const useRouteDesignerHook = () => {
         }
     }
 
-    //
-    // function 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: [],
-    //         }));
-    //     }
-    // }
-    //
+    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);
+            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 || '');
@@ -262,11 +202,7 @@ export const useRouteDesignerHook = () => {
         setSelectedPosition(position);
         setSelectorTabIndex((parentId === undefined && parentDsl === undefined) ? 'kamelet' : 'eip');
     }
-    //
-    // function closeDslSelector = () => {
-    //     this.routeDesigner.setState({showSelector: false})
-    // }
-    //
+
     const onDslSelect = (dsl: DslMetaModel, parentId: string, position?: number | undefined) => {
         switch (dsl.dsl) {
             case 'FromDefinition' :
@@ -324,11 +260,8 @@ export const useRouteDesignerHook = () => {
         setPropertyOnly(false);
         setSelectedUuids([selectedStep.uuid]);
     }
-    //
-    // function onIntegrationUpdate = (i: Integration) => {
-    //     this.routeDesigner.setState({integration: i, propertyOnly: false, showSelector: false, key: Math.random().toString()});
-    // }
-    //
+
+
     const moveElement = (source: string, target: string, asChild: boolean) => {
         const i = CamelDefinitionApiExt.moveRouteElement(integration, source, target, asChild);
         const clone = CamelUtil.cloneIntegration(i);
@@ -370,5 +303,6 @@ export const useRouteDesignerHook = () => {
         }
     }
 
-    return { deleteElement, selectElement, moveElement, onShowDeleteConfirmation, onDslSelect, openSelector, createRouteConfiguration, onCommand, handleKeyDown, handleKeyUp}
+    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/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx
index 8d4157c4..cd041e9e 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,
@@ -705,6 +705,8 @@ export class CamelUi {
         switch (dslName) {
             case 'AggregateDefinition':
                 return <AggregateIcon/>;
+            case 'ToDefinition':
+                return <ToIcon/>;
             case 'ChoiceDefinition' :
                 return <ChoiceIcon/>;
             case 'SplitDefinition' :
diff --git a/karavan-designer/src/designer/utils/KaravanIcons.tsx b/karavan-designer/src/designer/utils/KaravanIcons.tsx
index b7228640..23cc7a69 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"
+            >
+                <title>{"plug"}</title>
+                <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 7H2v2h6.07A8.007 8.007 0 0 0 16 24h6a2 2 0 0 0 2-2zm-8 0a6 6 0 0 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">