You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by ma...@apache.org on 2022/12/21 23:04:59 UTC

[camel-karavan] branch main updated: Fix #576

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 ab8ac92  Fix #576
ab8ac92 is described below

commit ab8ac92559d24ecc91fd18c1ab48615467f47617
Author: Marat Gubaidullin <ma...@gmail.com>
AuthorDate: Wed Dec 21 18:04:50 2022 -0500

    Fix #576
---
 karavan-core/src/core/api/CamelDefinitionApiExt.ts | 35 +++++----
 karavan-core/src/core/api/CamelDefinitionYaml.ts   |  6 +-
 karavan-core/src/core/api/CamelUtil.ts             | 20 +++---
 karavan-core/test/errorHandler.spec.ts             |  8 ++-
 karavan-core/test/errorHandler1.yaml               | 17 ++---
 karavan-core/test/plain.spec.ts                    |  2 -
 karavan-designer/src/designer/KaravanDesigner.tsx  |  6 +-
 .../RouteConfigurationCard.tsx}                    | 26 ++++---
 .../RouteConfigurationDesigner.tsx}                | 82 ++++++++++++----------
 .../src/designer/exception/ExceptionDesigner.tsx   | 74 -------------------
 .../src/designer/rest/RestDesigner.tsx             |  2 +-
 karavan-designer/src/designer/utils/CamelUi.tsx    | 12 ++--
 .../src/designer/utils/KaravanIcons.tsx            | 15 ++--
 13 files changed, 131 insertions(+), 174 deletions(-)

diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 3317253..a72b7f0 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -19,7 +19,7 @@ import {ComponentApi} from "./ComponentApi";
 import {CamelUtil} from "./CamelUtil";
 import {
     NamedBeanDefinition,
-    ExpressionDefinition, RouteDefinition, RestDefinition, RestConfigurationDefinition, ErrorHandlerDefinition
+    ExpressionDefinition, RouteDefinition, RestDefinition, RestConfigurationDefinition, RouteConfigurationDefinition
 } from "../model/CamelDefinition";
 import {
     Beans,
@@ -253,28 +253,33 @@ export class CamelDefinitionApiExt {
         return integration;
     }
 
-    static addErrorHandlerToIntegration = (integration: Integration, errorHandler: ErrorHandlerDefinition): Integration => {
-        const flows: any[] = [];
-        if (integration.spec.flows?.filter(flow => flow.dslName === 'ErrorHandlerDefinition').length === 0) {
-            flows.push(...integration.spec.flows);
-            flows.push(errorHandler)
-        } else {
-            flows.push(...integration.spec.flows?.filter(flow => flow.dslName !== 'ErrorHandlerDefinition') || []);
-            flows.push(errorHandler)
-        }
-        integration.spec.flows = flows;
+    static addRouteConfigurationToIntegration = (integration: Integration, routeConfiguration: RouteConfigurationDefinition): Integration => {
+        integration.spec.flows?.push(routeConfiguration);
         return integration;
     }
 
-    static deleteErrorHandlerFromIntegration = (integration: Integration): Integration => {
+    static deleteRouteConfigurationFromIntegration = (integration: Integration, routeConfiguration: RouteConfigurationDefinition): Integration => {
         const flows: any[] = [];
-        flows.push(...integration.spec.flows?.filter(flow => flow.dslName !== 'ErrorHandlerDefinition') || []);
+        flows.push(...integration.spec.flows?.filter(flow => flow.dslName !== 'RouteConfigurationDefinition') || []);
+        flows.push(...integration.spec.flows?.filter(flow => flow.dslName == 'RouteConfigurationDefinition' && flow.uuid !== routeConfiguration.uuid) || []);
         integration.spec.flows = flows;
         return integration;
     }
 
+    static updateRouteConfigurationToIntegration = (integration: Integration, e: CamelElement): Integration => {
+        const elementClone = CamelUtil.cloneStep(e);
+        const int: Integration = CamelUtil.cloneIntegration(integration);
+        const flows: CamelElement[] = [];
+        integration.spec.flows?.filter(f => f.dslName !== 'RouteConfigurationDefinition').forEach(f => flows.push(f));
+        integration.spec.flows?.filter(f => f.dslName === 'RouteConfigurationDefinition').forEach(f => {
+            const route = CamelDefinitionApiExt.updateElement(f, elementClone) as RouteConfigurationDefinition;
+            flows.push(CamelDefinitionApi.createRouteConfigurationDefinition(route));
+        })
+        int.spec.flows = flows
+        return int;
+    }
+
     static addRestToIntegration = (integration: Integration, rest: RestDefinition): Integration => {
-        const flows: any[] = [];
         integration.spec.flows?.push(rest)
         return integration;
     }
@@ -351,7 +356,7 @@ export class CamelDefinitionApiExt {
 
     static deleteRestConfigurationFromIntegration = (integration: Integration): Integration => {
         const flows: any[] = [];
-        integration.spec.flows?.filter(flow => flow.dslName !== 'RestConfigurationDefinition').forEach(x => flows.push(x));
+        integration.spec.flows?.filter(flow => flow.dslName !== 'RestConfiguration').forEach(x => flows.push(x));
         integration.spec.flows = flows;
         return integration;
     }
diff --git a/karavan-core/src/core/api/CamelDefinitionYaml.ts b/karavan-core/src/core/api/CamelDefinitionYaml.ts
index cbb5bdb..8aff38b 100644
--- a/karavan-core/src/core/api/CamelDefinitionYaml.ts
+++ b/karavan-core/src/core/api/CamelDefinitionYaml.ts
@@ -121,6 +121,8 @@ export class CamelDefinitionYaml {
                 || stepName === 'doFinally'
                 || stepName === 'resilience4jConfiguration'
                 || stepName === 'faultToleranceConfiguration'
+                || stepName === 'errorHandler'
+                || stepName === 'onException'
                 || stepName === 'deadLetterChannel'
                 || stepName === 'defaultErrorHandler'
                 || stepName === 'jtaTransactionErrorHandler'
@@ -184,8 +186,8 @@ export class CamelDefinitionYaml {
             .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)));
-        flows.filter((e: any) => e.hasOwnProperty('errorHandler'))
-            .forEach((e: any) => result.push(CamelDefinitionYamlStep.readErrorHandlerDefinition(e.errorHandler)));
+        flows.filter((e: any) => e.hasOwnProperty('routeConfiguration'))
+            .forEach((e: any) => result.push(CamelDefinitionYamlStep.readRouteConfigurationDefinition(e.routeConfiguration)));
         return result;
     }
 
diff --git a/karavan-core/src/core/api/CamelUtil.ts b/karavan-core/src/core/api/CamelUtil.ts
index 762e83b..914ac57 100644
--- a/karavan-core/src/core/api/CamelUtil.ts
+++ b/karavan-core/src/core/api/CamelUtil.ts
@@ -19,7 +19,7 @@ import {
     CamelElement, Beans
 } from "../model/IntegrationDefinition";
 import {CamelDefinitionApi} from "./CamelDefinitionApi";
-import {ErrorHandlerDefinition, KameletDefinition, NamedBeanDefinition, ToDefinition} from "../model/CamelDefinition";
+import {KameletDefinition, NamedBeanDefinition, RouteConfigurationDefinition, ToDefinition} from "../model/CamelDefinition";
 import {KameletApi} from "./KameletApi";
 import {KameletModel, Property} from "../model/KameletModels";
 import {ComponentProperty} from "../model/ComponentModels";
@@ -41,10 +41,10 @@ export class CamelUtil {
                 (beans as Beans).beans.forEach(b => newBeans.beans.push(CamelUtil.cloneBean(b)));
                 flows.push(newBeans);
             });
-        int.spec.flows?.filter((e: any) => e.dslName === 'ErrorHandler')
-            .forEach(errorHandler => {
-                const newErrorHandler = CamelUtil.cloneErrorHandler(errorHandler);
-                flows.push(newErrorHandler);
+        int.spec.flows?.filter((e: any) => e.dslName === 'RouteConfiguration')
+            .forEach(routeConfiguration => {
+                const newRouteConfiguration = CamelUtil.cloneRouteConfiguration(routeConfiguration);
+                flows.push(newRouteConfiguration);
             });
         int.spec.flows = flows;
         return int;
@@ -62,11 +62,11 @@ export class CamelUtil {
         return newBean;
     }
 
-    static cloneErrorHandler = (error: ErrorHandlerDefinition): ErrorHandlerDefinition => {
-        const clone = JSON.parse(JSON.stringify(error));
-        const newError = new ErrorHandlerDefinition(clone);
-        newError.uuid = error.uuid;
-        return newError;
+    static cloneRouteConfiguration = (routeConfiguration: RouteConfigurationDefinition): RouteConfigurationDefinition => {
+        const clone = JSON.parse(JSON.stringify(routeConfiguration));
+        const RouteConfiguration = new RouteConfigurationDefinition(clone);
+        RouteConfiguration.uuid = routeConfiguration.uuid;
+        return RouteConfiguration;
     }
 
     static capitalizeName = (name: string) => {
diff --git a/karavan-core/test/errorHandler.spec.ts b/karavan-core/test/errorHandler.spec.ts
index 051d3ff..4d5ff87 100644
--- a/karavan-core/test/errorHandler.spec.ts
+++ b/karavan-core/test/errorHandler.spec.ts
@@ -28,8 +28,10 @@ describe('Global Error Handler', () => {
         expect(i.metadata.name).to.equal('errorHandler1.yaml');
         expect(i.spec.flows?.length).to.equal(2);
         expect(i.type).to.equal('plain');
-        expect(i.spec.flows?.[1].deadLetterChannel.deadLetterUri).to.equal('log:dlq');
-        expect(i.spec.flows?.[1].deadLetterChannel.useOriginalMessage).to.equal(true);
-        expect(i.spec.flows?.[1].deadLetterChannel.level).to.equal('TRACE');
+        expect(i.spec.flows?.[1].errorHandler.deadLetterChannel.deadLetterUri).to.equal('log:dlq');
+        expect(i.spec.flows?.[1].errorHandler.deadLetterChannel.useOriginalMessage).to.equal(true);
+        expect(i.spec.flows?.[1].errorHandler.deadLetterChannel.level).to.equal('TRACE');
+        const yaml2 = CamelDefinitionYaml.integrationToYaml(i);
+        expect(yaml).to.equal(yaml2);
     });
 });
\ No newline at end of file
diff --git a/karavan-core/test/errorHandler1.yaml b/karavan-core/test/errorHandler1.yaml
index 29eabd7..680be14 100644
--- a/karavan-core/test/errorHandler1.yaml
+++ b/karavan-core/test/errorHandler1.yaml
@@ -1,11 +1,9 @@
-- errorHandler:
-    deadLetterChannel:
-      deadLetterUri: log:dlq
-      level: TRACE
-      useOriginalMessage: true
 - route:
     from:
       uri: kamelet:timer-source
+      parameters:
+        period: 1000
+        message: '1'
       steps:
         - setBody:
             expression:
@@ -13,6 +11,9 @@
                 expression: 1000 / 0
         - log:
             message: $[body}
-      parameters:
-        period: 1000
-        message: '1'
\ No newline at end of file
+- routeConfiguration:
+    errorHandler:
+      deadLetterChannel:
+        deadLetterUri: log:dlq
+        level: TRACE
+        useOriginalMessage: true
diff --git a/karavan-core/test/plain.spec.ts b/karavan-core/test/plain.spec.ts
index c6dafc4..d886128 100644
--- a/karavan-core/test/plain.spec.ts
+++ b/karavan-core/test/plain.spec.ts
@@ -58,8 +58,6 @@ describe('Plain YAML to integration', () => {
         expect(i.spec.flows?.length).to.equal(1);
         expect(i.type).to.equal('plain');
         const yaml2 = CamelDefinitionYaml.integrationToYaml(i);
-        console.log(i.spec.flows?.[0].from)
-        console.log(yaml2)
         expect(yaml).to.equal(yaml2);
     });
 
diff --git a/karavan-designer/src/designer/KaravanDesigner.tsx b/karavan-designer/src/designer/KaravanDesigner.tsx
index b215192..b4ac345 100644
--- a/karavan-designer/src/designer/KaravanDesigner.tsx
+++ b/karavan-designer/src/designer/KaravanDesigner.tsx
@@ -27,7 +27,7 @@ import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelUi} from "./utils/CamelUi";
 import {BeansDesigner} from "./beans/BeansDesigner";
 import {RestDesigner} from "./rest/RestDesigner";
-import {ErrorHandlerDesigner} from "./error/ErrorHandlerDesigner";
+import {RouteConfigurationDesigner} from "./configuration/RouteConfigurationDesigner";
 import {getDesignerIcon} from "./utils/KaravanIcons";
 
 interface Props {
@@ -132,7 +132,7 @@ export class KaravanDesigner extends React.Component<Props, State> {
                     <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 Handler", "Global Error Handler", "error")}></Tab>
+                    <Tab eventKey='routeConfiguration' title={this.getTab("Configuration", "Route Configuration", "routeConfiguration")}></Tab>
                 </Tabs>
                     {tab === 'routes' && <RouteDesigner integration={this.state.integration}
                                                         onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
@@ -144,7 +144,7 @@ export class KaravanDesigner extends React.Component<Props, State> {
                     {tab === 'beans' && <BeansDesigner integration={this.state.integration}
                                                        onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
                                                        dark={this.props.dark}/>}
-                    {tab === 'error' && <ErrorHandlerDesigner integration={this.state.integration}
+                    {tab === 'routeConfiguration' && <RouteConfigurationDesigner integration={this.state.integration}
                                                               onSave={(integration, propertyOnly) => this.save(integration, propertyOnly)}
                                                               dark={this.props.dark}/>}
             </PageSection>
diff --git a/karavan-designer/src/designer/error/ErrorHandlerCard.tsx b/karavan-designer/src/designer/configuration/RouteConfigurationCard.tsx
similarity index 54%
rename from karavan-designer/src/designer/error/ErrorHandlerCard.tsx
rename to karavan-designer/src/designer/configuration/RouteConfigurationCard.tsx
index f0d534c..c4f1940 100644
--- a/karavan-designer/src/designer/error/ErrorHandlerCard.tsx
+++ b/karavan-designer/src/designer/configuration/RouteConfigurationCard.tsx
@@ -19,27 +19,37 @@ import {
     Button
 } from '@patternfly/react-core';
 import '../karavan.css';
-import {ErrorHandlerDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {RouteConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition";
 import DeleteIcon from "@patternfly/react-icons/dist/js/icons/times-circle-icon";
+import {CamelElement} from "../../../../karavan-core/src/core/model/IntegrationDefinition";
 
 interface Props {
-    errorHandler: ErrorHandlerDefinition
-    deleteElement: (element: ErrorHandlerDefinition) => void
+    routeConfiguration: RouteConfigurationDefinition
+    selectedStep?: CamelElement
+    deleteElement: (element: RouteConfigurationDefinition) => void
+    selectElement: (element: RouteConfigurationDefinition) => void
 }
 
-export class ErrorHandlerCard extends React.Component<Props, any> {
+export class RouteConfigurationCard extends React.Component<Props, any> {
+
+    selectElement = (evt: React.MouseEvent) => {
+        evt.stopPropagation();
+        this.props.selectElement.call(this, this.props.routeConfiguration);
+    }
 
     delete = (evt: React.MouseEvent) => {
         evt.stopPropagation();
-        this.props.deleteElement.call(this, this.props.errorHandler);
+        this.props.deleteElement.call(this, this.props.routeConfiguration);
     }
 
     render() {
+        const {selectedStep, routeConfiguration} = this.props;
         return (
-            <div className="rest-card rest-card-selected">
+            <div className={selectedStep?.uuid === routeConfiguration.uuid ? "rest-card rest-card-selected" : "rest-card rest-card-unselected"}
+                 onClick={e => this.selectElement(e)}>
                 <div className="header">
-                    <div className="title">Error Handler</div>
-                    <div className="description">Global error handler for the RouteBuilder</div>
+                    <div className="title">Route Configuration</div>
+                    <div className="description">Route Configuration</div>
                     <Button variant="link" className="delete-button" onClick={e => this.delete(e)}><DeleteIcon/></Button>
                 </div>
             </div>
diff --git a/karavan-designer/src/designer/error/ErrorHandlerDesigner.tsx b/karavan-designer/src/designer/configuration/RouteConfigurationDesigner.tsx
similarity index 66%
rename from karavan-designer/src/designer/error/ErrorHandlerDesigner.tsx
rename to karavan-designer/src/designer/configuration/RouteConfigurationDesigner.tsx
index ba35ccc..d7fdb61 100644
--- a/karavan-designer/src/designer/error/ErrorHandlerDesigner.tsx
+++ b/karavan-designer/src/designer/configuration/RouteConfigurationDesigner.tsx
@@ -19,13 +19,13 @@ import {
     Button, Drawer, DrawerContent, DrawerContentBody, DrawerPanelContent, Modal, PageSection
 } from '@patternfly/react-core';
 import '../karavan.css';
-import {ErrorHandlerDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {RouteConfigurationDefinition} from "karavan-core/lib/model/CamelDefinition";
 import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {CamelUi} from "../utils/CamelUi";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {CamelDefinitionApiExt} from "karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
-import {ErrorHandlerCard} from "./ErrorHandlerCard";
+import {RouteConfigurationCard} from "./RouteConfigurationCard";
 import {DslProperties} from "../route/DslProperties";
 
 interface Props {
@@ -37,15 +37,17 @@ interface Props {
 interface State {
     integration: Integration
     showDeleteConfirmation: boolean
-    errorHandler?: ErrorHandlerDefinition
+    routeConfigurations: RouteConfigurationDefinition[]
+    selectedRouteConfiguration?: RouteConfigurationDefinition
     key: string
     propertyOnly: boolean
 }
 
-export class ErrorHandlerDesigner extends React.Component<Props, State> {
+export class RouteConfigurationDesigner extends React.Component<Props, State> {
 
     public state: State = {
         integration: this.props.integration,
+        routeConfigurations: [],
         showDeleteConfirmation: false,
         key: "",
         propertyOnly: false
@@ -61,29 +63,26 @@ export class ErrorHandlerDesigner extends React.Component<Props, State> {
         }
     }
 
-    showDeleteConfirmation = (errorHandler: ErrorHandlerDefinition) => {
-        this.setState({errorHandler: errorHandler, showDeleteConfirmation: true});
+    showDeleteConfirmation = (routeConfiguration: RouteConfigurationDefinition) => {
+        this.setState({selectedRouteConfiguration: routeConfiguration, showDeleteConfirmation: true});
     }
 
     onIntegrationUpdate = (i: Integration) => {
         this.setState({integration: i, propertyOnly: false, showDeleteConfirmation: false, key: Math.random().toString()});
     }
 
-    deleteErrorHandler = () => {
-        const i = CamelDefinitionApiExt.deleteErrorHandlerFromIntegration(this.state.integration);
-        this.setState({
-            integration: i,
-            showDeleteConfirmation: false,
-            key: Math.random().toString(),
-            errorHandler: undefined,
-            propertyOnly: false
-        });
-    }
-
-    changeErrorHandler = (errorHandler: ErrorHandlerDefinition) => {
-        const clone = CamelUtil.cloneIntegration(this.state.integration);
-        const i = CamelDefinitionApiExt.addErrorHandlerToIntegration(clone, errorHandler);
-        this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), errorHandler: errorHandler});
+    deleteRouteConfiguration = () => {
+        const {selectedRouteConfiguration} = this.state;
+        if (selectedRouteConfiguration) {
+            const i = CamelDefinitionApiExt.deleteRouteConfigurationFromIntegration(this.state.integration, selectedRouteConfiguration);
+            this.setState({
+                integration: i,
+                showDeleteConfirmation: false,
+                key: Math.random().toString(),
+                selectedRouteConfiguration: undefined,
+                propertyOnly: false
+            });
+        }
     }
 
     getDeleteConfirmation() {
@@ -93,33 +92,40 @@ export class ErrorHandlerDesigner extends React.Component<Props, State> {
             isOpen={this.state.showDeleteConfirmation}
             onClose={() => this.setState({showDeleteConfirmation: false})}
             actions={[
-                <Button key="confirm" variant="primary" onClick={e => this.deleteErrorHandler()}>Delete</Button>,
+                <Button key="confirm" variant="primary" onClick={e => this.deleteRouteConfiguration()}>Delete</Button>,
                 <Button key="cancel" variant="link"
                         onClick={e => this.setState({showDeleteConfirmation: false})}>Cancel</Button>
             ]}
             onEscapePress={e => this.setState({showDeleteConfirmation: false})}>
             <div>
-                Delete Global Error Handler from integration?
+                Delete Route Configuration from integration?
             </div>
         </Modal>)
     }
 
-    createErrorHandlerErrorHandle = () => {
-        this.changeErrorHandler(new ErrorHandlerDefinition());
+    createRouteConfiguration = () => {
+        const clone = CamelUtil.cloneIntegration(this.state.integration);
+        const routeConfiguration = new RouteConfigurationDefinition();
+        const i = CamelDefinitionApiExt.addRouteConfigurationToIntegration(clone, routeConfiguration);
+        this.setState({integration: i, propertyOnly: false, key: Math.random().toString(), selectedRouteConfiguration: routeConfiguration});
+    }
+
+    selectRouteConfiguration = (element: RouteConfigurationDefinition) => {
+        this.setState({selectedRouteConfiguration: element})
     }
 
     onPropertyUpdate = (element: CamelElement) => {
         const clone = CamelUtil.cloneIntegration(this.state.integration);
-        const i = CamelDefinitionApiExt.addErrorHandlerToIntegration(clone, element);
+        const i = CamelDefinitionApiExt.updateRouteConfigurationToIntegration(clone, element);
         this.setState({integration: i, propertyOnly: true, key: Math.random().toString()});
     }
 
-    getPropertiesPanel(errorHandler?: ErrorHandlerDefinition) {
+    getPropertiesPanel() {
         return (
             <DrawerPanelContent isResizable hasNoBorder defaultSize={'400px'} maxSize={'800px'} minSize={'300px'}>
                 <DslProperties
                     integration={this.props.integration}
-                    step={errorHandler}
+                    step={this.state.selectedRouteConfiguration}
                     onIntegrationUpdate={this.onIntegrationUpdate}
                     onPropertyUpdate={this.onPropertyUpdate}
                     clipboardStep={undefined}
@@ -131,25 +137,29 @@ export class ErrorHandlerDesigner extends React.Component<Props, State> {
     }
 
     render() {
-        const errorHandler = CamelUi.getErrorHandler(this.state.integration);
+        const routeConfigurations = CamelUi.getRouteConfigurations(this.state.integration);
         return (
             <PageSection className="rest-page" isFilled padding={{default: 'noPadding'}}>
                 <div className="rest-page-columns">
                     <Drawer isExpanded isInline>
-                        <DrawerContent panelContent={this.getPropertiesPanel(errorHandler)}>
+                        <DrawerContent panelContent={this.getPropertiesPanel()}>
                             <DrawerContentBody>
                                 <div className="graph" data-click="REST">
                                     <div className="flows">
-                                        {errorHandler && <ErrorHandlerCard key={errorHandler.uuid + this.state.key}
-                                                                           errorHandler={errorHandler}
-                                                                           deleteElement={this.showDeleteConfirmation}/>}
+                                        {routeConfigurations?.map(routeConfiguration =>
+                                            <RouteConfigurationCard key={routeConfiguration.uuid + this.state.key}
+                                                                    routeConfiguration={routeConfiguration}
+                                                                    selectedStep={this.state.selectedRouteConfiguration}
+                                                                    selectElement={this.selectRouteConfiguration}
+                                                                    deleteElement={this.showDeleteConfirmation}/>
+                                        )}
                                         <div className="add-rest">
-                                            {errorHandler === undefined && <Button
+                                            <Button
                                                 variant="primary"
                                                 data-click="ADD_REST"
                                                 icon={<PlusIcon/>}
-                                                onClick={e => this.createErrorHandlerErrorHandle()}>Create new error handler
-                                            </Button>}
+                                                onClick={e => this.createRouteConfiguration()}>Create new configuration
+                                            </Button>
                                         </div>
                                     </div>
                                 </div>
diff --git a/karavan-designer/src/designer/exception/ExceptionDesigner.tsx b/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
deleted file mode 100644
index d3b39d8..0000000
--- a/karavan-designer/src/designer/exception/ExceptionDesigner.tsx
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-import React from 'react';
-import {
-     EmptyState, EmptyStateBody, EmptyStateIcon,
-    PageSection, Title
-} from '@patternfly/react-core';
-import '../karavan.css';
-import {Integration, CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
-import CubesIcon from '@patternfly/react-icons/dist/esm/icons/cubes-icon';
-
-interface Props {
-    onSave?: (integration: Integration, propertyOnly: boolean) => void
-    integration: Integration
-    dark: boolean
-}
-
-interface State {
-    integration: Integration
-    selectedStep?: CamelElement
-    key: string
-    propertyOnly: boolean
-}
-
-export class ExceptionDesigner extends React.Component<Props, State> {
-
-    public state: State = {
-        integration: this.props.integration,
-        key: "",
-        propertyOnly: false
-    };
-
-    componentDidUpdate = (prevProps: Readonly<Props>, prevState: Readonly<State>, snapshot?: any) => {
-        if (prevState.key !== this.state.key) {
-            this.props.onSave?.call(this, this.state.integration, this.state.propertyOnly);
-        }
-    }
-
-    onIntegrationUpdate = (i: Integration) => {
-        this.setState({integration: i, key: Math.random().toString()});
-    }
-
-    render() {
-        return (
-            <PageSection className="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/rest/RestDesigner.tsx b/karavan-designer/src/designer/rest/RestDesigner.tsx
index bc32cc9..13fd96a 100644
--- a/karavan-designer/src/designer/rest/RestDesigner.tsx
+++ b/karavan-designer/src/designer/rest/RestDesigner.tsx
@@ -99,7 +99,7 @@ export class RestDesigner extends React.Component<Props, State> {
             evt.stopPropagation()
             this.setState({selectedStep: undefined,})
         }
-    };
+    }
 
     addRest = (rest: RestDefinition) => {
         const clone = CamelUtil.cloneIntegration(this.state.integration);
diff --git a/karavan-designer/src/designer/utils/CamelUi.tsx b/karavan-designer/src/designer/utils/CamelUi.tsx
index 51f8517..f4e33c5 100644
--- a/karavan-designer/src/designer/utils/CamelUi.tsx
+++ b/karavan-designer/src/designer/utils/CamelUi.tsx
@@ -21,7 +21,7 @@ import {ComponentApi} from "karavan-core/lib/api/ComponentApi";
 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 {ErrorHandlerDefinition, NamedBeanDefinition, RouteDefinition, SagaDefinition, ToDefinition} from "karavan-core/lib/model/CamelDefinition";
+import {NamedBeanDefinition, RouteConfigurationDefinition, RouteDefinition, SagaDefinition, ToDefinition} from "karavan-core/lib/model/CamelDefinition";
 import {CamelElement, Integration} from "karavan-core/lib/model/IntegrationDefinition";
 import {AggregateIcon, ChoiceIcon, FilterIcon, SagaIcon, SortIcon, SplitIcon} from "./KaravanIcons";
 import React from "react";
@@ -512,7 +512,7 @@ export class CamelUi {
         const result = new Map<string, number>();
         result.set('routes', i.spec.flows?.filter((e: any) => e.dslName === 'RouteDefinition').length || 0);
         result.set('rest', i.spec.flows?.filter((e: any) => e.dslName === 'RestDefinition').length || 0);
-        result.set('error', i.spec.flows?.filter((e: any) => e.dslName === 'ErrorHandlerDefinition').length || 0);
+        result.set('routeConfiguration', i.spec.flows?.filter((e: any) => e.dslName === 'RouteConfigurationDefinition').length || 0);
         const beans = i.spec.flows?.filter((e: any) => e.dslName === 'Beans');
         if (beans && beans.length > 0 && beans[0].beans && beans[0].beans.length > 0){
             result.set('beans', Array.from(beans[0].beans).length);
@@ -536,8 +536,10 @@ export class CamelUi {
         return result;
     }
 
-    static getErrorHandler = (integration: Integration): ErrorHandlerDefinition | undefined => {
-        const errorHandler = integration.spec.flows?.filter((e: any) => e.dslName === 'ErrorHandlerDefinition').at(0);
-        return errorHandler;
+    static getRouteConfigurations = (integration: Integration): RouteConfigurationDefinition[] | undefined => {
+        const result: CamelElement[] = [];
+        integration.spec.flows?.filter((e: any) => e.dslName === 'RouteConfigurationDefinition')
+            .forEach((f: any) => result.push(f));
+        return result;
     }
 }
\ No newline at end of file
diff --git a/karavan-designer/src/designer/utils/KaravanIcons.tsx b/karavan-designer/src/designer/utils/KaravanIcons.tsx
index 37a3182..33206f4 100644
--- a/karavan-designer/src/designer/utils/KaravanIcons.tsx
+++ b/karavan-designer/src/designer/utils/KaravanIcons.tsx
@@ -254,16 +254,17 @@ export function getDesignerIcon(icon: string) {
             <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">
+    if (icon === 'routeConfiguration') return (
+        <svg className="top-icon" width="32" height="32" viewBox="0 0 32 32">
             <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)"/>
+            <path d="M28.83 21.17L25 17.37l.67-.67a1 1 0 000-1.41l-6-6a1 1 0 00-1.41 0l-.79.79-6.76-6.79a1 1 0 00-1.41 0l-4 4-.12.15-4 6a1 1 0 00.12 1.26l3 3a1 1 0 001.42 0L10 13.41l2.09 2.09-4.8 4.79a1 1 0 000 1.41l2 2a1 1 0 00.71.3 1 1 0 00.52-.15l4.33-2.6 2.44 2.45a1 1 0 001.41 0l.67-.7 3.79 3.83a4 4 0 005.66-5.66zM10 10.58l-5 5-1.71-1.71 3.49-5.24L10 5.41l6.09 6.09-2.59 2.58zm8 11l-2.84-2.84-5 3-.74-.74L19 11.41 23.59 16zm9.42 3.83a2 2 0 01-2.83 0l-3.8-3.79 2.83-2.83 3.8 3.79a2 2 0 0 [...]
+            <path
+                d="M0 0H32V32H0z"
+                className="cls-1"
+                data-name="&lt;Transparent Rectangle&gt;"
+            ></path>
         </svg>)
     if (icon === 'yaml') return (
         <svg className="top-icon" x="0px" y="0px" width="32px" height="32px"