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]) {