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 8c56c8bf Fix #1318
8c56c8bf is described below

commit 8c56c8bf5cd53b8b3f5b21f7f59e5bb86160d8a8
Author: Marat Gubaidullin <ma...@talismancloud.io>
AuthorDate: Thu Jun 13 19:51:31 2024 -0400

    Fix #1318
---
 .../property/property/ComponentPropertyField.tsx   |  2 +-
 .../property/property/DslPropertyField.tsx         | 65 +++++++-------
 .../property/property/KameletPropertyField.tsx     |  2 +-
 .../src/designer/route/element/DslElement.tsx      |  2 +-
 .../designer/route/element/DslElementHeader.tsx    |  8 +-
 karavan-core/src/core/api/CamelDefinitionApiExt.ts | 19 ++---
 karavan-core/test/findStep.spec.ts                 |  4 +-
 karavan-core/test/hasElementWithId.camel.yaml      | 98 ++++++++++++++++++++++
 karavan-core/test/hasElementWithId.spec.ts         | 57 +++++++++++++
 karavan-core/test/hasElementWithId1.camel.yaml     | 16 ++++
 karavan-core/test/hasElementWithIdError.camel.yaml | 98 ++++++++++++++++++++++
 .../property/property/ComponentPropertyField.tsx   |  2 +-
 .../property/property/DslPropertyField.tsx         | 65 +++++++-------
 .../property/property/KameletPropertyField.tsx     |  2 +-
 .../src/designer/route/element/DslElement.tsx      |  2 +-
 .../designer/route/element/DslElementHeader.tsx    |  8 +-
 karavan-space/src/designer/karavan.css             | 41 +++++----
 .../property/property/ComponentPropertyField.tsx   |  2 +-
 .../property/property/DslPropertyField.tsx         | 91 ++++++++++----------
 .../property/property/KameletPropertyField.tsx     |  4 +-
 .../src/designer/route/element/DslElement.tsx      |  2 +-
 .../designer/route/element/DslElementHeader.tsx    |  8 +-
 22 files changed, 440 insertions(+), 158 deletions(-)

diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
index 5e05ceb7..33b39fd6 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/ComponentPropertyField.tsx
@@ -92,7 +92,7 @@ export function ComponentPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     parametersChanged(property.name, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
index db35ddb4..67de1077 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/DslPropertyField.tsx
@@ -32,7 +32,7 @@ import {
     Tooltip,
     Card,
     InputGroup,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem, 
HelperTextItem, FormHelperText, HelperText
 } from '@patternfly/react-core';
 import {
     Select,
@@ -51,7 +51,7 @@ import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt"
 import {ExpressionField} from "./ExpressionField";
 import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
 import {ComponentPropertyField} from "./ComponentPropertyField";
-import {CamelElement, IntegrationFile} from 
"karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {KameletPropertyField} from "./KameletPropertyField";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {ObjectField} from "./ObjectField";
@@ -77,7 +77,6 @@ import {BeanProperties} from "./BeanProperties";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {VariablesDropdown} from "./VariablesDropdown";
 import {ROUTE, GLOBAL} from "karavan-core/lib/api/VariableUtil";
-import {getIntegrations} from "../../../topology/TopologyApi";
 
 interface Props {
     property: PropertyMeta,
@@ -122,7 +121,7 @@ export function DslPropertyField(props: Props) {
                         propertyChanged(property.name, textValue);
                     }
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
@@ -160,9 +159,6 @@ export function DslPropertyField(props: Props) {
 
     function propertyChanged(fieldId: string, value: string | number | boolean 
| any, newRoute?: RouteToCreate) {
         setCheckChanges(false);
-        if (fieldId === 'id' && 
CamelDefinitionApiExt.hasElementWithId(integration, value)) {
-            value = props.element;
-        }
         props.onPropertyChange?.(fieldId, value, newRoute);
         clearSelection(fieldId);
         if (isVariable) {
@@ -358,34 +354,33 @@ export function DslPropertyField(props: Props) {
                 </InputGroupItem>
             }
             {(!showEditor || property.secret) &&
-                <InputGroupItem isFill>
-                    <TextInput ref={ref}
-                               className="text-field" isRequired
-                               type={property.secret ? "password" : "text"}
-                               id={property.name} name={property.name}
-                               value={textValue?.toString()}
-                               customIcon={property.type !== 'string' ?
-                                   <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
-                               onBlur={_ => {
-                                   if (isNumber && isNumeric((textValue))) {
-                                       propertyChanged(property.name, 
Number(textValue))
-                                   } else if (!isNumber) {
-                                       propertyChanged(property.name, 
textValue)
-                                   }
-                               }}
-                               onFocus={_ => setCheckChanges(true)}
-                               onChange={(_, v) => {
-
-                                   if (isNumber && isNumeric(v)) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   } else if (!isNumber) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   }
-                               }}
-                               readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
-                </InputGroupItem>
+                <TextInput ref={ref}
+                           className="text-field" isRequired
+                           type={property.secret ? "password" : "text"}
+                           id={property.name} name={property.name}
+                           value={textValue?.toString()}
+                           customIcon={property.type !== 'string' ?
+                               <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
+                           onBlur={_ => {
+                               if (isNumber && isNumeric((textValue))) {
+                                   propertyChanged(property.name, 
Number(textValue))
+                               } else if (!isNumber) {
+                                   console.log("onBlur", property.name, 
textValue)
+                                   propertyChanged(property.name, textValue)
+                               }
+                           }}
+                           onFocus={_ => setCheckChanges(true)}
+                           onChange={(_, v) => {
+
+                               if (isNumber && isNumeric(v)) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               } else if (!isNumber) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               }
+                           }}
+                           readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
             }
             {showEditorButton && <InputGroupItem>
                 <Tooltip position="bottom-end" content={"Show Editor"}>
diff --git 
a/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
 
b/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
index c17a6e05..0bbda26b 100644
--- 
a/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
+++ 
b/karavan-app/src/main/webui/src/designer/property/property/KameletPropertyField.tsx
@@ -64,7 +64,7 @@ export function KameletPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     onParametersChange(property.id, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
diff --git 
a/karavan-app/src/main/webui/src/designer/route/element/DslElement.tsx 
b/karavan-app/src/main/webui/src/designer/route/element/DslElement.tsx
index 0416f3cb..d5acb0c0 100644
--- a/karavan-app/src/main/webui/src/designer/route/element/DslElement.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/element/DslElement.tsx
@@ -51,7 +51,7 @@ export function DslElement(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
-    const [integration] = useIntegrationStore((s) => [s.integration, 
s.setIntegration], shallow)
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
 
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
diff --git 
a/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx 
b/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
index 78e7da52..a9f78827 100644
--- a/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-app/src/main/webui/src/designer/route/element/DslElementHeader.tsx
@@ -23,7 +23,7 @@ import {CamelUi} from "../../utils/CamelUi";
 import {ChildElement, CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {useDesignerStore} from "../../DesignerStore";
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
 import {useRouteDesignerHook} from "../useRouteDesignerHook";
 import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from 
"../../utils/ElementIcons";
@@ -53,6 +53,8 @@ export function DslElementHeader(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
             [s.selectedUuids, s.selectedStep, s.showMoveConfirmation, 
s.setShowMoveConfirmation, s.setMoveElements], shallow)
@@ -217,6 +219,10 @@ export function DslElementHeader(props: Props) {
     function getHeaderTextWithTooltip(step: CamelElement, 
hasWideChildrenElement: boolean) {
         const title = getHeaderText(step);
         const checkRequired = CamelUtil.checkRequired(step);
+        if (CamelDefinitionApiExt.hasElementWithId(integration, (step as 
any).id) > 1) {
+            checkRequired[0] = false;
+            checkRequired[1].push('Id should be unique');
+        }
         let className = hasWideChildrenElement ? "text text-right" : "text 
text-bottom";
         if (!checkRequired[0]) className = className + " header-text-required";
         if (checkRequired[0]) {
diff --git a/karavan-core/src/core/api/CamelDefinitionApiExt.ts 
b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
index 3e2eade6..b562df1c 100644
--- a/karavan-core/src/core/api/CamelDefinitionApiExt.ts
+++ b/karavan-core/src/core/api/CamelDefinitionApiExt.ts
@@ -168,26 +168,25 @@ export class CamelDefinitionApiExt {
         return new CamelElementMeta(result?.step, result?.parentUuid, 
result?.position);
     };
 
-    static hasElementWithId = (integration: Integration, id: string): boolean 
=> {
-        let hasId = false;
-        return CamelDefinitionApiExt.checkIfHasId(integration, id, hasId);
+    static hasElementWithId = (integration: Integration, id: string): number 
=> {
+        return CamelDefinitionApiExt.checkIfHasId(integration, id, 0);
     };
 
-    static checkIfHasId = (obj: Object, id: string, hasId: boolean): boolean 
=> {
+    static checkIfHasId = (obj: Object, id: string, counter: number): number 
=> {
         for (const propName in obj) {
             let prop = (obj as any)[propName];
-            if (hasId || (propName === 'id' && id === prop)) {
-                hasId = true;
-                break;
+            if (propName === 'id' && id === prop) {
+                counter++;
+                counter = CamelDefinitionApiExt.checkIfHasId(prop, id, 
counter);
             } else if (typeof prop === 'object' && prop !== null) {
-                hasId = CamelDefinitionApiExt.checkIfHasId(prop, id, hasId);
+                counter = CamelDefinitionApiExt.checkIfHasId(prop, id, 
counter);
             } else if (Array.isArray(prop)) {
                 for (const element of prop) {
-                    CamelDefinitionApiExt.checkIfHasId(element, id, hasId);
+                    CamelDefinitionApiExt.checkIfHasId(element, id, counter);
                 }
             }
         }
-        return hasId;
+        return counter;
     };
 
     static moveRouteElement = (integration: Integration, source: string, 
target: string, asChild: boolean,): Integration => {
diff --git a/karavan-core/test/findStep.spec.ts 
b/karavan-core/test/findStep.spec.ts
index e85c087d..6fc0226e 100644
--- a/karavan-core/test/findStep.spec.ts
+++ b/karavan-core/test/findStep.spec.ts
@@ -106,7 +106,7 @@ describe('Find Step', () => {
         const res1 = CamelDefinitionApiExt.hasElementWithId(i, 'to-6a8b');
         const res2 = CamelDefinitionApiExt.hasElementWithId(i, 'to-6a81');
 
-        expect(res1).to.equal(true);
-        expect(res2).to.equal(false);
+        expect(res1).to.equal(1);
+        expect(res2).to.equal(0);
     });
 });
\ No newline at end of file
diff --git a/karavan-core/test/hasElementWithId.camel.yaml 
b/karavan-core/test/hasElementWithId.camel.yaml
new file mode 100644
index 00000000..1ac491b4
--- /dev/null
+++ b/karavan-core/test/hasElementWithId.camel.yaml
@@ -0,0 +1,98 @@
+- rest:
+    id: rest-328e
+    description: >-
+      It has a broken design for long endpoint descriptions and a dual topology
+      view rendering
+    get:
+      - id: get-5ab7
+        to: direct:hello
+- route:
+    id: route-0dc7
+    description: Audit Start
+    nodePrefixId: route-972
+    from:
+      id: from-846a
+      description: Audit Start
+      uri: direct
+      parameters:
+        name: start
+      steps:
+        - to:
+            id: to-3597
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: route-a54e
+    description: Audit Finish
+    nodePrefixId: route-1d1
+    from:
+      id: from-47d5
+      description: Audit Finish
+      uri: direct
+      parameters:
+        name: finish
+      steps:
+        - to:
+            id: to-3cf2
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: route-07ed
+    description: Audit Step
+    nodePrefixId: route-833
+    from:
+      id: from-e007
+      uri: direct
+      parameters:
+        name: step
+      steps:
+        - to:
+            id: to-fa9e
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: hello
+    from:
+      id: from-3f49
+      uri: direct
+      parameters:
+        name: hello
+      steps:
+        - to:
+            id: to-428d
+            uri: activemq
+        - to:
+            id: to-fed7
+            uri: kafka
+- routeConfiguration:
+    id: auditedRoute
+    intercept:
+      - intercept:
+          id: intercept-0deb
+          steps:
+            - to:
+                id: to-b470
+                uri: direct
+                parameters:
+                  name: step
+    interceptFrom:
+      - interceptFrom:
+          id: interceptFrom-4041
+          steps:
+            - to:
+                id: to-6861
+                uri: direct
+                parameters:
+                  name: start
+    onCompletion:
+      - onCompletion:
+          id: onCompletion-3dab
+          steps:
+            - to:
+                id: to-dd4e
+                uri: direct
+                parameters:
+                  name: finish
diff --git a/karavan-core/test/hasElementWithId.spec.ts 
b/karavan-core/test/hasElementWithId.spec.ts
new file mode 100644
index 00000000..68116e2a
--- /dev/null
+++ b/karavan-core/test/hasElementWithId.spec.ts
@@ -0,0 +1,57 @@
+/*
+ * 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 'mocha';
+import {
+    FromDefinition,
+    LogDefinition,
+    WhenDefinition,
+    ChoiceDefinition,
+    MulticastDefinition,
+    ExpressionDefinition,
+    RouteDefinition, TryDefinition,CatchDefinition
+} from "../src/core/model/CamelDefinition";
+import {CamelDefinitionApiExt} from "../src/core/api/CamelDefinitionApiExt";
+import {CamelDefinitionYaml} from "../src/core/api/CamelDefinitionYaml";
+import {SimpleExpression} from "../src/core/model/CamelDefinition";
+import {Integration} from "../src/core/model/IntegrationDefinition";
+import * as fs from 'fs';
+
+describe('Check for id duplicates', () => {
+
+    it('Check YAML OK', () => {
+        const yaml = 
fs.readFileSync('test/hasElementWithId.camel.yaml',{encoding:'utf8', flag:'r'});
+        const i1 = 
CamelDefinitionYaml.yamlToIntegration("hasElementWithId.camel.yaml", yaml);
+
+        expect(CamelDefinitionApiExt.hasElementWithId(i1, 
'from-47d5')).to.equal(1);
+    });
+
+    it('Check YAML OK', () => {
+        const yaml = 
fs.readFileSync('test/hasElementWithId1.camel.yaml',{encoding:'utf8', 
flag:'r'});
+        const i1 = 
CamelDefinitionYaml.yamlToIntegration("hasElementWithId.camel.yaml", yaml);
+
+        expect(CamelDefinitionApiExt.hasElementWithId(i1, 
'fhello-world')).to.equal(2);
+    });
+
+    it('Check YAML Error', () => {
+        const yaml = fs.readFileSync('test/hasElementWithIdError.camel.yaml', 
{ encoding: 'utf8', flag: 'r' });
+        const i1 = 
CamelDefinitionYaml.yamlToIntegration('hasElementWithId.camel.yaml', yaml);
+
+        expect(CamelDefinitionApiExt.hasElementWithId(i1, 
'from-47d5')).to.equal(2);
+    });
+
+});
diff --git a/karavan-core/test/hasElementWithId1.camel.yaml 
b/karavan-core/test/hasElementWithId1.camel.yaml
new file mode 100644
index 00000000..84226c40
--- /dev/null
+++ b/karavan-core/test/hasElementWithId1.camel.yaml
@@ -0,0 +1,16 @@
+- route:
+    id: route-0dc7
+    description: Audit Start
+    nodePrefixId: route-972
+    from:
+      id: fhello-world
+      description: Audit Start
+      uri: direct
+      parameters:
+        name: start
+      steps:
+        - to:
+            id: fhello-world
+            uri: kafka
+            parameters:
+              topic: audit
diff --git a/karavan-core/test/hasElementWithIdError.camel.yaml 
b/karavan-core/test/hasElementWithIdError.camel.yaml
new file mode 100644
index 00000000..addebf3f
--- /dev/null
+++ b/karavan-core/test/hasElementWithIdError.camel.yaml
@@ -0,0 +1,98 @@
+- rest:
+    id: rest-328e
+    description: >-
+      It has a broken design for long endpoint descriptions and a dual topology
+      view rendering
+    get:
+      - id: get-5ab7
+        to: direct:hello
+- route:
+    id: route-0dc7
+    description: Audit Start
+    nodePrefixId: route-972
+    from:
+      id: from-47d5
+      description: Audit Start
+      uri: direct
+      parameters:
+        name: start
+      steps:
+        - to:
+            id: to-3597
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: route-a54e
+    description: Audit Finish
+    nodePrefixId: route-1d1
+    from:
+      id: from-47d5
+      description: Audit Finish
+      uri: direct
+      parameters:
+        name: finish
+      steps:
+        - to:
+            id: to-3cf2
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: route-07ed
+    description: Audit Step
+    nodePrefixId: route-833
+    from:
+      id: from-e007
+      uri: direct
+      parameters:
+        name: step
+      steps:
+        - to:
+            id: to-fa9e
+            uri: kafka
+            parameters:
+              topic: audit
+- route:
+    id: hello
+    from:
+      id: from-3f49
+      uri: direct
+      parameters:
+        name: hello
+      steps:
+        - to:
+            id: to-428d
+            uri: activemq
+        - to:
+            id: to-fed7
+            uri: kafka
+- routeConfiguration:
+    id: auditedRoute
+    intercept:
+      - intercept:
+          id: intercept-0deb
+          steps:
+            - to:
+                id: to-b470
+                uri: direct
+                parameters:
+                  name: step
+    interceptFrom:
+      - interceptFrom:
+          id: interceptFrom-4041
+          steps:
+            - to:
+                id: to-6861
+                uri: direct
+                parameters:
+                  name: start
+    onCompletion:
+      - onCompletion:
+          id: onCompletion-3dab
+          steps:
+            - to:
+                id: to-dd4e
+                uri: direct
+                parameters:
+                  name: finish
diff --git 
a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx 
b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
index 5e05ceb7..33b39fd6 100644
--- a/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/ComponentPropertyField.tsx
@@ -92,7 +92,7 @@ export function ComponentPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     parametersChanged(property.name, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
diff --git 
a/karavan-designer/src/designer/property/property/DslPropertyField.tsx 
b/karavan-designer/src/designer/property/property/DslPropertyField.tsx
index db35ddb4..67de1077 100644
--- a/karavan-designer/src/designer/property/property/DslPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/DslPropertyField.tsx
@@ -32,7 +32,7 @@ import {
     Tooltip,
     Card,
     InputGroup,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem, 
HelperTextItem, FormHelperText, HelperText
 } from '@patternfly/react-core';
 import {
     Select,
@@ -51,7 +51,7 @@ import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt"
 import {ExpressionField} from "./ExpressionField";
 import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
 import {ComponentPropertyField} from "./ComponentPropertyField";
-import {CamelElement, IntegrationFile} from 
"karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {KameletPropertyField} from "./KameletPropertyField";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {ObjectField} from "./ObjectField";
@@ -77,7 +77,6 @@ import {BeanProperties} from "./BeanProperties";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {VariablesDropdown} from "./VariablesDropdown";
 import {ROUTE, GLOBAL} from "karavan-core/lib/api/VariableUtil";
-import {getIntegrations} from "../../../topology/TopologyApi";
 
 interface Props {
     property: PropertyMeta,
@@ -122,7 +121,7 @@ export function DslPropertyField(props: Props) {
                         propertyChanged(property.name, textValue);
                     }
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
@@ -160,9 +159,6 @@ export function DslPropertyField(props: Props) {
 
     function propertyChanged(fieldId: string, value: string | number | boolean 
| any, newRoute?: RouteToCreate) {
         setCheckChanges(false);
-        if (fieldId === 'id' && 
CamelDefinitionApiExt.hasElementWithId(integration, value)) {
-            value = props.element;
-        }
         props.onPropertyChange?.(fieldId, value, newRoute);
         clearSelection(fieldId);
         if (isVariable) {
@@ -358,34 +354,33 @@ export function DslPropertyField(props: Props) {
                 </InputGroupItem>
             }
             {(!showEditor || property.secret) &&
-                <InputGroupItem isFill>
-                    <TextInput ref={ref}
-                               className="text-field" isRequired
-                               type={property.secret ? "password" : "text"}
-                               id={property.name} name={property.name}
-                               value={textValue?.toString()}
-                               customIcon={property.type !== 'string' ?
-                                   <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
-                               onBlur={_ => {
-                                   if (isNumber && isNumeric((textValue))) {
-                                       propertyChanged(property.name, 
Number(textValue))
-                                   } else if (!isNumber) {
-                                       propertyChanged(property.name, 
textValue)
-                                   }
-                               }}
-                               onFocus={_ => setCheckChanges(true)}
-                               onChange={(_, v) => {
-
-                                   if (isNumber && isNumeric(v)) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   } else if (!isNumber) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   }
-                               }}
-                               readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
-                </InputGroupItem>
+                <TextInput ref={ref}
+                           className="text-field" isRequired
+                           type={property.secret ? "password" : "text"}
+                           id={property.name} name={property.name}
+                           value={textValue?.toString()}
+                           customIcon={property.type !== 'string' ?
+                               <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
+                           onBlur={_ => {
+                               if (isNumber && isNumeric((textValue))) {
+                                   propertyChanged(property.name, 
Number(textValue))
+                               } else if (!isNumber) {
+                                   console.log("onBlur", property.name, 
textValue)
+                                   propertyChanged(property.name, textValue)
+                               }
+                           }}
+                           onFocus={_ => setCheckChanges(true)}
+                           onChange={(_, v) => {
+
+                               if (isNumber && isNumeric(v)) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               } else if (!isNumber) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               }
+                           }}
+                           readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
             }
             {showEditorButton && <InputGroupItem>
                 <Tooltip position="bottom-end" content={"Show Editor"}>
diff --git 
a/karavan-designer/src/designer/property/property/KameletPropertyField.tsx 
b/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
index c17a6e05..0bbda26b 100644
--- a/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
+++ b/karavan-designer/src/designer/property/property/KameletPropertyField.tsx
@@ -64,7 +64,7 @@ export function KameletPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     onParametersChange(property.id, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
diff --git a/karavan-designer/src/designer/route/element/DslElement.tsx 
b/karavan-designer/src/designer/route/element/DslElement.tsx
index 0416f3cb..d5acb0c0 100644
--- a/karavan-designer/src/designer/route/element/DslElement.tsx
+++ b/karavan-designer/src/designer/route/element/DslElement.tsx
@@ -51,7 +51,7 @@ export function DslElement(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
-    const [integration] = useIntegrationStore((s) => [s.integration, 
s.setIntegration], shallow)
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
 
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
diff --git a/karavan-designer/src/designer/route/element/DslElementHeader.tsx 
b/karavan-designer/src/designer/route/element/DslElementHeader.tsx
index 78e7da52..a9f78827 100644
--- a/karavan-designer/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-designer/src/designer/route/element/DslElementHeader.tsx
@@ -23,7 +23,7 @@ import {CamelUi} from "../../utils/CamelUi";
 import {ChildElement, CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {useDesignerStore} from "../../DesignerStore";
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
 import {useRouteDesignerHook} from "../useRouteDesignerHook";
 import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from 
"../../utils/ElementIcons";
@@ -53,6 +53,8 @@ export function DslElementHeader(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
             [s.selectedUuids, s.selectedStep, s.showMoveConfirmation, 
s.setShowMoveConfirmation, s.setMoveElements], shallow)
@@ -217,6 +219,10 @@ export function DslElementHeader(props: Props) {
     function getHeaderTextWithTooltip(step: CamelElement, 
hasWideChildrenElement: boolean) {
         const title = getHeaderText(step);
         const checkRequired = CamelUtil.checkRequired(step);
+        if (CamelDefinitionApiExt.hasElementWithId(integration, (step as 
any).id) > 1) {
+            checkRequired[0] = false;
+            checkRequired[1].push('Id should be unique');
+        }
         let className = hasWideChildrenElement ? "text text-right" : "text 
text-bottom";
         if (!checkRequired[0]) className = className + " header-text-required";
         if (checkRequired[0]) {
diff --git a/karavan-space/src/designer/karavan.css 
b/karavan-space/src/designer/karavan.css
index 9e5826a8..99a0392d 100644
--- a/karavan-space/src/designer/karavan.css
+++ b/karavan-space/src/designer/karavan.css
@@ -146,7 +146,6 @@
     height: 160px;
 }
 
-
 .kamelets-page .kamelet-card .pf-v5-c-card__header {
     padding-top: var(--pf-v5-global--spacer--sm);
 }
@@ -189,12 +188,13 @@
     padding: 5px;
     display: flex;
     flex-direction: row;
-    justify-content:flex-end;
+    justify-content: flex-end;
 }
-.kamelets-page .kamelet-card .header-labels .pf-v5-c-card__header-main{
+
+.kamelets-page .kamelet-card .header-labels .pf-v5-c-card__header-main {
     display: flex;
     flex-direction: row;
-    justify-content:space-between;
+    justify-content: space-between;
 }
 
 .kamelets-page .kamelet-card .footer-labels {
@@ -320,7 +320,12 @@
     min-width: 0px;
 }
 
-.karavan .page .main-tabs-wrapper .main-tabs .pf-v5-c-tabs__link 
.pf-v5-c-tabs__item-icon {
+.karavan
+.page
+.main-tabs-wrapper
+.main-tabs
+.pf-v5-c-tabs__link
+.pf-v5-c-tabs__item-icon {
     height: 24px;
     margin-right: 0;
 }
@@ -416,8 +421,8 @@
 
 .karavan .dsl-page .graph .connections .path-incoming {
     stroke-dasharray: 5;
-    -webkit-animation: dashdraw .5s linear infinite;
-    animation: dashdraw .5s linear infinite;
+    -webkit-animation: dashdraw 0.5s linear infinite;
+    animation: dashdraw 0.5s linear infinite;
     stroke: var(--pf-v5-global--Color--200);
     stroke-width: 1;
     fill: transparent;
@@ -442,15 +447,15 @@
 .karavan .dsl-page .graph .connections .path-seda {
     stroke-dasharray: 2;
     stroke: var(--pf-v5-global--Color--200);
-    -webkit-animation: dashdraw .5s linear infinite;
-    animation: dashdraw .5s linear infinite;
+    -webkit-animation: dashdraw 0.5s linear infinite;
+    animation: dashdraw 0.5s linear infinite;
     stroke-width: 1;
     fill: transparent;
 }
 
 @keyframes dashdraw {
     0% {
-        stroke-dashoffset: 10
+        stroke-dashoffset: 10;
     }
 }
 
@@ -514,7 +519,6 @@
     margin: 0 auto 3px auto;
 }
 
-
 .element-builder:hover .add-button,
 .karavan .step-element:hover .add-element-button,
 .karavan .step-element:hover .add-button {
@@ -548,7 +552,6 @@
     overflow-wrap: anywhere;
 }
 
-
 /*Beans*/
 .karavan .rest-page .properties .bean-properties .pf-v5-c-form__group-control {
     display: flex;
@@ -616,7 +619,6 @@
     padding: 0;
 }
 
-
 .karavan .project-builder .card-header svg {
     margin-right: 6px;
 }
@@ -710,6 +712,15 @@
     background-color: var(--pf-v5-global--BackgroundColor--light-300);
     margin-bottom: 100px;
 }
-.karavan .knowledbase-eip-section .pf-v5-c-toggle-group{
-    margin:16px;
+
+.karavan .knowledbase-eip-section .pf-v5-c-toggle-group {
+    margin: 16px;
 }
+
+input[type="number"]::-webkit-inner-spin-button,
+input[type="number"]::-webkit-outer-spin-button {
+    -webkit-appearance: none;
+    -moz-appearance: none;
+    appearance: none;
+    margin: 0;
+}
\ No newline at end of file
diff --git 
a/karavan-space/src/designer/property/property/ComponentPropertyField.tsx 
b/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
index 5e05ceb7..33b39fd6 100644
--- a/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/ComponentPropertyField.tsx
@@ -92,7 +92,7 @@ export function ComponentPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     parametersChanged(property.name, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
diff --git a/karavan-space/src/designer/property/property/DslPropertyField.tsx 
b/karavan-space/src/designer/property/property/DslPropertyField.tsx
index 24d22a24..67de1077 100644
--- a/karavan-space/src/designer/property/property/DslPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/DslPropertyField.tsx
@@ -32,7 +32,7 @@ import {
     Tooltip,
     Card,
     InputGroup,
-    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem
+    capitalize, InputGroupItem, TextVariants, ToggleGroup, ToggleGroupItem, 
HelperTextItem, FormHelperText, HelperText
 } from '@patternfly/react-core';
 import {
     Select,
@@ -51,7 +51,7 @@ import {CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt"
 import {ExpressionField} from "./ExpressionField";
 import {CamelUi, RouteToCreate} from "../../utils/CamelUi";
 import {ComponentPropertyField} from "./ComponentPropertyField";
-import {CamelElement, IntegrationFile} from 
"karavan-core/lib/model/IntegrationDefinition";
+import {CamelElement} from "karavan-core/lib/model/IntegrationDefinition";
 import {KameletPropertyField} from "./KameletPropertyField";
 import PlusIcon from "@patternfly/react-icons/dist/esm/icons/plus-icon";
 import {ObjectField} from "./ObjectField";
@@ -77,7 +77,6 @@ import {BeanProperties} from "./BeanProperties";
 import {PropertyPlaceholderDropdown} from "./PropertyPlaceholderDropdown";
 import {VariablesDropdown} from "./VariablesDropdown";
 import {ROUTE, GLOBAL} from "karavan-core/lib/api/VariableUtil";
-import {getIntegrations} from "../../../topology/TopologyApi";
 
 interface Props {
     property: PropertyMeta,
@@ -122,7 +121,7 @@ export function DslPropertyField(props: Props) {
                         propertyChanged(property.name, textValue);
                     }
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
@@ -160,9 +159,6 @@ export function DslPropertyField(props: Props) {
 
     function propertyChanged(fieldId: string, value: string | number | boolean 
| any, newRoute?: RouteToCreate) {
         setCheckChanges(false);
-        if (fieldId === 'id' && 
CamelDefinitionApiExt.hasElementWithId(integration, value)) {
-            value = props.element;
-        }
         props.onPropertyChange?.(fieldId, value, newRoute);
         clearSelection(fieldId);
         if (isVariable) {
@@ -358,34 +354,33 @@ export function DslPropertyField(props: Props) {
                 </InputGroupItem>
             }
             {(!showEditor || property.secret) &&
-                <InputGroupItem isFill>
-                    <TextInput ref={ref}
-                               className="text-field" isRequired
-                               type={property.secret ? "password" : "text"}
-                               id={property.name} name={property.name}
-                               value={textValue?.toString()}
-                               customIcon={property.type !== 'string' ?
-                                   <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
-                               onBlur={_ => {
-                                   if (isNumber && isNumeric((textValue))) {
-                                       propertyChanged(property.name, 
Number(textValue))
-                                   } else if (!isNumber) {
-                                       propertyChanged(property.name, 
textValue)
-                                   }
-                               }}
-                               onFocus={_ => setCheckChanges(true)}
-                               onChange={(_, v) => {
-
-                                   if (isNumber && isNumeric(v)) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   } else if (!isNumber) {
-                                       setTextValue(v);
-                                       setCheckChanges(true);
-                                   }
-                               }}
-                               readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
-                </InputGroupItem>
+                <TextInput ref={ref}
+                           className="text-field" isRequired
+                           type={property.secret ? "password" : "text"}
+                           id={property.name} name={property.name}
+                           value={textValue?.toString()}
+                           customIcon={property.type !== 'string' ?
+                               <Text 
component={TextVariants.p}>{property.type}</Text> : undefined}
+                           onBlur={_ => {
+                               if (isNumber && isNumeric((textValue))) {
+                                   propertyChanged(property.name, 
Number(textValue))
+                               } else if (!isNumber) {
+                                   console.log("onBlur", property.name, 
textValue)
+                                   propertyChanged(property.name, textValue)
+                               }
+                           }}
+                           onFocus={_ => setCheckChanges(true)}
+                           onChange={(_, v) => {
+
+                               if (isNumber && isNumeric(v)) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               } else if (!isNumber) {
+                                   setTextValue(v);
+                                   setCheckChanges(true);
+                               }
+                           }}
+                           readOnlyVariant={uriReadOnly ? "default" : 
undefined}/>
             }
             {showEditorButton && <InputGroupItem>
                 <Tooltip position="bottom-end" content={"Show Editor"}>
@@ -403,10 +398,10 @@ export function DslPropertyField(props: Props) {
                                        title={property.displayName}
                                        onClose={() => setShowEditor(false)}
                                        onSave={(fieldId, value1) => {
-                                 propertyChanged(property.name, value1)
-                                 setTextValue(value1);
-                                 setShowEditor(false);
-                             }}/>
+                                           propertyChanged(property.name, 
value1)
+                                           setTextValue(value1);
+                                           setShowEditor(false);
+                                       }}/>
             </InputGroupItem>}
         </InputGroup>
     }
@@ -457,10 +452,10 @@ export function DslPropertyField(props: Props) {
                                        title="Java Class"
                                        onClose={() => setShowEditor(false)}
                                        onSave={(fieldId, value1) => {
-                                 propertyChanged(fieldId, value);
-                                 InfrastructureAPI.onSaveCustomCode?.(value, 
value1);
-                                 setShowEditor(false)
-                             }}/>
+                                           propertyChanged(fieldId, value);
+                                           
InfrastructureAPI.onSaveCustomCode?.(value, value1);
+                                           setShowEditor(false)
+                                       }}/>
             </InputGroupItem>}
         </InputGroup>)
     }
@@ -500,10 +495,10 @@ export function DslPropertyField(props: Props) {
                                            title={`Expression 
(${dslLanguage?.[0]})`}
                                            onClose={() => setShowEditor(false)}
                                            onSave={(fieldId, value1) => {
-                                     propertyChanged(fieldId, value1);
-                                     setTextValue(value1);
-                                     setShowEditor(false);
-                                 }}/>
+                                               propertyChanged(fieldId, 
value1);
+                                               setTextValue(value1);
+                                               setShowEditor(false);
+                                           }}/>
                 </InputGroupItem>}
             </InputGroup>
         )
@@ -1016,4 +1011,4 @@ export function DslPropertyField(props: Props) {
             {getInfrastructureSelectorModal()}
         </div>
     )
-}
+}
\ No newline at end of file
diff --git 
a/karavan-space/src/designer/property/property/KameletPropertyField.tsx 
b/karavan-space/src/designer/property/property/KameletPropertyField.tsx
index 43c4860d..0bbda26b 100644
--- a/karavan-space/src/designer/property/property/KameletPropertyField.tsx
+++ b/karavan-space/src/designer/property/property/KameletPropertyField.tsx
@@ -64,7 +64,7 @@ export function KameletPropertyField(props: Props) {
                 if (props.value !== textValue) {
                     onParametersChange(property.id, textValue);
                 }
-            }, 3000);
+            }, 1300);
             return () => {
                 clearInterval(interval)
             }
@@ -218,7 +218,7 @@ export function KameletPropertyField(props: Props) {
                        name={id}
                        className="text-field"
                        isRequired
-                       // type='number'
+                // type='number'
                        value={textValue?.toString()}
                        customIcon={<Text 
component={TextVariants.p}>{property.type}</Text>}
                        onBlur={_ => {
diff --git a/karavan-space/src/designer/route/element/DslElement.tsx 
b/karavan-space/src/designer/route/element/DslElement.tsx
index 0416f3cb..d5acb0c0 100644
--- a/karavan-space/src/designer/route/element/DslElement.tsx
+++ b/karavan-space/src/designer/route/element/DslElement.tsx
@@ -51,7 +51,7 @@ export function DslElement(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
-    const [integration] = useIntegrationStore((s) => [s.integration, 
s.setIntegration], shallow)
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
 
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
diff --git a/karavan-space/src/designer/route/element/DslElementHeader.tsx 
b/karavan-space/src/designer/route/element/DslElementHeader.tsx
index 78e7da52..a9f78827 100644
--- a/karavan-space/src/designer/route/element/DslElementHeader.tsx
+++ b/karavan-space/src/designer/route/element/DslElementHeader.tsx
@@ -23,7 +23,7 @@ import {CamelUi} from "../../utils/CamelUi";
 import {ChildElement, CamelDefinitionApiExt} from 
"karavan-core/lib/api/CamelDefinitionApiExt";
 import {CamelUtil} from "karavan-core/lib/api/CamelUtil";
 import {CamelDisplayUtil} from "karavan-core/lib/api/CamelDisplayUtil";
-import {useDesignerStore} from "../../DesignerStore";
+import {useDesignerStore, useIntegrationStore} from "../../DesignerStore";
 import {shallow} from "zustand/shallow";
 import {useRouteDesignerHook} from "../useRouteDesignerHook";
 import {AddElementIcon, DeleteElementIcon, InsertElementIcon} from 
"../../utils/ElementIcons";
@@ -53,6 +53,8 @@ export function DslElementHeader(props: Props) {
         isActionKamelet
     } = useRouteDesignerHook();
 
+    const [integration] = useIntegrationStore((s) => [s.integration], shallow)
+
     const [selectedUuids, selectedStep, showMoveConfirmation, 
setShowMoveConfirmation, setMoveElements] =
         useDesignerStore((s) =>
             [s.selectedUuids, s.selectedStep, s.showMoveConfirmation, 
s.setShowMoveConfirmation, s.setMoveElements], shallow)
@@ -217,6 +219,10 @@ export function DslElementHeader(props: Props) {
     function getHeaderTextWithTooltip(step: CamelElement, 
hasWideChildrenElement: boolean) {
         const title = getHeaderText(step);
         const checkRequired = CamelUtil.checkRequired(step);
+        if (CamelDefinitionApiExt.hasElementWithId(integration, (step as 
any).id) > 1) {
+            checkRequired[0] = false;
+            checkRequired[1].push('Id should be unique');
+        }
         let className = hasWideChildrenElement ? "text text-right" : "text 
text-bottom";
         if (!checkRequired[0]) className = className + " header-text-required";
         if (checkRequired[0]) {

Reply via email to