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

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

commit b4fbb2925156e811bcff97b1324ec8893d00dfef
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Tue Dec 5 19:07:19 2023 -0500

    First example of new Designer #1012
---
 karavan-designer/public/example/demo.camel.yaml    |  92 +++++
 karavan-designer/src/designer/DesignerStore.ts     |  30 +-
 karavan-designer/src/designer/karavan.css          | 409 +--------------------
 .../src/designer/route/DslConnections.tsx          | 280 +++++---------
 karavan-designer/src/designer/route/DslElement.css |  18 -
 .../src/designer/route/DslProperties.css           | 250 +++++++++++++
 .../src/designer/route/DslProperties.tsx           |  21 +-
 .../src/designer/route/RouteDesigner.tsx           |  24 +-
 .../src/designer/route/element/DslElement.css      | 220 +++++++++++
 .../designer/route/{ => element}/DslElement.tsx    | 169 +++++----
 .../src/designer/route/element/DslElementIcons.tsx |  80 ++++
 .../route/{ => element}/DslElementMoveModal.tsx    |   6 +-
 .../src/designer/route/usePropertiesHook.tsx       |  11 +-
 .../src/designer/route/useRouteDesignerHook.tsx    |   3 +-
 karavan-designer/src/designer/utils/CamelUi.tsx    |   9 +
 karavan-designer/src/designer/utils/EventBus.ts    |  32 +-
 16 files changed, 950 insertions(+), 704 deletions(-)

diff --git a/karavan-designer/public/example/demo.camel.yaml 
b/karavan-designer/public/example/demo.camel.yaml
index 56bd06fc..40e3c45b 100644
--- a/karavan-designer/public/example/demo.camel.yaml
+++ b/karavan-designer/public/example/demo.camel.yaml
@@ -4,3 +4,95 @@
     from:
       uri: timer
       id: from-cfa5
+      steps:
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    id: simple-99bf
+                id: when-ab5e
+                steps:
+                  - to:
+                      uri: arangodb
+                      id: to-f70a
+                  - removeProperties:
+                      id: removeProperties-344a
+              - expression:
+                  simple:
+                    id: simple-d199
+                id: when-37cd
+                steps:
+                  - to:
+                      uri: amqp
+                      id: to-fbfe
+            otherwise:
+              id: otherwise-382c
+              steps:
+                - log:
+                    message: ${body}
+                    id: log-6831
+            id: choice-c1db
+        - multicast:
+            id: multicast-6a53
+            steps:
+              - log:
+                  message: ${body}
+                  id: log-799d
+              - log:
+                  message: ${body}
+                  id: log-fc8e
+              - log:
+                  message: ${body}
+                  id: log-1e42
+        - filter:
+            expression:
+              simple:
+                id: simple-7ff9
+            id: filter-8c99
+            steps:
+              - process:
+                  id: process-e1c1
+                  description: Call cutom java bean
+              - delay:
+                  expression:
+                    simple:
+                      id: simple-64a6
+                  id: delay-b1ec
+        - doTry:
+            id: doTry-46cd
+            doCatch:
+              - id: doCatch-c6e7
+                steps:
+                  - log:
+                      message: ${body}
+                      id: log-77df
+                  - wireTap:
+                      id: wireTap-a25e
+            doFinally:
+              id: doFinally-0a65
+              steps:
+                - log:
+                    message: ${body}
+                    id: log-f4fa
+                - log:
+                    message: ${body}
+                    id: log-cd30
+            steps:
+              - pollEnrich:
+                  expression:
+                    simple:
+                      id: simple-6181
+                  id: pollEnrich-a41b
+              - filter:
+                  expression:
+                    simple:
+                      id: simple-a69b
+                  id: filter-07cf
+                  steps:
+                    - setBody:
+                        expression:
+                          simple:
+                            id: simple-f0dc
+                        id: setBody-3c0c
+        - circuitBreaker:
+            id: circuitBreaker-4af8
diff --git a/karavan-designer/src/designer/DesignerStore.ts 
b/karavan-designer/src/designer/DesignerStore.ts
index 4831855f..f9bc38d1 100644
--- a/karavan-designer/src/designer/DesignerStore.ts
+++ b/karavan-designer/src/designer/DesignerStore.ts
@@ -16,7 +16,7 @@
  */
 
 import {CamelElement, Integration} from 
"karavan-core/lib/model/IntegrationDefinition";
-import {DslPosition, EventBus} from "./utils/EventBus";
+import {ButtonPosition, DslPosition, EventBus} from "./utils/EventBus";
 import {createWithEqualityFn} from "zustand/traditional";
 import {shallow} from "zustand/shallow";
 
@@ -120,6 +120,10 @@ interface ConnectionsState {
     deleteStep: (uuid: string) => void;
     clearSteps: () => void;
     setSteps: (steps: Map<string, DslPosition>) => void;
+    buttons: ButtonPosition[];
+    addButton: (button: ButtonPosition) => void;
+    deleteButton: (button: ButtonPosition) => void;
+    clearButtons: () => void;
 }
 
 export const useConnectionsStore = 
createWithEqualityFn<ConnectionsState>((set) => ({
@@ -148,6 +152,30 @@ export const useConnectionsStore = 
createWithEqualityFn<ConnectionsState>((set)
     setSteps: (steps: Map<string, DslPosition>) => {
         set({steps: steps})
     },
+    buttons: [],
+    addButton: (button: ButtonPosition) => {
+        set((state: ConnectionsState) => {
+            const index = state.buttons.findIndex(b => b.uuid === button.uuid);
+            if (index !== -1) {
+                state.buttons.splice(index, 1);
+            }
+            state.buttons.push(button);
+            return state;
+        })
+    },
+    clearButtons: () => {
+        set((state: ConnectionsState) => {
+            state.buttons.length = 0;
+            return state;
+        })
+    },
+    deleteButton: (button: ButtonPosition) => {
+        set((state: ConnectionsState) => {
+            const index = state.buttons.findIndex(b => b.uuid === button.uuid);
+            state.buttons.splice(index, 1);
+            return state;
+        })
+    },
 }), shallow)
 
 type DesignerState = {
diff --git a/karavan-designer/src/designer/karavan.css 
b/karavan-designer/src/designer/karavan.css
index 31aa866b..5e558152 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -355,241 +355,6 @@
     display: none;
 }
 
-.karavan .properties .headers {
-    grid-row-gap: 10px;
-    row-gap: 10px;
-    display: contents;
-}
-
-.karavan .properties .headers .top {
-    width: 100%;
-    display: flex;
-    flex-direction: row;
-}
-
-.karavan .properties .headers .top h1 {
-    width: 100%;
-    margin-top: auto;
-    margin-bottom: auto;
-}
-
-.karavan .properties .footer {
-    height: 100%;
-    display: contents;
-}
-
-.karavan .properties .pf-v5-c-form {
-    row-gap: 10px;
-}
-
-.karavan .properties .pf-v5-c-form__group-label {
-    padding-bottom: 3px;
-    display: flex;
-    justify-content: space-between;
-}
-
-.karavan .properties .pf-v5-c-form-control:focus-within {
-    --pf-v5-c-form-control--after--BorderBottomColor: 
var(--pf-v5-c-form-control--after--BorderBottomColor);
-    --pf-v5-c-form-control--after--BorderBottomWidth: 
var(--pf-v5-c-form-control--after--BorderBottomWidth);
-}
-
-.karavan .properties .pf-v5-c-select {
-    --pf-v5-c-select__toggle--FontSize: 14px;
-    --pf-v5-c-select__menu-item--FontSize: 14px;
-}
-
-.karavan .properties .input-group .pf-v5-c-text-input-group__text {
-    width: 100%;
-}
-
-.karavan .properties .input-group .pf-v5-c-chip-group,
-.karavan .properties .input-group .pf-v5-c-text-input-group__main,
-.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__list,
-.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__list .pf-v5-c-chip-group__list-item,
-.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__main {
-    display: block;
-}
-
-.karavan .properties .input-group .pf-v5-c-chip-group {
-    margin-left: 0;
-}
-
-.karavan .properties .input-group .pf-v5-c-chip-group .pf-v5-c-chip 
.pf-v5-c-chip__text {
-    max-width: inherit;
-}
-
-.karavan .properties .input-group .pf-v5-c-chip-group .pf-v5-c-chip {
-    width: 100%;
-}
-
-.karavan .properties .input-group .pf-v5-c-text-input-group__utilities {
-    align-items: end;
-    margin-top: auto;
-}
-
-.karavan .properties .chip .pf-v5-c-button {
-    position: absolute;
-    right: 0;
-}
-
-.karavan .properties .expression-title {
-    font-size: 17px;
-    font-weight: bold;
-}
-
-.karavan .properties .text-area {
-    font-size: 13px;
-}
-
-.karavan .properties .pf-v5-c-select__menu-search {
-    padding: 0px 6px 6px 6px;
-}
-
-.karavan .properties .pf-v5-c-select__toggle-typeahead {
-    height: auto;
-}
-
-.karavan .properties .pf-v5-c-select__menu-item {
-    /*width: 280px;*/
-}
-
-.karavan .properties .pf-v5-c-select__menu-item-description {
-    overflow-wrap: anywhere;
-}
-
-.karavan .properties .number {
-    display: flex;
-    justify-content: space-between;
-}
-
-.karavan .properties .number .number-property {
-    width: 100%;
-}
-
-.karavan .properties .number .clear-button {
-    color: #b1b1b7;
-    --pf-v5-c-button--BorderRadius: 
var(--pf-v5-c-button--m-control--BorderRadius);
-    --pf-v5-c-button--disabled--BackgroundColor: 
var(--pf-v5-c-button--m-control--disabled--BackgroundColor);
-    --pf-v5-c-button--after--BorderWidth: 
var(--pf-v5-c-button--m-control--after--BorderWidth);
-    --pf-v5-c-button--after--BorderColor: 
var(--pf-v5-c-button--m-control--after--BorderTopColor) 
var(--pf-v5-c-button--m-control--after--BorderRightColor) 
var(--pf-v5-c-button--m-control--after--BorderBottomColor) 
var(--pf-v5-c-button--m-control--after--BorderLeftColor);
-    color: var(--pf-v5-c-button--m-control--Color);
-    background-color: var(--pf-v5-c-button--m-control--BackgroundColor);
-    padding-left: 5px;
-    padding-right: 5px;
-}
-
-.karavan .properties .help-button {
-    font-size: 12px;
-}
-
-.karavan .properties .component-selector {
-    border-width: var(--pf-v5-global--BorderWidth--sm);
-    border-top-color: var(--pf-v5-global--BorderColor--300);
-    border-right-color: var(--pf-v5-global--BorderColor--300);
-    border-bottom-color: var(--pf-v5-global--BorderColor--200);
-    border-left-color: var(--pf-v5-global--BorderColor--300);
-    border-style: solid;
-}
-
-.karavan .properties .object-value {
-    display: flex;
-    flex-direction: row;
-    margin-bottom: 3px;
-}
-
-.karavan .properties .object-key-value .object {
-    padding-top: 0;
-}
-
-.karavan .properties .object-value .delete-button {
-    margin: 0;
-    padding: 5px 3px 0px 6px;
-    height: 16px;
-    color: #909090;
-}
-
-.karavan .properties .object-key-value,
-.karavan .properties .object-key-value .object-field {
-    display: flex;
-    flex-direction: row;
-    gap: 3px;
-}
-
-.karavan .properties .object-key-value .delete-button {
-    margin: auto 0 22px 0;
-    padding: 0px 0px 0px 3px;
-    height: 16px;
-    color: #909090;
-}
-
-.karavan .properties .expression,
-.karavan .properties .object,
-.karavan .properties .dataformat,
-.karavan .properties .parameters {
-    padding-top: 6px;
-    padding-left: 16px;
-    row-gap: 6px;
-    display: grid;
-    width: 100%;
-}
-
-.karavan .properties .expression .pf-v5-c-form__group-label,
-.karavan .properties .object .pf-v5-c-form__group-label,
-.karavan .properties .dataformat .pf-v5-c-form__group-label,
-.karavan .properties .parameters .pf-v5-c-form__group-label {
-    font-weight: 100;
-}
-
-.karavan .properties .expression .pf-v5-c-form__group,
-.karavan .properties .object .pf-v5-c-form__group,
-.karavan .properties .dataformat .pf-v5-c-form__group,
-.karavan .properties .parameters .pf-v5-c-form__group {
-    margin-bottom: 10px;
-}
-
-.karavan .properties .expression .pf-v5-c-select__menu-wrapper,
-.karavan .properties .object .pf-v5-c-select__menu-wrapper,
-.karavan .properties .dataformat .pf-v5-c-select__menu-wrapper,
-.karavan .properties .parameters .pf-v5-c-select__menu-wrapper {
-    width: 350px;
-}
-
-.karavan .properties .change-button {
-    font-size: 15px;
-    height: 15px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: auto auto auto 6px;
-    background: transparent;
-}
-
-.karavan .properties .change-button svg {
-    margin-right: 6px;
-}
-
-.karavan .properties .add-button {
-    color: var(--pf-v5-global--active-color--100);
-}
-
-.karavan .properties .delete-button {
-    color: #909090;
-}
-
-.karavan .properties .pf-v5-c-expandable-section__toggle {
-    margin: 0;
-    padding: 0;
-}
-
-.karavan .properties .pf-v5-c-expandable-section__content {
-    margin: 0;
-}
-
-.karavan .properties .pf-v5-c-expandable-section__content p {
-    min-height: 6px;
-}
-
-
 /*Graph*/
 .karavan .dsl-page .graph {
     display: block;
@@ -691,7 +456,7 @@
     flex-direction: column;
     width: fit-content;
     border-color: var(--pf-v5-global--Color--200);
-    border-radius: 16px;
+    border-radius: 42px;
     border-width: 1px;
     min-width: 120px;
     padding: 3px 4px 4px 4px;
@@ -718,178 +483,6 @@
     gap: 6px;
 }
 
-.karavan .dsl-page .flows .step-element .header-route {
-    display: block;
-    border: none;
-    background: transparent;
-    padding: 0px 0px 0px 0px;
-    margin-bottom: 10px;
-    min-width: 160px;
-    z-index: 101;
-}
-
-.karavan .step-element .header-route .delete-button {
-    position: absolute;
-    top: 4px;
-    right: 4px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: 0;
-    background: transparent;
-    color: #909090;
-    visibility: hidden;
-}
-
-.karavan .step-element .header .delete-button,
-.element-builder .header .delete-button {
-    position: absolute;
-    top: -5px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: 0 0 0 10px;
-    background: transparent;
-    color: #909090;
-    visibility: hidden;
-}
-
-/*.karavan .step-element:hover .delete-button,*/
-/*.karavan .step-element:hover .delete-button,*/
-.karavan .step-element .header:hover .delete-button,
-.karavan .step-element .header-route:hover .delete-button,
-.element-builder .header:hover .delete-button {
-    visibility: visible;
-}
-
-.modal-delete {
-    width: 350px !important;
-}
-
-.karavan .step-element .header {
-    height: 50px;
-}
-
-.karavan .step-element-selected {
-    background-color: rgba(var(--pf-v5-global--palette--blue-50), 1);
-}
-
-.karavan .step-element .selected .header-icon {
-    border-color: var(--pf-v5-global--primary-color--100);
-    background-color: var(--pf-v5-global--palette--blue-50);
-    border-width: 2px;
-}
-
-.karavan .step-element .header .header-text {
-    position: absolute;
-    top: 8px;
-    left: 0;
-    width: 100%;
-    display: flex;
-    flex-direction: row;
-}
-
-.karavan .step-element .header .spacer {
-    width: 50%
-}
-
-.karavan .step-element .header .text-bottom {
-    background-color: rgba(255, 255, 255, 0.5);
-}
-
-.karavan .step-element .header .text-right {
-    padding-left: 17px;
-    width: 50%;
-    text-align: start;
-}
-
-.karavan .step-element .header .header-text-required {
-    color: var(--pf-v5-global--danger-color--100);
-    font-weight: bold;
-}
-
-.karavan .step-element .header-icon {
-    border-color: var(--pf-v5-global--Color--200);
-    border-style: solid;
-    border-radius: 30px;
-    border-width: 1px;
-    background: white;
-    width: 30px;
-    height: 30px;
-    margin: auto;
-    display: flex;
-    justify-content: center;
-    align-items: center;
-}
-
-.karavan .step-element .header .icon,
-.element-builder .header .icon {
-    height: 20px;
-    width: auto;
-    border: none;
-    -webkit-user-select: none;
-    -khtml-user-select: none;
-    -moz-user-select: none;
-    -o-user-select: none;
-    user-select: none;
-}
-
-.karavan .step-element .add-element-button {
-    top: 5px;
-    left: 5px;
-    font-size: 15px;
-    height: 15px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    background: transparent;
-    color: var(--pf-v5-global--primary-color--100);
-    visibility: hidden;
-    z-index: 100;
-    position: absolute;
-}
-
-.karavan .step-element .insert-element-button {
-    position: absolute;
-    top: -5px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: 0 0 0 -25px;
-    background: transparent;
-    background: transparent;
-    color: var(--pf-v5-global--primary-color--100);
-    visibility: hidden;
-    z-index: 100;
-}
-
-.karavan .step-element .header:hover .insert-element-button {
-    visibility: visible;
-}
-
-.karavan .step-element .add-button-bottom {
-    position: relative;
-}
-
-.karavan .step-element .add-button-left {
-    position: absolute;
-    top: 4px;
-    left: 4px;
-}
-
-.karavan .step-element .add-button {
-    font-size: 15px;
-    height: 15px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: 0;
-    background: transparent;
-    color: var(--pf-v5-global--primary-color--100);
-    visibility: hidden;
-    z-index: 100;
-}
-
 .karavan .dsl-page .flows .hidden-step {
     display: none;
 }
diff --git a/karavan-designer/src/designer/route/DslConnections.tsx 
b/karavan-designer/src/designer/route/DslConnections.tsx
index a636339e..6bb318c2 100644
--- a/karavan-designer/src/designer/route/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -17,9 +17,8 @@
 import React, {useEffect} from 'react';
 import '../karavan.css';
 import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
-import {DslPosition, EventBus} from "../utils/EventBus";
+import {ButtonPosition, DslPosition, EventBus} from "../utils/EventBus";
 import {CamelUi} from "../utils/CamelUi";
-import {SagaDefinition} from "karavan-core/lib/model/CamelDefinition";
 import {useConnectionsStore, useDesignerStore, useIntegrationStore} from 
"../DesignerStore";
 import {shallow} from "zustand/shallow";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
@@ -32,12 +31,16 @@ export function DslConnections() {
     const [integration] = useIntegrationStore((state) => [state.integration], 
shallow)
     const [width, height, top, left, hideLogDSL] = useDesignerStore((s) =>
         [s.width, s.height, s.top, s.left, s.hideLogDSL], shallow)
-    const [ steps, addStep, deleteStep, clearSteps] = useConnectionsStore((s) 
=> [s.steps, s.addStep, s.deleteStep, s.clearSteps], shallow)
+    const [steps, addStep, deleteStep, clearSteps, buttons, addButton, 
clearButtons, deleteButton] =
+        useConnectionsStore((s) => [s.steps, s.addStep, s.deleteStep, 
s.clearSteps,
+            s.buttons, s.addButton, s.clearButtons, s.deleteButton], shallow)
 
     useEffect(() => {
-        const sub = EventBus.onPosition()?.subscribe((evt: DslPosition) => 
setPosition(evt));
+        const sub1 = EventBus.onPosition()?.subscribe((evt: DslPosition) => 
setPosition(evt));
+        const sub2 = EventBus.onButtonPosition()?.subscribe((btn: 
ButtonPosition) => setButtonPosition(btn));
         return () => {
-            sub?.unsubscribe();
+            sub1?.unsubscribe();
+            sub2?.unsubscribe();
         };
     });
 
@@ -46,14 +49,22 @@ export function DslConnections() {
         toDelete.forEach(key => deleteStep(key));
     }, [integration]);
 
+    function setButtonPosition(btn: ButtonPosition) {
+        if (btn.command === "add") {
+            addButton(btn);
+        } else if (btn.command === "delete") {
+            deleteButton(btn);
+        } else if (btn.command === "clean") {
+            clearButtons();
+        }
+    }
+
     function setPosition(evt: DslPosition) {
         if (evt.command === "add") {
             addStep(evt.step.uuid, evt);
-        }
-        else if (evt.command === "delete") {
+        } else if (evt.command === "delete") {
             deleteStep(evt.step.uuid);
-        }
-        else if (evt.command === "clean") {
+        } else if (evt.command === "clean") {
             clearSteps();
         }
     }
@@ -110,7 +121,8 @@ export function DslConnections() {
             const imageX = incomingX - r + 5;
             const imageY = fromY - r + 5;
             return (
-                <div key={pos.step.uuid + "-icon"} style={{display: "block", 
position: "absolute", top: imageY, left: imageX}}>
+                <div key={pos.step.uuid + "-icon"}
+                     style={{display: "block", position: "absolute", top: 
imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
                 </div>
             )
@@ -174,16 +186,14 @@ export function DslConnections() {
             const lineXi = lineX1 + 40;
             const lineYi = lineY2;
 
-            let image = CamelUi.getConnectionIconString(pos.step);
-            const imageX = outgoingX - r + 5;
-            const imageY = outgoingY - r + 5;
             return (
                 <g key={pos.step.uuid + "-outgoing"}>
                     <circle cx={outgoingX} cy={outgoingY} r={r} 
className="circle-outgoing"/>
                     {/*<image x={imageX} y={imageY} href={image} 
className="icon"/>*/}
                     {/*<text x={imageX + 25} y={imageY + 40}  
className="caption" 
textAnchor="end">{CamelUi.getOutgoingTitle(pos.step)}</text>*/}
-                    <path d={`M ${lineX1},${lineY1} C ${lineXi - 20}, 
${lineY1} ${lineX1 - 15},${lineYi} ${lineXi},${lineYi} L ${lineX2},${lineY2}`}
-                          className="path-incoming" 
markerEnd="url(#arrowhead)"/>
+                    <path
+                        d={`M ${lineX1},${lineY1} C ${lineXi - 20}, ${lineY1} 
${lineX1 - 15},${lineYi} ${lineXi},${lineYi} L ${lineX2},${lineY2}`}
+                        className="path-incoming" markerEnd="url(#arrowhead)"/>
                 </g>
             )
         }
@@ -198,185 +208,25 @@ export function DslConnections() {
             const imageX = outgoingX - r + 5;
             const imageY = outgoingY - r + 5;
             return (
-                <div key={pos.step.uuid + "-icon"} style={{display: "block", 
position: "absolute", top: imageY, left: imageX}}>
+                <div key={pos.step.uuid + "-icon"}
+                     style={{display: "block", position: "absolute", top: 
imageY, left: imageX}}>
                     {CamelUi.getConnectionIcon(pos.step)}
                 </div>
             )
         }
     }
 
-    function getInternals(): [string, number, boolean][] {
-        const outgoingDefinitions = TopologyUtils.getOutgoingDefinitions();
-        let outs: [string, number, boolean][] = Array.from(steps.values())
-            .filter(pos => outgoingDefinitions.includes(pos.step.dslName) && 
TopologyUtils.hasInternalUri(pos.step))
-            .sort((pos1: DslPosition, pos2: DslPosition) => {
-                const y1 = pos1.headerRect.y + pos1.headerRect.height / 2;
-                const y2 = pos2.headerRect.y + pos2.headerRect.height / 2;
-                return y1 > y2 ? 1 : -1
-            })
-            .map(pos => [pos.step.uuid, pos.headerRect.y - top, 
pos.isSelected]);
-        return outs;
-    }
-
-    function getInternalLines(data: [string, number, boolean]) {
-        const pos = steps.get(data[0]);
-        const uri = (pos?.step as any).uri;
-        if (uri && uri.length && pos) {
-            const key = pos.step.uuid + "-outgoing"
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
-            const r = pos.headerRect.height / 2;
-            const className = (TopologyUtils.hasDirectUri(pos.step) ? 
"path-direct" : "path-seda") + (data[2] ? "-selected" : "");
-            return getInternalLine(uri, key, className, fromX, fromY, r, 
data[1]);
-        } else if (pos?.step.dslName === 'SagaDefinition'){
-            const saga = (pos?.step as SagaDefinition);
-            const fromX = pos.headerRect.x + pos.headerRect.width / 2 - left;
-            const fromY = pos.headerRect.y + pos.headerRect.height / 2 - top;
-            const r = pos.headerRect.height / 2;
-            const result:any[] = [];
-            if (saga.completion && (saga.completion.startsWith("direct") || 
saga.completion.startsWith("seda"))){
-                const key = pos.step.uuid + "-completion"
-                const className = saga.completion.startsWith("direct") ? 
"path-direct" : "path-seda";
-                result.push(getInternalLine(saga.completion, key, className, 
fromX, fromY, r, data[1]));
-            }
-            if (saga.compensation && (saga.compensation.startsWith("direct") 
|| saga.compensation.startsWith("seda"))){
-                const key = pos.step.uuid + "-compensation"
-                const className = saga.compensation.startsWith("direct") ? 
"path-direct" : "path-seda";
-                result.push(getInternalLine(saga.compensation, key, className, 
fromX, fromY, r, data[1]));
-            }
-            return result;
-        }
-    }
-
-    function getInternalLine(uri: string, key: string, className: string, 
fromX: number, fromY: number, r: number, i: number) {
-        const target = Array.from(steps.values())
-            .filter(s => s.step.dslName === 'FromDefinition')
-            .filter(s => (s.step as any).uri && (s.step as any).uri === 
uri)[0];
-        if (target) {
-            const targetX = target.headerRect.x + target.headerRect.width / 2 
- left;
-            const targetY = target.headerRect.y + target.headerRect.height / 2 
- top;
-            const gap = 100;
-            const add = 0.2;
-
-            // right
-            if (targetX - fromX >= gap) {
-                const startX = fromX + r;
-                const startY = fromY;
-                const endX = targetX - r * 2 + 4;
-                const endY = targetY;
-
-                const coefX = 24 + (i * add);
-                const coefY = (targetY > fromY) ? 24 : -24;
-
-                const pointX1 = startX + coefX;
-                const pointY1 = startY;
-                const pointX2 = startX + coefX;
-                const pointY2 = startY + coefY;
-
-                const pointLX = pointX1;
-                const pointLY = targetY - coefY;
-
-                const pointX3 = pointLX;
-                const pointY3 = endY;
-                const pointX4 = pointLX + coefX;
-                const pointY4 = endY;
-
-                return getInternalPath(key, className, startX, startY, 
pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, 
pointX4, pointY4, endX, endY);
-            } else if (targetX > fromX && targetX - fromX < gap) {
-                const startX = fromX - r;
-                const startY = fromY;
-                const endX = targetX - r * 2 + 4;
-                const endY = targetY;
-
-                const coefX = -24 - (i * add);
-                const coefY = (targetY > fromY) ? 24 : -24;
-
-                const pointX1 = startX + coefX;
-                const pointY1 = startY;
-                const pointX2 = startX + coefX;
-                const pointY2 = startY + coefY;
-
-                const pointLX = pointX1;
-                const pointLY = targetY - coefY;
-
-                const pointX3 = pointLX;
-                const pointY3 = endY;
-                const pointX4 = pointLX - coefX/2;
-                const pointY4 = endY;
-
-                return getInternalPath(key, className, startX, startY, 
pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, 
pointX4, pointY4, endX, endY);
-            } else if (targetX <= fromX && fromX - targetX < gap) {
-                const startX = fromX + r;
-                const startY = fromY;
-                const endX = targetX + r * 2 - 4;
-                const endY = targetY;
-
-                const coefX = 24 + (i * add);
-                const coefY = (targetY > fromY) ? 24 : -24;
-
-                const pointX1 = startX + coefX;
-                const pointY1 = startY;
-                const pointX2 = startX + coefX;
-                const pointY2 = startY + coefY;
-
-                const pointLX = pointX1;
-                const pointLY = targetY - coefY;
-
-                const pointX3 = pointLX;
-                const pointY3 = endY;
-                const pointX4 = pointLX - coefX/2;
-                const pointY4 = endY;
-
-                return getInternalPath(key, className, startX, startY, 
pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, 
pointX4, pointY4, endX, endY);
-            } else {
-                const startX = fromX - r;
-                const startY = fromY;
-                const endX = targetX + r * 2 - 4;
-                const endY = targetY;
-
-                const coefX = -24 - (i * add);
-                const coefY = (targetY > fromY) ? 24 : -24;
-
-                const pointX1 = startX + coefX;
-                const pointY1 = startY;
-                const pointX2 = startX + coefX;
-                const pointY2 = startY + coefY;
-
-                const pointLX = pointX1;
-                const pointLY = targetY - coefY;
-
-                const pointX3 = pointLX;
-                const pointY3 = endY;
-                const pointX4 = pointLX + coefX;
-                const pointY4 = endY;
-
-                return getInternalPath(key, className, startX, startY, 
pointX1, pointY1, pointX2, pointY2, pointLX, pointLY, pointX3, pointY3, 
pointX4, pointY4, endX, endY);
-            }
-        }
-    }
-
-    function getInternalPath(key: string, className: string, startX: number, 
startY: number, pointX1: number, pointY1: number, pointX2: number, pointY2: 
number, pointLX: number, pointLY: number,
-                    pointX3: number, pointY3: number, pointX4: number, 
pointY4: number, endX: number, endY: number) {
-        return (
-            <g key={key}>
-                <path d={`M ${startX} ${startY} 
-                        Q ${pointX1} ${pointY1} ${pointX2} ${pointY2} L 
${pointLX},${pointLY}
-                        Q ${pointX3} ${pointY3} ${pointX4} ${pointY4} L 
${endX},${endY}`}
-                      className={className} markerEnd="url(#arrowhead)"/>
-            </g>
-        )
-    }
-
     function getCircle(pos: DslPosition) {
         const cx = pos.headerRect.x + pos.headerRect.width / 2 - left;
         const cy = pos.headerRect.y + pos.headerRect.height / 2 - top;
         const r = pos.headerRect.height / 2;
         return (
-            <circle cx={cx} cy={cy} r={r} stroke="transparent" strokeWidth="3" 
fill="transparent" key={pos.step.uuid + "-circle"}/>
+            <circle cx={cx} cy={cy} r={r} stroke="transparent" strokeWidth="3" 
fill="transparent"
+                    key={pos.step.uuid + "-circle"}/>
         )
     }
 
-    function hasSteps  (step: CamelElement): boolean  {
+    function hasSteps(step: CamelElement): boolean {
         return (step.hasSteps() && !['FromDefinition'].includes(step.dslName))
             || ['RouteDefinition', 'TryDefinition', 'ChoiceDefinition', 
'SwitchDefinition'].includes(step.dslName);
     }
@@ -393,18 +243,21 @@ export function DslConnections() {
         const endY = pos.headerRect.y - 9 - top;
         if (pos.parent) {
             const parent = steps.get(pos.parent.uuid);
-            if (parent) {
+            const showArrow = pos.prevStep !== undefined && !['TryDefinition', 
'ChoiceDefinition'].includes(pos.prevStep.dslName);
+            const name = pos.prevStep?.dslName;
+            if (parent && showArrow) {
                 const startX = parent.headerRect.x + parent.headerRect.width / 
2 - left;
                 const startY = parent.headerRect.y + parent.headerRect.height 
- top;
                 if ((!pos.inSteps || (pos.inSteps && pos.position === 0)) && 
parent.step.dslName !== 'MulticastDefinition') {
                     return (
-                        <path name={pos.step.dslName} d={`M 
${startX},${startY} C ${startX},${endY} ${endX},${startY}   ${endX},${endY}`}
+                        <path name={pos.step.dslName}
+                              d={`M ${startX},${startY} C ${startX},${endY} 
${endX},${startY}   ${endX},${endY}`}
                               className="path" key={pos.step.uuid} 
markerEnd="url(#arrowhead)"/>
                     )
                 } else if (parent.step.dslName === 'MulticastDefinition' && 
pos.inSteps) {
                     return (
                         <path d={`M ${startX},${startY} C ${startX},${endY} 
${endX},${startY}   ${endX},${endY}`}
-                              className="path" key={pos.step.uuid} 
markerEnd="url(#arrowhead)"/>
+                              name={name} className="path" key={pos.step.uuid} 
markerEnd="url(#arrowhead)"/>
                     )
                 } else if (pos.inSteps && pos.position > 0 && 
!hasSteps(pos.step)) {
                     const prev = getPreviousStep(pos);
@@ -413,7 +266,8 @@ export function DslConnections() {
                         const prevX = r.x + r.width / 2 - left;
                         const prevY = r.y + r.height - top;
                         return (
-                            <line x1={prevX} y1={prevY} x2={endX} y2={endY} 
className="path" key={pos.step.uuid} markerEnd="url(#arrowhead)"/>
+                            <line name={name} x1={prevX} y1={prevY} x2={endX} 
y2={endY} className="path"
+                                  key={pos.step.uuid} 
markerEnd="url(#arrowhead)"/>
                         )
                     }
                 } else if (pos.inSteps && pos.position > 0 && 
hasSteps(pos.step)) {
@@ -423,7 +277,8 @@ export function DslConnections() {
                         const prevX = r.x + r.width / 2 - left;
                         const prevY = r.y + r.height - top;
                         return (
-                            <line x1={prevX} y1={prevY} x2={endX} y2={endY} 
className="path" key={pos.step.uuid} markerEnd="url(#arrowhead)"/>
+                            <line name={name} x1={prevX} y1={prevY} x2={endX} 
y2={endY} className="path"
+                                  key={pos.step.uuid} 
markerEnd="url(#arrowhead)"/>
                         )
                     }
                 }
@@ -431,6 +286,55 @@ export function DslConnections() {
         }
     }
 
+    function getButtonArrow(btn: ButtonPosition) {
+        const rect1 = btn.rect;
+        const uuid = btn.nextstep.uuid;
+        const nextStep = steps.get(uuid);
+        const rect2 = nextStep?.rect;
+        if (rect1 && rect2) {
+            const startX = rect1.x + rect1.width / 2 - left;
+            const startY = rect1.y + rect1.height - top - 2;
+            const endX = rect2.x + rect2.width / 2 - left;
+            const endTempY = rect2.y - top - 9;
+
+            const gapX = Math.abs(endX - startX);
+            const gapY = Math.abs(endTempY - startY);
+
+            const radX = gapX > 30 ? 20 : gapX/2;
+            const radY = gapY > 30 ? 20 : gapY/2;
+            const endY = rect2.y - top - 9 - radY;
+
+            const iRadX = startX > endX ? -1 * radX : radX;
+            const iRadY = startY > endY ? -1 * radY : radY;
+
+            const LX1 = startX;
+            const LY1 = endY - radY;
+
+            const Q1_X1 = startX;
+            const Q1_Y1 = LY1 + radY;
+            const Q1_X2 = startX + iRadX;
+            const Q1_Y2 = LY1 + radY;
+
+            const LX2 = startX + (endX - startX) - iRadX;
+            const LY2 = LY1 + radY;
+
+            const Q2_X1 = LX2 + iRadX;
+            const Q2_Y1 = endY;
+            const Q2_X2 = LX2 + iRadX;
+            const Q2_Y2 = endY + radY;
+
+            const path = `M ${startX} ${startY}`
+                + ` L ${LX1} ${LY1} `
+                + ` Q ${Q1_X1} ${Q1_Y1} ${Q1_X2} ${Q1_Y2}`
+                + ` L ${LX2} ${LY2}`
+                + ` Q ${Q2_X1} ${Q2_Y1} ${Q2_X2} ${Q2_Y2}`
+                // + ` L ${endX} ${endY}`;
+            return (
+                <path key={btn.uuid} d={path} className="path" 
markerEnd="url(#arrowhead)"/>
+            )
+        }
+    }
+
     function getSvg() {
         const stepsArray = Array.from(steps.values());
         return (
@@ -438,12 +342,14 @@ export function DslConnections() {
                 style={{width: width, height: height, position: "absolute", 
left: 0, top: 0}}
                 viewBox={"0 0 " + (width) + " " + (height)}>
                 <defs>
-                    <marker id="arrowhead" markerWidth="9" markerHeight="6" 
refX="0" refY="3" orient="auto" className="arrow">
+                    <marker id="arrowhead" markerWidth="9" markerHeight="6" 
refX="0" refY="3" orient="auto"
+                            className="arrow">
                         <polygon points="0 0, 9 3, 0 6"/>
                     </marker>
                 </defs>
                 {stepsArray.map(pos => getCircle(pos))}
                 {stepsArray.map(pos => getArrow(pos))}
+                {buttons.map(btn => getButtonArrow(btn)).filter(b => b !== 
undefined)}
                 {getIncomings().map(p => getIncoming(p))}
                 {getOutgoings().map(p => getOutgoing(p))}
                 {/*{getInternals().map((p) => getInternalLines(p)).flat()}*/}
@@ -452,7 +358,7 @@ export function DslConnections() {
     }
 
     return (
-        <div id="connections" className="connections" style={{ width: width, 
height: height}}>
+        <div id="connections" className="connections" style={{width: width, 
height: height}}>
             {getSvg()}
             {getIncomings().map(p => getIncomingIcons(p))}
             {getOutgoings().map(p => getOutgoingIcons(p))}
diff --git a/karavan-designer/src/designer/route/DslElement.css 
b/karavan-designer/src/designer/route/DslElement.css
deleted file mode 100644
index d3ed7177..00000000
--- a/karavan-designer/src/designer/route/DslElement.css
+++ /dev/null
@@ -1,18 +0,0 @@
-.disabled {
-    opacity: 0.5;
-}
-.menu-button {
-    position: absolute;
-    top: 26px;
-    line-height: 1;
-    border: 0;
-    padding: 0;
-    margin: 0 0 0 10px;
-    background: transparent;
-    color: var(--pf-v5-global--primary-color--100);
-    visibility: hidden;
-}
-
-.dsl-element:hover .menu-button {
-    visibility: visible;
-}
diff --git a/karavan-designer/src/designer/route/DslProperties.css 
b/karavan-designer/src/designer/route/DslProperties.css
new file mode 100644
index 00000000..7040fd40
--- /dev/null
+++ b/karavan-designer/src/designer/route/DslProperties.css
@@ -0,0 +1,250 @@
+/*
+ * 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.
+ */
+.karavan .properties .headers {
+    grid-row-gap: 10px;
+    row-gap: 10px;
+    display: contents;
+}
+
+.karavan .properties .headers .top {
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+}
+
+.karavan .properties .headers .top h1 {
+    width: 100%;
+    margin-top: auto;
+    margin-bottom: auto;
+}
+
+.karavan .properties .footer {
+    height: 100%;
+    display: contents;
+}
+
+.karavan .properties .pf-v5-c-form {
+    row-gap: 10px;
+}
+
+.karavan .properties .pf-v5-c-form__group-label {
+    padding-bottom: 3px;
+    display: flex;
+    justify-content: space-between;
+}
+
+.karavan .properties .pf-v5-c-form-control:focus-within {
+    --pf-v5-c-form-control--after--BorderBottomColor: 
var(--pf-v5-c-form-control--after--BorderBottomColor);
+    --pf-v5-c-form-control--after--BorderBottomWidth: 
var(--pf-v5-c-form-control--after--BorderBottomWidth);
+}
+
+.karavan .properties .pf-v5-c-select {
+    --pf-v5-c-select__toggle--FontSize: 14px;
+    --pf-v5-c-select__menu-item--FontSize: 14px;
+}
+
+.karavan .properties .input-group .pf-v5-c-text-input-group__text {
+    width: 100%;
+}
+
+.karavan .properties .input-group .pf-v5-c-chip-group,
+.karavan .properties .input-group .pf-v5-c-text-input-group__main,
+.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__list,
+.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__list .pf-v5-c-chip-group__list-item,
+.karavan .properties .input-group .pf-v5-c-chip-group 
.pf-v5-c-chip-group__main {
+    display: block;
+}
+
+.karavan .properties .input-group .pf-v5-c-chip-group {
+    margin-left: 0;
+}
+
+.karavan .properties .input-group .pf-v5-c-chip-group .pf-v5-c-chip 
.pf-v5-c-chip__text {
+    max-width: inherit;
+}
+
+.karavan .properties .input-group .pf-v5-c-chip-group .pf-v5-c-chip {
+    width: 100%;
+}
+
+.karavan .properties .input-group .pf-v5-c-text-input-group__utilities {
+    align-items: end;
+    margin-top: auto;
+}
+
+.karavan .properties .chip .pf-v5-c-button {
+    position: absolute;
+    right: 0;
+}
+
+.karavan .properties .expression-title {
+    font-size: 17px;
+    font-weight: bold;
+}
+
+.karavan .properties .text-area {
+    font-size: 13px;
+}
+
+.karavan .properties .pf-v5-c-select__menu-search {
+    padding: 0px 6px 6px 6px;
+}
+
+.karavan .properties .pf-v5-c-select__toggle-typeahead {
+    height: auto;
+}
+
+.karavan .properties .pf-v5-c-select__menu-item {
+    /*width: 280px;*/
+}
+
+.karavan .properties .pf-v5-c-select__menu-item-description {
+    overflow-wrap: anywhere;
+}
+
+.karavan .properties .number {
+    display: flex;
+    justify-content: space-between;
+}
+
+.karavan .properties .number .number-property {
+    width: 100%;
+}
+
+.karavan .properties .number .clear-button {
+    color: #b1b1b7;
+    --pf-v5-c-button--BorderRadius: 
var(--pf-v5-c-button--m-control--BorderRadius);
+    --pf-v5-c-button--disabled--BackgroundColor: 
var(--pf-v5-c-button--m-control--disabled--BackgroundColor);
+    --pf-v5-c-button--after--BorderWidth: 
var(--pf-v5-c-button--m-control--after--BorderWidth);
+    --pf-v5-c-button--after--BorderColor: 
var(--pf-v5-c-button--m-control--after--BorderTopColor) 
var(--pf-v5-c-button--m-control--after--BorderRightColor) 
var(--pf-v5-c-button--m-control--after--BorderBottomColor) 
var(--pf-v5-c-button--m-control--after--BorderLeftColor);
+    color: var(--pf-v5-c-button--m-control--Color);
+    background-color: var(--pf-v5-c-button--m-control--BackgroundColor);
+    padding-left: 5px;
+    padding-right: 5px;
+}
+
+.karavan .properties .help-button {
+    font-size: 12px;
+}
+
+.karavan .properties .component-selector {
+    border-width: var(--pf-v5-global--BorderWidth--sm);
+    border-top-color: var(--pf-v5-global--BorderColor--300);
+    border-right-color: var(--pf-v5-global--BorderColor--300);
+    border-bottom-color: var(--pf-v5-global--BorderColor--200);
+    border-left-color: var(--pf-v5-global--BorderColor--300);
+    border-style: solid;
+}
+
+.karavan .properties .object-value {
+    display: flex;
+    flex-direction: row;
+    margin-bottom: 3px;
+}
+
+.karavan .properties .object-key-value .object {
+    padding-top: 0;
+}
+
+.karavan .properties .object-value .delete-button {
+    margin: 0;
+    padding: 5px 3px 0px 6px;
+    height: 16px;
+    color: #909090;
+}
+
+.karavan .properties .object-key-value,
+.karavan .properties .object-key-value .object-field {
+    display: flex;
+    flex-direction: row;
+    gap: 3px;
+}
+
+.karavan .properties .object-key-value .delete-button {
+    margin: auto 0 22px 0;
+    padding: 0px 0px 0px 3px;
+    height: 16px;
+    color: #909090;
+}
+
+.karavan .properties .expression,
+.karavan .properties .object,
+.karavan .properties .dataformat,
+.karavan .properties .parameters {
+    padding-top: 6px;
+    padding-left: 16px;
+    row-gap: 6px;
+    display: grid;
+    width: 100%;
+}
+
+.karavan .properties .expression .pf-v5-c-form__group-label,
+.karavan .properties .object .pf-v5-c-form__group-label,
+.karavan .properties .dataformat .pf-v5-c-form__group-label,
+.karavan .properties .parameters .pf-v5-c-form__group-label {
+    font-weight: 100;
+}
+
+.karavan .properties .expression .pf-v5-c-form__group,
+.karavan .properties .object .pf-v5-c-form__group,
+.karavan .properties .dataformat .pf-v5-c-form__group,
+.karavan .properties .parameters .pf-v5-c-form__group {
+    margin-bottom: 10px;
+}
+
+.karavan .properties .expression .pf-v5-c-select__menu-wrapper,
+.karavan .properties .object .pf-v5-c-select__menu-wrapper,
+.karavan .properties .dataformat .pf-v5-c-select__menu-wrapper,
+.karavan .properties .parameters .pf-v5-c-select__menu-wrapper {
+    width: 350px;
+}
+
+.karavan .properties .change-button {
+    font-size: 15px;
+    height: 15px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: auto auto auto 6px;
+    background: transparent;
+}
+
+.karavan .properties .change-button svg {
+    margin-right: 6px;
+}
+
+.karavan .properties .add-button {
+    color: var(--pf-v5-global--active-color--100);
+}
+
+.karavan .properties .delete-button {
+    color: #909090;
+}
+
+.karavan .properties .pf-v5-c-expandable-section__toggle {
+    margin: 0;
+    padding: 0;
+}
+
+.karavan .properties .pf-v5-c-expandable-section__content {
+    margin: 0;
+}
+
+.karavan .properties .pf-v5-c-expandable-section__content p {
+    min-height: 6px;
+}
+
diff --git a/karavan-designer/src/designer/route/DslProperties.tsx 
b/karavan-designer/src/designer/route/DslProperties.tsx
index 8231759c..b958b2b3 100644
--- a/karavan-designer/src/designer/route/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -22,6 +22,7 @@ import {
     TextVariants, ExpandableSection, Button, Tooltip,
 } from '@patternfly/react-core';
 import '../karavan.css';
+import './DslProperties.css';
 import "@patternfly/patternfly/patternfly.css";
 import {DataFormatField} from "./property/DataFormatField";
 import {DslPropertyField} from "./property/DslPropertyField";
@@ -30,6 +31,7 @@ import {CamelUi} from "../utils/CamelUi";
 import {CamelMetadataApi, DataFormats, PropertyMeta} from 
"karavan-core/lib/model/CamelMetadata";
 import {IntegrationHeader} from "../utils/IntegrationHeader";
 import CloneIcon from "@patternfly/react-icons/dist/esm/icons/clone-icon";
+import ConvertIcon from "@patternfly/react-icons/dist/esm/icons/optimize-icon";
 import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
 import {shallow} from "zustand/shallow";
 import {usePropertiesHook} from "./usePropertiesHook";
@@ -43,7 +45,8 @@ export function DslProperties(props: Props) {
 
     const [integration] = useIntegrationStore((state) => [state.integration], 
shallow)
 
-    const {cloneElement, onDataFormatChange, onPropertyChange, 
onParametersChange, onExpressionChange} = 
usePropertiesHook(props.isRouteDesigner);
+    const {convertStep, cloneElement, onDataFormatChange, onPropertyChange, 
onParametersChange, onExpressionChange} =
+        usePropertiesHook(props.isRouteDesigner);
 
     const [selectedStep, dark] = useDesignerStore((s) => [s.selectedStep, 
s.dark], shallow)
 
@@ -54,10 +57,26 @@ export function DslProperties(props: Props) {
         const title = selectedStep && CamelDisplayUtil.getTitle(selectedStep)
         const description = selectedStep && 
CamelUi.getDescription(selectedStep);
         const descriptionLines: string [] = description ? 
description?.split("\n") : [""];
+        const targetDsl = CamelUi.getConvertTargetDsl(selectedStep?.dslName);
+        const targetDslTitle = targetDsl?.replace("Definition", "");
         return (
             <div className="headers">
                 <div className="top">
                     <Title headingLevel="h1" size="md">{title}</Title>
+                    {targetDsl &&
+                        <Button
+                            variant={"link"}
+                            icon={<ConvertIcon/>}
+                            iconPosition={"right"}
+                            onClick={event => {
+                                if (selectedStep) {
+                                    convertStep(selectedStep, targetDsl);
+                                }
+                            }}
+                        >
+                            Convert to {targetDslTitle}
+                        </Button>
+                    }
                 </div>
                 <Text 
component={TextVariants.p}>{descriptionLines.at(0)}</Text>
                 {descriptionLines.length > 1 &&
diff --git a/karavan-designer/src/designer/route/RouteDesigner.tsx 
b/karavan-designer/src/designer/route/RouteDesigner.tsx
index c57260db..b6b1c942 100644
--- a/karavan-designer/src/designer/route/RouteDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -27,7 +27,7 @@ import {DslSelector} from "./DslSelector";
 import {DslProperties} from "./DslProperties";
 import {DslConnections} from "./DslConnections";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {DslElement} from "./DslElement";
+import {DslElement} from "./element/DslElement";
 import {CamelUi} from "../utils/CamelUi";
 import {useRouteDesignerHook} from "./useRouteDesignerHook";
 import {useConnectionsStore, useDesignerStore, useIntegrationStore, 
useSelectorStore} from "../DesignerStore";
@@ -36,7 +36,7 @@ import useResizeObserver from "./useResizeObserver";
 import {Command, EventBus} from "../utils/EventBus";
 import useMutationsObserver from "./useDrawerMutationsObserver";
 import {DeleteConfirmation} from "./DeleteConfirmation";
-import {DslElementMoveModal} from "./DslElementMoveModal";
+import {DslElementMoveModal} from "./element/DslElementMoveModal";
 
 export function RouteDesigner() {
 
@@ -152,15 +152,21 @@ export function RouteDesigner() {
                                     inSteps={false}
                                     position={index}
                                     step={routeConfiguration}
+                                    nextStep={undefined}
+                                    prevStep={undefined}
                                     parent={undefined}/>
                     ))}
-                    {routes?.map((route: any, index: number) => (
-                        <DslElement key={route.uuid}
-                                    inSteps={false}
-                                    position={index}
-                                    step={route}
-                                    parent={undefined}/>
-                    ))}
+                    {routes?.map((route: any, index: number) => {
+                        return (
+                            <DslElement key={route.uuid}
+                                        inSteps={false}
+                                        position={index}
+                                        step={route}
+                                        nextStep={undefined}
+                                        prevStep={undefined}
+                                        parent={undefined}/>
+                        )
+                    })}
                     {getGraphButtons()}
                 </div>
             </div>)
diff --git a/karavan-designer/src/designer/route/element/DslElement.css 
b/karavan-designer/src/designer/route/element/DslElement.css
new file mode 100644
index 00000000..85f7b46a
--- /dev/null
+++ b/karavan-designer/src/designer/route/element/DslElement.css
@@ -0,0 +1,220 @@
+/*
+ * 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.
+ */
+
+.karavan .dsl-page .flows .step-element .header-route {
+    display: block;
+    border: none;
+    background: transparent;
+    padding: 0px 0px 0px 0px;
+    margin-bottom: 10px;
+    min-width: 160px;
+    z-index: 101;
+}
+
+.karavan .step-element .header-route .delete-button {
+    position: absolute;
+    top: 4px;
+    right: 4px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0;
+    background: transparent;
+    color: #909090;
+    visibility: hidden;
+}
+
+.karavan .step-element .header .delete-button,
+.element-builder .header .delete-button {
+    position: absolute;
+    top: -8px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0 0 0 10px;
+    background: transparent;
+    color: #909090;
+    visibility: hidden;
+}
+
+/*.karavan .step-element:hover .delete-button,*/
+/*.karavan .step-element:hover .delete-button,*/
+.karavan .step-element .header:hover .delete-button,
+.karavan .step-element .header-route:hover .delete-button,
+.element-builder .header:hover .delete-button {
+    visibility: visible;
+}
+
+.modal-delete {
+    width: 350px !important;
+}
+
+.karavan .step-element .header {
+    height: 50px;
+}
+
+.karavan .step-element-selected {
+    background-color: rgba(var(--pf-v5-global--palette--blue-50), 1);
+}
+
+.karavan .step-element .selected .header-icon {
+    border-color: var(--pf-v5-global--primary-color--100);
+    background-color: var(--pf-v5-global--palette--blue-50);
+    border-width: 2px;
+}
+
+.karavan .step-element .header .header-text {
+    position: absolute;
+    top: 8px;
+    left: 0;
+    width: 100%;
+    display: flex;
+    flex-direction: row;
+}
+
+.karavan .step-element .header .spacer {
+    width: 50%
+}
+
+.karavan .step-element .header .text-bottom {
+    background-color: rgba(255, 255, 255, 0.5);
+}
+
+.karavan .step-element .header .text-right {
+    padding-left: 17px;
+    width: 50%;
+    text-align: start;
+}
+
+.karavan .step-element .header .header-text-required {
+    color: var(--pf-v5-global--danger-color--100);
+    font-weight: bold;
+}
+
+.karavan .step-element .header-icon {
+    border-color: var(--pf-v5-global--Color--200);
+    border-style: solid;
+    border-radius: 30px;
+    border-width: 1px;
+    background: white;
+    width: 30px;
+    height: 30px;
+    margin: auto;
+    display: flex;
+    justify-content: center;
+    align-items: center;
+}
+
+.karavan .step-element .header .icon,
+.element-builder .header .icon {
+    height: 20px;
+    width: auto;
+    border: none;
+    -webkit-user-select: none;
+    -khtml-user-select: none;
+    -moz-user-select: none;
+    -o-user-select: none;
+    user-select: none;
+}
+
+.karavan .step-element .add-element-button {
+    top: 5px;
+    left: 5px;
+    font-size: 15px;
+    height: 15px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    background: transparent;
+    color: var(--pf-v5-global--primary-color--100);
+    visibility: hidden;
+    z-index: 100;
+    position: absolute;
+}
+
+.karavan .step-element .insert-element-button {
+    position: absolute;
+    top: -8px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0 0 0 -30px;
+    background: transparent;
+    color: var(--pf-v5-global--primary-color--100);
+    visibility: hidden;
+    z-index: 100;
+}
+
+.karavan .step-element .header:hover .insert-element-button {
+    visibility: visible;
+}
+
+.karavan .step-element .add-button-bottom {
+    position: relative;
+}
+
+.karavan .step-element .add-button-left {
+    position: absolute;
+    top: 4px;
+    left: 4px;
+}
+
+.karavan .step-element .add-button {
+    font-size: 15px;
+    height: 15px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0;
+    background: transparent;
+    color: var(--pf-v5-global--primary-color--100);
+    visibility: hidden;
+    z-index: 100;
+}
+
+.disabled {
+    opacity: 0.5;
+}
+.menu-button {
+    position: absolute;
+    top: 26px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0 0 0 10px;
+    background: transparent;
+    color: var(--pf-v5-global--primary-color--100);
+    visibility: hidden;
+}
+
+.dsl-element:hover .menu-button {
+    visibility: visible;
+}
+
+.add-button-icon, .insert-button-icon {
+    fill: var(--pf-v5-global--primary-color--100);
+    width: 20px;
+    height: 20px;
+    background: white;
+}
+
+.delete-button-icon {
+    fill: var(--pf-v5-global--danger-color--100);
+    width: 20px;
+    height: 20px;
+    background: white;
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/DslElement.tsx 
b/karavan-designer/src/designer/route/element/DslElement.tsx
similarity index 79%
rename from karavan-designer/src/designer/route/DslElement.tsx
rename to karavan-designer/src/designer/route/element/DslElement.tsx
index e3dfdbfc..ce780636 100644
--- a/karavan-designer/src/designer/route/DslElement.tsx
+++ b/karavan-designer/src/designer/route/element/DslElement.tsx
@@ -15,27 +15,25 @@
  * limitations under the License.
  */
 import React, {CSSProperties, useMemo, useState} from 'react';
-import {Menu, MenuContent, MenuItem, MenuList, Popover, Text, Tooltip,} from 
'@patternfly/react-core';
-import '../karavan.css';
+import {Text, Tooltip,} from '@patternfly/react-core';
+import '../../karavan.css';
 import './DslElement.css';
-import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
-import DeleteIcon from 
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
-import SyncIcon from "@patternfly/react-icons/dist/js/icons/sync-icon";
-import TurnIcon from 
"@patternfly/react-icons/dist/js/icons/chevron-circle-right-icon";
-import InsertIcon from 
"@patternfly/react-icons/dist/js/icons/arrow-alt-circle-right-icon";
 import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
-import {CamelUi} from "../utils/CamelUi";
-import {EventBus} from "../utils/EventBus";
+import {CamelUi} from "../../utils/CamelUi";
+import {EventBus} from "../../utils/EventBus";
 import {ChildElement, CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
-import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import {useRouteDesignerHook} from "../useRouteDesignerHook";
+import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from 
"./DslElementIcons";
 
 interface Props {
     step: CamelElement,
     parent: CamelElement | undefined,
+    nextStep: CamelElement | undefined,
+    prevStep: CamelElement | undefined,
     inSteps: boolean
     position: number
 }
@@ -43,7 +41,16 @@ interface Props {
 export function DslElement(props: Props) {
 
     const headerRef = React.useRef<HTMLDivElement>(null);
-    const {selectElement, moveElement, onShowDeleteConfirmation, openSelector, 
isKamelet, isSourceKamelet, isActionKamelet} = useRouteDesignerHook();
+    const addButtonRef = React.useRef<HTMLDivElement>(null);
+    const {
+        selectElement,
+        moveElement,
+        onShowDeleteConfirmation,
+        openSelector,
+        isKamelet,
+        isSourceKamelet,
+        isActionKamelet
+    } = useRouteDesignerHook();
 
     const [integration] = useIntegrationStore((s) => [s.integration, 
s.setIntegration], shallow)
 
@@ -98,12 +105,20 @@ export function DslElement(props: Props) {
     }
 
     function hasBorder(): boolean {
-        return (props.step?.hasSteps() && 
!['FromDefinition'].includes(props.step.dslName))
-            || ['RouteConfigurationDefinition',
-                'RouteDefinition',
-                'TryDefinition',
-                'ChoiceDefinition',
-                'SwitchDefinition'].includes(props.step.dslName);
+        const step = props.step;
+        if (['FilterDefinition'].includes(step.dslName)) {
+            return true;
+        }
+        if (['FromDefinition',
+            'RouteDefinition',
+            'TryDefinition',
+            'CatchDefinition', 'FinallyDefinition',
+            'ChoiceDefinition',
+            'SwitchDefinition', 'WhenDefinition', 'OtherwiseDefinition'
+        ].includes(step.dslName)) {
+            return false;
+        }
+        return props.step?.hasSteps();
     }
 
     function isNotDraggable(): boolean {
@@ -177,7 +192,26 @@ export function DslElement(props: Props) {
         return style;
     }
 
+    function sendButtonPosition(el: HTMLButtonElement | null) {
+        const {nextStep, step, parent} = props;
+        let needArrow = !hasBorder() && !['ChoiceDefinition', 
'MulticastDefinition', 'TryDefinition'].includes(step.dslName);
+
+        if (parent
+            && ['TryDefinition'].includes(parent.dslName)
+            && !['CatchDefinition', 
'FinallyDefinition'].includes(step.dslName)) {
+            needArrow = true;
+        }
+
+        if (el && nextStep && needArrow) {
+            const rect = headerRef.current?.getBoundingClientRect();
+
+            if (rect)
+                EventBus.sendButtonPosition("add", step.uuid, nextStep, rect);
+        }
+    }
+
     function sendPosition(el: HTMLDivElement | null) {
+        const {step, prevStep, parent} = props;
         const isSelected = isElementSelected();
         const isHidden = isElementHidden();
         if (el) {
@@ -186,15 +220,14 @@ export function DslElement(props: Props) {
                 const headerIcon: any = 
Array.from(header.childNodes.values()).filter((n: any) => 
n.classList.contains("header-icon"))[0];
                 const headerRect = headerIcon.getBoundingClientRect();
                 const rect = el.getBoundingClientRect();
-                if (props.step.showChildren) {
+                if (step.showChildren) {
                     if (isHidden) {
-                        // EventBus.sendPosition("delete", props.step, 
props.parent, new DOMRect(), new DOMRect(), 0);
-                        EventBus.sendPosition("add", props.step, props.parent, 
rect, headerRect, props.position, props.inSteps, isSelected);
+                        EventBus.sendPosition("add", step, prevStep, parent, 
rect, headerRect, props.position, props.inSteps, isSelected);
                     } else {
-                        EventBus.sendPosition("add", props.step, props.parent, 
rect, headerRect, props.position, props.inSteps, isSelected);
+                        EventBus.sendPosition("add", step, prevStep, parent, 
rect, headerRect, props.position, props.inSteps, isSelected);
                     }
                 } else {
-                    EventBus.sendPosition("delete", props.step, props.parent, 
new DOMRect(), new DOMRect(), 0);
+                    EventBus.sendPosition("delete", step, prevStep, parent, 
new DOMRect(), new DOMRect(), 0);
                 }
             }
         }
@@ -237,7 +270,6 @@ export function DslElement(props: Props) {
                 </div>
                 {showInsertButton && getInsertElementButton()}
                 {getDeleteButton()}
-                {/*{getMenuButton()}*/}
                 {showAddButton && getAddElementButton()}
             </div>
         )
@@ -304,7 +336,7 @@ export function DslElement(props: Props) {
         const step = props.step;
         const isBorder = child.name === 'steps' && hasBorderOverSteps(step);
         const style: CSSProperties = {
-            borderStyle: isBorder ? "dotted" : "none",
+            // borderStyle: isBorder ? "dotted" : "none",
             borderColor: "var(--step-border-color)",
             borderWidth: "1px",
             borderRadius: "16px",
@@ -343,15 +375,25 @@ export function DslElement(props: Props) {
             return (
                 <div className={child.name + " has-child"} 
style={getChildrenElementsStyle(child, notOnlySteps)}
                      key={step.uuid + "-child-" + index}>
-                    {children.map((element, index) => (
-                        <div key={step.uuid + child.className + index}>
-                            <DslElement
-                                inSteps={child.name === 'steps'}
-                                position={index}
-                                step={element}
-                                parent={step}/>
-                        </div>
-                    ))}
+                    {children.map((element, index) => {
+                            let prevStep = children.at(index - 1);
+                            let nextStep = undefined;
+                            if (['TryDefinition', 
'ChoiceDefinition'].includes(step.dslName)) {
+                                nextStep = props.nextStep;
+                            } else {
+                                nextStep = children.at(index + 1);
+                            }
+                            return (<div key={step.uuid + child.className + 
index}>
+                                <DslElement
+                                    inSteps={child.name === 'steps'}
+                                    position={index}
+                                    step={element}
+                                    nextStep={nextStep}
+                                    prevStep={prevStep}
+                                    parent={step}/>
+                            </div>)
+                        }
+                    )}
                     {child.name === 'steps' && getAddStepButton()}
                 </div>
             )
@@ -366,16 +408,23 @@ export function DslElement(props: Props) {
     }
 
     function getAddStepButton() {
-        const {step} = props;
+        const {step, nextStep} = props;
         const hideAddButton = step.dslName === 'StepDefinition' && 
!CamelDisplayUtil.isStepDefinitionExpanded(integration, step.uuid, 
selectedUuids.at(0));
         if (hideAddButton) return (<></>)
         else return (
             <Tooltip position={"bottom"}
-                     content={<div>{"Add step to " + 
CamelDisplayUtil.getTitle(step)}</div>}>
-                <button type="button" aria-label="Add" onClick={e => 
onOpenSelector(e)}
-                        className={isAddStepButtonLeft() ? "add-button 
add-button-left" : "add-button add-button-bottom"}>
-                    <AddIcon/>
-                </button>
+                     content={<div>{nextStep?.dslName.replace("Definition", 
"")}</div>}
+                // content={<div>{"Add step to " + 
CamelDisplayUtil.getTitle(step)}</div>}
+            >
+                <div ref={addButtonRef}>
+                    <button type="button"
+                            ref={el => sendButtonPosition(el)}
+                            aria-label="Add"
+                            onClick={e => onOpenSelector(e)}
+                            className={isAddStepButtonLeft() ? "add-button 
add-button-left" : "add-button add-button-bottom"}>
+                        <AddElementIcon/>
+                    </button>
+                </div>
             </Tooltip>
         )
     }
@@ -389,7 +438,7 @@ export function DslElement(props: Props) {
                     aria-label="Add"
                     onClick={e => onOpenSelector(e, false)}
                     className={"add-element-button"}>
-                    <AddIcon/>
+                    <AddElementIcon/>
                 </button>
             </Tooltip>
         )
@@ -398,8 +447,11 @@ export function DslElement(props: Props) {
     function getInsertElementButton() {
         return (
             <Tooltip position={"left"} content={<div>{"Insert element 
before"}</div>}>
-                <button type="button" aria-label="Insert" onClick={e => 
onOpenSelector(e, true, true)}
-                        className={"insert-element-button"}><InsertIcon/>
+                <button type="button"
+                        aria-label="Insert"
+                        onClick={e => onOpenSelector(e, true, true)}
+                        className={"insert-element-button"}>
+                    <InsertElementIcon/>
                 </button>
             </Tooltip>
         )
@@ -409,39 +461,12 @@ export function DslElement(props: Props) {
         return (
             <Tooltip position={"right"} content={<div>{"Delete 
element"}</div>}>
                 <button type="button" aria-label="Delete" onClick={e => 
onDeleteElement(e)} className="delete-button">
-                    <DeleteIcon/>
+                    <DeleteElementIcon/>
                 </button>
             </Tooltip>
         )
     }
 
-    function getMenuButton() {
-        return (
-            <Popover
-                aria-label="Convert Popover"
-                hasNoPadding
-                position={"right"}
-                hideOnOutsideClick={true}
-                showClose={false}
-                bodyContent={
-                    <Menu activeItemId={''} onSelect={event => {}} isPlain>
-                        <MenuContent>
-                            <MenuList>
-                                <MenuItem itemId={0} icon={<SyncIcon 
aria-hidden />}>Convert to SetHeader</MenuItem>
-                                {/*<MenuItem itemId={1}>Action</MenuItem>*/}
-                                {/*<MenuItem itemId={2}>Action</MenuItem>*/}
-                            </MenuList>
-                        </MenuContent>
-                    </Menu>
-                }
-            >
-                <button type="button" aria-label="Menu" onClick={e => {}} 
className="menu-button">
-                    <TurnIcon/>
-                </button>
-            </Popover>
-        )
-    }
-
     const element: CamelElement = props.step;
     const className = "step-element"
         + (isElementSelected() ? " step-element-selected" : "") + 
(!props.step.showChildren ? " hidden-step" : "")
@@ -451,7 +476,7 @@ export function DslElement(props: Props) {
              className={className}
              ref={el => sendPosition(el)}
              style={{
-                 borderStyle: hasBorder() ? "dotted" : "none",
+                 borderStyle: hasBorder() ? "dashed" : "none",
                  borderColor: isElementSelected() ? 
"var(--step-border-color-selected)" : "var(--step-border-color)",
                  marginTop: isInStepWithChildren() ? "16px" : "8px",
                  zIndex: element.dslName === 'ToDefinition' ? 20 : 10,
diff --git a/karavan-designer/src/designer/route/element/DslElementIcons.tsx 
b/karavan-designer/src/designer/route/element/DslElementIcons.tsx
new file mode 100644
index 00000000..3b6b984b
--- /dev/null
+++ b/karavan-designer/src/designer/route/element/DslElementIcons.tsx
@@ -0,0 +1,80 @@
+/*
+ * 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 "./DslElement.css"
+
+export function DeleteElementIcon() {
+    return (
+        <svg
+            xmlns="http://www.w3.org/2000/svg";
+            xmlSpace="preserve"
+            viewBox="0 0 32 32"
+            className="delete-button-icon"
+        >
+            <path d="M16 2C8.2 2 2 8.2 2 16s6.2 14 14 14 14-6.2 14-14S23.8 2 
16 2zm0 26C9.4 28 4 22.6 4 16S9.4 4 16 4s12 5.4 12 12-5.4 12-12 12z" />
+            <path
+                d="M0 0h32v32H0z"
+                style={{
+                    fill: "none",
+                }}
+            />
+            <path d="M21.4 23 16 17.6 10.6 23 9 21.4l5.4-5.4L9 10.6 10.6 9l5.4 
5.4L21.4 9l1.6 1.6-5.4 5.4 5.4 5.4z" />
+        </svg>
+    )
+}
+
+export function AddElementIcon() {
+    return (
+        <svg
+            xmlns="http://www.w3.org/2000/svg";
+            xmlSpace="preserve"
+            viewBox="0 0 32 32"
+            className="add-button-icon"
+        >
+            <path
+                d="M16 4c6.6 0 12 5.4 12 12s-5.4 12-12 12S4 22.6 4 16 9.4 4 16 
4m0-2C8.3 2 2 8.3 2 16s6.3 14 14 14 14-6.3 14-14S23.7 2 16 2z"/>
+            <path d="M24 15h-7V8h-2v7H8v2h7v7h2v-7h7z"/>
+            <path
+                d="M0 0h32v32H0z"
+                style={{
+                    fill: "none",
+                }}
+            />
+        </svg>
+    )
+}
+
+export function InsertElementIcon() {
+    return (
+        <svg
+            xmlns="http://www.w3.org/2000/svg";
+            xmlSpace="preserve"
+            viewBox="0 0 32 32"
+            className="insert-button-icon"
+        >
+            <path d="m16 8-1.43 1.393L20.15 15H8v2h12.15l-5.58 5.573L16 
24l8-8-8-8z" />
+            <path d="M16 30a14 14 0 1 1 14-14 14.016 14.016 0 0 1-14 
14Zm0-26a12 12 0 1 0 12 12A12.014 12.014 0 0 0 16 4Z" />
+            <path
+                d="M0 0h32v32H0z"
+                data-name="&lt;Transparent Rectangle&gt;"
+                style={{
+                    fill: "none",
+                }}
+            />
+        </svg>
+    )
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/route/DslElementMoveModal.tsx 
b/karavan-designer/src/designer/route/element/DslElementMoveModal.tsx
similarity index 94%
rename from karavan-designer/src/designer/route/DslElementMoveModal.tsx
rename to karavan-designer/src/designer/route/element/DslElementMoveModal.tsx
index d1e17ecf..75d4f58f 100644
--- a/karavan-designer/src/designer/route/DslElementMoveModal.tsx
+++ b/karavan-designer/src/designer/route/element/DslElementMoveModal.tsx
@@ -20,10 +20,10 @@ import {
     Flex,
     Modal, ModalVariant,
 } from '@patternfly/react-core';
-import '../karavan.css';
-import {useDesignerStore, useIntegrationStore} from "../DesignerStore";
+import '../../karavan.css';
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
-import {useRouteDesignerHook} from "./useRouteDesignerHook";
+import {useRouteDesignerHook} from "../useRouteDesignerHook";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 
 export function DslElementMoveModal() {
diff --git a/karavan-designer/src/designer/route/usePropertiesHook.tsx 
b/karavan-designer/src/designer/route/usePropertiesHook.tsx
index 87513b18..a9bd9ef9 100644
--- a/karavan-designer/src/designer/route/usePropertiesHook.tsx
+++ b/karavan-designer/src/designer/route/usePropertiesHook.tsx
@@ -126,5 +126,14 @@ export function usePropertiesHook (isRouteDesigner: 
boolean = true) {
         // TODO:
     }
 
-    return {cloneElement, onPropertyChange, onParametersChange, 
onDataFormatChange, onExpressionChange, getInternalComponentName}
+    const convertStep = (step: CamelElement, targetDslName: string ) => {
+        // const clone = CamelUtil.cloneIntegration(integration);
+        // const i = CamelDefinitionApiExt.addStepToIntegration(clone, step, 
parentId, position);
+        // const selectedStep = step.dslName === 'RouteDefinition' ? (step as 
RouteDefinition).from  : step;
+        // setIntegration(i, false);
+        // setSelectedStep(selectedStep);
+        // setSelectedUuids([selectedStep.uuid]);
+    }
+
+    return {convertStep, cloneElement, onPropertyChange, onParametersChange, 
onDataFormatChange, onExpressionChange, getInternalComponentName}
 }
\ 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 f48fc850..b65966a0 100644
--- a/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
+++ b/karavan-designer/src/designer/route/useRouteDesignerHook.tsx
@@ -105,7 +105,8 @@ export function useRouteDesignerHook () {
     }
 
     const deleteElement = () =>  {
-        EventBus.sendPosition("clean", new CamelElement(""), undefined, new 
DOMRect(), new DOMRect(), 0);
+        EventBus.sendPosition("clean", new CamelElement(""), undefined, 
undefined, new DOMRect(), new DOMRect(), 0);
+        EventBus.sendButtonPosition("clean", '',  new CamelElement(""), new 
DOMRect());
         let i = integration;
         selectedUuids.forEach(uuidToDelete => {
              i = CamelDefinitionApiExt.deleteStepFromIntegration(i, 
uuidToDelete);
diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx 
b/karavan-designer/src/designer/utils/CamelUi.tsx
index ec4d5796..83476b1b 100644
--- a/karavan-designer/src/designer/utils/CamelUi.tsx
+++ b/karavan-designer/src/designer/utils/CamelUi.tsx
@@ -166,8 +166,17 @@ export class RouteToCreate {
 const INTEGRATION_PATTERNS = 'Integration Patterns';
 const connectorNavs = ['routing', "transformation", "error", "configuration", 
"endpoint", "kamelet", "component"];
 
+const stepConvertMap = new Map<string, string>([
+    ["SetBodyDefinition", "SetHeaderDefinition"],
+    ["SetHeaderDefinition", "SetBodyDefinition"],
+]);
+
 export class CamelUi {
 
+    static getConvertTargetDsl = (sourceDsl?: string): string | undefined => {
+        return sourceDsl ? stepConvertMap.get(sourceDsl) : undefined;
+    }
+
     static createNewInternalRoute = (uri: string): RouteToCreate | undefined 
=> {
         const uris = uri.toString().split(":");
         const componentName = uris[0];
diff --git a/karavan-designer/src/designer/utils/EventBus.ts 
b/karavan-designer/src/designer/utils/EventBus.ts
index 0a20d3c6..55906f0f 100644
--- a/karavan-designer/src/designer/utils/EventBus.ts
+++ b/karavan-designer/src/designer/utils/EventBus.ts
@@ -18,10 +18,26 @@ import {Subject} from 'rxjs';
 import {CamelElement, Integration} from 
"karavan-core/lib/model/IntegrationDefinition";
 import {v4 as uuidv4} from "uuid";
 
-const positions = new Subject<DslPosition>();
+export class ButtonPosition {
+    uuid: string = '';
+    nextstep: CamelElement = new CamelElement("");
+    rect: DOMRect = new DOMRect();
+    command: "add" | "delete" | "clean" = "add";
+
+    constructor(command: "add" | "delete" | "clean",
+                uuid: string,
+                nextstep: CamelElement,
+                rect: DOMRect) {
+        this.uuid = uuid;
+        this.command = command;
+        this.nextstep = nextstep;
+        this.rect = rect;
+    }
+}
 
 export class DslPosition {
     step: CamelElement = new CamelElement("");
+    prevStep: CamelElement | undefined;
     parent: CamelElement | undefined;
     inSteps: boolean = false;
     isSelected: boolean = false;
@@ -32,6 +48,7 @@ export class DslPosition {
 
     constructor(command: "add" | "delete" | "clean",
                 step: CamelElement,
+                prevStep: CamelElement | undefined,
                 parent:CamelElement | undefined,
                 rect: DOMRect,
                 headerRect:DOMRect,
@@ -40,6 +57,7 @@ export class DslPosition {
                 isSelected: boolean = false) {
         this.command = command;
         this.step = step;
+        this.prevStep = prevStep;
         this.parent = parent;
         this.rect = rect;
         this.headerRect = headerRect;
@@ -85,17 +103,25 @@ export class ToastMessage {
         this.variant = variant;
     }
 }
+const dslPositions = new Subject<DslPosition>();
+const buttonPositions = new Subject<ButtonPosition>();
 
 export const EventBus = {
     sendPosition: (command: "add" | "delete" | "clean",
                    step: CamelElement,
+                   prevStep: CamelElement | undefined,
                    parent: CamelElement | undefined,
                    rect: DOMRect,
                    headerRect: DOMRect,
                    position: number,
                    inSteps: boolean = false,
-                   isSelected: boolean = false) => positions.next(new 
DslPosition(command, step, parent, rect, headerRect, position, inSteps, 
isSelected)),
-    onPosition: () => positions.asObservable(),
+                   isSelected: boolean = false) => dslPositions.next(new 
DslPosition(command, step, prevStep, parent, rect, headerRect, position, 
inSteps, isSelected)),
+    onPosition: () => dslPositions.asObservable(),
+
+    sendButtonPosition: (command: "add" | "delete" | "clean", uuid: string,
+                   nextStep: CamelElement,
+                   rect: DOMRect) => buttonPositions.next(new 
ButtonPosition(command, uuid, nextStep, rect)),
+    onButtonPosition: () => buttonPositions.asObservable(),
 
     sendIntegrationUpdate: (i: Integration, propertyOnly: boolean) => 
updates.next(new IntegrationUpdate(i, propertyOnly)),
     onIntegrationUpdate: () => updates.asObservable(),

Reply via email to