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


The following commit(s) were added to refs/heads/main by this push:
     new b1bf31b  Beans config (#181)
b1bf31b is described below

commit b1bf31b5888b667dc0bb49b9c1855a8822d96536
Author: Marat Gubaidullin <[email protected]>
AuthorDate: Thu Feb 10 16:21:48 2022 -0500

    Beans config (#181)
    
    * Support bean in Core
    
    * Beans gallery
    
    * Beans editor
    
    * Bean config UI
    
    * Bump version to 0.0.12
---
 karavan-app/pom.xml                                |   2 +-
 karavan-app/src/main/webapp/package.json           |   2 +-
 .../webapp/src/integrations/IntegrationCard.tsx    |   2 +-
 .../webapp/src/integrations/IntegrationPage.tsx    |   2 +-
 .../src/main/webapp/src/kamelets/KameletCard.tsx   |   2 +-
 karavan-core/src/core/api/CamelDefinitionApiExt.ts |  67 ++++-
 karavan-core/src/core/api/CamelDefinitionYaml.ts   |  46 ++-
 karavan-core/src/core/api/CamelUtil.ts             |  21 +-
 karavan-core/src/core/model/CamelDefinition.ts     |  20 ++
 karavan-core/test/addStep.spec.ts                  |   1 -
 karavan-core/test/beans.spec.ts                    |  56 ++++
 karavan-core/test/beans1.yaml                      |  36 +++
 karavan-core/test/beans2.yaml                      |  42 +++
 karavan-demo/http-to-kafka.yaml                    |  35 +++
 karavan-designer/package-lock.json                 |   4 +-
 karavan-designer/package.json                      |   2 +-
 karavan-designer/src/App.tsx                       |  62 ++--
 karavan-designer/src/designer/KaravanDesigner.tsx  | 314 +++++----------------
 .../src/designer/beans/BeanProperties.tsx          | 157 +++++++++++
 .../src/designer/beans/BeansDesigner.tsx           | 183 ++++++++++++
 .../src/designer/error/ErrorDesigner.tsx           |  74 +++++
 .../src/designer/exception/ExceptionDesigner.tsx   |  74 +++++
 .../src/designer/field/DataFormatField.tsx         |   1 -
 .../src/designer/field/DslPropertyField.tsx        |   2 +-
 .../src/designer/field/ExpressionField.tsx         |   2 +-
 karavan-designer/src/designer/karavan.css          | 251 ++++++++++++----
 .../src/designer/rest/RestDesigner.tsx             |  74 +++++
 .../src/designer/{ => route}/DslConnections.tsx    |   6 +-
 .../src/designer/{ => route}/DslElement.tsx        |   6 +-
 .../src/designer/{ => route}/DslProperties.tsx     |  31 +-
 .../src/designer/{ => route}/DslSelector.tsx       |   6 +-
 .../RouteDesigner.tsx}                             | 129 ++-------
 .../src/designer/templates/TemplatesDesigner.tsx   |  74 +++++
 .../src/designer/{ => utils}/CamelUi.ts            |  36 ++-
 .../src/designer/utils}/DslMetaModel.ts            |   0
 .../src/designer/{ => utils}/EventBus.ts           |   0
 .../src/designer/utils/KaravanComponents.tsx       |  45 +++
 .../src/designer/utils/KaravanIcons.tsx            |  51 ++++
 karavan-generator/pom.xml                          |   2 +-
 .../src/main/resources/CamelDefinition.header.ts   |  21 +-
 karavan-vscode/package.json                        |  12 +-
 karavan-vscode/webview/App.tsx                     |   2 +-
 karavan-vscode/webview/index.css                   |  79 +++++-
 43 files changed, 1504 insertions(+), 530 deletions(-)

diff --git a/karavan-app/pom.xml b/karavan-app/pom.xml
index d305aa8..63c03e8 100644
--- a/karavan-app/pom.xml
+++ b/karavan-app/pom.xml
@@ -18,7 +18,7 @@
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance";>
     <modelVersion>4.0.0</modelVersion>
         <groupId>org.apache.camel.karavan</groupId>
-        <version>0.0.11</version>
+        <version>0.0.12</version>
     <artifactId>karavan</artifactId>
     <properties>
         <compiler-plugin.version>3.8.1</compiler-plugin.version>
diff --git a/karavan-app/src/main/webapp/package.json 
b/karavan-app/src/main/webapp/package.json
index 98bcc76..5f5ecef 100644
--- a/karavan-app/src/main/webapp/package.json
+++ b/karavan-app/src/main/webapp/package.json
@@ -1,6 +1,6 @@
 {
   "name": "karavan",
-  "version": "0.0.11",
+  "version": "0.0.12",
   "private": true,
   "dependencies": {
     "@patternfly/patternfly": "^4.171.1",
diff --git a/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx 
b/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
index db25be9..7402caf 100644
--- a/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
+++ b/karavan-app/src/main/webapp/src/integrations/IntegrationCard.tsx
@@ -4,7 +4,7 @@ import {
 } from '@patternfly/react-core';
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
 import '../designer/karavan.css';
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
 
 interface Props {
     name: string,
diff --git a/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx 
b/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
index 328c6ae..d9b62a6 100644
--- a/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
+++ b/karavan-app/src/main/webapp/src/integrations/IntegrationPage.tsx
@@ -16,7 +16,7 @@ import {MainToolbar} from "../MainToolbar";
 import RefreshIcon from '@patternfly/react-icons/dist/esm/icons/sync-alt-icon';
 import PlusIcon from '@patternfly/react-icons/dist/esm/icons/plus-icon';
 import {Integration} from "karavan-core/lib/model/CamelDefinition";
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
 
 interface Props {
     integrations: Map<string,string>
diff --git a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx 
b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
index 80e56a4..8a9cd75 100644
--- a/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
+++ b/karavan-app/src/main/webapp/src/kamelets/KameletCard.tsx
@@ -4,7 +4,7 @@ import {
 } from '@patternfly/react-core';
 import '../designer/karavan.css';
 import {KameletModel} from "karavan-core/lib/model/KameletModels";
-import {CamelUi} from "../designer/CamelUi";
+import {CamelUi} from "../designer/utils/CamelUi";
 
 interface Props {
     kamelet: KameletModel,
diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts 
b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 02b03c5..1197f73 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -18,6 +18,7 @@ import {CamelMetadataApi, ElementMeta, Languages, 
PropertyMeta} from "../model/C
 import {ComponentApi} from "./ComponentApi";
 import {CamelUtil} from "./CamelUtil";
 import {
+    Bean, Beans,
     CamelElement, CamelElementMeta,
     ExpressionDefinition,
     Integration, RouteDefinition
@@ -54,8 +55,8 @@ export class CamelDefinitionApiExt {
         let added = false;
         // Check all fields except steps
         children.filter(child => child.name !== 'steps').forEach(child => {
-            if (result.uuid === parentId){
-                if (child.className === stepAdded.dslName){
+            if (result.uuid === parentId) {
+                if (child.className === stepAdded.dslName) {
                     added = true;
                     if (child.multiple) (result as 
any)[child.name].push(stepAdded)
                     else (result as any)[child.name] = stepAdded;
@@ -68,7 +69,7 @@ export class CamelDefinitionApiExt {
         });
         // Then steps
         const steps = children.filter(child => child.name === 'steps');
-        if (!added && steps && result.uuid === parentId){
+        if (!added && steps && result.uuid === parentId) {
             (result as any).steps.push(stepAdded);
         } else if (!added && steps && (result as any).steps) {
             (result as any).steps = 
CamelDefinitionApiExt.addStepToSteps((result as any).steps, stepAdded, 
parentId, position);
@@ -92,7 +93,7 @@ export class CamelDefinitionApiExt {
 
     static findStep = (steps: CamelElement[] | undefined, uuid: string, 
result: CamelElementMeta = new CamelElementMeta(undefined, undefined, 
undefined, []), parentUuid?: string): CamelElementMeta => {
         if (result?.step !== undefined) return result;
-        if (steps !== undefined){
+        if (steps !== undefined) {
             for (let index = 0, step: CamelElement; step = steps[index]; 
index++) {
                 if (step.uuid === uuid) {
                     const p = [...result.pathUuids];
@@ -141,8 +142,11 @@ export class CamelDefinitionApiExt {
     }
 
     static deleteStepFromIntegration = (integration: Integration, 
uuidToDelete: string): Integration => {
-        const flows = 
CamelDefinitionApiExt.deleteStepFromSteps(integration.spec.flows, uuidToDelete);
-        integration.spec.flows = flows as RouteDefinition[];
+        const flows: any[] = [];
+        integration.spec.flows?.filter(flow => flow.dslName === 
'Beans').forEach(bean => flows.push(bean));
+        const routes = 
CamelDefinitionApiExt.deleteStepFromSteps(integration.spec.flows?.filter(flow 
=> flow.dslName === 'RouteDefinition'), uuidToDelete);
+        flows.push(...routes);
+        integration.spec.flows = flows;
         return integration;
     }
 
@@ -151,7 +155,7 @@ export class CamelDefinitionApiExt {
         const ce = 
CamelDefinitionApiExt.getElementChildrenDefinition(step.dslName);
         ce.forEach(e => {
             const cel = CamelDefinitionApiExt.getElementChildren(step, e);
-            if (e.multiple){
+            if (e.multiple) {
                 (result as any)[e.name] = 
CamelDefinitionApiExt.deleteStepFromSteps((result as any)[e.name], 
uuidToDelete);
             } else {
                 const prop = (result as any)[e.name];
@@ -169,7 +173,7 @@ export class CamelDefinitionApiExt {
 
     static deleteStepFromSteps = (steps: CamelElement[] | undefined, 
uuidToDelete: string): CamelElement[] => {
         const result: CamelElement[] = []
-        if (steps !== undefined){
+        if (steps !== undefined) {
             steps.forEach(step => {
                 if (step.uuid !== uuidToDelete) {
                     step = CamelDefinitionApiExt.deleteStepFromStep(step, 
uuidToDelete);
@@ -180,6 +184,47 @@ export class CamelDefinitionApiExt {
         return result
     }
 
+    static addBeanToIntegration = (integration: Integration, bean: Bean): 
Integration => {
+        const flows: any[] = [];
+        if (integration.spec.flows?.filter(flow => flow.dslName === 
'Beans').length === 0) {
+            flows.push(...integration.spec.flows);
+            flows.push(new Beans({beans: [bean]}))
+        } else {
+            flows.push(...integration.spec.flows?.filter(flow => flow.dslName 
!== 'Beans') || []);
+            integration.spec.flows?.filter(flow => flow.dslName === 
'Beans').forEach(flow => {
+                const beans: Bean[] = [];
+                if ((flow as Beans).beans.filter(b => b.uuid === 
bean.uuid).length === 0){
+                    beans.push(...(flow as Beans).beans.filter(b => b.uuid !== 
bean.uuid));
+                    beans.push(bean);
+                } else {
+                    (flow as Beans).beans.forEach(b => {
+                        if (b.uuid === bean.uuid) beans.push(bean)
+                        else beans.push(b);
+                    })
+                }
+                const newBeans = new Beans({beans: beans});
+                flows.push(newBeans);
+            })
+        }
+        integration.spec.flows = flows;
+        return integration;
+    }
+
+    static deleteBeanFromIntegration = (integration: Integration, bean?: 
Bean): Integration => {
+        const flows: any[] = [];
+        integration.spec.flows?.forEach(flow => {
+            if (flow.dslName === 'Beans') {
+                const beans = (flow as Beans).beans.filter(b => !(b.uuid === 
bean?.uuid && b.type === bean?.type));
+                const newBeans = new Beans({beans: beans});
+                flows.push(newBeans);
+            } else {
+                flows.push(flow);
+            }
+        })
+        integration.spec.flows = flows;
+        return integration;
+    }
+
     static getExpressionLanguageName = (expression: ExpressionDefinition | 
undefined): string | undefined => {
         let result: string | undefined = undefined;
         if (expression) {
@@ -304,15 +349,15 @@ export class CamelDefinitionApiExt {
 
     static getElementPropertiesByName = (name: string): PropertyMeta[] => {
         const model = CamelMetadataApi.getCamelModelMetadataByName(name);
-        if (model){
+        if (model) {
             return this.getElementProperties(model.className);
         }
         const language = CamelMetadataApi.getCamelLanguageMetadataByName(name);
-        if (language){
+        if (language) {
             return this.getElementProperties(language.className);
         }
         const dataFormat = 
CamelMetadataApi.getCamelDataFormatMetadataByName(name);
-        if (dataFormat){
+        if (dataFormat) {
             return this.getElementProperties(dataFormat.className);
         }
         return [];
diff --git a/karavan-core/src/core/api/CamelDefinitionYaml.ts 
b/karavan-core/src/core/api/CamelDefinitionYaml.ts
index 3e022c5..0587dc0 100644
--- a/karavan-core/src/core/api/CamelDefinitionYaml.ts
+++ b/karavan-core/src/core/api/CamelDefinitionYaml.ts
@@ -17,7 +17,7 @@
 import * as yaml from 'js-yaml';
 import {
     Integration,
-    CamelElement, RouteDefinition,
+    CamelElement, RouteDefinition, Bean, Beans,
 } from "../model/CamelDefinition";
 import {CamelUtil} from "./CamelUtil";
 import {CamelDefinitionYamlStep} from "./CamelDefinitionYamlStep";
@@ -27,7 +27,7 @@ export class CamelDefinitionYaml {
     static integrationToYaml = (integration: Integration): string => {
         const clone: any = Object.assign({}, integration);
         const flows = integration.spec.flows
-        clone.spec.flows = flows?.map((f: any) => 
CamelDefinitionYaml.cleanupElement(f));
+        clone.spec.flows = flows?.map((f: any) => 
CamelDefinitionYaml.cleanupElement(f)).filter(x => Object.keys(x).length !== 0);
         if (integration.crd) {
             delete clone.crd
             const i = JSON.parse(JSON.stringify(clone, null, 3)); // fix 
undefined in string attributes
@@ -48,6 +48,8 @@ export class CamelDefinitionYaml {
             delete object.expressionName;
         } else if (object.dslName.endsWith('DataFormat')) {
             delete object.dataFormatName;
+        } else if (object.dslName = 'Bean') {
+            if (object.properties && Object.keys(object.properties).length === 
0) delete object.properties;
         }
         delete object.uuid;
         delete object.dslName;
@@ -122,14 +124,50 @@ export class CamelDefinitionYaml {
         return i;
     }
 
-    static flowsToCamelElements = (flows: any[]): CamelElement[] => {
-        const result:CamelElement[] = [];
+    static flowsToCamelElements = (flows: any[]): any[] => {
+        const result: any[] = [];
         flows.filter((e: any) => e.hasOwnProperty('route'))
             .forEach((f: any) =>
                 
result.push(CamelDefinitionYamlStep.readRouteDefinition(f.route)));
         flows.filter((e: any) => e.hasOwnProperty('from'))
             .forEach((f: any) =>
                 result.push(CamelDefinitionYamlStep.readRouteDefinition(new 
RouteDefinition({from: f.from}))));
+        flows.filter((e: any) => e.hasOwnProperty('beans'))
+            .forEach((b: any) => 
result.push(CamelDefinitionYaml.readBeanDefinition(b)));
         return result;
     }
+
+    static readBeanDefinition = (beans: any): Beans => {
+        const result: Beans = new Beans();
+        beans.beans.forEach((b: any) => {
+            const props: any = {}
+            if (b && b.properties){
+                // convert map style to properties if requires
+                Object.keys(b.properties).forEach( key => {
+                    const value = b.properties[key];
+                    CamelDefinitionYaml.flatMapProperty(key, value, new 
Map<string, any>())
+                        .forEach((v, k) => props[k] = v);
+                })
+            }
+            b.properties = props;
+            result.beans.push(new Bean(b))
+        })
+        return result;
+    }
+
+    // convert map style to properties if requires
+    static flatMapProperty = (key: string, value: any, properties: Map<string, 
any>): Map<string, any> => {
+        if (value === undefined) {
+        } else if (typeof value === 'object') {
+            Object.keys(value).forEach(k => {
+                const key2 = key + "." + k;
+                const value2: any = value[k];
+                CamelDefinitionYaml.flatMapProperty(key2, value2, new 
Map<string, any>())
+                    .forEach((value1, key1) => properties.set(key1, value1));
+            })
+        } else {
+            properties.set(key, value);
+        }
+        return properties;
+    }
 }
diff --git a/karavan-core/src/core/api/CamelUtil.ts 
b/karavan-core/src/core/api/CamelUtil.ts
index 3beec6f..484c7fb 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -16,7 +16,7 @@
  */
 import {
     Integration,
-    CamelElement,
+    CamelElement, Bean, Beans,
 } from "../model/CamelDefinition";
 import {CamelDefinitionApi} from "./CamelDefinitionApi";
 
@@ -25,7 +25,15 @@ export class CamelUtil {
     static cloneIntegration = (integration: Integration): Integration => {
         const clone = JSON.parse(JSON.stringify(integration));
         const int: Integration = new Integration({...clone});
-        const flows = int.spec.flows?.map(f => 
CamelDefinitionApi.createStep(f.dslName, f));
+        const flows: any[] = [];
+        int.spec.flows?.filter((e: any) => e.dslName === 'RouteDefinition')
+            .forEach(f => flows.push(CamelDefinitionApi.createStep(f.dslName, 
f)));
+        int.spec.flows?.filter((e: any) => e.dslName === 'Beans')
+            .forEach(beans => {
+                const newBeans = new Beans();
+                (beans as Beans).beans.forEach(b => 
newBeans.beans.push(CamelUtil.cloneBean(b)));
+                flows.push(newBeans);
+            });
         int.spec.flows = flows;
         return int;
     }
@@ -35,7 +43,14 @@ export class CamelUtil {
         return CamelDefinitionApi.createStep(step.dslName, clone, true);
     }
 
-    static replacer =  (key:string, value:any): any=> {
+    static cloneBean = (bean: Bean): Bean => {
+        const clone = JSON.parse(JSON.stringify(bean));
+        const newBean = new Bean(clone);
+        newBean.uuid = bean.uuid;
+        return newBean;
+    }
+
+    static replacer = (key:string, value:any): any => {
         if (typeof value == 'object' && (value.hasOwnProperty('stepName') || 
value.hasOwnProperty('step-name'))) {
             const stepNameField = value.hasOwnProperty('stepName') ? 
'stepName' : 'step-name';
             const stepName = value[stepNameField];
diff --git a/karavan-core/src/core/model/CamelDefinition.ts 
b/karavan-core/src/core/model/CamelDefinition.ts
index 107c9f5..6e22563 100644
--- a/karavan-core/src/core/model/CamelDefinition.ts
+++ b/karavan-core/src/core/model/CamelDefinition.ts
@@ -53,6 +53,26 @@ export class CamelElement {
     }
 }
 
+export class Beans extends CamelElement {
+    beans: Bean[] = []
+
+    public constructor(init?: Partial<Beans>) {
+        super("Beans")
+        Object.assign(this, init);
+    }
+}
+
+export class Bean extends CamelElement {
+    name: string = ''
+    type: string = ''
+    properties: any
+
+    public constructor(init?: Partial<Bean>) {
+        super("Bean")
+        Object.assign(this, init);
+    }
+}
+
 export class CamelElementMeta {
     step?: CamelElement
     parentUuid?: string
diff --git a/karavan-core/test/addStep.spec.ts 
b/karavan-core/test/addStep.spec.ts
index d59a5da..e8c4552 100644
--- a/karavan-core/test/addStep.spec.ts
+++ b/karavan-core/test/addStep.spec.ts
@@ -92,7 +92,6 @@ describe('Add Step', () => {
             const i2 = CamelDefinitionApiExt.addStepToIntegration(i1, w, 
parentUuid);
 
             if (i2.spec.flows) {
-                console.log(CamelDefinitionYaml.integrationToYaml(i2));
                 
expect(i2.spec.flows[0].from.steps[0].doCatch[0].onWhen.expression.simple.expression).to.equal("${body}
 != null");
             }
         }
diff --git a/karavan-core/test/beans.spec.ts b/karavan-core/test/beans.spec.ts
new file mode 100644
index 0000000..42f593d
--- /dev/null
+++ b/karavan-core/test/beans.spec.ts
@@ -0,0 +1,56 @@
+/*
+ * 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 {expect} from 'chai';
+import * as fs from 'fs';
+import 'mocha';
+import {CamelDefinitionYaml} from "../src/core/api/CamelDefinitionYaml";
+import {CamelDefinitionYamlStep} from 
"../src/core/api/CamelDefinitionYamlStep";
+import {RouteDefinition} from "../src/core/model/CamelDefinition";
+
+describe('bean configuration', () => {
+
+    it('Read beans from plain YAML', () => {
+        const yaml = fs.readFileSync('test/beans1.yaml',{encoding:'utf8', 
flag:'r'});
+        const i = CamelDefinitionYaml.yamlToIntegration("beans.yaml", yaml);
+        expect(i.metadata.name).to.equal('beans.yaml');
+        expect(i.kind).to.equal('Integration');
+        expect(i.spec.flows?.length).to.equal(3);
+        expect(i.crd).to.equal(false);
+        if (i.spec.flows) {
+            expect(i.spec.flows[2].beans[0].name).to.equal('myNested');
+            
expect(i.spec.flows[2].beans[0].type).to.equal('${MyBean.class.name}');
+            
expect(i.spec.flows[2].beans[0].properties['nested.foo']).to.equal('valueFoo');
+            expect(i.spec.flows[2].beans[1].name).to.equal('myProps');
+        }
+    });
+
+    it('Read beans from Integration', () => {
+        const yaml = fs.readFileSync('test/beans2.yaml',{encoding:'utf8', 
flag:'r'});
+        const i = CamelDefinitionYaml.yamlToIntegration("beans.yaml", yaml);
+        expect(i.metadata.name).to.equal('beans.yaml');
+        expect(i.kind).to.equal('Integration');
+        expect(i.spec.flows?.length).to.equal(3);
+        expect(i.crd).to.equal(true);
+        if (i.spec.flows) {
+            expect(i.spec.flows[2].beans[0].name).to.equal('myNested');
+            
expect(i.spec.flows[2].beans[0].type).to.equal('${MyBean.class.name}');
+            
expect(i.spec.flows[2].beans[0].properties['nested.foo']).to.equal('valueFoo');
+            expect(i.spec.flows[2].beans[1].name).to.equal('myProps');
+        }
+    });
+
+});
diff --git a/karavan-core/test/beans1.yaml b/karavan-core/test/beans1.yaml
new file mode 100644
index 0000000..fbe81fc
--- /dev/null
+++ b/karavan-core/test/beans1.yaml
@@ -0,0 +1,36 @@
+- beans:
+    - name: myNested
+      type: ${MyBean.class.name}
+      properties:
+        field1: 'value1'
+        field2: 'value2'
+        nested:
+          foo: 'valueFoo'
+          bar: 'valueBar'
+    - name: myProps
+      type: ${MyBean.class.name}
+      properties:
+        field1: 'f1_p'
+        field2: 'f2_p'
+        nested.foo: 'nf1_p'
+        nested.bar: 'nf2_p'
+- from:
+    uri: "direct:route"
+    steps:
+      - aggregate:
+          strategy-ref: "myAggregatorStrategy"
+          completion-size: 2
+          correlation-expression:
+            simple: "${header.StockSymbol}"
+          steps:
+            - to: "mock:route"
+- from:
+    uri: "direct:route"
+    steps:
+      - aggregate:
+          strategy-ref: "myAggregatorStrategy"
+          completion-size: 2
+          correlation-expression:
+            simple: "${header.StockSymbol}"
+          steps:
+            - to: "mock:route"
\ No newline at end of file
diff --git a/karavan-core/test/beans2.yaml b/karavan-core/test/beans2.yaml
new file mode 100644
index 0000000..4bf83d1
--- /dev/null
+++ b/karavan-core/test/beans2.yaml
@@ -0,0 +1,42 @@
+apiVersion: camel.apache.org/v1
+kind: Integration
+metadata:
+  name: test1.yaml
+spec:
+  flows:
+  - beans:
+      - name: myNested
+        type: ${MyBean.class.name}
+        properties:
+          field1: 'value1'
+          field2: 'value2'
+          nested:
+            foo: 'valueFoo'
+            bar: 'valueBar'
+      - name: myProps
+        type: ${MyBean.class.name}
+        properties:
+          field1: 'f1_p'
+          field2: 'f2_p'
+          nested.foo: 'nf1_p'
+          nested.bar: 'nf2_p'
+  - from:
+      uri: "direct:route"
+      steps:
+        - aggregate:
+            strategy-ref: "myAggregatorStrategy"
+            completion-size: 2
+            correlation-expression:
+              simple: "${header.StockSymbol}"
+            steps:
+              - to: "mock:route"
+  - from:
+      uri: "direct:route"
+      steps:
+        - aggregate:
+            strategy-ref: "myAggregatorStrategy"
+            completion-size: 2
+            correlation-expression:
+              simple: "${header.StockSymbol}"
+            steps:
+              - to: "mock:route"
\ No newline at end of file
diff --git a/karavan-demo/http-to-kafka.yaml b/karavan-demo/http-to-kafka.yaml
new file mode 100644
index 0000000..298967a
--- /dev/null
+++ b/karavan-demo/http-to-kafka.yaml
@@ -0,0 +1,35 @@
+- route:
+    from:
+      uri: platform-http:/demo
+      steps:
+        - unmarshal:
+            json:
+              library: jackson
+        - choice:
+            when:
+              - expression:
+                  simple:
+                    expression: ${body[amount]} > 1000
+                steps:
+                  - marshal:
+                      json:
+                        library: jackson
+                  - kamelet:
+                      name: kafka-not-secured-sink
+                      parameters:
+                        topic: topic-demo
+                        bootstrapServers: localhost:9092
+            otherwise:
+              steps:
+                - log:
+                    message: Amount is too small
+                    loggingLevel: INFO
+                    logName: demo
+        - setBody:
+            expression:
+              constant:
+                expression: '{"result":"OK"}'
+        - circuitBreaker: {}
+      parameters:
+        httpMethodRestrict: POST
+        produces: application/json
diff --git a/karavan-designer/package-lock.json 
b/karavan-designer/package-lock.json
index 409e45c..1795c1d 100644
--- a/karavan-designer/package-lock.json
+++ b/karavan-designer/package-lock.json
@@ -1,12 +1,12 @@
 {
   "name": "karavan-designer",
-  "version": "0.0.10",
+  "version": "0.0.11",
   "lockfileVersion": 2,
   "requires": true,
   "packages": {
     "": {
       "name": "karavan-designer",
-      "version": "0.0.10",
+      "version": "0.0.11",
       "license": "Apache-2.0",
       "dependencies": {
         "@patternfly/patternfly": "4.171.1",
diff --git a/karavan-designer/package.json b/karavan-designer/package.json
index 1c331d0..50b555a 100644
--- a/karavan-designer/package.json
+++ b/karavan-designer/package.json
@@ -1,6 +1,6 @@
 {
   "name": "karavan-designer",
-  "version": "0.0.11",
+  "version": "0.0.12",
   "license": "Apache-2.0",
   "scripts": {
     "start": "react-scripts start",
diff --git a/karavan-designer/src/App.tsx b/karavan-designer/src/App.tsx
index 3d29a5e..c504245 100644
--- a/karavan-designer/src/App.tsx
+++ b/karavan-designer/src/App.tsx
@@ -34,11 +34,11 @@ interface State {
 class App extends React.Component<Props, State> {
 
     public state: State = {
-        name: '',
+        name: 'demo.yaml',
         yaml: 'apiVersion: camel.apache.org/v1\n' +
             'kind: Integration\n' +
             'metadata:\n' +
-            '  name: \'\'\n' +
+            '  name: demo.yaml\'\'\n' +
             'spec:\n' +
             '  flows:\n' +
             '    - route:\n' +
@@ -53,26 +53,26 @@ class App extends React.Component<Props, State> {
             // '                 - option-name: o2\n' +
             // '                   expression:\n' +
             // '                     simple: "${body}" \n' +
-            '            - do-try:\n' +
-            '                steps:\n' +
-            '                  - to: "direct:direct1"\n' +
-            '                  - to: "direct:direct2"\n' +
-            '                  - log: "log1"\n' +
-            '                do-catch:\n' +
-            '                  - exception:\n' +
-            '                      - "java.io.FileNotFoundException"\n' +
-            '                      - "java.io.IOException"\n' +
-            '                    steps:\n' +
-            '                      - log: "log1"\n' +
-            '                      - kamelet: \n' +
-            '                           name: kafka-sink \n' +
-            '                  - exception:\n' +
-            '                      - "java.io.FileNotFoundException"\n' +
-            '                      - "java.io.IOException"\n' +
-            '                    steps:\n' +
-            '                      - log: "log1"\n' +
-            '                      - kamelet: \n' +
-            '                           name: http-sink \n' +
+            // '            - do-try:\n' +
+            // '                steps:\n' +
+            // '                  - to: "direct:direct1"\n' +
+            // '                  - to: "direct:direct2"\n' +
+            // '                  - log: "log1"\n' +
+            // '                do-catch:\n' +
+            // '                  - exception:\n' +
+            // '                      - "java.io.FileNotFoundException"\n' +
+            // '                      - "java.io.IOException"\n' +
+            // '                    steps:\n' +
+            // '                      - log: "log1"\n' +
+            // '                      - kamelet: \n' +
+            // '                           name: kafka-sink \n' +
+            // '                  - exception:\n' +
+            // '                      - "java.io.FileNotFoundException"\n' +
+            // '                      - "java.io.IOException"\n' +
+            // '                    steps:\n' +
+            // '                      - log: "log1"\n' +
+            // '                      - kamelet: \n' +
+            // '                           name: http-sink \n' +
             '            - choice:\n' +
             '                when:\n' +
             '                  - simple: "hello world"\n' +
@@ -81,6 +81,24 @@ class App extends React.Component<Props, State> {
             '                           message: hello22s\n' +
             '                           logName: log22\n' +
             '                otherwise: {}\n'+
+            '    - beans:\n' +
+            '      - name: myNested\n' +
+            '        type: ${MyBean.class.name}\n' +
+            '        properties:\n' +
+            '          field1: \'value1\'\n' +
+            '          field2: \'value2\'\n' +
+            '          nested:\n' +
+            '            foo: \'valueFoo\'\n' +
+            '            bar: \'valueBar\'\n' +
+            '      - name: myProps\n' +
+            '        type: ${MyBean.class.name}\n' +
+            '        properties:\n' +
+            '          field1: \'f1_p\'\n' +
+            '          field2: \'f2_p\'\n' +
+            '          nested.foo: \'nf1_p\'\n' +
+            '          nested.bar: \'nf2_p\'\n'+
+            '      - name: myAggregatorStrategy \n' +
+            '        type: 
org.apache.camel.processor.aggregate.UseLatestAggregationStrategy\n' +
             '',
         key: ''
     };
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx 
b/karavan-designer/src/designer/KaravanDesigner.tsx
index d132ba2..7a3e423 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/KaravanDesigner.tsx
@@ -16,22 +16,20 @@
  */
 import React from 'react';
 import {
-    Button, Modal,
+    Badge,
     PageSection, Tab, Tabs, TabTitleIcon, TabTitleText, Tooltip,
 } from '@patternfly/react-core';
 import './karavan.css';
-import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
-import {DslProperties} from "./DslProperties";
-import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {CamelElement, FromDefinition, Integration} from 
"karavan-core/lib/model/CamelDefinition";
+import {RouteDesigner} from "./route/RouteDesigner";
 import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
-import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
-import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
-import {DslConnections} from "./DslConnections";
-import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
-import {DslElement} from "./DslElement";
-import {EventBus} from "./EventBus";
+import {Integration} from "karavan-core/lib/model/CamelDefinition";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {CamelUi} from "./utils/CamelUi";
+import {BeansDesigner} from "./beans/BeansDesigner";
+import {RestDesigner} from "./rest/RestDesigner";
+import {ErrorDesigner} from "./error/ErrorDesigner";
+import {TemplatesDesigner} from "./templates/TemplatesDesigner";
+import {ExceptionDesigner} from "./exception/ExceptionDesigner";
 
 interface Props {
     onSave?: (filename: string, yaml: string) => void
@@ -43,241 +41,45 @@ interface Props {
 }
 
 interface State {
-    integration: Integration
-    selectedStep?: CamelElement
-    showSelector: boolean
-    showDeleteConfirmation: boolean
-    parentId: string
-    parentDsl?: string
-    showSteps: boolean
-    selectedUuid: string
-    key: string
-    width: number
-    height: number
-    top: number
+    tab: string,
+    integration: Integration,
+    key: string,
 }
 
 export class KaravanDesigner extends React.Component<Props, State> {
 
     public state: State = {
+        tab: 'routes',
         integration: this.props.yaml
             ? CamelDefinitionYaml.yamlToIntegration(this.props.filename, 
this.props.yaml)
             : Integration.createNew(this.props.filename),
-        showSelector: false,
-        showDeleteConfirmation: false,
-        parentId: '',
-        showSteps: true,
-        selectedUuid: '',
         key: "",
-        width: 1000,
-        height: 1000,
-        top: 0,
     };
 
-    componentDidMount() {
-        window.addEventListener('resize', this.handleResize);
-    }
-
-    componentWillUnmount() {
-        window.removeEventListener('resize', this.handleResize);
-    }
-
-    handleResize = () => {
-        this.setState({key: Math.random().toString()});
-    }
-
     componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
         if (prevState.key !== this.state.key) {
             this.props.onSave?.call(this, 
this.state.integration.metadata.name, this.getCode(this.state.integration));
         }
     }
 
-    unselectElement = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
-        if ((evt.target as any).dataset.click === 'FLOWS') {
-            evt.stopPropagation()
-            this.setState({selectedStep: undefined, selectedUuid: '', 
showSelector: false})
-        }
-    };
+    save = (integration: Integration): void => {
+        this.setState({key: Math.random().toString(), integration: 
integration});
+    }
 
     getCode = (integration: Integration): string => {
         const clone = CamelUtil.cloneIntegration(integration);
         return CamelDefinitionYaml.integrationToYaml(clone);
     }
 
-    onPropertyUpdate = (element: CamelElement, updatedUuid: string) => {
-        const clone = CamelUtil.cloneIntegration(this.state.integration);
-        const i = CamelDefinitionApiExt.updateIntegration(clone, element, 
updatedUuid);
-        this.setState({integration: i, key: Math.random().toString()});
-    }
-
-    showDeleteConfirmation = (id: string) => {
-        this.setState({selectedUuid: id, showSelector: false, 
showDeleteConfirmation: true});
-    }
-
-    deleteElement = () => {
-        const id = this.state.selectedUuid;
-        const i = 
CamelDefinitionApiExt.deleteStepFromIntegration(this.state.integration, id);
-        this.setState({
-            integration: i,
-            showSelector: false,
-            showDeleteConfirmation: false,
-            key: Math.random().toString(),
-            selectedStep: undefined,
-            selectedUuid: ''
-        });
-        const el = new CamelElement("");
-        el.uuid = id;
-        EventBus.sendPosition("delete", el, undefined, new DOMRect(), new 
DOMRect(), 0);
-    }
-
-    selectElement = (element: CamelElement) => {
-        this.setState({selectedStep: element, selectedUuid: element.uuid, 
showSelector: false})
-    }
-
-    openSelector = (parentId: string | undefined, parentDsl: string | 
undefined, showSteps: boolean = true) => {
-        this.setState({showSelector: true, parentId: parentId || '', 
parentDsl: parentDsl, showSteps: showSteps})
-    }
-
-    closeDslSelector = () => {
-        this.setState({showSelector: false})
-    }
-
-    onDslSelect = (dsl: DslMetaModel, parentId: string) => {
-        switch (dsl.dsl) {
-            case 'FromDefinition' :
-                const from = CamelDefinitionApi.createRouteDefinition({from: 
new FromDefinition({uri: dsl.uri})});
-                this.addStep(from, parentId)
-                break;
-            case 'ToDefinition' :
-                const to = CamelDefinitionApi.createStep(dsl.dsl, {uri: 
dsl.uri});
-                this.addStep(to, parentId)
-                break;
-            case 'ToDynamicDefinition' :
-                const toD = CamelDefinitionApi.createStep(dsl.dsl, {uri: 
dsl.uri});
-                this.addStep(toD, parentId)
-                break;
-            case 'KameletDefinition' :
-                const kamelet = CamelDefinitionApi.createStep(dsl.dsl, {name: 
dsl.name});
-                this.addStep(kamelet, parentId)
-                break;
-            default:
-                const step = CamelDefinitionApi.createStep(dsl.dsl, undefined);
-                this.addStep(step, parentId)
-                break;
-        }
-    }
-
-    addStep = (step: CamelElement, parentId: string) => {
-        const i = 
CamelDefinitionApiExt.addStepToIntegration(this.state.integration, step, 
parentId);
-        const clone = CamelUtil.cloneIntegration(i);
-        this.setState({
-            integration: clone,
-            key: Math.random().toString(),
-            showSelector: false,
-            selectedStep: step,
-            selectedUuid: step.uuid
-        });
-    }
-
-    onIntegrationUpdate = (i: Integration) => {
-        this.setState({integration: i, showSelector: false, key: 
Math.random().toString()});
-    }
-
-    moveElement = (source: string, target: string) => {
-        const i = CamelDefinitionApiExt.moveElement(this.state.integration, 
source, target);
-        const clone = CamelUtil.cloneIntegration(i);
-        const selectedStep = 
CamelDefinitionApiExt.findElementInIntegration(clone, source);
-        this.setState({
-            integration: clone,
-            key: Math.random().toString(),
-            showSelector: false,
-            selectedStep: selectedStep,
-            selectedUuid: source
-        });
-    }
-
-    onResizePage(el: HTMLDivElement | null) {
-        const rect = el?.getBoundingClientRect();
-        if (el && rect && (rect?.width !== this.state.width || rect.height !== 
this.state.height || rect.top !== this.state.top)) {
-            this.setState({width: rect.width, height: rect.height, top: 
rect.top});
-        }
-    }
-
-    getSelectorModal() {
-        return (
-            <Modal
-                title={this.state.parentDsl === undefined ? "Select 
source/from" : "Select step"}
-                width={'90%'}
-                className='dsl-modal'
-                isOpen={this.state.showSelector}
-                onClose={() => this.closeDslSelector()}
-                actions={{}}>
-                <DslSelector
-                    dark={this.props.dark}
-                    parentId={this.state.parentId}
-                    parentDsl={this.state.parentDsl}
-                    showSteps={this.state.showSteps}
-                    onDslSelect={this.onDslSelect}/>
-            </Modal>)
-    }
-
-    getDeleteConfirmation() {
-        return (<Modal
-            className="modal-delete"
-            title="Confirmation"
-            isOpen={this.state.showDeleteConfirmation}
-            onClose={() => this.setState({showDeleteConfirmation: false})}
-            actions={[
-                <Button key="confirm" variant="primary" onClick={e => 
this.deleteElement()}>Delete</Button>,
-                <Button key="cancel" variant="link"
-                        onClick={e => this.setState({showDeleteConfirmation: 
false})}>Cancel</Button>
-            ]}
-            onEscapePress={e => this.setState({showDeleteConfirmation: 
false})}>
-            <div>
-                Delete element from integration?
-            </div>
-        </Modal>)
-    }
-
-    getGraph() {
-        return (
-            <div className="graph">
-                <DslConnections height={this.state.height} 
width={this.state.width} top={this.state.top} 
integration={this.state.integration}/>
-                <div className="flows" data-click="FLOWS" onClick={event => 
this.unselectElement(event)}
-                     ref={el => this.onResizePage(el)}>
-                    {this.state.integration.spec.flows?.map((from: any, index: 
number) => (
-                        <DslElement key={from.uuid + this.state.key}
-                                    openSelector={this.openSelector}
-                                    deleteElement={this.showDeleteConfirmation}
-                                    selectElement={this.selectElement}
-                                    moveElement={this.moveElement}
-                                    selectedUuid={this.state.selectedUuid}
-                                    borderColor={this.props.borderColor}
-                                    
borderColorSelected={this.props.borderColorSelected}
-                                    inSteps={false}
-                                    position={index}
-                                    step={from}
-                                    parent={undefined}/>
-                    ))}
-                    <div className="add-flow">
-                        <Button
-                            variant={this.state.integration.spec.flows?.length 
=== 0 ? "primary" : "secondary"}
-                            data-click="ADD_ROUTE"
-                            icon={<PlusIcon/>}
-                            onClick={e => this.openSelector(undefined, 
undefined)}>Add new route
-                        </Button>
-                    </div>
-                </div>
-            </div>)
-    }
-
     getTab(title: string, tooltip: string, icon: string) {
+        const counts = CamelUi.getFlowCounts(this.state.integration);
         return (
             <Tooltip position={"bottom"}
                      content={<div>{tooltip}</div>}>
                 <div className="top-menu-item">
                     <TabTitleIcon>{this.getIcon(icon)}</TabTitleIcon>
                     <TabTitleText>{title}</TabTitleText>
+                    {counts.has(icon) && <Badge isRead 
className="count">{counts.get(icon)}</Badge>}
                 </div>
             </Tooltip>
 
@@ -310,14 +112,13 @@ export class KaravanDesigner extends 
React.Component<Props, State> {
             </svg>
         )
         if (icon === 'beans') return (
-            <svg className="top-icon" viewBox="0 0 536.243 536.242" >
-                <g>
-                    <path 
d="M471.053,197.07c-94.2-101.601-284-183.601-423.5-154.2c-9.2,1.8-12.9,9.2-12.2,16.5c-86.9,47.7,9.2,213,45.9,261.3
-                        
c72.2,96.1,200.701,203.2,329.901,173.8c60-13.5,103.399-69.8,120-126.1C550.053,304.77,513.253,242.37,471.053,197.07z
-                         
M393.353,465.17c-102.199,23.3-210.5-75.9-271.7-145c-61.2-70.4-108.3-155.4-71-243c83.8,151.8,253.4,269.3,414.9,321.899
-                        
c19.601,6.101,28.2-24.5,8.601-31.199C318.753,315.27,166.353,209.97,73.953,72.27c111.4-13.5,238.701,45.9,326.201,107.101
-                        
c50.199,35.5,98.5,87.5,102.8,151.8C505.954,394.17,451.454,451.67,393.353,465.17z"/>
-                </g>
+            <svg className="top-icon" width="32px" height="32px" viewBox="0 0 
32 32">
+                <defs>
+                    <style>{".cls-1 {fill: none;}"}</style>
+                </defs>
+                <path
+                    
d="M28.5039,8.1362l-12-7a1,1,0,0,0-1.0078,0l-12,7A1,1,0,0,0,3,9V23a1,1,0,0,0,.4961.8638l12,7a1,1,0,0,0,1.0078,0l12-7A1,1,0,0,0,29,23V9A1,1,0,0,0,28.5039,8.1362ZM16,3.1577,26.0156,9,16,14.8423,5.9844,9ZM5,10.7412l10,5.833V28.2588L5,22.4258ZM17,28.2588V16.5742l10-5.833V22.4258Z"/>
+                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32"/>
             </svg>
         )
         if (icon === 'error') return (
@@ -351,30 +152,47 @@ export class KaravanDesigner extends 
React.Component<Props, State> {
     }
 
     render() {
+        const tab = this.state.tab;
         return (
-            <PageSection className="dsl-page" isFilled padding={{default: 
'noPadding'}}>
-                <div className="dsl-page-columns">
-                    <div style={{width: "100%"}}>
-                        <Tabs isFilled className="main-tabs" activeKey={0} 
onSelect={event => {
-                        }} style={{width: "100%"}}>
-                            <Tab eventKey={0} title={this.getTab("Routes", 
"Integration flows", "routes")}></Tab>
-                            <Tab eventKey={1} title={this.getTab("REST", "REST 
services","rest")}></Tab>
-                            <Tab eventKey={2} title={this.getTab("Beans", 
"Beans Configuration","beans")}></Tab>
-                            <Tab eventKey={3} 
title={this.getTab("Error","Error Handler configuration", "error")}></Tab>
-                            <Tab eventKey={4} 
title={this.getTab("Exceptions","Exception Clauses per type", 
"exception")}></Tab>
-                            <Tab eventKey={5} title={this.getTab("Templates", 
"Route Templates","template")}></Tab>
-                        </Tabs>
-                        {this.getGraph()}
-                    </div>
-                    <DslProperties
-                        integration={this.state.integration}
-                        step={this.state.selectedStep}
-                        onIntegrationUpdate={this.onIntegrationUpdate}
-                        onPropertyUpdate={this.onPropertyUpdate}
-                    />
-                </div>
-                {this.getSelectorModal()}
-                {this.getDeleteConfirmation()}
+            <PageSection className="page" isFilled padding={{default: 
'noPadding'}}>
+                <Tabs className="main-tabs" activeKey={tab} onSelect={(event, 
tabIndex) => this.setState({tab: tabIndex.toString()})} style={{width: "100%"}}>
+                    <Tab eventKey='routes' title={this.getTab("Routes", 
"Integration flows", "routes")}></Tab>
+                    <Tab eventKey='rest' title={this.getTab("REST", "REST 
services", "rest")}></Tab>
+                    <Tab eventKey='beans' title={this.getTab("Beans", "Beans 
Configuration", "beans")}></Tab>
+                    <Tab eventKey='error' title={this.getTab("Error", "Error 
Handler configuration", "error")}></Tab>
+                    <Tab eventKey='exception' title={this.getTab("Exceptions", 
"Exception Clauses per type", "exception")}></Tab>
+                    <Tab eventKey='templates' title={this.getTab("Templates", 
"Route Templates", "template")}></Tab>
+                </Tabs>
+                {tab === 'routes' && <RouteDesigner 
integration={this.state.integration}
+                                                    onSave={(integration) => 
this.save(integration)}
+                                                    
borderColor={this.props.borderColor}
+                                                    
borderColorSelected={this.props.borderColorSelected}
+                                                    dark={this.props.dark}/>}
+                {tab === 'rest' && <RestDesigner 
integration={this.state.integration}
+                                                 onSave={(integration) => 
this.save(integration)}
+                                                 
borderColor={this.props.borderColor}
+                                                 
borderColorSelected={this.props.borderColorSelected}
+                                                 dark={this.props.dark}/>}
+                {tab === 'beans' && <BeansDesigner 
integration={this.state.integration}
+                                                   onSave={(integration) => 
this.save(integration)}
+                                                   
borderColor={this.props.borderColor}
+                                                   
borderColorSelected={this.props.borderColorSelected}
+                                                   dark={this.props.dark}/>}
+                {tab === 'error' && <ErrorDesigner 
integration={this.state.integration}
+                                                   onSave={(integration) => 
this.save(integration)}
+                                                   
borderColor={this.props.borderColor}
+                                                   
borderColorSelected={this.props.borderColorSelected}
+                                                   dark={this.props.dark}/>}
+                {tab === 'exception' && <ExceptionDesigner 
integration={this.state.integration}
+                                                           
onSave={(integration) => this.save(integration)}
+                                                           
borderColor={this.props.borderColor}
+                                                           
borderColorSelected={this.props.borderColorSelected}
+                                                           
dark={this.props.dark}/>}
+                {tab === 'templates' && <TemplatesDesigner 
integration={this.state.integration}
+                                                           
onSave={(integration) => this.save(integration)}
+                                                           
borderColor={this.props.borderColor}
+                                                           
borderColorSelected={this.props.borderColorSelected}
+                                                           
dark={this.props.dark}/>}
             </PageSection>
         );
     }
diff --git a/karavan-designer/src/designer/beans/BeanProperties.tsx 
b/karavan-designer/src/designer/beans/BeanProperties.tsx
new file mode 100644
index 0000000..ad6b578
--- /dev/null
+++ b/karavan-designer/src/designer/beans/BeanProperties.tsx
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Form,
+    FormGroup,
+    TextInput,
+    Text,
+    Title,
+    TextVariants, Button,
+} from '@patternfly/react-core';
+import '../karavan.css';
+import "@patternfly/patternfly/patternfly.css";
+import {DataFormatField} from "../field/DataFormatField";
+import {DslPropertyField} from "../field/DslPropertyField";
+import {
+    CamelElement,
+    Integration,
+    ExpressionDefinition,
+    DataFormatDefinition, Bean
+} from "karavan-core/lib/model/CamelDefinition";
+import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
+import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+import {CamelUi} from "../utils/CamelUi";
+import {CamelMetadataApi, PropertyMeta} from 
"karavan-core/lib/model/CamelMetadata";
+import {v4 as uuidv4} from "uuid";
+import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-icon";
+import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
+import {IntegrationHeader} from "../utils/KaravanComponents";
+
+interface Props {
+    integration: Integration
+    bean?: Bean
+    dark: boolean
+    onChange: (bean: Bean) => void
+}
+
+interface State {
+    bean?: Bean
+    properties: Map<string, [string, string]>
+    key: string
+}
+
+export class BeanProperties extends React.Component<Props, State> {
+
+    preparePropertiesMap = (properties: any): Map<string, [string, string]> => 
{
+        const result = new Map<string, [string, string]>();
+        Object.keys(properties).forEach((k, i, a) => result.set(uuidv4(), [k, 
properties[k]]));
+        return result;
+    }
+
+    public state: State = {
+        bean: this.props.bean,
+        key: '',
+        properties: this.props.bean?.properties ? 
this.preparePropertiesMap(this.props.bean?.properties) : new Map<string, 
[string, string]>()
+    };
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevProps.bean?.uuid !== this.props.bean?.uuid) {
+            this.setBean(this.props.bean);
+        }
+        if (prevState.key !== this.state.key && this.state.bean) {
+            const bean = CamelUtil.cloneBean(this.state.bean);
+            const properties: any = {};
+            this.state.properties.forEach(p => properties[p[0]] = p[1]);
+            bean.properties = properties;
+            this.setState({bean: bean});
+            this.props.onChange?.call(this, bean);
+        }
+    }
+
+    setBean = (bean?: Bean) => {
+        this.setState({
+            bean: bean,
+            properties: bean?.properties ? 
this.preparePropertiesMap(bean.properties) : new Map<string, [string, string]>()
+        });
+    }
+
+    beanChanged = (fieldId: string, value: string) => {
+        if (this.state.bean) {
+            const bean = CamelUtil.cloneBean(this.state.bean);
+            (bean as any)[fieldId] = value;
+            this.setState({bean: bean});
+            this.props.onChange?.call(this, bean);
+        }
+    }
+
+    propertyChanged = (uuid: string, key: string, value: string) => {
+        this.setState(state => {
+            state.properties.set(uuid, [key, value]);
+            return {properties: state.properties, key: 
Math.random().toString()};
+        })
+    }
+
+    propertyDeleted = (uuid: string) => {
+        this.setState(state => {
+            state.properties.delete(uuid);
+            return {properties: state.properties, key: 
Math.random().toString()};
+        })
+    }
+
+    getBeanForm() {
+        const bean = this.state.bean;
+        return (
+            <>
+                <FormGroup label="Name" fieldId="name" isRequired>
+                    <TextInput className="text-field" isRequired type="text" 
id="name" name="name" value={bean?.name}
+                               onChange={e => this.beanChanged("name", e)}/>
+                </FormGroup>
+                <FormGroup label="Type" fieldId="type" isRequired>
+                    <TextInput className="text-field" isRequired type="text" 
id="type" name="type" value={bean?.type} onChange={e => 
this.beanChanged("type", e)}/>
+                </FormGroup>
+                <FormGroup label="Properties" fieldId="properties" 
className="bean-properties">
+                    {Array.from(this.state.properties.entries()).map((v, 
index, array) => {
+                        const i = v[0];
+                        const key = v[1][0];
+                        const value = v[1][1];
+                        return (
+                            <div key={"key-" + i} className="bean-property">
+                                <TextInput className="text-field" isRequired 
type="text" id="key" name="key" value={key} onChange={e => 
this.propertyChanged(i, e, value)}/>
+                                <TextInput className="text-field" isRequired 
type="text" id="value" name="value" value={value} onChange={e => 
this.propertyChanged(i, key, e)}/>
+                                <Button variant="link" 
className="delete-button" onClick={e => 
this.propertyDeleted(i)}><DeleteIcon/></Button>
+                            </div>
+                        )
+                    })}
+                    <Button variant="link" className="add-button" onClick={e 
=> this.propertyChanged(uuidv4(), '', '')}><AddIcon/>Add property</Button>
+                </FormGroup>
+            </>
+        )
+    }
+
+    render() {
+        return (
+            <div className='properties' key={this.state.bean ? 
this.state.bean.uuid : 'integration'}>
+                <Form autoComplete="off" onSubmit={event => 
event.preventDefault()}>
+                    {this.state.bean === undefined && <IntegrationHeader 
integration={this.props.integration}/>}
+                    {this.state.bean !== undefined && this.getBeanForm()}
+                </Form>
+            </div>
+        )
+    }
+}
\ No newline at end of file
diff --git a/karavan-designer/src/designer/beans/BeansDesigner.tsx 
b/karavan-designer/src/designer/beans/BeansDesigner.tsx
new file mode 100644
index 0000000..2416964
--- /dev/null
+++ b/karavan-designer/src/designer/beans/BeansDesigner.tsx
@@ -0,0 +1,183 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, Card, CardActions, CardBody, CardFooter, CardHeader, CardTitle, 
Gallery, Modal, PageSection
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {Bean, Integration} from "karavan-core/lib/model/CamelDefinition";
+import {CamelUi} from "../utils/CamelUi";
+import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
+import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
+import DeleteIcon from 
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import {BeanIcon} from "../utils/KaravanIcons";
+import {BeanProperties} from "./BeanProperties";
+import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
+
+interface Props {
+    onSave?: (integration: Integration) => void
+    integration: Integration
+    borderColor: string
+    borderColorSelected: string
+    dark: boolean
+}
+
+interface State {
+    integration: Integration
+    showDeleteConfirmation: boolean
+    selectedBean?: Bean
+    key: string
+    showBeanEditor: boolean
+}
+
+export class BeansDesigner extends React.Component<Props, State> {
+
+    public state: State = {
+        integration: this.props.integration,
+        showDeleteConfirmation: false,
+        key: "",
+        showBeanEditor: false,
+    };
+
+    componentDidMount() {
+        window.addEventListener('resize', this.handleResize);
+    }
+
+    componentWillUnmount() {
+        window.removeEventListener('resize', this.handleResize);
+    }
+
+    handleResize = () => {
+        this.setState({key: Math.random().toString()});
+    }
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevState.key !== this.state.key) {
+            this.props.onSave?.call(this, this.state.integration);
+        }
+    }
+
+    showDeleteConfirmation = (e: React.MouseEvent, bean: Bean) => {
+        e.stopPropagation();
+        this.setState({selectedBean: bean, showDeleteConfirmation: true});
+    }
+
+    onIntegrationUpdate = (i: Integration) => {
+        this.setState({integration: i, showDeleteConfirmation: false, key: 
Math.random().toString()});
+    }
+
+    deleteBean = () => {
+        const i = 
CamelDefinitionApiExt.deleteBeanFromIntegration(this.state.integration, 
this.state.selectedBean);
+        this.setState({
+            integration: i,
+            showDeleteConfirmation: false,
+            key: Math.random().toString(),
+            selectedBean: new Bean()
+        });
+    }
+
+    changeBean = (bean: Bean) => {
+        const clone = CamelUtil.cloneIntegration(this.state.integration);
+        const i = CamelDefinitionApiExt.addBeanToIntegration(clone, bean);
+        this.setState({integration: i, key: Math.random().toString(), 
selectedBean: bean});
+    }
+
+    getDeleteConfirmation() {
+        return (<Modal
+            className="modal-delete"
+            title="Confirmation"
+            isOpen={this.state.showDeleteConfirmation}
+            onClose={() => this.setState({showDeleteConfirmation: false})}
+            actions={[
+                <Button key="confirm" variant="primary" onClick={e => 
this.deleteBean()}>Delete</Button>,
+                <Button key="cancel" variant="link"
+                        onClick={e => this.setState({showDeleteConfirmation: 
false})}>Cancel</Button>
+            ]}
+            onEscapePress={e => this.setState({showDeleteConfirmation: 
false})}>
+            <div>
+                Delete bean from integration?
+            </div>
+        </Modal>)
+    }
+
+    closeBeanEditor = () => {
+        this.setState({showBeanEditor: false})
+    }
+
+    openBeanEditor = () => {
+        this.setState({showBeanEditor: true})
+    }
+
+    selectBean = (bean?: Bean) => {
+        this.setState({selectedBean: bean})
+    }
+
+    unselectBean = (evt: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
+        if ((evt.target as any).dataset.click === 'BEANS') {
+            evt.stopPropagation()
+            this.setState({selectedBean: undefined})
+        }
+    };
+
+    createBean = () => {
+        this.changeBean(new Bean());
+    }
+
+    getCard(bean: Bean, index: number) {
+        return (
+            <Card key={bean.dslName + index} isHoverable isCompact
+                  className={this.state.selectedBean?.uuid === bean.uuid ? 
"bean-card bean-card-selected" : "bean-card bean-card-unselected"}
+                  onClick={e => this.selectBean(bean)}>
+                <CardHeader>
+                    <BeanIcon/>
+                    <CardActions>
+                        <Button variant="link" className="delete-button" 
onClick={e => this.showDeleteConfirmation(e, bean)}><DeleteIcon/></Button>
+                    </CardActions>
+                </CardHeader>
+                <CardTitle>{bean.name}</CardTitle>
+                <CardBody>{bean.type}</CardBody>
+                <CardFooter className="">
+                </CardFooter>
+            </Card>
+        )
+    }
+
+    render() {
+        const beans = CamelUi.getBeans(this.state.integration);
+        return (
+            <PageSection className="beans-page" isFilled padding={{default: 
'noPadding'}}>
+                <div className="beans-page-columns" data-click="BEANS" 
onClick={event => this.unselectBean(event)}>
+                    <div className="beans-panel">
+                        <Gallery hasGutter className="beans-gallery" 
data-click="BEANS" onClick={event => this.unselectBean(event)}>
+                            {beans.map((bean: Bean, index: number) => 
this.getCard(bean, index))}
+                        </Gallery>
+                        <div className="add-button-div" data-click="BEANS" 
onClick={event => this.unselectBean(event)}>
+                            <Button icon={<PlusIcon/>} variant={beans.length 
=== 0 ? "primary" : "secondary"} onClick={e => this.createBean()} 
className="add-bean-button">
+                                Add new bean
+                            </Button>
+                        </div>
+                    </div>
+                    <BeanProperties integration={this.props.integration}
+                                    bean={this.state.selectedBean}
+                                    dark={this.props.dark}
+                                    onChange={this.changeBean}/>
+                </div>
+                {this.getDeleteConfirmation()}
+            </PageSection>
+        );
+    }
+}
diff --git a/karavan-designer/src/designer/error/ErrorDesigner.tsx 
b/karavan-designer/src/designer/error/ErrorDesigner.tsx
new file mode 100644
index 0000000..39336a3
--- /dev/null
+++ b/karavan-designer/src/designer/error/ErrorDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+    PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from 
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+    onSave?: (integration: Integration) => void
+    integration: Integration
+    borderColor: string
+    borderColorSelected: string
+    dark: boolean
+}
+
+interface State {
+    integration: Integration
+    selectedStep?: CamelElement
+    key: string
+}
+
+export class ErrorDesigner extends React.Component<Props, State> {
+
+    public state: State = {
+        integration: this.props.integration,
+        key: "",
+    };
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevState.key !== this.state.key) {
+            this.props.onSave?.call(this, this.state.integration);
+        }
+    }
+
+    onIntegrationUpdate = (i: Integration) => {
+        this.setState({integration: i, key: Math.random().toString()});
+    }
+
+    render() {
+        return (
+            <PageSection className="error-page" isFilled padding={{default: 
'noPadding'}}>
+                <div className="error-page-columns">
+                    <EmptyState>
+                        <EmptyStateIcon icon={CubesIcon} />
+                        <Title headingLevel="h4" size="lg">
+                            Error handler
+                        </Title>
+                        <EmptyStateBody>
+                            Error handler not implemented yet
+                        </EmptyStateBody>
+                    </EmptyState>
+                </div>
+            </PageSection>
+        );
+    }
+}
diff --git a/karavan-designer/src/designer/exception/ExceptionDesigner.tsx 
b/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
new file mode 100644
index 0000000..a340fd8
--- /dev/null
+++ b/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+    PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from 
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+    onSave?: (integration: Integration) => void
+    integration: Integration
+    borderColor: string
+    borderColorSelected: string
+    dark: boolean
+}
+
+interface State {
+    integration: Integration
+    selectedStep?: CamelElement
+    key: string
+}
+
+export class ExceptionDesigner extends React.Component<Props, State> {
+
+    public state: State = {
+        integration: this.props.integration,
+        key: "",
+    };
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevState.key !== this.state.key) {
+            this.props.onSave?.call(this, this.state.integration);
+        }
+    }
+
+    onIntegrationUpdate = (i: Integration) => {
+        this.setState({integration: i, key: Math.random().toString()});
+    }
+
+    render() {
+        return (
+            <PageSection className="exception-page" isFilled 
padding={{default: 'noPadding'}}>
+                <div className="exception-page-columns">
+                    <EmptyState>
+                        <EmptyStateIcon icon={CubesIcon} />
+                        <Title headingLevel="h4" size="lg">
+                            Exception Clauses
+                        </Title>
+                        <EmptyStateBody>
+                            Exception Clauses not implemented yet
+                        </EmptyStateBody>
+                    </EmptyState>
+                </div>
+            </PageSection>
+        );
+    }
+}
diff --git a/karavan-designer/src/designer/field/DataFormatField.tsx 
b/karavan-designer/src/designer/field/DataFormatField.tsx
index 0250ed2..78d4487 100644
--- a/karavan-designer/src/designer/field/DataFormatField.tsx
+++ b/karavan-designer/src/designer/field/DataFormatField.tsx
@@ -99,7 +99,6 @@ export class DataFormatField extends React.Component<Props, 
State> {
             const s = <SelectOption key={lang[0]} value={lang[0]} 
description={lang[2]}/>;
             selectOptions.push(s);
         })
-        console.log(properties)
         return (
             <div>
                 <FormGroup label={"Data Format"} key={"dataFormat"} 
fieldId={"dataFormat"}>
diff --git a/karavan-designer/src/designer/field/DslPropertyField.tsx 
b/karavan-designer/src/designer/field/DslPropertyField.tsx
index fa79cc4..820d2b2 100644
--- a/karavan-designer/src/designer/field/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/field/DslPropertyField.tsx
@@ -33,7 +33,7 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import { PropertyMeta} from "karavan-core/lib/model/CamelMetadata";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {ExpressionField} from "./ExpressionField";
-import {CamelUi} from "../CamelUi";
+import {CamelUi} from "../utils/CamelUi";
 import {ComponentParameterField} from "./ComponentParameterField";
 import {CamelElement, DataFormatDefinition} from 
"karavan-core/lib/model/CamelDefinition";
 import {KameletPropertyField} from "./KameletPropertyField";
diff --git a/karavan-designer/src/designer/field/ExpressionField.tsx 
b/karavan-designer/src/designer/field/ExpressionField.tsx
index c90f1e7..1b23db8 100644
--- a/karavan-designer/src/designer/field/ExpressionField.tsx
+++ b/karavan-designer/src/designer/field/ExpressionField.tsx
@@ -31,7 +31,7 @@ import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt"
 import {CamelElement, ExpressionDefinition} from 
"karavan-core/lib/model/CamelDefinition";
 import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
 import {DslPropertyField} from "./DslPropertyField";
-import {CamelUi} from "../CamelUi";
+import {CamelUi} from "../utils/CamelUi";
 
 interface Props {
     property: PropertyMeta,
diff --git a/karavan-designer/src/designer/karavan.css 
b/karavan-designer/src/designer/karavan.css
index 578ccc5..4a20c73 100644
--- a/karavan-designer/src/designer/karavan.css
+++ b/karavan-designer/src/designer/karavan.css
@@ -171,10 +171,18 @@
     user-select: none;
 }
 
-/*DSL*/
-.karavan .dsl-page {
+.karavan .page {
     height: 100%;
+    width: 100%;
     overflow: hidden;
+    display: flex;
+    flex-direction: column;
+}
+
+/*DSL*/
+.karavan .dsl-page {
+    flex: 1;
+    overflow: auto;
 }
 
 .karavan .dsl-page .dsl-page-columns {
@@ -193,14 +201,25 @@
     flex-direction: row;
 }
 
+.karavan .main-tabs .top-menu-item .count {
+    background: var(--pf-global--active-color--100);
+    /*color: white;*/
+    height: fit-content;
+    margin-top: auto;
+    margin-bottom: auto;
+}
+
 .karavan .main-tabs .pf-c-tabs__link .pf-c-tabs__item-icon {
     height: 24px;
-    margin-right: 10px
+    margin-right: 0;
 }
 
 .karavan .main-tabs .pf-c-tabs__item-text {
     font-size: 14px;
     font-weight: bold;
+    margin-top: auto;
+    margin-bottom: auto;
+    margin-right: 6px;
 }
 
 .karavan .main-tabs .pf-c-tabs__item.pf-m-current {
@@ -208,7 +227,7 @@
 }
 
 /*Properties*/
-.karavan .dsl-page .properties {
+.karavan .properties {
     border: 1px solid #eee;
     padding: 10px 10px 10px 10px;
     font-size: 13px;
@@ -221,87 +240,87 @@
     justify-content: space-between;
 }
 
-.karavan .dsl-page .properties .headers {
+.karavan .properties .headers {
     grid-row-gap: 10px;
     row-gap: 10px;
     display: contents;
 }
 
-.karavan .dsl-page .properties .footer {
+.karavan .properties .footer {
     height: 100%;
     display: contents;
 }
 
-.karavan .dsl-page .properties .pf-c-form {
+.karavan .properties .pf-c-form {
     row-gap: 10px;
 }
 
-.karavan .dsl-page .properties .pf-c-form__group-label {
+.karavan .properties .pf-c-form__group-label {
     padding-bottom: 3px;
     display: flex;
     justify-content: space-between;
 }
 
-.karavan .dsl-page .properties .pf-c-form__label {
+.karavan .properties .pf-c-form__label {
     font-size: 13px;
 }
 
-.karavan .dsl-page .properties .text-field {
+.karavan .properties .text-field {
     font-size: 13px;
     height: auto;
 }
 
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__text {
+.karavan .properties .input-group .pf-c-text-input-group__text {
     width: 100%;
 }
 
-.karavan .dsl-page .properties .input-group .pf-c-chip-group,
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__main,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group 
.pf-c-chip-group__list,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group 
.pf-c-chip-group__list .pf-c-chip-group__list-item,
-.karavan .dsl-page .properties .input-group .pf-c-chip-group 
.pf-c-chip-group__main {
+.karavan .properties .input-group .pf-c-chip-group,
+.karavan .properties .input-group .pf-c-text-input-group__main,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__list,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__list 
.pf-c-chip-group__list-item,
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip-group__main {
     display:block;
 }
 
-.karavan .dsl-page .properties .input-group .pf-c-chip-group {
+.karavan .properties .input-group .pf-c-chip-group {
     margin-left: 0;
 }
 
-.karavan .dsl-page .properties .input-group .pf-c-chip-group .pf-c-chip 
.pf-c-chip__text{
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip .pf-c-chip__text{
     max-width: inherit;
 }
-.karavan .dsl-page .properties .input-group .pf-c-chip-group .pf-c-chip {
+.karavan .properties .input-group .pf-c-chip-group .pf-c-chip {
     width: 100%;
 }
 
-.karavan .dsl-page .properties .input-group .pf-c-text-input-group__utilities {
+.karavan .properties .input-group .pf-c-text-input-group__utilities {
     align-items: end;
 }
 
-.karavan .dsl-page .properties .chip .pf-c-button{
+.karavan .properties .chip .pf-c-button{
     position:absolute;
     right: 0;
 }
 
-.karavan .dsl-page .properties .expression-title {
+.karavan .properties .expression-title {
     font-size: 17px;
     font-weught: bold;
 }
 
-.karavan .dsl-page .properties .text-area {
+.karavan .properties .text-area {
     font-size: 13px;
 }
 
-.karavan .dsl-page .properties .pf-c-select__menu-search {
+.karavan .properties .pf-c-select__menu-search {
     padding: 0px 6px 6px 6px;
 }
 
-.karavan .dsl-page .properties .pf-c-select__toggle-typeahead {
+.karavan .properties .pf-c-select__toggle-typeahead {
     font-size: 13px;
     height: auto;
 }
 
-.karavan .dsl-page .properties .pf-c-select__menu-item {
+.karavan .properties .pf-c-select__menu-item {
     width: 280px;
     font-size: 15px;
     /*white-space: nowrap;*/
@@ -310,16 +329,16 @@
     /*line-height: 12px;*/
 }
 
-.karavan .dsl-page .properties .number {
+.karavan .properties .number {
     display: flex;
     justify-content: space-between;
 }
 
-.karavan .dsl-page .properties .number .number-property {
+.karavan .properties .number .number-property {
     width: 100%;
 }
 
-.karavan .dsl-page .properties .number .clear-button {
+.karavan .properties .number .clear-button {
     color: #b1b1b7;
     --pf-c-button--BorderRadius: var(--pf-c-button--m-control--BorderRadius);
     --pf-c-button--disabled--BackgroundColor: 
var(--pf-c-button--m-control--disabled--BackgroundColor);
@@ -331,11 +350,11 @@
     padding-right: 5px;
 }
 
-.karavan .dsl-page .properties .help-button {
+.karavan .properties .help-button {
     font-size: 12px;
 }
 
-.karavan .dsl-page .properties .component-selector {
+.karavan .properties .component-selector {
     border-width: var(--pf-global--BorderWidth--sm);
     border-top-color: var(--pf-global--BorderColor--300);
     border-right-color: var(--pf-global--BorderColor--300);
@@ -344,38 +363,38 @@
     border-style: solid;
 }
 
-.karavan .dsl-page .properties .expression,
-.karavan .dsl-page .properties .object,
-.karavan .dsl-page .properties .dataformat,
-.karavan .dsl-page .properties .parameters {
+.karavan .properties .expression,
+.karavan .properties .object,
+.karavan .properties .dataformat,
+.karavan .properties .parameters {
     padding-top: 6px;
     padding-left: 16px;
     row-gap: 6px;
     display: grid;
 }
 
-.karavan .dsl-page .properties .expression .pf-c-form__group-label,
-.karavan .dsl-page .properties .object .pf-c-form__group-label,
-.karavan .dsl-page .properties .dataformat .pf-c-form__group-label,
-.karavan .dsl-page .properties .parameters .pf-c-form__group-label {
+.karavan .properties .expression .pf-c-form__group-label,
+.karavan .properties .object .pf-c-form__group-label,
+.karavan .properties .dataformat .pf-c-form__group-label,
+.karavan .properties .parameters .pf-c-form__group-label {
     font-weight: 100;
 }
 
-.karavan .dsl-page .properties .expression .pf-c-form__group,
-.karavan .dsl-page .properties .object .pf-c-form__group,
-.karavan .dsl-page .properties .dataformat .pf-c-form__group,
-.karavan .dsl-page .properties .parameters .pf-c-form__group {
+.karavan .properties .expression .pf-c-form__group,
+.karavan .properties .object .pf-c-form__group,
+.karavan .properties .dataformat .pf-c-form__group,
+.karavan .properties .parameters .pf-c-form__group {
     margin-bottom: 10px;
 }
 
-.karavan .dsl-page .properties .expression .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .object .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .dataformat .pf-c-select__menu-wrapper,
-.karavan .dsl-page .properties .parameters .pf-c-select__menu-wrapper{
+.karavan .properties .expression .pf-c-select__menu-wrapper,
+.karavan .properties .object .pf-c-select__menu-wrapper,
+.karavan .properties .dataformat .pf-c-select__menu-wrapper,
+.karavan .properties .parameters .pf-c-select__menu-wrapper{
     width: 350px;
 }
 
-.karavan .dsl-page .properties .add-button {
+.karavan .properties .add-button {
     font-size: 15px;
     height: 15px;
     line-height: 1;
@@ -386,6 +405,10 @@
     color: #fb8824;
 }
 
+.karavan .properties .add-button svg {
+    margin-right: 6px;
+}
+
 
 /*Graph*/
 .karavan .dsl-page .graph {
@@ -500,13 +523,13 @@
     position: absolute;
     top: 4px;
     right: 4px;
-    font-size: 13px;
+    font-size: 14px;
     line-height: 1;
     border: 0;
     padding: 0;
     margin: 0;
     background: transparent;
-    color: #b1b1b7;
+    color: #909090;
     visibility: hidden;
 }
 
@@ -514,13 +537,13 @@
 .element-builder .header .delete-button {
     position: absolute;
     top: 0px;
-    font-size: 13px;
+    font-size: 14px;
     line-height: 1;
     border: 0;
     padding: 0;
     margin: 0 0 0 10px;
     background: transparent;
-    color: #b1b1b7;
+    color: #909090;
     visibility: hidden;
 }
 
@@ -531,7 +554,7 @@
 }
 
 .modal-delete {
-    width: 350px;
+    width: 350px !important;
 }
 
 .step-element .header {
@@ -775,4 +798,126 @@
 
 .karavan .pf-c-select__menu-wrapper:hover, .karavan 
.pf-c-select__menu-item:hover {
     background-color: #fca338;
+}
+
+/*Beans*/
+.karavan .beans-page {
+    flex: 1 1;
+    overflow: auto;
+}
+.karavan .beans-page-columns {
+    height: 100%;
+    background: #fafafa;
+    display: flex;
+    flex-direction: row;
+}
+
+.karavan .beans-panel {
+    padding: 16px;
+    display: block;
+    flex-direction: column;
+    height: 100%;
+    width: 100%;
+    position: relative;
+    overflow-y: auto;
+}
+.karavan .beans-page .add-button-div {
+    width: 100%;
+    margin-top: 16px;
+    display: flex;
+}
+
+.karavan .beans-page .add-bean-button {
+    margin: auto;
+}
+
+.karavan .beans-page .bean-card-selected {
+    border-color: rgb(48, 50, 132);
+    background-color: rgb(171, 172, 224, 0.1);
+}
+
+.karavan .beans-page .bean-card-unselected {
+    border-color: #fb8824;
+    background-color: transparent;
+}
+
+.karavan .beans-page .bean-card,
+.karavan .beans-page .bean-card:hover {
+    border-radius: 20px;
+    border-width: 1px;
+    border-style: dotted;
+    box-shadow: none;
+}
+
+.karavan .beans-page .bean-card .pf-c-card__header {
+    padding-right: 6px;
+    word-wrap:anywhere;
+}
+
+.karavan .beans-page .bean-card .pf-c-card__body {
+    word-wrap:anywhere;
+}
+
+.karavan .beans-page .bean-card .icon {
+    height: 24px;
+}
+
+.karavan .beans-page .bean-card .delete-button {
+    position: absolute;
+    top: 4px;
+    right: 4px;
+    font-size: 14px;
+    line-height: 1;
+    border: 0;
+    padding: 0;
+    margin: 0;
+    background: transparent;
+    color: #909090;
+    visibility: hidden;
+}
+
+.karavan .beans-page .bean-card:hover .delete-button {
+    visibility: visible;
+}
+
+.karavan .beans-page .properties .bean-properties .pf-c-form__group-control {
+    display: flex;
+    flex-direction: column;
+    gap: 6px;
+}
+
+.karavan .beans-page .properties .bean-property {
+    display: flex;
+    flex-direction: row;
+    gap: 3px;
+}
+
+.karavan .beans-page .properties .bean-property .delete-button {
+    padding: 3px;
+    color: #b1b1b7;
+    font-size: 13px;
+}
+
+.karavan .templates-page,
+.karavan .exception-page,
+.karavan .error-page,
+.karavan .rest-page {
+    flex: 1;
+    overflow: auto;
+}
+
+.karavan .templates-page-columns,
+.karavan .exception-page-columns,
+.karavan .error-page-columns,
+.karavan .rest-page-columns {
+    height: 100%;
+    background: #fafafa;
+}
+
+.karavan .templates-page-columns .pf-c-empty-state,
+.karavan .exception-page-columns .pf-c-empty-state,
+.karavan .error-page-columns .pf-c-empty-state,
+.karavan .rest-page-columns .pf-c-empty-state {
+    margin: auto;
+    height: 100%;
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/rest/RestDesigner.tsx 
b/karavan-designer/src/designer/rest/RestDesigner.tsx
new file mode 100644
index 0000000..036b3e7
--- /dev/null
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+    PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from 
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+    onSave?: (integration: Integration) => void
+    integration: Integration
+    borderColor: string
+    borderColorSelected: string
+    dark: boolean
+}
+
+interface State {
+    integration: Integration
+    selectedStep?: CamelElement
+    key: string
+}
+
+export class RestDesigner extends React.Component<Props, State> {
+
+    public state: State = {
+        integration: this.props.integration,
+        key: "",
+    };
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevState.key !== this.state.key) {
+            this.props.onSave?.call(this, this.state.integration);
+        }
+    }
+
+    onIntegrationUpdate = (i: Integration) => {
+        this.setState({integration: i, key: Math.random().toString()});
+    }
+
+    render() {
+        return (
+            <PageSection className="rest-page" isFilled padding={{default: 
'noPadding'}}>
+                <div className="rest-page-columns">
+                    <EmptyState>
+                        <EmptyStateIcon icon={CubesIcon} />
+                        <Title headingLevel="h4" size="lg">
+                            REST
+                        </Title>
+                        <EmptyStateBody>
+                            Rest DSL not implemented yet
+                        </EmptyStateBody>
+                    </EmptyState>
+                </div>
+            </PageSection>
+        );
+    }
+}
diff --git a/karavan-designer/src/designer/DslConnections.tsx 
b/karavan-designer/src/designer/route/DslConnections.tsx
similarity index 98%
rename from karavan-designer/src/designer/DslConnections.tsx
rename to karavan-designer/src/designer/route/DslConnections.tsx
index c5dd52b..db82cc3 100644
--- a/karavan-designer/src/designer/DslConnections.tsx
+++ b/karavan-designer/src/designer/route/DslConnections.tsx
@@ -15,10 +15,10 @@
  * limitations under the License.
  */
 import React from 'react';
-import './karavan.css';
+import '../karavan.css';
 import {CamelElement, Integration} from 
"karavan-core/lib/model/CamelDefinition";
-import {DslPosition, EventBus} from "./EventBus";
-import {CamelUi} from "./CamelUi";
+import {DslPosition, EventBus} from "../utils/EventBus";
+import {CamelUi} from "../utils/CamelUi";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {Subscription} from "rxjs";
 
diff --git a/karavan-designer/src/designer/DslElement.tsx 
b/karavan-designer/src/designer/route/DslElement.tsx
similarity index 99%
rename from karavan-designer/src/designer/DslElement.tsx
rename to karavan-designer/src/designer/route/DslElement.tsx
index cda6016..f214a24 100644
--- a/karavan-designer/src/designer/DslElement.tsx
+++ b/karavan-designer/src/designer/route/DslElement.tsx
@@ -18,12 +18,12 @@ import React, {CSSProperties} from 'react';
 import {
     Text, Tooltip,
 } from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
 import AddIcon from "@patternfly/react-icons/dist/js/icons/plus-circle-icon";
 import DeleteIcon from 
"@patternfly/react-icons/dist/js/icons/times-circle-icon";
 import {CamelElement} from "karavan-core/lib/model/CamelDefinition";
-import {CamelUi} from "./CamelUi";
-import {EventBus} from "./EventBus";
+import {CamelUi} from "../utils/CamelUi";
+import {EventBus} from "../utils/EventBus";
 import {ChildElement, CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import ReactDOM from "react-dom";
 
diff --git a/karavan-designer/src/designer/DslProperties.tsx 
b/karavan-designer/src/designer/route/DslProperties.tsx
similarity index 84%
rename from karavan-designer/src/designer/DslProperties.tsx
rename to karavan-designer/src/designer/route/DslProperties.tsx
index e67305a..86f4a1e 100644
--- a/karavan-designer/src/designer/DslProperties.tsx
+++ b/karavan-designer/src/designer/route/DslProperties.tsx
@@ -23,10 +23,10 @@ import {
     Title,
     TextVariants,
 } from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
 import "@patternfly/patternfly/patternfly.css";
-import {DataFormatField} from "./field/DataFormatField";
-import {DslPropertyField} from "./field/DslPropertyField";
+import {DataFormatField} from "../field/DataFormatField";
+import {DslPropertyField} from "../field/DslPropertyField";
 import {
     CamelElement,
     Integration,
@@ -36,8 +36,9 @@ import {
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {CamelUi} from "./CamelUi";
+import {CamelUi} from "../utils/CamelUi";
 import {CamelMetadataApi, PropertyMeta} from 
"karavan-core/lib/model/CamelMetadata";
+import {IntegrationHeader} from "../utils/KaravanComponents";
 
 interface Props {
     integration: Integration,
@@ -47,7 +48,6 @@ interface Props {
 }
 
 interface State {
-    integration: Integration,
     step?: CamelElement,
     selectStatus: Map<string, boolean>
 }
@@ -56,7 +56,6 @@ export class DslProperties extends React.Component<Props, 
State> {
 
     public state: State = {
         step: this.props.step,
-        integration: this.props.integration,
         selectStatus: new Map<string, boolean>(),
     };
 
@@ -113,24 +112,6 @@ export class DslProperties extends React.Component<Props, 
State> {
         });
     }
 
-    getIntegrationHeader = (): JSX.Element => {
-        return (
-            <div className="headers">
-                <Title headingLevel="h1" size="md">Integration</Title>
-                <FormGroup label="Title" fieldId="title" isRequired>
-                    <TextInput className="text-field" type="text" id="title" 
name="title" isReadOnly
-                               value={
-                                   
CamelUi.titleFromName(this.state.integration.metadata.name)
-                               }/>
-                </FormGroup>
-                <FormGroup label="Name" fieldId="name" isRequired>
-                    <TextInput className="text-field" type="text" id="name" 
name="name" isReadOnly
-                               value={this.state.integration.metadata.name}/>
-                </FormGroup>
-            </div>
-        )
-    }
-
     getComponentHeader = (): JSX.Element => {
         const title = this.state.step && CamelUi.getTitle(this.state.step)
         const kamelet = this.state.step && CamelUi.getKamelet(this.state.step)
@@ -155,7 +136,7 @@ export class DslProperties extends React.Component<Props, 
State> {
         return (
             <div key={this.state.step ? this.state.step.uuid : 'integration'} 
className='properties'>
                 <Form autoComplete="off" onSubmit={event => 
event.preventDefault()}>
-                    {this.state.step === undefined && 
this.getIntegrationHeader()}
+                    {this.state.step === undefined && <IntegrationHeader 
integration={this.props.integration}/>}
                     {this.state.step && this.getComponentHeader()}
                     {this.state.step && !['MarshalDefinition', 
'UnmarshalDefinition'].includes(this.state.step.dslName) && 
this.getProps().map((property: PropertyMeta) =>
                         <DslPropertyField key={property.name}
diff --git a/karavan-designer/src/designer/DslSelector.tsx 
b/karavan-designer/src/designer/route/DslSelector.tsx
similarity index 97%
rename from karavan-designer/src/designer/DslSelector.tsx
rename to karavan-designer/src/designer/route/DslSelector.tsx
index 7636240..04c9e3e 100644
--- a/karavan-designer/src/designer/DslSelector.tsx
+++ b/karavan-designer/src/designer/route/DslSelector.tsx
@@ -21,9 +21,9 @@ import {
     Tab, Tabs, TabTitleText,
     Text, TextInput,
 } from '@patternfly/react-core';
-import './karavan.css';
-import {CamelUi} from "./CamelUi";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import '../karavan.css';
+import {CamelUi} from "../utils/CamelUi";
+import {DslMetaModel} from "../utils/DslMetaModel";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 
 interface Props {
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx 
b/karavan-designer/src/designer/route/RouteDesigner.tsx
similarity index 56%
copy from karavan-designer/src/designer/KaravanDesigner.tsx
copy to karavan-designer/src/designer/route/RouteDesigner.tsx
index d132ba2..0f16413 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/route/RouteDesigner.tsx
@@ -17,26 +17,25 @@
 import React from 'react';
 import {
     Button, Modal,
-    PageSection, Tab, Tabs, TabTitleIcon, TabTitleText, Tooltip,
+    PageSection
 } from '@patternfly/react-core';
-import './karavan.css';
+import '../karavan.css';
 import {DslSelector} from "./DslSelector";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import {DslMetaModel} from "../utils/DslMetaModel";
 import {DslProperties} from "./DslProperties";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelElement, FromDefinition, Integration} from 
"karavan-core/lib/model/CamelDefinition";
-import {CamelDefinitionYaml} from "karavan-core/lib/api/CamelDefinitionYaml";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelDefinitionApi} from "karavan-core/lib/api/CamelDefinitionApi";
 import {DslConnections} from "./DslConnections";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {DslElement} from "./DslElement";
-import {EventBus} from "./EventBus";
+import {EventBus} from "../utils/EventBus";
+import {CamelUi} from "../utils/CamelUi";
 
 interface Props {
-    onSave?: (filename: string, yaml: string) => void
-    filename: string
-    yaml: string
+    onSave?: (integration: Integration) => void
+    integration: Integration
     borderColor: string
     borderColorSelected: string
     dark: boolean
@@ -57,12 +56,10 @@ interface State {
     top: number
 }
 
-export class KaravanDesigner extends React.Component<Props, State> {
+export class RouteDesigner extends React.Component<Props, State> {
 
     public state: State = {
-        integration: this.props.yaml
-            ? CamelDefinitionYaml.yamlToIntegration(this.props.filename, 
this.props.yaml)
-            : Integration.createNew(this.props.filename),
+        integration: this.props.integration,
         showSelector: false,
         showDeleteConfirmation: false,
         parentId: '',
@@ -88,7 +85,7 @@ export class KaravanDesigner extends React.Component<Props, 
State> {
 
     componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
         if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, 
this.state.integration.metadata.name, this.getCode(this.state.integration));
+            this.props.onSave?.call(this, this.state.integration);
         }
     }
 
@@ -99,11 +96,6 @@ export class KaravanDesigner extends React.Component<Props, 
State> {
         }
     };
 
-    getCode = (integration: Integration): string => {
-        const clone = CamelUtil.cloneIntegration(integration);
-        return CamelDefinitionYaml.integrationToYaml(clone);
-    }
-
     onPropertyUpdate = (element: CamelElement, updatedUuid: string) => {
         const clone = CamelUtil.cloneIntegration(this.state.integration);
         const i = CamelDefinitionApiExt.updateIntegration(clone, element, 
updatedUuid);
@@ -240,13 +232,14 @@ export class KaravanDesigner extends 
React.Component<Props, State> {
     }
 
     getGraph() {
+        const integrations = CamelUi.getRoutes(this.state.integration);
         return (
             <div className="graph">
                 <DslConnections height={this.state.height} 
width={this.state.width} top={this.state.top} 
integration={this.state.integration}/>
                 <div className="flows" data-click="FLOWS" onClick={event => 
this.unselectElement(event)}
                      ref={el => this.onResizePage(el)}>
-                    {this.state.integration.spec.flows?.map((from: any, index: 
number) => (
-                        <DslElement key={from.uuid + this.state.key}
+                    {integrations?.map((route: any, index: number) => (
+                        <DslElement key={route.uuid + this.state.key}
                                     openSelector={this.openSelector}
                                     deleteElement={this.showDeleteConfirmation}
                                     selectElement={this.selectElement}
@@ -256,12 +249,12 @@ export class KaravanDesigner extends 
React.Component<Props, State> {
                                     
borderColorSelected={this.props.borderColorSelected}
                                     inSteps={false}
                                     position={index}
-                                    step={from}
+                                    step={route}
                                     parent={undefined}/>
                     ))}
                     <div className="add-flow">
                         <Button
-                            variant={this.state.integration.spec.flows?.length 
=== 0 ? "primary" : "secondary"}
+                            variant={integrations.length === 0 ? "primary" : 
"secondary"}
                             data-click="ADD_ROUTE"
                             icon={<PlusIcon/>}
                             onClick={e => this.openSelector(undefined, 
undefined)}>Add new route
@@ -271,101 +264,11 @@ export class KaravanDesigner extends 
React.Component<Props, State> {
             </div>)
     }
 
-    getTab(title: string, tooltip: string, icon: string) {
-        return (
-            <Tooltip position={"bottom"}
-                     content={<div>{tooltip}</div>}>
-                <div className="top-menu-item">
-                    <TabTitleIcon>{this.getIcon(icon)}</TabTitleIcon>
-                    <TabTitleText>{title}</TabTitleText>
-                </div>
-            </Tooltip>
-
-        )
-    }
-
-    getIcon(icon: string) {
-        if (icon === 'routes') return (
-            <svg className="top-icon" width="32px" height="32px" viewBox="0 0 
32 32" id="icon">
-                <defs>
-                    <style>{".cls-1{fill:none;}"}</style>
-                </defs>
-                <path 
d="M29,10H24v2h5v6H22v2h3v2.142a4,4,0,1,0,2,0V20h2a2.0027,2.0027,0,0,0,2-2V12A2.0023,2.0023,0,0,0,29,10ZM28,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,28,26Z"/>
-                <path 
d="M19,6H14V8h5v6H12v2h3v6.142a4,4,0,1,0,2,0V16h2a2.0023,2.0023,0,0,0,2-2V8A2.0023,2.0023,0,0,0,19,6ZM18,26a2,2,0,1,1-2-2A2.0027,2.0027,0,0,1,18,26Z"/>
-                <path
-                    
d="M9,2H3A2.002,2.002,0,0,0,1,4v6a2.002,2.002,0,0,0,2,2H5V22.142a4,4,0,1,0,2,0V12H9a2.002,2.002,0,0,0,2-2V4A2.002,2.002,0,0,0,9,2ZM8,26a2,2,0,1,1-2-2A2.0023,2.0023,0,0,1,8,26ZM3,10V4H9l.0015,6Z"/>
-                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32"/>
-            </svg>)
-        if (icon === 'rest') return (
-            <svg className="top-icon" viewBox="0 0 32 32">
-                <g className="layer">
-                    <title>Layer 1</title>
-                    <path
-                        d="m23.50007,22l-0.5,0l0,-2l0.5,0a4.4975,4.4975 0 0 0 
0.3564,-8.981l-0.8154,-0.0639l-0.0986,-0.812a6.9938,6.9938 0 0 0 
-13.8838,0l-0.0991,0.812l-0.8155,0.0639a4.4975,4.4975 0 0 0 
0.356,8.981l0.5,0l0,2l-0.5,0a6.4973,6.4973 0 0 1 -1.3,-12.8638a8.9943,8.9943 0 
0 1 17.6006,0a6.4974,6.4974 0 0 1 -1.3006,12.8638z"
-                        id="svg_1"/>
-                    <path
-                        d="m22.9724,22.26637l0,-2l-2.1011,0a4.9678,4.9678 0 0 
0 -0.7319,-1.7529l1.49,-1.49l-1.414,-1.414l-1.49,1.49a4.9678,4.9678 0 0 0 
-1.753,-0.732l0,-2.1011l-2,0l0,2.1011a4.9678,4.9678 0 0 0 
-1.7529,0.7319l-1.49,-1.49l-1.414,1.414l1.49,1.49a4.9678,4.9678 0 0 0 
-0.732,1.753l-2.1011,0l0,2l2.1011,0a4.9678,4.9678 0 0 0 
0.7319,1.7529l-1.49,1.49l1.414,1.414l1.49,-1.49a4.9678,4.9678 0 0 0 
1.753,0.732l0,2.1011l2,0l0,-2.1011a4.9678,4.9678 0 0 0 
1.7529,-0.7319l1.49,1.49l1.414,-1 [...]
-                        id="svg_2" transform="rotate(25 15.9724 21.2664)" 
xmlns="http://www.w3.org/2000/svg"/>
-                </g>
-            </svg>
-        )
-        if (icon === 'beans') return (
-            <svg className="top-icon" viewBox="0 0 536.243 536.242" >
-                <g>
-                    <path 
d="M471.053,197.07c-94.2-101.601-284-183.601-423.5-154.2c-9.2,1.8-12.9,9.2-12.2,16.5c-86.9,47.7,9.2,213,45.9,261.3
-                        
c72.2,96.1,200.701,203.2,329.901,173.8c60-13.5,103.399-69.8,120-126.1C550.053,304.77,513.253,242.37,471.053,197.07z
-                         
M393.353,465.17c-102.199,23.3-210.5-75.9-271.7-145c-61.2-70.4-108.3-155.4-71-243c83.8,151.8,253.4,269.3,414.9,321.899
-                        
c19.601,6.101,28.2-24.5,8.601-31.199C318.753,315.27,166.353,209.97,73.953,72.27c111.4-13.5,238.701,45.9,326.201,107.101
-                        
c50.199,35.5,98.5,87.5,102.8,151.8C505.954,394.17,451.454,451.67,393.353,465.17z"/>
-                </g>
-            </svg>
-        )
-        if (icon === 'error') return (
-            <svg className="top-icon" width="36px" height="36px" viewBox="0 0 
36 36" version="1.1" preserveAspectRatio="xMidYMid meet">
-                <circle className="clr-i-outline clr-i-outline-path-1" cx="18" 
cy="26.06" r="1.33"/>
-                <path className="clr-i-outline clr-i-outline-path-2" 
d="M18,22.61a1,1,0,0,1-1-1v-12a1,1,0,1,1,2,0v12A1,1,0,0,1,18,22.61Z"/>
-                <path className="clr-i-outline clr-i-outline-path-3" 
d="M18,34A16,16,0,1,1,34,18,16,16,0,0,1,18,34ZM18,4A14,14,0,1,0,32,18,14,14,0,0,0,18,4Z"/>
-                <rect x="0" y="0" width="36" height="36" fillOpacity="0"/>
-            </svg>)
-        if (icon === 'exception') return (
-            <svg className="top-icon" width="32px" height="32px" viewBox="0 0 
32 32" id="icon">
-                <defs>
-                    <style>{".cls-1{fill:none;}"}</style>
-                </defs>
-                <title>misuse--alt</title>
-                <polygon points="21.41 23 16 17.591 10.59 23 9 21.41 14.409 16 
9 10.591 10.591 9 16 14.409 21.409 9 23 10.591 17.591 16 23 21.41 21.41 23"/>
-                <path 
d="M16,4A12,12,0,1,1,4,16,12.0136,12.0136,0,0,1,16,4m0-2A14,14,0,1,0,30,16,14,14,0,0,0,16,2Z"
 transform="translate(0)"/>
-                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32"/>
-            </svg>)
-        if (icon === 'template') return (
-            <svg className="top-icon" width="32px" height="32px" viewBox="0 0 
32 32" id="icon" xmlns="http://www.w3.org/2000/svg";>
-                <defs>
-                    <style>{".cls-1{fill:none;}"}</style>
-                </defs>
-                <title>code</title>
-                <polygon points="31 16 24 23 22.59 21.59 28.17 16 22.59 10.41 
24 9 31 16"/>
-                <polygon points="1 16 8 9 9.41 10.41 3.83 16 9.41 21.59 8 23 1 
16"/>
-                <rect x="5.91" y="15" width="20.17" height="2" 
transform="translate(-3.6 27.31) rotate(-75)"/>
-                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32" transform="translate(0 
32) rotate(-90)"/>
-            </svg>)
-    }
-
     render() {
         return (
             <PageSection className="dsl-page" isFilled padding={{default: 
'noPadding'}}>
                 <div className="dsl-page-columns">
-                    <div style={{width: "100%"}}>
-                        <Tabs isFilled className="main-tabs" activeKey={0} 
onSelect={event => {
-                        }} style={{width: "100%"}}>
-                            <Tab eventKey={0} title={this.getTab("Routes", 
"Integration flows", "routes")}></Tab>
-                            <Tab eventKey={1} title={this.getTab("REST", "REST 
services","rest")}></Tab>
-                            <Tab eventKey={2} title={this.getTab("Beans", 
"Beans Configuration","beans")}></Tab>
-                            <Tab eventKey={3} 
title={this.getTab("Error","Error Handler configuration", "error")}></Tab>
-                            <Tab eventKey={4} 
title={this.getTab("Exceptions","Exception Clauses per type", 
"exception")}></Tab>
-                            <Tab eventKey={5} title={this.getTab("Templates", 
"Route Templates","template")}></Tab>
-                        </Tabs>
-                        {this.getGraph()}
-                    </div>
+                    {this.getGraph()}
                     <DslProperties
                         integration={this.state.integration}
                         step={this.state.selectedStep}
diff --git a/karavan-designer/src/designer/templates/TemplatesDesigner.tsx 
b/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
new file mode 100644
index 0000000..c49ed10
--- /dev/null
+++ b/karavan-designer/src/designer/templates/TemplatesDesigner.tsx
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {
+    Button, EmptyState, EmptyStateBody, EmptyStateIcon, Modal,
+    PageSection, Title
+} from '@patternfly/react-core';
+import '../karavan.css';
+import {CamelElement, Integration} from 
"karavan-core/lib/model/CamelDefinition";
+import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
+
+interface Props {
+    onSave?: (integration: Integration) => void
+    integration: Integration
+    borderColor: string
+    borderColorSelected: string
+    dark: boolean
+}
+
+interface State {
+    integration: Integration
+    selectedStep?: CamelElement
+    key: string
+}
+
+export class TemplatesDesigner extends React.Component<Props, State> {
+
+    public state: State = {
+        integration: this.props.integration,
+        key: "",
+    };
+
+    componentDidUpdate = (prevProps: Readonly<Props>, prevState: 
Readonly<State>, snapshot?: any) => {
+        if (prevState.key !== this.state.key) {
+            this.props.onSave?.call(this, this.state.integration);
+        }
+    }
+
+    onIntegrationUpdate = (i: Integration) => {
+        this.setState({integration: i, key: Math.random().toString()});
+    }
+
+    render() {
+        return (
+            <PageSection className="templates-page" isFilled 
padding={{default: 'noPadding'}}>
+                <div className="templates-page-columns">
+                    <EmptyState>
+                        <EmptyStateIcon icon={CubesIcon} />
+                        <Title headingLevel="h4" size="lg">
+                            Templates
+                        </Title>
+                        <EmptyStateBody>
+                            Templates not implemented yet
+                        </EmptyStateBody>
+                    </EmptyState>
+                </div>
+            </PageSection>
+        );
+    }
+}
diff --git a/karavan-designer/src/designer/CamelUi.ts 
b/karavan-designer/src/designer/utils/CamelUi.ts
similarity index 75%
rename from karavan-designer/src/designer/CamelUi.ts
rename to karavan-designer/src/designer/utils/CamelUi.ts
index de294da..5fdbd6d 100644
--- a/karavan-designer/src/designer/CamelUi.ts
+++ b/karavan-designer/src/designer/utils/CamelUi.ts
@@ -16,13 +16,14 @@
  */
 import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import {KameletModel, Property} from "karavan-core/lib/model/KameletModels";
-import {DslMetaModel} from "karavan-core/lib/model/DslMetaModel";
+import {DslMetaModel} from "./DslMetaModel";
 import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 import {ComponentProperty} from "karavan-core/lib/model/ComponentModels";
 import {CamelMetadataApi} from "karavan-core/lib/model/CamelMetadata";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelElement, KameletDefinition, RouteDefinition} from 
"karavan-core/lib/model/CamelDefinition";
+import {Bean, Beans, Integration} from 
"karavan-core/src/core/model/CamelDefinition";
 
 const StepElements: string[] = [
     "AggregateDefinition",
@@ -269,9 +270,9 @@ export class CamelUi {
             case "WhenDefinition":
                 return "data:image/svg+xml,%0A%3Csvg width='32px' 
height='32px' viewBox='0 0 32 32' id='icon' 
xmlns='http://www.w3.org/2000/svg'%3E%3Cdefs%3E%3Cstyle%3E.cls-1%7Bfill:none;%7D%3C/style%3E%3C/defs%3E%3Ctitle%3Eidea%3C/title%3E%3Crect
 x='11' y='24' width='10' height='2'/%3E%3Crect x='13' y='28' width='6' 
height='2'/%3E%3Cpath 
d='M16,2A10,10,0,0,0,6,12a9.19,9.19,0,0,0,3.46,7.62c1,.93,1.54,1.46,1.54,2.38h2c0-1.84-1.11-2.87-2.19-3.86A7.2,7.2,0,0,1,8,12a8,8,0,0,1,16,0,7.2,7.2,0,
 [...]
             case "AggregateDefinition":
-                return "data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' 
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' 
x='0px' y='0px' width='512px' height='640px' viewBox='0 0 512 640' 
enable-background='new 0 0 512 640' xml:space='preserve'%3E%3Cimage id='image0' 
width='512' height='640' x='0' y='0' 
href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKACAAAAADPo5/+AAAABGdBTUEAALGPC/xhBQAAACBjSFJN%0AAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3Ccul
 [...]
+                return "data:image/svg+xml,%3Csvg 
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' 
version='1.1' id='icon' x='0px' y='0px' width='32px' height='32px' viewBox='0 0 
32 32' style='enable-background:new 0 0 32 32;' xml:space='preserve'%3E%3Cstyle 
type='text/css'%3E .st0%7Bfill:none;%7D%0A%3C/style%3E%3Cpath 
d='M16,4c6.6,0,12,5.4,12,12s-5.4,12-12,12S4,22.6,4,16S9.4,4,16,4 
M16,2C8.3,2,2,8.3,2,16s6.3,14,14,14s14-6.3,14-14 S23.7,2,16,2z'/%3E%3Cpolygon 
[...]
             case "SplitDefinition":
-                return "data:image/svg+xml,%3Csvg version='1.1' id='Layer_1' 
xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' 
x='0px' y='0px' width='512px' height='640px' viewBox='0 0 512 640' 
enable-background='new 0 0 512 640' xml:space='preserve'%3E%3Cimage id='image0' 
width='512' height='640' x='0' y='0' 
href='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAgAAAAKACAAAAADPo5/+AAAABGdBTUEAALGPC/xhBQAAACBjSFJN%0AAAB6JgAAgIQAAPoAAACA6AAAdTAAAOpgAAA6mAAAF3Ccul
 [...]
+                return "data:image/svg+xml,%3Csvg 
xmlns='http://www.w3.org/2000/svg' width='32px' height='32px' viewBox='0 0 32 
32' id='icon'%3E%3Cdefs%3E%3Cstyle%3E .cls-1 %7B fill: none; %7D 
%3C/style%3E%3C/defs%3E%3Ctitle%3Esplit%3C/title%3E%3Crect x='15' y='20' 
width='2' height='4'/%3E%3Crect x='15' y='14' width='2' height='4'/%3E%3Crect 
x='15' y='8' width='2' height='4'/%3E%3Cpath 
d='M28,16A12.01,12.01,0,0,0,17,4.0508V2H15V4.0508a11.99,11.99,0,0,0,0,23.8984V30h2V27.9492A12.01,12.01,
 [...]
             case "SortDefinition":
                 return "data:image/svg+xml,%0A%3Csvg aria-hidden='true' 
focusable='false' data-prefix='fas' data-icon='sort-amount-down' 
class='svg-inline--fa fa-sort-amount-down fa-w-16' role='img' 
xmlns='http://www.w3.org/2000/svg' viewBox='0 0 512 512'%3E%3Cpath 
fill='currentColor' d='M304 416h-64a16 16 0 0 0-16 16v32a16 16 0 0 0 16 
16h64a16 16 0 0 0 16-16v-32a16 16 0 0 0-16-16zm-128-64h-48V48a16 16 0 0 
0-16-16H80a16 16 0 0 0-16 16v304H16c-14.19 0-21.37 17.24-11.29 27.31l80 96a16 
16 0 [...]
             case "ResequenceDefinition":
@@ -352,13 +353,30 @@ export class CamelUi {
         }
     }
 
-    static getIconForComponentLabel = (dslName: string): string => {
-        switch (dslName) {
-            case "messaging":
-                return "data:image/svg+xml,%3Csvg aria-hidden='true' 
focusable='false' data-prefix='fas' data-icon='filter' class='svg-inline--fa 
fa-filter fa-w-16' role='img' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 
512 512'%3E%3Cpath fill='currentColor' d='M487.976 0H24.028C2.71 0-8.047 25.866 
7.058 40.971L192 225.941V432c0 7.831 3.821 15.17 10.237 19.662l80 55.98C298.02 
518.69 320 507.493 320 487.98V225.941l184.947-184.97C520.021 25.896 509.338 0 
487.976 0z'%3E%3C/path%3E%3C/svg%3E";
-            default:
-                return defaultIcon;
+    static getFlowCounts = (i: Integration): Map<string, number> => {
+        const result = new Map<string, number>();
+        result.set('routes', i.spec.flows?.filter((e: any) => e.dslName === 
'RouteDefinition').length || 0);
+        const beans = i.spec.flows?.filter((e: any) => e.dslName === 'Beans');
+        if (beans && beans.length > 0 && beans[0].beans){
+            result.set('beans', Array.from(beans[0].beans).length);
+        }
+        return result;
+    }
+
+    static getRoutes = (integration: Integration): CamelElement[] => {
+        const result: CamelElement[] = [];
+        integration.spec.flows?.filter((e: any) => e.dslName === 
'RouteDefinition')
+            .forEach((f: any) => result.push(f));
+        return result;
+    }
+
+    static getBeans = (integration: Integration): Bean[] => {
+        const result: Bean[] = [];
+        const beans = integration.spec.flows?.filter((e: any) => e.dslName === 
'Beans');
+        if (beans && beans.length > 0 && beans[0].beans) {
+            result.push(...beans[0].beans);
         }
+        return result;
     }
 
 }
diff --git a/karavan-core/src/core/model/DslMetaModel.ts 
b/karavan-designer/src/designer/utils/DslMetaModel.ts
similarity index 100%
rename from karavan-core/src/core/model/DslMetaModel.ts
rename to karavan-designer/src/designer/utils/DslMetaModel.ts
diff --git a/karavan-designer/src/designer/EventBus.ts 
b/karavan-designer/src/designer/utils/EventBus.ts
similarity index 100%
rename from karavan-designer/src/designer/EventBus.ts
rename to karavan-designer/src/designer/utils/EventBus.ts
diff --git a/karavan-designer/src/designer/utils/KaravanComponents.tsx 
b/karavan-designer/src/designer/utils/KaravanComponents.tsx
new file mode 100644
index 0000000..c8ad23b
--- /dev/null
+++ b/karavan-designer/src/designer/utils/KaravanComponents.tsx
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+import {FormGroup, TextInput, Title} from "@patternfly/react-core";
+import {CamelUi} from "./CamelUi";
+import {Integration} from "karavan-core/lib/model/CamelDefinition";
+
+interface Props {
+    integration: Integration,
+}
+
+export class IntegrationHeader extends React.Component<Props> {
+
+    render() {
+        return (
+            <div className="headers">
+                <Title headingLevel="h1" size="md">Integration</Title>
+                <FormGroup label="Title" fieldId="title" isRequired>
+                    <TextInput className="text-field" type="text" id="title" 
name="title" isReadOnly
+                               value={
+                                   
CamelUi.titleFromName(this.props.integration.metadata.name)
+                               }/>
+                </FormGroup>
+                <FormGroup label="Name" fieldId="name" isRequired>
+                    <TextInput className="text-field" type="text" id="name" 
name="name" isReadOnly
+                               value={this.props.integration.metadata.name}/>
+                </FormGroup>
+            </div>
+        )
+    }
+}
diff --git a/karavan-designer/src/designer/utils/KaravanIcons.tsx 
b/karavan-designer/src/designer/utils/KaravanIcons.tsx
new file mode 100644
index 0000000..f2866a1
--- /dev/null
+++ b/karavan-designer/src/designer/utils/KaravanIcons.tsx
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import React from 'react';
+
+
+export class BeanIcon extends React.Component<any> {
+
+    render() {
+        return (
+            <svg className="icon" width="32px" height="32px" viewBox="0 0 32 
32">
+                <defs>
+                    <style>{".cls-1 {fill: none;}"}</style>
+                </defs>
+                <path
+                    
d="M28.5039,8.1362l-12-7a1,1,0,0,0-1.0078,0l-12,7A1,1,0,0,0,3,9V23a1,1,0,0,0,.4961.8638l12,7a1,1,0,0,0,1.0078,0l12-7A1,1,0,0,0,29,23V9A1,1,0,0,0,28.5039,8.1362ZM16,3.1577,26.0156,9,16,14.8423,5.9844,9ZM5,10.7412l10,5.833V28.2588L5,22.4258ZM17,28.2588V16.5742l10-5.833V22.4258Z"/>
+                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32"/>
+            </svg>
+        )
+    }
+}
+
+export class ConceptIcon extends React.Component<any> {
+
+    render() {
+        return (
+            <svg className="icon" width="32px" height="32px" viewBox="0 0 32 
32" >
+                <defs>
+                    <style>{".cls-1 {fill: none;}"}</style>
+                </defs>
+                <title>concept</title>
+                <path
+                    
d="M20.8851,19.4711a5.9609,5.9609,0,0,0,0-6.9422L23,10.4141l1.293,1.2929a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414l-4-4a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414L21.5859,9l-2.1148,2.1149a5.9609,5.9609,0,0,0-6.9422,0L10,8.5859V2H2v8H8.5859l2.529,2.5289a5.9609,5.9609,0,0,0,0,6.9422L9,21.5859,7.707,20.293a.9994.9994,0,0,0-1.414,0l-4,4a.9994.9994,0,0,0,0,1.414l4,4a.9995.9995,0,0,0,1.414,0l4-4a.9994.9994,0,0,0,0-1.414L10.4141,23l2.1148-2.1149a5.960
 [...]
+                <rect id="_Transparent_Rectangle_" data-name="&lt;Transparent 
Rectangle&gt;" className="cls-1" width="32" height="32"/>
+            </svg>
+        )
+    }
+}
\ No newline at end of file
diff --git a/karavan-generator/pom.xml b/karavan-generator/pom.xml
index f286a49..8457c9a 100644
--- a/karavan-generator/pom.xml
+++ b/karavan-generator/pom.xml
@@ -19,7 +19,7 @@
     <modelVersion>4.0.0</modelVersion>
     <groupId>org.apache.camel.karavan</groupId>
     <artifactId>karavan-generator</artifactId>
-    <version>0.0.11</version>
+    <version>0.0.12</version>
     <properties>
         <compiler-plugin.version>3.8.1</compiler-plugin.version>
         <maven.compiler.parameters>true</maven.compiler.parameters>
diff --git a/karavan-generator/src/main/resources/CamelDefinition.header.ts 
b/karavan-generator/src/main/resources/CamelDefinition.header.ts
index f43e85f..ebda5ea 100644
--- a/karavan-generator/src/main/resources/CamelDefinition.header.ts
+++ b/karavan-generator/src/main/resources/CamelDefinition.header.ts
@@ -53,13 +53,32 @@ export class CamelElement {
     }
 }
 
+export class Beans extends CamelElement {
+    beans: Bean[] = []
+
+    public constructor(init?: Partial<Beans>) {
+        super("Beans")
+        Object.assign(this, init);
+    }
+}
+
+export class Bean extends CamelElement {
+    name: string = ''
+    type: string = ''
+    properties: any
+
+    public constructor(init?: Partial<Bean>) {
+        super("Bean")
+        Object.assign(this, init);
+    }
+}
+
 export class CamelElementMeta {
     step?: CamelElement
     parentUuid?: string
     position: number = 0;
     pathUuids: string [] = [];
 
-
     constructor(step?: CamelElement, parentUuid?: string, position?: number, 
pathUuids?: string []) {
         this.step = step;
         this.parentUuid = parentUuid;
diff --git a/karavan-vscode/package.json b/karavan-vscode/package.json
index 660c0a3..6358f23 100644
--- a/karavan-vscode/package.json
+++ b/karavan-vscode/package.json
@@ -4,7 +4,7 @@
   "displayName": "Camel Karavan Designer",
   "icon": "icons/icon.png",
   "description": "Integration Designer for Apache Camel",
-  "version": "0.0.11",
+  "version": "0.0.12",
   "license": "Apache-2.0",
   "preview": true,
   "bugs": {
@@ -151,13 +151,13 @@
     }
   },
   "scripts": {
-    "vscode:prepublish": "cp -r ../karavan-designer/src/designer . && yarn run 
package",
-    "compile": "cp -r ../karavan-designer/src/designer . && cross-env 
NODE_ENV=development webpack --progress",
-    "watch": "cp -r ../karavan-designer/src/designer . && cross-env 
NODE_ENV=development webpack --progress --watch",
-    "package": "cp -r ../karavan-designer/src/designer . && cross-env 
NODE_ENV=production webpack --progress",
+    "vscode:prepublish": "cp -r ../karavan-designer/src/designer webview && 
yarn run package",
+    "compile": "cp -r ../karavan-designer/src/designer webview && cross-env 
NODE_ENV=development webpack --progress",
+    "watch": "cp -r ../karavan-designer/src/designer webview && cross-env 
NODE_ENV=development webpack --progress --watch",
+    "package": "cp -r ../karavan-designer/src/designer webview  && cross-env 
NODE_ENV=production webpack --progress",
     "test-compile": "tsc -p ./",
     "test-watch": "tsc -watch -p ./",
-    "pretest": "cp -r ../karavan-designer/src/designer . && yarn run 
test-compile && yarn run lint",
+    "pretest": "cp -r ../karavan-designer/src/designer webview && yarn run 
test-compile && yarn run lint",
     "lint": "eslint src webview --ext .ts,.tsx",
     "lint:fix": "eslint --fix src webview --ext .ts,.tsx",
     "test": "node ./out/test/runTest.js"
diff --git a/karavan-vscode/webview/App.tsx b/karavan-vscode/webview/App.tsx
index 11d27c2..c833189 100644
--- a/karavan-vscode/webview/App.tsx
+++ b/karavan-vscode/webview/App.tsx
@@ -18,7 +18,7 @@ import * as React from "react";
 import {
   Page,
 } from "@patternfly/react-core";
-import {KaravanDesigner} from "../designer/KaravanDesigner";
+import {KaravanDesigner} from "./designer/KaravanDesigner";
 import vscode from "./vscode";
 import {KameletApi} from "karavan-core/lib/api/KameletApi";
 import { ComponentApi } from "karavan-core/lib/api/ComponentApi";
diff --git a/karavan-vscode/webview/index.css b/karavan-vscode/webview/index.css
index a062dba..689c7a2 100644
--- a/karavan-vscode/webview/index.css
+++ b/karavan-vscode/webview/index.css
@@ -17,6 +17,8 @@ body,
   --pf-global--link--Color--light--hover: rgb(239, 166, 79) !important;
   --pf-global--link--Color--dark: rgb(239, 166, 79) !important;
   --pf-global--link--Color--dark--hover: rgb(235, 146, 40) !important;
+
+  --pf-global--active-color--100: rgb(247, 205, 159) !important;
 }
 
 .vscode-dark .karavan {
@@ -27,15 +29,28 @@ body,
   fill: rgb(255, 255, 255);
 }
 
+.vscode-dark .karavan .main-tabs {
+  background-color: rgb(37, 37, 38);
+}
+
 .vscode-dark .karavan .main-tabs .pf-c-tabs__list {
     background-color: rgb(37, 37, 38);
 }
 
+.vscode-dark .karavan .main-tabs::before {
+  border-color: rgb(37, 37, 38);
+}
+
 .vscode-dark .karavan .main-tabs .pf-c-tabs__item.pf-m-current {
   background-color: rgb(30, 30, 30);
 }
 
-.vscode-dark .karavan .dsl-page .dsl-page-columns {
+.vscode-dark .karavan .dsl-page .dsl-page-columns,
+.vscode-dark .karavan .rest-page .rest-page-columns,
+.vscode-dark .karavan .beans-page .beans-page-columns,
+.vscode-dark .karavan .error-page .error-page-columns,
+.vscode-dark .karavan .exception-page .exception-page-columns,
+.vscode-dark .karavan .templates-page .templates-page-columns {  
   background-color: rgb(50, 50, 50);
 }
 
@@ -76,17 +91,21 @@ body,
     background-color: rgb(50, 50, 50, 0.5);
 }
 
-.vscode-dark .karavan .dsl-page .properties {
+.vscode-dark .karavan .properties {
   border: none;
   background: rgb(37, 37, 38);
 }
 
-.vscode-dark .karavan .dsl-page .properties .text-field {
+.vscode-dark .karavan .properties .text-field {
     background-color: rgb(50, 50, 50);
     border-color: rgb(50, 50, 50);
     color: rgb(255, 255, 255);
 }
 
+.vscode-dark .karavan .properties .add-button {
+  color: var(--pf-global--active-color--100);
+}
+
 .vscode-dark .pf-c-select {
   --pf-c-select__toggle--BackgroundColor: #3B3B3B;
   --pf-c-select__toggle--before--BorderTopColor: #3B3B3B;
@@ -101,15 +120,15 @@ body,
   box-shadow: var(--pf-c-select__menu--BoxShadow);
 }
 
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__menu-item {
+.vscode-dark .karavan .properties .pf-c-select__menu-item {
   color: rgb(255, 255, 255);
 }
 
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__menu-item:hover {
+.vscode-dark .karavan .properties .pf-c-select__menu-item:hover {
   color: black;
 }
 
-.vscode-dark .karavan .dsl-page .properties .pf-c-select__toggle-typeahead {
+.vscode-dark .karavan .properties .pf-c-select__toggle-typeahead {
   color: rgb(255, 255, 255);
 }
 
@@ -186,7 +205,7 @@ body,
   color: rgb(255, 255, 255);
 }
 
-.vscode-dark .karavan .dsl-page .properties .pf-c-text-input-group {
+.vscode-dark .karavan .properties .pf-c-text-input-group {
   background-color: rgb(50, 50, 50);
   border-color: #3B3B3B;
   color: rgb(255, 255, 255);
@@ -194,7 +213,7 @@ body,
   --pf-c-text-input-group__text--after--BorderBottomColor: transparent;
 }
 
-.vscode-dark .karavan .dsl-page .properties .input-group .pf-c-chip-group 
.pf-c-chip {
+.vscode-dark .karavan .properties .input-group .pf-c-chip-group .pf-c-chip {
   --pf-c-chip--BackgroundColor: transparent;
   --pf-c-chip__text--Color: white;
   --pf-c-chip--before--BorderColor: grey;
@@ -211,13 +230,49 @@ body,
   color: rgb(239, 166, 79);
 }
 
-.vscode-dark .karavan .dsl-page .properties .expression,
-.vscode-dark .karavan .dsl-page .properties .object,
-.vscode-dark .karavan .dsl-page .properties .dataformat,
-.vscode-dark .karavan .dsl-page .properties .parameters {
+.vscode-dark .karavan .properties .expression,
+.vscode-dark .karavan .properties .object,
+.vscode-dark .karavan .properties .dataformat,
+.vscode-dark .karavan .properties .parameters {
     border-style: none;
 }
 
 .vscode-dark .modal-delete {
   width: 350px;
+  --pf-c-modal-box--BackgroundColor: #505050;
 }
+
+/* Bean */
+.vscode-dark .karavan .beans-page {
+  --pf-c-page__main-section--BackgroundColor: 
var(--pf-c-page__main-section--m-dark-100--BackgroundColor);
+}
+
+.vscode-dark .karavan .beans-page .add-bean-button {
+  color: rgb(239, 166, 79);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-unselected {
+  border-color: rgb(239, 166, 79);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected {
+  color: rgb(171, 172, 224);
+  border-color: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected {
+  background-color: rgb(37, 37, 38, 0.7);
+  color: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-selected .icon {
+  fill: rgb(171, 172, 224);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card:hover {
+  box-shadow: 0 0.01rem 0.001rem 0rem rgb(247 205 159 / 13%), 0 0.1rem 0.5rem 
0.1rem rgb(247 205 159 / 12%);
+}
+
+.vscode-dark .beans-page .beans-page-columns .bean-card-unselected .icon {
+  fill: white;
+}
\ No newline at end of file

Reply via email to